]> www.fi.muni.cz Git - evince.git/blob - backend/ev-page-cache.c
Set current page to 0 if document has pages
[evince.git] / backend / ev-page-cache.c
1 #include "ev-page-cache.h"
2 #include "ev-job-queue.h"
3 #include <stdlib.h>
4 #include <string.h>
5
6 typedef struct _EvPageCacheInfo
7 {
8         double width;
9         double height;
10 }
11 EvPageCacheInfo;
12
13
14 struct _EvPageCache
15 {
16         GObject parent;
17
18         gint current_page;
19         int n_pages;
20         char *title;
21         char **page_labels;
22
23         gboolean uniform;
24         double uniform_width;
25         double uniform_height;
26
27         EvPageCacheInfo *size_cache;
28 };
29
30 struct _EvPageCacheClass
31 {
32         GObjectClass parent_class;
33
34         void (* page_changed) (EvPageCache *page_cache, gint page);
35 };
36
37 enum
38 {
39         PAGE_CHANGED,
40         N_SIGNALS,
41 };
42
43 static guint signals[N_SIGNALS] = {0, };
44
45 static void ev_page_cache_init       (EvPageCache      *page_cache);
46 static void ev_page_cache_class_init (EvPageCacheClass *page_cache);
47 static void ev_page_cache_finalize   (GObject *object);
48
49 G_DEFINE_TYPE (EvPageCache, ev_page_cache, G_TYPE_OBJECT)
50
51 static void
52 ev_page_cache_init (EvPageCache *page_cache)
53 {
54         page_cache->current_page = -1;
55 }
56
57 static void
58 ev_page_cache_class_init (EvPageCacheClass *class)
59 {
60         GObjectClass *object_class;
61
62         object_class = G_OBJECT_CLASS (class);
63
64         object_class->finalize = ev_page_cache_finalize;
65
66         signals [PAGE_CHANGED] =
67                 g_signal_new ("page-changed",
68                               EV_TYPE_PAGE_CACHE,
69                               G_SIGNAL_RUN_LAST,
70                               G_STRUCT_OFFSET (EvPageCacheClass, page_changed),
71                               NULL, NULL,
72                               g_cclosure_marshal_VOID__INT,
73                               G_TYPE_NONE, 1,
74                               G_TYPE_INT);
75
76 }
77
78 static void
79 ev_page_cache_finalize (GObject *object)
80 {
81         EvPageCache *page_cache;
82
83         page_cache = EV_PAGE_CACHE (object);
84
85         g_free (page_cache->title);
86         g_free (page_cache->size_cache);
87 }
88
89 EvPageCache *
90 _ev_page_cache_new (EvDocument *document)
91 {
92         EvPageCache *page_cache;
93         EvPageCacheInfo *info;
94         gint i;
95
96         page_cache = (EvPageCache *) g_object_new (EV_TYPE_PAGE_CACHE, NULL);
97
98         g_mutex_lock (EV_DOC_MUTEX);
99
100         /* We read page information out of the document */
101
102         /* Assume all pages are the same size until proven otherwise */
103         page_cache->uniform = TRUE;
104         page_cache->n_pages = ev_document_get_n_pages (document);
105         page_cache->title = ev_document_get_title (document);
106         page_cache->page_labels = g_new0 (char *, page_cache->n_pages);
107
108         for (i = 0; i < page_cache->n_pages; i++) {
109                 double page_width = 0;
110                 double page_height = 0;
111
112                 ev_document_get_page_size (document, i, &page_width, &page_height);
113                 page_cache->page_labels[i] = ev_document_get_page_label (document, i);
114
115                 if (i == 0) {
116                         page_cache->uniform_width = page_width;
117                         page_cache->uniform_height = page_height;
118                 } else if (page_cache->uniform &&
119                            (page_cache->uniform_width != page_width ||
120                             page_cache->uniform_height != page_height)) {
121                         /* It's a different page size.  Backfill the array. */
122                         int j;
123
124                         page_cache->size_cache = g_new0 (EvPageCacheInfo, page_cache->n_pages);
125
126                         for (j = 0; j < i; j++) {
127                                 info = &(page_cache->size_cache [j]);
128                                 info->width = page_cache->uniform_width;
129                                 info->height = page_cache->uniform_height;
130                         }
131                         page_cache->uniform = FALSE;
132
133                 }
134
135                 if (! page_cache->uniform) {
136                         info = &(page_cache->size_cache [i]);
137
138                         info->width = page_width;
139                         info->height = page_height;
140                 }
141         }
142
143         /* make some sanity check assertions */
144         if (! page_cache->uniform)
145                 g_assert (page_cache->size_cache != NULL);
146
147         g_mutex_unlock (EV_DOC_MUTEX);
148
149         if (page_cache->n_pages > 0)
150                 ev_page_cache_set_current_page (page_cache, 0);
151
152         return page_cache;
153 }
154
155 gint
156 ev_page_cache_get_n_pages (EvPageCache *page_cache)
157 {
158         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0);
159
160         return page_cache->n_pages;
161 }
162
163 gint
164 ev_page_cache_get_current_page (EvPageCache *page_cache)
165 {
166         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0);
167
168         return page_cache->current_page;
169 }
170
171 void
172 ev_page_cache_set_current_page (EvPageCache *page_cache,
173                                 int          page)
174 {
175         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
176         g_return_if_fail (page >= 0 || page < page_cache->n_pages);
177
178         if (page == page_cache->current_page)
179                 return;
180
181         page_cache->current_page = page;
182         g_signal_emit (page_cache, signals[PAGE_CHANGED], 0, page);
183 }
184
185 gboolean
186 ev_page_cache_set_page_label (EvPageCache *page_cache,
187                               const char  *page_label)
188 {
189         gint i, page;
190         long value;
191         char *endptr = NULL;
192         
193         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE);
194         g_return_val_if_fail (page_label != NULL, FALSE);
195
196         /* First, look for a literal label match */
197         for (i = 0; i < page_cache->n_pages; i ++) {
198                 if (page_cache->page_labels[i] != NULL &&
199                     ! strcmp (page_label, page_cache->page_labels[i])) {
200                         ev_page_cache_set_current_page (page_cache, i);
201                         return TRUE;
202                 }
203         }
204
205         /* Next, parse the label, and see if the number fits */
206         value = strtol (page_label, &endptr, 10);
207         if (endptr[0] == '\0') {
208                 /* Page number is an integer */
209                 page = MIN (G_MAXINT, value);
210
211                 /* convert from a page label to a page offset */
212                 page --;
213                 if (page >= 0 &&
214                     page < page_cache->n_pages &&
215                     page_cache->page_labels[page] == NULL) {
216                         ev_page_cache_set_current_page (page_cache, page);
217                         return TRUE;
218                 }
219         }
220
221         return FALSE;
222 }
223
224 void
225 ev_page_cache_set_link (EvPageCache *page_cache,
226                         EvLink      *link)
227 {
228         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
229         g_return_if_fail (EV_IS_LINK (link));
230
231         ev_page_cache_set_current_page (page_cache, ev_link_get_page (link));
232 }
233
234 char *
235 ev_page_cache_get_title (EvPageCache *page_cache)
236 {
237         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), NULL);
238
239         return page_cache->title;
240 }
241
242 void
243 ev_page_cache_get_size (EvPageCache *page_cache,
244                         gint         page,
245                         gfloat       scale,
246                         gint        *width,
247                         gint        *height)
248 {
249         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
250         g_return_if_fail (page >= 0 && page < page_cache->n_pages);
251
252         if (page_cache->uniform) {
253                 if (width)
254                         *width = page_cache->uniform_width;
255                 if (height)
256                         *height = page_cache->uniform_height;
257         } else {
258                 EvPageCacheInfo *info;
259
260                 info = &(page_cache->size_cache [page]);
261                 
262                 if (width)
263                         *width = info->width;
264                 if (height)
265                         *height = info->height;
266         }
267
268         if (width)
269                 *width = (*width) * scale;
270         if (width)
271                 *height = (*height) * scale;
272
273 }
274 gchar *
275 ev_page_cache_get_page_label (EvPageCache *page_cache,
276                               gint         page)
277 {
278         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), NULL);
279         g_return_val_if_fail (page >= 0 && page < page_cache->n_pages, NULL);
280
281         if (page_cache->page_labels[page] == NULL)
282                 return g_strdup_printf ("%d", page + 1);
283
284         return g_strdup (page_cache->page_labels[page]);
285 }
286
287
288 gboolean
289 ev_page_cache_next_page (EvPageCache *page_cache)
290 {
291         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE);
292
293         if (page_cache->current_page >= page_cache->n_pages - 1)
294                 return FALSE;
295
296         ev_page_cache_set_current_page (page_cache, page_cache->current_page + 1);
297         return TRUE;
298
299 }
300
301 gboolean
302 ev_page_cache_prev_page (EvPageCache *page_cache)
303 {
304         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE);
305
306         if (page_cache->current_page <= 0)
307                 return FALSE;
308
309         ev_page_cache_set_current_page (page_cache, page_cache->current_page - 1);
310         return TRUE;
311 }
312