GnuCash 2.4.99
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 #include "gnc-uri-utils.h"
00047 
00048 static GObjectClass *parent_class = NULL;
00049 
00050 #define FILENAME_STRING "filename"
00051 
00052 static void gnc_plugin_file_history_class_init (GncPluginFileHistoryClass *klass);
00053 static void gnc_plugin_file_history_init (GncPluginFileHistory *plugin);
00054 static void gnc_plugin_file_history_finalize (GObject *object);
00055 
00056 static void gnc_plugin_file_history_add_to_window (GncPlugin *plugin, GncMainWindow *window, GQuark type);
00057 static void gnc_plugin_file_history_remove_from_window (GncPlugin *plugin, GncMainWindow *window, GQuark type);
00058 
00059 
00061 static QofLogModule log_module = GNC_MOD_GUI;
00062 
00063 /* Command callbacks */
00064 static void gnc_plugin_file_history_cmd_open_file (GtkAction *action, GncMainWindowActionData *data);
00065 
00066 
00068 #define PLUGIN_ACTIONS_NAME "gnc-plugin-file-history-actions"
00069 
00070 #define PLUGIN_UI_FILENAME  "gnc-plugin-file-history-ui.xml"
00071 
00072 #define GNOME1_HISTORY "History"
00073 #define GNOME1_MAXFILES "MaxFiles"
00074 
00080 static GtkActionEntry gnc_plugin_actions [] =
00081 {
00082     { "RecentFile0Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00083     { "RecentFile1Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00084     { "RecentFile2Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00085     { "RecentFile3Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00086     { "RecentFile4Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00087     { "RecentFile5Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00088     { "RecentFile6Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00089     { "RecentFile7Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00090     { "RecentFile8Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00091     { "RecentFile9Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
00092 };
00094 static guint gnc_plugin_n_actions = G_N_ELEMENTS (gnc_plugin_actions);
00095 
00096 
00099 typedef struct GncPluginFileHistoryPrivate
00100 {
00101     gpointer dummy;
00102 } GncPluginFileHistoryPrivate;
00103 
00104 
00105 #define GNC_PLUGIN_FILE_HISTORY_GET_PRIVATE(o)  \
00106    (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_PLUGIN_FILE_HISTORY, GncPluginFileHistoryPrivate))
00107 
00108 /************************************************************
00109  *                     Other Functions                      *
00110  ************************************************************/
00111 
00120 static gchar *
00121 gnc_history_gconf_index_to_key (guint index)
00122 {
00123     return g_strdup_printf(HISTORY_STRING_FILE_N, index);
00124 }
00125 
00126 
00135 static gint
00136 gnc_history_gconf_key_to_index (const gchar *key)
00137 {
00138     gint index, result;
00139 
00140     result = sscanf(key, HISTORY_STRING_FILE_N, &index);
00141     if (result != 1)
00142         return -1;
00143     if ((index < 0) || (index >= gnc_plugin_n_actions))
00144         return -1;
00145     return index;
00146 }
00147 
00148 
00149 /*  Add a file name to the front of the file "history list".  If the
00150  *  name already exist on the list, then it is moved from its current
00151  *  location to the front of the list.  The "list" is actually a
00152  *  sequence of up to ten gconf keys.
00153  */
00154 void
00155 gnc_history_add_file (const char *newfile)
00156 {
00157     gchar *filename, *from, *to;
00158     gint i, last;
00159 
00160     if (newfile == NULL)
00161         return;
00162     if (!g_utf8_validate(newfile, -1, NULL))
00163         return;
00164 
00165     /*
00166      * Look for the filename in gconf.
00167      */
00168     last = MAX_HISTORY_FILES - 1;
00169     for (i = 0; i < MAX_HISTORY_FILES; i++)
00170     {
00171         from = gnc_history_gconf_index_to_key(i);
00172         filename = gnc_gconf_get_string(HISTORY_STRING_SECTION, from, NULL);
00173         g_free(from);
00174 
00175         if (!filename)
00176         {
00177             last = i;
00178             break;
00179         }
00180         if (g_utf8_collate(newfile, filename) == 0)
00181         {
00182             g_free(filename);
00183             last = i;
00184             break;
00185         }
00186         g_free(filename);
00187     }
00188 
00189     /*
00190      * Shuffle filenames upward through gconf.
00191      */
00192     to = gnc_history_gconf_index_to_key(last);
00193     for (i = last - 1; i >= 0; i--)
00194     {
00195         from = gnc_history_gconf_index_to_key(i);
00196         filename = gnc_gconf_get_string(HISTORY_STRING_SECTION, from, NULL);
00197         if (filename)
00198         {
00199             gnc_gconf_set_string(HISTORY_STRING_SECTION, to, filename, NULL);
00200             g_free(filename);
00201         }
00202         else
00203         {
00204             gnc_gconf_unset(HISTORY_STRING_SECTION, to, NULL);
00205         }
00206         g_free(to);
00207         to = from;
00208     }
00209 
00210     /*
00211      * Store the new zero entry.
00212      */
00213     gnc_gconf_set_string(HISTORY_STRING_SECTION, to, newfile, NULL);
00214     g_free(to);
00215 }
00216 
00217 
00223 void
00224 gnc_history_remove_file (const char *oldfile)
00225 {
00226     gchar *filename, *from, *to;
00227     gint i, j;
00228 
00229     if (!oldfile)
00230         return;
00231     if (!g_utf8_validate(oldfile, -1, NULL))
00232         return;
00233 
00234     for (i = 0, j = 0; i < MAX_HISTORY_FILES; i++)
00235     {
00236         from = gnc_history_gconf_index_to_key(i);
00237         filename = gnc_gconf_get_string(HISTORY_STRING_SECTION, from, NULL);
00238 
00239         if (filename)
00240         {
00241             if (g_utf8_collate(oldfile, filename) == 0)
00242             {
00243                 gnc_gconf_unset(HISTORY_STRING_SECTION, from, NULL);
00244             }
00245             else
00246             {
00247                 if (i != j)
00248                 {
00249                     to = gnc_history_gconf_index_to_key(j);
00250                     gnc_gconf_set_string(HISTORY_STRING_SECTION, to, filename, NULL);
00251                     gnc_gconf_unset(HISTORY_STRING_SECTION, from, NULL);
00252                     g_free(to);
00253                 }
00254                 j++;
00255             }
00256         }
00257         g_free(from);
00258     }
00259 }
00260 
00261 /*  Retrieve the name of the file most recently accessed.  This is the
00262  *  name at the front of the list.  Since the "list" is actually a
00263  *  sequence of up to ten gconf keys, this is the value of key zero.
00264  */
00265 char *
00266 gnc_history_get_last (void)
00267 {
00268     char *filename, *key;
00269 
00270     key = gnc_history_gconf_index_to_key(0);
00271     filename = gnc_gconf_get_string(HISTORY_STRING_SECTION, key, NULL);
00272     g_free(key);
00273 
00274     return filename;
00275 }
00276 
00277 
00278 /************************************************************
00279  *                     Other Functions                      *
00280  ************************************************************/
00281 
00291 static gchar *
00292 gnc_history_generate_label (int index, const gchar *filename)
00293 {
00294     gchar *label, *result;
00295     gchar **splitlabel;
00296 
00297     if ( gnc_uri_is_file_uri ( filename ) )
00298     {
00299         /* for file paths, only display the file name */
00300         gchar *filepath = gnc_uri_get_path ( filename );
00301         label = g_path_get_basename ( filepath );
00302         g_free ( filepath );
00303     }
00304     else
00305     {
00306         /* for databases, display the full uri, except for the password */
00307         label = gnc_uri_normalize_uri ( filename, FALSE );
00308     }
00309 
00310     /* Escape '_' characters */
00311     splitlabel = g_strsplit ( label, "_", 0);
00312     g_free (label);
00313     label = g_strjoinv ( "__", splitlabel);
00314     g_strfreev (splitlabel);
00315 
00316     result = g_strdup_printf ( "_%d %s", (index + 1) % 10, label);
00317     g_free ( label );
00318     return result;
00319 
00320 }
00321 
00322 
00340 static void
00341 gnc_history_update_action (GncMainWindow *window,
00342                            gint index,
00343                            const gchar *filename)
00344 {
00345     GtkActionGroup *action_group;
00346     GtkAction *action;
00347     gchar *action_name, *label_name, *old_filename;
00348     gint limit;
00349 
00350     ENTER("window %p, index %d, filename %s", window, index,
00351           filename ? filename : "(null)");
00352     /* Get the action group */
00353     action_group =
00354         gnc_main_window_get_action_group(window, PLUGIN_ACTIONS_NAME);
00355 
00356     action_name = g_strdup_printf("RecentFile%dAction", index);
00357     action = gtk_action_group_get_action (action_group, action_name);
00358 
00359     limit = gnc_gconf_get_int (HISTORY_STRING_SECTION,
00360                                HISTORY_STRING_MAXFILES,
00361                                NULL);
00362 
00363     if (filename && (strlen(filename) > 0) && (index < limit))
00364     {
00365         /* set the menu label (w/accelerator) */
00366         label_name = gnc_history_generate_label(index, filename);
00367         g_object_set(G_OBJECT(action), "label", label_name, "visible", TRUE, NULL);
00368         g_free(label_name);
00369 
00370         /* set the filename for the callback function */
00371         old_filename = g_object_get_data(G_OBJECT(action), FILENAME_STRING);
00372         if (old_filename)
00373             g_free(old_filename);
00374         g_object_set_data(G_OBJECT(action), FILENAME_STRING, g_strdup(filename));
00375     }
00376     else
00377     {
00378         gtk_action_set_visible(action, FALSE);
00379     }
00380     g_free(action_name);
00381     LEAVE("");
00382 }
00383 
00384 
00393 static void
00394 gnc_history_update_menus (GncMainWindow *window)
00395 {
00396     gchar *filename, *key;
00397     guint i;
00398 
00399     ENTER("");
00400     for (i = 0; i < MAX_HISTORY_FILES; i++)
00401     {
00402         key = gnc_history_gconf_index_to_key(i);
00403         filename = gnc_gconf_get_string(HISTORY_STRING_SECTION, key, NULL);
00404         gnc_history_update_action(window, i, filename);
00405         g_free(filename);
00406         g_free(key);
00407     }
00408     LEAVE("");
00409 }
00410 
00411 
00427 static void
00428 gnc_plugin_history_list_changed (GConfClient *client,
00429                                  guint cnxn_id,
00430                                  GConfEntry *entry,
00431                                  gpointer user_data)
00432 {
00433     GncMainWindow *window;
00434     GConfValue *value;
00435     const gchar *fullkey, *key, *filename;
00436     gint index;
00437 
00438     ENTER("");
00439     window = GNC_MAIN_WINDOW(user_data);
00440 
00441     fullkey = gconf_entry_get_key(entry);
00442     key = strrchr(fullkey, '/') + 1;
00443     if (strcmp(key, HISTORY_STRING_MAXFILES) == 0)
00444     {
00445         gnc_history_update_menus (window);
00446         LEAVE("updated maxfiles");
00447         return;
00448     }
00449     index = gnc_history_gconf_key_to_index(key);
00450     if (index < 0)
00451     {
00452         LEAVE("bad index");
00453         return;
00454     }
00455 
00456     value = gconf_entry_get_value(entry);
00457     if (!value)
00458     {
00459         LEAVE("No gconf value");
00460         return;
00461     }
00462     filename = gconf_value_get_string(value);
00463     gnc_history_update_action (window, index, filename);
00464 
00465     gnc_main_window_actions_updated (window);
00466     LEAVE("");
00467 }
00468 
00469 
00470 /* This routine copies the gnucash 1.x file history list over to
00471  * gnucash 2.0. */
00472 static void
00473 gnc_plugin_history_list_from_gnucash1 (void)
00474 {
00475     GKeyFile *keyfile;
00476     const gchar *home;
00477     gchar *mdi_file, *value;
00478     gchar **keys, **key, *new_key;
00479     gint file_id, max;
00480 
00481     /* First test if there are already files in the gconf file history.
00482      * If so, then bail out now. */
00483     value = gnc_gconf_get_string(HISTORY_STRING_SECTION, "file0", NULL);
00484     if (value)
00485     {
00486         g_free(value);
00487         return;
00488     }
00489 
00490     home = g_get_home_dir();
00491     if (!home)
00492         return;
00493 
00494     /* Copy the old values from the gnucash 1.x/gnome1 settings file to
00495      * the gnucash 2.x/gconf settings area.  */
00496     mdi_file = g_build_filename(home, ".gnome", "GnuCash", (gchar *)NULL);
00497     keyfile = gnc_key_file_load_from_file (mdi_file, FALSE, FALSE, NULL);
00498     if (keyfile)
00499     {
00500         keys = g_key_file_get_keys(keyfile, GNOME1_HISTORY, NULL, NULL);
00501         if (keys)
00502         {
00503             for (key = keys; *key; key++)
00504             {
00505                 if (!strcmp(*key, GNOME1_MAXFILES))
00506                 {
00507                     max = g_key_file_get_integer(keyfile, GNOME1_HISTORY,
00508                                                  GNOME1_MAXFILES, NULL);
00509                     printf("Found old maxfiles: %d\n", max);
00510                     if ((max > 0) && (max < MAX_HISTORY_FILES))
00511                         printf("Setting maxfiles: %d\n\n", max);
00512                     gnc_gconf_set_int(HISTORY_STRING_SECTION, HISTORY_STRING_MAXFILES,
00513                                       max, NULL);
00514                     continue;
00515                 }
00516 
00517                 if (sscanf(*key, "File%d", &file_id) == 1)
00518                 {
00519                     value = g_key_file_get_string(keyfile, GNOME1_HISTORY, *key, NULL);
00520                     if (!value)
00521                         continue;
00522                     printf("Found old file %d: %s\n", file_id, value);
00523                     new_key = g_strdup_printf(HISTORY_STRING_FILE_N, file_id);
00524                     gnc_gconf_set_string (HISTORY_STRING_SECTION, new_key, value, NULL);
00525                     printf("Setting %s: %s\n\n", new_key, value);
00526                     g_free(new_key);
00527                     g_free(value);
00528                 }
00529             }
00530             g_strfreev(keys);
00531         }
00532         g_key_file_free(keyfile);
00533     }
00534 
00535     g_free(mdi_file);
00536 }
00537 
00538 /************************************************************
00539  *                  Object Implementation                   *
00540  ************************************************************/
00541 
00542 /*  Get the type of a file history plugin.  */
00543 GType
00544 gnc_plugin_file_history_get_type (void)
00545 {
00546     static GType gnc_plugin_file_history_type = 0;
00547 
00548     if (gnc_plugin_file_history_type == 0)
00549     {
00550         static const GTypeInfo our_info =
00551         {
00552             sizeof (GncPluginFileHistoryClass),
00553             NULL,               /* base_init */
00554             NULL,               /* base_finalize */
00555             (GClassInitFunc) gnc_plugin_file_history_class_init,
00556             NULL,               /* class_finalize */
00557             NULL,               /* class_data */
00558             sizeof (GncPluginFileHistory),
00559             0,
00560             (GInstanceInitFunc) gnc_plugin_file_history_init
00561         };
00562 
00563         gnc_plugin_file_history_type =
00564             g_type_register_static (GNC_TYPE_PLUGIN,
00565                                     "GncPluginFileHistory",
00566                                     &our_info, 0);
00567     }
00568 
00569     return gnc_plugin_file_history_type;
00570 }
00571 
00572 
00574 static void
00575 gnc_plugin_file_history_class_init (GncPluginFileHistoryClass *klass)
00576 {
00577     GObjectClass *object_class = G_OBJECT_CLASS (klass);
00578     GncPluginClass *plugin_class = GNC_PLUGIN_CLASS (klass);
00579 
00580     parent_class = g_type_class_peek_parent (klass);
00581 
00582     object_class->finalize = gnc_plugin_file_history_finalize;
00583 
00584     /* plugin info */
00585     plugin_class->plugin_name   = GNC_PLUGIN_FILE_HISTORY_NAME;
00586 
00587     /* function overrides */
00588     plugin_class->add_to_window = gnc_plugin_file_history_add_to_window;
00589     plugin_class->remove_from_window =
00590         gnc_plugin_file_history_remove_from_window;
00591 
00592     /* widget addition/removal */
00593     plugin_class->actions_name  = PLUGIN_ACTIONS_NAME;
00594     plugin_class->actions       = gnc_plugin_actions;
00595     plugin_class->n_actions     = gnc_plugin_n_actions;
00596     plugin_class->ui_filename   = PLUGIN_UI_FILENAME;
00597 
00598     plugin_class->gconf_section = HISTORY_STRING_SECTION;
00599     plugin_class->gconf_notifications = gnc_plugin_history_list_changed;
00600 
00601     g_type_class_add_private(klass, sizeof(GncPluginFileHistoryPrivate));
00602 
00603     gnc_plugin_history_list_from_gnucash1();
00604 }
00605 
00606 
00608 static void
00609 gnc_plugin_file_history_init (GncPluginFileHistory *plugin)
00610 {
00611     ENTER("plugin %p", plugin);
00612     LEAVE("");
00613 }
00614 
00615 
00617 static void
00618 gnc_plugin_file_history_finalize (GObject *object)
00619 {
00620     GncPluginFileHistory *plugin;
00621     GncPluginFileHistoryPrivate *priv;
00622 
00623     g_return_if_fail (GNC_IS_PLUGIN_FILE_HISTORY (object));
00624 
00625     ENTER("plugin %p", object);
00626     plugin = GNC_PLUGIN_FILE_HISTORY (object);
00627     priv = GNC_PLUGIN_FILE_HISTORY_GET_PRIVATE (plugin);
00628 
00629     G_OBJECT_CLASS (parent_class)->finalize (object);
00630     LEAVE("");
00631 }
00632 
00633 
00634 /*  Create a new file history plugin.  This plugin attaches the file
00635  *  history menu to any window that is opened.
00636  */
00637 GncPlugin *
00638 gnc_plugin_file_history_new (void)
00639 {
00640     GncPlugin *plugin_page = NULL;
00641 
00642     ENTER("");
00643     plugin_page = GNC_PLUGIN (g_object_new (GNC_TYPE_PLUGIN_FILE_HISTORY, NULL));
00644     LEAVE("plugin %p", plugin_page);
00645     return plugin_page;
00646 }
00647 
00648 /************************************************************
00649  *              Plugin Function Implementation              *
00650  ************************************************************/
00651 
00668 static void
00669 gnc_plugin_file_history_add_to_window (GncPlugin *plugin,
00670                                        GncMainWindow *window,
00671                                        GQuark type)
00672 {
00673     gnc_history_update_menus(window);
00674 }
00675 
00676 
00689 static void
00690 gnc_plugin_file_history_remove_from_window (GncPlugin *plugin,
00691         GncMainWindow *window,
00692         GQuark type)
00693 {
00694 }
00695 
00696 /************************************************************
00697  *                    Command Callbacks                     *
00698  ************************************************************/
00699 
00712 static void
00713 gnc_plugin_file_history_cmd_open_file (GtkAction *action,
00714                                        GncMainWindowActionData *data)
00715 {
00716     gchar *filename;
00717 
00718     g_return_if_fail(GTK_IS_ACTION(action));
00719     g_return_if_fail(data != NULL);
00720 
00721     /* DRH - Do we need to close all open windows but the first?
00722      * Which progress bar should we be using? One in a window, or
00723      * in a new "file loading" dialog???
00724      */
00725     filename = g_object_get_data(G_OBJECT(action), FILENAME_STRING);
00726     gnc_window_set_progressbar_window (GNC_WINDOW(data->window));
00727     /* also opens new account page */
00728     gnc_file_open_file (filename, /*open_readonly*/ FALSE);
00729     gnc_window_set_progressbar_window (NULL);
00730 }
00731 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines