org.eclipse.emf.edit.command.ChangeCommand Maven / Gradle / Ivy
/**
* Copyright (c) 2006-2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* IBM - Initial API and implementation
*/
package org.eclipse.emf.edit.command;
import java.util.Collection;
import java.util.Collections;
import org.eclipse.emf.common.command.AbstractCommand;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.ecore.change.ChangeDescription;
import org.eclipse.emf.ecore.change.util.ChangeRecorder;
/**
* This command uses the Change Model facilities to enable a group of modifications
* to be executed as one single command. The undo operation reverts all the
* modifications made when the command was executed
* In order to use this class, the org.eclipse.emf.ecore.change plugin has to
* be available in your Eclipse configuration.
*
* @since 2.2.0
*/
abstract public class ChangeCommand extends AbstractCommand
{
protected ChangeDescription changeDescription;
// Possible scope for the ChangeRecorder
protected Notifier notifier;
protected Collection notifiers;
protected ChangeRecorder changeRecorder;
protected ChangeCommand(ChangeRecorder changeRecorder)
{
if (changeRecorder.isRecording())
{
throw new IllegalStateException("The changeRecorder cannot be currently recording.");
}
this.changeRecorder = changeRecorder;
}
public ChangeCommand(ChangeRecorder changeRecorder, Notifier notifier)
{
this(changeRecorder);
this.notifier = notifier;
}
public ChangeCommand(Notifier notifier)
{
this.notifier = notifier;
}
public ChangeCommand(ChangeRecorder changeRecorder, Collection notifiers)
{
this(changeRecorder);
this.notifiers = notifiers;
}
public ChangeCommand(Collection notifiers)
{
this.notifiers = notifiers;
}
@Override
public void dispose()
{
changeRecorder = null;
notifier = null;
notifiers = null;
changeDescription = null;
super.dispose();
}
/**
* Returns the {@link ChangeRecorder} specified in the
* constructor if any.
* @return {@link ChangeRecorder}
*/
public ChangeRecorder getChangeRecorder()
{
return changeRecorder;
}
protected ChangeRecorder createChangeRecorder()
{
return new ChangeRecorder();
}
protected ChangeDescription getChangeDescription()
{
return changeDescription;
}
protected void setChangeDescription(ChangeDescription changeDescription)
{
this.changeDescription = changeDescription;
}
@Override
protected boolean prepare()
{
return getChangeDescription() == null;
}
/**
* Executes the command. Subclasses are not expected to overwrite
* this method, and implement their changes on {@link #doExecute()}.
*/
public void execute()
{
ChangeRecorder changeRecorder = getChangeRecorder();
if (changeRecorder == null)
{
changeRecorder = createChangeRecorder();
}
changeRecorder.beginRecording(notifier != null ? Collections.singleton(notifier) : notifiers);
try
{
doExecute();
}
finally
{
setChangeDescription(changeRecorder.endRecording());
disposeChangeRecorder(changeRecorder);
}
}
/**
* Subclasses should override this to perform modifications to resources and objects.
* If no modification occurs, an {@link org.eclipse.emf.common.command.AbortExecutionException}
* may be thrown to avoid placing the command on the command stack.
*/
abstract protected void doExecute();
/**
* Disposes the {@link ChangeRecorder} created by {@link #execute()}. The default
* implementation doesn't dispose the change recorder if it was passed in
* through one of the constructor methods.
* @param changeRecorder
*/
protected void disposeChangeRecorder(ChangeRecorder changeRecorder)
{
if (changeRecorder != getChangeRecorder())
{
changeRecorder.dispose();
}
}
@Override
public void undo()
{
getChangeDescription().applyAndReverse();
}
public void redo()
{
getChangeDescription().applyAndReverse();
}
}