PageRenderTime 57ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/src/HistoryStack.cs

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