KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > gjt > sp > jedit > buffer > UndoManager


1 /*
2  * UndoManager.java - Buffer undo manager
3  * :tabSize=8:indentSize=8:noTabs=false:
4  * :folding=explicit:collapseFolds=1:
5  *
6  * Copyright (C) 2001, 2005 Slava Pestov
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  */

22
23 package org.gjt.sp.jedit.buffer;
24
25 //{{{ Imports
26
import org.gjt.sp.util.Log;
27 //}}}
28

29 /**
30  * A class internal to jEdit's document model. You should not use it
31  * directly. To improve performance, none of the methods in this class
32  * check for out of bounds access, nor are they thread-safe. The
33  * <code>Buffer</code> class, through which these methods must be
34  * called through, implements such protection.
35  *
36  * @author Slava Pestov
37  * @version $Id: UndoManager.java 7130 2006-09-25 22:00:25Z kpouer $
38  * @since jEdit 4.0pre1
39  */

40 public class UndoManager
41 {
42     //{{{ UndoManager constructor
43
public UndoManager(JEditBuffer buffer)
44     {
45         this.buffer = buffer;
46     } //}}}
47

48     //{{{ setLimit() method
49
public void setLimit(int limit)
50     {
51         this.limit = limit;
52     } //}}}
53

54     //{{{ clear() method
55
public void clear()
56     {
57         undosFirst = undosLast = redosFirst = redosLast = null;
58         undoCount = 0;
59     } //}}}
60

61     //{{{ undo() method
62
public int undo()
63     {
64         if(insideCompoundEdit())
65             throw new InternalError JavaDoc("Unbalanced begin/endCompoundEdit()");
66
67         if(undosLast == null)
68             return -1;
69         else
70         {
71             undoCount--;
72
73             int caret = undosLast.undo();
74             redosFirst = undosLast;
75             undosLast = undosLast.prev;
76             if(undosLast == null)
77                 undosFirst = null;
78             return caret;
79         }
80     } //}}}
81

82     //{{{ redo() method
83
public int redo()
84     {
85         if(insideCompoundEdit())
86             throw new InternalError JavaDoc("Unbalanced begin/endCompoundEdit()");
87
88         if(redosFirst == null)
89             return -1;
90         else
91         {
92             undoCount++;
93
94             int caret = redosFirst.redo();
95             undosLast = redosFirst;
96             if(undosFirst == null)
97                 undosFirst = undosLast;
98             redosFirst = redosFirst.next;
99             return caret;
100         }
101     } //}}}
102

103     //{{{ beginCompoundEdit() method
104
public void beginCompoundEdit()
105     {
106         if(compoundEditCount == 0)
107             compoundEdit = new CompoundEdit();
108
109         compoundEditCount++;
110     } //}}}
111

112     //{{{ endCompoundEdit() method
113
public void endCompoundEdit()
114     {
115         if(compoundEditCount == 0)
116         {
117             Log.log(Log.WARNING,this,new Exception JavaDoc("Unbalanced begin/endCompoundEdit()"));
118             return;
119         }
120         else if(compoundEditCount == 1)
121         {
122             if(compoundEdit.first == null)
123                 /* nothing done between begin/end calls */;
124             else if(compoundEdit.first == compoundEdit.last)
125                 addEdit(compoundEdit.first);
126             else
127                 addEdit(compoundEdit);
128
129             compoundEdit = null;
130         }
131
132         compoundEditCount--;
133     } //}}}
134

135     //{{{ insideCompoundEdit() method
136
public boolean insideCompoundEdit()
137     {
138         return compoundEditCount != 0;
139     } //}}}
140

141     //{{{ contentInserted() method
142
public void contentInserted(int offset, int length, String JavaDoc text, boolean clearDirty)
143     {
144         Edit last = getLastEdit();
145         Edit toMerge = getMergeEdit();
146
147         if(!clearDirty && toMerge instanceof Insert
148             && redosFirst == null)
149         {
150             Insert ins = (Insert)toMerge;
151             if(ins.offset == offset)
152             {
153                 ins.str = text.concat(ins.str);
154                 ins.length += length;
155                 return;
156             }
157             else if(ins.offset + ins.length == offset)
158             {
159                 ins.str = ins.str.concat(text);
160                 ins.length += length;
161                 return;
162             }
163         }
164
165         Insert ins = new Insert(this,offset,length,text);
166
167         if(clearDirty)
168         {
169             redoClearDirty = last;
170             undoClearDirty = ins;
171         }
172
173         if(compoundEdit != null)
174             compoundEdit.add(ins);
175         else
176             addEdit(ins);
177     } //}}}
178

179     //{{{ contentRemoved() method
180
public void contentRemoved(int offset, int length, String JavaDoc text, boolean clearDirty)
181     {
182         Edit last = getLastEdit();
183         Edit toMerge = getMergeEdit();
184
185         if(!clearDirty && toMerge instanceof Remove
186             && redosFirst == null)
187         {
188             Remove rem = (Remove)toMerge;
189             if(rem.offset == offset)
190             {
191                 rem.str = rem.str.concat(text);
192                 rem.hashcode = rem.str.hashCode();
193                 rem.length += length;
194                 KillRing.getInstance().changed(rem);
195                 return;
196             }
197             else if(offset + length == rem.offset)
198             {
199                 rem.str = text.concat(rem.str);
200                 rem.hashcode = rem.str.hashCode();
201                 rem.length += length;
202                 rem.offset = offset;
203                 KillRing.getInstance().changed(rem);
204                 return;
205             }
206         }
207
208         Remove rem = new Remove(this,offset,length,text);
209         if(clearDirty)
210         {
211             redoClearDirty = last;
212             undoClearDirty = rem;
213         }
214
215         if(compoundEdit != null)
216             compoundEdit.add(rem);
217         else
218             addEdit(rem);
219
220         KillRing.getInstance().add(rem);
221     } //}}}
222

223     //{{{ bufferSaved() method
224
public void bufferSaved()
225     {
226         redoClearDirty = getLastEdit();
227         if(redosFirst instanceof CompoundEdit)
228             undoClearDirty = ((CompoundEdit)redosFirst).first;
229         else
230             undoClearDirty = redosFirst;
231     } //}}}
232

233     //{{{ Private members
234

235     //{{{ Instance variables
236
private JEditBuffer buffer;
237
238     // queue of undos. last is most recent, first is oldest
239
private Edit undosFirst;
240     private Edit undosLast;
241
242     // queue of redos. first is most recent, last is oldest
243
private Edit redosFirst;
244     private Edit redosLast;
245
246     private int limit;
247     private int undoCount;
248     private int compoundEditCount;
249     private CompoundEdit compoundEdit;
250     private Edit undoClearDirty, redoClearDirty;
251     //}}}
252

253     //{{{ addEdit() method
254
private void addEdit(Edit edit)
255     {
256         if(undosFirst == null)
257             undosFirst = undosLast = edit;
258         else
259         {
260             undosLast.next = edit;
261             edit.prev = undosLast;
262             undosLast = edit;
263         }
264
265         redosFirst = redosLast = null;
266
267         undoCount++;
268
269         while(undoCount > limit)
270         {
271             undoCount--;
272
273             if(undosFirst == undosLast)
274                 undosFirst = undosLast = null;
275             else
276             {
277                 undosFirst.next.prev = null;
278                 undosFirst = undosFirst.next;
279             }
280         }
281     } //}}}
282

283     //{{{ getMergeEdit() method
284
private Edit getMergeEdit()
285     {
286         Edit last = getLastEdit();
287         return (compoundEdit != null ? compoundEdit.last : last);
288     } //}}}
289

290     //{{{ getLastEdit() method
291
private Edit getLastEdit()
292     {
293         if(undosLast instanceof CompoundEdit)
294             return ((CompoundEdit)undosLast).last;
295         else
296             return undosLast;
297     } //}}}
298

299     //}}}
300

301     //{{{ Inner classes
302

303     //{{{ Edit class
304
abstract static class Edit
305     {
306         Edit prev, next;
307
308         //{{{ undo() method
309
abstract int undo();
310         //}}}
311

312         //{{{ redo() method
313
abstract int redo();
314         //}}}
315
} //}}}
316

317     //{{{ Insert class
318
static class Insert extends Edit
319     {
320         //{{{ Insert constructor
321
Insert(UndoManager mgr, int offset, int length, String JavaDoc str)
322         {
323             this.mgr = mgr;
324             this.offset = offset;
325             this.length = length;
326             this.str = str;
327         } //}}}
328

329         //{{{ undo() method
330
int undo()
331         {
332             mgr.buffer.remove(offset,length);
333             if(mgr.undoClearDirty == this)
334                 mgr.buffer.setDirty(false);
335             return offset;
336         } //}}}
337

338         //{{{ redo() method
339
int redo()
340         {
341             mgr.buffer.insert(offset,str);
342             if(mgr.redoClearDirty == this)
343                 mgr.buffer.setDirty(false);
344             return offset + length;
345         } //}}}
346

347         UndoManager mgr;
348         int offset;
349         int length;
350         String JavaDoc str;
351     } //}}}
352

353     //{{{ Remove class
354
public static class Remove extends Edit
355     {
356         //{{{ Remove constructor
357
Remove(UndoManager mgr, int offset, int length, String JavaDoc str)
358         {
359             this.mgr = mgr;
360             this.offset = offset;
361             this.length = length;
362             this.str = str;
363             hashcode = str.hashCode();
364         } //}}}
365

366         //{{{ undo() method
367
int undo()
368         {
369             mgr.buffer.insert(offset,str);
370             if(mgr.undoClearDirty == this)
371                 mgr.buffer.setDirty(false);
372             return offset + length;
373         } //}}}
374

375         //{{{ redo() method
376
int redo()
377         {
378             mgr.buffer.remove(offset,length);
379             if(mgr.redoClearDirty == this)
380                 mgr.buffer.setDirty(false);
381             return offset;
382         } //}}}
383

384         //{{{ toString() method
385
public String JavaDoc toString()
386         {
387             return str;
388         } //}}}
389

390         UndoManager mgr;
391         int offset;
392         int length;
393         String JavaDoc str;
394         int hashcode;
395         boolean inKillRing;
396     } //}}}
397

398     //{{{ CompoundEdit class
399
static class CompoundEdit extends Edit
400     {
401         //{{{ undo() method
402
public int undo()
403         {
404             int retVal = -1;
405             Edit edit = last;
406             while(edit != null)
407             {
408                 retVal = edit.undo();
409                 edit = edit.prev;
410             }
411             return retVal;
412         } //}}}
413

414         //{{{ redo() method
415
public int redo()
416         {
417             int retVal = -1;
418             Edit edit = first;
419             while(edit != null)
420             {
421                 retVal = edit.redo();
422                 edit = edit.next;
423             }
424             return retVal;
425         } //}}}
426

427         //{{{ add() method
428
public void add(Edit edit)
429         {
430             if(first == null)
431                 first = last = edit;
432             else
433             {
434                 edit.prev = last;
435                 last.next = edit;
436                 last = edit;
437             }
438         } //}}}
439

440         Edit first, last;
441     } //}}}
442

443     //}}}
444
}
445
Popular Tags