HaikuDepot: notify work status from main window
[haiku.git] / src / apps / haikudepot / edits_generic / EditManager.cpp
blobb91f1954f0ab4892c76ac58f55eeec4c594d3b4c
1 /*
2 * Copyright 2006-2012, Stephan Aßmus <superstippi@gmx.de>
3 * Distributed under the terms of the MIT License.
4 */
6 #include "EditManager.h"
8 #include <stdio.h>
9 #include <string.h>
11 #include <Locker.h>
12 #include <String.h>
15 EditManager::Listener::~Listener()
20 EditManager::EditManager()
25 EditManager::~EditManager()
27 Clear();
31 status_t
32 EditManager::Perform(UndoableEdit* edit, EditContext& context)
34 if (edit == NULL)
35 return B_BAD_VALUE;
37 return Perform(UndoableEditRef(edit, true), context);
41 status_t
42 EditManager::Perform(const UndoableEditRef& edit, EditContext& context)
44 status_t ret = edit.Get() != NULL ? B_OK : B_BAD_VALUE;
45 if (ret == B_OK)
46 ret = edit->InitCheck();
48 if (ret == B_OK)
49 ret = edit->Perform(context);
51 if (ret == B_OK) {
52 ret = _AddEdit(edit);
53 if (ret != B_OK)
54 edit->Undo(context);
57 _NotifyListeners();
59 return ret;
63 status_t
64 EditManager::Undo(EditContext& context)
66 status_t status = B_ERROR;
67 if (!fUndoHistory.IsEmpty()) {
68 UndoableEditRef edit(fUndoHistory.Top());
69 fUndoHistory.Pop();
70 status = edit->Undo(context);
71 if (status == B_OK)
72 fRedoHistory.Push(edit);
73 else
74 fUndoHistory.Push(edit);
77 _NotifyListeners();
79 return status;
83 status_t
84 EditManager::Redo(EditContext& context)
86 status_t status = B_ERROR;
87 if (!fRedoHistory.IsEmpty()) {
88 UndoableEditRef edit(fRedoHistory.Top());
89 fRedoHistory.Pop();
90 status = edit->Redo(context);
91 if (status == B_OK)
92 fUndoHistory.Push(edit);
93 else
94 fRedoHistory.Push(edit);
97 _NotifyListeners();
99 return status;
103 bool
104 EditManager::GetUndoName(BString& name)
106 if (!fUndoHistory.IsEmpty()) {
107 name << " ";
108 fUndoHistory.Top()->GetName(name);
109 return true;
111 return false;
115 bool
116 EditManager::GetRedoName(BString& name)
118 if (!fRedoHistory.IsEmpty()) {
119 name << " ";
120 fRedoHistory.Top()->GetName(name);
121 return true;
123 return false;
127 void
128 EditManager::Clear()
130 while (!fUndoHistory.IsEmpty())
131 fUndoHistory.Pop();
132 while (!fRedoHistory.IsEmpty())
133 fRedoHistory.Pop();
135 _NotifyListeners();
139 void
140 EditManager::Save()
142 if (!fUndoHistory.IsEmpty())
143 fEditAtSave = fUndoHistory.Top();
145 _NotifyListeners();
149 bool
150 EditManager::IsSaved()
152 bool saved = fUndoHistory.IsEmpty();
153 if (fEditAtSave.Get() != NULL && !saved) {
154 if (fEditAtSave == fUndoHistory.Top())
155 saved = true;
157 return saved;
161 // #pragma mark -
164 bool
165 EditManager::AddListener(Listener* listener)
167 return fListeners.Add(listener);
171 void
172 EditManager::RemoveListener(Listener* listener)
174 fListeners.Remove(listener);
178 // #pragma mark -
181 status_t
182 EditManager::_AddEdit(const UndoableEditRef& edit)
184 status_t status = B_OK;
186 bool add = true;
187 if (!fUndoHistory.IsEmpty()) {
188 // Try to collapse edits to a single edit
189 // or remove this and the previous edit if
190 // they reverse each other
191 const UndoableEditRef& top = fUndoHistory.Top();
192 if (edit->UndoesPrevious(top.Get())) {
193 add = false;
194 fUndoHistory.Pop();
195 } else if (top->CombineWithNext(edit.Get())) {
196 add = false;
197 // After collapsing, the edit might
198 // have changed it's mind about InitCheck()
199 // (the commands reversed each other)
200 if (top->InitCheck() != B_OK) {
201 fUndoHistory.Pop();
203 } else if (edit->CombineWithPrevious(top.Get())) {
204 fUndoHistory.Pop();
205 // After collapsing, the edit might
206 // have changed it's mind about InitCheck()
207 // (the commands reversed each other)
208 if (edit->InitCheck() != B_OK) {
209 add = false;
213 if (add) {
214 if (!fUndoHistory.Push(edit))
215 status = B_NO_MEMORY;
218 if (status == B_OK) {
219 // The redo stack needs to be empty
220 // as soon as an edit was added (also in case of collapsing)
221 while (!fRedoHistory.IsEmpty()) {
222 fRedoHistory.Pop();
226 return status;
230 void
231 EditManager::_NotifyListeners()
233 int32 count = fListeners.CountItems();
234 if (count == 0)
235 return;
236 // Iterate a copy of the list, so we don't crash if listeners
237 // detach themselves while being notified.
238 ListenerList listenersCopy(fListeners);
239 if (listenersCopy.CountItems() != count)
240 return;
241 for (int32 i = 0; i < count; i++)
242 listenersCopy.ItemAtFast(i)->EditManagerChanged(this);