X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;f=shell%2Fev-sidebar-bookmarks.c;h=fa252d898c7879e2726860ea2983cb4f5d5fbcfb;hb=64f2cca8898d08f2b8c549d98a9c5869f7035e3f;hp=6cc2eb0e8ae97780ec7b6b2fc7877631b404be3a;hpb=8b3ebe4d7024547993d3b4660f3f22036e327be3;p=evince.git diff --git a/shell/ev-sidebar-bookmarks.c b/shell/ev-sidebar-bookmarks.c index 6cc2eb0e..fa252d89 100644 --- a/shell/ev-sidebar-bookmarks.c +++ b/shell/ev-sidebar-bookmarks.c @@ -1,9 +1,7 @@ -/* this file is part of evince, a gnome document viewer +/* ev-sidebar-bookmarks.c + * this file is part of evince, a gnome document viewer * - * Copyright (C) 2004 Red Hat, Inc. - * - * Author: - * Jonathan Blandford + * Copyright (C) 2010 Carlos Garcia Campos * * Evince is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by @@ -20,335 +18,597 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ -#ifdef HAVE_CONFIG_H #include "config.h" -#endif -#include -#include +#include #include "ev-sidebar-bookmarks.h" -#include "ev-document-bookmarks.h" -/* Amount of time we devote to each iteration of the idle, in microseconds */ -#define IDLE_WORK_LENGTH 5000 +#include "ev-document.h" +#include "ev-sidebar-page.h" +#include "ev-utils.h" -typedef struct { - EvDocumentBookmarksIter *bookmarks_iter; - GtkTreeIter *tree_iter; -} IdleStackData; +enum { + PROP_0, + PROP_WIDGET +}; -struct _EvSidebarBookmarksPrivate { - GtkWidget *tree_view; - GtkTreeModel *model; - EvDocument *current_document; - GList *idle_stack; - guint idle_id; +enum { + COLUMN_MARKUP, + COLUMN_PAGE, + N_COLUMNS }; enum { - BOOKMARKS_COLUMN_MARKUP, - BOOKMARKS_COLUMN_PAGE_NUM, - BOOKMARKS_COLUMN_PAGE_VALID, - BOOKMARKS_COLUMN_NUM_COLUMNS + ADD_BOOKMARK, + N_SIGNALS +}; + +struct _EvSidebarBookmarksPrivate { + EvDocumentModel *model; + EvBookmarks *bookmarks; + + GtkWidget *tree_view; + GtkWidget *del_button; + GtkWidget *add_button; + + /* Popup menu */ + GtkWidget *popup; + GtkUIManager *ui_manager; + GtkActionGroup *action_group; }; -static void bookmarks_page_num_func (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *tree_model, - GtkTreeIter *iter, - gpointer data); +static void ev_sidebar_bookmarks_page_iface_init (EvSidebarPageInterface *iface); -G_DEFINE_TYPE (EvSidebarBookmarks, ev_sidebar_bookmarks, GTK_TYPE_VBOX) +G_DEFINE_TYPE_EXTENDED (EvSidebarBookmarks, + ev_sidebar_bookmarks, + GTK_TYPE_VBOX, + 0, + G_IMPLEMENT_INTERFACE (EV_TYPE_SIDEBAR_PAGE, + ev_sidebar_bookmarks_page_iface_init)) -#define EV_SIDEBAR_BOOKMARKS_GET_PRIVATE(object) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR_BOOKMARKS, EvSidebarBookmarksPrivate)) +static guint signals[N_SIGNALS]; +static const gchar popup_menu_ui[] = + "\n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +static gint +ev_sidebar_bookmarks_get_selected_page (EvSidebarBookmarks *sidebar_bookmarks, + GtkTreeSelection *selection) +{ + GtkTreeModel *model; + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + guint page; + + gtk_tree_model_get (model, &iter, + COLUMN_PAGE, &page, + -1); + return page; + } + + return -1; +} static void -ev_sidebar_bookmarks_destroy (GtkObject *object) +ev_bookmarks_popup_cmd_open_bookmark (GtkAction *action, + EvSidebarBookmarks *sidebar_bookmarks) { - EvSidebarBookmarks *ev_sidebar_bookmarks = (EvSidebarBookmarks *) object; + EvSidebarBookmarksPrivate *priv = sidebar_bookmarks->priv; + GtkTreeSelection *selection; + gint page; - g_print ("ev_sidebar_bookmarks_destroy!\n"); - ev_sidebar_bookmarks_clear_document (ev_sidebar_bookmarks); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view)); + page = ev_sidebar_bookmarks_get_selected_page (sidebar_bookmarks, selection); + ev_document_model_set_page (priv->model, page); } static void -ev_sidebar_bookmarks_class_init (EvSidebarBookmarksClass *ev_sidebar_bookmarks_class) +ev_bookmarks_popup_cmd_rename_bookmark (GtkAction *action, + EvSidebarBookmarks *sidebar_bookmarks) { - GObjectClass *g_object_class; - GtkObjectClass *gtk_object_class; + EvSidebarBookmarksPrivate *priv = sidebar_bookmarks->priv; + GtkTreeView *tree_view = GTK_TREE_VIEW (priv->tree_view); + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + + + selection = gtk_tree_view_get_selection (tree_view); + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + GtkTreePath *path; + + path = gtk_tree_model_get_path (model, &iter); + gtk_tree_view_set_cursor (tree_view, path, + gtk_tree_view_get_column (tree_view, 0), + TRUE); + gtk_tree_path_free (path); + } +} - g_object_class = G_OBJECT_CLASS (ev_sidebar_bookmarks_class); - gtk_object_class = GTK_OBJECT_CLASS (ev_sidebar_bookmarks_class); +static void +ev_bookmarks_popup_cmd_remove_bookmark (GtkAction *action, + EvSidebarBookmarks *sidebar_bookmarks) +{ + EvSidebarBookmarksPrivate *priv = sidebar_bookmarks->priv; + GtkTreeSelection *selection; + gint page; + EvBookmark bm; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view)); + page = ev_sidebar_bookmarks_get_selected_page (sidebar_bookmarks, selection); + bm.page = page; + bm.title = NULL; + ev_bookmarks_delete (priv->bookmarks, &bm); +} - gtk_object_class->destroy = ev_sidebar_bookmarks_destroy; +static const GtkActionEntry popup_entries[] = { + { "OpenBookmark", GTK_STOCK_OPEN, N_("_Open Bookmark"), NULL, + NULL, G_CALLBACK (ev_bookmarks_popup_cmd_open_bookmark) }, + { "RenameBookmark", NULL, N_("_Rename Bookmark"), NULL, + NULL, G_CALLBACK (ev_bookmarks_popup_cmd_rename_bookmark) }, + { "RemoveBookmark", NULL, N_("_Remove Bookmark"), NULL, + NULL, G_CALLBACK (ev_bookmarks_popup_cmd_remove_bookmark) } +}; - g_type_class_add_private (g_object_class, sizeof (EvSidebarBookmarksPrivate)); +static gint +compare_bookmarks (EvBookmark *a, + EvBookmark *b) +{ + if (a->page < b->page) + return -1; + if (a->page > b->page) + return 1; + return 0; } +static void +ev_sidebar_bookmarks_update (EvSidebarBookmarks *sidebar_bookmarks) +{ + EvSidebarBookmarksPrivate *priv = sidebar_bookmarks->priv; + GtkListStore *model; + GList *items, *l; + GtkTreeIter iter; + + model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree_view))); + gtk_list_store_clear (model); + + if (!priv->bookmarks) { + g_object_set (priv->tree_view, "has-tooltip", FALSE, NULL); + return; + } + + items = ev_bookmarks_get_bookmarks (priv->bookmarks); + items = g_list_sort (items, (GCompareFunc)compare_bookmarks); + for (l = items; l; l = g_list_next (l)) { + EvBookmark *bm = (EvBookmark *)l->data; + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, + COLUMN_MARKUP, bm->title, + COLUMN_PAGE, bm->page, + -1); + } + g_list_free (items); + g_object_set (priv->tree_view, "has-tooltip", TRUE, NULL); +} static void -ev_sidebar_bookmarks_construct (EvSidebarBookmarks *ev_sidebar_bookmarks) +ev_sidebar_bookmarks_changed (EvBookmarks *bookmarks, + EvSidebarBookmarks *sidebar_bookmarks) { - EvSidebarBookmarksPrivate *priv; - GtkWidget *swindow; - GtkTreeViewColumn *column; - GtkCellRenderer *renderer; - - priv = ev_sidebar_bookmarks->priv; - priv->model = (GtkTreeModel *) gtk_tree_store_new (BOOKMARKS_COLUMN_NUM_COLUMNS, - G_TYPE_STRING, - G_TYPE_INT, - G_TYPE_BOOLEAN); - - swindow = gtk_scrolled_window_new (NULL, NULL); - - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow), - GTK_SHADOW_IN); - - /* Create tree view */ - priv->tree_view = gtk_tree_view_new_with_model (priv->model); - g_object_unref (priv->model); - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE); - gtk_container_add (GTK_CONTAINER (swindow), priv->tree_view); - gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (priv->tree_view), TRUE); - - gtk_box_pack_start (GTK_BOX (ev_sidebar_bookmarks), swindow, TRUE, TRUE, 0); - gtk_widget_show_all (GTK_WIDGET (ev_sidebar_bookmarks)); - - column = gtk_tree_view_column_new (); - gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE); - gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), column); - - renderer = (GtkCellRenderer*) - g_object_new (GTK_TYPE_CELL_RENDERER_TEXT, - "ellipsize", PANGO_ELLIPSIZE_END, - NULL); - gtk_tree_view_column_pack_start (GTK_TREE_VIEW_COLUMN (column), renderer, TRUE); - gtk_tree_view_column_set_attributes (GTK_TREE_VIEW_COLUMN (column), renderer, - "markup", BOOKMARKS_COLUMN_MARKUP, - NULL); - - renderer = gtk_cell_renderer_text_new (); - gtk_tree_view_column_pack_end (GTK_TREE_VIEW_COLUMN (column), renderer, FALSE); - gtk_tree_view_column_set_cell_data_func (GTK_TREE_VIEW_COLUMN (column), renderer, - (GtkTreeCellDataFunc) bookmarks_page_num_func, - NULL, NULL); + ev_sidebar_bookmarks_update (sidebar_bookmarks); +} +static void +ev_sidebar_bookmarks_selection_changed (GtkTreeSelection *selection, + EvSidebarBookmarks *sidebar_bookmarks) +{ + EvSidebarBookmarksPrivate *priv = sidebar_bookmarks->priv; + gint page; + + page = ev_sidebar_bookmarks_get_selected_page (sidebar_bookmarks, selection); + if (page >= 0) { + ev_document_model_set_page (priv->model, page); + gtk_widget_set_sensitive (priv->del_button, TRUE); + } else { + gtk_widget_set_sensitive (priv->del_button, FALSE); + } } static void -ev_sidebar_bookmarks_init (EvSidebarBookmarks *ev_sidebar_bookmarks) +ev_sidebar_bookmarks_add_clicked (GtkWidget *button, + EvSidebarBookmarks *sidebar_bookmarks) { - ev_sidebar_bookmarks->priv = EV_SIDEBAR_BOOKMARKS_GET_PRIVATE (ev_sidebar_bookmarks); + /* Let the window add the bookmark since + * since we don't know the page title + */ + g_signal_emit (sidebar_bookmarks, signals[ADD_BOOKMARK], 0); +} - ev_sidebar_bookmarks_construct (ev_sidebar_bookmarks); +static void +ev_sidebar_bookmarks_del_clicked (GtkWidget *button, + EvSidebarBookmarks *sidebar_bookmarks) +{ + EvSidebarBookmarksPrivate *priv = sidebar_bookmarks->priv; + GtkTreeSelection *selection; + gint page; + EvBookmark bm; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view)); + page = ev_sidebar_bookmarks_get_selected_page (sidebar_bookmarks, selection); + if (page < 0) + return; + + bm.page = page; + bm.title = NULL; + ev_bookmarks_delete (priv->bookmarks, &bm); } static void -bookmarks_page_num_func (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *tree_model, - GtkTreeIter *iter, - gpointer data) +ev_sidebar_bookmarks_bookmark_renamed (GtkCellRendererText *renderer, + const gchar *path_string, + const gchar *new_text, + EvSidebarBookmarks *sidebar_bookmarks) { - int page_num; - gboolean page_valid; - - gtk_tree_model_get (tree_model, iter, - BOOKMARKS_COLUMN_PAGE_NUM, &page_num, - BOOKMARKS_COLUMN_PAGE_VALID, &page_valid, - -1); - - if (page_valid) { - gchar *markup = g_strdup_printf ("%d", page_num); - g_object_set (cell, - "markup", markup, - "visible", TRUE, - NULL); - g_free (markup); - } else { - g_object_set (cell, - "visible", FALSE, - NULL); - } + EvSidebarBookmarksPrivate *priv = sidebar_bookmarks->priv; + GtkTreePath *path = gtk_tree_path_new_from_string (path_string); + GtkTreeModel *model; + GtkTreeIter iter; + guint page; + EvBookmark bm; + + if (!new_text || new_text[0] == '\0') + return; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree_view)); + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, + COLUMN_PAGE, &page, + -1); + gtk_tree_path_free (path); + + bm.page = page; + bm.title = g_strdup (new_text); + ev_bookmarks_update (priv->bookmarks, &bm); } -/* Public Functions */ +static gboolean +ev_sidebar_bookmarks_query_tooltip (GtkWidget *widget, + gint x, + gint y, + gboolean keyboard_tip, + GtkTooltip *tooltip, + EvSidebarBookmarks *sidebar_bookmarks) +{ + EvSidebarBookmarksPrivate *priv = sidebar_bookmarks->priv; + GtkTreeModel *model; + GtkTreeIter iter; + GtkTreePath *path = NULL; + EvDocument *document; + guint page; + gchar *page_label; + gchar *text; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree_view)); + if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (priv->tree_view), + &x, &y, keyboard_tip, + &model, &path, &iter)) + return FALSE; + + gtk_tree_model_get (model, &iter, + COLUMN_PAGE, &page, + -1); + + document = ev_document_model_get_document (priv->model); + page_label = ev_document_get_page_label (document, page); + text = g_strdup_printf (_("Page %s"), page_label); + gtk_tooltip_set_text (tooltip, text); + g_free (text); + g_free (page_label); + + gtk_tree_view_set_tooltip_row (GTK_TREE_VIEW (priv->tree_view), + tooltip, path); + gtk_tree_path_free (path); + + return TRUE; +} -GtkWidget * -ev_sidebar_bookmarks_new (void) +static gboolean +ev_sidebar_bookmarks_popup_menu_show (EvSidebarBookmarks *sidebar_bookmarks, + gint x, + gint y, + gboolean keyboard_mode) { - GtkWidget *ev_sidebar_bookmarks; + EvSidebarBookmarksPrivate *priv = sidebar_bookmarks->priv; + GtkTreeView *tree_view = GTK_TREE_VIEW (sidebar_bookmarks->priv->tree_view); + GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view); + + if (keyboard_mode) { + if (!gtk_tree_selection_get_selected (selection, NULL, NULL)) + return FALSE; + } else { + GtkTreePath *path; + + if (!gtk_tree_view_get_path_at_pos (tree_view, x, y, &path, NULL, NULL, NULL)) + return FALSE; + + g_signal_handlers_block_by_func (selection, + ev_sidebar_bookmarks_selection_changed, + sidebar_bookmarks); + gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE); + g_signal_handlers_unblock_by_func (selection, + ev_sidebar_bookmarks_selection_changed, + sidebar_bookmarks); + gtk_tree_path_free (path); + } + + if (!priv->popup) + priv->popup = gtk_ui_manager_get_widget (priv->ui_manager, "/BookmarksPopup"); + + gtk_menu_popup (GTK_MENU (priv->popup), + NULL, NULL, + keyboard_mode ? ev_gui_menu_position_tree_selection : NULL, + keyboard_mode ? tree_view : NULL, + keyboard_mode ? 0 : 3, + gtk_get_current_event_time ()); + return TRUE; +} - ev_sidebar_bookmarks = g_object_new (EV_TYPE_SIDEBAR_BOOKMARKS, NULL); +static gboolean +ev_sidebar_bookmarks_button_press (GtkWidget *widget, + GdkEventButton *event, + EvSidebarBookmarks *sidebar_bookmarks) +{ + if (event->button != 3) + return FALSE; - return ev_sidebar_bookmarks; + return ev_sidebar_bookmarks_popup_menu_show (sidebar_bookmarks, event->x, event->y, FALSE); } -static void -stack_data_free (IdleStackData *stack_data, - EvDocumentBookmarks *document_bookmarks) +static gboolean +ev_sidebar_bookmarks_popup_menu (GtkWidget *widget) { - g_assert (stack_data); + EvSidebarBookmarks *sidebar_bookmarks = EV_SIDEBAR_BOOKMARKS (widget); + gint x, y; - if (stack_data->tree_iter) - gtk_tree_iter_free (stack_data->tree_iter); - if (stack_data->bookmarks_iter) - ev_document_bookmarks_free_iter (document_bookmarks, stack_data->bookmarks_iter); - g_free (stack_data); + gtk_widget_get_pointer (widget, &x, &y); + return ev_sidebar_bookmarks_popup_menu_show (sidebar_bookmarks, x, y, TRUE); } -static gboolean -do_one_iteration (EvSidebarBookmarks *ev_sidebar_bookmarks) +static void +ev_sidebar_bookmarks_dispose (GObject *object) { - EvSidebarBookmarksPrivate *priv = ev_sidebar_bookmarks->priv; - EvBookmark *bookmark; - IdleStackData *stack_data; - GtkTreeIter tree_iter; - EvDocumentBookmarksIter *child_iter; - gint page; - - g_assert (priv->idle_stack); - - stack_data = (IdleStackData *) priv->idle_stack->data; - - bookmark = ev_document_bookmarks_get_bookmark - (EV_DOCUMENT_BOOKMARKS (priv->current_document), - stack_data->bookmarks_iter); - if (bookmark == NULL) { - g_warning ("mismatch in model. No values available at current level.\n"); - return FALSE; - } - - page = ev_bookmark_get_page (bookmark); - gtk_tree_store_append (GTK_TREE_STORE (priv->model), &tree_iter, stack_data->tree_iter); - gtk_tree_store_set (GTK_TREE_STORE (priv->model), &tree_iter, - BOOKMARKS_COLUMN_MARKUP, ev_bookmark_get_title (bookmark), - BOOKMARKS_COLUMN_PAGE_NUM, page, - /* FIXME: Handle links for real. */ - BOOKMARKS_COLUMN_PAGE_VALID, (page >= 0), - -1); - g_object_unref (bookmark); - - child_iter = ev_document_bookmarks_get_child (EV_DOCUMENT_BOOKMARKS (priv->current_document), - stack_data->bookmarks_iter); - if (child_iter) { - IdleStackData *child_stack_data; - - child_stack_data = g_new0 (IdleStackData, 1); - child_stack_data->tree_iter = gtk_tree_iter_copy (&tree_iter); - child_stack_data->bookmarks_iter = child_iter; - priv->idle_stack = g_list_prepend (priv->idle_stack, child_stack_data); - - return TRUE; - } - - /* We don't have children, so we need to walk to the next node */ - while (TRUE) { - if (ev_document_bookmarks_next (EV_DOCUMENT_BOOKMARKS (priv->current_document), - stack_data->bookmarks_iter)) - return TRUE; - - /* We're done with this level. Pop it off the idle stack and go - * to the next level */ - stack_data_free (stack_data, EV_DOCUMENT_BOOKMARKS (priv->current_document)); - priv->idle_stack = g_list_delete_link (priv->idle_stack, priv->idle_stack); - if (priv->idle_stack == NULL) - return FALSE; - stack_data = priv->idle_stack->data; - } + EvSidebarBookmarks *sidebar_bookmarks = EV_SIDEBAR_BOOKMARKS (object); + EvSidebarBookmarksPrivate *priv = sidebar_bookmarks->priv; + + if (priv->model) { + g_object_unref (priv->model); + priv->model = NULL; + } + + if (priv->bookmarks) { + g_object_unref (priv->bookmarks); + priv->bookmarks = NULL; + } + + if (priv->action_group) { + g_object_unref (priv->action_group); + priv->action_group = NULL; + } + + if (priv->ui_manager) { + g_object_unref (priv->ui_manager); + priv->ui_manager = NULL; + } + + G_OBJECT_CLASS (ev_sidebar_bookmarks_parent_class)->dispose (object); } -static gboolean -populate_bookmarks_idle (gpointer data) +static void +ev_sidebar_bookmarks_init (EvSidebarBookmarks *sidebar_bookmarks) { - GTimer *timer; - gint i; - gulong microseconds = 0; - - EvSidebarBookmarks *ev_sidebar_bookmarks = (EvSidebarBookmarks *)data; - EvSidebarBookmarksPrivate *priv = ev_sidebar_bookmarks->priv; - - if (priv->idle_stack == NULL) { - priv->idle_id = 0; - return FALSE; - } - - /* The amount of time that reading the next bookmark takes is wildly - * inconsistent, so we constrain it to IDLE_WORK_LENGTH microseconds per - * idle iteration. */ - timer = g_timer_new (); - i = 0; - g_timer_start (timer); - while (do_one_iteration (ev_sidebar_bookmarks)) { - i++; - g_timer_elapsed (timer, µseconds); - if (microseconds > IDLE_WORK_LENGTH) - break; - } - g_timer_destroy (timer); -#if 0 - g_print ("%d rows done this idle in %d\n", i, (int)microseconds); -#endif - return TRUE; + EvSidebarBookmarksPrivate *priv; + GtkWidget *swindow; + GtkWidget *hbox; + GtkListStore *model; + GtkCellRenderer *renderer; + GtkTreeSelection *selection; + + sidebar_bookmarks->priv = G_TYPE_INSTANCE_GET_PRIVATE (sidebar_bookmarks, + EV_TYPE_SIDEBAR_BOOKMARKS, + EvSidebarBookmarksPrivate); + priv = sidebar_bookmarks->priv; + + gtk_box_set_spacing (GTK_BOX (sidebar_bookmarks), 6); + + swindow = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow), + GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (sidebar_bookmarks), swindow, TRUE, TRUE, 0); + gtk_widget_show (swindow); + + model = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_UINT); + priv->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model)); + g_object_unref (model); + g_signal_connect (priv->tree_view, "query-tooltip", + G_CALLBACK (ev_sidebar_bookmarks_query_tooltip), + sidebar_bookmarks); + g_signal_connect (priv->tree_view, + "button-press-event", + G_CALLBACK (ev_sidebar_bookmarks_button_press), + sidebar_bookmarks); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view)); + g_signal_connect (selection, "changed", + G_CALLBACK (ev_sidebar_bookmarks_selection_changed), + sidebar_bookmarks); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "ellipsize", PANGO_ELLIPSIZE_END, + "editable", TRUE, + NULL); + g_signal_connect (renderer, "edited", + G_CALLBACK (ev_sidebar_bookmarks_bookmark_renamed), + sidebar_bookmarks); + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->tree_view), + 0, NULL, renderer, + "markup", COLUMN_MARKUP, + NULL); + gtk_container_add (GTK_CONTAINER (swindow), priv->tree_view); + gtk_widget_show (priv->tree_view); + + hbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + + priv->add_button = gtk_button_new_from_stock (GTK_STOCK_ADD); + g_signal_connect (priv->add_button, "clicked", + G_CALLBACK (ev_sidebar_bookmarks_add_clicked), + sidebar_bookmarks); + gtk_widget_set_sensitive (priv->add_button, FALSE); + gtk_box_pack_start (GTK_BOX (hbox), priv->add_button, TRUE, TRUE, 6); + gtk_widget_show (priv->add_button); + + priv->del_button = gtk_button_new_from_stock (GTK_STOCK_REMOVE); + g_signal_connect (priv->del_button, "clicked", + G_CALLBACK (ev_sidebar_bookmarks_del_clicked), + sidebar_bookmarks); + gtk_widget_set_sensitive (priv->del_button, FALSE); + gtk_box_pack_start (GTK_BOX (hbox), priv->del_button, TRUE, TRUE, 6); + gtk_widget_show (priv->del_button); + + gtk_box_pack_end (GTK_BOX (sidebar_bookmarks), hbox, FALSE, TRUE, 0); + gtk_widget_show (hbox); + gtk_widget_show (GTK_WIDGET (sidebar_bookmarks)); + + /* Popup menu */ + priv->action_group = gtk_action_group_new ("BookmarsPopupActions"); + gtk_action_group_set_translation_domain (priv->action_group, NULL); + gtk_action_group_add_actions (priv->action_group, popup_entries, + G_N_ELEMENTS (popup_entries), + sidebar_bookmarks); + priv->ui_manager = gtk_ui_manager_new (); + gtk_ui_manager_insert_action_group (priv->ui_manager, + priv->action_group, 0); + gtk_ui_manager_add_ui_from_string (priv->ui_manager, popup_menu_ui, -1, NULL); } -void -ev_sidebar_bookmarks_clear_document (EvSidebarBookmarks *sidebar_bookmarks) +static void +ev_sidebar_bookmarks_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - EvSidebarBookmarksPrivate *priv; - - g_return_if_fail (EV_IS_SIDEBAR_BOOKMARKS (sidebar_bookmarks)); - - priv = sidebar_bookmarks->priv; - if (priv->current_document) { - g_object_unref (priv->current_document); - priv->current_document = NULL; - } - gtk_tree_store_clear (GTK_TREE_STORE (priv->model)); - - /* Clear the idle */ - if (priv->idle_id != 0) { - g_source_remove (priv->idle_id); - priv->idle_id = 0; - } - g_list_foreach (priv->idle_stack, (GFunc) stack_data_free, priv->current_document); - g_list_free (priv->idle_stack); - priv->idle_stack = NULL; + EvSidebarBookmarks *sidebar_bookmarks; + + sidebar_bookmarks = EV_SIDEBAR_BOOKMARKS (object); + + switch (prop_id) { + case PROP_WIDGET: + g_value_set_object (value, sidebar_bookmarks->priv->tree_view); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ev_sidebar_bookmarks_class_init (EvSidebarBookmarksClass *klass) +{ + GObjectClass *g_object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + g_object_class->get_property = ev_sidebar_bookmarks_get_property; + g_object_class->dispose = ev_sidebar_bookmarks_dispose; + widget_class->popup_menu = ev_sidebar_bookmarks_popup_menu; + + g_type_class_add_private (g_object_class, sizeof (EvSidebarBookmarksPrivate)); + + g_object_class_override_property (g_object_class, PROP_WIDGET, "main-widget"); + + signals[ADD_BOOKMARK] = + g_signal_new ("add-bookmark", + G_TYPE_FROM_CLASS (g_object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EvSidebarBookmarksClass, add_bookmark), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0, + G_TYPE_NONE); +} + +GtkWidget * +ev_sidebar_bookmarks_new (void) +{ + return GTK_WIDGET (g_object_new (EV_TYPE_SIDEBAR_BOOKMARKS, NULL)); } void -ev_sidebar_bookmarks_set_document (EvSidebarBookmarks *sidebar_bookmarks, - EvDocument *document) +ev_sidebar_bookmarks_set_bookmarks (EvSidebarBookmarks *sidebar_bookmarks, + EvBookmarks *bookmarks) { - EvSidebarBookmarksPrivate *priv; - EvDocumentBookmarksIter *bookmarks_iter; + EvSidebarBookmarksPrivate *priv = sidebar_bookmarks->priv; + + g_return_if_fail (EV_IS_BOOKMARKS (bookmarks)); - g_return_if_fail (EV_IS_SIDEBAR_BOOKMARKS (sidebar_bookmarks)); - g_return_if_fail (EV_IS_DOCUMENT (document)); + if (priv->bookmarks == bookmarks) + return; - priv = sidebar_bookmarks->priv; + if (priv->bookmarks) + g_object_unref (priv->bookmarks); + priv->bookmarks = g_object_ref (bookmarks); + g_signal_connect (priv->bookmarks, "changed", + G_CALLBACK (ev_sidebar_bookmarks_changed), + sidebar_bookmarks); + + gtk_widget_set_sensitive (priv->add_button, TRUE); + ev_sidebar_bookmarks_update (sidebar_bookmarks); +} + +/* EvSidebarPageIface */ +static void +ev_sidebar_bookmarks_set_model (EvSidebarPage *sidebar_page, + EvDocumentModel *model) +{ + EvSidebarBookmarks *sidebar_bookmarks = EV_SIDEBAR_BOOKMARKS (sidebar_page); + EvSidebarBookmarksPrivate *priv = sidebar_bookmarks->priv; - g_object_ref (document); - ev_sidebar_bookmarks_clear_document (sidebar_bookmarks); + if (priv->model == model) + return; - priv->current_document = document; - bookmarks_iter = ev_document_bookmarks_begin_read (EV_DOCUMENT_BOOKMARKS (document)); - if (bookmarks_iter) { - IdleStackData *stack_data; + if (priv->model) + g_object_unref (priv->model); + priv->model = g_object_ref (model); +} - stack_data = g_new0 (IdleStackData, 1); - stack_data->bookmarks_iter = bookmarks_iter; - stack_data->tree_iter = NULL; +static gboolean +ev_sidebar_bookmarks_support_document (EvSidebarPage *sidebar_page, + EvDocument *document) +{ + return TRUE; +} - priv->idle_stack = g_list_prepend (priv->idle_stack, stack_data); - priv->idle_id = g_idle_add (populate_bookmarks_idle, sidebar_bookmarks); - } +static const gchar * +ev_sidebar_bookmarks_get_label (EvSidebarPage *sidebar_page) +{ + return _("Bookmarks"); } +static void +ev_sidebar_bookmarks_page_iface_init (EvSidebarPageInterface *iface) +{ + iface->support_document = ev_sidebar_bookmarks_support_document; + iface->set_model = ev_sidebar_bookmarks_set_model; + iface->get_label = ev_sidebar_bookmarks_get_label; +}