btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / mediaplayer / support / CommandStack.cpp
blob4a57fa277e217f37a0ace3e9dfd1edd37dc1bdad
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"
18 #include "RWLocker.h"
20 // constructor
21 CommandStack::CommandStack(RWLocker* locker)
22 : Notifier()
23 , fLocker(locker)
24 , fSavedCommand(NULL)
28 // destructor
29 CommandStack::~CommandStack()
31 Clear();
34 // Perform
35 status_t
36 CommandStack::Perform(Command* command)
38 if (!fLocker->WriteLock())
39 return B_ERROR;
41 status_t ret = command ? B_OK : B_BAD_VALUE;
42 if (ret == B_OK)
43 ret = command->InitCheck();
45 if (ret == B_OK)
46 ret = command->Perform();
48 if (ret == B_OK)
49 ret = _AddCommand(command);
51 if (ret != B_OK) {
52 // no one else feels responsible...
53 delete command;
55 fLocker->WriteUnlock();
57 Notify();
59 return ret;
62 // Undo
63 status_t
64 CommandStack::Undo()
66 if (!fLocker->WriteLock())
67 return B_ERROR;
69 status_t status = B_ERROR;
70 if (!fUndoHistory.empty()) {
71 Command* command = fUndoHistory.top();
72 fUndoHistory.pop();
73 status = command->Undo();
74 if (status == B_OK)
75 fRedoHistory.push(command);
76 else
77 fUndoHistory.push(command);
79 fLocker->WriteUnlock();
81 Notify();
83 return status;
86 // Redo
87 status_t
88 CommandStack::Redo()
90 if (!fLocker->WriteLock())
91 return B_ERROR;
93 status_t status = B_ERROR;
94 if (!fRedoHistory.empty()) {
95 Command* command = fRedoHistory.top();
96 fRedoHistory.pop();
97 status = command->Redo();
98 if (status == B_OK)
99 fUndoHistory.push(command);
100 else
101 fRedoHistory.push(command);
103 fLocker->WriteUnlock();
105 Notify();
107 return status;
110 // UndoName
111 bool
112 CommandStack::GetUndoName(BString& name)
114 bool success = false;
115 if (fLocker->ReadLock()) {
116 if (!fUndoHistory.empty()) {
117 name << " ";
118 fUndoHistory.top()->GetName(name);
119 success = true;
121 fLocker->ReadUnlock();
123 return success;
126 // RedoName
127 bool
128 CommandStack::GetRedoName(BString& name)
130 bool success = false;
131 if (fLocker->ReadLock()) {
132 if (!fRedoHistory.empty()) {
133 name << " ";
134 fRedoHistory.top()->GetName(name);
135 success = true;
137 fLocker->ReadUnlock();
139 return success;
142 // Clear
143 void
144 CommandStack::Clear()
146 if (fLocker->WriteLock()) {
147 while (!fUndoHistory.empty()) {
148 delete fUndoHistory.top();
149 fUndoHistory.pop();
151 while (!fRedoHistory.empty()) {
152 delete fRedoHistory.top();
153 fRedoHistory.pop();
155 fLocker->WriteUnlock();
158 Notify();
161 // Save
162 void
163 CommandStack::Save()
165 if (fLocker->WriteLock()) {
166 if (!fUndoHistory.empty())
167 fSavedCommand = fUndoHistory.top();
168 fLocker->WriteUnlock();
171 Notify();
174 // IsSaved
175 bool
176 CommandStack::IsSaved()
178 bool saved = false;
179 if (fLocker->ReadLock()) {
180 saved = fUndoHistory.empty();
181 if (fSavedCommand && !saved) {
182 if (fSavedCommand == fUndoHistory.top())
183 saved = true;
185 fLocker->ReadUnlock();
187 return saved;
190 // #pragma mark -
192 // _AddCommand
193 status_t
194 CommandStack::_AddCommand(Command* command)
196 status_t status = B_OK;
198 bool add = true;
199 if (!fUndoHistory.empty()) {
200 // try to collapse commands to a single command
201 // or remove this and the previous command if
202 // they reverse each other
203 if (Command* top = fUndoHistory.top()) {
204 if (command->UndoesPrevious(top)) {
205 add = false;
206 fUndoHistory.pop();
207 delete top;
208 delete command;
209 } else if (top->CombineWithNext(command)) {
210 add = false;
211 delete command;
212 // after collapsing, the command might
213 // have changed it's mind about InitCheck()
214 // (the commands reversed each other)
215 if (top->InitCheck() < B_OK) {
216 fUndoHistory.pop();
217 delete top;
219 } else if (command->CombineWithPrevious(top)) {
220 fUndoHistory.pop();
221 delete top;
222 // after collapsing, the command might
223 // have changed it's mind about InitCheck()
224 // (the commands reversed each other)
225 if (command->InitCheck() < B_OK) {
226 delete command;
227 add = false;
232 if (add) {
233 try {
234 fUndoHistory.push(command);
235 } catch (...) {
236 status = B_ERROR;
240 if (status == B_OK) {
241 // the redo stack needs to be empty
242 // as soon as a command was added (also in case of collapsing)
243 while (!fRedoHistory.empty()) {
244 delete fRedoHistory.top();
245 fRedoHistory.pop();
249 return status;