2 * Copyright (C) 2013 FooProject
\r
3 * * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
\r
4 * the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
\r
6 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
\r
9 You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
\r
12 using System.Collections.Generic;
\r
15 namespace FooEditEngine
\r
30 /// <param name="a"></param>
\r
31 /// <returns>マージできた場合は真、そうでない場合は偽を返す</returns>
\r
32 bool marge(ICommand a);
\r
34 /// コマンドを結合した結果が空なら真。そうでないなら偽を返す
\r
36 /// <returns></returns>
\r
41 sealed class BeginActionCommand : ICommand
\r
43 #region ICommand メンバー
\r
53 public bool marge(ICommand a)
\r
58 public bool isempty()
\r
65 sealed class EndActionCommand : ICommand
\r
67 #region ICommand メンバー
\r
77 public bool marge(ICommand a)
\r
82 public bool isempty()
\r
90 /// アンドゥバッファーを管理するクラス
\r
92 public sealed class UndoManager
\r
94 private bool locked = false;
\r
95 private Stack<ICommand> UndoStack = new Stack<ICommand>();
\r
96 private Stack<ICommand> RedoStack = new Stack<ICommand>();
\r
97 private int groupLevel = 0;
\r
102 internal UndoManager()
\r
104 this.Grouping = false;
\r
110 /// <param name="cmd">ICommandインターフェイス</param>
\r
111 internal void push(ICommand cmd)
\r
113 if (this.locked == true)
\r
115 ICommand last = null;
\r
116 if (this.AutoMerge && UndoStack.Count() > 0)
\r
117 last = UndoStack.First();
\r
118 if(last == null || last.marge(cmd) == false)
\r
119 UndoStack.Push(cmd);
\r
120 if (last != null && last.isempty())
\r
122 if (this.RedoStack.Count > 0)
\r
127 /// 履歴として残される操作が一連のグループとして追加されるなら真を返し、そうでなければ偽を返す
\r
129 internal bool Grouping
\r
137 /// アクションを結合するなら真。そうでないなら偽
\r
139 internal bool AutoMerge
\r
146 /// 一連のアンドゥアクションの開始を宣言します
\r
148 public void BeginUndoGroup()
\r
156 this.push(new BeginActionCommand());
\r
157 this.Grouping = true;
\r
158 this.AutoMerge = true;
\r
163 /// 一連のアンドゥアクションの終了を宣言します
\r
165 public void EndUndoGroup()
\r
167 if (this.Grouping == false)
\r
168 throw new InvalidOperationException("BeginUndoGroup()を呼び出してください");
\r
169 if (this.groupLevel > 0)
\r
175 ICommand last = UndoStack.First();
\r
176 if (last != null && last is BeginActionCommand)
\r
177 this.UndoStack.Pop();
\r
179 this.push(new EndActionCommand());
\r
180 this.Grouping = false;
\r
181 this.AutoMerge = false;
\r
190 if (this.UndoStack.Count == 0 || this.locked == true)
\r
194 bool isGrouped = false;
\r
198 cmd = this.UndoStack.Pop();
\r
199 this.RedoStack.Push(cmd);
\r
203 //アンドゥスタック上ではEndActionCommand,...,BeginActionCommandの順番になる
\r
204 if (cmd is EndActionCommand)
\r
206 else if (cmd is BeginActionCommand)
\r
208 } while (isGrouped);
\r
217 if (this.RedoStack.Count == 0 || this.locked == true)
\r
220 bool isGrouped = false;
\r
224 cmd = this.RedoStack.Pop();
\r
225 this.UndoStack.Push(cmd);
\r
229 //リドゥスタック上ではBeginActionCommand,...,EndActionCommandの順番になる
\r
230 if (cmd is BeginActionCommand)
\r
232 else if (cmd is EndActionCommand)
\r
234 } while (isGrouped);
\r
240 public void clear()
\r
242 if (this.locked == true)
\r
244 this.UndoStack.Clear();
\r
245 this.RedoStack.Clear();
\r
248 /// 以後の操作をアンドゥ不能にする
\r
250 public void BeginLock()
\r
252 this.locked = true;
\r
256 /// 以後の操作をアンドゥ可能にする
\r
258 public void EndLock()
\r
260 this.locked = false;
\r