Skip to content
Snippets Groups Projects
Commit 0bdc4137 authored by Alexander Diewald's avatar Alexander Diewald
Browse files

Merge branch '3482' into 'master'

3482

See merge request !47
parents 6b5aea28 926a9462
No related branches found
No related tags found
1 merge request!473482
Showing
with 384 additions and 97 deletions
HierarchicModelElementTreeViewer.java 8662b201c3a459f3ebe3620970652f7a3f90270e GREEN ModelElementTreeViewer.java 8a555fc12eb6c0531f6334fdc61e9abf52ff784d YELLOW
...@@ -15,35 +15,54 @@ ...@@ -15,35 +15,54 @@
+--------------------------------------------------------------------------*/ +--------------------------------------------------------------------------*/
package org.fortiss.tooling.base.ui.javafx.control.treetableview; package org.fortiss.tooling.base.ui.javafx.control.treetableview;
import javafx.embed.swt.SWTFXUtils; import static javafx.embed.swt.SWTFXUtils.toFXImage;
import javafx.scene.Node;
import javafx.scene.control.ContextMenu; import java.util.ArrayList;
import javafx.scene.control.TreeView; import java.util.List;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import org.fortiss.tooling.base.model.element.IHierarchicElement; import org.fortiss.tooling.base.model.element.IHierarchicElement;
import org.fortiss.tooling.base.model.element.IModelElement;
import org.fortiss.tooling.common.ui.javafx.AF3FXViewPart;
import org.fortiss.tooling.common.ui.javafx.control.treetableview.DynamicTreeContentProviderBase; 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.DynamicTreeUIProviderBase;
import org.fortiss.tooling.common.ui.javafx.control.treetableview.DynamicTreeViewer; import org.fortiss.tooling.common.ui.javafx.control.treetableview.DynamicTreeViewer;
import org.fortiss.tooling.kernel.model.INamedCommentedElement; import org.fortiss.tooling.kernel.model.INamedCommentedElement;
import org.fortiss.tooling.kernel.ui.service.IModelElementHandlerService; import org.fortiss.tooling.kernel.ui.service.IModelElementHandlerService;
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;
/** /**
* This class is a support fragment for creating tree views in JavaFX Controls. It provides the view
* counter part of a {@link DynamicTreeContentProviderBase}. The content provider is responsible
* for selecting elements from a base model and ordering them acc. to a custom defined structure.
* These two fragments have to be combined in a JavaFX controller inheriting from the base class
* {@link AF3FXViewPart}.
* <p>
* TreeViewer that constructs a DynamicTreeViewer whose UI provider uses the methods and kernel * TreeViewer that constructs a DynamicTreeViewer whose UI provider uses the methods and kernel
* services for {@link IHierarchicElement}s and {@link INamedCommentedElement}s. * services for {@link IHierarchicElement}s and {@link INamedCommentedElement}s.
* The Viewer uses a composition principle where a client must provide {@link TreeView} (JavaFX), a * The Viewer uses a composition principle where a client must provide a {@link TreeView} (JavaFX),
* root element (AF3), and a content provider that selects the elements to be displayed. * a root element (AF3), and a content provider that selects the elements to be displayed.
* *
* @author diewald * @author diewald
*/ */
public class HierarchicModelElementTreeViewer<T extends IHierarchicElement & INamedCommentedElement> { public class ModelElementTreeViewer<T extends IModelElement & INamedCommentedElement> {
/** References the constructed {@link DynamicTreeViewer} "controller". */ /** References the constructed {@link DynamicTreeViewer} "controller". */
protected DynamicTreeViewer<T> dynTreeViewer; protected DynamicTreeViewer<T> dynTreeViewer;
/**
* List of context menu entries that supplied by clients (see
* {@link #addContextMenuEntry(MenuItem)}).
*/
protected List<MenuItem> contextMenuEntries = new ArrayList<>();
/** Constructor. */ /** Constructor. */
public HierarchicModelElementTreeViewer(TreeView<T> treeView, T modelRoot, public ModelElementTreeViewer(TreeView<T> treeView, T modelRoot,
DynamicTreeContentProviderBase<T> contentProvider) { DynamicTreeContentProviderBase<T> contentProvider) {
DynamicTreeUIProviderBase<T> uiProvider = createContentUIProvider(); DynamicTreeUIProviderBase<T> uiProvider = createContentUIProvider();
dynTreeViewer = dynTreeViewer =
...@@ -54,8 +73,6 @@ public class HierarchicModelElementTreeViewer<T extends IHierarchicElement & INa ...@@ -54,8 +73,6 @@ public class HierarchicModelElementTreeViewer<T extends IHierarchicElement & INa
* Creates a default UI provider for {@link DynamicTreeViewer}s that present * Creates a default UI provider for {@link DynamicTreeViewer}s that present
* {@link IHierarchicElement}s. It also uses the {@link IModelElementHandlerService} for a nicer * {@link IHierarchicElement}s. It also uses the {@link IModelElementHandlerService} for a nicer
* visual appearance. * visual appearance.
* <p>
* Externalize this method into a class when subclassing seems appropriate.
* *
* @return The constructed UI Provider. * @return The constructed UI Provider.
*/ */
...@@ -74,7 +91,7 @@ public class HierarchicModelElementTreeViewer<T extends IHierarchicElement & INa ...@@ -74,7 +91,7 @@ public class HierarchicModelElementTreeViewer<T extends IHierarchicElement & INa
org.eclipse.swt.graphics.Image icon = org.eclipse.swt.graphics.Image icon =
IModelElementHandlerService.getInstance().getIcon(element); IModelElementHandlerService.getInstance().getIcon(element);
if(icon != null) { if(icon != null) {
Image fxImage = SWTFXUtils.toFXImage(icon.getImageData(), null); Image fxImage = toFXImage(icon.getImageData(), null);
return new ImageView(fxImage); return new ImageView(fxImage);
} }
return null; return null;
...@@ -84,18 +101,26 @@ public class HierarchicModelElementTreeViewer<T extends IHierarchicElement & INa ...@@ -84,18 +101,26 @@ public class HierarchicModelElementTreeViewer<T extends IHierarchicElement & INa
@Override @Override
public ContextMenu createContextMenu(T element) { public ContextMenu createContextMenu(T element) {
ContextMenu menu = new ContextMenu(); ContextMenu menu = new ContextMenu();
// TODO (3209): Add sensible default operations for AF3 elements, if they are contextMenuEntries.forEach(entry -> menu.getItems().add(entry));
// needed. Otherwise, use a list provided by subclasses that defines the menu items
// and their order. The code below is taken from SystemFOCUS and shall serve as a
// reference.
// MenuItem item = new MenuItem("Delete '" + getLabel(element) + "'.");
// item.setOnAction(event -> {
// new DeleteOperation(element).delete();
// viewer.update();
// });
// menu.getItems().add(item);
return menu; return menu;
} }
}; };
} }
/**
* Method to define context {@link MenuItem}s for items of the underlying content. The given
* function may use the selected element (given as a parameter to the function) to define
* dynamic behavior.
*
* @param menuItem
* {@link MenuItem} and its logic to be added to the context menu.
*/
public void addContextMenuEntry(MenuItem menuItem) {
contextMenuEntries.add(menuItem);
}
/** Update the internal viewer. */
public void update() {
dynTreeViewer.update();
}
} }
...@@ -75,7 +75,8 @@ Export-Package: org.conqat.ide.commons.gef, ...@@ -75,7 +75,8 @@ Export-Package: org.conqat.ide.commons.gef,
org.eclipse.wb.swt.widgets.baseline, org.eclipse.wb.swt.widgets.baseline,
org.fortiss.tooling.common.ui, org.fortiss.tooling.common.ui,
org.fortiss.tooling.common.ui.javafx, org.fortiss.tooling.common.ui.javafx,
org.fortiss.tooling.common.ui.javafx.control.treetableview org.fortiss.tooling.common.ui.javafx.control.treetableview,
org.fortiss.tooling.common.ui.javafx.util
Bundle-Vendor: fortiss GmbH Bundle-Vendor: fortiss GmbH
Bundle-Activator: org.fortiss.tooling.common.ui.ToolingCommonUIActivator Bundle-Activator: org.fortiss.tooling.common.ui.ToolingCommonUIActivator
Bundle-ActivationPolicy: lazy Bundle-ActivationPolicy: lazy
......
AF3FXViewPart.java f1b4c05a7a22cd7a0a2524600204a0ad6365c419 GREEN AF3FXViewPart.java 1af5c5fba174c2f81ebdde4e90552a8501f1d86e GREEN
...@@ -18,31 +18,29 @@ package org.fortiss.tooling.common.ui.javafx; ...@@ -18,31 +18,29 @@ package org.fortiss.tooling.common.ui.javafx;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle;
import org.apache.commons.lang3.SystemUtils;
import org.eclipse.fx.ui.workbench3.FXViewPart;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import org.apache.commons.lang3.SystemUtils;
import org.eclipse.fx.ui.workbench3.FXViewPart;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;
/** /**
* Base class to create eclipse (SWT-based) views using JavaFX GUI elements. This class requires * Base class to create eclipse (SWT-based) views using JavaFX GUI elements. This class requires
* FXML file that defines the GUI elements of the view. * FXML file that defines the GUI elements of the view.
* *
* @author diewald * @author diewald
*/ */
/** public abstract class AF3FXViewPart extends FXViewPart implements Initializable {
* This class will be used for the migration to JavaFX, which is work-in-progress. Hence, mark the
* class for non-removal.
*/
public abstract class AF3FXViewPart extends FXViewPart { // NO_UCD
/** For later use, if we need to define different styles. */ /** For later use, if we need to define different styles. */
private String cssLocation; private String cssLocation;
...@@ -124,6 +122,7 @@ public abstract class AF3FXViewPart extends FXViewPart { // NO_UCD ...@@ -124,6 +122,7 @@ public abstract class AF3FXViewPart extends FXViewPart { // NO_UCD
protected Scene createFxScene() { protected Scene createFxScene() {
FXMLLoader loader = new FXMLLoader(); FXMLLoader loader = new FXMLLoader();
loader.setClassLoader(viewerClass.getClassLoader()); loader.setClassLoader(viewerClass.getClassLoader());
loader.setController(this);
if(fXMLLocation != null) { if(fXMLLocation != null) {
loader.setLocation(viewerClass.getResource(fXMLLocation)); loader.setLocation(viewerClass.getResource(fXMLLocation));
try { try {
...@@ -135,7 +134,8 @@ public abstract class AF3FXViewPart extends FXViewPart { // NO_UCD ...@@ -135,7 +134,8 @@ public abstract class AF3FXViewPart extends FXViewPart { // NO_UCD
} else { } else {
root = new AnchorPane(); root = new AnchorPane();
try { try {
viewerClass.getMethod("initialize").invoke(this); viewerClass.getMethod("initialize", URL.class, ResourceBundle.class).invoke(this,
null, null);
} catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException | } catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException |
SecurityException e) { SecurityException e) {
throw new RuntimeException("The initialize method of the View " + throw new RuntimeException("The initialize method of the View " +
...@@ -164,17 +164,6 @@ public abstract class AF3FXViewPart extends FXViewPart { // NO_UCD ...@@ -164,17 +164,6 @@ public abstract class AF3FXViewPart extends FXViewPart { // NO_UCD
// Not needed. // Not needed.
} }
/**
* Init method that is called after the JavaFX toolkit has been launched. The initialize method
* is needed for single-node/view/control {@link ViewPart}s and for controls in a FXML-based
* view that require an initial configuration. If no initial configuration is required place a
* stub.
* <p>
* For FXML, the initialize method is called via the JavaFX framework. Otherwise, it is called
* via reflection from this class.
*/
protected abstract void initialize();
/** /**
* Adds a single {@link Node} to this view. It embeds the given {@link Node} to the * Adds a single {@link Node} to this view. It embeds the given {@link Node} to the
* {@link AnchorPane} of this view and stretches it to the borders of the view. * {@link AnchorPane} of this view and stretches it to the borders of the view.
......
...@@ -3,6 +3,6 @@ DynamicTreeItem.java afc105cf5acf3d2506d89e0892555100c234ce5b GREEN ...@@ -3,6 +3,6 @@ DynamicTreeItem.java afc105cf5acf3d2506d89e0892555100c234ce5b GREEN
DynamicTreeTableUIProviderBase.java fd9fce19a65eb1006ceacb0d869bbe90a8c578b3 GREEN DynamicTreeTableUIProviderBase.java fd9fce19a65eb1006ceacb0d869bbe90a8c578b3 GREEN
DynamicTreeTableViewer.java e474f3a890fd6525db7de8e299d7fbe67f932a15 GREEN DynamicTreeTableViewer.java e474f3a890fd6525db7de8e299d7fbe67f932a15 GREEN
DynamicTreeUIProviderBase.java 56fe4df4577b35f1e5e6e4c4be189b706c852d52 GREEN DynamicTreeUIProviderBase.java 56fe4df4577b35f1e5e6e4c4be189b706c852d52 GREEN
DynamicTreeViewer.java d5b9f87862d9c42327c46bce02fb34d64673d413 GREEN DynamicTreeViewer.java ffead9e76286fb7a17723cd201fdc187187a737f GREEN
DynamicTreeViewerBase.java 47124c847de322a0ae26eb7a114f85ce4bd02d7e GREEN DynamicTreeViewerBase.java 47124c847de322a0ae26eb7a114f85ce4bd02d7e GREEN
IDoubleClickHandler.java 447f7769dead9a106b3ea3139ef0da51eb0b9a89 GREEN IDoubleClickHandler.java 447f7769dead9a106b3ea3139ef0da51eb0b9a89 GREEN
...@@ -34,6 +34,8 @@ import javafx.scene.input.MouseEvent; ...@@ -34,6 +34,8 @@ import javafx.scene.input.MouseEvent;
public final class DynamicTreeViewer<T> extends DynamicTreeViewerBase<T> { public final class DynamicTreeViewer<T> extends DynamicTreeViewerBase<T> {
/** The {@link TreeView} control to be managed. */ /** The {@link TreeView} control to be managed. */
private final TreeView<T> view; private final TreeView<T> view;
/** {@link TreeItem} constructed for the root object. */
private final DynamicTreeItem<T> rootItem;
/** The UI provider implementation. */ /** The UI provider implementation. */
private final DynamicTreeUIProviderBase<T> uiProvider; private final DynamicTreeUIProviderBase<T> uiProvider;
/** The selection change listener. */ /** The selection change listener. */
...@@ -49,7 +51,7 @@ public final class DynamicTreeViewer<T> extends DynamicTreeViewerBase<T> { ...@@ -49,7 +51,7 @@ public final class DynamicTreeViewer<T> extends DynamicTreeViewerBase<T> {
this.uiProvider = uiProvider; this.uiProvider = uiProvider;
// construct view // construct view
this.view = view; this.view = view;
DynamicTreeItem<T> rootItem = new DynamicTreeItem<T>(root, this); rootItem = new DynamicTreeItem<T>(root, this);
view.setRoot(rootItem); view.setRoot(rootItem);
view.setShowRoot(showRoot); view.setShowRoot(showRoot);
configureCellFactory(); configureCellFactory();
...@@ -88,6 +90,11 @@ public final class DynamicTreeViewer<T> extends DynamicTreeViewerBase<T> { ...@@ -88,6 +90,11 @@ public final class DynamicTreeViewer<T> extends DynamicTreeViewerBase<T> {
view.getSelectionModel().select(row); view.getSelectionModel().select(row);
} }
/** Searches the {@link DynamicTreeItem} for the given value from the root. */
public DynamicTreeItem<T> findItem(T value) {
return findItem(rootItem, value);
}
/** Searches the {@link DynamicTreeItem} for the given value. */ /** Searches the {@link DynamicTreeItem} for the given value. */
public DynamicTreeItem<T> findItem(DynamicTreeItem<T> item, Object value) { public DynamicTreeItem<T> findItem(DynamicTreeItem<T> item, Object value) {
if(item == null || value == null) { if(item == null || value == null) {
...@@ -142,6 +149,14 @@ public final class DynamicTreeViewer<T> extends DynamicTreeViewerBase<T> { ...@@ -142,6 +149,14 @@ public final class DynamicTreeViewer<T> extends DynamicTreeViewerBase<T> {
}); });
} }
/** Expands the tree to the given item. */
public void expandItem(TreeItem<T> item) {
while(item.getParent() != null) {
item = item.getParent();
item.setExpanded(true);
}
}
/** Expands items up to the given level. */ /** Expands items up to the given level. */
private void expandItem(TreeItem<T> parentItem, int revealLevel) { private void expandItem(TreeItem<T> parentItem, int revealLevel) {
if(revealLevel <= 0) { if(revealLevel <= 0) {
...@@ -165,7 +180,7 @@ public final class DynamicTreeViewer<T> extends DynamicTreeViewerBase<T> { ...@@ -165,7 +180,7 @@ public final class DynamicTreeViewer<T> extends DynamicTreeViewerBase<T> {
} }
/** /**
* Customized event dispatcher to fix double-click behavior. Thiss prevents opening/closing of * Customized event dispatcher to fix double-click behavior. This prevents opening/closing of
* tree items with double click listeners assigned. * tree items with double click listeners assigned.
*/ */
private class DoubleClickEventDispatcher implements EventDispatcher { private class DoubleClickEventDispatcher implements EventDispatcher {
......
SceneGraphUtils.java f54304c2eb604934de9afdf9d2a8ca88a762398a GREEN
/*-------------------------------------------------------------------------+
| Copyright 2019 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.common.ui.javafx.util;
import java.util.LinkedList;
import java.util.Queue;
import java.util.function.Predicate;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
/**
* Utility methods for {@link Scene} graph.
*
* @author hoelzl
* @author diewald
*/
public final class SceneGraphUtils {
/** Prevent instantiation. */
private SceneGraphUtils() {
// Nothing to do
}
/**
* Searches the scene graph hierarchy for the nearest parent node of the given class.
*
* @param start
* the start node
* @param clazz
* the target class of the node to be found
* @return the nearest parent node
*/
@SuppressWarnings("unchecked")
public static <T extends Node> T findParentNode(Parent start, Class<T> clazz) {
return (T)findParentNode(start, t -> clazz.isInstance(t));
}
/**
* Searches the scene graph hierarchy for the nearest child node with the given id.
*
* @param start
* the start node
* @param id
* string identified (field "fx:id" in FXML files).
* @return the nearest child node
*/
public static Node findParentById(Parent start, String id) {
return findParentNode(start, t -> t.getId().equals(id));
}
/**
* Searches the scene graph hierarchy for the nearest parent node with the given id and type.
*
* @param start
* the start node
* @param id
* string identified (field "fx:id" in FXML files).
* @param type
* the target class of the node to be found
* @return the nearest child node
*/
@SuppressWarnings("unchecked")
public static <T extends Node> T findParentByIdType(Parent start, String id, Class<T> type) {
return (T)findChildNode(start,
t -> (type.isAssignableFrom(type)) && (t.getId().equals(id)));
}
/**
* Searches the scene graph hierarchy for the nearest parent node fulfilling the given
* {@link Predicate}.
*
* @param start
* the start node
* @param pred
* predicate evaluated during the parent walk
* @return the nearest parent node
*/
public static Node findParentNode(Parent start, Predicate<Node> pred) {
while(start != null) {
start = start.getParent();
if(pred.test(start)) {
return start;
}
}
return null;
}
/**
* Searches the scene graph hierarchy for the nearest child node of the given class.
*
* @param start
* the start node
* @param clazz
* the target class of the node to be found
* @return the nearest child node
*/
@SuppressWarnings("unchecked")
public static <T extends Node> T findChildNode(Parent start, Class<T> clazz) {
return (T)findChildNode(start, t -> clazz.isInstance(t));
}
/**
* Searches the scene graph hierarchy for the nearest child node with the given id.
*
* @param start
* the start node
* @param id
* string identified (field "fx:id" in FXML files).
* @return the nearest child node
*/
public static Node findChildById(Parent start, String id) {
return findChildNode(start, t -> t.getId().equals(id));
}
/**
* Searches the scene graph hierarchy for the nearest child node with the given id and type.
*
* @param start
* the start node
* @param id
* string identified (field "fx:id" in FXML files).
* @param type
* the target class of the node to be found
* @return the nearest child node
*/
@SuppressWarnings("unchecked")
public static <T extends Node> T findChildByIdType(Parent start, String id, Class<T> type) {
// @CodeFormatterOff
return (T)findChildNode(start,
t -> (t.getId() != null
&& (t.getId().equals(id))
&& type.isAssignableFrom(t.getClass())));
// @CodeFormatterOn
}
/**
* Searches the scene graph hierarchy for the nearest child node of the given fulfilling the
* given {@link Predicate}.
*
* @param start
* the start node
* @param pred
* predicate evaluated during the child walk
* @return the nearest parent node
*/
public static Node findChildNode(Parent start, Predicate<Node> pred) {
Queue<Node> children = new LinkedList<>();
children.addAll(start.getChildrenUnmodifiable());
while(!children.isEmpty()) {
Node child = children.poll();
if(pred.test(child)) {
return child;
}
if(child instanceof Parent) {
children.addAll(((Parent)child).getChildrenUnmodifiable());
}
}
return null;
}
}
Manifest-Version: 1.0 Manifest-Version: 1.0
Bundle-ManifestVersion: 2 Bundle-ManifestVersion: 2
Bundle-Name: %pluginName Bundle-Name: %pluginName
Bundle-SymbolicName: org.fortiss.tooling.kernel;singleton:=true Bundle-SymbolicName: org.fortiss.tooling.kernel;singleton:=true
Bundle-Version: 2.14.0.qualifier Bundle-Version: 2.14.0.qualifier
Bundle-ClassPath: . Bundle-ClassPath: .
Bundle-Activator: org.fortiss.tooling.kernel.ToolingKernelActivator Bundle-Activator: org.fortiss.tooling.kernel.ToolingKernelActivator
Bundle-Vendor: %providerName Bundle-Vendor: %providerName
Bundle-Localization: plugin Bundle-Localization: plugin
Require-Bundle: org.fortiss.tooling.common;visibility:=reexport;bundle-version="2.14.0", Require-Bundle: org.fortiss.tooling.common;visibility:=reexport;bundle-version="2.14.0",
org.eclipse.core.runtime, org.eclipse.core.runtime,
org.eclipse.emf.ecore;visibility:=reexport;bundle-version="2.7.0", org.eclipse.emf.ecore;visibility:=reexport;bundle-version="2.7.0",
org.eclipse.emf.transaction;visibility:=reexport;bundle-version="1.4.0", org.eclipse.emf.transaction;visibility:=reexport;bundle-version="1.4.0",
org.eclipse.emf.ecore.xmi;visibility:=reexport;bundle-version="2.7.0" org.eclipse.emf.ecore.xmi;visibility:=reexport;bundle-version="2.7.0"
Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-RequiredExecutionEnvironment: JavaSE-11
Bundle-ActivationPolicy: lazy Bundle-ActivationPolicy: lazy
Export-Package: org.fortiss.tooling.kernel;uses:="org.eclipse.core.runtime, Export-Package: org.fortiss.tooling.kernel;uses:="org.eclipse.core.runtime,
org.osgi.framework", org.osgi.framework",
org.fortiss.tooling.kernel.constraint, org.fortiss.tooling.kernel.constraint,
org.fortiss.tooling.kernel.extension, org.fortiss.tooling.kernel.extension,
org.fortiss.tooling.kernel.extension.base, org.fortiss.tooling.kernel.extension.base,
org.fortiss.tooling.kernel.extension.data, org.fortiss.tooling.kernel.extension.data,
org.fortiss.tooling.kernel.extension.exception, org.fortiss.tooling.kernel.extension.exception,
org.fortiss.tooling.kernel.introspection, org.fortiss.tooling.kernel.introspection,
org.fortiss.tooling.kernel.introspection.items, org.fortiss.tooling.kernel.introspection.items,
org.fortiss.tooling.kernel.model;uses:=org.eclipse.emf.ecore, org.fortiss.tooling.kernel.model;uses:=org.eclipse.emf.ecore,
org.fortiss.tooling.kernel.model.constraints, org.fortiss.tooling.kernel.model.constraints,
org.fortiss.tooling.kernel.model.constraints.impl, org.fortiss.tooling.kernel.model.constraints.impl,
org.fortiss.tooling.kernel.model.constraints.util, org.fortiss.tooling.kernel.model.constraints.util,
org.fortiss.tooling.kernel.model.impl;uses:=org.fortiss.tooling.kernel.model, org.fortiss.tooling.kernel.model.impl;uses:=org.fortiss.tooling.kernel.model,
org.fortiss.tooling.kernel.model.util;uses:="org.eclipse.emf.ecore, org.fortiss.tooling.kernel.model.util;uses:="org.eclipse.emf.ecore,
org.fortiss.tooling.kernel.model, org.fortiss.tooling.kernel.model,
org.eclipse.emf.common.notify.impl, org.eclipse.emf.common.notify.impl,
org.eclipse.emf.common.notify", org.eclipse.emf.common.notify",
org.fortiss.tooling.kernel.service;uses:="org.eclipse.core.runtime, org.fortiss.tooling.kernel.service;uses:="org.eclipse.core.runtime,
org.eclipse.emf.ecore, org.eclipse.emf.ecore,
org.fortiss.tooling.kernel.interfaces, org.fortiss.tooling.kernel.interfaces,
org.conqat.lib.commons.collections", org.conqat.lib.commons.collections",
org.fortiss.tooling.kernel.service.base, org.fortiss.tooling.kernel.service.base,
org.fortiss.tooling.kernel.service.listener, org.fortiss.tooling.kernel.service.listener,
org.fortiss.tooling.kernel.service.types, org.fortiss.tooling.kernel.service.types,
org.fortiss.tooling.kernel.utils;uses:="org.eclipse.emf.ecore, org.fortiss.tooling.kernel.utils;uses:="org.eclipse.emf.ecore,
org.eclipse.core.resources" org.eclipse.core.resources"
Automatic-Module-Name: org.fortiss.tooling.kernel Automatic-Module-Name: org.fortiss.tooling.kernel
Import-Package: com.google.common.collect
...@@ -2,7 +2,7 @@ CompositionUtils.java 34c0a191bd0fb4176c94b4d61abb5c88a679d5e8 GREEN ...@@ -2,7 +2,7 @@ CompositionUtils.java 34c0a191bd0fb4176c94b4d61abb5c88a679d5e8 GREEN
ConstraintsUtils.java 0f8be020f2ca4bb08931c32452163c04a28e30ce GREEN ConstraintsUtils.java 0f8be020f2ca4bb08931c32452163c04a28e30ce GREEN
EMFResourceUtils.java 979d0e1f4f66a2b3e715d2da0ebef6493f547fd7 GREEN EMFResourceUtils.java 979d0e1f4f66a2b3e715d2da0ebef6493f547fd7 GREEN
EcoreSerializerBase.java 0a0c2969d793d2e68094c55c8f7b0a662ef6e5d5 GREEN EcoreSerializerBase.java 0a0c2969d793d2e68094c55c8f7b0a662ef6e5d5 GREEN
EcoreUtils.java 3e2e2193312cd4ce6fd0c7ea2beb7daae428d2ed GREEN EcoreUtils.java accd567a0dcd1447d6f3e112f19fe8d53862d0cb GREEN
ExtensionPointUtils.java 7ce63242b49eb9a7cd4eaadd223f5ebce1dfd75b GREEN ExtensionPointUtils.java 7ce63242b49eb9a7cd4eaadd223f5ebce1dfd75b GREEN
HierarchicalNameComparator.java 6face1b673126701a0721af48ead2f9766c17d46 GREEN HierarchicalNameComparator.java 6face1b673126701a0721af48ead2f9766c17d46 GREEN
IdentifierUtils.java fff43dc4e84cdd89c3ece4f5d9d89aec4b0749c2 GREEN IdentifierUtils.java fff43dc4e84cdd89c3ece4f5d9d89aec4b0749c2 GREEN
......
...@@ -15,12 +15,14 @@ ...@@ -15,12 +15,14 @@
+--------------------------------------------------------------------------*/ +--------------------------------------------------------------------------*/
package org.fortiss.tooling.kernel.utils; package org.fortiss.tooling.kernel.utils;
import static java.util.stream.Collectors.toList;
import static org.eclipse.emf.common.notify.Notification.EVENT_TYPE_COUNT; import static org.eclipse.emf.common.notify.Notification.EVENT_TYPE_COUNT;
import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents; import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
import static org.eclipse.emf.ecore.util.EcoreUtil.getRootContainer; import static org.eclipse.emf.ecore.util.EcoreUtil.getRootContainer;
import static org.eclipse.emf.ecore.util.EcoreUtil.replace; import static org.eclipse.emf.ecore.util.EcoreUtil.replace;
import static org.eclipse.emf.ecore.util.EcoreUtil.UsageCrossReferencer.find; import static org.eclipse.emf.ecore.util.EcoreUtil.UsageCrossReferencer.find;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
...@@ -50,6 +52,9 @@ import org.eclipse.emf.ecore.resource.ResourceSet; ...@@ -50,6 +52,9 @@ import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.EcoreUtil.Copier; import org.eclipse.emf.ecore.util.EcoreUtil.Copier;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
/** /**
* Utility methods for dealing with <code>Ecore</code> models. These methods should be used to * Utility methods for dealing with <code>Ecore</code> models. These methods should be used to
* define EMF operations that make the models easier to use. * define EMF operations that make the models easier to use.
...@@ -395,6 +400,17 @@ public class EcoreUtils { ...@@ -395,6 +400,17 @@ public class EcoreUtils {
return t; return t;
} }
/**
* Returns a self-contained copy of the given collection of {@link EObject}s.
*
* @return Self-contained copy of the given {@link EObject}s.
*/
@SuppressWarnings("unchecked")
public static <T extends EObject> Collection<T> copy(Collection<T> eObjects) {
Map<EObject, EObject> copyMap = copyToRefMap(eObjects);
return (Collection<T>)eObjects.stream().map(orig -> copyMap.get(orig)).collect(toList());
}
/** /**
* Creates a self-contained copy of the given {@link EObject}. * Creates a self-contained copy of the given {@link EObject}.
* *
...@@ -409,6 +425,70 @@ public class EcoreUtils { ...@@ -409,6 +425,70 @@ public class EcoreUtils {
return copier; return copier;
} }
/**
* Creates a self-contained copy of the given collection of {@link EObject}s. References
* between elements of the given {@link EObject}s are updated to point to their copies.
*
* @param originalEObjects
* collection of {@link EObject}s to copy.
* @return The method returns a {@link Map} that relates each original sub-element (including
* the given {@link EObject}) to the corresponding copy.
*/
public static Map<EObject, EObject>
copyToRefMap(Collection<? extends EObject> originalEObjects) {
BiMap<EObject, EObject> copyRefMap = HashBiMap.create();
// First, create all copies such that bi-references between the input object can be
// resolved in a second step: This step requires the existence of all copied elements.
for(EObject originalElement : originalEObjects) {
Map<EObject, EObject> currentCopyMap = copyToRefMap(originalElement);
copyRefMap.putAll(currentCopyMap);
}
for(EObject eObject : copyRefMap.values()) {
Collection<EReference> refToOrigList = eObject.eClass().getEAllReferences();
for(EReference refToOrig : refToOrigList) {
if(refToOrig.isContainment()) {
// Containments are handled by the copy operation itself.
continue;
}
if(refToOrig.isMany()) {
@SuppressWarnings("unchecked") EList<EObject> origList =
(EList<EObject>)eObject.eGet(refToOrig, false);
List<EObject> origCacheList = new ArrayList<>(origList);
// WARNING! WARNING! WARNING!
// We MUST add the copied elements to the list first, such that the
// reference list is not nulled by EMF in the parent element. This
// happens if the list contains only a single element: Removing this
// element empties the list and triggers a removal of the list from
// its container via the EMF notification mechanism.
origCacheList.forEach(e -> {
EObject eObj = copyRefMap.get(e);
if(eObj != null) {
origList.add(eObj);
origList.remove(e);
}
});
} else {
EObject origRef = (EObject)eObject.eGet(refToOrig);
if(origRef == null && refToOrig.getEOpposite() != null) {
// Note: For bi-references between the input elements we must use the
// inverse view of the bi-copy-map since the bi-references are nulled at
// both ends.
EObject origEObj = copyRefMap.inverse().get(eObject);
origRef = (EObject)origEObj.eGet(refToOrig);
}
EObject copyRef = copyRefMap.get(origRef);
if(copyRef != null) {
eObject.eSet(refToOrig, copyRef);
}
}
}
}
return copyRefMap;
}
/** Map to cache potentially expensive lookups in {@link #getEClassForClass(Class)}. */ /** Map to cache potentially expensive lookups in {@link #getEClassForClass(Class)}. */
private static Map<Class<?>, EClass> clazz2EClassCache = new HashMap<Class<?>, EClass>(); private static Map<Class<?>, EClass> clazz2EClassCache = new HashMap<Class<?>, EClass>();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment