From 63467a17d06397b831373b0d736da9cb404436dd Mon Sep 17 00:00:00 2001
From: Simon Barner <barner@fortiss.org>
Date: Tue, 30 Jan 2018 14:27:19 +0000
Subject: [PATCH] Ensure that hint how to create a connection is displayed
 until the user has successfully created one IConnection specialization. refs
 2229

---
 .../fortiss/tooling/base/ui/editor/.ratings   |  3 +-
 .../ui/editor/CommonDiagramEditorBase.java    | 82 ++++++++++---------
 2 files changed, 46 insertions(+), 39 deletions(-)

diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/editor/.ratings b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/editor/.ratings
index ac0bea468..2b36aa4f2 100644
--- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/editor/.ratings
+++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/editor/.ratings
@@ -1,7 +1,6 @@
-
 AdvancedTreeViewerEditorBase.java 731483771c9d23f5b926da79b027b570001ea6cd GREEN
 AllocationDiagramEditorBase.java 3c03b9220f1c342ded673d6d1b2fd2c01b57fba6 GREEN
-CommonDiagramEditorBase.java d1b10f0eae6fe13508d185c0cc983c46747928dc RED
+CommonDiagramEditorBase.java 3d83b0b5eb1081b0a85e88d291062f215a7ca74e YELLOW
 ConstraintBasedProcessEditor.java ff7253ad26f25f681e09a36d0527b0214df08d30 RED
 DiagramEditorBase.java 3d2bb40e18548ebca0dfdd78f094598e5ee298d1 GREEN
 DiagramKeyHandler.java 9c59eca862c9f878da7cbf7c220f26b38737095c GREEN
diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/editor/CommonDiagramEditorBase.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/editor/CommonDiagramEditorBase.java
index 90047a448..47355bf09 100644
--- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/editor/CommonDiagramEditorBase.java
+++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/editor/CommonDiagramEditorBase.java
@@ -25,6 +25,7 @@ import static org.eclipse.gef.editparts.ZoomManager.FIT_WIDTH;
 import static org.fortiss.tooling.base.layout.DefaultLayoutConstants.DEFAULT_GRID_ORIGIN_X;
 import static org.fortiss.tooling.base.layout.DefaultLayoutConstants.DEFAULT_GRID_ORIGIN_Y;
 import static org.fortiss.tooling.base.layout.DefaultLayoutConstants.DEFAULT_GRID_SIZE;
+import static org.fortiss.tooling.common.util.LambdaUtils.asStream;
 import static org.fortiss.tooling.kernel.ui.util.EObjectSelectionUtils.getEObjectElements;
 import static org.fortiss.tooling.kernel.ui.util.EObjectSelectionUtils.getFirstElement;
 
@@ -34,6 +35,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.conqat.ide.commons.ui.selection.SelectionUtils;
@@ -44,7 +46,6 @@ import org.eclipse.draw2d.geometry.Dimension;
 import org.eclipse.draw2d.geometry.Point;
 import org.eclipse.emf.common.notify.Adapter;
 import org.eclipse.emf.common.notify.Notification;
-import org.eclipse.emf.common.util.TreeIterator;
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.util.EContentAdapter;
 import org.eclipse.gef.EditDomain;
@@ -141,15 +142,32 @@ abstract class CommonDiagramEditorBase<T extends EObject> extends GEFEditorBase<
 	/** A container for editor actions. */
 	private final ActionRegistry actionRegistry = new ActionRegistry();
 
-	/**
-	 * Number of times the hint was displayed until we assume the user knows how to draw a
-	 * connection.
-	 */
-	private static int numberOfHintDisplays = 1;
+	/** Maps projects to the number of {@link IConnection} contained in them. */
+	private static Map<EObject, Long> connectionCountMap = new HashMap<EObject, Long>();
+
+	/** Predicate whether to show the hint how to create {@link IConnection}s. */
+	private static boolean shouldDisplayCreateConnectionHint(EObject object) {
+		if(connectionCountMap == null) {
+			return false;
+		}
+
+		// Determine number of connections in current rootObject ("project")
+		EObject rootObject = getRootObject(object);
+		Long n = asStream(rootObject.eAllContents()).filter(e -> e instanceof IConnection).count();
 
-	/** Returns numberOfHintDisplays *and decrements it*. */
-	private static boolean shouldDisplayHint() {
-		return numberOfHintDisplays-- >= 0;
+		Long oldN = connectionCountMap.get(rootObject);
+		boolean rval = oldN == null || n <= oldN;
+		if(rval == false) {
+			// Increase in IConnection count detected: Disable hint.
+			for(EObject obj : connectionCountMap.keySet()) {
+				obj.eAdapters().remove(addConnectionAdapter);
+			}
+			connectionCountMap = null;
+		} else {
+			connectionCountMap.put(rootObject, n);
+		}
+
+		return rval;
 	}
 
 	/** Constructor. */
@@ -158,10 +176,7 @@ abstract class CommonDiagramEditorBase<T extends EObject> extends GEFEditorBase<
 		this.editPartFactory = factory;
 	}
 
