From 28b28bf057056d2aa28458b322319bf679608ae5 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Sun, 17 Aug 2008 01:36:11 +0000 Subject: Write the algorithm for sorting items in the "New" menu. Not yet tested. svn path=/branches/kill-bonobo/; revision=36004 --- shell/e-shell-view.c | 226 ++++++++++++++++++++++++++++++++++++++++- shell/e-shell-view.h | 13 ++- shell/e-shell-window-actions.c | 9 +- shell/e-shell-window-actions.h | 2 - shell/e-shell-window-private.c | 2 - shell/e-shell-window-private.h | 1 - 6 files changed, 240 insertions(+), 13 deletions(-) (limited to 'shell') diff --git a/shell/e-shell-view.c b/shell/e-shell-view.c index ef921a2ebf..1187c17ee4 100644 --- a/shell/e-shell-view.c +++ b/shell/e-shell-view.c @@ -23,6 +23,7 @@ #include #include "e-shell-window.h" +#include "e-shell-window-actions.h" #define E_SHELL_VIEW_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ @@ -41,9 +42,105 @@ enum { static gpointer parent_class; +static gint +shell_view_compare_actions (GtkAction *action1, + GtkAction *action2) +{ + gchar *label1, *label2; + gint result; + + /* XXX This is really inefficient, but we're only sorting + * a small number of actions (repeatedly, though). */ + + g_object_get (action1, "label", &label1, NULL); + g_object_get (action2, "label", &label2, NULL); + + result = g_utf8_collate (label1, label2); + + g_free (label1); + g_free (label2); + + return result; +} + +static void +shell_view_extract_actions (EShellView *shell_view, + GList **source_list, + GList **destination_list) +{ + GList *match_list = NULL; + GList *iter; + + /* Pick out the actions from the source list that are tagged + * as belonging to the given EShellView and move them to the + * destination list. */ + + /* Example: Suppose [A] and [C] are tagged for this EShellView. + * + * source_list = [A] -> [B] -> [C] + * ^ ^ + * | | + * match_list = [ ] --------> [ ] + * + * + * destination_list = [1] -> [2] (other actions) + */ + for (iter = *source_list; iter != NULL; iter = iter->next) { + GtkAction *action = iter->data; + EShellView *action_shell_view; + + action_shell_view = g_object_get_data ( + G_OBJECT (action), "shell-view"); + + if (action_shell_view != shell_view) + continue; + + match_list = g_list_append (match_list, iter); + } + + /* source_list = [B] match_list = [A] -> [C] */ + for (iter = match_list; iter != NULL; iter = iter->next) { + GList *link = iter->data; + + iter->data = link->data; + *source_list = g_list_delete_link (*source_list, link); + } + + /* destination_list = [1] -> [2] -> [A] -> [C] */ + *destination_list = g_list_concat (*destination_list, match_list); +} + +static void +shell_view_register_new_actions (EShellView *shell_view, + GtkActionGroup *action_group, + const GtkActionEntry *entries, + guint n_entries) +{ + guint ii; + + gtk_action_group_add_actions ( + action_group, entries, n_entries, shell_view); + + /* Tag each action with the shell view that registered it. + * This is used to help sort items in the "New" menu. */ + + for (ii = 0; ii < n_entries; ii++) { + const gchar *action_name; + GtkAction *action; + + action_name = entries[ii].name; + + action = gtk_action_group_get_action ( + action_group, action_name); + + g_object_set_data ( + G_OBJECT (action), "shell-view", shell_view); + } +} + static void shell_view_set_window (EShellView *shell_view, - GtkWindow *window) + GtkWidget *window) { g_return_if_fail (GTK_IS_WINDOW (window)); @@ -129,6 +226,80 @@ shell_view_finalize (GObject *object) G_OBJECT_CLASS (parent_class)->finalize (object); } +static GtkWidget * +shell_view_create_new_menu (EShellView *shell_view) +{ + GtkActionGroup *action_group; + GList *new_item_actions; + GList *new_source_actions; + GList *iter, *list = NULL; + GtkWidget *menu; + GtkWidget *separator; + GtkWidget *window; + + window = e_shell_view_get_window (shell_view); + + /* Get sorted lists of "new item" and "new source" actions. */ + + action_group = E_SHELL_WINDOW_ACTION_GROUP_NEW_ITEM (window); + + new_item_actions = g_list_sort ( + gtk_action_group_list_actions (action_group), + (GCompareFunc) shell_view_compare_actions); + + action_group = E_SHELL_WINDOW_ACTION_GROUP_NEW_SOURCE (window); + + new_source_actions = g_list_sort ( + gtk_action_group_list_actions (action_group), + (GCompareFunc) shell_view_compare_actions); + + /* Give priority to actions that belong to this shell view. */ + + shell_view_extract_actions ( + shell_view, &new_item_actions, &list); + + shell_view_extract_actions ( + shell_view, &new_source_actions, &list); + + /* Convert the actions to menu item proxy widgets. */ + + for (iter = list; iter != NULL; iter = iter->next) + iter->data = gtk_action_create_menu_item (iter->data); + + for (iter = new_item_actions; iter != NULL; iter = iter->next) + iter->data = gtk_action_create_menu_item (iter->data); + + for (iter = new_source_actions; iter != NULL; iter = iter->next) + iter->data = gtk_action_create_menu_item (iter->data); + + /* Add menu separators. */ + + separator = gtk_separator_menu_item_new (); + new_item_actions = g_list_prepend (new_item_actions, separator); + + separator = gtk_separator_menu_item_new (); + new_source_actions = g_list_prepend (new_source_actions, separator); + + /* Merge everything into one list, reflecting the menu layout. */ + + list = g_list_concat (list, new_item_actions); + new_item_actions = NULL; /* just for clarity */ + + list = g_list_concat (list, new_source_actions); + new_source_actions = NULL; /* just for clarity */ + + /* And finally, build the menu. */ + + menu = gtk_menu_new (); + + for (iter = list; iter != NULL; iter = iter->next) + gtk_menu_shell_append (GTK_MENU_SHELL (menu), iter->data); + + g_list_free (list); + + return menu; +} + static void shell_view_class_init (EShellViewClass *class) { @@ -143,6 +314,8 @@ shell_view_class_init (EShellViewClass *class) object_class->dispose = shell_view_dispose; object_class->finalize = shell_view_finalize; + class->create_new_menu = shell_view_create_new_menu; + g_object_class_install_property ( object_class, PROP_TITLE, @@ -219,7 +392,7 @@ e_shell_view_set_title (EShellView *shell_view, g_object_notify (G_OBJECT (shell_view), "title"); } -GtkWindow * +GtkWidget * e_shell_view_get_window (EShellView *shell_view) { g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); @@ -227,6 +400,19 @@ e_shell_view_get_window (EShellView *shell_view) return shell_view->priv->window; } +GtkWidget * +e_shell_view_create_new_menu (EShellView *shell_view) +{ + EShellViewClass *class; + + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); + + class = E_SHELL_VIEW_CLASS (shell_view); + g_return_val_if_fail (class->create_new_menu != NULL, NULL); + + return class->create_new_menu (shell_view); +} + GtkWidget * e_shell_view_get_content_widget (EShellView *shell_view) { @@ -265,3 +451,39 @@ e_shell_view_get_status_widget (EShellView *shell_view) return class->get_status_widget (shell_view); } + +void +e_shell_view_register_new_item_actions (EShellView *shell_view, + const GtkActionEntry *entries, + guint n_entries) +{ + GtkWidget *window; + GtkActionGroup *action_group; + + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + g_return_if_fail (entries != NULL); + + window = e_shell_view_get_window (shell_view); + action_group = E_SHELL_WINDOW_ACTION_GROUP_NEW_ITEM (window); + + shell_view_register_new_actions ( + shell_view, action_group, entries, n_entries); +} + +void +e_shell_view_register_new_source_actions (EShellView *shell_view, + const GtkActionEntry *entries, + guint n_entries) +{ + GtkWidget *window; + GtkActionGroup *action_group; + + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + g_return_if_fail (entries != NULL); + + window = e_shell_view_get_window (shell_view); + action_group = E_SHELL_WINDOW_ACTION_GROUP_NEW_SOURCE (window); + + shell_view_register_new_actions ( + shell_view, action_group, entries, n_entries); +} diff --git a/shell/e-shell-view.h b/shell/e-shell-view.h index 641eed6406..5f1be6fa7d 100644 --- a/shell/e-shell-view.h +++ b/shell/e-shell-view.h @@ -60,6 +60,7 @@ struct _EShellViewClass { const gchar *label; const gchar *icon_name; + GtkWidget * (*create_new_menu) (EShellView *shell_view); GtkWidget * (*get_content_widget) (EShellView *shell_view); GtkWidget * (*get_sidebar_widget) (EShellView *shell_view); GtkWidget * (*get_status_widget) (EShellView *shell_view); @@ -69,11 +70,21 @@ GType e_shell_view_get_type (void); const gchar * e_shell_view_get_title (EShellView *shell_view); void e_shell_view_set_title (EShellView *shell_view, const gchar *title); -GtkWindow * e_shell_view_get_window (EShellView *shell_view); +GtkWidget * e_shell_view_get_window (EShellView *shell_view); +GtkWidget * e_shell_view_create_new_menu (EShellView *shell_view); GtkWidget * e_shell_view_get_content_widget (EShellView *shell_view); GtkWidget * e_shell_view_get_sidebar_widget (EShellView *shell_view); GtkWidget * e_shell_view_get_status_widget (EShellView *shell_view); +void e_shell_view_register_new_item_actions + (EShellView *shell_view, + const GtkActionEntry *entries, + guint n_entries); +void e_shell_view_register_new_source_actions + (EShellView *shell_view, + const GtkActionEntry *entries, + guint n_entries); + G_END_DECLS #endif /* E_SHELL_VIEW_H */ diff --git a/shell/e-shell-window-actions.c b/shell/e-shell-window-actions.c index c4d9b1b99e..85bdf445d9 100644 --- a/shell/e-shell-window-actions.c +++ b/shell/e-shell-window-actions.c @@ -1220,11 +1220,6 @@ e_shell_window_actions_init (EShellWindow *window) gtk_action_group_set_translation_domain (action_group, domain); gtk_ui_manager_insert_action_group (manager, action_group, 0); - /* New Group Actions (empty) */ - action_group = window->priv->new_group_actions; - gtk_action_group_set_translation_domain (action_group, domain); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - /* New Source Actions (empty) */ action_group = window->priv->new_source_actions; gtk_action_group_set_translation_domain (action_group, domain); @@ -1253,6 +1248,10 @@ e_shell_window_create_shell_view_actions (EShellWindow *window) manager = e_shell_window_get_ui_manager (window); merge_id = gtk_ui_manager_new_merge_id (manager); + /* Construct a group of radio actions from the various EShellView + * subclasses and register them with our ESidebar. These actions + * are manifested as switcher buttons and View->Window menu items. */ + for (ii = 0; ii < n_types; ii++) { EShellViewClass *class; GtkRadioAction *action; diff --git a/shell/e-shell-window-actions.h b/shell/e-shell-window-actions.h index a05165cdbd..80c16b11bf 100644 --- a/shell/e-shell-window-actions.h +++ b/shell/e-shell-window-actions.h @@ -68,8 +68,6 @@ E_SHELL_WINDOW_ACTION ((window), "work-online") /* Action Groups */ -#define E_SHELL_WINDOW_ACTION_GROUP_NEW_GROUP(window) \ - E_SHELL_WINDOW_ACTION_GROUP ((window), "new-group") #define E_SHELL_WINDOW_ACTION_GROUP_NEW_ITEM(window) \ E_SHELL_WINDOW_ACTION_GROUP ((window), "new-item") #define E_SHELL_WINDOW_ACTION_GROUP_NEW_SOURCE(window) \ diff --git a/shell/e-shell-window-private.c b/shell/e-shell-window-private.c index be25861c73..1db8652cfa 100644 --- a/shell/e-shell-window-private.c +++ b/shell/e-shell-window-private.c @@ -108,7 +108,6 @@ e_shell_window_private_init (EShellWindow *window) priv->manager = gtk_ui_manager_new (); priv->shell_actions = gtk_action_group_new ("shell"); priv->new_item_actions = gtk_action_group_new ("new-item"); - priv->new_group_actions = gtk_action_group_new ("new-group"); priv->new_source_actions = gtk_action_group_new ("new-source"); priv->shell_view_actions = gtk_action_group_new ("shell-view"); @@ -253,7 +252,6 @@ e_shell_window_private_dispose (EShellWindow *window) DISPOSE (priv->manager); DISPOSE (priv->shell_actions); DISPOSE (priv->new_item_actions); - DISPOSE (priv->new_group_actions); DISPOSE (priv->new_source_actions); DISPOSE (priv->shell_view_actions); diff --git a/shell/e-shell-window-private.h b/shell/e-shell-window-private.h index 53a086fba9..aae09b4467 100644 --- a/shell/e-shell-window-private.h +++ b/shell/e-shell-window-private.h @@ -56,7 +56,6 @@ struct _EShellWindowPrivate { GtkUIManager *manager; GtkActionGroup *shell_actions; GtkActionGroup *new_item_actions; - GtkActionGroup *new_group_actions; GtkActionGroup *new_source_actions; GtkActionGroup *shell_view_actions; -- cgit