HaikuDepot: notify work status from main window
[haiku.git] / src / apps / icon-o-matic / generic / command / CommandStack.cpp
blobf257268916f8ce5c3722dee514002f58e8c56356
1 /*
2 * Copyright 2006-2007, Haiku.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Stephan Aßmus <superstippi@gmx.de>
7 */
9 #include "CommandStack.h"
11 #include <stdio.h>
12 #include <string.h>
14 #include <Locker.h>
15 #include <String.h>
17 #include "Command.h"
19 // constructor
20 CommandStack::CommandStack()
21 : BLocker("history"),
22 Observable(),
23 fSavedCommand(NULL)
27 // destructor
28 CommandStack::~CommandStack()
30 Clear();
33 // Perform
34 status_t
35 CommandStack::Perform(Command* command)
37 if (!Lock())
38 return B_ERROR;
40 status_t ret = command ? B_OK : B_BAD_VALUE;
41 if (ret == B_OK)
42 ret = command->InitCheck();
44 if (ret == B_OK)
45 ret = command->Perform();
47 if (ret == B_OK)
48 ret = _AddCommand(command);
50 if (ret != B_OK) {
51 // no one else feels responsible...
52 delete command;
55 Unlock();
56 return ret;
59 // Undo
60 status_t
61 CommandStack::Undo()
63 if (!Lock())
64 return B_ERROR;
66 status_t status = B_ERROR;
67 if (!fUndoHistory.empty()) {
68 Command* command = fUndoHistory.top();
69 fUndoHistory.pop();
70 status = command->Undo();
71 if (status == B_OK)
72 fRedoHistory.push(command);
73 else
74 fUndoHistory.push(command);
76 Unlock();
78 Notify();
80 return status;
83 // Redo
84 status_t
85 CommandStack::Redo()
87 if (!Lock())
88 return B_ERROR;
90 status_t status = B_ERROR;
91 if (!fRedoHistory.empty()) {
92 Command* command = fRedoHistory.top();
93 fRedoHistory.pop();
94 status = command->Redo();
95 if (status == B_OK)
96 fUndoHistory.push(command);
97 else
98 fRedoHistory.push(command);
100 Unlock();
102 Notify();
104 return status;
107 // UndoName
108 bool
109 CommandStack::GetUndoName(BString& name)
111 bool success = false;
112 if (Lock()) {
113 if (!fUndoHistory.empty()) {
114 name << " ";
115 fUndoHistory.top()->GetName(name);
116 success = true;
118 Unlock();
120 return success;
123 // RedoName
124 bool
125 CommandStack::GetRedoName(BString& name)
127 bool success = false;
128 if (Lock()) {
129 if (!fRedoHistory.empty()) {
130 name << " ";
131 fRedoHistory.top()->GetName(name);
132 success = true;
134 Unlock();
136 return success;
139 // Clear
140 void
141 CommandStack::Clear()
143 if (Lock()) {
144 while (!fUndoHistory.empty()) {
145 delete fUndoHistory.top();
146 fUndoHistory.pop();
148 while (!fRedoHistory.empty()) {
149 delete fRedoHistory.top();
150 fRedoHistory.pop();
152 Unlock();
155 Notify();
158 // Save
159 void
160 CommandStack::Save()
162 if (Lock()) {
163 if (!fUndoHistory.empty())
164 fSavedCommand = fUndoHistory.top();
165 Unlock();
168 Notify();
171 // IsSaved
172 bool
173 CommandStack::IsSaved()
175 bool saved = false;
176 if (Lock()) {
177 saved = fUndoHistory.empty();
178 if (fSavedCommand && !saved) {
179 if (fSavedCommand == fUndoHistory.top())
180 saved = true;
182 Unlock();
184 return saved;
187 // #pragma mark -
189 // _AddCommand
190 status_t
191 CommandStack::_AddCommand(Command* command)
193 status_t status = B_OK;
195 bool add = true;
196 if (!fUndoHistory.empty()) {
197 // try to collapse commands to a single command
198 // or remove this and the previous command if
199 // they reverse each other
200 if (Command* top = fUndoHistory.top()) {
201 if (command->UndoesPrevious(top)) {
202 add = false;
203 fUndoHistory.pop();
204 delete top;
205 delete command;
206 } else if (top->CombineWithNext(command)) {
207 add = false;
208 delete command;
209 // after collapsing, the command might
210 // have changed it's mind about InitCheck()
211 // (the commands reversed each other)
212 if (top->InitCheck() < B_OK) {
213 fUndoHistory.pop();
214 delete top;
216 } else if (command->CombineWithPrevious(top)) {
217 fUndoHistory.pop();
218 delete top;
219 // after collapsing, the command might
220 // have changed it's mind about InitCheck()
221 // (the commands reversed each other)
222 if (command->InitCheck() < B_OK) {
223 delete command;
224 add = false;
229 if (add) {
230 try {
231 fUndoHistory.push(command);
232 } catch (...) {
233 status = B_ERROR;
237 if (status == B_OK) {
238 // the redo stack needs to be empty
239 // as soon as a command was added (also in case of collapsing)
240 while (!fRedoHistory.empty()) {
241 delete fRedoHistory.top();
242 fRedoHistory.pop();
246 Notify();
248 return status;