gtk+ r21767 - in trunk: . docs/reference/gtk/tmpl gtk gtk/tests



Author: tvb
Date: Thu Nov  6 17:34:30 2008
New Revision: 21767
URL: http://svn.gnome.org/viewvc/gtk+?rev=21767&view=rev

Log:

	* gtk/gtkmenuitem.c: Made buildable and added support for adding children
	of type "submenu"

	* gtk/gtkwindow.c: Added support for custom tag "accel-groups" to add GtkAccelGroups
	to the window.

	* gtk/gtkcontainer.c: Added builder contextual warnings in buildable_add_child()

	* gtk/tests/builder.c: Added tests for buildable menus (test that accelerators are
	properly connected on stock items, test the menu hierarchy, test permission to
	add alien/custom menuitem children).

	* docs/reference/gtk/tmpl/gtkbuilder.sgml, docs/reference/gtk/tmpl/gtkwindow.sgml,
	docs/reference/gtk/tmpl/gtkmenuitem.sgml: Updated docs for buildable submenus
	and accel groups.



Modified:
   trunk/ChangeLog
   trunk/docs/reference/gtk/tmpl/gtkbuilder.sgml
   trunk/docs/reference/gtk/tmpl/gtkmenuitem.sgml
   trunk/docs/reference/gtk/tmpl/gtkwindow.sgml
   trunk/gtk/gtkcontainer.c
   trunk/gtk/gtkmenuitem.c
   trunk/gtk/gtkwindow.c
   trunk/gtk/tests/builder.c

Modified: trunk/docs/reference/gtk/tmpl/gtkbuilder.sgml
==============================================================================
--- trunk/docs/reference/gtk/tmpl/gtkbuilder.sgml	(original)
+++ trunk/docs/reference/gtk/tmpl/gtkbuilder.sgml	Thu Nov  6 17:34:30 2008
@@ -212,6 +212,7 @@
 respective objects, see 
 <link linkend="GtkWidget-BUILDER-UI">GtkWidget</link>,
 <link linkend="GtkLabel-BUILDER-UI">GtkLabel</link>,
+<link linkend="GtkWindow-BUILDER-UI">GtkWindow</link>,
 <link linkend="GtkContainer-BUILDER-UI">GtkContainer</link>,
 <link linkend="GtkDialog-BUILDER-UI">GtkDialog</link>,
 <link linkend="GtkCellLayout-BUILDER-UI">GtkCellLayout</link>,
@@ -227,6 +228,7 @@
 <link linkend="GtkTreeView-BUILDER-UI">GtkTreeView</link>,
 <link linkend="GtkUIManager-BUILDER-UI">GtkUIManager</link>,
 <link linkend="GtkActionGroup-BUILDER-UI">GtkActionGroup</link>.
+<link linkend="GtkMenuItem-BUILDER-UI">GtkMenuItem</link>.
 </para>
 </refsect2>
 

Modified: trunk/docs/reference/gtk/tmpl/gtkmenuitem.sgml
==============================================================================
--- trunk/docs/reference/gtk/tmpl/gtkmenuitem.sgml	(original)
+++ trunk/docs/reference/gtk/tmpl/gtkmenuitem.sgml	Thu Nov  6 17:34:30 2008
@@ -14,6 +14,24 @@
 As it derives from #GtkBin it can hold any valid child widget, altough
 only a few are really useful.
 </para>
+<refsect2 id="GtkMenuItem-BUILDER-UI">
+<title>GtkMenuItem as GtkBuildable</title>
+<para>
+The GtkMenuItem implementation of the GtkBuildable interface
+supports adding a submenu by specifying "submenu" as the "type" 
+attribute of a &lt;child&gt; element.
+</para>
+<example>
+<title>A UI definition fragment with submenus</title>
+<programlisting><![CDATA[
+<object class="GtkMenuItem">
+  <child type="submenu">
+    <object class="GtkMenu"/>
+  </child>
+</object>
+]]></programlisting>
+</example>
+</refsect2>
 
 <!-- ##### SECTION See_Also ##### -->
 <para>

Modified: trunk/docs/reference/gtk/tmpl/gtkwindow.sgml
==============================================================================
--- trunk/docs/reference/gtk/tmpl/gtkwindow.sgml	(original)
+++ trunk/docs/reference/gtk/tmpl/gtkwindow.sgml	Thu Nov  6 17:34:30 2008
@@ -8,6 +8,29 @@
 <para>
 
 </para>
