[glade/gbinding: 26/60] Implement "Bind property" command to undo/redo system and expose it as "Bind to source..." popup men



commit 7a5fe9a22cf9cd4df1a6667f472bd45c18c739f1
Author: Denis Washington <denisw src gnome org>
Date:   Fri Jun 17 20:16:02 2011 +0200

    Implement "Bind property" command to undo/redo system and expose it as "Bind to source..." popup menu item in the property inspector
    
    Don't take the UI of the "Bind Property" dialog seriously, it's just for testing purposes. Instead of raw text entries, there will naturally be a list of widgets and properties to choose from or something. However, the actual commands,
    including undo/redo, do already work.

 gladeui/glade-command.c         |  147 +++++++++++++++++++++++++++++++++++++++
 gladeui/glade-command.h         |    3 +
 gladeui/glade-editor-property.c |   74 ++++++++++++++++++++
 gladeui/glade-editor-property.h |    4 +
 gladeui/glade-popup.c           |   26 +++++++
 5 files changed, 254 insertions(+), 0 deletions(-)
---
diff --git a/gladeui/glade-command.c b/gladeui/glade-command.c
index 617994c..f67c86b 100644
--- a/gladeui/glade-command.c
+++ b/gladeui/glade-command.c
@@ -787,6 +787,153 @@ glade_command_set_property (GladeProperty * property, ...)
 }
 
 /**************************************************/
+/*******     GLADE_COMMAND_BIND_PROPERTY     ******/
+/**************************************************/
+
+/* create a new GladeCommandBindProperty class.  Objects of this class will
+ * encapsulate a "bind property" operation */
+
+typedef struct
+{
+  GladeCommand parent;
+  GladeProperty *target;
+  GladeProperty *new_source;
+  GladeProperty *old_source;
+  GValue old_value;
+  gboolean undo;
+} GladeCommandBindProperty;
+
+/* standard macros */
+GLADE_MAKE_COMMAND (GladeCommandBindProperty, glade_command_bind_property);
+#define GLADE_COMMAND_BIND_PROPERTY_TYPE	(glade_command_bind_property_get_type ())
+#define GLADE_COMMAND_BIND_PROPERTY(o)	  	(G_TYPE_CHECK_INSTANCE_CAST ((o), GLADE_COMMAND_BIND_PROPERTY_TYPE, GladeCommandBindProperty))
+#define GLADE_COMMAND_BIND_PROPERTY_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST ((k), GLADE_COMMAND_BIND_PROPERTY_TYPE, GladeCommandBindPropertyClass))
+#define GLADE_IS_COMMAND_BIND_PROPERTY(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GLADE_COMMAND_BIND_PROPERTY_TYPE))
+#define GLADE_IS_COMMAND_BIND_PROPERTY_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GLADE_COMMAND_BIND_PROPERTY_TYPE))
+
+/* Undo the last "bind property command" */
+static gboolean
+glade_command_bind_property_undo (GladeCommand * cmd)
+{
+  return glade_command_bind_property_execute (cmd);
+}
+
+/*
+ * Execute the set property command and revert it. IE, after the execution of 
+ * this function cmd will point to the undo action
+ */
+static gboolean
+glade_command_bind_property_execute (GladeCommand * cmd)
+{
+  GladeCommandBindProperty *bcmd; 
+  GladeProperty *target, *source;
+  GladeBinding *binding;
+
+  g_return_val_if_fail (GLADE_IS_COMMAND_BIND_PROPERTY (cmd), TRUE);
+  
+  bcmd = GLADE_COMMAND_BIND_PROPERTY (cmd);
+  target = bcmd->target;
+  source = bcmd->undo ? bcmd->old_source : bcmd->new_source;
+  binding = glade_property_get_binding (bcmd->target);
+  
+  if (!binding && source)
+    {
+      glade_property_set_binding (target,
+                                  glade_binding_new (source, target));
+      bcmd->old_source = NULL;
+    }
+  else if (binding)
+    {
+      bcmd->old_source = glade_binding_get_source (binding);
+
+      if (!source)
+        {
+          glade_property_set_binding (target, NULL);
+          glade_property_set_value (target, &bcmd->old_value);
+        }
+      else
+        glade_binding_set_source (binding, source);
+    }
+
+  bcmd->undo = !bcmd->undo;
+  return TRUE;
+}
+
+static void
+glade_command_bind_property_finalize (GObject * obj)
+{
+  glade_command_finalize (obj);
+}
+
+static gboolean
+glade_command_bind_property_unifies (GladeCommand * this_cmd,
+                                     GladeCommand * other_cmd)
+{
+  GladeCommandBindProperty *cmd1, *cmd2;
+
+  if (GLADE_IS_COMMAND_BIND_PROPERTY (this_cmd) &&
+      GLADE_IS_COMMAND_BIND_PROPERTY (other_cmd))
+    {
+      cmd1 = GLADE_COMMAND_BIND_PROPERTY (this_cmd);
+      cmd2 = GLADE_COMMAND_BIND_PROPERTY (other_cmd);
+
+      return (cmd1->target == cmd2->target
+              && cmd1->new_source == cmd2->new_source);
+    }
+
+  return FALSE;
+}
+
+static void
+glade_command_bind_property_collapse (GladeCommand * this_cmd,
+                                      GladeCommand * other_cmd)
+{
+  g_return_if_fail (GLADE_IS_COMMAND_BIND_PROPERTY (this_cmd));
+  g_return_if_fail (GLADE_IS_COMMAND_BIND_PROPERTY (other_cmd));
+
+  /* Nothing to do */
+}
+
+void
+glade_command_bind_property (GladeProperty * target, GladeProperty * source)
+{
+  GladeCommandBindProperty *me;
+  GladeBinding *binding;
+  GladeCommand *cmd;
+  
+  g_return_if_fail (GLADE_IS_PROPERTY (target));
+  g_return_if_fail (GLADE_IS_PROPERTY (source));
+
+  me = g_object_new (GLADE_COMMAND_BIND_PROPERTY_TYPE, NULL);
+  me->target = target;
+  me->new_source = source;
+  me->undo = FALSE;
+  
+  if ((binding = glade_property_get_binding (target)) != NULL)
+    me->old_source = glade_binding_get_source (binding);
+  else
+    {
+      me->old_source = NULL;
+      glade_property_get_value (target, &me->old_value);
+    }
+
+  cmd = GLADE_COMMAND (me);
+  cmd->priv->project =
+    glade_widget_get_project (glade_property_get_widget (me->target));
+  cmd->priv->description =
+      g_strdup_printf (_("Binding property \"%s\" of %s"),
+                       glade_property_class_id (glade_property_get_class (target)),
+                       glade_widget_get_name (glade_property_get_widget (target)));
+
+  glade_command_check_group (GLADE_COMMAND (me));
+
+  if (glade_command_bind_property_execute (GLADE_COMMAND (me)))
+      glade_project_push_undo (cmd->priv->project, cmd);
+  else
+    g_object_unref (G_OBJECT (me));
+}
+
+/**************************************************/
 /*******       GLADE_COMMAND_SET_NAME       *******/
 /**************************************************/
 
