diff --git a/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/common/IPlugInPort.java b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/common/IPlugInPort.java index 8478c3b8..58e1b47f 100644 --- a/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/common/IPlugInPort.java +++ b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/common/IPlugInPort.java @@ -169,11 +169,9 @@ public interface IPlugInPort { ComponentSelection getSelectedComponents(); /** - * Changes component selection. - * - * @param selection + * Selects all components in the project. */ - void setSelectedComponents(ComponentSelection selection); + void selectAll(); /** * Returns the {@link Area} occupied by the component. @@ -306,4 +304,8 @@ public interface IPlugInPort { * @param isMetric */ void setMetric(boolean isMetric); + + void groupSelectedComponents(); + + void ungroupSelectedComponents(); } diff --git a/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/core/Project.java b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/core/Project.java index 216f28d9..c659734b 100644 --- a/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/core/Project.java +++ b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/core/Project.java @@ -2,7 +2,9 @@ package org.diylc.core; import java.io.Serializable; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.diylc.core.annotations.EditableProperty; import org.diylc.core.measures.Size; @@ -29,9 +31,11 @@ public class Project implements Serializable { private Size width; private Size height; private List> components; + private Set>> groups; public Project() { components = new ArrayList>(); + groups = new HashSet>>(); title = DEFAULT_TITLE; author = System.getProperty("user.name"); width = DEFAULT_WIDTH; @@ -39,7 +43,7 @@ public class Project implements Serializable { } public Project(String title, String author, String description, Size width, Size height, - List> components) { + List> components, Set>> groups) { super(); this.title = title; this.author = author; @@ -47,6 +51,7 @@ public class Project implements Serializable { this.width = width; this.height = height; this.components = components; + this.groups = groups; } @EditableProperty @@ -103,6 +108,15 @@ public class Project implements Serializable { return components; } + /** + * Set of grouped components. + * + * @return + */ + public Set>> getGroups() { + return groups; + } + @Override public int hashCode() { final int prime = 31; diff --git a/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/images/IconLoader.java b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/images/IconLoader.java index aa73e8a0..c0ced882 100644 --- a/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/images/IconLoader.java +++ b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/images/IconLoader.java @@ -21,7 +21,7 @@ public enum IconLoader { "csv.png"), HTML("html.png"), Image("image.png"), Cut("cut.png"), Copy("copy.png"), Paste( "paste.png"), Selection("selection.png"), BOM("bom.png"), BlackBoard("blackboard.png"), IdCard( "id_card.png"), IdCardAdd("id_card_add.png"), Chest("chest.png"), Upload("upload.png"), Wrench( - "wrench.png"), ; + "wrench.png"), Group("group.png"), Ungroup("ungroup.png"); protected String name; diff --git a/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/images/group.png b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/images/group.png new file mode 100644 index 00000000..be9d2df1 Binary files /dev/null and b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/images/group.png differ diff --git a/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/images/ungroup.png b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/images/ungroup.png new file mode 100644 index 00000000..383e6330 Binary files /dev/null and b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/images/ungroup.png differ diff --git a/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/plugins/clipboard/ClipboardManager.java b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/plugins/clipboard/ClipboardManager.java index 5554cac2..794e22ee 100644 --- a/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/plugins/clipboard/ClipboardManager.java +++ b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/plugins/clipboard/ClipboardManager.java @@ -76,6 +76,9 @@ public class ClipboardManager implements IPlugIn, ClipboardOwner { plugInPort.injectMenuAction(pasteAction, EDIT_TITLE); plugInPort.injectMenuAction(null, EDIT_TITLE); plugInPort.injectMenuAction(new SelectAllAction(), EDIT_TITLE); + plugInPort.injectMenuAction(null, EDIT_TITLE); + plugInPort.injectMenuAction(new GroupAction(), EDIT_TITLE); + plugInPort.injectMenuAction(new UngroupAction(), EDIT_TITLE); refreshActions(); } @@ -187,8 +190,45 @@ public class ClipboardManager implements IPlugIn, ClipboardOwner { @Override public void actionPerformed(ActionEvent e) { LOG.info("Select All triggered"); - plugInPort.setSelectedComponents(new ComponentSelection(plugInPort.getCurrentProject() - .getComponents())); + plugInPort.selectAll(); + } + } + + class GroupAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + public GroupAction() { + super(); + putValue(AbstractAction.NAME, "Group Selection"); + putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_G, + ActionEvent.CTRL_MASK)); + putValue(AbstractAction.SMALL_ICON, IconLoader.Group.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("Group Selection triggered"); + plugInPort.groupSelectedComponents(); + } + } + + class UngroupAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + public UngroupAction() { + super(); + putValue(AbstractAction.NAME, "Ungroup Selection"); + putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_U, + ActionEvent.CTRL_MASK)); + putValue(AbstractAction.SMALL_ICON, IconLoader.Ungroup.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("Ungroup Selection triggered"); + plugInPort.ungroupSelectedComponents(); } } diff --git a/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/presenter/Presenter.java b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/presenter/Presenter.java index a6f70383..ea5fb9c9 100644 --- a/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/presenter/Presenter.java +++ b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/presenter/Presenter.java @@ -13,9 +13,11 @@ import java.awt.geom.Area; import java.awt.geom.Point2D; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -384,14 +386,14 @@ public class Presenter implements IPlugInPort { // cursor. if (ctrlDown) { if (selectedComponents.contains(component)) { - selectedComponents.remove(component); + selectedComponents.removeAll(findAllGroupedComponents(component)); } else { - selectedComponents.add(component); + selectedComponents.addAll(findAllGroupedComponents(component)); } } else { // Otherwise just select that one component. selectedComponents.clear(); - selectedComponents.add(component); + selectedComponents.addAll(findAllGroupedComponents(component)); } } messageDispatcher.dispatchMessage(EventType.SELECTION_CHANGED, selectedComponents); @@ -433,10 +435,10 @@ public class Presenter implements IPlugInPort { } } } -// // If CTRL is pressed, we only care about the top most component. -// if (altDown && components.size() > 0) { -// break; -// } + // // If CTRL is pressed, we only care about the top most component. + // if (altDown && components.size() > 0) { + // break; + // } } messageDispatcher.dispatchMessage(EventType.MOUSE_MOVED, scaledPoint); @@ -454,8 +456,8 @@ public class Presenter implements IPlugInPort { } @Override - public void setSelectedComponents(ComponentSelection selection) { - this.selectedComponents = new ComponentSelection(selection); + public void selectAll() { + this.selectedComponents = new ComponentSelection(currentProject.getComponents()); messageDispatcher.dispatchMessage(EventType.SELECTION_CHANGED, selectedComponents); messageDispatcher.dispatchMessage(EventType.SELECTION_SIZE_CHANGED, calculateSelectionDimension()); @@ -502,7 +504,7 @@ public class Presenter implements IPlugInPort { // it into the only selected component. if (!selectedComponents.contains(component)) { selectedComponents.clear(); - selectedComponents.add(component); + selectedComponents.addAll(findAllGroupedComponents(component)); messageDispatcher.dispatchMessage(EventType.SELECTION_CHANGED, selectedComponents); messageDispatcher.dispatchMessage(EventType.SELECTION_SIZE_CHANGED, calculateSelectionDimension()); @@ -587,7 +589,7 @@ public class Presenter implements IPlugInPort { for (IDIYComponent component : currentProject.getComponents()) { Area area = componentAreaMap.get(component); if ((area != null) && (selectionRect != null) && area.intersects(selectionRect)) { - selectedComponents.add(component); + selectedComponents.addAll(findAllGroupedComponents(component)); } } selectionRect = null; @@ -622,6 +624,8 @@ public class Presenter implements IPlugInPort { public void deleteSelectedComponents() { LOG.debug("deleteSelectedComponents()"); Project oldProject = cloner.deepClone(currentProject); + // Remove selected components from any groups. + ungroupComponents(selectedComponents); currentProject.getComponents().removeAll(selectedComponents); messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner .deepClone(currentProject), "Delete"); @@ -673,6 +677,55 @@ public class Presenter implements IPlugInPort { calculateSelectionDimension()); } + @Override + public void groupSelectedComponents() { + LOG.debug("groupSelectedComponents()"); + Project oldProject = cloner.deepClone(currentProject); + // First remove the selected components from other groups. + ungroupComponents(selectedComponents); + // Then group them together + currentProject.getGroups().add(new HashSet>(selectedComponents)); + // Notify the listeners. + if (!oldProject.equals(currentProject)) { + messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner + .deepClone(currentProject), "Group"); + } + } + + @Override + public void ungroupSelectedComponents() { + LOG.debug("ungroupSelectedComponents()"); + Project oldProject = cloner.deepClone(currentProject); + ungroupComponents(selectedComponents); + // Notify the listeners. + if (!oldProject.equals(currentProject)) { + messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner + .deepClone(currentProject), "Group"); + } + } + + private void ungroupComponents(Collection> components) { + Iterator>> groupIterator = currentProject.getGroups().iterator(); + while (groupIterator.hasNext()) { + Set> group = groupIterator.next(); + group.removeAll(components); + if (group.isEmpty()) { + groupIterator.remove(); + } + } + } + + private Set> findAllGroupedComponents(IDIYComponent component) { + Set> components = new HashSet>(); + components.add(component); + for (Set> group : currentProject.getGroups()) { + if (group.contains(component)) { + components.addAll(group); + } + } + return components; + } + /** * @return selection size expressed in either inches or centimeters, based * on the user preference.