+<refsect2 id="GtkWindow-BUILDER-UI">
+<title>GtkWindow as GtkBuildable</title>
+<para>
+The GtkWindow implementation of the GtkBuildable interface supports a 
+custom &lt;accel-groups&gt; element, which supports any number of &lt;group&gt;
+elements representing the GtkAccelGroup objects you want to add to your
+window (synonymous with gtk_window_add_accel_group().
+</para>
+<example>
+<title>A UI definition fragment with accel groups</title>
+<programlisting><![CDATA[
+<object class="GtkWindow">
+  <accel-groups>
+    <group name="accelgroup1"/>
+  </accel-groups>
+</object>
+
+...
+
+<object class="GtkAccelGroup" id="accelgroup1"/>
+]]></programlisting>
+</example>
+</refsect2>
 
 <!-- ##### SECTION See_Also ##### -->
 <para>

Modified: trunk/gtk/gtkcontainer.c
==============================================================================
--- trunk/gtk/gtkcontainer.c	(original)
+++ trunk/gtk/gtkcontainer.c	Thu Nov  6 17:34:30 2008
@@ -307,9 +307,17 @@
 				   GObject       *child,
 				   const gchar   *type)
 {
-  g_return_if_fail (GTK_IS_WIDGET (child));
-
-  gtk_container_add (GTK_CONTAINER (buildable), GTK_WIDGET (child));
+  if (type)
+    {
+      GTK_BUILDER_WARN_INVALID_CHILD_TYPE (buildable, type);
+    }
+  else if (GTK_IS_WIDGET (child) && GTK_WIDGET_TOPLEVEL (child) == FALSE)
+    {
+      gtk_container_add (GTK_CONTAINER (buildable), GTK_WIDGET (child));
+    }
+  else
+    g_warning ("Cannot add an object of type %s to a container of type %s", 
+	       g_type_name (G_OBJECT_TYPE (child)), g_type_name (G_OBJECT_TYPE (buildable)));
 }
 
 static void

Modified: trunk/gtk/gtkmenuitem.c
==============================================================================
--- trunk/gtk/gtkmenuitem.c	(original)
+++ trunk/gtk/gtkmenuitem.c	Thu Nov  6 17:34:30 2008
@@ -36,6 +36,7 @@
 #include "gtkmenubar.h"
 #include "gtkseparatormenuitem.h"
 #include "gtkprivate.h"
+#include "gtkbuildable.h"
 #include "gtkintl.h"
 #include "gtkalias.h"
 
@@ -113,9 +114,19 @@
 static G_CONST_RETURN gchar * gtk_real_menu_item_get_label (GtkMenuItem *menu_item);
 
 
+static void gtk_menu_item_buildable_interface_init (GtkBuildableIface   *iface);
+static void gtk_menu_item_buildable_add_child      (GtkBuildable        *buildable,
+						    GtkBuilder          *builder,
+						    GObject             *child,
+						    const gchar         *type);
+
 static guint menu_item_signals[LAST_SIGNAL] = { 0 };
 
-G_DEFINE_TYPE (GtkMenuItem, gtk_menu_item, GTK_TYPE_ITEM)
+static GtkBuildableIface *parent_buildable_iface;
+
+G_DEFINE_TYPE_WITH_CODE (GtkMenuItem, gtk_menu_item, GTK_TYPE_ITEM,
+			 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+						gtk_menu_item_buildable_interface_init))
 
 static void
 gtk_menu_item_class_init (GtkMenuItemClass *klass)
@@ -474,6 +485,26 @@
   menu_item->submenu = NULL;
 }
 
