From ef2f3b3aa4921892d925dd4d4d54cce508630161 Mon Sep 17 00:00:00 2001
From: Simon Barner <barner@fortiss.org>
Date: Thu, 28 Sep 2023 09:26:19 +0200
Subject: [PATCH] Move TreeContextMenuItem to DynamicTreeUIProviderBase

* Context menus are generally applicable, not only for
  ModelElementTreeViewers

Issue-Ref: 4322
Issue-URL: https://git.fortiss.org/af3/af3/-/issues/4322

Signed-off-by: Simon Barner <barner@fortiss.org>
---
 .../ui/javafx/control/treetableview/.ratings  |   2 +-
 .../treetableview/ModelElementTreeViewer.java |  85 ---------------
 .../ui/javafx/control/treetableview/.ratings  |   2 +-
 .../DynamicTreeUIProviderBase.java            | 100 +++++++++++++++++-
 4 files changed, 97 insertions(+), 92 deletions(-)

diff --git a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/javafx/control/treetableview/.ratings b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/javafx/control/treetableview/.ratings
index 316c66d44..f6028344d 100644
--- a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/javafx/control/treetableview/.ratings
+++ b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/javafx/control/treetableview/.ratings
@@ -1,2 +1,2 @@
 DynamicTreeTableNameProvider.java 3ca45f24b94e97b02313e80b16ba8b370f541541 GREEN
-ModelElementTreeViewer.java af87b0aa1780f3b02a60d09db9676b4e54903be5 YELLOW
+ModelElementTreeViewer.java 83a3693cf820161e42e7d84a697a3cd0d55f8c1f YELLOW
diff --git a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/javafx/control/treetableview/ModelElementTreeViewer.java b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/javafx/control/treetableview/ModelElementTreeViewer.java
index af87b0aa1..83a3693cf 100644
--- a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/javafx/control/treetableview/ModelElementTreeViewer.java
+++ b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/javafx/control/treetableview/ModelElementTreeViewer.java
@@ -18,10 +18,6 @@ package org.fortiss.tooling.base.ui.javafx.control.treetableview;
 import static javafx.embed.swt.SWTFXUtils.toFXImage;
 import static org.fortiss.tooling.kernel.ui.util.KernelUIUtils.getName;
 
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.List;
-
 import org.fortiss.tooling.base.model.element.IHierarchicElement;
 import org.fortiss.tooling.base.model.element.IModelElement;
 import org.fortiss.tooling.common.ui.javafx.AF3FXViewPart;
@@ -32,11 +28,7 @@ import org.fortiss.tooling.common.ui.javafx.control.treetableview.DynamicTreeVie
 import org.fortiss.tooling.kernel.model.INamedElement;
 import org.fortiss.tooling.kernel.ui.service.IModelElementHandlerService;
 
-import javafx.event.ActionEvent;
-import javafx.event.EventHandler;
 import javafx.scene.Node;
-import javafx.scene.control.ContextMenu;
-import javafx.scene.control.MenuItem;
 import javafx.scene.control.TreeView;
 import javafx.scene.image.Image;
 import javafx.scene.image.ImageView;
@@ -77,80 +69,11 @@ public class ModelElementTreeViewer<T extends INamedElement> {
 			}
 			return null;
 		}
