1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2005 Novell, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU Lesser General Public
7 * License as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
25 #include <libxml/parser.h>
27 #include <glib/gi18n.h>
28 #include <gconf/gconf-client.h>
29 #include "e-categories.h"
31 #include "libedataserver-private.h"
40 static CategoryInfo default_categories[] = {
41 { N_("Anniversary") },
42 { N_("Birthday"), "category_birthday_16.png" },
43 { N_("Business"), "category_business_16.png" },
44 { N_("Competition") },
45 { N_("Favorites"), "category_favorites_16.png" },
46 { N_("Gifts"), "category_gifts_16.png" },
47 { N_("Goals/Objectives"), "category_goals_16.png" },
48 { N_("Holiday"), "category_holiday_16.png" },
49 { N_("Holiday Cards"), "category_holiday-cards_16.png" },
50 /* important people (e.g. new business partners) */
51 { N_("Hot Contacts"), "category_hot-contacts_16.png" },
52 { N_("Ideas"), "category_ideas_16.png" },
53 { N_("International"), "category_international_16.png" },
54 { N_("Key Customer"), "category_key-customer_16.png" },
55 { N_("Miscellaneous"), "category_miscellaneous_16.png" },
56 { N_("Personal"), "category_personal_16.png" },
57 { N_("Phone Calls"), "category_phonecalls_16.png" },
58 { N_("Status"), "category_status_16.png" },
59 { N_("Strategies"), "category_strategies_16.png" },
60 { N_("Suppliers"), "category_suppliers_16.png" },
61 { N_("Time & Expenses"), "category_time-and-expenses_16.png" },
67 static gboolean initialized = FALSE;
68 static GHashTable *categories_table = NULL;
69 static gboolean save_is_pending = FALSE;
70 static guint idle_id = 0;
73 build_categories_filename (void)
75 return g_build_filename (g_get_home_dir (),
76 ".evolution", "categories.xml", NULL);
80 free_category_info (CategoryInfo *cat_info)
82 g_free (cat_info->category);
83 g_free (cat_info->icon_file);
84 g_free (cat_info->color);
89 escape_string (const gchar *source)
93 buffer = g_string_sized_new (strlen (source));
98 g_string_append_len (buffer, "<", 4);
101 g_string_append_len (buffer, ">", 4);
104 g_string_append_len (buffer, "&", 5);
107 g_string_append_len (buffer, """, 6);
110 g_string_append_c (buffer, *source);
116 return g_string_free (buffer, FALSE);
120 hash_to_xml_string (gpointer key, gpointer value, gpointer user_data)
122 CategoryInfo *cat_info = value;
123 GString *string = user_data;
126 g_string_append_len (string, "\t<category", 10);
128 category = escape_string (cat_info->category);
129 g_string_append_printf (string, " a=\"%s\"", category);
132 if (cat_info->icon_file != NULL)
133 g_string_append_printf (
134 string, " icon=\"%s\"", cat_info->icon_file);
136 if (cat_info->color != NULL)
137 g_string_append_printf (
138 string, " color=\"%s\"", cat_info->color);
140 g_string_append_printf (
141 string, " searchable=\"%d\"", cat_info->searchable);
143 g_string_append_len (string, "/>\n", 3);
147 idle_saver_cb (gpointer user_data)
152 GError *error = NULL;
154 if (!save_is_pending)
157 filename = build_categories_filename ();
159 g_debug ("Saving categories to \"%s\"", filename);
161 /* build the file contents */
162 buffer = g_string_new ("<categories>\n");
163 g_hash_table_foreach (categories_table, hash_to_xml_string, buffer);
164 g_string_append_len (buffer, "</categories>\n", 14);
165 contents = g_string_free (buffer, FALSE);
167 if (!g_file_set_contents (filename, contents, -1, &error)) {
168 g_warning ("Unable to save categories: %s", error->message);
169 g_error_free (error);
174 save_is_pending = FALSE;
182 save_categories (void)
184 save_is_pending = TRUE;
187 idle_id = g_idle_add (idle_saver_cb, NULL);
191 parse_categories (const gchar *contents, gsize length)
197 doc = xmlParseMemory (contents, length);
199 g_warning ("Unable to parse categories");
203 node = xmlDocGetRootElement (doc);
205 g_warning ("Unable to parse categories");
210 for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
211 xmlChar *category, *icon, *color, *searchable;
213 category = xmlGetProp (node, (xmlChar *) "a");
214 icon = xmlGetProp (node, (xmlChar *) "icon");
215 color = xmlGetProp (node, (xmlChar *) "color");
216 searchable = xmlGetProp (node, (xmlChar *) "searchable");
218 if (category != NULL) {
223 (searchable != NULL) &&
224 strcmp ((gchar *) searchable, "0") != 0);
231 xmlFree (searchable);
240 load_categories (void)
246 GError *error = NULL;
249 filename = build_categories_filename ();
251 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
254 g_debug ("Loading categories from \"%s\"", filename);
256 if (!g_file_get_contents (filename, &contents, &length, &error)) {
257 g_warning ("Unable to load categories: %s", error->message);
258 g_error_free (error);
262 n_added = parse_categories (contents, length);
272 migrate_old_icon_file (gpointer key, gpointer value, gpointer user_data)
274 CategoryInfo *info = value;
277 if (info->icon_file == NULL)
280 /* We can't be sure where the old icon files were stored, but
281 * a good guess is (E_DATA_SERVER_IMAGESDIR "-2.x"). Convert
282 * any such paths to just E_DATA_SERVER_IMAGESDIR. */
283 if (g_str_has_prefix (info->icon_file, E_DATA_SERVER_IMAGESDIR)) {
284 basename = g_path_get_basename (info->icon_file);
285 g_free (info->icon_file);
286 info->icon_file = g_build_filename (
287 E_DATA_SERVER_IMAGESDIR, basename, NULL);
293 migrate_old_categories (void)
295 /* Try migrating old category settings from GConf to the new
296 * category XML file. If successful, unset the old GConf key
297 * so that this is a one-time-only operation. */
299 const gchar *key = "/apps/evolution/general/category_master_list";
305 client = gconf_client_get_default ();
306 string = gconf_client_get_string (client, key, NULL);
307 if (string == NULL || *string == '\0')
310 g_debug ("Loading categories from GConf key \"%s\"", key);
312 n_added = parse_categories (string, strlen (string));
316 /* default icon files are now in an unversioned directory */
317 g_hash_table_foreach (categories_table, migrate_old_icon_file, NULL);
319 gconf_client_unset (client, key, NULL);
322 g_object_unref (client);
329 load_default_categories (void)
331 CategoryInfo *cat_info = default_categories;
333 /* Note: All default categories are searchable. */
334 while (cat_info->category != NULL) {
335 if (cat_info->icon_file != NULL)
336 cat_info->icon_file = g_build_filename (E_DATA_SERVER_IMAGESDIR, cat_info->icon_file, NULL);
338 gettext (cat_info->category),
339 NULL, cat_info->icon_file, TRUE);
340 g_free (cat_info->icon_file);
346 finalize_categories (void)
349 idle_saver_cb (NULL);
352 g_source_remove (idle_id);
356 if (categories_table != NULL) {
357 g_hash_table_destroy (categories_table);
358 categories_table = NULL;
365 initialize_categories (void)
374 categories_table = g_hash_table_new_full (
375 g_str_hash, g_str_equal, g_free,
376 (GDestroyNotify) free_category_info);
378 g_atexit (finalize_categories);
380 n_added = load_categories ();
382 g_debug ("Loaded %d categories", n_added);
383 save_is_pending = FALSE;
387 n_added = migrate_old_categories ();
389 g_debug ("Loaded %d categories", n_added);
394 load_default_categories ();
395 g_debug ("Loaded default categories");
400 add_hash_to_list (gpointer key, gpointer value, gpointer user_data)
402 GList **list = user_data;
404 *list = g_list_prepend (*list, key);
408 * e_categories_get_list:
410 * Returns a sorted list of all the category names currently configured.
412 * Return value: a sorted GList containing the names of the categories. The
413 * list should be freed using g_list_free, but the names of the categories
414 * should not be touched at all, they are internal strings.
417 e_categories_get_list (void)
422 initialize_categories ();
424 g_hash_table_foreach (categories_table, add_hash_to_list, &list);
426 return g_list_sort (list, (GCompareFunc) g_utf8_collate);
431 * @category: name of category to add.
432 * @color: associated color.
433 * @icon_file: full path of the icon associated to the category.
434 * @searchable: whether the category can be used for searching in the GUI.
436 * Adds a new category, with its corresponding color and icon, to the
437 * configuration database.
440 e_categories_add (const char *category, const char *color, const char *icon_file, gboolean searchable)
442 CategoryInfo *cat_info;
444 g_return_if_fail (category != NULL);
447 initialize_categories ();
449 /* add the new category */
450 cat_info = g_new0 (CategoryInfo, 1);
451 cat_info->category = g_strdup (category);
452 cat_info->color = g_strdup (color);
453 cat_info->icon_file = g_strdup (icon_file);
454 cat_info->searchable = searchable;
456 g_hash_table_insert (categories_table, g_strdup (category), cat_info);
462 * e_categories_remove:
463 * @category: category to be removed.
465 * Removes the given category from the configuration.
468 e_categories_remove (const char *category)
470 g_return_if_fail (category != NULL);
473 initialize_categories ();
475 if (g_hash_table_remove (categories_table, category))
480 * e_categories_exist:
481 * @category: category to be searched.
483 * Checks whether the given category is available in the configuration.
485 * Return value: %TRUE if the category is available, %FALSE otherwise.
488 e_categories_exist (const char *category)
490 g_return_val_if_fail (category != NULL, FALSE);
493 initialize_categories ();
495 return (g_hash_table_lookup (categories_table, category) != NULL);
499 * e_categories_get_color_for:
500 * @category: category to retrieve the color for.
502 * Gets the color associated with the given category.
504 * Return value: a string representation of the color.
507 e_categories_get_color_for (const char *category)
509 CategoryInfo *cat_info;
511 g_return_val_if_fail (category != NULL, NULL);
514 initialize_categories ();
516 cat_info = g_hash_table_lookup (categories_table, category);
517 if (cat_info == NULL)
520 return cat_info->color;
524 * e_categories_set_color_for:
525 * @category: category to set the color for.
528 * Sets the color associated with the given category.
531 e_categories_set_color_for (const char *category, const char *color)
533 CategoryInfo *cat_info;
535 g_return_if_fail (category != NULL);
538 initialize_categories ();
540 cat_info = g_hash_table_lookup (categories_table, category);
541 g_return_if_fail (cat_info != NULL);
543 g_free (cat_info->color);
544 cat_info->color = g_strdup (color);
549 * e_categories_get_icon_file_for:
550 * @category: category to retrieve the icon file for.
552 * Gets the icon file associated with the given category.
554 * Return value: a string representation of the color.
557 e_categories_get_icon_file_for (const char *category)
559 CategoryInfo *cat_info;
561 g_return_val_if_fail (category != NULL, NULL);
564 initialize_categories ();
566 cat_info = g_hash_table_lookup (categories_table, category);
567 if (cat_info == NULL)
570 return cat_info->icon_file;
574 * e_categories_set_icon_file_for:
575 * @category: category to set the icon file for.
578 * Sets the icon file associated with the given category.
581 e_categories_set_icon_file_for (const char *category, const char *icon_file)
583 CategoryInfo *cat_info;
585 g_return_if_fail (category != NULL);
588 initialize_categories ();
590 cat_info = g_hash_table_lookup (categories_table, category);
591 g_return_if_fail (cat_info != NULL);
593 g_free (cat_info->icon_file);
594 cat_info->icon_file = g_strdup (icon_file);
599 * e_categories_is_searchable:
600 * @category: category name.
602 * Gets whether the given calendar is to be used for searches in the GUI.
604 * Return value; %TRUE% if the category is searchable, %FALSE% if not.
607 e_categories_is_searchable (const char *category)
609 CategoryInfo *cat_info;
611 g_return_val_if_fail (category != NULL, FALSE);
614 initialize_categories ();
616 cat_info = g_hash_table_lookup (categories_table, category);
617 if (cat_info == NULL)
620 return cat_info->searchable;