PageRenderTime 28ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-3-pre5/org/gjt/sp/jedit/buffer/UndoManager.java

#
Java | 444 lines | 311 code | 59 blank | 74 comment | 66 complexity | 97422ef336a8d0663f5845f9c9b80344 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  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. package org.gjt.sp.jedit.buffer;
  23. //{{{ Imports
  24. import org.gjt.sp.util.Log;
  25. //}}}
  26. /**
  27. * A class internal to jEdit's document model. You should not use it
  28. * directly. To improve performance, none of the methods in this class
  29. * check for out of bounds access, nor are they thread-safe. The
  30. * <code>Buffer</code> class, through which these methods must be
  31. * called through, implements such protection.
  32. *
  33. * @author Slava Pestov
  34. * @version $Id: UndoManager.java 5339 2006-01-25 23:12:07Z spestov $
  35. * @since jEdit 4.0pre1
  36. */
  37. public class UndoManager
  38. {
  39. //{{{ UndoManager constructor
  40. public UndoManager(JEditBuffer buffer)
  41. {
  42. this.buffer = buffer;
  43. } //}}}
  44. //{{{ setLimit() method
  45. public void setLimit(int limit)
  46. {
  47. this.limit = limit;
  48. } //}}}
  49. //{{{ clear() method
  50. public void clear()
  51. {
  52. undosFirst = undosLast = redosFirst = redosLast = null;
  53. undoCount = 0;
  54. } //}}}
  55. //{{{ undo() method
  56. public int undo()
  57. {
  58. if(insideCompoundEdit())
  59. throw new InternalError("Unbalanced begin/endCompoundEdit()");
  60. if(undosLast == null)
  61. return -1;
  62. else
  63. {
  64. undoCount--;
  65. int caret = undosLast.undo();
  66. redosFirst = undosLast;
  67. undosLast = undosLast.prev;
  68. if(undosLast == null)
  69. undosFirst = null;
  70. return caret;
  71. }
  72. } //}}}
  73. //{{{ redo() method
  74. public int redo()
  75. {
  76. if(insideCompoundEdit())
  77. throw new InternalError("Unbalanced begin/endCompoundEdit()");
  78. if(redosFirst == null)
  79. return -1;
  80. else
  81. {
  82. undoCount++;
  83. int caret = redosFirst.redo();
  84. undosLast = redosFirst;
  85. if(undosFirst == null)
  86. undosFirst = undosLast;
  87. redosFirst = redosFirst.next;
  88. return caret;
  89. }
  90. } //}}}
  91. //{{{ beginCompoundEdit() method
  92. public void beginCompoundEdit()
  93. {
  94. if(compoundEditCount == 0)
  95. compoundEdit = new CompoundEdit();
  96. compoundEditCount++;
  97. } //}}}
  98. //{{{ endCompoundEdit() method
  99. public void endCompoundEdit()
  100. {
  101. if(compoundEditCount == 0)
  102. {
  103. Log.log(Log.WARNING,this,new Exception("Unbalanced begin/endCompoundEdit()"));
  104. return;
  105. }
  106. else if(compoundEditCount == 1)
  107. {
  108. if(compoundEdit.first == null)
  109. /* nothing done between begin/end calls */;
  110. else if(compoundEdit.first == compoundEdit.last)
  111. addEdit(compoundEdit.first);
  112. else
  113. addEdit(compoundEdit);
  114. compoundEdit = null;
  115. }
  116. compoundEditCount--;
  117. } //}}}
  118. //{{{ insideCompoundEdit() method
  119. public boolean insideCompoundEdit()
  120. {
  121. return compoundEditCount != 0;
  122. } //}}}
  123. //{{{ contentInserted() method
  124. public void contentInserted(int offset, int length, String text, boolean clearDirty)
  125. {
  126. Edit last = getLastEdit();
  127. Edit toMerge = getMergeEdit();
  128. if(!clearDirty && toMerge instanceof Insert
  129. && redosFirst == null)
  130. {
  131. Insert ins = (Insert)toMerge;
  132. if(ins.offset == offset)
  133. {
  134. ins.str = text.concat(ins.str);
  135. ins.length += length;
  136. return;
  137. }
  138. else if(ins.offset + ins.length == offset)
  139. {
  140. ins.str = ins.str.concat(text);
  141. ins.length += length;
  142. return;
  143. }
  144. }
  145. Insert ins = new Insert(this,offset,length,text);
  146. if(clearDirty)
  147. {
  148. redoClearDirty = last;
  149. undoClearDirty = ins;
  150. }
  151. if(compoundEdit != null)
  152. compoundEdit.add(ins);
  153. else
  154. addEdit(ins);
  155. } //}}}
  156. //{{{ contentRemoved() method
  157. public void contentRemoved(int offset, int length, String text, boolean clearDirty)
  158. {
  159. Edit last = getLastEdit();
  160. Edit toMerge = getMergeEdit();
  161. if(!clearDirty && toMerge instanceof Remove
  162. && redosFirst == null)
  163. {
  164. Remove rem = (Remove)toMerge;
  165. if(rem.offset == offset)
  166. {
  167. rem.str = rem.str.concat(text);
  168. rem.hashcode = rem.str.hashCode();
  169. rem.length += length;
  170. KillRing.getInstance().changed(rem);
  171. return;
  172. }
  173. else if(offset + length == rem.offset)
  174. {
  175. rem.str = text.concat(rem.str);
  176. rem.hashcode = rem.str.hashCode();
  177. rem.length += length;
  178. rem.offset = offset;
  179. KillRing.getInstance().changed(rem);
  180. return;
  181. }
  182. }
  183. Remove rem = new Remove(this,offset,length,text);
  184. if(clearDirty)
  185. {
  186. redoClearDirty = last;
  187. undoClearDirty = rem;
  188. }
  189. if(compoundEdit != null)
  190. compoundEdit.add(rem);
  191. else
  192. addEdit(rem);
  193. KillRing.getInstance().add(rem);
  194. } //}}}
  195. //{{{ bufferSaved() method
  196. public void bufferSaved()
  197. {
  198. redoClearDirty = getLastEdit();
  199. if(redosFirst instanceof CompoundEdit)
  200. undoClearDirty = ((CompoundEdit)redosFirst).first;
  201. else
  202. undoClearDirty = redosFirst;
  203. } //}}}
  204. //{{{ Private members
  205. //{{{ Instance variables
  206. private JEditBuffer buffer;
  207. // queue of undos. last is most recent, first is oldest
  208. private Edit undosFirst;
  209. private Edit undosLast;
  210. // queue of redos. first is most recent, last is oldest
  211. private Edit redosFirst;
  212. private Edit redosLast;
  213. private int limit;
  214. private int undoCount;
  215. private int compoundEditCount;
  216. private CompoundEdit compoundEdit;
  217. private Edit undoClearDirty, redoClearDirty;
  218. //}}}
  219. //{{{ addEdit() method
  220. private void addEdit(Edit edit)
  221. {
  222. if(undosFirst == null)
  223. undosFirst = undosLast = edit;
  224. else
  225. {
  226. undosLast.next = edit;
  227. edit.prev = undosLast;
  228. undosLast = edit;
  229. }
  230. redosFirst = redosLast = null;
  231. undoCount++;
  232. while(undoCount > limit)
  233. {
  234. undoCount--;
  235. if(undosFirst == undosLast)
  236. undosFirst = undosLast = null;
  237. else
  238. {
  239. undosFirst.next.prev = null;
  240. undosFirst = undosFirst.next;
  241. }
  242. }
  243. } //}}}
  244. //{{{ getMergeEdit() method
  245. private Edit getMergeEdit()
  246. {
  247. Edit last = getLastEdit();
  248. return (compoundEdit != null ? compoundEdit.last : last);
  249. } //}}}
  250. //{{{ getLastEdit() method
  251. private Edit getLastEdit()
  252. {
  253. if(undosLast instanceof CompoundEdit)
  254. return ((CompoundEdit)undosLast).last;
  255. else
  256. return undosLast;
  257. } //}}}
  258. //}}}
  259. //{{{ Inner classes
  260. //{{{ Edit class
  261. abstract static class Edit
  262. {
  263. Edit prev, next;
  264. //{{{ undo() method
  265. abstract int undo();
  266. //}}}
  267. //{{{ redo() method
  268. abstract int redo();
  269. //}}}
  270. } //}}}
  271. //{{{ Insert class
  272. static class Insert extends Edit
  273. {
  274. //{{{ Insert constructor
  275. Insert(UndoManager mgr, int offset, int length, String str)
  276. {
  277. this.mgr = mgr;
  278. this.offset = offset;
  279. this.length = length;
  280. this.str = str;
  281. } //}}}
  282. //{{{ undo() method
  283. int undo()
  284. {
  285. mgr.buffer.remove(offset,length);
  286. if(mgr.undoClearDirty == this)
  287. mgr.buffer.setDirty(false);
  288. return offset;
  289. } //}}}
  290. //{{{ redo() method
  291. int redo()
  292. {
  293. mgr.buffer.insert(offset,str);
  294. if(mgr.redoClearDirty == this)
  295. mgr.buffer.setDirty(false);
  296. return offset + length;
  297. } //}}}
  298. UndoManager mgr;
  299. int offset;
  300. int length;
  301. String str;
  302. } //}}}
  303. //{{{ Remove class
  304. static class Remove extends Edit
  305. {
  306. //{{{ Remove constructor
  307. Remove(UndoManager mgr, int offset, int length, String str)
  308. {
  309. this.mgr = mgr;
  310. this.offset = offset;
  311. this.length = length;
  312. this.str = str;
  313. hashcode = str.hashCode();
  314. } //}}}
  315. //{{{ undo() method
  316. int undo()
  317. {
  318. mgr.buffer.insert(offset,str);
  319. if(mgr.undoClearDirty == this)
  320. mgr.buffer.setDirty(false);
  321. return offset + length;
  322. } //}}}
  323. //{{{ redo() method
  324. int redo()
  325. {
  326. mgr.buffer.remove(offset,length);
  327. if(mgr.redoClearDirty == this)
  328. mgr.buffer.setDirty(false);
  329. return offset;
  330. } //}}}
  331. //{{{ toString() method
  332. public String toString()
  333. {
  334. return str;
  335. } //}}}
  336. UndoManager mgr;
  337. int offset;
  338. int length;
  339. String str;
  340. int hashcode;
  341. boolean inKillRing;
  342. } //}}}
  343. //{{{ CompoundEdit class
  344. static class CompoundEdit extends Edit
  345. {
  346. //{{{ undo() method
  347. public int undo()
  348. {
  349. int retVal = -1;
  350. Edit edit = last;
  351. while(edit != null)
  352. {
  353. retVal = edit.undo();
  354. edit = edit.prev;
  355. }
  356. return retVal;
  357. } //}}}
  358. //{{{ redo() method
  359. public int redo()
  360. {
  361. int retVal = -1;
  362. Edit edit = first;
  363. while(edit != null)
  364. {
  365. retVal = edit.redo();
  366. edit = edit.next;
  367. }
  368. return retVal;
  369. } //}}}
  370. //{{{ add() method
  371. public void add(Edit edit)
  372. {
  373. if(first == null)
  374. first = last = edit;
  375. else
  376. {
  377. edit.prev = last;
  378. last.next = edit;
  379. last = edit;
  380. }
  381. } //}}}
  382. Edit first, last;
  383. } //}}}
  384. //}}}
  385. }