-
-		/** {@inheritDoc} */
-		@Override
-		public final ContextMenu createContextMenu(T element) {
-			ContextMenu menu = new ContextMenu();
-			for(Class<? extends TreeContextMenuItem> entryType : contextMenuEntryTypes) {
-
-				try {
-					Constructor<? extends TreeContextMenuItem> ctr =
-							entryType.getConstructor(INamedElement.class);
-					TreeContextMenuItem entry = ctr.newInstance(element);
-					if(!entry.isHidden()) {
-						menu.getItems().add(entry);
-						entry.setDisable(entry.isDisabled());
-					}
-				} catch(Exception e) {
-					e.printStackTrace();
-				}
-			}
-			return menu;
-		}
-	}
-
-	/** Base class for {@link MenuItem}s used by {@link ModelElementTreeViewer}s. */
-	protected static abstract class TreeContextMenuItem extends MenuItem {
-
-		/** The model element on which the context menu operates. */
-		private INamedElement element;
-
-		/** Constructor. */
-		public TreeContextMenuItem(INamedElement element, String label) {
-			super(label);
-			init(element);
-		}
-
-		/** Constructor. */
-		public TreeContextMenuItem(INamedElement element, String label, Node graphic) {
-			super(label, graphic);
-			init(element);
-		}
-
-		/** Helper for constructors. */
-		private void init(INamedElement element) {
-			this.element = element;
-			setOnAction(createOnActionHandler());
-		}
-
-		/** Getter for {@link #element}. */
-		protected INamedElement getElement() {
-			return element;
-		}
-
-		/** Predicate iff this {@link TreeContextMenuItem} is hidden. */
-		public abstract boolean isHidden();
-
-		/** Predicate when this {@link TreeContextMenuItem} is disabled. */
-		public abstract boolean isDisabled();
-
-		/**
-		 * Factory method for {@link EventHandler} that implements the action triggered by the
-		 * context menu.
-		 */
-		protected abstract EventHandler<ActionEvent> createOnActionHandler();
 	}
 
 	/** References the constructed {@link DynamicTreeViewer} "controller". */
 	protected DynamicTreeViewer<T> dynTreeViewer;
 
