Code

Connector tool: make connectors avoid the convex hull of shapes.
[inkscape.git] / src / document-undo.cpp
index f37a3fcafb9450b14de2bac28075782bbfe048b6..ae1c82e71f4e4d2e02b4ab2e6e480599ac26096f 100644 (file)
@@ -7,6 +7,7 @@
  *   Lauris Kaplinski <lauris@kaplinski.com>
  *   MenTaLguY <mental@rydia.net>
  *
+ * Copyright (C) 2007  MenTaLguY <mental@rydia.net>
  * Copyright (C) 1999-2003 authors
  * Copyright (C) 2001-2002 Ximian, Inc.
  *
@@ -22,7 +23,7 @@
  * stack. Two methods exist to indicate that the given action is completed:
  *
  * \verbatim
-   void sp_document_done (SPDocument *document)
+   void sp_document_done (SPDocument *document);
    void sp_document_maybe_done (SPDocument *document, const unsigned char *key) \endverbatim
  *
  * Both move the recent action list into the undo stack and clear the
 #if HAVE_STDLIB_H
 #endif
 
+#include <string>
+#include <cstring>
 #include "xml/repr.h"
 #include "document-private.h"
 #include "inkscape.h"
 #include "debug/event-tracker.h"
 #include "debug/simple-event.h"
+#include "debug/timestamp.h"
+#include "event.h"
 
 
 /*
  *   Since undo sensitivity needs to be nested, setting undo sensitivity
  *   should be done like this:
  *\verbatim
-        gboolean saved = sp_document_get_undo_sensitive(document);
-        sp_document_set_undo_sensitive(document, FALSE);
+        bool saved = sp_document_get_undo_sensitive(document);
+        sp_document_set_undo_sensitive(document, false);
         ... do stuff ...
         sp_document_set_undo_sensitive(document, saved);  \endverbatim
  */
 void
-sp_document_set_undo_sensitive (SPDocument *doc, gboolean sensitive)
+sp_document_set_undo_sensitive (SPDocument *doc, bool sensitive)
 {
        g_assert (doc != NULL);
        g_assert (doc->priv != NULL);
 
-       if ( !(sensitive) == !(doc->priv->sensitive) )
+       if ( sensitive == doc->priv->sensitive )
                return;
 
        if (sensitive) {
@@ -97,10 +102,17 @@ sp_document_set_undo_sensitive (SPDocument *doc, gboolean sensitive)
                );
        }
 
-       doc->priv->sensitive = !!sensitive;
+       doc->priv->sensitive = sensitive;
 }
 
