gnc-plugin-file-history.c

Go to the documentation of this file.
00001 /* 
00002  * gnc-plugin-file-history.c -- 
00003  * Copyright (C) 2003,2005 David Hampton <hampton@employees.org>
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License as
00007  * published by the Free Software Foundation; either version 2 of
00008  * the License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, contact:
00017  *
00018  * Free Software Foundation           Voice:  +1-617-542-5942
00019  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
00020  * Boston, MA  02110-1301,  USA       gnu@gnu.org
00021  */
00022 
00032 #include "config.h"
00033 
00034 #include <gtk/gtk.h>
00035 #include <glib/gi18n.h>
00036 #include <glib/gprintf.h>
00037 #include <string.h>
00038 
00039 #include "gnc-gkeyfile-utils.h"
00040 #include "gnc-file.h"
00041 #include "gnc-main-window.h"
00042 #include "gnc-plugin-file-history.h"
00043 #include "gnc-window.h"
00044 #include "gnc-engine.h"
00045 #include "gnc-gconf-utils.h"
00046 
00047 static GObjectClass *parent_class = NULL;
00048 
00049 #define FILENAME_STRING "filename"
00050 
00051 static void gnc_plugin_file_history_class_init (GncPluginFileHistoryClass *klass);
00052 static void gnc_plugin_file_history_init (GncPluginFileHistory *plugin);
00053 static void gnc_plugin_file_history_finalize (GObject *object);
00054 
00055 static void gnc_plugin_file_history_add_to_window (GncPlugin *plugin, GncMainWindow *window, GQuark type);
00056 static void gnc_plugin_file_history_remove_from_window (GncPlugin *plugin, GncMainWindow *window, GQuark type);
00057 
00058 
00060 static QofLogModule log_module = GNC_MOD_GUI;
00061 
00062 /* Command callbacks */
00063 static void gnc_plugin_file_history_cmd_open_file (GtkAction *action, GncMainWindowActionData *data);
00064 
00065 
00067 #define PLUGIN_ACTIONS_NAME "gnc-plugin-file-history-actions"
00068 
00069 #define PLUGIN_UI_FILENAME  "gnc-plugin-file-history-ui.xml"
00070 
00071 #define GNOME1_HISTORY "History"
00072 #define GNOME1_MAXFILES "MaxFiles"
00073 
00079 static GtkActionEntry gnc_plugin_actions [] = {
00080         { "RecentFile0Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00081         { "RecentFile1Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00082         { "RecentFile2Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00083         { "RecentFile3Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00084         { "RecentFile4Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00085         { "RecentFile5Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00086         { "RecentFile6Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00087         { "RecentFile7Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00088         { "RecentFile8Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00089         { "RecentFile9Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00090 };
00092 static guint gnc_plugin_n_actions = G_N_ELEMENTS (gnc_plugin_actions);
00093 
00094 
00097 typedef struct GncPluginFileHistoryPrivate
00098 {
00099         gpointer dummy;
00100 } GncPluginFileHistoryPrivate;
00101 
00102 
00103 #define GNC_PLUGIN_FILE_HISTORY_GET_PRIVATE(o)  \
00104    (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_PLUGIN_FILE_HISTORY, GncPluginFileHistoryPrivate))
00105 
00106 /************************************************************
00107  *                     Other Functions                      *
00108  ************************************************************/
00109 
00118 static gchar *
00119 gnc_history_gconf_index_to_key (guint index)
00120 {
00121   return g_strdup_printf(HISTORY_STRING_FILE_N, index);
00122 }
00123 
00124 
00133 static gint
00134 gnc_history_gconf_key_to_index (const gchar *key)
00135 {
00136   gint index, result;
00137 
00138   result = sscanf(key, HISTORY_STRING_FILE_N, &index);
00139   if (result != 1)
00140     return -1;
00141   if ((index < 0) || (index >= gnc_plugin_n_actions))
00142       return -1;
00143   return index;
00144 }
00145 
00146 
00147 /*  Add a file name to the front of the file "history list".  If the
00148  *  name already exist on the list, then it is moved from its current
00149  *  location to the front of the list.  The "list" is actually a
00150  *  sequence of up to ten gconf keys.
00151  */
00152 void
00153 gnc_history_add_file (const char *newfile)
00154 {
00155   gchar *filename, *from, *to;
00156   gint i, last;
00157 
00158   if (newfile == NULL)
00159     return;
00160   if (!g_utf8_validate(newfile, -1, NULL))
00161     return;
00162 
00163   /*
00164    * Look for the filename in gconf.
00165    */
00166   last = MAX_HISTORY_FILES - 1;
00167   for (i = 0; i < MAX_HISTORY_FILES; i++) {
00168     from = gnc_history_gconf_index_to_key(i);
00169     filename = gnc_gconf_get_string(HISTORY_STRING_SECTION, from, NULL);
00170     g_free(from);
00171 
00172     if (!filename) {
00173       last = i;
00174       break;
00175     }
00176     if (g_utf8_collate(newfile, filename) == 0) {
00177       g_free(filename);
00178       last = i;
00179       break;
00180     }
00181     g_free(filename);
00182   }
00183 
00184   /*
00185    * Shuffle filenames upward through gconf.
00186    */
00187   to = gnc_history_gconf_index_to_key(last);
00188   for (i = last - 1; i >= 0; i--) {
00189     from = gnc_history_gconf_index_to_key(i);
00190     filename = gnc_gconf_get_string(HISTORY_STRING_SECTION, from, NULL);
00191     if (filename) {
00192       gnc_gconf_set_string(HISTORY_STRING_SECTION, to, filename, NULL);
00193       g_free(filename);
00194     } else {
00195       gnc_gconf_unset(HISTORY_STRING_SECTION, to, NULL);
00196     }
00197     g_free(to);
00198     to = from;
00199   }
00200 
00201   /*
00202    * Store the new zero entry.
00203    */
00204   gnc_gconf_set_string(HISTORY_STRING_SECTION, to, newfile, NULL);
00205   g_free(to);
00206 }
00207 
00208 
00214 void
00215 gnc_history_remove_file (const char *oldfile)
00216 {
00217   gchar *filename, *from, *to;
00218   gint i, j;
00219 
00220   if (!oldfile)
00221     return;
00222   if (!g_utf8_validate(oldfile, -1, NULL))
00223     return;
00224 
00225   for (i=0, j=0; i<MAX_HISTORY_FILES; i++) {
00226     from = gnc_history_gconf_index_to_key(i);
00227     filename = gnc_gconf_get_string(HISTORY_STRING_SECTION, from, NULL);
00228 
00229     if (filename) {
00230       if (g_utf8_collate(oldfile, filename) == 0) {
00231         gnc_gconf_unset(HISTORY_STRING_SECTION, from, NULL);
00232       } else {
00233         if (i != j) {
00234           to = gnc_history_gconf_index_to_key(j);
00235           gnc_gconf_set_string(HISTORY_STRING_SECTION, to, filename, NULL);
00236           gnc_gconf_unset(HISTORY_STRING_SECTION, from, NULL);
00237           g_free(to);
00238         }
00239         j++;
00240       }
00241     }
00242     g_free(from);
00243   }
00244 }
00245 
00246 /*  Retrieve the name of the file most recently accessed.  This is the
00247  *  name at the front of the list.  Since the "list" is actually a
00248  *  sequence of up to ten gconf keys, this is the value of key zero.
00249  */
00250 char *
00251 gnc_history_get_last (void)
00252 {
00253   char *filename, *key;
00254 
00255   key = gnc_history_gconf_index_to_key(0);
00256   filename = gnc_gconf_get_string(HISTORY_STRING_SECTION, key, NULL);
00257   g_free(key);
00258 
00259   return filename;
00260 }
00261 
00262 
00263 /************************************************************
00264  *                     Other Functions                      *
00265  ************************************************************/
00266 
00276 static gchar *
00277 gnc_history_generate_label (int index, const gchar *filename)
00278 {
00279         const gchar *src;
00280         gchar *result, *dst;
00281         gunichar  unichar;
00282 
00283         /* raw byte length, not num characters */
00284         result = g_malloc(strlen(filename) * 2);
00285 
00286         dst = result;
00287         if (index < 10)
00288           dst += g_sprintf(result, "_%d ", (index + 1) % 10);
00289 
00290         /* Find the filename portion of the path */
00291         src = g_utf8_strrchr(filename, -1, G_DIR_SEPARATOR);
00292         if (src) {
00293           src = g_utf8_next_char(src);
00294 
00295           /* Fix up any underline characters so they aren't mistaken as
00296            * command accelerator keys. */
00297           for ( ; *src; src = g_utf8_next_char(src)) {
00298             unichar = g_utf8_get_char(src);
00299             dst += g_unichar_to_utf8 (unichar, dst);
00300 
00301             if (unichar == '_')
00302               dst += g_unichar_to_utf8 ('_', dst);
00303           }
00304         }
00305 
00306         *dst = '\0';
00307         return result;
00308 }
00309 
00310 
00328 static void
00329 gnc_history_update_action (GncMainWindow *window,
00330                            gint index,
00331                            const gchar *filename)
00332 {
00333         GtkActionGroup *action_group;
00334         GtkAction *action;
00335         gchar *action_name, *label_name, *old_filename;
00336         gint limit;
00337 
00338         ENTER("window %p, index %d, filename %s", window, index,
00339               filename ? filename : "(null)");
00340         /* Get the action group */
00341         action_group =
00342           gnc_main_window_get_action_group(window, PLUGIN_ACTIONS_NAME);
00343 
00344         action_name = g_strdup_printf("RecentFile%dAction", index);
00345         action = gtk_action_group_get_action (action_group, action_name);
00346 
00347         limit = gnc_gconf_get_int (HISTORY_STRING_SECTION,
00348                                    HISTORY_STRING_MAXFILES,
00349                                    NULL);
00350 
00351         if (filename && (strlen(filename) > 0) && (index < limit)) {
00352           /* set the menu label (w/accelerator) */
00353           label_name = gnc_history_generate_label(index, filename);
00354           g_object_set(G_OBJECT(action), "label", label_name, "visible", TRUE, NULL);
00355           g_free(label_name);
00356 
00357           /* set the filename for the callback function */
00358           old_filename = g_object_get_data(G_OBJECT(action), FILENAME_STRING);
00359           if (old_filename)
00360             g_free(old_filename);
00361           g_object_set_data(G_OBJECT(action), FILENAME_STRING, g_strdup(filename));
00362         } else {
00363           gtk_action_set_visible(action, FALSE);
00364         }
00365         g_free(action_name);
00366         LEAVE("");
00367 }
00368 
00369 
00378 static void
00379 gnc_history_update_menus (GncMainWindow *window)
00380 {
00381         gchar *filename, *key;
00382         guint i;
00383 
00384         ENTER("");
00385         for (i = 0; i < MAX_HISTORY_FILES; i++) {
00386           key = gnc_history_gconf_index_to_key(i);
00387           filename = gnc_gconf_get_string(HISTORY_STRING_SECTION, key, NULL);
00388           gnc_history_update_action(window, i, filename);
00389           g_free(filename);
00390           g_free(key);
00391         }
00392         LEAVE("");
00393 }
00394 
00395 
00411 static void
00412 gnc_plugin_history_list_changed (GConfClient *client,
00413                                  guint cnxn_id,
00414                                  GConfEntry *entry,
00415                                  gpointer user_data)
00416 {
00417         GncMainWindow *window;
00418         GConfValue *value;
00419         const gchar *fullkey, *key, *filename;
00420         gint index;
00421 
00422         ENTER("");
00423         window = GNC_MAIN_WINDOW(user_data);
00424 
00425         fullkey = gconf_entry_get_key(entry);
00426         key = strrchr(fullkey, '/') + 1;
00427         if (strcmp(key, HISTORY_STRING_MAXFILES) == 0) {
00428           gnc_history_update_menus (window);
00429           LEAVE("updated maxfiles");
00430           return;
00431         }
00432         index = gnc_history_gconf_key_to_index(key);
00433         if (index < 0) {
00434           LEAVE("bad index");
00435           return;
00436         }
00437 
00438         value = gconf_entry_get_value(entry);
00439         if (!value) {
00440           LEAVE("No gconf value");
00441           return;
00442         }
00443         filename = gconf_value_get_string(value);
00444         gnc_history_update_action (window, index, filename);
00445 
00446         gnc_main_window_actions_updated (window);
00447         LEAVE("");
00448 }
00449 
00450 
00451 /* This routine copies the gnucash 1.x file history list over to
00452  * gnucash 2.0. */
00453 static void
00454 gnc_plugin_history_list_from_gnucash1 (void)
00455 {
00456   GKeyFile *keyfile;
00457   const gchar *home;
00458   gchar *mdi_file, *value;
00459   gchar **keys, **key, *new_key;
00460   gint file_id, max;
00461 
00462   /* First test if there are already files in the gconf file history.
00463    * If so, then bail out now. */
00464   value = gnc_gconf_get_string(HISTORY_STRING_SECTION, "file0", NULL);
00465   if (value) {
00466     g_free(value);
00467     return;
00468   }
00469 
00470   home = g_get_home_dir();
00471   if (!home)
00472     return;
00473 
00474   /* Copy the old values from the gnucash 1.x/gnome1 settings file to
00475    * the gnucash 2.x/gconf settings area.  */
00476   mdi_file = g_build_filename(home, ".gnome", "GnuCash", (gchar *)NULL);
00477   keyfile = gnc_key_file_load_from_file (mdi_file, FALSE, FALSE, NULL);
00478   if (keyfile) {
00479     keys = g_key_file_get_keys(keyfile, GNOME1_HISTORY, NULL, NULL);
00480     if (keys) {
00481       for (key = keys; *key; key++) {
00482         if (!strcmp(*key, GNOME1_MAXFILES)) {
00483           max = g_key_file_get_integer(keyfile, GNOME1_HISTORY,
00484                                        GNOME1_MAXFILES, NULL);
00485           printf("Found old maxfiles: %d\n", max);
00486           if ((max > 0) && (max < MAX_HISTORY_FILES))
00487             printf("Setting maxfiles: %d\n\n", max);
00488             gnc_gconf_set_int(HISTORY_STRING_SECTION, HISTORY_STRING_MAXFILES,
00489                               max, NULL);
00490           continue;
00491         }
00492 
00493         if (sscanf(*key, "File%d", &file_id) == 1) {
00494           value = g_key_file_get_string(keyfile, GNOME1_HISTORY, *key, NULL);
00495           if (!value)
00496             continue;
00497           printf("Found old file %d: %s\n", file_id, value);
00498           new_key = g_strdup_printf(HISTORY_STRING_FILE_N, file_id);
00499           gnc_gconf_set_string (HISTORY_STRING_SECTION, new_key, value, NULL);
00500           printf("Setting %s: %s\n\n", new_key, value);
00501           g_free(new_key);
00502           g_free(value);
00503         }
00504       }
00505       g_strfreev(keys);
00506     }
00507     g_key_file_free(keyfile);
00508   }
00509 
00510   g_free(mdi_file);
00511 }
00512 
00513 /************************************************************
00514  *                  Object Implementation                   *
00515  ************************************************************/
00516 
00517 /*  Get the type of a file history plugin.  */
00518 GType
00519 gnc_plugin_file_history_get_type (void)
00520 {
00521         static GType gnc_plugin_file_history_type = 0;
00522 
00523         if (gnc_plugin_file_history_type == 0) {
00524                 static const GTypeInfo our_info = {
00525                         sizeof (GncPluginFileHistoryClass),
00526                         NULL,           /* base_init */
00527                         NULL,           /* base_finalize */
00528                         (GClassInitFunc) gnc_plugin_file_history_class_init,
00529                         NULL,           /* class_finalize */
00530                         NULL,           /* class_data */
00531                         sizeof (GncPluginFileHistory),
00532                         0,
00533                         (GInstanceInitFunc) gnc_plugin_file_history_init
00534                 };
00535 
00536                 gnc_plugin_file_history_type =
00537                   g_type_register_static (GNC_TYPE_PLUGIN,
00538                                           "GncPluginFileHistory",
00539                                           &our_info, 0);
00540         }
00541 
00542         return gnc_plugin_file_history_type;
00543 }
00544 
00545 
00547 static void
00548 gnc_plugin_file_history_class_init (GncPluginFileHistoryClass *klass)
00549 {
00550         GObjectClass *object_class = G_OBJECT_CLASS (klass);
00551         GncPluginClass *plugin_class = GNC_PLUGIN_CLASS (klass);
00552 
00553         parent_class = g_type_class_peek_parent (klass);
00554 
00555         object_class->finalize = gnc_plugin_file_history_finalize;
00556 
00557         /* plugin info */
00558         plugin_class->plugin_name   = GNC_PLUGIN_FILE_HISTORY_NAME;
00559 
00560         /* function overrides */
00561         plugin_class->add_to_window = gnc_plugin_file_history_add_to_window;
00562         plugin_class->remove_from_window =
00563           gnc_plugin_file_history_remove_from_window;
00564 
00565         /* widget addition/removal */
00566         plugin_class->actions_name  = PLUGIN_ACTIONS_NAME;
00567         plugin_class->actions       = gnc_plugin_actions;
00568         plugin_class->n_actions     = gnc_plugin_n_actions;
00569         plugin_class->ui_filename   = PLUGIN_UI_FILENAME;
00570 
00571         plugin_class->gconf_section = HISTORY_STRING_SECTION;
00572         plugin_class->gconf_notifications = gnc_plugin_history_list_changed;
00573 
00574         g_type_class_add_private(klass, sizeof(GncPluginFileHistoryPrivate));
00575 
00576         gnc_plugin_history_list_from_gnucash1();
00577 }
00578 
00579 
00581 static void
00582 gnc_plugin_file_history_init (GncPluginFileHistory *plugin)
00583 {
00584         ENTER("plugin %p", plugin);
00585         LEAVE("");
00586 }
00587 
00588 
00590 static void
00591 gnc_plugin_file_history_finalize (GObject *object)
00592 {
00593         GncPluginFileHistory *plugin;
00594         GncPluginFileHistoryPrivate *priv;
00595 
00596         g_return_if_fail (GNC_IS_PLUGIN_FILE_HISTORY (object));
00597 
00598         ENTER("plugin %p", object);
00599         plugin = GNC_PLUGIN_FILE_HISTORY (object);
00600         priv = GNC_PLUGIN_FILE_HISTORY_GET_PRIVATE (plugin);
00601 
00602         G_OBJECT_CLASS (parent_class)->finalize (object);
00603         LEAVE("");
00604 }
00605 
00606 
00607 /*  Create a new file history plugin.  This plugin attaches the file
00608  *  history menu to any window that is opened.
00609  */
00610 GncPlugin *
00611 gnc_plugin_file_history_new (void)
00612 {
00613         GncPlugin *plugin_page = NULL;
00614 
00615         ENTER("");
00616         plugin_page = GNC_PLUGIN (g_object_new (GNC_TYPE_PLUGIN_FILE_HISTORY, NULL));
00617         LEAVE("plugin %p", plugin_page);
00618         return plugin_page;
00619 }
00620 
00621 /************************************************************
00622  *              Plugin Function Implementation              *
00623  ************************************************************/
00624 
00641 static void
00642 gnc_plugin_file_history_add_to_window (GncPlugin *plugin,
00643                                        GncMainWindow *window,
00644                                        GQuark type)
00645 {
00646         gnc_history_update_menus(window);
00647 }
00648 
00649 
00662 static void
00663 gnc_plugin_file_history_remove_from_window (GncPlugin *plugin,
00664                                             GncMainWindow *window,
00665                                             GQuark type)
00666 {
00667 }
00668 
00669 /************************************************************
00670  *                    Command Callbacks                     *
00671  ************************************************************/
00672 
00685 static void
00686 gnc_plugin_file_history_cmd_open_file (GtkAction *action,
00687                                        GncMainWindowActionData *data)
00688 {
00689         gchar *filename;
00690 
00691         g_return_if_fail(GTK_IS_ACTION(action));
00692         g_return_if_fail(data != NULL);
00693 
00694         /* DRH - Do we need to close all open windows but the first?
00695          * Which progress bar should we be using? One in a window, or
00696          * in a new "file loading" dialog???
00697          */
00698         filename = g_object_get_data(G_OBJECT(action), FILENAME_STRING);
00699         gnc_window_set_progressbar_window (GNC_WINDOW(data->window));
00700         /* also opens new account page */
00701         if (!gnc_file_open_file (filename))
00702           gnc_history_remove_file (filename);
00703         gnc_window_set_progressbar_window (NULL);
00704 }
00705 

Generated on Mon Sep 8 05:04:04 2008 for GnuCash by  doxygen 1.5.2