PageRenderTime 39ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/src/HistoryStack.cs

https://bitbucket.org/tcz001/openpdn
C# | 395 lines | 294 code | 68 blank | 33 comment | 44 complexity | 8a906e547e3aea0a0b69cee0966ec446 MD5 | raw file
Possible License(s): Unlicense
  1. /////////////////////////////////////////////////////////////////////////////////
  2. // Paint.NET //
  3. // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. //
  4. // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
  5. // See src/Resources/Files/License.txt for full licensing and attribution //
  6. // details. //
  7. // . //
  8. /////////////////////////////////////////////////////////////////////////////////
  9. using PaintDotNet.HistoryMementos;
  10. using System;
  11. using System.Collections;
  12. using System.Collections.Generic;
  13. using System.Windows.Forms;
  14. namespace PaintDotNet
  15. {
  16. /// <summary>
  17. /// The HistoryStack class for the History "concept".
  18. /// Serves as the undo and redo stacks.
  19. /// </summary>
  20. [Serializable]
  21. internal class HistoryStack
  22. {
  23. private List<HistoryMemento> undoStack;
  24. private List<HistoryMemento> redoStack;
  25. private DocumentWorkspace documentWorkspace;
  26. private int stepGroupDepth;
  27. private int isExecutingMemento = 0; // 0 -> false, >0 -> true
  28. public bool IsExecutingMemento
  29. {
  30. get
  31. {
  32. return this.isExecutingMemento > 0;
  33. }
  34. }
  35. private void PushExecutingMemento()
  36. {
  37. ++this.isExecutingMemento;
  38. }
  39. private void PopExecutingMemento()
  40. {
  41. --this.isExecutingMemento;
  42. }
  43. public List<HistoryMemento> UndoStack
  44. {
  45. get
  46. {
  47. return this.undoStack;
  48. }
  49. }
  50. public List<HistoryMemento> RedoStack
  51. {
  52. get
  53. {
  54. return this.redoStack;
  55. }
  56. }
  57. public void BeginStepGroup()
  58. {
  59. ++this.stepGroupDepth;
  60. }
  61. public void EndStepGroup()
  62. {
  63. --this.stepGroupDepth;
  64. if (this.stepGroupDepth == 0)
  65. {
  66. OnFinishedStepGroup();
  67. }
  68. }
  69. public event EventHandler FinishedStepGroup;
  70. protected void OnFinishedStepGroup()
  71. {
  72. if (FinishedStepGroup != null)
  73. {
  74. FinishedStepGroup(this, EventArgs.Empty);
  75. }
  76. }
  77. public event EventHandler SteppedBackward;
  78. protected void OnSteppedBackward()
  79. {
  80. if (SteppedBackward != null)
  81. {
  82. SteppedBackward(this, EventArgs.Empty);
  83. }
  84. }
  85. public event EventHandler SteppedForward;
  86. protected void OnSteppedForward()
  87. {
  88. if (SteppedForward != null)
  89. {
  90. SteppedForward(this, EventArgs.Empty);
  91. }
  92. }
  93. /// <summary>
  94. /// Event handler for when a new history memento has been added.
  95. /// </summary>
  96. public event EventHandler NewHistoryMemento;
  97. protected void OnNewHistoryMemento()
  98. {
  99. if (NewHistoryMemento != null)
  100. {
  101. NewHistoryMemento(this, EventArgs.Empty);
  102. }
  103. }
  104. /// <summary>
  105. /// Event handler for when changes have been made to the history.
  106. /// </summary>
  107. public event EventHandler Changed;
  108. protected void OnChanged()
  109. {
  110. if (Changed != null)
  111. {
  112. Changed(this, EventArgs.Empty);
  113. }
  114. }
  115. public event EventHandler Changing;
  116. protected void OnChanging()
  117. {
  118. if (Changing != null)
  119. {
  120. Changing(this, EventArgs.Empty);
  121. }
  122. }
  123. public event EventHandler HistoryFlushed;
  124. protected void OnHistoryFlushed()
  125. {
  126. if (HistoryFlushed != null)
  127. {
  128. HistoryFlushed(this, EventArgs.Empty);
  129. }
  130. }
  131. public event ExecutingHistoryMementoEventHandler ExecutingHistoryMemento;
  132. protected void OnExecutingHistoryMemento(ExecutingHistoryMementoEventArgs e)
  133. {
  134. if (ExecutingHistoryMemento != null)
  135. {
  136. ExecutingHistoryMemento(this, e);
  137. }
  138. }
  139. public event ExecutedHistoryMementoEventHandler ExecutedHistoryMemento;
  140. protected void OnExecutedHistoryMemento(ExecutedHistoryMementoEventArgs e)
  141. {
  142. if (ExecutedHistoryMemento != null)
  143. {
  144. ExecutedHistoryMemento(this, e);
  145. }
  146. }
  147. public void PerformChanged()
  148. {
  149. OnChanged();
  150. }
  151. public HistoryStack(DocumentWorkspace documentWorkspace)
  152. {
  153. this.documentWorkspace = documentWorkspace;
  154. undoStack = new List<HistoryMemento>();
  155. redoStack = new List<HistoryMemento>();
  156. }
  157. private HistoryStack(
  158. List<HistoryMemento> undoStack,
  159. List<HistoryMemento> redoStack)
  160. {
  161. this.undoStack = new List<HistoryMemento>(undoStack);
  162. this.redoStack = new List<HistoryMemento>(redoStack);
  163. }
  164. /// <summary>
  165. /// When the user does something new, it will clear out the redo stack.
  166. /// </summary>
  167. public void PushNewMemento(HistoryMemento value)
  168. {
  169. Utility.GCFullCollect();
  170. OnChanging();
  171. ClearRedoStack();
  172. undoStack.Add(value);
  173. OnNewHistoryMemento();
  174. OnChanged();
  175. value.Flush();
  176. Utility.GCFullCollect();
  177. }
  178. /// <summary>
  179. /// Takes one item from the redo stack, "redoes" it, then places the redo
  180. /// memento object to the top of the undo stack.
  181. /// </summary>
  182. public void StepForward()
  183. {
  184. PushExecutingMemento();
  185. try
  186. {
  187. StepForwardImpl();
  188. }
  189. finally
  190. {
  191. PopExecutingMemento();
  192. }
  193. }
  194. private void StepForwardImpl()
  195. {
  196. HistoryMemento topMemento = redoStack[0];
  197. ToolHistoryMemento asToolHistoryMemento = topMemento as ToolHistoryMemento;
  198. if (asToolHistoryMemento != null && asToolHistoryMemento.ToolType != this.documentWorkspace.GetToolType())
  199. {
  200. this.documentWorkspace.SetToolFromType(asToolHistoryMemento.ToolType);
  201. StepForward();
  202. }
  203. else
  204. {
  205. OnChanging();
  206. ExecutingHistoryMementoEventArgs ehaea1 = new ExecutingHistoryMementoEventArgs(topMemento, true, false);
  207. if (asToolHistoryMemento == null && topMemento.SeriesGuid != Guid.Empty)
  208. {
  209. ehaea1.SuspendTool = true;
  210. }
  211. OnExecutingHistoryMemento(ehaea1);
  212. if (ehaea1.SuspendTool)
  213. {
  214. this.documentWorkspace.PushNullTool();
  215. }
  216. HistoryMemento redoMemento = redoStack[0];
  217. // Possibly useful invariant here:
  218. // ehaea1.HistoryMemento.SeriesGuid == ehaea2.HistoryMemento.SeriesGuid == ehaea3.HistoryMemento.SeriesGuid
  219. ExecutingHistoryMementoEventArgs ehaea2 = new ExecutingHistoryMementoEventArgs(redoMemento, false, ehaea1.SuspendTool);
  220. OnExecutingHistoryMemento(ehaea2);
  221. HistoryMemento undoMemento = redoMemento.PerformUndo();
  222. redoStack.RemoveAt(0);
  223. undoStack.Add(undoMemento);
  224. ExecutedHistoryMementoEventArgs ehaea3 = new ExecutedHistoryMementoEventArgs(undoMemento);
  225. OnExecutedHistoryMemento(ehaea3);
  226. OnChanged();
  227. OnSteppedForward();
  228. undoMemento.Flush();
  229. if (ehaea1.SuspendTool)
  230. {
  231. this.documentWorkspace.PopNullTool();
  232. }
  233. }
  234. if (this.stepGroupDepth == 0)
  235. {
  236. OnFinishedStepGroup();
  237. }
  238. }
  239. /// <summary>
  240. /// Undoes the top of the undo stack, then places the redo memento object to the
  241. /// top of the redo stack.
  242. /// </summary>
  243. public void StepBackward()
  244. {
  245. PushExecutingMemento();
  246. try
  247. {
  248. StepBackwardImpl();
  249. }
  250. finally
  251. {
  252. PopExecutingMemento();
  253. }
  254. }
  255. private void StepBackwardImpl()
  256. {
  257. HistoryMemento topMemento = undoStack[undoStack.Count - 1];
  258. ToolHistoryMemento asToolHistoryMemento = topMemento as ToolHistoryMemento;
  259. if (asToolHistoryMemento != null && asToolHistoryMemento.ToolType != this.documentWorkspace.GetToolType())
  260. {
  261. this.documentWorkspace.SetToolFromType(asToolHistoryMemento.ToolType);
  262. StepBackward();
  263. }
  264. else
  265. {
  266. OnChanging();
  267. ExecutingHistoryMementoEventArgs ehaea1 = new ExecutingHistoryMementoEventArgs(topMemento, true, false);
  268. if (asToolHistoryMemento == null && topMemento.SeriesGuid == Guid.Empty)
  269. {
  270. ehaea1.SuspendTool = true;
  271. }
  272. OnExecutingHistoryMemento(ehaea1);
  273. if (ehaea1.SuspendTool)
  274. {
  275. this.documentWorkspace.PushNullTool();
  276. }
  277. HistoryMemento undoMemento = undoStack[undoStack.Count - 1];
  278. ExecutingHistoryMementoEventArgs ehaea2 = new ExecutingHistoryMementoEventArgs(undoMemento, false, ehaea1.SuspendTool);
  279. OnExecutingHistoryMemento(ehaea2);
  280. HistoryMemento redoMemento = undoStack[undoStack.Count - 1].PerformUndo();
  281. undoStack.RemoveAt(undoStack.Count - 1);
  282. redoStack.Insert(0, redoMemento);
  283. // Possibly useful invariant here:
  284. // ehaea1.HistoryMemento.SeriesGuid == ehaea2.HistoryMemento.SeriesGuid == ehaea3.HistoryMemento.SeriesGuid
  285. ExecutedHistoryMementoEventArgs ehaea3 = new ExecutedHistoryMementoEventArgs(redoMemento);
  286. OnExecutedHistoryMemento(ehaea3);
  287. OnChanged();
  288. OnSteppedBackward();
  289. redoMemento.Flush();
  290. if (ehaea1.SuspendTool)
  291. {
  292. this.documentWorkspace.PopNullTool();
  293. }
  294. }
  295. if (this.stepGroupDepth == 0)
  296. {
  297. OnFinishedStepGroup();
  298. }
  299. }
  300. public void ClearAll()
  301. {
  302. OnChanging();
  303. foreach (HistoryMemento ha in undoStack)
  304. {
  305. ha.Flush();
  306. }
  307. foreach (HistoryMemento ha in redoStack)
  308. {
  309. ha.Flush();
  310. }
  311. undoStack = new List<HistoryMemento>();
  312. redoStack = new List<HistoryMemento>();
  313. OnChanged();
  314. OnHistoryFlushed();
  315. }
  316. public void ClearRedoStack()
  317. {
  318. foreach (HistoryMemento ha in redoStack)
  319. {
  320. ha.Flush();
  321. }
  322. OnChanging();
  323. redoStack = new List<HistoryMemento>();
  324. OnChanged();
  325. }
  326. }
  327. }