+static void
+gtk_menu_item_buildable_interface_init (GtkBuildableIface *iface)
+{
+  parent_buildable_iface = g_type_interface_peek_parent (iface);
+  iface->add_child = gtk_menu_item_buildable_add_child;
+}
+
+static void 
+gtk_menu_item_buildable_add_child (GtkBuildable *buildable,
+				   GtkBuilder   *builder,
+				   GObject      *child,
+				   const gchar  *type)
+{
+  if (type && strcmp (type, "submenu") == 0)
+	gtk_menu_item_set_submenu (GTK_MENU_ITEM (buildable),
+				   GTK_WIDGET (child));
+  else
+    parent_buildable_iface->add_child (buildable, builder, child, type);
+}
+
 /**
  * gtk_menu_item_set_submenu:
  * @menu_item: a #GtkMenuItem

Modified: trunk/gtk/gtkwindow.c
==============================================================================
--- trunk/gtk/gtkwindow.c	(original)
+++ trunk/gtk/gtkwindow.c	Thu Nov  6 17:34:30 2008
@@ -310,6 +310,7 @@
 static GQuark       quark_gtk_window_key_hash = 0;
 static GQuark       quark_gtk_window_default_icon_pixmap = 0;
 static GQuark       quark_gtk_window_icon_info = 0;
+static GQuark       quark_gtk_buildable_accels = 0;
 
 static GtkBuildableIface *parent_buildable_iface;
 
@@ -330,6 +331,17 @@
 							 const GValue        *value);
 static void gtk_window_buildable_parser_finished (GtkBuildable     *buildable,
 						  GtkBuilder       *builder);
+static gboolean gtk_window_buildable_custom_tag_start (GtkBuildable  *buildable,
+						       GtkBuilder    *builder,
+						       GObject       *child,
+						       const gchar   *tagname,
+						       GMarkupParser *parser,
+						       gpointer      *data);
+static void gtk_window_buildable_custom_finished (GtkBuildable  *buildable,
+						      GtkBuilder    *builder,
+						      GObject       *child,
+						      const gchar   *tagname,
+						      gpointer       user_data);
 
 
 G_DEFINE_TYPE_WITH_CODE (GtkWindow, gtk_window, GTK_TYPE_BIN,
@@ -415,6 +427,7 @@
   quark_gtk_window_key_hash = g_quark_from_static_string ("gtk-window-key-hash");
   quark_gtk_window_default_icon_pixmap = g_quark_from_static_string ("gtk-window-default-icon-pixmap");
   quark_gtk_window_icon_info = g_quark_from_static_string ("gtk-window-icon-info");
+  quark_gtk_buildable_accels = g_quark_from_static_string ("gtk-window-buildable-accels");
 
   gobject_class->dispose = gtk_window_dispose;
   gobject_class->finalize = gtk_window_finalize;
@@ -1137,7 +1150,8 @@
   parent_buildable_iface = g_type_interface_peek_parent (iface);
   iface->set_buildable_property = gtk_window_buildable_set_buildable_property;
   iface->parser_finished = gtk_window_buildable_parser_finished;
-
+  iface->custom_tag_start = gtk_window_buildable_custom_tag_start;
+  iface->custom_finished = gtk_window_buildable_custom_finished;
 }
 
 static void
@@ -1159,11 +1173,118 @@
 				      GtkBuilder   *builder)
 {
   GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (buildable);
+  GObject *object;
+  GSList *accels, *l;
 
   if (priv->builder_visible)
     gtk_widget_show (GTK_WIDGET (buildable));
 
-    parent_buildable_iface->parser_finished (buildable, builder);
+  accels = g_object_get_qdata (G_OBJECT (buildable), quark_gtk_buildable_accels);
+  for (l = accels; l; l = l->next)
+    {
+      object = gtk_builder_get_object (builder, l->data);
+      if (!object)
+	{
+	  g_warning ("Unknown accel group %s specified in window %s",
+		     (const gchar*)l->data, gtk_buildable_get_name (buildable));
+	  continue;
+	}
+      gtk_window_add_accel_group (GTK_WINDOW (buildable),
+				  GTK_ACCEL_GROUP (object));
+      g_free (l->data);
+    }
+
+  g_object_set_qdata (G_OBJECT (buildable), quark_gtk_buildable_accels, NULL);
+
+  parent_buildable_iface->parser_finished (buildable, builder);
+}
+
+typedef struct {
+  GObject *object;
+  GSList *items;
+} GSListSubParserData;
+
+static void
+window_start_element (GMarkupParseContext *context,
+			  const gchar         *element_name,
+			  const gchar        **names,
+			  const gchar        **values,
+			  gpointer            user_data,
+			  GError            **error)
+{
+  guint i;
+  GSListSubParserData *data = (GSListSubParserData*)user_data;
+
+  if (strcmp (element_name, "group") == 0)
+    {
+      for (i = 0; names[i]; i++)
+	{
+	  if (strcmp (names[i], "name") == 0)
+	    data->items = g_slist_prepend (data->items, g_strdup (values[i]));
+	}
+    }
+  else if (strcmp (element_name, "accel-groups") == 0)
+    return;
+  else
+    g_warning ("Unsupported tag type for GtkWindow: %s\n",
+	       element_name);
+
+}
+
+static const GMarkupParser window_parser =
+  {
+    window_start_element
+  };
+
+static gboolean
+gtk_window_buildable_custom_tag_start (GtkBuildable  *buildable,
+				       GtkBuilder    *builder,
+				       GObject       *child,
+				       const gchar   *tagname,
+				       GMarkupParser *parser,
+				       gpointer      *data)
+{
+  GSListSubParserData *parser_data;
+
+  if (parent_buildable_iface->custom_tag_start (buildable, builder, child, 
+						tagname, parser, data))
+    return TRUE;
+
+  if (strcmp (tagname, "accel-groups") == 0)
+    {
+      parser_data = g_slice_new0 (GSListSubParserData);
+      parser_data->items = NULL;
+      parser_data->object = G_OBJECT (buildable);
+
+      *parser = window_parser;
+      *data = parser_data;
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+gtk_window_buildable_custom_finished (GtkBuildable  *buildable,
+					  GtkBuilder    *builder,
+					  GObject       *child,
+					  const gchar   *tagname,
+					  gpointer       user_data)
+{
+  GSListSubParserData *data;
+
+  parent_buildable_iface->custom_finished (buildable, builder, child, 
+					   tagname, user_data);
+
+  if (strcmp (tagname, "accel-groups") != 0)
+    return;
+  
+  data = (GSListSubParserData*)user_data;
+
+  g_object_set_qdata_full (G_OBJECT (buildable), quark_gtk_buildable_accels, 
+			   data->items, (GDestroyNotify) g_slist_free);
+
+  g_slice_free (GSListSubParserData, data);
 }
 
 /**

Modified: trunk/gtk/tests/builder.c
==============================================================================
--- trunk/gtk/tests/builder.c	(original)
+++ trunk/gtk/tests/builder.c	Thu Nov  6 17:34:30 2008
@@ -2282,6 +2282,158 @@
   g_object_unref (builder);
 }
 
+GtkWidget *
+get_parent_menubar (GtkWidget *menuitem)
+{
+  GtkMenuShell *menu_shell = (GtkMenuShell *)menuitem->parent;
+  GtkWidget *attach = NULL;
+
+  g_assert (GTK_IS_MENU_SHELL (menu_shell));
+
+  while (menu_shell && !GTK_IS_MENU_BAR (menu_shell))
+    {
+      if (GTK_IS_MENU (menu_shell) && 
+	  (attach = gtk_menu_get_attach_widget (GTK_MENU (menu_shell))) != NULL)
+	menu_shell = (GtkMenuShell *)attach->parent;
+      else
+	menu_shell = NULL;
+    }
+
+  return menu_shell ? GTK_WIDGET (menu_shell) : NULL;
+}
+
+static void
+test_menus (void)
+{
+  gchar *buffer =
+    "<interface>"
+    "  <object class=\"GtkWindow\" id=\"window1\">"
+    "    <accel-groups>"
+    "      <group name=\"accelgroup1\"/>"
+    "    </accel-groups>"
+    "    <child>"
+    "      <object class=\"GtkVBox\" id=\"vbox1\">"
+    "        <property name=\"visible\">True</property>"
+    "        <property name=\"orientation\">vertical</property>"
+    "        <child>"
+    "          <object class=\"GtkMenuBar\" id=\"menubar1\">"
+    "            <property name=\"visible\">True</property>"
+    "            <child>"
+    "              <object class=\"GtkMenuItem\" id=\"menuitem1\">"
+    "                <property name=\"visible\">True</property>"
+    "                <property name=\"label\" translatable=\"yes\">_File</property>"
+    "                <property name=\"use_underline\">True</property>"
+    "                <child type=\"submenu\">"
+    "                  <object class=\"GtkMenu\" id=\"menu1\">"
+    "                    <property name=\"visible\">True</property>"
+    "                    <child>"
+    "                      <object class=\"GtkImageMenuItem\" id=\"imagemenuitem1\">"
+    "                        <property name=\"label\">gtk-new</property>"
+    "                        <property name=\"visible\">True</property>"
+    "                        <property name=\"use_stock\">True</property>"
+    "                        <property name=\"accel_group\">accelgroup1</property>"
+    "                      </object>"
+    "                    </child>"
+    "                  </object>"
+    "                </child>"
+    "              </object>"
+    "            </child>"
+    "          </object>"
+    "        </child>"
+    "      </object>"
+    "    </child>"
+    "  </object>"
+    "<object class=\"GtkAccelGroup\" id=\"accelgroup1\"/>"
+    "</interface>";
+
+  gchar *buffer1 =
+    "<interface>"
+    "  <object class=\"GtkWindow\" id=\"window1\">"
+    "    <accel-groups>"
+    "      <group name=\"accelgroup1\"/>"
+    "    </accel-groups>"
+    "    <child>"
+    "      <object class=\"GtkVBox\" id=\"vbox1\">"
+    "        <property name=\"visible\">True</property>"
+    "        <property name=\"orientation\">vertical</property>"
+    "        <child>"
+    "          <object class=\"GtkMenuBar\" id=\"menubar1\">"
+    "            <property name=\"visible\">True</property>"
+    "            <child>"
+    "              <object class=\"GtkImageMenuItem\" id=\"imagemenuitem1\">"
+    "                <property name=\"visible\">True</property>"
+    "                <child>"
+    "                  <object class=\"GtkLabel\" id=\"custom1\">"
+    "                    <property name=\"visible\">True</property>"
+    "                    <property name=\"label\">a label</property>"
+    "                  </object>"
+    "                </child>"
+    "              </object>"
+    "            </child>"
+    "          </object>"
+    "        </child>"
+    "      </object>"
+    "    </child>"
+    "  </object>"
+    "<object class=\"GtkAccelGroup\" id=\"accelgroup1\"/>"
+    "</interface>";
+  GtkBuilder *builder;
+  GtkWidget *window, *item;
+  GtkAccelGroup *accel_group;
+  GtkWidget *item_accel_label, *sample_accel_label, *sample_menu_item, *custom;
+
+  /* Check that the item has the correct accel label string set
+   */
+  builder = builder_new_from_string (buffer, -1, NULL);
+  window = (GtkWidget *)gtk_builder_get_object (builder, "window1");
+  item = (GtkWidget *)gtk_builder_get_object (builder, "imagemenuitem1");
+  accel_group = (GtkAccelGroup *)gtk_builder_get_object (builder, "accelgroup1");
+
+  gtk_widget_show_all (window);
+
+  sample_menu_item = gtk_image_menu_item_new_from_stock (GTK_STOCK_NEW, accel_group);
+
+  g_assert (GTK_BIN (sample_menu_item)->child);
+  g_assert (GTK_IS_ACCEL_LABEL (GTK_BIN (sample_menu_item)->child));
+  sample_accel_label = GTK_WIDGET (GTK_BIN (sample_menu_item)->child);
+  gtk_widget_show (sample_accel_label);
+
+  g_assert (GTK_BIN (item)->child);
+  g_assert (GTK_IS_ACCEL_LABEL (GTK_BIN (item)->child));
+  item_accel_label = GTK_WIDGET (GTK_BIN (item)->child);
+
+  gtk_accel_label_refetch (GTK_ACCEL_LABEL (sample_accel_label));
+  gtk_accel_label_refetch (GTK_ACCEL_LABEL (item_accel_label));
+
+  g_assert (GTK_ACCEL_LABEL (sample_accel_label)->accel_string != NULL);
+  g_assert (GTK_ACCEL_LABEL (item_accel_label)->accel_string != NULL);
+  g_assert (strcmp (GTK_ACCEL_LABEL (item_accel_label)->accel_string, 
+		    GTK_ACCEL_LABEL (sample_accel_label)->accel_string) == 0);
+
+  /* Check the menu heirarchy worked here  */
+  g_assert (get_parent_menubar (item));
+
+  gtk_widget_destroy (GTK_WIDGET (window));
+  gtk_widget_destroy (sample_menu_item);
+  g_object_unref (builder);
+
+
+  /* Check that we can add alien children to menu items via normal
+   * GtkContainer apis.
+   */
+  builder = builder_new_from_string (buffer1, -1, NULL);
+  window = (GtkWidget *)gtk_builder_get_object (builder, "window1");
+  item = (GtkWidget *)gtk_builder_get_object (builder, "imagemenuitem1");
+  custom = (GtkWidget *)gtk_builder_get_object (builder, "custom1");
+
+  g_assert (custom->parent == item);
+
+  gtk_widget_destroy (GTK_WIDGET (window));
+  g_object_unref (builder);
+
+}
+
+
 static void 
 test_file (const gchar *filename)
 {
@@ -2367,6 +2519,7 @@
   g_test_add_func ("/Builder/PangoAttributes", test_pango_attributes);
   g_test_add_func ("/Builder/Requires", test_requires);
   g_test_add_func ("/Builder/AddObjects", test_add_objects);
+  g_test_add_func ("/Builder/Menus", test_menus);
 
   return g_test_run();
 }



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