CraftSynth.ImageEditor – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | using System; |
2 | using System.Collections.Generic; |
||
3 | |||
4 | /// Undo-Redo code is written using the article: |
||
5 | /// http://www.codeproject.com/cs/design/commandpatterndemo.asp |
||
6 | // The Command Pattern and MVC Architecture |
||
7 | // By David Veeneman. |
||
8 | namespace CraftSynth.ImageEditor |
||
9 | { |
||
10 | /// <summary> |
||
11 | /// Class is responsible for executing Undo - Redo operations |
||
12 | /// </summary> |
||
13 | internal class UndoManager:IDisposable |
||
14 | { |
||
15 | #region Class Members |
||
16 | private Layers layers; |
||
17 | |||
18 | private List<Command> historyList; |
||
19 | private int nextUndo; |
||
20 | #endregion Class Members |
||
21 | |||
22 | #region Constructor |
||
23 | public UndoManager(Layers layerList) |
||
24 | { |
||
25 | layers = layerList; |
||
26 | |||
27 | ClearHistory(); |
||
28 | } |
||
29 | #endregion Constructor |
||
30 | |||
31 | #region Destruction |
||
32 | public void Dispose() |
||
33 | { |
||
34 | this.Dispose(true); |
||
35 | GC.SuppressFinalize(this); |
||
36 | } |
||
37 | |||
38 | private bool _disposed = false; |
||
39 | |||
40 | protected void Dispose(bool disposing) |
||
41 | { |
||
42 | if (!this._disposed) |
||
43 | { |
||
44 | if (disposing) |
||
45 | { |
||
46 | // Free any managed objects here. |
||
47 | if (this.historyList != null) |
||
48 | { |
||
49 | foreach (Command command in this.historyList) |
||
50 | { |
||
51 | if (command != null) |
||
52 | { |
||
53 | command.Dispose(); |
||
54 | } |
||
55 | } |
||
56 | } |
||
57 | if (this.layers != null) |
||
58 | { |
||
59 | for (int i = 0; i < this.layers.Count; i++) |
||
60 | { |
||
61 | if (this.layers[i] != null) |
||
62 | { |
||
63 | this.layers[i].Dispose(); |
||
64 | } |
||
65 | } |
||
66 | } |
||
67 | } |
||
68 | |||
69 | // Free any unmanaged objects here. |
||
70 | |||
71 | this._disposed = true; |
||
72 | } |
||
73 | } |
||
74 | |||
75 | ~UndoManager() |
||
76 | { |
||
77 | this.Dispose(false); |
||
78 | } |
||
79 | #endregion |
||
80 | |||
81 | #region Properties |
||
82 | /// <summary> |
||
83 | /// Return true if Undo operation is available |
||
84 | /// </summary> |
||
85 | public bool CanUndo |
||
86 | { |
||
87 | get |
||
88 | { |
||
89 | // If the NextUndo pointer is -1, no commands to undo |
||
90 | if (nextUndo < 0 || |
||
91 | nextUndo > historyList.Count - 1) // precaution |
||
92 | { |
||
93 | return false; |
||
94 | } |
||
95 | |||
96 | return true; |
||
97 | } |
||
98 | } |
||
99 | |||
100 | /// <summary> |
||
101 | /// Return true if Redo operation is available |
||
102 | /// </summary> |
||
103 | public bool CanRedo |
||
104 | { |
||
105 | get |
||
106 | { |
||
107 | // If the NextUndo pointer points to the last item, no commands to redo |
||
108 | if (nextUndo == historyList.Count - 1) |
||
109 | { |
||
110 | return false; |
||
111 | } |
||
112 | |||
113 | return true; |
||
114 | } |
||
115 | } |
||
116 | #endregion Properties |
||
117 | |||
118 | #region Public Functions |
||
119 | /// <summary> |
||
120 | /// Clear History |
||
121 | /// </summary> |
||
122 | public void ClearHistory() |
||
123 | { |
||
124 | if (this.historyList != null) |
||
125 | { |
||
126 | foreach (Command command in historyList) |
||
127 | { |
||
128 | if (command != null) |
||
129 | { |
||
130 | command.Dispose(); |
||
131 | } |
||
132 | } |
||
133 | } |
||
134 | historyList = new List<Command>(); |
||
135 | nextUndo = -1; |
||
136 | } |
||
137 | |||
138 | /// <summary> |
||
139 | /// Add new command to history. |
||
140 | /// Called by client after executing some action. |
||
141 | /// </summary> |
||
142 | /// <param name="command"></param> |
||
143 | public void AddCommandToHistory(Command command) |
||
144 | { |
||
145 | // Purge history list |
||
146 | TrimHistoryList(); |
||
147 | |||
148 | // Add command and increment undo counter |
||
149 | historyList.Add(command); |
||
150 | |||
151 | nextUndo++; |
||
152 | } |
||
153 | |||
154 | /// <summary> |
||
155 | /// Undo |
||
156 | /// </summary> |
||
157 | public void Undo() |
||
158 | { |
||
159 | if (!CanUndo) |
||
160 | { |
||
161 | return; |
||
162 | } |
||
163 | |||
164 | // Get the Command object to be undone |
||
165 | Command command = historyList[nextUndo]; |
||
166 | |||
167 | // Execute the Command object's undo method |
||
168 | command.Undo(layers); |
||
169 | |||
170 | // Move the pointer up one item |
||
171 | nextUndo--; |
||
172 | } |
||
173 | |||
174 | /// <summary> |
||
175 | /// Redo |
||
176 | /// </summary> |
||
177 | public void Redo() |
||
178 | { |
||
179 | if (!CanRedo) |
||
180 | { |
||
181 | return; |
||
182 | } |
||
183 | |||
184 | // Get the Command object to redo |
||
185 | int itemToRedo = nextUndo + 1; |
||
186 | Command command = historyList[itemToRedo]; |
||
187 | |||
188 | // Execute the Command object |
||
189 | command.Redo(layers); |
||
190 | |||
191 | // Move the undo pointer down one item |
||
192 | nextUndo++; |
||
193 | } |
||
194 | #endregion Public Functions |
||
195 | |||
196 | #region Private Functions |
||
197 | private void TrimHistoryList() |
||
198 | { |
||
199 | // We can redo any undone command until we execute a new |
||
200 | // command. The new command takes us off in a new direction, |
||
201 | // which means we can no longer redo previously undone actions. |
||
202 | // So, we purge all undone commands from the history list.*/ |
||
203 | |||
204 | // Exit if no items in History list |
||
205 | if (historyList.Count == 0) |
||
206 | { |
||
207 | return; |
||
208 | } |
||
209 | |||
210 | // Exit if NextUndo points to last item on the list |
||
211 | if (nextUndo == historyList.Count - 1) |
||
212 | { |
||
213 | return; |
||
214 | } |
||
215 | |||
216 | // Purge all items below the NextUndo pointer |
||
217 | for (int i = historyList.Count - 1; i > nextUndo; i--) |
||
218 | { |
||
219 | historyList.RemoveAt(i); |
||
220 | } |
||
221 | } |
||
222 | #endregion |
||
223 | } |
||
224 | } |