1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * ev-metadata-manager.c
4 * This file is part of ev
6 * Copyright (C) 2003 Paolo Maggi
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330,
21 * Boston, MA 02111-1307, USA.
25 * Modified by the ev Team, 2003. See the AUTHORS file for a
26 * list of people on the ev Team.
27 * See the ChangeLog files for a list of changes.
37 #include <libxml/xmlreader.h>
39 #include "ev-metadata-manager.h"
40 #include "ev-file-helpers.h"
42 #define METADATA_FILE "ev-metadata.xml"
46 typedef struct _EvMetadataManager EvMetadataManager;
48 typedef struct _Item Item;
52 time_t atime; /* time of last access */
57 struct _EvMetadataManager
59 gboolean values_loaded; /* It is true if the file
62 gboolean modified; /* It is true if the file
70 static gboolean ev_metadata_manager_save (gpointer data);
73 static EvMetadataManager *ev_metadata_manager = NULL;
76 item_free (gpointer data)
80 g_return_if_fail (data != NULL);
84 if (item->values != NULL)
85 g_hash_table_destroy (item->values);
91 ev_metadata_manager_init (void)
93 ev_metadata_manager = g_new0 (EvMetadataManager, 1);
95 ev_metadata_manager->values_loaded = FALSE;
96 ev_metadata_manager->modified = FALSE;
98 ev_metadata_manager->items =
99 g_hash_table_new_full (g_str_hash,
104 ev_metadata_manager->timeout_id =
105 g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
107 (GSourceFunc)ev_metadata_manager_save,
112 /* This function must be called before exiting ev */
114 ev_metadata_manager_shutdown (void)
116 if (ev_metadata_manager == NULL)
119 g_source_remove (ev_metadata_manager->timeout_id);
121 ev_metadata_manager_save (NULL);
123 if (ev_metadata_manager->items != NULL)
124 g_hash_table_destroy (ev_metadata_manager->items);
126 g_free (ev_metadata_manager);
127 ev_metadata_manager = NULL;
131 parse_value (xmlChar *value, xmlChar *type)
136 ret_type = g_type_from_name ((char *)type);
137 ret = g_new0 (GValue, 1);
138 g_value_init (ret, ret_type);
142 g_value_set_string (ret, (char *)value);
145 g_value_set_int (ret, atoi ((char *)value));
148 g_value_set_double (ret, atof ((char *)value));
151 g_value_set_boolean (ret, atoi ((char *)value));
159 parseItem (xmlDocPtr doc, xmlNodePtr cur)
166 if (xmlStrcmp (cur->name, (const xmlChar *)"document") != 0)
169 uri = xmlGetProp (cur, (const xmlChar *)"uri");
173 atime = xmlGetProp (cur, (const xmlChar *)"atime");
180 item = g_new0 (Item, 1);
182 item->atime = atol ((char *)atime);
184 item->values = g_hash_table_new_full (g_str_hash,
189 cur = cur->xmlChildrenNode;
193 if (xmlStrcmp (cur->name, (const xmlChar *)"entry") == 0)
200 key = xmlGetProp (cur, (const xmlChar *)"key");
201 xml_value = xmlGetProp (cur, (const xmlChar *)"value");
202 type = xmlGetProp (cur, (const xmlChar *)"type");
203 value = parse_value (xml_value, type);
205 if ((key != NULL) && (value != NULL))
206 g_hash_table_insert (item->values,
212 if (xml_value != NULL)
219 g_hash_table_insert (ev_metadata_manager->items,
234 g_return_val_if_fail (ev_metadata_manager != NULL, FALSE);
235 g_return_val_if_fail (ev_metadata_manager->values_loaded == FALSE, FALSE);
237 ev_metadata_manager->values_loaded = TRUE;
239 xmlKeepBlanksDefault (0);
241 /* FIXME: file locking - Paolo */
242 file_name = g_build_filename (ev_dot_dir (), METADATA_FILE, NULL);
243 if (!g_file_test (file_name, G_FILE_TEST_EXISTS))
249 doc = xmlParseFile (file_name);
257 cur = xmlDocGetRootElement (doc);
260 g_message ("The metadata file '%s' is empty", METADATA_FILE);
266 if (xmlStrcmp (cur->name, (const xmlChar *) "metadata"))
268 g_message ("File '%s' is of the wrong type", METADATA_FILE);
274 cur = xmlDocGetRootElement (doc);
275 cur = cur->xmlChildrenNode;
279 parseItem (doc, cur);
290 value_free (gpointer data)
292 GValue *value = (GValue *)data;
294 g_value_unset (value);
299 #define LAST_URI "last-used-value"
302 ev_metadata_manager_get_last (const gchar *key,
309 g_assert (ev_metadata_manager->values_loaded);
314 item = (Item *)g_hash_table_lookup (ev_metadata_manager->items,
320 item->atime = time (NULL);
322 if (item->values == NULL)
325 ret = (GValue *)g_hash_table_lookup (item->values, key);
328 g_value_init (value, G_VALUE_TYPE (ret));
329 g_value_copy (ret, value);
337 ev_metadata_manager_set_last (const gchar *key,
342 g_assert (ev_metadata_manager->values_loaded);
344 item = (Item *)g_hash_table_lookup (ev_metadata_manager->items,
349 item = g_new0 (Item, 1);
351 g_hash_table_insert (ev_metadata_manager->items,
356 if (item->values == NULL)
357 item->values = g_hash_table_new_full (g_str_hash,
364 new = g_new0 (GValue, 1);
365 g_value_init (new, G_VALUE_TYPE (value));
366 g_value_copy (value, new);
368 g_hash_table_insert (item->values,
372 g_hash_table_remove (item->values,
376 item->atime = time (NULL);
377 ev_metadata_manager->modified = TRUE;
382 ev_metadata_manager_get (const gchar *uri,
385 gboolean ignore_last)
390 g_return_val_if_fail (key != NULL, FALSE);
392 if (ev_metadata_manager == NULL)
395 if (!ev_metadata_manager->values_loaded)
399 res = load_values ();
402 return ev_metadata_manager_get_last (key, value, ignore_last);
406 return ev_metadata_manager_get_last (key, value, ignore_last);
408 item = (Item *)g_hash_table_lookup (ev_metadata_manager->items,
412 return ev_metadata_manager_get_last (key, value, ignore_last);
414 item->atime = time (NULL);
416 if (item->values == NULL)
417 return ev_metadata_manager_get_last (key, value, ignore_last);
419 ret = (GValue *)g_hash_table_lookup (item->values, key);
422 g_value_init (value, G_VALUE_TYPE (ret));
423 g_value_copy (ret, value);
427 return ev_metadata_manager_get_last (key, value, ignore_last);
431 ev_metadata_manager_set (const gchar *uri,
437 g_return_if_fail (key != NULL);
439 if (ev_metadata_manager == NULL)
442 if (!ev_metadata_manager->values_loaded)
446 res = load_values ();
454 ev_metadata_manager_set_last (key, value);
458 item = (Item *)g_hash_table_lookup (ev_metadata_manager->items,
463 item = g_new0 (Item, 1);
465 g_hash_table_insert (ev_metadata_manager->items,
470 if (item->values == NULL)
471 item->values = g_hash_table_new_full (g_str_hash,
478 new = g_new0 (GValue, 1);
479 g_value_init (new, G_VALUE_TYPE (value));
480 g_value_copy (value, new);
482 g_hash_table_insert (item->values,
485 ev_metadata_manager_set_last (key, value);
487 g_hash_table_remove (item->values,
491 item->atime = time (NULL);
493 ev_metadata_manager->modified = TRUE;
497 save_values (const gchar *key, GValue *value, xmlNodePtr parent)
502 g_return_if_fail (key != NULL);
507 xml_node = xmlNewChild (parent, NULL, (const xmlChar *)"entry", NULL);
509 xmlSetProp (xml_node, (const xmlChar *)"key", (const xmlChar *)key);
510 xmlSetProp (xml_node,
511 (const xmlChar *)"type",
512 (const xmlChar *)g_type_name (G_VALUE_TYPE (value)));
514 switch (G_VALUE_TYPE (value)) {
516 string_value = g_strdup (g_value_get_string (value));
519 string_value = g_strdup_printf ("%d", g_value_get_int (value));
522 string_value = g_strdup_printf ("%f", g_value_get_double (value));
525 string_value = g_strdup_printf ("%d", g_value_get_boolean (value));
529 g_assert_not_reached ();
532 xmlSetProp (xml_node, (const xmlChar *)"value", (const xmlChar *)string_value);
534 g_free (string_value);
538 save_item (const gchar *key, const gpointer *data, xmlNodePtr parent)
541 const Item *item = (const Item *)data;
544 g_return_if_fail (key != NULL);
549 xml_node = xmlNewChild (parent, NULL, (const xmlChar *)"document", NULL);
551 xmlSetProp (xml_node, (const xmlChar *)"uri", (const xmlChar *)key);
553 /* FIXME: is the cast right? - Paolo */
554 atime = g_strdup_printf ("%d", (int)item->atime);
555 xmlSetProp (xml_node, (const xmlChar *)"atime", (const xmlChar *)atime);
559 g_hash_table_foreach (item->values,
560 (GHFunc)save_values, xml_node);
564 get_oldest (const gchar *key, const gpointer value, const gchar ** key_to_remove)
566 const Item *item = (const Item *)value;
568 if (*key_to_remove == NULL)
570 *key_to_remove = key;
574 const Item *item_to_remove =
575 g_hash_table_lookup (ev_metadata_manager->items,
578 g_return_if_fail (item_to_remove != NULL);
580 if (item->atime < item_to_remove->atime)
582 *key_to_remove = key;
590 while (g_hash_table_size (ev_metadata_manager->items) > MAX_ITEMS)
592 gpointer key_to_remove = NULL;
594 g_hash_table_foreach (ev_metadata_manager->items,
598 g_return_if_fail (key_to_remove != NULL);
600 g_hash_table_remove (ev_metadata_manager->items,
606 ev_metadata_manager_save (gpointer data)
612 if (!ev_metadata_manager->modified)
617 xmlIndentTreeOutput = TRUE;
619 doc = xmlNewDoc ((const xmlChar *)"1.0");
623 /* Create metadata root */
624 root = xmlNewDocNode (doc, NULL, (const xmlChar *)"metadata", NULL);
625 xmlDocSetRootElement (doc, root);
627 g_hash_table_foreach (ev_metadata_manager->items,
628 (GHFunc)save_item, root);
630 /* FIXME: lock file - Paolo */
631 file_name = g_build_filename (ev_dot_dir (), METADATA_FILE, NULL);
632 xmlSaveFormatFile (file_name, doc, 1);
637 ev_metadata_manager->modified = FALSE;
643 ev_metadata_manager_set_int (const gchar *uri, const gchar *key, int value)
647 g_value_init (&val, G_TYPE_INT);
648 g_value_set_int (&val, value);
650 ev_metadata_manager_set (uri, key, &val);
652 g_value_unset (&val);
656 ev_metadata_manager_set_double (const gchar *uri, const gchar *key, double value)
660 g_value_init (&val, G_TYPE_DOUBLE);
661 g_value_set_double (&val, value);
663 ev_metadata_manager_set (uri, key, &val);
665 g_value_unset (&val);
669 ev_metadata_manager_set_string (const gchar *uri, const gchar *key, const gchar *value)
673 g_value_init (&val, G_TYPE_STRING);
674 g_value_set_string (&val, value);
676 ev_metadata_manager_set (uri, key, &val);
678 g_value_unset (&val);
682 ev_metadata_manager_set_boolean (const gchar *uri, const gchar *key, gboolean value)
686 g_value_init (&val, G_TYPE_BOOLEAN);
687 g_value_set_boolean (&val, value);
689 ev_metadata_manager_set (uri, key, &val);
691 g_value_unset (&val);