[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
Re: [platform-ui-dev] Undo/Redo Proposal
|
My comments are marked in the attached document.
I also agree with most of the observations David made.
Title: Undo Redo Proposal
RFC
Undo Redo - Draft 1
Greg> My comments are marked by <GDA>....</GDA>
Summary
Currently, the Eclipse workbench includes global actions for Undo and Redo.
They appear as the first two items in the edit menu. As global actions, they
are targeted to the current active part in the current perspective. If the
active part does not supply a global action handler for them, they are disabled.
This means that the action that will be performed by Undo or Redo is dependent
on the active part and thus the behavior of these actions is modal. In many
cases the user must go back to the appropriate part before being able to undo
an action performed there.
By Randy Giffen, OTI
Last Modified: November 15,
2001
Modified: 20 Nov 2001 - Randy Giffen with
comments from Dirk Baeumer
<GDA> Top level Issues
* I will confess to some concern with a global/shared
undo stack.
* Here are some problematic scenarios:
1) workbench based - A workbench oriented solution implies
an undo in one window can cause something to happen in another window.
- cut some text from editor1 in window1
- switch to editor2 in window2
- Undo -- as a user I would not expect an undo to happen
in window1
2) window based - If we make it be window only (not workbench)
then the interaction of the undo stack between two editors could be puzzling:
- Editor1 -- cut "text1a"
- Switch to text editor2
- Cut "text2a"
- Switch back to editor1
- Cut "text1b"
- Undo - undoes text1b - good
- Undo - indoes text2a - I don't think a user would
expect this
3) Same as #2 except replace editor2 with a view such
as the task view
4) Confusion if some editors
(for example) do not support undo.
- user cuts text in editor1
- user opens editor2 deletes some stuff (maybe a diagram
bubble)- but editor2 does not support undo
- undo menu is enabled and has the cut showing - user
would incorrectly assume its for the delete of the bubble, undo it only
to have the bubble not reappar - but worse, something magically happened
in another editor and he may not know about it
5) Stale actions? What is
the interaction between the undo stack and its contributor. Examples:
- If an editor contributes to the stack and closes
does the undo stack continue to show "undo cut" - this seems odd.
In fact, the consequence is the stack could have a number of stale items sitting
on it. Presumably as he uses Ctrl+Z it skips stale stack entries but never
the less they would still show up as the menu label, or if you show the entire
stack they will also show there.
- User cuts some text, then exits an editor without
saving, is the undo still available, what happens if he reopens the editor
will it undo the cut from the last edit session.
6) Side by side editors
What if the user has two editors side by side and
is moving back and forth between them perhaps one is his plugin.xml and the
other plugin.properties. It seems he make get frustrated that they do not have
their own stacks. This is effectively #1 above, but I wanted to put it in context
of a real cases, and also side by side where its even more noticable
* OLE - As an observational point I believe if you are
editing in something supporting OLE (e.g. word) and you activate an object in
place (e.g. excel) that they have different undo stacks. In addition once you
stop editing the inner object, it throws away its undo stack and replaces it
with one entry which is a "go to last state" to undo everything you
did on the last inner edit. What is very interesting about this is the issues
I raise above, that from the users perception they switch to editing in the
inplace document and then switch back - effectively working with two documents
and each has its own undo stack.
* I believe undo should be done at a model type of level,
not a gesture type of level. This means rearranging views, toolbars etc should
not be recorded. Note however some gestures like drag and drop, resizing bubbles
in modelling diagram are obviously model oriented changes.
* Is the undo stack persisted through a shutdown/restart
* What is the behavior/interaction when we activate in
place editors like MS Word - how do they interact with the undo? Similarly what
if they in turn have inplace objects (e.g. excel spread sheet).
* To what extent will the workbench itself make use of
undo. For example will the following be undoable:
- drag/drop in navigatorbe undoable
- deleting a resource (incl. project)
- closing a project reopen it
* Is there additional core support required / being-provided
in order to support undo? For example consider the following: Do the workbench
& the JDT both have to write code to handle undeleting of a java class -
even though all that happened was the underlying resource was deleted (assuming
no reorg/refactor happens).
* Does it support a repeat capability. Redo typically
allows me to redo both something I undid and to repeatedly do a given action.
For example in an html editor if I bold some text I can select some other text
and do Ctrl+Y to have it redo the command.
* What information is an action contributor supposed
to record in order to perform validation. For example, do they need to hold
onto the part that contributed so they can make sure they are in that part to
apply it - after all they may want to use special api in the part? Does this
imply caching/holding onto lots of objects - what happens if the editor part
is closed - does it mean the undo entry is still holding onto it?
* Why is a dispose necessary? Are we expecting these
undo entries to hold onto cached resources? Shouldn't simply tossing them out
of the stack be sufficient? I guess I'm missing something obvious here.
* IUndoAction is a bad name because these are not actions.
Alternatives I have seen out there are frame, transaction, command.
* IUndoAction.getLabel() - is this intended so show the
type of operation or also more information. For example will it say "undo
cut" or "undo cut of funny day at th..."
* Will the hover help for the toolbar button change to
reflect the label for the top of stack?
* You can determine the enable state of the menu entries
each time the menu is recreated - when exactly will you be checking if the toolbar
buttons should be enabled.
* Picking an entry in the middle of the stack sounds
problematic. Tools (that I recall) which show the undo stack let you pick an
entry in the middle of the stack but then they also select the entries above
it. They then undo everything down to that point. Is this the intended behavior
of the proposal?
* The argument is "In the case of an IDE they are
using the UI to manipulate a model. However the eclipse platform allows what
would traditionally have been separately running IDE's to be integrated into
a composite integrated world. This also means that they may have different models.
Assume for the moment that they didn't have different models, they still may
have different semantic/logical presentations of the same underlying files.
You might even be able to argue two editors present the user two different sub-models.
For example a model diagram vs. a java source editor - maybe I am stretching
this argument?
* The proposal appears to suggest breaking all existing
text editors. This is *not* permitted. After all what's the win for them - they
already have it working.
</GDA>
Problem
Global actions are actions defined by the Eclipse workbench UI
which delegate their enablement and action to a global action handler supplied
but the active workbench part. Global actions were introduced to provide a
degree of consistency in the UI. The idea was that common functions like
undo/redo, cut/copy/paste, and delete should have a consistent location in the
UI and consistent menu accelerators. An additional benefit is that views (which
cannot contribute to the window menu and thus cannot define menu accelerators)
are able to respond to the menu accelerators defined for global actions.
Thus, in a way, the name global is a bit misleading in the undo/redo case.
The actions do not support a global undo/redo stack. They support a targeted
undo/redo directed at, and implemented by, the active part. This is typically
not what most users expect. In the case of an IDE, they are using the UI to
manipulate (make changes to) a model. They expect that undo/redo will allow them
to back out of or redo these changes regardless of what part of the ui they are
currently working.
This architecture requires that parts maintain their own undo/redo stack
(although theoretically some parts may decide to implement a shred stack among
themselves).
Another problem is that actions that don't belong to a
view (e.g. like the "Refactor" menu which gets retargeted to the active view)
can't access the undo/redo actions in the edit menu.
Possible Options
Let us assume for the moment that a workbench undo/redo stack is a good idea
and consider its implementation (this is based on discussions and PR 1887).
We would define an IUndoManager and add a method to IWorkbench to obtain such
a manger.The manager would have api for adding and removing a IUndoActions from
the manager.
IUndoAction would have the following definition
public interface IUndoAction {
String getLabel();
void undo();
void redo();
boolean isUndoValid();
boolean isRedoValid();
void dispose();
}
Comment: Should we consider having an abstract UndoAction rather than
an IUndoAction? In some cases this would allow us to modify API in a non-breaking
way but it means that clients will not be able to use an existing type to implement
IUndoAction (probably a rare case).
<GDA> I don't think the abstract class route is
appropriate. </GDA>
The manager will ensure that the top undo action and top
redo action are valid by calling the isUndoValid() and isRedoValid() api methods.
If the undo/redo action is no longer valid it will be punted and the next one
moved to the top.
<GDA> When exactly is this called?
Dirk indicated there are two ways to tell if the undo
entry should be enabled
- polling - undo manager asks the action if it is valid
before executing it
- listening - each undo entry listens to models and
informs the manager if it is unavailable
1) With polling it is unclear when the polling would
be done. This is especially important when ensuring the toolbar button is enabled
properly.
2) Listening seems problematic due to the example below.
3) It is unclear if the availability would be done only at the top of stack
or at all stack entries continually (or at intervals of time)
4) How does this availability interact with allowing the user to pick an entry
in the middle of the stack. Will we check applicability of all of the ones in
the stack each time we show the stack.
</GDA>
The valid check is required as an undo action cannot
validate itself simply by listening to model changes. It would also somehow need
additional information if the received delta will have an undo which will be put
onto the undo stack. Consider the following case: A Java refactoring renames
file A.java to B.java. Then the user goes to the navigator and renames B.java to
C.txt. If the navigator pushes an undo action onto the stack, the refactoring
undo is still valid since the user must first perform the undo for "rename
B.java to C.txt" before he can execute the undo for "rename A.java to B.java".
If the refactoring kernel listened to model changes only, without knowing that
there is an undo for the renaming of B.java to C.txt, the kernel would
invalidate the undo for rename A.java to B.java.
Note that we are only going to validate the top undo/redo
actions. Validating others on the stack would be too complicated. Consider the
case where one renames a compilation unit. In this case we have two changes, one
that renames the top level type and one that actual renames the file. To be able
to figure out if the undo for this refactoring is still valid, we have to check
if both changes are still valid. To do so we have to simulate the undo of the
rename of the file to be able to check if we still can undo the renaming of the
top level type. This is necessary since the rename of the top level type doesn't
know anything about the rename of the file. For example:
Rename A.java to B.java.
- change top level type in file A.java to B. The undo is
change top level type in file A.java to A
- change filename from A.java to B.java. The undo is
change B.java to A.java.
To figure out if this refactoring can still be undone we
have to simulate the rename form B.java to A.java. Otherwise we can't check
the undo "change top level type in file A.java to A" since A.java doesn't exist.
<GDA>
What do you mean "we would have to simulate?
Presumably any undo entry would include the necessary "prechecks"?
</GDA>
We would add tool bar buttons for undo and redo with a menu button to the
right like the "new" button. The menu button would show the current undo or redo
stack and let you select at any level in the stack. Again it is important that
IUndoActions be able to validate themselves since this will determine the
enablement of these buttons. The undo and redo actions in the Edit menu would
show the label for the action currently at the top of their stacks.
Once the new api is available, it is likely than many more actions would become
undoable (ex. resource rename, move etc.).
<GDA> Not sure I believe this claim. The mechanisms
now support it, we just are not using it. </GDA>
Problems with a Global Undo/Redo Stack
1) Since undo and redo are part
of the IWorkbenchActionConstants.GLOBAL_ACTIONS, it would be a breaking API
change to no longer support undo and redo as global (retargetable) actions.
Parts that are currently maintaining their own undo/redo stack would have to
change to add IUndoActions to the workbench stack. Until then the Edit menu
actions and their accelerators would no longer trigger an action in the part.
This is probably an acceptable breaking change.
2) The text widget implements its own undo. For example create a new task and
edit its description note that there is an undo item in the widgets popup menu.
This undo is local to the widget. Currently Undo is not enabled under edit in
this case since the tasklist does not supply a global action handler for this
purpose (There is no api on Text to allow programmatic undo). However if we
have a global stack it is likely that Edit>Undo would be enabled but it would
perform something different than undo on the popup.
Thus should we:
1) We could ask SWT for undo API on text in this case.
2) Continue to allow Undo/Redo to be global actions for which
we simply define a default behavior (which will not be retargeted by 95% of
the parts).
<GDA>
I don't follow why you need special undo support on the
widget.
</GDA>
3) It is not clear that an IDE built using the workbench has only a single
model. For example, suppose I
i) Edit some .java file in the Java
perspective
ii) Switch to the Team perspective and create something in the
Repositories view
iii) Switch back to the Java perspective, decide I don't
like my change and press Undo.
A global stack will cause the item I created
in the team perspective to be removed (this will perhaps happen silently).
But this is exactly what some would expect. They find it
confusing to have more than one undo stack in an application.
4) How do we define what can go on the undo redo stack? Do we limit it to
model changes? For example opening an editor could have an undo that would allow
the user to close the editor and return to the previously active part.
RFC
This proposal is not currently being voted on however you should
- Provide all comments/feedback to the mailing list.
- Clearly indicate if you are fundamentally opposed to the proposal and
provide reasons.
If you have serious concerns don't wait until there is a
vote - speak up now! Staying silent and then casting
a veto vote later isn't going to make you very popular.
RFC Termination Date
The period for comment ends 1 week from date proposal is submitted to the
mailing list.