undo: Turn describe() vfunc into "title" property
This way, applications can override the title to make it more useful.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user