diff options
author | Juan Pablo Ugarte <jpu@src.gnome.org> | 2007-05-23 19:38:46 +0000 |
---|---|---|
committer | Juan Pablo Ugarte <jpu@src.gnome.org> | 2007-05-23 19:38:46 +0000 |
commit | b9d029623faf79fd9cb70bed9653f5dffa4ec0ad (patch) | |
tree | fcb4b97d636ba45ecf440498f6c7cecc0f9d5b35 | |
parent | 4e6685d2bb46ad9e9848ce21f93932d7e02b14ea (diff) | |
download | glade-b9d029623faf79fd9cb70bed9653f5dffa4ec0ad.tar.gz |
added gladeui/glade-widget-action.[ch]
* gladeui/Makefile.am: added gladeui/glade-widget-action.[ch]
* gladeui/glade-popup.[ch]:
- added glade_popup_action_populate_menu()
- adapted popup code to reflect action changes.
* gladeui/glade-widget-action.[ch]: GladeWidgetAction GObject sources.
* gladeui/glade-widget-adaptor.[ch]:
- action-activated signal removed
- added GladeActionActivateFunc
- added glade_widget_adaptor_action_add() and glade_widget_adaptor_action_remove()
- glade_widget_adaptor_action_activate() reworked.
- load symbol and other catalog stuff in gwa_derived_class_init()
- added the posibility to override GObject constructor from the catalog.
This is a good place to add/remove actions, use GWA_GET_OCLASS() to chain up.
* gladeui/glade-widget.[ch]:
- removed action-activated signal
- added glade_widget_get_action (), glade_widget_remove_action() and
glade_widget_create_action_menu()
* gladeui/glade-xml-utils.h: added GLADE_TAG_ACTION_ACTIVATE_FUNCTION and
GLADE_TAG_CONSTRUCTOR_FUNCTION tags
* plugins/gtk+/glade-gtk.c:
- added glade_gtk_menu_shell_action_activate() glade_gtk_menu_item_action_activate()
and glade_gtk_toolbar_action_activate()
- removed glade_gtk_menu_post_create() and glade_gtk_menu_launch_editor_action()
* plugins/gtk+/gtk+.xml.in:
- glade_gtk_menu_post_create() removed
- added action-activate-function for MenuShell MenuItem and Toolbar.
svn path=/trunk/; revision=1325
-rw-r--r-- | ChangeLog | 46 | ||||
-rw-r--r-- | gladeui/Makefile.am | 4 | ||||
-rw-r--r-- | gladeui/glade-popup.c | 94 | ||||
-rw-r--r-- | gladeui/glade-popup.h | 1 | ||||
-rw-r--r-- | gladeui/glade-widget-action.c | 254 | ||||
-rw-r--r-- | gladeui/glade-widget-action.h | 78 | ||||
-rw-r--r-- | gladeui/glade-widget-adaptor.c | 688 | ||||
-rw-r--r-- | gladeui/glade-widget-adaptor.h | 52 | ||||
-rw-r--r-- | gladeui/glade-widget.c | 139 | ||||
-rw-r--r-- | gladeui/glade-widget.h | 13 | ||||
-rw-r--r-- | gladeui/glade-xml-utils.h | 2 | ||||
-rw-r--r-- | plugins/gtk+/glade-gtk.c | 102 | ||||
-rw-r--r-- | plugins/gtk+/gtk+.xml.in | 5 |
13 files changed, 1024 insertions, 454 deletions
@@ -1,3 +1,49 @@ +2007-05-23 Juan Pablo Ugarte <juanpablougarte@gmail.com> + + * gladeui/Makefile.am: added gladeui/glade-widget-action.[ch] + + * gladeui/glade-popup.[ch]: + - added glade_popup_action_populate_menu() + + - adapted popup code to reflect action changes. + + * gladeui/glade-widget-action.[ch]: GladeWidgetAction GObject sources. + + * gladeui/glade-widget-adaptor.[ch]: + + - action-activated signal removed + + - added GladeActionActivateFunc + + - added glade_widget_adaptor_action_add() and glade_widget_adaptor_action_remove() + + - glade_widget_adaptor_action_activate() reworked. + + - load symbol and other catalog stuff in gwa_derived_class_init() + + - added the posibility to override GObject constructor from the catalog. + This is a good place to add/remove actions, use GWA_GET_OCLASS() to chain up. + + * gladeui/glade-widget.[ch]: + - removed action-activated signal + + - added glade_widget_get_action (), glade_widget_remove_action() and + glade_widget_create_action_menu() + + * gladeui/glade-xml-utils.h: added GLADE_TAG_ACTION_ACTIVATE_FUNCTION and + GLADE_TAG_CONSTRUCTOR_FUNCTION tags + + * plugins/gtk+/glade-gtk.c: + - added glade_gtk_menu_shell_action_activate() glade_gtk_menu_item_action_activate() + and glade_gtk_toolbar_action_activate() + + - removed glade_gtk_menu_post_create() and glade_gtk_menu_launch_editor_action() + + * plugins/gtk+/gtk+.xml.in: + - glade_gtk_menu_post_create() removed + + - added action-activate-function for MenuShell MenuItem and Toolbar. + 2007-05-18 Juan Pablo Ugarte <juanpablougarte@gmail.com> * Patch reaplied with the missing '}' :S (bug 435912) diff --git a/gladeui/Makefile.am b/gladeui/Makefile.am index 70653447..33f7adca 100644 --- a/gladeui/Makefile.am +++ b/gladeui/Makefile.am @@ -63,7 +63,8 @@ libgladeui_1_la_SOURCES = \ glade-popup.h \ glade-catalog.h \ glade-marshallers.h \ - glade-accumulators.h + glade-accumulators.h \ + glade-widget-action.c libgladeui_1_la_CPPFLAGS = \ $(common_defines) \ @@ -113,6 +114,7 @@ libgladeuiinclude_HEADERS = \ glade-parser.h \ glade-signal.h \ glade-cursor.h \ + glade-widget-action.h \ fixed_bg.xpm diff --git a/gladeui/glade-popup.c b/gladeui/glade-popup.c index 6a7ac0c8..dcf61b71 100644 --- a/gladeui/glade-popup.c +++ b/gladeui/glade-popup.c @@ -176,62 +176,81 @@ glade_popup_append_item (GtkWidget *popup_menu, static void -glade_popup_menuitem_activated (GtkMenuItem *item, GladeWidget *widget) +glade_popup_menuitem_activated (GtkMenuItem *item, const gchar *action_path) { - gchar *detail; + GladeWidget *widget; - if ((detail = g_object_get_data (G_OBJECT (item), "menuitem_detail"))) - glade_widget_adaptor_action_activate (widget, detail); + if ((widget = g_object_get_data (G_OBJECT (item), "glade-widget"))) + glade_widget_adaptor_action_activate (widget->adaptor, + widget->object, + action_path); } -static void -glade_popup_add_actions_recurse (GtkWidget *menu, GladeWidget *widget, GList *actions) +static gint +glade_popup_action_populate_menu_real (GtkWidget *menu, + GladeWidget *widget, + GladeWidgetAction *action) { - GList *list; GtkWidget *item; + GList *list; + gint n = 0; - for (list = widget->adaptor->actions; list; list = g_list_next (list)) + for (list = (action) ? action->actions : widget->actions; + list; + list = g_list_next (list)) { - GWAAction *action = list->data; + GladeWidgetAction *a = list->data; GtkWidget *submenu = NULL; - - if (action->actions) + + if (a->actions) { submenu = gtk_menu_new (); - glade_popup_add_actions_recurse (submenu, widget, action->actions); + n += glade_popup_action_populate_menu (submenu, widget, a); } - - if (action->is_a_group && submenu == NULL) continue; - + item = glade_popup_append_item (menu, - action->stock, - action->label, TRUE, - (action->is_a_group) ? NULL : glade_popup_menuitem_activated, - (action->is_a_group) ? NULL : widget); - - if (action->is_a_group == FALSE) - g_object_set_data (G_OBJECT (item), "menuitem_detail", action->id); + a->klass->stock, + a->klass->label, TRUE, + (a->actions) ? NULL : glade_popup_menuitem_activated, + (a->actions) ? NULL : a->klass->path); + + g_object_set_data (G_OBJECT (item), "glade-widget", widget); + gtk_widget_set_sensitive (item, a->sensitive); if (submenu) gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu); + + n++; } + return n; } -static void -glade_popup_add_actions (GtkWidget *menu, GladeWidget *widget) +/* + * glade_popup_action_populate_menu: + * @menu: a GtkMenu to put the actions menu items. + * @widget: A #GladeWidget + * @action: a @widget subaction or NULL to include all actions. + * + * Populate a GtkMenu with widget's actions + * + * Returns the number of action appended to the menu. + */ +gint +glade_popup_action_populate_menu (GtkWidget *menu, + GladeWidget *widget, + GladeWidgetAction *action) { - GtkWidget *separator; - - if (widget->adaptor->actions) + g_return_val_if_fail (GTK_IS_MENU (menu), 0); + g_return_val_if_fail (GLADE_IS_WIDGET (widget), 0); + if (action) { - separator = gtk_menu_item_new (); - gtk_widget_show (separator); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), - separator); - - glade_popup_add_actions_recurse (menu, widget, widget->adaptor->actions); + g_return_val_if_fail (GLADE_IS_WIDGET_ACTION (action), 0); + if (action != glade_widget_get_action (widget, action->klass->path)) + return 0; } + + return glade_popup_action_populate_menu_real (menu, widget, action); } static GtkWidget * @@ -256,7 +275,14 @@ glade_popup_create_menu (GladeWidget *widget) glade_popup_append_item (popup_menu, GTK_STOCK_DELETE, NULL, TRUE, glade_popup_delete_cb, widget); - glade_popup_add_actions (popup_menu, widget); + if (widget->actions) + { + GtkWidget *separator = gtk_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), separator); + gtk_widget_show (separator); + + glade_popup_action_populate_menu (popup_menu, widget, NULL); + } return popup_menu; } diff --git a/gladeui/glade-popup.h b/gladeui/glade-popup.h index 5844878a..8a1025ef 100644 --- a/gladeui/glade-popup.h +++ b/gladeui/glade-popup.h @@ -7,6 +7,7 @@ G_BEGIN_DECLS void glade_popup_widget_pop (GladeWidget *widget, GdkEventButton *event); void glade_popup_placeholder_pop (GladePlaceholder *placeholder, GdkEventButton *event); void glade_popup_clipboard_pop (GladeWidget *widget, GdkEventButton *event); +gint glade_popup_action_populate_menu (GtkWidget *menu, GladeWidget *widget, GladeWidgetAction *action); G_END_DECLS diff --git a/gladeui/glade-widget-action.c b/gladeui/glade-widget-action.c new file mode 100644 index 00000000..97889af5 --- /dev/null +++ b/gladeui/glade-widget-action.c @@ -0,0 +1,254 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2007 Juan Pablo Ugarte. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Authors: + * Juan Pablo Ugarte <juanpablougarte@gmail.com> + */ + +#include "glade-widget-action.h" + +enum +{ + PROP_0, + + PROP_KLASS, + PROP_SENSITIVE +}; + + +static GObjectClass* parent_class = NULL; + +G_DEFINE_TYPE (GladeWidgetAction, glade_widget_action, G_TYPE_OBJECT); + +static void +glade_widget_action_init (GladeWidgetAction *object) +{ + object->sensitive = TRUE; + object->actions = NULL; +} + +static void +glade_widget_action_finalize (GObject *object) +{ + GladeWidgetAction *action = GLADE_WIDGET_ACTION (object); + + if (action->actions) + { + g_list_foreach (action->actions, (GFunc)g_object_unref, NULL); + g_list_free (action->actions); + } + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static GObject * +glade_widget_action_constructor(GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GladeWidgetAction *action; + GObject *object; + GList *l; + + object = G_OBJECT_CLASS (parent_class)->constructor (type, + n_construct_properties, + construct_properties); + action = GLADE_WIDGET_ACTION (object); + + if (action->klass == NULL) + { + g_warning ("GLadeWidgetAction constructed without klass properties"); + return object; + } + + for (l = action->klass->actions; l; l = g_list_next (l)) + { + GWActionClass *action_class = l->data; + GObject *obj = g_object_new (GLADE_TYPE_WIDGET_ACTION, + "klass", action_class, + NULL); + + action->actions = g_list_prepend (action->actions, + GLADE_WIDGET_ACTION (obj)); + } + + action->actions = g_list_reverse (action->actions); + + return object; +} + +static void +glade_widget_action_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GladeWidgetAction *action = GLADE_WIDGET_ACTION (object); + + g_return_if_fail (GLADE_IS_WIDGET_ACTION (object)); + + switch (prop_id) + { + case PROP_KLASS: + action->klass = g_value_get_pointer (value); + break; + case PROP_SENSITIVE: + action->sensitive = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +glade_widget_action_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GladeWidgetAction *action = GLADE_WIDGET_ACTION (object); + + g_return_if_fail (GLADE_IS_WIDGET_ACTION (object)); + + switch (prop_id) + { + case PROP_KLASS: + g_value_set_pointer (value, action->klass); + break; + case PROP_SENSITIVE: + g_value_set_boolean (value, action->sensitive); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +glade_widget_action_class_init (GladeWidgetActionClass *klass) +{ + GObjectClass* object_class = G_OBJECT_CLASS (klass); + parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass)); + + object_class->constructor = glade_widget_action_constructor; + object_class->finalize = glade_widget_action_finalize; + object_class->set_property = glade_widget_action_set_property; + object_class->get_property = glade_widget_action_get_property; + + g_object_class_install_property (object_class, + PROP_KLASS, + g_param_spec_pointer ("klass", + "class", + "GladeWidgetActionClass", + G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE)); + + g_object_class_install_property (object_class, + PROP_SENSITIVE, + g_param_spec_boolean ("sensitive", + "Sensitive", + "Wheater or not this action is sensitive", + TRUE, + G_PARAM_READABLE | G_PARAM_WRITABLE)); + +} + +/** + * glade_widegt_action_class_free: + * @action: a GWActionClass + * + * Frees a GWActionClass. + */ +void +glade_widget_action_class_free (GWActionClass *action) +{ + if (action->actions) + g_list_foreach (action->actions, (GFunc)glade_widget_action_class_free, NULL); + + /*Dont free id since it points to path*/ + g_free (action->path); + g_free (action->label); + g_free (action->stock); + g_free (action); +} + +/** + * glade_widget_action_class_clone: + * @action: a GWActionClass + * + * Returns: a newlly allocated copy of @action. + */ +GWActionClass * +glade_widget_action_class_clone (GWActionClass *action) +{ + GWActionClass *copy; + GList *l; + + g_return_val_if_fail (action != NULL, NULL); + + copy = g_new0 (GWActionClass, 1); + copy->id = g_strdup (action->id); + copy->label = g_strdup (action->label); + copy->stock = g_strdup (action->stock); + + for (l = action->actions; l; l = g_list_next (l)) + { + GWActionClass *child = glade_widget_action_class_clone (l->data); + copy->actions = g_list_append (copy->actions, child); + } + + return copy; +} + +/** + * glade_widget_action_remove: + * @action: a #GladeWidgetAction + * @child: a #GladeWidgetAction + * + * Remove an action. + * + * Returns: whether or not @child was removed from @action. + */ +gboolean +glade_widget_action_remove (GladeWidgetAction *action, + GladeWidgetAction *child) +{ + GList *l; + + g_return_val_if_fail (GLADE_IS_WIDGET_ACTION (action), FALSE); + g_return_val_if_fail (GLADE_IS_WIDGET_ACTION (child), FALSE); + + for (l = action->actions; l; l = g_list_next (l)) + { + if (child == l->data) + { + action->actions = g_list_remove (action->actions, child); + return TRUE; + } + } + return FALSE; +} + +/** + * glade_widget_action_set_sensitive: + * @action: a #GladeWidgetAction + * @sensitive: + * + * Set whether or not this action is sensitive. + * + */ +void +glade_widget_action_set_sensitive (GladeWidgetAction *action, gboolean sensitive) +{ + g_return_if_fail (GLADE_IS_WIDGET_ACTION (action)); + g_object_set (G_OBJECT (action), "sensitive", sensitive, NULL); +} diff --git a/gladeui/glade-widget-action.h b/gladeui/glade-widget-action.h new file mode 100644 index 00000000..aae3484d --- /dev/null +++ b/gladeui/glade-widget-action.h @@ -0,0 +1,78 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2007 Juan Pablo Ugarte. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Authors: + * Juan Pablo Ugarte <juanpablougarte@gmail.com> + */ + +#ifndef _GLADE_WIDGET_ACTION_H_ +#define _GLADE_WIDGET_ACTION_H_ + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define GLADE_TYPE_WIDGET_ACTION (glade_widget_action_get_type ()) +#define GLADE_WIDGET_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_WIDGET_ACTION, GladeWidgetAction)) +#define GLADE_WIDGET_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_WIDGET_ACTION, GladeWidgetActionClass)) +#define GLADE_IS_WIDGET_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_WIDGET_ACTION)) +#define GLADE_IS_WIDGET_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_WIDGET_ACTION)) +#define GLADE_WIDGET_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GLADE_TYPE_WIDGET_ACTION, GladeWidgetActionClass)) + +typedef struct _GladeWidgetActionClass GladeWidgetActionClass; +typedef struct _GladeWidgetAction GladeWidgetAction; +typedef struct _GWActionClass GWActionClass; + +struct _GWActionClass +{ + gchar *id; /* The identifier of this action in the action tree */ + gchar *path; /* Full action path */ + gchar *label; /* A translated label to show in the UI for this action */ + gchar *stock; /* If set, this stock item will be shown in the UI along side + * the label */ + GList *actions; /* Recursive list of child actions */ +}; + +struct _GladeWidgetActionClass +{ + GObjectClass parent_class; +}; + +struct _GladeWidgetAction +{ + GObject parent_instance; + + GWActionClass *klass; /* The action class */ + + gboolean sensitive; /* If this action is sensitive or not */ + + GList *actions; /* List of actions */ +}; + +GType glade_widget_action_get_type (void) G_GNUC_CONST; + +void glade_widget_action_class_free (GWActionClass *action); + +GWActionClass *glade_widget_action_class_clone (GWActionClass *action); + +gboolean glade_widget_action_remove (GladeWidgetAction *action, + GladeWidgetAction *child); + +G_END_DECLS + +#endif /* _GLADE_WIDGET_ACTION_H_ */ diff --git a/gladeui/glade-widget-adaptor.c b/gladeui/glade-widget-adaptor.c index 3f3dc165..32abba43 100644 --- a/gladeui/glade-widget-adaptor.c +++ b/gladeui/glade-widget-adaptor.c @@ -79,16 +79,8 @@ enum { PROP_CURSOR }; -enum -{ - SIGNAL_ACTION_ACTIVATED, - LAST_SIGNAL -}; - typedef struct _GladeChildPacking GladeChildPacking; -static guint gwa_signals [LAST_SIGNAL] = {0,}; - static GObjectClass *parent_class = NULL; static GHashTable *adaptor_hash = NULL; @@ -481,40 +473,6 @@ gwa_inherit_child_packing (GladeWidgetAdaptor *adaptor) return child_packings; } -static GList * -gwa_action_copy (GList *src) -{ - GList *l, *list = NULL; - - for (l = src; l; l = g_list_next (l)) - { - GWAAction *action = l->data, *copy = g_new0 (GWAAction, 1); - - copy->id = g_strdup (action->id); - copy->label = g_strdup (action->label); - copy->stock = g_strdup (action->stock); - copy->is_a_group = action->is_a_group; - - list = g_list_append (list, l->data); - - if (action->actions) - copy->actions = gwa_action_copy (action->actions); - } - - return list; -} - -static void -gwa_action_setup (GladeWidgetAdaptor *adaptor) -{ - GladeWidgetAdaptor *parent = gwa_get_parent_adaptor (adaptor); - - if (parent && parent->actions) - adaptor->actions = gwa_action_copy (parent->actions); - else - adaptor->actions = NULL; -} - static GObject * glade_widget_adaptor_constructor (GType type, guint n_construct_properties, @@ -564,7 +522,18 @@ glade_widget_adaptor_constructor (GType type, parent_adaptor->priv->special_child_type ? g_strdup (parent_adaptor->priv->special_child_type) : NULL; - gwa_action_setup (adaptor); + /* Copy parent actions */ + if (parent_adaptor && parent_adaptor->actions) + { + GList *l; + for (l = parent_adaptor->actions; l; l = g_list_next (l)) + { + GWActionClass *child = glade_widget_action_class_clone (l->data); + adaptor->actions = g_list_append (adaptor->actions, child); + } + } + else + adaptor->actions = NULL; return ret_obj; } @@ -586,25 +555,6 @@ gwa_child_packing_free (GladeChildPacking *packing) g_list_free (packing->packing_defaults); } -static void -gwa_actions_free (GList *actions) -{ - GList *l; - - for (l = actions; l; l = g_list_next (l)) - { - GWAAction *action = l->data; - - if (action->actions) gwa_actions_free (action->actions); - - g_free (action->id); - g_free (action->label); - g_free (action->stock); - g_free (action); - } - g_list_free (actions); -} - static void glade_widget_adaptor_finalize (GObject *object) { @@ -640,7 +590,10 @@ glade_widget_adaptor_finalize (GObject *object) if (adaptor->title) g_free (adaptor->title); if (adaptor->icon_name) g_free (adaptor->icon_name); - if (adaptor->actions) gwa_actions_free (adaptor->actions); + if (adaptor->actions) + g_list_foreach (adaptor->actions, + (GFunc) glade_widget_action_class_free, + NULL); g_free (adaptor->priv); @@ -747,6 +700,14 @@ glade_widget_adaptor_object_get_property (GladeWidgetAdaptor *adaptor, g_object_get_property (object, property_name, value); } +static void +glade_widget_adaptor_object_action_activate (GladeWidgetAdaptor *adaptor, + GObject *object, + const gchar *action_id) +{ + g_message ("No action_activate() support in adaptor %s for action '%s'", + adaptor->name, action_id); +} /******************************************************************************* GladeWidgetAdaptor type registration and class initializer @@ -757,23 +718,6 @@ glade_widget_adaptor_init (GladeWidgetAdaptor *adaptor) adaptor->priv = GLADE_WIDGET_ADAPTOR_GET_PRIVATE (adaptor); } -static gboolean -gwa_action_activated_impl (GladeWidgetAdaptor *adaptor, - GladeWidget *widget, - const gchar *action_id) -{ - static guint signal = 0; - gboolean retval; - - if (signal == 0) - signal = g_signal_lookup ("action-activated", GLADE_TYPE_WIDGET); - - g_signal_emit (widget, signal, g_quark_from_string (action_id), - action_id, &retval); - - return retval; -} - static void glade_widget_adaptor_class_init (GladeWidgetAdaptorClass *adaptor_class) { @@ -801,8 +745,7 @@ glade_widget_adaptor_class_init (GladeWidgetAdaptorClass *adaptor_class) adaptor_class->get_children = NULL; adaptor_class->child_set_property = NULL; adaptor_class->child_get_property = NULL; - - adaptor_class->action_activated = gwa_action_activated_impl; + adaptor_class->action_activate = glade_widget_adaptor_object_action_activate; /* Base defaults here */ adaptor_class->fixed = FALSE; @@ -811,26 +754,6 @@ glade_widget_adaptor_class_init (GladeWidgetAdaptorClass *adaptor_class) adaptor_class->default_width = -1; adaptor_class->default_height = -1; - /** - * GladeWidgetAdaptor::action-activated: - * @adaptor: the GladeWidgetAdaptor which received the signal. - * @widget: the action's GladeWidget or NULL. - * @action_id: the action id (signal detail) or NULL. - * - * Use this to catch up actions. - * - * Returns TRUE to stop others handlers being invoked. - * - */ - gwa_signals [SIGNAL_ACTION_ACTIVATED] = - g_signal_new ("action-activated", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - G_STRUCT_OFFSET (GladeWidgetAdaptorClass, action_activated), - glade_boolean_handled_accumulator, NULL, - glade_marshal_BOOLEAN__OBJECT_STRING, - G_TYPE_BOOLEAN, 2, GLADE_TYPE_WIDGET, G_TYPE_STRING); - /* Properties */ g_object_class_install_property (object_class, PROP_NAME, @@ -903,7 +826,7 @@ glade_widget_adaptor_class_init (GladeWidgetAdaptorClass *adaptor_class) ("cursor", _("Cursor"), _("A cursor for inserting widgets in the UI"), G_PARAM_READABLE)); - + g_type_class_add_private (adaptor_class, sizeof (GladeWidgetAdaptorPrivate)); } @@ -959,26 +882,163 @@ glade_create_reason_get_type (void) /******************************************************************************* Synthetic Object Derivation *******************************************************************************/ +typedef struct +{ + GladeXmlNode *node; + GModule *module; +} GWADerivedClassData; + static void -gwa_derived_init (GladeWidgetAdaptor *adaptor) +gwa_derived_init (GladeWidgetAdaptor *adaptor, gpointer g_class) { } static void -gwa_derived_class_init (GladeWidgetAdaptorClass *adaptor_class) +gwa_extend_with_node_load_sym (GladeWidgetAdaptorClass *klass, + GladeXmlNode *node, + GModule *module) { + GladeWidgetAdaptorClass *parent_class = g_type_class_peek_parent (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + gpointer symbol; + + /* + * We use a temporary variable to avoid a bogus gcc warning. + * the thing it that g_module_symbol() should use a function pointer + * instead of a gpointer! + */ + if (glade_xml_load_sym_from_node (node, module, + GLADE_TAG_CONSTRUCTOR_FUNCTION, + &symbol)) + object_class->constructor = symbol; + else + /* Chain up with parent, this way GWA_GET_OCLASS can work */ + object_class->constructor = ((GObjectClass*)parent_class)->constructor; + + if (glade_xml_load_sym_from_node (node, module, + GLADE_TAG_POST_CREATE_FUNCTION, + &symbol)) + klass->post_create = symbol; + + if (glade_xml_load_sym_from_node (node, module, + GLADE_TAG_GET_INTERNAL_CHILD_FUNCTION, + &symbol)) + klass->get_internal_child = symbol; + + if (glade_xml_load_sym_from_node (node, module, + GLADE_TAG_SET_FUNCTION, + &symbol)) + klass->set_property = symbol; + + if (glade_xml_load_sym_from_node (node, module, + GLADE_TAG_GET_FUNCTION, + &symbol)) + klass->get_property = symbol; + + if (glade_xml_load_sym_from_node (node, module, + GLADE_TAG_VERIFY_FUNCTION, + &symbol)) + klass->verify_property = symbol; + + if (glade_xml_load_sym_from_node (node, module, + GLADE_TAG_ADD_CHILD_FUNCTION, + &symbol)) + klass->add = symbol; + + if (glade_xml_load_sym_from_node (node, module, + GLADE_TAG_REMOVE_CHILD_FUNCTION, + &symbol)) + klass->remove = symbol; + + if (glade_xml_load_sym_from_node (node, module, + GLADE_TAG_GET_CHILDREN_FUNCTION, + &symbol)) + klass->get_children = symbol; + + if (glade_xml_load_sym_from_node (node, module, + GLADE_TAG_CHILD_SET_PROP_FUNCTION, + &symbol)) + klass->child_set_property = symbol; + + if (glade_xml_load_sym_from_node (node, module, + GLADE_TAG_CHILD_GET_PROP_FUNCTION, + &symbol)) + klass->child_get_property = symbol; + + if (glade_xml_load_sym_from_node (node, module, + GLADE_TAG_CHILD_VERIFY_FUNCTION, + &symbol)) + klass->child_verify_property = symbol; + + if (glade_xml_load_sym_from_node (node, module, + GLADE_TAG_REPLACE_CHILD_FUNCTION, + &symbol)) + klass->replace_child = symbol; + + if (glade_xml_load_sym_from_node (node, module, + GLADE_TAG_ACTION_ACTIVATE_FUNCTION, + &symbol)) + klass->action_activate = symbol; + else + /* Chain up with parent */ + klass->action_activate = parent_class->action_activate; +} + +static void +gwa_derived_class_init (GladeWidgetAdaptorClass *adaptor_class, + GWADerivedClassData *data) +{ + GladeXmlNode *node = data->node; + GModule *module = data->module; + + /* Load catalog symbols from module */ + if (module) gwa_extend_with_node_load_sym (adaptor_class, node, module); + + adaptor_class->fixed = + glade_xml_get_property_boolean + (node, GLADE_TAG_FIXED, adaptor_class->fixed); + + /* Check if this class is toplevel */ + adaptor_class->toplevel = + glade_xml_get_property_boolean + (node, GLADE_TAG_TOPLEVEL, adaptor_class->toplevel); + + /* Check if this class uses placeholders for child widgets */ + adaptor_class->use_placeholders = + glade_xml_get_property_boolean + (node, GLADE_TAG_USE_PLACEHOLDERS, adaptor_class->use_placeholders); + + /* Check default size when used as a toplevel in the GladeDesignView */ + adaptor_class->default_width = + glade_xml_get_property_int + (node, GLADE_TAG_DEFAULT_WIDTH, adaptor_class->default_width); + adaptor_class->default_height = + glade_xml_get_property_int + (node, GLADE_TAG_DEFAULT_HEIGHT, adaptor_class->default_height); } static GType -gwa_derive_adaptor_for_type (GType object_type) +gwa_derive_adaptor_for_type (GType object_type, GWADerivedClassData *data) { GladeWidgetAdaptor *adaptor; GType iter_type, derived_type; GType parent_type = GLADE_TYPE_WIDGET_ADAPTOR; gchar *type_name; - + GTypeInfo adaptor_info = + { + sizeof (GladeWidgetAdaptorClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gwa_derived_class_init, + (GClassFinalizeFunc) NULL, + data, /* class_data */ + sizeof (GladeWidgetAdaptor), + 0, /* n_preallocs */ + (GInstanceInitFunc) gwa_derived_init, + }; + for (iter_type = g_type_parent (object_type); iter_type > 0; iter_type = g_type_parent (iter_type)) @@ -995,12 +1055,9 @@ gwa_derive_adaptor_for_type (GType object_type) * to the type system */ type_name = g_strdup_printf ("Glade%sAdaptor", g_type_name (object_type)); - derived_type = - g_type_register_static_simple (parent_type, type_name, - sizeof (GladeWidgetAdaptorClass), - (GClassInitFunc)gwa_derived_class_init, - sizeof (GladeWidgetAdaptor), - (GInstanceInitFunc)gwa_derived_init, 0); + derived_type = g_type_register_static (parent_type, type_name, + &adaptor_info, 0); + return derived_type; } @@ -1226,83 +1283,13 @@ gwa_update_properties_from_node (GladeWidgetAdaptor *adaptor, } } -static GList ** -gwa_action_lookup (GList **actions, const gchar *id, gboolean only_group) -{ - GList **group = actions, *l; - - for (l = *actions; l; l = g_list_next (l)) - { - GWAAction *action = l->data; - - if (only_group && action->is_a_group == FALSE) continue; - - if (strcmp (action->id, id) == 0) - return (only_group) ? &action->actions : group; - - if (action->is_a_group && action->actions && - (group = gwa_action_lookup (&action->actions, id, only_group))) - return group; - } - - return NULL; -} - -/* - * gwa_action_append: - * - * @adaptor: the GladeWidgetAdaptor. - * @group_id: the group id weater to append this action or NULL. - * @id: the id of the action. - * @label: the label of the action or NULL. - * @stock: the stock id of the action or NULL (ie: "gtk-delete"). - * @is_a_group: if this is an action group. - * - * Append a new GWAAction to @adaptor. - * - * Returns weater or not the action wass appended - * - */ -static gboolean -gwa_action_append (GladeWidgetAdaptor *adaptor, - const gchar *group_id, - const gchar *id, - const gchar *label, - const gchar *stock, - gboolean is_a_group) -{ - GList **group; - GWAAction *action; - - g_return_val_if_fail (id != NULL, FALSE); - - if (group_id) - { - group = gwa_action_lookup (&adaptor->actions, group_id, TRUE); - if (group == NULL) return FALSE; - } - else group = &adaptor->actions; - - if (gwa_action_lookup (&adaptor->actions, id, FALSE)) return FALSE; - - action = g_new0 (GWAAction, 1); - action->id = g_strdup (id); - action->label = (label) ? g_strdup (label) : NULL; - action->stock = (stock) ? g_strdup (stock) : NULL; - action->is_a_group = is_a_group; - - *group = g_list_prepend (*group, action); - - return TRUE; -} - static void -gwa_update_actions (GladeWidgetAdaptor *adaptor, - GladeXmlNode *node, - gchar *group_id) +gwa_action_update_from_node (GladeWidgetAdaptor *adaptor, + GladeXmlNode *node, + gchar *group_path) { GladeXmlNode *child; - gchar *id, *label, *stock; + gchar *id, *label, *stock, *action_path; gboolean group; for (child = glade_xml_node_get_children (node); @@ -1317,128 +1304,33 @@ gwa_update_actions (GladeWidgetAdaptor *adaptor, if (id == NULL) continue; + if (group_path) + action_path = g_strdup_printf ("%s/%s", group_path, id); + else + action_path = id; + label = glade_xml_get_property_string (child, GLADE_TAG_NAME); stock = glade_xml_get_property_string (child, GLADE_TAG_STOCK); - gwa_action_append (adaptor, group_id, id, - (label == NULL && stock == NULL) ? id : label, - stock, group); - if (group) gwa_update_actions (adaptor, child, id); - + glade_widget_adaptor_action_add (adaptor, action_path, label, stock); + + if (group) gwa_action_update_from_node (adaptor, child, action_path); + g_free (id); g_free (label); g_free (stock); + if (group_path) g_free (action_path); } } -static void -gwa_extend_with_node_load_sym (GladeWidgetAdaptorClass *klass, - GladeXmlNode *node, - GModule *module) -{ - gpointer symbol; - - /* - * We use a temporary variable to avoid a bogus gcc warning. - * the thing it that g_module_symbol() should use a function pointer - * instead of a gpointer! - */ - - if (glade_xml_load_sym_from_node (node, module, - GLADE_TAG_POST_CREATE_FUNCTION, - &symbol)) - klass->post_create = symbol; - - if (glade_xml_load_sym_from_node (node, module, - GLADE_TAG_GET_INTERNAL_CHILD_FUNCTION, - &symbol)) - klass->get_internal_child = symbol; - - if (glade_xml_load_sym_from_node (node, module, - GLADE_TAG_SET_FUNCTION, - &symbol)) - klass->set_property = symbol; - - if (glade_xml_load_sym_from_node (node, module, - GLADE_TAG_GET_FUNCTION, - &symbol)) - klass->get_property = symbol; - - if (glade_xml_load_sym_from_node (node, module, - GLADE_TAG_VERIFY_FUNCTION, - &symbol)) - klass->verify_property = symbol; - - if (glade_xml_load_sym_from_node (node, module, - GLADE_TAG_ADD_CHILD_FUNCTION, - &symbol)) - klass->add = symbol; - - if (glade_xml_load_sym_from_node (node, module, - GLADE_TAG_REMOVE_CHILD_FUNCTION, - &symbol)) - klass->remove = symbol; - - if (glade_xml_load_sym_from_node (node, module, - GLADE_TAG_GET_CHILDREN_FUNCTION, - &symbol)) - klass->get_children = symbol; - - if (glade_xml_load_sym_from_node (node, module, - GLADE_TAG_CHILD_SET_PROP_FUNCTION, - &symbol)) - klass->child_set_property = symbol; - - if (glade_xml_load_sym_from_node (node, module, - GLADE_TAG_CHILD_GET_PROP_FUNCTION, - &symbol)) - klass->child_get_property = symbol; - - if (glade_xml_load_sym_from_node (node, module, - GLADE_TAG_CHILD_VERIFY_FUNCTION, - &symbol)) - klass->child_verify_property = symbol; - - if (glade_xml_load_sym_from_node (node, module, - GLADE_TAG_REPLACE_CHILD_FUNCTION, - &symbol)) - klass->replace_child = symbol; -} - static gboolean gwa_extend_with_node (GladeWidgetAdaptor *adaptor, GladeXmlNode *node, GModule *module, const gchar *domain) { - GladeWidgetAdaptorClass *adaptor_class = GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor); GladeXmlNode *child; gchar *child_type; - - /* Load catalog symbols from module */ - if (module) gwa_extend_with_node_load_sym (adaptor_class, node, module); - - adaptor_class->fixed = - glade_xml_get_property_boolean - (node, GLADE_TAG_FIXED, adaptor_class->fixed); - - /* Check if this class is toplevel */ - adaptor_class->toplevel = - glade_xml_get_property_boolean - (node, GLADE_TAG_TOPLEVEL, adaptor_class->toplevel); - - /* Check if this class uses placeholders for child widgets */ - adaptor_class->use_placeholders = - glade_xml_get_property_boolean - (node, GLADE_TAG_USE_PLACEHOLDERS, adaptor_class->use_placeholders); - - /* Check default size when used as a toplevel in the GladeDesignView */ - adaptor_class->default_width = - glade_xml_get_property_int - (node, GLADE_TAG_DEFAULT_WIDTH, adaptor_class->default_width); - adaptor_class->default_height = - glade_xml_get_property_int - (node, GLADE_TAG_DEFAULT_HEIGHT, adaptor_class->default_height); /* Override the special-child-type here */ if ((child_type = @@ -1462,9 +1354,9 @@ gwa_extend_with_node (GladeWidgetAdaptor *adaptor, if ((child = glade_xml_search_child (node, GLADE_TAG_PACKING_DEFAULTS)) != NULL) gwa_set_packing_defaults_from_node (adaptor, child); - - /* Search for actions */ - gwa_update_actions (adaptor, node, NULL); + + /* Update actions from node */ + gwa_action_update_from_node (adaptor, node, NULL); return TRUE; } @@ -1539,7 +1431,8 @@ glade_widget_adaptor_from_catalog (GladeXmlNode *class_node, GladeWidgetAdaptor *adaptor = NULL; gchar *name, *generic_name, *icon_name, *adaptor_icon_name, *adaptor_name, *func_name; GType object_type, adaptor_type, parent_type; - + GWADerivedClassData data; + if (!glade_xml_node_verify (class_node, GLADE_TAG_GLADE_WIDGET_CLASS)) { g_warning ("Widget class node is not '%s'", @@ -1575,7 +1468,16 @@ glade_widget_adaptor_from_catalog (GladeXmlNode *class_node, if ((adaptor_name = glade_xml_get_property_string (class_node, GLADE_TAG_ADAPTOR))) adaptor_type = g_type_from_name (adaptor_name); else - adaptor_type = gwa_derive_adaptor_for_type (object_type); + { + /* + * We use this struct pointer to pass data to + * gwa_derived_class_init() because we must override constructor() + * from the catalog before calling g_object_new() :P + */ + data.node = class_node; + data.module = module; + adaptor_type = gwa_derive_adaptor_for_type (object_type, &data); + } if (adaptor_type == 0) { @@ -2410,60 +2312,182 @@ glade_widget_adaptor_get_packing_default (GladeWidgetAdaptor *child_adaptor, return NULL; } -/* - * glade_widget_adaptor_action_activate: - * - * @widget: the GladeWidget. - * @action_id: The action id (detail of GladeWidgetAdaptor's action-activated signal). +/** + * glade_widget_adaptor_is_container: + * @adaptor: A #GladeWidgetAdaptor * - * Emit @widget's adaptor action-activated::@action_id signal. - * GladeWidget's action-activated proxy signal is also emited. + * Checks whether or not this adaptor has support + * to interface with child objects. * + * Returns whether or not @adaptor is a container */ -void -glade_widget_adaptor_action_activate (GladeWidget *widget, const gchar *action_id) +gboolean +glade_widget_adaptor_is_container (GladeWidgetAdaptor *adaptor) { - GladeWidgetAdaptor *adaptor; - GQuark detail; - guint signal; - gboolean retval; + + g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE); + + /* A GWA container must at least implement add/remove/get_children + */ + return (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->add && + GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->remove && + GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->get_children); +} + +static const gchar * +gwa_action_path_get_id (const gchar *action_path) +{ + const gchar *id; - g_return_if_fail (GLADE_IS_WIDGET (widget) && action_id); + if ((id = g_strrstr (action_path, "/")) && id[1] != '\0') + return &id[1]; + else + return action_path; +} - signal = gwa_signals [SIGNAL_ACTION_ACTIVATED]; - detail = g_quark_from_string (action_id); +static GWActionClass * +gwa_action_lookup (GList *actions, const gchar *action_id) +{ + GList *l; - for (adaptor = widget->adaptor; - adaptor; - adaptor = gwa_get_parent_adaptor (adaptor)) + for (l = actions; l; l = g_list_next (l)) { - if (gwa_action_lookup (&adaptor->actions, action_id, FALSE)) - g_signal_emit (adaptor, signal, detail, widget, - action_id, &retval); - else - return; + GWActionClass *action = l->data; + if (strcmp (action->id, action_id) == 0) + return action; } + + return NULL; } +static GWActionClass * +gwa_action_get_last_group (GladeWidgetAdaptor *adaptor, + const gchar *action_path) +{ + gchar **tokens = g_strsplit (action_path, "/", 0); + GList *list = adaptor->actions; + GWActionClass *group = NULL; + gint i; + + for (i = 0; tokens[i] && tokens[i+1]; i++) + { + if ((group = gwa_action_lookup (list, tokens[i])) == NULL) + { + g_strfreev (tokens); + return NULL; + } + list = group->actions; + } + + g_strfreev (tokens); + return group; +} /** - * glade_widget_adaptor_is_container: + * glade_widget_adaptor_action_add: * @adaptor: A #GladeWidgetAdaptor + * @action_path: The identifier of this action in the action tree + * @label: A translated label to show in the UI for this action + * @stock: If set, this stock item will be shown in the UI along side the label. * - * Checks whether or not this adaptor has support - * to interface with child objects. + * Add an action to @adaptor. + * If the action is present then it overrides label and stock * - * Returns whether or not @adaptor is a container + * Returns: whether or not the action was added/updated. */ gboolean -glade_widget_adaptor_is_container (GladeWidgetAdaptor *adaptor) -{ +glade_widget_adaptor_action_add (GladeWidgetAdaptor *adaptor, + const gchar *action_path, + const gchar *label, + const gchar *stock) +{ + GWActionClass *action, *group; + const gchar *id; + GList **list; + + g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE); + g_return_val_if_fail (action_path != NULL, FALSE); + + id = gwa_action_path_get_id (action_path); + + if ((group = gwa_action_get_last_group (adaptor, action_path))) + list = &group->actions; + else + list = &adaptor->actions; + + if ((action = gwa_action_lookup (*list, id))) + { + if (action->label) g_free (action->label); + if (action->stock) g_free (action->stock); + } + else + { + action = g_new0 (GWActionClass, 1); + action->path = g_strdup (action_path); + action->id = (gchar*) gwa_action_path_get_id (action->path); + } + + action->label = (label) ? g_strdup (label) : NULL; + action->stock = (stock) ? g_strdup (stock) : NULL; + + *list = g_list_prepend (*list, action); + + return TRUE; +} +/** + * glade_widget_adaptor_action_remove: + * @adaptor: A #GladeWidgetAdaptor + * @action_path: The identifier of this action in the action tree + * + * Remove an @adaptor's action. + * + * Returns: whether or not the action was removed. + */ +gboolean +glade_widget_adaptor_action_remove (GladeWidgetAdaptor *adaptor, + const gchar *action_path) +{ + GWActionClass *action, *group; + const gchar *id; + GList **list; + g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE); + g_return_val_if_fail (action_path != NULL, FALSE); + + id = gwa_action_path_get_id (action_path); + + if ((group = gwa_action_get_last_group (adaptor, action_path))) + list = &group->actions; + else + list = &adaptor->actions; - /* A GWA container must at least implement add/remove/get_children - */ - return (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->add && - GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->remove && - GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->get_children); + if ((action = gwa_action_lookup (*list, id)) == NULL) return FALSE; + + *list = g_list_remove (*list, action); + + glade_widget_action_class_free (action); + + return TRUE; +} + +/** + * glade_widget_adaptor_action_activate: + * @adaptor: A #GladeWidgetAdaptor + * @object: The #GObject + * @action_path: The action identifier in the action tree + * + * An adaptor function to be called on widget actions. + */ +void +glade_widget_adaptor_action_activate (GladeWidgetAdaptor *adaptor, + GObject *object, + const gchar *action_path) +{ + g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor)); + g_return_if_fail (G_IS_OBJECT (object)); + g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (object), adaptor->type)); + + if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->action_activate) + GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->action_activate (adaptor, object, action_path); } diff --git a/gladeui/glade-widget-adaptor.h b/gladeui/glade-widget-adaptor.h index 32c24470..acafb579 100644 --- a/gladeui/glade-widget-adaptor.h +++ b/gladeui/glade-widget-adaptor.h @@ -26,7 +26,6 @@ typedef struct _GladeWidgetAdaptor GladeWidgetAdaptor; typedef struct _GladeWidgetAdaptorPrivate GladeWidgetAdaptorPrivate; typedef struct _GladeWidgetAdaptorClass GladeWidgetAdaptorClass; typedef struct _GladeSignalClass GladeSignalClass; -typedef struct _GWAAction GWAAction; /** * GWA_IS_FIXED: @@ -92,6 +91,14 @@ typedef struct _GWAAction GWAAction; (GladeWidgetAdaptorClass *)g_type_class_peek (GLADE_TYPE_WIDGET_ADAPTOR) : \ GLADE_WIDGET_ADAPTOR_GET_CLASS (glade_widget_adaptor_get_by_type(type))) +/** + * GWA_GET_OCLASS: + * @type: A #GType. + * + * Same as GWA_GET_CLASS but casted to GObjectClass + */ +#define GWA_GET_OCLASS(type) ((GObjectClass*)GWA_GET_CLASS(type)) + #define GLADE_VALID_CREATE_REASON(reason) (reason >= 0 && reason < GLADE_CREATE_REASONS) @@ -302,6 +309,18 @@ typedef GObject *(* GladeGetInternalFunc) (GladeWidgetAdaptor *adaptor, GObject *parent, const gchar *name); +/** + * GladeActionActivatedFunc: + * @adaptor: A #GladeWidgetAdaptor + * @object: The #GObject + * @action_id: The action identifier + * + * This delagate function is used to catch actions from the core. + * + */ +typedef void (* GladeActionActivateFunc) (GladeWidgetAdaptor *adaptor, + GObject *object, + const gchar *action_id); /* GladeSignalClass contains all the info we need for a given signal, such as * the signal name, and maybe more in the future @@ -316,17 +335,6 @@ struct _GladeSignalClass }; -struct _GWAAction -{ - gchar *id; /* The identifier of this action in the action tree */ - gchar *label; /* A translated label to show in the UI for this action */ - gchar *stock; /* If set, this stock item will be shown in the UI along side - * the label */ - gboolean is_a_group; /* Marks whether this action is a group and can have children */ - - GList *actions; /* Recursive list of child actions */ -}; - /* Note that everything that must be processed at the creation of * every instance is managed on the instance structure, and everywhere * that we want to take advantage of inheritance is handled in the class @@ -369,7 +377,7 @@ struct _GladeWidgetAdaptor GList *child_packings; /* Default packing property values */ - GList *actions; /* A list of GWAAction */ + GList *actions; /* A list of GWActionClass */ GladeWidgetAdaptorPrivate *priv; @@ -442,8 +450,8 @@ struct _GladeWidgetAdaptorClass * replace a placeholder with * a widget and viceversa. */ - /* Signals */ - gboolean (*action_activated) (GladeWidgetAdaptor *, GladeWidget *, const gchar *); + + GladeActionActivateFunc action_activate; /* This method is used to catch actions */ }; #define glade_widget_adaptor_create_widget(adaptor, query, ...) \ @@ -564,13 +572,19 @@ gchar *glade_widget_adaptor_get_packing_default(GladeWidgetAdaptor GladeWidgetAdaptor *parent_adaptor, const gchar *propert_id); -void glade_widget_adaptor_action_activate (GladeWidget *widget, - const gchar *action_id); - - gboolean glade_widget_adaptor_is_container (GladeWidgetAdaptor *adaptor); +gboolean glade_widget_adaptor_action_add (GladeWidgetAdaptor *adaptor, + const gchar *action_path, + const gchar *label, + const gchar *stock); +gboolean glade_widget_adaptor_action_remove (GladeWidgetAdaptor *adaptor, + const gchar *action_path); + +void glade_widget_adaptor_action_activate (GladeWidgetAdaptor *adaptor, + GObject *object, + const gchar *action_path); G_END_DECLS #endif /* __GLADE_WIDGET_ADAPTOR_H__ */ diff --git a/gladeui/glade-widget.c b/gladeui/glade-widget.c index f0325a44..d8118b11 100644 --- a/gladeui/glade-widget.c +++ b/gladeui/glade-widget.c @@ -45,6 +45,7 @@ #include "glade-editor.h" #include "glade-app.h" #include "glade-design-view.h" +#include "glade-widget-action.h" @@ -74,7 +75,6 @@ enum BUTTON_PRESS_EVENT, BUTTON_RELEASE_EVENT, MOTION_NOTIFY_EVENT, - ACTION_ACTIVATED, LAST_SIGNAL }; @@ -754,6 +754,12 @@ glade_widget_dispose (GObject *object) g_list_foreach (widget->packing_properties, (GFunc)g_object_unref, NULL); g_list_free (widget->packing_properties); } + + if (widget->actions) + { + g_list_foreach (widget->actions, (GFunc)g_object_unref, NULL); + g_list_free (widget->actions); + } if (G_OBJECT_CLASS(parent_class)->dispose) G_OBJECT_CLASS(parent_class)->dispose(object); @@ -1149,27 +1155,6 @@ glade_widget_class_init (GladeWidgetClass *klass) glade_marshal_BOOLEAN__BOXED, G_TYPE_BOOLEAN, 1, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); - - - /** - * GladeWidget::action-activated: - * @widget: the #GladeWidget which received the signal. - * @action_id: the action id (signal detail) or NULL. - * - * Use this to catch up actions. This signal is proxied from - * GladeWidgetAdaptor's "action-emited" signal default handler. - * - * Returns TRUE to stop others handlers being invoked. - * - */ - glade_widget_signals [ACTION_ACTIVATED] = - g_signal_new ("action-activated", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - G_STRUCT_OFFSET (GladeWidgetClass, action_activated), - glade_boolean_handled_accumulator, NULL, - glade_marshal_BOOLEAN__STRING, - G_TYPE_BOOLEAN, 1, G_TYPE_STRING); } GType @@ -1642,6 +1627,23 @@ glade_widget_set_properties (GladeWidget *widget, GList *properties) } static void +glade_widget_set_actions (GladeWidget *widget, GladeWidgetAdaptor *adaptor) +{ + GList *l; + + for (l = adaptor->actions; l; l = g_list_next (l)) + { + GWActionClass *action = l->data; + GObject *obj = g_object_new (GLADE_TYPE_WIDGET_ACTION, + "klass", action, NULL); + + widget->actions = g_list_prepend (widget->actions, + GLADE_WIDGET_ACTION (obj)); + } + widget->actions = g_list_reverse (widget->actions); +} + +static void glade_widget_set_adaptor (GladeWidget *widget, GladeWidgetAdaptor *adaptor) { GladePropertyClass *property_class; @@ -1674,6 +1676,9 @@ glade_widget_set_adaptor (GladeWidget *widget, GladeWidgetAdaptor *adaptor) } widget->properties = g_list_reverse (widget->properties); } + + /* Create actions from adaptor */ + glade_widget_set_actions (widget, adaptor); } /* Connects a signal handler to the 'event' signal for a widget and @@ -3809,6 +3814,96 @@ glade_widget_placeholder_relation (GladeWidget *parent, GWA_USE_PLACEHOLDERS (parent->adaptor)); } +static GladeWidgetAction * +glade_widget_action_lookup (GList **actions, const gchar *path, gboolean remove) +{ + GList *l; + + for (l = *actions; l; l = g_list_next (l)) + { + GladeWidgetAction *action = l->data; + + if (strcmp (action->klass->path, path) == 0) + { + if (remove) + { + *actions = g_list_remove (*actions, action); + g_object_unref (action); + return NULL; + } + return action; + } + + if (action->actions && + g_str_has_prefix (path, action->klass->path) && + (action = glade_widget_action_lookup (&action->actions, path, remove))) + return action; + } + + return NULL; +} + +/** + * glade_widget_get_action: + * @widget: a #GladeWidget + * @action_path: a full action path including groups + * + * Returns a #GladeWidgetAction object indentified by @action_path. + * + * Returns: the action or NULL if not found. + */ +GladeWidgetAction * +glade_widget_get_action (GladeWidget *widget, const gchar *action_path) +{ + g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL); + g_return_val_if_fail (action_path == NULL, NULL); + + return glade_widget_action_lookup (&widget->actions, action_path, FALSE); +} + +/** + * glade_widget_remove_action: + * @widget: a #GladeWidget + * @action_path: a full action path including groups + * + * Remove an action. + */ +void +glade_widget_remove_action (GladeWidget *widget, const gchar *action_path) +{ + g_return_if_fail (GLADE_IS_WIDGET (widget)); + g_return_if_fail (action_path != NULL); + + glade_widget_action_lookup (&widget->actions, action_path, TRUE); +} + +/** + * glade_widget_create_action_menu: + * @widget: a #GladeWidget + * @action_path: an action path or NULL to include every @widget action. + * + * Create a new GtkMenu with every action in it. + * + */ +GtkWidget * +glade_widget_create_action_menu (GladeWidget *widget, const gchar *action_path) +{ + GladeWidgetAction *action = NULL; + GtkWidget *menu; + + g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL); + + if (action_path) + action = glade_widget_action_lookup (&widget->actions, action_path, FALSE); + + menu = gtk_menu_new (); + if (glade_popup_action_populate_menu (menu, widget, action)) + return menu; + + g_object_unref (G_OBJECT (menu)); + + return NULL; +} /******************************************************************************* * Toplevel GladeWidget Embedding * diff --git a/gladeui/glade-widget.h b/gladeui/glade-widget.h index c10d1a40..9e792b85 100644 --- a/gladeui/glade-widget.h +++ b/gladeui/glade-widget.h @@ -3,6 +3,7 @@ #define __GLADE_WIDGET_H__ #include <gladeui/glade-widget-adaptor.h> +#include <gladeui/glade-widget-action.h> #include <gladeui/glade-signal.h> #include <gladeui/glade-property.h> @@ -88,6 +89,8 @@ struct _GladeWidget gint height; /* usefull for parentless widgets in the * GladeDesignLayout */ + GList *actions; /* A GladeWidgetAction list */ + /* Construct parameters: */ GladeWidget *construct_template; GladeWidgetInfo *construct_info; @@ -106,7 +109,6 @@ struct _GladeWidgetClass void (*add_signal_handler) (GladeWidget *, GladeSignal *); void (*remove_signal_handler) (GladeWidget *, GladeSignal *); void (*change_signal_handler) (GladeWidget *, GladeSignal *, GladeSignal *); - gboolean (*action_activated) (GladeWidget *, const gchar *); gint (*button_press_event) (GladeWidget *, GdkEvent *); gint (*button_release_event) (GladeWidget *, GdkEvent *); @@ -190,6 +192,15 @@ gboolean glade_widget_event (GladeWidget *g gboolean glade_widget_placeholder_relation (GladeWidget *parent, GladeWidget *widget); +GladeWidgetAction * glade_widget_get_action (GladeWidget *widget, + const gchar *action_path); + +void glade_widget_remove_action (GladeWidget *widget, + const gchar *action_path); + +GtkWidget * glade_widget_create_action_menu (GladeWidget *widget, + const gchar *action_path); + /******************************************************************************* Project, object property references *******************************************************************************/ diff --git a/gladeui/glade-xml-utils.h b/gladeui/glade-xml-utils.h index 26ac14a0..297cee51 100644 --- a/gladeui/glade-xml-utils.h +++ b/gladeui/glade-xml-utils.h @@ -55,6 +55,8 @@ typedef struct _GladeXmlDoc GladeXmlDoc; #define GLADE_TAG_CHILD_SET_PROP_FUNCTION "child-set-property-function" #define GLADE_TAG_CHILD_GET_PROP_FUNCTION "child-get-property-function" #define GLADE_TAG_CHILD_VERIFY_FUNCTION "child-verify-function" +#define GLADE_TAG_CONSTRUCTOR_FUNCTION "constructor-function" +#define GLADE_TAG_ACTION_ACTIVATE_FUNCTION "action-activate-function" #define GLADE_TAG_PROPERTIES "properties" #define GLADE_TAG_PACKING_PROPERTIES "packing-properties" #define GLADE_TAG_PROPERTY "property" diff --git a/plugins/gtk+/glade-gtk.c b/plugins/gtk+/glade-gtk.c index 944f7eac..e8f1ee0e 100644 --- a/plugins/gtk+/glade-gtk.c +++ b/plugins/gtk+/glade-gtk.c @@ -3905,26 +3905,6 @@ glade_gtk_image_set_property (GladeWidgetAdaptor *adaptor, id, value); } -/* ----------------------------- menu callbacks ------------------------------ */ -static void glade_gtk_menu_shell_launch_editor (GObject *object, gchar *title); - -static gboolean -glade_gtk_menu_launch_editor_action (GladeWidget *gwidget, const gchar *data) -{ - GladeWidget *iter = gwidget; - - while (!GTK_IS_MENU_BAR (iter->object) && - /* Make sure we support menus inside toolbars */ - iter->parent && GTK_IS_MENU_SHELL (iter->parent->object)) - iter = iter->parent; - - glade_gtk_menu_shell_launch_editor (iter->object, - GTK_IS_MENU_BAR (iter->object) ? - _("Menu Bar Editor") : _("Menu Editor")); - return TRUE; -} - - /* ----------------------------- GtkMenuShell ------------------------------ */ void glade_gtk_menu_shell_add_item (GladeWidgetAdaptor *adaptor, @@ -4248,6 +4228,24 @@ glade_gtk_menu_shell_launch_editor (GObject *object, gchar *title) gtk_widget_show (window); } +void +glade_gtk_menu_shell_action_activate (GladeWidgetAdaptor *adaptor, + GObject *object, + const gchar *action_path) +{ + if (strcmp (action_path, "launch_editor") == 0) + { + if (GTK_IS_MENU_BAR (object)) + glade_gtk_menu_shell_launch_editor (object, _("Edit Menu Bar")); + else if (GTK_IS_MENU (object)) + glade_gtk_menu_shell_launch_editor (object, _("Edit Menu")); + } + else + GWA_GET_CLASS (GTK_TYPE_CONTAINER)->action_activate (adaptor, + object, + action_path); +} + /* ----------------------------- GtkMenuItem(s) ------------------------------ */ GList * glade_gtk_menu_item_get_children (GladeWidgetAdaptor *adaptor, @@ -4307,9 +4305,6 @@ glade_gtk_menu_item_post_create (GladeWidgetAdaptor *adaptor, g_return_if_fail (GTK_IS_MENU_ITEM (object)); gitem = glade_widget_get_from_gobject (object); g_return_if_fail (GLADE_IS_WIDGET (gitem)); - - /* hook the launch_editor action signal for all items */ - g_signal_connect (gitem, "action-activated::launch_editor", G_CALLBACK (glade_gtk_menu_launch_editor_action), NULL); if (GTK_IS_SEPARATOR_MENU_ITEM (object)) return; @@ -4721,6 +4716,31 @@ glade_gtk_radio_menu_item_set_property (GladeWidgetAdaptor *adaptor, id, value); } +void +glade_gtk_menu_item_action_activate (GladeWidgetAdaptor *adaptor, + GObject *object, + const gchar *action_path) +{ + if (strcmp (action_path, "launch_editor") == 0) + { + GladeWidget *w = glade_widget_get_from_gobject (object); + + while ((w = glade_widget_get_parent (w))) + { + GObject *obj = glade_widget_get_object (w); + if (GTK_IS_MENU_SHELL (obj)) object = obj; + } + + if (GTK_IS_MENU_BAR (object)) + glade_gtk_menu_shell_launch_editor (object, _("Edit Menu Bar")); + else if (GTK_IS_MENU (object)) + glade_gtk_menu_shell_launch_editor (object, _("Edit Menu")); + } + else + GWA_GET_CLASS (GTK_TYPE_CONTAINER)->action_activate (adaptor, + object, + action_path); +} /* ----------------------------- GtkMenuBar ------------------------------ */ static GladeWidget * @@ -4810,9 +4830,6 @@ glade_gtk_menu_bar_post_create (GladeWidgetAdaptor *adaptor, gmenubar = glade_widget_get_from_gobject (object); g_return_if_fail (GLADE_IS_WIDGET (gmenubar)); - /* hook the launch_editor action signal for all reasons */ - g_signal_connect (gmenubar, "action-activated::launch_editor", G_CALLBACK (glade_gtk_menu_launch_editor_action), NULL); - if (reason != GLADE_CREATE_USER) return; project = glade_widget_get_project (gmenubar); @@ -4844,23 +4861,6 @@ glade_gtk_menu_bar_post_create (GladeWidgetAdaptor *adaptor, glade_gtk_menu_bar_append_new_item (gsubmenu, project, "gtk-about", TRUE); } -/* ------------------------------ GtkMenu -------------------------------- */ -void -glade_gtk_menu_post_create (GladeWidgetAdaptor *adaptor, - GObject *object, - GladeCreateReason reason) -{ - GladeWidget *gmenu; - - g_return_if_fail (GTK_IS_MENU (object)); - gmenu = glade_widget_get_from_gobject (object); - g_return_if_fail (GLADE_IS_WIDGET (gmenu)); - - /* hook the launch_editor action signal for all reasons */ - g_signal_connect (gmenu, "action-activated::launch_editor", G_CALLBACK (glade_gtk_menu_launch_editor_action), NULL); - -} - /* ----------------------------- GtkToolBar ------------------------------ */ void glade_gtk_toolbar_get_child_property (GladeWidgetAdaptor *adaptor, @@ -5012,7 +5012,6 @@ glade_gtk_toolbar_child_selected (GladeBaseEditor *editor, "group", "active", NULL); } -/* XXX Must reintegrate this code with actions when ready */ void glade_gtk_toolbar_launch_editor (GladeWidgetAdaptor *adaptor, GObject *toolbar) @@ -5047,6 +5046,21 @@ glade_gtk_toolbar_launch_editor (GladeWidgetAdaptor *adaptor, gtk_widget_show (window); } +void +glade_gtk_toolbar_action_activate (GladeWidgetAdaptor *adaptor, + GObject *object, + const gchar *action_path) +{ + if (strcmp (action_path, "launch_editor") == 0) + { + glade_gtk_toolbar_launch_editor (adaptor, object); + } + else + GWA_GET_CLASS (GTK_TYPE_CONTAINER)->action_activate (adaptor, + object, + action_path); +} + /* ----------------------------- GtkToolItem ------------------------------ */ void glade_gtk_tool_item_post_create (GladeWidgetAdaptor *adaptor, diff --git a/plugins/gtk+/gtk+.xml.in b/plugins/gtk+/gtk+.xml.in index 0be483fd..93ac58ea 100644 --- a/plugins/gtk+/gtk+.xml.in +++ b/plugins/gtk+/gtk+.xml.in @@ -292,6 +292,7 @@ embedded in another object</_tooltip> <remove-child-function>glade_gtk_menu_shell_remove_item</remove-child-function> <child-set-property-function>glade_gtk_menu_shell_set_child_property</child-set-property-function> <child-get-property-function>glade_gtk_menu_shell_get_child_property</child-get-property-function> + <action-activate-function>glade_gtk_menu_shell_action_activate</action-activate-function> <packing-properties> <property id="position" _name="Position" default="-1" save="False"> <spec>glade_standard_int_spec</spec> @@ -307,6 +308,7 @@ embedded in another object</_tooltip> <set-property-function>glade_gtk_menu_item_set_property</set-property-function> <add-child-function>glade_gtk_menu_item_add_submenu</add-child-function> <remove-child-function>glade_gtk_menu_item_remove_submenu</remove-child-function> + <action-activate-function>glade_gtk_menu_item_action_activate</action-activate-function> <properties> <property id="label" _name="Label" translatable="True"> <_tooltip>The text of the menu item</_tooltip> @@ -399,6 +401,7 @@ embedded in another object</_tooltip> <remove-child-function>glade_gtk_toolbar_remove_child</remove-child-function> <child-set-property-function>glade_gtk_toolbar_set_child_property</child-set-property-function> <child-get-property-function>glade_gtk_toolbar_get_child_property</child-get-property-function> + <action-activate-function>glade_gtk_toolbar_action_activate</action-activate-function> <properties> <property id="orientation"> @@ -1023,7 +1026,7 @@ embedded in another object</_tooltip> <glade-widget-class name="GtkMenu" generic-name="menu" _title="Popup Menu" toplevel="True"> <action id="launch_editor" _name="Edit Menu" stock="gtk-edit"/> <!-- We do not want glade_gtk_container_post_create be executed --> - <post-create-function>glade_gtk_menu_post_create</post-create-function> + <post-create-function>empty</post-create-function> </glade-widget-class> <glade-widget-class name="GtkHScrollbar" generic-name="hscrollbar" _title="Horizontal Scrollbar"/> |