diff options
author | Dan Winship <danw@src.gnome.org> | 2004-04-09 23:46:00 +0800 |
---|---|---|
committer | Dan Winship <danw@src.gnome.org> | 2004-04-09 23:46:00 +0800 |
commit | 7f2badb024128819fbb1d2656057c5e476100cd8 (patch) | |
tree | c13bcea14f62769857b72307f6eef59f183babaa /shell | |
parent | fabe4f1d8ae42c7bf8f1674c98ef4103e2e53bf0 (diff) | |
download | gsoc2013-evolution-7f2badb024128819fbb1d2656057c5e476100cd8.tar gsoc2013-evolution-7f2badb024128819fbb1d2656057c5e476100cd8.tar.gz gsoc2013-evolution-7f2badb024128819fbb1d2656057c5e476100cd8.tar.bz2 gsoc2013-evolution-7f2badb024128819fbb1d2656057c5e476100cd8.tar.lz gsoc2013-evolution-7f2badb024128819fbb1d2656057c5e476100cd8.tar.xz gsoc2013-evolution-7f2badb024128819fbb1d2656057c5e476100cd8.tar.zst gsoc2013-evolution-7f2badb024128819fbb1d2656057c5e476100cd8.zip |
Change this a lot. Now each component will maintain its own
* e-user-creatable-items-handler.c: Change this a lot. Now each
component will maintain its own EUserCreatableItemsHandler and
merge the button and menus in and out of the UI as its controls
are activated and deactivated. (This lets the connector component
display the correct default for the New button). Also, update to
the Product Design Team's new organization (separating object
types from folder types)
* e-shell.c: Remove all creatable_items_handler references
* e-shell-window.c (e_shell_window_new): Remove
creatable_items_handler reference
* Makefile.am: Move e-user-creatable-items-handler from evolution
to libeshell, and make libeshell depend on libemiscwidgets (for
the combo button)
* Evolution-Component.idl: add another field to CreatableItemType
so we can distinguish object types from folder types.
svn path=/trunk/; revision=25379
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ChangeLog | 22 | ||||
-rw-r--r-- | shell/Evolution-Component.idl | 6 | ||||
-rw-r--r-- | shell/Makefile.am | 7 | ||||
-rw-r--r-- | shell/e-shell-window.c | 2 | ||||
-rw-r--r-- | shell/e-shell.c | 16 | ||||
-rw-r--r-- | shell/e-shell.h | 3 | ||||
-rw-r--r-- | shell/e-user-creatable-items-handler.c | 746 | ||||
-rw-r--r-- | shell/e-user-creatable-items-handler.h | 19 |
8 files changed, 446 insertions, 375 deletions
diff --git a/shell/ChangeLog b/shell/ChangeLog index 3ab4e72c68..8635e6537a 100644 --- a/shell/ChangeLog +++ b/shell/ChangeLog @@ -1,3 +1,25 @@ +2004-04-09 Dan Winship <danw@ximian.com> + + * e-user-creatable-items-handler.c: Change this a lot. Now each + component will maintain its own EUserCreatableItemsHandler and + merge the button and menus in and out of the UI as its controls + are activated and deactivated. (This lets the connector component + display the correct default for the New button). Also, update to + the Product Design Team's new organization (separating object + types from folder types) + + * e-shell.c: Remove all creatable_items_handler references + + * e-shell-window.c (e_shell_window_new): Remove + creatable_items_handler reference + + * Makefile.am: Move e-user-creatable-items-handler from evolution + to libeshell, and make libeshell depend on libemiscwidgets (for + the combo button) + + * Evolution-Component.idl: add another field to CreatableItemType + so we can distinguish object types from folder types. + 2004-04-07 Jeffrey Stedfast <fejj@ximian.com> * Evolution-ConfigControl.idl: Removed the "apply" method. diff --git a/shell/Evolution-Component.idl b/shell/Evolution-Component.idl index 873cd6b7d0..69893387fc 100644 --- a/shell/Evolution-Component.idl +++ b/shell/Evolution-Component.idl @@ -12,6 +12,11 @@ module GNOME { module Evolution { + enum CreatableItem { + CREATABLE_OBJECT, + CREATABLE_FOLDER + }; + /* A type of item that the component can create when asked by the user, e.g. a mail message or an appointment. */ struct CreatableItemType { @@ -21,6 +26,7 @@ module Evolution { string tooltip; char menuShortcut; string iconName; + CreatableItem type; }; typedef sequence <CreatableItemType> CreatableItemTypeList; diff --git a/shell/Makefile.am b/shell/Makefile.am index db789739a1..6ade83a734 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -104,6 +104,7 @@ eshellinclude_HEADERS = \ e-icon-factory.h \ e-shell-corba-icon-utils.h \ e-shell-utils.h \ + e-user-creatable-items-handler.h \ evolution-config-control.h \ evolution-shell-component-utils.h \ evolution-wizard.h @@ -114,13 +115,15 @@ libeshell_la_SOURCES = \ e-icon-factory.c \ e-shell-corba-icon-utils.c \ e-shell-utils.c \ + e-user-creatable-items-handler.c \ evolution-config-control.c \ evolution-shell-component-utils.c \ evolution-wizard.c \ $(eshellinclude_HEADERS) libeshell_la_LIBADD = \ - $(top_builddir)/e-util/libeutil.la + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/widgets/misc/libemiscwidgets.la # Evolution executable @@ -156,8 +159,6 @@ evolution_SOURCES = \ e-shell.h \ e-sidebar.c \ e-sidebar.h \ - e-user-creatable-items-handler.c \ - e-user-creatable-items-handler.h \ main.c evolution_LDADD = \ diff --git a/shell/e-shell-window.c b/shell/e-shell-window.c index b74ca15374..592b20688f 100644 --- a/shell/e-shell-window.c +++ b/shell/e-shell-window.c @@ -738,8 +738,6 @@ e_shell_window_new (EShell *shell, gconf_client_get_int (gconf_client, "/apps/evolution/shell/view_defaults/width", NULL), gconf_client_get_int (gconf_client, "/apps/evolution/shell/view_defaults/height", NULL)); - e_user_creatable_items_handler_attach_menus (e_shell_peek_user_creatable_items_handler (shell), window); - g_object_unref (gconf_client); return GTK_WIDGET (window); } diff --git a/shell/e-shell.c b/shell/e-shell.c index 8068d0a145..4c5748031f 100644 --- a/shell/e-shell.c +++ b/shell/e-shell.c @@ -77,7 +77,6 @@ struct _EShellPrivate { GList *windows; - EUserCreatableItemsHandler *user_creatable_items_handler; /* EUriSchemaRegistry *uri_schema_registry; FIXME */ EComponentRegistry *component_registry; @@ -340,11 +339,6 @@ impl_dispose (GObject *object) priv->is_initialized = FALSE; - if (priv->user_creatable_items_handler != NULL) { - g_object_unref (priv->user_creatable_items_handler); - priv->user_creatable_items_handler = NULL; - } - #if 0 /* FIXME */ if (priv->uri_schema_registry != NULL) { g_object_unref (priv->uri_schema_registry); @@ -465,7 +459,6 @@ e_shell_init (EShell *shell) priv = g_new0 (EShellPrivate, 1); priv->line_status = E_SHELL_LINE_STATUS_OFFLINE; priv->component_registry = e_component_registry_new (); - priv->user_creatable_items_handler = e_user_creatable_items_handler_new (priv->component_registry); shell->priv = priv; } @@ -1165,13 +1158,4 @@ e_shell_quit(EShell *shell) return can_quit; } -EUserCreatableItemsHandler * -e_shell_peek_user_creatable_items_handler (EShell *shell) -{ - g_return_val_if_fail (E_IS_SHELL (shell), NULL); - - return shell->priv->user_creatable_items_handler; -} - - BONOBO_TYPE_FUNC_FULL (EShell, GNOME_Evolution_Shell, PARENT_TYPE, e_shell) diff --git a/shell/e-shell.h b/shell/e-shell.h index 976016da97..f9aa3855e0 100644 --- a/shell/e-shell.h +++ b/shell/e-shell.h @@ -39,7 +39,6 @@ typedef struct _EShellClass EShellClass; #include "e-component-registry.h" #include "e-shell-window.h" -#include "e-user-creatable-items-handler.h" #define E_TYPE_SHELL (e_shell_get_type ()) @@ -137,8 +136,6 @@ gboolean e_shell_quit (EShell *shell); const char *e_shell_construct_result_to_string (EShellConstructResult result); -EUserCreatableItemsHandler *e_shell_peek_user_creatable_items_handler (EShell *shell); - #ifdef __cplusplus } diff --git a/shell/e-user-creatable-items-handler.c b/shell/e-user-creatable-items-handler.c index d7e4454cf6..ba6c006c8d 100644 --- a/shell/e-user-creatable-items-handler.c +++ b/shell/e-user-creatable-items-handler.c @@ -1,7 +1,7 @@ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* e-shell-user-creatable-items-handler.c +/* e-user-creatable-items-handler.c * - * Copyright (C) 2001 Ximian, Inc. + * Copyright (C) 2001-2004 Novell, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -27,10 +27,10 @@ #include "e-user-creatable-items-handler.h" #include "e-shell-utils.h" - -#include "widgets/misc/e-combo-button.h" +#include "Evolution.h" #include "e-util/e-corba-utils.h" +#include "widgets/misc/e-combo-button.h" #include <gal/util/e-util.h> @@ -40,6 +40,11 @@ #include <libgnome/gnome-i18n.h> +#include <gtk/gtkaccelgroup.h> +#include <gtk/gtkimage.h> +#include <gtk/gtkimagemenuitem.h> +#include <gtk/gtkmenu.h> +#include <gtk/gtkseparatormenuitem.h> #include <gtk/gtksignal.h> #include <gtk/gtktooltips.h> @@ -52,16 +57,8 @@ static GObjectClass *parent_class = NULL; -#define VERB_PREFIX "ShellUserCreatableItemVerb" - -#define EVOLUTION_MAIL_OAFIID "OAFIID:GNOME_Evolution_Mail_ShellComponent:" BASE_VERSION - -#define SHELL_WINDOW_KEY "EUserCreatableItemsHandler:shell_window" -#define COMBO_BUTTON_WIDGET_KEY "EUserCreatableItemsHandler:combo_button" -#define TOOLTIPS_KEY "EUserCreatableItemsHandler:tooltips" - struct _Component { - char *id; + char *id, *alias; GNOME_Evolution_Component component; GNOME_Evolution_CreatableItemTypeList *type_list; }; @@ -73,23 +70,38 @@ struct _MenuItem { char shortcut; char *verb; char *tooltip; - char *component_id; + char *component; GdkPixbuf *icon; }; typedef struct _MenuItem MenuItem; struct _EUserCreatableItemsHandlerPrivate { + /* This component's alias */ + char *this_component; + /* The components that register user creatable items. */ GSList *components; /* Component */ /* The "New ..." menu items. */ - GSList *menu_items; /* MenuItem */ + GSList *objects; /* MenuItem */ + GSList *folders; /* MenuItem */ /* The default item (the mailer's "message" item). To be used when the component in the view we are in doesn't provide a default user creatable type. This pointer always points to one of the menu items - in ->menu_items. */ + in ->objects. */ const MenuItem *default_menu_item; + + char *menu_xml; + GtkWidget *new_button, *new_menu; + BonoboControl *new_control; + GtkTooltips *tooltips; + GtkAccelGroup *accel_group; +}; + +enum { + PROP_THIS_COMPONENT = 1, + LAST_PROP }; @@ -97,6 +109,7 @@ struct _EUserCreatableItemsHandlerPrivate { static Component * component_new (const char *id, + const char *component_alias, GNOME_Evolution_Component component) { CORBA_Environment ev; @@ -106,6 +119,7 @@ component_new (const char *id, new = g_new (Component, 1); new->id = g_strdup (id); + new->alias = g_strdup (component_alias); new->type_list = GNOME_Evolution_Component__get_userCreatableItems (component, &ev); if (BONOBO_EX (&ev)) @@ -132,6 +146,7 @@ component_free (Component *component) Bonobo_Unknown_unref (component->component, &ev); g_free (component->id); + g_free (component->alias); if (component->type_list != NULL) CORBA_free (component->type_list); @@ -141,25 +156,47 @@ component_free (Component *component) g_free (component); } +static const char *component_query = + "repo_ids.has ('IDL:GNOME/Evolution/Component:" BASE_VERSION "')"; + static void -get_components_from_registry (EUserCreatableItemsHandler *handler, - EComponentRegistry *registry) +get_components_from_bonobo (EUserCreatableItemsHandler *handler) { - GSList *registry_list = e_component_registry_peek_list (registry); - GSList *p; + Bonobo_ServerInfoList *info_list; + Bonobo_ActivationProperty *property; + CORBA_Environment ev; + char *iid, *alias; + GNOME_Evolution_Component corba_component; + Component *component; + int i; - for (p = registry_list; p != NULL; p = p->next) { - EComponentInfo *info = p->data; - Component *component = NULL; + CORBA_exception_init (&ev); + info_list = bonobo_activation_query (component_query, NULL, &ev); + if (BONOBO_EX (&ev)) { + char *ex_text = bonobo_exception_get_text (&ev); + g_warning ("Cannot query for components: %s\n", ex_text); + g_free (ex_text); + CORBA_exception_free (&ev); + return; + } - e_component_registry_activate (registry, info->id, NULL); + for (i = 0; i < info_list->_length; i++) { + iid = info_list->_buffer[i].iid; + corba_component = bonobo_activation_activate_from_id (iid, Bonobo_ACTIVATION_FLAG_EXISTING_ONLY, NULL, &ev); + if (BONOBO_EX (&ev)) { + CORBA_exception_free (&ev); + continue; + } - if (info->iface != CORBA_OBJECT_NIL) - component = component_new (info->id, info->iface); + property = bonobo_server_info_prop_find (&info_list->_buffer[i], + "evolution:component_alias"); + alias = property ? property->v._u.value_string : "unknown"; - if (component) - handler->priv->components = g_slist_prepend (handler->priv->components, component); + component = component_new (iid, alias, corba_component); + handler->priv->components = g_slist_prepend (handler->priv->components, component); } + + CORBA_free (info_list); } @@ -167,22 +204,24 @@ get_components_from_registry (EUserCreatableItemsHandler *handler, static gboolean item_is_default (const MenuItem *item, - const char *component_id) + const char *component) { - if (component_id == NULL) + if (component == NULL) return FALSE; - if (strcmp (item->component_id, component_id) == 0) + if (strcmp (item->component, component) == 0) return TRUE; else return FALSE; } static char * -create_verb_from_component_number_and_type_id (int component_num, - const char *type_id) +create_verb (EUserCreatableItemsHandler *handler, + int component_num, const char *type_id) { - return g_strdup_printf (VERB_PREFIX ":%d:%s", component_num, type_id); + return g_strdup_printf ("EUserCreatableItemsHandler-%s:%d:%s", + handler->priv->this_component, + component_num, type_id); } @@ -193,16 +232,16 @@ static void ensure_menu_items (EUserCreatableItemsHandler *handler) { EUserCreatableItemsHandlerPrivate *priv; - GSList *menu_items; + GSList *objects, *folders; GSList *p; int component_num; const char *default_verb; priv = handler->priv; - if (priv->menu_items != NULL) + if (priv->objects != NULL) return; - menu_items = NULL; + objects = folders = NULL; component_num = 0; default_verb = NULL; for (p = priv->components; p != NULL; p = p->next) { @@ -212,42 +251,46 @@ ensure_menu_items (EUserCreatableItemsHandler *handler) component = (const Component *) p->data; if (component->type_list != NULL) { for (i = 0; i < component->type_list->_length; i ++) { - const GNOME_Evolution_CreatableItemType *type; + const GNOME_Evolution_CreatableItemType *corba_item; MenuItem *item; - type = (const GNOME_Evolution_CreatableItemType *) component->type_list->_buffer + i; + corba_item = (const GNOME_Evolution_CreatableItemType *) component->type_list->_buffer + i; item = g_new (MenuItem, 1); - item->label = type->menuDescription; - item->shortcut = type->menuShortcut; - item->verb = create_verb_from_component_number_and_type_id (component_num, type->id); - item->tooltip = type->tooltip; - item->component_id = g_strdup (component->id); - - if (strcmp (item->component_id, EVOLUTION_MAIL_OAFIID) == 0 - && strcmp (type->id, "message") == 0) + item->label = corba_item->menuDescription; + item->shortcut = corba_item->menuShortcut; + item->verb = create_verb (handler, component_num, corba_item->id); + item->tooltip = corba_item->tooltip; + item->component = g_strdup (component->alias); + + if (strcmp (item->component, "mail") == 0 + && strcmp (corba_item->id, "message") == 0) default_verb = item->verb; - if (type->iconName == "") { + if (corba_item->iconName == "") { item->icon = NULL; } else { - char *icon_path = e_shell_get_icon_path (type->iconName, TRUE); + char *icon_path = e_shell_get_icon_path (corba_item->iconName, TRUE); item->icon = gdk_pixbuf_new_from_file (icon_path, NULL); g_free (icon_path); } - menu_items = g_slist_prepend (menu_items, item); + if (corba_item->type == GNOME_Evolution_CREATABLE_OBJECT) + objects = g_slist_prepend (objects, item); + else + folders = g_slist_prepend (folders, item); } } component_num ++; } - priv->menu_items = g_slist_reverse (menu_items); + priv->objects = g_slist_reverse (objects); + priv->folders = g_slist_reverse (folders); priv->default_menu_item = NULL; if (default_verb != NULL) { - for (p = priv->menu_items; p != NULL; p = p->next) { + for (p = priv->objects; p != NULL; p = p->next) { const MenuItem *item; item = (const MenuItem *) p->data; @@ -274,7 +317,7 @@ free_menu_items (GSList *menu_items) if (item->icon != NULL) g_object_unref (item->icon); - g_free (item->component_id); + g_free (item->component); g_free (item); } @@ -282,24 +325,18 @@ free_menu_items (GSList *menu_items) } static const MenuItem * -get_default_action_for_view (EUserCreatableItemsHandler *handler, - EShellWindow *window) +get_default_action_for_view (EUserCreatableItemsHandler *handler) { EUserCreatableItemsHandlerPrivate *priv; - const char *window_component_id; const GSList *p; priv = handler->priv; - window_component_id = e_shell_window_peek_current_component_id (window); - if (window_component_id == NULL) - return priv->default_menu_item; - - for (p = priv->menu_items; p != NULL; p = p->next) { + for (p = priv->objects; p != NULL; p = p->next) { const MenuItem *item; item = (const MenuItem *) p->data; - if (item_is_default (item, window_component_id)) + if (item_is_default (item, priv->this_component)) return item; } @@ -307,163 +344,10 @@ get_default_action_for_view (EUserCreatableItemsHandler *handler, } -/* The XML description for "File -> New". */ - -/* This adds a menu item for @item. If @first is true, the keyboard shortcut - is going to be "Control-N" instead of whatever the component defines. */ -static void -append_xml_for_menu_item (GString *xml, - const MenuItem *item, - gboolean first) -{ - char *encoded_label; - char *encoded_tooltip; - - encoded_label = bonobo_ui_util_encode_str (item->label); - g_string_append_printf (xml, "<menuitem name=\"New:%s\" verb=\"%s\" label=\"%s\"", - item->verb, item->verb, encoded_label); - - if (first) - g_string_append_printf (xml, " accel=\"*Control*N\""); - else if (item->shortcut != '\0') - g_string_append_printf (xml, " accel=\"*Control**Shift*%c\"", item->shortcut); - - if (item->icon != NULL) { - char *icon_xml; - - icon_xml = bonobo_ui_util_pixbuf_to_xml (item->icon); - g_string_append_printf (xml, " pixtype=\"pixbuf\" pixname=\"%s\"", icon_xml); - g_free (icon_xml); - } - - encoded_tooltip = bonobo_ui_util_encode_str (item->tooltip); - g_string_append_printf (xml, " tip=\"%s\"", encoded_tooltip); - - g_string_append (xml, "/> "); - - g_free (encoded_label); - g_free (encoded_tooltip); -} - -static int -item_types_sort_func (const void *a, - const void *b) -{ - const MenuItem *item_a; - const MenuItem *item_b; - const char *p1, *p2; - - item_a = (const MenuItem *) a; - item_b = (const MenuItem *) b; - - p1 = item_a->label; - p2 = item_b->label; - - while (*p1 != '\0' && *p2 != '\0') { - if (*p1 == '_') { - p1 ++; - continue; - } - - if (*p2 == '_') { - p2 ++; - continue; - } - - if (toupper ((int) *p1) < toupper ((int) *p2)) - return -1; - else if (toupper ((int) *p1) > toupper ((int) *p2)) - return +1; - - p1 ++, p2 ++; - } - - if (*p1 == '\0') { - if (*p2 == '\0') - return 0; - else - return -1; - } else { - return +1; - } -} - -static char * -create_menu_xml (EUserCreatableItemsHandler *handler, - const char *component_id) -{ - EUserCreatableItemsHandlerPrivate *priv; - GString *xml; - GSList *p; - GSList *non_default_items; - char *retval; - - priv = handler->priv; - - ensure_menu_items (handler); - - xml = g_string_new (""); - - g_string_append (xml, "<placeholder name=\"ComponentItems\">"); - g_string_append (xml, "<placeholder name=\"EUserCreatableItemsPlaceholder\">"); - - /* 1. Add all the elements that are default for this component. (Note - that we don't need to do any sorting since the items are already - sorted alphabetically.) */ - - if (component_id != NULL) { - gboolean first = TRUE; - - for (p = priv->menu_items; p != NULL; p = p->next) { - const MenuItem *item; - - item = (const MenuItem *) p->data; - if (item_is_default (item, component_id)) { - append_xml_for_menu_item (xml, item, first); - first = FALSE; - } - } - } - - /* 2. Add a separator. */ - - if (component_id != NULL) - g_string_append_printf (xml, - "<separator f=\"\" name=\"EUserCreatableItemsHandlerSeparator\"/>"); - - /* 3. Add the elements that are not default for this component. */ - - non_default_items = NULL; - for (p = priv->menu_items; p != NULL; p = p->next) { - const MenuItem *item; - - item = (const MenuItem *) p->data; - if (! item_is_default (item, component_id)) - non_default_items = g_slist_prepend (non_default_items, (void *) item); - } - - non_default_items = g_slist_sort (non_default_items, item_types_sort_func); - for (p = non_default_items; p != NULL; p = p->next) - append_xml_for_menu_item (xml, (const MenuItem *) p->data, FALSE); - g_slist_free (non_default_items); - - /* Done... */ - - g_string_append (xml, "</placeholder>"); /* EUserCreatableItemsPlaceholder */ - g_string_append (xml, "</placeholder>"); /* ComponentItems */ - - retval = xml->str; - g_string_free (xml, FALSE); - - return retval; -} - - /* Verb handling. */ static void execute_verb (EUserCreatableItemsHandler *handler, - EShellWindow *window, const char *verb_name) { EUserCreatableItemsHandlerPrivate *priv; @@ -514,31 +398,22 @@ verb_fn (BonoboUIComponent *ui_component, void *data, const char *verb_name) { - EUserCreatableItemsHandler *handler; - EShellWindow *shell_window; + EUserCreatableItemsHandler *handler= + E_USER_CREATABLE_ITEMS_HANDLER (data); - shell_window = g_object_get_data (G_OBJECT (ui_component), SHELL_WINDOW_KEY); - g_assert (E_IS_SHELL_WINDOW (shell_window)); - - handler = E_USER_CREATABLE_ITEMS_HANDLER (data); - - execute_verb (handler, shell_window, verb_name); + execute_verb (handler, verb_name); } static void add_verbs (EUserCreatableItemsHandler *handler, - EShellWindow *window) + BonoboUIComponent *ui_component) { EUserCreatableItemsHandlerPrivate *priv; - BonoboUIComponent *ui_component; int component_num; GSList *p; priv = handler->priv; - ui_component = e_shell_window_peek_bonobo_ui_component (window); - g_object_set_data (G_OBJECT (ui_component), SHELL_WINDOW_KEY, window); - component_num = 0; for (p = priv->components; p != NULL; p = p->next) { const Component *component; @@ -550,8 +425,9 @@ add_verbs (EUserCreatableItemsHandler *handler, for (i = 0; i < component->type_list->_length; i ++) { char *verb_name; - verb_name = create_verb_from_component_number_and_type_id - (component_num, component->type_list->_buffer[i].id); + verb_name = create_verb (handler, + component_num, + component->type_list->_buffer[i].id); bonobo_ui_component_add_verb (ui_component, verb_name, verb_fn, handler); @@ -564,119 +440,298 @@ add_verbs (EUserCreatableItemsHandler *handler, } -/* The "New" button in the toolbar. */ +/* Generic menu construction code */ -static void -combo_button_activate_default_callback (EComboButton *combo_button, - void *data) +static int +item_types_sort_func (const void *a, + const void *b) { - EShellWindow *shell_window; - EUserCreatableItemsHandler *handler; - const MenuItem *menu_item; + const MenuItem *item_a; + const MenuItem *item_b; + const char *p1, *p2; + + item_a = (const MenuItem *) a; + item_b = (const MenuItem *) b; + + p1 = item_a->label; + p2 = item_b->label; + + while (*p1 != '\0' && *p2 != '\0') { + if (*p1 == '_') { + p1 ++; + continue; + } + + if (*p2 == '_') { + p2 ++; + continue; + } + + if (toupper ((int) *p1) < toupper ((int) *p2)) + return -1; + else if (toupper ((int) *p1) > toupper ((int) *p2)) + return +1; - shell_window = E_SHELL_WINDOW (data); - handler = e_shell_peek_user_creatable_items_handler (e_shell_window_peek_shell (shell_window)); + p1 ++, p2 ++; + } - menu_item = get_default_action_for_view (handler, shell_window); - execute_verb (handler, shell_window, menu_item->verb); + if (*p1 == '\0') { + if (*p2 == '\0') + return 0; + else + return -1; + } else { + return +1; + } } +typedef void (*EUserCreatableItemsHandlerMenuItemFunc) (EUserCreatableItemsHandler *, gpointer, MenuItem *, gboolean); +typedef void (*EUserCreatableItemsHandlerSeparatorFunc) (EUserCreatableItemsHandler *, gpointer, int); + static void -setup_toolbar_button (EUserCreatableItemsHandler *handler, - EShellWindow *window) +construct_menu (EUserCreatableItemsHandler *handler, gpointer menu, + EUserCreatableItemsHandlerMenuItemFunc menu_item_func, + EUserCreatableItemsHandlerSeparatorFunc separator_func) { EUserCreatableItemsHandlerPrivate *priv; - BonoboUIComponent *ui_component; - GtkWidget *combo_button; - GtkWidget *menu; - GtkTooltips *tooltips; - BonoboControl *control; + MenuItem *item; + GSList *p, *items; + gboolean first = TRUE; priv = handler->priv; - menu = gtk_menu_new (); + /* First add the current component's creatable objects */ + for (p = priv->objects; p != NULL; p = p->next) { + item = p->data; + if (item_is_default (item, priv->this_component)) { + menu_item_func (handler, menu, item, first); + first = FALSE; + } + } - combo_button = e_combo_button_new (); - e_combo_button_set_menu (E_COMBO_BUTTON (combo_button), GTK_MENU (menu)); - e_combo_button_set_label (E_COMBO_BUTTON (combo_button), _("New")); - gtk_widget_show (combo_button); + /* Then its creatable folders */ + for (p = priv->folders; p != NULL; p = p->next) { + item = p->data; + if (item_is_default (item, priv->this_component)) + menu_item_func (handler, menu, item, FALSE); + } - g_signal_connect (combo_button, "activate_default", G_CALLBACK (combo_button_activate_default_callback), window); + /* Then a separator */ + separator_func (handler, menu, 1); - ui_component = e_shell_window_peek_bonobo_ui_component (window); - bonobo_window_add_popup (BONOBO_WINDOW (window), GTK_MENU (menu), "/popups/NewPopup"); + /* Then the objects from other components. */ + items = NULL; + for (p = priv->objects; p != NULL; p = p->next) { + item = p->data; + if (! item_is_default (item, priv->this_component)) + items = g_slist_prepend (items, item); + } - control = bonobo_control_new (combo_button); + items = g_slist_sort (items, item_types_sort_func); + for (p = items; p != NULL; p = p->next) + menu_item_func (handler, menu, p->data, FALSE); + g_slist_free (items); - bonobo_ui_component_object_set (ui_component, "/Toolbar/NewComboButton", - BONOBO_OBJREF (control), NULL); + /* Another separator */ + separator_func (handler, menu, 2); - bonobo_object_unref (control); - - g_object_set_data (G_OBJECT (window), COMBO_BUTTON_WIDGET_KEY, combo_button); + /* And finally the folders from other components */ + items = NULL; + for (p = priv->folders; p != NULL; p = p->next) { + item = p->data; + if (! item_is_default (item, priv->this_component)) + items = g_slist_prepend (items, item); + } - tooltips = gtk_tooltips_new (); - g_object_set_data (G_OBJECT (combo_button), TOOLTIPS_KEY, tooltips); + items = g_slist_sort (items, item_types_sort_func); + for (p = items; p != NULL; p = p->next) + menu_item_func (handler, menu, p->data, FALSE); + g_slist_free (items); } +/* The XML description for "File -> New". */ static void -update_for_window (EUserCreatableItemsHandler *handler, - EShellWindow *window) +xml_menu_item_func (EUserCreatableItemsHandler *handler, gpointer menu, + MenuItem *item, gboolean first) { - GtkWidget *combo_button_widget; - GtkTooltips *tooltips; - BonoboUIComponent *ui_component; - const MenuItem *default_menu_item; - char *menu_xml; + GString *xml = menu; + char *encoded_label; + char *encoded_tooltip; - combo_button_widget = g_object_get_data (G_OBJECT (window), COMBO_BUTTON_WIDGET_KEY); - g_assert (E_IS_COMBO_BUTTON (combo_button_widget)); + encoded_label = bonobo_ui_util_encode_str (item->label); + g_string_append_printf (xml, "<menuitem name=\"New:%s\" verb=\"%s\" label=\"%s\"", + item->verb, item->verb, encoded_label); - tooltips = g_object_get_data (G_OBJECT (combo_button_widget), TOOLTIPS_KEY); - g_assert (tooltips != NULL); + if (first) + g_string_append_printf (xml, " accel=\"*Control*N\""); + else if (item->shortcut != '\0') + g_string_append_printf (xml, " accel=\"*Control**Shift*%c\"", item->shortcut); - default_menu_item = get_default_action_for_view (handler, window); - if (default_menu_item == NULL) { - gtk_widget_set_sensitive (combo_button_widget, FALSE); - e_combo_button_set_label (E_COMBO_BUTTON (combo_button_widget), _("New")); - e_combo_button_set_icon (E_COMBO_BUTTON (combo_button_widget), NULL); - gtk_tooltips_set_tip (tooltips, combo_button_widget, NULL, NULL); - return; + if (item->icon != NULL) { + char *icon_xml; + + icon_xml = bonobo_ui_util_pixbuf_to_xml (item->icon); + g_string_append_printf (xml, " pixtype=\"pixbuf\" pixname=\"%s\"", icon_xml); + g_free (icon_xml); } - gtk_widget_set_sensitive (combo_button_widget, TRUE); + encoded_tooltip = bonobo_ui_util_encode_str (item->tooltip); + g_string_append_printf (xml, " tip=\"%s\"", encoded_tooltip); - e_combo_button_set_icon (E_COMBO_BUTTON (combo_button_widget), default_menu_item->icon); - gtk_tooltips_set_tip (tooltips, combo_button_widget, default_menu_item->tooltip, NULL); + g_string_append (xml, "/> "); - ui_component = e_shell_window_peek_bonobo_ui_component (window); - bonobo_ui_component_rm (ui_component, "/menu/File/New/ComponentItems/EUserCreatableItemsPlaceholder", NULL); - bonobo_ui_component_rm (ui_component, "/popups/NewPopup/ComponentItems/EUserCreatableItemsPlaceholder", NULL); + g_free (encoded_label); + g_free (encoded_tooltip); +} + +static void +xml_separator_func (EUserCreatableItemsHandler *handler, gpointer menu, int nth) +{ + GString *xml = menu; + + g_string_append_printf (xml, "<separator f=\"\" name=\"EUserCreatableItemsHandlerSeparator%d\"/>", nth); +} + +static void +create_menu_xml (EUserCreatableItemsHandler *handler) +{ + GString *xml; - menu_xml = create_menu_xml (handler, e_shell_window_peek_current_component_id (window)); + xml = g_string_new ("<placeholder name=\"NewMenu\">"); + construct_menu (handler, xml, xml_menu_item_func, xml_separator_func); + g_string_append (xml, "</placeholder>"); - bonobo_ui_component_set (ui_component, "/menu/File/New", menu_xml, NULL); - bonobo_ui_component_set (ui_component, "/popups/NewPopup", menu_xml, NULL); - g_free (menu_xml); + handler->priv->menu_xml = xml->str; + g_string_free (xml, FALSE); } -/* This handles the menus for a given EShellWindow. We have to rebuild the menu - and set the toolbar button every time the view changes, and clean up when - the view is destroyed. */ +/* The GtkMenu for the toolbar button. */ + +static void +menuitem_activate (GtkMenuItem *item, gpointer data) +{ + EUserCreatableItemsHandler *handler = data; + const char *verb; + + verb = g_object_get_data (G_OBJECT (item), "EUserCreatableItemsHandler:verb"); + execute_verb (handler, verb); +} + +static void +default_activate (EComboButton *combo_button, gpointer data) +{ + EUserCreatableItemsHandler *handler = data; + + execute_verb (handler, handler->priv->default_menu_item->verb); +} + +static void +gtk_menu_item_func (EUserCreatableItemsHandler *handler, gpointer menu, + MenuItem *item, gboolean first) +{ + GtkWidget *menuitem, *icon; + + menuitem = gtk_image_menu_item_new_with_mnemonic (item->label); + + if (item->icon) { + icon = gtk_image_new_from_pixbuf (item->icon); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), + icon); + } + + if (first) { + gtk_widget_add_accelerator (menuitem, "activate", + handler->priv->accel_group, + 'n', GDK_CONTROL_MASK, + GTK_ACCEL_VISIBLE); + } else { + gtk_widget_add_accelerator (menuitem, "activate", + handler->priv->accel_group, + item->shortcut, + GDK_CONTROL_MASK | GDK_SHIFT_MASK, + GTK_ACCEL_VISIBLE); + } + + g_object_set_data (G_OBJECT (menuitem), "EUserCreatableItemsHandler:verb", item->verb); + g_signal_connect (menuitem, "activate", + G_CALLBACK (menuitem_activate), handler); + + gtk_menu_shell_append (menu, menuitem); +} + +static void +gtk_separator_func (EUserCreatableItemsHandler *handler, gpointer menu, int nth) +{ + gtk_menu_shell_append (menu, gtk_separator_menu_item_new ()); +} static void -shell_window_component_changed_callback (EShellWindow *shell_window, - EUserCreatableItemsHandler *handler) +setup_toolbar_button (EUserCreatableItemsHandler *handler) { - update_for_window (handler, shell_window); + EUserCreatableItemsHandlerPrivate *priv; + const MenuItem *default_menu_item; + + priv = handler->priv; + + priv->new_button = e_combo_button_new (); + priv->new_menu = gtk_menu_new (); + priv->accel_group = gtk_accel_group_new (); + construct_menu (handler, priv->new_menu, + gtk_menu_item_func, gtk_separator_func); + gtk_widget_show_all (priv->new_menu); + e_combo_button_set_menu (E_COMBO_BUTTON (priv->new_button), + GTK_MENU (priv->new_menu)); + e_combo_button_set_label (E_COMBO_BUTTON (priv->new_button), _("New")); + gtk_widget_show (priv->new_button); + + g_signal_connect (priv->new_button, "activate_default", + G_CALLBACK (default_activate), handler); + + priv->new_control = bonobo_control_new (priv->new_button); + + default_menu_item = get_default_action_for_view (handler); + if (!default_menu_item) { + gtk_widget_set_sensitive (priv->new_button, FALSE); + return; + } + + gtk_widget_set_sensitive (priv->new_button, TRUE); + + e_combo_button_set_icon (E_COMBO_BUTTON (priv->new_button), + default_menu_item->icon); + + priv->tooltips = gtk_tooltips_new (); + gtk_object_ref (GTK_OBJECT (priv->tooltips)); + gtk_object_sink (GTK_OBJECT (priv->tooltips)); + gtk_tooltips_set_tip (priv->tooltips, priv->new_button, + default_menu_item->tooltip, NULL); } /* GObject methods. */ static void +impl_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + EUserCreatableItemsHandler *handler = + E_USER_CREATABLE_ITEMS_HANDLER (object); + + switch (prop_id) { + case PROP_THIS_COMPONENT: + handler->priv->this_component = g_value_dup_string (value); + + get_components_from_bonobo (handler); + ensure_menu_items (handler); + break; + default: + break; + } +} + +static void impl_dispose (GObject *object) { EUserCreatableItemsHandler *handler; @@ -692,7 +747,21 @@ impl_dispose (GObject *object) g_slist_free (priv->components); priv->components = NULL; - + if (priv->new_control) { + bonobo_object_unref (priv->new_control); + priv->new_control = NULL; + } + + if (priv->tooltips) { + g_object_unref (priv->tooltips); + priv->tooltips = NULL; + } + + if (priv->accel_group) { + g_object_unref (priv->accel_group); + priv->accel_group = NULL; + } + (* G_OBJECT_CLASS (parent_class)->dispose) (object); } @@ -705,7 +774,10 @@ impl_finalize (GObject *object) handler = E_USER_CREATABLE_ITEMS_HANDLER (object); priv = handler->priv; - free_menu_items (priv->menu_items); + g_free (priv->this_component); + + free_menu_items (priv->objects); + free_menu_items (priv->folders); g_free (priv); @@ -718,73 +790,69 @@ class_init (GObjectClass *object_class) { parent_class = g_type_class_ref(PARENT_TYPE); - object_class->dispose = impl_dispose; - object_class->finalize = impl_finalize; + object_class->dispose = impl_dispose; + object_class->finalize = impl_finalize; + object_class->set_property = impl_set_property; + + g_object_class_install_property ( + object_class, PROP_THIS_COMPONENT, + g_param_spec_string ("this_component", "Component alias", + "The component_alias of this component", + NULL, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); } static void -init (EUserCreatableItemsHandler *shell_user_creatable_items_handler) +init (EUserCreatableItemsHandler *handler) { EUserCreatableItemsHandlerPrivate *priv; - priv = g_new (EUserCreatableItemsHandlerPrivate, 1); - priv->components = NULL; - priv->menu_items = NULL; - priv->default_menu_item = NULL; + priv = g_new0 (EUserCreatableItemsHandlerPrivate, 1); - shell_user_creatable_items_handler->priv = priv; + handler->priv = priv; } EUserCreatableItemsHandler * -e_user_creatable_items_handler_new (EComponentRegistry *registry) +e_user_creatable_items_handler_new (const char *component_alias) { - EUserCreatableItemsHandler *new; - - new = g_object_new (e_user_creatable_items_handler_get_type (), NULL); - - get_components_from_registry (new, registry); - - return new; + return g_object_new (e_user_creatable_items_handler_get_type (), + "this_component", component_alias, + NULL); } /** - * e_user_creatable_items_handler_attach_menus: - * @handler: - * @shell_window: + * e_user_creatable_items_handler_activate: + * @handler: the #EUserCreatableItemsHandler + * @ui_component: the #BonoboUIComponent to attach to * - * Set up the menus and toolbar items for @shell_window. When the shell changes - * view, the menu and the toolbar item will update automatically (i.e. the - * actions for the current folder will go on top etc.). + * Set up the menus and toolbar items for @ui_component. **/ void -e_user_creatable_items_handler_attach_menus (EUserCreatableItemsHandler *handler, - EShellWindow *window) +e_user_creatable_items_handler_activate (EUserCreatableItemsHandler *handler, + BonoboUIComponent *ui_component) { - BonoboUIComponent *ui_component; EUserCreatableItemsHandlerPrivate *priv; - char *menu_xml; g_return_if_fail (E_IS_USER_CREATABLE_ITEMS_HANDLER (handler)); - g_return_if_fail (E_IS_SHELL_WINDOW (window)); + g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui_component)); priv = handler->priv; - setup_toolbar_button (handler, window); - g_signal_connect (window, "component_changed", G_CALLBACK (shell_window_component_changed_callback), handler); - - add_verbs (handler, window); - menu_xml = create_menu_xml (handler, e_shell_window_peek_current_component_id (window)); - - ui_component = e_shell_window_peek_bonobo_ui_component (window); - bonobo_ui_component_set (ui_component, "/menu/File/New", menu_xml, NULL); - bonobo_ui_component_set (ui_component, "/popups/NewPopup", menu_xml, NULL); + if (!priv->menu_xml) { + create_menu_xml (handler); + setup_toolbar_button (handler); + add_verbs (handler, ui_component); + } - g_free (menu_xml); + bonobo_ui_component_set (ui_component, "/menu/File/New", + priv->menu_xml, NULL); - update_for_window (handler, window); + bonobo_ui_component_object_set (ui_component, + "/Toolbar/NewComboButton", + BONOBO_OBJREF (priv->new_control), + NULL); } - E_MAKE_TYPE (e_user_creatable_items_handler, "EUserCreatableItemsHandler", EUserCreatableItemsHandler, class_init, init, PARENT_TYPE) diff --git a/shell/e-user-creatable-items-handler.h b/shell/e-user-creatable-items-handler.h index d6f12e3973..f7be31894e 100644 --- a/shell/e-user-creatable-items-handler.h +++ b/shell/e-user-creatable-items-handler.h @@ -1,7 +1,7 @@ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* e-shell-user-creatable-items-handler.h +/* e-user-creatable-items-handler.h * - * Copyright (C) 2001 Ximian, Inc. + * Copyright (C) 2001-2004 Novell, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -25,6 +25,7 @@ #include <glib-object.h> #include <bonobo/bonobo-ui-component.h> +#include <bonobo/bonobo-window.h> #ifdef __cplusplus extern "C" { @@ -43,9 +44,6 @@ typedef struct _EUserCreatableItemsHandlerPrivate EUserCreatableItemsHandlerPriv typedef struct _EUserCreatableItemsHandlerClass EUserCreatableItemsHandlerClass; -#include "e-shell-window.h" - - struct _EUserCreatableItemsHandler { GObject parent; @@ -57,14 +55,11 @@ struct _EUserCreatableItemsHandlerClass { }; -GtkType e_user_creatable_items_handler_get_type (void); -EUserCreatableItemsHandler *e_user_creatable_items_handler_new (EComponentRegistry *registry); +GType e_user_creatable_items_handler_get_type (void); +EUserCreatableItemsHandler *e_user_creatable_items_handler_new (const char *component_alias); -void e_user_creatable_items_handler_add_component (EUserCreatableItemsHandler *handler, - const char *id, - GNOME_Evolution_Component component); -void e_user_creatable_items_handler_attach_menus (EUserCreatableItemsHandler *handler, - EShellWindow *window); +void e_user_creatable_items_handler_activate (EUserCreatableItemsHandler *handler, + BonoboUIComponent *ui_component); #ifdef __cplusplus } |