From 7df07c2bd1620a24dc273f5620cea3dd143ef226 Mon Sep 17 00:00:00 2001 From: bancika Date: Sun, 19 Apr 2020 19:32:50 +0200 Subject: [PATCH] Added ability to lock and unlock individual components from the context menu --- .../src/org/diylc/common/IPlugInPort.java | 7 +- .../org/diylc/common/ISelectionProcessor.java | 5 +- .../src/org/diylc/core/Project.java | 25 ++++- .../src/org/diylc/presenter/Presenter.java | 44 +++++++- .../src/org/diylc/presenter/update.xml | 8 ++ .../src/org/diylc/images/IconLoader.java | 3 +- .../diylc-swing/src/org/diylc/images/lock.png | Bin 0 -> 764 bytes .../src/org/diylc/images/lock_open.png | Bin 0 -> 815 bytes .../swing/plugins/canvas/CanvasPlugin.java | 104 +++++++++++++++--- 9 files changed, 168 insertions(+), 28 deletions(-) create mode 100644 diylc/diylc-swing/src/org/diylc/images/lock.png create mode 100644 diylc/diylc-swing/src/org/diylc/images/lock_open.png diff --git a/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java b/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java index d6506744..e4b5541a 100644 --- a/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java +++ b/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java @@ -383,5 +383,10 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP * * @param editor */ - void applyEditor(IProjectEditor editor); + void applyEditor(IProjectEditor editor); + + /** + * Locks or unlocks a single component. + */ + void lockComponent(IDIYComponent c, boolean locked); } diff --git a/diylc/diylc-core/src/org/diylc/common/ISelectionProcessor.java b/diylc/diylc-core/src/org/diylc/common/ISelectionProcessor.java index e754ccc7..8bab2c58 100644 --- a/diylc/diylc-core/src/org/diylc/common/ISelectionProcessor.java +++ b/diylc/diylc-core/src/org/diylc/common/ISelectionProcessor.java @@ -51,10 +51,11 @@ public interface ISelectionProcessor { * Finds all components at the specified location, sorted by z-index from top to bottom. Location * depends on the current zoom level. * - * @param point + * @param point + * @param includeLocked * @return */ - List> findComponentsAt(Point point); + List> findComponentsAt(Point point, boolean includeLocked); /** * Expands the current selection to include surrounding components. Options are controlled with diff --git a/diylc/diylc-core/src/org/diylc/core/Project.java b/diylc/diylc-core/src/org/diylc/core/Project.java index 0bb50ab0..f86996d7 100644 --- a/diylc/diylc-core/src/org/diylc/core/Project.java +++ b/diylc/diylc-core/src/org/diylc/core/Project.java @@ -67,7 +67,8 @@ public class Project implements Serializable, Cloneable { private Integer dotSpacing; private List> components; private Set>> groups; - private Set lockedLayers; + private Set lockedLayers; + private Set> lockedComponents; private Set hiddenLayers; private Font font = DEFAULT_FONT; @@ -75,7 +76,8 @@ public class Project implements Serializable, Cloneable { components = new ArrayList>(); groups = new HashSet>>(); lockedLayers = new HashSet(); - hiddenLayers = new HashSet(); + hiddenLayers = new HashSet(); + lockedComponents = new HashSet>(); title = DEFAULT_TITLE; author = System.getProperty("user.name"); width = DEFAULT_WIDTH; @@ -165,6 +167,12 @@ public class Project implements Serializable, Cloneable { */ public Set>> getGroups() { return groups; + } + + public Set> getLockedComponents() { + if (lockedComponents == null) + lockedComponents = new HashSet>(); + return lockedComponents; } public Set getLockedLayers() { @@ -289,6 +297,11 @@ public class Project implements Serializable, Cloneable { return false; } else if (!lockedLayers.equals(other.lockedLayers)) return false; + if (getLockedComponents() == null) { + if (other.lockedComponents != null) + return false; + } else if (!getLockedComponents().equals(other.lockedComponents)) + return false; if (hiddenLayers == null) { if (other.hiddenLayers != null) return false; @@ -328,14 +341,14 @@ public class Project implements Serializable, Cloneable { project.setHeight(this.getHeight()); project.setWidth(this.getWidth()); project.getLockedLayers().addAll(this.getLockedLayers()); - project.getHiddenLayers().addAll(this.getHiddenLayers()); + project.getHiddenLayers().addAll(this.getHiddenLayers()); project.setFont(this.getFont()); Map, IDIYComponent> cloneMap = new HashMap, IDIYComponent>(); for (IDIYComponent component : this.components) { try { - IDIYComponent clone = component.clone(); + IDIYComponent clone = component.clone(); project.getComponents().add(clone); cloneMap.put(component, clone); } catch (CloneNotSupportedException e) { @@ -349,6 +362,10 @@ public class Project implements Serializable, Cloneable { cloneGroup.add(cloneMap.get(component)); } project.groups.add(cloneGroup); + } + + for (IDIYComponent component : this.getLockedComponents()) { + project.lockedComponents.add(cloneMap.get(component)); } return project; } diff --git a/diylc/diylc-core/src/org/diylc/presenter/Presenter.java b/diylc/diylc-core/src/org/diylc/presenter/Presenter.java index 625b75c4..1b4a918c 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/Presenter.java +++ b/diylc/diylc-core/src/org/diylc/presenter/Presenter.java @@ -529,12 +529,12 @@ public class Presenter implements IPlugInPort { * * @return */ - public List> findComponentsAtScaled(Point point) { + public List> findComponentsAtScaled(Point point, boolean includeLocked) { List> components = drawingManager.findComponentsAt(point, currentProject); Iterator> iterator = components.iterator(); while (iterator.hasNext()) { IDIYComponent component = iterator.next(); - if (isComponentLocked(component) || !isComponentVisible(component)) { + if ((includeLocked ? isComponentLayerLocked(component) : isComponentLocked(component)) || !isComponentVisible(component)) { iterator.remove(); } } @@ -542,9 +542,9 @@ public class Presenter implements IPlugInPort { } @Override - public List> findComponentsAt(Point point) { + public List> findComponentsAt(Point point, boolean includeLocked) { Point scaledPoint = scalePoint(point); - List> components = findComponentsAtScaled(scaledPoint); + List> components = findComponentsAtScaled(scaledPoint, includeLocked); return components; } @@ -654,7 +654,7 @@ public class Presenter implements IPlugInPort { messageDispatcher.dispatchMessage(EventType.REPAINT); } else { List> newSelection = new ArrayList>(selectedComponents); - List> components = findComponentsAtScaled(scaledPoint); + List> components = findComponentsAtScaled(scaledPoint, false); // If there's nothing under mouse cursor deselect all. if (components.isEmpty()) { if (!ctrlDown) { @@ -1087,7 +1087,7 @@ public class Presenter implements IPlugInPort { this.preDragProject = currentProject.clone(); Point scaledPoint = scalePoint(point); this.previousDragPoint = scaledPoint; - List> components = forceSelectionRect ? null : findComponentsAtScaled(scaledPoint); + List> components = forceSelectionRect ? null : findComponentsAtScaled(scaledPoint, false); if (controlPointMap != null && !this.controlPointMap.isEmpty()) { // If we're dragging control points reset selection. updateSelection(new ArrayList>(this.controlPointMap.keySet())); @@ -2765,9 +2765,41 @@ public class Presenter implements IPlugInPort { } return lockedComponents; } + + @Override + public void lockComponent(IDIYComponent c, boolean locked) { + LOG.debug(String.format("lockComponent(%s, %s)", c.getName(), locked)); + Project oldProject = currentProject.clone(); + try { + if (locked) { + currentProject.getLockedComponents().add(c); + selectedComponents.remove(c); + } else { + currentProject.getLockedComponents().remove(c); + } + } finally { + // Notify the listeners. + if (!oldProject.equals(currentProject)) { + messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, currentProject.clone(), + locked ? "Lock Component" : "Unlock Component"); + projectFileManager.notifyFileChange(); + } + messageDispatcher.dispatchMessage(EventType.REPAINT); + if (locked) + updateSelection(selectedComponents); + } + } @SuppressWarnings("unchecked") private boolean isComponentLocked(IDIYComponent component) { + ComponentType componentType = + ComponentProcessor.getInstance().extractComponentTypeFrom( + (Class>) component.getClass()); + return currentProject.getLockedLayers().contains((int) Math.round(componentType.getZOrder())) || currentProject.getLockedComponents().contains(component); + } + + @SuppressWarnings("unchecked") + private boolean isComponentLayerLocked(IDIYComponent component) { ComponentType componentType = ComponentProcessor.getInstance().extractComponentTypeFrom( (Class>) component.getClass()); diff --git a/diylc/diylc-core/src/org/diylc/presenter/update.xml b/diylc/diylc-core/src/org/diylc/presenter/update.xml index cc32720d..bea4113a 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/update.xml +++ b/diylc/diylc-core/src/org/diylc/presenter/update.xml @@ -3002,9 +3002,17 @@ NEW_FEATURE "Add Flexible Leads" action added in the context menu that replaces straight leads of leaded components with flexible leads and adds leds to some components that do not have them (e.g. Transistors, Tube Sockets, Potentiometers, etc) + + NEW_FEATURE + Added ability to lock and unlock individual components from the context menu + NEW_FEATURE Added "Rotary Selector Switch" component + + + NEW_FEATURE + Added support for automated regression testing of core functionalities which should reduce regression bugs in the long run IMPROVEMENT diff --git a/diylc/diylc-swing/src/org/diylc/images/IconLoader.java b/diylc/diylc-swing/src/org/diylc/images/IconLoader.java index 75331645..97c4a1b5 100644 --- a/diylc/diylc-swing/src/org/diylc/images/IconLoader.java +++ b/diylc/diylc-swing/src/org/diylc/images/IconLoader.java @@ -65,7 +65,8 @@ public enum IconLoader { "splash_electrolytic.png"), SplashFilm("splash_film.png"), Splash("splash.png"), Help("help2.png"), ScrollInformation("scroll_information.png"), Node("node.png"), Web("web.png"), Guitar("guitar.png"), Scientist("scientist.png"), StarGrey("star_grey.png"), StarBlue("star_blue.png"), JarBeanInto("jar_bean_into.png"), GraphEdgeDirected("graph_edge_directed.png"), LaserPointer("laserpointer.png"), TapeMeasure("tape_measure1.png"), - Elements("elements1.png"), GraphNodes("graph_nodes.png"), User("user1.png"), FlexibleLeads("flexible_leads.png"), Pads("pads.png"); + Elements("elements1.png"), GraphNodes("graph_nodes.png"), User("user1.png"), FlexibleLeads("flexible_leads.png"), Pads("pads.png"), Lock("lock.png"), + Unlock("lock_open.png"); protected String name; diff --git a/diylc/diylc-swing/src/org/diylc/images/lock.png b/diylc/diylc-swing/src/org/diylc/images/lock.png new file mode 100644 index 0000000000000000000000000000000000000000..1de4d29a89c2d75f7393c12d7124488ccbe137f3 GIT binary patch literal 764 zcmVWdKHUATcr^L}hv)GB7YRATlyKF)%tYH6SZ6F)%P+<{wS~000McNliru z)&&<0G98OE9zOs8010qNS#tmY3h)2`3h)6!tTdPa000DMK}|sb0I`n?{9y$E00LA= zL_t(|+J%!#XcJKshX2VlP14Y2C`4jx3|Op!T2ZSK)P<;YCPlj#X!jmUQiY<}P1uFZro zeRdUM)P9V8rf9UOK64b3zt=2o9rt)db1N2gNh^ft{F?Tw7>*cO1M8wUO}Oy-|`pMXh0 zbO`qihoiaL<-JqDl=#{@Ko2~v26wfxty0SOIBp_LOcLY7X#12bZ&r1!o4DQ< u_+>XzZ_-X;xQ(+TMO(zWiRE@0&G8rX81&-!$`uy?0000WdKHUATcr^L}hv)GB7YRATlyKF)%tYH6SZ6F)%P+<{wS~000McNliru z)&&<0G98OE9zOs8010qNS#tmY3h)2`3h)6!tTdPa000DMK}|sb0I`n?{9y$E00M_e zL_t(|+I^GHYZE~f$KUQw(zQPVUnB6t(L=*^oTLVNQf^e?EF-YPkW zAP5B`h$3G6aj;eJ5J;e4iib*U)7n~7ciYA!-Oc`-@lCQKjkE(FUMBCyy!pOa0S;N2 zOeWIX+xyV6tm~#}+U0Wjb+K5S&gF6|=(Z3h9#$ZcNIYkZ-Ow~mZ!{W#v9Yn6>2&%{ zG#X8#y9W`ZgOan^Y+RD0nS4IKIy*c2YJPrxA(cvXDTawOBni&}0C|I?9DrBZn(iXxL` zc>wo={2GKYIBHqKI6(Z0C>|dohIs-u8^P7}C-h}$8p3kDKN$mI@jFmeRkdcbNeLlc znB0dDk!@dGSb7$@|MA}PHMYXe2y{diB12>#+7sN_cn>jUYw*EcxP`${6f#IDW!MGp zmLMYW)UWa3OFb}r?g&6v2%Mb_aGSf}>Kfc0c?^2hfu;pq>{PW{UB=`WXcgQy5lUS7 zB#_ftoai0!>T>`ZmPQxFDMyY07})IET1y+;L2zPXViN6Temc@1u4PjIN8%HeLI9G{ zuI*p}&qL5l{|U^HD)PzS*9i3(hB2w-6Z{0e9Ax`%K@lZ!+uaDzxp=ZD zw2J=k^p6qiYHb~04}YSFTq-`GAR4sY-Kc>MOs#Qc!1I&XzC*^ZLh^hfFqs?;jVj8{ zselc#u?yzL56~7%u>N!o%1fIq#Xlo&k)NF}508ek$OR;Z^!qdR{1>Pq-+U_mSGfP_ twwrFfEdGTBpnVzY7cr5#KX component : plugInPort.findComponentsAt(new Point(x, y))) { + for (IDIYComponent component : plugInPort.findComponentsAt(new Point(x, y), false)) { JMenuItem item = new JMenuItem(component.getName()); final IDIYComponent finalComponent = component; item.addActionListener(new ActionListener() { @@ -529,6 +557,30 @@ public class CanvasPlugin implements IPlugIn, ClipboardOwner { } } + private void updateLock(int x, int y) { + getLockMenu().removeAll(); + getUnlockMenu().removeAll(); + List> componentsAt = plugInPort.findComponentsAt(new Point(x, y), true); + if (componentsAt.size() == 0) { + getLockMenu().setEnabled(false); + getUnlockMenu().setEnabled(false); + } else { + boolean hasLocked = false; + boolean hasUnlocked = false; + for (IDIYComponent c : componentsAt) { + if (plugInPort.getCurrentProject().getLockedComponents().contains(c)) { + getUnlockMenu().add(new LockAction(c, false)); + hasLocked = true; + } else { + getLockMenu().add(new LockAction(c, true)); + hasUnlocked = true; + } + } + getLockMenu().setEnabled(hasUnlocked); + getUnlockMenu().setEnabled(hasLocked); + } + } + private void updateApplyTemplateMenu() { getApplyTemplateMenu().removeAll(); List