Code

Translations. French translation minor update.
[inkscape.git] / src / document-undo.cpp
index f37a3fcafb9450b14de2bac28075782bbfe048b6..1559dc5ba6cb10945fcb6ddc8aa37d00c37441c3 100644 (file)
@@ -1,12 +1,12 @@
-#define __SP_DOCUMENT_UNDO_C__
-
 /** \file
  * Undo/Redo stack implementation
  *
  * Authors:
  *   Lauris Kaplinski <lauris@kaplinski.com>
  *   MenTaLguY <mental@rydia.net>
+ *   Abhishek Sharma
  *
+ * Copyright (C) 2007  MenTaLguY <mental@rydia.net>
  * Copyright (C) 1999-2003 authors
  * Copyright (C) 2001-2002 Ximian, Inc.
  *
@@ -22,8 +22,8 @@
  * stack. Two methods exist to indicate that the given action is completed:
  *
  * \verbatim
-   void sp_document_done (SPDocument *document)
-   void sp_document_maybe_done (SPDocument *document, const unsigned char *key) \endverbatim
+   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
  * list afterwards.  While the first method does an unconditional push,
 #if HAVE_STDLIB_H
 #endif
 
+#include <string>
+#include <cstring>
 #include "xml/repr.h"
 #include "document-private.h"
 #include "inkscape.h"
+#include "document-undo.h"
 #include "debug/event-tracker.h"
 #include "debug/simple-event.h"
+#include "debug/timestamp.h"
+#include "event.h"
 
 
 /*
  * Undo & redo
  */
-/**
- * Set undo sensitivity.
- *
- * \note
- *   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);
-        ... do stuff ...
-        sp_document_set_undo_sensitive(document, saved);  \endverbatim
- */
-void
-sp_document_set_undo_sensitive (SPDocument *doc, gboolean sensitive)
+
+void Inkscape::DocumentUndo::setUndoSensitive(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,41 +90,83 @@ 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 Inkscape::DocumentUndo::getUndoSensitive(SPDocument const *document) {
        g_assert(document != NULL);
        g_assert(document->priv != NULL);
 
        return document->priv->sensitive;
 }
 
-void
-sp_document_done (SPDocument *doc)
+void Inkscape::DocumentUndo::done(SPDocument *doc, const unsigned int event_type, Glib::ustring const &event_description)
 {
-       sp_document_maybe_done (doc, NULL);
+    maybeDone(doc, NULL, event_type, event_description);
 }
 
-void
-sp_document_reset_key (Inkscape::Application *inkscape, SPDesktop *desktop, GtkObject *base)
+void Inkscape::DocumentUndo::resetKey( Inkscape::Application * /*inkscape*/, SPDesktop * /*desktop*/, GtkObject *base )
 {
-       SPDocument *doc = (SPDocument *) base;
-       doc->actionkey = NULL;
+    SPDocument *doc = reinterpret_cast<SPDocument *>(base);
+    doc->actionkey.clear();
+}
+
+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)
+void Inkscape::DocumentUndo::maybeDone(SPDocument *doc, const gchar *key, const unsigned int event_type,
+                                       Glib::ustring const &event_description)
 {
        g_assert (doc != NULL);
        g_assert (doc->priv != NULL);
        g_assert (doc->priv->sensitive);
+        if ( key && !*key ) {
+            g_warning("Blank undo key specified.");
+        }
+
+        Inkscape::Debug::EventTracker<CommitEvent> tracker(doc, key, event_type);
 
        doc->collectOrphans();
 
-       sp_document_ensure_up_to_date (doc);
+       doc->ensureUpToDate();
 
-       sp_document_clear_redo (doc);
+       DocumentUndo::clearRedo(doc);
 
        Inkscape::XML::Event *log = sp_repr_coalesce_log (doc->priv->partial, sp_repr_commit_undoable (doc->rdoc));
        doc->priv->partial = NULL;
@@ -141,26 +176,31 @@ sp_document_maybe_done (SPDocument *doc, const gchar *key)
                return;
        }
 
-       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);
+       if (key && !doc->actionkey.empty() && (doc->actionkey == key) && doc->priv->undo) {
+                ((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;
+        if ( key ) {
+            doc->actionkey = key;
+        } else {
+            doc->actionkey.clear();
+        }
 
        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
-sp_document_cancel (SPDocument *doc)
+void Inkscape::DocumentUndo::cancel(SPDocument *doc)
 {
        g_assert (doc != NULL);
        g_assert (doc->priv != NULL);
@@ -177,24 +217,21 @@ 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)
+gboolean Inkscape::DocumentUndo::undo(SPDocument *doc)
 {
        using Inkscape::Debug::EventTracker;
        using Inkscape::Debug::SimpleEvent;
@@ -208,19 +245,20 @@ sp_document_undo (SPDocument *doc)
        g_assert (doc->priv->sensitive);
 
        doc->priv->sensitive = FALSE;
+        doc->priv->seeking = true;
 
-       doc->actionkey = NULL;
+       doc->actionkey.clear();
 
        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 +268,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();
@@ -237,8 +276,7 @@ sp_document_undo (SPDocument *doc)
        return ret;
 }
 
-gboolean
-sp_document_redo (SPDocument *doc)
+gboolean Inkscape::DocumentUndo::redo(SPDocument *doc)
 {
        using Inkscape::Debug::EventTracker;
        using Inkscape::Debug::SimpleEvent;
@@ -252,18 +290,19 @@ sp_document_redo (SPDocument *doc)
        g_assert (doc->priv->sensitive);
 
        doc->priv->sensitive = FALSE;
+        doc->priv->seeking = true;
 
-       doc->actionkey = NULL;
+       doc->actionkey.clear();
 
        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 +313,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();
@@ -281,9 +321,11 @@ sp_document_redo (SPDocument *doc)
        return ret;
 }
 
-void
-sp_document_clear_undo (SPDocument *doc)
+void Inkscape::DocumentUndo::clearUndo(SPDocument *doc)
 {
+        if (doc->priv->undo)
+                doc->priv->undoStackObservers.notifyClearUndoEvent();
+
        while (doc->priv->undo) {
                GSList *current;
 
@@ -291,14 +333,16 @@ 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);
        }
 }
 
-void
-sp_document_clear_redo (SPDocument *doc)
+void Inkscape::DocumentUndo::clearRedo(SPDocument *doc)
 {
+        if (doc->priv->redo)
+                doc->priv->undoStackObservers.notifyClearRedoEvent();
+
        while (doc->priv->redo) {
                GSList *current;
 
@@ -306,7 +350,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);
        }
 }