Code

3c46cb11e1ef0a8cf8d9966db156f42cdc23a930
[inkscape.git] / src / composite-undo-stack-observer.cpp
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(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(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(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         }
111 void
112 CompositeUndoStackObserver::_unlock()
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         }