Implement copy action
This commit is contained in:
		| @@ -3,7 +3,6 @@ package ovh.gasser.newshapes; | ||||
| import ovh.gasser.newshapes.shapes.SCircle; | ||||
| import ovh.gasser.newshapes.shapes.SCollection; | ||||
| import ovh.gasser.newshapes.shapes.SRectangle; | ||||
| import ovh.gasser.newshapes.shapes.Shape; | ||||
| import ovh.gasser.newshapes.ui.ShapesView; | ||||
|  | ||||
| import javax.swing.*; | ||||
| @@ -12,7 +11,7 @@ import java.awt.*; | ||||
| public class App { | ||||
|  | ||||
|     public static final Dimension WIN_SIZE = new Dimension(800, 600); | ||||
|     private Shape model; | ||||
|     private SCollection model; | ||||
|  | ||||
|     private App() throws HeadlessException { | ||||
|         final JFrame frame = new JFrame("Reactive shapes"); | ||||
|   | ||||
| @@ -48,4 +48,7 @@ public abstract class AbstractShape implements Shape { | ||||
|     public String toString() { | ||||
|         return String.format("x=%d, y=%d, width=%d, height=%d", bounds.x, bounds.y, bounds.width, bounds.height); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public abstract Shape clone(); | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package ovh.gasser.newshapes.shapes; | ||||
|  | ||||
| import ovh.gasser.newshapes.ShapeVisitor; | ||||
| import ovh.gasser.newshapes.attributes.ColorAttributes; | ||||
| import ovh.gasser.newshapes.attributes.SelectionAttributes; | ||||
|  | ||||
| import java.awt.*; | ||||
| @@ -19,13 +20,24 @@ public class SCircle extends AbstractShape { | ||||
|         visitor.visitCircle(this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Shape clone() { | ||||
|         var color = (ColorAttributes) getAttributes(ColorAttributes.ID); | ||||
|         return SCircle.create(super.getBounds().x, super.getBounds().y, this.radius, color.strokedColor); | ||||
|     } | ||||
|  | ||||
|     public int getRadius() { | ||||
|         return radius; | ||||
|     } | ||||
|  | ||||
|     public static SCircle create(int x, int y, int radius) { | ||||
|         return create(x, y, radius, Color.BLACK); | ||||
|     } | ||||
|  | ||||
|     public static SCircle create(int x, int y, int radius, Color color) { | ||||
|         var circle = new SCircle(x, y, radius); | ||||
|         circle.addAttributes(new SelectionAttributes()); | ||||
|         circle.addAttributes(new ColorAttributes(false, true, Color.BLACK,  color)); | ||||
|         return circle; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -12,6 +12,7 @@ import java.util.ArrayList; | ||||
| import java.util.Iterator; | ||||
| import java.util.List; | ||||
| import java.util.Spliterator; | ||||
| import java.util.stream.Collectors; | ||||
|  | ||||
| public class SCollection extends AbstractShape implements Streamable<Shape> { | ||||
|     private final static Logger logger = LoggerFactory.getLogger(SCollection.class); | ||||
| @@ -43,6 +44,14 @@ public class SCollection extends AbstractShape implements Streamable<Shape> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Shape clone() { | ||||
|         var clonedChildren = children.stream().map(Shape::clone).toArray(Shape[]::new); | ||||
|         var collection = new SCollection(clonedChildren); | ||||
|         collection.addAttributes(new SelectionAttributes()); | ||||
|         return collection; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void setLoc(Point newLoc) { | ||||
|         final Point loc = getBounds().getLocation(); | ||||
| @@ -59,6 +68,10 @@ public class SCollection extends AbstractShape implements Streamable<Shape> { | ||||
|         return children.spliterator(); | ||||
|     } | ||||
|  | ||||
|     public void add(Shape s) { | ||||
|         children.add(s); | ||||
|     } | ||||
|  | ||||
|     public void remove(Shape s) { | ||||
|         if (!children.remove(s)) { | ||||
|             logger.error("Unable to delete shape: {}", s); | ||||
|   | ||||
| @@ -24,14 +24,19 @@ public class SRectangle extends AbstractShape { | ||||
|                 '}'; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Shape clone() { | ||||
|         var color = (ColorAttributes) this.getAttributes(ColorAttributes.ID); | ||||
|         return SRectangle.create(super.getBounds().x, super.getBounds().y, getBounds().width, getBounds().height, color.strokedColor); | ||||
|     } | ||||
|  | ||||
|     public static SRectangle create(int x, int y, int width, int height) { | ||||
|         SRectangle rect = new SRectangle(new Rectangle(x, y, width, height)); | ||||
|         rect.addAttributes(new SelectionAttributes()); | ||||
|         return rect; | ||||
|         return create(x, y, width, height, Color.BLACK); | ||||
|     } | ||||
|  | ||||
|     public static SRectangle create(int x, int y, int width, int height, Color color) { | ||||
|         final SRectangle rect = create(x, y, width, height); | ||||
|         SRectangle rect = new SRectangle(new Rectangle(x, y, width, height)); | ||||
|         rect.addAttributes(new SelectionAttributes()); | ||||
|         rect.addAttributes(new ColorAttributes(false, true, Color.BLACK, color)); | ||||
|         return rect; | ||||
|     } | ||||
|   | ||||
| @@ -12,4 +12,5 @@ public interface Shape { | ||||
|     Attributes getAttributes(String key); | ||||
|     void addAttributes(Attributes attr); | ||||
|     Rectangle getBounds(); | ||||
|     Shape clone(); | ||||
| } | ||||
|   | ||||
| @@ -15,10 +15,10 @@ import java.util.Optional; | ||||
| public class Controller { | ||||
|     private final static Logger logger = LoggerFactory.getLogger(Controller.class); | ||||
|     private final ShapesView view; | ||||
|     private final Shape model; | ||||
|     private final SCollection model; | ||||
|     private Selection selection; | ||||
|  | ||||
|     Controller(ShapesView view, Shape model) { | ||||
|     Controller(ShapesView view, SCollection model) { | ||||
|         this.view = view; | ||||
|         this.model = model; | ||||
|  | ||||
| @@ -53,8 +53,7 @@ public class Controller { | ||||
|     } | ||||
|  | ||||
|     private void handleMousePressed(MouseEvent evt) { | ||||
|         var sc = (SCollection) this.model; | ||||
|         getTarget(evt, sc) | ||||
|         getTarget(evt, this.model) | ||||
|                 .ifPresentOrElse( | ||||
|                         s -> { | ||||
|                             if (selection != null) resetSelection(); | ||||
| @@ -73,18 +72,29 @@ public class Controller { | ||||
|             case KeyEvent.VK_DELETE: | ||||
|                 deleteSelected(); | ||||
|                 break; | ||||
|             case KeyEvent.VK_C: | ||||
|                 copySelection(); | ||||
|                 break; | ||||
|             default: | ||||
|                 logger.warn("Pressed unhandled key: {}", evt.getKeyChar()); | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void copySelection() { | ||||
|         if (selection == null) { | ||||
|             logger.debug("No selection to copy"); | ||||
|             return; | ||||
|         } | ||||
|         this.model.add(selection.shape.clone()); | ||||
|         view.repaint(); | ||||
|     } | ||||
|  | ||||
|     private void deleteSelected() { | ||||
|         if (selection == null) return; | ||||
|         logger.debug("Deleting selected shape(s)"); | ||||
|         var sc = (SCollection) this.model; | ||||
|         sc.remove(selection.shape); | ||||
|         selection = null; | ||||
|         this.model.remove(selection.shape); | ||||
|         resetSelection(); | ||||
|         view.repaint(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -3,6 +3,7 @@ package ovh.gasser.newshapes.ui; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| import ovh.gasser.newshapes.ShapeVisitor; | ||||
| import ovh.gasser.newshapes.shapes.SCollection; | ||||
| import ovh.gasser.newshapes.shapes.Shape; | ||||
|  | ||||
| import javax.swing.*; | ||||
| @@ -15,7 +16,7 @@ public class ShapesView extends JPanel { | ||||
|     private final Controller controller; | ||||
|     private ShapeVisitor draftman; | ||||
|  | ||||
|     public ShapesView(Shape model) { | ||||
|     public ShapesView(SCollection model) { | ||||
|         this.model = model; | ||||
|         this.controller = new Controller(this, model); | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user