-gboolean sp_document_get_undo_sensitive(SPDocument const *document) {
+/*TODO: Throughout the inkscape code tree set/get_undo_sensitive are used for
+ * as is shown above.  Perhaps it makes sense to create new functions,
+ * undo_ignore, and undo_recall to replace the start and end parts of the above.
+ * The main complexity with this is that they have to nest, so you have to store
+ * the saved bools in a stack.  Perhaps this is why the above solution is better.
+ */
+
+bool sp_document_get_undo_sensitive(SPDocument const *document) {
        g_assert(document != NULL);
        g_assert(document->priv != NULL);
 
@@ -108,25 +120,60 @@ gboolean sp_document_get_undo_sensitive(SPDocument const *document) {
 }
 
 void
-sp_document_done (SPDocument *doc)
+sp_document_done (SPDocument *doc, const unsigned int event_type, Glib::ustring event_description)
 {
-       sp_document_maybe_done (doc, NULL);
+        sp_document_maybe_done (doc, NULL, event_type, event_description);
 }
 
 void
-sp_document_reset_key (Inkscape::Application *inkscape, SPDesktop *desktop, GtkObject *base)
+sp_document_reset_key (Inkscape::Application */*inkscape*/, SPDesktop */*desktop*/, GtkObject *base)
 {
-       SPDocument *doc = (SPDocument *) base;
-       doc->actionkey = NULL;
+    SPDocument *doc = (SPDocument *) base;
+    doc->actionkey = NULL;
+}
+
+namespace {
+
+using Inkscape::Debug::Event;
+using Inkscape::Debug::SimpleEvent;
+using Inkscape::Util::share_static_string;
+using Inkscape::Debug::timestamp;
+using Inkscape::Verb;
+
+typedef SimpleEvent<Event::INTERACTION> InteractionEvent;
+
+class CommitEvent : public InteractionEvent {
+public:
+
+    CommitEvent(SPDocument *doc, const gchar *key, const unsigned int type)
+    : InteractionEvent(share_static_string("commit"))
+    {
+        _addProperty(share_static_string("timestamp"), timestamp());
+        gchar *serial = g_strdup_printf("%lu", doc->serial());
+        _addProperty(share_static_string("document"), serial);
+        g_free(serial);
+        Verb *verb = Verb::get(type);
+        if (verb) {
+            _addProperty(share_static_string("context"), verb->get_id());
+        }
+        if (key) {
+            _addProperty(share_static_string("merge-key"), key);
+        }
+    }
+};
+
 }
 
 void
-sp_document_maybe_done (SPDocument *doc, const gchar *key)
+sp_document_maybe_done (SPDocument *doc, const gchar *key, const unsigned int event_type,
+                        Glib::ustring event_description)
 {
        g_assert (doc != NULL);
        g_assert (doc->priv != NULL);
        g_assert (doc->priv->sensitive);
 
+        Inkscape::Debug::EventTracker<CommitEvent> tracker(doc, key, event_type);
+
        doc->collectOrphans();
 
        sp_document_ensure_up_to_date (doc);
@@ -142,21 +189,23 @@ sp_document_maybe_done (SPDocument *doc, const gchar *key)
        }
 
        if (key && doc->actionkey && !strcmp (key, doc->actionkey) && doc->priv->undo) {
-               doc->priv->undo->data = sp_repr_coalesce_log ((Inkscape::XML::Event *)doc->priv->undo->data, log);
+                ((Inkscape::Event *)doc->priv->undo->data)->event =
+                    sp_repr_coalesce_log (((Inkscape::Event *)doc->priv->undo->data)->event, log);
        } else {
-               doc->priv->undo = g_slist_prepend (doc->priv->undo, log);
+                Inkscape::Event *event = new Inkscape::Event(log, event_type, event_description);
+                doc->priv->undo = g_slist_prepend (doc->priv->undo, event);
                doc->priv->history_size++;
-               doc->priv->undoStackObservers.notifyUndoCommitEvent(log);
+               doc->priv->undoStackObservers.notifyUndoCommitEvent(event);
        }
 
        doc->actionkey = key;
 
        doc->virgin = FALSE;
-       if (!doc->rroot->attribute("sodipodi:modified")) {
-               doc->rroot->setAttribute("sodipodi:modified", "true");
-       }
+        doc->setModifiedSinceSave();
 
        sp_repr_begin_transaction (doc->rdoc);
+
+  doc->priv->commit_signal.emit();
 }
 
 void
@@ -177,22 +226,20 @@ sp_document_cancel (SPDocument *doc)
        sp_repr_begin_transaction (doc->rdoc);
 }
 
