GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dialog-file-access.c
1 /********************************************************************\
2  * dialog-file-access.c -- dialog for opening a file or making a *
3  * connection to a libdbi database *
4  * *
5  * Copyright (C) 2009 Phil Longstaff ([email protected]) *
6  * *
7  * This program is free software; you can redistribute it and/or *
8  * modify it under the terms of the GNU General Public License as *
9  * published by the Free Software Foundation; either version 2 of *
10  * the License, or (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License*
18  * along with this program; if not, contact: *
19  * *
20  * Free Software Foundation Voice: +1-617-542-5942 *
21  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
22  * Boston, MA 02110-1301, USA [email protected] *
23 \********************************************************************/
24 
25 #include "config.h"
26 
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
29 
30 #include "gnc-ui.h"
31 #include "gnc-ui-util.h"
32 #include "gnc-uri-utils.h"
33 #include "dialog-utils.h"
34 #include "dialog-file-access.h"
35 #include "gnc-file.h"
37 #include "gnc-session.h"
38 
39 static QofLogModule log_module = GNC_MOD_GUI;
40 
41 #define DEFAULT_HOST "localhost"
42 #define DEFAULT_DATABASE "gnucash"
43 #define FILE_ACCESS_OPEN 0
44 #define FILE_ACCESS_SAVE_AS 1
45 #define FILE_ACCESS_EXPORT 2
46 
47 typedef struct FileAccessWindow
48 {
49  /* Parts of the dialog */
50  int type;
51 
52  GtkWidget *dialog;
53  GtkWidget *frame_file;
54  GtkWidget *frame_database;
55  GtkWidget *readonly_checkbutton;
56  GtkFileChooser *fileChooser;
57  gchar *starting_dir;
58  GtkComboBoxText *cb_uri_type;
59  GtkEntry *tf_host;
60  GtkEntry *tf_database;
61  GtkEntry *tf_username;
62  GtkEntry *tf_password;
64 
65 void gnc_ui_file_access_file_activated_cb( GtkFileChooser *chooser,
66  FileAccessWindow *faw );
67 void gnc_ui_file_access_response_cb( GtkDialog *, gint, GtkDialog * );
68 static void cb_uri_type_changed_cb( GtkComboBoxText* cb );
69 
70 static gchar*
71 geturl( FileAccessWindow* faw )
72 {
73  gchar* url = NULL;
74  const gchar* host;
75  const gchar* database;
76  const gchar* username;
77  const gchar* password;
78  const gchar* type;
79  const gchar* file;
80  const gchar* path;
81 
82  host = gtk_entry_get_text( faw->tf_host );
83  database = gtk_entry_get_text( faw->tf_database );
84  username = gtk_entry_get_text( faw->tf_username );
85  password = gtk_entry_get_text( faw->tf_password );
86  file = gtk_file_chooser_get_filename( faw->fileChooser );
87 
88  type = gtk_combo_box_text_get_active_text(faw->cb_uri_type );
89  if ( gnc_uri_is_file_protocol( type ) )
90  {
91  if ( file == NULL ) /* file protocol was chosen but no filename was set */
92  return NULL;
93  else /* file protocol was chosen with filename set */
94  path = file;
95  }
96  else /* db protocol was chosen */
97  path = database;
98 
99  url = gnc_uri_create_uri (type, host, 0, username, password, path);
100 
101  return url;
102 }
103 
104 void
105 gnc_ui_file_access_file_activated_cb( GtkFileChooser *chooser, FileAccessWindow *faw )
106 {
107  g_return_if_fail( chooser != NULL );
108 
109  gnc_ui_file_access_response_cb( GTK_DIALOG(faw->dialog), GTK_RESPONSE_OK, NULL );
110 }
111 
112 void
113 gnc_ui_file_access_response_cb(GtkDialog *dialog, gint response, GtkDialog *unused)
114 {
115  FileAccessWindow* faw;
116  gchar* url;
117 
118  g_return_if_fail( dialog != NULL );
119 
120  faw = g_object_get_data( G_OBJECT(dialog), "FileAccessWindow" );
121  g_return_if_fail( faw != NULL );
122 
123  switch ( response )
124  {
125  case GTK_RESPONSE_HELP:
126  gnc_gnome_help( HF_HELP, HL_GLOBPREFS );
127  break;
128 
129  case GTK_RESPONSE_OK:
130  url = geturl( faw );
131  if ( url == NULL )
132  {
133  return;
134  }
135 
136  if ( g_file_test( g_filename_from_uri( url, NULL, NULL ),
137  G_FILE_TEST_IS_DIR ))
138  {
139  gtk_file_chooser_set_current_folder_uri( faw->fileChooser, url );
140  return;
141  }
142  if ( faw->type == FILE_ACCESS_OPEN )
143  {
144  gboolean open_readonly = faw->readonly_checkbutton
145  ? gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(faw->readonly_checkbutton))
146  : FALSE;
147  gnc_file_open_file( url, open_readonly );
148  }
149  else if ( faw->type == FILE_ACCESS_SAVE_AS )
150  {
151  gnc_file_do_save_as( url );
152  }
153  else if ( faw->type == FILE_ACCESS_EXPORT )
154  {
155  gnc_file_do_export( url );
156  }
157  break;
158 
159  case GTK_RESPONSE_CANCEL:
160  break;
161 
162  default:
163  PERR( "Invalid response" );
164  break;
165  }
166 
167  if ( response != GTK_RESPONSE_HELP )
168  {
169  gtk_widget_destroy( GTK_WIDGET(dialog) );
170  }
171 }
172 
173 /* Activate the file chooser and deactivate the db selection fields */
174 static void
175 set_widget_sensitivity( FileAccessWindow* faw, gboolean is_file_based_uri )
176 {
177  if (is_file_based_uri)
178  {
179  gtk_widget_show(faw->frame_file);
180  gtk_widget_hide(faw->frame_database);
181  gtk_file_chooser_set_current_folder(faw->fileChooser, faw->starting_dir);
182  }
183  else
184  {
185  gtk_widget_show(faw->frame_database);
186  gtk_widget_hide(faw->frame_file);
187  }
188 // gtk_widget_set_sensitive( faw->frame_file, is_file_based_uri );
189 // gtk_widget_set_sensitive( faw->frame_database, !is_file_based_uri );
190 }
191 
192 static void
193 set_widget_sensitivity_for_uri_type( FileAccessWindow* faw, const gchar* uri_type )
194 {
195  if ( strcmp( uri_type, "file" ) == 0 || strcmp( uri_type, "xml" ) == 0
196  || strcmp( uri_type, "sqlite3" ) == 0 )
197  {
198  set_widget_sensitivity( faw, /* is_file_based_uri */ TRUE );
199  }
200  else if ( strcmp( uri_type, "mysql" ) == 0 || strcmp( uri_type, "postgres" ) == 0 )
201  {
202  set_widget_sensitivity( faw, /* is_file_based_uri */ FALSE );
203  }
204  else
205  {
206  g_assert( FALSE );
207  }
208 }
209 
210 static void
211 cb_uri_type_changed_cb( GtkComboBoxText* cb )
212 {
213  GtkWidget* dialog;
214  FileAccessWindow* faw;
215  const gchar* type;
216 
217  g_return_if_fail( cb != NULL );
218 
219  dialog = gtk_widget_get_toplevel( GTK_WIDGET(cb) );
220  g_return_if_fail( dialog != NULL );
221  faw = g_object_get_data( G_OBJECT(dialog), "FileAccessWindow" );
222  g_return_if_fail( faw != NULL );
223 
224  type = gtk_combo_box_text_get_active_text( cb );
225  set_widget_sensitivity_for_uri_type( faw, type );
226 }
227 
228 static const char*
229 get_default_database( void )
230 {
231  const gchar* default_db;
232 
233  default_db = g_getenv( "GNC_DEFAULT_DATABASE" );
234  if ( default_db == NULL )
235  {
236  default_db = DEFAULT_DATABASE;
237  }
238 
239  return default_db;
240 }
241 
242 static void
243 gnc_ui_file_access( int type )
244 {
245  FileAccessWindow *faw;
246  GtkBuilder* builder;
247  GtkButton* op;
248  GtkWidget* file_chooser;
249  GtkFileChooserWidget* fileChooser;
250  GtkFileChooserAction fileChooserAction = GTK_FILE_CHOOSER_ACTION_OPEN;
251  GList* list;
252  GList* node;
253  GtkWidget* uri_type_container;
254  gboolean need_access_method_file = FALSE;
255  gboolean need_access_method_mysql = FALSE;
256  gboolean need_access_method_postgres = FALSE;
257  gboolean need_access_method_sqlite3 = FALSE;
258  gboolean need_access_method_xml = FALSE;
259  gint access_method_index = -1;
260  gint active_access_method_index = -1;
261  const gchar* default_db;
262  const gchar *button_label = NULL;
263  const gchar *settings_section = NULL;
264  gchar *last;
265 
266  g_return_if_fail( type == FILE_ACCESS_OPEN || type == FILE_ACCESS_SAVE_AS || type == FILE_ACCESS_EXPORT );
267 
268  faw = g_new0(FileAccessWindow, 1);
269  g_return_if_fail( faw != NULL );
270 
271  faw->type = type;
272  faw->starting_dir = NULL;
273 
274  /* Open the dialog */
275  builder = gtk_builder_new();
276  gnc_builder_add_from_file (builder, "dialog-file-access.glade", "File Access" );
277  faw->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "File Access" ));
278  g_object_set_data_full( G_OBJECT(faw->dialog), "FileAccessWindow", faw,
279  g_free );
280 
281  faw->frame_file = GTK_WIDGET(gtk_builder_get_object (builder, "frame_file" ));
282  faw->frame_database = GTK_WIDGET(gtk_builder_get_object (builder, "frame_database" ));
283  faw->readonly_checkbutton = GTK_WIDGET(gtk_builder_get_object (builder, "readonly_checkbutton"));
284  faw->tf_host = GTK_ENTRY(gtk_builder_get_object (builder, "tf_host" ));
285  gtk_entry_set_text( faw->tf_host, DEFAULT_HOST );
286  faw->tf_database = GTK_ENTRY(gtk_builder_get_object (builder, "tf_database" ));
287  default_db = get_default_database();
288  gtk_entry_set_text( faw->tf_database, default_db );
289  faw->tf_username = GTK_ENTRY(gtk_builder_get_object (builder, "tf_username" ));
290  faw->tf_password = GTK_ENTRY(gtk_builder_get_object (builder, "tf_password" ));
291 
292  switch ( type )
293  {
294  case FILE_ACCESS_OPEN:
295  gtk_window_set_title(GTK_WINDOW(faw->dialog), _("Open..."));
296  button_label = "gtk-open";
297  fileChooserAction = GTK_FILE_CHOOSER_ACTION_OPEN;
298  settings_section = GNC_PREFS_GROUP_OPEN_SAVE;
299  break;
300 
301  case FILE_ACCESS_SAVE_AS:
302  gtk_window_set_title(GTK_WINDOW(faw->dialog), _("Save As..."));
303  button_label = "gtk-save-as";
304  fileChooserAction = GTK_FILE_CHOOSER_ACTION_SAVE;
305  settings_section = GNC_PREFS_GROUP_OPEN_SAVE;
306  gtk_widget_destroy(faw->readonly_checkbutton);
307  faw->readonly_checkbutton = NULL;
308  break;
309 
310  case FILE_ACCESS_EXPORT:
311  gtk_window_set_title(GTK_WINDOW(faw->dialog), _("Export"));
312  button_label = "gtk-save-as";
313  fileChooserAction = GTK_FILE_CHOOSER_ACTION_SAVE;
314  settings_section = GNC_PREFS_GROUP_EXPORT;
315  gtk_widget_destroy(faw->readonly_checkbutton);
316  faw->readonly_checkbutton = NULL;
317  break;
318  }
319 
320  op = GTK_BUTTON(gtk_builder_get_object (builder, "pb_op" ));
321  if ( op != NULL )
322  {
323  gtk_button_set_label( op, button_label );
324  gtk_button_set_use_stock( op, TRUE );
325  }
326 
327  file_chooser = GTK_WIDGET(gtk_builder_get_object (builder, "file_chooser" ));
328  fileChooser = GTK_FILE_CHOOSER_WIDGET(gtk_file_chooser_widget_new( fileChooserAction ));
329  faw->fileChooser = GTK_FILE_CHOOSER(fileChooser);
330  gtk_box_pack_start( GTK_BOX(file_chooser), GTK_WIDGET(fileChooser), TRUE, TRUE, 6 );
331 
332  /* Set the default directory */
333  if (type == FILE_ACCESS_OPEN || type == FILE_ACCESS_SAVE_AS)
334  {
335  last = gnc_history_get_last();
336  if ( last && gnc_uri_is_file_uri ( last ) )
337  {
338  gchar *filepath = gnc_uri_get_path ( last );
339  faw->starting_dir = g_path_get_dirname( filepath );
340  g_free ( filepath );
341  }
342  }
343  if (!faw->starting_dir)
344  faw->starting_dir = gnc_get_default_directory(settings_section);
345  gtk_file_chooser_set_current_folder(faw->fileChooser, faw->starting_dir);
346 
347  g_object_connect( G_OBJECT(faw->fileChooser), "signal::file-activated",
348  gnc_ui_file_access_file_activated_cb, faw, NULL );
349 
350  uri_type_container = GTK_WIDGET(gtk_builder_get_object (builder, "vb_uri_type_container" ));
351  faw->cb_uri_type = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new());
352  gtk_container_add( GTK_CONTAINER(uri_type_container), GTK_WIDGET(faw->cb_uri_type) );
353  gtk_box_set_child_packing( GTK_BOX(uri_type_container), GTK_WIDGET(faw->cb_uri_type),
354  /*expand*/TRUE, /*fill*/FALSE, /*padding*/0, GTK_PACK_START );
355  g_object_connect( G_OBJECT(faw->cb_uri_type),
356  "signal::changed", cb_uri_type_changed_cb, NULL,
357  NULL );
358 
359  /* Autoconnect signals */
360  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, faw);
361 
362  /* See what qof backends are available and add appropriate ones to the combo box */
364  for ( node = list; node != NULL; node = node->next )
365  {
366  const gchar* access_method = node->data;
367 
368  /* For the different access methods, "mysql" and "postgres" are added if available. Access
369  methods "xml" and "sqlite3" are compressed to "file" if opening a file, but when saving a file,
370  both access methods are added. */
371  if ( strcmp( access_method, "mysql" ) == 0 )
372  {
373  need_access_method_mysql = TRUE;
374  }
375  else if ( strcmp( access_method, "postgres" ) == 0 )
376  {
377  need_access_method_postgres = TRUE;
378  }
379  else if ( strcmp( access_method, "xml" ) == 0 )
380  {
381  if ( type == FILE_ACCESS_OPEN )
382  {
383  need_access_method_file = TRUE;
384  }
385  else
386  {
387  need_access_method_xml = TRUE;
388  }
389  }
390  else if ( strcmp( access_method, "sqlite3" ) == 0 )
391  {
392  if ( type == FILE_ACCESS_OPEN )
393  {
394  need_access_method_file = TRUE;
395  }
396  else
397  {
398  need_access_method_sqlite3 = TRUE;
399  }
400  }
401  }
402  g_list_free(list);
403 
404  /* Now that the set of access methods has been ascertained, add them to the list, and set the
405  default. */
406  access_method_index = -1;
407  if ( need_access_method_file )
408  {
409  gtk_combo_box_text_append_text( faw->cb_uri_type, "file" );
410  active_access_method_index = ++access_method_index;
411  }
412  if ( need_access_method_mysql )
413  {
414  gtk_combo_box_text_append_text( faw->cb_uri_type, "mysql" );
415  ++access_method_index;
416  }
417  if ( need_access_method_postgres )
418  {
419  gtk_combo_box_text_append_text( faw->cb_uri_type, "postgres" );
420  ++access_method_index;
421  }
422  if ( need_access_method_sqlite3 )
423  {
424  gtk_combo_box_text_append_text( faw->cb_uri_type, "sqlite3" );
425  active_access_method_index = ++access_method_index;
426  }
427  if ( need_access_method_xml )
428  {
429  gtk_combo_box_text_append_text( faw->cb_uri_type, "xml" );
430  ++access_method_index;
431 
432  // Set XML as default if it is offered (which mean we are in
433  // the "Save As" dialog)
434  active_access_method_index = access_method_index;
435  }
436  g_assert( active_access_method_index >= 0 );
437 
438  g_object_unref(G_OBJECT(builder));
439 
440  /* Run the dialog */
441  gtk_widget_show_all( faw->dialog );
442 
443  /* Hide the frame that's not required for the active access method so either only
444  * the File or only the Database frame are presented. */
445  gtk_combo_box_set_active(GTK_COMBO_BOX(faw->cb_uri_type), active_access_method_index );
446  set_widget_sensitivity_for_uri_type( faw, gtk_combo_box_text_get_active_text( faw->cb_uri_type ));
447 }
448 
449 void
450 gnc_ui_file_access_for_open( void )
451 {
452  gnc_ui_file_access( FILE_ACCESS_OPEN );
453 }
454 
455 
456 void
457 gnc_ui_file_access_for_save_as( void )
458 {
459  gnc_ui_file_access( FILE_ACCESS_SAVE_AS );
460 }
461 
462 
463 void
464 gnc_ui_file_access_for_export( void )
465 {
466  gnc_ui_file_access( FILE_ACCESS_EXPORT );
467 }
gboolean gnc_uri_is_file_protocol(const gchar *protocol)
Definition: gnc-uri-utils.c:58
gboolean gnc_uri_is_file_uri(const gchar *uri)
Definition: gnc-uri-utils.c:71
utility functions for the GnuCash UI
gchar * gnc_uri_get_path(const gchar *uri)
#define PERR(format, args...)
Definition: qoflog.h:237
char * gnc_history_get_last(void)
Functions providing the file history menu.
void gnc_gnome_help(const char *file_name, const char *anchor)
gchar * gnc_uri_create_uri(const gchar *protocol, const gchar *hostname, gint32 port, const gchar *username, const gchar *password, const gchar *path)
GList * qof_backend_get_registered_access_method_list(void)
Utility functions for convert uri in separate components and back.
const gchar * QofLogModule
Definition: qofid.h:89