blob: acfd36b202b0ddaef17d0d87812969b315c08560 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 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 Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.bpel.common.ui.command;
import java.util.EventObject;
import org.eclipse.bpel.common.ui.details.IOngoingChange;
import org.eclipse.bpel.common.ui.editmodel.EditModelCommandStack;
import org.eclipse.bpel.common.ui.editmodel.PlaceHolderCommand;
import org.eclipse.bpel.common.ui.editmodel.EditModelCommandStack.SharedCommandStackChangedEvent;
import org.eclipse.bpel.common.ui.editmodel.EditModelCommandStack.SharedCommandStackListener;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.commands.CommandStackListener;
/**
* Support for using IOngoingChange with the EditModel framework.
*/
public class EditModelCommandFramework implements ICommandFramework {
IOngoingChange fCurrentChange;
CommandStack fCommandStack;
boolean fIgnoreEvents = false;
/**
* @param editModelCommandStack
*/
public EditModelCommandFramework (EditModelCommandStack editModelCommandStack) {
fCommandStack = editModelCommandStack;
editModelCommandStack.addCommandStackListener(new CommandStackListener() {
public void commandStackChanged(EventObject event) {
if (fIgnoreEvents || event instanceof SharedCommandStackChangedEvent == false) {
return;
}
/**
* The most important thing to consider here is that we may have pending
* change through the ChangeHelper mechanism being played on the the stack.
* If we are about to execute a new command or undo the last command, we
* have to apply any current change (that is execute the new command) before
* either execute or undo is called.
*/
SharedCommandStackChangedEvent e = (SharedCommandStackChangedEvent) event;
/**
* The use case here is that we are about to run a command on the stack and
* have some pending changes to do. We have to finish the current change first.
*
*/
if (e.getProperty() == SharedCommandStackListener.EVENT_START_EXECUTE) {
applyCurrentChange();
}
/**
* The use case for applying the currently pending edit is simply that a
* pending edit may not be applied but an undo is called.
* In this case, we have to apply the pending command, then undo it.
*
*/
if(e.getProperty() == SharedCommandStackListener.EVENT_START_UNDO) {
applyCurrentChange();
}
// FIXME: what about redo?
}
});
}
/**
* Forward these to the implementation.
*
* @see org.eclipse.bpel.common.ui.command.ICommandFramework#abortCurrentChange()
*/
public void abortCurrentChange() {
finishCurrentChange(true);
}
/**
* @see org.eclipse.bpel.common.ui.command.ICommandFramework#applyCurrentChange()
*/
public void applyCurrentChange() {
finishCurrentChange(false);
}
/**
* @see org.eclipse.bpel.common.ui.command.ICommandFramework#notifyChangeInProgress(org.eclipse.bpel.common.ui.details.IOngoingChange)
*/
public void notifyChangeInProgress(IOngoingChange ongoingChange) {
if (fCurrentChange != ongoingChange) {
applyCurrentChange();
if (fCommandStack.getUndoCommand() instanceof PlaceHolderCommand) {
throw new IllegalStateException();
}
PlaceHolderCommand placeholderCommand = new PlaceHolderCommand(ongoingChange.getLabel());
fIgnoreEvents = true;
try {
fCommandStack.execute(placeholderCommand);
} finally {
fIgnoreEvents = false;
}
fCurrentChange = ongoingChange;
}
}
/**
* @see org.eclipse.bpel.common.ui.command.ICommandFramework#notifyChangeDone(org.eclipse.bpel.common.ui.details.IOngoingChange)
*/
public void notifyChangeDone(IOngoingChange ongoingChange) {
if (fCurrentChange == ongoingChange) {
applyCurrentChange();
}
}
/**
* @see org.eclipse.bpel.common.ui.command.ICommandFramework#execute(org.eclipse.gef.commands.Command)
*/
public void execute(Command command) {
fCommandStack.execute(command);
}
protected void finishCurrentChange(boolean changeUndone) {
if (fCurrentChange == null) {
return;
}
IOngoingChange change = fCurrentChange;
// Null out the current change. This is important !!
fCurrentChange = null;
// Make sure there's a placeholder on the stack.
if (fIgnoreEvents) {
throw new IllegalStateException();
}
if (!(fCommandStack.getUndoCommand() instanceof PlaceHolderCommand)) {
throw new IllegalStateException();
}
fIgnoreEvents = true;
try {
fCommandStack.undo(); // Remove placeholder.
} finally {
fIgnoreEvents = false;
}
Command cmd = change.createApplyCommand();
if (cmd != null) {
cmd.setLabel(change.getLabel());
if (changeUndone) {
change.restoreOldState();
} else {
// TODO: if the command is not actually executable, should we call
// restoreOldState() instead? I'm inclined not to because we've been
// using !canExecute() to elide no-op commands. But maybe we should
// rethink that (especially since IOngoingChange makes it much less
// common, and maybe confusing, to elide a command in that way?).
// TODO: above comment is obsolete. Now that no-ops are handled in
// a different way by EditModelCommandStack, we should consider calling
// restoreOldState() if canExecute() fails.
fCommandStack.execute(cmd);
}
} else {
change.restoreOldState();
}
}
}