/* * Copyright (C) 2003 Marco Pesenti Gritti * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "ephy-bookmarks-editor.h" #include "ephy-bookmark-properties.h" #include "ephy-node-common.h" #include "ephy-node-view.h" #include "ephy-window.h" #include "ephy-dnd.h" #include "ephy-prefs.h" #include "ephy-shell.h" #include "eel-gconf-extensions.h" #include "ephy-file-helpers.h" #include "egg-action-group.h" #include "egg-toggle-action.h" #include "egg-menu-merge.h" #include "egg-toggle-action.h" #include "popup-commands.h" #include "ephy-state.h" #include "window-commands.h" #include "ephy-debug.h" #include "ephy-gui.h" #include "ephy-stock-icons.h" static GtkTargetEntry topic_drag_dest_types [] = { { EPHY_DND_BOOKMARK_TYPE, 0, 0 } }; static int n_topic_drag_dest_types = G_N_ELEMENTS (topic_drag_dest_types); static GtkTargetEntry bmk_drag_types [] = { { EPHY_DND_URI_LIST_TYPE, 0, 0 }, { EPHY_DND_TEXT_TYPE, 0, 1 }, { EPHY_DND_URL_TYPE, 0, 2 }, { EPHY_DND_BOOKMARK_TYPE, 0, 3 } }; static int n_bmk_drag_types = G_N_ELEMENTS (bmk_drag_types); static GtkTargetEntry topic_drag_types [] = { { EPHY_DND_TOPIC_TYPE, 0, 0 } }; static int n_topic_drag_types = G_N_ELEMENTS (topic_drag_types); static void ephy_bookmarks_editor_class_init (EphyBookmarksEditorClass *klass); static void ephy_bookmarks_editor_init (EphyBookmarksEditor *editor); static void ephy_bookmarks_editor_finalize (GObject *object); static void ephy_bookmarks_editor_dispose (GObject *object); static void ephy_bookmarks_editor_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void ephy_bookmarks_editor_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void ephy_bookmarks_editor_update_menu (EphyBookmarksEditor *editor); static void search_entry_changed_cb (GtkWidget *entry, EphyBookmarksEditor *editor); static void cmd_open_bookmarks_in_tabs (EggAction *action, EphyBookmarksEditor *editor); static void cmd_open_bookmarks_in_browser (EggAction *action, EphyBookmarksEditor *editor); static void cmd_show_in_bookmarks_bar (EggAction *action, EphyBookmarksEditor *editor); static void cmd_delete (EggAction *action, EphyBookmarksEditor *editor); static void cmd_bookmark_properties (EggAction *action, EphyBookmarksEditor *editor); static void cmd_add_topic (EggAction *action, EphyBookmarksEditor *editor); static void cmd_rename (EggAction *action, EphyBookmarksEditor *editor); static void cmd_close (EggAction *action, EphyBookmarksEditor *editor); static void cmd_cut (EggAction *action, EphyBookmarksEditor *editor); static void cmd_copy (EggAction *action, EphyBookmarksEditor *editor); static void cmd_paste (EggAction *action, EphyBookmarksEditor *editor); static void cmd_select_all (EggAction *action, EphyBookmarksEditor *editor); static void cmd_help_contents (EggAction *action, EphyBookmarksEditor *editor); struct EphyBookmarksEditorPrivate { EphyBookmarks *bookmarks; GtkWidget *bm_view; GtkWidget *key_view; EphyNodeFilter *bookmarks_filter; GtkWidget *search_entry; GtkWidget *menu_dock; GtkWidget *window; EggMenuMerge *ui_merge; EggActionGroup *action_group; int priority_col; EphyToolbarsModel *tb_model; GHashTable *props_dialogs; }; enum { PROP_0, PROP_BOOKMARKS }; static GObjectClass *parent_class = NULL; static EggActionGroupEntry ephy_bookmark_popup_entries [] = { /* Toplevel */ { "File", N_("_File"), NULL, NULL, NULL, NULL, NULL }, { "Edit", N_("_Edit"), NULL, NULL, NULL, NULL, NULL }, { "View", N_("_View"), NULL, NULL, NULL, NULL, NULL }, { "Help", N_("_Help"), NULL, NULL, NULL, NULL, NULL }, { "FakeToplevel", (""), NULL, NULL, NULL, NULL, NULL }, /* File Menu*/ { "NewTopic", N_("_New Topic"), GTK_STOCK_NEW, "N", N_("Create a new topic"), G_CALLBACK (cmd_add_topic), NULL }, { "OpenInWindow", N_("_Open in New Window"), GTK_STOCK_OPEN, "O", N_("Open the selected bookmark in a new window"), G_CALLBACK (cmd_open_bookmarks_in_browser), NULL }, { "OpenInTab", N_("Open in New _Tab"), NULL, "O", N_("Open the selected bookmark in a new tab"), G_CALLBACK (cmd_open_bookmarks_in_tabs), NULL }, { "Rename", N_("_Rename..."), NULL, "F2", N_("Rename the selected bookmark or topic"), G_CALLBACK (cmd_rename), NULL }, { "Delete", N_("_Delete"), GTK_STOCK_DELETE, NULL, N_("Delete the selected bookmark or topic"), G_CALLBACK (cmd_delete), NULL }, { "ShowInBookmarksBar", N_("_Show in Bookmarks Bar"), NULL, NULL, N_("Show the selected bookmark or topic in the bookmarks bar"), G_CALLBACK (cmd_show_in_bookmarks_bar), NULL, TOGGLE_ACTION }, { "Properties", N_("_Properties"), GTK_STOCK_PROPERTIES, "Return", N_("View or modify the properties of the selected bookmark"), G_CALLBACK (cmd_bookmark_properties), NULL }, { "Close", N_("_Close"), GTK_STOCK_CLOSE, "W", N_("Close the bookmarks window"), G_CALLBACK (cmd_close), NULL }, /* Edit Menu */ { "Cut", N_("Cu_t"), GTK_STOCK_CUT, "X", N_("Cut the selection"), G_CALLBACK (cmd_cut), NULL }, { "Copy", N_("_Copy"), GTK_STOCK_COPY, "C", N_("Copy the selection"), G_CALLBACK (cmd_copy), NULL }, { "Paste", N_("_Paste"), GTK_STOCK_PASTE, "V", N_("Paste the clipboard"), G_CALLBACK (cmd_paste), NULL }, { "SelectAll", N_("Select _All"), NULL, "A", N_("Select all bookmarks or text"), G_CALLBACK (cmd_select_all), NULL }, /* View Menu */ { "ViewTitle", N_("_Title"), NULL, NULL, N_("Show only the title column"), NULL, NULL, RADIO_ACTION, NULL }, { "ViewLocation", N_("_Address"), NULL, NULL, N_("Show only the address column"), NULL, NULL, RADIO_ACTION, "ViewTitle" }, { "ViewTitleLocation", N_("T_itle and Address"), NULL, NULL, N_("Show both the title and address columns"), NULL, NULL, RADIO_ACTION, "ViewTitle" }, /* Help Menu */ { "HelpContents", N_("_Contents"), GTK_STOCK_HELP, "F1", N_("Display bookmarks help"), G_CALLBACK (cmd_help_contents), NULL }, { "HelpAbout", N_("_About"), GNOME_STOCK_ABOUT, NULL, N_("Display credits for the web browser creators"), G_CALLBACK (window_cmd_help_about), NULL }, }; static guint ephy_bookmark_popup_n_entries = G_N_ELEMENTS (ephy_bookmark_popup_entries); static void entry_selection_changed_cb (GtkWidget *widget, GParamSpec *pspec, EphyBookmarksEditor *editor) { ephy_bookmarks_editor_update_menu (editor); } static void add_entry_monitor (EphyBookmarksEditor *editor, GtkWidget *entry) { g_signal_connect (G_OBJECT (entry), "notify::selection-bound", G_CALLBACK (entry_selection_changed_cb), editor); g_signal_connect (G_OBJECT (entry), "notify::cursor-position", G_CALLBACK (entry_selection_changed_cb), editor); } static void add_text_renderer_monitor (EphyBookmarksEditor *editor) { GtkWidget *entry; entry = gtk_window_get_focus (GTK_WINDOW (editor)); g_return_if_fail (GTK_IS_EDITABLE (entry)); add_entry_monitor (editor, entry); } static void cmd_add_topic (EggAction *action, EphyBookmarksEditor *editor) { EphyNode *node; node = ephy_bookmarks_add_keyword (editor->priv->bookmarks, _("Type a topic")); ephy_node_view_select_node (EPHY_NODE_VIEW (editor->priv->key_view), node); ephy_node_view_edit (EPHY_NODE_VIEW (editor->priv->key_view)); add_text_renderer_monitor (editor); } static void cmd_close (EggAction *action, EphyBookmarksEditor *editor) { gtk_widget_hide (GTK_WIDGET (editor)); } static void cmd_rename (EggAction *action, EphyBookmarksEditor *editor) { if (ephy_node_view_is_target (EPHY_NODE_VIEW (editor->priv->bm_view))) { ephy_node_view_edit (EPHY_NODE_VIEW (editor->priv->bm_view)); } else if (ephy_node_view_is_target (EPHY_NODE_VIEW (editor->priv->key_view))) { ephy_node_view_edit (EPHY_NODE_VIEW (editor->priv->key_view)); } add_text_renderer_monitor (editor); } static GtkWidget * get_target_window (EphyBookmarksEditor *editor) { if (editor->priv->window) { return editor->priv->window; } else { return GTK_WIDGET (ephy_shell_get_active_window (ephy_shell)); } } static void cmd_show_in_bookmarks_bar (EggAction *action, EphyBookmarksEditor *editor) { EphyNode *node; GList *selection; gboolean state, topic; gulong id; if (ephy_node_view_is_target (EPHY_NODE_VIEW (editor->priv->bm_view))) { selection = ephy_node_view_get_selection (EPHY_NODE_VIEW (editor->priv->bm_view)); topic = FALSE; } else if (ephy_node_view_is_target (EPHY_NODE_VIEW (editor->priv->key_view))) { selection = ephy_node_view_get_selection (EPHY_NODE_VIEW (editor->priv->key_view)); topic = TRUE; } else { return; } node = selection->data; id = ephy_node_get_id (node); state = EGG_TOGGLE_ACTION (action)->active; if (state) { ephy_toolbars_model_add_bookmark (editor->priv->tb_model, topic, id); } else { ephy_toolbars_model_remove_bookmark (editor->priv->tb_model, topic, id); } g_list_free (selection); } static void cmd_open_bookmarks_in_tabs (EggAction *action, EphyBookmarksEditor *editor) { EphyWindow *window; GList *selection; GList *l; window = EPHY_WINDOW (get_target_window (editor)); selection = ephy_node_view_get_selection (EPHY_NODE_VIEW (editor->priv->bm_view)); for (l = selection; l; l = l->next) { EphyNode *node = l->data; const char *location; location = ephy_node_get_property_string (node, EPHY_NODE_BMK_PROP_LOCATION); ephy_shell_new_tab (ephy_shell, window, NULL, location, EPHY_NEW_TAB_OPEN_PAGE | EPHY_NEW_TAB_IN_EXISTING_WINDOW); } g_list_free (selection); } static void cmd_open_bookmarks_in_browser (EggAction *action, EphyBookmarksEditor *editor) { EphyWindow *window; GList *selection; GList *l; window = EPHY_WINDOW (get_target_window (editor)); selection = ephy_node_view_get_selection (EPHY_NODE_VIEW (editor->priv->bm_view)); for (l = selection; l; l = l->next) { EphyNode *node = l->data; const char *location; location = ephy_node_get_property_string (node, EPHY_NODE_BMK_PROP_LOCATION); ephy_shell_new_tab (ephy_shell, window, NULL, location, EPHY_NEW_TAB_IN_NEW_WINDOW); } g_list_free (selection); } static void cmd_delete (EggAction *action, EphyBookmarksEditor *editor) { if (ephy_node_view_is_target (EPHY_NODE_VIEW (editor->priv->bm_view))) { ephy_node_view_remove (EPHY_NODE_VIEW (editor->priv->bm_view)); } else if (ephy_node_view_is_target (EPHY_NODE_VIEW (editor->priv->key_view))) { EphyNodePriority priority; GList *selected; EphyNode *node; selected = ephy_node_view_get_selection (EPHY_NODE_VIEW (editor->priv->key_view)); node = selected->data; priority = ephy_node_get_property_int (node, EPHY_NODE_KEYWORD_PROP_PRIORITY); if (priority == -1) priority = EPHY_NODE_NORMAL_PRIORITY; if (priority == EPHY_NODE_NORMAL_PRIORITY) { ephy_node_view_remove (EPHY_NODE_VIEW (editor->priv->key_view)); } g_list_free (selected); } } static void prop_dialog_destroy_cb (GtkWidget *dialog, EphyBookmarksEditor *editor) { EphyNode *node; node = ephy_bookmark_properties_get_node (EPHY_BOOKMARK_PROPERTIES (dialog)); g_hash_table_remove (editor->priv->props_dialogs, node); } static void show_properties_dialog (EphyBookmarksEditor *editor, EphyNode *node) { GtkWidget *dialog; dialog = g_hash_table_lookup (editor->priv->props_dialogs, node); if (!dialog) { dialog = ephy_bookmark_properties_new (editor->priv->bookmarks, node, GTK_WINDOW (editor)); g_signal_connect (dialog, "destroy", G_CALLBACK (prop_dialog_destroy_cb), editor); g_hash_table_insert (editor->priv->props_dialogs, node, dialog); } gtk_window_present (GTK_WINDOW (dialog)); } static void cmd_bookmark_properties (EggAction *action, EphyBookmarksEditor *editor) { GList *selection; GList *l; selection = ephy_node_view_get_selection (EPHY_NODE_VIEW (editor->priv->bm_view)); for (l = selection; l; l = l->next) { EphyNode *node = l->data; show_properties_dialog (editor, node); } g_list_free (selection); } static void cmd_cut (EggAction *action, EphyBookmarksEditor *editor) { GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (editor)); if (GTK_IS_EDITABLE (widget)) { gtk_editable_cut_clipboard (GTK_EDITABLE (widget)); } } static void cmd_copy (EggAction *action, EphyBookmarksEditor *editor) { GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (editor)); if (GTK_IS_EDITABLE (widget)) { gtk_editable_copy_clipboard (GTK_EDITABLE (widget)); } else if (ephy_node_view_is_target (EPHY_NODE_VIEW (editor->priv->bm_view))) { GList *selection; selection = ephy_node_view_get_selection (EPHY_NODE_VIEW (editor->priv->bm_view)); if (g_list_length (selection) == 1) { const char *tmp; EphyNode *node = selection->data; tmp = ephy_node_get_property_string (node, EPHY_NODE_BMK_PROP_LOCATION); gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), tmp, -1); } g_list_free (selection); } } static void cmd_paste (EggAction *action, EphyBookmarksEditor *editor) { GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (editor)); if (GTK_IS_EDITABLE (widget)) { gtk_editable_paste_clipboard (GTK_EDITABLE (widget)); } } static void cmd_select_all (EggAction *action, EphyBookmarksEditor *editor) { GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (editor)); GtkWidget *bm_view = editor->priv->bm_view; if (GTK_IS_EDITABLE (widget)) { gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1); } else if (ephy_node_view_is_target (EPHY_NODE_VIEW (bm_view))) { GtkTreeSelection *sel; sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (bm_view)); gtk_tree_selection_select_all (sel); } } static void cmd_help_contents (EggAction *action, EphyBookmarksEditor *editor) { ephy_gui_help (GTK_WINDOW (editor), "epiphany", "ephy-managing-bookmarks"); } GType ephy_bookmarks_editor_get_type (void) { static GType ephy_bookmarks_editor_type = 0; if (ephy_bookmarks_editor_type == 0) { static const GTypeInfo our_info = { sizeof (EphyBookmarksEditorClass), NULL, NULL, (GClassInitFunc) ephy_bookmarks_editor_class_init, NULL, NULL, sizeof (EphyBookmarksEditor), 0, (GInstanceInitFunc) ephy_bookmarks_editor_init }; ephy_bookmarks_editor_type = g_type_register_static (GTK_TYPE_WINDOW, "EphyBookmarksEditor", &our_info, 0); } return ephy_bookmarks_editor_type; } static void ephy_bookmarks_editor_class_init (EphyBookmarksEditorClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); object_class->finalize = ephy_bookmarks_editor_finalize; object_class->dispose = ephy_bookmarks_editor_dispose; object_class->set_property = ephy_bookmarks_editor_set_property; object_class->get_property = ephy_bookmarks_editor_get_property; g_object_class_install_property (object_class, PROP_BOOKMARKS, g_param_spec_object ("bookmarks", "Bookmarks set", "Bookmarks set", EPHY_BOOKMARKS_TYPE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); } static void ephy_bookmarks_editor_finalize (GObject *object) { EphyBookmarksEditor *editor; g_return_if_fail (object != NULL); g_return_if_fail (EPHY_IS_BOOKMARKS_EDITOR (object)); editor = EPHY_BOOKMARKS_EDITOR (object); g_return_if_fail (editor->priv != NULL); g_object_unref (G_OBJECT (editor->priv->bookmarks_filter)); g_object_unref (editor->priv->action_group); egg_menu_merge_remove_action_group (editor->priv->ui_merge, editor->priv->action_group); g_object_unref (editor->priv->ui_merge); if (editor->priv->window) { g_object_remove_weak_pointer (G_OBJECT(editor->priv->window), (gpointer *)&editor->priv->window); } g_hash_table_destroy (editor->priv->props_dialogs); g_free (editor->priv); G_OBJECT_CLASS (parent_class)->finalize (object); } static void ephy_bookmarks_editor_node_activated_cb (GtkWidget *view, EphyNode *node, EphyBookmarksEditor *editor) { const char *location; EphyWindow *window; location = ephy_node_get_property_string (node, EPHY_NODE_BMK_PROP_LOCATION); g_return_if_fail (location != NULL); window = EPHY_WINDOW (get_target_window (editor)); if (window != NULL) { ephy_window_load_url (EPHY_WINDOW (window), location); gtk_window_present (GTK_WINDOW (window)); } else { /* We have to create a browser window */ ephy_shell_new_tab (ephy_shell, NULL, NULL, location, EPHY_NEW_TAB_OPEN_PAGE | EPHY_NEW_TAB_IN_NEW_WINDOW); } } static void ephy_bookmarks_editor_update_menu (EphyBookmarksEditor *editor) { gboolean open_in_window, open_in_tab, rename, delete, properties; const gchar *open_in_window_label, *open_in_tab_label, *copy_label; gboolean bmk_focus, key_focus; gboolean key_selection, bmk_selection; gboolean key_normal = FALSE; gboolean bmk_multiple_selection; gboolean cut, copy, paste, select_all; gboolean can_show_in_bookmarks_bar, show_in_bookmarks_bar = FALSE; EggActionGroup *action_group; EggAction *action; GList *selected; GtkWidget *focus_widget; LOG ("Update menu sensitivity") bmk_focus = ephy_node_view_is_target (EPHY_NODE_VIEW (editor->priv->bm_view)); key_focus = ephy_node_view_is_target (EPHY_NODE_VIEW (editor->priv->key_view)); focus_widget = gtk_window_get_focus (GTK_WINDOW (editor)); bmk_selection = ephy_node_view_has_selection (EPHY_NODE_VIEW (editor->priv->bm_view), &bmk_multiple_selection); key_selection = ephy_node_view_has_selection (EPHY_NODE_VIEW (editor->priv->key_view), NULL); if (GTK_IS_EDITABLE (focus_widget)) { gboolean has_selection; gboolean clipboard_contains_text; has_selection = gtk_editable_get_selection_bounds (GTK_EDITABLE (focus_widget), NULL, NULL); clipboard_contains_text = gtk_clipboard_wait_is_text_available (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)); cut = has_selection; copy = has_selection; paste = clipboard_contains_text; select_all = TRUE; } else { cut = FALSE; copy = (bmk_focus && !bmk_multiple_selection && bmk_selection); paste = FALSE; select_all = bmk_focus; } selected = ephy_node_view_get_selection (EPHY_NODE_VIEW (editor->priv->key_view)); if (key_focus && selected) { EphyNode *node = selected->data; EphyNodePriority priority; gulong id; id = ephy_node_get_id (node); show_in_bookmarks_bar = ephy_toolbars_model_has_bookmark (editor->priv->tb_model, TRUE, id); priority = ephy_node_get_property_int (node, EPHY_NODE_KEYWORD_PROP_PRIORITY); if (priority == -1) priority = EPHY_NODE_NORMAL_PRIORITY; key_normal = (priority == EPHY_NODE_NORMAL_PRIORITY); g_list_free (selected); } selected = ephy_node_view_get_selection (EPHY_NODE_VIEW (editor->priv->bm_view)); if (bmk_focus && selected) { EphyNode *node = selected->data; gulong id; id = ephy_node_get_id (node); show_in_bookmarks_bar = ephy_toolbars_model_has_bookmark (editor->priv->tb_model, FALSE, id); g_list_free (selected); } if (bmk_multiple_selection) { open_in_window_label = N_("_Open in New Windows"); open_in_tab_label = N_("Open in New _Tabs"); } else { open_in_window_label = _("_Open in New Window"); open_in_tab_label = _("Open in New _Tab"); } if (bmk_focus) { copy_label = _("_Copy Address"); } else { copy_label = _("_Copy"); } open_in_window = (bmk_focus && bmk_selection); open_in_tab = (bmk_focus && bmk_selection); rename = (bmk_focus && bmk_selection && !bmk_multiple_selection) || (key_selection && key_focus && key_normal); delete = (bmk_focus && bmk_selection) || (key_selection && key_focus && key_normal); properties = (bmk_focus && bmk_selection && !bmk_multiple_selection); can_show_in_bookmarks_bar = (bmk_focus && bmk_selection && !bmk_multiple_selection) || (key_selection && key_focus); action_group = editor->priv->action_group; action = egg_action_group_get_action (action_group, "OpenInWindow"); g_object_set (action, "sensitive", open_in_window, NULL); g_object_set (action, "label", open_in_window_label, NULL); action = egg_action_group_get_action (action_group, "OpenInTab"); g_object_set (action, "sensitive", open_in_tab, NULL); g_object_set (action, "label", open_in_tab_label, NULL); action = egg_action_group_get_action (action_group, "Rename"); g_object_set (action, "sensitive", rename, NULL); action = egg_action_group_get_action (action_group, "Delete"); g_object_set (action, "sensitive", delete, NULL); action = egg_action_group_get_action (action_group, "Properties"); g_object_set (action, "sensitive", properties, NULL); action = egg_action_group_get_action (action_group, "Cut"); g_object_set (action, "sensitive", cut, NULL); action = egg_action_group_get_action (action_group, "Copy"); g_object_set (action, "sensitive", copy, NULL); g_object_set (action, "label", copy_label, NULL); action = egg_action_group_get_action (action_group, "Paste"); g_object_set (action, "sensitive", paste, NULL); action = egg_action_group_get_action (action_group, "SelectAll"); g_object_set (action, "sensitive", select_all, NULL); action = egg_action_group_get_action (action_group, "ShowInBookmarksBar"); g_object_set (action, "sensitive", can_show_in_bookmarks_bar, NULL); g_signal_handlers_block_by_func (G_OBJECT (EGG_TOGGLE_ACTION (action)), G_CALLBACK (cmd_show_in_bookmarks_bar), editor); egg_toggle_action_set_active (EGG_TOGGLE_ACTION (action), show_in_bookmarks_bar); g_signal_handlers_unblock_by_func (G_OBJECT (EGG_TOGGLE_ACTION (action)), G_CALLBACK (cmd_show_in_bookmarks_bar), editor); } static gboolean view_focus_cb (EphyNodeView *view, GdkEventFocus *event, EphyBookmarksEditor *editor) { ephy_bookmarks_editor_update_menu (editor); return FALSE; } static void add_focus_monitor (EphyBookmarksEditor *editor, GtkWidget *widget) { g_signal_connect (G_OBJECT (widget), "focus_in_event", G_CALLBACK (view_focus_cb), editor); g_signal_connect (G_OBJECT (widget), "focus_out_event", G_CALLBACK (view_focus_cb), editor); } static void remove_focus_monitor (EphyBookmarksEditor *editor, GtkWidget *widget) { g_signal_handlers_disconnect_by_func (G_OBJECT (widget), G_CALLBACK (view_focus_cb), editor); } static void ephy_bookmarks_editor_show_popup_cb (GtkWidget *view, EphyBookmarksEditor *editor) { GtkWidget *widget; widget = egg_menu_merge_get_widget (editor->priv->ui_merge, "/popups/EphyBookmarkEditorPopup"); gtk_menu_popup (GTK_MENU (widget), NULL, NULL, NULL, NULL, 2, gtk_get_current_event_time ()); } static void ephy_bookmarks_editor_dispose (GObject *object) { EphyBookmarksEditor *editor; long selected_id; char *selected_id_str; GList *selection; g_return_if_fail (object != NULL); g_return_if_fail (EPHY_IS_BOOKMARKS_EDITOR (object)); editor = EPHY_BOOKMARKS_EDITOR (object); g_return_if_fail (editor->priv != NULL); if (editor->priv->key_view != NULL) { remove_focus_monitor (editor, editor->priv->key_view); remove_focus_monitor (editor, editor->priv->bm_view); remove_focus_monitor (editor, editor->priv->search_entry); selection = ephy_node_view_get_selection (EPHY_NODE_VIEW (editor->priv->key_view)); if (selection == NULL || selection->data == NULL) { editor->priv->key_view = NULL; G_OBJECT_CLASS (parent_class)->dispose (object); return; } selected_id = ephy_node_get_id (selection->data); if (selected_id >= 0) { selected_id_str = g_strdup_printf ("%ld", selected_id); eel_gconf_set_string (CONF_BOOKMARKS_SELECTED_NODE, selected_id_str); g_free (selected_id_str); } g_list_free (selection); editor->priv->key_view = NULL; } G_OBJECT_CLASS (parent_class)->dispose (object); } static void bookmarks_filter (EphyBookmarksEditor *editor, EphyNode *keyword) { ephy_node_filter_empty (editor->priv->bookmarks_filter); ephy_node_filter_add_expression (editor->priv->bookmarks_filter, ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_HAS_PARENT, keyword), 0); ephy_node_filter_done_changing (editor->priv->bookmarks_filter); } static gboolean key_pressed_cb (EphyNodeView *view, GdkEventKey *event, EphyBookmarksEditor *editor) { switch (event->keyval) { case GDK_Delete: case GDK_KP_Delete: cmd_delete (NULL, editor); return TRUE; default: break; } return FALSE; } static void reset_search_entry (EphyBookmarksEditor *editor) { g_signal_handlers_block_by_func (G_OBJECT (editor->priv->search_entry), G_CALLBACK (search_entry_changed_cb), editor); gtk_entry_set_text (GTK_ENTRY (editor->priv->search_entry), ""); g_signal_handlers_unblock_by_func (G_OBJECT (editor->priv->search_entry), G_CALLBACK (search_entry_changed_cb), editor); } static void keyword_node_selected_cb (EphyNodeView *view, EphyNode *node, EphyBookmarksEditor *editor) { EphyNode *bookmarks; if (node == NULL) { bookmarks = ephy_bookmarks_get_bookmarks (editor->priv->bookmarks); ephy_node_view_select_node (EPHY_NODE_VIEW (editor->priv->key_view), bookmarks); } else { reset_search_entry (editor); bookmarks_filter (editor, node); } } static void keyword_node_show_popup_cb (GtkWidget *view, EphyBookmarksEditor *editor) { GtkWidget *widget; widget = egg_menu_merge_get_widget (editor->priv->ui_merge, "/popups/EphyBookmarkKeywordPopup"); gtk_menu_popup (GTK_MENU (widget), NULL, NULL, NULL, NULL, 2, gtk_get_current_event_time ()); } static void search_entry_changed_cb (GtkWidget *entry, EphyBookmarksEditor *editor) { EphyNode *all; char *search_text; g_signal_handlers_block_by_func (G_OBJECT (editor->priv->key_view), G_CALLBACK (keyword_node_selected_cb), editor); all = ephy_bookmarks_get_bookmarks (editor->priv->bookmarks); ephy_node_view_select_node (EPHY_NODE_VIEW (editor->priv->key_view), all); g_signal_handlers_unblock_by_func (G_OBJECT (editor->priv->key_view), G_CALLBACK (keyword_node_selected_cb), editor); search_text = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); GDK_THREADS_ENTER (); ephy_node_filter_empty (editor->priv->bookmarks_filter); ephy_node_filter_add_expression (editor->priv->bookmarks_filter, ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS, EPHY_NODE_BMK_PROP_TITLE, search_text), 0); ephy_node_filter_add_expression (editor->priv->bookmarks_filter, ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS, EPHY_NODE_BMK_PROP_KEYWORDS, search_text), 0); ephy_node_filter_done_changing (editor->priv->bookmarks_filter); GDK_THREADS_LEAVE (); g_free (search_text); } static GtkWidget * build_search_box (EphyBookmarksEditor *editor) { GtkWidget *box; GtkWidget *label; GtkWidget *entry; char *str; box = gtk_hbox_new (FALSE, 6); gtk_container_set_border_width (GTK_CONTAINER (box), 6); gtk_widget_show (box); entry = gtk_entry_new (); editor->priv->search_entry = entry; gtk_widget_show (entry); g_signal_connect (G_OBJECT (entry), "changed", G_CALLBACK (search_entry_changed_cb), editor); add_entry_monitor (editor, entry); add_focus_monitor (editor, entry); label = gtk_label_new (NULL); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); str = g_strconcat ("", _("_Search:"), "", NULL); gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), str); g_free (str); gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (box), label, FALSE, TRUE, 0); gtk_box_pack_start (GTK_BOX (box), entry, TRUE, TRUE, 0); return box; } static void add_widget (EggMenuMerge *merge, GtkWidget *widget, EphyBookmarksEditor *editor) { gtk_box_pack_start (GTK_BOX (editor->priv->menu_dock), widget, FALSE, FALSE, 0); gtk_widget_show (widget); } static gboolean delete_event_cb (EphyBookmarksEditor *editor) { gtk_widget_hide (GTK_WIDGET (editor)); return TRUE; } static void node_dropped_cb (EphyNodeView *view, EphyNode *node, GList *nodes, EphyBookmarksEditor *editor) { GList *l; for (l = nodes; l != NULL; l = l->next) { EphyNode *bmk = l->data; ephy_bookmarks_set_keyword (editor->priv->bookmarks, node, bmk); } } static void provide_favicon (EphyNode *node, GValue *value, gpointer user_data) { EphyFaviconCache *cache; const char *icon_location; GdkPixbuf *pixbuf = NULL; cache = ephy_embed_shell_get_favicon_cache (EPHY_EMBED_SHELL (ephy_shell)); icon_location = ephy_node_get_property_string (node, EPHY_NODE_BMK_PROP_ICON); LOG ("Get favicon for %s", icon_location ? icon_location : "None") if (icon_location) { pixbuf = ephy_favicon_cache_get (cache, icon_location); } g_value_init (value, GDK_TYPE_PIXBUF); g_value_set_object (value, pixbuf); } static void view_selection_changed_cb (GtkWidget *view, EphyBookmarksEditor *editor) { ephy_bookmarks_editor_update_menu (editor); } static void ephy_bookmarks_editor_construct (EphyBookmarksEditor *editor) { GtkTreeSelection *selection; GtkWidget *hpaned, *vbox; GtkWidget *bm_view, *key_view; GtkWidget *scrolled_window; EphyNode *node; long selected_id; EphyNode *selected_node; char *selected_id_str; EggMenuMerge *ui_merge; EggActionGroup *action_group; EggAction *action; GdkPixbuf *icon; int i; gtk_window_set_title (GTK_WINDOW (editor), _("Bookmarks")); icon = gtk_widget_render_icon (GTK_WIDGET (editor), EPHY_STOCK_BOOKMARKS, GTK_ICON_SIZE_MENU, NULL); gtk_window_set_icon (GTK_WINDOW(editor), icon); g_signal_connect (editor, "delete_event", G_CALLBACK (delete_event_cb), NULL); for (i = 0; i < ephy_bookmark_popup_n_entries; i++) { ephy_bookmark_popup_entries[i].user_data = editor; } editor->priv->menu_dock = gtk_vbox_new (FALSE, 0); gtk_widget_show (editor->priv->menu_dock); gtk_container_add (GTK_CONTAINER (editor), editor->priv->menu_dock); ui_merge = egg_menu_merge_new (); g_signal_connect (ui_merge, "add_widget", G_CALLBACK (add_widget), editor); action_group = egg_action_group_new ("PopupActions"); egg_action_group_add_actions (action_group, ephy_bookmark_popup_entries, ephy_bookmark_popup_n_entries); egg_menu_merge_insert_action_group (ui_merge, action_group, 0); egg_menu_merge_add_ui_from_file (ui_merge, ephy_file ("epiphany-bookmark-editor-ui.xml"), NULL); gtk_window_add_accel_group (GTK_WINDOW (editor), ui_merge->accel_group); egg_menu_merge_ensure_update (ui_merge); editor->priv->ui_merge = ui_merge; editor->priv->action_group = action_group; /* Fixme: We should implement gconf prefs for monitoring this setting */ action = egg_action_group_get_action (action_group, "ViewTitle"); egg_toggle_action_set_active (EGG_TOGGLE_ACTION (action), TRUE); hpaned = gtk_hpaned_new (); gtk_container_set_border_width (GTK_CONTAINER (hpaned), 0); gtk_container_add (GTK_CONTAINER (editor->priv->menu_dock), hpaned); gtk_widget_show (hpaned); g_assert (editor->priv->bookmarks); node = ephy_bookmarks_get_keywords (editor->priv->bookmarks); scrolled_window = g_object_new (GTK_TYPE_SCROLLED_WINDOW, "hadjustment", NULL, "vadjustment", NULL, "hscrollbar_policy", GTK_POLICY_AUTOMATIC, "vscrollbar_policy", GTK_POLICY_AUTOMATIC, "shadow_type", GTK_SHADOW_IN, NULL); gtk_paned_pack1 (GTK_PANED (hpaned), GTK_WIDGET (scrolled_window), TRUE, TRUE); gtk_widget_show (scrolled_window); /* Keywords View */ key_view = ephy_node_view_new (node, NULL); add_focus_monitor (editor, key_view); ephy_node_view_enable_drag_source (EPHY_NODE_VIEW (key_view), topic_drag_types, n_topic_drag_types, -1); ephy_node_view_enable_drag_dest (EPHY_NODE_VIEW (key_view), topic_drag_dest_types, n_topic_drag_dest_types); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (key_view)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (view_selection_changed_cb), editor); ephy_node_view_add_column (EPHY_NODE_VIEW (key_view), _("Topics"), G_TYPE_STRING, EPHY_NODE_KEYWORD_PROP_NAME, EPHY_NODE_KEYWORD_PROP_PRIORITY, EPHY_NODE_VIEW_AUTO_SORT | EPHY_NODE_VIEW_EDITABLE, NULL); gtk_container_add (GTK_CONTAINER (scrolled_window), key_view); gtk_widget_set_size_request (key_view, 130, -1); gtk_widget_show (key_view); editor->priv->key_view = key_view; g_signal_connect (G_OBJECT (key_view), "key_press_event", G_CALLBACK (key_pressed_cb), editor); g_signal_connect (G_OBJECT (key_view), "node_selected", G_CALLBACK (keyword_node_selected_cb), editor); g_signal_connect (G_OBJECT (key_view), "node_dropped", G_CALLBACK (node_dropped_cb), editor); g_signal_connect (G_OBJECT (key_view), "show_popup", G_CALLBACK (keyword_node_show_popup_cb), editor); vbox = gtk_vbox_new (FALSE, 0); gtk_paned_pack2 (GTK_PANED (hpaned), vbox, TRUE, TRUE); gtk_widget_show (vbox); gtk_box_pack_start (GTK_BOX (vbox), build_search_box (editor), FALSE, FALSE, 0); add_focus_monitor (editor, editor->priv->search_entry); scrolled_window = g_object_new (GTK_TYPE_SCROLLED_WINDOW, "hadjustment", NULL, "vadjustment", NULL, "hscrollbar_policy", GTK_POLICY_AUTOMATIC, "vscrollbar_policy", GTK_POLICY_AUTOMATIC, "shadow_type", GTK_SHADOW_IN, NULL); gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0); gtk_widget_show (scrolled_window); node = ephy_bookmarks_get_bookmarks (editor->priv->bookmarks); editor->priv->bookmarks_filter = ephy_node_filter_new (); /* Bookmarks View */ bm_view = ephy_node_view_new (node, editor->priv->bookmarks_filter); add_focus_monitor (editor, bm_view); ephy_node_view_enable_drag_source (EPHY_NODE_VIEW (bm_view), bmk_drag_types, n_bmk_drag_types, EPHY_NODE_BMK_PROP_LOCATION); ephy_node_view_add_column (EPHY_NODE_VIEW (bm_view), _("Title"), G_TYPE_STRING, EPHY_NODE_BMK_PROP_TITLE, -1, EPHY_NODE_VIEW_AUTO_SORT | EPHY_NODE_VIEW_EDITABLE, provide_favicon); gtk_container_add (GTK_CONTAINER (scrolled_window), bm_view); gtk_widget_show (bm_view); editor->priv->bm_view = bm_view; g_signal_connect (G_OBJECT (bm_view), "key_press_event", G_CALLBACK (key_pressed_cb), editor); g_signal_connect (G_OBJECT (bm_view), "node_activated", G_CALLBACK (ephy_bookmarks_editor_node_activated_cb), editor); g_signal_connect (G_OBJECT (bm_view), "show_popup", G_CALLBACK (ephy_bookmarks_editor_show_popup_cb), editor); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (bm_view)); g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (view_selection_changed_cb), editor); ephy_state_add_window (GTK_WIDGET(editor), "bookmarks_editor", 450, 400, EPHY_STATE_WINDOW_SAVE_SIZE | EPHY_STATE_WINDOW_SAVE_POSITION); ephy_state_add_paned (GTK_WIDGET (hpaned), "bookmarks_paned", 130); selected_id_str = eel_gconf_get_string (CONF_BOOKMARKS_SELECTED_NODE); selected_id = g_ascii_strtoull (selected_id_str, NULL, 10); if (selected_id <= 0) { g_free (selected_id_str); return; } selected_node = ephy_bookmarks_get_from_id (editor->priv->bookmarks, selected_id); if (selected_node != NULL) { ephy_node_view_select_node (EPHY_NODE_VIEW (key_view), selected_node); } g_free (selected_id_str); } void ephy_bookmarks_editor_set_parent (EphyBookmarksEditor *ebe, GtkWidget *window) { if (ebe->priv->window) { g_object_remove_weak_pointer (G_OBJECT(ebe->priv->window), (gpointer *)&ebe->priv->window); } ebe->priv->window = window; g_object_add_weak_pointer (G_OBJECT(ebe->priv->window), (gpointer *)&ebe->priv->window); } GtkWidget * ephy_bookmarks_editor_new (EphyBookmarks *bookmarks) { EphyBookmarksEditor *editor; g_assert (bookmarks != NULL); editor = EPHY_BOOKMARKS_EDITOR (g_object_new (EPHY_TYPE_BOOKMARKS_EDITOR, "bookmarks", bookmarks, NULL)); ephy_bookmarks_editor_construct (editor); return GTK_WIDGET (editor); } static void ephy_bookmarks_editor_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { EphyBookmarksEditor *editor = EPHY_BOOKMARKS_EDITOR (object); switch (prop_id) { case PROP_BOOKMARKS: editor->priv->bookmarks = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void ephy_bookmarks_editor_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { EphyBookmarksEditor *editor = EPHY_BOOKMARKS_EDITOR (object); switch (prop_id) { case PROP_BOOKMARKS: g_value_set_object (value, editor->priv->bookmarks); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void toolbar_items_changed_cb (EphyToolbarsModel *model, int toolbar_position, int position, EphyBookmarksEditor *editor) { ephy_bookmarks_editor_update_menu (editor); } static void ephy_bookmarks_editor_init (EphyBookmarksEditor *editor) { editor->priv = g_new0 (EphyBookmarksEditorPrivate, 1); editor->priv->props_dialogs = g_hash_table_new (g_direct_hash, g_direct_equal); editor->priv->tb_model = ephy_shell_get_toolbars_model (ephy_shell); g_signal_connect (editor->priv->tb_model, "item_added", G_CALLBACK (toolbar_items_changed_cb), editor); g_signal_connect (editor->priv->tb_model, "item_removed", G_CALLBACK (toolbar_items_changed_cb), editor); }