Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 332351 - [Command] CommandStack canRedo should check Command canExecute
Summary: [Command] CommandStack canRedo should check Command canExecute
Status: RESOLVED FIXED
Alias: None
Product: GEF
Classification: Tools
Component: GEF-Legacy GEF (MVC) (show other bugs)
Version: unspecified   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: 3.10.0 (Mars) M2   Edit
Assignee: Alexander Nyßen CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-12-10 18:10 EST by Paul Bilnoski CLA
Modified: 2014-08-20 12:13 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Paul Bilnoski CLA 2010-12-10 18:10:33 EST
Build Identifier: 3.6.1

I have a GEF viewer and a JFace tree viewer both visualizing the same model and both allowing edit operations, such as the ability to reparent an item. In the GEF viewer this is done through handling a RequestConstants.REQ_ADD ("add children") command.

When a reparent is done, the "undo" action is correctly available and the "redo" action is correctly unavailable. If a change is made to the same model element via the JFace viewer, the "redo" action becomes unavailable because the command itself revalidates when asked to by the command stack.

However, if the "undo" is performed, and the "redo" action correctly becomes available and then the model element is updated, the "redo" action is still available even though it is invalid. This is because the command stack simply tests "canRedo" by checking that a command exists on the redoable stack, but does not check that the command is again executable.

I have subclassed CommandStack and overridden "canRedo" as such:
public boolean canRedo()
{
   Command toRedo = getRedoCommand();
   if (toRedo == null)
      return false;
   return toRedo.canExecute();
}

A proposed patch to the code could access internals, and might be instead:
public boolean canRedo() {
   if (redoable.isEmpty())
      return false;
   return ((Command)redoable.peek()).canExecute();
}



Reproducible: Always
Comment 1 Paul Bilnoski CLA 2010-12-10 18:13:55 EST
I found a mistake in the description, it should instead read:
"If a change is made to the same model element via the JFace viewer, the "UNDO" action becomes unavailable because the command itself revalidates when asked to by the command stack."
Comment 2 Alexander Nyßen CLA 2014-08-19 14:25:10 EDT
Actually Command seems to be missing a canRedo(), which should be called by CommandStack as you described. Calling canExecute() to check whether redo() can be called does not seem to be appropriate because redo() will only by default delegate to execute() and may be implemented differently. I think we should add canRedo() to Command, delegating to canExecute() by default and call this from within CommandStack#canRedo(). We will also have to overwrite in within CompoundCommand to collect the canRedo()-results from nested commands.
Comment 3 Alexander Nyßen CLA 2014-08-20 12:13:24 EDT
Implemented the following changes:

- Added canRedo() to Command, which by default delegates to canExecute(), similar to redo() delegates to execute(). Subclasses may overwrite to decide whether a command is redoable.
- Added an implementation for canRedo() within CompoundCommand, which overwrites the default implementation within Command and delegates to the canRedo() of the nested commands (similar as for canExecute() and canUndo()).
- Changed implementation of CommandStack#canRedo() to evaluate the canRedo() of the current redoable command.
- Fixed that undo() did not check that the undoable command is indeed undoable (like done for redo()) but execute the undo in each case. Now, as redo() it is a no-op in case the current undoable command is not undoable.

All changes committed to origin/master. Resolving as fixed in 3.10.0M2.