X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fhandler%2FCopyPasteUtil.java;fp=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fhandler%2FCopyPasteUtil.java;h=739516942f965cc4176b1bd21c2bcc61d7a372c8;hp=791826dee3751bdff02e53189d7382b54e3b69b2;hb=0ae2b770234dfc3cbb18bd38f324125cf0faca07;hpb=24e2b34260f219f0d1644ca7a138894980e25b14 diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/CopyPasteUtil.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/CopyPasteUtil.java index 791826dee..739516942 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/CopyPasteUtil.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/CopyPasteUtil.java @@ -1,537 +1,537 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management - * in Industry THTH ry. - * 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: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.diagram.handler; - -import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; -import java.util.Collection; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.Set; - -import org.simantics.Simantics; -import org.simantics.databoard.Bindings; -import org.simantics.db.ReadGraph; -import org.simantics.db.RequestProcessor; -import org.simantics.db.Resource; -import org.simantics.db.Session; -import org.simantics.db.WriteGraph; -import org.simantics.db.common.CommentMetadata; -import org.simantics.db.common.request.IndexRoot; -import org.simantics.db.common.request.UniqueRead; -import org.simantics.db.common.request.WriteRequest; -import org.simantics.db.common.utils.OrderedSetUtils; -import org.simantics.db.exception.DatabaseException; -import org.simantics.db.layer0.util.Layer0Utils; -import org.simantics.diagram.flag.DiagramFlagPreferences; -import org.simantics.diagram.flag.FlagLabelingScheme; -import org.simantics.diagram.flag.FlagUtil; -import org.simantics.diagram.flag.IOTableUtil; -import org.simantics.diagram.flag.IOTablesInfo; -import org.simantics.diagram.stubs.DiagramResource; -import org.simantics.diagram.synchronization.CopyAdvisor; -import org.simantics.diagram.synchronization.IModifiableSynchronizationContext; -import org.simantics.diagram.synchronization.SynchronizationHints; -import org.simantics.diagram.synchronization.graph.AddElement; -import org.simantics.diagram.synchronization.graph.CopyAdvisorUtil; -import org.simantics.diagram.synchronization.graph.DiagramGraphUtil; -import org.simantics.diagram.synchronization.graph.GraphSynchronizationHints; -import org.simantics.diagram.synchronization.graph.MoveRouteGraphConnection; -import org.simantics.diagram.synchronization.graph.layer.GraphLayerManager; -import org.simantics.diagram.ui.DiagramModelHints; -import org.simantics.g2d.canvas.ICanvasContext; -import org.simantics.g2d.diagram.DiagramHints; -import org.simantics.g2d.diagram.IDiagram; -import org.simantics.g2d.element.ElementUtils; -import org.simantics.g2d.element.IElement; -import org.simantics.g2d.elementclass.FlagClass.Type; -import org.simantics.g2d.elementclass.FlagHandler; -import org.simantics.layer0.Layer0; -import org.simantics.modeling.ModelingResources; -import org.simantics.scenegraph.g2d.snap.ISnapAdvisor; -import org.simantics.scl.commands.Command; -import org.simantics.scl.commands.Commands; - -/** - * @author Tuukka Lehtonen - */ -public final class CopyPasteUtil { - - static final EnumSet NODES = EnumSet.of(ElementType.Node); - static final EnumSet CONNECTIONS = EnumSet.of(ElementType.Connection); - public static final EnumSet CONNECTION_PARTS = EnumSet.of(ElementType.Edge, ElementType.BranchPoint); - public static final EnumSet FLAGS = EnumSet.of(ElementType.Flag); - static final EnumSet MONITORS = EnumSet.of(ElementType.Monitor); - static final EnumSet OTHERS = EnumSet.of(ElementType.Other); - static final EnumSet NODES_AND_EDGES = EnumSet.of(ElementType.Node); - static final EnumSet NOT_FLAGS = EnumSet.complementOf(FLAGS); - - public static boolean isFlagsOnlySelection(IElementAssortment ea) { - return !ea.containsAny(NOT_FLAGS) - && ea.contains(FLAGS) - && ea.count(ElementType.Flag) > 0; - } - - public static boolean onlyFlagsWithoutCorrespondence(RequestProcessor processor, ElementObjectAssortment ea) - throws DatabaseException { - return isFlagsOnlySelection(ea) - && checkFlagsCorrespondences(processor, ea.flags, false); - } - - public static boolean onlyFlagsWithoutCorrespondence(ElementAssortment ea) { - return isFlagsOnlySelection(ea) - && checkFlagsCorrespondences(ea.flags, false); - } - - /** - * Check that all specified flag elements either have a correspondence or - * don't. Flag collections with both connected and disconnected flags will - * always return false; - * - * @param flags - * @param expectedValue - * @return - * @throws DatabaseException - */ - public static boolean checkFlagsCorrespondences(RequestProcessor processor, final Iterable flags, final boolean expectedValue) throws DatabaseException { - return processor.syncRequest(new UniqueRead() { - @Override - public Boolean perform(ReadGraph graph) throws DatabaseException { - return checkFlagsCorrespondences(graph, flags, expectedValue); - } - }); - } - - /** - * Check that all specified flag elements either have a correspondence or - * don't. Flag collections with both connected and disconnected flags will - * always return false; - * - * @param flags - * @param expectedValue - * @return - * @throws DatabaseException - */ - public static boolean checkFlagsCorrespondences(ReadGraph graph, Iterable flags, boolean expectedValue) throws DatabaseException { - for (Resource flag : flags) { - if (FlagUtil.isJoined(graph, flag) != expectedValue) { - return false; - } - } - return true; - } - - /** - * Check that all specified flag elements either have a correspondence or - * don't. Flag collections with both connected and disconnected flags will - * always return false; - * - * @param flags - * @param expectedValue - * @return - */ - public static boolean checkFlagsCorrespondences(Iterable flags, boolean expectedValue) { - for (IElement flag : flags) { - if (flagHasCorrespondence(flag) != expectedValue) { - return false; - } - } - return true; - } - - /** - * @param flags flags to test - * @param expectedValue true to return true only - * if all flags are external, false to return - * true only if all flags are not external - * @return - * @throws DatabaseException - */ - public static boolean checkFlagExternality(RequestProcessor processor, final Iterable flags, final boolean expectedValue) throws DatabaseException { - return processor.syncRequest(new UniqueRead() { - @Override - public Boolean perform(ReadGraph graph) throws DatabaseException { - return checkFlagExternality(graph, flags, expectedValue); - } - }); - } - - /** - * @param flags flags to test - * @param expectedValue true to return true only - * if all flags are external, false to return - * true only if all flags are not external - * @return - * @throws DatabaseException - */ - public static boolean checkFlagExternality(ReadGraph graph, Iterable flags, boolean expectedValue) throws DatabaseException { - for (Resource flag : flags) - if (FlagUtil.isExternal(graph, flag) != expectedValue) - return false; - return true; - } - - /** - * @param flags flags to test - * @param expectedValue true to return true only - * if all flags are external, false to return - * true only if all flags are not external - * @return - */ - public static boolean checkFlagExternality(Iterable flags, boolean expectedValue) { - for (IElement flag : flags) - if (flagIsExternal(flag) != expectedValue) - return false; - return true; - } - - public static boolean flagHasCorrespondence(IElement flag) { - FlagHandler fh = flag.getElementClass().getSingleItem(FlagHandler.class); - if (fh == null) - throw new IllegalArgumentException("Not a flag element: " + flag); - //return (fh.getConnection(flag) != null || fh.getConnectionData(flag) != null); - return fh.getConnectionData(flag) != null; - } - - public static boolean flagIsExternal(IElement flag) { - FlagHandler fh = flag.getElementClass().getSingleItem(FlagHandler.class); - if (fh == null) - throw new IllegalArgumentException("Not a flag element: " + flag); - //return (fh.getConnection(flag) != null || fh.getConnectionData(flag) != null); - return fh.isExternal(flag); - } - - /** - * @param graph - * @param connection - * @return - * @throws DatabaseException - */ - public static Set gatherBranchPoints(ReadGraph graph, ElementObjectAssortment ea) throws DatabaseException { - Set bps = new HashSet(); - bps.addAll(ea.branchPoints); - for (Resource connection : ea.connections) - bps.addAll( getBranchPoints(graph, connection) ); - return bps; - } - - /** - * @param connection - * @return - * @throws DatabaseException - */ - public static Set gatherRouteGraphConnections(ReadGraph graph, ElementObjectAssortment ea) throws DatabaseException { - Set rgcs = new HashSet(); - DiagramResource DIA = DiagramResource.getInstance(graph); - for (Resource connection : ea.connections) { - if (graph.isInstanceOf(connection, DIA.RouteGraphConnection)) - rgcs.add(connection); - } - return rgcs; - } - - /** - * @param connection - * @return - * @throws DatabaseException - */ - public static Collection getBranchPoints(ReadGraph graph, Resource connection) throws DatabaseException { - return graph.getObjects(connection, DiagramResource.getInstance(graph).HasBranchPoint); - } - - /** - * @param m - * @param elements - * @param xoffset - * @param yoffset - * @throws DatabaseException - */ - public static void moveElements(WriteGraph graph, Set elements, double xoffset, double yoffset) - throws DatabaseException { - for (Resource e : elements) { - AffineTransform at = DiagramGraphUtil.getAffineTransform(graph, e); - at.setTransform(at.getScaleX(), at.getShearY(), at.getShearX(), at.getScaleY(), - at.getTranslateX() + xoffset, - at.getTranslateY() + yoffset); - DiagramGraphUtil.setTransform(graph, e, at); - } - } - - /** - * @param m - * @param elements - * @param offset - * @throws DatabaseException - */ - public static void moveElements(WriteGraph graph, Set elements, Point2D offset) throws DatabaseException { - moveElements(graph, elements, offset.getX(), offset.getY()); - } - - /** - * @param m - * @param elements - * @param xoffset - * @param yoffset - * @throws DatabaseException - */ - public static void moveParentedElements(WriteGraph graph, PasteOperation op, Set elements, Resource parentRelation, double xoffset, double yoffset) - throws DatabaseException { - ModelingResources MOD = ModelingResources.getInstance(graph); - for (Resource e : elements) { - Resource referencedParentComponent = graph.getPossibleObject(e, parentRelation); - if (referencedParentComponent == null) - continue; - Resource referencedElement = graph.getPossibleObject(referencedParentComponent, MOD.ComponentToElement); - // Don't move the element if it's parent element is also included in the moved set of elements. - if (referencedElement != null && op.ea.all.contains(referencedElement)) - continue; - - AffineTransform at = DiagramGraphUtil.getAffineTransform(graph, e); - at.setTransform(at.getScaleX(), at.getShearY(), at.getShearX(), at.getScaleY(), - at.getTranslateX() + xoffset, - at.getTranslateY() + yoffset); - DiagramGraphUtil.setTransform(graph, e, at); - } - } - - /** - * @param m - * @param elements - * @param xoffset - * @param yoffset - * @throws DatabaseException - */ - public static void moveMonitors(WriteGraph graph, PasteOperation op, Set elements, double xoffset, double yoffset) - throws DatabaseException { - moveParentedElements(graph, op, elements, DiagramResource.getInstance(graph).HasMonitorComponent, xoffset, yoffset); - } - - - /** - * @param m - * @param elements - * @param xoffset - * @param yoffset - * @throws DatabaseException - */ - public static void moveReferenceElements(WriteGraph graph, PasteOperation op, Set elements, double xoffset, double yoffset) - throws DatabaseException { - moveParentedElements(graph, op, elements, ModelingResources.getInstance(graph).HasParentComponent, xoffset, yoffset); - } - - /** - * @param graph - * @param connections - * @param xoffset - * @param yoffset - * @throws DatabaseException - */ - public static void moveRouteGraphConnections(WriteGraph graph, Set connections, Point2D offset) throws DatabaseException { - if(!connections.isEmpty()) { - Command command = Commands.get(graph, "Simantics/Diagram/moveConnection"); - Resource root = graph.syncRequest(new IndexRoot(connections.iterator().next())); - for (Resource r : connections) - command.execute(graph, root, r, offset.getX(), offset.getY()); - } - } - - public static void moveConnection(WriteGraph graph, Resource connection, double offsetX, double offsetY) throws DatabaseException { - new MoveRouteGraphConnection(connection, offsetX, offsetY).perform(graph); - } - - /** - * @param ctx - * @param source - * @param target - * @param offset - */ - public static void copyElementPosition(ICanvasContext ctx, IElement source, IElement target, Point2D offset) { - Point2D pos = ElementUtils.getPos(source); - double x = pos.getX() + offset.getX(); - double y = pos.getY() + offset.getY(); - ElementUtils.setPos(target, snap(ctx, new Point2D.Double(x, y))); - } - - /** - * @param ctx - * @param source - * @param target - * @param offset - * @throws DatabaseException - */ - public static AffineTransform copyElementPosition(WriteGraph graph, ICanvasContext ctx, Resource sourceElement, Resource targetElement, Point2D offset) throws DatabaseException { - AffineTransform at = getCopyTransform(graph, ctx, sourceElement); - Point2D snapped = snap(ctx, new Point2D.Double(at.getTranslateX() + offset.getX(), at.getTranslateY() + offset.getY())); - at.setTransform(at.getScaleX(), at.getShearY(), at.getShearX(), at.getScaleY(), snapped.getX(), snapped.getY()); - DiagramGraphUtil.setTransform(graph, targetElement, at); - return at; - } - - private static AffineTransform getCopyTransform(ReadGraph graph, ICanvasContext ctx, Resource sourceElement) throws DatabaseException { - if(ctx != null){ - Resource runtimeDiagram = (Resource)((IDiagram)ctx.getDefaultHintContext().getHint(DiagramHints.KEY_DIAGRAM)).getHint(DiagramModelHints.KEY_DIAGRAM_RUNTIME_RESOURCE); - return DiagramGraphUtil.getDynamicAffineTransform(graph, runtimeDiagram, sourceElement); - } else { - return DiagramGraphUtil.getAffineTransform(graph, sourceElement); - } - } - - /** - * @param ctx - * @param p - * @return - */ - public static Point2D snap(ICanvasContext ctx, Point2D p) { - if (ctx != null) { - ISnapAdvisor snapAdvisor = ctx.getHintStack().getHint(DiagramHints.SNAP_ADVISOR); - if (snapAdvisor != null) - snapAdvisor.snap(p); - } - return p; - } - - // ------------------------------------------------------------------------ - - /** - * Performs the operations related to a diagram-local cut-paste operation. - * This default implementation will merely translate the selection specified - * by the operation. - * - * @param op - * @throws DatabaseException - */ - public static void localCutPaste(final PasteOperation op) throws DatabaseException { - Simantics.getSession().sync(new WriteRequest() { - @Override - public void perform(WriteGraph graph) throws DatabaseException { - graph.markUndoPoint(); - localCutPaste(graph, op); - Layer0Utils.addCommentMetadata(graph, "Cutted " + op + " to local target"); - } - }); - } - - /** - * Performs the operations related to a diagram-local cut-paste operation. - * This default implementation will merely translate the selection specified - * by the operation. - * - * @param graph - * @param op - * @throws DatabaseException - */ - public static void localCutPaste(WriteGraph graph, PasteOperation op) throws DatabaseException { - if (op.sameDiagram() && op.cut) { - CopyPasteUtil.moveElements(graph, op.ea.nodes, op.offset); - CopyPasteUtil.moveElements(graph, op.ea.flags, op.offset); - if(!op.ea.flags.isEmpty()) { - IOTablesInfo ioTablesInfo = IOTableUtil.getIOTablesInfo(graph, op.targetDiagram); - DiagramResource DIA = DiagramResource.getInstance(graph); - for(Resource flag : op.ea.flags) { - double[] transform = graph.getRelatedValue(flag, DIA.HasTransform, Bindings.DOUBLE_ARRAY); - ioTablesInfo.updateBinding(graph, DIA, flag, transform[4], transform[5]); - } - } - CopyPasteUtil.moveElements(graph, CopyPasteUtil.gatherBranchPoints(graph, op.ea), op.offset); - CopyPasteUtil.moveRouteGraphConnections(graph, CopyPasteUtil.gatherRouteGraphConnections(graph, op.ea), op.offset); - CopyPasteUtil.moveElements(graph, op.ea.others, op.offset); - CopyPasteUtil.moveMonitors(graph, op, op.ea.monitors, op.offset.getX(), op.offset.getY()); - CopyPasteUtil.moveReferenceElements(graph, op, op.ea.references, op.offset.getX(), op.offset.getY()); - } - } - - /** - * @param op - * @throws DatabaseException - */ - public static void continueFlags(final PasteOperation op) throws DatabaseException { - Simantics.getSession().sync(new WriteRequest() { - @Override - public void perform(WriteGraph graph) throws DatabaseException { - continueFlags(graph, op); - } - }); - } - - /** - * @param graph - * @param op - * @throws DatabaseException - */ - public static void continueFlags(WriteGraph graph, final PasteOperation op) throws DatabaseException { - IModifiableSynchronizationContext targetContext = (IModifiableSynchronizationContext) op.target.getHint(SynchronizationHints.CONTEXT); - if (targetContext == null) - throw new IllegalArgumentException("target diagram has no synchronization context"); - - CopyAdvisor ca = op.target.getHint(SynchronizationHints.COPY_ADVISOR); - if (ca == null) - throw new IllegalArgumentException("no copy advisor"); - - Layer0 L0 = Layer0.getInstance(graph); - DiagramResource DIA = DiagramResource.getInstance(graph); - - FlagLabelingScheme scheme = DiagramFlagPreferences.getActiveFlagLabelingScheme(graph); - int joinedFlags = 0; - - for (Resource src : op.ea.flags) { - Resource sourceDiagram = graph.getPossibleObject(src, L0.PartOf); - Resource copy = CopyAdvisorUtil.copy(targetContext, graph, ca, src, sourceDiagram, op.targetDiagram); - if(copy == null) - continue; - OrderedSetUtils.add(graph, op.targetDiagram, copy); - graph.claim(op.targetDiagram, L0.ConsistsOf, copy); - AddElement.claimFreshElementName(graph, op.targetDiagram, copy); - - GraphLayerManager glm = targetContext.get(GraphSynchronizationHints.GRAPH_LAYER_MANAGER); - if (glm != null) { - glm.removeFromAllLayers(graph, copy); - glm.putElementOnVisibleLayers(op.target, graph, copy); - } - - AffineTransform at = CopyPasteUtil.copyElementPosition(graph, op.ctx, src, copy, op.offset); - Type type = FlagUtil.getFlagType(graph, src, Type.Out); - FlagUtil.setFlagType(graph, copy, type.other()); - - FlagUtil.join(graph, src, copy); - - if (scheme != null) { - String label = scheme.generateLabel(graph, op.targetDiagram); - if (label != null) { - graph.claimLiteral(src, L0.HasLabel, DIA.FlagLabel, label, Bindings.STRING); - graph.claimLiteral(copy, L0.HasLabel, DIA.FlagLabel, label, Bindings.STRING); - } - } - - // Update flag table binding - IOTablesInfo ioTablesInfo = IOTableUtil.getIOTablesInfo(graph, op.targetDiagram); - ioTablesInfo.updateBinding(graph, DIA, copy, at.getTranslateX(), at.getTranslateY()); - - ++joinedFlags; - } - - if (joinedFlags > 0) { - // Add comment to change set. - CommentMetadata cm = graph.getMetadata(CommentMetadata.class); - graph.addMetadata(cm.add("Continued " + joinedFlags + " flag(s)")); - } - } - - /** - * @param op - * @throws DatabaseException - */ - public static void performDefaultPaste(PasteOperation op) throws DatabaseException { - Session session = Simantics.getSession(); - new Paster(session, op).perform(); - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * 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: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.diagram.handler; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Set; + +import org.simantics.Simantics; +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.RequestProcessor; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.CommentMetadata; +import org.simantics.db.common.request.IndexRoot; +import org.simantics.db.common.request.UniqueRead; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.common.utils.OrderedSetUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.util.Layer0Utils; +import org.simantics.diagram.flag.DiagramFlagPreferences; +import org.simantics.diagram.flag.FlagLabelingScheme; +import org.simantics.diagram.flag.FlagUtil; +import org.simantics.diagram.flag.IOTableUtil; +import org.simantics.diagram.flag.IOTablesInfo; +import org.simantics.diagram.stubs.DiagramResource; +import org.simantics.diagram.synchronization.CopyAdvisor; +import org.simantics.diagram.synchronization.IModifiableSynchronizationContext; +import org.simantics.diagram.synchronization.SynchronizationHints; +import org.simantics.diagram.synchronization.graph.AddElement; +import org.simantics.diagram.synchronization.graph.CopyAdvisorUtil; +import org.simantics.diagram.synchronization.graph.DiagramGraphUtil; +import org.simantics.diagram.synchronization.graph.GraphSynchronizationHints; +import org.simantics.diagram.synchronization.graph.MoveRouteGraphConnection; +import org.simantics.diagram.synchronization.graph.layer.GraphLayerManager; +import org.simantics.diagram.ui.DiagramModelHints; +import org.simantics.g2d.canvas.ICanvasContext; +import org.simantics.g2d.diagram.DiagramHints; +import org.simantics.g2d.diagram.IDiagram; +import org.simantics.g2d.element.ElementUtils; +import org.simantics.g2d.element.IElement; +import org.simantics.g2d.elementclass.FlagClass.Type; +import org.simantics.g2d.elementclass.FlagHandler; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.ModelingResources; +import org.simantics.scenegraph.g2d.snap.ISnapAdvisor; +import org.simantics.scl.commands.Command; +import org.simantics.scl.commands.Commands; + +/** + * @author Tuukka Lehtonen + */ +public final class CopyPasteUtil { + + static final EnumSet NODES = EnumSet.of(ElementType.Node); + static final EnumSet CONNECTIONS = EnumSet.of(ElementType.Connection); + public static final EnumSet CONNECTION_PARTS = EnumSet.of(ElementType.Edge, ElementType.BranchPoint); + public static final EnumSet FLAGS = EnumSet.of(ElementType.Flag); + static final EnumSet MONITORS = EnumSet.of(ElementType.Monitor); + static final EnumSet OTHERS = EnumSet.of(ElementType.Other); + static final EnumSet NODES_AND_EDGES = EnumSet.of(ElementType.Node); + static final EnumSet NOT_FLAGS = EnumSet.complementOf(FLAGS); + + public static boolean isFlagsOnlySelection(IElementAssortment ea) { + return !ea.containsAny(NOT_FLAGS) + && ea.contains(FLAGS) + && ea.count(ElementType.Flag) > 0; + } + + public static boolean onlyFlagsWithoutCorrespondence(RequestProcessor processor, ElementObjectAssortment ea) + throws DatabaseException { + return isFlagsOnlySelection(ea) + && checkFlagsCorrespondences(processor, ea.flags, false); + } + + public static boolean onlyFlagsWithoutCorrespondence(ElementAssortment ea) { + return isFlagsOnlySelection(ea) + && checkFlagsCorrespondences(ea.flags, false); + } + + /** + * Check that all specified flag elements either have a correspondence or + * don't. Flag collections with both connected and disconnected flags will + * always return false; + * + * @param flags + * @param expectedValue + * @return + * @throws DatabaseException + */ + public static boolean checkFlagsCorrespondences(RequestProcessor processor, final Iterable flags, final boolean expectedValue) throws DatabaseException { + return processor.syncRequest(new UniqueRead() { + @Override + public Boolean perform(ReadGraph graph) throws DatabaseException { + return checkFlagsCorrespondences(graph, flags, expectedValue); + } + }); + } + + /** + * Check that all specified flag elements either have a correspondence or + * don't. Flag collections with both connected and disconnected flags will + * always return false; + * + * @param flags + * @param expectedValue + * @return + * @throws DatabaseException + */ + public static boolean checkFlagsCorrespondences(ReadGraph graph, Iterable flags, boolean expectedValue) throws DatabaseException { + for (Resource flag : flags) { + if (FlagUtil.isJoined(graph, flag) != expectedValue) { + return false; + } + } + return true; + } + + /** + * Check that all specified flag elements either have a correspondence or + * don't. Flag collections with both connected and disconnected flags will + * always return false; + * + * @param flags + * @param expectedValue + * @return + */ + public static boolean checkFlagsCorrespondences(Iterable flags, boolean expectedValue) { + for (IElement flag : flags) { + if (flagHasCorrespondence(flag) != expectedValue) { + return false; + } + } + return true; + } + + /** + * @param flags flags to test + * @param expectedValue true to return true only + * if all flags are external, false to return + * true only if all flags are not external + * @return + * @throws DatabaseException + */ + public static boolean checkFlagExternality(RequestProcessor processor, final Iterable flags, final boolean expectedValue) throws DatabaseException { + return processor.syncRequest(new UniqueRead() { + @Override + public Boolean perform(ReadGraph graph) throws DatabaseException { + return checkFlagExternality(graph, flags, expectedValue); + } + }); + } + + /** + * @param flags flags to test + * @param expectedValue true to return true only + * if all flags are external, false to return + * true only if all flags are not external + * @return + * @throws DatabaseException + */ + public static boolean checkFlagExternality(ReadGraph graph, Iterable flags, boolean expectedValue) throws DatabaseException { + for (Resource flag : flags) + if (FlagUtil.isExternal(graph, flag) != expectedValue) + return false; + return true; + } + + /** + * @param flags flags to test + * @param expectedValue true to return true only + * if all flags are external, false to return + * true only if all flags are not external + * @return + */ + public static boolean checkFlagExternality(Iterable flags, boolean expectedValue) { + for (IElement flag : flags) + if (flagIsExternal(flag) != expectedValue) + return false; + return true; + } + + public static boolean flagHasCorrespondence(IElement flag) { + FlagHandler fh = flag.getElementClass().getSingleItem(FlagHandler.class); + if (fh == null) + throw new IllegalArgumentException("Not a flag element: " + flag); + //return (fh.getConnection(flag) != null || fh.getConnectionData(flag) != null); + return fh.getConnectionData(flag) != null; + } + + public static boolean flagIsExternal(IElement flag) { + FlagHandler fh = flag.getElementClass().getSingleItem(FlagHandler.class); + if (fh == null) + throw new IllegalArgumentException("Not a flag element: " + flag); + //return (fh.getConnection(flag) != null || fh.getConnectionData(flag) != null); + return fh.isExternal(flag); + } + + /** + * @param graph + * @param connection + * @return + * @throws DatabaseException + */ + public static Set gatherBranchPoints(ReadGraph graph, ElementObjectAssortment ea) throws DatabaseException { + Set bps = new HashSet(); + bps.addAll(ea.branchPoints); + for (Resource connection : ea.connections) + bps.addAll( getBranchPoints(graph, connection) ); + return bps; + } + + /** + * @param connection + * @return + * @throws DatabaseException + */ + public static Set gatherRouteGraphConnections(ReadGraph graph, ElementObjectAssortment ea) throws DatabaseException { + Set rgcs = new HashSet(); + DiagramResource DIA = DiagramResource.getInstance(graph); + for (Resource connection : ea.connections) { + if (graph.isInstanceOf(connection, DIA.RouteGraphConnection)) + rgcs.add(connection); + } + return rgcs; + } + + /** + * @param connection + * @return + * @throws DatabaseException + */ + public static Collection getBranchPoints(ReadGraph graph, Resource connection) throws DatabaseException { + return graph.getObjects(connection, DiagramResource.getInstance(graph).HasBranchPoint); + } + + /** + * @param m + * @param elements + * @param xoffset + * @param yoffset + * @throws DatabaseException + */ + public static void moveElements(WriteGraph graph, Set elements, double xoffset, double yoffset) + throws DatabaseException { + for (Resource e : elements) { + AffineTransform at = DiagramGraphUtil.getAffineTransform(graph, e); + at.setTransform(at.getScaleX(), at.getShearY(), at.getShearX(), at.getScaleY(), + at.getTranslateX() + xoffset, + at.getTranslateY() + yoffset); + DiagramGraphUtil.setTransform(graph, e, at); + } + } + + /** + * @param m + * @param elements + * @param offset + * @throws DatabaseException + */ + public static void moveElements(WriteGraph graph, Set elements, Point2D offset) throws DatabaseException { + moveElements(graph, elements, offset.getX(), offset.getY()); + } + + /** + * @param m + * @param elements + * @param xoffset + * @param yoffset + * @throws DatabaseException + */ + public static void moveParentedElements(WriteGraph graph, PasteOperation op, Set elements, Resource parentRelation, double xoffset, double yoffset) + throws DatabaseException { + ModelingResources MOD = ModelingResources.getInstance(graph); + for (Resource e : elements) { + Resource referencedParentComponent = graph.getPossibleObject(e, parentRelation); + if (referencedParentComponent == null) + continue; + Resource referencedElement = graph.getPossibleObject(referencedParentComponent, MOD.ComponentToElement); + // Don't move the element if it's parent element is also included in the moved set of elements. + if (referencedElement != null && op.ea.all.contains(referencedElement)) + continue; + + AffineTransform at = DiagramGraphUtil.getAffineTransform(graph, e); + at.setTransform(at.getScaleX(), at.getShearY(), at.getShearX(), at.getScaleY(), + at.getTranslateX() + xoffset, + at.getTranslateY() + yoffset); + DiagramGraphUtil.setTransform(graph, e, at); + } + } + + /** + * @param m + * @param elements + * @param xoffset + * @param yoffset + * @throws DatabaseException + */ + public static void moveMonitors(WriteGraph graph, PasteOperation op, Set elements, double xoffset, double yoffset) + throws DatabaseException { + moveParentedElements(graph, op, elements, DiagramResource.getInstance(graph).HasMonitorComponent, xoffset, yoffset); + } + + + /** + * @param m + * @param elements + * @param xoffset + * @param yoffset + * @throws DatabaseException + */ + public static void moveReferenceElements(WriteGraph graph, PasteOperation op, Set elements, double xoffset, double yoffset) + throws DatabaseException { + moveParentedElements(graph, op, elements, ModelingResources.getInstance(graph).HasParentComponent, xoffset, yoffset); + } + + /** + * @param graph + * @param connections + * @param xoffset + * @param yoffset + * @throws DatabaseException + */ + public static void moveRouteGraphConnections(WriteGraph graph, Set connections, Point2D offset) throws DatabaseException { + if(!connections.isEmpty()) { + Command command = Commands.get(graph, "Simantics/Diagram/moveConnection"); + Resource root = graph.syncRequest(new IndexRoot(connections.iterator().next())); + for (Resource r : connections) + command.execute(graph, root, r, offset.getX(), offset.getY()); + } + } + + public static void moveConnection(WriteGraph graph, Resource connection, double offsetX, double offsetY) throws DatabaseException { + new MoveRouteGraphConnection(connection, offsetX, offsetY).perform(graph); + } + + /** + * @param ctx + * @param source + * @param target + * @param offset + */ + public static void copyElementPosition(ICanvasContext ctx, IElement source, IElement target, Point2D offset) { + Point2D pos = ElementUtils.getPos(source); + double x = pos.getX() + offset.getX(); + double y = pos.getY() + offset.getY(); + ElementUtils.setPos(target, snap(ctx, new Point2D.Double(x, y))); + } + + /** + * @param ctx + * @param source + * @param target + * @param offset + * @throws DatabaseException + */ + public static AffineTransform copyElementPosition(WriteGraph graph, ICanvasContext ctx, Resource sourceElement, Resource targetElement, Point2D offset) throws DatabaseException { + AffineTransform at = getCopyTransform(graph, ctx, sourceElement); + Point2D snapped = snap(ctx, new Point2D.Double(at.getTranslateX() + offset.getX(), at.getTranslateY() + offset.getY())); + at.setTransform(at.getScaleX(), at.getShearY(), at.getShearX(), at.getScaleY(), snapped.getX(), snapped.getY()); + DiagramGraphUtil.setTransform(graph, targetElement, at); + return at; + } + + private static AffineTransform getCopyTransform(ReadGraph graph, ICanvasContext ctx, Resource sourceElement) throws DatabaseException { + if(ctx != null){ + Resource runtimeDiagram = (Resource)((IDiagram)ctx.getDefaultHintContext().getHint(DiagramHints.KEY_DIAGRAM)).getHint(DiagramModelHints.KEY_DIAGRAM_RUNTIME_RESOURCE); + return DiagramGraphUtil.getDynamicAffineTransform(graph, runtimeDiagram, sourceElement); + } else { + return DiagramGraphUtil.getAffineTransform(graph, sourceElement); + } + } + + /** + * @param ctx + * @param p + * @return + */ + public static Point2D snap(ICanvasContext ctx, Point2D p) { + if (ctx != null) { + ISnapAdvisor snapAdvisor = ctx.getHintStack().getHint(DiagramHints.SNAP_ADVISOR); + if (snapAdvisor != null) + snapAdvisor.snap(p); + } + return p; + } + + // ------------------------------------------------------------------------ + + /** + * Performs the operations related to a diagram-local cut-paste operation. + * This default implementation will merely translate the selection specified + * by the operation. + * + * @param op + * @throws DatabaseException + */ + public static void localCutPaste(final PasteOperation op) throws DatabaseException { + Simantics.getSession().sync(new WriteRequest() { + @Override + public void perform(WriteGraph graph) throws DatabaseException { + graph.markUndoPoint(); + localCutPaste(graph, op); + Layer0Utils.addCommentMetadata(graph, "Cutted " + op + " to local target"); + } + }); + } + + /** + * Performs the operations related to a diagram-local cut-paste operation. + * This default implementation will merely translate the selection specified + * by the operation. + * + * @param graph + * @param op + * @throws DatabaseException + */ + public static void localCutPaste(WriteGraph graph, PasteOperation op) throws DatabaseException { + if (op.sameDiagram() && op.cut) { + CopyPasteUtil.moveElements(graph, op.ea.nodes, op.offset); + CopyPasteUtil.moveElements(graph, op.ea.flags, op.offset); + if(!op.ea.flags.isEmpty()) { + IOTablesInfo ioTablesInfo = IOTableUtil.getIOTablesInfo(graph, op.targetDiagram); + DiagramResource DIA = DiagramResource.getInstance(graph); + for(Resource flag : op.ea.flags) { + double[] transform = graph.getRelatedValue(flag, DIA.HasTransform, Bindings.DOUBLE_ARRAY); + ioTablesInfo.updateBinding(graph, DIA, flag, transform[4], transform[5]); + } + } + CopyPasteUtil.moveElements(graph, CopyPasteUtil.gatherBranchPoints(graph, op.ea), op.offset); + CopyPasteUtil.moveRouteGraphConnections(graph, CopyPasteUtil.gatherRouteGraphConnections(graph, op.ea), op.offset); + CopyPasteUtil.moveElements(graph, op.ea.others, op.offset); + CopyPasteUtil.moveMonitors(graph, op, op.ea.monitors, op.offset.getX(), op.offset.getY()); + CopyPasteUtil.moveReferenceElements(graph, op, op.ea.references, op.offset.getX(), op.offset.getY()); + } + } + + /** + * @param op + * @throws DatabaseException + */ + public static void continueFlags(final PasteOperation op) throws DatabaseException { + Simantics.getSession().sync(new WriteRequest() { + @Override + public void perform(WriteGraph graph) throws DatabaseException { + continueFlags(graph, op); + } + }); + } + + /** + * @param graph + * @param op + * @throws DatabaseException + */ + public static void continueFlags(WriteGraph graph, final PasteOperation op) throws DatabaseException { + IModifiableSynchronizationContext targetContext = (IModifiableSynchronizationContext) op.target.getHint(SynchronizationHints.CONTEXT); + if (targetContext == null) + throw new IllegalArgumentException("target diagram has no synchronization context"); + + CopyAdvisor ca = op.target.getHint(SynchronizationHints.COPY_ADVISOR); + if (ca == null) + throw new IllegalArgumentException("no copy advisor"); + + Layer0 L0 = Layer0.getInstance(graph); + DiagramResource DIA = DiagramResource.getInstance(graph); + + FlagLabelingScheme scheme = DiagramFlagPreferences.getActiveFlagLabelingScheme(graph); + int joinedFlags = 0; + + for (Resource src : op.ea.flags) { + Resource sourceDiagram = graph.getPossibleObject(src, L0.PartOf); + Resource copy = CopyAdvisorUtil.copy(targetContext, graph, ca, src, sourceDiagram, op.targetDiagram); + if(copy == null) + continue; + OrderedSetUtils.add(graph, op.targetDiagram, copy); + graph.claim(op.targetDiagram, L0.ConsistsOf, copy); + AddElement.claimFreshElementName(graph, op.targetDiagram, copy); + + GraphLayerManager glm = targetContext.get(GraphSynchronizationHints.GRAPH_LAYER_MANAGER); + if (glm != null) { + glm.removeFromAllLayers(graph, copy); + glm.putElementOnVisibleLayers(op.target, graph, copy); + } + + AffineTransform at = CopyPasteUtil.copyElementPosition(graph, op.ctx, src, copy, op.offset); + Type type = FlagUtil.getFlagType(graph, src, Type.Out); + FlagUtil.setFlagType(graph, copy, type.other()); + + FlagUtil.join(graph, src, copy); + + if (scheme != null) { + String label = scheme.generateLabel(graph, op.targetDiagram); + if (label != null) { + graph.claimLiteral(src, L0.HasLabel, DIA.FlagLabel, label, Bindings.STRING); + graph.claimLiteral(copy, L0.HasLabel, DIA.FlagLabel, label, Bindings.STRING); + } + } + + // Update flag table binding + IOTablesInfo ioTablesInfo = IOTableUtil.getIOTablesInfo(graph, op.targetDiagram); + ioTablesInfo.updateBinding(graph, DIA, copy, at.getTranslateX(), at.getTranslateY()); + + ++joinedFlags; + } + + if (joinedFlags > 0) { + // Add comment to change set. + CommentMetadata cm = graph.getMetadata(CommentMetadata.class); + graph.addMetadata(cm.add("Continued " + joinedFlags + " flag(s)")); + } + } + + /** + * @param op + * @throws DatabaseException + */ + public static void performDefaultPaste(PasteOperation op) throws DatabaseException { + Session session = Simantics.getSession(); + new Paster(session, op).perform(); + } + +}