From cca66b9ec4e494c1d919bff0f71a820d8afab1fa Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:24:48 +0200 Subject: Adding upstream version 1.2.2. Signed-off-by: Daniel Baumann --- src/xml/event.h | 260 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 src/xml/event.h (limited to 'src/xml/event.h') 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 (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 + +#include +#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 +{ +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 Iterator; + typedef Inkscape::Util::ForwardPointerIterator 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 : -- cgit v1.2.3