-	/**
-	 * Adapter to watch for added {@link IConnection}s (used to update {@link #numberOfHintDisplays}
-	 * ).
-	 */
+	/** Adapter to watch for added {@link IConnection}s. */
 	private static final Adapter addConnectionAdapter = new EContentAdapter() {
 		@Override
 		public void notifyChanged(Notification notification) {
@@ -177,18 +192,8 @@ abstract class CommonDiagramEditorBase<T extends EObject> extends GEFEditorBase<
 			Object newValue = notification.getNewValue();
 			if(eventType == Notification.ADD && newValue instanceof IConnection &&
 					notification.getNotifier() == ((EObject)newValue).eContainer()) {
-				if(!shouldDisplayHint()) {
-					// Hints will no longer be displayed: remove adapter
-					EObject rootObj = (EObject)notification.getNotifier();
-					while(rootObj.eContainer() != null) {
-						rootObj = rootObj.eContainer();
-					}
-					rootObj.eAdapters().remove(addConnectionAdapter);
-					for(TreeIterator<EObject> iter = rootObj.eAllContents(); iter.hasNext();) {
-						EObject obj = iter.next();
-						obj.eAdapters().remove(addConnectionAdapter);
-					}
-				}
+
+				shouldDisplayCreateConnectionHint((EObject)notification.getNotifier());
 			}
 		}
 	};
@@ -205,7 +210,7 @@ abstract class CommonDiagramEditorBase<T extends EObject> extends GEFEditorBase<
 				Object model = ep.getModel();
 
 				String hint = "";
-				if(shouldDisplayHint()) {
+				if(model instanceof EObject && shouldDisplayCreateConnectionHint((EObject)model)) {
 					String key = Platform.getOS().equals(Platform.OS_LINUX) ? "Ctrl" : "Alt";
 					String commonStr = " by pressing " + key + " and dragging";
 					if(model instanceof IConnector) {
@@ -213,8 +218,6 @@ abstract class CommonDiagramEditorBase<T extends EObject> extends GEFEditorBase<
 					} else if(model instanceof IHierarchicElement) {
 						hint = "Create a connection" + commonStr;
 					}
-					hint +=
-							" (select anything on the diagram to prevent further display of this message).";
 				}
 				control.setToolTipText(hint);
 			}
@@ -231,20 +234,25 @@ abstract class CommonDiagramEditorBase<T extends EObject> extends GEFEditorBase<
 				.addSelectionListener(selectionListener);
 
 		// Install adapter to top-most object to watch for addition of IConnections.
-		if(shouldDisplayHint()) {
-			EObject model = getEditedObject();
-			EObject obj = model;
-			while(obj != null) {
-				obj = obj.eContainer();
-			}
-			// TODO(VA) shouldn't obj be used here? Otherwise obj is used nowhere...
-			if(!model.eAdapters().contains(addConnectionAdapter)) {
-				model.eAdapters().add(addConnectionAdapter);
+		if(shouldDisplayCreateConnectionHint(getEditedObject())) {
+			EObject rootObj = getRootObject(getEditedObject());
+
+			if(!rootObj.eAdapters().contains(addConnectionAdapter)) {
+				rootObj.eAdapters().add(addConnectionAdapter);
 			}
 		}
 		viewer.setKeyHandler(new DiagramKeyHandler(viewer));
 	}
 
+	/** Returns the root object of the given {@code object}. */
+	private static EObject getRootObject(EObject object) {
+		EObject rootObj = object;
+		while(rootObj.eContainer() != null) {
+			rootObj = rootObj.eContainer();
+		}
+		return rootObj;
+	}
+
 	/** {@inheritDoc} */
 	@Override
 	public EObject getSelectedModelElement() {
-- 
GitLab