GT-2947 - updated Edit Function dialog to put focus in the signature

field by default; added undo/redo support
This commit is contained in:
dragonmacher 2019-06-19 17:44:34 -04:00
parent fb3e941959
commit a77efd2524
5 changed files with 128 additions and 75 deletions

View file

@ -87,7 +87,7 @@ import resources.ResourceManager;
* <tr><td>{@link JList}</td><td>{@link GList}</td></tr>
* <tr><td>{@link ListCellRenderer}<br>{@link DefaultListCellRenderer}</td><td>{@link GListCellRenderer}</td></tr>
* <tr><td>{@link TableCellRenderer}</td><td>{@link GTableCellRenderer}</td></tr>
* <tr><td>{@link TreeCellRenderer}<br>{@link DefaultTreeCellRenderer}</td><td>{@link GTreeRenderer}<br>{@link DnDTreeCellRenderer}</td></tr>
* <tr><td>{@link TreeCellRenderer}<br>{@link DefaultTreeCellRenderer}</td><td>{@link GTreeRenderer}<br><code>DnDTreeCellRenderer</code></td></tr>
* <tr><td>{@link JRadioButton}</td><td>{@link GRadioButton}</td></tr>
* <tr><td>{@link JButton}</td><td>???tbd???</td></tr>
* </table>
@ -179,15 +179,6 @@ public class DockingUtils {
final UndoRedoKeeper undoRedoKeeper = new UndoRedoKeeper();
document.addUndoableEditListener(e -> {
UndoableEdit edit = e.getEdit();
// TODO We are now handed a wrapper class and not the event for the 'edit'. It is not clear
// which use case caused this code to be added. If/when we find out, we can revisit how
// to filter these types of updates.
// DefaultDocumentEvent defaultDocumentEvent = (DefaultDocumentEvent) edit;
// if (defaultDocumentEvent.getType() == EventType.CHANGE) {
// return; // this happens for style updates
// }
undoRedoKeeper.addUndo(edit);
});

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,31 +15,85 @@
*/
package docking;
import ghidra.util.datastruct.FixedSizeStack;
import javax.swing.JTextPane;
import javax.swing.undo.CompoundEdit;
import javax.swing.undo.UndoableEdit;
import ghidra.util.datastruct.FixedSizeStack;
/**
* Handles tracking undo and redo events. Clients may wish to hold on to this class in order
* to clear the undo/redo queue.
*
* <p><b><u>Style Edits</u></b><br>
* {@link JTextPane}s allow for styles (color, bold, etc) to be applied to their text. The
* default undo/redo events may arrive singly, not in bulk. Thus, when the user presses undo,
* each style change is undo, one at a time. This is intuitive when the user controls the
* application of style. However, when style is applied programmatically, it can be odd to
* see that the user-type text does not change, but just the coloring applied to that text.
* <p>
* To address this issue, this class takes the approach of combining all style edits into a
* single bulk edit. Then, as the user presses undo, all style edits can be removed together, as
* well as any neighboring text edits. <b>Put simply, this class tracks style edits such
* that an undo operation will undo all style changes, as well as a single text edit.</b>
*/
public class UndoRedoKeeper {
private static final int MAX_UNDO_REDO_SIZE = 50;
private static final String STYLE_EDIT_KEY = "style";
private FixedSizeStack<UndoableEdit> undoStack = new FixedSizeStack<UndoableEdit>(
MAX_UNDO_REDO_SIZE);
private FixedSizeStack<UndoableEdit> redoStack = new FixedSizeStack<UndoableEdit>(
MAX_UNDO_REDO_SIZE);
private FixedSizeStack<UndoableEdit> undoStack = new FixedSizeStack<>(MAX_UNDO_REDO_SIZE);
private FixedSizeStack<UndoableEdit> redoStack = new FixedSizeStack<>(MAX_UNDO_REDO_SIZE);
private StyleCompoundEdit lastStyleUndo;
void addUndo(UndoableEdit edit) {
String name = edit.getPresentationName();
if (name.contains(STYLE_EDIT_KEY)) {
// (see header note about style edits)
addStyleEdit(edit);
return;
}
endOutstandingStyleEdits();
undoStack.push(edit);
redoStack.clear();
redoStack.clear(); // new edit added; clear redo
}
private void endOutstandingStyleEdits() {
if (lastStyleUndo != null) {
lastStyleUndo.end();
lastStyleUndo = null;
}
}
private void addStyleEdit(UndoableEdit edit) {
if (lastStyleUndo == null) {
lastStyleUndo = new StyleCompoundEdit();
undoStack.push(lastStyleUndo);
}
lastStyleUndo.addEdit(edit);
redoStack.clear(); // new edit added; clear redo
}
void undo() {
if (undoStack.isEmpty()) {
return;
}
endOutstandingStyleEdits();
UndoableEdit item = undoStack.pop();
redoStack.push(item);
item.undo();
// (see header note)
if (item instanceof StyleCompoundEdit) {
undo(); // call again to get a 'real' edit
}
}
void redo() {
@ -48,13 +101,24 @@ public class UndoRedoKeeper {
return;
}
endOutstandingStyleEdits();
UndoableEdit item = redoStack.pop();
undoStack.push(item);
item.redo();
// (see header note)
if (item instanceof StyleCompoundEdit) {
undo(); // call again to get a 'real' edit
}
}
public void clear() {
undoStack.clear();
redoStack.clear();
}
private static class StyleCompoundEdit extends CompoundEdit {
// simple class for us to track internally
}
}