[gtk+] GtkBuilder: Make IDs optional



commit df455db2e320be73cbc39a67e69eeeee19375aba
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Nov 17 20:15:54 2013 -0500

    GtkBuilder: Make IDs optional
    
    One requirement of .ui files is that each object must have an ID,
    even if it is never referred to or directly loaded from the code.
    This makes editing .ui files much more onerous than it has to be,
    due to the frequent need to invent new IDs, while avoiding
    clashes.
    
    This commit makes IDs optional in the XML. They only need to
    be provided for objects which are referred to or explictly loaded
    from the code. Since GtkBuilder needs IDs for its own internal
    accounting, we create IDs of the form ___object_N___ if not
    specified in the XML.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=712553

 gtk/gtkbuilder.c        |   11 ++-------
 gtk/gtkbuilder.rnc      |    2 +-
 gtk/gtkbuilder.rng      |    8 ++++--
 gtk/gtkbuilderparser.c  |    8 +++---
 gtk/gtkbuilderprivate.h |    2 +
 testsuite/gtk/builder.c |   48 +++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 63 insertions(+), 16 deletions(-)
---
diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c
index c6b6b25..695b53e 100644
--- a/gtk/gtkbuilder.c
+++ b/gtk/gtkbuilder.c
@@ -100,17 +100,12 @@
  * specifying the id of the #GtkUIManager in the "constructor" attribute and the
  * name of the object in the "id" attribute.
  *
- * Objects must be given a name with the "id" attribute, which allows the
+ * Objects may be given a name with the "id" attribute, which allows the
  * application to retrieve them from the builder with gtk_builder_get_object().
  * An id is also necessary to use the object as property value in other parts of
- * the UI definition.
+ * the UI definition. GTK+ reserves ids starting and ending with ___ (3 underscores)
+ * for its own purposes.
  * </para>
- * <note><para>
- * Prior to 2.20, GtkBuilder was setting the "name" property of constructed widgets to the
- * "id" attribute. In GTK+ 2.20 or newer, you have to use gtk_buildable_get_name() instead
- * of gtk_widget_get_name() to obtain the "id", or set the "name" property in your UI
- * definition.
- * </para></note>
  * <para>
  * Setting properties of objects is pretty straightforward with the
  * &lt;property&gt; element: the "name" attribute specifies the name of the
diff --git a/gtk/gtkbuilder.rnc b/gtk/gtkbuilder.rnc
index 635fd4f..6e3aea3 100644
--- a/gtk/gtkbuilder.rnc
+++ b/gtk/gtkbuilder.rnc
@@ -9,7 +9,7 @@ requires = element requires {
 }
 
 object = element object {
-  attribute id { xsd:ID },
+  attribute id { xsd:ID } ?,
   attribute class { text },
   attribute type-func { text } ?,
   attribute constructor { text } ?,
diff --git a/gtk/gtkbuilder.rng b/gtk/gtkbuilder.rng
index eee698a..341d19f 100644
--- a/gtk/gtkbuilder.rng
+++ b/gtk/gtkbuilder.rng
@@ -29,9 +29,11 @@
   </define>
   <define name="object">
     <element name="object">
-      <attribute name="id">
-        <data type="ID" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"/>
-      </attribute>
+      <optional>
+        <attribute name="id">
+          <data type="ID" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"/>
+        </attribute>
+      </optional>
       <attribute name="class">
         <text/>
       </attribute>
diff --git a/gtk/gtkbuilderparser.c b/gtk/gtkbuilderparser.c
index 11e04cb..e2111d6 100644
--- a/gtk/gtkbuilderparser.c
+++ b/gtk/gtkbuilderparser.c
@@ -301,7 +301,7 @@ is_requested_object (const gchar *object,
 
   for (l = data->requested_objects; l; l = l->next)
     {
-      if (strcmp (l->data, object) == 0)
+      if (g_strcmp0 (l->data, object) == 0)
         return TRUE;
     }
 
@@ -369,10 +369,11 @@ parse_object (GMarkupParseContext  *context,
       return;
     }
 
+  data->object_counter++;
+
   if (!object_id)
     {
-      error_missing_attribute (data, element_name, "id", error);
-      return;
+      object_id = g_strdup_printf ("___object_%d___", data->object_counter++);
     }
 
   ++data->cur_object_level;
@@ -420,7 +421,6 @@ parse_object (GMarkupParseContext  *context,
       return;
     }
 
-
   g_hash_table_insert (data->object_ids, g_strdup (object_id), GINT_TO_POINTER (line));
 }
 
diff --git a/gtk/gtkbuilderprivate.h b/gtk/gtkbuilderprivate.h
index 346459c..b653373 100644
--- a/gtk/gtkbuilderprivate.h
+++ b/gtk/gtkbuilderprivate.h
@@ -107,6 +107,8 @@ typedef struct {
   gint requested_object_level;
   gint cur_object_level;
 
+  gint object_counter;
+
   GHashTable *object_ids;
 } ParserData;
 
diff --git a/testsuite/gtk/builder.c b/testsuite/gtk/builder.c
index 0858262..d20fba6 100644
--- a/testsuite/gtk/builder.c
+++ b/testsuite/gtk/builder.c
@@ -2728,6 +2728,53 @@ test_expose_object (void)
   g_object_unref (image);
 }
 
+static void
+test_no_ids (void)
+{
+  GtkBuilder *builder;
+  GError *error = NULL;
+  GObject *obj;
+  const gchar buffer[] =
+    "<interface>"
+    "  <object class=\"GtkInfoBar\">"
+    "    <child internal-child=\"content_area\">"
+    "      <object class=\"GtkHBox\">"
+    "        <child>"
+    "          <object class=\"GtkLabel\">"
+    "            <property name=\"label\" translatable=\"yes\">Message</property>"
+    "          </object>"
+    "          <packing>"
+    "            <property name='expand'>False</property>"
+    "          </packing>"
+    "        </child>"
+    "      </object>"
+    "    </child>"
+    "    <child internal-child=\"action_area\">"
+    "      <object class=\"GtkVButtonBox\">"
+    "        <child>"
+    "          <object class=\"GtkButton\" id=\"button_ok\">"
+    "            <property name=\"label\">gtk-ok</property>"
+    "            <property name=\"use-stock\">yes</property>"
+    "          </object>"
+    "        </child>"
+    "      </object>"
+    "    </child>"
+    "    <action-widgets>"
+    "      <action-widget response=\"1\">button_ok</action-widget>"
+    "    </action-widgets>"
+    "  </object>"
+    "</interface>";
+
+  builder = gtk_builder_new ();
+  gtk_builder_add_from_string (builder, buffer, -1, &error);
+  g_assert (error == NULL);
+
+  obj = gtk_builder_get_object (builder, "button_ok");
+  g_assert (GTK_IS_BUTTON (obj));
+
+  g_object_unref (builder);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -2777,6 +2824,7 @@ main (int argc, char **argv)
   g_test_add_func ("/Builder/GMenu", test_gmenu);
   g_test_add_func ("/Builder/LevelBar", test_level_bar);
   g_test_add_func ("/Builder/Expose Object", test_expose_object);
+  g_test_add_func ("/Builder/No IDs", test_no_ids);
 
   return g_test_run();
 }


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