[glade] GladeProject/GladeCommand: Implement undo/redo for project template widget
- From: Tristan Van Berkom <tvb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glade] GladeProject/GladeCommand: Implement undo/redo for project template widget
- Date: Tue, 9 Apr 2013 14:48:53 +0000 (UTC)
commit ffc5a8cc08a39936fe650e1468243c598e1bd980
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date: Tue Apr 9 23:48:24 2013 +0900
GladeProject/GladeCommand: Implement undo/redo for project template widget
gladeui/glade-command.c | 187 ++++++++++++++++++++++++++++++++++
gladeui/glade-command.h | 5 +
gladeui/glade-project.c | 257 +++++++++++++++++++++++++++++++---------------
gladeui/glade-project.h | 4 +
4 files changed, 369 insertions(+), 84 deletions(-)
---
diff --git a/gladeui/glade-command.c b/gladeui/glade-command.c
index 7d77c68..0e75bde 100644
--- a/gladeui/glade-command.c
+++ b/gladeui/glade-command.c
@@ -860,6 +860,17 @@ glade_command_set_name_unifies (GladeCommand *this_cmd, GladeCommand *other_cmd)
GladeCommandSetName *cmd1;
GladeCommandSetName *cmd2;
+ if (!other_cmd)
+ {
+ if (GLADE_IS_COMMAND_SET_NAME (this_cmd))
+ {
+ cmd1 = (GladeCommandSetName *) this_cmd;
+
+ return (g_strcmp0 (cmd1->old_name, cmd1->name) == 0);
+ }
+ return FALSE;
+ }
+
if (GLADE_IS_COMMAND_SET_NAME (this_cmd) &&
GLADE_IS_COMMAND_SET_NAME (other_cmd))
{
@@ -2302,3 +2313,179 @@ glade_command_unlock_widget (GladeWidget *widget)
g_object_unref (G_OBJECT (me));
}
+
+
+
+/******************************************************************************
+ *
+ * This command sets the template object in a GtkBuilder file
+ *
+ *****************************************************************************/
+
+typedef struct
+{
+ GladeCommand parent;
+ GladeWidget *old_template;
+ GladeWidget *new_template;
+} GladeCommandTemplate;
+
+
+GLADE_MAKE_COMMAND (GladeCommandTemplate, glade_command_template);
+#define GLADE_COMMAND_TEMPLATE_TYPE (glade_command_template_get_type ())
+#define GLADE_COMMAND_TEMPLATE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o),
GLADE_COMMAND_TEMPLATE_TYPE, GladeCommandTemplate))
+#define GLADE_COMMAND_TEMPLATE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k),
GLADE_COMMAND_TEMPLATE_TYPE, GladeCommandTemplateClass))
+#define GLADE_IS_COMMAND_TEMPLATE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o),
GLADE_COMMAND_TEMPLATE_TYPE))
+#define GLADE_IS_COMMAND_TEMPLATE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GLADE_COMMAND_TEMPLATE_TYPE))
+
+static gboolean
+glade_command_template_execute (GladeCommand *cmd)
+{
+ GladeCommandTemplate *me = (GladeCommandTemplate *) cmd;
+
+ glade_project_set_template (cmd->priv->project, me->new_template);
+
+ return TRUE;
+}
+
+static gboolean
+glade_command_template_undo (GladeCommand *cmd)
+{
+ GladeCommandTemplate *me = (GladeCommandTemplate *) cmd;
+
+ glade_project_set_template (cmd->priv->project, me->old_template);
+
+ return TRUE;
+}
+
+static void
+glade_command_template_finalize (GObject *obj)
+{
+ GladeCommandTemplate *me = (GladeCommandTemplate *) obj;
+
+ if (me->new_template)
+ g_object_unref (me->new_template);
+
+ if (me->old_template)
+ g_object_unref (me->old_template);
+
+ glade_command_finalize (obj);
+}
+
+static gboolean
+glade_command_template_unifies (GladeCommand *this_cmd, GladeCommand *other_cmd)
+{
+ GladeCommandTemplate *me;
+
+ /* Do we unify with self ? */
+ if (!other_cmd)
+ {
+ if (GLADE_IS_COMMAND_TEMPLATE (this_cmd))
+ {
+ me = (GladeCommandTemplate *) this_cmd;
+
+ return me->old_template == me->new_template;
+ }
+ return FALSE;
+ }
+
+ if (GLADE_IS_COMMAND_TEMPLATE (this_cmd) &&
+ GLADE_IS_COMMAND_TEMPLATE (other_cmd))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+glade_command_template_collapse (GladeCommand *this_cmd, GladeCommand *other_cmd)
+{
+ GladeCommandTemplate *this;
+ GladeCommandTemplate *other;
+
+ g_return_if_fail (GLADE_IS_COMMAND_TEMPLATE (this_cmd) &&
+ GLADE_IS_COMMAND_TEMPLATE (other_cmd));
+
+ this = GLADE_COMMAND_TEMPLATE (this_cmd);
+ other = GLADE_COMMAND_TEMPLATE (other_cmd);
+
+ if (this->new_template)
+ g_object_unref (this->new_template);
+
+ this->new_template = other->new_template;
+
+ if (this->new_template)
+ g_object_ref (this->new_template);
+
+ if (this->new_template == NULL && this->old_template != NULL)
+ {
+ g_free (this_cmd->priv->description);
+ this_cmd->priv->description =
+ g_strdup_printf (_("Unsetting widget '%s' as template"),
+ glade_widget_get_name (this->old_template));
+ }
+ else if (this->new_template != NULL)
+ {
+ g_free (this_cmd->priv->description);
+ this_cmd->priv->description =
+ g_strdup_printf (_("Setting widget '%s' as template"),
+ glade_widget_get_name (this->new_template));
+ }
+}
+
+/**
+ * glade_command_set_template:
+ * @project: A #GladeProject
+ * @widget: The #GladeWidget to make template
+ *
+ * Sets @widget to be the template widget in @project.
+ */
+void
+glade_command_set_template (GladeProject *project,
+ GladeWidget *widget)
+{
+ GladeCommandTemplate *me;
+ GladeWidget *old_template;
+
+ g_return_if_fail (GLADE_IS_PROJECT (project));
+ g_return_if_fail (widget == NULL || GLADE_IS_WIDGET (widget));
+
+ old_template = glade_project_get_template (project);
+
+ if (widget == old_template)
+ {
+ /* Just do nothing if there's nothing to do */
+ return;
+ }
+
+ /* load up the command */
+ me = g_object_new (GLADE_COMMAND_TEMPLATE_TYPE, NULL);
+ GLADE_COMMAND (me)->priv->project = project;
+
+ if (old_template)
+ me->old_template = g_object_ref (old_template);
+
+ if (widget)
+ {
+ me->new_template = g_object_ref (widget);
+
+ GLADE_COMMAND (me)->priv->description =
+ g_strdup_printf (_("Setting widget '%s' as template"),
+ glade_widget_get_name (widget));
+ }
+ else
+ GLADE_COMMAND (me)->priv->description =
+ g_strdup_printf (_("Unsetting widget '%s' as template"),
+ glade_widget_get_name (me->old_template));
+
+ glade_command_check_group (GLADE_COMMAND (me));
+
+ /* execute the command and push it on the stack if successful
+ * this sets the actual policy
+ */
+ if (glade_command_template_execute (GLADE_COMMAND (me)))
+ glade_project_push_undo (GLADE_COMMAND (me)->priv->project, GLADE_COMMAND (me));
+ else
+ g_object_unref (G_OBJECT (me));
+}
+
diff --git a/gladeui/glade-command.h b/gladeui/glade-command.h
index 0e7837d..812725f 100644
--- a/gladeui/glade-command.h
+++ b/gladeui/glade-command.h
@@ -79,6 +79,11 @@ gboolean glade_command_unifies (GladeCommand *com
void glade_command_collapse (GladeCommand *command,
GladeCommand *other);
+/************************ project ******************************/
+
+void glade_command_set_template (GladeProject *project,
+ GladeWidget *widget);
+
/************************** properties *********************************/
void glade_command_set_property (GladeProperty *property,
diff --git a/gladeui/glade-project.c b/gladeui/glade-project.c
index f359739..896feee 100644
--- a/gladeui/glade-project.c
+++ b/gladeui/glade-project.c
@@ -80,6 +80,7 @@ enum
PROP_ADD_ITEM,
PROP_POINTER_MODE,
PROP_TRANSLATION_DOMAIN,
+ PROP_TEMPLATE,
N_PROPERTIES
};
@@ -119,7 +120,7 @@ struct _GladeProjectPrivate
* undo this modification
*/
- GtkAccelGroup *accel_group;
+ GladeWidget *template; /* The template widget */
gchar *comment; /* XML comment, Glade will preserve whatever comment was
* in file, so users can delete or change it.
@@ -237,6 +238,9 @@ static void glade_project_model_get_iter_for_object (GladeProject *project,
static gint glade_project_count_children (GladeProject *project,
GladeWidget *parent);
+static void glade_project_fix_template (GladeProject *project);
+
+
static guint glade_project_signals[LAST_SIGNAL] = { 0 };
static GladeIDAllocator *unsaved_number_allocator = NULL;
@@ -409,6 +413,9 @@ glade_project_get_property (GObject *object,
case PROP_TRANSLATION_DOMAIN:
g_value_set_string (value, project->priv->translation_domain);
break;
+ case PROP_TEMPLATE:
+ g_value_set_object (value, project->priv->template);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -421,13 +428,16 @@ glade_project_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
-
switch (prop_id)
{
case PROP_TRANSLATION_DOMAIN:
glade_project_set_translation_domain (GLADE_PROJECT (object),
g_value_get_string (value));
break;
+ case PROP_TEMPLATE:
+ glade_project_set_template (GLADE_PROJECT (object),
+ g_value_get_object (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -510,6 +520,47 @@ glade_project_get_pointer_mode (GladeProject *project)
return project->priv->pointer_mode;
}
+void
+glade_project_set_template (GladeProject *project,
+ GladeWidget *widget)
+{
+ g_return_if_fail (GLADE_IS_PROJECT (project));
+ g_return_if_fail (widget == NULL || GLADE_IS_WIDGET (widget));
+
+ if (widget)
+ {
+ GObject *object = glade_widget_get_object (widget);
+
+ g_return_if_fail (GTK_IS_WIDGET (object));
+ g_return_if_fail (glade_widget_get_parent (widget) == NULL);
+ g_return_if_fail (glade_widget_get_project (widget) == project);
+ }
+
+ /* Let's not add any strong reference here, we already own the widget */
+ if (project->priv->template != widget)
+ {
+ if (project->priv->template)
+ glade_widget_set_is_composite (project->priv->template, FALSE);
+
+ project->priv->template = widget;
+
+ if (project->priv->template)
+ glade_widget_set_is_composite (project->priv->template, TRUE);
+
+ glade_project_fix_template (project);
+
+ g_object_notify_by_pspec (G_OBJECT (project), properties[PROP_TEMPLATE]);
+ }
+}
+
+GladeWidget *
+glade_project_get_template (GladeProject *project)
+{
+ g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
+
+ return project->priv->template;
+}
+
void
glade_project_set_add_item (GladeProject *project, GladeWidgetAdaptor *adaptor)
@@ -784,8 +835,6 @@ glade_project_init (GladeProject *project)
priv->widget_names = glade_name_context_new ();
- priv->accel_group = NULL;
-
priv->unsaved_number =
glade_id_allocator_allocate (get_unsaved_number_allocator ());
@@ -1062,6 +1111,13 @@ glade_project_class_init (GladeProjectClass *klass)
NULL,
G_PARAM_READWRITE);
+ properties[PROP_TEMPLATE] =
+ g_param_spec_object ("template",
+ _("Template"),
+ _("The project's template widget, if any"),
+ GLADE_TYPE_WIDGET,
+ G_PARAM_READWRITE);
+
/* Install all properties */
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
@@ -1620,57 +1676,6 @@ glade_project_autosave_name (const gchar *path)
}
static gboolean
-toplevel_visible_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
-{
- GtkTreeIter parent;
- return !gtk_tree_model_iter_parent (model, &parent, iter);
-}
-
-static GtkTreeModel *
-glade_project_toplevel_model_filter_new (GladeProject *project)
-{
- GtkTreeModel *model = gtk_tree_model_filter_new (GTK_TREE_MODEL (project), NULL);
- gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (model),
- toplevel_visible_func, NULL, NULL);
- return model;
-}
-
-static void
-glade_project_fix_template (GladeProject *project)
-{
- GtkTreeModel *model = glade_project_toplevel_model_filter_new (project);
- GladeProjectPrivate *priv = project->priv;
- GtkTreeIter iter;
- gboolean valid;
-
- valid = gtk_tree_model_get_iter_first (model, &iter);
- while (valid)
- {
- gboolean composite;
- GladeWidget *gwidget;
- GObject *obj;
-
- gtk_tree_model_get (model, &iter,
- GLADE_PROJECT_MODEL_COLUMN_OBJECT, &obj,
- -1);
-
- gwidget = glade_widget_get_from_gobject (obj);
- composite = glade_widget_get_is_composite (gwidget);
-
- if (composite)
- {
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->template_checkbutton), TRUE);
- gtk_combo_box_set_model (GTK_COMBO_BOX (priv->template_combobox), model);
- gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->template_combobox), &iter);
- }
-
- valid = gtk_tree_model_iter_next (model, &iter);
- }
-
- g_object_unref (model);
-}
-
-static gboolean
glade_project_load_internal (GladeProject *project)
{
GladeProjectPrivate *priv = project->priv;
@@ -4232,26 +4237,12 @@ on_domain_entry_activate (GtkWidget *entry, GladeProject *project)
}
static void
-glade_project_clear_composite (GladeProject *project)
-{
- GladeProjectPrivate *priv = project->priv;
- GList *l;
-
- for (l = priv->tree; l; l = g_list_next (l))
- {
- GladeWidget *gwidget = glade_widget_get_from_gobject (l->data);
-
- /* XXX Need a glade_command_set_composite() */
- glade_widget_set_is_composite (gwidget, FALSE);
- }
-}
-
-static void
on_template_combo_box_changed (GtkComboBox *combo, GladeProject *project)
{
GtkTreeIter iter;
- glade_project_clear_composite (project);
+ if (project->priv->loading)
+ return;
if (gtk_combo_box_get_active_iter (combo, &iter))
{
@@ -4263,8 +4254,7 @@ on_template_combo_box_changed (GtkComboBox *combo, GladeProject *project)
gwidget = glade_widget_get_from_gobject (object);
- /* XXX Need a glade_command_set_composite() */
- glade_widget_set_is_composite (gwidget, TRUE);
+ glade_command_set_template (project, gwidget);
}
}
@@ -4272,28 +4262,127 @@ static void
on_template_checkbutton_toggled (GtkToggleButton *togglebutton,
GladeProject *project)
{
- GtkComboBox *combobox = GTK_COMBO_BOX (project->priv->template_combobox);
gboolean active = gtk_toggle_button_get_active (togglebutton);
+ gboolean composite = FALSE;
- glade_project_clear_composite (project);
-
- if (gtk_combo_box_get_model (combobox))
- gtk_combo_box_set_active_iter (combobox, NULL);
+ if (project->priv->loading)
+ return;
if (active)
{
- GtkTreeModel *model = glade_project_toplevel_model_filter_new (project);
- GladeProjectPrivate *priv = project->priv;
+ GList *l;
+
+ for (l = project->priv->tree; l; l = l->next)
+ {
+ GObject *object = l->data;
+ GladeWidget *gwidget;
+
+ gwidget = glade_widget_get_from_gobject (object);
+
+ if (GTK_IS_WIDGET (object))
+ {
+ glade_command_set_template (project, gwidget);
+ composite = TRUE;
+ break;
+ }
+ }
+
+ if (!composite)
+ gtk_toggle_button_set_active (togglebutton, FALSE);
+ }
+ else
+ glade_command_set_template (project, NULL);
+}
+
+static gboolean
+template_visible_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
+{
+ GtkTreeIter parent;
+ gboolean visible;
+ GObject *object;
- gtk_combo_box_set_model (combobox, model);
+ visible = !gtk_tree_model_iter_parent (model, &parent, iter);
- if (priv->tree && !g_list_next (priv->tree))
- gtk_combo_box_set_active (combobox, 0);
+ if (visible)
+ {
+ gtk_tree_model_get (model, iter,
+ GLADE_PROJECT_MODEL_COLUMN_OBJECT, &object,
+ -1);
+
+ visible = GTK_IS_WIDGET (object);
+ g_object_unref (object);
}
- gtk_widget_set_sensitive (GTK_WIDGET (combobox), active);
+ return visible;
}
+static GtkTreeModel *
+glade_project_toplevel_model_filter_new (GladeProject *project)
+{
+ GtkTreeModel *model = gtk_tree_model_filter_new (GTK_TREE_MODEL (project), NULL);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (model),
+ template_visible_func, NULL, NULL);
+ return model;
+}
+
+static void
+glade_project_fix_template (GladeProject *project)
+{
+ GtkTreeModel *model;
+ GladeProjectPrivate *priv = project->priv;
+ GtkTreeIter iter;
+ gboolean valid;
+ gboolean composite = FALSE;
+
+ g_signal_handlers_block_by_func (priv->template_combobox, on_template_combo_box_changed, project);
+ g_signal_handlers_block_by_func (priv->template_checkbutton, on_template_checkbutton_toggled, project);
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->template_combobox));
+ if (!model)
+ {
+ model = glade_project_toplevel_model_filter_new (project);
+
+ gtk_combo_box_set_model (GTK_COMBO_BOX (priv->template_combobox), model);
+ g_object_unref (model);
+ }
+
+ valid = gtk_tree_model_get_iter_first (model, &iter);
+ while (valid)
+ {
+ GladeWidget *gwidget;
+ GObject *obj;
+
+ gtk_tree_model_get (model, &iter,
+ GLADE_PROJECT_MODEL_COLUMN_OBJECT, &obj,
+ -1);
+
+ gwidget = glade_widget_get_from_gobject (obj);
+ g_object_unref (obj);
+
+ composite = glade_widget_get_is_composite (gwidget);
+
+ if (composite)
+ {
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->template_combobox), &iter);
+
+ /* Resolve the template widget for this project */
+ priv->template = gwidget;
+
+ break;
+ }
+
+ valid = gtk_tree_model_iter_next (model, &iter);
+ }
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->template_checkbutton), composite);
+ gtk_widget_set_sensitive (priv->template_combobox, composite);
+
+ if (!composite && gtk_combo_box_get_model (GTK_COMBO_BOX (priv->template_combobox)))
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->template_combobox), NULL);
+
+ g_signal_handlers_unblock_by_func (priv->template_combobox, on_template_combo_box_changed, project);
+ g_signal_handlers_unblock_by_func (priv->template_checkbutton, on_template_checkbutton_toggled, project);
+}
#define GET_OBJECT(b,c,o) c(gtk_builder_get_object(b,o));
diff --git a/gladeui/glade-project.h b/gladeui/glade-project.h
index 915a9a5..c243eec 100644
--- a/gladeui/glade-project.h
+++ b/gladeui/glade-project.h
@@ -145,6 +145,10 @@ void glade_project_check_reordered (GladeProject *proj
GladeWidget *parent,
GList *old_order);
+void glade_project_set_template (GladeProject *project,
+ GladeWidget *widget);
+GladeWidget *glade_project_get_template (GladeProject *project);
+
/* Commands */
void glade_project_undo (GladeProject *project);
void glade_project_redo (GladeProject *project);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]