Code

Super duper mega (fun!) commit: replaced encoding=utf-8 with fileencoding=utf-8 in...
[inkscape.git] / src / xml / event.h
1 /** @file
2  * @brief Event object representing a change of the XML document
3  */
4 /* Authors:
5  *   Unknown author(s)
6  *   Krzysztof KosiƄski <tweenk.pl@gmail.com> (documentation)
7  *
8  * Copyright 2008 Authors
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * See the file COPYING for details.
16  */
18 #ifndef SEEN_INKSCAPE_XML_SP_REPR_ACTION_H
19 #define SEEN_INKSCAPE_XML_SP_REPR_ACTION_H
21 #include <glib/gtypes.h>
22 #include <glib/gquark.h>
23 #include <glibmm/ustring.h>
25 #include <iterator>
26 #include "util/share.h"
27 #include "util/forward-pointer-iterator.h"
28 #include "gc-managed.h"
29 #include "xml/xml-forward.h"
30 #include "xml/node.h"
32 namespace Inkscape {
33 namespace XML {
35 /**
36  * @brief Enumeration of all XML event types
37  */
38 enum EventType {
39     EVENT_ADD, ///< Child added
40     EVENT_DEL, ///< Child removed
41     EVENT_CHG_ATTR, ///< Attribute changed
42     EVENT_CHG_CONTENT, ///< Content changed
43     EVENT_CHG_ORDER ///< Order of children changed
44 };
46 /**
47  * @brief Generic XML modification event
48  *
49  * This is the base class for all other modification events. It is actually a singly-linked
50  * list of events, called an event chain or an event log. Logs of events that happened
51  * in a transaction can be obtained from Document::commitUndoable(). Events can be replayed
52  * to a NodeObserver, or undone (which is equivalent to replaying opposite events in reverse
53  * order).
54  *
55  * Event logs are built by appending to the front, so by walking the list one iterates over
56  * the events in reverse chronological order.
57  */
58 class Event
59 : public Inkscape::GC::Managed<Inkscape::GC::SCANNED, Inkscape::GC::MANUAL>
60 {
61 public:        
62     virtual ~Event() {}
64     /**
65      * @brief Pointer to the next event in the event chain
66      * 
67      * Note that the event this pointer points to actually happened before this event.
68      * This is because the event log is built by appending to the front.
69      */
70     Event *next;
71     /**
72      * @brief Serial number of the event, not used at the moment
73      */
74     int serial;
75     /**
76      * @brief Pointer to the node that was the object of the event
77      *
78      * Because the nodes are garbage-collected, this pointer guarantees that the node
79      * will stay in memory as long as the event does. This simplifies rolling back
80      * extensive deletions.
81      */
82     Node *repr;
84     struct IteratorStrategy {
85         static Event const *next(Event const *action) {
86             return action->next;
87         }
88     };
90     typedef Inkscape::Util::ForwardPointerIterator<Event, IteratorStrategy> Iterator;
91     typedef Inkscape::Util::ForwardPointerIterator<Event const, IteratorStrategy> ConstIterator;
93     /**
94      * @brief If possible, combine this event with the next to reduce memory use
95      * @return Pointer to the optimized event chain, which may have changed
96      */
97     Event *optimizeOne() { return _optimizeOne(); }
98     /**
99      * @brief Undo this event to an observer
100      *
101      * This method notifies the specified observer of an action opposite to the one that
102      * is described by this event.
103      */
104     void undoOne(NodeObserver &observer) const {
105         _undoOne(observer);
106     }
107     /**
108      * @brief Replay this event to an observer
109      *
110      * This method notifies the specified event of the same action that it describes.
111      */
112     void replayOne(NodeObserver &observer) const {
113         _replayOne(observer);
114     }
116 protected:
117     Event(Node *r, Event *n)
118     : next(n), serial(_next_serial++), repr(r) {}
120     virtual Event *_optimizeOne()=0;
121     virtual void _undoOne(NodeObserver &) const=0;
122     virtual void _replayOne(NodeObserver &) const=0;
124 private:
125     static int _next_serial;
126 };
128 /**
129  * @brief Object representing child addition
130  */
131 class EventAdd : public Event {
132 public:
133     EventAdd(Node *repr, Node *c, Node *rr, Event *next)
134     : Event(repr, next), child(c), ref(rr) {}
136     /// The added child node
137     Node *child;
138     /// The node after which the child has been added, or NULL if it was added as first
139     Node *ref;
141 private:
142     Event *_optimizeOne();
143     void _undoOne(NodeObserver &observer) const;
144     void _replayOne(NodeObserver &observer) const;
145 };
147 /**
148  * @brief Object representing child removal
149  */
150 class EventDel : public Event {
151 public:
152     EventDel(Node *repr, Node *c, Node *rr, Event *next)
153     : Event(repr, next), child(c), ref(rr) {}
155     /// The child node that was removed
156     Node *child;
157     /// The node after which the removed node was in the sibling order, or NULL if it was first
158     Node *ref;
160 private:
161     Event *_optimizeOne();
162     void _undoOne(NodeObserver &observer) const;
163     void _replayOne(NodeObserver &observer) const;
164 };
166 /**
167  * @brief Object representing attribute change
168  */
169 class EventChgAttr : public Event {
170 public:
171     EventChgAttr(Node *repr, GQuark k,
172                  Inkscape::Util::ptr_shared<char> ov,
173                  Inkscape::Util::ptr_shared<char> nv,
174                  Event *next)
175     : Event(repr, next), key(k),
176       oldval(ov), newval(nv) {}
178     /// GQuark corresponding to the changed attribute's name
179     GQuark key;
180     /// Value of the attribute before the change
181     Inkscape::Util::ptr_shared<char> oldval;
182     /// Value of the attribute after the change
183     Inkscape::Util::ptr_shared<char> newval;
185 private:
186     Event *_optimizeOne();
187     void _undoOne(NodeObserver &observer) const;
188     void _replayOne(NodeObserver &observer) const;
189 };
191 /**
192  * @brief Object representing content change
193  */
194 class EventChgContent : public Event {
195 public:
196     EventChgContent(Node *repr,
197                     Inkscape::Util::ptr_shared<char> ov,
198                     Inkscape::Util::ptr_shared<char> nv,
199                     Event *next)
200     : Event(repr, next), oldval(ov), newval(nv) {}
202     /// Content of the node before the change
203     Inkscape::Util::ptr_shared<char> oldval;
204     /// Content of the node after the change
205     Inkscape::Util::ptr_shared<char> newval;
207 private:
208     Event *_optimizeOne();
209     void _undoOne(NodeObserver &observer) const;
210     void _replayOne(NodeObserver &observer) const;
211 };
213 /**
214  * @brief Obect representing child order change
215  */
216 class EventChgOrder : public Event {
217 public:
218     EventChgOrder(Node *repr, Node *c, Node *orr, Node *nrr, Event *next)
219     : Event(repr, next), child(c),
220       oldref(orr), newref(nrr) {}
222     /// The node that was relocated in sibling order
223     Node *child;
224     /// The node after which the relocated node was in the sibling order before the change, or NULL if it was first
225     Node *oldref;
226     /// The node after which the relocated node is after the change, or if it's first
227     Node *newref;
229 private:
230     Event *_optimizeOne();
231     void _undoOne(NodeObserver &observer) const;
232     void _replayOne(NodeObserver &observer) const;
233 };
238 #endif
239 /*
240   Local Variables:
241   mode:c++
242   c-file-style:"stroustrup"
243   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
244   indent-tabs-mode:nil
245   fill-column:99
246   End:
247 */
248 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :