[Glade-devel] [glade-3] Updated patch to support flags properties



--=-rgvuwJvfLqIv5DQULVie
Content-Type: text/plain
Content-Transfer-Encoding: 7bit


Here's an updated patch to support flags properties.
It now updates the entry in the property editor after the dialog is
closed.

OK to commit? Or do we want to put the flags code in a separate file?

Damon


--=-rgvuwJvfLqIv5DQULVie
Content-Disposition: attachment; filename=glade3.patch
Content-Type: text/x-patch; name=glade3.patch; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

Index: src/glade-editor.c
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-editor.c,v
retrieving revision 1.52
diff -u -r1.52 glade-editor.c
--- src/glade-editor.c  21 Apr 2004 21:03:40 -0000      1.52
+++ src/glade-editor.c  25 Apr 2004 14:20:37 -0000
@@ -65,6 +65,8 @@
                                                 gboolean common);
 
 
+static void glade_editor_property_load_flags (GladeEditorProperty *property);
+
 /* marshallers */
 
 static void
@@ -481,6 +483,165 @@
        glade_editor_property_changed_unichar (entry, property);
 }
 
+#define FLAGS_COLUMN_SETTING           0
+#define FLAGS_COLUMN_SYMBOL            1
+
+static void
+flag_toggled (GtkCellRendererToggle *cell,
+             gchar                 *path_string,
+             GtkTreeModel          *model)
+{
+       GtkTreeIter iter;
+       gboolean setting;
+
+       gtk_tree_model_get_iter_from_string (model, &iter, path_string);
+
+       gtk_tree_model_get (model, &iter,
+                           FLAGS_COLUMN_SETTING, &setting,
+                           -1);
+
+       setting = setting ? FALSE : TRUE;
+
+       gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+                           FLAGS_COLUMN_SETTING, setting,
+                           -1);
+}
+
+
+static void
+glade_editor_property_show_flags_dialog (GtkWidget *entry,
+                                        GladeEditorProperty *property)
+{
+       GtkWidget *editor;
+       GtkWidget *dialog;
+       GtkWidget *scrolled_window;
+       GtkListStore *model;
+       GtkWidget *tree_view;
+       GtkTreeViewColumn *column;
+       GtkCellRenderer *renderer;
+       GFlagsClass *class;
+       gint flag_num, response_id;
+       guint value;
+
+       g_return_if_fail (property != NULL);
+
+       editor = gtk_widget_get_toplevel (entry);
+       dialog = gtk_dialog_new_with_buttons (_("Set Flags"),
+                                             GTK_WINDOW (editor),
+                                             GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                             GTK_STOCK_CANCEL,
+                                             GTK_RESPONSE_CANCEL,
+                                             GTK_STOCK_OK,
+                                             GTK_RESPONSE_OK,
+                                             NULL);
+       gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 400);
+
+       scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+                                       GTK_POLICY_AUTOMATIC,
+                                       GTK_POLICY_AUTOMATIC);
+       gtk_widget_show (scrolled_window);
+       gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+                           scrolled_window, TRUE, TRUE, 0);
+
+       /* Create the treeview using a simple list model with 2 columns. */
+       model = gtk_list_store_new (2, G_TYPE_BOOLEAN, G_TYPE_STRING);
+
+       tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
+       gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
+       gtk_widget_show (tree_view);
+       gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
+
+       column = gtk_tree_view_column_new ();
+
+       renderer = gtk_cell_renderer_toggle_new ();
+       gtk_tree_view_column_pack_start (column, renderer, FALSE);
+       gtk_tree_view_column_set_attributes (column, renderer,
+                                            "active", FLAGS_COLUMN_SETTING,
+                                            NULL);
+       g_signal_connect (renderer, "toggled",
+                         G_CALLBACK (flag_toggled), model);
+
+       renderer = gtk_cell_renderer_text_new ();
+       gtk_tree_view_column_pack_start (column, renderer, TRUE);
+       gtk_tree_view_column_set_attributes (column, renderer,
+                                            "text", FLAGS_COLUMN_SYMBOL,
+                                            NULL);
+
+       gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+
+       /* Populate the model with the flags. */
+       class = g_type_class_ref (G_VALUE_TYPE (property->property->value));
+       value = g_value_get_flags (property->property->value);
+
+       /* Step through each of the flags in the class. */
+       for (flag_num = 0; flag_num < class->n_values; flag_num++) {
+               GtkTreeIter iter;
+               guint mask;
+               gboolean setting;
+
+               mask = class->values[flag_num].value;
+               setting = ((value & mask) == mask) ? TRUE : FALSE;
+
+               /* Add a row to represent the flag. */
+               gtk_list_store_append (model, &iter);
+               gtk_list_store_set (model, &iter,
+                                   FLAGS_COLUMN_SETTING,
+                                   setting,
+                                   FLAGS_COLUMN_SYMBOL,
+                                   class->values[flag_num].value_name,
+                                   -1);
+       }
+
+       /* Run the dialog. */
+       response_id = gtk_dialog_run (GTK_DIALOG (dialog));
+
+       /* If the user selects OK, update the flags property. */
+       if (response_id == GTK_RESPONSE_OK) {
+               GtkTreeIter iter;
+               guint new_value = 0;
+
+               gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
+
+               /* Step through each of the flags in the class, checking if
+                  the corresponding toggle in the dialog is selected, If it
+                  is, OR the flags' mask with the new value. */
+               for (flag_num = 0; flag_num < class->n_values; flag_num++) {
+                       gboolean setting;
+
+                       gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
+                                           FLAGS_COLUMN_SETTING, &setting,
+                                           -1);
+
+                       if (setting)
+                               new_value |= class->values[flag_num].value;
+
+                       gtk_tree_model_iter_next (GTK_TREE_MODEL (model),
+                                                 &iter);
+               }
+
+               /* If the new_value is different from the old value, we need
+                  to update the property. */
+               if (new_value != value) {
+                       GValue val = { 0, };
+
+                       g_value_init (&val, G_VALUE_TYPE (property->property->value));
+                       g_value_set_flags (&val, new_value);
+                       glade_command_set_property (property->property, &val);
+                       g_value_unset (&val);
+
+                       /* Update the entry in the property editor. */
+                       glade_editor_property_load_flags (property);
+               }
+
+       }
+
+       g_type_class_unref (class);
+
+       gtk_widget_destroy (dialog);
+}
+
 /* ================================ Create inputs ==================================== */
 static GtkWidget *
 glade_editor_create_input_enum_item (GladeEditorProperty *property,
@@ -530,7 +691,26 @@
 static GtkWidget *
 glade_editor_create_input_flags (GladeEditorProperty *property) 
 {
-       return gtk_label_new ("Fix Me");
+       GtkWidget *hbox;
+       GtkWidget *entry;
+       GtkWidget *button;
+
+       hbox = gtk_hbox_new (FALSE, 0);
+
+       entry = gtk_entry_new ();
+       gtk_entry_set_editable (GTK_ENTRY (entry), FALSE);
+       gtk_widget_show (entry);
+       gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
+
+       button = gtk_button_new_with_label ("...");
+       gtk_widget_show (button);
+       gtk_box_pack_start (GTK_BOX (hbox), button,  FALSE, FALSE, 0);
+
+       g_signal_connect (G_OBJECT (button), "clicked",
+                         G_CALLBACK (glade_editor_property_show_flags_dialog),
+                         property);
+
+       return hbox;
 }
 
 static GtkWidget *
@@ -1175,7 +1355,30 @@
 static void
 glade_editor_property_load_flags (GladeEditorProperty *property)
 {
-       glade_implement_me ();
+       GtkBoxChild *child;
+       GtkWidget *entry;
+       GValue tmp_value = { 0, };
+       gchar *text;
+
+       g_return_if_fail (property != NULL);
+       g_return_if_fail (property->property != NULL);
+       g_return_if_fail (property->property->value != NULL);
+       g_return_if_fail (property->input != NULL);
+       g_return_if_fail (GTK_IS_HBOX (property->input));
+
+       /* The entry should be the first child. */
+       child = GTK_BOX (property->input)->children->data;
+       entry = child->widget;
+       g_return_if_fail (GTK_IS_ENTRY (entry));
+
+       /* Transform the GValue from flags to a string. */
+       g_value_init (&tmp_value, G_TYPE_STRING);
+       g_value_transform (property->property->value, &tmp_value);
+       text = g_strescape (g_value_get_string (&tmp_value), NULL);
+       g_value_unset (&tmp_value);
+
+       gtk_entry_set_text (GTK_ENTRY (entry), text);
+       g_free (text);
 }
 
 static void
Index: src/glade-property-class.h
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-property-class.h,v
retrieving revision 1.27
diff -u -r1.27 glade-property-class.h
--- src/glade-property-class.h  7 Nov 2003 16:20:17 -0000       1.27
+++ src/glade-property-class.h  25 Apr 2004 14:20:56 -0000
@@ -132,8 +132,9 @@
                            * and is NULL for other poperties.
                            * [See glade-choice.h]
                            */
-       GType enum_type;   /* If it is GLADE_PROPERTY_TYPE_ENUM, this holds
-                           * the GType of the enum, otherwise it's 0.
+       GType enum_type;   /* If it is GLADE_PROPERTY_TYPE_ENUM or
+                           * GLADE_PROPERTY_TYPE_FLAGS, this holds
+                           * the GType of the enum or flags, otherwise it's 0.
                            */
 
        gboolean optional; /* Some properties are optional by nature like
Index: src/glade-property-class.c
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-property-class.c,v
retrieving revision 1.53
diff -u -r1.53 glade-property-class.c
--- src/glade-property-class.c  27 Jan 2004 18:27:40 -0000      1.53
+++ src/glade-property-class.c  25 Apr 2004 14:21:00 -0000
@@ -259,11 +259,7 @@
        } else if (G_IS_PARAM_SPEC_ENUM (spec)) {
                return GLADE_PROPERTY_TYPE_ENUM;
        } else if (G_IS_PARAM_SPEC_FLAGS (spec)) {
-               /* FIXME: We should implement the "events" property */
-               if (g_ascii_strcasecmp (spec->name, "events") == 0)
-                       return GLADE_PROPERTY_TYPE_ERROR;
-               else
-                       return GLADE_PROPERTY_TYPE_FLAGS;
+               return GLADE_PROPERTY_TYPE_FLAGS;
        } else if (G_IS_PARAM_SPEC_DOUBLE (spec)) {
                return GLADE_PROPERTY_TYPE_DOUBLE;
        } else if (G_IS_PARAM_SPEC_LONG (spec)) {
@@ -385,6 +381,17 @@
                        }
                }
                break;
+       case GLADE_PROPERTY_TYPE_FLAGS:
+               {
+                       GValue tmp_value = { 0, };
+
+                       g_value_init (&tmp_value, G_TYPE_STRING);
+                       g_value_transform (value, &tmp_value);
+                       string = g_strescape (g_value_get_string (&tmp_value),
+                                             NULL);
+                       g_value_unset (&tmp_value);
+               }
+               break;
        default:
                g_warning ("Could not make string from gvalue for type %s\n",
                         glade_property_type_enum_to_string (type));
@@ -393,6 +400,86 @@
        return string;
 }
 
+/* This is copied exactly from libglade. I've just renamed the function. */
+static guint
+glade_property_class_make_flags_from_string (GType type, const char *string)
+{
+    GFlagsClass *fclass;
+    gchar *endptr, *prevptr;
+    guint i, j, ret = 0;
+    char *flagstr;
+
+    ret = strtoul(string, &endptr, 0);
+    if (endptr != string) /* parsed a number */
+       return ret;
+
+    fclass = g_type_class_ref(type);
+
+
+    flagstr = g_strdup (string);
+    for (ret = i = j = 0; ; i++) {
+       gboolean eos;
+
+       eos = flagstr [i] == '\0';
+       
+       if (eos || flagstr [i] == '|') {
+           GFlagsValue *fv;
+           const char  *flag;
+           gunichar ch;
+
+           flag = &flagstr [j];
+            endptr = &flagstr [i];
+
+           if (!eos) {
+               flagstr [i++] = '\0';
+               j = i;
+           }
+
+            /* trim spaces */
+           for (;;)
+             {
+               ch = g_utf8_get_char (flag);
+               if (!g_unichar_isspace (ch))
+                 break;
+               flag = g_utf8_next_char (flag);
+             }
+
+           while (endptr > flag)
+             {
+               prevptr = g_utf8_prev_char (endptr);
+               ch = g_utf8_get_char (prevptr);
+               if (!g_unichar_isspace (ch))
+                 break;
+               endptr = prevptr;
+             }
+
+           if (endptr > flag)
+             {
+               *endptr = '\0';
+               fv = g_flags_get_value_by_name (fclass, flag);
+
+               if (!fv)
+                 fv = g_flags_get_value_by_nick (fclass, flag);
+
+               if (fv)
+                 ret |= fv->value;
+               else
+                 g_warning ("Unknown flag: '%s'", flag);
+             }
+
+           if (eos)
+               break;
+       }
+    }
+    
+    g_free (flagstr);
+
+    g_type_class_unref(fclass);
+
+    return ret;
+}
+
+
 GValue *
 glade_property_class_make_gvalue_from_string (GladePropertyClass *property_class,
                                              const gchar *string)
@@ -454,6 +541,14 @@
                        }
                }
                break;
+       case GLADE_PROPERTY_TYPE_FLAGS:
+               {
+                       guint flags;
+
+                       g_value_init (value, property_class->enum_type);
+                       flags = glade_property_class_make_flags_from_string (property_class->enum_type, 
string);
+                       g_value_set_flags (value, flags);
+               }
        case GLADE_PROPERTY_TYPE_OBJECT:
                break;
        default:
@@ -562,6 +657,7 @@
                property_class->enum_type = spec->value_type;
                break;
        case GLADE_PROPERTY_TYPE_FLAGS:
+               property_class->enum_type = spec->value_type;
                break;
        case GLADE_PROPERTY_TYPE_STRING:
                break;

--=-rgvuwJvfLqIv5DQULVie--





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