]> www.fi.muni.cz Git - evince.git/blob - backend/ev-document-factory.c
f524e1a0e0724f0f0e4a3be36527c3e812eea9d2
[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         /* PDF: */
69         {"application/pdf",            EV_BACKEND_PDF,  pdf_document_get_type},
70
71 #ifdef ENABLE_PS
72         /* Postscript: */
73         {"application/postscript",     EV_BACKEND_PS,   ps_document_get_type},
74         {"application/x-gzpostscript", EV_BACKEND_PS,   ps_document_get_type},
75         {"image/x-eps",                EV_BACKEND_PS,   ps_document_get_type},
76 #endif
77
78 #ifdef ENABLE_TIFF
79         /* Tiff: */
80         {"image/tiff",                 EV_BACKEND_TIFF, tiff_document_get_type},
81 #endif
82
83 #ifdef ENABLE_DJVU
84         /* djvu: */
85         {"image/vnd.djvu",             EV_BACKEND_DJVU, djvu_document_get_type},
86 #endif          
87
88 #ifdef ENABLE_DVI
89         /* dvi: */
90         {"application/x-dvi",          EV_BACKEND_DVI,  dvi_document_get_type},
91 #endif
92
93 #ifdef ENABLE_COMICS
94         /* cbr/cbz: */
95         {"application/x-cbr",           EV_BACKEND_COMICS,  comics_document_get_type},
96         {"application/x-cbz",           EV_BACKEND_COMICS,  comics_document_get_type},
97 #endif
98
99 #ifdef ENABLE_IMPRESS
100         /* Impress slides: */
101         {"application/vnd.sun.xml.impress", EV_BACKEND_IMPRESS, impress_document_get_type},
102         {"application/vnd.oasis.opendocument.presentation", EV_BACKEND_IMPRESS, impress_document_get_type},
103 #endif
104
105 };
106
107 #ifdef ENABLE_PIXBUF
108
109 static GList*
110 gdk_pixbuf_mime_type_list ()
111 {
112         GSList *formats, *list;
113         GList *result;
114
115         formats = gdk_pixbuf_get_formats ();
116         result = NULL;
117
118         for (list = formats; list != NULL; list = list->next) {
119                 GdkPixbufFormat *format = list->data;
120                 int i;
121                 gchar **mime_types;
122
123                 if (gdk_pixbuf_format_is_disabled (format))
124                         continue;
125
126                 mime_types = gdk_pixbuf_format_get_mime_types (format);
127
128                 for (i = 0; mime_types[i] != NULL; i++) {
129                         result = g_list_append (result, mime_types[i]);
130                 }
131         }
132         g_slist_free (formats);
133
134         return result;
135 }
136
137 /* Would be nice to have this in gdk-pixbuf */
138 static gboolean
139 mime_type_supported_by_gdk_pixbuf (const gchar *mime_type)
140 {
141         GList *mime_types;
142         GList *list;
143         gboolean retval = FALSE;
144         
145         mime_types = gdk_pixbuf_mime_type_list ();
146         for (list = mime_types; list; list = list->next) {
147                 if (strcmp ((char *)list->data, mime_type) == 0) {
148                         retval = TRUE;
149                         break;
150                 }
151         }
152         
153         g_list_foreach (mime_types, (GFunc)g_free, NULL);
154         g_list_free (mime_types);
155
156         return retval;
157 }
158 #endif
159
160 static EvDocument*
161 ev_document_factory_get_from_mime (const char *mime_type)
162 {
163         int i;
164         GType type = G_TYPE_INVALID;
165         EvDocument *document = NULL;
166         
167         g_return_val_if_fail (mime_type, G_TYPE_INVALID);
168
169         for (i = 0; i < G_N_ELEMENTS (document_types); i++) {
170                 if (strcmp (mime_type, document_types[i].mime_type) == 0) {
171                         g_assert (document_types[i].document_type_factory_callback != NULL);
172                         type = document_types[i].document_type_factory_callback();
173                         break;
174                 }
175         }
176 #ifdef ENABLE_PIXBUF
177         if (type == G_TYPE_INVALID && mime_type_supported_by_gdk_pixbuf (mime_type)) {
178                 type = pixbuf_document_get_type ();
179         }
180 #endif
181         if (type != G_TYPE_INVALID) {
182                 document = g_object_new (type, NULL);
183         } 
184
185         return document;
186 }
187
188 EvBackend
189 ev_document_factory_get_backend (EvDocument *document)
190 {
191         int i;
192
193         for (i = 0; i < G_N_ELEMENTS (document_types); i++) {
194                 GType type = document_types[i].document_type_factory_callback ();
195                 if (type == G_TYPE_FROM_INSTANCE (document)) {
196                         return  document_types[i].backend;
197                 }
198         }
199
200 #ifdef ENABLE_PIXBUF
201         if (G_TYPE_FROM_INSTANCE (document) == pixbuf_document_get_type ())
202                 return EV_BACKEND_PIXBUF;
203 #endif
204         g_assert_not_reached ();
205         
206         return 0;
207 }
208
209 static GList *
210 ev_document_factory_get_mime_types (EvBackend backend)
211 {
212         GList *types = NULL;
213         int i;
214         
215 #ifdef ENABLE_PIXBUF
216         if (backend == EV_BACKEND_PIXBUF) {
217                 return gdk_pixbuf_mime_type_list ();
218         }
219 #endif
220         
221         for (i = 0; i < G_N_ELEMENTS (document_types); i++) {
222                 if (document_types[i].backend == backend) {
223                         types = g_list_append (types, g_strdup (document_types[i].mime_type));
224                 }
225         }
226
227         return types;
228 }
229
230 static GList *
231 ev_document_factory_get_all_mime_types (void)
232 {
233         GList *types = NULL;
234         int i;
235         
236         for (i = 0; i < G_N_ELEMENTS (document_types); i++) {
237                 types = g_list_append (types, g_strdup (document_types[i].mime_type));
238         }
239         
240 #ifdef ENABLE_PIXBUF
241         types = g_list_concat (types, gdk_pixbuf_mime_type_list ());
242 #endif
243
244         return types;
245 }
246
247 static EvDocument *
248 get_document_from_uri (const char *uri, gboolean slow, GError **error)
249 {
250         EvDocument *document = NULL;
251
252         GnomeVFSFileInfo *info;
253         GnomeVFSResult result;
254
255         info = gnome_vfs_file_info_new ();
256         result = gnome_vfs_get_file_info (uri, info,
257                                           GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
258                                           GNOME_VFS_FILE_INFO_FOLLOW_LINKS | 
259                                           (slow ? GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE : 0));
260         if (result != GNOME_VFS_OK) {
261                 g_set_error (error,
262                              EV_DOCUMENT_ERROR,
263                              0,
264                              gnome_vfs_result_to_string (result));                      
265                 gnome_vfs_file_info_unref (info);
266                 return NULL;
267         } 
268         
269         if (info->mime_type == NULL) {
270                 g_set_error (error,
271                              EV_DOCUMENT_ERROR, 
272                              0,
273                              _("Unknown MIME Type"));
274                 gnome_vfs_file_info_unref (info);
275                 return NULL;
276         }
277
278         document = ev_document_factory_get_from_mime (info->mime_type);
279                 
280         if (document == NULL) {
281                 g_set_error (error,
282                              EV_DOCUMENT_ERROR, 
283                              0,
284                              _("Unhandled MIME type: ā€œ%sā€"), info->mime_type);
285                 gnome_vfs_file_info_unref (info);
286                 return NULL;
287         }                       
288
289         gnome_vfs_file_info_unref (info);
290         
291         return document;
292 }
293
294 EvDocument *
295 ev_document_factory_get_document (const char *uri, GError **error)
296 {
297         EvDocument *document;
298         int result;
299
300         document = get_document_from_uri (uri, FALSE, error);
301
302         if (*error == NULL) {
303                 result = ev_document_load (document, uri, error);
304
305                 if (result == FALSE || *error) {
306                         if (*error &&
307                             (*error)->domain == EV_DOCUMENT_ERROR &&
308                             (*error)->code == EV_DOCUMENT_ERROR_ENCRYPTED)
309                                 return document;
310                 } else {
311                         return document;
312                 }
313         }
314         
315         /* Try again with slow mime detection */
316         if (document)
317                 g_object_unref (document);
318         document = NULL;
319
320         if (*error)
321                 g_error_free (*error);
322         *error = NULL;
323
324         document = get_document_from_uri (uri, TRUE, error);
325
326         if (*error != NULL) {
327                 return NULL;
328         }
329
330         result = ev_document_load (document, uri, error);
331
332         if (result == FALSE) {
333                 if (*error == NULL) {
334                         g_set_error (error,
335                                      EV_DOCUMENT_ERROR,
336                                      0,
337                                      _("Unknown MIME Type"));
338                 } else if ((*error)->domain == EV_DOCUMENT_ERROR &&
339                            (*error)->code == EV_DOCUMENT_ERROR_ENCRYPTED) {
340                         return document;
341                 }
342
343                 if (document)
344                         g_object_unref (document);
345                 document = NULL;
346         }
347         
348         return document;
349 }
350
351 static void
352 file_filter_add_mime_list_and_free (GtkFileFilter *filter, GList *mime_types)
353 {
354         GList *l;
355
356         for (l = mime_types; l != NULL; l = l->next) {
357                 gtk_file_filter_add_mime_type (filter, l->data);
358         }
359
360         g_list_foreach (mime_types, (GFunc)g_free, NULL);
361         g_list_free (mime_types);
362 }
363
364 void 
365 ev_document_factory_add_filters (GtkWidget *chooser, EvDocument *document)
366 {
367         EvBackend backend = 0;
368         GList *mime_types;
369         GtkFileFilter *filter;
370         GtkFileFilter *default_filter;
371         GtkFileFilter *document_filter;
372
373         if (document != NULL) {
374                 backend = ev_document_factory_get_backend (document);
375         }
376
377         default_filter = document_filter = filter = gtk_file_filter_new ();
378         gtk_file_filter_set_name (filter, _("All Documents"));
379         mime_types = ev_document_factory_get_all_mime_types ();
380         file_filter_add_mime_list_and_free (filter, mime_types);
381         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
382
383 #ifdef ENABLE_PS
384         if (document == NULL || backend == EV_BACKEND_PS) {
385                 default_filter = filter = gtk_file_filter_new ();
386                 gtk_file_filter_set_name (filter, _("PostScript Documents"));
387                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_PS);
388                 file_filter_add_mime_list_and_free (filter, mime_types);
389                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
390         }
391 #endif
392
393         if (document == NULL || backend == EV_BACKEND_PDF) {
394                 default_filter = filter = gtk_file_filter_new ();
395                 gtk_file_filter_set_name (filter, _("PDF Documents"));
396                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_PDF);
397                 file_filter_add_mime_list_and_free (filter, mime_types);
398                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
399         }
400
401 #ifdef ENABLE_PIXBUF
402         if (document == NULL || backend == EV_BACKEND_PIXBUF) {
403                 default_filter = filter = gtk_file_filter_new ();
404                 gtk_file_filter_set_name (filter, _("Images"));
405                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_PIXBUF);
406                 file_filter_add_mime_list_and_free (filter, mime_types);
407                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
408         }
409 #endif
410
411 #ifdef ENABLE_DVI
412         if (document == NULL || backend == EV_BACKEND_DVI) {
413                 default_filter = filter = gtk_file_filter_new ();
414                 gtk_file_filter_set_name (filter, _("DVI Documents"));
415                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_DVI);
416                 file_filter_add_mime_list_and_free (filter, mime_types);
417                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
418         }
419 #endif
420
421 #ifdef ENABLE_DJVU
422         if (document == NULL || backend == EV_BACKEND_DJVU) {
423                 default_filter = filter = gtk_file_filter_new ();
424                 gtk_file_filter_set_name (filter, _("Djvu Documents"));
425                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_DJVU);
426                 file_filter_add_mime_list_and_free (filter, mime_types);
427                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
428         }
429 #endif  
430
431 #ifdef ENABLE_COMICS
432         if (document == NULL || backend == EV_BACKEND_COMICS) {
433                 default_filter = filter = gtk_file_filter_new ();
434                 gtk_file_filter_set_name (filter, _("Comic Books"));
435                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_COMICS);
436                 file_filter_add_mime_list_and_free (filter, mime_types);
437                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
438         }
439 #endif  
440
441 #ifdef ENABLE_IMPRESS
442         if (document == NULL || backend == EV_BACKEND_IMPRESS) {
443                 default_filter = filter = gtk_file_filter_new ();
444                 gtk_file_filter_set_name (filter, _("Impress Slides"));
445                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_IMPRESS);
446                 file_filter_add_mime_list_and_free (filter, mime_types);
447                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
448         }
449 #endif  
450
451         filter = gtk_file_filter_new ();
452         gtk_file_filter_set_name (filter, _("All Files"));
453         gtk_file_filter_add_pattern (filter, "*");
454         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
455
456         gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (chooser),
457                                      document == NULL ? document_filter : default_filter);
458 }