]> www.fi.muni.cz Git - evince.git/blob - backend/ev-document-factory.c
Make pdf compilation optional. See bug #38007.
[evince.git] / backend / ev-document-factory.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /*
3  *  Copyright (C) 2005, Red Hat, Inc. 
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "ev-document-factory.h"
26
27 /* The various document type backends: */
28 #include "ev-poppler.h"
29
30 #ifdef ENABLE_PS
31 #include "ps-document.h"
32 #endif
33 #ifdef ENABLE_TIFF
34 #include "tiff-document.h"
35 #endif
36 #ifdef ENABLE_DVI
37 #include "dvi-document.h"
38 #endif
39 #ifdef ENABLE_PIXBUF
40 #include "pixbuf-document.h"
41 #endif
42 #ifdef ENABLE_DJVU
43 #include "djvu-document.h"
44 #endif
45 #ifdef ENABLE_COMICS
46 #include "comics-document.h"
47 #endif
48 #ifdef ENABLE_IMPRESS
49 #include "impress-document.h"
50 #endif
51
52 #include <string.h>
53 #include <glib/gi18n.h>
54 #include <libgnomevfs/gnome-vfs-mime-utils.h>
55 #include <libgnomevfs/gnome-vfs-file-info.h>
56 #include <libgnomevfs/gnome-vfs-ops.h>
57 #include <gtk/gtkfilechooserdialog.h>
58
59 typedef struct _EvDocumentType EvDocumentType;
60 struct _EvDocumentType
61 {
62         const char *mime_type;
63         EvBackend backend;
64         GType (*document_type_factory_callback)();
65 };
66
67 const EvDocumentType document_types[] = {
68 #ifdef ENABLE_PDF
69         /* PDF: */
70         {"application/pdf",            EV_BACKEND_PDF,  pdf_document_get_type},
71 #endif
72
73 #ifdef ENABLE_PS
74         /* Postscript: */
75         {"application/postscript",     EV_BACKEND_PS,   ps_document_get_type},
76         {"application/x-gzpostscript", EV_BACKEND_PS,   ps_document_get_type},
77         {"image/x-eps",                EV_BACKEND_PS,   ps_document_get_type},
78 #endif
79
80 #ifdef ENABLE_TIFF
81         /* Tiff: */
82         {"image/tiff",                 EV_BACKEND_TIFF, tiff_document_get_type},
83 #endif
84
85 #ifdef ENABLE_DJVU
86         /* djvu: */
87         {"image/vnd.djvu",             EV_BACKEND_DJVU, djvu_document_get_type},
88 #endif          
89
90 #ifdef ENABLE_DVI
91         /* dvi: */
92         {"application/x-dvi",          EV_BACKEND_DVI,  dvi_document_get_type},
93 #endif
94
95 #ifdef ENABLE_COMICS
96         /* cbr/cbz: */
97         {"application/x-cbr",           EV_BACKEND_COMICS,  comics_document_get_type},
98         {"application/x-cbz",           EV_BACKEND_COMICS,  comics_document_get_type},
99 #endif
100
101 #ifdef ENABLE_IMPRESS
102         /* Impress slides: */
103         {"application/vnd.sun.xml.impress", EV_BACKEND_IMPRESS, impress_document_get_type},
104         {"application/vnd.oasis.opendocument.presentation", EV_BACKEND_IMPRESS, impress_document_get_type},
105 #endif
106
107 };
108
109 #ifdef ENABLE_PIXBUF
110
111 static GList*
112 gdk_pixbuf_mime_type_list ()
113 {
114         GSList *formats, *list;
115         GList *result;
116
117         formats = gdk_pixbuf_get_formats ();
118         result = NULL;
119
120         for (list = formats; list != NULL; list = list->next) {
121                 GdkPixbufFormat *format = list->data;
122                 int i;
123                 gchar **mime_types;
124
125                 if (gdk_pixbuf_format_is_disabled (format))
126                         continue;
127
128                 mime_types = gdk_pixbuf_format_get_mime_types (format);
129
130                 for (i = 0; mime_types[i] != NULL; i++) {
131                         result = g_list_append (result, mime_types[i]);
132                 }
133         }
134         g_slist_free (formats);
135
136         return result;
137 }
138
139 /* Would be nice to have this in gdk-pixbuf */
140 static gboolean
141 mime_type_supported_by_gdk_pixbuf (const gchar *mime_type)
142 {
143         GList *mime_types;
144         GList *list;
145         gboolean retval = FALSE;
146         
147         mime_types = gdk_pixbuf_mime_type_list ();
148         for (list = mime_types; list; list = list->next) {
149                 if (strcmp ((char *)list->data, mime_type) == 0) {
150                         retval = TRUE;
151                         break;
152                 }
153         }
154         
155         g_list_foreach (mime_types, (GFunc)g_free, NULL);
156         g_list_free (mime_types);
157
158         return retval;
159 }
160 #endif
161
162 static EvDocument*
163 ev_document_factory_get_from_mime (const char *mime_type)
164 {
165         int i;
166         GType type = G_TYPE_INVALID;
167         EvDocument *document = NULL;
168         
169         g_return_val_if_fail (mime_type, G_TYPE_INVALID);
170
171         for (i = 0; i < G_N_ELEMENTS (document_types); i++) {
172                 if (strcmp (mime_type, document_types[i].mime_type) == 0) {
173                         g_assert (document_types[i].document_type_factory_callback != NULL);
174                         type = document_types[i].document_type_factory_callback();
175                         break;
176                 }
177         }
178 #ifdef ENABLE_PIXBUF
179         if (type == G_TYPE_INVALID && mime_type_supported_by_gdk_pixbuf (mime_type)) {
180                 type = pixbuf_document_get_type ();
181         }
182 #endif
183         if (type != G_TYPE_INVALID) {
184                 document = g_object_new (type, NULL);
185         } 
186
187         return document;
188 }
189
190 EvBackend
191 ev_document_factory_get_backend (EvDocument *document)
192 {
193         int i;
194
195         for (i = 0; i < G_N_ELEMENTS (document_types); i++) {
196                 GType type = document_types[i].document_type_factory_callback ();
197                 if (type == G_TYPE_FROM_INSTANCE (document)) {
198                         return  document_types[i].backend;
199                 }
200         }
201
202 #ifdef ENABLE_PIXBUF
203         if (G_TYPE_FROM_INSTANCE (document) == pixbuf_document_get_type ())
204                 return EV_BACKEND_PIXBUF;
205 #endif
206         g_assert_not_reached ();
207         
208         return 0;
209 }
210
211 static GList *
212 ev_document_factory_get_mime_types (EvBackend backend)
213 {
214         GList *types = NULL;
215         int i;
216         
217 #ifdef ENABLE_PIXBUF
218         if (backend == EV_BACKEND_PIXBUF) {
219                 return gdk_pixbuf_mime_type_list ();
220         }
221 #endif
222         
223         for (i = 0; i < G_N_ELEMENTS (document_types); i++) {
224                 if (document_types[i].backend == backend) {
225                         types = g_list_append (types, g_strdup (document_types[i].mime_type));
226                 }
227         }
228
229         return types;
230 }
231
232 static GList *
233 ev_document_factory_get_all_mime_types (void)
234 {
235         GList *types = NULL;
236         int i;
237         
238         for (i = 0; i < G_N_ELEMENTS (document_types); i++) {
239                 types = g_list_append (types, g_strdup (document_types[i].mime_type));
240         }
241         
242 #ifdef ENABLE_PIXBUF
243         types = g_list_concat (types, gdk_pixbuf_mime_type_list ());
244 #endif
245
246         return types;
247 }
248
249 static EvDocument *
250 get_document_from_uri (const char *uri, gboolean slow, GError **error)
251 {
252         EvDocument *document = NULL;
253
254         GnomeVFSFileInfo *info;
255         GnomeVFSResult result;
256
257         info = gnome_vfs_file_info_new ();
258         result = gnome_vfs_get_file_info (uri, info,
259                                           GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
260                                           GNOME_VFS_FILE_INFO_FOLLOW_LINKS | 
261                                           (slow ? GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE : 0));
262         if (result != GNOME_VFS_OK) {
263                 g_set_error (error,
264                              EV_DOCUMENT_ERROR,
265                              0,
266                              gnome_vfs_result_to_string (result));                      
267                 gnome_vfs_file_info_unref (info);
268                 return NULL;
269         } 
270         
271         if (info->mime_type == NULL) {
272                 g_set_error (error,
273                              EV_DOCUMENT_ERROR, 
274                              0,
275                              _("Unknown MIME Type"));
276                 gnome_vfs_file_info_unref (info);
277                 return NULL;
278         }
279
280         document = ev_document_factory_get_from_mime (info->mime_type);
281                 
282         if (document == NULL) {
283                 g_set_error (error,
284                              EV_DOCUMENT_ERROR, 
285                              0,
286                              _("Unhandled MIME type: ā€œ%sā€"), info->mime_type);
287                 gnome_vfs_file_info_unref (info);
288                 return NULL;
289         }                       
290
291         gnome_vfs_file_info_unref (info);
292         
293         return document;
294 }
295
296 EvDocument *
297 ev_document_factory_get_document (const char *uri, GError **error)
298 {
299         EvDocument *document;
300         int result;
301
302         document = get_document_from_uri (uri, FALSE, error);
303
304         if (*error == NULL) {
305                 result = ev_document_load (document, uri, error);
306
307                 if (result == FALSE || *error) {
308                         if (*error &&
309                             (*error)->domain == EV_DOCUMENT_ERROR &&
310                             (*error)->code == EV_DOCUMENT_ERROR_ENCRYPTED)
311                                 return document;
312                 } else {
313                         return document;
314                 }
315         }
316         
317         /* Try again with slow mime detection */
318         if (document)
319                 g_object_unref (document);
320         document = NULL;
321
322         if (*error)
323                 g_error_free (*error);
324         *error = NULL;
325
326         document = get_document_from_uri (uri, TRUE, error);
327
328         if (*error != NULL) {
329                 return NULL;
330         }
331
332         result = ev_document_load (document, uri, error);
333
334         if (result == FALSE) {
335                 if (*error == NULL) {
336                         g_set_error (error,
337                                      EV_DOCUMENT_ERROR,
338                                      0,
339                                      _("Unknown MIME Type"));
340                 } else if ((*error)->domain == EV_DOCUMENT_ERROR &&
341                            (*error)->code == EV_DOCUMENT_ERROR_ENCRYPTED) {
342                         return document;
343                 }
344
345                 if (document)
346                         g_object_unref (document);
347                 document = NULL;
348         }
349         
350         return document;
351 }
352
353 static void
354 file_filter_add_mime_list_and_free (GtkFileFilter *filter, GList *mime_types)
355 {
356         GList *l;
357
358         for (l = mime_types; l != NULL; l = l->next) {
359                 gtk_file_filter_add_mime_type (filter, l->data);
360         }
361
362         g_list_foreach (mime_types, (GFunc)g_free, NULL);
363         g_list_free (mime_types);
364 }
365
366 void 
367 ev_document_factory_add_filters (GtkWidget *chooser, EvDocument *document)
368 {
369         EvBackend backend = 0;
370         GList *mime_types;
371         GtkFileFilter *filter;
372         GtkFileFilter *default_filter;
373         GtkFileFilter *document_filter;
374
375         if (document != NULL) {
376                 backend = ev_document_factory_get_backend (document);
377         }
378
379         default_filter = document_filter = filter = gtk_file_filter_new ();
380         gtk_file_filter_set_name (filter, _("All Documents"));
381         mime_types = ev_document_factory_get_all_mime_types ();
382         file_filter_add_mime_list_and_free (filter, mime_types);
383         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
384
385 #ifdef ENABLE_PS
386         if (document == NULL || backend == EV_BACKEND_PS) {
387                 default_filter = filter = gtk_file_filter_new ();
388                 gtk_file_filter_set_name (filter, _("PostScript Documents"));
389                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_PS);
390                 file_filter_add_mime_list_and_free (filter, mime_types);
391                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
392         }
393 #endif
394
395 #ifdef ENABLE_PDF
396         if (document == NULL || backend == EV_BACKEND_PDF) {
397                 default_filter = filter = gtk_file_filter_new ();
398                 gtk_file_filter_set_name (filter, _("PDF Documents"));
399                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_PDF);
400                 file_filter_add_mime_list_and_free (filter, mime_types);
401                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
402         }
403 #endif
404
405 #ifdef ENABLE_PIXBUF
406         if (document == NULL || backend == EV_BACKEND_PIXBUF) {
407                 default_filter = filter = gtk_file_filter_new ();
408                 gtk_file_filter_set_name (filter, _("Images"));
409                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_PIXBUF);
410                 file_filter_add_mime_list_and_free (filter, mime_types);
411                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
412         }
413 #endif
414
415 #ifdef ENABLE_DVI
416         if (document == NULL || backend == EV_BACKEND_DVI) {
417                 default_filter = filter = gtk_file_filter_new ();
418                 gtk_file_filter_set_name (filter, _("DVI Documents"));
419                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_DVI);
420                 file_filter_add_mime_list_and_free (filter, mime_types);
421                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
422         }
423 #endif
424
425 #ifdef ENABLE_DJVU
426         if (document == NULL || backend == EV_BACKEND_DJVU) {
427                 default_filter = filter = gtk_file_filter_new ();
428                 gtk_file_filter_set_name (filter, _("Djvu Documents"));
429                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_DJVU);
430                 file_filter_add_mime_list_and_free (filter, mime_types);
431                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
432         }
433 #endif  
434
435 #ifdef ENABLE_COMICS
436         if (document == NULL || backend == EV_BACKEND_COMICS) {
437                 default_filter = filter = gtk_file_filter_new ();
438                 gtk_file_filter_set_name (filter, _("Comic Books"));
439                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_COMICS);
440                 file_filter_add_mime_list_and_free (filter, mime_types);
441                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
442         }
443 #endif  
444
445 #ifdef ENABLE_IMPRESS
446         if (document == NULL || backend == EV_BACKEND_IMPRESS) {
447                 default_filter = filter = gtk_file_filter_new ();
448                 gtk_file_filter_set_name (filter, _("Impress Slides"));
449                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_IMPRESS);
450                 file_filter_add_mime_list_and_free (filter, mime_types);
451                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
452         }
453 #endif  
454
455         filter = gtk_file_filter_new ();
456         gtk_file_filter_set_name (filter, _("All Files"));
457         gtk_file_filter_add_pattern (filter, "*");
458         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
459
460         gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (chooser),
461                                      document == NULL ? document_filter : default_filter);
462 }