[gtk/wip/otte/undo: 14/17] undo: Turn describe() vfunc into "title" property



commit 716878cc90c65129fedf590e6ea75ccf70ea3e31
Author: Benjamin Otte <otte redhat com>
Date:   Wed Aug 19 19:27:50 2015 +0200

    undo: Turn describe() vfunc into "title" property
    
    This way, applications can override the title to make it more useful.

 gtk/gtkentryundocommand.c   | 122 +++++++++++++++++++++++---------------------
 gtk/gtkundocommand.c        |  99 +++++++++++++++++++++++++++++------
 gtk/gtkundocommandprivate.h |   6 +--
 gtk/gtkundostack.c          |   4 +-
 gtk/gtkundoundocommand.c    |  14 ++---
 5 files changed, 155 insertions(+), 90 deletions(-)
---
diff --git a/gtk/gtkentryundocommand.c b/gtk/gtkentryundocommand.c
index eefc78ce22..c88570caa9 100644
--- a/gtk/gtkentryundocommand.c
+++ b/gtk/gtkentryundocommand.c
@@ -103,6 +103,64 @@ gtk_entry_undo_command_redo (GtkUndoCommand *command)
   return gtk_entry_undo_command_run (priv->entry, &priv->after);
 }
 
+static guint
+get_prefix_len (const char *str1,
+                const char *str2)
+{
+  guint i;
+
+  for (i = 0; str1[i] == str2[i] && str1[i] != 0; i++)
+    {
+      /* nothing to do here */
+    }
+
+  return i;
+}
+
+static guint
+get_suffix_len (const char *str1,
+                guint       len1,
+                const char *str2,
+                guint       len2)
+{
+  const char *cur1, *cur2;
+  guint i, max_len;
+
+  cur1 = str1 + len1 - 1;
+  cur2 = str2 + len2 - 1;
+  max_len = MIN (len1, len2);
+
+  for (i = 0; *cur1 == *cur2 && i < max_len; i++)
+    {
+      cur1--;
+      cur2--;
+    }
+
+  return i;
+}
+
+char *
+generate_title (const GtkEntrySnapshot *before,
+                const GtkEntrySnapshot *after)
+{
+  guint before_len, after_len, prefix_len, suffix_len;
+
+  before_len = strlen (before->text);
+  after_len = strlen (after->text);
+  prefix_len = get_prefix_len (before->text, after->text);
+  suffix_len = get_suffix_len (before->text, before_len,
+                               after->text, after_len);
+
+  if (before_len == after_len && before_len == prefix_len)
+    return g_strdup (_("No changes")); /* huh? */
+  else if (prefix_len + suffix_len == before_len)
+    return g_strdup_printf (_("Entered `%.*s'"), after_len - prefix_len - suffix_len, after->text + 
prefix_len);
+  else if (prefix_len + suffix_len == after_len)
+    return g_strdup_printf (_("Deleted `%.*s'"), before_len - prefix_len - suffix_len, before->text + 
prefix_len);
+  else
+    return g_strdup (_("Text changed"));
+}
+
 static GtkUndoCommand *
 gtk_entry_undo_command_new_from_snapshots (GtkEntry               *entry,
                                            gint64                  timestamp,
@@ -111,11 +169,16 @@ gtk_entry_undo_command_new_from_snapshots (GtkEntry               *entry,
 {
   GtkEntryUndoCommand *command;
   GtkEntryUndoCommandPrivate *priv;
+  char *title;
+
+  title = generate_title (before, after);
 
   command = g_object_new (GTK_TYPE_ENTRY_UNDO_COMMAND,
                           "timestamp", timestamp,
+                          "title", title,
                           NULL);
   priv = gtk_entry_undo_command_get_instance_private (command);
+  g_free (title);
 
   priv->entry = entry;
   gtk_entry_snapshot_copy (&priv->before, before);
@@ -167,64 +230,6 @@ gtk_entry_undo_command_should_merge (GtkUndoCommand *command,
   return TRUE;
 }
 
-static guint
-get_prefix_len (const char *str1,
-                const char *str2)
-{
-  guint i;
-
-  for (i = 0; str1[i] == str2[i] && str1[i] != 0; i++)
-    {
-      /* nothing to do here */
-    }
-
-  return i;
-}
-
-static guint
-get_suffix_len (const char *str1,
-                guint       len1,
-                const char *str2,
-                guint       len2)
-{
-  const char *cur1, *cur2;
-  guint i, max_len;
-
-  cur1 = str1 + len1 - 1;
-  cur2 = str2 + len2 - 1;
-  max_len = MIN (len1, len2);
-
-  for (i = 0; *cur1 == *cur2 && i < max_len; i++)
-    {
-      cur1--;
-      cur2--;
-    }
-
-  return i;
-}
-
-char *
-gtk_entry_undo_command_describe (GtkUndoCommand *command)
-{
-  GtkEntryUndoCommandPrivate *priv = gtk_entry_undo_command_get_instance_private (GTK_ENTRY_UNDO_COMMAND 
(command));
-  guint before_len, after_len, prefix_len, suffix_len;
-
-  before_len = strlen (priv->before.text);
-  after_len = strlen (priv->after.text);
-  prefix_len = get_prefix_len (priv->before.text, priv->after.text);
-  suffix_len = get_suffix_len (priv->before.text, before_len,
-                               priv->after.text, after_len);
-
-  if (before_len == after_len && before_len == prefix_len)
-    return g_strdup (_("No changes")); /* huh? */
-  else if (prefix_len + suffix_len == before_len)
-    return g_strdup_printf (_("Entered `%.*s'"), after_len - prefix_len - suffix_len, priv->after.text + 
prefix_len);
-  else if (prefix_len + suffix_len == after_len)
-    return g_strdup_printf (_("Deleted `%.*s'"), before_len - prefix_len - suffix_len, priv->before.text + 
prefix_len);
-  else
-    return g_strdup (_("Text changed"));
-}
-
 static void
 gtk_entry_undo_command_finalize (GObject *object)
 {
@@ -248,7 +253,6 @@ gtk_entry_undo_command_class_init (GtkEntryUndoCommandClass *klass)
   undo_class->redo = gtk_entry_undo_command_redo;
   undo_class->merge = gtk_entry_undo_command_merge;
   undo_class->should_merge = gtk_entry_undo_command_should_merge;
-  undo_class->describe = gtk_entry_undo_command_describe;
 }
 
 static void
diff --git a/gtk/gtkundocommand.c b/gtk/gtkundocommand.c
index bbc60efabf..b7fc36683d 100644
--- a/gtk/gtkundocommand.c
+++ b/gtk/gtkundocommand.c
@@ -26,11 +26,13 @@
 typedef struct _GtkUndoCommandPrivate GtkUndoCommandPrivate;
 struct _GtkUndoCommandPrivate {
   gint64 timestamp;
+  char *title;
 };
 
 enum {
   PROP_0,
   PROP_TIMESTAMP,
+  PROP_TITLE,
   /* add more */
   NUM_PROPERTIES
 };
@@ -54,6 +56,10 @@ gtk_undo_command_get_property (GObject    *object,
       g_value_set_int64 (value, priv->timestamp);
       break;
 
+    case PROP_TITLE:
+      g_value_set_string (value, priv->title);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     }
@@ -65,7 +71,8 @@ gtk_undo_command_set_property (GObject      *object,
                                const GValue *value,
                                GParamSpec   *pspec)
 {
-  GtkUndoCommandPrivate *priv = gtk_undo_command_get_instance_private (GTK_UNDO_COMMAND (object));
+  GtkUndoCommand *command = GTK_UNDO_COMMAND (object);
+  GtkUndoCommandPrivate *priv = gtk_undo_command_get_instance_private (command);
 
   switch (property_id)
     {
@@ -75,11 +82,25 @@ gtk_undo_command_set_property (GObject      *object,
         priv->timestamp = g_get_real_time ();
       break;
 
+    case PROP_TITLE:
+      gtk_undo_command_set_title (command, g_value_get_string (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     }
 }
 
+static void
+gtk_undo_command_finalize (GObject *object)
+{
+  GtkUndoCommandPrivate *priv = gtk_undo_command_get_instance_private (GTK_UNDO_COMMAND (object));
+
+  g_free (priv->title);
+
+  G_OBJECT_CLASS (gtk_undo_command_parent_class)->finalize (object);
+}
+
 static gboolean
 gtk_undo_command_real_undo (GtkUndoCommand *command)
 {
@@ -116,17 +137,6 @@ gtk_undo_command_real_should_merge (GtkUndoCommand *command,
   return TRUE;
 }
 
-char *
-gtk_undo_command_real_describe (GtkUndoCommand *command)
-{
-  g_warning ("%s class failed to implement undo", G_OBJECT_TYPE_NAME (command));
-
-  /* translators: This string is the fallback message that gets used
-   * when undo commands are improperly implemented and don't have a
-   * proper description. */
-  return g_strdup (_("unknown undo command"));
-}
-
 static void
 gtk_undo_command_class_init (GtkUndoCommandClass *klass)
 {
@@ -134,12 +144,12 @@ gtk_undo_command_class_init (GtkUndoCommandClass *klass)
 
   object_class->set_property = gtk_undo_command_set_property;
   object_class->get_property = gtk_undo_command_get_property;
+  object_class->finalize = gtk_undo_command_finalize;
 
   klass->undo = gtk_undo_command_real_undo;
   klass->redo = gtk_undo_command_real_redo;
   klass->merge = gtk_undo_command_real_merge;
   klass->should_merge = gtk_undo_command_real_should_merge;
-  klass->describe = gtk_undo_command_real_describe;
 
   /*
    * GtkUndoCommand:timestamp:
@@ -153,6 +163,18 @@ gtk_undo_command_class_init (GtkUndoCommandClass *klass)
                                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
                                                    G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
+  /*
+   * GtkUndoCommand:title:
+   *
+   * Title of this command. See
+   * gtk_undo_command_get_title() for details.
+   */
+  properties[PROP_TITLE] = g_param_spec_string ("title", "Title",
+                                                "Title of this command",
+                                                NULL,
+                                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
+                                                G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
   g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
 }
 
@@ -209,12 +231,57 @@ gtk_undo_command_should_merge (GtkUndoCommand *command,
   return GTK_UNDO_COMMAND_GET_CLASS (command)->should_merge (command, followup_command);
 }
 
-char *
-gtk_undo_command_describe (GtkUndoCommand *command)
+/*
+ * gtk_undo_command_get_title:
+ * @command: The command
+ *
+ * Gets the title of the @command. The title is a translated string
+ * for presentation in a user interface, for example a list of actions
+ * to undo.
+ *
+ * Undo commands always have a title set, but that title is often generic.
+ * Applications may want to update titles via gtk_undo_command_set_title()
+ *
+ * Returns: The title for the command
+ */
+const char *
+gtk_undo_command_get_title (GtkUndoCommand *command)
 {
+  GtkUndoCommandPrivate *priv = gtk_undo_command_get_instance_private (command);
+
   g_return_val_if_fail (GTK_IS_UNDO_COMMAND (command), NULL);
 
-  return GTK_UNDO_COMMAND_GET_CLASS (command)->describe (command);
+  return priv->title;
+}
+
+/*
+ * gtk_undo_command_set_title:
+ * @command: The command
+ * @title: The new title
+ *
+ * Updates the title for the given @command. This function should be called 
+ * when applications can provide a better title for an action than the generic
+ * title provided upon creation of commands.
+ */
+void
+gtk_undo_command_set_title (GtkUndoCommand *command,
+                            const char     *title)
+{
+  GtkUndoCommandPrivate *priv = gtk_undo_command_get_instance_private (command);
+
+  g_return_if_fail (GTK_IS_UNDO_COMMAND (command));
+
+  if (title == NULL)
+    /* translators: This is the (hopefully never used) fallback string for undo commands without a name */
+    title = _("Unknown command");
+
+  if (g_strcmp0 (priv->title, title) == 0)
+    return;
+
+  g_free (priv->title);
+  priv->title = g_strdup (title);
+
+  g_object_notify_by_pspec (G_OBJECT (command), properties[PROP_TITLE]);
 }
 
 /*
diff --git a/gtk/gtkundocommandprivate.h b/gtk/gtkundocommandprivate.h
index bfe982e47a..f5d00002d2 100644
--- a/gtk/gtkundocommandprivate.h
+++ b/gtk/gtkundocommandprivate.h
@@ -53,13 +53,14 @@ struct _GtkUndoCommandClass
   /* should the two commands be merged for user undo purposes? */
   gboolean              (* should_merge)                (GtkUndoCommand                *command,
                                                          GtkUndoCommand                *followup_command);
-  /* get a translated string describing the command */
-  char *                (* describe)                    (GtkUndoCommand                *command);
 };
 
 GType                   gtk_undo_command_get_type       (void) G_GNUC_CONST;
 
 gint64                  gtk_undo_command_get_timestamp  (GtkUndoCommand                *command);
+const char *            gtk_undo_command_get_title      (GtkUndoCommand                *command);
+void                    gtk_undo_command_set_title      (GtkUndoCommand                *command,
+                                                         const char                    *title);
 
 gboolean                gtk_undo_command_undo           (GtkUndoCommand                *command);
 gboolean                gtk_undo_command_redo           (GtkUndoCommand                *command);
@@ -67,7 +68,6 @@ GtkUndoCommand *        gtk_undo_command_merge          (GtkUndoCommand
                                                          GtkUndoCommand                *followup_command);
 gboolean                gtk_undo_command_should_merge   (GtkUndoCommand                *command,
                                                          GtkUndoCommand                *followup_command);
-char *                  gtk_undo_command_describe       (GtkUndoCommand                *command);
 
 
 G_END_DECLS
diff --git a/gtk/gtkundostack.c b/gtk/gtkundostack.c
index d977b1799d..5dea553ab9 100644
--- a/gtk/gtkundostack.c
+++ b/gtk/gtkundostack.c
@@ -147,10 +147,8 @@ gtk_undo_stack_dump (GtkUndoStack *stack)
        iter = g_sequence_iter_next (iter))
     {
       GtkUndoCommand *command = g_sequence_get (iter);
-      char *desc;
 
-      desc = gtk_undo_command_describe (command);
-      g_print ("  %s\n", desc);
+      g_print ("  %s\n", gtk_undo_command_get_title (command));
     }
 }
 
diff --git a/gtk/gtkundoundocommand.c b/gtk/gtkundoundocommand.c
index 0c119c9d0b..17aa3907e6 100644
--- a/gtk/gtkundoundocommand.c
+++ b/gtk/gtkundoundocommand.c
@@ -77,14 +77,6 @@ gtk_undo_undo_command_merge (GtkUndoCommand *command,
   return NULL;
 }
 
-char *
-gtk_undo_undo_command_describe (GtkUndoCommand *command)
-{
-  GtkUndoUndoCommandPrivate *priv = gtk_undo_undo_command_get_instance_private (GTK_UNDO_UNDO_COMMAND 
(command));
-
-  return g_strdup_printf (_("Undo last %u commands"), g_sequence_get_length (priv->commands));
-}
-
 static void
 gtk_undo_undo_command_finalize (GObject *object)
 {
@@ -106,7 +98,6 @@ gtk_undo_undo_command_class_init (GtkUndoUndoCommandClass *klass)
   undo_class->undo = gtk_undo_undo_command_undo;
   undo_class->redo = gtk_undo_undo_command_redo;
   undo_class->merge = gtk_undo_undo_command_merge;
-  undo_class->describe = gtk_undo_undo_command_describe;
 }
 
 static void
@@ -124,6 +115,7 @@ gtk_undo_undo_command_new (GSequenceIter *begin_iter,
   GtkUndoUndoCommand *result;
   GtkUndoUndoCommandPrivate *priv;
   GSequenceIter *iter;
+  char *title;
 
   g_return_val_if_fail (begin_iter != NULL, NULL);
   g_return_val_if_fail (end_iter != NULL, NULL);
@@ -136,6 +128,10 @@ gtk_undo_undo_command_new (GSequenceIter *begin_iter,
       g_sequence_prepend (priv->commands, g_object_ref (g_sequence_get (iter)));
     }
 
+  title = g_strdup_printf (_("Undo last %u commands"), g_sequence_get_length (priv->commands));
+  gtk_undo_command_set_title (GTK_UNDO_COMMAND (result), title);
+  g_free (title);
+
   return GTK_UNDO_COMMAND (result);
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]