summaryrefslogtreecommitdiffstats
path: root/src/xml/event.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/xml/event.h')
-rw-r--r--src/xml/event.h260
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 :