use of org.osate.ge.internal.diagram.runtime.DiagramNode in project osate2 by osate.
the class GefAgeDiagram method ensureSceneNodesExistForChildren.
/**
* Ensures the scene node exists for the children of a diagram node.
* Creates or recreates scene graph nodes and adds to the scene graph as necessary. Populates {@link #diagramElementToGefDiagramElementMap}.
* @param parentDiagramNode the diagram node for which scene nodes will be created for its children.
* @param parentDiagramNodeSceneNode the scene node for the parent diagram node
* @return the created or updated JavaFX node
*/
private void ensureSceneNodesExistForChildren(final DiagramNode parentDiagramNode, final Node parentDiagramNodeSceneNode) {
for (final DiagramElement childDiagramElement : parentDiagramNode.getChildren()) {
final GefDiagramElement childGefDiagramElement = diagramElementToGefDiagramElementMap.computeIfAbsent(childDiagramElement, e -> new GefDiagramElement(childDiagramElement));
final Node childSceneNode = ensureSceneNodeExists(childGefDiagramElement, parentDiagramNodeSceneNode);
ensureSceneNodesExistForChildren(childDiagramElement, childSceneNode);
}
}
use of org.osate.ge.internal.diagram.runtime.DiagramNode in project osate2 by osate.
the class DiagramUpdater method updateStructure.
/**
* Updates the structure of the diagram based on the business object tree.
* Creates/Unghosts elements to match the business object tree. Ghosts diagram elements which are not in the diagram element tree.
* @param m
* @param container
* @param bos
*/
private void updateStructure(final DiagramModification m, final DiagramNode container, final Collection<BusinessObjectNode> bos) {
for (final BusinessObjectNode n : bos) {
// Get existing element if it exists.
DiagramElement element = container.getChildByRelativeReference(n.getRelativeReference());
// Create the element if it does not exist
if (element == null) {
final DiagramElement removedGhost = removeGhost(container, n.getRelativeReference());
if (removedGhost == null) {
final BusinessObjectHandler boh = infoProvider.getApplicableBusinessObjectHandler(n.getBusinessObject());
if (boh == null) {
// Ignore the object
continue;
}
element = new DiagramElement(container, n.getBusinessObject(), boh, n.getRelativeReference(), n.getId());
} else {
element = removedGhost;
m.updateBusinessObject(element, n.getBusinessObject(), n.getRelativeReference());
}
m.addElement(element);
} else {
// Update the business object and relative reference. Although the reference matches. The business object may be new and the
// relative reference may have case differences.
m.updateBusinessObject(element, n.getBusinessObject(), n.getRelativeReference());
}
// Set the business object handler if it is null
if (element.getBusinessObjectHandler() == null) {
final BusinessObjectHandler boh = infoProvider.getApplicableBusinessObjectHandler(n.getBusinessObject());
if (boh == null) {
ghostAndRemove(m, element);
continue;
} else {
m.setBusinessObjectHandler(element, boh);
}
}
// Update the element's children
updateStructure(m, element, n.getChildren());
}
// If the collections are the same size, there is nothing to remove
if (bos.size() != container.getChildren().size()) {
// Build Set of Relative References of All the Objects in the Business Object Tree
final Set<RelativeBusinessObjectReference> boTreeRelativeReferenceSet = bos.stream().map((n) -> n.getRelativeReference()).collect(Collectors.toCollection(HashSet::new));
Iterator<DiagramElement> childrenIt = container.getChildren().iterator();
while (childrenIt.hasNext()) {
final DiagramElement child = childrenIt.next();
if (!boTreeRelativeReferenceSet.contains(child.getRelativeReference())) {
ghostAndRemove(m, child);
}
}
}
}
use of org.osate.ge.internal.diagram.runtime.DiagramNode in project osate2 by osate.
the class PasteAction method isEnabled.
@Override
public boolean isEnabled() {
// Return value if this is called before constructor is finished
if (clipboard == null) {
return false;
}
final DiagramNode dstDiagramNode = getDestinationDiagramNode();
if (dstDiagramNode == null) {
return false;
}
final Collection<CopiedDiagramElement> copiedDiagramElements = getCopiedDiagramElements();
if (copiedDiagramElements.isEmpty()) {
return false;
}
final boolean anyEmbeddedBoCopied = copiedDiagramElements.stream().anyMatch(de -> de.getCopiedBusinessObject() instanceof EmbeddedBusinessObject);
final boolean anyEObjectCopied = copiedDiagramElements.stream().anyMatch(de -> de.getCopiedBusinessObject() instanceof EObject);
// Such objects are not supported because layout issues have been observed.
return !(getBusinessObject(dstDiagramNode) instanceof EmbeddedBusinessObject) && (!anyEmbeddedBoCopied || DiagramNodePredicates.isDiagramOrUndockedShape(dstDiagramNode)) && (!anyEObjectCopied || getDestinationEObject(dstDiagramNode) != null);
}
use of org.osate.ge.internal.diagram.runtime.DiagramNode in project osate2 by osate.
the class PasteAction method copyClipboardContents.
/**
* Copies the clipboard contents to the destination business object and diagram element.
* @return the diagram elements which were created. Does not include children of created diagram elements.
*/
private Collection<DiagramElement> copyClipboardContents(final EObject dstBoToModify, final DiagramNode dstDiagramNode, final DiagramModification m, final ReferenceBuilderService refBuilder) {
// Determine the minimum coordinates from the elements whose positions will be copied
// The minimum coordinates is null if none of the copied diagram elements have an absolute position. This is reasonable because the minimum coordinates
// are only needed if a copied diagram element has an absolute position.
final Point minCoordinates = getCopiedDiagramElements().stream().map(CopiedDiagramElement::getAbsolutePosition).filter(Predicates.notNull()).reduce((a, b) -> new Point(Math.min(a.x, b.x), Math.min(a.y, b.y))).orElse(null);
// This list will contain the diagram elements that are created by the copying process. Does not contain their children.
final List<DiagramElement> newDiagramElements = new ArrayList<>();
// Copy each copied diagram element into the diagram and model.
for (final CopiedDiagramElement copiedDiagramElement : getCopiedDiagramElements()) {
final DiagramElement newDiagramElement;
if (copiedDiagramElement.getCopiedBusinessObject() == null) {
newDiagramElement = CopyAndPasteUtil.copyDiagramElement(copiedDiagramElement.getDiagramElement(), dstDiagramNode, copiedDiagramElement.getDiagramElement().getRelativeReference(), refBuilder);
} else {
final Object boFromCopiedDiagramElement = copiedDiagramElement.getCopiedBusinessObject();
final RelativeBusinessObjectReference newRelativeRef;
if (boFromCopiedDiagramElement instanceof EmbeddedBusinessObject) {
// The relative reference will be assigned when copying the diagram element.
newRelativeRef = null;
} else if (boFromCopiedDiagramElement instanceof EObject) {
// Get the list that to which the copied object will be added
final EStructuralFeature compatibleFeature = getCompatibleStructuralFeature(copiedDiagramElement.getContainingFeature(), dstBoToModify.eClass());
final Object containingFeatureValue = dstBoToModify.eGet(compatibleFeature);
if (!(containingFeatureValue instanceof Collection)) {
throw new RuntimeException("Unexpected case. Value of containing feature was not a collection");
}
@SuppressWarnings("unchecked") final Collection<EObject> containingFeatureValueCollection = (Collection<EObject>) containingFeatureValue;
final EObject copiedEObject = EcoreUtil.copy((EObject) boFromCopiedDiagramElement);
containingFeatureValueCollection.add(copiedEObject);
ensureBusinessObjectHasUniqueName(copiedEObject, copiedDiagramElement.getDiagramElement().getBusinessObjectHandler());
ensurePackagesAreImported(copiedEObject);
newRelativeRef = refBuilder.getRelativeReference(copiedEObject);
} else {
throw new RuntimeException("Unsupported case: " + boFromCopiedDiagramElement);
}
newDiagramElement = CopyAndPasteUtil.copyDiagramElement(copiedDiagramElement.getDiagramElement(), dstDiagramNode, newRelativeRef, refBuilder);
}
// Set the position of the new diagram element. They are positioned relative to each other at a fixed offset within the new parent.
final Point cp = copiedDiagramElement.getAbsolutePosition();
final Point newPosition = cp == null ? null : new Point(cp.x - minCoordinates.x + 50, cp.y - minCoordinates.y + 50);
DiagramElementLayoutUtil.moveElement(m, newDiagramElement, newPosition);
// Remove existing element
final DiagramElement existingDiagramElement = dstDiagramNode.getChildByRelativeReference(newDiagramElement.getRelativeReference());
if (existingDiagramElement != null) {
m.removeElement(existingDiagramElement);
}
// Add the new diagram element to the diagram.
m.addElement(newDiagramElement);
newDiagramElements.add(newDiagramElement);
}
return newDiagramElements;
}
use of org.osate.ge.internal.diagram.runtime.DiagramNode in project osate2 by osate.
the class AgeContentOutlinePage method createControl.
@Override
public void createControl(final Composite parent) {
super.createControl(parent);
final TreeViewer viewer = getTreeViewer();
ContextHelpUtil.setHelp(viewer.getControl(), ContextHelpUtil.OUTLINE_VIEW);
// A comparator is set to allow comparing tree elements of different types in a way where they will be equal if the relative reference is equal.
// This is needed so that tree node will be preserved when elements are hidden and shown and the underlying object type changes.
// If link with editor is enabled, selection may not be retained.
viewer.setComparer(new IElementComparer() {
@Override
public int hashCode(final Object element) {
if (element == null) {
return 0;
}
return Objects.hashCode(getRelativeReferenceForElement(element)) + hashCode(getElementParent(element));
}
@Override
public boolean equals(final Object element1, final Object element2) {
final Object ref1 = getRelativeReferenceForElement(element1);
final Object ref2 = getRelativeReferenceForElement(element2);
final boolean referencesAreEqual = Objects.equals(ref1, ref2);
if (!referencesAreEqual) {
return false;
}
if (element1 == null || element2 == null) {
return element1 == element2;
}
return equals(getElementParent(element1), getElementParent(element2));
}
});
viewer.setContentProvider(new ITreeContentProvider() {
@Override
public void dispose() {
}
@Override
public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) {
}
@Override
public Object[] getElements(final Object inputElement) {
if (inputElement instanceof InternalDiagramEditor) {
final InternalDiagramEditor editor = (InternalDiagramEditor) inputElement;
return getChildren(editor.getDiagram());
}
return new BusinessObjectContext[0];
}
@Override
public Object[] getChildren(final Object parentElement) {
if (parentElement instanceof BusinessObjectContext) {
final BusinessObjectContext parent = ((BusinessObjectContext) parentElement);
final List<BusinessObjectContext> children = new ArrayList<>();
// DiagramNodes represent elements which are part of the diagram
if (parent instanceof DiagramNode) {
final DiagramNode parentNode = (DiagramNode) parent;
// Add child diagram nodes
parentNode.getChildren().stream().filter((de) -> !Strings.isNullOrEmpty(de.getUserInterfaceName()) || de.getBusinessObject() instanceof EObject).forEach(children::add);
// Add children which are hidden based on user preference
if (showHiddenElementsAction.isChecked()) {
// If the diagram is a contextless diagram, create a business object context which uses the current project as the business object
final BusinessObjectContext parentForRetrieval;
if (parentElement instanceof AgeDiagram && ((AgeDiagram) parentElement).getConfiguration().getContextBoReference() == null) {
parentForRetrieval = new BusinessObjectContext() {
@Override
public Collection<? extends BusinessObjectContext> getChildren() {
return parentNode.getChildren();
}
@Override
public BusinessObjectContext getParent() {
return parent.getParent();
}
@Override
public Object getBusinessObject() {
return projectProvider.getProject();
}
};
} else {
parentForRetrieval = parent;
}
// Add children based on the objects returns by the business object provider for business objects which are not currently in the
// diagram.
getChildContextsFromProvider(parent, parentForRetrieval, childRef -> {
return !children.stream().map(AgeContentOutlinePage.this::getRelativeReferenceForElement).anyMatch(childRef::equals);
}).filter(this::includeHiddenBusinessObjectContext).forEachOrdered(children::add);
}
} else if (parent instanceof BusinessObjectContext) {
// Add children which are hidden based on user preference
if (showHiddenElementsAction.isChecked()) {
getChildContextsFromProvider(parent, parent, childRef -> true).filter(this::includeHiddenBusinessObjectContext).forEachOrdered(children::add);
}
}
return children.toArray();
}
return new BusinessObjectContext[0];
}
/**
* Filter returns whether a hidden business object context should be shown. This is implemented to be consistent with
* handling for diagram elements.
*/
private boolean includeHiddenBusinessObjectContext(final BusinessObjectContext boc) {
final Object bo = boc.getBusinessObject();
if (bo instanceof EObject) {
return true;
}
final BusinessObjectHandler boh = extRegistry.getApplicableBusinessObjectHandler(bo);
return boh != null && !Strings.isNullOrEmpty(boh.getName(new GetNameContext(bo)));
}
/**
* Creates a stream of business object contexts representing the children returned by the business object provider.
* Such contexts do not have a valid isChildren() method.
* @param parent is the context to use as the parent of returned contexts. This should be the DiagramNode if one exists.
* @param parentForRetrieval is the context to use when requesting children from the business object provider
* @param filterPredicate is a filter that can be used to filter results by the relative reference before the context is created
* @return A stream of child business object contexts
*/
private Stream<BusinessObjectContext> getChildContextsFromProvider(final BusinessObjectContext parent, final BusinessObjectContext parentForRetrieval, final Predicate<RelativeBusinessObjectReference> filterPredicate) {
return bopHelper.getChildBusinessObjects(parentForRetrieval).stream().map(childBo -> {
if (childBo instanceof BusinessObjectProxy) {
return ((BusinessObjectProxy) childBo).resolve(referenceService);
} else {
return childBo;
}
}).filter(Objects::nonNull).filter(childBo -> {
final RelativeBusinessObjectReference childRef = referenceService.getRelativeReference(childBo);
return childRef != null && filterPredicate.test(childRef);
}).map(childBo -> new BusinessObjectContext() {
@Override
public Collection<? extends BusinessObjectContext> getChildren() {
// Returns an empty list. Shouldn't be needed. All children are hidden and such children will be provided by the content provider.
return Collections.emptyList();
}
@Override
public BusinessObjectContext getParent() {
return parent;
}
@Override
public Object getBusinessObject() {
return childBo;
}
});
}
@Override
public Object getParent(final Object element) {
return getElementParent(element);
}
@Override
public boolean hasChildren(final Object element) {
if (element instanceof BusinessObjectContext) {
return getChildren(element).length > 0;
}
return false;
}
});
// Create a label provider that will be used by the tree's actual label provider which will be a StyledCellLabelProvider.
// This label provider is also used by the custom comparator because the default one does not support text provided by the styled cell label provider.
final LabelProvider innerLabelProvider = new LabelProvider() {
@Override
public String getText(final Object element) {
if (element instanceof BusinessObjectContext) {
final BusinessObjectContext boc = (BusinessObjectContext) element;
return UiUtil.getDescription(boc, extRegistry);
}
return super.getText(element);
}
@Override
public Image getImage(final Object element) {
if (element instanceof DiagramElement) {
final DiagramElement de = (DiagramElement) element;
return UiUtil.getImage(de.getBusinessObjectHandler(), de.getBusinessObject()).orElse(null);
} else if (element instanceof BusinessObjectContext) {
final BusinessObjectContext boc = (BusinessObjectContext) element;
final Object bo = boc.getBusinessObject();
return UiUtil.getImage(extRegistry, bo).orElse(null);
}
return null;
}
};
viewer.setLabelProvider(new StyledCellLabelProvider(StyledCellLabelProvider.COLORS_ON_SELECTION) {
@Override
public void update(final ViewerCell cell) {
final Object element = cell.getElement();
cell.setText(innerLabelProvider.getText(element));
cell.setForeground(element instanceof DiagramNode ? null : Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
cell.setImage(innerLabelProvider.getImage(element));
}
});
viewer.setComparator(new ViewerComparator() {
@Override
public int compare(final Viewer viewer, final Object e1, final Object e2) {
final String t1 = innerLabelProvider.getText(e1);
final String t2 = innerLabelProvider.getText(e2);
return getComparator().compare(t1, t2);
}
});
viewer.addDoubleClickListener(event -> UiUtil.openPropertiesView());
final MenuManager menuMgr = new MenuManager();
menuMgr.setRemoveAllWhenShown(true);
final Tree tree = viewer.getTree();
final Menu menu = menuMgr.createContextMenu(tree);
tree.setMenu(menu);
// Allow contributions
getSite().registerContextMenu("org.osate.ge.editor.AgeDiagramEditor", menuMgr, viewer);
editor.addSelectionChangedListener(event -> updateOutlineSelectionIfLinked());
editor.getDiagram().addModificationListener(diagramModificationListener);
viewer.addSelectionChangedListener(this);
viewer.setInput(editor);
}
Aggregations