source: other-projects/rsyntax-textarea/src/java/org/fife/ui/rtextarea/RUndoManager.java@ 25584

Last change on this file since 25584 was 25584, checked in by davidb, 12 years ago

Initial cut an a text edit area for GLI that supports color syntax highlighting

File size: 6.2 KB
Line 
1/*
2 * 12/06/2008
3 *
4 * RUndoManager.java - Handles undo/redo behavior for RTextArea.
5 *
6 * This library is distributed under a modified BSD license. See the included
7 * RSyntaxTextArea.License.txt file for details.
8 */
9package org.fife.ui.rtextarea;
10
11import java.util.ResourceBundle;
12import javax.swing.Action;
13import javax.swing.UIManager;
14import javax.swing.event.UndoableEditEvent;
15import javax.swing.undo.CannotRedoException;
16import javax.swing.undo.CannotUndoException;
17import javax.swing.undo.CompoundEdit;
18import javax.swing.undo.UndoManager;
19import javax.swing.undo.UndoableEdit;
20
21
22/**
23 * This class manages undos/redos for a particular editor pane. It groups
24 * all undos that occur one character position apart together, to avoid
25 * Java's horrible "one character at a time" undo behavior. It also
26 * recognizes "replace" actions (i.e., text is selected, then the user
27 * types), and treats it as a single action, instead of a remove/insert
28 * action pair.
29 *
30 * @author Robert Futrell
31 * @version 1.0
32 */
33public class RUndoManager extends UndoManager {
34
35 private RCompoundEdit compoundEdit;
36 private RTextArea textArea;
37 private int lastOffset;
38 private String cantUndoText;
39 private String cantRedoText;
40
41 private int internalAtomicEditDepth;
42
43 private static final String MSG = "org.fife.ui.rtextarea.RTextArea";
44
45
46 /**
47 * Constructor.
48 *
49 * @param textArea The parent text area.
50 */
51 public RUndoManager(RTextArea textArea) {
52 this.textArea = textArea;
53 ResourceBundle msg = ResourceBundle.getBundle(MSG);
54 cantUndoText = msg.getString("Action.CantUndo.Name");
55 cantRedoText = msg.getString("Action.CantRedo.Name");
56 }
57
58
59 /**
60 * Begins an "atomic" edit. This method is called when RTextArea
61 * KNOWS that some edits should be compound automatically, such as
62 * when the user is typing in overwrite mode (the deletion of the
63 * current char + insertion of the new one) or the playing back of a
64 * macro.
65 *
66 * @see #endInternalAtomicEdit()
67 */
68 public void beginInternalAtomicEdit() {
69 if (++internalAtomicEditDepth==1) {
70 if (compoundEdit!=null)
71 compoundEdit.end();
72 compoundEdit = new RCompoundEdit();
73 }
74 }
75
76
77 /**
78 * Ends an "atomic" edit.
79 *
80 * @see #beginInternalAtomicEdit()
81 */
82 public void endInternalAtomicEdit() {
83 if (internalAtomicEditDepth>0 && --internalAtomicEditDepth==0) {
84 addEdit(compoundEdit);
85 compoundEdit.end();
86 compoundEdit = null;
87 updateActions(); // Needed to show the new display name.
88 }
89 }
90
91
92 /**
93 * Returns the localized "Can't Redo" string.
94 *
95 * @return The localized "Can't Redo" string.
96 * @see #getCantUndoText()
97 */
98 public String getCantRedoText() {
99 return cantRedoText;
100 }
101
102
103 /**
104 * Returns the localized "Can't Undo" string.
105 *
106 * @return The localized "Can't Undo" string.
107 * @see #getCantRedoText()
108 */
109 public String getCantUndoText() {
110 return cantUndoText;
111 }
112
113
114 /**
115 * {@inheritDoc}
116 */
117 public void redo() throws CannotRedoException {
118 super.redo();
119 updateActions();
120 }
121
122
123 private RCompoundEdit startCompoundEdit(UndoableEdit edit) {
124 lastOffset = textArea.getCaretPosition();
125 compoundEdit = new RCompoundEdit();
126 compoundEdit.addEdit(edit);
127 addEdit(compoundEdit);
128 return compoundEdit;
129 }
130
131
132 /**
133 * {@inheritDoc}
134 */
135 public void undo() throws CannotUndoException {
136 super.undo();
137 updateActions();
138 }
139
140
141 public void undoableEditHappened(UndoableEditEvent e) {
142
143 // This happens when the first undoable edit occurs, and
144 // just after an undo. So, we need to update our actions.
145 if (compoundEdit==null) {
146 compoundEdit = startCompoundEdit(e.getEdit());
147 updateActions();
148 return;
149 }
150
151 else if (internalAtomicEditDepth>0) {
152 compoundEdit.addEdit(e.getEdit());
153 return;
154 }
155
156 // This happens when there's already an undo that has occurred.
157 // Test to see if these undos are on back-to-back characters,
158 // and if they are, group them as a single edit. Since an
159 // undo has already occurred, there is no need to update our
160 // actions here.
161 int diff = textArea.getCaretPosition() - lastOffset;
162 // "<=1" allows contiguous "overwrite mode" key presses to be
163 // grouped together.
164 if (Math.abs(diff)<=1) {//==1) {
165 compoundEdit.addEdit(e.getEdit());
166 lastOffset += diff;
167 //updateActions();
168 return;
169 }
170
171 // This happens when this UndoableEdit didn't occur at the
172 // character just after the previous undlabeledit. Since an
173 // undo has already occurred, there is no need to update our
174 // actions here either.
175 compoundEdit.end();
176 compoundEdit = startCompoundEdit(e.getEdit());
177 //updateActions();
178
179 }
180
181
182 /**
183 * Ensures that undo/redo actions are enabled appropriately and have
184 * descriptive text at all times.
185 */
186 public void updateActions() {
187
188 String text;
189
190 Action a = RTextArea.getAction(RTextArea.UNDO_ACTION);
191 if (canUndo()) {
192 a.setEnabled(true);
193 text = getUndoPresentationName();
194 a.putValue(Action.NAME, text);
195 a.putValue(Action.SHORT_DESCRIPTION, text);
196 }
197 else {
198 if (a.isEnabled()) {
199 a.setEnabled(false);
200 text = cantUndoText;
201 a.putValue(Action.NAME, text);
202 a.putValue(Action.SHORT_DESCRIPTION, text);
203 }
204 }
205
206 a = RTextArea.getAction(RTextArea.REDO_ACTION);
207 if (canRedo()) {
208 a.setEnabled(true);
209 text = getRedoPresentationName();
210 a.putValue(Action.NAME, text);
211 a.putValue(Action.SHORT_DESCRIPTION, text);
212 }
213 else {
214 if (a.isEnabled()) {
215 a.setEnabled(false);
216 text = cantRedoText;
217 a.putValue(Action.NAME, text);
218 a.putValue(Action.SHORT_DESCRIPTION, text);
219 }
220 }
221
222 }
223
224 /**
225 * The action used by {@link RUndoManager}.
226 *
227 * @author Robert Futrell
228 * @version 1.0
229 */
230 class RCompoundEdit extends CompoundEdit {
231
232 public String getUndoPresentationName() {
233 return UIManager.getString("AbstractUndoableEdit.undoText");
234 }
235
236 public String getRedoPresentationName() {
237 return UIManager.getString("AbstractUndoableEdit.redoText");
238 }
239
240 public boolean isInProgress() {
241 return false;
242 }
243
244 public void undo() throws CannotUndoException {
245 if (compoundEdit!=null)
246 compoundEdit.end();
247 super.undo();
248 compoundEdit = null;
249 }
250
251 }
252
253
254}
Note: See TracBrowser for help on using the repository browser.