1 /**
2 * Aggregates undo stack observers for convenient management and triggering in SPDocument
3 *
4 * Heavily inspired by Inkscape::XML::CompositeNodeObserver.
5 *
6 * Authors:
7 * David Yip <yipdw@rose-hulman.edu>
8 *
9 * Copyright (c) 2005 Authors
10 *
11 * Released under GNU GPL, read the file 'COPYING' for more information
12 */
15 #include "composite-undo-stack-observer.h"
16 #include "xml/event.h"
18 namespace Inkscape {
20 CompositeUndoStackObserver::CompositeUndoStackObserver() : _iterating(0) { }
21 CompositeUndoStackObserver::~CompositeUndoStackObserver() { }
23 void
24 CompositeUndoStackObserver::add(UndoStackObserver& observer)
25 {
26 if (!this->_iterating) {
27 this->_active.push_back(UndoStackObserverRecord(observer));
28 } else {
29 this->_pending.push_back(UndoStackObserverRecord(observer));
30 }
31 }
33 void
34 CompositeUndoStackObserver::remove(UndoStackObserver& observer)
35 {
36 if (!this->_iterating) {
37 // logical-or operator short-circuits
38 this->_remove_one(this->_active, observer) || this->_remove_one(this->_pending, observer);
39 } else {
40 this->_mark_one(this->_active, observer) || this->_mark_one(this->_pending, observer);
41 }
42 }
44 void
45 CompositeUndoStackObserver::notifyUndoEvent(XML::Event* log)
46 {
47 this->_lock();
48 for(UndoObserverRecordList::iterator i = this->_active.begin(); i != _active.end(); ++i) {
49 if (!i->to_remove) {
50 i->issueUndo(log);
51 }
52 }
53 this->_unlock();
54 }
56 void
57 CompositeUndoStackObserver::notifyRedoEvent(XML::Event* log)
58 {
60 this->_lock();
61 for(UndoObserverRecordList::iterator i = this->_active.begin(); i != _active.end(); ++i) {
62 if (!i->to_remove) {
63 i->issueRedo(log);
64 }
65 }
66 this->_unlock();
67 }
69 void
70 CompositeUndoStackObserver::notifyUndoCommitEvent(XML::Event* log)
71 {
72 this->_lock();
73 for(UndoObserverRecordList::iterator i = this->_active.begin(); i != _active.end(); ++i) {
74 if (!i->to_remove) {
75 i->issueUndoCommit(log);
76 }
77 }
78 this->_unlock();
79 }
81 bool
82 CompositeUndoStackObserver::_remove_one(UndoObserverRecordList& list, UndoStackObserver& o)
83 {
84 UndoStackObserverRecord eq_comp(o);
86 UndoObserverRecordList::iterator i = std::find_if(list.begin(), list.end(), std::bind1st(std::equal_to< UndoStackObserverRecord >(), eq_comp));
88 if (i != list.end()) {
89 list.erase(i);
90 return true;
91 } else {
92 return false;
93 }
94 }
96 bool
97 CompositeUndoStackObserver::_mark_one(UndoObserverRecordList& list, UndoStackObserver& o)
98 {
99 UndoStackObserverRecord eq_comp(o);
101 UndoObserverRecordList::iterator i = std::find_if(list.begin(), list.end(), std::bind1st(std::equal_to< UndoStackObserverRecord >(), eq_comp));
103 if (i != list.end()) {
104 (*i).to_remove = true;
105 return true;
106 } else {
107 return false;
108 }
109 }
111 void
112 CompositeUndoStackObserver::_unlock()
113 {
114 if (!--this->_iterating) {
115 // Remove marked observers
116 UndoObserverRecordList::iterator i = this->_active.begin();
117 for(; i != this->_active.begin(); i++) {
118 if (i->to_remove) {
119 this->_active.erase(i);
120 }
121 }
123 i = this->_pending.begin();
124 for(; i != this->_pending.begin(); i++) {
125 if (i->to_remove) {
126 this->_active.erase(i);
127 }
128 }
130 // Merge pending and active
131 this->_active.insert(this->_active.end(), this->_pending.begin(), this->_pending.end());
132 this->_pending.clear();
133 }
134 }
136 }