]> www.fi.muni.cz Git - evince.git/blob - shell/ev-convert-metadata.c
44a71b772bf314774c15222eb52d1a37870245df
[evince.git] / shell / ev-convert-metadata.c
1 /* ev-convert-metadata.c
2  *  this file is part of evince, a gnome document viewer
3  *
4  * Copyright (C) 2009 Carlos Garcia Campos  <carlosgc@gnome.org>
5  *
6  * Evince is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Evince is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20
21 //#include <config.h>
22
23 #include <gtk/gtk.h>
24 #include <glib.h>
25 #include <gio/gio.h>
26 #include <glib/gi18n.h>
27 #include <string.h>
28 #include <libxml/tree.h>
29
30 #define EV_METADATA_NAMESPACE "metadata::evince"
31
32 typedef struct {
33         xmlNodePtr cur;
34         xmlChar *uri;
35 } DocItem;
36
37 typedef struct {
38         GtkWidget *progress;
39         GtkWidget *label;
40
41         xmlDocPtr doc;
42         GList *items;
43         GList *current;
44         guint n_item;
45 } ConvertData;
46
47 static void
48 free_doc_item (DocItem *item)
49 {
50         xmlFree (item->uri);
51         g_free (item);
52 }
53
54 static void
55 convert_finish (ConvertData *data)
56 {
57         g_list_foreach (data->items, (GFunc)free_doc_item, NULL);
58         g_list_free (data->items);
59         xmlFreeDoc (data->doc);
60         g_free (data);
61
62         gtk_main_quit ();
63 }
64
65 static gboolean
66 convert_file (ConvertData *data)
67 {
68         GFile *file;
69         DocItem *item;
70         const gchar *uri;
71         xmlNodePtr node;
72         xmlNodePtr cur;
73         gint total, current;
74         gchar *text;
75
76         if (!data->current)
77                 return FALSE;
78
79         item = (DocItem *) data->current->data;
80         uri = (const gchar *)item->uri;
81         node = item->cur;
82         data->current = g_list_next (data->current);
83
84         /* Update progress information */
85         total = g_list_length (data->items);
86         current = ++(data->n_item);
87
88         text = g_strdup_printf (_("Converting %s"), uri);
89         gtk_label_set_text (GTK_LABEL (data->label), text);
90         g_free (text);
91
92         text = g_strdup_printf (_("%d of %d documents converted"), current, total);
93         gtk_progress_bar_set_text (GTK_PROGRESS_BAR (data->progress), text);
94         g_free (text);
95         gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (data->progress),
96                                        (gdouble)(current - 1) / total);
97
98         file = g_file_new_for_uri (uri);
99         if (!g_file_query_exists (file, NULL)) {
100                 g_printerr ("Uri %s does not exist\n", uri);
101                 g_object_unref (file);
102
103                 return data->current != NULL;
104         }
105
106         for (cur = node->xmlChildrenNode; cur != NULL; cur = cur->next) {
107                 xmlChar *key;
108                 xmlChar *value;
109
110                 if (xmlStrcmp (cur->name, (const xmlChar *)"entry") != 0)
111                         continue;
112
113                 key = xmlGetProp (cur, (const xmlChar *)"key");
114                 value = xmlGetProp (cur, (const xmlChar *)"value");
115                 if (key && value) {
116                         GFileInfo *info;
117                         gchar *gio_key;
118                         GError *error = NULL;
119
120                         info = g_file_info_new ();
121
122                         gio_key = g_strconcat (EV_METADATA_NAMESPACE"::", key, NULL);
123                         g_file_info_set_attribute_string (info, gio_key, (const gchar *)value);
124                         g_free (gio_key);
125
126                         if (!g_file_set_attributes_from_info (file, info, 0, NULL, &error)) {
127                                 g_printerr ("Error setting metadata for %s: %s\n",
128                                             uri, error->message);
129                                 g_error_free (error);
130                         }
131
132                         g_object_unref (info);
133                 }
134
135                 if (key)
136                         xmlFree (key);
137                 if (value)
138                         xmlFree (value);
139         }
140
141         g_object_unref (file);
142
143         return data->current != NULL;
144 }
145
146 static void
147 convert_metadata_cancel (GtkDialog   *dialog,
148                          gint         response_id,
149                          ConvertData *data)
150 {
151         convert_finish (data);
152         exit (1);
153 }
154
155 static void
156 show_progress_dialog (ConvertData *data)
157 {
158         GtkWidget *dialog;
159         GtkWidget *action_area;
160         GtkWidget *vbox, *pbox;
161         GtkWidget *label;
162         GtkWidget *progress;
163         gchar     *text;
164
165         dialog = gtk_dialog_new_with_buttons (_("Converting metadata"),
166                                               NULL,
167                                               0,
168                                               GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
169                                               NULL);
170         action_area = gtk_dialog_get_action_area (GTK_DIALOG (dialog));
171         gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
172         gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
173         gtk_box_set_spacing (GTK_BOX (action_area), 6);
174
175         vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
176         gtk_box_set_spacing (GTK_BOX (vbox), 12);
177
178         label = gtk_label_new (NULL);
179         gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
180         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
181         text = g_strdup_printf ("<b>%s</b>", _("Converting metadata"));
182         gtk_label_set_markup (GTK_LABEL (label), text);
183         g_free (text);
184         gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
185         gtk_widget_show (label);
186
187         label = gtk_label_new (_("The metadata format used by Evince "
188                                  "has changed, and hence it needs to be migrated. "
189                                  "If the migration is cancelled the metadata "
190                                  "storage will not work."));
191         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
192         gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
193         gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
194         gtk_widget_show (label);
195
196         pbox = gtk_vbox_new (FALSE, 6);
197         progress = gtk_progress_bar_new ();
198         data->progress = progress;
199         gtk_box_pack_start (GTK_BOX (pbox), progress, TRUE, TRUE, 0);
200         gtk_widget_show (progress);
201
202         label = gtk_label_new (NULL);
203         data->label = label;
204         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
205         gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
206         gtk_box_pack_start (GTK_BOX (pbox), label, FALSE, FALSE, 0);
207         gtk_widget_show (label);
208
209         gtk_box_pack_start (GTK_BOX (vbox), pbox, TRUE, TRUE, 0);
210         gtk_widget_show (pbox);
211
212         g_signal_connect (dialog, "response",
213                           G_CALLBACK (convert_metadata_cancel),
214                           data);
215
216         gtk_widget_show (dialog);
217 }
218
219 static gboolean
220 convert_metadata_file (const gchar *filename)
221 {
222         ConvertData *data;
223         xmlDocPtr doc;
224         xmlNodePtr cur;
225
226         if (!g_file_test (filename, G_FILE_TEST_EXISTS))
227                 return FALSE;
228
229         doc = xmlParseFile (filename);
230         if (!doc) {
231                 g_printerr ("Error loading metadata file %s\n", filename);
232                 return FALSE;
233         }
234
235         cur = xmlDocGetRootElement (doc);
236         if (!cur) {
237                 g_printerr ("Metadata file %s is empty\n", filename);
238                 xmlFreeDoc (doc);
239                 return TRUE;
240         }
241
242         if (xmlStrcmp (cur->name, (const xmlChar *) "metadata")) {
243                 g_printerr ("File %s is not a valid evince metadata file\n", filename);
244                 xmlFreeDoc (doc);
245                 return FALSE;
246         }
247
248         data = g_new0 (ConvertData, 1);
249         data->doc = doc;
250
251         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
252                 xmlChar *uri;
253                 DocItem *item;
254
255                 if (xmlStrcmp (cur->name, (const xmlChar *)"document") != 0)
256                         continue;
257
258                 uri = xmlGetProp (cur, (const xmlChar *)"uri");
259                 if (!uri)
260                         continue;
261
262                 item = g_new (DocItem, 1);
263                 item->uri = uri;
264                 item->cur = cur;
265                 data->items = g_list_prepend (data->items, item);
266         }
267
268         if (!data->items) {
269                 xmlFreeDoc (data->doc);
270                 g_free (data);
271
272                 return TRUE;
273         }
274
275         show_progress_dialog (data);
276
277         data->current = data->items;
278         g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
279                          (GSourceFunc)convert_file,
280                          data,
281                          (GDestroyNotify)convert_finish);
282
283         return TRUE;
284 }
285
286 gint
287 main (gint argc, gchar **argv)
288 {
289         if (argc != 2) {
290                 g_printerr ("%s\n", "Usage: evince-convert-metadata FILE");
291                 return 1;
292         }
293
294         gtk_init (&argc, &argv);
295
296         if (!convert_metadata_file (argv[1]))
297                 return 1;
298
299         gtk_main ();
300
301         return 0;
302 }