/* * Copyright (C) 2004-2006 Jimmy Do * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "gloo-presets.h" #include #include #define DATA_DIR_PATH "/.gnome2/timer-applet" #define DATA_FILE_PATH "/.gnome2/timer-applet/presets.xml" #define DATA_FILE_VERSION "1.1" #define OLD_DATA_FILE_PATH "/.gnome2/timer-applet-presets-old" static GObjectClass *parent_class = NULL; struct _GlooPresetsPrivate { gboolean dispose_has_run; }; /** * Saves the list of timer presets into a file. */ static void save_presets (GlooPresets *self) { xmlDocPtr doc; xmlNodePtr root; doc = xmlNewDoc ((xmlChar *) "1.0"); root = xmlNewDocNode (doc, NULL, (xmlChar *) "timerapplet", NULL); xmlDocSetRootElement (doc, root); xmlNewProp (root, (xmlChar *) "version", (xmlChar *) DATA_FILE_VERSION); { GtkTreeIter iter; gboolean valid; valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self), &iter); while (valid) { gchar *preset_name; guint preset_duration; gtk_tree_model_get (GTK_TREE_MODEL (self), &iter, GLOO_PRESETS_NAME_COL, &preset_name, GLOO_PRESETS_DURATION_COL, &preset_duration, -1); { xmlNodePtr node; gchar *preset_duration_str; node = xmlNewChild (root, NULL, (xmlChar *) "preset", NULL); preset_duration_str = g_strdup_printf ("%u", preset_duration); g_assert (preset_duration_str); xmlNewProp (node, (xmlChar *) "name", (xmlChar *) preset_name); xmlNewProp (node, (xmlChar *) "duration", (xmlChar *) preset_duration_str); g_free (preset_duration_str); preset_duration_str = NULL; } g_free (preset_name); preset_name = NULL; valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (self), &iter); } } { gchar *file_path; /* The file should already exist because the applet makes sure that the * directory and file are both created if they don't already exist on * applet startup. */ file_path = g_build_filename (g_get_home_dir (), DATA_FILE_PATH, NULL); xmlSaveFormatFile (file_path, doc, 1); g_free (file_path); file_path = NULL; } g_assert (doc); xmlFreeDoc (doc); g_signal_emit (self, GLOO_PRESETS_GET_CLASS (self)->presets_changed_signal_id, 0, NULL); } static void load_from_file (GlooPresets *self, const gchar *file_path) { xmlDocPtr doc; xmlNodePtr root; xmlNodePtr node; g_assert (file_path); doc = xmlParseFile (file_path); if (!doc) { /* If the file doesn't exist, we create an empty one */ g_print ("Couldn't find presets file. Creating new one.\n"); save_presets (self); g_print ("Created presets file.\n"); return; } root = xmlDocGetRootElement (doc); if (!root || xmlStrcmp (root->name, (xmlChar *) "timerapplet")) { /* the file was corrupted */ xmlFreeDoc (doc); save_presets (self); return; } node = root->xmlChildrenNode; while (node) { if (xmlStrcmp (node->name, (xmlChar *) "preset") == 0) { xmlChar *preset_name; guint preset_duration; preset_name = xmlGetProp (node, (xmlChar *) "name"); { xmlChar *preset_duration_str; preset_duration_str = xmlGetProp (node, (xmlChar *) "duration"); g_assert (preset_duration_str); preset_duration = atoi ((const char *)preset_duration_str); xmlFree (preset_duration_str); preset_duration_str = NULL; } g_assert (preset_name); gloo_presets_add_preset (self, (const gchar *)preset_name, preset_duration); xmlFree (preset_name); preset_name = NULL; } node = node->next; } xmlFreeDoc (doc); doc = NULL; } static void load_presets_from_old_file (GlooPresets *self, const gchar *file_path) { xmlDocPtr doc; xmlNodePtr root; xmlNodePtr node; doc = xmlParseFile (file_path); if (!doc) { g_warning ("Old presets file should exist.\n"); return; } root = xmlDocGetRootElement (doc); if (!root || xmlStrcmp (root->name, (xmlChar *) "timerapplet")) { /* the file was corrupted */ xmlFreeDoc (doc); g_warning ("Old presets file is corrupted.\n"); return; } node = root->xmlChildrenNode; while (node) { if (xmlStrcmp (node->name, (xmlChar *) "profile") == 0) { xmlChar *preset_name; gdouble preset_duration; preset_name = xmlGetProp (node, (xmlChar *) "name"); /* Get the duration and convert it to a gdouble */ { xmlChar *preset_duration_str; preset_duration_str = xmlGetProp (node, (xmlChar *) "duration"); g_assert (preset_duration_str); preset_duration = atof ((const char *)preset_duration_str); xmlFree (preset_duration_str); preset_duration_str = NULL; } g_assert (preset_name); g_assert (preset_duration >= 0); gloo_presets_add_preset (self, (const gchar *)preset_name, preset_duration); xmlFree (preset_name); preset_name = NULL; } node = node->next; } xmlFreeDoc (doc); doc = NULL; } /** * Load the list of timer presets from the data file. */ static void load_presets (GlooPresets *self) { gchar *file_path; gchar *dir_path; gchar *old_file_path; file_path = g_build_filename (g_get_home_dir (), DATA_FILE_PATH, NULL); dir_path = g_build_filename (g_get_home_dir (), DATA_DIR_PATH, NULL); old_file_path = g_build_filename (g_get_home_dir (), OLD_DATA_FILE_PATH, NULL); if (g_file_test (dir_path, G_FILE_TEST_EXISTS)) { if (!g_file_test (dir_path, G_FILE_TEST_IS_DIR)) { g_rename (dir_path, old_file_path); g_mkdir_with_parents (dir_path, 0700); load_presets_from_old_file (self, old_file_path); save_presets (self); } else { /* else, it's a directory, so we're all good. */ load_from_file (self, file_path); } } else { /* else directory doesn't exist */ g_mkdir_with_parents (dir_path, 0700); load_from_file (self, file_path); } g_free (file_path); file_path = NULL; g_free (dir_path); dir_path = NULL; g_free (old_file_path); old_file_path = NULL; } static void row_ref_to_iter (GtkTreeModel *tree_model, GtkTreeRowReference *row_ref, GtkTreeIter *tree_iter) { GtkTreePath *path; gboolean iter_set; g_assert (tree_model); g_assert (row_ref); g_assert (tree_iter); path = gtk_tree_row_reference_get_path (row_ref); iter_set = gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_model), tree_iter, path); g_assert (iter_set); g_free (path); path = NULL; } GtkTreeRowReference * row_ref_from_iter (GtkTreeModel *tree_model, GtkTreeIter *tree_iter) { GtkTreeRowReference *new_row_ref; GtkTreePath *tree_path; g_assert (tree_model); g_assert (tree_iter); tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_model), tree_iter); g_assert (tree_path); new_row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (tree_model), tree_path); g_assert (new_row_ref); g_free (tree_path); tree_path = NULL; return new_row_ref; } static void gloo_presets_instance_init (GTypeInstance *instance, gpointer g_class) { GlooPresets *self; self = (GlooPresets *)instance; self->priv = g_new (GlooPresetsPrivate, 1); self->priv->dispose_has_run = FALSE; static GType col_types[] = { G_TYPE_STRING, G_TYPE_UINT }; gtk_list_store_set_column_types (GTK_LIST_STORE (self), 2, col_types); load_presets (self); } static void gloo_presets_dispose (GObject *obj) { GlooPresets *self; self = (GlooPresets *)obj; if (self->priv->dispose_has_run) { return; } self->priv->dispose_has_run = TRUE; G_OBJECT_CLASS (parent_class)->dispose (obj); } static void gloo_presets_finalize (GObject *obj) { GlooPresets *self; self = (GlooPresets *)obj; g_free (self->priv); self->priv = NULL; G_OBJECT_CLASS (parent_class)->finalize (obj); } /** * Used to add a new timer preset with the given name and duration */ GtkTreeRowReference * gloo_presets_add_preset (GlooPresets *self, const gchar *name, guint duration) { GtkTreeIter iter; gtk_list_store_append (GTK_LIST_STORE (self), &iter); gtk_list_store_set (GTK_LIST_STORE (self), &iter, GLOO_PRESETS_NAME_COL, name, GLOO_PRESETS_DURATION_COL, duration, -1); save_presets (self); return row_ref_from_iter (GTK_TREE_MODEL (self), &iter); } /** * Remove the given timer preset referenced by row_ref */ void gloo_presets_remove_preset (GlooPresets *self, GtkTreeRowReference *row_ref) { GtkTreeIter iter; gboolean iter_reset; row_ref_to_iter (GTK_TREE_MODEL (self), row_ref, &iter); iter_reset = gtk_list_store_remove (GTK_LIST_STORE (self), &iter); save_presets (self); } /** * Update the timer preset at row_ref to the given name and duration */ void gloo_presets_update_preset (GlooPresets *self, GtkTreeRowReference *row_ref, const gchar *name, guint duration) { GtkTreeIter iter; row_ref_to_iter (GTK_TREE_MODEL (self), row_ref, &iter); gtk_list_store_set (GTK_LIST_STORE (self), &iter, GLOO_PRESETS_NAME_COL, name, GLOO_PRESETS_DURATION_COL, duration, -1); save_presets (self); } /** * Returns the name and duration for the preset at the given row. * User should free 'name' when done. */ void gloo_presets_get_name_and_duration (GlooPresets *self, GtkTreeRowReference *row_ref, gchar **name, guint *duration) { GtkTreeIter iter; g_assert (self); g_assert (row_ref); g_assert (name); g_assert (duration); row_ref_to_iter (GTK_TREE_MODEL (self), row_ref, &iter); gtk_tree_model_get (GTK_TREE_MODEL (self), &iter, GLOO_PRESETS_NAME_COL, name, GLOO_PRESETS_DURATION_COL, duration, -1); } static void gloo_presets_class_init (gpointer g_class, gpointer g_class_data) { GObjectClass *gobject_class; GlooPresetsClass *klass; gobject_class = G_OBJECT_CLASS (g_class); klass = GLOO_PRESETS_CLASS (g_class); gobject_class->dispose = gloo_presets_dispose; gobject_class->finalize = gloo_presets_finalize; parent_class = g_type_class_peek_parent (klass); klass->presets_changed_signal_id = g_signal_newv ("presets-changed", G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, NULL, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL); } GType gloo_presets_get_type (void) { static GType type = 0; if (type == 0) { static const GTypeInfo info = { sizeof (GlooPresetsClass), NULL, NULL, gloo_presets_class_init, NULL, NULL, sizeof (GlooPresets), 0, gloo_presets_instance_init }; type = g_type_register_static (GTK_TYPE_LIST_STORE, "GlooPresetsType", &info, 0); } return type; }