CS 349 - User interfaces, LEC 001
6-15-2016
Elvin Yung
- Conceptually, undo is similar to something called checkpointing.
- Checkpointing is a way of manually undoing something - like saving and and reloading in a video game.
- Undo/redo is basically an automated way of checkpointing.
- Version control systems like Git are a way of checkpointing.
- There's quite a bit of research done in this area, about how people use GUIs.
- People rely on undo-redo not just to revert mistakes, but also to experiment with the UI, without fear of commitment.
- Fast undo-redo lets you compare two different states very easily.
- This is actually one of the features that you basically have to include, for a usable GUI.
-
You have to make a bunch of design decision
-
What's undoable? Not everything should be. For example, if I resize a window, it isn't normally undoable. Usually it's data changes that are undoable.
-
Destructive operations are difficult to undo, e.g. quitting an application with unsaved data, emptying the trash.
- When users initiate a destructive action, the UI usually does something to make sure the user is suer they want to do it, like showing a "are you sure?" dialog box.
-
Some things can't be undone. e.g. printing.
- Every change to the model should be undoable.
- Ask for confirmation.
- How does the UI reflect the undo/redo?
- e.g. should you highlight the thing that the undo restored?
- The restored item should be highlighted, since before the delete, it was selected.
- It's probably meaningful for the scroll to move to the restored text. e.g. Sublime Text does this.
- What should be considered as an undoable step?
- It's pretty obvious in most cases, but there are some ambiguities.
- For example, should typing a character be considered a discrete action, or should the smallest unit be an entire word?
- Different text editing software handle this differently.
- Another example: A paint-like app, where you use the mouse to draw strokes.
- In this case, a mousedown-mousedrag-mouseup sequence (i.e. drawing an entire line segment) should be an entire action, instead of each mouse drag.
- Ignore
- An interface event should be one step - e.g. find and replace all. In other words, if it takes one click to make that change, it should be considered a single change.
- Delimit on user input breaks - like spaces
- At what level does undo operate - at system, application, document, or widget level?
- Obviously, when you do something in Photoshop, and then do something in Word, when you go back to Photoshop and undo something, it shouldn't affect Word.
- It gets tricker when you involve a software that can have multiple documents at the same time.
- Usually in this case, you maintain a separate undo
- In general: It should be at the application level, unless you can open more than one document in the app. Then it should be document level.
- Save the state periodically, and log all the changes (or diffs) to the current state since that change.
- To undo, get the new state by replaying the last n-1 change records from the last saved state.
- Save every different state in the history.
- When you undo, you can just go back to the last state.
- Clearly, this is pretty inefficienct in terms of state use.
- Every time you make a change, add a
- Generally, this is partially implemented with checkpointing,
- Square root decomposition
- Keep track of two stacks: an undo stack and a redo stack.
- Every time you do something, you put it on the undo stack.
- Every time you undo something, you pop from the undo stack, and push it to the redo stack.
- If undo something and then do something else, clear the redo stack.
- Some software might do some more complicated stuff like keeping a tree, but this is how it's basically implemented.
- Swing has an undo manager, provided in
javax.swing.undo.*
. - It exposes an
UndoManager
class, which you usually put in your model. - When you implement the method that performs some change, you add an
AbstractUndoableEdit
object to theUndoManager
. - The
UndoManager
hasundo
andredo
methods to do the actual operations, which you typically bind to your accelerator keys.
Consider a situation like this:
You have a few options of resolving this:
- Use forward command undo.
- Use Memento. When it's difficult to reconstruct the state from scratch, you're better off taking a snapshot.
-
We consider drag-and-drop as the same thing as cut-paste, since they're both basically removing data from somewhere, and putting it somewhere.
-
Why do we care about this?
-
It's the primary mechanism to transfer information.
-
A clipboard where any application can access is a huge security risk. People copy some pretty sensitive things.
-
We don't address this in this course, but it's something to consider.
-
Copy-and-paste is essentially IPC - you need a common format for it to work between different programs.
-
It's straightforward for text, but how do you do it for things like graphics, where some formats might be proprietary, or not universally supported?
-
In OSX, The application indicates what formats it supports.
-
When you copy something, the data is usually copied lazily, i.e. isn't copied onto the clipboard. Usually it only adds a placeholder or a reference.
-
This is better because sometimes copied data might never be pasted.
-
Every OS/windowing system/toolkit does it differently.
-
In Java, look at
java.awt.datatransfer
. -
Java has two kinds of clipboard: a system clipboard, and also a local clipboard, which is a clipboard that only your application can access.
-
Don't use the local clipboard - the main point of copy-and-paste is to be able to transfer data between different programs.
- As we said, drag-and-drop is identical to copy-and-paste.
- The only difference is that you need listeners on the source and destination widgets to move the data.