]> www.fi.muni.cz Git - evince.git/blob - shell/ev-convert-metadata.c
5ee725c38c9a948c77cdce1bfee7f7b749ff298e
[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 #if GTK_CHECK_VERSION (2, 90, 8)
168                                               0,
169 #else
170                                               GTK_DIALOG_NO_SEPARATOR,
171 #endif
172                                               GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
173                                               NULL);
174         action_area = gtk_dialog_get_action_area (GTK_DIALOG (dialog));
175         gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
176         gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
177         gtk_box_set_spacing (GTK_BOX (action_area), 6);
178
179         vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
180         gtk_box_set_spacing (GTK_BOX (vbox), 12);
181
182         label = gtk_label_new (NULL);
183         gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
184         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
185         text = g_strdup_printf ("<b>%s</b>", _("Converting metadata"));
186         gtk_label_set_markup (GTK_LABEL (label), text);
187         g_free (text);
188         gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
189         gtk_widget_show (label);
190
191         label = gtk_label_new (_("The metadata format used by Evince "
192                                  "has changed, and hence it needs to be migrated. "
193                                  "If the migration is cancelled the metadata "
194                                  "storage will not work."));
195         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
196         gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
197         gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
198         gtk_widget_show (label);
199
200         pbox = gtk_vbox_new (FALSE, 6);
201         progress = gtk_progress_bar_new ();
202         data->progress = progress;
203         gtk_box_pack_start (GTK_BOX (pbox), progress, TRUE, TRUE, 0);
204         gtk_widget_show (progress);
205
206         label = gtk_label_new (NULL);
207         data->label = label;
208         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
209         gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
210         gtk_box_pack_start (GTK_BOX (pbox), label, FALSE, FALSE, 0);
211         gtk_widget_show (label);
212
213         gtk_box_pack_start (GTK_BOX (vbox), pbox, TRUE, TRUE, 0);
214         gtk_widget_show (pbox);
215
216         g_signal_connect (dialog, "response",
217                           G_CALLBACK (convert_metadata_cancel),
218                           data);
219
220         gtk_widget_show (dialog);
221 }
222
223 static gboolean
224 convert_metadata_file (const gchar *filename)
225 {
226         ConvertData *data;
227         xmlDocPtr doc;
228         xmlNodePtr cur;
229
230         if (!g_file_test (filename, G_FILE_TEST_EXISTS))
231                 return FALSE;
232
233         doc = xmlParseFile (filename);
234         if (!doc) {
235                 g_printerr ("Error loading metadata file %s\n", filename);
236                 return FALSE;
237         }
238
239         cur = xmlDocGetRootElement (doc);
240         if (!cur) {
241                 g_printerr ("Metadata file %s is empty\n", filename);
242                 xmlFreeDoc (doc);
243                 return TRUE;
244         }
245
246         if (xmlStrcmp (cur->name, (const xmlChar *) "metadata")) {
247                 g_printerr ("File %s is not a valid evince metadata file\n", filename);
248                 xmlFreeDoc (doc);
249                 return FALSE;
250         }
251
252         data = g_new0 (ConvertData, 1);
253         data->doc = doc;
254
255         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
256                 xmlChar *uri;
257                 DocItem *item;
258
259                 if (xmlStrcmp (cur->name, (const xmlChar *)"document") != 0)
260                         continue;
261
262                 uri = xmlGetProp (cur, (const xmlChar *)"uri");
263                 if (!uri)
264                         continue;
265
266                 item = g_new (DocItem, 1);
267                 item->uri = uri;
268                 item->cur = cur;
269                 data->items = g_list_prepend (data->items, item);
270         }
271
272         if (!data->items) {
273                 xmlFreeDoc (data->doc);
274                 g_free (data);
275
276                 return TRUE;
277         }
278
279         show_progress_dialog (data);
280
281         data->current = data->items;
282         g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
283                          (GSourceFunc)convert_file,
284                          data,
285                          (GDestroyNotify)convert_finish);
286
287         return TRUE;
288 }
289
290 gint
291 main (gint argc, gchar **argv)
292 {
293         if (argc != 2) {
294                 g_printerr ("%s\n", "Usage: evince-convert-metadata FILE");
295                 return 1;
296         }
297
298         gtk_init (&argc, &argv);
299
300         if (!convert_metadata_file (argv[1]))
301                 return 1;
302
303         gtk_main ();
304
305         return 0;
306 }