* Copyright 2006-2012, Stephan Aßmus <superstippi@gmx.de>
* Copyright 2021, Andrew Lindesay <apl@lindesay.co.nz>
* Distributed under the terms of the MIT License.
*/
#include "EditManager.h"
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <Locker.h>
#include <String.h>
EditManager::Listener::~Listener()
{
}
EditManager::EditManager()
{
}
EditManager::~EditManager()
{
Clear();
}
status_t
EditManager::Perform(UndoableEdit* edit, EditContext& context)
{
if (edit == NULL)
return B_BAD_VALUE;
return Perform(UndoableEditRef(edit, true), context);
}
status_t
EditManager::Perform(const UndoableEditRef& edit, EditContext& context)
{
status_t ret = edit.IsSet() ? B_OK : B_BAD_VALUE;
if (ret == B_OK)
ret = edit->InitCheck();
if (ret == B_OK)
ret = edit->Perform(context);
if (ret == B_OK) {
ret = _AddEdit(edit);
if (ret != B_OK)
edit->Undo(context);
}
_NotifyListeners();
return ret;
}
status_t
EditManager::Undo(EditContext& context)
{
status_t status = B_ERROR;
if (!fUndoHistory.empty()) {
UndoableEditRef edit(fUndoHistory.top());
fUndoHistory.pop();
status = edit->Undo(context);
if (status == B_OK)
fRedoHistory.push(edit);
else
fUndoHistory.push(edit);
}
_NotifyListeners();
return status;
}
status_t
EditManager::Redo(EditContext& context)
{
status_t status = B_ERROR;
if (!fRedoHistory.empty()) {
UndoableEditRef edit(fRedoHistory.top());
fRedoHistory.pop();
status = edit->Redo(context);
if (status == B_OK)
fUndoHistory.push(edit);
else
fRedoHistory.push(edit);
}
_NotifyListeners();
return status;
}
bool
EditManager::GetUndoName(BString& name)
{
if (!fUndoHistory.empty()) {
name << " ";
fUndoHistory.top()->GetName(name);
return true;
}
return false;
}
bool
EditManager::GetRedoName(BString& name)
{
if (!fRedoHistory.empty()) {
name << " ";
fRedoHistory.top()->GetName(name);
return true;
}
return false;
}
void
EditManager::Clear()
{
while (!fUndoHistory.empty())
fUndoHistory.pop();
while (!fRedoHistory.empty())
fRedoHistory.pop();
_NotifyListeners();
}
void
EditManager::Save()
{
if (!fUndoHistory.empty())
fEditAtSave = fUndoHistory.top();
_NotifyListeners();
}
bool
EditManager::IsSaved()
{
bool saved = fUndoHistory.empty();
if (fEditAtSave.IsSet() && !saved) {
if (fEditAtSave == fUndoHistory.top())
saved = true;
}
return saved;
}
void
EditManager::AddListener(Listener* listener)
{
return fListeners.push_back(listener);
}
void
EditManager::RemoveListener(Listener* listener)
{
fListeners.erase(std::remove(fListeners.begin(), fListeners.end(),
listener), fListeners.end());
}
status_t
EditManager::_AddEdit(const UndoableEditRef& edit)
{
status_t status = B_OK;
bool add = true;
if (!fUndoHistory.empty()) {
const UndoableEditRef& top = fUndoHistory.top();
if (edit->UndoesPrevious(top.Get())) {
add = false;
fUndoHistory.pop();
} else if (top->CombineWithNext(edit.Get())) {
add = false;
if (top->InitCheck() != B_OK) {
fUndoHistory.pop();
}
} else if (edit->CombineWithPrevious(top.Get())) {
fUndoHistory.pop();
if (edit->InitCheck() != B_OK) {
add = false;
}
}
}
if (add)
fUndoHistory.push(edit);
if (status == B_OK) {
while (!fRedoHistory.empty()) {
fRedoHistory.pop();
}
}
return status;
}
void
EditManager::_NotifyListeners()
{
std::vector<Listener*> listeners(fListeners);
std::vector<Listener*>::const_iterator it;
for (it = listeners.begin(); it != listeners.end(); it++) {
Listener* listener = *it;
listener->EditManagerChanged(this);
}
}