/** * Copyright (c) 2002-2007 IBM Corporation 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: * IBM - Initial API and implementation */ package org.eclipse.emf.edit.command; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import org.eclipse.emf.common.command.Command; import org.eclipse.emf.common.command.CommandWrapper; import org.eclipse.emf.common.command.StrictCompoundCommand; import org.eclipse.emf.edit.EMFEditPlugin; import org.eclipse.emf.edit.domain.EditingDomain; /** * This works exactly like an {@link AddCommand} but the things to be added are copied from the {@link EditingDomain} clipboard. * If the copied clipboard instance is of the same type as the original clipboard instance, * the clipboard instance is replaced by the copied instance and the original instance is used for the add. */ public class PasteFromClipboardCommand extends AbstractOverrideableCommand { /** * This creates a command to add copies from the clipboard to the specified feature of the owner. */ public static Command create(EditingDomain domain, Object owner, Object feature) { return create(domain, owner, feature, CommandParameter.NO_INDEX); } /** * This creates a command to add copies from the clipboard to the specified feature of the owner and at the given index. */ public static Command create(EditingDomain domain, Object owner, Object feature, int index) { if (domain == null) { return new PasteFromClipboardCommand(domain, owner, feature, index, true); } else { Command command = domain.createCommand(PasteFromClipboardCommand.class, new CommandParameter(owner, feature, Collections.emptyList(), index)); return command; } } /** * This caches the label. */ protected static final String LABEL = EMFEditPlugin.INSTANCE.getString("_UI_PasteFromClipboardCommand_label"); /** * This caches the description. */ protected static final String DESCRIPTION = EMFEditPlugin.INSTANCE.getString("_UI_PasteFromClipboardCommand_description"); /** * This is the command that does the actual pasting. */ protected StrictCompoundCommand command; /** * This is object where the clipboard copy is pasted. */ protected Object owner; /** * This is feature of the owner where the clipboard copy is pasted. */ protected Object feature; /** * This is index in the feature of the owner where the clipboard copy is pasted. */ protected int index; /** * This controls whether or not to optimize the canExecute (prepare) */ protected boolean optimize; /** * This constructs an instance from the domain, which provides access the clipboard collection * via {@link EditingDomain#getCommandStack}. */ public PasteFromClipboardCommand(EditingDomain domain, Object owner, Object feature, int index) { this(domain, owner, feature, index, true); } public PasteFromClipboardCommand(EditingDomain domain, Object owner, Object feature, int index, boolean optimize) { super(domain, LABEL, DESCRIPTION); this.owner = owner; this.feature = feature; this.index = index; this.optimize = optimize; } public Object getOwner() { return owner; } public Object getFeature() { return feature; } public int getIndex() { return index; } @Override protected boolean prepare() { // Create a strict compound command to do a copy and then add the result // command = new StrictCompoundCommand(); // Create a command to copy the clipboard. // final Command copyCommand = CopyCommand.create(domain, domain.getClipboard()); command.append(copyCommand); // Create a proxy that will create an add command. // command.append (new CommandWrapper() { protected Collection<Object> original; protected Collection<Object> copy; @Override protected Command createCommand() { original = domain.getClipboard(); copy = new ArrayList<Object>(copyCommand.getResult()); // Use the original to do the add, but only if it's of the same type as the copy. // This ensures that if there is conversion being done as part of the copy, // as would be the case for a cross domain copy in the mapping framework, // that we do actually use the converted instance. // if (original.size() == copy.size()) { for (Iterator<Object> i = original.iterator(), j = copy.iterator(); i.hasNext(); ) { Object originalObject = i.next(); Object copyObject = j.next(); if (originalObject.getClass() != copyObject.getClass()) { original = null; break; } } } Command addCommand = AddCommand.create(domain, owner, feature, original == null ? copy : original, index); return addCommand; } @Override public void execute() { if (original != null) { domain.setClipboard(copy); } super.execute(); } @Override public void undo() { super.undo(); if (original != null) { domain.setClipboard(original); } } @Override public void redo() { if (original != null) { domain.setClipboard(copy); } super.redo(); } }); boolean result; if (optimize) { // This will determine canExecute as efficiently as possible. // result = optimizedCanExecute(); } else { // This will actually execute the copy command in order to check if the add can execute. // result = command.canExecute(); } return result; } protected boolean optimizedCanExecute() { // We'll assume that the copy command can execute and that adding a copy of the clipboard // is the same test as adding the clipboard contents itself. // Command addCommand = AddCommand.create(domain, owner, feature, domain.getClipboard()); boolean result = addCommand.canExecute(); addCommand.dispose(); return result; } @Override public void doExecute() { // We need to check canExecute() here in case prepare() went down the "optimize" path. // if (command.canExecute()) { command.execute(); } else { // Thread.dumpStack(); } } @Override public void doUndo() { command.undo(); } @Override public void doRedo() { command.redo(); } @Override public Collection<?> doGetResult() { return command.getResult(); } @Override public Collection<?> doGetAffectedObjects() { return command.getAffectedObjects(); } @Override public void doDispose() { if (command != null) command.dispose(); } /** * This gives an abbreviated name using this object's own class' name, without package qualification, * followed by a space separated list of <tt>field:value</tt> pairs. */ @Override public String toString() { StringBuffer result = new StringBuffer(super.toString()); result.append(" (domain: " + domain + ")"); return result.toString(); } }