| /******************************************************************************* |
| * Copyright (c) 2007, 2016 THALES GLOBAL SERVICES and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Obeo - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.sirius.diagram.business.internal.experimental.sync; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.emf.common.util.BasicEList; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.sirius.business.api.logger.RuntimeLoggerManager; |
| import org.eclipse.sirius.common.tools.DslCommonPlugin; |
| import org.eclipse.sirius.common.tools.api.interpreter.EvaluationException; |
| import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter; |
| import org.eclipse.sirius.common.tools.api.interpreter.IInterpreterSiriusVariables; |
| import org.eclipse.sirius.common.tools.api.util.StringUtil; |
| import org.eclipse.sirius.diagram.AbstractDNode; |
| import org.eclipse.sirius.diagram.DDiagram; |
| import org.eclipse.sirius.diagram.DDiagramElement; |
| import org.eclipse.sirius.diagram.DDiagramElementContainer; |
| import org.eclipse.sirius.diagram.DEdge; |
| import org.eclipse.sirius.diagram.DNode; |
| import org.eclipse.sirius.diagram.DNodeContainer; |
| import org.eclipse.sirius.diagram.DNodeList; |
| import org.eclipse.sirius.diagram.DNodeListElement; |
| import org.eclipse.sirius.diagram.DSemanticDiagram; |
| import org.eclipse.sirius.diagram.DiagramFactory; |
| import org.eclipse.sirius.diagram.DiagramPackage; |
| import org.eclipse.sirius.diagram.DragAndDropTarget; |
| import org.eclipse.sirius.diagram.EdgeStyle; |
| import org.eclipse.sirius.diagram.EdgeTarget; |
| import org.eclipse.sirius.diagram.NodeStyle; |
| import org.eclipse.sirius.diagram.WorkspaceImage; |
| import org.eclipse.sirius.diagram.business.api.componentization.DiagramDescriptionMappingsManager; |
| import org.eclipse.sirius.diagram.business.api.componentization.DiagramMappingsManager; |
| import org.eclipse.sirius.diagram.business.api.helper.SiriusDiagramHelper; |
| import org.eclipse.sirius.diagram.business.api.helper.display.DisplayMode; |
| import org.eclipse.sirius.diagram.business.api.helper.display.DisplayService; |
| import org.eclipse.sirius.diagram.business.api.helper.display.DisplayServiceManager; |
| import org.eclipse.sirius.diagram.business.api.helper.graphicalfilters.HideFilterHelper; |
| import org.eclipse.sirius.diagram.business.api.query.ContainerMappingQuery; |
| import org.eclipse.sirius.diagram.business.api.query.DiagramDescriptionMappingManagerQuery; |
| import org.eclipse.sirius.diagram.business.api.query.IEdgeMappingQuery; |
| import org.eclipse.sirius.diagram.business.internal.componentization.mappings.DiagramDescriptionMappingsManagerImpl; |
| import org.eclipse.sirius.diagram.business.internal.metamodel.helper.DiagramElementMappingHelper; |
| import org.eclipse.sirius.diagram.business.internal.metamodel.helper.LayerHelper; |
| import org.eclipse.sirius.diagram.business.internal.metamodel.helper.MappingHelper; |
| import org.eclipse.sirius.diagram.business.internal.metamodel.helper.StyleHelper; |
| import org.eclipse.sirius.diagram.description.AbstractNodeMapping; |
| import org.eclipse.sirius.diagram.description.ContainerMapping; |
| import org.eclipse.sirius.diagram.description.DescriptionPackage; |
| import org.eclipse.sirius.diagram.description.DiagramDescription; |
| import org.eclipse.sirius.diagram.description.DiagramElementMapping; |
| import org.eclipse.sirius.diagram.description.EdgeMapping; |
| import org.eclipse.sirius.diagram.description.IEdgeMapping; |
| import org.eclipse.sirius.diagram.description.MappingBasedDecoration; |
| import org.eclipse.sirius.diagram.description.NodeMapping; |
| import org.eclipse.sirius.diagram.description.style.ContainerStyleDescription; |
| import org.eclipse.sirius.diagram.description.style.EdgeStyleDescription; |
| import org.eclipse.sirius.diagram.description.style.EllipseNodeDescription; |
| import org.eclipse.sirius.diagram.description.style.LozengeNodeDescription; |
| import org.eclipse.sirius.diagram.description.style.NodeStyleDescription; |
| import org.eclipse.sirius.diagram.description.style.SquareDescription; |
| import org.eclipse.sirius.diagram.description.style.WorkspaceImageDescription; |
| import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor; |
| import org.eclipse.sirius.ext.base.Option; |
| import org.eclipse.sirius.ext.base.Options; |
| import org.eclipse.sirius.tools.api.interpreter.IInterpreterMessages; |
| import org.eclipse.sirius.tools.api.profiler.SiriusTasksKey; |
| import org.eclipse.sirius.viewpoint.DSemanticDecorator; |
| import org.eclipse.sirius.viewpoint.Decoration; |
| import org.eclipse.sirius.viewpoint.Style; |
| import org.eclipse.sirius.viewpoint.ViewpointFactory; |
| import org.eclipse.sirius.viewpoint.description.DecorationDescription; |
| import org.eclipse.sirius.viewpoint.description.SemanticBasedDecoration; |
| import org.eclipse.sirius.viewpoint.description.Viewpoint; |
| import org.eclipse.sirius.viewpoint.description.style.BasicLabelStyleDescription; |
| import org.eclipse.sirius.viewpoint.description.style.LabelStyleDescription; |
| import org.eclipse.sirius.viewpoint.description.style.StyleDescription; |
| import org.eclipse.sirius.viewpoint.description.style.StylePackage; |
| import org.eclipse.sirius.viewpoint.description.style.TooltipStyleDescription; |
| |
| import com.google.common.base.Objects; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Iterables; |
| |
| /** |
| * This class is able to synchronize diagram elements and styles. |
| * |
| * @author cbrun |
| */ |
| public class DDiagramElementSynchronizer { |
| |
| private final IInterpreter interpreter; |
| |
| private final DSemanticDiagram diagram; |
| |
| private final ModelAccessor accessor; |
| |
| private final StyleHelper styleHelper; |
| |
| private final MappingHelper mappingHelper; |
| |
| /** |
| * Create a new synchronizer for the given diagram. |
| * |
| * @param diagram |
| * diagram to synchronize. |
| * @param interpreter |
| * current interpreter. |
| * @param accessor |
| * model accessor |
| */ |
| public DDiagramElementSynchronizer(final DSemanticDiagram diagram, final IInterpreter interpreter, final ModelAccessor accessor) { |
| super(); |
| this.diagram = diagram; |
| this.interpreter = interpreter; |
| this.accessor = accessor; |
| this.styleHelper = new StyleHelper(interpreter); |
| this.mappingHelper = new MappingHelper(interpreter); |
| } |
| |
| /** |
| * Create completely a new Node with its style and so on from a candidate. |
| * |
| * @param mappingManager |
| * the manager used to handle return the Mappings to consider |
| * regarding the enablement of Viewpoints. |
| * @param candidate |
| * the node candidate, it contains the mapping and the semantic |
| * target. |
| * @param isBorder |
| * true if the element is a border one. |
| * @return newly created node. |
| */ |
| public AbstractDNode createNewNode(DiagramMappingsManager mappingManager, final AbstractDNodeCandidate candidate, final boolean isBorder) { |
| return createNewNode(mappingManager, candidate, isBorder, -1); |
| } |
| |
| /** |
| * Build a new Node from a candidate. |
| * |
| * @param mappingManager |
| * the manager used to handle return the Mappings to consider |
| * regarding the enablement of Viewpoints. |
| * @param candidate |
| * the node candidate, it contains the mapping and the semantic |
| * target. |
| * @param isBorder |
| * true if the element is a border one. |
| * @param insertionIndex |
| * the insertion index. give a negative value if you don't care |
| * @return newly created node. |
| */ |
| public AbstractDNode createNewNode(DiagramMappingsManager mappingManager, final AbstractDNodeCandidate candidate, final boolean isBorder, final int insertionIndex) { |
| final DragAndDropTarget container = candidate.getViewContainer(); |
| final AbstractDNode newNode = createAbstractNode(container, candidate, isBorder); |
| if (insertionIndex > 0) { |
| SiriusDiagramHelper.addNodeInContainer(container, isBorder, newNode, insertionIndex); |
| } else { |
| SiriusDiagramHelper.addNodeInContainer(container, isBorder, newNode); |
| } |
| refresh(newNode); |
| refreshSemanticElements(newNode, candidate.getMapping()); |
| createStyle(newNode, candidate.getMapping()); |
| computeVisibilityOnCreation(mappingManager, newNode); |
| return newNode; |
| } |
| |
| /** |
| * Build a new Node from a candidate. |
| * |
| * @param container |
| * the object who will contain the new node. |
| * @param candidate |
| * the node candidate, it contains the mapping and the semantic |
| * target. |
| * @param border |
| * true if the element is a border one. |
| * @return newly created node. |
| */ |
| private AbstractDNode createAbstractNode(final DragAndDropTarget container, final AbstractDNodeCandidate candidate, final boolean border) { |
| AbstractDNode result = null; |
| if (candidate.getMapping() instanceof NodeMapping) { |
| final NodeMapping mapping = (NodeMapping) candidate.getMapping(); |
| if (container instanceof DNodeList) { |
| if (!border) { |
| final DNodeListElement newNode = DiagramFactory.eINSTANCE.createDNodeListElement(); |
| newNode.setTarget(candidate.getSemantic()); |
| newNode.setActualMapping(mapping); |
| result = newNode; |
| } else { |
| final DNode newNode = DiagramFactory.eINSTANCE.createDNode(); |
| newNode.setTarget(candidate.getSemantic()); |
| newNode.setActualMapping(mapping); |
| result = newNode; |
| } |
| } else { |
| final DNode newNode = DiagramFactory.eINSTANCE.createDNode(); |
| newNode.setTarget(candidate.getSemantic()); |
| newNode.setActualMapping(mapping); |
| result = newNode; |
| |
| } |
| |
| } else if (candidate.getMapping() instanceof ContainerMapping) { |
| final ContainerMapping mapping = (ContainerMapping) candidate.getMapping(); |
| DDiagramElementContainer newContainer = null; |
| if (new ContainerMappingQuery(mapping).isListContainer()) { |
| newContainer = DiagramFactory.eINSTANCE.createDNodeList(); |
| } else { |
| // Other behaviors : ContainerLayout.FreeForm/VerticalStack |
| DNodeContainer nodeContainer = DiagramFactory.eINSTANCE.createDNodeContainer(); |
| nodeContainer.setChildrenPresentation(mapping.getChildrenPresentation()); |
| newContainer = nodeContainer; |
| } |
| newContainer.setTarget(candidate.getSemantic()); |
| newContainer.setActualMapping(mapping); |
| result = newContainer; |
| } |
| return result; |
| } |
| |
| /** |
| * Compute a mappings to edge target map for a given diagram. |
| * |
| * @param enabledVp |
| * the list of viewpoints to consider |
| * |
| * @return the requested map |
| */ |
| public Map<DiagramElementMapping, Collection<EdgeTarget>> computeMappingsToEdgeTargets(Collection<Viewpoint> enabledVp) { |
| final Map<DiagramElementMapping, Collection<EdgeTarget>> mappingsToEdgeTargets = new HashMap<DiagramElementMapping, Collection<EdgeTarget>>(); |
| |
| final DiagramDescription description = diagram.getDescription(); |
| |
| final DiagramDescriptionMappingsManager mappingsManager = new DiagramDescriptionMappingsManagerImpl(description); |
| mappingsManager.computeMappings(enabledVp); |
| final Set<DiagramElementMapping> allMappings = new DiagramDescriptionMappingManagerQuery(mappingsManager).computeAllMappings(); |
| final Iterable<NodeMapping> allNodeMappings = Iterables.filter(allMappings, NodeMapping.class); |
| final Iterable<ContainerMapping> allContainerMappings = Iterables.filter(allMappings, ContainerMapping.class); |
| final Iterable<EdgeMapping> allEdgeMappings = Iterables.filter(allMappings, EdgeMapping.class); |
| |
| for (final NodeMapping nodeMapping : allNodeMappings) { |
| final List<DNode> nodes = diagram.getNodesFromMapping(nodeMapping); |
| if (!nodes.isEmpty()) { |
| mappingsToEdgeTargets.put(nodeMapping, DDiagramElementSynchronizer.convertNodesAndContainersToEdgeTarget(nodes)); |
| } |
| } |
| |
| for (final ContainerMapping containerMapping : allContainerMappings) { |
| final List<DDiagramElementContainer> containers = diagram.getContainersFromMapping(containerMapping); |
| if (!containers.isEmpty()) { |
| mappingsToEdgeTargets.put(containerMapping, DDiagramElementSynchronizer.convertNodesAndContainersToEdgeTarget(containers)); |
| } |
| } |
| |
| for (final EdgeMapping edgeMapping : allEdgeMappings) { |
| final List<DEdge> edges = diagram.getEdgesFromMapping(edgeMapping); |
| if (!edges.isEmpty()) { |
| mappingsToEdgeTargets.put(edgeMapping, DDiagramElementSynchronizer.convertNodesAndContainersToEdgeTarget(edges)); |
| } |
| } |
| |
| return mappingsToEdgeTargets; |
| } |
| |
| private static Collection<EdgeTarget> convertNodesAndContainersToEdgeTarget(final Collection<? extends DDiagramElement> diagramElements) { |
| return ImmutableSet.copyOf(Iterables.filter(diagramElements, EdgeTarget.class)); |
| } |
| |
| /** |
| * Create completely a new Edge with it style path and so on from a |
| * candidate and the mappings maps. |
| * |
| * @param mappingManager |
| * the manager used to handle return the Mappings to consider |
| * regarding the enablement of Viewpoints. |
| * @param candidate |
| * the edge candidate |
| * @param mappingsToEdgeTargets |
| * mappings to edge targets map |
| * @param edgeToMappingBasedDecoration |
| * a map with for key a mapping and for value the associated |
| * decorations |
| * @param edgeToSemanticBasedDecoration |
| * a map with for key a domain class as string and for value the |
| * associated decorations |
| * @return the created edge |
| */ |
| public DEdge createNewEdge(DiagramMappingsManager mappingManager, final DEdgeCandidate candidate, final Map<DiagramElementMapping, Collection<EdgeTarget>> mappingsToEdgeTargets, |
| final Map<EdgeMapping, Collection<MappingBasedDecoration>> edgeToMappingBasedDecoration, final Map<String, Collection<SemanticBasedDecoration>> edgeToSemanticBasedDecoration) { |
| |
| DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.CREATE_MISSING_EDGES_KEY); |
| DEdge newEdge = createEdge(candidate); |
| diagram.getOwnedDiagramElements().add(newEdge); |
| |
| Option<EdgeMapping> edgeMapping = new IEdgeMappingQuery(candidate.getMapping()).getEdgeMapping(); |
| if (edgeMapping.some()) { |
| refreshSemanticElements(newEdge, edgeMapping.get()); |
| createStyle(newEdge, edgeMapping.get(), diagram); |
| refresh(newEdge); |
| updatePath(newEdge, edgeMapping.get(), mappingsToEdgeTargets); |
| } |
| |
| computeEdgeDecorations(newEdge, edgeToMappingBasedDecoration, edgeToSemanticBasedDecoration); |
| computeVisibilityOnCreation(mappingManager, newEdge); |
| |
| DslCommonPlugin.PROFILER.stopWork(SiriusTasksKey.CREATE_MISSING_EDGES_KEY); |
| return newEdge; |
| } |
| |
| /** |
| * Create a new Edge from a candidate. |
| * |
| * @param candidate |
| * the edge candidate containing the mapping and the edge |
| * semantic target (among other things). |
| * @return the newly created edge. |
| */ |
| private DEdge createEdge(final DEdgeCandidate candidate) { |
| final DEdge newEdge = DiagramFactory.eINSTANCE.createDEdge(); |
| newEdge.setTarget(candidate.getSemantic()); |
| newEdge.setActualMapping(candidate.getMapping()); |
| newEdge.setSourceNode(candidate.getSourceView()); |
| newEdge.setTargetNode(candidate.getTargetView()); |
| return newEdge; |
| } |
| |
| private void computeVisibilityOnCreation(DiagramMappingsManager mappingManager, final DDiagramElement element) { |
| final DisplayService service = DisplayServiceManager.INSTANCE.getDisplayService(DisplayMode.CREATION); |
| if (service == null) { |
| return; |
| } |
| |
| DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.IS_VISIBLE_KEY); |
| element.setVisible(service.computeVisibility(mappingManager, diagram, element)); |
| if (!service.computeLabelVisibility(diagram, element)) { |
| HideFilterHelper.INSTANCE.hideLabel(element); |
| } |
| DslCommonPlugin.PROFILER.stopWork(SiriusTasksKey.IS_VISIBLE_KEY); |
| } |
| |
| /** |
| * Compute edge decorations. |
| * |
| * @param edge |
| * the edge |
| * @param edgeToMappingBasedDecoration |
| * a map with for key a mapping and for value the associated |
| * decorations |
| * @param edgeToSemanticBasedDecoration |
| * a map with for key a domain class as string and for value the |
| * associated decorations |
| */ |
| public void computeEdgeDecorations(final DEdge edge, final Map<EdgeMapping, Collection<MappingBasedDecoration>> edgeToMappingBasedDecoration, |
| final Map<String, Collection<SemanticBasedDecoration>> edgeToSemanticBasedDecoration) { |
| /* semantic based decorations */ |
| IEdgeMapping actualMapping = edge.getActualMapping(); |
| final Option<EdgeMapping> edgeMapping = new IEdgeMappingQuery(actualMapping).getEdgeMapping(); |
| if (edgeMapping.some() && edgeMapping.get().isUseDomainElement() && edgeToSemanticBasedDecoration.containsKey(edgeMapping.get().getDomainClass())) { |
| final Collection<SemanticBasedDecoration> semanticBasedDecorations = edgeToSemanticBasedDecoration.get(edgeMapping.get().getDomainClass()); |
| for (final SemanticBasedDecoration semanticBasedDecoration : semanticBasedDecorations) { |
| this.addDecoration(edge, semanticBasedDecoration); |
| } |
| } |
| /* mapping based decoration */ |
| if (edgeToMappingBasedDecoration.containsKey(actualMapping)) { |
| final Collection<MappingBasedDecoration> mappingBasedDecorations = edgeToMappingBasedDecoration.get(actualMapping); |
| for (final MappingBasedDecoration mappingBasedDecoration : mappingBasedDecorations) { |
| this.addDecoration(edge, mappingBasedDecoration); |
| } |
| } |
| } |
| |
| /** |
| * Refresh an edge computing it's new size and style. |
| * |
| * @param edge |
| * edge to be refreshed. |
| */ |
| protected void refresh(final DEdge edge) { |
| EObject containerVariable = null; |
| if (edge.eContainer() instanceof DSemanticDecorator) { |
| containerVariable = ((DSemanticDecorator) edge.eContainer()).getTarget(); |
| } |
| // Recompute the conditional style |
| this.interpreter.setVariable(IInterpreterSiriusVariables.DIAGRAM, this.diagram); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.VIEW, edge); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.SOURCE_VIEW, edge.getSourceNode()); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.TARGET_VIEW, edge.getTargetNode()); |
| |
| this.mappingHelper.affectAndRefreshStyle(edge.getDiagramElementMapping(), edge, edge.getTarget(), containerVariable, (DDiagram) edge.eContainer()); |
| |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.DIAGRAM); |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.VIEW); |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.SOURCE_VIEW); |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.TARGET_VIEW); |
| |
| final EdgeStyle edgeStyle = edge.getOwnedStyle(); |
| if (edgeStyle != null) { |
| final EdgeStyleDescription edgeStyleDescription = (EdgeStyleDescription) edgeStyle.getDescription(); |
| // LABEL |
| refreshCenterLabel(edge, edgeStyleDescription); |
| refreshBeginLabel(edge, edgeStyleDescription); |
| refreshEndLabel(edge, edgeStyleDescription); |
| } |
| |
| // semantic elements |
| final Option<EdgeMapping> actualMapping = new IEdgeMappingQuery(edge.getActualMapping()).getEdgeMapping(); |
| if (actualMapping.some()) { |
| refreshSemanticElements(edge, actualMapping.get()); |
| } |
| |
| // clean decorations |
| cleanDecoration(edge); |
| } |
| |
| /** |
| * @param edge |
| * @param edgeStyleDescription |
| */ |
| private void refreshEndLabel(final DEdge edge, final EdgeStyleDescription edgeStyleDescription) { |
| if (edgeStyleDescription.getEndLabelStyleDescription() != null && !StringUtil.isEmpty(edgeStyleDescription.getEndLabelStyleDescription().getLabelExpression())) { |
| final String label = computeLabel(edge, edgeStyleDescription.getEndLabelStyleDescription()); |
| edge.setEndLabel(label); |
| if (!("".equals(edge.getEndLabel()) && label == null) && !StringUtil.equals(edge.getEndLabel(), label)) { //$NON-NLS-1$ |
| // This is a workaround for a CDO issue in legacy mode |
| // (https://bugs.eclipse.org/bugs/show_bug.cgi?id=404152) |
| edge.setEndLabel(label); |
| } |
| } else if (!StringUtil.isEmpty(edge.getEndLabel())) { |
| edge.setEndLabel(""); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * @param edge |
| * @param edgeStyleDescription |
| */ |
| private void refreshBeginLabel(final DEdge edge, final EdgeStyleDescription edgeStyleDescription) { |
| if (edgeStyleDescription.getBeginLabelStyleDescription() != null && !StringUtil.isEmpty(edgeStyleDescription.getBeginLabelStyleDescription().getLabelExpression())) { |
| final String label = computeLabel(edge, edgeStyleDescription.getBeginLabelStyleDescription()); |
| if (!("".equals(edge.getBeginLabel()) && label == null) && !StringUtil.equals(edge.getBeginLabel(), label)) { //$NON-NLS-1$ |
| // This is a workaround for a CDO issue in legacy mode |
| // (https://bugs.eclipse.org/bugs/show_bug.cgi?id=404152) |
| edge.setBeginLabel(label); |
| } |
| } else if (!StringUtil.isEmpty(edge.getBeginLabel())) { |
| edge.setBeginLabel(""); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * @param edge |
| * @param edgeStyleDescription |
| */ |
| private void refreshCenterLabel(final DEdge edge, final EdgeStyleDescription edgeStyleDescription) { |
| if (edgeStyleDescription.getCenterLabelStyleDescription() != null && !StringUtil.isEmpty(edgeStyleDescription.getCenterLabelStyleDescription().getLabelExpression())) { |
| final String label = computeLabel(edge, edgeStyleDescription.getCenterLabelStyleDescription()); |
| if (!("".equals(edge.getName()) && label == null) && !StringUtil.equals(edge.getName(), label)) { //$NON-NLS-1$ |
| // This is a workaround for a CDO issue in legacy mode |
| // (https://bugs.eclipse.org/bugs/show_bug.cgi?id=404152) |
| edge.setName(label); |
| } |
| } else if (!StringUtil.isEmpty(edge.getName())) { |
| edge.setName(""); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Refresh a DDiagramElement computing it's label, size and style. |
| * |
| * @param dde |
| * node to be refreshed. |
| */ |
| public void refresh(final DDiagramElement dde) { |
| if (accessor.getPermissionAuthority().canEditInstance(dde)) { |
| if (dde instanceof DNode) { |
| refresh((DNode) dde); |
| } else if (dde instanceof DNodeListElement) { |
| refresh((DNodeListElement) dde); |
| } else if (dde instanceof DDiagramElementContainer) { |
| refresh((DDiagramElementContainer) dde); |
| } else if (dde instanceof DEdge) { |
| refresh((DEdge) dde); |
| } |
| } |
| } |
| |
| /** |
| * Refresh a list element. |
| * |
| * @param newNode |
| * list element to be refreshed. |
| */ |
| protected void refresh(final DNodeListElement newNode) { |
| final DSemanticDecorator container = (DSemanticDecorator) newNode.eContainer(); |
| if (container != null) { |
| final NodeStyleDescription style = (NodeStyleDescription) this.mappingHelper.getBestStyleDescription(newNode.getActualMapping(), newNode.getTarget(), newNode, container.getTarget(), |
| diagram); |
| if (style != null) { |
| refreshLabel(newNode, style); |
| refreshTooltip(newNode, style); |
| } |
| } |
| if (newNode.getOwnedStyle() != null) { |
| Option<NodeStyle> noPreviousStyle = Options.newNone(); |
| styleHelper.refreshStyle(newNode.getOwnedStyle(), noPreviousStyle); |
| } |
| refreshSemanticElements(newNode, newNode.getDiagramElementMapping()); |
| } |
| |
| /** |
| * Refresh a container. |
| * |
| * @param container |
| * element to be refreshed. |
| */ |
| protected void refresh(final DDiagramElementContainer container) { |
| final DSemanticDecorator cContainer = (DSemanticDecorator) container.eContainer(); |
| ContainerMapping containerMapping = container.getActualMapping(); |
| if (cContainer != null) { |
| ContainerStyleDescription containerStyleDescription = null; |
| if (hasSafeTarget(container) && hasSafeTarget(cContainer)) { |
| containerStyleDescription = (ContainerStyleDescription) this.mappingHelper.getBestStyleDescription(containerMapping, container.getTarget(), container, cContainer.getTarget(), diagram); |
| } |
| if (containerStyleDescription != null) { |
| refreshLabel(container, containerStyleDescription); |
| refreshTooltip(container, containerStyleDescription); |
| refreshStyle(container, containerMapping); |
| } |
| } |
| // clean decorations |
| cleanDecoration(container); |
| refreshSemanticElements(container, containerMapping); |
| } |
| |
| private void cleanDecoration(final DDiagramElement element) { |
| Iterator<Decoration> it = element.getDecorations().iterator(); |
| while (it.hasNext()) { |
| Decoration decoration = it.next(); |
| final DecorationDescription description = decoration.getDescription(); |
| if (!diagram.getActivatedLayers().contains(LayerHelper.getParentLayer(description)) |
| || !checkDecoratorPrecondition(element.getTarget(), (DSemanticDecorator) element.eContainer(), description)) { |
| it.remove(); |
| } |
| } |
| } |
| |
| /** |
| * Refresh a {@link DNode}. |
| * |
| * @param newNode |
| * node to be refreshed. |
| */ |
| protected void refresh(final DNode newNode) { |
| final DSemanticDecorator container = (DSemanticDecorator) newNode.eContainer(); |
| if (container != null) { |
| NodeStyleDescription nodeStyleDescription = null; |
| NodeMapping nodeMapping = newNode.getActualMapping(); |
| if (hasSafeTarget(newNode) && hasSafeTarget(container)) { |
| nodeStyleDescription = (NodeStyleDescription) this.mappingHelper.getBestStyleDescription(nodeMapping, newNode.getTarget(), newNode, container.getTarget(), diagram); |
| } |
| if (nodeStyleDescription != null) { |
| if (newNode.getResizeKind() != nodeStyleDescription.getResizeKind()) { |
| newNode.setResizeKind(nodeStyleDescription.getResizeKind()); |
| } |
| |
| // Don't set width and height here for Ellipse, Lozenge, Square |
| // or WorkspaceImage styles |
| boolean customSizeRefresh = nodeStyleDescription instanceof EllipseNodeDescription || nodeStyleDescription instanceof LozengeNodeDescription |
| || nodeStyleDescription instanceof SquareDescription || nodeStyleDescription instanceof WorkspaceImageDescription; |
| |
| if (!StringUtil.isEmpty(nodeStyleDescription.getSizeComputationExpression()) && !customSizeRefresh) { |
| styleHelper.setComputedSize(newNode, nodeStyleDescription); |
| } |
| |
| refreshLabel(newNode, nodeStyleDescription); |
| refreshTooltip(newNode, nodeStyleDescription); |
| refreshStyle(newNode, nodeMapping); |
| } |
| } |
| |
| // clean decorations |
| cleanDecoration(newNode); |
| refreshSemanticElements(newNode, newNode.getDiagramElementMapping()); |
| } |
| |
| private void refreshLabel(final DDiagramElement dde, LabelStyleDescription labelStyleDescription) { |
| if (!StringUtil.isEmpty(labelStyleDescription.getLabelExpression())) { |
| String computedLabel = computeLabel(dde, labelStyleDescription); |
| if (!("".equals(dde.getName()) && computedLabel == null) && !StringUtil.equals(dde.getName(), computedLabel)) { //$NON-NLS-1$ |
| // This is a workaround for a CDO issue in legacy mode |
| // (https://bugs.eclipse.org/bugs/show_bug.cgi?id=404152) |
| dde.setName(computedLabel); |
| } |
| } |
| } |
| |
| private void refreshTooltip(final DDiagramElement elt, final TooltipStyleDescription style) { |
| if (!StringUtil.isEmpty(style.getTooltipExpression())) { |
| final String oldValue = elt.getTooltipText(); |
| final String newValue = computeTooltip(elt, style); |
| if (!Objects.equal(newValue, oldValue)) { |
| elt.setTooltipText(newValue); |
| } |
| } |
| } |
| |
| /** |
| * Refreshes a node style. |
| * |
| * @param node |
| * Node which style is to be refreshed. |
| * @param mapping |
| * Mapping that is to be used to compute the best style for this |
| * node. |
| */ |
| public void refreshStyle(final AbstractDNode node, final AbstractNodeMapping mapping) { |
| EObject containerVariable = null; |
| if (node.eContainer() != null) { |
| this.interpreter.setVariable(IInterpreterSiriusVariables.CONTAINER_VIEW, node.eContainer()); |
| if (node.eContainer() instanceof DSemanticDecorator) { |
| containerVariable = ((DSemanticDecorator) node.eContainer()).getTarget(); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.CONTAINER, containerVariable); |
| |
| } |
| } |
| this.interpreter.setVariable(IInterpreterSiriusVariables.VIEWPOINT, this.diagram); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.DIAGRAM, this.diagram); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.VIEW, node); |
| |
| StyleDescription bestStyleDescription = null; |
| if (hasSafeTarget(node)) { |
| bestStyleDescription = this.mappingHelper.getBestStyleDescription(mapping, node.getTarget(), node, containerVariable, diagram); |
| } |
| Style style = node.getStyle(); |
| if (style != null) { |
| Style bestStyle = this.mappingHelper.getBestStyle(mapping, node.getTarget(), node, containerVariable, diagram); |
| // In case the current Style is a customized |
| if (bestStyleDescription != null && !isSameDescription(bestStyleDescription, style, bestStyle)) { |
| final Style currentStyle = style; |
| if (isCustomizedWorkspaceImageWorkspacePath(currentStyle)) { |
| styleHelper.refreshStyle(style); |
| } else { |
| styleHelper.setAndRefreshStyle(node, currentStyle, styleHelper.createStyle(bestStyleDescription)); |
| } |
| } else { |
| styleHelper.refreshStyle(style); |
| } |
| } else { |
| styleHelper.setAndRefreshStyle(node, null, styleHelper.createStyle(bestStyleDescription)); |
| } |
| |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.VIEW); |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.DIAGRAM); |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.VIEWPOINT); |
| if (node.eContainer() != null) { |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.CONTAINER_VIEW); |
| if (node.eContainer() instanceof DSemanticDecorator) { |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.CONTAINER); |
| } |
| } |
| } |
| |
| private boolean isCustomizedWorkspaceImageWorkspacePath(Style style) { |
| boolean isCustomizedWorkspaceImageWorkspacePath = false; |
| if (style instanceof WorkspaceImage) { |
| WorkspaceImage workspaceImage = (WorkspaceImage) style; |
| isCustomizedWorkspaceImageWorkspacePath = workspaceImage.getCustomFeatures().contains(DiagramPackage.Literals.WORKSPACE_IMAGE__WORKSPACE_PATH.getName()); |
| } |
| return isCustomizedWorkspaceImageWorkspacePath; |
| } |
| |
| /** |
| * |
| * @param bestStyleDescription |
| * the description |
| * @param style |
| * the current style |
| * @param bestStyle |
| * the best style |
| * @return if the description is the same type as the style |
| */ |
| private boolean isSameDescription(StyleDescription bestStyleDescription, Style style, Style bestStyle) { |
| return bestStyleDescription == style.getDescription() && bestStyle.eClass().equals(style.eClass()); |
| } |
| |
| /** |
| * Refreshes an edge style. |
| * |
| * @param edge |
| * Edge which style is to be refreshed. |
| * @param mapping |
| * Mapping that is to be used to compute the best style for this |
| * node. |
| * @param parentDiagram |
| * the parent diagram of the edge |
| */ |
| public void refreshStyle(final DEdge edge, final EdgeMapping mapping, final DDiagram parentDiagram) { |
| this.interpreter.setVariable(IInterpreterSiriusVariables.DIAGRAM, this.diagram); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.VIEW, edge); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.SOURCE_VIEW, edge.getSourceNode()); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.TARGET_VIEW, edge.getTargetNode()); |
| |
| EObject containerVariable = null; |
| if (edge.eContainer() instanceof DSemanticDecorator) { |
| containerVariable = ((DSemanticDecorator) edge.eContainer()).getTarget(); |
| } |
| StyleDescription bestStyleDescription = null; |
| if (edge.getTarget() != null) { |
| bestStyleDescription = this.mappingHelper.getBestStyleDescription(mapping, edge.getTarget(), edge, containerVariable, parentDiagram); |
| } |
| if (bestStyleDescription != null && bestStyleDescription != edge.getStyle().getDescription()) { |
| final Style currentStyle = edge.getStyle(); |
| styleHelper.setAndRefreshStyle(edge, currentStyle, styleHelper.createStyle(bestStyleDescription)); |
| } else if (edge.getStyle() != null) { |
| styleHelper.refreshStyle(edge.getStyle()); |
| } |
| |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.DIAGRAM); |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.VIEW); |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.SOURCE_VIEW); |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.TARGET_VIEW); |
| } |
| |
| /** |
| * Creates a node style. |
| * |
| * @param node |
| * node to refresh. |
| * @param mapping |
| * mapping to use to compute the style. |
| */ |
| public void createStyle(final AbstractDNode node, final AbstractNodeMapping mapping) { |
| EObject containerVariable = null; |
| if (node.eContainer() != null) { |
| this.interpreter.setVariable(IInterpreterSiriusVariables.CONTAINER_VIEW, node.eContainer()); |
| if (node.eContainer() instanceof DSemanticDecorator) { |
| containerVariable = ((DSemanticDecorator) node.eContainer()).getTarget(); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.CONTAINER, containerVariable); |
| } |
| } |
| this.interpreter.setVariable(IInterpreterSiriusVariables.VIEWPOINT, this.diagram); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.DIAGRAM, this.diagram); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.VIEW, node); |
| |
| this.mappingHelper.affectAndRefreshStyle(mapping, node, node.getTarget(), containerVariable, diagram); |
| |
| if (node.eContainer() != null) { |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.CONTAINER_VIEW); |
| if (node.eContainer() instanceof DSemanticDecorator) { |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.CONTAINER); |
| } |
| } |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.VIEW); |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.DIAGRAM); |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.VIEWPOINT); |
| } |
| |
| /** |
| * Creates an edge style. |
| * |
| * @param edge |
| * edge to refresh. |
| * |
| * @param mapping |
| * mapping to use to compute the new style. |
| * @param parentDiagram |
| * the parent diagram of the edge |
| */ |
| public void createStyle(final DEdge edge, final EdgeMapping mapping, final DDiagram parentDiagram) { |
| this.interpreter.setVariable(IInterpreterSiriusVariables.DIAGRAM, this.diagram); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.VIEW, edge); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.SOURCE_VIEW, edge.getSourceNode()); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.TARGET_VIEW, edge.getTargetNode()); |
| |
| if (edge.getStyle() == null || edge.getStyle().getCustomFeatures().isEmpty()) { |
| EObject containerVariable = null; |
| if (edge.eContainer() instanceof DSemanticDecorator) { |
| containerVariable = ((DSemanticDecorator) edge.eContainer()).getTarget(); |
| } |
| this.mappingHelper.affectAndRefreshStyle(mapping, edge, edge.getTarget(), containerVariable, parentDiagram); |
| } else { |
| if (edge.getStyle().getCustomFeatures().isEmpty()) { |
| Option<EdgeStyle> noPreviousStyle = Options.newNone(); |
| styleHelper.refreshStyle(edge.getOwnedStyle(), noPreviousStyle); |
| } else { |
| styleHelper.refreshStyle(edge.getOwnedStyle(), Options.newSome(edge.getOwnedStyle())); |
| } |
| } |
| |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.DIAGRAM); |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.VIEW); |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.SOURCE_VIEW); |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.TARGET_VIEW); |
| } |
| |
| private String computeLabel(final DDiagramElement view, final EObject descriptionObject) { |
| String result = IInterpreterMessages.DEFAULT_NAME_ON_FACTORY_EXCEPTION; |
| |
| if (descriptionObject instanceof BasicLabelStyleDescription) { |
| result = DiagramElementMappingHelper.computeLabel(view, (BasicLabelStyleDescription) descriptionObject, this.diagram, interpreter); |
| } |
| |
| return result; |
| } |
| |
| private String computeTooltip(final DSemanticDecorator view, final EObject descriptionObject) { |
| String result = StylePackage.eINSTANCE.getTooltipStyleDescription_TooltipExpression().getDefaultValueLiteral(); |
| |
| if (descriptionObject instanceof TooltipStyleDescription) { |
| String tooltipExpression = ((TooltipStyleDescription) descriptionObject).getTooltipExpression(); |
| |
| try { |
| interpreter.setVariable(IInterpreterSiriusVariables.VIEW, view); |
| result = interpreter.evaluateString(view.getTarget(), tooltipExpression); |
| } catch (final EvaluationException e) { |
| RuntimeLoggerManager.INSTANCE.error(descriptionObject, StylePackage.eINSTANCE.getTooltipStyleDescription_TooltipExpression(), e); |
| } finally { |
| interpreter.unSetVariable(IInterpreterSiriusVariables.VIEW); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Create the edge path if needed path. |
| * |
| * @param edge |
| * edge to update. |
| * @param mapping |
| * the edge mapping used for the path computing. |
| * @param mappingsToEdgeTargets |
| * map for the Mapping eobject to view elements. |
| */ |
| public void updatePath(final DEdge edge, final EdgeMapping mapping, final Map<DiagramElementMapping, Collection<EdgeTarget>> mappingsToEdgeTargets) { |
| if (mapping.getPathExpression() != null && !StringUtil.isEmpty(mapping.getPathExpression()) && mapping.getPathNodeMapping() != null) { |
| |
| List<EObject> pathSemanticCandidates = Collections.<EObject> emptyList(); |
| // variables. |
| interpreter.setVariable(IInterpreterSiriusVariables.VIEWPOINT, diagram); |
| interpreter.setVariable(IInterpreterSiriusVariables.DIAGRAM, diagram); |
| interpreter.setVariable(IInterpreterSiriusVariables.ELEMENT, edge.getTarget()); |
| if (edge.getSourceNode() instanceof DSemanticDecorator) { |
| interpreter.setVariable(IInterpreterSiriusVariables.SOURCE, ((DSemanticDecorator) edge.getSourceNode()).getTarget()); |
| } |
| if (edge.getTargetNode() instanceof DSemanticDecorator) { |
| interpreter.setVariable(IInterpreterSiriusVariables.TARGET, ((DSemanticDecorator) edge.getTargetNode()).getTarget()); |
| } |
| |
| try { |
| pathSemanticCandidates = new ArrayList<EObject>(interpreter.evaluateCollection(edge.getTarget(), mapping.getPathExpression())); |
| } catch (final EvaluationException e) { |
| RuntimeLoggerManager.INSTANCE.error(mapping, DescriptionPackage.eINSTANCE.getEdgeMapping_PathExpression(), e); |
| } finally { |
| interpreter.unSetVariable(IInterpreterSiriusVariables.VIEWPOINT); |
| interpreter.unSetVariable(IInterpreterSiriusVariables.DIAGRAM); |
| interpreter.unSetVariable(IInterpreterSiriusVariables.ELEMENT); |
| interpreter.unSetVariable(IInterpreterSiriusVariables.SOURCE); |
| interpreter.unSetVariable(IInterpreterSiriusVariables.TARGET); |
| } |
| |
| final Map<EObject, EdgeTarget> availableElements = getAvailableElements(mappingsToEdgeTargets, mapping.getPathNodeMapping()); |
| |
| final Collection<EObject> semanticAvailableElements = availableElements.keySet(); |
| |
| EList<EdgeTarget> newPath = new BasicEList<EdgeTarget>(); |
| |
| for (final EObject pathSemanticCandidate : pathSemanticCandidates) { |
| if (semanticAvailableElements.contains(pathSemanticCandidate)) { |
| newPath.add(availableElements.get(pathSemanticCandidate)); |
| } |
| } |
| |
| if (!newPath.isEmpty() && !edge.getPath().equals(newPath)) { |
| edge.getPath().clear(); |
| edge.getPath().addAll(newPath); |
| } |
| } |
| } |
| |
| private Map<EObject, EdgeTarget> getAvailableElements(final Map<DiagramElementMapping, Collection<EdgeTarget>> mappingsToEdgeTargets, final Collection<AbstractNodeMapping> mappings) { |
| final Map<EObject, EdgeTarget> semanticToEdgeTargets = new HashMap<EObject, EdgeTarget>(); |
| for (final DiagramElementMapping availableMapping : mappings) { |
| final Collection<EdgeTarget> edgeTargets = mappingsToEdgeTargets.get(availableMapping); |
| if (edgeTargets != null) { |
| for (final EdgeTarget edgeTarget : edgeTargets) { |
| if (edgeTarget instanceof DSemanticDecorator) { |
| semanticToEdgeTargets.put(((DSemanticDecorator) edgeTarget).getTarget(), edgeTarget); |
| } |
| } |
| } |
| } |
| return semanticToEdgeTargets; |
| } |
| |
| /** |
| * Add a decoration to a DdiagramElement. |
| * |
| * @param element |
| * element to decorate |
| * @param decorationDescription |
| * description of the decoration |
| */ |
| public void addDecoration(final DDiagramElement element, final DecorationDescription decorationDescription) { |
| for (final Decoration decoration : new ArrayList<Decoration>(element.getDecorations())) { |
| if (EcoreUtil.equals(decorationDescription, decoration.getDescription())) { |
| return; |
| } |
| } |
| // new decoration |
| if (checkDecoratorPrecondition(element.getTarget(), (DSemanticDecorator) element.eContainer(), decorationDescription)) { |
| final Decoration decoration = ViewpointFactory.eINSTANCE.createDecoration(); |
| decoration.setDescription(decorationDescription); |
| element.getDecorations().add(decoration); |
| } |
| } |
| |
| private boolean checkDecoratorPrecondition(final EObject semantic, final DSemanticDecorator container, final DecorationDescription decorationDescription) { |
| DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.CHECK_PRECONDITION_KEY); |
| boolean result = false; |
| if (decorationDescription != null && !decorationDescription.eIsProxy()) { |
| result = true; |
| final String preconditionExpression = decorationDescription.getPreconditionExpression(); |
| if (!StringUtil.isEmpty(preconditionExpression)) { |
| this.interpreter.setVariable(IInterpreterSiriusVariables.CONTAINER_VIEW, container); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.CONTAINER, container != null ? container.getTarget() : null); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.VIEWPOINT, this.diagram); |
| this.interpreter.setVariable(IInterpreterSiriusVariables.DIAGRAM, this.diagram); |
| try { |
| result = interpreter.evaluateBoolean(semantic, preconditionExpression); |
| } catch (final EvaluationException e) { |
| RuntimeLoggerManager.INSTANCE.error(decorationDescription, org.eclipse.sirius.viewpoint.description.DescriptionPackage.eINSTANCE.getDecorationDescription_PreconditionExpression(), |
| e); |
| } |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.CONTAINER_VIEW); |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.CONTAINER); |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.VIEWPOINT); |
| this.interpreter.unSetVariable(IInterpreterSiriusVariables.DIAGRAM); |
| } |
| } |
| DslCommonPlugin.PROFILER.stopWork(SiriusTasksKey.CHECK_PRECONDITION_KEY); |
| return result; |
| } |
| |
| private void refreshSemanticElements(final DDiagramElement element, final DiagramElementMapping mapping) { |
| DiagramElementMappingHelper.refreshSemanticElements(mapping, element, this.interpreter); |
| } |
| |
| /** |
| * Check if the target of this decorator is not null and is in a eResource. |
| * |
| * @param decorator |
| * The decorator to check |
| * @return true if the target is OK, false otherwise. |
| */ |
| private boolean hasSafeTarget(DSemanticDecorator semDec) { |
| EObject target = semDec.getTarget(); |
| return target != null && (target.eContainer() != null || target.eResource() != null); |
| } |
| } |