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