diff --git a/gladeui/glade-command.h b/gladeui/glade-command.h
index 0e7837d..4e1c26d 100644
--- a/gladeui/glade-command.h
+++ b/gladeui/glade-command.h
@@ -95,6 +95,9 @@ void           glade_command_set_properties      (GladeProperty *property,
 void           glade_command_set_properties_list (GladeProject  *project, 
 						  GList         *props); /* list of GCSetPropData */
 
+void           glade_command_bind_property        (GladeProperty *target,     
+					           GladeProperty *source);
+
 /************************** name ******************************/
 
 void           glade_command_set_name      (GladeWidget       *glade_widget, const gchar  *name);
diff --git a/gladeui/glade-editor-property.c b/gladeui/glade-editor-property.c
index 61b485a..4022c19 100644
--- a/gladeui/glade-editor-property.c
+++ b/gladeui/glade-editor-property.c
@@ -179,6 +179,80 @@ glade_editor_property_loading (GladeEditorProperty *eprop)
   return eprop->priv->loading;
 }
 
+/**
+ * glade_editor_property_show_bind_dialog:
+ * @parent: The parent widget for the dialog.
+ *
+ * Runs a dialog and updates the provided values.
+ *
+ * Returns: %TRUE if OK was selected.
+ */
+gboolean
+glade_editor_property_show_bind_dialog (GtkWidget * parent,
+                                        gchar ** source_obj,
+                                        gchar ** source_prop)
+{
+  GtkWidget *dialog;
+  GtkWidget *content_area, *action_area;
+  GtkWidget *grid;
+  GtkWidget *obj_label, *prop_label;
+  GtkWidget *obj_entry, *prop_entry;
+  gint res;
+
+  g_return_val_if_fail (source_obj && source_prop, FALSE);
+
+  dialog = gtk_dialog_new_with_buttons (_("Bind Property"),
+                                        parent ?
+                                        GTK_WINDOW (gtk_widget_get_toplevel
+                                                    (parent)) : NULL,
+                                        GTK_DIALOG_MODAL,
+                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                        GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+                                           GTK_RESPONSE_OK,
+                                           GTK_RESPONSE_CANCEL, -1);
+
+  /* HIG spacings */
+  gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+  content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+  gtk_box_set_spacing (GTK_BOX (content_area), 2);      /* 2 * 5 + 2 = 12 */
+  action_area = gtk_dialog_get_action_area (GTK_DIALOG (dialog));
+  gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
+  gtk_box_set_spacing (GTK_BOX (action_area), 6);
+
+  grid = gtk_grid_new ();
+  gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
+
+  obj_entry = gtk_entry_new ();
+  prop_entry = gtk_entry_new ();
+  
+  obj_label = gtk_label_new_with_mnemonic (_("Object:"));
+  prop_label = gtk_label_new_with_mnemonic (_("Property:"));
+  gtk_label_set_mnemonic_widget (GTK_LABEL (obj_label), obj_entry);
+  gtk_label_set_mnemonic_widget (GTK_LABEL (prop_label), prop_entry);  
+
+  gtk_grid_attach (GTK_GRID (grid), obj_label, 0, 0, 1, 1);
+  gtk_grid_attach (GTK_GRID (grid), prop_label, 0, 1, 1, 1);
+  gtk_grid_attach (GTK_GRID (grid), obj_entry, 1, 0, 1, 1);
+  gtk_grid_attach (GTK_GRID (grid), prop_entry, 1, 1, 1, 1);
+
+  gtk_box_pack_start (GTK_BOX (content_area), grid, TRUE, TRUE, 0);
+  gtk_widget_show_all (grid);
+  
+  res = gtk_dialog_run (GTK_DIALOG (dialog));
+  if (res == GTK_RESPONSE_OK)
+    {
+      *source_obj = g_strdup (gtk_entry_get_text (GTK_ENTRY (obj_entry)));
+      *source_prop = g_strdup (gtk_entry_get_text (GTK_ENTRY (prop_entry)));
+    }
+
+  gtk_widget_destroy (dialog);
+  return res;
+}
+
 static void
 glade_editor_property_tooltip_cb (GladeProperty * property,
                                   const gchar * tooltip,
diff --git a/gladeui/glade-editor-property.h b/gladeui/glade-editor-property.h
index d1678ae..b1f7c88 100644
--- a/gladeui/glade-editor-property.h
+++ b/gladeui/glade-editor-property.h
@@ -132,6 +132,10 @@ gboolean             glade_editor_property_show_object_dialog (GladeProject
 							       GladeWidget        *exception,
 							       GladeWidget       **object);
 
+gboolean             glade_editor_property_show_bind_dialog (GtkWidget            *parent,
+                                                             gchar               **source_obj,
+                                                             gchar               **source_prop);
+
 /* Generic eprops */
 #define GLADE_TYPE_EPROP_NUMERIC         (glade_eprop_numeric_get_type())
 #define GLADE_TYPE_EPROP_ENUM            (glade_eprop_enum_get_type())
diff --git a/gladeui/glade-popup.c b/gladeui/glade-popup.c
index 072ea58..5cc8113 100644
--- a/gladeui/glade-popup.c
+++ b/gladeui/glade-popup.c
@@ -618,6 +618,29 @@ glade_popup_palette_pop (GladePalette       *palette,
 }
 
 static void
+glade_popup_bind_property_cb (GtkMenuItem * item, GladeProperty * property)
+{
+  gchar *source_obj, *source_prop;
+
+  if (glade_editor_property_show_bind_dialog (NULL, &source_obj, &source_prop))
+    {
+      GladeWidget *widget = glade_property_get_widget (property);
+      GladeProject *project = glade_widget_get_project (widget);
+      GladeWidget *source_w;
+      GladeProperty *source;
+
+      source_w = glade_project_get_widget_by_name (project, source_obj);
+      g_assert (source_w != NULL);
+      source = glade_widget_get_property (source_w, source_prop);
+      g_assert (source != NULL);
+      
+      glade_command_bind_property (property, source);
+      g_free (source_obj);
+      g_free (source_prop);
+    }
+}
+
+static void
 glade_popup_clear_property_cb (GtkMenuItem * item, GladeProperty * property)
 {
   GValue value = { 0, };
@@ -670,6 +693,9 @@ glade_popup_property_pop (GladeProperty * property, GdkEventButton * event)
 
   popup_menu = gtk_menu_new ();
 
+  glade_popup_append_item (popup_menu, 0, _("Bind to source..."),
+                           NULL, TRUE, glade_popup_bind_property_cb, property);
+
   glade_popup_append_item (popup_menu, GTK_STOCK_CLEAR, _("Set default value"),
                            NULL, TRUE, glade_popup_clear_property_cb, property);
 



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