| /******************************************************************************* |
| * 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(); |
| } |
| } |
| } |