]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkmodelmenu.c
filechooserbutton: Add tests for unselect_all()
[~andy/gtk] / gtk / gtkmodelmenu.c
index a3d115218509fe226ea6b47fb88a3d6b470ef935..0c3cc5e96ccd94d8fc9baf2c55f261312d16cc83 100644 (file)
@@ -13,9 +13,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  *
  * Author: Matthias Clasen <mclasen@redhat.com>
  *         Ryan Lortie <desrt@desrt.ca>
 
 #include "config.h"
 
-#include "gtkmodelmenu.h"
-
-#include "gtkmenu.h"
+#include "gtkmenushell.h"
 #include "gtkmenubar.h"
+#include "gtkmenu.h"
+
 #include "gtkseparatormenuitem.h"
 #include "gtkmodelmenuitem.h"
+#include "gtkapplicationprivate.h"
+
+#define MODEL_MENU_WIDGET_DATA "gtk-model-menu-widget-data"
 
 typedef struct {
-  GActionObservable *actions;
   GMenuModel        *model;
-  GtkAccelGroup     *accels;
   GtkMenuShell      *shell;
   guint              update_idle;
   GSList            *connected;
   gboolean           with_separators;
   gint               n_items;
+  gchar             *action_namespace;
 } GtkModelMenuBinding;
 
 static void
@@ -49,6 +49,7 @@ gtk_model_menu_binding_items_changed (GMenuModel *model,
                                       gpointer    user_data);
 static void gtk_model_menu_binding_append_model (GtkModelMenuBinding *binding,
                                                  GMenuModel *model,
+                                                 const gchar *action_namespace,
                                                  gboolean with_separators);
 
 static void
@@ -65,13 +66,16 @@ gtk_model_menu_binding_free (gpointer data)
       binding->connected = g_slist_delete_link (binding->connected, binding->connected);
     }
 
-  g_object_unref (binding->actions);
   g_object_unref (binding->model);
