GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-plugin-file-history.c
Go to the documentation of this file.
1 /*
2  * gnc-plugin-file-history.c --
3  * Copyright (C) 2003,2005 David Hampton <[email protected]>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of
8  * the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, contact:
17  *
18  * Free Software Foundation Voice: +1-617-542-5942
19  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
20  * Boston, MA 02110-1301, USA [email protected]
21  */
22 
32 #include "config.h"
33 
34 #include <gtk/gtk.h>
35 #include <glib/gi18n.h>
36 #include <glib/gprintf.h>
37 #include <string.h>
38 
39 #include "gnc-gkeyfile-utils.h"
40 #include "gnc-file.h"
41 #include "gnc-main-window.h"
43 #include "gnc-window.h"
44 #include "gnc-engine.h"
45 #include "gnc-prefs.h"
46 #include "gnc-uri-utils.h"
47 
48 static GObjectClass *parent_class = NULL;
49 
50 #define FILENAME_STRING "filename"
51 #define MAX_HISTORY_FILES 10 /* May be any number up to 10 */
52 #define GNC_PREFS_GROUP_HISTORY "history"
53 #define GNC_PREF_HISTORY_MAXFILES "maxfiles"
54 #define HISTORY_STRING_FILE_N "file%d"
55 
56 static void gnc_plugin_file_history_class_init (GncPluginFileHistoryClass *klass);
57 static void gnc_plugin_file_history_init (GncPluginFileHistory *plugin);
58 static void gnc_plugin_file_history_finalize (GObject *object);
59 
60 static void gnc_plugin_file_history_add_to_window (GncPlugin *plugin, GncMainWindow *window, GQuark type);
61 static void gnc_plugin_file_history_remove_from_window (GncPlugin *plugin, GncMainWindow *window, GQuark type);
62 
63 
65 static QofLogModule log_module = GNC_MOD_GUI;
66 
67 /* Command callbacks */
68 static void gnc_plugin_file_history_cmd_open_file (GtkAction *action, GncMainWindowActionData *data);
69 
70 
72 #define PLUGIN_ACTIONS_NAME "gnc-plugin-file-history-actions"
73 
74 #define PLUGIN_UI_FILENAME "gnc-plugin-file-history-ui.xml"
75 
76 #define GNOME1_HISTORY "History"
77 #define GNOME1_MAXFILES "MaxFiles"
78 
84 static GtkActionEntry gnc_plugin_actions [] =
85 {
86  { "RecentFile0Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
87  { "RecentFile1Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
88  { "RecentFile2Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
89  { "RecentFile3Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
90  { "RecentFile4Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
91  { "RecentFile5Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
92  { "RecentFile6Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
93  { "RecentFile7Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
94  { "RecentFile8Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
95  { "RecentFile9Action", NULL, "", NULL, NULL, G_CALLBACK (gnc_plugin_file_history_cmd_open_file) },
96 };
98 static guint gnc_plugin_n_actions = G_N_ELEMENTS (gnc_plugin_actions);
99 
100 
104 {
105  gpointer dummy;
107 
108 
109 #define GNC_PLUGIN_FILE_HISTORY_GET_PRIVATE(o) \
110  (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_PLUGIN_FILE_HISTORY, GncPluginFileHistoryPrivate))
111 
112 /************************************************************
113  * Other Functions *
114  ************************************************************/
115 
124 static gchar *
125 gnc_history_index_to_pref_name (guint index)
126 {
127  return g_strdup_printf(HISTORY_STRING_FILE_N, index);
128 }
129 
130 
139 static gint
140 gnc_history_pref_name_to_index (const gchar *pref)
141 {
142  gint index, result;
143 
144  result = sscanf(pref, HISTORY_STRING_FILE_N, &index);
145  if (result != 1)
146  return -1;
147  if ((index < 0) || (index >= gnc_plugin_n_actions))
148  return -1;
149  return index;
150 }
151 
152 
153 /* Add a file name to the front of the file "history list". If the
154  * name already exist on the list, then it is moved from its current
155  * location to the front of the list. The "list" is actually a
156  * sequence of up to ten preferences.
157  */
158 void
159 gnc_history_add_file (const char *newfile)
160 {
161  gchar *filename, *from, *to;
162  gint i, last;
163 
164  if (newfile == NULL)
165  return;
166  if (!g_utf8_validate(newfile, -1, NULL))
167  return;
168 
169  /*
170  * Look for the filename in preferences.
171  */
172  last = MAX_HISTORY_FILES - 1;
173  for (i = 0; i < MAX_HISTORY_FILES; i++)
174  {
175  from = gnc_history_index_to_pref_name(i);
176  filename = gnc_prefs_get_string(GNC_PREFS_GROUP_HISTORY, from);
177  g_free(from);
178 
179  if (!filename)
180  {
181  last = i;
182  break;
183  }
184  if (g_utf8_collate(newfile, filename) == 0)
185  {
186  g_free(filename);
187  last = i;
188  break;
189  }
190  g_free(filename);
191  }
192 
193  /*
194  * Shuffle filenames upward through preferences.
195  */
196  to = gnc_history_index_to_pref_name(last);
197  for (i = last - 1; i >= 0; i--)
198  {
199  from = gnc_history_index_to_pref_name(i);
200  filename = gnc_prefs_get_string(GNC_PREFS_GROUP_HISTORY, from);
201  if (filename)
202  {
203  gnc_prefs_set_string(GNC_PREFS_GROUP_HISTORY, to, filename);
204  g_free(filename);
205  }
206  else
207  {
208  gnc_prefs_reset(GNC_PREFS_GROUP_HISTORY, to);
209  }
210  g_free(to);
211  to = from;
212  }
213 
214  /*
215  * Store the new zero entry.
216  */
217  gnc_prefs_set_string(GNC_PREFS_GROUP_HISTORY, to, newfile);
218  g_free(to);
219 }
220 
221 
227 void
228 gnc_history_remove_file (const char *oldfile)
229 {
230  gchar *filename, *from, *to;
231  gint i, j;
232 
233  if (!oldfile)
234  return;
235  if (!g_utf8_validate(oldfile, -1, NULL))
236  return;
237 
238  for (i = 0, j = 0; i < MAX_HISTORY_FILES; i++)
239  {
240  from = gnc_history_index_to_pref_name(i);
241  filename = gnc_prefs_get_string(GNC_PREFS_GROUP_HISTORY, from);
242 
243  if (filename)
244  {
245  if (g_utf8_collate(oldfile, filename) == 0)
246  {
247  gnc_prefs_reset(GNC_PREFS_GROUP_HISTORY, from);
248  }
249  else
250  {
251  if (i != j)
252  {
253  to = gnc_history_index_to_pref_name(j);
254  gnc_prefs_set_string(GNC_PREFS_GROUP_HISTORY, to, filename);
255  gnc_prefs_reset(GNC_PREFS_GROUP_HISTORY, from);
256  g_free(to);
257  }
258  j++;
259  }
260  }
261  g_free(from);
262  }
263 }
264 
265 /* Retrieve the name of the file most recently accessed. This is the
266  * name at the front of the list. Since the "list" is actually a
267  * sequence of up to ten preference names, this is the value of the first preference.
268  */
269 char *
271 {
272  char *filename, *pref;
273 
274  pref = gnc_history_index_to_pref_name(0);
275  filename = gnc_prefs_get_string(GNC_PREFS_GROUP_HISTORY, pref);
276  g_free(pref);
277 
278  return filename;
279 }
280 
281 
282 /************************************************************
283  * Other Functions *
284  ************************************************************/
285 
295 static gchar *
296 gnc_history_generate_label (int index, const gchar *filename)
297 {
298  gchar *label, *result;
299  gchar **splitlabel;
300 
301  if ( gnc_uri_is_file_uri ( filename ) )
302  {
303  /* for file paths, only display the file name */
304  gchar *filepath = gnc_uri_get_path ( filename );
305  label = g_path_get_basename ( filepath );
306  g_free ( filepath );
307  }
308  else
309  {
310  /* for databases, display the full uri, except for the password */
311  label = gnc_uri_normalize_uri ( filename, FALSE );
312  }
313 
314  /* Escape '_' characters */
315  splitlabel = g_strsplit ( label, "_", 0);
316  g_free (label);
317  label = g_strjoinv ( "__", splitlabel);
318  g_strfreev (splitlabel);
319 
320  result = g_strdup_printf ( "_%d %s", (index + 1) % 10, label);
321  g_free ( label );
322  return result;
323 
324 }
325 
336 static gchar *
337 gnc_history_generate_tooltip (int index, const gchar *filename)
338 {
339 
340  if ( gnc_uri_is_file_uri ( filename ) )
341  /* for file paths, display the full file path */
342  return gnc_uri_get_path ( filename );
343  else
344  /* for databases, display the full uri, except for the password */
345  return gnc_uri_normalize_uri ( filename, FALSE );
346 
347 }
348 
349 
367 static void
368 gnc_history_update_action (GncMainWindow *window,
369  gint index,
370  const gchar *filename)
371 {
372  GtkActionGroup *action_group;
373  GtkAction *action;
374  gchar *action_name, *label_name, *tooltip, *old_filename;
375  gint limit;
376 
377  ENTER("window %p, index %d, filename %s", window, index,
378  filename ? filename : "(null)");
379  /* Get the action group */
380  action_group =
382 
383  action_name = g_strdup_printf("RecentFile%dAction", index);
384  action = gtk_action_group_get_action (action_group, action_name);
385 
386  limit = gnc_prefs_get_int (GNC_PREFS_GROUP_HISTORY,
387  GNC_PREF_HISTORY_MAXFILES);
388 
389  if (filename && (strlen(filename) > 0) && (index < limit))
390  {
391  /* set the menu label (w/accelerator) */
392  label_name = gnc_history_generate_label(index, filename);
393  tooltip = gnc_history_generate_tooltip(index, filename);
394  g_object_set(G_OBJECT(action), "label", label_name,
395  "tooltip", tooltip,
396  "visible", TRUE,
397  NULL);
398  g_free(label_name);
399  g_free(tooltip);
400 
401  /* set the filename for the callback function */
402  old_filename = g_object_get_data(G_OBJECT(action), FILENAME_STRING);
403  if (old_filename)
404  g_free(old_filename);
405  g_object_set_data(G_OBJECT(action), FILENAME_STRING, g_strdup(filename));
406  }
407  else
408  {
409  gtk_action_set_visible(action, FALSE);
410  }
411  g_free(action_name);
412  LEAVE("");
413 }
414 
415 
424 static void
425 gnc_history_update_menus (GncMainWindow *window)
426 {
427  gchar *filename, *pref;
428  guint i;
429 
430  ENTER("");
431  for (i = 0; i < MAX_HISTORY_FILES; i++)
432  {
433  pref = gnc_history_index_to_pref_name(i);
434  filename = gnc_prefs_get_string(GNC_PREFS_GROUP_HISTORY, pref);
435  gnc_history_update_action(window, i, filename);
436  g_free(filename);
437  g_free(pref);
438  }
439  LEAVE("");
440 }
441 
442 
454 static void
455 gnc_plugin_history_list_changed (gpointer prefs,
456  gchar *pref,
457  gpointer user_data)
458 {
459  GncMainWindow *window;
460  const gchar *filename;
461  gint index;
462 
463  ENTER("");
464  window = GNC_MAIN_WINDOW(user_data);
465 
466  if (strcmp(pref, GNC_PREF_HISTORY_MAXFILES) == 0)
467  {
468  gnc_history_update_menus (window);
469  LEAVE("updated maxfiles");
470  return;
471  }
472  index = gnc_history_pref_name_to_index(pref);
473  if (index < 0)
474  {
475  LEAVE("bad index");
476  return;
477  }
478 
479  filename = gnc_prefs_get_string (GNC_PREFS_GROUP_HISTORY, pref);
480  gnc_history_update_action (window, index, filename);
481 
483  LEAVE("");
484 }
485 
486 /************************************************************
487  * Object Implementation *
488  ************************************************************/
489 
490 /* Get the type of a file history plugin. */
491 GType
493 {
494  static GType gnc_plugin_file_history_type = 0;
495 
496  if (gnc_plugin_file_history_type == 0)
497  {
498  static const GTypeInfo our_info =
499  {
500  sizeof (GncPluginFileHistoryClass),
501  NULL, /* base_init */
502  NULL, /* base_finalize */
503  (GClassInitFunc) gnc_plugin_file_history_class_init,
504  NULL, /* class_finalize */
505  NULL, /* class_data */
506  sizeof (GncPluginFileHistory),
507  0,
508  (GInstanceInitFunc) gnc_plugin_file_history_init
509  };
510 
511  gnc_plugin_file_history_type =
512  g_type_register_static (GNC_TYPE_PLUGIN,
513  "GncPluginFileHistory",
514  &our_info, 0);
515  }
516 
517  return gnc_plugin_file_history_type;
518 }
519 
520 
522 static void
523 gnc_plugin_file_history_class_init (GncPluginFileHistoryClass *klass)
524 {
525  GObjectClass *object_class = G_OBJECT_CLASS (klass);
526  GncPluginClass *plugin_class = GNC_PLUGIN_CLASS (klass);
527 
528  parent_class = g_type_class_peek_parent (klass);
529 
530  object_class->finalize = gnc_plugin_file_history_finalize;
531 
532  /* plugin info */
533  plugin_class->plugin_name = GNC_PLUGIN_FILE_HISTORY_NAME;
534 
535  /* function overrides */
536  plugin_class->add_to_window = gnc_plugin_file_history_add_to_window;
537  plugin_class->remove_from_window =
538  gnc_plugin_file_history_remove_from_window;
539 
540  /* widget addition/removal */
541  plugin_class->actions_name = PLUGIN_ACTIONS_NAME;
542  plugin_class->actions = gnc_plugin_actions;
543  plugin_class->n_actions = gnc_plugin_n_actions;
544  plugin_class->ui_filename = PLUGIN_UI_FILENAME;
545 
546  g_type_class_add_private(klass, sizeof(GncPluginFileHistoryPrivate));
547 }
548 
549 
551 static void
552 gnc_plugin_file_history_init (GncPluginFileHistory *plugin)
553 {
554  ENTER("plugin %p", plugin);
555  LEAVE("");
556 }
557 
558 
560 static void
561 gnc_plugin_file_history_finalize (GObject *object)
562 {
563  g_return_if_fail (GNC_IS_PLUGIN_FILE_HISTORY (object));
564 
565  ENTER("plugin %p", object);
566  G_OBJECT_CLASS (parent_class)->finalize (object);
567  LEAVE("");
568 }
569 
570 
571 /* Create a new file history plugin. This plugin attaches the file
572  * history menu to any window that is opened.
573  */
574 GncPlugin *
576 {
577  GncPlugin *plugin_page = NULL;
578 
579  ENTER("");
580  plugin_page = GNC_PLUGIN (g_object_new (GNC_TYPE_PLUGIN_FILE_HISTORY, NULL));
581  LEAVE("plugin %p", plugin_page);
582  return plugin_page;
583 }
584 
585 /************************************************************
586  * Plugin Function Implementation *
587  ************************************************************/
588 
605 static void
606 gnc_plugin_file_history_add_to_window (GncPlugin *plugin,
607  GncMainWindow *window,
608  GQuark type)
609 {
610  gnc_prefs_register_cb (GNC_PREFS_GROUP_HISTORY, NULL,
611  gnc_plugin_history_list_changed, window);
612  gnc_history_update_menus(window);
613 }
614 
615 
627 static void
628 gnc_plugin_file_history_remove_from_window (GncPlugin *plugin,
629  GncMainWindow *window,
630  GQuark type)
631 {
632  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_HISTORY, NULL,
633  gnc_plugin_history_list_changed, window);
634 }
635 
636 /************************************************************
637  * Command Callbacks *
638  ************************************************************/
639 
652 static void
653 gnc_plugin_file_history_cmd_open_file (GtkAction *action,
655 {
656  gchar *filename;
657 
658  g_return_if_fail(GTK_IS_ACTION(action));
659  g_return_if_fail(data != NULL);
660 
661  /* DRH - Do we need to close all open windows but the first?
662  * Which progress bar should we be using? One in a window, or
663  * in a new "file loading" dialog???
664  */
665  filename = g_object_get_data(G_OBJECT(action), FILENAME_STRING);
666  gnc_window_set_progressbar_window (GNC_WINDOW(data->window));
667  /* also opens new account page */
668  gnc_file_open_file (filename, /*open_readonly*/ FALSE);
669  gnc_window_set_progressbar_window (NULL);
670 }
671 
gchar * gnc_prefs_get_string(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:237
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Definition: gnc-prefs.c:128
gboolean gnc_uri_is_file_uri(const gchar *uri)
Definition: gnc-uri-utils.c:71
Functions that are supported by all types of windows.
GncPlugin * gnc_plugin_file_history_new(void)
GKeyFile helper routines.
gchar * gnc_uri_get_path(const gchar *uri)
void gnc_prefs_reset(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:366
gboolean gnc_prefs_set_string(const gchar *group, const gchar *pref_name, const gchar *value)
Definition: gnc-prefs.c:324
#define ENTER(format, args...)
Definition: qoflog.h:261
const gchar * ui_filename
Definition: gnc-plugin.h:137
gint gnc_prefs_get_int(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:206
Functions for adding content to a window.
GtkActionEntry * actions
Definition: gnc-plugin.h:122
void gnc_history_add_file(const char *newfile)
char * gnc_history_get_last(void)
gchar * gnc_uri_normalize_uri(const gchar *uri, gboolean allow_password)
void(* remove_from_window)(GncPlugin *plugin, GncMainWindow *window, GQuark type)
Definition: gnc-plugin.h:171
Functions providing the file history menu.
void gnc_history_remove_file(const char *oldfile)
All type declarations for the whole Gnucash engine.
const gchar * actions_name
Definition: gnc-plugin.h:119
Generic api to store and retrieve preferences.
GtkActionGroup * gnc_main_window_get_action_group(GncMainWindow *window, const gchar *group_name)
struct GncPluginFileHistoryPrivate GncPluginFileHistoryPrivate
const gchar * plugin_name
Definition: gnc-plugin.h:112
#define PLUGIN_ACTIONS_NAME
#define LEAVE(format, args...)
Definition: qoflog.h:271
void(* add_to_window)(GncPlugin *plugin, GncMainWindow *window, GQuark type)
Definition: gnc-plugin.h:155
Utility functions for convert uri in separate components and back.
GType gnc_plugin_file_history_get_type(void)
void gnc_main_window_actions_updated(GncMainWindow *window)
#define PLUGIN_UI_FILENAME
const gchar * QofLogModule
Definition: qofid.h:89
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Definition: gnc-prefs.c:148