From c920acd557d2b96f3aade8a2de51d524a94f45b8 Mon Sep 17 00:00:00 2001
From: Florian Hoelzl <hoelzl@fortiss.org>
Date: Tue, 18 Feb 2020 10:57:59 +0100
Subject: [PATCH] Kernel: JavaFX view for model elements view implementation.

Issue-Ref: 3921
Issue-Url: https://af3-developer.fortiss.org/issues/3907
Signed-off-by: Florian Hoelzl <hoelzl@fortiss.org>
---
 .../ui/javafx/control/treetableview/.ratings  |   2 +-
 .../treetableview/DynamicTreeViewer.java      |  13 ++
 .../tooling/kernel/ui/internal/views/.ratings |   3 +-
 .../internal/views/ModelElementsViewFX.java   | 190 +++++++++++++++++-
 4 files changed, 198 insertions(+), 10 deletions(-)

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 4850e6d5c..e664805a7 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
@@ -3,6 +3,6 @@ DynamicTreeItem.java 75dc5534b119ffdb3c10a65810c2a0f330b7955e GREEN
 DynamicTreeTableUIProviderBase.java 7bfc1395283d3dc10026aff5e2e65df88d25f3a7 GREEN
 DynamicTreeTableViewer.java 43757359b3071192ae79710bcbc0e9577bb6f62d GREEN
 DynamicTreeUIProviderBase.java 56fe4df4577b35f1e5e6e4c4be189b706c852d52 GREEN
-DynamicTreeViewer.java da5e24ae57777a482d8e12c8262513d8143bfa93 GREEN
+DynamicTreeViewer.java 6fc80215348ddb8bb0f79f5b1b66bad1d73adace YELLOW
 DynamicTreeViewerBase.java 47124c847de322a0ae26eb7a114f85ce4bd02d7e GREEN
 IDoubleClickHandler.java 447f7769dead9a106b3ea3139ef0da51eb0b9a89 GREEN
diff --git a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/DynamicTreeViewer.java b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/DynamicTreeViewer.java
index da5e24ae5..6fc802153 100644
--- a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/DynamicTreeViewer.java
+++ b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/DynamicTreeViewer.java
@@ -169,6 +169,19 @@ public final class DynamicTreeViewer<T> extends DynamicTreeViewerBase<T> {
 		}
 	}
 
