diff options
author | Peter Harvey <pah06@uow.edu.au> | 2005-10-17 04:29:26 +0800 |
---|---|---|
committer | Christian Persch <chpe@src.gnome.org> | 2005-10-17 04:29:26 +0800 |
commit | d21007362f8d0701d63e50fe6b219de067d95a87 (patch) | |
tree | 46326d5633d4f3c8504049476d0e72ae7ed0ca2c /src/bookmarks/ephy-bookmarks-menu.c | |
parent | 35b9deda1f37ac0cc81d926b5295983de6b55dcf (diff) | |
download | gsoc2013-epiphany-d21007362f8d0701d63e50fe6b219de067d95a87.tar gsoc2013-epiphany-d21007362f8d0701d63e50fe6b219de067d95a87.tar.gz gsoc2013-epiphany-d21007362f8d0701d63e50fe6b219de067d95a87.tar.bz2 gsoc2013-epiphany-d21007362f8d0701d63e50fe6b219de067d95a87.tar.lz gsoc2013-epiphany-d21007362f8d0701d63e50fe6b219de067d95a87.tar.xz gsoc2013-epiphany-d21007362f8d0701d63e50fe6b219de067d95a87.tar.zst gsoc2013-epiphany-d21007362f8d0701d63e50fe6b219de067d95a87.zip |
H18 patch, by Peter Harvey <pah06@uow.edu.au>.
2005-10-16 Peter Harvey <pah06@uow.edu.au>
H18 patch, by Peter Harvey <pah06@uow.edu.au>.
* data/ui/epiphany-bookmark-editor-ui.xml:
* data/ui/epiphany-ui.xml:
* lib/egg/egg-editable-toolbar.c: (get_dock_position),
(get_toolbar_position), (get_toolbar_nth), (find_action),
(drag_data_delete_cb), (drag_begin_cb), (drag_end_cb),
(drag_data_get_cb), (move_item_cb), (set_dock_visible),
(remove_item_cb), (remove_toolbar_cb), (toggle_visibility_cb),
(egg_editable_toolbar_add_visibility_items),
(egg_editable_toolbar_add_popup_items), (popup_context_menu_cb),
(button_press_event_cb), (configure_item_sensitivity),
(configure_item_cursor), (connect_widget_signals),
(action_sensitive_cb), (create_item_from_action),
(create_item_from_position), (toolbar_drag_data_received_cb),
(toolbar_drag_drop_cb), (toolbar_drag_motion_cb),
(toolbar_drag_leave_cb), (configure_drag_dest), (create_dock),
(toolbar_changed_cb), (unparent_fixed), (update_fixed),
(toolbar_added_cb), (toolbar_removed_cb), (item_added_cb),
(item_removed_cb), (egg_editable_toolbar_construct),
(egg_editable_toolbar_set_ui_manager),
(egg_editable_toolbar_set_property),
(egg_editable_toolbar_get_property), (egg_editable_toolbar_init),
(egg_editable_toolbar_finalize),
(egg_editable_toolbar_get_edit_mode),
(egg_editable_toolbar_set_edit_mode),
(egg_editable_toolbar_set_fixed):
* lib/egg/egg-editable-toolbar.h:
* lib/egg/egg-toolbar-editor.c: (compare_items),
(item_added_or_removed_cb), (toolbar_removed_cb),
(egg_toolbar_editor_set_model), (egg_toolbar_editor_finalize),
(drag_begin_cb), (drag_end_cb), (drag_data_get_cb),
(editor_create_item), (editor_create_item_from_name),
(append_table), (update_editor_sheet), (egg_toolbar_editor_init):
* lib/egg/egg-toolbar-editor.h:
* lib/egg/egg-toolbars-model.c: (egg_toolbars_model_to_xml),
(egg_toolbars_model_save), (toolbar_node_new), (item_node_new),
(item_node_free), (toolbar_node_free),
(egg_toolbars_model_get_flags), (egg_toolbars_model_set_flags),
(egg_toolbars_model_get_data), (egg_toolbars_model_get_name),
(impl_add_item), (egg_toolbars_model_add_item),
(egg_toolbars_model_add_toolbar), (parse_data_list),
(parse_item_list), (parse_toolbars), (egg_toolbars_model_load),
(egg_toolbars_model_class_init), (egg_toolbars_model_init),
(egg_toolbars_model_finalize), (egg_toolbars_model_remove_toolbar),
(egg_toolbars_model_remove_item), (egg_toolbars_model_move_item),
(egg_toolbars_model_n_items), (egg_toolbars_model_item_nth),
(egg_toolbars_model_n_toolbars), (egg_toolbars_model_toolbar_nth),
(egg_toolbars_model_get_types), (egg_toolbars_model_set_types),
(fill_avail_array), (egg_toolbars_model_get_avail),
(egg_toolbars_model_get_n_avail), (egg_toolbars_model_set_n_avail):
* lib/egg/egg-toolbars-model.h:
* src/bookmarks/Makefile.am:
* src/bookmarks/ephy-bookmark-action-group.c: (smart_added_cb),
(smart_removed_cb), (node_changed_cb), (node_added_cb),
(node_removed_cb), (ephy_bookmark_group_new):
* src/bookmarks/ephy-bookmark-action-group.h:
* src/bookmarks/ephy-bookmark-action.c: (create_tool_item),
(ephy_bookmark_action_sync_icon), (show_context_menu),
(popup_menu_cb), (button_press_cb), (button_release_cb),
(connect_proxy), (ephy_bookmark_action_updated),
(ephy_bookmark_action_get_bookmark),
(ephy_bookmark_action_set_bookmark),
(ephy_bookmark_action_set_property),
(ephy_bookmark_action_get_property),
(ephy_bookmark_action_finalize), (ephy_bookmark_action_class_init),
(ephy_bookmark_action_init), (ephy_bookmark_action_name),
(ephy_bookmark_action_new):
* src/bookmarks/ephy-bookmark-action.h:
* src/bookmarks/ephy-bookmark-factory-action.c:
(ephy_bookmark_factory_action_get_type), (activate_item_cb),
(build_menu_for_topic), (build_menu), (remove_placeholder_cb),
(activate_placeholder_cb), (clicked_placeholder_cb),
(realize_placeholder_cb), (create_tool_item), (connect_proxy),
(ephy_bookmark_factory_action_class_init),
(ephy_bookmark_factory_action_new):
* src/bookmarks/ephy-bookmark-factory-action.h:
* src/bookmarks/ephy-bookmark-properties.c:
(ephy_bookmark_properties_set_property),
(ephy_bookmark_properties_get_property),
(bookmark_properties_response_cb), (update_entry),
(location_entry_changed_cb), (build_ui):
* src/bookmarks/ephy-bookmarks-editor.c: (add_entry_monitor),
(cmd_add_topic), (delete_topic_dialog_construct),
(cmd_bookmarks_import), (ephy_bookmarks_editor_finalize),
(ephy_bookmarks_editor_node_activated_cb),
(ephy_bookmarks_editor_update_menu), (view_focus_cb),
(add_focus_monitor), (remove_focus_monitor), (bookmarks_filter),
(search_entry_search_cb), (ephy_bookmarks_editor_construct),
(ephy_bookmarks_editor_set_parent),
(ephy_bookmarks_editor_set_property),
(ephy_bookmarks_editor_get_property), (ephy_bookmarks_editor_init):
* src/bookmarks/ephy-bookmarks-menu.c: (append_bookmarks),
(append_menu), (ephy_bookmarks_menu_build):
* src/bookmarks/ephy-bookmarks-menu.h:
* src/bookmarks/ephy-bookmarks-ui.c: (find_action),
(activate_bookmarks_menu), (activate_favorites_menu),
(erase_bookmarks_menu), (erase_favorites_menu), (tree_changed_cb),
(node_added_cb), (node_changed_cb), (node_removed_cb),
(ephy_bookmarks_ui_attach_window),
(ephy_bookmarks_ui_detach_window), (toolbar_node_removed_cb),
(topic_has_data), (topic_get_data), (topic_get_name),
(bookmark_has_data), (bookmark_get_data), (bookmark_get_name),
(bookmark_new_name), (ephy_bookmarks_ui_attach_toolbar_model),
(ephy_bookmarks_ui_detach_toolbar_model):
* src/bookmarks/ephy-bookmarks-ui.h:
* src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_get_type),
(ephy_bookmarks_init_defaults), (ephy_bookmarks_class_init),
(ephy_bookmarks_save_delayed), (add_to_favorites),
(update_bookmark_keywords), (ephy_bookmarks_init),
(ephy_bookmarks_finalize), (ephy_bookmarks_add),
(ephy_bookmarks_set_address), (ephy_bookmarks_set_icon),
(ephy_bookmarks_add_keyword),
(ephy_bookmarks_show_bookmark_properties),
(ephy_bookmarks_get_from_id), (ephy_bookmarks_compare_topics),
(ephy_bookmarks_compare_topic_pointers),
(ephy_bookmarks_compare_bookmarks),
(ephy_bookmarks_compare_bookmark_pointers):
* src/bookmarks/ephy-bookmarks.h:
* src/bookmarks/ephy-bookmarksbar-model.c:
* src/bookmarks/ephy-bookmarksbar-model.h:
* src/bookmarks/ephy-bookmarksbar.c:
* src/bookmarks/ephy-bookmarksbar.h:
* src/bookmarks/ephy-favorites-menu.c:
* src/bookmarks/ephy-favorites-menu.h:
* src/bookmarks/ephy-new-bookmark.c: (ephy_new_bookmark_add),
(build_editing_table), (ephy_new_bookmark_construct),
(ephy_new_bookmark_set_property), (ephy_new_bookmark_get_property):
* src/bookmarks/ephy-nodes-cover.c: (ephy_nodes_count_covered),
(ephy_nodes_remove_covered), (ephy_nodes_remove_not_covered),
(ephy_nodes_get_covered), (ephy_nodes_covered),
(ephy_nodes_get_covering):
* src/bookmarks/ephy-nodes-cover.h:
* src/bookmarks/ephy-open-tabs-action.c: (activate_cb),
(node_added_cb), (node_removed_cb), (ephy_open_tabs_group_new),
(ephy_open_tabs_action_name):
* src/bookmarks/ephy-open-tabs-action.h:
* src/bookmarks/ephy-related-action.c: (node_changed),
(node_destroyed), (open_link), (iface_init),
(ephy_related_action_get_type), (ephy_related_action_new):
* src/bookmarks/ephy-related-action.h:
* src/bookmarks/ephy-topic-action-group.c: (node_changed_cb),
(node_added_cb), (node_removed_cb), (ephy_topic_group_new):
* src/bookmarks/ephy-topic-action-group.h:
* src/bookmarks/ephy-topic-action.c: (ephy_topic_action_get_type),
(create_tool_item), (ephy_topic_action_sync_label), (get_popup),
(erase_popup), (child_added_cb), (child_changed_cb),
(child_removed_cb), (menu_destroy_cb), (menu_init_cb),
(button_deactivate_cb), (button_toggled_cb), (button_release_cb),
(button_press_cb), (connect_proxy), (ephy_topic_action_updated),
(ephy_topic_action_get_topic), (ephy_topic_action_set_topic),
(ephy_topic_action_set_property), (ephy_topic_action_get_property),
(ephy_topic_action_class_init), (ephy_topic_action_init),
(ephy_topic_action_name), (ephy_topic_action_new):
* src/bookmarks/ephy-topic-action.h:
* src/bookmarks/ephy-topic-factory-action.c:
(ephy_topic_factory_action_get_type), (sort_topics),
(activate_item_cb), (build_menu), (remove_placeholder_cb),
(activate_placeholder_cb), (clicked_placeholder_cb),
(realize_placeholder_cb), (create_tool_item), (connect_proxy),
(ephy_topic_factory_action_class_init),
(ephy_topic_factory_action_new):
* src/bookmarks/ephy-topic-factory-action.h:
* src/ephy-link-action.c: (ephy_link_action_group_get_type),
(ephy_link_action_group_new):
* src/ephy-link-action.h:
* src/ephy-lockdown.c: (find_name), (find_action_group),
(update_window):
* src/ephy-notebook.c: (move_tab_to_another_notebook),
(ephy_notebook_switch_page_cb), (ephy_notebook_init),
(tab_label_style_set_cb), (build_tab_label),
(ephy_notebook_add_tab):
* src/ephy-shell.c: (ephy_shell_get_toolbars_model):
* src/ephy-toolbar-editor.c: (ephy_toolbar_editor_constructor),
(ephy_toolbar_editor_finalize), (ephy_toolbar_editor_set_property),
(ephy_toolbar_editor_class_init):
* src/ephy-toolbar.c: (ephy_toolbar_realize),
(ephy_toolbar_unrealize), (ephy_toolbar_finalize):
* src/ephy-toolbars-model.c: (update_flags),
(ephy_toolbars_model_load):
* src/ephy-window.c: (ephy_window_get_type),
(get_chromes_visibility), (sync_chromes_visibility),
(ephy_window_key_press_event), (tool_item_enter_cb),
(tool_item_leave_cb), (tool_item_drag_begin_cb),
(connect_tool_item), (disconnect_tool_item), (disconnect_proxy_cb),
(connect_proxy_cb), (update_chromes_actions), (show_embed_popup),
(tab_added_cb), (tab_removed_cb), (ephy_window_set_chrome),
(ephy_window_dispose), (ephy_window_class_init),
(ephy_window_init), (ephy_window_finalize),
(ephy_window_remove_tab), (ephy_window_set_zoom),
(sync_prefs_with_chrome), (ephy_window_view_toolbar_cb):
* src/ephy-window.h:
Revision history:
h18, released 2005/09/23, for Epiphany 1.8.0
* Just an update for 1.8.0.
h17, released 2005/08/30, for Epiphany 1.7.6 or CVS HEAD
* Mostly just an update for 1.7.6.
* Topic menus on the toolbar now open without releasing the mouse button.
* Topic menus on the toolbar are now also hierarchical (see if you like it.
h16, released 2005/08/25, for Epiphany 1.7.5 or CVS HEAD
* Just an update for 1.7.5. Sorry, I've been busy. :)
h15, released 2005/07/19, for Epiphany 1.7.2 or CVS HEAD
* Code cleanup
h14, released 2005/07/9, for Epiphany 1.7.1 or CVS HEAD
* Improved helpful tip when adding a bookmark
* Improved toolbar context menu
* Toolbar visibility state is now saved
* Separated bookmark/topic action groups into separate files
* Topics in the overflow menu now behave as submenus
* Now importing old bookmarksbar, and saving to new filename
* Incremented toolbar file format version number to 1.1
* Fixed the 'sticky' statusbar help
* Fixed a crashing bug (dnd then open a topic on the toolbar)
h13, released 2005/05/12, for CVS HEAD
* Added middle-mouse drag-drop for the editable toolbar.
* Fixed some warnings at compile and run time.
* Added brief help for the user when adding a new bookmark.
* Cleaned up the editable toolbar code a little.
h12, released 2005/05/10, for CVS HEAD
* Added new editing facilities for the editable toolbar.
h11, released 2005/04/29, for CVS HEAD
* Fixed bug in statusbar information for toolbar items.
* Added an all-new 'Related' toolbar widget which changes to show
the most related topic whenever a bookmark is activated.
h10, released 2005/04/15, for Epiphany 1.6.2 or CVS HEAD
* Added statusbar information for all toolbar items.
* Empty toolbars are now only deleted when exiting edit mode.
* Fixed regression of middle-click for bookmarks on toolbar.
* Fixed regression of ellipsized bookmark names in menus.
h9, released 2005/04/12, for Epiphany 1.6.1
* Updated patch for 1.6.1. Long time no see.
* Now using EphyLink objects everywhere.
h7, released 2004/10/21, for Epiphany 1.4.4
* Updated patch for 1.4.4.
* Fixed bugs causing crashes when bookmarks were added (thanks Reinout).
* Added "Open in Tabs" back into bookmark menus where suitable.
h6, released 2004/09/20, for Epiphany 1.4.0
* Updated patch for 1.4.0.
* Removed the bookmarks bar.
* Generate shared XML string for bookmarks menu.
* Slightly improve performance of node-cover code.
* Delay adding bookmarks menu until it is first used.
* Fixed bug(?) in ephy-node.
h4, released 2004/08/08, for Epiphany 1.3.4
* Updated patch due to changes to topics selector.
* Removed 'Most Visited' from the min-cover calculations.
* Fixed Epiphany 1.3.4 bug where topics in selector aren't sorted.
* Updated patch due to other changes in Epiphany 1.3.4 source.
h3, released 2004/07/12, for Epiphany 1.3.2
* Simple update for Epiphany 1.3.2
h3, released 2004/05/24, for Epiphany 1.2.5
* Moved duplicated functions into a seperate file.
* Improved topic selector.
* Bookmarks toolbar topic menus now have subdivisions.
* Topic names in menu now change if modified in the bookmarks editor.
h2, released 2004/05/23, for Epiphany 1.2.5
* Significantly cleaned up the code.
* 'Most Visited' no longer appears as a submenu.
* Subtopics are selected much more intelligently, giving a better
approximation to a true minimum cover.
* Topic selector now shows suggestions with arrows, not bold font.
h1, released 2004/05/19, for Epiphany 1.2.5
* Initial release.
Diffstat (limited to 'src/bookmarks/ephy-bookmarks-menu.c')
-rw-r--r-- | src/bookmarks/ephy-bookmarks-menu.c | 902 |
1 files changed, 163 insertions, 739 deletions
diff --git a/src/bookmarks/ephy-bookmarks-menu.c b/src/bookmarks/ephy-bookmarks-menu.c index 8c54408bb..bbc223655 100644 --- a/src/bookmarks/ephy-bookmarks-menu.c +++ b/src/bookmarks/ephy-bookmarks-menu.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2003, 2004 Marco Pesenti Gritti * Copyright (C) 2003, 2004 Christian Persch + * Copyright (C) 2004 Peter Harvey * * 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 @@ -22,790 +23,213 @@ #include "config.h" #include "ephy-bookmarks-menu.h" +#include "ephy-bookmarks-ui.h" #include "ephy-bookmark-action.h" +#include "ephy-open-tabs-action.h" +#include "ephy-topic-action.h" +#include "ephy-nodes-cover.h" +#include "ephy-node-common.h" #include "ephy-link.h" #include "ephy-shell.h" -#include "ephy-node-common.h" +#include "ephy-string.h" #include "ephy-gui.h" #include "ephy-debug.h" -#include <glib/gprintf.h> -#include <glib/gi18n.h> -#include <gtk/gtkuimanager.h> -#include <gtk/gtklabel.h> -#include <gtk/gtkmenuitem.h> #include <string.h> -#define EPHY_BOOKMARKS_MENU_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_BOOKMARKS_MENU, EphyBookmarksMenuPrivate)) - -struct _EphyBookmarksMenuPrivate -{ - GtkUIManager *manager; - char *path; - EphyBookmarks *bookmarks; - GtkActionGroup *bmk_actions; - GtkActionGroup *folder_actions; - GSList *removed_bmks; - guint ui_id; - guint update_tag; - gboolean needs_update; -}; - -/* 14 = strlen ("0000000000000000") - strlen ("%x") - * FIXME: for 32bit, 6 is sufficient -> use some #if magic? - */ -#define MAXLEN 14 - -/* this %x is bookmark node id */ -#define BMK_VERB_FORMAT "Bmk%x" -#define BMK_VERB_FORMAT_LENGTH strlen (BMK_VERB_FORMAT) + MAXLEN + 1 - -/* first %x is bookmark node id, second %x is g_str_hash of path */ -#define BMK_NAME_FORMAT "Bmk%x%x" -#define BMK_NAME_FORMAT_LENGTH strlen (BMK_NAME_FORMAT) + 2 * MAXLEN + 1 - -/* first %x is g_str_hash of folder name, 2nd %x is g_str_hash of path */ -#define FOLDER_VERB_FORMAT "Fld%x%x" -#define FOLDER_VERB_FORMAT_LENGTH strlen (FOLDER_VERB_FORMAT) + 2 * MAXLEN + 1 - -#define BMK_ACCEL_PATH_PREFIX "<Actions>/BmkActions/" - -#define GAZILLION 200 -#define UPDATE_DELAY 5000 /* ms */ -#define LABEL_WIDTH_CHARS 32 +#define MIN_MENU_SIZE 7 +#define MAX_MENU_SIZE 21 enum { - PROP_0, - PROP_PATH, - PROP_UI_MANAGER + BUILD_SUBDIVIS = 1 << 0, + BUILD_SUBMENUS = 1 << 1, + BUILD_CHILD_SUBDIVIS = 1 << 2, + BUILD_CHILD_SUBMENUS = 1 << 3 }; -static void ephy_bookmarks_menu_class_init (EphyBookmarksMenuClass *klass); -static void ephy_bookmarks_menu_init (EphyBookmarksMenu *menu); - -static GObjectClass *parent_class = NULL; - -GType -ephy_bookmarks_menu_get_type (void) -{ - static GType type = 0; - - if (G_UNLIKELY (type == 0)) - { - static const GTypeInfo our_info = - { - sizeof (EphyBookmarksMenuClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) ephy_bookmarks_menu_class_init, - NULL, - NULL, /* class_data */ - sizeof (EphyBookmarksMenu), - 0, /* n_preallocs */ - (GInstanceInitFunc) ephy_bookmarks_menu_init - }; - static const GInterfaceInfo link_info = - { - NULL, - NULL, - NULL - }; - - type = g_type_register_static (G_TYPE_OBJECT, - "EphyBookmarksMenu", - &our_info, 0); - g_type_add_interface_static (type, - EPHY_TYPE_LINK, - &link_info); - } - - return type; -} - -static void -connect_proxy_cb (GtkActionGroup *action_group, - GtkAction *action, - GtkWidget *proxy) -{ - if (GTK_IS_MENU_ITEM (proxy)) - { - GtkLabel *label; - - label = (GtkLabel *) ((GtkBin *) proxy)->child; - - gtk_label_set_use_underline (label, FALSE); - gtk_label_set_ellipsize (label, PANGO_ELLIPSIZE_END); - gtk_label_set_max_width_chars (label, LABEL_WIDTH_CHARS); - } -} - -static void -remove_action (gpointer idptr, - GtkActionGroup *action_group) -{ - GtkAction *action; - char verb[BMK_VERB_FORMAT_LENGTH]; - - g_snprintf (verb, sizeof (verb), BMK_VERB_FORMAT, GPOINTER_TO_UINT (idptr)); - action = gtk_action_group_get_action (action_group, verb); - g_return_if_fail (action != NULL); - - gtk_action_group_remove_action (action_group, action); -} - -static void -ephy_bookmarks_menu_clean (EphyBookmarksMenu *menu) -{ - EphyBookmarksMenuPrivate *p = menu->priv; - - START_PROFILER ("Cleaning bookmarks menu") - - if (p->ui_id != 0) - { - gtk_ui_manager_remove_ui (p->manager, p->ui_id); - gtk_ui_manager_ensure_update (p->manager); - p->ui_id = 0; - } - - if (p->bmk_actions != NULL && menu->priv->removed_bmks != NULL) - { - /* now we can remove the actions for removed bookmarks */ - g_slist_foreach (menu->priv->removed_bmks, (GFunc) remove_action, - menu->priv->bmk_actions); - g_slist_free (menu->priv->removed_bmks); - menu->priv->removed_bmks = NULL; - } - - if (p->folder_actions != NULL) - { - gtk_ui_manager_remove_action_group (p->manager, p->folder_actions); - g_object_unref (p->folder_actions); - } - - STOP_PROFILER ("Cleaning bookmarks menu") -} - -static void -add_action_for_bookmark (EphyBookmarksMenu *menu, - EphyNode *bmk) -{ - GtkAction *action; - char verb[BMK_VERB_FORMAT_LENGTH]; - char apath[strlen (BMK_ACCEL_PATH_PREFIX) + BMK_VERB_FORMAT_LENGTH]; - guint id; - - g_return_if_fail (bmk != NULL); - - id = ephy_node_get_id (bmk); - - g_snprintf (verb, sizeof (verb), BMK_VERB_FORMAT, id); - g_snprintf (apath, sizeof (apath), BMK_ACCEL_PATH_PREFIX "%s", verb); - - action = ephy_bookmark_action_new (verb, bmk); - - gtk_action_set_accel_path (action, apath); - - g_signal_connect_swapped (action, "open-link", - G_CALLBACK (ephy_link_open), menu); - - gtk_action_group_add_action (menu->priv->bmk_actions, action); - g_object_unref (action); -} - -static void -ensure_bookmark_actions (EphyBookmarksMenu *menu) -{ - EphyNode *bookmarks, *bmk; - GPtrArray *children; - int i; - - if (menu->priv->bmk_actions != NULL) return; - - START_PROFILER ("Adding bookmarks actions") - - menu->priv->bmk_actions = gtk_action_group_new ("BmkActions"); - gtk_ui_manager_insert_action_group (menu->priv->manager, - menu->priv->bmk_actions, -1); - - g_signal_connect (menu->priv->bmk_actions, "connect-proxy", - G_CALLBACK (connect_proxy_cb), NULL); - - bookmarks = ephy_bookmarks_get_bookmarks (menu->priv->bookmarks); - children = ephy_node_get_children (bookmarks); - for (i = 0; i < children->len; i++) - { - bmk = g_ptr_array_index (children, i); - - add_action_for_bookmark (menu, bmk); - } - - STOP_PROFILER ("Adding bookmarks actions") -} - -static int -sort_topics (gconstpointer a, gconstpointer b) -{ - EphyNode *node_a = (EphyNode *)a; - EphyNode *node_b = (EphyNode *)b; - const char *title1, *title2; - int retval; - - title1 = ephy_node_get_property_string (node_a, EPHY_NODE_KEYWORD_PROP_NAME); - title2 = ephy_node_get_property_string (node_b, EPHY_NODE_KEYWORD_PROP_NAME); - - if (title1 == NULL) - { - retval = -1; - } - else if (title2 == NULL) - { - retval = 1; - } - else - { - char *str_a, *str_b; - - str_a = g_utf8_casefold (title1, -1); - str_b = g_utf8_casefold (title2, -1); - retval = g_utf8_collate (str_a, str_b); - g_free (str_a); - g_free (str_b); - } - - return retval; -} - -static int -sort_bookmarks (gconstpointer a, gconstpointer b) -{ - EphyNode *node_a = (EphyNode *)a; - EphyNode *node_b = (EphyNode *)b; - const char *title1, *title2; - int retval; - - title1 = ephy_node_get_property_string (node_a, EPHY_NODE_BMK_PROP_TITLE); - title2 = ephy_node_get_property_string (node_b, EPHY_NODE_BMK_PROP_TITLE); - - if (title1 == NULL) - { - retval = -1; - } - else if (title2 == NULL) - { - retval = 1; - } - else - { - char *str_a, *str_b; - - str_a = g_utf8_casefold (title1, -1); - str_b = g_utf8_casefold (title2, -1); - retval = g_utf8_collate (str_a, str_b); - g_free (str_a); - g_free (str_b); - } - - return retval; -} - +/* Construct a block of bookmark actions, postfixing the names with a topic id + * to allow different. */ static void -create_menu (EphyBookmarksMenu *menu, - EphyNode *node, - const char *path) +append_bookmarks (GString *string, const GPtrArray *bookmarks, gint instance) { - GPtrArray *children; - EphyBookmarksMenuPrivate *p = menu->priv; - GList *node_list = NULL, *l; - guint phash; - int i; - - phash = g_str_hash (path); - - children = ephy_node_get_children (node); - for (i = 0; i < children->len; ++i) - { - node_list = g_list_prepend (node_list, - g_ptr_array_index (children, i)); - } - - node_list = g_list_sort (node_list, (GCompareFunc)sort_bookmarks); - for (l = node_list; l != NULL; l = l->next) - { - char verb[BMK_VERB_FORMAT_LENGTH]; - char name[BMK_NAME_FORMAT_LENGTH]; - guint id; - - id = ephy_node_get_id ((EphyNode *) l->data); - - g_snprintf (verb, sizeof (verb), BMK_VERB_FORMAT, id); - g_snprintf (name, sizeof (name), BMK_NAME_FORMAT, id, phash); - - gtk_ui_manager_add_ui (p->manager, p->ui_id, path, - name, verb, - GTK_UI_MANAGER_MENUITEM, FALSE); - } - g_list_free (node_list); -} - -#define FOLDER_ACCEL_PATH_PREFIX "<Actions>/FolderActions/" - -static char * -create_submenu (EphyBookmarksMenu *menu, - EphyNode *topic) -{ - EphyBookmarksMenuPrivate *p = menu->priv; - GtkAction *action; - char verb[FOLDER_VERB_FORMAT_LENGTH]; - char apath[strlen (FOLDER_ACCEL_PATH_PREFIX) + FOLDER_VERB_FORMAT_LENGTH]; - const char *title; - char *folder; - char **folders; - GString *path; - guint phash, fhash; - int i; - - title = ephy_node_get_property_string (topic, EPHY_NODE_KEYWORD_PROP_NAME); - g_return_val_if_fail (title != NULL, NULL); - - folders = g_strsplit (title, BOOKMARKS_HIERARCHY_SEP, -1); - - /* occurs if topic name was "" or BOOKMARKS_HIERARCHY_SEP */ - if (folders == NULL || folders[0] == NULL) - { - g_strfreev (folders); - return g_strdup (p->path); - } - - path = g_string_new (p->path); - for (i = 0; folders[i] != NULL; i++) - { - folder = folders[i]; - - /* happens for BOOKMARKS_HIERARCHY_SEP at start/end of title, - * or when occurring twice in succession. - * Treat as if it didn't occur/only occurred once. - */ - if (folders[i][0] == '\0') continue; - - phash = g_str_hash (path->str); - fhash = g_str_hash (folder); - g_snprintf (verb, sizeof (verb), FOLDER_VERB_FORMAT, fhash, phash); + char *name; + long i; - if (gtk_action_group_get_action (p->folder_actions, verb) == NULL) + for (i = 0; i < bookmarks->len; i++) + { + name = ephy_bookmark_action_name (g_ptr_array_index (bookmarks, i)); + if (name) { - g_snprintf (apath, sizeof (apath), - FOLDER_ACCEL_PATH_PREFIX "%s", verb); - - action = g_object_new (GTK_TYPE_ACTION, - "name", verb, - "label", folder, - "hide_if_empty", FALSE, - NULL); - gtk_action_set_accel_path (action, apath); - - gtk_action_group_add_action (p->folder_actions, action); - g_object_unref (action); - - gtk_ui_manager_add_ui (p->manager, p->ui_id, path->str, - verb, verb, - GTK_UI_MANAGER_MENU, FALSE); + g_string_append_printf (string, "<menuitem action=\"%s\" name=\"%s-%d\"/>", + name, name, instance); + g_free (name); } - - g_string_append (path, "/"); - g_string_append (path, verb); } - - g_strfreev (folders); - - return g_string_free (path, FALSE); } +/* Build a menu of the given bookmarks categorised by the given topics. + * Shows categorisation using subdivisions, submenus, or a mix of both. */ static void -ephy_bookmarks_menu_rebuild (EphyBookmarksMenu *menu) +append_menu (GString *string, const GPtrArray *topics, const GPtrArray *bookmarks, guint flags) { - EphyBookmarksMenuPrivate *p = menu->priv; - EphyNode *topics, *not_categorized, *node; - GPtrArray *children; - GList *node_list = NULL, *l; - char *path; - int i; - - if (menu->priv->needs_update == FALSE) - { - LOG ("No update required"); + GPtrArray *uncovered; + guint i; - return; - } - - LOG ("Rebuilding bookmarks menu"); - - ephy_bookmarks_menu_clean (menu); - - START_PROFILER ("Rebuilding bookmarks menu") - - ensure_bookmark_actions (menu); - p->folder_actions = gtk_action_group_new ("FolderActions"); - gtk_ui_manager_insert_action_group (p->manager, p->folder_actions, -1); - - g_signal_connect (p->folder_actions, "connect-proxy", - G_CALLBACK (connect_proxy_cb), NULL); - - p->ui_id = gtk_ui_manager_new_merge_id (p->manager); - - topics = ephy_bookmarks_get_keywords (p->bookmarks); - children = ephy_node_get_children (topics); - - for (i = 0; i < children->len; ++i) - { - EphyNode *kid; - EphyNodePriority priority; - - kid = g_ptr_array_index (children, i); - - priority = ephy_node_get_property_int - (kid, EPHY_NODE_KEYWORD_PROP_PRIORITY); - - if (priority == EPHY_NODE_NORMAL_PRIORITY) + gboolean use_subdivis = flags & BUILD_SUBDIVIS; + gboolean use_submenus = flags & BUILD_SUBMENUS; + + if (use_subdivis || use_submenus) + { + GPtrArray *subset, *covering, *subdivisions, *submenus; + GArray *sizes = 0; + EphyNode *topic; + gint size, total; + gboolean separate = FALSE; + char *name; + + /* Get the subtopics, uncovered bookmarks, and subtopic sizes. */ + sizes = g_array_sized_new (FALSE, FALSE, sizeof(int), topics->len); + uncovered = g_ptr_array_sized_new (bookmarks->len); + covering = ephy_nodes_get_covering (topics, bookmarks, 0, uncovered, sizes); + + /* Preallocate arrays for submenus, subdivisions, and bookmark subsets. */ + subdivisions = g_ptr_array_sized_new (topics->len); + submenus = g_ptr_array_sized_new (topics->len); + subset = g_ptr_array_sized_new (bookmarks->len); + + /* Get the total number of items in the menu. */ + total = uncovered->len; + for (i = 0; i < covering->len; i++) + total += g_array_index (sizes, int, i); + + /* Seperate covering into list of submenus and subdivisions */ + for (i = 0; i < covering->len; i++) { - node_list = g_list_prepend (node_list, kid); + topic = g_ptr_array_index (covering, i); + size = g_array_index (sizes, int, i); + + if (!use_submenus || (use_subdivis && (size < MIN_MENU_SIZE || total < MAX_MENU_SIZE))) + { + g_ptr_array_add (subdivisions, topic); + } + else + { + g_ptr_array_add (submenus, topic); + total = total - size + 1; + } } - } - - node_list = g_list_sort (node_list, (GCompareFunc) sort_topics); - - for (l = node_list; l != NULL; l = l->next) - { - node = (EphyNode *) l->data; - - path = create_submenu (menu, node); - create_menu (menu, node, path); - g_free (path); - } - - not_categorized = ephy_bookmarks_get_not_categorized (p->bookmarks); - - if (ephy_node_get_n_children (not_categorized) > 0) - { - create_menu (menu, not_categorized, p->path); - } - - g_list_free (node_list); - - STOP_PROFILER ("Rebuilding bookmarks menu") - - menu->priv->needs_update = FALSE; -} - -static gboolean -do_update_cb (EphyBookmarksMenu *menu) -{ - LOG ("do_update_cb"); - - ephy_bookmarks_menu_rebuild (menu); - menu->priv->update_tag = 0; - - /* don't run again */ - return FALSE; -} - -static void -ephy_bookmarks_menu_maybe_update (EphyBookmarksMenu *menu) -{ - EphyNode *bookmarks; - GPtrArray *children; - - menu->priv->needs_update = TRUE; - - /* FIXME: is there any way that we get here while the menu is popped up? - * if so, needs to do_update NOW - */ - - /* if there are only a few bookmarks, update soon */ - bookmarks = ephy_bookmarks_get_bookmarks (menu->priv->bookmarks); - children = ephy_node_get_children (bookmarks); - if (children->len < GAZILLION) - { - if (menu->priv->update_tag == 0) + + /* Sort the list of submenus and subdivisions. */ + g_ptr_array_sort (submenus, ephy_bookmarks_compare_topic_pointers); + g_ptr_array_sort (subdivisions, ephy_bookmarks_compare_topic_pointers); + + if (flags & BUILD_CHILD_SUBDIVIS) flags |= BUILD_SUBDIVIS; + if (flags & BUILD_CHILD_SUBMENUS) flags |= BUILD_SUBMENUS; + + /* Create each of the submenus. */ + for (i = 0; i < submenus->len; i++) { - menu->priv->update_tag = - g_timeout_add (UPDATE_DELAY, - (GSourceFunc) do_update_cb, menu); + topic = g_ptr_array_index (submenus, i); + ephy_nodes_get_covered (topic, bookmarks, subset); + + name = ephy_topic_action_name (topic); + if (name) + { + g_string_append_printf (string, "<menu name=\"%s\" action=\"%s\">", + name, name); + append_menu (string, topics, subset, flags); + g_string_append (string, "</menu>"); + separate = TRUE; + g_free (name); + } } - } - else if (menu->priv->update_tag != 0) - { - /* remove scheduled update, update on demand */ - g_source_remove (menu->priv->update_tag); - menu->priv->update_tag = 0; - } -} - -static void -ephy_bookmarks_menu_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - EphyBookmarksMenu *menu = EPHY_BOOKMARKS_MENU (object); - - switch (prop_id) - { - case PROP_PATH: - menu->priv->path = g_value_dup_string (value); - break; - case PROP_UI_MANAGER: - menu->priv->manager = g_value_get_object (value); - break; - } -} - -static void -ephy_bookmarks_menu_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - /* no readable properties */ - g_return_if_reached (); -} - -static void -bookmarks_tree_changed_cb (EphyBookmarks *bookmarks, - EphyBookmarksMenu *menu) -{ - LOG ("bookmarks_tree_changed_cb"); - - ephy_bookmarks_menu_maybe_update (menu); -} - -static void -topics_added_cb (EphyNode *keywords, - EphyNode *bmk, - EphyBookmarksMenu *menu) -{ - LOG ("topics_added_cb"); - - ephy_bookmarks_menu_maybe_update (menu); -} - -static void -topics_removed_cb (EphyNode *keywords, - EphyNode *child, - guint old_index, - EphyBookmarksMenu *menu) -{ - LOG ("topics_removed_cb"); - - ephy_bookmarks_menu_maybe_update (menu); -} - -static void -topic_child_changed_cb (EphyNode *node, - EphyNode *child, - guint property_id, - EphyBookmarksMenu *menu) -{ - LOG ("topic_child_changed_cb id=%d property=%d", - ephy_node_get_id (child), property_id); - - if (property_id == EPHY_NODE_KEYWORD_PROP_NAME) - { - /* the title of the topic has changed, which may change the - * hierarchy. - */ - ephy_bookmarks_menu_maybe_update (menu); - } -} - -static void -bookmark_added_cb (EphyNode *bookmarks, - EphyNode *bmk, - EphyBookmarksMenu *menu) -{ - LOG ("bookmark_added_cb id=%d", ephy_node_get_id (bmk)); - if (menu->priv->bmk_actions != NULL) - { - /* If the new bookmark has the node ID of one scheduled to - * be removed, remove the old one first then add new one. - * This works since the action name depends only on the - * node ID. See bug #154805. - */ - GSList *l; - - l = g_slist_find (menu->priv->removed_bmks, - GUINT_TO_POINTER (ephy_node_get_id (bmk))); - if (l != NULL) + /* Create each of the subdivisions. */ + for (i = 0; i < subdivisions->len; i++) { - remove_action (l->data, menu->priv->bmk_actions); - - menu->priv->removed_bmks = g_slist_delete_link - (menu->priv->removed_bmks, l); + topic = g_ptr_array_index (subdivisions, i); + ephy_nodes_get_covered (topic, bookmarks, subset); + g_ptr_array_sort (subset, ephy_bookmarks_compare_bookmark_pointers); + + if (separate) g_string_append (string, "<separator/>"); + append_bookmarks (string, subset, i+1); + separate = TRUE; } - add_action_for_bookmark (menu, bmk); - - ephy_bookmarks_menu_maybe_update (menu); + g_array_free (sizes, TRUE); + g_ptr_array_free (covering, TRUE); + g_ptr_array_free (subdivisions, TRUE); + g_ptr_array_free (submenus, TRUE); + g_ptr_array_free (subset, TRUE); + + if (separate && uncovered->len) g_string_append (string, "<separator/>"); } -} - -static void -bookmark_removed_cb (EphyNode *bookmarks, - EphyNode *bmk, - guint old_index, - EphyBookmarksMenu *menu) -{ - LOG ("bookmark_removed_cb id=%d", ephy_node_get_id (bmk)); - - if (menu->priv->bmk_actions != NULL) + else { - /* we cannot remove the action here since the menu might still - * reference it. - */ - menu->priv->removed_bmks = - g_slist_prepend (menu->priv->removed_bmks, - GUINT_TO_POINTER (ephy_node_get_id (bmk))); - - ephy_bookmarks_menu_maybe_update (menu); + uncovered = g_ptr_array_sized_new (bookmarks->len); + for (i = 0; i < bookmarks->len; i++) + g_ptr_array_add (uncovered, g_ptr_array_index (bookmarks, i)); + g_ptr_array_sort (uncovered, ephy_bookmarks_compare_bookmark_pointers); } + + /* Create the final subdivision (uncovered bookmarks). */ + g_ptr_array_sort (uncovered, ephy_bookmarks_compare_bookmark_pointers); + append_bookmarks (string, uncovered, 0); + g_ptr_array_free (uncovered, TRUE); } -static void -activate_cb (GtkAction *action, - EphyBookmarksMenu *menu) -{ - LOG ("activate_cb"); - - ephy_bookmarks_menu_rebuild (menu); -} - -static void -ephy_bookmarks_menu_init (EphyBookmarksMenu *menu) -{ - menu->priv = EPHY_BOOKMARKS_MENU_GET_PRIVATE (menu); -} - -static GObject * -ephy_bookmarks_menu_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_params) +void +ephy_bookmarks_menu_build (GString *string, EphyNode *parent) { - EphyBookmarksMenu *menu; - GObject *object; - GtkAction *action; + GPtrArray *children, *topics; + EphyBookmarks *eb; EphyNode *node; + gint priority; + guint flags, id, i; + + eb = ephy_shell_get_bookmarks (ephy_shell); - object = parent_class->constructor (type, n_construct_properties, - construct_params); - - menu = EPHY_BOOKMARKS_MENU (object); - - g_assert (menu->priv->manager != NULL && menu->priv->path != NULL); - - menu->priv->bookmarks = ephy_shell_get_bookmarks (ephy_shell); - g_signal_connect_object (menu->priv->bookmarks, "tree_changed", - G_CALLBACK (bookmarks_tree_changed_cb), - menu, 0); - - node = ephy_bookmarks_get_keywords (menu->priv->bookmarks); - ephy_node_signal_connect_object (node, EPHY_NODE_CHILD_ADDED, - (EphyNodeCallback) topics_added_cb, - G_OBJECT (menu)); - ephy_node_signal_connect_object (node, EPHY_NODE_CHILD_REMOVED, - (EphyNodeCallback) topics_removed_cb, - G_OBJECT (menu)); - ephy_node_signal_connect_object (node, EPHY_NODE_CHILD_CHANGED, - (EphyNodeCallback) topic_child_changed_cb, - G_OBJECT (menu)); - - node = ephy_bookmarks_get_bookmarks (menu->priv->bookmarks); - ephy_node_signal_connect_object (node, EPHY_NODE_CHILD_ADDED, - (EphyNodeCallback) bookmark_added_cb, - G_OBJECT (menu)); - ephy_node_signal_connect_object (node, EPHY_NODE_CHILD_REMOVED, - (EphyNodeCallback) bookmark_removed_cb, - G_OBJECT (menu)); - - action = gtk_ui_manager_get_action (menu->priv->manager, - menu->priv->path); - g_signal_connect_object (action, "activate", - G_CALLBACK (activate_cb), menu, 0); - - ephy_bookmarks_menu_maybe_update (menu); - - return object; -} - -static void -ephy_bookmarks_menu_finalize (GObject *o) -{ - EphyBookmarksMenu *menu = EPHY_BOOKMARKS_MENU (o); - EphyBookmarksMenuPrivate *p = menu->priv; - - if (menu->priv->update_tag != 0) + children = ephy_node_get_children (ephy_bookmarks_get_keywords (eb)); + topics = g_ptr_array_sized_new (children->len); + for (i = 0; i < children->len; i++) { - g_source_remove (menu->priv->update_tag); + node = g_ptr_array_index (children, i); + priority = ephy_node_get_property_int (node, EPHY_NODE_KEYWORD_PROP_PRIORITY); + if (priority == EPHY_NODE_NORMAL_PRIORITY) + g_ptr_array_add (topics, node); } - g_slist_free (menu->priv->removed_bmks); + /* If no parent was supplied, use the default 'All' */ + node = parent ? parent : ephy_bookmarks_get_bookmarks(eb); + children = ephy_node_get_children (node); - if (p->bmk_actions != NULL) - { - g_object_unref (p->bmk_actions); - } + /* Determine what kind of menu we want. */ + id = ephy_node_get_id (node); + switch(id) + { + case FAVORITES_NODE_ID: + flags = 0; + break; + case BOOKMARKS_NODE_ID: + flags = BUILD_SUBMENUS | BUILD_CHILD_SUBDIVIS; + break; + default: + flags = BUILD_SUBMENUS | BUILD_SUBDIVIS | BUILD_CHILD_SUBDIVIS; + /* flags = BUILD_SUBDIVIS; */ + break; + } - if (p->folder_actions != NULL) + /* Build the menu, and return the merge_id */ + append_menu (string, topics, children, flags); + g_ptr_array_free (topics, TRUE); + + /* Add a "Open in tabs" menu item if this menu isn't the 'All' menu. */ + if (id != BOOKMARKS_NODE_ID) { - g_object_unref (p->folder_actions); + char *name = ephy_open_tabs_action_name (node); + g_string_append_printf + (string, "<separator/><menuitem action=\"%s\" name=\"OpenTabs\"/>", name); + g_free (name); } - - g_free (p->path); - - LOG ("EphyBookmarksMenu finalised %p", o);; - - G_OBJECT_CLASS (parent_class)->finalize (o); -} - -static void -ephy_bookmarks_menu_class_init (EphyBookmarksMenuClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - object_class->constructor = ephy_bookmarks_menu_constructor; - object_class->finalize = ephy_bookmarks_menu_finalize; - object_class->set_property = ephy_bookmarks_menu_set_property; - object_class->get_property = ephy_bookmarks_menu_get_property; - - g_object_class_install_property (object_class, - PROP_PATH, - g_param_spec_string ("path", - "Path", - "Merge path", - NULL, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property (object_class, - PROP_UI_MANAGER, - g_param_spec_object ("ui-manager", - "UI Manager", - "UI Manager", - GTK_TYPE_UI_MANAGER, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY)); - - g_type_class_add_private (object_class, sizeof (EphyBookmarksMenuPrivate)); -} - -EphyBookmarksMenu * -ephy_bookmarks_menu_new (GtkUIManager *manager, - const char *path) -{ - return EPHY_BOOKMARKS_MENU (g_object_new (EPHY_TYPE_BOOKMARKS_MENU, - "ui-manager", manager, - "path", path, - NULL)); } |