-	/**
-	 * List of context menu entries types that supplied by clients
-	 * (see{@link #addContextMenuEntry(Class)}).
-	 */
-	protected List<Class<? extends TreeContextMenuItem>> contextMenuEntryTypes = new ArrayList<>();
-
 	/** Constructor. */
 	public ModelElementTreeViewer(TreeView<T> treeView, T modelRoot,
 			DynamicTreeContentProviderBase<T> contentProvider) {
@@ -170,14 +93,6 @@ public class ModelElementTreeViewer<T extends INamedElement> {
 		return new ModelElementUIProvider();
 	}
 
-	/**
-	 * Method to define context {@link TreeContextMenuItem}s. Depending on the selected content, the
-	 * editor will show and enable the context menu.
-	 */
-	public void addContextMenuEntry(Class<? extends TreeContextMenuItem> menuItemType) {
-		contextMenuEntryTypes.add(menuItemType);
-	}
-
 	/** Update the internal viewer. */
 	public void update() {
 		dynTreeViewer.update();
diff --git a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/.ratings b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/.ratings
index 0994db332..3aa6ebc49 100644
--- a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/.ratings
+++ b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/.ratings
@@ -7,7 +7,7 @@ DynamicTreeItem.java 7e81ea98038b5eca90df583e0268d4e8f37aaf25 GREEN
 DynamicTreeItemBase.java d883066ecc181120302ca32f328538de7a45b093 GREEN
 DynamicTreeTableUIProviderBase.java c52a1f9598de25874f83c133a8cbbcddc86442e9 GREEN
 DynamicTreeTableViewer.java 77e9995a3bee37d57578dad9434a53c702128efa YELLOW
-DynamicTreeUIProviderBase.java 82d3c051213f0147f4c67ad247a08696cee73110 GREEN
+DynamicTreeUIProviderBase.java 3688498020e322174d222d433220ee56c4549fbb YELLOW
 DynamicTreeViewer.java b0d8cc4b3e11aa970446af12d1e54c750713b297 YELLOW
 DynamicTreeViewerBase.java a2013538b62d86f6a09efdf2cd78babac2072484 GREEN
 EmptyChildrenContentProvider.java 51b4468f9df8423abeea5ac6aa2f6cf99c2eb512 GREEN
diff --git a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/DynamicTreeUIProviderBase.java b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/DynamicTreeUIProviderBase.java
index 82d3c0512..368849802 100644
--- a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/DynamicTreeUIProviderBase.java
+++ b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/DynamicTreeUIProviderBase.java
@@ -13,8 +13,15 @@
  *******************************************************************************/
 package org.fortiss.tooling.common.ui.javafx.control.treetableview;
 
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.List;
+
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
 import javafx.scene.Node;
 import javafx.scene.control.ContextMenu;
+import javafx.scene.control.MenuItem;
 import javafx.scene.control.TreeItem;
 import javafx.scene.input.ClipboardContent;
 import javafx.scene.input.Dragboard;
@@ -55,12 +62,95 @@ public abstract class DynamicTreeUIProviderBase<T> {
 	}
 
 	/**
-	 * @param element
-	 *            the displayed element
-	 * @return the context menu
+	 * Base class for {@link MenuItem}s used by {@link DynamicTreeViewer}s. Subclasses must provide
+	 * exactly one public constructor that takes the underlying tree element as single argument.
 	 */
-	public ContextMenu createContextMenu(T element) {
-		return null;
+	public static abstract class TreeContextMenuItem<T> extends MenuItem {
+
+		/** The model element on which the context menu operates. */
+		private T element;
+
+		/** Constructor. */
+		public TreeContextMenuItem(T element, String label) {
+			super(label);
+			init(element);
+		}
+
+		/** Constructor. */
+		public TreeContextMenuItem(T element, String label, Node graphic) {
+			super(label, graphic);
+			init(element);
+		}
+
+		/** Helper for constructors. */
+		private void init(T element) {
+			this.element = element;
+			setOnAction(createOnActionHandler());
+		}
+
+		/** Getter for {@link #element}. */
+		protected T getElement() {
+			return element;
+		}
+
+		/** Predicate iff this {@link TreeContextMenuItem} is hidden. */
+		public abstract boolean isHidden();
+
+		/** Predicate when this {@link TreeContextMenuItem} is disabled. */
+		public abstract boolean isDisabled();
+
+		/**
+		 * Factory method for {@link EventHandler} that implements the action triggered by the
+		 * context menu.
+		 */
+		protected abstract EventHandler<ActionEvent> createOnActionHandler();
+	}
+
+	/**
+	 * List of context menu entries types that supplied by clients
+	 * (see{@link #addContextMenuEntry(Class)}).
+	 */
+	private List<Class<? extends TreeContextMenuItem<T>>> contextMenuEntryTypes = new ArrayList<>();
+
+	/**
+	 * Method to define context {@link TreeContextMenuItem}s. Depending on the selected content, the
+	 * editor will show and enable the context menu.
+	 */
+	protected void addContextMenuEntry(Class<? extends TreeContextMenuItem<T>> menuItemType) {
+		contextMenuEntryTypes.add(menuItemType);
+	}
+
+	/**
+	 * Creates a context menu based on the the {@link TreeContextMenuItem} types registered via
+	 * {@link #addContextMenuEntry(Class)}.
+	 */
+	public final ContextMenu createContextMenu(T element) {
+		ContextMenu menu = new ContextMenu();
+		for(Class<? extends TreeContextMenuItem<T>> entryType : contextMenuEntryTypes) {
+
+			try {
+				Constructor<?>[] ctrs = entryType.getConstructors();
+				if(ctrs.length != 1) {
+					throw new RuntimeException(
+							"Subclasses of TreeContextMenuItem must provide exactly one public constructor");
+				}
+				@SuppressWarnings("unchecked") Constructor<? extends TreeContextMenuItem<T>> ctr =
+						(Constructor<? extends TreeContextMenuItem<T>>)ctrs[0];
+				if(ctr.getParameterCount() != 1) {
+					throw new RuntimeException(
+							"The constructor of subclasses of TreeContextMenuItem must take the tree element for which the context menu is created as single argument.");
+				}
+
+				TreeContextMenuItem<T> entry = ctr.newInstance(element);
+				if(!entry.isHidden()) {
+					menu.getItems().add(entry);
+					entry.setDisable(entry.isDisabled());
+				}
+			} catch(Exception e) {
+				e.printStackTrace();
+			}
+		}
+		return menu;
 	}
 
 	/**
-- 
GitLab