diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 11:50:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 11:50:49 +0000 |
commit | c853ffb5b2f75f5a889ed2e3ef89b818a736e87a (patch) | |
tree | 7d13a0883bb7936b84d6ecdd7bc332b41ed04bee /src/xml/event.h | |
parent | Initial commit. (diff) | |
download | inkscape-c853ffb5b2f75f5a889ed2e3ef89b818a736e87a.tar.xz inkscape-c853ffb5b2f75f5a889ed2e3ef89b818a736e87a.zip |
Adding upstream version 1.3+ds.upstream/1.3+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/xml/event.h')
-rw-r--r-- | src/xml/event.h | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/src/xml/event.h b/src/xml/event.h new file mode 100644 index 0000000..4256eea --- /dev/null +++ b/src/xml/event.h @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * @brief Event object representing a change of the XML document + *//* + * Authors: + * Unknown author(s) + * Krzysztof KosiĆski <tweenk.pl@gmail.com> (documentation) + * + * Copyright (C) 2018 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#ifndef SEEN_INKSCAPE_XML_SP_REPR_ACTION_H +#define SEEN_INKSCAPE_XML_SP_REPR_ACTION_H + +typedef unsigned int GQuark; +#include <glibmm/ustring.h> + +#include <iterator> +#include "util/share.h" +#include "util/forward-pointer-iterator.h" +#include "inkgc/gc-managed.h" +#include "xml/node.h" + +namespace Inkscape { +namespace XML { + +/** + * @brief Enumeration of all XML event types + */ +// enum EventType { +// EVENT_ADD, ///< Child added +// EVENT_DEL, ///< Child removed +// EVENT_CHG_ATTR, ///< Attribute changed +// EVENT_CHG_CONTENT, ///< Content changed +// EVENT_CHG_ORDER ///< Order of children changed +// }; + +/** + * @brief Generic XML modification event + * + * This is the base class for all other modification events. It is actually a singly-linked + * list of events, called an event chain or an event log. Logs of events that happened + * in a transaction can be obtained from Document::commitUndoable(). Events can be replayed + * to a NodeObserver, or undone (which is equivalent to replaying opposite events in reverse + * order). + * + * Event logs are built by appending to the front, so by walking the list one iterates over + * the events in reverse chronological order. + */ +class Event +: public Inkscape::GC::Managed<Inkscape::GC::SCANNED, Inkscape::GC::MANUAL> +{ +public: + virtual ~Event() = default; + + /** + * @brief Pointer to the next event in the event chain + * + * Note that the event this pointer points to actually happened before this event. + * This is because the event log is built by appending to the front. + */ + Event *next; + /** + * @brief Serial number of the event, not used at the moment + */ + int serial; + /** + * @brief Pointer to the node that was the object of the event + * + * Because the nodes are garbage-collected, this pointer guarantees that the node + * will stay in memory as long as the event does. This simplifies rolling back + * extensive deletions. + */ + Node *repr; + + struct IteratorStrategy { + static Event const *next(Event const *action) { + return action->next; + } + }; + + typedef Inkscape::Util::ForwardPointerIterator<Event, IteratorStrategy> Iterator; + typedef Inkscape::Util::ForwardPointerIterator<Event const, IteratorStrategy> ConstIterator; + + /** + * @brief If possible, combine this event with the next to reduce memory use + * @return Pointer to the optimized event chain, which may have changed + */ + Event *optimizeOne() { return _optimizeOne(); } + /** + * @brief Undo this event to an observer + * + * This method notifies the specified observer of an action opposite to the one that + * is described by this event. + */ + void undoOne(NodeObserver &observer) const { + _undoOne(observer); + } + /** + * @brief Replay this event to an observer + * + * This method notifies the specified event of the same action that it describes. + */ + void replayOne(NodeObserver &observer) const { + _replayOne(observer); + } + +protected: + Event(Node *r, Event *n) + : next(n), serial(_next_serial++), repr(r) {} + + virtual Event *_optimizeOne()=0; + virtual void _undoOne(NodeObserver &) const=0; + virtual void _replayOne(NodeObserver &) const=0; + +private: + static int _next_serial; +}; + +/** + * @brief Object representing child addition + */ +class EventAdd : public Event { +public: + EventAdd(Node *repr, Node *c, Node *rr, Event *next) + : Event(repr, next), child(c), ref(rr) {} + + /// The added child node + Node *child; + /// The node after which the child has been added, or NULL if it was added as first + Node *ref; + +private: + Event *_optimizeOne() override; + void _undoOne(NodeObserver &observer) const override; + void _replayOne(NodeObserver &observer) const override; +}; + +/** + * @brief Object representing child removal + */ +class EventDel : public Event { +public: + EventDel(Node *repr, Node *c, Node *rr, Event *next) + : Event(repr, next), child(c), ref(rr) {} + + /// The child node that was removed + Node *child; + /// The node after which the removed node was in the sibling order, or NULL if it was first + Node *ref; + +private: + Event *_optimizeOne() override; + void _undoOne(NodeObserver &observer) const override; + void _replayOne(NodeObserver &observer) const override; +}; + +/** + * @brief Object representing attribute change + */ +class EventChgAttr : public Event { +public: + EventChgAttr(Node *repr, GQuark k, + Inkscape::Util::ptr_shared ov, + Inkscape::Util::ptr_shared nv, + Event *next) + : Event(repr, next), key(k), + oldval(ov), newval(nv) {} + + /// GQuark corresponding to the changed attribute's name + GQuark key; + /// Value of the attribute before the change + Inkscape::Util::ptr_shared oldval; + /// Value of the attribute after the change + Inkscape::Util::ptr_shared newval; + +private: + Event *_optimizeOne() override; + void _undoOne(NodeObserver &observer) const override; + void _replayOne(NodeObserver &observer) const override; +}; + +/** + * @brief Object representing content change + */ +class EventChgContent : public Event { +public: + EventChgContent(Node *repr, + Inkscape::Util::ptr_shared ov, + Inkscape::Util::ptr_shared nv, + Event *next) + : Event(repr, next), oldval(ov), newval(nv) {} + + /// Content of the node before the change + Inkscape::Util::ptr_shared oldval; + /// Content of the node after the change + Inkscape::Util::ptr_shared newval; + +private: + Event *_optimizeOne() override; + void _undoOne(NodeObserver &observer) const override; + void _replayOne(NodeObserver &observer) const override; +}; + +/** + * @brief Object representing child order change + */ +class EventChgOrder : public Event { +public: + EventChgOrder(Node *repr, Node *c, Node *orr, Node *nrr, Event *next) + : Event(repr, next), child(c), + oldref(orr), newref(nrr) {} + + /// The node that was relocated in sibling order + Node *child; + /// The node after which the relocated node was in the sibling order before the change, or NULL if it was first + Node *oldref; + /// The node after which the relocated node is after the change, or if it's first + Node *newref; + +private: + Event *_optimizeOne() override; + void _undoOne(NodeObserver &observer) const override; + void _replayOne(NodeObserver &observer) const override; +}; + +/** + * @brief Object representing element name change. + */ +class EventChgElementName : public Event { +public: + EventChgElementName(Node* repr, GQuark old_name, GQuark new_name, Event* next) + : Event(repr, next), old_name(old_name), new_name(new_name) {} + + /// GQuark corresponding to the old element name. + GQuark old_name; + /// GQuark corresponding to the new element name. + GQuark new_name; + +private: + Event* _optimizeOne() override; + void _undoOne(NodeObserver& observer) const override; + void _replayOne(NodeObserver& observer) const override; +}; + +} +} + +#endif +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : |