/*******************************************************************************
* 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.synchronization.graph;
import gnu.trove.map.hash.THashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.simantics.databoard.Bindings;
import org.simantics.databoard.binding.Binding;
import org.simantics.databoard.type.Datatype;
import org.simantics.db.ReadGraph;
import org.simantics.db.Resource;
import org.simantics.db.Statement;
import org.simantics.db.WriteGraph;
import org.simantics.db.common.utils.NameUtils;
import org.simantics.db.exception.DatabaseException;
import org.simantics.db.layer0.adapter.CopyHandler;
import org.simantics.db.layer0.adapter.impl.FixedRootImportAdvisor;
import org.simantics.db.layer0.util.ClipboardUtils;
import org.simantics.db.layer0.util.SimanticsClipboard;
import org.simantics.db.layer0.util.SimanticsClipboard.Representation;
import org.simantics.db.layer0.util.SimanticsClipboardImpl;
import org.simantics.db.layer0.util.SimanticsKeys;
import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;
import org.simantics.diagram.internal.DebugPolicy;
import org.simantics.diagram.synchronization.CopyAdvisor;
import org.simantics.diagram.synchronization.CopyAdvisor.Evaluation;
import org.simantics.diagram.synchronization.ErrorHandler;
import org.simantics.diagram.synchronization.IModifiableSynchronizationContext;
import org.simantics.diagram.synchronization.StatementEvaluation;
import org.simantics.diagram.synchronization.SynchronizationException;
import org.simantics.diagram.synchronization.SynchronizationHints;
import org.simantics.graph.db.TransferableGraphs;
import org.simantics.graph.representation.TransferableGraph1;
import org.simantics.layer0.Layer0;
/**
* This class contains utility methods for the basic cut/copy operations
* performed related to cut-copy-pasting diagram/configuration component and
* composites.
*
*
* Methods
* {@link #cut(IModifiableSynchronizationContext, WriteGraph, CopyAdvisor, Resource, Resource, Resource)}
* and
* {@link #copy(IModifiableSynchronizationContext, WriteGraph, CopyAdvisor, Resource, Resource, Resource)}
* are available for making it easier to properly invoke
* {@link CopyAdvisor#cut(org.simantics.diagram.synchronization.ISynchronizationContext, Object, Object, Object)}
* and
* {@link CopyAdvisor#copy(org.simantics.diagram.synchronization.ISynchronizationContext, Object, Object, Object)}
* operations in a diagram/graph transaction context.
*
*
* Methods {@link #copy(WriteGraph, Resource, BinaryFunction)},
* {@link #copy2(WriteGraph, Resource, BinaryFunction)},
* {@link #copy3(WriteGraph, Resource, Resource, BinaryFunction)},
* {@link #copy4(WriteGraph, Resource)} and
* {@link #copy4(WriteGraph, Resource, CopyHandler)} offer differently
* functioning versions of copying a single resource in the graph that are
* mainly tuned for copying diagram elements and configuration components.
*
*
* IMPORTANT: Note that copy, copy2 and copy3 cannot handle copying of ordered sets
* properly.
*
* @author Tuukka Lehtonen
*/
public class CopyAdvisorUtil {
public static final boolean DEBUG_COPY = DebugPolicy.DEBUG_COPY_PASTE;
/**
* @param context a synchronization context instance, such as
* {@link GraphToDiagramSynchronizer}
* @param g handle for graph writing
* @param ca the advisor for the copy operation
* @param cut the resource that is about to be cut
* @param sourceContainer the container from which the cut argument is about
* to be removed
* @param targetContainer the container into which the cut argument is about
* to be moved
* @return the result of
* {@link CopyAdvisor#cut(org.simantics.diagram.synchronization.ISynchronizationContext, Object, Object, Object)}
* @throws DatabaseException
*/
public static Object cut(IModifiableSynchronizationContext context, WriteGraph g, CopyAdvisor ca, Resource cut, Resource sourceContainer, Resource targetContainer) throws DatabaseException {
if (DEBUG_COPY)
System.out.println("Attempting to cut component " + NameUtils.getSafeName(g, cut, true));
try {
context.set(GraphSynchronizationHints.READ_TRANSACTION, g);
context.set(GraphSynchronizationHints.WRITE_TRANSACTION, g);
return ca.cut(context, cut, sourceContainer, targetContainer);
} catch (SynchronizationException e) {
ErrorHandler eh = context.get(SynchronizationHints.ERROR_HANDLER);
eh.error(e.getMessage(), e);
} finally {
context.set(GraphSynchronizationHints.READ_TRANSACTION, null);
context.set(GraphSynchronizationHints.WRITE_TRANSACTION, null);
}
return null;
}
/**
* @param context a synchronization context instance, such as
* {@link GraphToDiagramSynchronizer}
* @param g handle for graph writing
* @param ca the advisor for the copy operation
* @param copyOf the resource that is about to be copied
* @param sourceContainer the container of the resource that will be copied
* @param targetContainer the to-be container of the copied resource instance
* @return the copied resource
* @throws DatabaseException
*/
public static Resource copy(IModifiableSynchronizationContext context, WriteGraph g, CopyAdvisor ca,
Resource copyOf, Resource sourceContainer, Resource targetContainer) throws DatabaseException {
Resource resource = null;
if (DEBUG_COPY)
System.out.println("Attempting to copy component " + NameUtils.getSafeName(g, copyOf, true));
try {
context.set(GraphSynchronizationHints.READ_TRANSACTION, g);
context.set(GraphSynchronizationHints.WRITE_TRANSACTION, g);
Evaluation eval = ca.canCopy(context, copyOf, sourceContainer, targetContainer);
if (DEBUG_COPY)
System.out.println(" CopyAdvisor(" + ca + ").canCopy evaluation result: " + eval);
if (CopyAdvisor.SUPPORTED.contains(eval)) {
Object copy = ca.copy(context, copyOf, sourceContainer, targetContainer);
if (DEBUG_COPY)
System.out.println(" CopyAdvisor(" + ca + ").copy result: " + copy);
if (copy instanceof Resource) {
resource = (Resource) copy;
} else {
throw new UnsupportedOperationException("Cannot copy element " + copyOf);
}
}
} catch (SynchronizationException e) {
ErrorHandler eh = context.get(SynchronizationHints.ERROR_HANDLER);
eh.error(e.getMessage(), e);
// throwing exception allows canceling failed copy!
throw new DatabaseException(e);
} finally {
context.set(GraphSynchronizationHints.READ_TRANSACTION, null);
context.set(GraphSynchronizationHints.WRITE_TRANSACTION, null);
}
return resource;
}
/**
* @param context a synchronization context instance, such as
* {@link GraphToDiagramSynchronizer}
* @param g handle for graph writing
* @param ca the advisor for the copy operation
* @param copyOf the resource that is about to be copied
* @param sourceContainer the container of the resource that will be copied
* @param targetContainer the to-be container of the copied resource instance
* @param map a map for storing the correspondences between original and
* copied objects. This is used to output data from the copy process.
* @return the copied resource
* @throws DatabaseException
*/
public static Resource copy(IModifiableSynchronizationContext context, WriteGraph g, CopyAdvisor ca,
Resource copyOf, Resource sourceContainer, Resource targetContainer, Map