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 */
14 #include <algorithm>
16 #include "composite-undo-stack-observer.h"
17 #include "xml/event.h"
19 namespace Inkscape {
21 CompositeUndoStackObserver::CompositeUndoStackObserver() : _iterating(0) { }
22 CompositeUndoStackObserver::~CompositeUndoStackObserver() { }
24 void
25 CompositeUndoStackObserver::add(UndoStackObserver& observer)
26 {
27 if (!this->_iterating) {
28 this->_active.push_back(UndoStackObserverRecord(observer));
29 } else {
30 this->_pending.push_back(UndoStackObserverRecord(observer));
31 }
32 }
34 void
35 CompositeUndoStackObserver::remove(UndoStackObserver& observer)
36 {
37 if (!this->_iterating) {
38 // logical-or operator short-circuits
39 this->_remove_one(this->_active, observer) || this->_remove_one(this->_pending, observer);
40 } else {
41 this->_mark_one(this->_active, observer) || this->_mark_one(this->_pending, observer);
42 }
43 }
45 void
46 CompositeUndoStackObserver::notifyUndoEvent(Event* log)
47 {
48 this->_lock();
49 for(UndoObserverRecordList::iterator i = this->_active.begin(); i != _active.end(); ++i) {
50 if (!i->to_remove) {
51 i->issueUndo(log);
52 }
53 }
54 this->_unlock();
55 }
57 void
58 CompositeUndoStackObserver::notifyRedoEvent(Event* log)
59 {
61 this->_lock();
62 for(UndoObserverRecordList::iterator i = this->_active.begin(); i != _active.end(); ++i) {
63 if (!i->to_remove) {
64 i->issueRedo(log);
65 }
66 }
67 this->_unlock();
68 }
70 void
71 CompositeUndoStackObserver::notifyUndoCommitEvent(Event* log)
72 {
73 this->_lock();
74 for(UndoObserverRecordList::iterator i = this->_active.begin(); i != _active.end(); ++i) {
75 if (!i->to_remove) {
76 i->issueUndoCommit(log);
77 }
78 }
79 this->_unlock();
80 }
82 void
83 CompositeUndoStackObserver::notifyClearUndoEvent()
84 {
85 this->_lock();
86 for(UndoObserverRecordList::iterator i = this->_active.begin(); i != _active.end(); ++i) {
87 if (!i->to_remove) {
88 i->issueClearUndo();
89 }
90 }
91 this->_unlock();
92 }
94 void
95 CompositeUndoStackObserver::notifyClearRedoEvent()
96 {
97 this->_lock();
98 for(UndoObserverRecordList::iterator i = this->_active.begin(); i != _active.end(); ++i) {
99 if (!i->to_remove) {
100 i->issueClearRedo();
101 }
102 }
103 this->_unlock();
104 }
106 bool
107 CompositeUndoStackObserver::_remove_one(UndoObserverRecordList& list, UndoStackObserver& o)
108 {
109 UndoStackObserverRecord eq_comp(o);
111 UndoObserverRecordList::iterator i = std::find_if(list.begin(), list.end(), std::bind1st(std::equal_to< UndoStackObserverRecord >(), eq_comp));
113 if (i != list.end()) {
114 list.erase(i);
115 return true;
116 } else {
117 return false;
118 }
119 }
121 bool
122 CompositeUndoStackObserver::_mark_one(UndoObserverRecordList& list, UndoStackObserver& o)
123 {
124 UndoStackObserverRecord eq_comp(o);
126 UndoObserverRecordList::iterator i = std::find_if(list.begin(), list.end(), std::bind1st(std::equal_to< UndoStackObserverRecord >(), eq_comp));
128 if (i != list.end()) {
129 (*i).to_remove = true;
130 return true;
131 } else {
132 return false;
133 }
134 }
136 void
137 CompositeUndoStackObserver::_unlock()
138 {
139 if (!--this->_iterating) {
140 // Remove marked observers
141 UndoObserverRecordList::iterator i = this->_active.begin();
142 for(; i != this->_active.begin(); i++) {
143 if (i->to_remove) {
144 this->_active.erase(i);
145 }
146 }
148 i = this->_pending.begin();
149 for(; i != this->_pending.begin(); i++) {
150 if (i->to_remove) {
151 this->_active.erase(i);
152 }
153 }
155 // Merge pending and active
156 this->_active.insert(this->_active.end(), this->_pending.begin(), this->_pending.end());
157 this->_pending.clear();
158 }
159 }
161 }