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
67 static gboolean ev_metadata_manager_save (gpointer data);
70 static EvMetadataManager *ev_metadata_manager = NULL;
74 * @data: a pointer to a #Item data
76 * It does free the values on the #GHashTable where data points.
79 item_free (gpointer data)
83 g_return_if_fail (data != NULL);
87 if (item->values != NULL)
88 g_hash_table_destroy (item->values);
94 * ev_metadata_arm_timeout
96 * Setup a timeout for saving the metadata to disk.
99 ev_metadata_arm_timeout(void)
101 if (ev_metadata_manager->timeout_id)
103 #if GLIB_CHECK_VERSION (2, 13, 5)
104 ev_metadata_manager->timeout_id =
105 g_timeout_add_seconds_full (G_PRIORITY_DEFAULT_IDLE,
107 (GSourceFunc)ev_metadata_manager_save,
111 ev_metadata_manager->timeout_id =
112 g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
114 (GSourceFunc)ev_metadata_manager_save,
121 * ev_metadata_manager_init:
123 * Creates an EvMetadataManager with default values.
125 * values_loaded -> %FALSE.
126 * timeout_id -> the id of the event source.
127 * items -> a new full empty #GHashTable.
130 ev_metadata_manager_init (void)
132 ev_metadata_manager = g_new0 (EvMetadataManager, 1);
134 ev_metadata_manager->values_loaded = FALSE;
136 ev_metadata_manager->items =
137 g_hash_table_new_full (g_str_hash,
143 /* This function must be called before exiting ev */
145 ev_metadata_manager_shutdown (void)
147 if (ev_metadata_manager == NULL)
150 if (ev_metadata_manager->timeout_id) {
151 g_source_remove (ev_metadata_manager->timeout_id);
152 ev_metadata_manager->timeout_id = 0;
153 ev_metadata_manager_save (NULL);
156 if (ev_metadata_manager->items != NULL)
157 g_hash_table_destroy (ev_metadata_manager->items);
159 g_free (ev_metadata_manager);
160 ev_metadata_manager = NULL;
164 value_free (gpointer data)
166 GValue *value = (GValue *)data;
168 g_value_unset (value);
173 parse_value (xmlChar *value, xmlChar *type)
178 ret_type = g_type_from_name ((char *)type);
179 ret = g_new0 (GValue, 1);
180 g_value_init (ret, ret_type);
184 g_value_set_string (ret, (char *)value);
187 g_value_set_int (ret, g_ascii_strtoull ((char *)value, NULL, 0));
190 g_value_set_double (ret, g_ascii_strtod ((char *)value, NULL));
193 g_value_set_boolean (ret, g_ascii_strtoull ((char *)value, NULL, 0));
201 parseItem (xmlDocPtr doc, xmlNodePtr cur)
208 if (xmlStrcmp (cur->name, (const xmlChar *)"document") != 0)
211 uri = xmlGetProp (cur, (const xmlChar *)"uri");
215 atime = xmlGetProp (cur, (const xmlChar *)"atime");
222 item = g_new0 (Item, 1);
224 item->atime = g_ascii_strtoull((char*)atime, NULL, 0);
226 item->values = g_hash_table_new_full (g_str_hash,
231 cur = cur->xmlChildrenNode;
235 if (xmlStrcmp (cur->name, (const xmlChar *)"entry") == 0)
242 key = xmlGetProp (cur, (const xmlChar *)"key");
243 xml_value = xmlGetProp (cur, (const xmlChar *)"value");
244 type = xmlGetProp (cur, (const xmlChar *)"type");
245 value = parse_value (xml_value, type);
247 if ((key != NULL) && (value != NULL))
248 g_hash_table_insert (item->values,
256 if (xml_value != NULL)
263 g_hash_table_insert (ev_metadata_manager->items,
278 g_return_val_if_fail (ev_metadata_manager != NULL, FALSE);
279 g_return_val_if_fail (ev_metadata_manager->values_loaded == FALSE, FALSE);
281 ev_metadata_manager->values_loaded = TRUE;
283 xmlKeepBlanksDefault (0);
285 /* FIXME: file locking - Paolo */
286 file_name = g_build_filename (ev_dot_dir (), METADATA_FILE, NULL);
287 if (!g_file_test (file_name, G_FILE_TEST_EXISTS))
293 doc = xmlParseFile (file_name);
301 cur = xmlDocGetRootElement (doc);
304 g_message ("The metadata file “%s” is empty", METADATA_FILE);
310 if (xmlStrcmp (cur->name, (const xmlChar *) "metadata"))
312 g_message ("File “%s” is of the wrong type", METADATA_FILE);
318 cur = xmlDocGetRootElement (doc);
319 cur = cur->xmlChildrenNode;
323 parseItem (doc, cur);
333 #define LAST_URI "last-used-value"
336 ev_metadata_manager_get_last (const gchar *key,
343 g_assert (ev_metadata_manager->values_loaded);
348 item = (Item *)g_hash_table_lookup (ev_metadata_manager->items,
354 item->atime = time (NULL);
356 if (item->values == NULL)
359 ret = (GValue *)g_hash_table_lookup (item->values, key);
362 g_value_init (value, G_VALUE_TYPE (ret));
363 g_value_copy (ret, value);
371 ev_metadata_manager_set_last (const gchar *key,
376 g_assert (ev_metadata_manager->values_loaded);
378 item = (Item *)g_hash_table_lookup (ev_metadata_manager->items,
383 item = g_new0 (Item, 1);
385 g_hash_table_insert (ev_metadata_manager->items,
390 if (item->values == NULL)
391 item->values = g_hash_table_new_full (g_str_hash,
398 new = g_new0 (GValue, 1);
399 g_value_init (new, G_VALUE_TYPE (value));
400 g_value_copy (value, new);
402 g_hash_table_insert (item->values,
406 g_hash_table_remove (item->values,
410 item->atime = time (NULL);
411 ev_metadata_arm_timeout ();
416 * ev_metadata_manager_get:
417 * @uri: Uri to set data for, if @NULL, we return default value
418 * @key: Key to set uri
419 * @value: GValue struct filled up with value
420 * @ignore_last: if @TRUE, default value is ignored
422 * Retrieve value for uri in metadata database
424 * Returns: @TRUE if value was taken.
427 ev_metadata_manager_get (const gchar *uri,
430 gboolean ignore_last)
435 g_return_val_if_fail (key != NULL, FALSE);
437 if (ev_metadata_manager == NULL)
440 if (!ev_metadata_manager->values_loaded)
444 res = load_values ();
447 return ev_metadata_manager_get_last (key, value, ignore_last);
451 return ev_metadata_manager_get_last (key, value, ignore_last);
453 item = (Item *)g_hash_table_lookup (ev_metadata_manager->items,
457 return ev_metadata_manager_get_last (key, value, ignore_last);
459 item->atime = time (NULL);
461 if (item->values == NULL)
462 return ev_metadata_manager_get_last (key, value, ignore_last);
464 ret = (GValue *)g_hash_table_lookup (item->values, key);
467 g_value_init (value, G_VALUE_TYPE (ret));
468 g_value_copy (ret, value);
472 return ev_metadata_manager_get_last (key, value, ignore_last);
476 * ev_metadata_manager_set:
477 * @uri: Uri to set data for, if @NULL, we set default value
478 * @key: Key to set uri
479 * @value: GValue struct containing value
481 * Set value for key in metadata database
484 ev_metadata_manager_set (const gchar *uri,
490 g_return_if_fail (key != NULL);
492 if (ev_metadata_manager == NULL)
495 if (!ev_metadata_manager->values_loaded)
499 res = load_values ();
507 ev_metadata_manager_set_last (key, value);
511 item = (Item *)g_hash_table_lookup (ev_metadata_manager->items,
516 item = g_new0 (Item, 1);
518 g_hash_table_insert (ev_metadata_manager->items,
523 if (item->values == NULL)
524 item->values = g_hash_table_new_full (g_str_hash,
531 new = g_new0 (GValue, 1);
532 g_value_init (new, G_VALUE_TYPE (value));
533 g_value_copy (value, new);
535 g_hash_table_insert (item->values,
538 ev_metadata_manager_set_last (key, value);
540 g_hash_table_remove (item->values,
544 item->atime = time (NULL);
546 ev_metadata_arm_timeout ();
550 save_values (const gchar *key, GValue *value, xmlNodePtr parent)
555 g_return_if_fail (key != NULL);
560 xml_node = xmlNewChild (parent, NULL, (const xmlChar *)"entry", NULL);
562 xmlSetProp (xml_node, (const xmlChar *)"key", (const xmlChar *)key);
563 xmlSetProp (xml_node,
564 (const xmlChar *)"type",
565 (const xmlChar *)g_type_name (G_VALUE_TYPE (value)));
567 switch (G_VALUE_TYPE (value)) {
569 string_value = g_strdup (g_value_get_string (value));
572 string_value = g_strdup_printf ("%d", g_value_get_int (value));
576 gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
577 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, g_value_get_double (value));
578 string_value = g_strdup_printf ("%s", buf);
582 string_value = g_strdup_printf ("%d", g_value_get_boolean (value));
586 g_assert_not_reached ();
589 xmlSetProp (xml_node, (const xmlChar *)"value", (const xmlChar *)string_value);
591 g_free (string_value);
595 save_item (const gchar *key, const gpointer *data, xmlNodePtr parent)
598 const Item *item = (const Item *)data;
601 g_return_if_fail (key != NULL);
606 xml_node = xmlNewChild (parent, NULL, (const xmlChar *)"document", NULL);
608 xmlSetProp (xml_node, (const xmlChar *)"uri", (const xmlChar *)key);
610 atime = g_strdup_printf ("%ld", item->atime);
611 xmlSetProp (xml_node, (const xmlChar *)"atime", (const xmlChar *)atime);
614 g_hash_table_foreach (item->values,
615 (GHFunc)save_values, xml_node);
619 get_oldest (const gchar *key, const gpointer value, const gchar ** key_to_remove)
621 const Item *item = (const Item *)value;
623 if (*key_to_remove == NULL)
625 *key_to_remove = key;
629 const Item *item_to_remove =
630 g_hash_table_lookup (ev_metadata_manager->items,
633 g_return_if_fail (item_to_remove != NULL);
635 if (item->atime < item_to_remove->atime)
637 *key_to_remove = key;
645 while (g_hash_table_size (ev_metadata_manager->items) > MAX_ITEMS)
647 gpointer key_to_remove = NULL;
649 g_hash_table_foreach (ev_metadata_manager->items,
653 g_return_if_fail (key_to_remove != NULL);
655 g_hash_table_remove (ev_metadata_manager->items,
661 ev_metadata_manager_save (gpointer data)
667 ev_metadata_manager->timeout_id = 0;
671 xmlIndentTreeOutput = TRUE;
673 doc = xmlNewDoc ((const xmlChar *)"1.0");
677 /* Create metadata root */
678 root = xmlNewDocNode (doc, NULL, (const xmlChar *)"metadata", NULL);
679 xmlDocSetRootElement (doc, root);
681 g_hash_table_foreach (ev_metadata_manager->items,
682 (GHFunc)save_item, root);
684 /* FIXME: lock file - Paolo */
685 file_name = g_build_filename (ev_dot_dir (), METADATA_FILE, NULL);
686 xmlSaveFormatFile (file_name, doc, 1);
695 ev_metadata_manager_set_int (const gchar *uri, const gchar *key, int value)
699 g_value_init (&val, G_TYPE_INT);
700 g_value_set_int (&val, value);
702 ev_metadata_manager_set (uri, key, &val);
704 g_value_unset (&val);
708 ev_metadata_manager_set_double (const gchar *uri, const gchar *key, double value)
712 g_value_init (&val, G_TYPE_DOUBLE);
713 g_value_set_double (&val, value);
715 ev_metadata_manager_set (uri, key, &val);
717 g_value_unset (&val);
721 ev_metadata_manager_set_string (const gchar *uri, const gchar *key, const gchar *value)
725 g_value_init (&val, G_TYPE_STRING);
726 g_value_set_string (&val, value);
728 ev_metadata_manager_set (uri, key, &val);
730 g_value_unset (&val);
734 ev_metadata_manager_set_boolean (const gchar *uri, const gchar *key, gboolean value)
738 g_value_init (&val, G_TYPE_BOOLEAN);
739 g_value_set_boolean (&val, value);
741 ev_metadata_manager_set (uri, key, &val);
743 g_value_unset (&val);