blob: 4d9e0751dc9c54078595ad5844940932e9330cc9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2016 EclipseSource Muenchen GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Johannes Faltermeier - initial API and implementation
******************************************************************************/
package org.eclipse.emf.ecp.edit.spi.swt.commands;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CommandWrapper;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.command.PasteFromClipboardCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Display;
/**
* Extension of the {@link PasteFromClipboardCommand} which enabled progress reporting.
*
* @author Johannes Faltermeier
* @since 1.11
*
*/
public class ProgressPasteFromClipboardCommand extends PasteFromClipboardCommand implements IProgressMonitorProvider {
private IProgressMonitor monitor;
/**
* Constructs a new {@link ProgressPasteFromClipboardCommand}.
*
* @param domain the {@link EditingDomain}
* @param owner the owner object
* @param feature the feature
* @param index the index
*/
public ProgressPasteFromClipboardCommand(EditingDomain domain, Object owner, Object feature, int index) {
super(domain, owner, feature, index);
}
/**
* Constructs a new {@link ProgressPasteFromClipboardCommand}.
*
* @param domain the {@link EditingDomain}
* @param owner the owner object
* @param feature the feature
* @param index the index
* @param optimize whether to call the optimized can execute method
*/
public ProgressPasteFromClipboardCommand(EditingDomain domain, Object owner, Object feature, int index,
boolean optimize) {
super(domain, owner, feature, index, optimize);
}
@Override
protected boolean prepare() {
{
// Create a strict compound command to do a copy and then add the result
//
command = new ProgressStrictCompoundCommand(this);
// Create a command to copy the clipboard.
//
final Command copyCommand = ProgressCopyCommandFactory.create(domain, domain.getClipboard(), this);
// REUSED CLASS
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();) {
final Object originalObject = i.next();
final Object copyObject = j.next();
if (originalObject.getClass() != copyObject.getClass()) {
original = null;
break;
}
}
}
final Command addCommand = AddCommand.create(domain, owner, feature,
original == null ? copy : original, index);
if (IProgressMonitorConsumer.class.isInstance(addCommand)) {
IProgressMonitorConsumer.class.cast(addCommand)
.setIProgressMonitorAccessor(ProgressPasteFromClipboardCommand.this);
}
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;
}
}
// END REUSED CLASS
@Override
public void doExecute() {
doExecuteWithProgress("Pasting elements..."); //$NON-NLS-1$
}
/**
* Does the same as {@link #doExecute()} but also displays a progress dialog.
*
* @param task the name of the task
*/
protected void doExecuteWithProgress(final String task) {
try {
final ProgressMonitorDialog progressMonitorDialog = new ProgressMonitorDialog(
Display.getDefault().getActiveShell());
progressMonitorDialog.run(
false, /* if we fork auto UI updates of EMF.edit.ui do not work, so stay on UI thread */
false,
new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
ProgressPasteFromClipboardCommand.this.monitor = monitor;
monitor.beginTask(task, getTotalWorkExecute());
ProgressPasteFromClipboardCommand.super.doExecute();
ProgressPasteFromClipboardCommand.this.monitor = null;
}
});
} catch (final InvocationTargetException ex) {
} catch (final InterruptedException ex) {
}
}
/**
* @return the total work required to execute the paste operation
*/
protected int getTotalWorkExecute() {
int work = domain.getClipboard().size();
final List<Command> commandList = command.getCommandList();
work += commandList.size();
for (final Command subCommand : commandList) {
if (!ProgressCompoundCommand.class.isInstance(subCommand)) {
continue;
}
work += ProgressCompoundCommand.class.cast(subCommand).getCommandList().size();
}
return work;
}
@Override
public void doUndo() {
doUndoWithProgress("Undoing paste operation"); //$NON-NLS-1$
}
/**
* Does the same as {@link #doUndo()} but also displays a progress dialog.
*
* @param task the name of the task
*/
protected void doUndoWithProgress(final String task) {
try {
final ProgressMonitorDialog progressMonitorDialog = new ProgressMonitorDialog(
Display.getDefault().getActiveShell());
progressMonitorDialog.run(
false, /* if we fork auto UI updates of EMF.edit.ui do not work, so stay on UI thread */
false,
new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
ProgressPasteFromClipboardCommand.this.monitor = monitor;
monitor.beginTask(task, 1);
ProgressPasteFromClipboardCommand.super.doUndo();
ProgressPasteFromClipboardCommand.this.monitor = null;
}
});
} catch (final InvocationTargetException ex) {
} catch (final InterruptedException ex) {
}
}
@Override
public void doRedo() {
doRedoWithProgress("Redoing paste operation."); //$NON-NLS-1$
}
/**
* Does the same as {@link #doRedo()} but also displays a progress dialog.
*
* @param task the name of the task
*/
protected void doRedoWithProgress(final String task) {
try {
final ProgressMonitorDialog progressMonitorDialog = new ProgressMonitorDialog(
Display.getDefault().getActiveShell());
progressMonitorDialog.run(
false, /* if we fork auto UI updates of EMF.edit.ui do not work, so stay on UI thread */
false,
new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
ProgressPasteFromClipboardCommand.this.monitor = monitor;
monitor.beginTask(task, 1);
ProgressPasteFromClipboardCommand.super.doRedo();
ProgressPasteFromClipboardCommand.this.monitor = null;
}
});
} catch (final InvocationTargetException ex) {
} catch (final InterruptedException ex) {
}
}
@Override
public IProgressMonitor getProgressMonitor() {
return monitor;
}
}