From 4eb4ae3be83fcc187ac0ca3bd104a14ceeb0786f Mon Sep 17 00:00:00 2001 From: Ettore Perazzoli Date: Wed, 23 Jan 2002 22:21:24 +0000 Subject: [Implement an Outlook-style "New" dropdown button. It is basically done but it needs pretty icons so I am leaving it disabled for now.] * e-combo-button.c: Remove member `separator' from `EComboButtonPrivate'. New members `icon', `label'. (init): There shall be no separator no more. Init `icon' and `label' to %NULL. (e_combo_button_construct): Set no relief. (e_combo_button_new): Don't get a @menu arg anymore. (e_combo_button_construct): Likewise. (e_combo_button_set_icon): New. (e_combo_button_set_label): New. (e_combo_button_set_menu): New. (impl_clicked): New, overriding the "clicked" method for GtkButton. (class_init): Install. (impl_button_release_event): Removed. (class_init): No need to override ::release_event with this anymore. (impl_released): New, override for the GtkButton::released method. (class_init): Install. * e-shell-user-creatable-items-handler.c: New member `id' in struct `Component'. New member `icon' in struct `MenuItem'. (component_free): Free ->id. (component_new): Renamed from `component_new_from_client'. Get an @id arg and set ->id accordingly. (e_shell_user_creatable_items_handler_add_component): New arg @id. Pass it to `component_new'. (e_shell_user_creatable_items_handler_setup_menus): New arg @current_component_id. (e_shell_user_creatable_items_handler_update_menus): New. (set_current_component): New helper function. (get_component_by_id): New helper function. (add_verbs): Renamed from `add_verbs_to_ui_component()'. Get a @shell_view instead of a @ui_component. Set the SHELL_VIEW_KEY on the ui_component of the shell_view to point to the shell_view itself. (ensure_menu_items): Set item->icon to NULL. (free_menu_items): Unref item->icon. (ensure_menu_xml): Set the icon as well. (get_default_action_for_view): New helper function. (find_menu_item_for_verb): New helper function. (shell_view_view_changed_callback): New callback, set up the label on the "New" button depending on the current component. (e_shell_user_creatable_items_handler_attach_menus): New. For now, do not display the toolbar button yet. (execute_verb): New helper function, splitting out code from `verb_fn'. (verb_fn): Use `execute_verb'. (combo_button_activate_default_callback): Callback for the "activate_default" signal on the EComboButton. (setup_toolbar_button): Connect. * evolution-shell-component.c: New member `icon' in `UserCreatableItemType'. (impl__get_userCreatableItemTypes): Put the ->icon in the corba_type as well. (user_creatable_item_type_new): Get a new @icon argument. (evolution_shell_component_add_user_creatable_item): New arg @icon. * Evolution-ShellComponent.idl: New member `icon' in struct `UserCreatableItemType'. * evolution-test-component.c (register_component): Pass a NULL @icon to `evolution_shell_component_add_user_creatable_item()'. * e-shell-view.c (class_init): Add the signal to the class. (e_shell_view_display_uri): Emit "view_changed". (e_shell_view_get_current_component_id): New. * evolution-shell-component-client.c: New member `id' in EvolutionShellComponentClientPrivate. (init): Init to NULL. (impl_destroy): Free. (evolution_shell_component_client_new_for_objref): Removed. (evolution_shell_component_client_construct): New arg @id. Initialize ->id from it. (evolution_shell_component_client_get_id): New. * e-shell-view.h: New signal "view_changed". * evolution-activity-client.c (create_icon_from_pixbuf): Removed. (create_corba_animated_icon_from_pixbuf_array): Removed. (evolution_activity_client_construct): Use `e_new_corba_animated_icon_from_pixbuf_array()' instead. svn path=/trunk/; revision=15438 --- shell/e-shell-user-creatable-items-handler.c | 381 +++++++++++++++++++++------ 1 file changed, 299 insertions(+), 82 deletions(-) (limited to 'shell/e-shell-user-creatable-items-handler.c') diff --git a/shell/e-shell-user-creatable-items-handler.c b/shell/e-shell-user-creatable-items-handler.c index 4b2554fb66..cafd074605 100644 --- a/shell/e-shell-user-creatable-items-handler.c +++ b/shell/e-shell-user-creatable-items-handler.c @@ -26,12 +26,18 @@ #include "e-shell-user-creatable-items-handler.h" +#include "widgets/misc/e-combo-button.h" + #include "e-util/e-corba-utils.h" #include #include +#include + +#include + #include #include @@ -41,7 +47,9 @@ static GtkObjectClass *parent_class = NULL; #define VERB_PREFIX "ShellUserCreatableItemVerb" -#define SHELL_VIEW_DATA_KEY "EShellUserCreatableItemsHandler:shell_view" + +#define SHELL_VIEW_KEY "EShellUserCreatableItemsHandler:shell_view" +#define COMBO_BUTTON_WIDGET_KEY "EShellUserCreatableItemsHandler:combo_button" struct _Component { EvolutionShellComponentClient *component_client; @@ -50,9 +58,18 @@ struct _Component { }; typedef struct _Component Component; +struct _MenuItem { + const char *label; + char shortcut; + char *verb; + GdkPixbuf *icon; +}; +typedef struct _MenuItem MenuItem; + struct _EShellUserCreatableItemsHandlerPrivate { GSList *components; /* Component */ + GSList *menu_items; /* MenuItem */ char *menu_xml; }; @@ -60,7 +77,8 @@ struct _EShellUserCreatableItemsHandlerPrivate { /* Component struct handling. */ static Component * -component_new_from_client (EvolutionShellComponentClient *client) +component_new (const char *id, + EvolutionShellComponentClient *client) { CORBA_Environment ev; Component *new; @@ -106,14 +124,8 @@ create_verb_from_component_number_and_type_id (int component_num, } -/* Setting up the XML for the menus. */ - -struct _MenuItem { - const char *label; - char shortcut; - char *verb; -}; -typedef struct _MenuItem MenuItem; +/* Setting up menu items for the "File -> New" submenu and the "New" toolbar + button. */ static int item_types_sort_func (const void *a, @@ -156,51 +168,10 @@ item_types_sort_func (const void *a, } else { return +1; } - -} - -static char * -create_xml_from_menu_items (GSList *items) -{ - GString *xml; - GSList *p; - char *str; - - xml = g_string_new (""); - - g_string_append (xml, " "); - - g_string_append (xml, " "); - - for (p = items; p != NULL; p = p->next) { - const MenuItem *item; - char *encoded_label; - - item = (const MenuItem *) p->data; - - encoded_label = bonobo_ui_util_encode_str (item->label); - - g_string_sprintfa (xml, "verb, item->verb, encoded_label); - - if (item->shortcut != '\0') - g_string_sprintfa (xml, " accel=\"*Control**Shift*%c\"", item->shortcut); - - g_string_append (xml, "/> "); - - g_free (encoded_label); - } - - g_string_append (xml, " "); - - str = xml->str; - g_string_free (xml, FALSE); - - return str; } static void -setup_menu_xml (EShellUserCreatableItemsHandler *handler) +ensure_menu_items (EShellUserCreatableItemsHandler *handler) { EShellUserCreatableItemsHandlerPrivate *priv; GSList *menu_items; @@ -208,7 +179,8 @@ setup_menu_xml (EShellUserCreatableItemsHandler *handler) int component_num; priv = handler->priv; - g_assert (priv->menu_xml == NULL); + if (priv->menu_items != NULL) + return; menu_items = NULL; component_num = 0; @@ -228,6 +200,7 @@ setup_menu_xml (EShellUserCreatableItemsHandler *handler) item->label = type->menuDescription; item->shortcut = type->menuShortcut; item->verb = create_verb_from_component_number_and_type_id (component_num, type->id); + item->icon = NULL; menu_items = g_slist_prepend (menu_items, item); } @@ -236,36 +209,154 @@ setup_menu_xml (EShellUserCreatableItemsHandler *handler) component_num ++; } - if (menu_items == NULL) { - priv->menu_xml = g_strdup (""); - return; - } + if (menu_items == NULL) + priv->menu_items = NULL; + else + priv->menu_items = g_slist_sort (menu_items, item_types_sort_func); +} - menu_items = g_slist_sort (menu_items, item_types_sort_func); +static void +free_menu_items (GSList *menu_items) +{ + GSList *p; - priv->menu_xml = create_xml_from_menu_items (menu_items); + if (menu_items == NULL) + return; for (p = menu_items; p != NULL; p = p->next) { MenuItem *item; item = (MenuItem *) p->data; g_free (item->verb); + + if (item->icon != NULL) + gdk_pixbuf_unref (item->icon); + g_free (item); } + g_slist_free (menu_items); } +static const MenuItem * +find_menu_item_for_verb (EShellUserCreatableItemsHandler *handler, + const char *verb) +{ + EShellUserCreatableItemsHandlerPrivate *priv; + GSList *p; + + priv = handler->priv; + + for (p = priv->menu_items; p != NULL; p = p->next) { + const MenuItem *item; + + item = (const MenuItem *) p->data; + if (strcmp (item->verb, verb) == 0) + return item; + } + + return NULL; +} + +static const MenuItem * +get_default_action_for_view (EShellUserCreatableItemsHandler *handler, + EShellView *shell_view) +{ + EShellUserCreatableItemsHandlerPrivate *priv; + const char *view_component_id; + const GSList *p; + int component_num; + + priv = handler->priv; + + /* FIXME-1.2: This should be based on the folder type not the component + that handles it. For this, we are going to have to make the IDL a + little more complex. Also, this is a pretty brutal and ugly hack. */ + + view_component_id = e_shell_view_get_current_component_id (shell_view); + + for (p = priv->components, component_num = 0; p != NULL; p = p->next, component_num ++) { + const Component *component; + const GNOME_Evolution_UserCreatableItemType *type; + const char *component_id; + + component = (const Component *) p->data; + type = & component->type_list->_buffer[0]; + component_id = evolution_shell_component_client_get_id (component->component_client); + + if (strcmp (component_id, view_component_id) == 0) { + const MenuItem *item; + char *verb; + + verb = create_verb_from_component_number_and_type_id (component_num, type->id); + item = find_menu_item_for_verb (handler, verb); + g_free (verb); + + return item; + } + } + + return NULL; +} + + +/* The XML description for "File -> New". */ + +static void +ensure_menu_xml (EShellUserCreatableItemsHandler *handler) +{ + EShellUserCreatableItemsHandlerPrivate *priv; + GString *xml; + GSList *p; + + priv = handler->priv; + if (priv->menu_xml != NULL) + return; + + ensure_menu_items (handler); + + xml = g_string_new (""); + + g_string_append (xml, ""); + + for (p = priv->menu_items; p != NULL; p = p->next) { + const MenuItem *item; + char *encoded_label; + + item = (const MenuItem *) p->data; + + encoded_label = bonobo_ui_util_encode_str (item->label); + + g_string_sprintfa (xml, "verb, item->verb, encoded_label); + + if (item->shortcut != '\0') + g_string_sprintfa (xml, " accel=\"*Control**Shift*%c\"", item->shortcut); + + if (item->icon != NULL) + g_string_sprintfa (xml, " pixtype=\"pixbuf\" pixname=\"%s\"", + bonobo_ui_util_pixbuf_to_xml (item->icon)); + + g_string_append (xml, "/> "); + + g_free (encoded_label); + } + + g_string_append (xml, ""); + + priv->menu_xml = xml->str; + g_string_free (xml, FALSE); +} + /* Verb handling. */ static void -verb_fn (BonoboUIComponent *ui_component, - void *data, - const char *verb_name) +execute_verb (EShellUserCreatableItemsHandler *handler, + EShellView *shell_view, + const char *verb_name) { - EShellUserCreatableItemsHandler *handler; EShellUserCreatableItemsHandlerPrivate *priv; - EShellView *shell_view; const Component *component; int component_number; const char *p; @@ -273,10 +364,6 @@ verb_fn (BonoboUIComponent *ui_component, GSList *component_list_item; int i; - shell_view = gtk_object_get_data (GTK_OBJECT (ui_component), SHELL_VIEW_DATA_KEY); - g_assert (E_IS_SHELL_VIEW (shell_view)); - - handler = E_SHELL_USER_CREATABLE_ITEMS_HANDLER (data); priv = handler->priv; p = strchr (verb_name, ':'); @@ -318,15 +405,35 @@ verb_fn (BonoboUIComponent *ui_component, } static void -add_verbs_to_ui_component (EShellUserCreatableItemsHandler *handler, - BonoboUIComponent *ui_component) +verb_fn (BonoboUIComponent *ui_component, + void *data, + const char *verb_name) +{ + EShellUserCreatableItemsHandler *handler; + EShellView *shell_view; + + shell_view = gtk_object_get_data (GTK_OBJECT (ui_component), SHELL_VIEW_KEY); + g_assert (E_IS_SHELL_VIEW (shell_view)); + + handler = E_SHELL_USER_CREATABLE_ITEMS_HANDLER (data); + + execute_verb (handler, shell_view, verb_name); +} + +static void +add_verbs (EShellUserCreatableItemsHandler *handler, + EShellView *shell_view) { EShellUserCreatableItemsHandlerPrivate *priv; + BonoboUIComponent *ui_component; int component_num; GSList *p; priv = handler->priv; + ui_component = e_shell_view_get_bonobo_ui_component (shell_view); + gtk_object_set_data (GTK_OBJECT (ui_component), SHELL_VIEW_KEY, shell_view); + component_num = 0; for (p = priv->components; p != NULL; p = p->next) { const Component *component; @@ -351,6 +458,99 @@ add_verbs_to_ui_component (EShellUserCreatableItemsHandler *handler, } } + +/* The "New" button in the toolbar. */ + +static void +combo_button_activate_default_callback (EComboButton *combo_button, + void *data) +{ + EShellView *shell_view; + EShellUserCreatableItemsHandler *handler; + const MenuItem *menu_item; + + shell_view = E_SHELL_VIEW (data); + handler = e_shell_get_user_creatable_items_handler (e_shell_view_get_shell (shell_view)); + + menu_item = get_default_action_for_view (handler, shell_view); + execute_verb (handler, shell_view, menu_item->verb); +} + +static void +setup_toolbar_button (EShellUserCreatableItemsHandler *handler, + EShellView *shell_view) +{ + EShellUserCreatableItemsHandlerPrivate *priv; + BonoboUIComponent *ui_component; + GtkWidget *combo_button; + GtkWidget *menu; + BonoboControl *control; + + priv = handler->priv; + + menu = gtk_menu_new (); + + 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); + + gtk_signal_connect (GTK_OBJECT (combo_button), "activate_default", + GTK_SIGNAL_FUNC (combo_button_activate_default_callback), + shell_view); + + ui_component = e_shell_view_get_bonobo_ui_component (shell_view); + bonobo_window_add_popup (BONOBO_WINDOW (shell_view), GTK_MENU (menu), "/popups/NewPopup"); + + control = bonobo_control_new (combo_button); + + bonobo_ui_component_object_set (ui_component, "/Toolbar/NewComboButton", + BONOBO_OBJREF (control), NULL); + + gtk_object_set_data (GTK_OBJECT (shell_view), COMBO_BUTTON_WIDGET_KEY, combo_button); +} + + +/* This handles the menus for a given EShellView. We have to rebuild the menu + and set the toolbar button every time the view changes, and clean up when + the view is destroyed. */ + +static void +shell_view_view_changed_callback (EShellView *shell_view, + const char *evolution_path, + const char *physical_uri, + const char *folder_type, + const char *component_id, + void *data) +{ + EShellUserCreatableItemsHandler *handler; + EShellUserCreatableItemsHandlerPrivate *priv; + GtkWidget *combo_button_widget; + const MenuItem *default_menu_item; + + handler = E_SHELL_USER_CREATABLE_ITEMS_HANDLER (data); + priv = handler->priv; + + combo_button_widget = gtk_object_get_data (GTK_OBJECT (shell_view), COMBO_BUTTON_WIDGET_KEY); + g_assert (E_IS_COMBO_BUTTON (combo_button_widget)); + + default_menu_item = get_default_action_for_view (handler, shell_view); + 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); + return; + } + + gtk_widget_set_sensitive (combo_button_widget, TRUE); + + /* FIXME: This is temporary. We should just always say "New" once we + have the icons for all the actions. */ + e_combo_button_set_label (E_COMBO_BUTTON (combo_button_widget), default_menu_item->label); + + e_combo_button_set_icon (E_COMBO_BUTTON (combo_button_widget), default_menu_item->icon); +} + /* GtkObject methods. */ @@ -371,6 +571,8 @@ impl_destroy (GtkObject *object) g_free (priv->menu_xml); + free_menu_items (priv->menu_items); + g_free (priv); (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); @@ -393,6 +595,7 @@ init (EShellUserCreatableItemsHandler *shell_user_creatable_items_handler) priv = g_new (EShellUserCreatableItemsHandlerPrivate, 1); priv->components = NULL; priv->menu_xml = NULL; + priv->menu_items = NULL; shell_user_creatable_items_handler->priv = priv; } @@ -410,6 +613,7 @@ e_shell_user_creatable_items_handler_new (void) void e_shell_user_creatable_items_handler_add_component (EShellUserCreatableItemsHandler *handler, + const char *id, EvolutionShellComponentClient *shell_component_client) { EShellUserCreatableItemsHandlerPrivate *priv; @@ -422,15 +626,25 @@ e_shell_user_creatable_items_handler_add_component (EShellUserCreatableItemsHan priv = handler->priv; g_return_if_fail (priv->menu_xml == NULL); - priv->components = g_slist_prepend (priv->components, component_new_from_client (shell_component_client)); + priv->components = g_slist_prepend (priv->components, component_new (id, shell_component_client)); } + +/** + * e_shell_user_creatable_items_handler_attach_menus: + * @handler: + * @shell_view: + * + * Set up the menus and toolbar items for @shell_view. 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.). + **/ void -e_shell_user_creatable_items_handler_setup_menus (EShellUserCreatableItemsHandler *handler, - EShellView *shell_view) +e_shell_user_creatable_items_handler_attach_menus (EShellUserCreatableItemsHandler *handler, + EShellView *shell_view) { - EShellUserCreatableItemsHandlerPrivate *priv; BonoboUIComponent *ui_component; + EShellUserCreatableItemsHandlerPrivate *priv; g_return_if_fail (handler != NULL); g_return_if_fail (E_IS_SHELL_USER_CREATABLE_ITEMS_HANDLER (handler)); @@ -439,17 +653,20 @@ e_shell_user_creatable_items_handler_setup_menus (EShellUserCreatableItemsHandle priv = handler->priv; - if (priv->menu_xml == NULL) - setup_menu_xml (handler); - - ui_component = e_shell_view_get_bonobo_ui_component (shell_view); - g_assert (ui_component); + /* FIXME: Re-enable this. */ + if (0) { + setup_toolbar_button (handler, shell_view); + gtk_signal_connect (GTK_OBJECT (shell_view), "view_changed", + GTK_SIGNAL_FUNC (shell_view_view_changed_callback), handler); + } - add_verbs_to_ui_component (handler, ui_component); + ensure_menu_xml (handler); - gtk_object_set_data (GTK_OBJECT (ui_component), SHELL_VIEW_DATA_KEY, shell_view); /* Yuck. */ + add_verbs (handler, shell_view); - bonobo_ui_component_set (ui_component, "/", priv->menu_xml, NULL); + ui_component = e_shell_view_get_bonobo_ui_component (shell_view); + bonobo_ui_component_set (ui_component, "/menu/File/New/NewItems", priv->menu_xml, NULL); + bonobo_ui_component_set (ui_component, "/popups/NewPopup", priv->menu_xml, NULL); } -- cgit v1.2.3