summaryrefslogtreecommitdiffstats
path: root/src/composite-undo-stack-observer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/composite-undo-stack-observer.cpp')
-rw-r--r--src/composite-undo-stack-observer.cpp167
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();
+ }
+}
+
+}