diff options
Diffstat (limited to '')
-rw-r--r-- | src/composite-undo-stack-observer.cpp | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/src/composite-undo-stack-observer.cpp b/src/composite-undo-stack-observer.cpp new file mode 100644 index 0000000..e41d51a --- /dev/null +++ b/src/composite-undo-stack-observer.cpp @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Heavily inspired by Inkscape::XML::CompositeNodeObserver. + * + * Authors: + * David Yip <yipdw@rose-hulman.edu> + * + * Copyright (c) 2005 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <algorithm> + +#include "composite-undo-stack-observer.h" +#include "xml/event.h" + +namespace Inkscape { + +CompositeUndoStackObserver::CompositeUndoStackObserver() : _iterating(0) { } +CompositeUndoStackObserver::~CompositeUndoStackObserver() = default; + +void +CompositeUndoStackObserver::add(UndoStackObserver& observer) +{ + if (!this->_iterating) { + this->_active.push_back(UndoStackObserverRecord(observer)); + } else { + this->_pending.push_back(UndoStackObserverRecord(observer)); + } +} + +void +CompositeUndoStackObserver::remove(UndoStackObserver& observer) +{ + if (!this->_iterating) { + // logical-or operator short-circuits + this->_remove_one(this->_active, observer) || this->_remove_one(this->_pending, observer); + } else { + this->_mark_one(this->_active, observer) || this->_mark_one(this->_pending, observer); + } +} + +void +CompositeUndoStackObserver::notifyUndoEvent(Event* log) +{ + this->_lock(); + for (auto &i : _active) { + if (!i.to_remove) { + i.issueUndo(log); + } + } + this->_unlock(); +} + +void +CompositeUndoStackObserver::notifyRedoEvent(Event* log) +{ + + this->_lock(); + for (auto &i : _active) { + if (!i.to_remove) { + i.issueRedo(log); + } + } + this->_unlock(); +} + +void +CompositeUndoStackObserver::notifyUndoCommitEvent(Event* log) +{ + this->_lock(); + for (auto &i : _active) { + if (!i.to_remove) { + i.issueUndoCommit(log); + } + } + this->_unlock(); +} + +void +CompositeUndoStackObserver::notifyClearUndoEvent() +{ + this->_lock(); + for (auto &i : _active) { + if (!i.to_remove) { + i.issueClearUndo(); + } + } + this->_unlock(); +} + +void +CompositeUndoStackObserver::notifyClearRedoEvent() +{ + this->_lock(); + for (auto &i : _active) { + if (!i.to_remove) { + i.issueClearRedo(); + } + } + this->_unlock(); +} + +bool +CompositeUndoStackObserver::_remove_one(UndoObserverRecordList& list, UndoStackObserver& o) +{ + UndoStackObserverRecord eq_comp(o); + + auto i = std::find(list.begin(), list.end(), eq_comp); + + if (i != list.end()) { + list.erase(i); + return true; + } else { + return false; + } +} + +bool +CompositeUndoStackObserver::_mark_one(UndoObserverRecordList& list, UndoStackObserver& o) +{ + UndoStackObserverRecord eq_comp(o); + + auto i = std::find(list.begin(), list.end(), eq_comp); + + if (i != list.end()) { + i->to_remove = true; + return true; + } else { + return false; + } +} + +void +CompositeUndoStackObserver::_unlock() +{ + if (!--_iterating) { + // Remove marked observers + const auto pred = [](UndoStackObserverRecord const &i) -> bool { return i.to_remove; }; + + auto newEnd = std::remove_if(_active.begin(), _active.end(), pred); + _active.erase(newEnd, _active.end()); + + newEnd = std::remove_if(_pending.begin(), _pending.end(), pred); + _pending.erase(newEnd, _pending.end()); + + // Merge pending and active + _active.insert(_active.end(), _pending.begin(), _pending.end()); + _pending.clear(); + } +} + +} |