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