summaryrefslogtreecommitdiff
path: root/shell/ev-sidebar-links.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ev-sidebar-links.c')
-rw-r--r--shell/ev-sidebar-links.c158
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),