// SPDX-License-Identifier: GPL-2.0-or-later /* * Heavily inspired by Inkscape::XML::CompositeNodeObserver. * * Authors: * David Yip * * Copyright (c) 2005 Authors * * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ #include #include #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(); } } }