1 /* this file is part of evince, a gnome document viewer
3 * Copyright (C) 2004 Red Hat, Inc.
4 * Copyright (C) 2004, 2005 Anders Carlsson <andersca@gnome.org>
7 * Jonathan Blandford <jrb@alum.mit.edu>
8 * Anders Carlsson <andersca@gnome.org>
10 * Evince is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * Evince is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31 #include <glib/gi18n.h>
34 #include "ev-document-misc.h"
35 #include "ev-job-scheduler.h"
36 #include "ev-sidebar-page.h"
37 #include "ev-sidebar-thumbnails.h"
39 #include "ev-window.h"
41 #define THUMBNAIL_WIDTH 100
43 /* The IconView doesn't scale nearly as well as the TreeView, so we arbitrarily
45 #define MAX_ICON_VIEW_PAGE_COUNT 1500
47 typedef struct _EvThumbsSize
53 typedef struct _EvThumbsSizeCache {
60 struct _EvSidebarThumbnailsPrivate {
64 GtkAdjustment *vadjustment;
65 GtkListStore *list_store;
66 GHashTable *loading_icons;
68 EvDocumentModel *model;
69 EvThumbsSizeCache *size_cache;
71 gint n_pages, pages_done;
74 gboolean inverted_colors;
77 gint start_page, end_page;
93 static void ev_sidebar_thumbnails_clear_model (EvSidebarThumbnails *sidebar);
94 static gboolean ev_sidebar_thumbnails_support_document (EvSidebarPage *sidebar_page,
95 EvDocument *document);
96 static void ev_sidebar_thumbnails_page_iface_init (EvSidebarPageInterface *iface);
97 static const gchar* ev_sidebar_thumbnails_get_label (EvSidebarPage *sidebar_page);
98 static void thumbnail_job_completed_callback (EvJobThumbnail *job,
99 EvSidebarThumbnails *sidebar_thumbnails);
100 static void adjustment_changed_cb (EvSidebarThumbnails *sidebar_thumbnails);
102 G_DEFINE_TYPE_EXTENDED (EvSidebarThumbnails,
103 ev_sidebar_thumbnails,
106 G_IMPLEMENT_INTERFACE (EV_TYPE_SIDEBAR_PAGE,
107 ev_sidebar_thumbnails_page_iface_init))
109 #define EV_SIDEBAR_THUMBNAILS_GET_PRIVATE(object) \
110 (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR_THUMBNAILS, EvSidebarThumbnailsPrivate));
112 /* Thumbnails dimensions cache */
113 #define EV_THUMBNAILS_SIZE_CACHE_KEY "ev-thumbnails-size-cache"
116 get_thumbnail_size_for_page (EvDocument *document,
124 ev_document_get_page_size (document, page, &w, &h);
125 scale = (gdouble)THUMBNAIL_WIDTH / w;
127 *width = MAX ((gint)(w * scale + 0.5), 1);
128 *height = MAX ((gint)(h * scale + 0.5), 1);
131 static EvThumbsSizeCache *
132 ev_thumbnails_size_cache_new (EvDocument *document)
134 EvThumbsSizeCache *cache;
136 EvThumbsSize *thumb_size;
138 cache = g_new0 (EvThumbsSizeCache, 1);
140 if (ev_document_is_page_size_uniform (document)) {
141 cache->uniform = TRUE;
142 get_thumbnail_size_for_page (document, 0,
143 &cache->uniform_width,
144 &cache->uniform_height);
148 n_pages = ev_document_get_n_pages (document);
149 cache->sizes = g_new0 (EvThumbsSize, n_pages);
151 for (i = 0; i < n_pages; i++) {
152 thumb_size = &(cache->sizes[i]);
153 get_thumbnail_size_for_page (document, i,
155 &thumb_size->height);
162 ev_thumbnails_size_cache_get_size (EvThumbsSizeCache *cache,
170 if (cache->uniform) {
171 w = cache->uniform_width;
172 h = cache->uniform_height;
174 EvThumbsSize *thumb_size;
176 thumb_size = &(cache->sizes[page]);
178 w = thumb_size->width;
179 h = thumb_size->height;
182 if (rotation == 0 || rotation == 180) {
183 if (width) *width = w;
184 if (height) *height = h;
186 if (width) *width = h;
187 if (height) *height = w;
192 ev_thumbnails_size_cache_free (EvThumbsSizeCache *cache)
195 g_free (cache->sizes);
202 static EvThumbsSizeCache *
203 ev_thumbnails_size_cache_get (EvDocument *document)
205 EvThumbsSizeCache *cache;
207 cache = g_object_get_data (G_OBJECT (document), EV_THUMBNAILS_SIZE_CACHE_KEY);
209 cache = ev_thumbnails_size_cache_new (document);
210 g_object_set_data_full (G_OBJECT (document),
211 EV_THUMBNAILS_SIZE_CACHE_KEY,
213 (GDestroyNotify)ev_thumbnails_size_cache_free);
221 ev_sidebar_thumbnails_dispose (GObject *object)
223 EvSidebarThumbnails *sidebar_thumbnails = EV_SIDEBAR_THUMBNAILS (object);
225 if (sidebar_thumbnails->priv->loading_icons) {
226 g_hash_table_destroy (sidebar_thumbnails->priv->loading_icons);
227 sidebar_thumbnails->priv->loading_icons = NULL;
230 if (sidebar_thumbnails->priv->list_store) {
231 ev_sidebar_thumbnails_clear_model (sidebar_thumbnails);
232 g_object_unref (sidebar_thumbnails->priv->list_store);
233 sidebar_thumbnails->priv->list_store = NULL;
236 G_OBJECT_CLASS (ev_sidebar_thumbnails_parent_class)->dispose (object);
240 ev_sidebar_thumbnails_get_property (GObject *object,
245 EvSidebarThumbnails *sidebar = EV_SIDEBAR_THUMBNAILS (object);
249 if (sidebar->priv->tree_view)
250 g_value_set_object (value, sidebar->priv->tree_view);
252 g_value_set_object (value, sidebar->priv->icon_view);
255 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
261 ev_sidebar_thumbnails_map (GtkWidget *widget)
263 EvSidebarThumbnails *sidebar;
265 sidebar = EV_SIDEBAR_THUMBNAILS (widget);
267 GTK_WIDGET_CLASS (ev_sidebar_thumbnails_parent_class)->map (widget);
269 adjustment_changed_cb (sidebar);
273 ev_sidebar_thumbnails_class_init (EvSidebarThumbnailsClass *ev_sidebar_thumbnails_class)
275 GObjectClass *g_object_class;
276 GtkWidgetClass *widget_class;
278 g_object_class = G_OBJECT_CLASS (ev_sidebar_thumbnails_class);
279 widget_class = GTK_WIDGET_CLASS (ev_sidebar_thumbnails_class);
281 g_object_class->dispose = ev_sidebar_thumbnails_dispose;
282 g_object_class->get_property = ev_sidebar_thumbnails_get_property;
283 widget_class->map = ev_sidebar_thumbnails_map;
285 g_object_class_override_property (g_object_class,
289 g_type_class_add_private (g_object_class, sizeof (EvSidebarThumbnailsPrivate));
293 ev_sidebar_thumbnails_new (void)
295 GtkWidget *ev_sidebar_thumbnails;
297 ev_sidebar_thumbnails = g_object_new (EV_TYPE_SIDEBAR_THUMBNAILS, NULL);
299 return ev_sidebar_thumbnails;
303 ev_sidebar_thumbnails_get_loading_icon (EvSidebarThumbnails *sidebar_thumbnails,
307 EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
311 key = g_strdup_printf ("%dx%d", width, height);
312 icon = g_hash_table_lookup (priv->loading_icons, key);
314 gboolean inverted_colors;
316 inverted_colors = ev_document_model_get_inverted_colors (priv->model);
317 icon = ev_document_misc_get_loading_thumbnail (width, height, inverted_colors);
318 g_hash_table_insert (priv->loading_icons, key, icon);
327 clear_range (EvSidebarThumbnails *sidebar_thumbnails,
331 EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
335 gint prev_width = -1;
336 gint prev_height = -1;
338 g_assert (start_page <= end_page);
340 path = gtk_tree_path_new_from_indices (start_page, -1);
341 for (result = gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->list_store), &iter, path);
342 result && start_page <= end_page;
343 result = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->list_store), &iter), start_page ++) {
345 GdkPixbuf *loading_icon = NULL;
348 gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store),
354 g_signal_handlers_disconnect_by_func (job, thumbnail_job_completed_callback, sidebar_thumbnails);
355 ev_job_cancel (EV_JOB (job));
356 g_object_unref (job);
359 ev_thumbnails_size_cache_get_size (priv->size_cache, start_page,
362 if (!loading_icon || (width != prev_width && height != prev_height)) {
364 ev_sidebar_thumbnails_get_loading_icon (sidebar_thumbnails,
369 prev_height = height;
371 gtk_list_store_set (priv->list_store, &iter,
373 COLUMN_THUMBNAIL_SET, FALSE,
374 COLUMN_PIXBUF, loading_icon,
377 gtk_tree_path_free (path);
381 get_scale_for_page (EvSidebarThumbnails *sidebar_thumbnails,
384 EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
387 ev_document_get_page_size (priv->document, page, &width, NULL);
389 return (gdouble)THUMBNAIL_WIDTH / width;
393 add_range (EvSidebarThumbnails *sidebar_thumbnails,
397 EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
401 gint page = start_page;
403 g_assert (start_page <= end_page);
405 path = gtk_tree_path_new_from_indices (start_page, -1);
406 for (result = gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->list_store), &iter, path);
407 result && page <= end_page;
408 result = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->list_store), &iter), page ++) {
410 gboolean thumbnail_set;
412 gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store), &iter,
414 COLUMN_THUMBNAIL_SET, &thumbnail_set,
417 if (job == NULL && !thumbnail_set) {
418 job = ev_job_thumbnail_new (priv->document,
419 page, priv->rotation,
420 get_scale_for_page (sidebar_thumbnails, page));
421 ev_job_scheduler_push_job (EV_JOB (job), EV_JOB_PRIORITY_HIGH);
423 g_object_set_data_full (G_OBJECT (job), "tree_iter",
424 gtk_tree_iter_copy (&iter),
425 (GDestroyNotify) gtk_tree_iter_free);
426 g_signal_connect (job, "finished",
427 G_CALLBACK (thumbnail_job_completed_callback),
429 gtk_list_store_set (priv->list_store, &iter,
433 /* The queue and the list own a ref to the job now */
434 g_object_unref (job);
436 g_object_unref (job);
439 gtk_tree_path_free (path);
442 /* This modifies start */
444 update_visible_range (EvSidebarThumbnails *sidebar_thumbnails,
448 EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
449 int old_start_page, old_end_page;
451 old_start_page = priv->start_page;
452 old_end_page = priv->end_page;
454 if (start_page == old_start_page &&
455 end_page == old_end_page)
458 /* Clear the areas we no longer display */
459 if (old_start_page >= 0 && old_start_page < start_page)
460 clear_range (sidebar_thumbnails, old_start_page, MIN (start_page - 1, old_end_page));
462 if (old_end_page > 0 && old_end_page > end_page)
463 clear_range (sidebar_thumbnails, MAX (end_page + 1, old_start_page), old_end_page);
465 add_range (sidebar_thumbnails, start_page, end_page);
467 priv->start_page = start_page;
468 priv->end_page = end_page;
472 adjustment_changed_cb (EvSidebarThumbnails *sidebar_thumbnails)
474 EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
475 GtkTreePath *path = NULL;
476 GtkTreePath *path2 = NULL;
482 /* Widget is not currently visible */
483 if (!gtk_widget_get_mapped (GTK_WIDGET (sidebar_thumbnails)))
486 page_size = gtk_adjustment_get_page_size (priv->vadjustment);
491 value = gtk_adjustment_get_value (priv->vadjustment);
493 if (priv->tree_view) {
494 if (! gtk_widget_get_realized (priv->tree_view))
497 gtk_tree_view_convert_tree_to_bin_window_coords (GTK_TREE_VIEW (priv->tree_view),
500 gtk_tree_view_convert_tree_to_bin_window_coords (GTK_TREE_VIEW (priv->tree_view),
501 0, (int) (value + page_size),
503 gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (priv->tree_view),
506 gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (priv->tree_view),
509 } else if (priv->icon_view) {
510 if (! gtk_widget_get_realized (priv->icon_view))
512 if (! gtk_icon_view_get_visible_range (GTK_ICON_VIEW (priv->icon_view), &path, &path2))
519 update_visible_range (sidebar_thumbnails,
520 gtk_tree_path_get_indices (path)[0],
521 gtk_tree_path_get_indices (path2)[0]);
524 gtk_tree_path_free (path);
525 gtk_tree_path_free (path2);
529 ev_sidebar_thumbnails_fill_model (EvSidebarThumbnails *sidebar_thumbnails)
531 EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
534 gint prev_width = -1;
535 gint prev_height = -1;
537 for (i = 0; i < sidebar_thumbnails->priv->n_pages; i++) {
540 GdkPixbuf *loading_icon = NULL;
543 page_label = ev_document_get_page_label (priv->document, i);
544 page_string = g_markup_printf_escaped ("<i>%s</i>", page_label);
545 ev_thumbnails_size_cache_get_size (sidebar_thumbnails->priv->size_cache, i,
546 sidebar_thumbnails->priv->rotation,
548 if (!loading_icon || (width != prev_width && height != prev_height)) {
550 ev_sidebar_thumbnails_get_loading_icon (sidebar_thumbnails,
555 prev_height = height;
557 gtk_list_store_append (priv->list_store, &iter);
558 gtk_list_store_set (priv->list_store, &iter,
559 COLUMN_PAGE_STRING, page_string,
560 COLUMN_PIXBUF, loading_icon,
561 COLUMN_THUMBNAIL_SET, FALSE,
564 g_free (page_string);
569 ev_sidebar_tree_selection_changed (GtkTreeSelection *selection,
570 EvSidebarThumbnails *ev_sidebar_thumbnails)
572 EvSidebarThumbnailsPrivate *priv = ev_sidebar_thumbnails->priv;
577 if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
580 path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->list_store),
582 page = gtk_tree_path_get_indices (path)[0];
583 gtk_tree_path_free (path);
585 ev_document_model_set_page (priv->model, page);
589 ev_sidebar_icon_selection_changed (GtkIconView *icon_view,
590 EvSidebarThumbnails *ev_sidebar_thumbnails)
592 EvSidebarThumbnailsPrivate *priv = ev_sidebar_thumbnails->priv;
597 selected = gtk_icon_view_get_selected_items (icon_view);
598 if (selected == NULL)
601 /* We don't handle or expect multiple selection. */
602 g_assert (selected->next == NULL);
604 path = selected->data;
605 page = gtk_tree_path_get_indices (path)[0];
607 gtk_tree_path_free (path);
608 g_list_free (selected);
610 ev_document_model_set_page (priv->model, page);
614 ev_sidebar_init_tree_view (EvSidebarThumbnails *ev_sidebar_thumbnails)
616 EvSidebarThumbnailsPrivate *priv;
617 GtkTreeSelection *selection;
618 GtkCellRenderer *renderer;
620 priv = ev_sidebar_thumbnails->priv;
621 priv->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (priv->list_store));
623 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view));
624 g_signal_connect (selection, "changed",
625 G_CALLBACK (ev_sidebar_tree_selection_changed), ev_sidebar_thumbnails);
626 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE);
627 renderer = g_object_new (GTK_TYPE_CELL_RENDERER_PIXBUF,
631 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->tree_view), -1,
635 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->tree_view), -1,
636 NULL, gtk_cell_renderer_text_new (),
638 gtk_container_add (GTK_CONTAINER (priv->swindow), priv->tree_view);
639 gtk_widget_show (priv->tree_view);
643 ev_sidebar_init_icon_view (EvSidebarThumbnails *ev_sidebar_thumbnails)
645 EvSidebarThumbnailsPrivate *priv;
647 priv = ev_sidebar_thumbnails->priv;
649 priv->icon_view = gtk_icon_view_new_with_model (GTK_TREE_MODEL (priv->list_store));
650 gtk_icon_view_set_markup_column (GTK_ICON_VIEW (priv->icon_view), 0);
651 gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (priv->icon_view), 1);
652 g_signal_connect (priv->icon_view, "selection-changed",
653 G_CALLBACK (ev_sidebar_icon_selection_changed), ev_sidebar_thumbnails);
655 gtk_container_add (GTK_CONTAINER (priv->swindow), priv->icon_view);
656 gtk_widget_show (priv->icon_view);
660 ev_sidebar_thumbnails_use_icon_view (EvSidebarThumbnails *sidebar_thumbnails)
662 EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
664 return (ev_document_get_n_pages (priv->document) <= MAX_ICON_VIEW_PAGE_COUNT);
668 ev_sidebar_thumbnails_init (EvSidebarThumbnails *ev_sidebar_thumbnails)
670 EvSidebarThumbnailsPrivate *priv;
672 priv = ev_sidebar_thumbnails->priv = EV_SIDEBAR_THUMBNAILS_GET_PRIVATE (ev_sidebar_thumbnails);
674 priv->list_store = gtk_list_store_new (NUM_COLUMNS,
678 EV_TYPE_JOB_THUMBNAIL);
680 priv->swindow = gtk_scrolled_window_new (NULL, NULL);
682 /* We actually don't want GTK_POLICY_AUTOMATIC for horizontal scrollbar here
683 * it's just a workaround for bug #449462
685 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->swindow),
686 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
687 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->swindow),
689 priv->vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->swindow));
690 g_signal_connect_data (priv->vadjustment, "value-changed",
691 G_CALLBACK (adjustment_changed_cb),
692 ev_sidebar_thumbnails, NULL,
693 G_CONNECT_SWAPPED | G_CONNECT_AFTER);
694 g_signal_connect_swapped (priv->swindow, "size-allocate",
695 G_CALLBACK (adjustment_changed_cb),
696 ev_sidebar_thumbnails);
697 gtk_box_pack_start (GTK_BOX (ev_sidebar_thumbnails), priv->swindow, TRUE, TRUE, 0);
699 /* Put it all together */
700 gtk_widget_show_all (priv->swindow);
704 ev_sidebar_thumbnails_set_current_page (EvSidebarThumbnails *sidebar,
707 GtkTreeView *tree_view;
710 path = gtk_tree_path_new_from_indices (page, -1);
712 if (sidebar->priv->tree_view) {
713 tree_view = GTK_TREE_VIEW (sidebar->priv->tree_view);
714 gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
715 gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
716 } else if (sidebar->priv->icon_view) {
718 g_signal_handlers_block_by_func
719 (sidebar->priv->icon_view,
720 G_CALLBACK (ev_sidebar_icon_selection_changed), sidebar);
722 gtk_icon_view_select_path (GTK_ICON_VIEW (sidebar->priv->icon_view), path);
724 g_signal_handlers_unblock_by_func
725 (sidebar->priv->icon_view,
726 G_CALLBACK (ev_sidebar_icon_selection_changed), sidebar);
728 gtk_icon_view_set_cursor (GTK_ICON_VIEW (sidebar->priv->icon_view), path, NULL, FALSE);
731 gtk_tree_path_free (path);
735 page_changed_cb (EvSidebarThumbnails *sidebar,
739 ev_sidebar_thumbnails_set_current_page (sidebar, new_page);
743 refresh (EvSidebarThumbnails *sidebar_thumbnails)
745 adjustment_changed_cb (sidebar_thumbnails);
750 ev_sidebar_thumbnails_reload (EvSidebarThumbnails *sidebar_thumbnails)
752 EvDocumentModel *model;
754 if (sidebar_thumbnails->priv->loading_icons)
755 g_hash_table_remove_all (sidebar_thumbnails->priv->loading_icons);
757 if (sidebar_thumbnails->priv->document == NULL ||
758 sidebar_thumbnails->priv->n_pages <= 0)
761 model = sidebar_thumbnails->priv->model;
763 ev_sidebar_thumbnails_clear_model (sidebar_thumbnails);
764 ev_sidebar_thumbnails_fill_model (sidebar_thumbnails);
766 /* Trigger a redraw */
767 sidebar_thumbnails->priv->start_page = -1;
768 sidebar_thumbnails->priv->end_page = -1;
769 ev_sidebar_thumbnails_set_current_page (sidebar_thumbnails,
770 ev_document_model_get_page (model));
771 g_idle_add ((GSourceFunc)refresh, sidebar_thumbnails);
775 ev_sidebar_thumbnails_rotation_changed_cb (EvDocumentModel *model,
777 EvSidebarThumbnails *sidebar_thumbnails)
779 gint rotation = ev_document_model_get_rotation (model);
781 sidebar_thumbnails->priv->rotation = rotation;
782 ev_sidebar_thumbnails_reload (sidebar_thumbnails);
786 ev_sidebar_thumbnails_inverted_colors_changed_cb (EvDocumentModel *model,
788 EvSidebarThumbnails *sidebar_thumbnails)
790 gboolean inverted_colors = ev_document_model_get_inverted_colors (model);
792 sidebar_thumbnails->priv->inverted_colors = inverted_colors;
793 ev_sidebar_thumbnails_reload (sidebar_thumbnails);
797 thumbnail_job_completed_callback (EvJobThumbnail *job,
798 EvSidebarThumbnails *sidebar_thumbnails)
800 EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
803 iter = (GtkTreeIter *) g_object_get_data (G_OBJECT (job), "tree_iter");
804 if (priv->inverted_colors)
805 ev_document_misc_invert_pixbuf (job->thumbnail);
806 gtk_list_store_set (priv->list_store,
808 COLUMN_PIXBUF, job->thumbnail,
809 COLUMN_THUMBNAIL_SET, TRUE,
815 ev_sidebar_thumbnails_document_changed_cb (EvDocumentModel *model,
817 EvSidebarThumbnails *sidebar_thumbnails)
819 EvDocument *document = ev_document_model_get_document (model);
820 EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
822 if (ev_document_get_n_pages (document) <= 0 ||
823 !ev_document_check_dimensions (document)) {
827 priv->size_cache = ev_thumbnails_size_cache_get (document);
828 priv->document = document;
829 priv->n_pages = ev_document_get_n_pages (document);
830 priv->rotation = ev_document_model_get_rotation (model);
831 priv->inverted_colors = ev_document_model_get_inverted_colors (model);
832 priv->loading_icons = g_hash_table_new_full (g_str_hash,
834 (GDestroyNotify)g_free,
835 (GDestroyNotify)g_object_unref);
837 ev_sidebar_thumbnails_clear_model (sidebar_thumbnails);
838 ev_sidebar_thumbnails_fill_model (sidebar_thumbnails);
840 /* Create the view widget, and remove the old one, if needed */
841 if (ev_sidebar_thumbnails_use_icon_view (sidebar_thumbnails)) {
842 if (priv->tree_view) {
843 gtk_container_remove (GTK_CONTAINER (priv->swindow), priv->tree_view);
844 priv->tree_view = NULL;
847 if (! priv->icon_view) {
848 ev_sidebar_init_icon_view (sidebar_thumbnails);
849 g_object_notify (G_OBJECT (sidebar_thumbnails), "main_widget");
851 gtk_widget_queue_resize (priv->icon_view);
854 if (priv->icon_view) {
855 gtk_container_remove (GTK_CONTAINER (priv->swindow), priv->icon_view);
856 priv->icon_view = NULL;
859 if (! priv->tree_view) {
860 ev_sidebar_init_tree_view (sidebar_thumbnails);
861 g_object_notify (G_OBJECT (sidebar_thumbnails), "main_widget");
865 /* Connect to the signal and trigger a fake callback */
866 g_signal_connect_swapped (priv->model, "page-changed",
867 G_CALLBACK (page_changed_cb),
869 g_signal_connect (priv->model, "notify::rotation",
870 G_CALLBACK (ev_sidebar_thumbnails_rotation_changed_cb),
872 g_signal_connect (priv->model, "notify::inverted-colors",
873 G_CALLBACK (ev_sidebar_thumbnails_inverted_colors_changed_cb),
875 sidebar_thumbnails->priv->start_page = -1;
876 sidebar_thumbnails->priv->end_page = -1;
877 ev_sidebar_thumbnails_set_current_page (sidebar_thumbnails,
878 ev_document_model_get_page (model));
879 adjustment_changed_cb (sidebar_thumbnails);
883 ev_sidebar_thumbnails_set_model (EvSidebarPage *sidebar_page,
884 EvDocumentModel *model)
886 EvSidebarThumbnails *sidebar_thumbnails = EV_SIDEBAR_THUMBNAILS (sidebar_page);
887 EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
889 if (priv->model == model)
893 g_signal_connect (model, "notify::document",
894 G_CALLBACK (ev_sidebar_thumbnails_document_changed_cb),
899 ev_sidebar_thumbnails_clear_job (GtkTreeModel *model,
906 gtk_tree_model_get (model, iter, COLUMN_JOB, &job, -1);
910 g_signal_handlers_disconnect_by_func (job, thumbnail_job_completed_callback, data);
911 g_object_unref (job);
918 ev_sidebar_thumbnails_clear_model (EvSidebarThumbnails *sidebar_thumbnails)
920 EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
922 gtk_tree_model_foreach (GTK_TREE_MODEL (priv->list_store), ev_sidebar_thumbnails_clear_job, sidebar_thumbnails);
923 gtk_list_store_clear (priv->list_store);
927 ev_sidebar_thumbnails_support_document (EvSidebarPage *sidebar_page,
928 EvDocument *document)
934 ev_sidebar_thumbnails_get_label (EvSidebarPage *sidebar_page)
936 return _("Thumbnails");
940 ev_sidebar_thumbnails_page_iface_init (EvSidebarPageInterface *iface)
942 iface->support_document = ev_sidebar_thumbnails_support_document;
943 iface->set_model = ev_sidebar_thumbnails_set_model;
944 iface->get_label = ev_sidebar_thumbnails_get_label;