+  g_free (binding->action_namespace);
+
+  g_slice_free (GtkModelMenuBinding, binding);
 }
 
 static void
 gtk_model_menu_binding_append_item (GtkModelMenuBinding  *binding,
                                     GMenuModel           *model,
+                                    const gchar          *action_namespace,
                                     gint                  item_index,
                                     gchar               **heading)
 {
@@ -79,14 +83,30 @@ gtk_model_menu_binding_append_item (GtkModelMenuBinding  *binding,
 
   if ((section = g_menu_model_get_item_link (model, item_index, "section")))
     {
+      gchar *section_namespace = NULL;
+
       g_menu_model_get_item_attribute (model, item_index, "label", "s", heading);
-      gtk_model_menu_binding_append_model (binding, section, FALSE);
+      g_menu_model_get_item_attribute (model, item_index, "action-namespace", "s", &section_namespace);
+
+      if (action_namespace)
+        {
+          gchar *namespace = g_strjoin (".", action_namespace, section_namespace, NULL);
+          gtk_model_menu_binding_append_model (binding, section, namespace, FALSE);
+          g_free (namespace);
+        }
+      else
+        {
+          gtk_model_menu_binding_append_model (binding, section, section_namespace, FALSE);
+        }
+
+      g_free (section_namespace);
+      g_object_unref (section);
     }
   else
     {
       GtkMenuItem *item;
 
-      item = gtk_model_menu_item_new (model, item_index, binding->actions, binding->accels);
+      item = gtk_model_menu_item_new (model, item_index, action_namespace);
       gtk_menu_shell_append (binding->shell, GTK_WIDGET (item));
       gtk_widget_show (GTK_WIDGET (item));
       binding->n_items++;
@@ -96,6 +116,7 @@ gtk_model_menu_binding_append_item (GtkModelMenuBinding  *binding,
 static void
 gtk_model_menu_binding_append_model (GtkModelMenuBinding *binding,
                                      GMenuModel          *model,
+                                     const gchar         *action_namespace,
                                      gboolean             with_separators)
 {
   gint n, i;
@@ -138,7 +159,7 @@ gtk_model_menu_binding_append_model (GtkModelMenuBinding *binding,
       gint our_position = binding->n_items;
       gchar *heading = NULL;
 
-      gtk_model_menu_binding_append_item (binding, model, i, &heading);
+      gtk_model_menu_binding_append_item (binding, model, action_namespace, i, &heading);
 
       if (with_separators && our_position < binding->n_items)
         {
@@ -180,7 +201,7 @@ gtk_model_menu_binding_populate (GtkModelMenuBinding *binding)
   binding->n_items = 0;
 
   /* add new items from the model */
-  gtk_model_menu_binding_append_model (binding, binding->model, binding->with_separators);
+  gtk_model_menu_binding_append_model (binding, binding->model, binding->action_namespace, binding->with_separators);
 }
 
 static gboolean
@@ -222,52 +243,80 @@ gtk_model_menu_binding_items_changed (GMenuModel *model,
     }
 }
 
+/**
+ * gtk_menu_shell_bind_model:
+ * @menu_shell: a #GtkMenuShell
+ * @model: (allow-none): the #GMenuModel to bind to or %NULL to remove
+ *   binding
+ * @action_namespace: (allow-none): the namespace for actions in @model
+ * @with_separators: %TRUE if toplevel items in @shell should have
+ *   separators between them
+ *
+ * Establishes a binding between a #GtkMenuShell and a #GMenuModel.
+ *
+ * The contents of @shell are removed and then refilled with menu items
+ * according to @model.  When @model changes, @shell is updated.
+ * Calling this function twice on @shell with different @model will
+ * cause the first binding to be replaced with a binding to the new
+ * model. If @model is %NULL then any previous binding is undone and
+ * all children are removed.
+ *
+ * @with_separators determines if toplevel items (eg: sections) have
+ * separators inserted between them.  This is typically desired for
+ * menus but doesn't make sense for menubars.
+ *
+ * If @action_namespace is non-%NULL then the effect is as if all
+ * actions mentioned in the @model have their names prefixed with the
+ * namespace, plus a dot.  For example, if the action "quit" is
+ * mentioned and @action_namespace is "app" then the effective action
+ * name is "app.quit".
+ *
+ * For most cases you are probably better off using
+ * gtk_menu_new_from_model() or gtk_menu_bar_new_from_model() or just
+ * directly passing the #GMenuModel to gtk_application_set_app_menu() or
+ * gtk_application_set_menu_bar().
+ *
+ * Since: 3.6
+ */
 void
-gtk_model_menu_bind (GtkMenuShell      *shell,
-                     GMenuModel        *model,
-                     GActionObservable *actions,
-                     GtkAccelGroup     *accels,
-                     gboolean           with_separators)
+gtk_menu_shell_bind_model (GtkMenuShell *shell,
+                           GMenuModel   *model,
+                           const gchar  *action_namespace,
+                           gboolean      with_separators)
 {
-  GtkModelMenuBinding *binding;
+  g_return_if_fail (GTK_IS_MENU_SHELL (shell));
+  g_return_if_fail (model == NULL || G_IS_MENU_MODEL (model));
 
-  binding = g_slice_new (GtkModelMenuBinding);
-  binding->model = g_object_ref (model);
-  binding->actions = g_object_ref (actions);
-  binding->accels = accels;
-  binding->shell = shell;
-  binding->update_idle = 0;
-  binding->connected = NULL;
-  binding->with_separators = with_separators;
-
-  g_object_set_data_full (G_OBJECT (shell), "gtk-model-menu-binding", binding, gtk_model_menu_binding_free);
-  gtk_model_menu_binding_populate (binding);
-}
+  if (model)
+    {
+      GtkModelMenuBinding *binding;
 
-GtkWidget *
-gtk_model_menu_create_menu (GMenuModel        *model,
-                            GActionObservable *actions,
-                            GtkAccelGroup     *accels)
-{
-  GtkWidget *menu;
+      binding = g_slice_new (GtkModelMenuBinding);
+      binding->model = g_object_ref (model);
+      binding->shell = shell;
+      binding->update_idle = 0;
+      binding->connected = NULL;
+      binding->with_separators = with_separators;
+      binding->action_namespace = g_strdup (action_namespace);
 
-  menu = gtk_menu_new ();
-  gtk_menu_set_accel_group (GTK_MENU (menu), accels);
-  gtk_model_menu_bind (GTK_MENU_SHELL (menu), model, actions, accels, TRUE);
+      g_object_set_data_full (G_OBJECT (shell), "gtk-model-menu-binding", binding, gtk_model_menu_binding_free);
 
-  return menu;
-}
+      gtk_model_menu_binding_populate (binding);
+    }
 
-GtkWidget *
-gtk_model_menu_create_menu_bar (GMenuModel        *model,
-                                GActionObservable *actions,
-                                GtkAccelGroup     *accels)
-{
-  GtkWidget *menubar;
+  else
+    {
+      GList *children;
 
-  menubar = gtk_menu_bar_new ();
-  gtk_model_menu_bind (GTK_MENU_SHELL (menubar), model, actions, accels, FALSE);
+      /* break existing binding */
+      g_object_set_data (G_OBJECT (shell), "gtk-model-menu-binding", NULL);
 
-  return menubar;
+      /* remove all children */
+      children = gtk_container_get_children (GTK_CONTAINER (shell));
+      while (children)
+        {
+          gtk_container_remove (GTK_CONTAINER (shell), children->data);
+          children = g_list_delete_link (children, children);
+        }
+    }
 }
-