Code

Merge and cleanup of GSoC C++-ification project.
[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  */
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();
106 bool
107 CompositeUndoStackObserver::_remove_one(UndoObserverRecordList& list, UndoStackObserver& o)
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         }
121 bool
122 CompositeUndoStackObserver::_mark_one(UndoObserverRecordList& list, UndoStackObserver& o)
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         }
136 void
137 CompositeUndoStackObserver::_unlock()
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         }