+	/** Expands the whole tree. */
+	public void expandAllItems() {
+		expandAllItems(rootItem);
+	}
+
+	/** Recursively expands the whole tree. */
+	private void expandAllItems(TreeItem<T> item) {
+		item.setExpanded(true);
+		for(TreeItem<T> child : item.getChildren()) {
+			expandAllItems(child);
+		}
+	}
+
 	/** Returns the underlying {@link TreeView}. */
 	public TreeView<T> getControl() {
 		return view;
diff --git a/org.fortiss.tooling.kernel.ui/src/org/fortiss/tooling/kernel/ui/internal/views/.ratings b/org.fortiss.tooling.kernel.ui/src/org/fortiss/tooling/kernel/ui/internal/views/.ratings
index 4cd930deb..6a45de1ab 100644
--- a/org.fortiss.tooling.kernel.ui/src/org/fortiss/tooling/kernel/ui/internal/views/.ratings
+++ b/org.fortiss.tooling.kernel.ui/src/org/fortiss/tooling/kernel/ui/internal/views/.ratings
@@ -2,11 +2,10 @@ DoubleClick.java fd00e7737c0bad903433c0adb67dad92220ff451 GREEN
 GenericNewMenu.java 7e0dd435cb5ca6d4b486235ec17eef3e5c7aa5f6 GREEN
 LibraryView.java 44107622da7bcf431e1177e462d711646488957f GREEN
 LibraryViewDragSourceAdapter.java 56ef61b214ef5d6cb5b751791a92158bda0391ec GREEN
-LibraryViewFX.java 5d9a95ee3362c9610728d6f9cee33672994640c2 RED
 LinkWithEditorPartListener.java c5ab74424378e7b158a805c4dd14fc03c8abeded GREEN
 MarkerViewContentProvider.java 4cb1192baebe21bca951c439c163d0c171512515 GREEN
 MarkerViewPart.java cbb650271b6877af205421b7cb11f930440a7ef9 GREEN
-ModelElementsViewFX.java 77a93fe5ca28e4ce0c18deeca9cb4735a05032f8 RED
+ModelElementsViewFX.java 395402b845f6ce997ab8dac96a8fc70e715f88ab YELLOW
 NavigatorNewMenu.java a35e391960d1dacbe7f77982e53e1891e9382d5a GREEN
 NavigatorTreeContentComparator.java d9f1354cfdff78b104b28887d2397e5ca0e9755b GREEN
 NavigatorTreeContentProvider.java 1fbe97bebf3805cc1af190cecd784fc1cfd12306 GREEN
diff --git a/org.fortiss.tooling.kernel.ui/src/org/fortiss/tooling/kernel/ui/internal/views/ModelElementsViewFX.java b/org.fortiss.tooling.kernel.ui/src/org/fortiss/tooling/kernel/ui/internal/views/ModelElementsViewFX.java
index 77a93fe5c..395402b84 100644
--- a/org.fortiss.tooling.kernel.ui/src/org/fortiss/tooling/kernel/ui/internal/views/ModelElementsViewFX.java
+++ b/org.fortiss.tooling.kernel.ui/src/org/fortiss/tooling/kernel/ui/internal/views/ModelElementsViewFX.java
@@ -15,15 +15,36 @@
 +--------------------------------------------------------------------------*/
 package org.fortiss.tooling.kernel.ui.internal.views;
 
+import static java.util.Arrays.asList;
 import static java.util.Collections.emptyList;
+import static org.fortiss.tooling.kernel.utils.EcoreUtils.filterOutInstanceOf;
+import static org.fortiss.tooling.kernel.utils.KernelModelElementUtils.getParentElement;
 
 import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
 
+import org.conqat.ide.commons.ui.ui.EmptyPartListener;
+import org.conqat.lib.commons.collections.IdentityHashSet;
+import org.eclipse.emf.ecore.EObject;
 import org.eclipse.fx.ui.workbench3.FXViewPart;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPart;
 import org.fortiss.tooling.common.ui.javafx.control.treetableview.DynamicTreeContentProviderBase;
 import org.fortiss.tooling.common.ui.javafx.control.treetableview.DynamicTreeUIProviderBase;
 import org.fortiss.tooling.common.ui.javafx.control.treetableview.DynamicTreeViewer;
+import org.fortiss.tooling.kernel.extension.data.LibraryPrototype;
+import org.fortiss.tooling.kernel.extension.data.Prototype;
+import org.fortiss.tooling.kernel.extension.data.PrototypeCategory;
+import org.fortiss.tooling.kernel.model.ILibraryElement;
+import org.fortiss.tooling.kernel.service.IPrototypeService;
+import org.fortiss.tooling.kernel.ui.extension.base.EditorBase;
+import org.fortiss.tooling.kernel.ui.internal.editor.ExtendableMultiPageEditor;
+import org.fortiss.tooling.kernel.ui.listener.ExtendableMultiPageEditorPageChangeListener;
+import org.fortiss.tooling.kernel.ui.service.IModelElementHandlerService;
 
+import javafx.scene.Node;
 import javafx.scene.Scene;
 import javafx.scene.control.TextField;
 import javafx.scene.layout.BorderPane;
@@ -34,24 +55,45 @@ import javafx.scene.layout.BorderPane;
  * @author hoelzl
  */
 public final class ModelElementsViewFX extends FXViewPart {
+	/** A dummy object serving as hidden root element of the tree view. */
+	private static final Object DUMMY_ROOT = new Object();
 	/** The tree-table viewer. */
 	private DynamicTreeViewer<Object> treeViewer;
 	/** The filter text field if filtering is enabled in content provider. */
 	private TextField filterWidget;
+	/** Current active {@link ExtendableMultiPageEditor}. */
+	private ExtendableMultiPageEditor activeBindingEditor = null;
+	/** Stores the editor activation listener. */
+	private EditorActivationListener editorActivationListener = new EditorActivationListener();
+	/** The container object used. */
+	private EObject containerObject = null;
+	/** The prototypes supported by the current editor. */
+	private Set<Prototype> supportedBaseClasses = new IdentityHashSet<Prototype>();
+	/** Listener for reacting to changes of the embedded editor. */
+	private final ExtendableMultiPageEditorPageChangeListener bindingEditorPageChangeListener =
+			new ExtendableMultiPageEditorPageChangeListener() {
+				@Override
+				public void pageChanged() {
+					updateEditorFilters(activeBindingEditor.getActiveModelEditor());
+				}
+			};
 
 	/** {@inheritDoc} */
 	@Override
 	protected Scene createFxScene() {
+		getSite().getWorkbenchWindow().getPartService().addPartListener(editorActivationListener);
+
 		BorderPane pane = new BorderPane();
+		ContentProvider contentProvider = new ContentProvider();
+		UIProvider uiProvider = new UIProvider();
 
 		filterWidget = new TextField();
 		filterWidget.textProperty().addListener((obs, oVal, nVal) -> {
-			// contentProvider.setFilterExpression(nVal);
+			contentProvider.setFilterExpression(nVal);
 			treeViewer.update();
 		});
 
-		treeViewer = new DynamicTreeViewer<>(new Object(), true, 2, new LibraryContentProvider(),
-				new LibraryUIProvider());
+		treeViewer = new DynamicTreeViewer<>(DUMMY_ROOT, false, 2, contentProvider, uiProvider);
 
 		pane.setTop(filterWidget);
 		pane.setCenter(treeViewer.getControl());
@@ -65,17 +107,151 @@ public final class ModelElementsViewFX extends FXViewPart {
 		filterWidget.requestFocus();
 	}
 
+	/** Updates the filters according to the given editor. */
+	@SuppressWarnings("unchecked")
+	private void updateEditorFilters(IEditorPart editor) {
+		supportedBaseClasses.clear();
+		if(editor instanceof EditorBase &&
+				((EditorBase<? extends EObject>)editor).enableLibraryView()) {
+			EditorBase<? extends EObject> editorBase = (EditorBase<? extends EObject>)editor;
+			containerObject = editorBase.getEditedObject();
+
+			for(Class<? extends EObject> clazz : editorBase.getVisibleEObjectTypes()) {
+				List<Prototype> composablePrototypes =
+						IPrototypeService.getInstance().getComposablePrototypes(clazz);
+				if(getParentElement(containerObject, ILibraryElement.class, true) == null) {
+					supportedBaseClasses.addAll(composablePrototypes);
+				} else {
+					supportedBaseClasses.addAll(
+							filterOutInstanceOf(LibraryPrototype.class, composablePrototypes));
+				}
+			}
+		} else {
+			containerObject = null;
+		}
+
+		treeViewer.update();
+		treeViewer.expandAllItems();
+	}
+
+	/** Switches to the given workbench editor part. */
+	private void switchWorkbenchEditor(IEditorPart editor) {
+		if(activeBindingEditor != null) {
+			activeBindingEditor.removeBindingEditorListener(bindingEditorPageChangeListener);
+			activeBindingEditor = null;
+		}
+
+		if(editor instanceof ExtendableMultiPageEditor) {
+			activeBindingEditor = (ExtendableMultiPageEditor)editor;
+			activeBindingEditor.addBindingEditorListener(bindingEditorPageChangeListener);
+			updateEditorFilters(activeBindingEditor.getActiveModelEditor());
+		} else if(editor != null) {
+			updateEditorFilters(editor);
+		}
+	}
+
 	/** {@link DynamicTreeContentProviderBase} for the library view. */
-	private class LibraryContentProvider extends DynamicTreeContentProviderBase<Object> {
+	private class ContentProvider extends DynamicTreeContentProviderBase<Object> {
 		/** {@inheritDoc} */
 		@Override
 		protected Collection<? extends Object> getChildren(Object parent) {
-			return emptyList(); // FIXME
+			if(parent instanceof PrototypeCategory) {
+				PrototypeCategory protoCat = (PrototypeCategory)parent;
+				return asList(protoCat.getChildren());
+			}
+			if(parent == DUMMY_ROOT) {
+				return IPrototypeService.getInstance().getAllTopLevelPrototypesCategories();
+			}
+			return emptyList();
+		}
+
+		/** {@inheritDoc} */
+		@Override
+		protected boolean filter(Object element, String filterValue) {
+			if(containerObject == null || supportedBaseClasses.isEmpty()) {
+				return false;
+			}
+			if(element instanceof PrototypeCategory) {
+				PrototypeCategory protoCat = (PrototypeCategory)element;
+				for(Object child : protoCat.getChildren()) {
+					if(filter(child, filterValue)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			if(supportedBaseClasses.contains(element)) {
+				if(filterValue == null || "".equals(filterValue)) {
+					return true;
+				}
+				if(element instanceof Prototype) {
+					Prototype proto = (Prototype)element;
+					return proto.getName().contains(filterValue);
+				}
+			}
+			return false;
+		}
+
+		/** {@inheritDoc} */
+		@Override
+		protected Predicate<Object> getFilterPredicate(String filterValue) {
+			// this override is needed, because super implementation does not
+			// call filter(Object, String) when filter value is null.
+			if(filterValue == null || "".equals(filterValue)) {
+				return (o) -> {
+					return filter(o, null);
+				};
+			}
+			return super.getFilterPredicate(filterValue);
 		}
 	}
 
 	/** {@link DynamicTreeUIProviderBase} for the library view. */
-	private class LibraryUIProvider extends DynamicTreeUIProviderBase<Object> {
-		// TODO: go on here
+	private class UIProvider extends DynamicTreeUIProviderBase<Object> {
+		/** {@inheritDoc} */
+		@Override
+		public String getLabel(Object element) {
+			if(element instanceof Prototype) {
+				Prototype proto = (Prototype)element;
+				return proto.getName();
+			}
+			if(element instanceof PrototypeCategory) {
+				PrototypeCategory protoCat = (PrototypeCategory)element;
+				return protoCat.getName();
+			}
+			return element == null ? "" : element.toString();
+		}
+
+		/** {@inheritDoc} */
+		@Override
+		public Node getIconNode(Object element) {
+			if(element instanceof Prototype) {
+				Prototype proto = (Prototype)element;
+				EObject eoPrototype = proto.getPrototype();
+				return IModelElementHandlerService.getInstance().getFXIcon(eoPrototype);
+			}
+			if(element instanceof PrototypeCategory) {
+				PrototypeCategory protoCat = (PrototypeCategory)element;
+				if(protoCat.getChildren().length > 0) {
+					return getIconNode(protoCat.getChildren()[0]);
+				}
+			}
+			return null;
+		}
+	}
+
+	/** If an editor in a different Project is opened the Model is reinitialized */
+	private class EditorActivationListener extends EmptyPartListener {
+		/** Change the tree viewer content whenever workbench part changes. */
+		@Override
+		public void partActivated(IWorkbenchPart workbenchPart) {
+			if(!(workbenchPart instanceof IEditorPart)) {
+				return;
+			}
+
+			IEditorPart part = (IEditorPart)workbenchPart;
+			treeViewer.update();
+			switchWorkbenchEditor(part);
+		}
 	}
 }
-- 
GitLab