-namespace {
-
-void finish_incomplete_transaction(SPDocument &doc) {
+static void finish_incomplete_transaction(SPDocument &doc) {
        SPDocumentPrivate &priv=*doc.priv;
        Inkscape::XML::Event *log=sp_repr_commit_undoable(doc.rdoc);
        if (log || priv.partial) {
                g_warning ("Incomplete undo transaction:");
                priv.partial = sp_repr_coalesce_log(priv.partial, log);
                sp_repr_debug_print_log(priv.partial);
-               priv.undo = g_slist_prepend(priv.undo, priv.partial);
+                Inkscape::Event *event = new Inkscape::Event(priv.partial);
+               priv.undo = g_slist_prepend(priv.undo, event);
+                priv.undoStackObservers.notifyUndoCommitEvent(event);
                priv.partial = NULL;
        }
 }
 
-}
-
 gboolean
 sp_document_undo (SPDocument *doc)
 {
@@ -208,19 +255,20 @@ sp_document_undo (SPDocument *doc)
        g_assert (doc->priv->sensitive);
 
        doc->priv->sensitive = FALSE;
+        doc->priv->seeking = true;
 
        doc->actionkey = NULL;
 
        finish_incomplete_transaction(*doc);
 
        if (doc->priv->undo) {
-               Inkscape::XML::Event *log=(Inkscape::XML::Event *)doc->priv->undo->data;
+               Inkscape::Event *log=(Inkscape::Event *)doc->priv->undo->data;
                doc->priv->undo = g_slist_remove (doc->priv->undo, log);
-               sp_repr_undo_log (log);
+               sp_repr_undo_log (log->event);
                doc->priv->redo = g_slist_prepend (doc->priv->redo, log);
 
-               doc->rroot->setAttribute("sodipodi:modified", "true");
-               doc->priv->undoStackObservers.notifyUndoEvent(log);
+                doc->setModifiedSinceSave();
+                doc->priv->undoStackObservers.notifyUndoEvent(log);
 
                ret = TRUE;
        } else {
@@ -230,6 +278,7 @@ sp_document_undo (SPDocument *doc)
        sp_repr_begin_transaction (doc->rdoc);
 
        doc->priv->sensitive = TRUE;
+        doc->priv->seeking = false;
 
        if (ret)
                inkscape_external_change();
@@ -252,18 +301,19 @@ sp_document_redo (SPDocument *doc)
        g_assert (doc->priv->sensitive);
 
        doc->priv->sensitive = FALSE;
+        doc->priv->seeking = true;
 
        doc->actionkey = NULL;
 
        finish_incomplete_transaction(*doc);
 
        if (doc->priv->redo) {
-               Inkscape::XML::Event *log=(Inkscape::XML::Event *)doc->priv->redo->data;
+               Inkscape::Event *log=(Inkscape::Event *)doc->priv->redo->data;
                doc->priv->redo = g_slist_remove (doc->priv->redo, log);
-               sp_repr_replay_log (log);
+               sp_repr_replay_log (log->event);
                doc->priv->undo = g_slist_prepend (doc->priv->undo, log);
 
-               doc->rroot->setAttribute("sodipodi:modified", "true");
+                doc->setModifiedSinceSave();
                doc->priv->undoStackObservers.notifyRedoEvent(log);
 
                ret = TRUE;
@@ -274,6 +324,7 @@ sp_document_redo (SPDocument *doc)
        sp_repr_begin_transaction (doc->rdoc);
 
        doc->priv->sensitive = TRUE;
+        doc->priv->seeking = false;
 
        if (ret)
                inkscape_external_change();
@@ -284,6 +335,9 @@ sp_document_redo (SPDocument *doc)
 void
 sp_document_clear_undo (SPDocument *doc)
 {
+        if (doc->priv->undo)
+                doc->priv->undoStackObservers.notifyClearUndoEvent();
+
        while (doc->priv->undo) {
                GSList *current;
 
@@ -291,7 +345,7 @@ sp_document_clear_undo (SPDocument *doc)
                doc->priv->undo = current->next;
                doc->priv->history_size--;
 
-               sp_repr_free_log ((Inkscape::XML::Event *)current->data);
+                delete ((Inkscape::Event *) current->data);
                g_slist_free_1 (current);
        }
 }
@@ -299,6 +353,9 @@ sp_document_clear_undo (SPDocument *doc)
 void
 sp_document_clear_redo (SPDocument *doc)
 {
+        if (doc->priv->redo)
+                doc->priv->undoStackObservers.notifyClearRedoEvent();
+
        while (doc->priv->redo) {
                GSList *current;
 
@@ -306,7 +363,7 @@ sp_document_clear_redo (SPDocument *doc)
                doc->priv->redo = current->next;
                doc->priv->history_size--;
 
-               sp_repr_free_log ((Inkscape::XML::Event *)current->data);
+                delete ((Inkscape::Event *) current->data);
                g_slist_free_1 (current);
        }
 }