]> www.fi.muni.cz Git - evince.git/blob - backend/ev-document-factory.c
Rework factory functions so they are placed now in a single file
[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 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, gchar **mime_type, 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         if (mime_type != NULL) {
275                     *mime_type = g_strdup (info->mime_type);
276         }
277
278         gnome_vfs_file_info_unref (info);
279         
280         return document;
281 }
282
283 EvDocument *
284 ev_document_factory_get_document (const char *uri, gchar **mime_type, GError **error)
285 {
286         EvDocument *document;
287         
288         document = get_document_from_uri (uri, FALSE, mime_type, error);
289
290         if (document != NULL) {
291                 return document;
292         }
293                 
294         if (error) {
295                 g_error_free (*error);
296                 *error = NULL;
297         }
298
299         document = get_document_from_uri (uri, TRUE, mime_type, error);
300
301         return document;
302 }
303
304 static void
305 file_filter_add_mime_list_and_free (GtkFileFilter *filter, GList *mime_types)
306 {
307         GList *l;
308
309         for (l = mime_types; l != NULL; l = l->next) {
310                 gtk_file_filter_add_mime_type (filter, l->data);
311         }
312
313         g_list_foreach (mime_types, (GFunc)g_free, NULL);
314         g_list_free (mime_types);
315 }
316
317 void 
318 ev_document_factory_add_filters (GtkWidget *chooser, EvDocument *document)
319 {
320         EvBackend backend = 0;
321         GList *mime_types;
322         GtkFileFilter *filter;
323         GtkFileFilter *default_filter;
324         GtkFileFilter *document_filter;
325
326         if (document != NULL) {
327                 backend = ev_document_factory_get_backend (document);
328         }
329
330         default_filter = document_filter = filter = gtk_file_filter_new ();
331         gtk_file_filter_set_name (filter, _("All Documents"));
332         mime_types = ev_document_factory_get_all_mime_types ();
333         file_filter_add_mime_list_and_free (filter, mime_types);
334         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
335
336 #ifdef ENABLE_PS
337         if (document == NULL || backend == EV_BACKEND_PS) {
338                 default_filter = filter = gtk_file_filter_new ();
339                 gtk_file_filter_set_name (filter, _("PostScript Documents"));
340                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_PS);
341                 file_filter_add_mime_list_and_free (filter, mime_types);
342                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
343         }
344 #endif
345
346         if (document == NULL || backend == EV_BACKEND_PDF) {
347                 default_filter = filter = gtk_file_filter_new ();
348                 gtk_file_filter_set_name (filter, _("PDF Documents"));
349                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_PDF);
350                 file_filter_add_mime_list_and_free (filter, mime_types);
351                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
352         }
353
354 #ifdef ENABLE_PIXBUF
355         if (document == NULL || backend == EV_BACKEND_PIXBUF) {
356                 default_filter = filter = gtk_file_filter_new ();
357                 gtk_file_filter_set_name (filter, _("Images"));
358                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_PIXBUF);
359                 file_filter_add_mime_list_and_free (filter, mime_types);
360                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
361         }
362 #endif
363
364 #ifdef ENABLE_DVI
365         if (document == NULL || backend == EV_BACKEND_DVI) {
366                 default_filter = filter = gtk_file_filter_new ();
367                 gtk_file_filter_set_name (filter, _("DVI Documents"));
368                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_DVI);
369                 file_filter_add_mime_list_and_free (filter, mime_types);
370                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
371         }
372 #endif
373
374 #ifdef ENABLE_DJVU
375         if (document == NULL || backend == EV_BACKEND_DJVU) {
376                 default_filter = filter = gtk_file_filter_new ();
377                 gtk_file_filter_set_name (filter, _("Djvu Documents"));
378                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_DJVU);
379                 file_filter_add_mime_list_and_free (filter, mime_types);
380                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
381         }
382 #endif  
383
384 #ifdef ENABLE_COMICS
385         if (document == NULL || backend == EV_BACKEND_COMICS) {
386                 default_filter = filter = gtk_file_filter_new ();
387                 gtk_file_filter_set_name (filter, _("Comic Books"));
388                 mime_types = ev_document_factory_get_mime_types (EV_BACKEND_COMICS);
389                 file_filter_add_mime_list_and_free (filter, mime_types);
390                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
391         }
392 #endif  
393
394         filter = gtk_file_filter_new ();
395         gtk_file_filter_set_name (filter, _("All Files"));
396         gtk_file_filter_add_pattern (filter, "*");
397         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
398
399         gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (chooser),
400                                      document == NULL ? document_filter : default_filter);
401 }