* Copyright 2006-2007, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/
#include "CommandStack.h"
#include <stdio.h>
#include <string.h>
#include <Locker.h>
#include <String.h>
#include "Command.h"
CommandStack::CommandStack()
: BLocker("history"),
Observable(),
fSavedCommand(NULL)
{
}
CommandStack::~CommandStack()
{
Clear();
}
status_t
CommandStack::Perform(Command* command)
{
if (!Lock())
return B_ERROR;
status_t ret = command ? B_OK : B_BAD_VALUE;
if (ret == B_OK)
ret = command->InitCheck();
if (ret == B_OK)
ret = command->Perform();
if (ret == B_OK)
ret = _AddCommand(command);
if (ret != B_OK) {
delete command;
}
Unlock();
return ret;
}
status_t
CommandStack::Undo()
{
if (!Lock())
return B_ERROR;
status_t status = B_ERROR;
if (!fUndoHistory.empty()) {
Command* command = fUndoHistory.top();
fUndoHistory.pop();
status = command->Undo();
if (status == B_OK)
fRedoHistory.push(command);
else
fUndoHistory.push(command);
}
Unlock();
Notify();
return status;
}
status_t
CommandStack::Redo()
{
if (!Lock())
return B_ERROR;
status_t status = B_ERROR;
if (!fRedoHistory.empty()) {
Command* command = fRedoHistory.top();
fRedoHistory.pop();
status = command->Redo();
if (status == B_OK)
fUndoHistory.push(command);
else
fRedoHistory.push(command);
}
Unlock();
Notify();
return status;
}
bool
CommandStack::GetUndoName(BString& name)
{
bool success = false;
if (Lock()) {
if (!fUndoHistory.empty()) {
name << " ";
fUndoHistory.top()->GetName(name);
success = true;
}
Unlock();
}
return success;
}
bool
CommandStack::GetRedoName(BString& name)
{
bool success = false;
if (Lock()) {
if (!fRedoHistory.empty()) {
name << " ";
fRedoHistory.top()->GetName(name);
success = true;
}
Unlock();
}
return success;
}
void
CommandStack::Clear()
{
if (Lock()) {
while (!fUndoHistory.empty()) {
delete fUndoHistory.top();
fUndoHistory.pop();
}
while (!fRedoHistory.empty()) {
delete fRedoHistory.top();
fRedoHistory.pop();
}
Unlock();
}
Notify();
}
void
CommandStack::Save()
{
if (Lock()) {
if (!fUndoHistory.empty())
fSavedCommand = fUndoHistory.top();
Unlock();
}
Notify();
}
bool
CommandStack::IsSaved()
{
bool saved = false;
if (Lock()) {
saved = fUndoHistory.empty();
if (fSavedCommand && !saved) {
if (fSavedCommand == fUndoHistory.top())
saved = true;
}
Unlock();
}
return saved;
}
status_t
CommandStack::_AddCommand(Command* command)
{
status_t status = B_OK;
bool add = true;
if (!fUndoHistory.empty()) {
if (Command* top = fUndoHistory.top()) {
if (command->UndoesPrevious(top)) {
add = false;
fUndoHistory.pop();
delete top;
delete command;
} else if (top->CombineWithNext(command)) {
add = false;
delete command;
if (top->InitCheck() < B_OK) {
fUndoHistory.pop();
delete top;
}
} else if (command->CombineWithPrevious(top)) {
fUndoHistory.pop();
delete top;
if (command->InitCheck() < B_OK) {
delete command;
add = false;
}
}
}
}
if (add) {
try {
fUndoHistory.push(command);
} catch (...) {
status = B_ERROR;
}
}
if (status == B_OK) {
while (!fRedoHistory.empty()) {
delete fRedoHistory.top();
fRedoHistory.pop();
}
}
Notify();
return status;
}