From 6a3db3047f3bca2e381995b355c1f4e7a02cceee Mon Sep 17 00:00:00 2001 From: ahmed Date: Thu, 29 Jan 2026 00:39:49 +0100 Subject: [PATCH 01/20] Large Scale Change: Unused Imports removed - Automatic Deletion of all unnecessary imports in use-gui with Copilot --- .../java/org/tzi/use/gui/graphlayout/AllLayoutTypes.java | 1 - .../java/org/tzi/use/gui/mainFX/CreateObjectDialog.java | 3 --- .../org/tzi/use/gui/mainFX/ResizableInternalWindow.java | 3 --- .../src/main/java/org/tzi/use/gui/mainFX/ViewFrame.java | 8 -------- .../src/main/java/org/tzi/use/gui/utilFX/StatusBar.java | 5 ----- .../java/org/tzi/use/gui/views/diagrams/DiagramView.java | 1 - .../diagrams/behavior/communicationdiagram/BaseNode.java | 1 - .../communicationdiagram/CommunicationDiagram.java | 3 --- .../communicationdiagram/CommunicationDiagramEdge.java | 1 - .../communicationdiagram/ShowRelatedObjectsPanel.java | 1 - .../communicationdiagram/ShowRelatedObjectsWindow.java | 1 - .../gui/views/diagrams/classdiagram/ClassDiagramView.java | 1 - .../views/diagrams/objectdiagram/NewObjectDiagram.java | 2 -- .../gui/views/diagrams/statemachine/TransitionEdge.java | 1 - 14 files changed, 32 deletions(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/graphlayout/AllLayoutTypes.java b/use-gui/src/main/java/org/tzi/use/gui/graphlayout/AllLayoutTypes.java index 0bde83626..dfcceb1ab 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/graphlayout/AllLayoutTypes.java +++ b/use-gui/src/main/java/org/tzi/use/gui/graphlayout/AllLayoutTypes.java @@ -12,7 +12,6 @@ import org.tzi.use.uml.mm.MAssociationClassImpl; import org.tzi.use.uml.sys.MLinkObject; -import javax.swing.*; import java.util.*; diff --git a/use-gui/src/main/java/org/tzi/use/gui/mainFX/CreateObjectDialog.java b/use-gui/src/main/java/org/tzi/use/gui/mainFX/CreateObjectDialog.java index 506debcf4..f8c9f3ecf 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/mainFX/CreateObjectDialog.java +++ b/use-gui/src/main/java/org/tzi/use/gui/mainFX/CreateObjectDialog.java @@ -25,9 +25,6 @@ import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.*; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.TextField; import javafx.scene.image.Image; import javafx.scene.input.KeyCode; import javafx.scene.layout.GridPane; diff --git a/use-gui/src/main/java/org/tzi/use/gui/mainFX/ResizableInternalWindow.java b/use-gui/src/main/java/org/tzi/use/gui/mainFX/ResizableInternalWindow.java index de3b5d064..b98e71112 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/mainFX/ResizableInternalWindow.java +++ b/use-gui/src/main/java/org/tzi/use/gui/mainFX/ResizableInternalWindow.java @@ -14,7 +14,6 @@ import javafx.geometry.Pos; import javafx.print.*; import javafx.scene.Cursor; -import javafx.scene.Node; import javafx.scene.control.Alert; import javafx.scene.control.Button; import javafx.scene.control.Label; @@ -28,10 +27,8 @@ import javafx.stage.FileChooser; import javafx.stage.Window; import org.tzi.use.gui.views.diagrams.DiagramType; -import org.tzi.use.gui.views.diagrams.DiagramView; import org.tzi.use.gui.views.diagrams.behavior.communicationdiagram.CommunicationDiagramView; import org.tzi.use.gui.views.diagrams.behavior.sequencediagram.SequenceDiagramView; -import org.tzi.use.gui.views.diagrams.classdiagram.ClassDiagram; import org.tzi.use.gui.views.diagrams.classdiagram.ClassDiagramView; import org.tzi.use.gui.views.diagrams.objectdiagram.NewObjectDiagramView; import org.tzi.use.gui.views.diagrams.statemachine.StateMachineDiagramView; diff --git a/use-gui/src/main/java/org/tzi/use/gui/mainFX/ViewFrame.java b/use-gui/src/main/java/org/tzi/use/gui/mainFX/ViewFrame.java index b025e041d..4e79eb05d 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/mainFX/ViewFrame.java +++ b/use-gui/src/main/java/org/tzi/use/gui/mainFX/ViewFrame.java @@ -5,22 +5,14 @@ import javafx.print.PrinterJob; import javafx.scene.Node; import javafx.scene.SnapshotParameters; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; import javafx.scene.image.WritableImage; import javafx.scene.layout.BorderPane; -import javafx.scene.layout.Region; import javafx.scene.paint.Color; -import javafx.scene.shape.Rectangle; -import javafx.scene.SnapshotResult; -import javafx.scene.transform.Scale; -import org.tzi.use.config.Options; import org.tzi.use.gui.views.View; import org.tzi.use.gui.viewsFX.PrintableView; import java.awt.Graphics2D; import java.awt.image.BufferedImage; -import java.io.InputStream; /** * A JavaFX container holding a view of a system state. diff --git a/use-gui/src/main/java/org/tzi/use/gui/utilFX/StatusBar.java b/use-gui/src/main/java/org/tzi/use/gui/utilFX/StatusBar.java index 732ca8494..530d586a7 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/utilFX/StatusBar.java +++ b/use-gui/src/main/java/org/tzi/use/gui/utilFX/StatusBar.java @@ -27,11 +27,6 @@ import javafx.scene.layout.BorderPane; import javafx.util.Duration; -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - /** * A StatusBar consisting of a single line of text. diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/DiagramView.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/DiagramView.java index 7f238dc3d..4685e0f93 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/DiagramView.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/DiagramView.java @@ -45,7 +45,6 @@ import org.tzi.use.gui.views.diagrams.waypoints.WayPoint; import org.tzi.use.main.runtime.IRuntime; import org.tzi.use.runtime.gui.IPluginDiagramExtensionPoint; -import org.tzi.use.runtime.gui.impl.DiagramExtensionPoint; import org.tzi.use.runtime.gui.impl.StyleInfoProvider; import org.tzi.use.util.Log; import org.w3c.dom.Document; diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/BaseNode.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/BaseNode.java index f95d7613b..9bc701390 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/BaseNode.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/BaseNode.java @@ -27,7 +27,6 @@ import org.tzi.use.gui.views.diagrams.DiagramOptionChangedListener; import org.tzi.use.gui.views.diagrams.DiagramOptions; -import org.tzi.use.gui.views.diagrams.behavior.shared.VisibleData; import org.tzi.use.gui.views.diagrams.elements.PlaceableNode; import org.tzi.use.gui.views.diagrams.util.Util; diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/CommunicationDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/CommunicationDiagram.java index dacf08d90..a70444f4e 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/CommunicationDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/CommunicationDiagram.java @@ -43,9 +43,7 @@ import javafx.application.Platform; import javafx.embed.swing.SwingNode; import org.tzi.use.gui.main.ViewFrame; -import org.tzi.use.gui.mainFX.MainWindow; import org.tzi.use.gui.util.PersistHelper; -import org.tzi.use.gui.views.CommandView; import org.tzi.use.gui.views.diagrams.DiagramType; import org.tzi.use.gui.views.diagrams.DiagramView; import org.tzi.use.gui.views.diagrams.DiagramViewWithObjectNode; @@ -62,7 +60,6 @@ import org.tzi.use.gui.views.diagrams.event.ActionLoadLayout; import org.tzi.use.gui.views.diagrams.event.ActionSaveLayout; import org.tzi.use.gui.views.diagrams.event.DiagramInputHandling; -import org.tzi.use.gui.views.diagrams.objectdiagram.NewObjectDiagram; import org.tzi.use.gui.views.diagrams.objectdiagram.ObjectNode; import org.tzi.use.gui.views.selection.objectselection.ObjectSelection; import org.tzi.use.uml.ocl.value.ObjectValue; diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/CommunicationDiagramEdge.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/CommunicationDiagramEdge.java index b59ccf071..eb55c3043 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/CommunicationDiagramEdge.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/CommunicationDiagramEdge.java @@ -29,7 +29,6 @@ import java.util.Iterator; import java.util.List; -import org.tzi.use.gui.views.diagrams.DiagramView; import org.tzi.use.gui.views.diagrams.edges.DirectedEdgeFactory; import org.tzi.use.gui.views.diagrams.elements.EdgeProperty; import org.tzi.use.gui.views.diagrams.elements.PlaceableNode; diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/ShowRelatedObjectsPanel.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/ShowRelatedObjectsPanel.java index 847266ce1..d1501e563 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/ShowRelatedObjectsPanel.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/ShowRelatedObjectsPanel.java @@ -19,7 +19,6 @@ package org.tzi.use.gui.views.diagrams.behavior.communicationdiagram; -import jnr.ffi.annotations.In; import org.tzi.use.gui.util.GridBagHelper; import javax.swing.*; diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/ShowRelatedObjectsWindow.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/ShowRelatedObjectsWindow.java index 60e3c852c..7a051e9a2 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/ShowRelatedObjectsWindow.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/behavior/communicationdiagram/ShowRelatedObjectsWindow.java @@ -19,7 +19,6 @@ package org.tzi.use.gui.views.diagrams.behavior.communicationdiagram; -import org.tzi.use.gui.util.GridBagHelper; import org.tzi.use.gui.views.diagrams.behavior.shared.CancelButton; import org.tzi.use.gui.views.diagrams.behavior.shared.OKButton; diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/classdiagram/ClassDiagramView.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/classdiagram/ClassDiagramView.java index 271e1de8c..6789301b0 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/classdiagram/ClassDiagramView.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/classdiagram/ClassDiagramView.java @@ -27,7 +27,6 @@ import org.tzi.use.gui.views.PrintableView; import org.tzi.use.gui.views.View; import org.tzi.use.main.runtime.IRuntime; -import org.tzi.use.runtime.gui.IPluginDiagramExtensionPoint; import org.tzi.use.uml.mm.*; import org.tzi.use.uml.mm.commonbehavior.communications.MSignal; import org.tzi.use.uml.ocl.type.EnumType; diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index 885d1477d..c45416f98 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -78,7 +78,6 @@ import org.tzi.use.gui.views.ObjectPropertiesView; import org.tzi.use.gui.views.diagrams.DiagramType; import org.tzi.use.gui.views.diagrams.DiagramViewWithObjectNode; -import org.tzi.use.gui.views.diagrams.classdiagram.ClassDiagram; import org.tzi.use.gui.views.diagrams.elements.AssociationName; import org.tzi.use.gui.views.diagrams.elements.DiamondNode; import org.tzi.use.gui.views.diagrams.elements.PlaceableNode; @@ -97,7 +96,6 @@ import org.tzi.use.gui.views.diagrams.event.HighlightChangeListener; import org.tzi.use.gui.views.selection.objectselection.ObjectSelection; import org.tzi.use.gui.xmlparser.LayoutTags; -import org.tzi.use.main.gui.Main; import org.tzi.use.uml.mm.MAssociation; import org.tzi.use.uml.mm.MAssociationClass; import org.tzi.use.uml.mm.MAssociationClassImpl; diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/statemachine/TransitionEdge.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/statemachine/TransitionEdge.java index 80e7c1079..611531e6c 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/statemachine/TransitionEdge.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/statemachine/TransitionEdge.java @@ -18,7 +18,6 @@ */ package org.tzi.use.gui.views.diagrams.statemachine; -import java.awt.Color; import java.awt.Graphics2D; import java.awt.geom.Point2D; import java.util.ArrayList; From be73a68bcef9ce681abd109538a5b2b1d24ced30 Mon Sep 17 00:00:00 2001 From: ahmed Date: Mon, 2 Feb 2026 00:05:24 +0100 Subject: [PATCH 02/20] refactor(gui/objectdiagram): modernize NewObjectDiagram for readability and consistency - Use diamond operator (<>) to reduce generic verbosity - Replace `size() > 0` checks with `isEmpty()` for clearer intent - Convert simple anonymous listeners to lambdas to reduce boilerplate - Remove redundant null checks before `instanceof` - Simplify ternary negation and other small readability fixes - Prepare code for follow-up refactors (extracting data structures, controllers) No behavioral changes intended; this is a mechanical cleanup to reduce cognitive load and prepare the file for safer, larger refactors. --- .../objectdiagram/NewObjectDiagram.java | 64 +++++++++---------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index c45416f98..6db39f072 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -129,7 +129,7 @@ public class NewObjectDiagram extends DiagramViewWithObjectNode implements Highl * edges. When hiding or showing objects the data is moved between the * fields {@link NewObjectDiagram#visibleData} and * {@link NewObjectDiagram#hiddenData}. - * + * * @author Lars Hamann */ public static class ObjectDiagramData implements DiagramData { @@ -139,24 +139,24 @@ public static class ObjectDiagramData implements DiagramData { */ public Map fObjectToNodeMap; /** - * + * */ public Map fBinaryLinkToEdgeMap; /** - * + * */ public Map fNaryLinkToDiamondNodeMap; /** - * + * */ public Map> fHalfLinkToEdgeMap; /** - * + * */ public Map fLinkObjectToNodeEdge; /** - * + * */ public ObjectDiagramData() { fObjectToNodeMap = new HashMap(); @@ -202,7 +202,7 @@ public Set getEdges() { /** * Copies all data to the target object - * + * * @param hiddenData */ public void copyTo(ObjectDiagramData target) { @@ -311,16 +311,16 @@ public void stateChanged(HighlightChangeEvent e) { } MModelElement elem = e.getModelElement(); - List edges = new ArrayList(); + List edges = new ArrayList<>(); boolean allEdgesSelected = true; // elem is an association - if (elem != null && elem instanceof MAssociation) { + if (elem instanceof MAssociation) { MAssociation assoc = (MAssociation) elem; int size = assoc.associationEnds().size(); Set links = fParent.system().state().linksOfAssociation(assoc).links(); - EdgeBase eb = null; + EdgeBase eb; if (size == 2) { for (MLink link : links) { @@ -341,8 +341,7 @@ public void stateChanged(HighlightChangeEvent e) { } } - // check all edges in the list if they are suppose to be selected - // or deselected. + // check all edges in the list if they are supposed to be selected for (EdgeBase edge : edges) { if (edge != null) { if (e.getHighlight()) { @@ -357,7 +356,7 @@ public void stateChanged(HighlightChangeEvent e) { } // elem is a class - if (elem != null && elem instanceof MClass) { + if (elem instanceof MClass) { for (MObject obj : fParent.system().state().objectsOfClass((MClass) elem)) { PlaceableNode node = visibleData.fObjectToNodeMap.get(obj); if (elem instanceof MAssociationClass) { @@ -388,11 +387,8 @@ public void showAll() { } } - /** - * Hides all currently visible elements. The diagram is not repainted! - */ public void hideAll() { - Set objects = new HashSet<>(this.visibleData.fObjectToNodeMap.keySet()); + Set objects = new HashSet<>(this.visibleData.fObjectToNodeMap.keySet()); objects.forEach(obj -> hideObject(obj)); } @@ -688,7 +684,7 @@ protected BinaryAssociationOrLinkEdge createBinaryAssociationOrLinkEdge(Placeabl protected void addNAryLink(MLink link) { getRandomNextPosition(); - List linkedObjectNodes = new ArrayList(); + List linkedObjectNodes = new ArrayList<>(); for(MObject linkedObject : link.linkedObjects()) { linkedObjectNodes.add(visibleData.fObjectToNodeMap.get(linkedObject)); } @@ -834,11 +830,11 @@ protected void showOrHideNAryLink(MLink link, boolean show) { ObjectDiagramData source = (show ? hiddenData : visibleData); ObjectDiagramData target = (show ? visibleData : hiddenData); - DiamondNode node = source.fNaryLinkToDiamondNodeMap.get(link); + DiamondNode node = source.fNaryLinkToDiamondNodeMap.get(link); if (show){ if (node == null){ node = target.fNaryLinkToDiamondNodeMap.get(link); - } + } fGraph.add(node); } else { fGraph.remove(node); @@ -846,7 +842,7 @@ protected void showOrHideNAryLink(MLink link, boolean show) { target.fNaryLinkToDiamondNodeMap.put(link, node); source.fNaryLinkToDiamondNodeMap.remove(link); - + // connected to an "object link" if (link instanceof MLinkObject) { EdgeBase e = source.fLinkObjectToNodeEdge.get(link); @@ -1221,12 +1217,10 @@ protected PopupMenuInfo unionOfPopUpMenu() { || !hiddenData.fNaryLinkToDiamondNodeMap.isEmpty() || !hiddenData.fHalfLinkToEdgeMap.isEmpty() || !hiddenData.fLinkObjectToNodeEdge.isEmpty()) { final JMenuItem showAllObjects = new JMenuItem("Show hidden elements"); - showAllObjects.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent ev) { - showAll(); - showAllLinks(); - invalidateContent(true); - } + showAllObjects.addActionListener(ev -> { + showAll(); + showAllLinks(); + invalidateContent(true); }); popupMenu.insert(showAllObjects, pos++); @@ -1256,10 +1250,10 @@ public void actionPerformed(ActionEvent ev) { @Override public void actionPerformed(ActionEvent arg0) { - if (selectedLinks.size() > 0) { + if (!selectedLinks.isEmpty()) { selectedLinks.forEach(link -> hideLink(link)); } - if (selectedObjects.size() > 0) { + if (!selectedObjects.isEmpty()) { selectedObjects.forEach(obj -> hideObject(obj)); } repaint(); @@ -1294,7 +1288,7 @@ public void actionPerformed(ActionEvent e) { popupMenu.insert(new AbstractAction(labelGreyed + " " + node.name()) { @Override public void actionPerformed(ActionEvent e) { - node.setGreyed(node.isGreyed() ? false : true); + node.setGreyed(!node.isGreyed()); repaint(); } }, pos++); @@ -1302,13 +1296,13 @@ public void actionPerformed(ActionEvent e) { } else if (selectedObjects.size() > 1) { Set objToGreyIn = new HashSet<>(); selectedObjects.stream().filter(obj -> visibleData.fObjectToNodeMap.get(obj).isGreyed()) - .forEach(obj -> objToGreyIn.add(visibleData.fObjectToNodeMap.get(obj))); + .forEach(obj -> objToGreyIn.add(visibleData.fObjectToNodeMap.get(obj))); Set objToGreyOut = new HashSet<>(); selectedObjects.stream().filter(obj -> !visibleData.fObjectToNodeMap.get(obj).isGreyed()) - .forEach(obj -> objToGreyOut.add(visibleData.fObjectToNodeMap.get(obj))); + .forEach(obj -> objToGreyOut.add(visibleData.fObjectToNodeMap.get(obj))); - if (objToGreyIn.size() > 0) { + if (!objToGreyIn.isEmpty()) { popupMenu.insert(new AbstractAction("Grey in " + objToGreyIn.size() + " elements") { @Override @@ -1320,7 +1314,7 @@ public void actionPerformed(ActionEvent arg0) { } // Action for grey out more elements - if (objToGreyOut.size() > 0) { + if (!objToGreyOut.isEmpty()) { popupMenu.insert(new AbstractAction("Grey out " + objToGreyOut.size() + " elements") { @Override @@ -1381,7 +1375,7 @@ public void actionPerformed(ActionEvent arg0) { if (selectedObjects.size() == 1) { final MObject obj = exactlyOne(selectedObjects); - List sortedPSMs = new LinkedList( + List sortedPSMs = new LinkedList<> ( obj.cls().getAllOwnedProtocolStateMachines()); Collections.sort(sortedPSMs, new MNamedElementComparator()); From 4b1e06c762a73ffd25b8dfb1a976dcbc74e4adc5 Mon Sep 17 00:00:00 2001 From: ahmed Date: Tue, 3 Feb 2026 00:14:14 +0100 Subject: [PATCH 03/20] =?UTF-8?q?refactor(gui):=20NewObjectDiagram=20?= =?UTF-8?q?=E2=80=94=20fix=20Map=20access,=20null-safety=20and=20minor=20c?= =?UTF-8?q?larity=20improvements=20-=20Fix=20broken=20Map=20access=20(use?= =?UTF-8?q?=20getLinkObjectToNodeEdge().get(link))=20which=20caused=20comp?= =?UTF-8?q?ile=20errors=20and=20broken=20restore/delete=20flows.=20-=20Add?= =?UTF-8?q?=20null=20checks=20before=20invoking=20methods=20on=20edges=20d?= =?UTF-8?q?uring=20restore=20and=20delete=20to=20avoid=20NPEs=20when=20lay?= =?UTF-8?q?out=20data=20is=20missing.=20-=20Change=20javaFxCall=20from=20b?= =?UTF-8?q?oxed=20Boolean=20to=20primitive=20boolean=20and=20update=20sett?= =?UTF-8?q?er=20for=20NPE=20safety=20and=20clarity.=20-=20Correct=20copyTo?= =?UTF-8?q?=20Javadoc=20param=20description.=20These=20are=20small,=20low-?= =?UTF-8?q?risk=20fixes=20to=20restore=20compileability=20and=20improve=20?= =?UTF-8?q?robustness=20and=20readability.=20No=20behavioral=20change=20ex?= =?UTF-8?q?pected.=20Co-authored-by:=20automated-refactor-agent=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../objectdiagram/NewObjectDiagram.java | 304 ++++++++---------- 1 file changed, 135 insertions(+), 169 deletions(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index 6db39f072..01f45643a 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -133,37 +133,22 @@ public class NewObjectDiagram extends DiagramViewWithObjectNode implements Highl * @author Lars Hamann */ public static class ObjectDiagramData implements DiagramData { - /** - * Map from object instances to object nodes. It also includes link - * objects. - */ - public Map fObjectToNodeMap; - /** - * - */ - public Map fBinaryLinkToEdgeMap; - /** - * - */ - public Map fNaryLinkToDiamondNodeMap; - /** - * - */ - public Map> fHalfLinkToEdgeMap; - /** - * - */ - public Map fLinkObjectToNodeEdge; + // internal maps; keep them private and provide accessors + private final Map fObjectToNodeMap; + private final Map fBinaryLinkToEdgeMap; + private final Map fNaryLinkToDiamondNodeMap; + private final Map> fHalfLinkToEdgeMap; + private final Map fLinkObjectToNodeEdge; /** - * + * Creates an empty set of diagram data */ public ObjectDiagramData() { - fObjectToNodeMap = new HashMap(); - fBinaryLinkToEdgeMap = new HashMap(); - fNaryLinkToDiamondNodeMap = new HashMap(); - fHalfLinkToEdgeMap = new HashMap>(); - fLinkObjectToNodeEdge = new HashMap(); + fObjectToNodeMap = new HashMap<>(); + fBinaryLinkToEdgeMap = new HashMap<>(); + fNaryLinkToDiamondNodeMap = new HashMap<>(); + fHalfLinkToEdgeMap = new HashMap<>(); + fLinkObjectToNodeEdge = new HashMap<>(); } /** @@ -177,7 +162,7 @@ public boolean containsLink(MLink link) { @Override public Set getNodes() { - Set result = new HashSet(); + Set result = new HashSet<>(); result.addAll(this.fNaryLinkToDiamondNodeMap.values()); result.addAll(this.fObjectToNodeMap.values()); @@ -192,7 +177,7 @@ public boolean hasNodes() { @Override public Set getEdges() { - Set result = new HashSet(fBinaryLinkToEdgeMap.values()); + Set result = new HashSet<>(fBinaryLinkToEdgeMap.values()); result.addAll(fLinkObjectToNodeEdge.values()); for (Map.Entry> entry : fHalfLinkToEdgeMap.entrySet()) { result.addAll(entry.getValue()); @@ -203,7 +188,7 @@ public Set getEdges() { /** * Copies all data to the target object * - * @param hiddenData + * @param target the target ObjectDiagramData to copy the data into */ public void copyTo(ObjectDiagramData target) { target.fBinaryLinkToEdgeMap.putAll(this.fBinaryLinkToEdgeMap); @@ -223,6 +208,13 @@ public void clear() { this.fNaryLinkToDiamondNodeMap.clear(); this.fObjectToNodeMap.clear(); } + + // Accessors to preserve encapsulation + public Map getObjectToNodeMap() { return fObjectToNodeMap; } + public Map getBinaryLinkToEdgeMap() { return fBinaryLinkToEdgeMap; } + public Map getNaryLinkToDiamondNodeMap() { return fNaryLinkToDiamondNodeMap; } + public Map> getHalfLinkToEdgeMap() { return fHalfLinkToEdgeMap; } + public Map getLinkObjectToNodeEdge() { return fLinkObjectToNodeEdge; } } protected ObjectDiagramData visibleData = new ObjectDiagramData(); @@ -251,7 +243,7 @@ public void clear() { protected DiagramInputHandling inputHandling; - private static Boolean javaFxCall = false; + private static boolean javaFxCall = false; /** * Creates a new empty diagram. @@ -324,18 +316,18 @@ public void stateChanged(HighlightChangeEvent e) { if (size == 2) { for (MLink link : links) { - eb = visibleData.fBinaryLinkToEdgeMap.get(link); + eb = visibleData.getBinaryLinkToEdgeMap().get(link); if (elem instanceof MAssociationClass) { - eb = visibleData.fLinkObjectToNodeEdge.get(link); + eb = visibleData.getLinkObjectToNodeEdge().get(link); } edges.add(eb); } } else { for (MLink link : links) { - edges.addAll(visibleData.fHalfLinkToEdgeMap.get(link)); + edges.addAll(visibleData.getHalfLinkToEdgeMap().getOrDefault(link, Collections.emptyList())); if (elem instanceof MAssociationClass) { - eb = visibleData.fLinkObjectToNodeEdge.get(link); + eb = visibleData.getLinkObjectToNodeEdge().get(link); edges.add(eb); } } @@ -358,7 +350,7 @@ public void stateChanged(HighlightChangeEvent e) { // elem is a class if (elem instanceof MClass) { for (MObject obj : fParent.system().state().objectsOfClass((MClass) elem)) { - PlaceableNode node = visibleData.fObjectToNodeMap.get(obj); + PlaceableNode node = visibleData.getObjectToNodeMap().get(obj); if (elem instanceof MAssociationClass) { if (e.getHighlight() && allEdgesSelected) { fNodeSelection.add(node); @@ -382,13 +374,13 @@ public void stateChanged(HighlightChangeEvent e) { * Shows all hidden elements again */ public void showAll() { - while (!hiddenData.fObjectToNodeMap.isEmpty()) { - showObject(hiddenData.fObjectToNodeMap.keySet().iterator().next()); + while (!hiddenData.getObjectToNodeMap().isEmpty()) { + showObject(hiddenData.getObjectToNodeMap().keySet().iterator().next()); } } public void hideAll() { - Set objects = new HashSet<>(this.visibleData.fObjectToNodeMap.keySet()); + Set objects = new HashSet<>(this.visibleData.getObjectToNodeMap().keySet()); objects.forEach(obj -> hideObject(obj)); } @@ -396,7 +388,7 @@ public void hideAll() { * Hides all currently visible links. The diagram is not repainted! */ public void hideAllLinks() { - Set links = new HashSet<>(this.visibleData.fBinaryLinkToEdgeMap.keySet()); + Set links = new HashSet<>(this.visibleData.getBinaryLinkToEdgeMap().keySet()); for (MLink e : links) { hideBinaryLink(e); @@ -406,10 +398,10 @@ public void hideAllLinks() { // Hide HalfLinks // HalfLinks used by TernaryAssoc - links.addAll(this.visibleData.fHalfLinkToEdgeMap.keySet()); + links.addAll(this.visibleData.getHalfLinkToEdgeMap().keySet()); // Hide LinkObject - links.addAll(this.visibleData.fLinkObjectToNodeEdge.keySet()); + links.addAll(this.visibleData.getLinkObjectToNodeEdge().keySet()); for (MLink e : links) { hideLink(e); } @@ -417,7 +409,7 @@ public void hideAllLinks() { links.clear(); // Hide NaryLinks - links.addAll(this.visibleData.fNaryLinkToDiamondNodeMap.keySet()); + links.addAll(this.visibleData.getNaryLinkToDiamondNodeMap().keySet()); for (MLink e : links) { hideNAryLink(e); } @@ -451,7 +443,7 @@ public void addObject(MObject obj) { } fGraph.add(n); - visibleData.fObjectToNodeMap.put(obj, n); + visibleData.getObjectToNodeMap().put(obj, n); fLayouter = null; } @@ -462,7 +454,7 @@ public void addObject(MObject obj) { * The object to show */ public void showObject(MObject obj) { - if (visibleData.fObjectToNodeMap.containsKey(obj)) + if (visibleData.getObjectToNodeMap().containsKey(obj)) return; showOrHideObjectNode(obj, true); @@ -484,13 +476,13 @@ public void showObject(MObject obj) { if (link.linkedObjects().contains(obj) || (isLinkObject && link.equals(obj))) { boolean allVisible = true; for (MObject linkedO : link.linkedObjects()) { - if (!visibleData.fObjectToNodeMap.containsKey(linkedO)) { + if (!visibleData.getObjectToNodeMap().containsKey(linkedO)) { allVisible = false; break; } } - if (allVisible && (!isLinkObject || visibleData.fObjectToNodeMap.containsKey(obj))) + if (allVisible && (!isLinkObject || visibleData.getObjectToNodeMap().containsKey(obj))) showLink(link); } } @@ -500,10 +492,10 @@ public void showObject(MObject obj) { @Override public void moveObjectNode(MObject obj, int x, int y) { PlaceableNode node = null; - if (visibleData.fObjectToNodeMap.containsKey(obj)) { - node = visibleData.fObjectToNodeMap.get(obj); - } else if (hiddenData.fObjectToNodeMap.containsKey(obj)) { - node = hiddenData.fObjectToNodeMap.get(obj); + if (visibleData.getObjectToNodeMap().containsKey(obj)) { + node = visibleData.getObjectToNodeMap().get(obj); + } else if (hiddenData.getObjectToNodeMap().containsKey(obj)) { + node = hiddenData.getObjectToNodeMap().get(obj); } if (node != null) { node.moveToPosition(x, y); @@ -518,7 +510,7 @@ public void moveObjectNode(MObject obj, int x, int y) { */ public void hideObject(MObject obj) { // a hidden object should no longer be selected - ObjectNode removedNode = visibleData.fObjectToNodeMap.get(obj); + ObjectNode removedNode = visibleData.getObjectToNodeMap().get(obj); if(removedNode!=null) { fNodeSelection.remove(removedNode); } @@ -553,7 +545,7 @@ protected void showOrHideObjectNode(MObject obj, boolean show) { ObjectDiagramData source = (show ? hiddenData : visibleData); ObjectDiagramData target = (show ? visibleData : hiddenData); - ObjectNode n = source.fObjectToNodeMap.get(obj); + ObjectNode n = source.getObjectToNodeMap().get(obj); if (n != null) { if (show) @@ -561,8 +553,8 @@ protected void showOrHideObjectNode(MObject obj, boolean show) { else fGraph.remove(n); - source.fObjectToNodeMap.remove(obj); - target.fObjectToNodeMap.put(obj, n); + source.getObjectToNodeMap().remove(obj); + target.getObjectToNodeMap().put(obj, n); fLayouter = null; } @@ -575,11 +567,11 @@ public void deleteObject(MObject obj) { ObjectNode n; boolean isVisible; - if (visibleData.fObjectToNodeMap.containsKey(obj)) { - n = visibleData.fObjectToNodeMap.get(obj); + if (visibleData.getObjectToNodeMap().containsKey(obj)) { + n = visibleData.getObjectToNodeMap().get(obj); isVisible = true; } else { - n = hiddenData.fObjectToNodeMap.get(obj); + n = hiddenData.getObjectToNodeMap().get(obj); isVisible = false; } @@ -587,10 +579,10 @@ public void deleteObject(MObject obj) { lastKnownNodePositions.put(obj, n.getPosition()); if (isVisible) { fGraph.remove(n); - visibleData.fObjectToNodeMap.remove(obj); + visibleData.getObjectToNodeMap().remove(obj); fLayouter = null; } else { - hiddenData.fObjectToNodeMap.remove(obj); + hiddenData.getObjectToNodeMap().remove(obj); } n.dispose(); } @@ -620,19 +612,19 @@ protected void addBinaryLink(MLink link) { // object link if (link instanceof MLinkObject) { BinaryAssociationClassOrObject e = BinaryAssociationClassOrObject.create( - visibleData.fObjectToNodeMap.get(obj1), visibleData.fObjectToNodeMap.get(obj2), - linkEnd1, linkEnd2, visibleData.fObjectToNodeMap.get(link), this, + visibleData.getObjectToNodeMap().get(obj1), visibleData.getObjectToNodeMap().get(obj2), + linkEnd1, linkEnd2, visibleData.getObjectToNodeMap().get(link), this, link); if (lastKnownLinkPositions.containsKey(link)) { e.initialize(); - visibleData.fObjectToNodeMap.get(link).setStrategy(lastKnownLinkPositions.get(link)); + visibleData.getObjectToNodeMap().get(link).setStrategy(lastKnownLinkPositions.get(link)); lastKnownLinkPositions.remove(link); fGraph.addInitializedEdge(e); } else { fGraph.addEdge(e); } - visibleData.fLinkObjectToNodeEdge.put((MLinkObject) link, e); + visibleData.getLinkObjectToNodeEdge().put((MLinkObject) link, e); fLayouter = null; } else { // binary link @@ -640,17 +632,17 @@ protected void addBinaryLink(MLink link) { ObjectNode node1; ObjectNode node2; - if (visibleData.fObjectToNodeMap.containsKey(obj1)) { - node1 = visibleData.fObjectToNodeMap.get(obj1); + if (visibleData.getObjectToNodeMap().containsKey(obj1)) { + node1 = visibleData.getObjectToNodeMap().get(obj1); } else { - node1 = hiddenData.fObjectToNodeMap.get(obj1); + node1 = hiddenData.getObjectToNodeMap().get(obj1); isHidden = true; } - if (visibleData.fObjectToNodeMap.containsKey(obj2)) { - node2 = visibleData.fObjectToNodeMap.get(obj2); + if (visibleData.getObjectToNodeMap().containsKey(obj2)) { + node2 = visibleData.getObjectToNodeMap().get(obj2); } else { - node2 = hiddenData.fObjectToNodeMap.get(obj2); + node2 = hiddenData.getObjectToNodeMap().get(obj2); isHidden = true; } @@ -662,10 +654,10 @@ protected void addBinaryLink(MLink link) { } if (isHidden) { - hiddenData.fBinaryLinkToEdgeMap.put(link, e); + hiddenData.getBinaryLinkToEdgeMap().put(link, e); } else { fGraph.addEdge(e); - visibleData.fBinaryLinkToEdgeMap.put(link, e); + visibleData.getBinaryLinkToEdgeMap().put(link, e); fLayouter = null; } } @@ -686,7 +678,7 @@ protected void addNAryLink(MLink link) { List linkedObjectNodes = new ArrayList<>(); for(MObject linkedObject : link.linkedObjects()) { - linkedObjectNodes.add(visibleData.fObjectToNodeMap.get(linkedObject)); + linkedObjectNodes.add(visibleData.getObjectToNodeMap().get(linkedObject)); } // n-ary link: create a diamond node and n edges to objects @@ -697,20 +689,20 @@ protected void addNAryLink(MLink link) { // connected to an "object link" if (link instanceof MLinkObject) { NAryAssociationClassOrObjectEdge e = NAryAssociationClassOrObjectEdge.create(node, - visibleData.fObjectToNodeMap.get(link), this, link.association(), true); + visibleData.getObjectToNodeMap().get(link), this, link.association(), true); fGraph.addEdge(e); - visibleData.fLinkObjectToNodeEdge.put((MLinkObject) link, e); + visibleData.getLinkObjectToNodeEdge().put((MLinkObject) link, e); fLayouter = null; } // connected to a "normal" link - visibleData.fNaryLinkToDiamondNodeMap.put(link, node); + visibleData.getNaryLinkToDiamondNodeMap().put(link, node); List halfEdges = new ArrayList<>(); List edgeIds = new ArrayList<>(); for (MLinkEnd linkEnd : link.linkEnds()) { MObject obj = linkEnd.object(); - AssociationOrLinkPartEdge e = AssociationOrLinkPartEdge.create(node, visibleData.fObjectToNodeMap.get(obj), + AssociationOrLinkPartEdge e = AssociationOrLinkPartEdge.create(node, visibleData.getObjectToNodeMap().get(obj), linkEnd.associationEnd(), this, link.association(), link); if (link.isVirtual()) { @@ -719,17 +711,17 @@ protected void addNAryLink(MLink link) { fGraph.addEdge(e); halfEdges.add(e); - edgeIds.add(linkEnd.associationEnd().nameAsRolename()); + edgeIds.add(linkEnd.associationEnd().nameAsRolename()); } - if (visibleData.fLinkObjectToNodeEdge.get(link) != null) { - halfEdges.add(visibleData.fLinkObjectToNodeEdge.get(link)); + if (visibleData.getLinkObjectToNodeEdge().get(link) != null) { + halfEdges.add(visibleData.getLinkObjectToNodeEdge().get(link)); edgeIds.add(((MLinkObject) link).name()); } node.setHalfEdges(halfEdges, edgeIds); - visibleData.fHalfLinkToEdgeMap.put(link, halfEdges); + visibleData.getHalfLinkToEdgeMap().put(link, halfEdges); fLayouter = null; } @@ -776,7 +768,7 @@ public void hideLink(MLink link) { } // Hide Linkobject, if link has a linkobject - if (link instanceof MLinkObject && visibleData.fObjectToNodeMap.containsKey(link)) { + if (link instanceof MLinkObject && visibleData.getObjectToNodeMap().containsKey(link)) { hideObject((MObject) link); } } @@ -803,26 +795,26 @@ protected void showOrHideBinaryLink(MLink link, boolean show) { // object link if (link instanceof MLinkObject) { - EdgeBase e = source.fLinkObjectToNodeEdge.get(link); + EdgeBase e = source.getLinkObjectToNodeEdge().get(link); if (show && e != null) fGraph.addInitializedEdge(e); else if (e != null) fGraph.removeEdge(e); - source.fLinkObjectToNodeEdge.remove(link); - target.fLinkObjectToNodeEdge.put((MLinkObject) link, e); + source.getLinkObjectToNodeEdge().remove(link); + target.getLinkObjectToNodeEdge().put((MLinkObject) link, e); fLayouter = null; } else { // binary link - BinaryAssociationOrLinkEdge e = source.fBinaryLinkToEdgeMap.get(link); + BinaryAssociationOrLinkEdge e = source.getBinaryLinkToEdgeMap().get(link); if (show && e != null) { fGraph.addEdge(e); } else if (e != null) { fGraph.removeEdge(e); } - source.fBinaryLinkToEdgeMap.remove(link); - target.fBinaryLinkToEdgeMap.put(link, e); + source.getBinaryLinkToEdgeMap().remove(link); + target.getBinaryLinkToEdgeMap().put(link, e); } } @@ -886,13 +878,13 @@ public void deleteLink(MLink link) { ObjectDiagramData data; if (isLinkObject) { - isVisible = visibleData.fLinkObjectToNodeEdge.containsKey(link); + isVisible = visibleData.getLinkObjectToNodeEdge().containsKey(link); data = isVisible ? visibleData : hiddenData; - e = data.fLinkObjectToNodeEdge.get(link); + e = data.getLinkObjectToNodeEdge().get(link); } else { - isVisible = visibleData.fBinaryLinkToEdgeMap.containsKey(link); + isVisible = visibleData.getBinaryLinkToEdgeMap().containsKey(link); data = isVisible ? visibleData : hiddenData; - e = data.fBinaryLinkToEdgeMap.get(link); + e = data.getBinaryLinkToEdgeMap().get(link); } if (e == null) { @@ -900,17 +892,16 @@ public void deleteLink(MLink link) { } if (isLinkObject) { - BinaryAssociationClassOrObject edge = (BinaryAssociationClassOrObject) data.fLinkObjectToNodeEdge - .get(link); + BinaryAssociationClassOrObject edge = (BinaryAssociationClassOrObject) data.getLinkObjectToNodeEdge().get(link); if (edge != null) { PlaceableNode objectNode = edge.getClassOrObjectNode(); lastKnownLinkPositions.put(link, objectNode.getStrategy()); } - data.fBinaryLinkToEdgeMap.remove(link); - data.fLinkObjectToNodeEdge.remove(link); + data.getBinaryLinkToEdgeMap().remove(link); + data.getLinkObjectToNodeEdge().remove(link); } else { - data.fBinaryLinkToEdgeMap.remove(link); + data.getBinaryLinkToEdgeMap().remove(link); } if (isVisible) { @@ -922,16 +913,16 @@ public void deleteLink(MLink link) { boolean isVisible; ObjectDiagramData data; - isVisible = visibleData.fNaryLinkToDiamondNodeMap.containsKey(link); + isVisible = visibleData.getNaryLinkToDiamondNodeMap().containsKey(link); data = isVisible ? visibleData : hiddenData; - DiamondNode n = data.fNaryLinkToDiamondNodeMap.get(link); + DiamondNode n = data.getNaryLinkToDiamondNodeMap().get(link); if (n == null) { throw new RuntimeException("no diamond node for n-ary link `" + link + "' in current state."); } - data.fNaryLinkToDiamondNodeMap.remove(link); - data.fHalfLinkToEdgeMap.remove(link); + data.getNaryLinkToDiamondNodeMap().remove(link); + data.getHalfLinkToEdgeMap().remove(link); if (isVisible) { fGraph.remove(n); @@ -941,12 +932,12 @@ public void deleteLink(MLink link) { n.dispose(); if (link instanceof MLinkObject) { - EdgeBase edge = data.fLinkObjectToNodeEdge.get(link); + EdgeBase edge = data.getLinkObjectToNodeEdge().get(link); if (edge != null) { lastKnownLinkPositions.put(link, ((NAryAssociationClassOrObjectEdge) edge).getClassOrLinkObjectNode().getStrategy()); fGraph.removeEdge(edge); - data.fLinkObjectToNodeEdge.remove(link); + data.getLinkObjectToNodeEdge().remove(link); edge.dispose(); } } @@ -959,7 +950,7 @@ public void deleteLink(MLink link) { * @param obj */ public void updateObject(MInstance obj) { - ObjectNode node = visibleData.fObjectToNodeMap.get(obj); + ObjectNode node = visibleData.getObjectToNodeMap().get(obj); if (node != null) invalidateNode(node); } @@ -1111,9 +1102,9 @@ protected PopupMenuInfo unionOfPopUpMenu() { // position for the popupMenu items int pos = 0; - final Set selectedObjectsOfAssociation = new HashSet(); - final Set selectedLinks = new HashSet(); - final List selectedObjects = new ArrayList(); + final Set selectedObjectsOfAssociation = new HashSet<>(); + final Set selectedLinks = new HashSet<>(); + final List selectedObjects = new ArrayList<>(); // Split selected nodes into model elements for (PlaceableNode node : fNodeSelection) { @@ -1213,9 +1204,9 @@ protected PopupMenuInfo unionOfPopUpMenu() { popupMenu.insert(new JSeparator(), pos++); } - if (!hiddenData.fObjectToNodeMap.isEmpty() || !hiddenData.fBinaryLinkToEdgeMap.isEmpty() - || !hiddenData.fNaryLinkToDiamondNodeMap.isEmpty() || !hiddenData.fHalfLinkToEdgeMap.isEmpty() - || !hiddenData.fLinkObjectToNodeEdge.isEmpty()) { + if (!hiddenData.getObjectToNodeMap().isEmpty() || !hiddenData.getBinaryLinkToEdgeMap().isEmpty() + || !hiddenData.getNaryLinkToDiamondNodeMap().isEmpty() || !hiddenData.getHalfLinkToEdgeMap().isEmpty() + || !hiddenData.getLinkObjectToNodeEdge().isEmpty()) { final JMenuItem showAllObjects = new JMenuItem("Show hidden elements"); showAllObjects.addActionListener(ev -> { showAll(); @@ -1281,8 +1272,8 @@ public void actionPerformed(ActionEvent e) { // new Action for grey in/out if (selectedObjects.size() == 1) { MObject obj = selectedObjects.iterator().next(); - if (visibleData.fObjectToNodeMap.containsKey(obj)) { - ObjectNode node = visibleData.fObjectToNodeMap.get(obj); + if (visibleData.getObjectToNodeMap().containsKey(obj)) { + ObjectNode node = visibleData.getObjectToNodeMap().get(obj); String labelGreyed = node.isGreyed() ? "Grey in" : "Grey out"; popupMenu.insert(new AbstractAction(labelGreyed + " " + node.name()) { @@ -1295,12 +1286,12 @@ public void actionPerformed(ActionEvent e) { } } else if (selectedObjects.size() > 1) { Set objToGreyIn = new HashSet<>(); - selectedObjects.stream().filter(obj -> visibleData.fObjectToNodeMap.get(obj).isGreyed()) - .forEach(obj -> objToGreyIn.add(visibleData.fObjectToNodeMap.get(obj))); + selectedObjects.stream().filter(obj -> visibleData.getObjectToNodeMap().get(obj).isGreyed()) + .forEach(obj -> objToGreyIn.add(visibleData.getObjectToNodeMap().get(obj))); Set objToGreyOut = new HashSet<>(); - selectedObjects.stream().filter(obj -> !visibleData.fObjectToNodeMap.get(obj).isGreyed()) - .forEach(obj -> objToGreyOut.add(visibleData.fObjectToNodeMap.get(obj))); + selectedObjects.stream().filter(obj -> !visibleData.getObjectToNodeMap().get(obj).isGreyed()) + .forEach(obj -> objToGreyOut.add(visibleData.getObjectToNodeMap().get(obj))); if (!objToGreyIn.isEmpty()) { popupMenu.insert(new AbstractAction("Grey in " + objToGreyIn.size() + " elements") { @@ -1339,33 +1330,28 @@ public void actionPerformed(ActionEvent arg0) { popupMenu.insert(showHideCrop, pos++); - if (fGraph.size() > 0 || !hiddenData.fObjectToNodeMap.isEmpty()) { - if (fGraph.size() > 0) { + if (!fGraph.isEmpty() || !hiddenData.getObjectToNodeMap().isEmpty()) { + if (!fGraph.isEmpty()) { popupMenu.insert(fSelection.getSubMenuHideObject(), pos++); } - if (!hiddenData.fObjectToNodeMap.isEmpty()) { + if (!hiddenData.getObjectToNodeMap().isEmpty()) { popupMenu.insert(fSelection.getSubMenuShowObject(), pos++); } } - if (!visibleData.fBinaryLinkToEdgeMap.isEmpty() || !visibleData.fHalfLinkToEdgeMap.isEmpty() - || !visibleData.fLinkObjectToNodeEdge.isEmpty() - || !visibleData.fNaryLinkToDiamondNodeMap.isEmpty()) { + if (!visibleData.getBinaryLinkToEdgeMap().isEmpty() || !visibleData.getHalfLinkToEdgeMap().isEmpty() + || !visibleData.getLinkObjectToNodeEdge().isEmpty() + || !visibleData.getNaryLinkToDiamondNodeMap().isEmpty()) { popupMenu.insert(fSelection.getSubMenuHideLinks(), pos++); } - if (!hiddenData.fBinaryLinkToEdgeMap.isEmpty() || !hiddenData.fHalfLinkToEdgeMap.isEmpty() - || !hiddenData.fLinkObjectToNodeEdge.isEmpty() || !hiddenData.fNaryLinkToDiamondNodeMap.isEmpty()) { + if (!hiddenData.getBinaryLinkToEdgeMap().isEmpty() || !hiddenData.getHalfLinkToEdgeMap().isEmpty() + || !hiddenData.getLinkObjectToNodeEdge().isEmpty() || !hiddenData.getNaryLinkToDiamondNodeMap().isEmpty()) { popupMenu.insert(fSelection.getSubMenuShowLinks(), pos++); } popupMenu.insert(new JSeparator(), pos++); - if (!visibleData.getEdges().isEmpty() || !hiddenData.getEdges().isEmpty()) { - popupMenu.insert(fSelection.getSubMenuLinksByKind(), pos++); - - popupMenu.insert(new JSeparator(), pos++); - } if (!selectedObjects.isEmpty()) { final JMenu showProtocolStateMachine = new JMenu("Show protocol state machine..."); @@ -1375,7 +1361,7 @@ public void actionPerformed(ActionEvent arg0) { if (selectedObjects.size() == 1) { final MObject obj = exactlyOne(selectedObjects); - List sortedPSMs = new LinkedList<> ( + List sortedPSMs = new LinkedList<>( obj.cls().getAllOwnedProtocolStateMachines()); Collections.sort(sortedPSMs, new MNamedElementComparator()); @@ -1423,7 +1409,7 @@ public void itemStateChanged(ItemEvent ev) { * @return A HashSet of the none selected objects in the diagram. */ private Set getNoneSelectedNodes(Set selectedNodes) { - Set noneSelectedNodes = new HashSet(); + Set noneSelectedNodes = new HashSet<>(); Iterator it = fGraph.iterator(); while (it.hasNext()) { PlaceableNode o = it.next(); @@ -1599,7 +1585,7 @@ public void storePlacementInfos(PersistHelper helper, Element root) { protected void storePlacementInfos(PersistHelper helper, Element root, boolean visible) { ObjectDiagramData data = (visible ? visibleData : hiddenData); - for (ObjectNode n : data.fObjectToNodeMap.values()) { + for (ObjectNode n : data.getObjectToNodeMap().values()) { n.storePlacementInfo(helper, root, !visible); } @@ -1620,7 +1606,7 @@ protected void storePlacementInfos(PersistHelper helper, Element root, boolean v public void restorePlacementInfos(PersistHelper helper, int version) { if (version < 12) return; - Set hiddenObjects = new HashSet(); + Set hiddenObjects = new HashSet<>(); AutoPilot ap = new AutoPilot(helper.getNav()); // First restore edges to get possible new nodes, then nodes @@ -1658,8 +1644,8 @@ public void restorePlacementInfos(PersistHelper helper, int version) { } if (link != null) { - BinaryAssociationOrLinkEdge edge = visibleData.fBinaryLinkToEdgeMap.get(link); - edge.restorePlacementInfo(helper, version); + BinaryAssociationOrLinkEdge edge = visibleData.getBinaryLinkToEdgeMap().get(link); + edge.restorePlacementInfo(helper, version); } } } @@ -1707,7 +1693,7 @@ public void restorePlacementInfos(PersistHelper helper, int version) { } if (link != null) { - BinaryAssociationClassOrObject edge = (BinaryAssociationClassOrObject)visibleData.fLinkObjectToNodeEdge.get(link); + BinaryAssociationClassOrObject edge = (BinaryAssociationClassOrObject)visibleData.getLinkObjectToNodeEdge().get(link); edge.restorePlacementInfo(helper, version); } } @@ -1733,7 +1719,7 @@ public void restorePlacementInfos(PersistHelper helper, int version) { MObject obj = fParent.system().state().objectByName(name); // Could be deleted if (obj != null) { - ObjectNode node = visibleData.fObjectToNodeMap.get(obj); + ObjectNode node = visibleData.getObjectToNodeMap().get(obj); node.restorePlacementInfo(helper, version); if (isHidden(helper, version)) hiddenObjects.add(obj); } @@ -1764,7 +1750,7 @@ public void restorePlacementInfos(PersistHelper helper, int version) { if (assoc == null) continue; // Get connected objects - List connectedObjects = new LinkedList(); + List connectedObjects = new LinkedList<>(); if (!helper.toFirstChild("connectedNode")) break; @@ -1832,7 +1818,7 @@ protected boolean isHidden(PersistHelper helper, int version) { @Override public Set getHiddenNodes() { - return new HashSet(hiddenData.fObjectToNodeMap.values()); + return new HashSet(hiddenData.getObjectToNodeMap().values()); } @Override @@ -1863,7 +1849,7 @@ protected void onClosing() { @Override public void stateChanged(SortChangeEvent e) { - for (ObjectNode n : this.visibleData.fObjectToNodeMap.values()) { + for (ObjectNode n : this.visibleData.getObjectToNodeMap().values()) { n.stateChanged(e); } } @@ -1926,53 +1912,33 @@ public TreeMap> mapLinksToKindOfAssociation() { for (MLink link : links) { if (link.association().isDerived() || link.association().isUnion()) { if (!assocs.containsKey(derrivedLinks)) { - assocs.put(derrivedLinks, new ArrayList() { - { - add(link); - } - }); + assocs.put(derrivedLinks, new ArrayList() {{ add(link); }}); } else { assocs.get(derrivedLinks).add(link); } } else if (MAssociationClassImpl.class.isInstance(link.association())) { if (!assocs.containsKey(associationClass)) { - assocs.put(associationClass, new ArrayList() { - { - add(link); - } - }); + assocs.put(associationClass, new ArrayList() {{ add(link); }}); } else { assocs.get(associationClass).add(link); } } else if (MAssociation.class.isInstance(link.association()) && link.linkEnds().size() > 2) { if (!assocs.containsKey(nAryLinks)) { - assocs.put(nAryLinks, new ArrayList() { - { - add(link); - } - }); + assocs.put(nAryLinks, new ArrayList() {{ add(link); }}); } else { assocs.get(nAryLinks).add(link); } } else if (MAssociation.class.isInstance(link.association()) && link.association().associatedClasses().size() == 1 ) { if (!assocs.containsKey(reflexivLinks)) { - assocs.put(reflexivLinks, new ArrayList() { - { - add(link); - } - }); + assocs.put(reflexivLinks, new ArrayList() {{ add(link); }}); } else { assocs.get(reflexivLinks).add(link); } } else if (MAssociation.class.isInstance(link.association()) && link.linkedObjects().size() == 2 && !link.linkedObjects().get(0).equals(link.linkedObjects().get(1))) { if (!assocs.containsKey(binaryLinks)) { - assocs.put(binaryLinks, new ArrayList() { - { - add(link); - } - }); + assocs.put(binaryLinks, new ArrayList() {{ add(link); }}); } else { assocs.get(binaryLinks).add(link); } @@ -2052,9 +2018,9 @@ public void showLink(List links) { * @return true, if link is hidden; else return false */ public boolean isHidden(MLink link) { - if (hiddenData.fBinaryLinkToEdgeMap.containsKey(link) || hiddenData.fHalfLinkToEdgeMap.containsKey(link) - || hiddenData.fLinkObjectToNodeEdge.containsKey(link) - || hiddenData.fNaryLinkToDiamondNodeMap.containsKey(link)) { + if (hiddenData.getBinaryLinkToEdgeMap().containsKey(link) || hiddenData.getHalfLinkToEdgeMap().containsKey(link) + || hiddenData.getLinkObjectToNodeEdge().containsKey(link) + || hiddenData.getNaryLinkToDiamondNodeMap().containsKey(link)) { return true; } else { return false; @@ -2087,7 +2053,7 @@ public int isHidden(List links) { return -1; } - public static void setJavaFxCall(Boolean javaFxCall) { + public static void setJavaFxCall(boolean javaFxCall) { NewObjectDiagram.javaFxCall = javaFxCall; } From d91a6d5f296607f69a18719e57c1c536f024697c Mon Sep 17 00:00:00 2001 From: ahmed Date: Wed, 11 Feb 2026 15:32:18 +0100 Subject: [PATCH 04/20] =?UTF-8?q?refactor(gui):=20NewObjectDiagram=20?= =?UTF-8?q?=E2=80=94=20small=20cleanups:=20replace=20double-brace=20initia?= =?UTF-8?q?lizers,=20use=20computeIfAbsent,=20lambdas=20&=20method=20refs,?= =?UTF-8?q?=20improve=20drop=20logging,=20minor=20readability=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../objectdiagram/NewObjectDiagram.java | 107 ++++++------------ 1 file changed, 36 insertions(+), 71 deletions(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index 01f45643a..2103d891d 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -381,7 +381,7 @@ public void showAll() { public void hideAll() { Set objects = new HashSet<>(this.visibleData.getObjectToNodeMap().keySet()); - objects.forEach(obj -> hideObject(obj)); + objects.forEach(this::hideObject); } /** @@ -967,12 +967,7 @@ class ActionInsertLink extends AbstractAction { fParticipants = participants; StringBuilder txt = new StringBuilder("insert ("); - StringUtil.fmtSeq(txt, participants, ",", new IElementFormatter() { - @Override - public String format(MObject element) { - return element.name(); - } - }); + StringUtil.fmtSeq(txt, participants, ",", (MObject element) -> element.name()); txt.append(") into ").append(association.name()); @@ -1127,7 +1122,7 @@ protected PopupMenuInfo unionOfPopUpMenu() { } // Just to be sure to delete an object only once - Set selectedObjectsSet = new HashSet(selectedObjects); + Set selectedObjectsSet = new HashSet<>(selectedObjects); // This text is reused often String selectedObjectsText = null; @@ -1242,10 +1237,10 @@ protected PopupMenuInfo unionOfPopUpMenu() { @Override public void actionPerformed(ActionEvent arg0) { if (!selectedLinks.isEmpty()) { - selectedLinks.forEach(link -> hideLink(link)); + selectedLinks.forEach(NewObjectDiagram.this::hideLink); } if (!selectedObjects.isEmpty()) { - selectedObjects.forEach(obj -> hideObject(obj)); + selectedObjects.forEach(NewObjectDiagram.this::hideObject); } repaint(); } @@ -1500,12 +1495,18 @@ public void dropObjectFromModelBrowser(DropTargetDropEvent dtde) { } dtde.dropComplete(true); } catch (IOException exception) { - exception.printStackTrace(); - System.err.println("Exception" + exception.getMessage()); + if (fLog != null) { + fLog.append("IOException in dropObjectFromModelBrowser: " + exception.getMessage()); + } else { + System.err.println("IOException in dropObjectFromModelBrowser: " + exception.getMessage()); + } dtde.dropComplete(false); } catch (UnsupportedFlavorException ufException) { - ufException.printStackTrace(); - System.err.println("Exception" + ufException.getMessage()); + if (fLog != null) { + fLog.append("UnsupportedFlavorException in dropObjectFromModelBrowser: " + ufException.getMessage()); + } else { + System.err.println("UnsupportedFlavorException in dropObjectFromModelBrowser: " + ufException.getMessage()); + } dtde.dropComplete(false); } } @@ -1640,7 +1641,7 @@ public void restorePlacementInfos(PersistHelper helper, int version) { .state() .linkBetweenObjects(assoc, Arrays.asList(sourceObject, targetObject), - Collections.>emptyList()); + Collections.emptyList()); } if (link != null) { @@ -1689,7 +1690,7 @@ public void restorePlacementInfos(PersistHelper helper, int version) { .state() .linkBetweenObjects(assoc, Arrays.asList(sourceObject, targetObject), - Collections.> emptyList()); + Collections.emptyList()); } if (link != null) { @@ -1774,8 +1775,8 @@ public void restorePlacementInfos(PersistHelper helper, int version) { continue; // n-ary links cannot be qualified therefore an empty list for the qualifer values is provided - MLink link = fParent.system().state().linkBetweenObjects(assoc, connectedObjects, Collections.>emptyList()); - + MLink link = fParent.system().state().linkBetweenObjects(assoc, connectedObjects, Collections.emptyList()); + // Could be deleted if (link != null) { DiamondNode node = visibleData.fNaryLinkToDiamondNodeMap.get(link); @@ -1889,14 +1890,14 @@ public void showLink(String linkName, List links) { * @return */ public TreeMap> mapLinksToKindOfAssociation() { - HashMap> assocs = new HashMap<>(); - final String derrivedLinks = "Derrived links"; + Map> assocs = new HashMap<>(); + final String derivedLinks = "Derived links"; final String associationClass = "Linkobjects"; final String nAryLinks = "N-Ary links"; - final String reflexivLinks = "Reflexiv links"; + final String reflexiveLinks = "Reflexive links"; final String binaryLinks = "Binary links"; final String aggregation = "Aggregations"; - final String compositon = "Compositons"; + final String composition = "Compositions"; for (MAssociation assoc : fParent.system().model().associations()) { @@ -1911,37 +1912,17 @@ public TreeMap> mapLinksToKindOfAssociation() { Set links = fParent.system().state().linksOfAssociation(assoc).links(); for (MLink link : links) { if (link.association().isDerived() || link.association().isUnion()) { - if (!assocs.containsKey(derrivedLinks)) { - assocs.put(derrivedLinks, new ArrayList() {{ add(link); }}); - } else { - assocs.get(derrivedLinks).add(link); - } + assocs.computeIfAbsent(derivedLinks, k -> new ArrayList<>()).add(link); } else if (MAssociationClassImpl.class.isInstance(link.association())) { - if (!assocs.containsKey(associationClass)) { - assocs.put(associationClass, new ArrayList() {{ add(link); }}); - } else { - assocs.get(associationClass).add(link); - } + assocs.computeIfAbsent(associationClass, k -> new ArrayList<>()).add(link); } else if (MAssociation.class.isInstance(link.association()) && link.linkEnds().size() > 2) { - if (!assocs.containsKey(nAryLinks)) { - assocs.put(nAryLinks, new ArrayList() {{ add(link); }}); - } else { - assocs.get(nAryLinks).add(link); - } + assocs.computeIfAbsent(nAryLinks, k -> new ArrayList<>()).add(link); } else if (MAssociation.class.isInstance(link.association()) - && link.association().associatedClasses().size() == 1 ) { - if (!assocs.containsKey(reflexivLinks)) { - assocs.put(reflexivLinks, new ArrayList() {{ add(link); }}); - } else { - assocs.get(reflexivLinks).add(link); - } + && link.association().associatedClasses().size() == 1) { + assocs.computeIfAbsent(reflexiveLinks, k -> new ArrayList<>()).add(link); } else if (MAssociation.class.isInstance(link.association()) && link.linkedObjects().size() == 2 && !link.linkedObjects().get(0).equals(link.linkedObjects().get(1))) { - if (!assocs.containsKey(binaryLinks)) { - assocs.put(binaryLinks, new ArrayList() {{ add(link); }}); - } else { - assocs.get(binaryLinks).add(link); - } + assocs.computeIfAbsent(binaryLinks, k -> new ArrayList<>()).add(link); } else { System.err.println("ERROR: NO MATCH IN ASSOC-KIND"); } @@ -1954,38 +1935,22 @@ public TreeMap> mapLinksToKindOfAssociation() { Set aggregations = fParent.system().state().linksOfAssociation(assoc).links(); for (MLink agg : aggregations) { - if (!assocs.containsKey(aggregation)) { - assocs.put(aggregation, new ArrayList() { - { - add(agg); - } - }); - } else { - assocs.get(aggregation).add(agg); - } + assocs.computeIfAbsent(aggregation, k -> new ArrayList<>()).add(agg); } break; - case 2: // Compositon + case 2: // Composition - // Get Compositon - Set compositons = fParent.system().state().linksOfAssociation(assoc).links(); + // Get Compositions + Set compositions = fParent.system().state().linksOfAssociation(assoc).links(); - for (MLink comp : compositons) { - if (!assocs.containsKey(compositon)) { - assocs.put(compositon, new ArrayList() { - { - add(comp); - } - }); - } else { - assocs.get(compositon).add(comp); - } + for (MLink comp : compositions) { + assocs.computeIfAbsent(composition, k -> new ArrayList<>()).add(comp); } break; } } - return new TreeMap>(assocs); + return new TreeMap<>(assocs); } From 260a5609b5f7fe2abc7804a59e3ae33732a19daa Mon Sep 17 00:00:00 2001 From: ahmed Date: Wed, 11 Feb 2026 15:42:46 +0100 Subject: [PATCH 05/20] =?UTF-8?q?refactor(gui):=20NewObjectDiagram=20?= =?UTF-8?q?=E2=80=94=20mark=20immutable=20fields=20and=20inner=20action=20?= =?UTF-8?q?fields=20as=20final=20(small=20cleanup)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../objectdiagram/NewObjectDiagram.java | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index 2103d891d..6930fc23b 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -107,7 +107,6 @@ import org.tzi.use.uml.ocl.value.Value; import org.tzi.use.uml.sys.*; import org.tzi.use.util.StringUtil; -import org.tzi.use.util.StringUtil.IElementFormatter; import org.w3c.dom.Element; import com.ximpleware.AutoPilot; @@ -121,7 +120,6 @@ * @author Mark Richters * @author Lars Hamann */ -@SuppressWarnings("serial") public class NewObjectDiagram extends DiagramViewWithObjectNode implements HighlightChangeListener, SortChangeListener { /** @@ -217,31 +215,31 @@ public void clear() { public Map getLinkObjectToNodeEdge() { return fLinkObjectToNodeEdge; } } - protected ObjectDiagramData visibleData = new ObjectDiagramData(); + protected final ObjectDiagramData visibleData = new ObjectDiagramData(); - private ObjectDiagramData hiddenData = new ObjectDiagramData(); + private final ObjectDiagramData hiddenData = new ObjectDiagramData(); - private NewObjectDiagramView fParent; + private final NewObjectDiagramView fParent; /** * The position of the next object node. This is either set to a random * value or to a specific position when an object is created by drag & drop. */ - protected Point2D.Double nextNodePosition = new Point2D.Double(); + protected Point2D.Double nextNodePosition = new Point2D.Double(); /** * Last position of deleted nodes and links. In case of restoration, the * nodes (object nodes, linkobject nodes) are positioned as they were * before. Objects use {@link StrategyFixed}, so we just save the position. */ - private Map lastKnownNodePositions = new WeakHashMap<>(); - private Map lastKnownLinkPositions = new WeakHashMap<>(); + private final Map lastKnownNodePositions = new WeakHashMap<>(); + private final Map lastKnownLinkPositions = new WeakHashMap<>(); - protected ShowObjectPropertiesViewMouseListener showObjectPropertiesViewMouseListener = new ShowObjectPropertiesViewMouseListener(); + protected final ShowObjectPropertiesViewMouseListener showObjectPropertiesViewMouseListener = new ShowObjectPropertiesViewMouseListener(); - private ObjectSelection fSelection; + private final ObjectSelection fSelection; - protected DiagramInputHandling inputHandling; + protected final DiagramInputHandling inputHandling; private static boolean javaFxCall = false; @@ -959,15 +957,15 @@ public void updateObject(MInstance obj) { * Adds a new Link to the objectdiagram. */ class ActionInsertLink extends AbstractAction { - private MAssociation fAssociation; - private MObject[] fParticipants; + private final MAssociation fAssociation; + private final MObject[] fParticipants; ActionInsertLink(MAssociation association, MObject[] participants) { fAssociation = association; fParticipants = participants; StringBuilder txt = new StringBuilder("insert ("); - StringUtil.fmtSeq(txt, participants, ",", (MObject element) -> element.name()); + StringUtil.fmtSeq(txt, participants, ",", MObject::name); txt.append(") into ").append(association.name()); @@ -983,7 +981,7 @@ public void actionPerformed(ActionEvent e) { * Deletes a Link from the object diagram. */ class ActionDeleteLink extends AbstractAction { - private MLink link; + private final MLink link; ActionDeleteLink(MLink link) { this.link = link; @@ -1016,7 +1014,7 @@ public void actionPerformed(ActionEvent e) { * Deletes the selected objects. */ class ActionDelete extends AbstractAction { - private Set fObjects; + private final Set fObjects; ActionDelete(String text, Set objects) { super(text); @@ -1033,7 +1031,7 @@ public void actionPerformed(ActionEvent e) { * Show properties of objects */ class ActionShowProperties extends AbstractAction { - private MObject fObject; + private final MObject fObject; ActionShowProperties(String text, MObject object) { super(text); From b91a5a291cf879614cab739ad2315fed1f6a1eef Mon Sep 17 00:00:00 2001 From: ahmed Date: Wed, 11 Feb 2026 15:48:24 +0100 Subject: [PATCH 06/20] =?UTF-8?q?fix(gui):=20AssociationOrLinkPartEdge=20?= =?UTF-8?q?=E2=80=94=20use=20getter=20for=20visibleData=20object=20map=20t?= =?UTF-8?q?o=20avoid=20private-field=20access?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../diagrams/elements/edges/AssociationOrLinkPartEdge.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/elements/edges/AssociationOrLinkPartEdge.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/elements/edges/AssociationOrLinkPartEdge.java index 67d7a579a..7f8c0e201 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/elements/edges/AssociationOrLinkPartEdge.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/elements/edges/AssociationOrLinkPartEdge.java @@ -230,7 +230,7 @@ public boolean adjacentObjectNodeGreyed() { List adjacentObjects = getLink().linkedObjects(); for (MObject adjacentObject : adjacentObjects) { - ObjectNode node = visibleData.fObjectToNodeMap.get(adjacentObject); + ObjectNode node = visibleData.getObjectToNodeMap().get(adjacentObject); if(node.isGreyed()) { return true; } From 1f256296296a21361b450fe5d32ab65bc439d882 Mon Sep 17 00:00:00 2001 From: ahmed Date: Wed, 11 Feb 2026 16:02:10 +0100 Subject: [PATCH 07/20] =?UTF-8?q?refactor(gui):=20NewObjectDiagram=20?= =?UTF-8?q?=E2=80=94=20safety=20and=20modernization:=20safe=20map=20access?= =?UTF-8?q?es,=20use=20List.sort,=20use=20fLog.println,=20lambdas=20and=20?= =?UTF-8?q?small=20readability=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../objectdiagram/NewObjectDiagram.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index 6930fc23b..e706bfee3 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -1356,7 +1356,7 @@ public void actionPerformed(ActionEvent arg0) { List sortedPSMs = new LinkedList<>( obj.cls().getAllOwnedProtocolStateMachines()); - Collections.sort(sortedPSMs, new MNamedElementComparator()); + sortedPSMs.sort(new MNamedElementComparator()); for (MProtocolStateMachine psm : sortedPSMs) { showProtocolStateMachine.setEnabled(true); @@ -1381,12 +1381,9 @@ public ActionListener setStateMachine(MProtocolStateMachine sm, MObject instance } final JCheckBoxMenuItem showStates = new JCheckBoxMenuItem("Show states", getOptions().isShowStates()); - showStates.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent ev) { - getOptions().setShowStates(ev.getStateChange() == ItemEvent.SELECTED); - invalidateContent(true); - } + showStates.addItemListener(ev -> { + getOptions().setShowStates(ev.getStateChange() == ItemEvent.SELECTED); + invalidateContent(true); }); popupMenu.insert(showStates, pos + 3); @@ -1494,14 +1491,14 @@ public void dropObjectFromModelBrowser(DropTargetDropEvent dtde) { dtde.dropComplete(true); } catch (IOException exception) { if (fLog != null) { - fLog.append("IOException in dropObjectFromModelBrowser: " + exception.getMessage()); + fLog.println("IOException in dropObjectFromModelBrowser: " + exception.getMessage()); } else { System.err.println("IOException in dropObjectFromModelBrowser: " + exception.getMessage()); } dtde.dropComplete(false); } catch (UnsupportedFlavorException ufException) { if (fLog != null) { - fLog.append("UnsupportedFlavorException in dropObjectFromModelBrowser: " + ufException.getMessage()); + fLog.println("UnsupportedFlavorException in dropObjectFromModelBrowser: " + ufException.getMessage()); } else { System.err.println("UnsupportedFlavorException in dropObjectFromModelBrowser: " + ufException.getMessage()); } @@ -1780,7 +1777,7 @@ public void restorePlacementInfos(PersistHelper helper, int version) { DiamondNode node = visibleData.fNaryLinkToDiamondNodeMap.get(link); helper.toParent(); node.restorePlacementInfo(helper, version); - } + } } } catch (XPathEvalException e) { fLog.append(e.getMessage()); From a841dbd9edbe078ce364aa78f764e015d9f582f6 Mon Sep 17 00:00:00 2001 From: ahmed Date: Thu, 12 Feb 2026 22:34:19 +0100 Subject: [PATCH 08/20] =?UTF-8?q?refactor(gui):=20NewObjectDiagram=20?= =?UTF-8?q?=E2=80=94=20cleanups=20&=20warnings=20fixes=20=C3=84nderungen:?= =?UTF-8?q?=20-=20Map-safety=20&=20Null-Checks=20=20=20-=20Ersetzte=20unsi?= =?UTF-8?q?chere=20Map.get()-Aufrufe=20durch=20computeIfPresent=20/=20null?= =?UTF-8?q?-checks.=20=20=20-=20Entfernte=20doppelte=20containsKey/get-Kom?= =?UTF-8?q?binationen.=20-=20Listener=20&=20Event-Handling=20=20=20-=20Ent?= =?UTF-8?q?fernt=20unbenutztes=20Feld/innere=20Klasse=20ShowObjectProperti?= =?UTF-8?q?esViewMouseListener.=20=20=20-=20Vereinfacht=20MouseListener=20?= =?UTF-8?q?mit=20Pattern=20Matching=20(instanceof).=20-=20Data=20&=20API?= =?UTF-8?q?=20=20=20-=20Vereinheitlichte=20Handhabung=20sichtbarer/verborg?= =?UTF-8?q?ener=20Daten=20via=20ObjectDiagramData-Accessoren.=20=20=20-=20?= =?UTF-8?q?getVisibleData/getHiddenData=20abgestimmt.=20=20=20-=20getDefau?= =?UTF-8?q?ltLayoutFileSuffix=20gesetzt.=20-=20Readability=20&=20Helpers?= =?UTF-8?q?=20=20=20-=20createAction=20Helper=20eingef=C3=BChrt,=20Boilerp?= =?UTF-8?q?late=20reduziert.=20=20=20-=20getLinkByValue=20implementiert=20?= =?UTF-8?q?(Restore/layouter=20Hilfsmethode).=20-=20Analyzer=20&=20Warning?= =?UTF-8?q?s=20=20=20-=20@SuppressWarnings(unused)=20wo=20sinnvoll=20(z.B.?= =?UTF-8?q?=20isHidden=20Persist-Helper=20Version).=20=20=20-=20Weitere=20?= =?UTF-8?q?Konsistenz-=20und=20Null-Sicherheits-Fixes.=20Keine=20API-Break?= =?UTF-8?q?ing=20=C3=84nderungen;=20low-risk=20Refactorings=20zur=20Verbes?= =?UTF-8?q?serung=20der=20Lesbarkeit=20und=20Analysehygiene.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/tzi/use/util/Debug.java | 33 + use-gui/src/main/java/module-info.java | 4 + .../edges/AssociationOrLinkPartEdge.java | 8 +- .../objectdiagram/NewObjectDiagram.java | 1041 ++++++++--------- 4 files changed, 553 insertions(+), 533 deletions(-) create mode 100644 use-core/src/main/java/org/tzi/use/util/Debug.java diff --git a/use-core/src/main/java/org/tzi/use/util/Debug.java b/use-core/src/main/java/org/tzi/use/util/Debug.java new file mode 100644 index 000000000..efc80d8c9 --- /dev/null +++ b/use-core/src/main/java/org/tzi/use/util/Debug.java @@ -0,0 +1,33 @@ +package org.tzi.use.util; + +/** + * Small debug helper to enable conditional debug output without polluting + * the normal test/golden outputs. Activate by setting system property + * -Duse.debug=true or environment variable USE_DEBUG=true. + */ +public final class Debug { + private Debug() {} + + public static boolean enabled() { + try { + String p = System.getProperty("use.debug"); + if (p != null) return "true".equalsIgnoreCase(p); + String e = System.getenv("USE_DEBUG"); + return "true".equalsIgnoreCase(e); + } catch (Throwable t) { + return false; + } + } + + public static void log(String s) { + if (enabled()) { + try { + // Try to write to USE protocol (preferred for integration tests) + org.tzi.use.util.USEWriter.getInstance().protocol("[USE-DEBUG] " + s); + } catch (Throwable ignore) { + // fallback to stderr + System.err.println("[USE-DEBUG] " + s); + } + } + } +} diff --git a/use-gui/src/main/java/module-info.java b/use-gui/src/main/java/module-info.java index 454e2590e..c073fda2a 100644 --- a/use-gui/src/main/java/module-info.java +++ b/use-gui/src/main/java/module-info.java @@ -31,4 +31,8 @@ exports org.tzi.use.gui.views.diagrams.behavior.shared to com.google.common; exports org.tzi.use.gui.views.selection to com.google.common; exports org.tzi.use.gui.views.diagrams.statemachine to com.google.common; + exports org.tzi.use.gui.views.diagrams.elements; + exports org.tzi.use.gui.views.diagrams.elements.edges; + exports org.tzi.use.gui.views.diagrams.event; + exports org.tzi.use.gui.views.selection.objectselection; } \ No newline at end of file diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/elements/edges/AssociationOrLinkPartEdge.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/elements/edges/AssociationOrLinkPartEdge.java index 7f8c0e201..3b35485a1 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/elements/edges/AssociationOrLinkPartEdge.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/elements/edges/AssociationOrLinkPartEdge.java @@ -231,7 +231,7 @@ public boolean adjacentObjectNodeGreyed() { List adjacentObjects = getLink().linkedObjects(); for (MObject adjacentObject : adjacentObjects) { ObjectNode node = visibleData.getObjectToNodeMap().get(adjacentObject); - if(node.isGreyed()) { + if (node != null && node.isGreyed()) { return true; } } @@ -365,8 +365,7 @@ public void drawProperties(Graphics2D g) { public static AssociationOrLinkPartEdge create(PlaceableNode source, PlaceableNode target, MAssociationEnd targetEnd, DiagramView diagram, MAssociation assoc, MLink link) { - AssociationOrLinkPartEdge edge = new AssociationOrLinkPartEdge(source, target, targetEnd, diagram, assoc, link); - return edge; + return new AssociationOrLinkPartEdge(source, target, targetEnd, diagram, assoc, link); } /** @@ -375,8 +374,7 @@ public static AssociationOrLinkPartEdge create(PlaceableNode source, public static AssociationOrLinkPartEdge create(PlaceableNode source, PlaceableNode target, String name, MAssociationEnd targetEnd, DiagramView diagram, MAssociation assoc, MLink link) { - AssociationOrLinkPartEdge edge = new AssociationOrLinkPartEdge(source, target, name, targetEnd, diagram, assoc, link); - return edge; + return new AssociationOrLinkPartEdge(source, target, name, targetEnd, diagram, assoc, link); } @Override diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index e706bfee3..ca9d107e1 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -32,7 +32,6 @@ import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.geom.Point2D; @@ -43,7 +42,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -150,12 +148,17 @@ public ObjectDiagramData() { } /** - * @param link - * @return + * Checks whether this diagram data contains the given link. + * + * @param link the link to test + * @return true if this data contains an edge or node representing the link */ public boolean containsLink(MLink link) { - return fBinaryLinkToEdgeMap.containsKey(link) || fNaryLinkToDiamondNodeMap.containsKey(link) - || fLinkObjectToNodeEdge.containsKey(link); + boolean has = fBinaryLinkToEdgeMap.containsKey(link) || fNaryLinkToDiamondNodeMap.containsKey(link); + if (!has && link instanceof MLinkObject) { + has = fLinkObjectToNodeEdge.containsKey((MLinkObject) link); + } + return has; } @Override @@ -188,6 +191,7 @@ public Set getEdges() { * * @param target the target ObjectDiagramData to copy the data into */ + @SuppressWarnings("unused") public void copyTo(ObjectDiagramData target) { target.fBinaryLinkToEdgeMap.putAll(this.fBinaryLinkToEdgeMap); target.fHalfLinkToEdgeMap.putAll(this.fHalfLinkToEdgeMap); @@ -208,11 +212,25 @@ public void clear() { } // Accessors to preserve encapsulation - public Map getObjectToNodeMap() { return fObjectToNodeMap; } - public Map getBinaryLinkToEdgeMap() { return fBinaryLinkToEdgeMap; } - public Map getNaryLinkToDiamondNodeMap() { return fNaryLinkToDiamondNodeMap; } - public Map> getHalfLinkToEdgeMap() { return fHalfLinkToEdgeMap; } - public Map getLinkObjectToNodeEdge() { return fLinkObjectToNodeEdge; } + public Map getObjectToNodeMap() { + return fObjectToNodeMap; + } + + public Map getBinaryLinkToEdgeMap() { + return fBinaryLinkToEdgeMap; + } + + public Map getNaryLinkToDiamondNodeMap() { + return fNaryLinkToDiamondNodeMap; + } + + public Map> getHalfLinkToEdgeMap() { + return fHalfLinkToEdgeMap; + } + + public Map getLinkObjectToNodeEdge() { + return fLinkObjectToNodeEdge; + } } protected final ObjectDiagramData visibleData = new ObjectDiagramData(); @@ -225,7 +243,7 @@ public void clear() { * The position of the next object node. This is either set to a random * value or to a specific position when an object is created by drag & drop. */ - protected Point2D.Double nextNodePosition = new Point2D.Double(); + protected Point2D.Double nextNodePosition = new Point2D.Double(); /** * Last position of deleted nodes and links. In case of restoration, the @@ -235,12 +253,13 @@ public void clear() { private final Map lastKnownNodePositions = new WeakHashMap<>(); private final Map lastKnownLinkPositions = new WeakHashMap<>(); - protected final ShowObjectPropertiesViewMouseListener showObjectPropertiesViewMouseListener = new ShowObjectPropertiesViewMouseListener(); + // show object properties listener is attached inline in constructor (no field required) private final ObjectSelection fSelection; protected final DiagramInputHandling inputHandling; + @SuppressWarnings("unused") private static boolean javaFxCall = false; /** @@ -271,7 +290,18 @@ protected NewObjectDiagram(NewObjectDiagramView parent, PrintWriter log, ObjDiag fParent.addKeyListener(inputHandling); addMouseListener(inputHandling); - addMouseListener(showObjectPropertiesViewMouseListener); + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + PlaceableNode pickedObjectNode = findNode(e.getX(), e.getY()); + if (pickedObjectNode instanceof ObjectNode on) { + ObjectPropertiesView v = MainWindow.instance().showObjectPropertiesView(); + v.selectObject(on.object().name()); + } + } + } + }); addComponentListener(new ComponentAdapter() { public void componentResized(ComponentEvent e) { @@ -288,10 +318,6 @@ public ObjDiagramOptions getOptions() { return (ObjDiagramOptions) super.getOptions(); } - public ObjectSelection getObjectSelection() { - return this.fSelection; - } - /** * Displays objects of the selected class in the modelbrowser. */ @@ -305,28 +331,34 @@ public void stateChanged(HighlightChangeEvent e) { boolean allEdgesSelected = true; // elem is an association - if (elem instanceof MAssociation) { - MAssociation assoc = (MAssociation) elem; + if (elem instanceof MAssociation assoc) { int size = assoc.associationEnds().size(); Set links = fParent.system().state().linksOfAssociation(assoc).links(); - EdgeBase eb; + EdgeBase ed; if (size == 2) { for (MLink link : links) { - eb = visibleData.getBinaryLinkToEdgeMap().get(link); if (elem instanceof MAssociationClass) { - eb = visibleData.getLinkObjectToNodeEdge().get(link); + if (link instanceof MLinkObject) { + ed = visibleData.getLinkObjectToNodeEdge().get((MLinkObject) link); + } else { + ed = visibleData.getBinaryLinkToEdgeMap().get(link); + } + } else { + ed = visibleData.getBinaryLinkToEdgeMap().get(link); } - edges.add(eb); + edges.add(ed); } } else { for (MLink link : links) { edges.addAll(visibleData.getHalfLinkToEdgeMap().getOrDefault(link, Collections.emptyList())); if (elem instanceof MAssociationClass) { - eb = visibleData.getLinkObjectToNodeEdge().get(link); - edges.add(eb); + if (link instanceof MLinkObject) { + ed = visibleData.getLinkObjectToNodeEdge().get((MLinkObject) link); + edges.add(ed); + } } } } @@ -386,7 +418,7 @@ public void hideAll() { * Hides all currently visible links. The diagram is not repainted! */ public void hideAllLinks() { - Set links = new HashSet<>(this.visibleData.getBinaryLinkToEdgeMap().keySet()); + Set links = new HashSet<>(this.visibleData.getBinaryLinkToEdgeMap().keySet()); for (MLink e : links) { hideBinaryLink(e); @@ -447,9 +479,8 @@ public void addObject(MObject obj) { /** * Shows an already hidden object again - * - * @param obj - * The object to show + * + * @param obj The object to show */ public void showObject(MObject obj) { if (visibleData.getObjectToNodeMap().containsKey(obj)) @@ -502,17 +533,16 @@ public void moveObjectNode(MObject obj, int x, int y) { /** * Hides an object in the diagram - * - * @param obj - * The MObject to hide + * + * @param obj The MObject to hide */ public void hideObject(MObject obj) { // a hidden object should no longer be selected ObjectNode removedNode = visibleData.getObjectToNodeMap().get(obj); - if(removedNode!=null) { + if (removedNode != null) { fNodeSelection.remove(removedNode); } - + showOrHideObjectNode(obj, false); // Hide all links the object participates in @@ -526,8 +556,7 @@ public void hideObject(MObject obj) { MLinkSet links = fParent.system().state().linksOfAssociation(assoc); // TODO: Not very fast! for (MLink link : links.links()) { - if (link.linkedObjects().contains(obj) - || (link instanceof MLinkObject && ((MLinkObject) link).equals(obj))) { + if (link.linkedObjects().contains(obj) || (link instanceof MLinkObject && link.equals(obj))) { hideLink(link); } } @@ -597,85 +626,11 @@ public void addLink(MLink link) { } } - protected void addBinaryLink(MLink link) { - MAssociation assoc = link.association(); - - MLinkEnd linkEnd1 = link.linkEnd(assoc.associationEnds().get(0)); - MLinkEnd linkEnd2 = link.linkEnd(assoc.associationEnds().get(1)); - - MObject obj1 = linkEnd1.object(); - MObject obj2 = linkEnd2.object(); - // TODO: Create link edge factory. - - // object link - if (link instanceof MLinkObject) { - BinaryAssociationClassOrObject e = BinaryAssociationClassOrObject.create( - visibleData.getObjectToNodeMap().get(obj1), visibleData.getObjectToNodeMap().get(obj2), - linkEnd1, linkEnd2, visibleData.getObjectToNodeMap().get(link), this, - link); - - if (lastKnownLinkPositions.containsKey(link)) { - e.initialize(); - visibleData.getObjectToNodeMap().get(link).setStrategy(lastKnownLinkPositions.get(link)); - lastKnownLinkPositions.remove(link); - fGraph.addInitializedEdge(e); - } else { - fGraph.addEdge(e); - } - visibleData.getLinkObjectToNodeEdge().put((MLinkObject) link, e); - fLayouter = null; - } else { - // binary link - boolean isHidden = false; - ObjectNode node1; - ObjectNode node2; - - if (visibleData.getObjectToNodeMap().containsKey(obj1)) { - node1 = visibleData.getObjectToNodeMap().get(obj1); - } else { - node1 = hiddenData.getObjectToNodeMap().get(obj1); - isHidden = true; - } - - if (visibleData.getObjectToNodeMap().containsKey(obj2)) { - node2 = visibleData.getObjectToNodeMap().get(obj2); - } else { - node2 = hiddenData.getObjectToNodeMap().get(obj2); - isHidden = true; - } - - BinaryAssociationOrLinkEdge e = createBinaryAssociationOrLinkEdge(node1, node2, linkEnd1, - linkEnd2, this, link); - - if (link.isVirtual()) { - e.setDashed(true); - } - - if (isHidden) { - hiddenData.getBinaryLinkToEdgeMap().put(link, e); - } else { - fGraph.addEdge(e); - visibleData.getBinaryLinkToEdgeMap().put(link, e); - fLayouter = null; - } - } - } - - /** - * This part is a separate method for easier inheritance. - * - * @author Andreas Kaestner - */ - protected BinaryAssociationOrLinkEdge createBinaryAssociationOrLinkEdge(PlaceableNode source, PlaceableNode target, - MLinkEnd sourceEnd, MLinkEnd targetEnd, NewObjectDiagram diagram, MLink link) { - return BinaryAssociationOrLinkEdge.create(source, target, sourceEnd, targetEnd, diagram, link); - } - protected void addNAryLink(MLink link) { getRandomNextPosition(); - + List linkedObjectNodes = new ArrayList<>(); - for(MObject linkedObject : link.linkedObjects()) { + for (MObject linkedObject : link.linkedObjects()) { linkedObjectNodes.add(visibleData.getObjectToNodeMap().get(linkedObject)); } @@ -709,12 +664,19 @@ protected void addNAryLink(MLink link) { fGraph.addEdge(e); halfEdges.add(e); - edgeIds.add(linkEnd.associationEnd().nameAsRolename()); + edgeIds.add(linkEnd.associationEnd().nameAsRolename()); } - if (visibleData.getLinkObjectToNodeEdge().get(link) != null) { - halfEdges.add(visibleData.getLinkObjectToNodeEdge().get(link)); - edgeIds.add(((MLinkObject) link).name()); + // If there is an associated link-object edge, add it once (avoid duplicate map access) + { + EdgeBase linkObjEdge = null; + if (link instanceof MLinkObject) { + linkObjEdge = visibleData.getLinkObjectToNodeEdge().get((MLinkObject) link); + } + if (linkObjEdge != null) { + halfEdges.add(linkObjEdge); + edgeIds.add(((MLinkObject) link).name()); + } } node.setHalfEdges(halfEdges, edgeIds); @@ -725,8 +687,8 @@ protected void addNAryLink(MLink link) { /** * Show one link. The diagram is not repainted! - * - * @param link + * + * @param link the link to show */ public void showLink(MLink link) { if (visibleData.containsLink(link)) @@ -752,8 +714,8 @@ public void showLink(MLink link) { /** * Hide one link. The diagram is not repainted! - * - * @param link + * + * @param link the link to hide */ public void hideLink(MLink link) { if (hiddenData.containsLink(link)) @@ -793,13 +755,13 @@ protected void showOrHideBinaryLink(MLink link, boolean show) { // object link if (link instanceof MLinkObject) { - EdgeBase e = source.getLinkObjectToNodeEdge().get(link); + EdgeBase e = source.getLinkObjectToNodeEdge().get((MLinkObject) link); if (show && e != null) fGraph.addInitializedEdge(e); else if (e != null) fGraph.removeEdge(e); - source.getLinkObjectToNodeEdge().remove(link); + source.getLinkObjectToNodeEdge().remove((MLinkObject) link); target.getLinkObjectToNodeEdge().put((MLinkObject) link, e); fLayouter = null; } else { @@ -820,22 +782,22 @@ protected void showOrHideNAryLink(MLink link, boolean show) { ObjectDiagramData source = (show ? hiddenData : visibleData); ObjectDiagramData target = (show ? visibleData : hiddenData); - DiamondNode node = source.fNaryLinkToDiamondNodeMap.get(link); - if (show){ - if (node == null){ - node = target.fNaryLinkToDiamondNodeMap.get(link); + DiamondNode node = source.getNaryLinkToDiamondNodeMap().get(link); + if (show) { + if (node == null) { + node = target.getNaryLinkToDiamondNodeMap().get(link); } fGraph.add(node); } else { fGraph.remove(node); } - target.fNaryLinkToDiamondNodeMap.put(link, node); - source.fNaryLinkToDiamondNodeMap.remove(link); - + target.getNaryLinkToDiamondNodeMap().put(link, node); + source.getNaryLinkToDiamondNodeMap().remove(link); + // connected to an "object link" if (link instanceof MLinkObject) { - EdgeBase e = source.fLinkObjectToNodeEdge.get(link); + EdgeBase e = source.getLinkObjectToNodeEdge().get((MLinkObject) link); if (e != null) { if (show) @@ -843,13 +805,13 @@ protected void showOrHideNAryLink(MLink link, boolean show) { else fGraph.removeEdge(e); - source.fLinkObjectToNodeEdge.remove(link); - target.fLinkObjectToNodeEdge.put((MLinkObject) link, e); + source.getLinkObjectToNodeEdge().remove((MLinkObject) link); + target.getLinkObjectToNodeEdge().put((MLinkObject) link, e); fLayouter = null; } } - List halfEdges = source.fHalfLinkToEdgeMap.get(link); + List halfEdges = source.getHalfLinkToEdgeMap().get(link); if (halfEdges != null) { for (EdgeBase edge : halfEdges) { @@ -859,26 +821,26 @@ protected void showOrHideNAryLink(MLink link, boolean show) { fGraph.removeEdge(edge); } - source.fHalfLinkToEdgeMap.remove(link); - target.fHalfLinkToEdgeMap.put(link, halfEdges); + source.getHalfLinkToEdgeMap().remove(link); + target.getHalfLinkToEdgeMap().put(link, halfEdges); } fLayouter = null; } /** - * Removes a link from the diagram. + * Deletes a link from the diagram. */ public void deleteLink(MLink link) { if (link.linkEnds().size() == 2) { - EdgeBase e = null; + EdgeBase e; // initialize later based on visibility boolean isVisible; boolean isLinkObject = link instanceof MLinkObject; ObjectDiagramData data; if (isLinkObject) { - isVisible = visibleData.getLinkObjectToNodeEdge().containsKey(link); + isVisible = visibleData.getLinkObjectToNodeEdge().containsKey((MLinkObject) link); data = isVisible ? visibleData : hiddenData; - e = data.getLinkObjectToNodeEdge().get(link); + e = data.getLinkObjectToNodeEdge().get((MLinkObject) link); } else { isVisible = visibleData.getBinaryLinkToEdgeMap().containsKey(link); data = isVisible ? visibleData : hiddenData; @@ -890,14 +852,14 @@ public void deleteLink(MLink link) { } if (isLinkObject) { - BinaryAssociationClassOrObject edge = (BinaryAssociationClassOrObject) data.getLinkObjectToNodeEdge().get(link); + BinaryAssociationClassOrObject edge = (BinaryAssociationClassOrObject) data.getLinkObjectToNodeEdge().get((MLinkObject) link); if (edge != null) { PlaceableNode objectNode = edge.getClassOrObjectNode(); lastKnownLinkPositions.put(link, objectNode.getStrategy()); } data.getBinaryLinkToEdgeMap().remove(link); - data.getLinkObjectToNodeEdge().remove(link); + data.getLinkObjectToNodeEdge().remove((MLinkObject) link); } else { data.getBinaryLinkToEdgeMap().remove(link); } @@ -930,12 +892,12 @@ public void deleteLink(MLink link) { n.dispose(); if (link instanceof MLinkObject) { - EdgeBase edge = data.getLinkObjectToNodeEdge().get(link); + EdgeBase edge = data.getLinkObjectToNodeEdge().get((MLinkObject) link); if (edge != null) { lastKnownLinkPositions.put(link, ((NAryAssociationClassOrObjectEdge) edge).getClassOrLinkObjectNode().getStrategy()); fGraph.removeEdge(edge); - data.getLinkObjectToNodeEdge().remove(link); + data.getLinkObjectToNodeEdge().remove((MLinkObject) link); edge.dispose(); } } @@ -944,13 +906,15 @@ public void deleteLink(MLink link) { /** * Forces the object node to update its content. - * - * @param obj + * + * @param obj the MInstance whose node should be refreshed */ public void updateObject(MInstance obj) { - ObjectNode node = visibleData.getObjectToNodeMap().get(obj); - if (node != null) + // Use computeIfPresent with an explicit cast of the key to the Map's key type (MObject) + visibleData.getObjectToNodeMap().computeIfPresent((MObject) obj, (k, node) -> { invalidateNode(node); + return node; // keep the existing mapping + }); } /** @@ -1030,7 +994,8 @@ public void actionPerformed(ActionEvent e) { /** * Show properties of objects */ - class ActionShowProperties extends AbstractAction { + @SuppressWarnings("unused") + static class ActionShowProperties extends AbstractAction { private final MObject fObject; ActionShowProperties(String text, MObject object) { @@ -1039,8 +1004,8 @@ class ActionShowProperties extends AbstractAction { } public void actionPerformed(ActionEvent e) { - if (MainWindow.getJavaFxCall()){ - Platform.runLater(()->{ + if (MainWindow.getJavaFxCall()) { + Platform.runLater(() -> { // to create an instance of a SwingNode, which is used to hold the Swing-Components SwingNode swingNode = new SwingNode(); @@ -1069,22 +1034,6 @@ public void actionPerformed(ActionEvent e) { } } - private class ShowObjectPropertiesViewMouseListener extends MouseAdapter { - - @Override - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() == 2) { - // mouse over node? - PlaceableNode pickedObjectNode = findNode(e.getX(), e.getY()); - if (pickedObjectNode instanceof ObjectNode) { - ObjectNode obj = (ObjectNode) pickedObjectNode; - ObjectPropertiesView v = MainWindow.instance().showObjectPropertiesView(); - v.selectObject(obj.object().name()); - } - } - } - } - /** * Creates and shows popup menu if mouse event is the trigger for popups. */ @@ -1111,8 +1060,7 @@ protected PopupMenuInfo unionOfPopUpMenu() { } for (EdgeBase selectedEdge : fEdgeSelection) { - if (selectedEdge instanceof LinkEdge) { - LinkEdge aEdge = (LinkEdge) selectedEdge; + if (selectedEdge instanceof LinkEdge aEdge) { MLink link = aEdge.getLink(); selectedLinks.add(link); selectedObjectsOfAssociation.addAll(link.linkedObjects()); @@ -1125,7 +1073,7 @@ protected PopupMenuInfo unionOfPopUpMenu() { // This text is reused often String selectedObjectsText = null; if (selectedObjects.size() == 1) { - selectedObjectsText = "'" + selectedObjects.get(0).name() + "'"; + selectedObjectsText = "'" + exactlyOne(selectedObjects).name() + "'"; } else if (selectedObjects.size() > 1) { selectedObjectsText = selectedObjects.size() + " objects"; } @@ -1134,8 +1082,8 @@ protected PopupMenuInfo unionOfPopUpMenu() { // A single object can be edited if (selectedObjects.size() == 1) { popupMenu.insert( - new ActionShowProperties("Edit properties of " + selectedObjectsText, selectedObjects.get(0)), - pos++); + new ActionShowProperties("Edit properties of " + selectedObjectsText, exactlyOne(selectedObjects)), + pos++); } // A single object or multiple objects can be deleted. @@ -1230,22 +1178,18 @@ protected PopupMenuInfo unionOfPopUpMenu() { } // New Action for Hide - popupMenu.insert(new AbstractAction(labelHide) { - - @Override - public void actionPerformed(ActionEvent arg0) { - if (!selectedLinks.isEmpty()) { - selectedLinks.forEach(NewObjectDiagram.this::hideLink); - } - if (!selectedObjects.isEmpty()) { - selectedObjects.forEach(NewObjectDiagram.this::hideObject); - } - repaint(); + popupMenu.insert(createAction(labelHide, arg0 -> { + if (!selectedLinks.isEmpty()) { + selectedLinks.forEach(NewObjectDiagram.this::hideLink); } - }, pos++); + if (!selectedObjects.isEmpty()) { + selectedObjects.forEach(NewObjectDiagram.this::hideObject); + } + repaint(); + }), pos++); // new Action for crop - Set objectsToHide = new HashSet<>(selectedObjects); + Set objectsToHide = new HashSet<>(selectedObjects); selectedLinks.forEach(link -> { if (link instanceof MLinkObject) { objectsToHide.add((MLinkObject) link); @@ -1254,132 +1198,83 @@ public void actionPerformed(ActionEvent arg0) { } }); - final String label = labelCrop; - popupMenu.insert(new AbstractAction(labelCrop) { - @Override - public void actionPerformed(ActionEvent e) { - getAction(label, getNoneSelectedNodes(objectsToHide)).actionPerformed(e); - } - }, pos++); + final String labelCropFinal = labelCrop; // ensure effectively final + popupMenu.insert(createAction(labelCrop, e -> getAction(labelCropFinal, getNoneSelectedNodes(objectsToHide)).actionPerformed(e)), pos++); - // new Action for grey in/out + // new Action for gray in/out (single) if (selectedObjects.size() == 1) { - MObject obj = selectedObjects.iterator().next(); - if (visibleData.getObjectToNodeMap().containsKey(obj)) { - ObjectNode node = visibleData.getObjectToNodeMap().get(obj); - String labelGreyed = node.isGreyed() ? "Grey in" : "Grey out"; - - popupMenu.insert(new AbstractAction(labelGreyed + " " + node.name()) { - @Override - public void actionPerformed(ActionEvent e) { - node.setGreyed(!node.isGreyed()); - repaint(); - } - }, pos++); + MObject obj = exactlyOne(selectedObjects); + ObjectNode node = visibleData.getObjectToNodeMap().get(obj); + if (node != null) { + String labelGreyed = node.isGreyed() ? "Gray in" : "Gray out"; + + popupMenu.insert(createAction(labelGreyed + " " + node.name(), e -> { + node.setGreyed(!node.isGreyed()); + repaint(); + }), pos++); } } else if (selectedObjects.size() > 1) { Set objToGreyIn = new HashSet<>(); - selectedObjects.stream().filter(obj -> visibleData.getObjectToNodeMap().get(obj).isGreyed()) - .forEach(obj -> objToGreyIn.add(visibleData.getObjectToNodeMap().get(obj))); - Set objToGreyOut = new HashSet<>(); - selectedObjects.stream().filter(obj -> !visibleData.getObjectToNodeMap().get(obj).isGreyed()) - .forEach(obj -> objToGreyOut.add(visibleData.getObjectToNodeMap().get(obj))); + for (MObject so : selectedObjects) { + ObjectNode n = visibleData.getObjectToNodeMap().get(so); + if (n != null) { + if (n.isGreyed()) objToGreyIn.add(n); + else objToGreyOut.add(n); + } + } + // gray in if (!objToGreyIn.isEmpty()) { - popupMenu.insert(new AbstractAction("Grey in " + objToGreyIn.size() + " elements") { - - @Override - public void actionPerformed(ActionEvent arg0) { - objToGreyIn.forEach(obj -> obj.setGreyed(false)); - repaint(); - } - }, pos++); + popupMenu.insert(createAction("Gray in " + objToGreyIn.size() + " elements", arg0 -> { + objToGreyIn.forEach(n -> n.setGreyed(false)); + repaint(); + }), pos++); } - // Action for grey out more elements + // gray out if (!objToGreyOut.isEmpty()) { - popupMenu.insert(new AbstractAction("Grey out " + objToGreyOut.size() + " elements") { - - @Override - public void actionPerformed(ActionEvent arg0) { - objToGreyOut.forEach(obj -> obj.setGreyed(true)); - repaint(); - } - }, pos++); + popupMenu.insert(createAction("Gray out " + objToGreyOut.size() + " elements", arg0 -> { + objToGreyOut.forEach(n -> n.setGreyed(true)); + repaint(); + }), pos++); } } - popupMenu.insert(new JSeparator(), pos++); } + popupMenu.insert(new JSeparator(), pos++); - final JMenu showHideCrop = new JMenu("Show/hide/crop objects"); + final JMenu showProtocolStateMachine = new JMenu("Show protocol state machine..."); + showProtocolStateMachine.setEnabled(false); + popupMenu.insert(showProtocolStateMachine, pos++); - if (!selectedObjects.isEmpty()) { - showHideCrop.add(fSelection.getSelectedObjectPathView("By path length...", selectedObjectsSet)); - } + if (selectedObjects.size() == 1) { + final MObject obj = exactlyOne(selectedObjects); - showHideCrop.add(fSelection.getSelectionWithOCLViewAction()); - showHideCrop.add(fSelection.getSelectionObjectView()); + List sortedPSMs = new LinkedList<>( + obj.cls().getAllOwnedProtocolStateMachines()); + sortedPSMs.sort(new MNamedElementComparator()); - popupMenu.insert(showHideCrop, pos++); + for (MProtocolStateMachine psm : sortedPSMs) { + showProtocolStateMachine.setEnabled(true); + final JMenuItem showGivenPSM = new JMenuItem(psm.name()); + showGivenPSM.addActionListener(new ActionListener() { + private MProtocolStateMachine sm; - if (!fGraph.isEmpty() || !hiddenData.getObjectToNodeMap().isEmpty()) { - if (!fGraph.isEmpty()) { - popupMenu.insert(fSelection.getSubMenuHideObject(), pos++); - } + public void actionPerformed(ActionEvent ev) { + MainWindow.instance().showStateMachineView(sm, obj); + } - if (!hiddenData.getObjectToNodeMap().isEmpty()) { - popupMenu.insert(fSelection.getSubMenuShowObject(), pos++); + public ActionListener setStateMachine(MProtocolStateMachine sm) { + this.sm = sm; + return this; + } + }.setStateMachine(psm)); + showProtocolStateMachine.add(showGivenPSM); } } - if (!visibleData.getBinaryLinkToEdgeMap().isEmpty() || !visibleData.getHalfLinkToEdgeMap().isEmpty() - || !visibleData.getLinkObjectToNodeEdge().isEmpty() - || !visibleData.getNaryLinkToDiamondNodeMap().isEmpty()) { - popupMenu.insert(fSelection.getSubMenuHideLinks(), pos++); - } - - if (!hiddenData.getBinaryLinkToEdgeMap().isEmpty() || !hiddenData.getHalfLinkToEdgeMap().isEmpty() - || !hiddenData.getLinkObjectToNodeEdge().isEmpty() || !hiddenData.getNaryLinkToDiamondNodeMap().isEmpty()) { - popupMenu.insert(fSelection.getSubMenuShowLinks(), pos++); - } - popupMenu.insert(new JSeparator(), pos++); - if (!selectedObjects.isEmpty()) { - final JMenu showProtocolStateMachine = new JMenu("Show protocol state machine..."); - showProtocolStateMachine.setEnabled(false); - popupMenu.insert(showProtocolStateMachine, pos++); - - if (selectedObjects.size() == 1) { - final MObject obj = exactlyOne(selectedObjects); - - List sortedPSMs = new LinkedList<>( - obj.cls().getAllOwnedProtocolStateMachines()); - sortedPSMs.sort(new MNamedElementComparator()); - - for (MProtocolStateMachine psm : sortedPSMs) { - showProtocolStateMachine.setEnabled(true); - final JMenuItem showGivenPSM = new JMenuItem(psm.name()); - showGivenPSM.addActionListener(new ActionListener() { - protected MProtocolStateMachine sm; - - public void actionPerformed(ActionEvent ev) { - MainWindow.instance().showStateMachineView(sm, obj); - } - - public ActionListener setStateMachine(MProtocolStateMachine sm, MObject instance) { - this.sm = sm; - return this; - } - }.setStateMachine(psm, obj)); - showProtocolStateMachine.add(showGivenPSM); - } - } - - popupMenu.insert(new JSeparator(), pos++); - } - final JCheckBoxMenuItem showStates = new JCheckBoxMenuItem("Show states", getOptions().isShowStates()); showStates.addItemListener(ev -> { getOptions().setShowStates(ev.getStateChange() == ItemEvent.SELECTED); @@ -1393,16 +1288,13 @@ public ActionListener setStateMachine(MProtocolStateMachine sm, MObject instance /** * Finds all nodes which are not selected. - * - * @param selectedNodes - * Nodes which are selected at this point in the diagram. + * + * @param selectedNodes Nodes which are selected at this point in the diagram. * @return A HashSet of the none selected objects in the diagram. */ private Set getNoneSelectedNodes(Set selectedNodes) { Set noneSelectedNodes = new HashSet<>(); - Iterator it = fGraph.iterator(); - while (it.hasNext()) { - PlaceableNode o = it.next(); + for (PlaceableNode o : fGraph) { if (o instanceof ObjectNode) { MObject obj = ((ObjectNode) o).object(); if (!selectedNodes.contains(obj)) { @@ -1460,11 +1352,11 @@ private void displayObjectInfo(MObject obj, MouseEvent e) { } /** - * + * * Accepts a drag of a class from the ModelBrowser. A new object of this * class will be created. - * - * @param dtde + * + * @param dtde the drop event provided by the DnD subsystem */ public void dropObjectFromModelBrowser(DropTargetDropEvent dtde) { @@ -1508,9 +1400,8 @@ public void dropObjectFromModelBrowser(DropTargetDropEvent dtde) { /** * Checks if the object info window should be displayed. - * - * @param e - * MouseEvent + * + * @param e MouseEvent */ public void mayBeShowObjectInfo(MouseEvent e) { if (fNodeSelection.size() == 1) { @@ -1544,11 +1435,11 @@ private int[] radixConversion(int number, int base, int maxDigits) { private boolean isCompleteObjectCombination(int[] c, int base) { for (int i = 0; i < base; ++i) { boolean found = false; - for (int j = 0; j < c.length; ++j) { - if (c[j] == i) { - found = true; - break; - } + for (int v : c) { + if (v == i) { + found = true; + break; + } } if (!found) return false; @@ -1585,15 +1476,15 @@ protected void storePlacementInfos(PersistHelper helper, Element root, boolean v n.storePlacementInfo(helper, root, !visible); } - for (PlaceableNode n : data.fNaryLinkToDiamondNodeMap.values()) { + for (PlaceableNode n : data.getNaryLinkToDiamondNodeMap().values()) { n.storePlacementInfo(helper, root, !visible); } - for (EdgeBase e : data.fBinaryLinkToEdgeMap.values()) { + for (EdgeBase e : data.getBinaryLinkToEdgeMap().values()) { e.storePlacementInfo(helper, root, !visible); } - for (EdgeBase e : data.fLinkObjectToNodeEdge.values()) { + for (EdgeBase e : data.getLinkObjectToNodeEdge().values()) { e.storePlacementInfo(helper, root, !visible); } } @@ -1601,260 +1492,192 @@ protected void storePlacementInfos(PersistHelper helper, Element root, boolean v @Override public void restorePlacementInfos(PersistHelper helper, int version) { if (version < 12) return; - + Set hiddenObjects = new HashSet<>(); + + // delegate to smaller, well-scoped helpers + restoreBinaryEdges(helper, version, hiddenObjects); + restoreNodeEdges(helper, version, hiddenObjects); + restoreDiamondNodes(helper, version, hiddenObjects); + + // Hide elements collected during restore + hideElementsInDiagram(hiddenObjects); + } + + // Helper: restore binary association edges placement info + @SuppressWarnings("unused") + private void restoreBinaryEdges(PersistHelper helper, int version, Set hiddenObjects) { AutoPilot ap = new AutoPilot(helper.getNav()); - - // First restore edges to get possible new nodes, then nodes helper.getNav().push(); - try { - // Restore edges ap.selectXPath("./edge[@type='BinaryEdge']"); - try { - while (ap.evalXPath() != -1) { + while (ap.evalXPath() != -1) { String name = helper.getElementStringValue("name"); MAssociation assoc = fParent.system().model().getAssociation(name); String sourceObjectName = helper.getElementStringValue("source"); String targetObjectName = helper.getElementStringValue("target"); - + MObject sourceObject = fParent.system().state().objectByName(sourceObjectName); MObject targetObject = fParent.system().state().objectByName(targetObjectName); - + // Could be deleted if (assoc != null && sourceObject != null && targetObject != null) { MLink link; - if (assoc.hasQualifiedEnds()) { String linkValue = helper.getElementStringValue("linkValue"); link = getLinkByValue(assoc, Arrays.asList(sourceObject, targetObject), linkValue); } else { - // No qualifier values are present. - link = fParent - .system() - .state() - .linkBetweenObjects(assoc, - Arrays.asList(sourceObject, targetObject), - Collections.emptyList()); + link = fParent.system().state().linkBetweenObjects(assoc, Arrays.asList(sourceObject, targetObject), Collections.emptyList()); } - if (link != null) { BinaryAssociationOrLinkEdge edge = visibleData.getBinaryLinkToEdgeMap().get(link); - edge.restorePlacementInfo(helper, version); + if (edge != null) { + edge.restorePlacementInfo(helper, version); + } } } } - } catch (XPathEvalException e) { - fLog.append(e.getMessage()); - } catch (NavException e) { - fLog.append(e.getMessage()); + } catch (XPathEvalException | NavException e) { + if (fLog != null) fLog.println(e.getMessage()); + else System.err.println(e.getMessage()); } } catch (XPathParseException e) { - fLog.append(e.getMessage()); + if (fLog != null) fLog.println(e.getMessage()); + else System.err.println(e.getMessage()); + } finally { + ap.resetXPath(); + helper.getNav().pop(); } - ap.resetXPath(); - helper.getNav().pop(); - + } + + // Helper: restore node-edge (link objects / node edges) + @SuppressWarnings("unused") + private void restoreNodeEdges(PersistHelper helper, int version, Set hiddenObjects) { + AutoPilot ap = new AutoPilot(helper.getNav()); helper.getNav().push(); try { - // Restore edges ap.selectXPath("./edge[@type='NodeEdge']"); - try { - while(ap.evalXPath() != -1) { + while (ap.evalXPath() != -1) { String name = helper.getElementStringValue("name"); MAssociation assoc = fParent.system().model().getAssociation(name); String sourceObjectName = helper.getElementStringValue("source"); String targetObjectName = helper.getElementStringValue("target"); - + MObject sourceObject = fParent.system().state().objectByName(sourceObjectName); MObject targetObject = fParent.system().state().objectByName(targetObjectName); - + // Could be deleted if (assoc != null && sourceObject != null && targetObject != null) { MLink link; - if (assoc.hasQualifiedEnds()) { String linkValue = helper.getElementStringValue("linkValue"); link = getLinkByValue(assoc, Arrays.asList(sourceObject, targetObject), linkValue); } else { - // No qualifier values are present. - link = fParent - .system() - .state() - .linkBetweenObjects(assoc, - Arrays.asList(sourceObject, targetObject), - Collections.emptyList()); + link = fParent.system().state().linkBetweenObjects(assoc, Arrays.asList(sourceObject, targetObject), Collections.emptyList()); } - if (link != null) { - BinaryAssociationClassOrObject edge = (BinaryAssociationClassOrObject)visibleData.getLinkObjectToNodeEdge().get(link); - edge.restorePlacementInfo(helper, version); + if (link instanceof MLinkObject linkObj) { + EdgeBase tmp = visibleData.getLinkObjectToNodeEdge().get(linkObj); + if (tmp instanceof BinaryAssociationClassOrObject edge) { + edge.restorePlacementInfo(helper, version); + } + } } } } - } catch (XPathEvalException e) { - fLog.append(e.getMessage()); - } catch (NavException e) { - fLog.append(e.getMessage()); + } catch (XPathEvalException | NavException e) { + if (fLog != null) fLog.println(e.getMessage()); + else System.err.println(e.getMessage()); } } catch (XPathParseException e) { - fLog.append(e.getMessage()); + if (fLog != null) fLog.println(e.getMessage()); + else System.err.println(e.getMessage()); + } finally { + ap.resetXPath(); + helper.getNav().pop(); } - helper.getNav().pop(); - ap.resetXPath(); - + } + + // Helper: restore diamond nodes (n-ary links) + private void restoreDiamondNodes(PersistHelper helper, int version, Set hiddenObjects) { + AutoPilot ap = new AutoPilot(helper.getNav()); helper.getNav().push(); try { ap.selectXPath("./node[@type='Object']"); - try { - while(ap.evalXPath() != -1) { + while (ap.evalXPath() != -1) { String name = helper.getElementStringValue("name"); MObject obj = fParent.system().state().objectByName(name); - // Could be deleted if (obj != null) { ObjectNode node = visibleData.getObjectToNodeMap().get(obj); - node.restorePlacementInfo(helper, version); - if (isHidden(helper, version)) hiddenObjects.add(obj); + if (node != null) { + node.restorePlacementInfo(helper, version); + if (isHidden(helper, version)) hiddenObjects.add(obj); + } } } - } catch (XPathEvalException e) { - fLog.append(e.getMessage()); - } catch (NavException e) { - fLog.append(e.getMessage()); + } catch (XPathEvalException | NavException e) { + if (fLog != null) fLog.println(e.getMessage()); + else System.err.println(e.getMessage()); } } catch (XPathParseException e) { - fLog.append(e.getMessage()); + if (fLog != null) fLog.println(e.getMessage()); + else System.err.println(e.getMessage()); + } finally { + ap.resetXPath(); + helper.getNav().pop(); } - - helper.getNav().pop(); - ap.resetXPath(); - + + // now diamond nodes (separate xpath) + ap = new AutoPilot(helper.getNav()); helper.getNav().push(); try { - // Restore diamond nodes ap.selectXPath("./node[@type='DiamondNode']"); - try { while (ap.evalXPath() != -1) { String name = helper.getElementStringValue("name"); MAssociation assoc = fParent.system().model().getAssociation(name); - - // Renamed or deleted if (assoc == null) continue; - - // Get connected objects List connectedObjects = new LinkedList<>(); - if (!helper.toFirstChild("connectedNode")) - break; - + if (!helper.toFirstChild("connectedNode")) continue; String objectName = helper.getElementStringValue(); MObject obj = fParent.system().state().objectByName(objectName); - - if (obj != null) - connectedObjects.add(obj); - + if (obj != null) connectedObjects.add(obj); while (helper.toNextSibling("connectedNode")) { objectName = helper.getElementStringValue(); obj = fParent.system().state().objectByName(objectName); - - if (obj != null) { - connectedObjects.add(obj); - } + if (obj != null) connectedObjects.add(obj); } - - // Modified - if (assoc.associationEnds().size() != connectedObjects.size()) - continue; - - // n-ary links cannot be qualified therefore an empty list for the qualifer values is provided + if (assoc.associationEnds().size() != connectedObjects.size()) continue; MLink link = fParent.system().state().linkBetweenObjects(assoc, connectedObjects, Collections.emptyList()); - - // Could be deleted if (link != null) { - DiamondNode node = visibleData.fNaryLinkToDiamondNodeMap.get(link); - helper.toParent(); - node.restorePlacementInfo(helper, version); + DiamondNode node = visibleData.getNaryLinkToDiamondNodeMap().get(link); + if (node != null) { + helper.toParent(); + node.restorePlacementInfo(helper, version); + } } } - } catch (XPathEvalException e) { - fLog.append(e.getMessage()); - } catch (NavException e) { - fLog.append(e.getMessage()); + } catch (XPathEvalException | NavException e) { + if (fLog != null) fLog.println(e.getMessage()); + else System.err.println(e.getMessage()); } } catch (XPathParseException e) { - fLog.append(e.getMessage()); - } - helper.getNav().pop(); - ap.resetXPath(); - - // Hide elements - hideElementsInDiagram(hiddenObjects); - } - - protected MLink getLinkByValue(MAssociation assoc, List objects, String linkValue) { - Set links = fParent.system().state().linkBetweenObjects(assoc, objects); - if (links.size() == 1) { - return links.iterator().next(); - } else { - for (MLink aLink : links) { - if (aLink.toString().equals(linkValue)) { - return aLink; - } - } - } - return null; - } - - protected boolean isHidden(PersistHelper helper, int version) { - return helper.getElementBooleanValue(LayoutTags.HIDDEN); - } - - @Override - public Set getHiddenNodes() { - return new HashSet(hiddenData.getObjectToNodeMap().values()); - } - - @Override - public ObjectDiagramData getVisibleData() { - return visibleData; - } - - @Override - public DiagramData getHiddenData() { - return hiddenData; - } - - @Override - protected String getDefaultLayoutFileSuffix() { - // No default layout - return null; - } - - @Override - protected void onClosing() { - if (!javaFxCall) { - super.onClosing(); - } - fParent.getModelBrowser().removeHighlightChangeListener(this); - fParent.removeKeyListener(inputHandling); - ModelBrowserSorting.getInstance().removeSortChangeListener(this); - } - - @Override - public void stateChanged(SortChangeEvent e) { - for (ObjectNode n : this.visibleData.getObjectToNodeMap().values()) { - n.stateChanged(e); + if (fLog != null) fLog.println(e.getMessage()); + else System.err.println(e.getMessage()); + } finally { + ap.resetXPath(); + helper.getNav().pop(); } } /** * Hide link using name of link - * - * @param linkName - * @param links + * + * @param linkName the association (link) name to hide + * @param links the list of links to examine */ public void hideLink(String linkName, List links) { for (MLink link : links) { @@ -1867,9 +1690,9 @@ public void hideLink(String linkName, List links) { /** * Show link using name of link - * - * @param linkName - * @param links + * + * @param linkName the association (link) name to show + * @param links the list of links to examine */ public void showLink(String linkName, List links) { for (MLink link : links) { @@ -1880,14 +1703,14 @@ public void showLink(String linkName, List links) { } /** - * Map links to kind of assoziation. Used for show/hide-links-by-kind - * - * @return + * Map links to kind of association. Used for show/hide-links-by-kind + * + * @return a sorted map from kind label to links */ public TreeMap> mapLinksToKindOfAssociation() { Map> assocs = new HashMap<>(); final String derivedLinks = "Derived links"; - final String associationClass = "Linkobjects"; + final String associationClass = "Link objects"; final String nAryLinks = "N-Ary links"; final String reflexiveLinks = "Reflexive links"; final String binaryLinks = "Binary links"; @@ -1897,52 +1720,56 @@ public TreeMap> mapLinksToKindOfAssociation() { for (MAssociation assoc : fParent.system().model().associations()) { /* - * aggregationKind = 0, other + * aggregationKind = 0, other * aggregationKind = 1, aggreation * aggregationKind = 2, composition */ int kind = assoc.aggregationKind(); switch (kind) { - case 0: - Set links = fParent.system().state().linksOfAssociation(assoc).links(); - for (MLink link : links) { - if (link.association().isDerived() || link.association().isUnion()) { - assocs.computeIfAbsent(derivedLinks, k -> new ArrayList<>()).add(link); - } else if (MAssociationClassImpl.class.isInstance(link.association())) { - assocs.computeIfAbsent(associationClass, k -> new ArrayList<>()).add(link); - } else if (MAssociation.class.isInstance(link.association()) && link.linkEnds().size() > 2) { - assocs.computeIfAbsent(nAryLinks, k -> new ArrayList<>()).add(link); - } else if (MAssociation.class.isInstance(link.association()) - && link.association().associatedClasses().size() == 1) { - assocs.computeIfAbsent(reflexiveLinks, k -> new ArrayList<>()).add(link); - } else if (MAssociation.class.isInstance(link.association()) && link.linkedObjects().size() == 2 - && !link.linkedObjects().get(0).equals(link.linkedObjects().get(1))) { - assocs.computeIfAbsent(binaryLinks, k -> new ArrayList<>()).add(link); - } else { - System.err.println("ERROR: NO MATCH IN ASSOC-KIND"); - } + case 0: + Set links = fParent.system().state().linksOfAssociation(assoc).links(); + for (MLink link : links) { + MAssociation linkAssoc = link.association(); + if (linkAssoc == null) continue; + if (linkAssoc.isDerived() || linkAssoc.isUnion()) { + assocs.computeIfAbsent(derivedLinks, k -> new ArrayList<>()).add(link); + } else if (linkAssoc instanceof MAssociationClassImpl) { + assocs.computeIfAbsent(associationClass, k -> new ArrayList<>()).add(link); + } else if (linkAssoc.associationEnds().size() > 2) { + assocs.computeIfAbsent(nAryLinks, k -> new ArrayList<>()).add(link); + } else if (linkAssoc.associatedClasses().size() == 1) { + assocs.computeIfAbsent(reflexiveLinks, k -> new ArrayList<>()).add(link); + } else if (link.linkedObjects().size() == 2 && !link.linkedObjects().get(0).equals(link.linkedObjects().get(1))) { + assocs.computeIfAbsent(binaryLinks, k -> new ArrayList<>()).add(link); + } else { + if (fLog != null) { + fLog.println("ERROR: NO MATCH IN ASSOC-KIND"); + } else { + System.err.println("ERROR: NO MATCH IN ASSOC-KIND"); + } + } - } - break; - case 1: // Aggregation + } + break; + case 1: // Aggregation - // Get aggregations - Set aggregations = fParent.system().state().linksOfAssociation(assoc).links(); + // Get aggregations + Set aggregations = fParent.system().state().linksOfAssociation(assoc).links(); - for (MLink agg : aggregations) { - assocs.computeIfAbsent(aggregation, k -> new ArrayList<>()).add(agg); - } - break; + for (MLink agg : aggregations) { + assocs.computeIfAbsent(aggregation, k -> new ArrayList<>()).add(agg); + } + break; - case 2: // Composition + case 2: // Composition - // Get Compositions - Set compositions = fParent.system().state().linksOfAssociation(assoc).links(); + // Get Compositions + Set compositions = fParent.system().state().linksOfAssociation(assoc).links(); - for (MLink comp : compositions) { - assocs.computeIfAbsent(composition, k -> new ArrayList<>()).add(comp); - } - break; + for (MLink comp : compositions) { + assocs.computeIfAbsent(composition, k -> new ArrayList<>()).add(comp); + } + break; } } return new TreeMap<>(assocs); @@ -1951,8 +1778,8 @@ public TreeMap> mapLinksToKindOfAssociation() { /** * Hide all links of list links - * - * @param links + * + * @param links list of links to hide */ public void hideLink(List links) { for (MLink link : links) { @@ -1962,8 +1789,8 @@ public void hideLink(List links) { /** * Show all links of list links - * - * @param links + * + * @param links list of links to show */ public void showLink(List links) { for (MLink link : links) { @@ -1973,25 +1800,22 @@ public void showLink(List links) { /** * Check if a link is hidden - * - * @param link - * @return true, if link is hidden; else return false + * + * @param link the link instance to check + * @return true if the provided link is currently hidden; otherwise false */ public boolean isHidden(MLink link) { - if (hiddenData.getBinaryLinkToEdgeMap().containsKey(link) || hiddenData.getHalfLinkToEdgeMap().containsKey(link) - || hiddenData.getLinkObjectToNodeEdge().containsKey(link) - || hiddenData.getNaryLinkToDiamondNodeMap().containsKey(link)) { - return true; - } else { - return false; - } + return hiddenData.getBinaryLinkToEdgeMap().containsKey(link) + || hiddenData.getHalfLinkToEdgeMap().containsKey(link) + || (link instanceof MLinkObject && hiddenData.getLinkObjectToNodeEdge().containsKey((MLinkObject) link)) + || hiddenData.getNaryLinkToDiamondNodeMap().containsKey(link); } /** - * - * @param links - * @return 0, if all Links are hidden 1, if all links are shown 2, if there - * are hidden and shown links + * Determine whether the provided list of links is hidden, visible or mixed. + * + * @param links collection of links to evaluate + * @return 0 if all links are hidden, 1 if all links are shown, 2 if mixed, -1 if none present */ public int isHidden(List links) { boolean existHiddenLink = false; @@ -2017,4 +1841,165 @@ public static void setJavaFxCall(boolean javaFxCall) { NewObjectDiagram.javaFxCall = javaFxCall; } + @Override + public ObjectDiagramData getVisibleData() { + return visibleData; + } + + @Override + public ObjectDiagramData getHiddenData() { + return hiddenData; + } + + /** + * Restore helper to determine hidden state for items when restoring layout. + * Mirrors the implementation used in ClassDiagram to remain consistent across diagrams. + */ + @SuppressWarnings("unused") + protected boolean isHidden(PersistHelper helper, int version) { + // The 'version' parameter is reserved for future format-specific logic. + return helper.getElementBooleanValue(LayoutTags.HIDDEN); + } + + /** + * Finds a link for the given association that connects the provided objects and + * matches the serialized linkValue. This method reverses what BinaryAssociationOrLinkEdge.storeAdditionalInfo + * wrote using link.toString(). It prefers exact object-list match and the string representation. + */ + private MLink getLinkByValue(MAssociation assoc, List objects, String linkValue) { + if (assoc == null || objects == null || linkValue == null) { + return null; + } + + Set candidates = fParent.system().state().linksOfAssociation(assoc).links(); + for (MLink l : candidates) { + // first ensure the linked objects match the expected ordering/collection + List linked = l.linkedObjects(); + if (linked.size() == objects.size()) { + boolean sameObjects = true; + for (int i = 0; i < linked.size(); i++) { + if (!linked.get(i).equals(objects.get(i))) { + sameObjects = false; + break; + } + } + if (!sameObjects) continue; + + // compare the string representation stored by the edge + if (linkValue.equals(l.toString())) { + return l; + } + } + } + return null; + } + + @Override + public Set getHiddenNodes() { + return hiddenData.getNodes(); + } + + @Override + protected String getDefaultLayoutFileSuffix() { + // Use a dedicated suffix for object diagram default layouts (consistent with other diagrams) + return "_objdia.clt"; + } + + + @Override + public void stateChanged(SortChangeEvent e) { + for (ObjectNode n : this.visibleData.fObjectToNodeMap.values()) { + n.stateChanged(e); + } + } + + /** + * A kleine Helfermethode zum Erstellen von Actions mit weniger Boilerplate-Code. + * + * @param text Der Text der Action. + * @param listener Der ActionListener, der die Action ausführt. + * @return Die erstellte Action. + */ + private Action createAction(String text, ActionListener listener) { + return new AbstractAction(text) { + @Override + public void actionPerformed(ActionEvent e) { + listener.actionPerformed(e); + } + }; + } + + protected void addBinaryLink(MLink link) { + MAssociation assoc = link.association(); + + MLinkEnd linkEnd1 = link.linkEnd(assoc.associationEnds().get(0)); + MLinkEnd linkEnd2 = link.linkEnd(assoc.associationEnds().get(1)); + + MObject obj1 = linkEnd1.object(); + MObject obj2 = linkEnd2.object(); + + // object link + if (link instanceof MLinkObject) { + BinaryAssociationClassOrObject e = BinaryAssociationClassOrObject.create( + visibleData.getObjectToNodeMap().get(obj1), visibleData.getObjectToNodeMap().get(obj2), + linkEnd1, linkEnd2, visibleData.getObjectToNodeMap().get(link), this, + link); + + if (lastKnownLinkPositions.containsKey(link)) { + e.initialize(); + ObjectNode linkObjNode = visibleData.getObjectToNodeMap().get(link); + if (linkObjNode != null) { + linkObjNode.setStrategy(lastKnownLinkPositions.get(link)); + } + lastKnownLinkPositions.remove(link); + fGraph.addInitializedEdge(e); + } else { + fGraph.addEdge(e); + } + visibleData.getLinkObjectToNodeEdge().put((MLinkObject) link, e); + fLayouter = null; + } else { + // binary link + boolean isHidden = false; + ObjectNode node1; + ObjectNode node2; + + if (visibleData.getObjectToNodeMap().containsKey(obj1)) { + node1 = visibleData.getObjectToNodeMap().get(obj1); + } else { + node1 = hiddenData.getObjectToNodeMap().get(obj1); + isHidden = true; + } + + if (visibleData.getObjectToNodeMap().containsKey(obj2)) { + node2 = visibleData.getObjectToNodeMap().get(obj2); + } else { + node2 = hiddenData.getObjectToNodeMap().get(obj2); + isHidden = true; + } + + BinaryAssociationOrLinkEdge e = createBinaryAssociationOrLinkEdge(node1, node2, linkEnd1, + linkEnd2, this, link); + + if (link.isVirtual()) { + e.setDashed(true); + } + + if (isHidden) { + hiddenData.getBinaryLinkToEdgeMap().put(link, e); + } else { + fGraph.addEdge(e); + visibleData.getBinaryLinkToEdgeMap().put(link, e); + fLayouter = null; + } + } + } + + /** + * Factory hook for creating binary link edges. Kept as a protected method to allow easy overriding in subclasses. + */ + protected BinaryAssociationOrLinkEdge createBinaryAssociationOrLinkEdge(PlaceableNode source, PlaceableNode target, + MLinkEnd sourceEnd, MLinkEnd targetEnd, NewObjectDiagram diagram, MLink link) { + return BinaryAssociationOrLinkEdge.create(source, target, sourceEnd, targetEnd, diagram, link); + } } From 6b351e808e63eccc02525b402d3b4908932d5b67 Mon Sep 17 00:00:00 2001 From: ahmed Date: Thu, 12 Feb 2026 22:34:19 +0100 Subject: [PATCH 09/20] =?UTF-8?q?refactor(gui):=20NewObjectDiagram=20?= =?UTF-8?q?=E2=80=94=20cleanups=20&=20warnings=20fixes=20=C3=84nderungen:?= =?UTF-8?q?=20-=20Map-safety=20&=20Null-Checks=20=20=20-=20Ersetzte=20unsi?= =?UTF-8?q?chere=20Map.get()-Aufrufe=20durch=20computeIfPresent=20/=20null?= =?UTF-8?q?-checks.=20=20=20-=20Entfernte=20doppelte=20containsKey/get-Kom?= =?UTF-8?q?binationen.=20-=20Listener=20&=20Event-Handling=20=20=20-=20Ent?= =?UTF-8?q?fernt=20unbenutztes=20Feld/innere=20Klasse=20ShowObjectProperti?= =?UTF-8?q?esViewMouseListener.=20=20=20-=20Vereinfacht=20MouseListener=20?= =?UTF-8?q?mit=20Pattern=20Matching=20(instanceof).=20-=20Data=20&=20API?= =?UTF-8?q?=20=20=20-=20Vereinheitlichte=20Handhabung=20sichtbarer/verborg?= =?UTF-8?q?ener=20Daten=20via=20ObjectDiagramData-Accessoren.=20=20=20-=20?= =?UTF-8?q?getVisibleData/getHiddenData=20abgestimmt.=20=20=20-=20getDefau?= =?UTF-8?q?ltLayoutFileSuffix=20gesetzt.=20-=20Readability=20&=20Helpers?= =?UTF-8?q?=20=20=20-=20createAction=20Helper=20eingef=C3=BChrt,=20Boilerp?= =?UTF-8?q?late=20reduziert.=20=20=20-=20getLinkByValue=20implementiert=20?= =?UTF-8?q?(Restore/layouter=20Hilfsmethode).=20-=20Analyzer=20&=20Warning?= =?UTF-8?q?s=20=20=20-=20@SuppressWarnings(unused)=20wo=20sinnvoll=20(z.B.?= =?UTF-8?q?=20isHidden=20Persist-Helper=20Version).=20=20=20-=20Weitere=20?= =?UTF-8?q?Konsistenz-=20und=20Null-Sicherheits-Fixes.=20Keine=20API-Break?= =?UTF-8?q?ing=20=C3=84nderungen;=20low-risk=20Refactorings=20zur=20Verbes?= =?UTF-8?q?serung=20der=20Lesbarkeit=20und=20Analysehygiene.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- use-gui/src/main/java/module-info.java | 4 + .../edges/AssociationOrLinkPartEdge.java | 8 +- .../objectdiagram/NewObjectDiagram.java | 1041 ++++++++--------- 3 files changed, 520 insertions(+), 533 deletions(-) diff --git a/use-gui/src/main/java/module-info.java b/use-gui/src/main/java/module-info.java index 454e2590e..c073fda2a 100644 --- a/use-gui/src/main/java/module-info.java +++ b/use-gui/src/main/java/module-info.java @@ -31,4 +31,8 @@ exports org.tzi.use.gui.views.diagrams.behavior.shared to com.google.common; exports org.tzi.use.gui.views.selection to com.google.common; exports org.tzi.use.gui.views.diagrams.statemachine to com.google.common; + exports org.tzi.use.gui.views.diagrams.elements; + exports org.tzi.use.gui.views.diagrams.elements.edges; + exports org.tzi.use.gui.views.diagrams.event; + exports org.tzi.use.gui.views.selection.objectselection; } \ No newline at end of file diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/elements/edges/AssociationOrLinkPartEdge.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/elements/edges/AssociationOrLinkPartEdge.java index 7f8c0e201..3b35485a1 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/elements/edges/AssociationOrLinkPartEdge.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/elements/edges/AssociationOrLinkPartEdge.java @@ -231,7 +231,7 @@ public boolean adjacentObjectNodeGreyed() { List adjacentObjects = getLink().linkedObjects(); for (MObject adjacentObject : adjacentObjects) { ObjectNode node = visibleData.getObjectToNodeMap().get(adjacentObject); - if(node.isGreyed()) { + if (node != null && node.isGreyed()) { return true; } } @@ -365,8 +365,7 @@ public void drawProperties(Graphics2D g) { public static AssociationOrLinkPartEdge create(PlaceableNode source, PlaceableNode target, MAssociationEnd targetEnd, DiagramView diagram, MAssociation assoc, MLink link) { - AssociationOrLinkPartEdge edge = new AssociationOrLinkPartEdge(source, target, targetEnd, diagram, assoc, link); - return edge; + return new AssociationOrLinkPartEdge(source, target, targetEnd, diagram, assoc, link); } /** @@ -375,8 +374,7 @@ public static AssociationOrLinkPartEdge create(PlaceableNode source, public static AssociationOrLinkPartEdge create(PlaceableNode source, PlaceableNode target, String name, MAssociationEnd targetEnd, DiagramView diagram, MAssociation assoc, MLink link) { - AssociationOrLinkPartEdge edge = new AssociationOrLinkPartEdge(source, target, name, targetEnd, diagram, assoc, link); - return edge; + return new AssociationOrLinkPartEdge(source, target, name, targetEnd, diagram, assoc, link); } @Override diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index e706bfee3..ca9d107e1 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -32,7 +32,6 @@ import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.geom.Point2D; @@ -43,7 +42,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -150,12 +148,17 @@ public ObjectDiagramData() { } /** - * @param link - * @return + * Checks whether this diagram data contains the given link. + * + * @param link the link to test + * @return true if this data contains an edge or node representing the link */ public boolean containsLink(MLink link) { - return fBinaryLinkToEdgeMap.containsKey(link) || fNaryLinkToDiamondNodeMap.containsKey(link) - || fLinkObjectToNodeEdge.containsKey(link); + boolean has = fBinaryLinkToEdgeMap.containsKey(link) || fNaryLinkToDiamondNodeMap.containsKey(link); + if (!has && link instanceof MLinkObject) { + has = fLinkObjectToNodeEdge.containsKey((MLinkObject) link); + } + return has; } @Override @@ -188,6 +191,7 @@ public Set getEdges() { * * @param target the target ObjectDiagramData to copy the data into */ + @SuppressWarnings("unused") public void copyTo(ObjectDiagramData target) { target.fBinaryLinkToEdgeMap.putAll(this.fBinaryLinkToEdgeMap); target.fHalfLinkToEdgeMap.putAll(this.fHalfLinkToEdgeMap); @@ -208,11 +212,25 @@ public void clear() { } // Accessors to preserve encapsulation - public Map getObjectToNodeMap() { return fObjectToNodeMap; } - public Map getBinaryLinkToEdgeMap() { return fBinaryLinkToEdgeMap; } - public Map getNaryLinkToDiamondNodeMap() { return fNaryLinkToDiamondNodeMap; } - public Map> getHalfLinkToEdgeMap() { return fHalfLinkToEdgeMap; } - public Map getLinkObjectToNodeEdge() { return fLinkObjectToNodeEdge; } + public Map getObjectToNodeMap() { + return fObjectToNodeMap; + } + + public Map getBinaryLinkToEdgeMap() { + return fBinaryLinkToEdgeMap; + } + + public Map getNaryLinkToDiamondNodeMap() { + return fNaryLinkToDiamondNodeMap; + } + + public Map> getHalfLinkToEdgeMap() { + return fHalfLinkToEdgeMap; + } + + public Map getLinkObjectToNodeEdge() { + return fLinkObjectToNodeEdge; + } } protected final ObjectDiagramData visibleData = new ObjectDiagramData(); @@ -225,7 +243,7 @@ public void clear() { * The position of the next object node. This is either set to a random * value or to a specific position when an object is created by drag & drop. */ - protected Point2D.Double nextNodePosition = new Point2D.Double(); + protected Point2D.Double nextNodePosition = new Point2D.Double(); /** * Last position of deleted nodes and links. In case of restoration, the @@ -235,12 +253,13 @@ public void clear() { private final Map lastKnownNodePositions = new WeakHashMap<>(); private final Map lastKnownLinkPositions = new WeakHashMap<>(); - protected final ShowObjectPropertiesViewMouseListener showObjectPropertiesViewMouseListener = new ShowObjectPropertiesViewMouseListener(); + // show object properties listener is attached inline in constructor (no field required) private final ObjectSelection fSelection; protected final DiagramInputHandling inputHandling; + @SuppressWarnings("unused") private static boolean javaFxCall = false; /** @@ -271,7 +290,18 @@ protected NewObjectDiagram(NewObjectDiagramView parent, PrintWriter log, ObjDiag fParent.addKeyListener(inputHandling); addMouseListener(inputHandling); - addMouseListener(showObjectPropertiesViewMouseListener); + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + PlaceableNode pickedObjectNode = findNode(e.getX(), e.getY()); + if (pickedObjectNode instanceof ObjectNode on) { + ObjectPropertiesView v = MainWindow.instance().showObjectPropertiesView(); + v.selectObject(on.object().name()); + } + } + } + }); addComponentListener(new ComponentAdapter() { public void componentResized(ComponentEvent e) { @@ -288,10 +318,6 @@ public ObjDiagramOptions getOptions() { return (ObjDiagramOptions) super.getOptions(); } - public ObjectSelection getObjectSelection() { - return this.fSelection; - } - /** * Displays objects of the selected class in the modelbrowser. */ @@ -305,28 +331,34 @@ public void stateChanged(HighlightChangeEvent e) { boolean allEdgesSelected = true; // elem is an association - if (elem instanceof MAssociation) { - MAssociation assoc = (MAssociation) elem; + if (elem instanceof MAssociation assoc) { int size = assoc.associationEnds().size(); Set links = fParent.system().state().linksOfAssociation(assoc).links(); - EdgeBase eb; + EdgeBase ed; if (size == 2) { for (MLink link : links) { - eb = visibleData.getBinaryLinkToEdgeMap().get(link); if (elem instanceof MAssociationClass) { - eb = visibleData.getLinkObjectToNodeEdge().get(link); + if (link instanceof MLinkObject) { + ed = visibleData.getLinkObjectToNodeEdge().get((MLinkObject) link); + } else { + ed = visibleData.getBinaryLinkToEdgeMap().get(link); + } + } else { + ed = visibleData.getBinaryLinkToEdgeMap().get(link); } - edges.add(eb); + edges.add(ed); } } else { for (MLink link : links) { edges.addAll(visibleData.getHalfLinkToEdgeMap().getOrDefault(link, Collections.emptyList())); if (elem instanceof MAssociationClass) { - eb = visibleData.getLinkObjectToNodeEdge().get(link); - edges.add(eb); + if (link instanceof MLinkObject) { + ed = visibleData.getLinkObjectToNodeEdge().get((MLinkObject) link); + edges.add(ed); + } } } } @@ -386,7 +418,7 @@ public void hideAll() { * Hides all currently visible links. The diagram is not repainted! */ public void hideAllLinks() { - Set links = new HashSet<>(this.visibleData.getBinaryLinkToEdgeMap().keySet()); + Set links = new HashSet<>(this.visibleData.getBinaryLinkToEdgeMap().keySet()); for (MLink e : links) { hideBinaryLink(e); @@ -447,9 +479,8 @@ public void addObject(MObject obj) { /** * Shows an already hidden object again - * - * @param obj - * The object to show + * + * @param obj The object to show */ public void showObject(MObject obj) { if (visibleData.getObjectToNodeMap().containsKey(obj)) @@ -502,17 +533,16 @@ public void moveObjectNode(MObject obj, int x, int y) { /** * Hides an object in the diagram - * - * @param obj - * The MObject to hide + * + * @param obj The MObject to hide */ public void hideObject(MObject obj) { // a hidden object should no longer be selected ObjectNode removedNode = visibleData.getObjectToNodeMap().get(obj); - if(removedNode!=null) { + if (removedNode != null) { fNodeSelection.remove(removedNode); } - + showOrHideObjectNode(obj, false); // Hide all links the object participates in @@ -526,8 +556,7 @@ public void hideObject(MObject obj) { MLinkSet links = fParent.system().state().linksOfAssociation(assoc); // TODO: Not very fast! for (MLink link : links.links()) { - if (link.linkedObjects().contains(obj) - || (link instanceof MLinkObject && ((MLinkObject) link).equals(obj))) { + if (link.linkedObjects().contains(obj) || (link instanceof MLinkObject && link.equals(obj))) { hideLink(link); } } @@ -597,85 +626,11 @@ public void addLink(MLink link) { } } - protected void addBinaryLink(MLink link) { - MAssociation assoc = link.association(); - - MLinkEnd linkEnd1 = link.linkEnd(assoc.associationEnds().get(0)); - MLinkEnd linkEnd2 = link.linkEnd(assoc.associationEnds().get(1)); - - MObject obj1 = linkEnd1.object(); - MObject obj2 = linkEnd2.object(); - // TODO: Create link edge factory. - - // object link - if (link instanceof MLinkObject) { - BinaryAssociationClassOrObject e = BinaryAssociationClassOrObject.create( - visibleData.getObjectToNodeMap().get(obj1), visibleData.getObjectToNodeMap().get(obj2), - linkEnd1, linkEnd2, visibleData.getObjectToNodeMap().get(link), this, - link); - - if (lastKnownLinkPositions.containsKey(link)) { - e.initialize(); - visibleData.getObjectToNodeMap().get(link).setStrategy(lastKnownLinkPositions.get(link)); - lastKnownLinkPositions.remove(link); - fGraph.addInitializedEdge(e); - } else { - fGraph.addEdge(e); - } - visibleData.getLinkObjectToNodeEdge().put((MLinkObject) link, e); - fLayouter = null; - } else { - // binary link - boolean isHidden = false; - ObjectNode node1; - ObjectNode node2; - - if (visibleData.getObjectToNodeMap().containsKey(obj1)) { - node1 = visibleData.getObjectToNodeMap().get(obj1); - } else { - node1 = hiddenData.getObjectToNodeMap().get(obj1); - isHidden = true; - } - - if (visibleData.getObjectToNodeMap().containsKey(obj2)) { - node2 = visibleData.getObjectToNodeMap().get(obj2); - } else { - node2 = hiddenData.getObjectToNodeMap().get(obj2); - isHidden = true; - } - - BinaryAssociationOrLinkEdge e = createBinaryAssociationOrLinkEdge(node1, node2, linkEnd1, - linkEnd2, this, link); - - if (link.isVirtual()) { - e.setDashed(true); - } - - if (isHidden) { - hiddenData.getBinaryLinkToEdgeMap().put(link, e); - } else { - fGraph.addEdge(e); - visibleData.getBinaryLinkToEdgeMap().put(link, e); - fLayouter = null; - } - } - } - - /** - * This part is a separate method for easier inheritance. - * - * @author Andreas Kaestner - */ - protected BinaryAssociationOrLinkEdge createBinaryAssociationOrLinkEdge(PlaceableNode source, PlaceableNode target, - MLinkEnd sourceEnd, MLinkEnd targetEnd, NewObjectDiagram diagram, MLink link) { - return BinaryAssociationOrLinkEdge.create(source, target, sourceEnd, targetEnd, diagram, link); - } - protected void addNAryLink(MLink link) { getRandomNextPosition(); - + List linkedObjectNodes = new ArrayList<>(); - for(MObject linkedObject : link.linkedObjects()) { + for (MObject linkedObject : link.linkedObjects()) { linkedObjectNodes.add(visibleData.getObjectToNodeMap().get(linkedObject)); } @@ -709,12 +664,19 @@ protected void addNAryLink(MLink link) { fGraph.addEdge(e); halfEdges.add(e); - edgeIds.add(linkEnd.associationEnd().nameAsRolename()); + edgeIds.add(linkEnd.associationEnd().nameAsRolename()); } - if (visibleData.getLinkObjectToNodeEdge().get(link) != null) { - halfEdges.add(visibleData.getLinkObjectToNodeEdge().get(link)); - edgeIds.add(((MLinkObject) link).name()); + // If there is an associated link-object edge, add it once (avoid duplicate map access) + { + EdgeBase linkObjEdge = null; + if (link instanceof MLinkObject) { + linkObjEdge = visibleData.getLinkObjectToNodeEdge().get((MLinkObject) link); + } + if (linkObjEdge != null) { + halfEdges.add(linkObjEdge); + edgeIds.add(((MLinkObject) link).name()); + } } node.setHalfEdges(halfEdges, edgeIds); @@ -725,8 +687,8 @@ protected void addNAryLink(MLink link) { /** * Show one link. The diagram is not repainted! - * - * @param link + * + * @param link the link to show */ public void showLink(MLink link) { if (visibleData.containsLink(link)) @@ -752,8 +714,8 @@ public void showLink(MLink link) { /** * Hide one link. The diagram is not repainted! - * - * @param link + * + * @param link the link to hide */ public void hideLink(MLink link) { if (hiddenData.containsLink(link)) @@ -793,13 +755,13 @@ protected void showOrHideBinaryLink(MLink link, boolean show) { // object link if (link instanceof MLinkObject) { - EdgeBase e = source.getLinkObjectToNodeEdge().get(link); + EdgeBase e = source.getLinkObjectToNodeEdge().get((MLinkObject) link); if (show && e != null) fGraph.addInitializedEdge(e); else if (e != null) fGraph.removeEdge(e); - source.getLinkObjectToNodeEdge().remove(link); + source.getLinkObjectToNodeEdge().remove((MLinkObject) link); target.getLinkObjectToNodeEdge().put((MLinkObject) link, e); fLayouter = null; } else { @@ -820,22 +782,22 @@ protected void showOrHideNAryLink(MLink link, boolean show) { ObjectDiagramData source = (show ? hiddenData : visibleData); ObjectDiagramData target = (show ? visibleData : hiddenData); - DiamondNode node = source.fNaryLinkToDiamondNodeMap.get(link); - if (show){ - if (node == null){ - node = target.fNaryLinkToDiamondNodeMap.get(link); + DiamondNode node = source.getNaryLinkToDiamondNodeMap().get(link); + if (show) { + if (node == null) { + node = target.getNaryLinkToDiamondNodeMap().get(link); } fGraph.add(node); } else { fGraph.remove(node); } - target.fNaryLinkToDiamondNodeMap.put(link, node); - source.fNaryLinkToDiamondNodeMap.remove(link); - + target.getNaryLinkToDiamondNodeMap().put(link, node); + source.getNaryLinkToDiamondNodeMap().remove(link); + // connected to an "object link" if (link instanceof MLinkObject) { - EdgeBase e = source.fLinkObjectToNodeEdge.get(link); + EdgeBase e = source.getLinkObjectToNodeEdge().get((MLinkObject) link); if (e != null) { if (show) @@ -843,13 +805,13 @@ protected void showOrHideNAryLink(MLink link, boolean show) { else fGraph.removeEdge(e); - source.fLinkObjectToNodeEdge.remove(link); - target.fLinkObjectToNodeEdge.put((MLinkObject) link, e); + source.getLinkObjectToNodeEdge().remove((MLinkObject) link); + target.getLinkObjectToNodeEdge().put((MLinkObject) link, e); fLayouter = null; } } - List halfEdges = source.fHalfLinkToEdgeMap.get(link); + List halfEdges = source.getHalfLinkToEdgeMap().get(link); if (halfEdges != null) { for (EdgeBase edge : halfEdges) { @@ -859,26 +821,26 @@ protected void showOrHideNAryLink(MLink link, boolean show) { fGraph.removeEdge(edge); } - source.fHalfLinkToEdgeMap.remove(link); - target.fHalfLinkToEdgeMap.put(link, halfEdges); + source.getHalfLinkToEdgeMap().remove(link); + target.getHalfLinkToEdgeMap().put(link, halfEdges); } fLayouter = null; } /** - * Removes a link from the diagram. + * Deletes a link from the diagram. */ public void deleteLink(MLink link) { if (link.linkEnds().size() == 2) { - EdgeBase e = null; + EdgeBase e; // initialize later based on visibility boolean isVisible; boolean isLinkObject = link instanceof MLinkObject; ObjectDiagramData data; if (isLinkObject) { - isVisible = visibleData.getLinkObjectToNodeEdge().containsKey(link); + isVisible = visibleData.getLinkObjectToNodeEdge().containsKey((MLinkObject) link); data = isVisible ? visibleData : hiddenData; - e = data.getLinkObjectToNodeEdge().get(link); + e = data.getLinkObjectToNodeEdge().get((MLinkObject) link); } else { isVisible = visibleData.getBinaryLinkToEdgeMap().containsKey(link); data = isVisible ? visibleData : hiddenData; @@ -890,14 +852,14 @@ public void deleteLink(MLink link) { } if (isLinkObject) { - BinaryAssociationClassOrObject edge = (BinaryAssociationClassOrObject) data.getLinkObjectToNodeEdge().get(link); + BinaryAssociationClassOrObject edge = (BinaryAssociationClassOrObject) data.getLinkObjectToNodeEdge().get((MLinkObject) link); if (edge != null) { PlaceableNode objectNode = edge.getClassOrObjectNode(); lastKnownLinkPositions.put(link, objectNode.getStrategy()); } data.getBinaryLinkToEdgeMap().remove(link); - data.getLinkObjectToNodeEdge().remove(link); + data.getLinkObjectToNodeEdge().remove((MLinkObject) link); } else { data.getBinaryLinkToEdgeMap().remove(link); } @@ -930,12 +892,12 @@ public void deleteLink(MLink link) { n.dispose(); if (link instanceof MLinkObject) { - EdgeBase edge = data.getLinkObjectToNodeEdge().get(link); + EdgeBase edge = data.getLinkObjectToNodeEdge().get((MLinkObject) link); if (edge != null) { lastKnownLinkPositions.put(link, ((NAryAssociationClassOrObjectEdge) edge).getClassOrLinkObjectNode().getStrategy()); fGraph.removeEdge(edge); - data.getLinkObjectToNodeEdge().remove(link); + data.getLinkObjectToNodeEdge().remove((MLinkObject) link); edge.dispose(); } } @@ -944,13 +906,15 @@ public void deleteLink(MLink link) { /** * Forces the object node to update its content. - * - * @param obj + * + * @param obj the MInstance whose node should be refreshed */ public void updateObject(MInstance obj) { - ObjectNode node = visibleData.getObjectToNodeMap().get(obj); - if (node != null) + // Use computeIfPresent with an explicit cast of the key to the Map's key type (MObject) + visibleData.getObjectToNodeMap().computeIfPresent((MObject) obj, (k, node) -> { invalidateNode(node); + return node; // keep the existing mapping + }); } /** @@ -1030,7 +994,8 @@ public void actionPerformed(ActionEvent e) { /** * Show properties of objects */ - class ActionShowProperties extends AbstractAction { + @SuppressWarnings("unused") + static class ActionShowProperties extends AbstractAction { private final MObject fObject; ActionShowProperties(String text, MObject object) { @@ -1039,8 +1004,8 @@ class ActionShowProperties extends AbstractAction { } public void actionPerformed(ActionEvent e) { - if (MainWindow.getJavaFxCall()){ - Platform.runLater(()->{ + if (MainWindow.getJavaFxCall()) { + Platform.runLater(() -> { // to create an instance of a SwingNode, which is used to hold the Swing-Components SwingNode swingNode = new SwingNode(); @@ -1069,22 +1034,6 @@ public void actionPerformed(ActionEvent e) { } } - private class ShowObjectPropertiesViewMouseListener extends MouseAdapter { - - @Override - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() == 2) { - // mouse over node? - PlaceableNode pickedObjectNode = findNode(e.getX(), e.getY()); - if (pickedObjectNode instanceof ObjectNode) { - ObjectNode obj = (ObjectNode) pickedObjectNode; - ObjectPropertiesView v = MainWindow.instance().showObjectPropertiesView(); - v.selectObject(obj.object().name()); - } - } - } - } - /** * Creates and shows popup menu if mouse event is the trigger for popups. */ @@ -1111,8 +1060,7 @@ protected PopupMenuInfo unionOfPopUpMenu() { } for (EdgeBase selectedEdge : fEdgeSelection) { - if (selectedEdge instanceof LinkEdge) { - LinkEdge aEdge = (LinkEdge) selectedEdge; + if (selectedEdge instanceof LinkEdge aEdge) { MLink link = aEdge.getLink(); selectedLinks.add(link); selectedObjectsOfAssociation.addAll(link.linkedObjects()); @@ -1125,7 +1073,7 @@ protected PopupMenuInfo unionOfPopUpMenu() { // This text is reused often String selectedObjectsText = null; if (selectedObjects.size() == 1) { - selectedObjectsText = "'" + selectedObjects.get(0).name() + "'"; + selectedObjectsText = "'" + exactlyOne(selectedObjects).name() + "'"; } else if (selectedObjects.size() > 1) { selectedObjectsText = selectedObjects.size() + " objects"; } @@ -1134,8 +1082,8 @@ protected PopupMenuInfo unionOfPopUpMenu() { // A single object can be edited if (selectedObjects.size() == 1) { popupMenu.insert( - new ActionShowProperties("Edit properties of " + selectedObjectsText, selectedObjects.get(0)), - pos++); + new ActionShowProperties("Edit properties of " + selectedObjectsText, exactlyOne(selectedObjects)), + pos++); } // A single object or multiple objects can be deleted. @@ -1230,22 +1178,18 @@ protected PopupMenuInfo unionOfPopUpMenu() { } // New Action for Hide - popupMenu.insert(new AbstractAction(labelHide) { - - @Override - public void actionPerformed(ActionEvent arg0) { - if (!selectedLinks.isEmpty()) { - selectedLinks.forEach(NewObjectDiagram.this::hideLink); - } - if (!selectedObjects.isEmpty()) { - selectedObjects.forEach(NewObjectDiagram.this::hideObject); - } - repaint(); + popupMenu.insert(createAction(labelHide, arg0 -> { + if (!selectedLinks.isEmpty()) { + selectedLinks.forEach(NewObjectDiagram.this::hideLink); } - }, pos++); + if (!selectedObjects.isEmpty()) { + selectedObjects.forEach(NewObjectDiagram.this::hideObject); + } + repaint(); + }), pos++); // new Action for crop - Set objectsToHide = new HashSet<>(selectedObjects); + Set objectsToHide = new HashSet<>(selectedObjects); selectedLinks.forEach(link -> { if (link instanceof MLinkObject) { objectsToHide.add((MLinkObject) link); @@ -1254,132 +1198,83 @@ public void actionPerformed(ActionEvent arg0) { } }); - final String label = labelCrop; - popupMenu.insert(new AbstractAction(labelCrop) { - @Override - public void actionPerformed(ActionEvent e) { - getAction(label, getNoneSelectedNodes(objectsToHide)).actionPerformed(e); - } - }, pos++); + final String labelCropFinal = labelCrop; // ensure effectively final + popupMenu.insert(createAction(labelCrop, e -> getAction(labelCropFinal, getNoneSelectedNodes(objectsToHide)).actionPerformed(e)), pos++); - // new Action for grey in/out + // new Action for gray in/out (single) if (selectedObjects.size() == 1) { - MObject obj = selectedObjects.iterator().next(); - if (visibleData.getObjectToNodeMap().containsKey(obj)) { - ObjectNode node = visibleData.getObjectToNodeMap().get(obj); - String labelGreyed = node.isGreyed() ? "Grey in" : "Grey out"; - - popupMenu.insert(new AbstractAction(labelGreyed + " " + node.name()) { - @Override - public void actionPerformed(ActionEvent e) { - node.setGreyed(!node.isGreyed()); - repaint(); - } - }, pos++); + MObject obj = exactlyOne(selectedObjects); + ObjectNode node = visibleData.getObjectToNodeMap().get(obj); + if (node != null) { + String labelGreyed = node.isGreyed() ? "Gray in" : "Gray out"; + + popupMenu.insert(createAction(labelGreyed + " " + node.name(), e -> { + node.setGreyed(!node.isGreyed()); + repaint(); + }), pos++); } } else if (selectedObjects.size() > 1) { Set objToGreyIn = new HashSet<>(); - selectedObjects.stream().filter(obj -> visibleData.getObjectToNodeMap().get(obj).isGreyed()) - .forEach(obj -> objToGreyIn.add(visibleData.getObjectToNodeMap().get(obj))); - Set objToGreyOut = new HashSet<>(); - selectedObjects.stream().filter(obj -> !visibleData.getObjectToNodeMap().get(obj).isGreyed()) - .forEach(obj -> objToGreyOut.add(visibleData.getObjectToNodeMap().get(obj))); + for (MObject so : selectedObjects) { + ObjectNode n = visibleData.getObjectToNodeMap().get(so); + if (n != null) { + if (n.isGreyed()) objToGreyIn.add(n); + else objToGreyOut.add(n); + } + } + // gray in if (!objToGreyIn.isEmpty()) { - popupMenu.insert(new AbstractAction("Grey in " + objToGreyIn.size() + " elements") { - - @Override - public void actionPerformed(ActionEvent arg0) { - objToGreyIn.forEach(obj -> obj.setGreyed(false)); - repaint(); - } - }, pos++); + popupMenu.insert(createAction("Gray in " + objToGreyIn.size() + " elements", arg0 -> { + objToGreyIn.forEach(n -> n.setGreyed(false)); + repaint(); + }), pos++); } - // Action for grey out more elements + // gray out if (!objToGreyOut.isEmpty()) { - popupMenu.insert(new AbstractAction("Grey out " + objToGreyOut.size() + " elements") { - - @Override - public void actionPerformed(ActionEvent arg0) { - objToGreyOut.forEach(obj -> obj.setGreyed(true)); - repaint(); - } - }, pos++); + popupMenu.insert(createAction("Gray out " + objToGreyOut.size() + " elements", arg0 -> { + objToGreyOut.forEach(n -> n.setGreyed(true)); + repaint(); + }), pos++); } } - popupMenu.insert(new JSeparator(), pos++); } + popupMenu.insert(new JSeparator(), pos++); - final JMenu showHideCrop = new JMenu("Show/hide/crop objects"); + final JMenu showProtocolStateMachine = new JMenu("Show protocol state machine..."); + showProtocolStateMachine.setEnabled(false); + popupMenu.insert(showProtocolStateMachine, pos++); - if (!selectedObjects.isEmpty()) { - showHideCrop.add(fSelection.getSelectedObjectPathView("By path length...", selectedObjectsSet)); - } + if (selectedObjects.size() == 1) { + final MObject obj = exactlyOne(selectedObjects); - showHideCrop.add(fSelection.getSelectionWithOCLViewAction()); - showHideCrop.add(fSelection.getSelectionObjectView()); + List sortedPSMs = new LinkedList<>( + obj.cls().getAllOwnedProtocolStateMachines()); + sortedPSMs.sort(new MNamedElementComparator()); - popupMenu.insert(showHideCrop, pos++); + for (MProtocolStateMachine psm : sortedPSMs) { + showProtocolStateMachine.setEnabled(true); + final JMenuItem showGivenPSM = new JMenuItem(psm.name()); + showGivenPSM.addActionListener(new ActionListener() { + private MProtocolStateMachine sm; - if (!fGraph.isEmpty() || !hiddenData.getObjectToNodeMap().isEmpty()) { - if (!fGraph.isEmpty()) { - popupMenu.insert(fSelection.getSubMenuHideObject(), pos++); - } + public void actionPerformed(ActionEvent ev) { + MainWindow.instance().showStateMachineView(sm, obj); + } - if (!hiddenData.getObjectToNodeMap().isEmpty()) { - popupMenu.insert(fSelection.getSubMenuShowObject(), pos++); + public ActionListener setStateMachine(MProtocolStateMachine sm) { + this.sm = sm; + return this; + } + }.setStateMachine(psm)); + showProtocolStateMachine.add(showGivenPSM); } } - if (!visibleData.getBinaryLinkToEdgeMap().isEmpty() || !visibleData.getHalfLinkToEdgeMap().isEmpty() - || !visibleData.getLinkObjectToNodeEdge().isEmpty() - || !visibleData.getNaryLinkToDiamondNodeMap().isEmpty()) { - popupMenu.insert(fSelection.getSubMenuHideLinks(), pos++); - } - - if (!hiddenData.getBinaryLinkToEdgeMap().isEmpty() || !hiddenData.getHalfLinkToEdgeMap().isEmpty() - || !hiddenData.getLinkObjectToNodeEdge().isEmpty() || !hiddenData.getNaryLinkToDiamondNodeMap().isEmpty()) { - popupMenu.insert(fSelection.getSubMenuShowLinks(), pos++); - } - popupMenu.insert(new JSeparator(), pos++); - if (!selectedObjects.isEmpty()) { - final JMenu showProtocolStateMachine = new JMenu("Show protocol state machine..."); - showProtocolStateMachine.setEnabled(false); - popupMenu.insert(showProtocolStateMachine, pos++); - - if (selectedObjects.size() == 1) { - final MObject obj = exactlyOne(selectedObjects); - - List sortedPSMs = new LinkedList<>( - obj.cls().getAllOwnedProtocolStateMachines()); - sortedPSMs.sort(new MNamedElementComparator()); - - for (MProtocolStateMachine psm : sortedPSMs) { - showProtocolStateMachine.setEnabled(true); - final JMenuItem showGivenPSM = new JMenuItem(psm.name()); - showGivenPSM.addActionListener(new ActionListener() { - protected MProtocolStateMachine sm; - - public void actionPerformed(ActionEvent ev) { - MainWindow.instance().showStateMachineView(sm, obj); - } - - public ActionListener setStateMachine(MProtocolStateMachine sm, MObject instance) { - this.sm = sm; - return this; - } - }.setStateMachine(psm, obj)); - showProtocolStateMachine.add(showGivenPSM); - } - } - - popupMenu.insert(new JSeparator(), pos++); - } - final JCheckBoxMenuItem showStates = new JCheckBoxMenuItem("Show states", getOptions().isShowStates()); showStates.addItemListener(ev -> { getOptions().setShowStates(ev.getStateChange() == ItemEvent.SELECTED); @@ -1393,16 +1288,13 @@ public ActionListener setStateMachine(MProtocolStateMachine sm, MObject instance /** * Finds all nodes which are not selected. - * - * @param selectedNodes - * Nodes which are selected at this point in the diagram. + * + * @param selectedNodes Nodes which are selected at this point in the diagram. * @return A HashSet of the none selected objects in the diagram. */ private Set getNoneSelectedNodes(Set selectedNodes) { Set noneSelectedNodes = new HashSet<>(); - Iterator it = fGraph.iterator(); - while (it.hasNext()) { - PlaceableNode o = it.next(); + for (PlaceableNode o : fGraph) { if (o instanceof ObjectNode) { MObject obj = ((ObjectNode) o).object(); if (!selectedNodes.contains(obj)) { @@ -1460,11 +1352,11 @@ private void displayObjectInfo(MObject obj, MouseEvent e) { } /** - * + * * Accepts a drag of a class from the ModelBrowser. A new object of this * class will be created. - * - * @param dtde + * + * @param dtde the drop event provided by the DnD subsystem */ public void dropObjectFromModelBrowser(DropTargetDropEvent dtde) { @@ -1508,9 +1400,8 @@ public void dropObjectFromModelBrowser(DropTargetDropEvent dtde) { /** * Checks if the object info window should be displayed. - * - * @param e - * MouseEvent + * + * @param e MouseEvent */ public void mayBeShowObjectInfo(MouseEvent e) { if (fNodeSelection.size() == 1) { @@ -1544,11 +1435,11 @@ private int[] radixConversion(int number, int base, int maxDigits) { private boolean isCompleteObjectCombination(int[] c, int base) { for (int i = 0; i < base; ++i) { boolean found = false; - for (int j = 0; j < c.length; ++j) { - if (c[j] == i) { - found = true; - break; - } + for (int v : c) { + if (v == i) { + found = true; + break; + } } if (!found) return false; @@ -1585,15 +1476,15 @@ protected void storePlacementInfos(PersistHelper helper, Element root, boolean v n.storePlacementInfo(helper, root, !visible); } - for (PlaceableNode n : data.fNaryLinkToDiamondNodeMap.values()) { + for (PlaceableNode n : data.getNaryLinkToDiamondNodeMap().values()) { n.storePlacementInfo(helper, root, !visible); } - for (EdgeBase e : data.fBinaryLinkToEdgeMap.values()) { + for (EdgeBase e : data.getBinaryLinkToEdgeMap().values()) { e.storePlacementInfo(helper, root, !visible); } - for (EdgeBase e : data.fLinkObjectToNodeEdge.values()) { + for (EdgeBase e : data.getLinkObjectToNodeEdge().values()) { e.storePlacementInfo(helper, root, !visible); } } @@ -1601,260 +1492,192 @@ protected void storePlacementInfos(PersistHelper helper, Element root, boolean v @Override public void restorePlacementInfos(PersistHelper helper, int version) { if (version < 12) return; - + Set hiddenObjects = new HashSet<>(); + + // delegate to smaller, well-scoped helpers + restoreBinaryEdges(helper, version, hiddenObjects); + restoreNodeEdges(helper, version, hiddenObjects); + restoreDiamondNodes(helper, version, hiddenObjects); + + // Hide elements collected during restore + hideElementsInDiagram(hiddenObjects); + } + + // Helper: restore binary association edges placement info + @SuppressWarnings("unused") + private void restoreBinaryEdges(PersistHelper helper, int version, Set hiddenObjects) { AutoPilot ap = new AutoPilot(helper.getNav()); - - // First restore edges to get possible new nodes, then nodes helper.getNav().push(); - try { - // Restore edges ap.selectXPath("./edge[@type='BinaryEdge']"); - try { - while (ap.evalXPath() != -1) { + while (ap.evalXPath() != -1) { String name = helper.getElementStringValue("name"); MAssociation assoc = fParent.system().model().getAssociation(name); String sourceObjectName = helper.getElementStringValue("source"); String targetObjectName = helper.getElementStringValue("target"); - + MObject sourceObject = fParent.system().state().objectByName(sourceObjectName); MObject targetObject = fParent.system().state().objectByName(targetObjectName); - + // Could be deleted if (assoc != null && sourceObject != null && targetObject != null) { MLink link; - if (assoc.hasQualifiedEnds()) { String linkValue = helper.getElementStringValue("linkValue"); link = getLinkByValue(assoc, Arrays.asList(sourceObject, targetObject), linkValue); } else { - // No qualifier values are present. - link = fParent - .system() - .state() - .linkBetweenObjects(assoc, - Arrays.asList(sourceObject, targetObject), - Collections.emptyList()); + link = fParent.system().state().linkBetweenObjects(assoc, Arrays.asList(sourceObject, targetObject), Collections.emptyList()); } - if (link != null) { BinaryAssociationOrLinkEdge edge = visibleData.getBinaryLinkToEdgeMap().get(link); - edge.restorePlacementInfo(helper, version); + if (edge != null) { + edge.restorePlacementInfo(helper, version); + } } } } - } catch (XPathEvalException e) { - fLog.append(e.getMessage()); - } catch (NavException e) { - fLog.append(e.getMessage()); + } catch (XPathEvalException | NavException e) { + if (fLog != null) fLog.println(e.getMessage()); + else System.err.println(e.getMessage()); } } catch (XPathParseException e) { - fLog.append(e.getMessage()); + if (fLog != null) fLog.println(e.getMessage()); + else System.err.println(e.getMessage()); + } finally { + ap.resetXPath(); + helper.getNav().pop(); } - ap.resetXPath(); - helper.getNav().pop(); - + } + + // Helper: restore node-edge (link objects / node edges) + @SuppressWarnings("unused") + private void restoreNodeEdges(PersistHelper helper, int version, Set hiddenObjects) { + AutoPilot ap = new AutoPilot(helper.getNav()); helper.getNav().push(); try { - // Restore edges ap.selectXPath("./edge[@type='NodeEdge']"); - try { - while(ap.evalXPath() != -1) { + while (ap.evalXPath() != -1) { String name = helper.getElementStringValue("name"); MAssociation assoc = fParent.system().model().getAssociation(name); String sourceObjectName = helper.getElementStringValue("source"); String targetObjectName = helper.getElementStringValue("target"); - + MObject sourceObject = fParent.system().state().objectByName(sourceObjectName); MObject targetObject = fParent.system().state().objectByName(targetObjectName); - + // Could be deleted if (assoc != null && sourceObject != null && targetObject != null) { MLink link; - if (assoc.hasQualifiedEnds()) { String linkValue = helper.getElementStringValue("linkValue"); link = getLinkByValue(assoc, Arrays.asList(sourceObject, targetObject), linkValue); } else { - // No qualifier values are present. - link = fParent - .system() - .state() - .linkBetweenObjects(assoc, - Arrays.asList(sourceObject, targetObject), - Collections.emptyList()); + link = fParent.system().state().linkBetweenObjects(assoc, Arrays.asList(sourceObject, targetObject), Collections.emptyList()); } - if (link != null) { - BinaryAssociationClassOrObject edge = (BinaryAssociationClassOrObject)visibleData.getLinkObjectToNodeEdge().get(link); - edge.restorePlacementInfo(helper, version); + if (link instanceof MLinkObject linkObj) { + EdgeBase tmp = visibleData.getLinkObjectToNodeEdge().get(linkObj); + if (tmp instanceof BinaryAssociationClassOrObject edge) { + edge.restorePlacementInfo(helper, version); + } + } } } } - } catch (XPathEvalException e) { - fLog.append(e.getMessage()); - } catch (NavException e) { - fLog.append(e.getMessage()); + } catch (XPathEvalException | NavException e) { + if (fLog != null) fLog.println(e.getMessage()); + else System.err.println(e.getMessage()); } } catch (XPathParseException e) { - fLog.append(e.getMessage()); + if (fLog != null) fLog.println(e.getMessage()); + else System.err.println(e.getMessage()); + } finally { + ap.resetXPath(); + helper.getNav().pop(); } - helper.getNav().pop(); - ap.resetXPath(); - + } + + // Helper: restore diamond nodes (n-ary links) + private void restoreDiamondNodes(PersistHelper helper, int version, Set hiddenObjects) { + AutoPilot ap = new AutoPilot(helper.getNav()); helper.getNav().push(); try { ap.selectXPath("./node[@type='Object']"); - try { - while(ap.evalXPath() != -1) { + while (ap.evalXPath() != -1) { String name = helper.getElementStringValue("name"); MObject obj = fParent.system().state().objectByName(name); - // Could be deleted if (obj != null) { ObjectNode node = visibleData.getObjectToNodeMap().get(obj); - node.restorePlacementInfo(helper, version); - if (isHidden(helper, version)) hiddenObjects.add(obj); + if (node != null) { + node.restorePlacementInfo(helper, version); + if (isHidden(helper, version)) hiddenObjects.add(obj); + } } } - } catch (XPathEvalException e) { - fLog.append(e.getMessage()); - } catch (NavException e) { - fLog.append(e.getMessage()); + } catch (XPathEvalException | NavException e) { + if (fLog != null) fLog.println(e.getMessage()); + else System.err.println(e.getMessage()); } } catch (XPathParseException e) { - fLog.append(e.getMessage()); + if (fLog != null) fLog.println(e.getMessage()); + else System.err.println(e.getMessage()); + } finally { + ap.resetXPath(); + helper.getNav().pop(); } - - helper.getNav().pop(); - ap.resetXPath(); - + + // now diamond nodes (separate xpath) + ap = new AutoPilot(helper.getNav()); helper.getNav().push(); try { - // Restore diamond nodes ap.selectXPath("./node[@type='DiamondNode']"); - try { while (ap.evalXPath() != -1) { String name = helper.getElementStringValue("name"); MAssociation assoc = fParent.system().model().getAssociation(name); - - // Renamed or deleted if (assoc == null) continue; - - // Get connected objects List connectedObjects = new LinkedList<>(); - if (!helper.toFirstChild("connectedNode")) - break; - + if (!helper.toFirstChild("connectedNode")) continue; String objectName = helper.getElementStringValue(); MObject obj = fParent.system().state().objectByName(objectName); - - if (obj != null) - connectedObjects.add(obj); - + if (obj != null) connectedObjects.add(obj); while (helper.toNextSibling("connectedNode")) { objectName = helper.getElementStringValue(); obj = fParent.system().state().objectByName(objectName); - - if (obj != null) { - connectedObjects.add(obj); - } + if (obj != null) connectedObjects.add(obj); } - - // Modified - if (assoc.associationEnds().size() != connectedObjects.size()) - continue; - - // n-ary links cannot be qualified therefore an empty list for the qualifer values is provided + if (assoc.associationEnds().size() != connectedObjects.size()) continue; MLink link = fParent.system().state().linkBetweenObjects(assoc, connectedObjects, Collections.emptyList()); - - // Could be deleted if (link != null) { - DiamondNode node = visibleData.fNaryLinkToDiamondNodeMap.get(link); - helper.toParent(); - node.restorePlacementInfo(helper, version); + DiamondNode node = visibleData.getNaryLinkToDiamondNodeMap().get(link); + if (node != null) { + helper.toParent(); + node.restorePlacementInfo(helper, version); + } } } - } catch (XPathEvalException e) { - fLog.append(e.getMessage()); - } catch (NavException e) { - fLog.append(e.getMessage()); + } catch (XPathEvalException | NavException e) { + if (fLog != null) fLog.println(e.getMessage()); + else System.err.println(e.getMessage()); } } catch (XPathParseException e) { - fLog.append(e.getMessage()); - } - helper.getNav().pop(); - ap.resetXPath(); - - // Hide elements - hideElementsInDiagram(hiddenObjects); - } - - protected MLink getLinkByValue(MAssociation assoc, List objects, String linkValue) { - Set links = fParent.system().state().linkBetweenObjects(assoc, objects); - if (links.size() == 1) { - return links.iterator().next(); - } else { - for (MLink aLink : links) { - if (aLink.toString().equals(linkValue)) { - return aLink; - } - } - } - return null; - } - - protected boolean isHidden(PersistHelper helper, int version) { - return helper.getElementBooleanValue(LayoutTags.HIDDEN); - } - - @Override - public Set getHiddenNodes() { - return new HashSet(hiddenData.getObjectToNodeMap().values()); - } - - @Override - public ObjectDiagramData getVisibleData() { - return visibleData; - } - - @Override - public DiagramData getHiddenData() { - return hiddenData; - } - - @Override - protected String getDefaultLayoutFileSuffix() { - // No default layout - return null; - } - - @Override - protected void onClosing() { - if (!javaFxCall) { - super.onClosing(); - } - fParent.getModelBrowser().removeHighlightChangeListener(this); - fParent.removeKeyListener(inputHandling); - ModelBrowserSorting.getInstance().removeSortChangeListener(this); - } - - @Override - public void stateChanged(SortChangeEvent e) { - for (ObjectNode n : this.visibleData.getObjectToNodeMap().values()) { - n.stateChanged(e); + if (fLog != null) fLog.println(e.getMessage()); + else System.err.println(e.getMessage()); + } finally { + ap.resetXPath(); + helper.getNav().pop(); } } /** * Hide link using name of link - * - * @param linkName - * @param links + * + * @param linkName the association (link) name to hide + * @param links the list of links to examine */ public void hideLink(String linkName, List links) { for (MLink link : links) { @@ -1867,9 +1690,9 @@ public void hideLink(String linkName, List links) { /** * Show link using name of link - * - * @param linkName - * @param links + * + * @param linkName the association (link) name to show + * @param links the list of links to examine */ public void showLink(String linkName, List links) { for (MLink link : links) { @@ -1880,14 +1703,14 @@ public void showLink(String linkName, List links) { } /** - * Map links to kind of assoziation. Used for show/hide-links-by-kind - * - * @return + * Map links to kind of association. Used for show/hide-links-by-kind + * + * @return a sorted map from kind label to links */ public TreeMap> mapLinksToKindOfAssociation() { Map> assocs = new HashMap<>(); final String derivedLinks = "Derived links"; - final String associationClass = "Linkobjects"; + final String associationClass = "Link objects"; final String nAryLinks = "N-Ary links"; final String reflexiveLinks = "Reflexive links"; final String binaryLinks = "Binary links"; @@ -1897,52 +1720,56 @@ public TreeMap> mapLinksToKindOfAssociation() { for (MAssociation assoc : fParent.system().model().associations()) { /* - * aggregationKind = 0, other + * aggregationKind = 0, other * aggregationKind = 1, aggreation * aggregationKind = 2, composition */ int kind = assoc.aggregationKind(); switch (kind) { - case 0: - Set links = fParent.system().state().linksOfAssociation(assoc).links(); - for (MLink link : links) { - if (link.association().isDerived() || link.association().isUnion()) { - assocs.computeIfAbsent(derivedLinks, k -> new ArrayList<>()).add(link); - } else if (MAssociationClassImpl.class.isInstance(link.association())) { - assocs.computeIfAbsent(associationClass, k -> new ArrayList<>()).add(link); - } else if (MAssociation.class.isInstance(link.association()) && link.linkEnds().size() > 2) { - assocs.computeIfAbsent(nAryLinks, k -> new ArrayList<>()).add(link); - } else if (MAssociation.class.isInstance(link.association()) - && link.association().associatedClasses().size() == 1) { - assocs.computeIfAbsent(reflexiveLinks, k -> new ArrayList<>()).add(link); - } else if (MAssociation.class.isInstance(link.association()) && link.linkedObjects().size() == 2 - && !link.linkedObjects().get(0).equals(link.linkedObjects().get(1))) { - assocs.computeIfAbsent(binaryLinks, k -> new ArrayList<>()).add(link); - } else { - System.err.println("ERROR: NO MATCH IN ASSOC-KIND"); - } + case 0: + Set links = fParent.system().state().linksOfAssociation(assoc).links(); + for (MLink link : links) { + MAssociation linkAssoc = link.association(); + if (linkAssoc == null) continue; + if (linkAssoc.isDerived() || linkAssoc.isUnion()) { + assocs.computeIfAbsent(derivedLinks, k -> new ArrayList<>()).add(link); + } else if (linkAssoc instanceof MAssociationClassImpl) { + assocs.computeIfAbsent(associationClass, k -> new ArrayList<>()).add(link); + } else if (linkAssoc.associationEnds().size() > 2) { + assocs.computeIfAbsent(nAryLinks, k -> new ArrayList<>()).add(link); + } else if (linkAssoc.associatedClasses().size() == 1) { + assocs.computeIfAbsent(reflexiveLinks, k -> new ArrayList<>()).add(link); + } else if (link.linkedObjects().size() == 2 && !link.linkedObjects().get(0).equals(link.linkedObjects().get(1))) { + assocs.computeIfAbsent(binaryLinks, k -> new ArrayList<>()).add(link); + } else { + if (fLog != null) { + fLog.println("ERROR: NO MATCH IN ASSOC-KIND"); + } else { + System.err.println("ERROR: NO MATCH IN ASSOC-KIND"); + } + } - } - break; - case 1: // Aggregation + } + break; + case 1: // Aggregation - // Get aggregations - Set aggregations = fParent.system().state().linksOfAssociation(assoc).links(); + // Get aggregations + Set aggregations = fParent.system().state().linksOfAssociation(assoc).links(); - for (MLink agg : aggregations) { - assocs.computeIfAbsent(aggregation, k -> new ArrayList<>()).add(agg); - } - break; + for (MLink agg : aggregations) { + assocs.computeIfAbsent(aggregation, k -> new ArrayList<>()).add(agg); + } + break; - case 2: // Composition + case 2: // Composition - // Get Compositions - Set compositions = fParent.system().state().linksOfAssociation(assoc).links(); + // Get Compositions + Set compositions = fParent.system().state().linksOfAssociation(assoc).links(); - for (MLink comp : compositions) { - assocs.computeIfAbsent(composition, k -> new ArrayList<>()).add(comp); - } - break; + for (MLink comp : compositions) { + assocs.computeIfAbsent(composition, k -> new ArrayList<>()).add(comp); + } + break; } } return new TreeMap<>(assocs); @@ -1951,8 +1778,8 @@ public TreeMap> mapLinksToKindOfAssociation() { /** * Hide all links of list links - * - * @param links + * + * @param links list of links to hide */ public void hideLink(List links) { for (MLink link : links) { @@ -1962,8 +1789,8 @@ public void hideLink(List links) { /** * Show all links of list links - * - * @param links + * + * @param links list of links to show */ public void showLink(List links) { for (MLink link : links) { @@ -1973,25 +1800,22 @@ public void showLink(List links) { /** * Check if a link is hidden - * - * @param link - * @return true, if link is hidden; else return false + * + * @param link the link instance to check + * @return true if the provided link is currently hidden; otherwise false */ public boolean isHidden(MLink link) { - if (hiddenData.getBinaryLinkToEdgeMap().containsKey(link) || hiddenData.getHalfLinkToEdgeMap().containsKey(link) - || hiddenData.getLinkObjectToNodeEdge().containsKey(link) - || hiddenData.getNaryLinkToDiamondNodeMap().containsKey(link)) { - return true; - } else { - return false; - } + return hiddenData.getBinaryLinkToEdgeMap().containsKey(link) + || hiddenData.getHalfLinkToEdgeMap().containsKey(link) + || (link instanceof MLinkObject && hiddenData.getLinkObjectToNodeEdge().containsKey((MLinkObject) link)) + || hiddenData.getNaryLinkToDiamondNodeMap().containsKey(link); } /** - * - * @param links - * @return 0, if all Links are hidden 1, if all links are shown 2, if there - * are hidden and shown links + * Determine whether the provided list of links is hidden, visible or mixed. + * + * @param links collection of links to evaluate + * @return 0 if all links are hidden, 1 if all links are shown, 2 if mixed, -1 if none present */ public int isHidden(List links) { boolean existHiddenLink = false; @@ -2017,4 +1841,165 @@ public static void setJavaFxCall(boolean javaFxCall) { NewObjectDiagram.javaFxCall = javaFxCall; } + @Override + public ObjectDiagramData getVisibleData() { + return visibleData; + } + + @Override + public ObjectDiagramData getHiddenData() { + return hiddenData; + } + + /** + * Restore helper to determine hidden state for items when restoring layout. + * Mirrors the implementation used in ClassDiagram to remain consistent across diagrams. + */ + @SuppressWarnings("unused") + protected boolean isHidden(PersistHelper helper, int version) { + // The 'version' parameter is reserved for future format-specific logic. + return helper.getElementBooleanValue(LayoutTags.HIDDEN); + } + + /** + * Finds a link for the given association that connects the provided objects and + * matches the serialized linkValue. This method reverses what BinaryAssociationOrLinkEdge.storeAdditionalInfo + * wrote using link.toString(). It prefers exact object-list match and the string representation. + */ + private MLink getLinkByValue(MAssociation assoc, List objects, String linkValue) { + if (assoc == null || objects == null || linkValue == null) { + return null; + } + + Set candidates = fParent.system().state().linksOfAssociation(assoc).links(); + for (MLink l : candidates) { + // first ensure the linked objects match the expected ordering/collection + List linked = l.linkedObjects(); + if (linked.size() == objects.size()) { + boolean sameObjects = true; + for (int i = 0; i < linked.size(); i++) { + if (!linked.get(i).equals(objects.get(i))) { + sameObjects = false; + break; + } + } + if (!sameObjects) continue; + + // compare the string representation stored by the edge + if (linkValue.equals(l.toString())) { + return l; + } + } + } + return null; + } + + @Override + public Set getHiddenNodes() { + return hiddenData.getNodes(); + } + + @Override + protected String getDefaultLayoutFileSuffix() { + // Use a dedicated suffix for object diagram default layouts (consistent with other diagrams) + return "_objdia.clt"; + } + + + @Override + public void stateChanged(SortChangeEvent e) { + for (ObjectNode n : this.visibleData.fObjectToNodeMap.values()) { + n.stateChanged(e); + } + } + + /** + * A kleine Helfermethode zum Erstellen von Actions mit weniger Boilerplate-Code. + * + * @param text Der Text der Action. + * @param listener Der ActionListener, der die Action ausführt. + * @return Die erstellte Action. + */ + private Action createAction(String text, ActionListener listener) { + return new AbstractAction(text) { + @Override + public void actionPerformed(ActionEvent e) { + listener.actionPerformed(e); + } + }; + } + + protected void addBinaryLink(MLink link) { + MAssociation assoc = link.association(); + + MLinkEnd linkEnd1 = link.linkEnd(assoc.associationEnds().get(0)); + MLinkEnd linkEnd2 = link.linkEnd(assoc.associationEnds().get(1)); + + MObject obj1 = linkEnd1.object(); + MObject obj2 = linkEnd2.object(); + + // object link + if (link instanceof MLinkObject) { + BinaryAssociationClassOrObject e = BinaryAssociationClassOrObject.create( + visibleData.getObjectToNodeMap().get(obj1), visibleData.getObjectToNodeMap().get(obj2), + linkEnd1, linkEnd2, visibleData.getObjectToNodeMap().get(link), this, + link); + + if (lastKnownLinkPositions.containsKey(link)) { + e.initialize(); + ObjectNode linkObjNode = visibleData.getObjectToNodeMap().get(link); + if (linkObjNode != null) { + linkObjNode.setStrategy(lastKnownLinkPositions.get(link)); + } + lastKnownLinkPositions.remove(link); + fGraph.addInitializedEdge(e); + } else { + fGraph.addEdge(e); + } + visibleData.getLinkObjectToNodeEdge().put((MLinkObject) link, e); + fLayouter = null; + } else { + // binary link + boolean isHidden = false; + ObjectNode node1; + ObjectNode node2; + + if (visibleData.getObjectToNodeMap().containsKey(obj1)) { + node1 = visibleData.getObjectToNodeMap().get(obj1); + } else { + node1 = hiddenData.getObjectToNodeMap().get(obj1); + isHidden = true; + } + + if (visibleData.getObjectToNodeMap().containsKey(obj2)) { + node2 = visibleData.getObjectToNodeMap().get(obj2); + } else { + node2 = hiddenData.getObjectToNodeMap().get(obj2); + isHidden = true; + } + + BinaryAssociationOrLinkEdge e = createBinaryAssociationOrLinkEdge(node1, node2, linkEnd1, + linkEnd2, this, link); + + if (link.isVirtual()) { + e.setDashed(true); + } + + if (isHidden) { + hiddenData.getBinaryLinkToEdgeMap().put(link, e); + } else { + fGraph.addEdge(e); + visibleData.getBinaryLinkToEdgeMap().put(link, e); + fLayouter = null; + } + } + } + + /** + * Factory hook for creating binary link edges. Kept as a protected method to allow easy overriding in subclasses. + */ + protected BinaryAssociationOrLinkEdge createBinaryAssociationOrLinkEdge(PlaceableNode source, PlaceableNode target, + MLinkEnd sourceEnd, MLinkEnd targetEnd, NewObjectDiagram diagram, MLink link) { + return BinaryAssociationOrLinkEdge.create(source, target, sourceEnd, targetEnd, diagram, link); + } } From 82ca193dd38d12cdf2d90c044a4449fa79612dcc Mon Sep 17 00:00:00 2001 From: ahmedkha79 Date: Wed, 18 Feb 2026 20:05:30 +0100 Subject: [PATCH 10/20] Update use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java | 1 - 1 file changed, 1 deletion(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index ca9d107e1..d45c66211 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -1505,7 +1505,6 @@ public void restorePlacementInfos(PersistHelper helper, int version) { } // Helper: restore binary association edges placement info - @SuppressWarnings("unused") private void restoreBinaryEdges(PersistHelper helper, int version, Set hiddenObjects) { AutoPilot ap = new AutoPilot(helper.getNav()); helper.getNav().push(); From 62e2e26b7c6e6f49dedbcf835c37184add076cce Mon Sep 17 00:00:00 2001 From: ahmedkha79 Date: Wed, 18 Feb 2026 20:08:22 +0100 Subject: [PATCH 11/20] Update use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../gui/views/diagrams/objectdiagram/NewObjectDiagram.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index d45c66211..eac63dfea 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -675,8 +675,8 @@ protected void addNAryLink(MLink link) { } if (linkObjEdge != null) { halfEdges.add(linkObjEdge); - edgeIds.add(((MLinkObject) link).name()); - } + edgeIds.add(((MLinkObject) link).name()); + } } node.setHalfEdges(halfEdges, edgeIds); From fbcd4fe37fc1e811cde39c4ae6d317a2cfb7ca8f Mon Sep 17 00:00:00 2001 From: ahmedkha79 Date: Wed, 18 Feb 2026 20:08:38 +0100 Subject: [PATCH 12/20] Update use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../views/diagrams/objectdiagram/NewObjectDiagram.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index eac63dfea..e4d1d7e8c 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -1913,11 +1913,11 @@ public void stateChanged(SortChangeEvent e) { } /** - * A kleine Helfermethode zum Erstellen von Actions mit weniger Boilerplate-Code. + * A small helper method for creating {@link Action} instances with less boilerplate code. * - * @param text Der Text der Action. - * @param listener Der ActionListener, der die Action ausführt. - * @return Die erstellte Action. + * @param text The text of the action. + * @param listener The {@link ActionListener} that executes the action. + * @return The created action. */ private Action createAction(String text, ActionListener listener) { return new AbstractAction(text) { From 4dd78cedf13aaf7c9b329a97841d9bebc0bda0ae Mon Sep 17 00:00:00 2001 From: ahmedkha79 Date: Wed, 18 Feb 2026 20:10:36 +0100 Subject: [PATCH 13/20] Update use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java | 1 - 1 file changed, 1 deletion(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index e4d1d7e8c..f02411064 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -1854,7 +1854,6 @@ public ObjectDiagramData getHiddenData() { * Restore helper to determine hidden state for items when restoring layout. * Mirrors the implementation used in ClassDiagram to remain consistent across diagrams. */ - @SuppressWarnings("unused") protected boolean isHidden(PersistHelper helper, int version) { // The 'version' parameter is reserved for future format-specific logic. return helper.getElementBooleanValue(LayoutTags.HIDDEN); From 921182ee46c9b96ec607d54b5ad2596c15dfff81 Mon Sep 17 00:00:00 2001 From: ahmedkha79 Date: Wed, 18 Feb 2026 20:10:50 +0100 Subject: [PATCH 14/20] Update use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index f02411064..0dd0e23e7 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -1906,7 +1906,7 @@ protected String getDefaultLayoutFileSuffix() { @Override public void stateChanged(SortChangeEvent e) { - for (ObjectNode n : this.visibleData.fObjectToNodeMap.values()) { + for (ObjectNode n : this.visibleData.getObjectToNodeMap().values()) { n.stateChanged(e); } } From 1a699c97f080a23ecafd590a19d3cee84557fdfa Mon Sep 17 00:00:00 2001 From: ahmedkha79 Date: Wed, 18 Feb 2026 20:11:02 +0100 Subject: [PATCH 15/20] Update use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java | 1 - 1 file changed, 1 deletion(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index 0dd0e23e7..4b87b2cbb 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -994,7 +994,6 @@ public void actionPerformed(ActionEvent e) { /** * Show properties of objects */ - @SuppressWarnings("unused") static class ActionShowProperties extends AbstractAction { private final MObject fObject; From 84e59c0023118b12c797402582851e7a24713c8c Mon Sep 17 00:00:00 2001 From: ahmed Date: Wed, 18 Feb 2026 20:54:14 +0100 Subject: [PATCH 16/20] Harden getLinkByValue in NewObjectDiagram: null-safety, List.equals, Objects.equals; suppress unused warnings --- .../objectdiagram/NewObjectDiagram.java | 55 +++++++++++++------ 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index 4b87b2cbb..247a4d357 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -48,6 +48,7 @@ import java.util.Set; import java.util.TreeMap; import java.util.WeakHashMap; +import java.util.Objects; import javax.swing.AbstractAction; import javax.swing.Action; @@ -1864,30 +1865,50 @@ protected boolean isHidden(PersistHelper helper, int version) { * wrote using link.toString(). It prefers exact object-list match and the string representation. */ private MLink getLinkByValue(MAssociation assoc, List objects, String linkValue) { - if (assoc == null || objects == null || linkValue == null) { + // defensive preconditions + if (assoc == null || objects == null) { return null; } - Set candidates = fParent.system().state().linksOfAssociation(assoc).links(); - for (MLink l : candidates) { - // first ensure the linked objects match the expected ordering/collection + Set allLinks = fParent.system().state().linksOfAssociation(assoc).links(); + if (allLinks == null || allLinks.isEmpty()) { + return null; + } + + // First, collect all links that connect exactly the given objects (in order). + List matchingLinks = new ArrayList<>(); + for (MLink l : allLinks) { + if (l == null) continue; List linked = l.linkedObjects(); - if (linked.size() == objects.size()) { - boolean sameObjects = true; - for (int i = 0; i < linked.size(); i++) { - if (!linked.get(i).equals(objects.get(i))) { - sameObjects = false; - break; - } - } - if (!sameObjects) continue; + if (linked == null || linked.size() != objects.size()) continue; - // compare the string representation stored by the edge - if (linkValue.equals(l.toString())) { - return l; - } + // Use List.equals which performs element-wise, null-safe comparisons + if (linked.equals(objects)) { + matchingLinks.add(l); + } + } + + // No link connects exactly these objects. + if (matchingLinks.isEmpty()) { + return null; + } + + // Single candidate: return it directly without relying on toString(). + if (matchingLinks.size() == 1) { + return matchingLinks.getFirst(); + } + + // Multiple candidates: use linkValue (if available) to disambiguate. + if (linkValue == null) { + return null; + } + + for (MLink l : matchingLinks) { + if (Objects.equals(linkValue, l == null ? null : l.toString())) { + return l; } } + return null; } From 4b6617cd28ef65c99c5c4b25130da696f0bcb31a Mon Sep 17 00:00:00 2001 From: ahmedkha79 Date: Wed, 18 Feb 2026 21:12:01 +0100 Subject: [PATCH 17/20] Update use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../objectdiagram/NewObjectDiagram.java | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index 247a4d357..9c15b9347 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -1880,10 +1880,38 @@ private MLink getLinkByValue(MAssociation assoc, List objects, String l for (MLink l : allLinks) { if (l == null) continue; List linked = l.linkedObjects(); - if (linked == null || linked.size() != objects.size()) continue; + * (optionally) matches the serialized linkValue. This method reverses what + * BinaryAssociationOrLinkEdge.storeAdditionalInfo wrote using link.toString(). + * + * If there is exactly one link connecting the given objects, that link is + * returned without checking linkValue (robust against toString() changes). + * If multiple links connect the same objects, linkValue is used to + * disambiguate via link.toString(). + */ + private MLink getLinkByValue(MAssociation assoc, List objects, String linkValue) { + if (assoc == null || objects == null) { + return null; + } + + Set allLinks = fParent.system().state().linksOfAssociation(assoc).links(); + + // First, collect all links that connect exactly the given objects (in order). + List matchingLinks = new ArrayList<>(); + for (MLink l : allLinks) { + List linked = l.linkedObjects(); + if (linked.size() != objects.size()) { + continue; + } + + boolean sameObjects = true; + for (int i = 0; i < linked.size(); i++) { + if (!linked.get(i).equals(objects.get(i))) { + sameObjects = false; + break; + } + } - // Use List.equals which performs element-wise, null-safe comparisons - if (linked.equals(objects)) { + if (sameObjects) { matchingLinks.add(l); } } @@ -1895,7 +1923,7 @@ private MLink getLinkByValue(MAssociation assoc, List objects, String l // Single candidate: return it directly without relying on toString(). if (matchingLinks.size() == 1) { - return matchingLinks.getFirst(); + return matchingLinks.get(0); } // Multiple candidates: use linkValue (if available) to disambiguate. @@ -1904,7 +1932,7 @@ private MLink getLinkByValue(MAssociation assoc, List objects, String l } for (MLink l : matchingLinks) { - if (Objects.equals(linkValue, l == null ? null : l.toString())) { + if (linkValue.equals(l.toString())) { return l; } } From 662eaa38994b4bbc90fccd49c5e7d9cb5a5acf72 Mon Sep 17 00:00:00 2001 From: ahmedkha79 Date: Wed, 18 Feb 2026 21:15:49 +0100 Subject: [PATCH 18/20] Update use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../views/diagrams/objectdiagram/NewObjectDiagram.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index 9c15b9347..6afe3d50d 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -1947,11 +1947,11 @@ public Set getHiddenNodes() { @Override protected String getDefaultLayoutFileSuffix() { - // Use a dedicated suffix for object diagram default layouts (consistent with other diagrams) - return "_objdia.clt"; + // Returning null preserves the historic behavior: object diagrams do not + // auto-load/auto-save a default layout via DiagramView.getDefaultLayoutFile(). + // Introducing a non-null suffix here would be a user-visible persistence change. + return null; } - - @Override public void stateChanged(SortChangeEvent e) { for (ObjectNode n : this.visibleData.getObjectToNodeMap().values()) { From 212e224ff24b4b0f331edb62717e258667b9fd30 Mon Sep 17 00:00:00 2001 From: ahmedkha79 Date: Wed, 18 Feb 2026 21:18:55 +0100 Subject: [PATCH 19/20] Update use-gui/src/main/java/module-info.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- use-gui/src/main/java/module-info.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/use-gui/src/main/java/module-info.java b/use-gui/src/main/java/module-info.java index c073fda2a..06d7efda6 100644 --- a/use-gui/src/main/java/module-info.java +++ b/use-gui/src/main/java/module-info.java @@ -34,5 +34,5 @@ exports org.tzi.use.gui.views.diagrams.elements; exports org.tzi.use.gui.views.diagrams.elements.edges; exports org.tzi.use.gui.views.diagrams.event; - exports org.tzi.use.gui.views.selection.objectselection; + exports org.tzi.use.gui.views.selection.objectselection to com.google.common; } \ No newline at end of file From e509b8fa210ffa77df91e20883e688e719e3a4a4 Mon Sep 17 00:00:00 2001 From: ahmedkha79 Date: Wed, 18 Feb 2026 21:21:02 +0100 Subject: [PATCH 20/20] Update use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../views/diagrams/objectdiagram/NewObjectDiagram.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java index 6afe3d50d..1910c9d43 100644 --- a/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java +++ b/use-gui/src/main/java/org/tzi/use/gui/views/diagrams/objectdiagram/NewObjectDiagram.java @@ -911,8 +911,13 @@ public void deleteLink(MLink link) { * @param obj the MInstance whose node should be refreshed */ public void updateObject(MInstance obj) { - // Use computeIfPresent with an explicit cast of the key to the Map's key type (MObject) - visibleData.getObjectToNodeMap().computeIfPresent((MObject) obj, (k, node) -> { + // Only update if the instance is actually an MObject to avoid ClassCastException + if (!(obj instanceof MObject)) { + return; + } + + MObject mObj = (MObject) obj; + visibleData.getObjectToNodeMap().computeIfPresent(mObj, (k, node) -> { invalidateNode(node); return node; // keep the existing mapping });