diff options
Diffstat (limited to 'shell/ev-sidebar-links.c')
-rw-r--r-- | shell/ev-sidebar-links.c | 158 |
1 files changed, 90 insertions, 68 deletions
diff --git a/shell/ev-sidebar-links.c b/shell/ev-sidebar-links.c index 92caa959..e6531cae 100644 --- a/shell/ev-sidebar-links.c +++ b/shell/ev-sidebar-links.c @@ -29,6 +29,8 @@ #include <glib/gi18n.h> #include <gtk/gtk.h> +#include <libmate-desktop/mate-image-menu-item.h> + #include "ev-document-links.h" #include "ev-job-scheduler.h" #include "ev-sidebar-links.h" @@ -39,14 +41,16 @@ struct _EvSidebarLinksPrivate { GtkWidget *tree_view; /* Keep these ids around for blocking */ - guint selection_id; - guint page_changed_id; - guint row_activated_id; + gulong selection_id; + gulong page_changed_id; + gulong row_activated_id; EvJob *job; GtkTreeModel *model; EvDocument *document; EvDocumentModel *doc_model; + + GTree *page_link_tree; }; enum { @@ -149,6 +153,11 @@ ev_sidebar_links_dispose (GObject *object) sidebar->priv->model = NULL; } + if (sidebar->priv->page_link_tree) { + g_tree_unref (sidebar->priv->page_link_tree); + sidebar->priv->page_link_tree = NULL; + } + if (sidebar->priv->document) { g_object_unref (sidebar->priv->document); sidebar->priv->document = NULL; @@ -324,11 +333,13 @@ static GtkMenu * build_popup_menu (EvSidebarLinks *sidebar) { GtkWidget *menu; + GtkWidget *image; GtkWidget *item; menu = gtk_menu_new (); - item = gtk_image_menu_item_new_from_stock ("gtk-print", NULL); - gtk_label_set_label (GTK_LABEL (gtk_bin_get_child (GTK_BIN (item))), _("Print…")); + item = mate_image_menu_item_new_with_label ("Print…"); + image = gtk_image_new_from_icon_name ("gtk-print", GTK_ICON_SIZE_MENU); + mate_image_menu_item_set_image (MATE_IMAGE_MENU_ITEM (item), image); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (item, "activate", @@ -372,7 +383,6 @@ button_press_cb (GtkWidget *treeview, return FALSE; } - static void ev_sidebar_links_construct (EvSidebarLinks *ev_sidebar_links) { @@ -418,7 +428,6 @@ ev_sidebar_links_construct (EvSidebarLinks *ev_sidebar_links) "markup", EV_DOCUMENT_LINKS_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_attributes (GTK_TREE_VIEW_COLUMN (column), renderer, @@ -461,40 +470,19 @@ ev_sidebar_links_new (void) return ev_sidebar_links; } -static gboolean -update_page_callback_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer data) -{ - EvSidebarLinks *sidebar_links = (data); - EvLink *link; - - gtk_tree_model_get (model, iter, - EV_DOCUMENT_LINKS_COLUMN_LINK, &link, - -1); - - if (link) { - int current_page; - int dest_page; - EvDocumentLinks *document_links = EV_DOCUMENT_LINKS (sidebar_links->priv->document); - - dest_page = ev_document_links_get_link_page (document_links, link); - g_object_unref (link); +typedef struct EvSidebarLinkPageSearch { + gint page; + gint best_existing; +} EvSidebarLinkPageSearch; - current_page = ev_document_model_get_page (sidebar_links->priv->doc_model); - - if (dest_page == current_page) { - gtk_tree_view_expand_to_path (GTK_TREE_VIEW (sidebar_links->priv->tree_view), - path); - gtk_tree_view_set_cursor (GTK_TREE_VIEW (sidebar_links->priv->tree_view), - path, NULL, FALSE); - - return TRUE; - } - } +static gint +page_link_tree_search_best_page (gpointer page_ptr, EvSidebarLinkPageSearch* data) +{ + gint page = GPOINTER_TO_INT (page_ptr); + if (page <= data->page && page > data->best_existing) + data->best_existing = page; - return FALSE; + return data->page - page; } static void @@ -502,44 +490,34 @@ ev_sidebar_links_set_current_page (EvSidebarLinks *sidebar_links, gint current_page) { GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; + GtkTreePath *path; + EvSidebarLinkPageSearch search_data; /* Widget is not currently visible */ - if (!gtk_widget_get_mapped (GTK_WIDGET (sidebar_links))) + if (!gtk_widget_is_visible (GTK_WIDGET (sidebar_links))) return; - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sidebar_links->priv->tree_view)); + search_data.page = current_page; + search_data.best_existing = G_MININT; - if (gtk_tree_selection_get_selected (selection, &model, &iter)) { - EvLink *link; - - gtk_tree_model_get (model, &iter, - EV_DOCUMENT_LINKS_COLUMN_LINK, &link, - -1); - if (link) { - gint dest_page; - EvDocumentLinks *document_links = EV_DOCUMENT_LINKS (sidebar_links->priv->document); + path = g_tree_search (sidebar_links->priv->page_link_tree, (GCompareFunc) page_link_tree_search_best_page, &search_data); + /* No direct hit, try a lookup on the best match. */ + if (!path) + path = g_tree_lookup (sidebar_links->priv->page_link_tree, GINT_TO_POINTER (search_data.best_existing)); - dest_page = ev_document_links_get_link_page (document_links, link); - g_object_unref (link); + /* Still no hit, give up. */ + if (!path) + return; - if (dest_page == current_page) - return; - } - } + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sidebar_links->priv->tree_view)); - /* We go through the tree linearly looking for the first page that - * matches. This is pretty inefficient. We can do something neat with - * a GtkTreeModelSort here to make it faster, if it turns out to be - * slow. - */ g_signal_handler_block (selection, sidebar_links->priv->selection_id); g_signal_handler_block (sidebar_links->priv->tree_view, sidebar_links->priv->row_activated_id); - gtk_tree_model_foreach (model, - update_page_callback_foreach, - sidebar_links); + gtk_tree_view_expand_to_path (GTK_TREE_VIEW (sidebar_links->priv->tree_view), + path); + gtk_tree_view_set_cursor (GTK_TREE_VIEW (sidebar_links->priv->tree_view), + path, NULL, FALSE); g_signal_handler_unblock (selection, sidebar_links->priv->selection_id); g_signal_handler_unblock (sidebar_links->priv->tree_view, sidebar_links->priv->row_activated_id); @@ -590,6 +568,41 @@ expand_open_links (GtkTreeView *tree_view, GtkTreeModel *model, GtkTreeIter *par } } +static gint +page_link_tree_sort (gconstpointer a, gconstpointer b, void *data) +{ + return GPOINTER_TO_INT (a) - GPOINTER_TO_INT (b); +} + +static gboolean +update_page_link_tree_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + EvSidebarLinks *sidebar_links = data; + EvSidebarLinksPrivate *priv = sidebar_links->priv; + EvDocumentLinks *document_links = EV_DOCUMENT_LINKS (priv->document); + EvLink *link; + int page; + + gtk_tree_model_get (model, iter, + EV_DOCUMENT_LINKS_COLUMN_LINK, &link, + -1); + + if (!link) + return FALSE; + + page = ev_document_links_get_link_page (document_links, link); + g_object_unref (link); + + /* Only save the first link we find per page. */ + if (!g_tree_lookup (priv->page_link_tree, GINT_TO_POINTER (page))) + g_tree_insert (priv->page_link_tree, GINT_TO_POINTER (page), gtk_tree_path_copy (path)); + + return FALSE; +} + static void ev_sidebar_links_set_links_model (EvSidebarLinks *sidebar_links, GtkTreeModel *model) @@ -603,6 +616,15 @@ ev_sidebar_links_set_links_model (EvSidebarLinks *sidebar_links, g_object_unref (priv->model); priv->model = g_object_ref (model); + /* Rebuild the binary search tree for finding links on pages. */ + if (priv->page_link_tree) + g_tree_unref (priv->page_link_tree); + priv->page_link_tree = g_tree_new_full (page_link_tree_sort, NULL, NULL, (GDestroyNotify) gtk_tree_path_free); + + gtk_tree_model_foreach (model, + update_page_link_tree_foreach, + sidebar_links); + g_object_notify (G_OBJECT (sidebar_links), "model"); } @@ -625,7 +647,7 @@ job_finished_callback (EvJobLinks *job, selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); - if (priv->selection_id <= 0) { + if (priv->selection_id == 0) { priv->selection_id = g_signal_connect (selection, "changed", G_CALLBACK (selection_changed_callback), @@ -635,7 +657,7 @@ job_finished_callback (EvJobLinks *job, g_signal_connect_swapped (priv->doc_model, "page-changed", G_CALLBACK (update_page_callback), sidebar_links); - if (priv->row_activated_id <= 0) { + if (priv->row_activated_id == 0) { priv->row_activated_id = g_signal_connect (priv->tree_view, "row-activated", G_CALLBACK (row_activated_callback), |