]> www.fi.muni.cz Git - evince.git/blob - shell/ev-sidebar-thumbnails.c
fill in the thumbnail with white. New interface to get the size of a page.
[evince.git] / shell / ev-sidebar-thumbnails.c
1 /* this file is part of evince, a gnome document viewer
2  *
3  *  Copyright (C) 2004 Red Hat, Inc.
4  *  Copyright (C) 2004 Anders Carlsson <andersca@gnome.org>
5  *
6  *  Authors:
7  *    Jonathan Blandford <jrb@alum.mit.edu>
8  *    Anders Carlsson <andersca@gnome.org>
9  *
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.
14  *
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.
19  *
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <string.h>
30 #include <gtk/gtk.h>
31
32 #include "ev-sidebar-thumbnails.h"
33 #include "ev-document-thumbnails.h"
34 #include "ev-document-misc.h"
35 #include "ev-utils.h"
36
37 #define THUMBNAIL_WIDTH 75
38 /* Amount of time we devote to each iteration of the idle, in microseconds */
39 #define IDLE_WORK_LENGTH 5000
40
41 struct _EvSidebarThumbnailsPrivate {
42         GtkWidget *tree_view;
43         GtkListStore *list_store;
44         EvDocument *document;
45         
46         guint idle_id;
47         gint current_page, n_pages;
48 };
49
50 enum {
51         COLUMN_PAGE_STRING,
52         COLUMN_PIXBUF,
53         NUM_COLUMNS
54 };
55
56 static GtkVBoxClass *parent_class;
57
58 G_DEFINE_TYPE (EvSidebarThumbnails, ev_sidebar_thumbnails, GTK_TYPE_VBOX);
59
60 #define EV_SIDEBAR_THUMBNAILS_GET_PRIVATE(object) \
61         (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR_THUMBNAILS, EvSidebarThumbnailsPrivate));
62
63 static void
64 ev_sidebar_thumbnails_destroy (GtkObject *object)
65 {
66         EvSidebarThumbnails *ev_sidebar_thumbnails = EV_SIDEBAR_THUMBNAILS (object);
67         EvSidebarThumbnailsPrivate *priv = ev_sidebar_thumbnails->priv;
68         
69         if (priv->idle_id != 0) {
70                 g_source_remove (priv->idle_id);
71
72                 priv->idle_id = 0;
73         }
74         
75         GTK_OBJECT_CLASS (parent_class)->destroy (object);
76 }
77
78 static void
79 ev_sidebar_thumbnails_class_init (EvSidebarThumbnailsClass *ev_sidebar_thumbnails_class)
80 {
81         GObjectClass *g_object_class;
82         GtkObjectClass *gtk_object_class;
83         
84         g_object_class = G_OBJECT_CLASS (ev_sidebar_thumbnails_class);
85         gtk_object_class = GTK_OBJECT_CLASS (ev_sidebar_thumbnails_class);
86
87         parent_class = g_type_class_peek_parent (ev_sidebar_thumbnails_class);
88         
89         gtk_object_class->destroy = ev_sidebar_thumbnails_destroy;
90         
91         g_type_class_add_private (g_object_class, sizeof (EvSidebarThumbnailsPrivate));
92
93 }
94
95 static void
96 ev_sidebar_thumbnails_init (EvSidebarThumbnails *ev_sidebar_thumbnails)
97 {
98         GtkWidget *swindow;
99         EvSidebarThumbnailsPrivate *priv;
100         GtkCellRenderer *renderer;
101
102         priv = ev_sidebar_thumbnails->priv = EV_SIDEBAR_THUMBNAILS_GET_PRIVATE (ev_sidebar_thumbnails);
103
104         priv->list_store = gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING, GDK_TYPE_PIXBUF);
105         priv->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (priv->list_store));
106
107         gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE);
108         renderer = g_object_new (GTK_TYPE_CELL_RENDERER_PIXBUF,
109                                  "xpad", 2,
110                                  "ypad", 2,
111                                  NULL);
112         gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->tree_view), -1,
113                                                      NULL, renderer,
114                                                      "pixbuf", 1,
115                                                      NULL);
116         gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->tree_view), -1,
117                                                      NULL, gtk_cell_renderer_text_new (),
118                                                      "markup", 0, NULL);
119         
120         g_object_unref (priv->list_store);
121
122         swindow = gtk_scrolled_window_new (NULL, NULL);
123         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
124                                         GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
125         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow),
126                                              GTK_SHADOW_IN);
127
128         gtk_container_add (GTK_CONTAINER (swindow), priv->tree_view);
129         gtk_box_pack_start (GTK_BOX (ev_sidebar_thumbnails), swindow, TRUE, TRUE, 0);
130         
131         gtk_widget_show_all (swindow);
132 }
133
134 GtkWidget *
135 ev_sidebar_thumbnails_new (void)
136 {
137         GtkWidget *ev_sidebar_thumbnails;
138
139         ev_sidebar_thumbnails = g_object_new (EV_TYPE_SIDEBAR_THUMBNAILS, NULL);
140
141         return ev_sidebar_thumbnails;
142 }
143
144 static gboolean
145 do_one_iteration (EvSidebarThumbnails *ev_sidebar_thumbnails)
146 {
147         EvSidebarThumbnailsPrivate *priv = ev_sidebar_thumbnails->priv;
148         GdkPixbuf *pixbuf;
149         GtkTreePath *path;
150         GtkTreeIter iter;
151
152         pixbuf = ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (priv->document),
153                                                        priv->current_page, THUMBNAIL_WIDTH);
154
155         path = gtk_tree_path_new_from_indices (priv->current_page, -1);
156         gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->list_store), &iter, path);
157         gtk_tree_path_free (path);
158
159         gtk_list_store_set (priv->list_store, &iter,
160                             COLUMN_PIXBUF, pixbuf,
161                             -1);
162
163         g_object_unref (pixbuf);
164         
165         priv->current_page++;
166         
167         if (priv->current_page == priv->n_pages)
168                 return FALSE;
169         else
170                 return TRUE;
171 }
172
173 static gboolean
174 populate_thumbnails_idle (gpointer data)
175 {
176         GTimer *timer;
177         int i;
178         gdouble time_elapsed = 0;
179
180         EvSidebarThumbnails *ev_sidebar_thumbnails = EV_SIDEBAR_THUMBNAILS (data);
181         EvSidebarThumbnailsPrivate *priv = ev_sidebar_thumbnails->priv;
182
183
184 #if PROFILE_THUMB == 1
185         static GTimer *total_timer;
186         static gboolean first_time = TRUE;
187
188         if (first_time) {
189                 total_timer = g_timer_new ();
190                 first_time = FALSE;
191                 g_timer_start (total_timer);
192         }
193 #endif
194
195         if (priv->current_page == priv->n_pages) {
196                 priv->idle_id = 0;
197 #if PROFILE_THUMB == 1
198                 time_elapsed = g_timer_elapsed (total_timer, NULL);
199                 g_timer_destroy (total_timer);
200                 g_print ("%d rows done in %f seconds\n",
201                          gtk_tree_model_iter_n_children (GTK_TREE_MODEL (priv->list_store), NULL),
202                          time_elapsed);
203 #endif
204                 return FALSE;
205         }
206
207         timer = g_timer_new ();
208         i = 0;
209         g_timer_start (timer);
210         while (do_one_iteration (ev_sidebar_thumbnails)) {
211                 i++;
212                 time_elapsed = g_timer_elapsed (timer, NULL);
213                 if (time_elapsed > IDLE_WORK_LENGTH/1000000)
214                         break;
215         }
216         g_timer_destroy (timer);
217 #if PROFILE_THUMB == 2
218         g_print ("%d rows done this idle in %f seconds\n", i, time_elapsed);
219 #endif
220
221         return TRUE;
222 }
223
224 void
225 ev_sidebar_thumbnails_set_document (EvSidebarThumbnails *sidebar_thumbnails,
226                                     EvDocument          *document)
227 {
228         GdkPixbuf *loading_icon;
229         gint i, n_pages;
230         GtkTreeIter iter;
231         gchar *page;
232         gint width = THUMBNAIL_WIDTH;
233         gint height = THUMBNAIL_WIDTH;
234
235         EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
236         
237         g_return_if_fail (EV_IS_DOCUMENT_THUMBNAILS (document));
238
239         if (priv->idle_id != 0) {
240                 g_source_remove (priv->idle_id);
241         }
242         n_pages = ev_document_get_n_pages (document);
243
244         priv->document = document;
245         priv->idle_id = g_idle_add (populate_thumbnails_idle, sidebar_thumbnails);
246         priv->n_pages = n_pages;
247         priv->current_page = 0;
248
249         /* We get the dimensions of the first doc so that   */
250         ev_document_thumbnails_get_dimensions (EV_DOCUMENT_THUMBNAILS (priv->document),
251                                                0, THUMBNAIL_WIDTH, &width, &height);
252         loading_icon = ev_document_misc_get_thumbnail_frame (width, height, NULL);
253
254         for (i = 0; i < n_pages; i++) {
255                 page = g_strdup_printf ("<i>%d</i>", i + 1);
256                 gtk_list_store_append (priv->list_store, &iter);
257                 gtk_list_store_set (priv->list_store, &iter,
258                                     COLUMN_PAGE_STRING, page,
259                                     COLUMN_PIXBUF, loading_icon,
260                                     -1);
261                 g_free (page);
262         }
263
264 }
265