diff options
Diffstat (limited to '')
-rw-r--r-- | src/composite-undo-stack-observer.cpp | 167 |
1 files changed, 167 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..0f66c65 --- /dev/null +++ b/src/composite-undo-stack-observer.cpp @@ -0,0 +1,167 @@ +// 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 <functional> + +#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(UndoObserverRecordList::iterator i = this->_active.begin(); i != _active.end(); ++i) { + if (!i->to_remove) { + i->issueUndo(log); + } + } + this->_unlock(); +} + +void +CompositeUndoStackObserver::notifyRedoEvent(Event* log) +{ + + this->_lock(); + for(UndoObserverRecordList::iterator i = this->_active.begin(); i != _active.end(); ++i) { + if (!i->to_remove) { + i->issueRedo(log); + } + } + this->_unlock(); +} + +void +CompositeUndoStackObserver::notifyUndoCommitEvent(Event* log) +{ + this->_lock(); + for(UndoObserverRecordList::iterator i = this->_active.begin(); i != _active.end(); ++i) { + if (!i->to_remove) { + i->issueUndoCommit(log); + } + } + this->_unlock(); +} + +void +CompositeUndoStackObserver::notifyClearUndoEvent() +{ + this->_lock(); + for(UndoObserverRecordList::iterator i = this->_active.begin(); i != _active.end(); ++i) { + if (!i->to_remove) { + i->issueClearUndo(); + } + } + this->_unlock(); +} + +void +CompositeUndoStackObserver::notifyClearRedoEvent() +{ + this->_lock(); + for(UndoObserverRecordList::iterator i = this->_active.begin(); i != _active.end(); ++i) { + if (!i->to_remove) { + i->issueClearRedo(); + } + } + this->_unlock(); +} + +bool +CompositeUndoStackObserver::_remove_one(UndoObserverRecordList& list, UndoStackObserver& o) +{ + UndoStackObserverRecord eq_comp(o); + + UndoObserverRecordList::iterator i = std::find_if(list.begin(), list.end(), std::bind(std::equal_to< UndoStackObserverRecord >(), std::placeholders::_1, 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); + + UndoObserverRecordList::iterator i = std::find_if(list.begin(), list.end(), std::bind(std::equal_to< UndoStackObserverRecord >(), std::placeholders::_1, eq_comp)); + + if (i != list.end()) { + (*i).to_remove = true; + return true; + } else { + return false; + } +} + +void +CompositeUndoStackObserver::_unlock() +{ + if (!--this->_iterating) { + // Remove marked observers + UndoObserverRecordList::iterator i = this->_active.begin(); + for(; i != this->_active.begin(); ) { + if (i->to_remove) { + i = this->_active.erase(i); + } + else{ + ++i; + } + } + + i = this->_pending.begin(); + for(; i != this->_pending.begin(); ) { + if (i->to_remove) { + i = this->_active.erase(i); + } + else { + ++i; + } + } + + // Merge pending and active + this->_active.insert(this->_active.end(), this->_pending.begin(), this->_pending.end()); + this->_pending.clear(); + } +} + +} |