31 #include <glib/gi18n.h> 33 #include "dialog-utils.h" 38 #include "gnc-component-manager.h" 41 #include "csv-account-import.h" 43 #define GNC_PREFS_GROUP "dialogs.import.csv" 44 #define ASSISTANT_CSV_IMPORT_CM_CLASS "assistant-csv-account-import" 47 static QofLogModule log_module = GNC_MOD_ASSISTANT;
51 void csv_import_assistant_prepare (GtkAssistant *assistant, GtkWidget *page, gpointer user_data);
52 void csv_import_assistant_finish (GtkAssistant *gtkassistant, gpointer user_data);
53 void csv_import_assistant_cancel (GtkAssistant *gtkassistant, gpointer user_data);
54 void csv_import_assistant_close (GtkAssistant *gtkassistant, gpointer user_data);
56 void csv_import_assistant_start_page_prepare (GtkAssistant *gtkassistant, gpointer user_data);
57 void csv_import_assistant_account_page_prepare (GtkAssistant *gtkassistant, gpointer user_data);
58 void csv_import_assistant_file_page_prepare (GtkAssistant *assistant, gpointer user_data);
59 void csv_import_assistant_finish_page_prepare (GtkAssistant *assistant, gpointer user_data);
60 void csv_import_assistant_summary_page_prepare (GtkAssistant *assistant, gpointer user_data);
62 void csv_import_sep_cb (GtkWidget *radio, gpointer user_data );
63 void csv_import_hrows_cb (GtkWidget *spin, gpointer user_data );
65 void csv_import_file_chooser_file_activated_cb (GtkFileChooser *chooser,
CsvImportInfo *info);
66 void csv_import_file_chooser_selection_changed_cb (GtkFileChooser *chooser,
CsvImportInfo *info);
68 static const gchar *finish_tree_string = N_(
69 "The accounts will be imported from the file '%s' when you click 'Apply'.\n\n" 70 "You can verify your selections by clicking on 'Back' or 'Cancel' to Abort Import.\n");
72 static const gchar *new_book_finish_tree_string = N_(
73 "The accounts will be imported from the file '%s' when you click 'Apply'.\n\n" 74 "You can verify your selections by clicking on 'Back' or 'Cancel' to Abort Import.\n\n" 75 "If this is your initial import into a new file, you will first see " 76 "a dialog for setting book options, since these can affect how " 77 "imported data is converted to GnuCash transactions.\n" 78 "Note: After import, you may need to use 'View / Filter By / Other' menu option " 79 "and select to show unused Accounts.\n");
82 static gchar *mnemonic_escape (
const gchar *source);
83 static gchar *mnemonic_escape (
const gchar *source)
89 g_return_val_if_fail (source != NULL, NULL);
91 p = (guchar *) source;
92 q = dest = g_malloc (strlen (source) * 2 + 1);
113 void create_regex (GString *regex_str,
const gchar *sep)
117 g_string_printf (regex_str,
118 "\\G(?<type>[^%s]*)%s" 119 "(?<full_name>\"(?:[^\"]|\"\")*\"|[^%s]*)%s" 120 "(?<name>\"(?:[^\"]|\"\")*\"|[^%s]*)%s" 121 "(?<code>\"(?:[^\"]|\"\")*\"|[^%s]*)%s?" 122 "(?<description>\"(?:[^\"]|\"\")*\"|[^%s]*)%s" 123 "(?<color>\"(?:[^\"]|\"\")*\"|[^%s]*)%s" 124 "(?<notes>\"(?:[^\"]|\"\")*\"|[^%s]*)%s" 125 "(?<symbol>\"(?:[^\"]|\"\")*\"|[^%s]*)%s" 126 "(?<namespace>\"(?:[^\"]|\"\")*\"|[^%s]*)%s" 127 "(?<hidden>[^%s]*)%s" 129 "(?<placeholder>[^%s[:cntrl:]]*)(?:\\R*)",
130 sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep,
131 sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep);
143 csv_import_assistant_check_filename (GtkFileChooser *chooser,
146 gchar *file_name = gtk_file_chooser_get_filename (chooser);
149 if (file_name && !g_file_test (file_name, G_FILE_TEST_IS_DIR))
152 gchar *filedir = g_path_get_dirname (filepath);
154 g_free (info->file_name);
155 info->file_name = g_strdup (file_name);
157 g_free (info->starting_dir);
158 info->starting_dir = g_strdup (filedir);
164 DEBUG(
"file_name selected is %s", info->file_name);
165 DEBUG(
"starting directory is %s", info->starting_dir);
179 csv_import_file_chooser_file_activated_cb (GtkFileChooser *chooser,
182 GtkAssistant *assistant = GTK_ASSISTANT(info->assistant);
183 gtk_assistant_set_page_complete (assistant, info->file_page, FALSE);
186 if (csv_import_assistant_check_filename (chooser, info))
188 gtk_assistant_set_page_complete (assistant, info->file_page, TRUE);
189 gtk_assistant_next_page (assistant);
200 csv_import_file_chooser_selection_changed_cb (GtkFileChooser *chooser,
203 GtkAssistant *assistant = GTK_ASSISTANT(info->assistant);
204 gtk_assistant_set_page_complete (assistant, info->account_page, FALSE);
207 gtk_assistant_set_page_complete (assistant, info->file_page,
208 csv_import_assistant_check_filename (chooser, info));
217 void csv_import_hrows_cb (GtkWidget *spin, gpointer user_data)
226 info->header_rows = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spin));
229 num_rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL(info->store), NULL);
232 if (info->header_rows == 0)
234 valid = gtk_tree_model_iter_nth_child (GTK_TREE_MODEL(info->store), &iter, NULL, 0 );
236 gtk_list_store_set (info->store, &iter, ROW_COLOR, NULL, -1);
240 if (info->header_rows - 1 < num_rows)
242 valid = gtk_tree_model_iter_nth_child (GTK_TREE_MODEL(info->store), &iter, NULL, info->header_rows - 1 );
244 gtk_list_store_set (info->store, &iter, ROW_COLOR,
"pink", -1);
245 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(info->store), &iter);
247 gtk_list_store_set (info->store, &iter, ROW_COLOR, NULL, -1);
258 static void csv_import_assistant_enable_account_forward (
CsvImportInfo *info)
260 GtkAssistant *assistant = GTK_ASSISTANT(info->assistant);
261 gboolean store_has_rows = TRUE;
264 if (gtk_tree_model_iter_n_children (GTK_TREE_MODEL(info->store), NULL) == 0)
265 store_has_rows = FALSE;
267 gtk_assistant_set_page_complete (assistant, info->account_page, store_has_rows);
276 void csv_import_sep_cb (GtkWidget *radio, gpointer user_data)
283 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(radio)))
285 LEAVE(
"1st callback of pair. Defer to 2nd callback.");
289 name = gtk_buildable_get_name (GTK_BUILDABLE(radio));
290 if (g_strcmp0 (name,
"radio_semi") == 0)
292 else if (g_strcmp0 (name,
"radio_colon") == 0)
297 create_regex (info->regexp, sep);
299 if (g_strcmp0 (name,
"radio_custom") == 0)
301 temp = gnc_input_dialog (GTK_WIDGET (info->assistant),
302 _(
"Adjust regular expression used for import"),
303 _(
"This regular expression is used to parse the import file. Modify according to your needs.\n"),
307 g_string_assign (info->regexp, temp);
313 gtk_list_store_clear (info->store);
314 gtk_widget_set_sensitive (info->header_row_spin, TRUE);
316 if (csv_import_read_file (GTK_WINDOW (info->assistant), info->file_name, info->regexp->str, info->store, 11) == MATCH_FOUND)
317 gtk_spin_button_set_value (GTK_SPIN_BUTTON(info->header_row_spin), 1);
319 gtk_spin_button_set_value (GTK_SPIN_BUTTON(info->header_row_spin), 0);
322 csv_import_assistant_enable_account_forward (info);
334 info->header_rows = 0;
336 info->starting_dir = NULL;
337 info->file_name = NULL;
341 info->starting_dir = gnc_get_default_directory (GNC_PREFS_GROUP);
351 csv_import_assistant_start_page_prepare (GtkAssistant *assistant,
354 gint num = gtk_assistant_get_current_page (assistant);
355 GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
358 gtk_assistant_set_page_complete (assistant, page, TRUE);
363 csv_import_assistant_file_page_prepare (GtkAssistant *assistant,
369 if (info->starting_dir)
370 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(info->file_chooser), info->starting_dir);
373 gtk_assistant_set_page_complete (assistant, info->file_page, FALSE);
378 csv_import_assistant_account_page_prepare (GtkAssistant *assistant,
382 csv_import_result res;
385 gtk_assistant_set_page_complete (assistant, info->account_page, FALSE);
388 gtk_list_store_clear (info->store);
389 res = csv_import_read_file (GTK_WINDOW (info->assistant), info->file_name, info->regexp->str, info->store, 1 );
390 if (res == RESULT_OPEN_FAILED)
392 gnc_error_dialog (GTK_WINDOW (info->assistant), _(
"The input file can not be opened."));
393 gtk_assistant_previous_page (assistant);
395 else if (res == RESULT_OK)
396 gtk_assistant_set_page_complete (assistant, info->account_page, TRUE);
397 else if (res == MATCH_FOUND)
398 gtk_assistant_set_page_complete (assistant, info->account_page, TRUE);
401 gtk_list_store_clear (info->store);
403 gtk_widget_set_sensitive (info->header_row_spin, TRUE);
405 if (csv_import_read_file (GTK_WINDOW (info->assistant), info->file_name, info->regexp->str, info->store, 11 ) == MATCH_FOUND)
406 gtk_spin_button_set_value (GTK_SPIN_BUTTON(info->header_row_spin), 1);
408 gtk_spin_button_set_value (GTK_SPIN_BUTTON(info->header_row_spin), 0);
411 csv_import_assistant_enable_account_forward (info);
416 csv_import_assistant_finish_page_prepare (GtkAssistant *assistant,
426 text = g_strdup_printf (gettext (new_book_finish_tree_string), info->file_name);
428 text = g_strdup_printf (gettext (finish_tree_string), info->file_name);
430 gtk_label_set_text (GTK_LABEL(info->finish_label), text);
434 gnc_set_default_directory (GNC_PREFS_GROUP, info->starting_dir);
437 gtk_assistant_set_page_complete (assistant, info->finish_label, TRUE);
442 csv_import_assistant_summary_page_prepare (GtkAssistant *assistant,
446 gchar *text, *errtext, *mtext;
451 info->new_book = gnc_new_book_option_display (info->assistant);
453 if (g_strcmp0 (info->error,
"") != 0)
455 GtkTextBuffer *buffer;
457 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(info->summary_error_view));
458 text = g_strdup_printf (gettext (
"Import completed but with errors!\n\nThe number of Accounts added was %u and " 459 "%u were updated.\n\nSee below for errors…"), info->num_new, info->num_updates);
460 errtext = g_strdup_printf (
"%s", info->error);
461 gtk_text_buffer_set_text (buffer, errtext, -1);
463 g_free (info->error);
466 text = g_strdup_printf (gettext (
"Import completed successfully!\n\nThe number of Accounts added was %u and " 467 "%u were updated.\n"), info->num_new, info->num_updates);
469 mtext = g_strdup_printf (
"<span size=\"medium\"><b>%s</b></span>", text);
470 gtk_label_set_markup (GTK_LABEL(info->summary_label), mtext);
478 csv_import_assistant_prepare (GtkAssistant *assistant, GtkWidget *page,
481 gint currentpage = gtk_assistant_get_current_page (assistant);
487 csv_import_assistant_start_page_prepare (assistant, user_data);
491 csv_import_assistant_file_page_prepare (assistant, user_data);
495 csv_import_assistant_account_page_prepare (assistant, user_data);
499 csv_import_assistant_finish_page_prepare (assistant, user_data);
503 csv_import_assistant_summary_page_prepare (assistant, user_data);
513 csv_import_assistant_destroy_cb (GtkWidget *
object, gpointer user_data)
516 gnc_unregister_gui_component_by_data (ASSISTANT_CSV_IMPORT_CM_CLASS, info);
521 csv_import_assistant_cancel (GtkAssistant *assistant, gpointer user_data)
524 gnc_close_gui_component_by_data (ASSISTANT_CSV_IMPORT_CM_CLASS, info);
528 csv_import_assistant_close (GtkAssistant *assistant, gpointer user_data)
531 gnc_close_gui_component_by_data (ASSISTANT_CSV_IMPORT_CM_CLASS, info);
535 csv_import_assistant_finish (GtkAssistant *assistant, gpointer user_data)
539 gtk_list_store_clear (info->store);
540 csv_import_read_file (GTK_WINDOW (info->assistant), info->file_name, info->regexp->str, info->store, 0 );
541 csv_account_import (info);
545 csv_import_close_handler (gpointer user_data)
549 g_free (info->starting_dir);
550 g_free (info->file_name);
551 g_string_free (info->regexp, TRUE);
552 g_object_unref (info->store);
554 gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(info->assistant));
555 gtk_widget_destroy (info->assistant);
565 GtkCellRenderer *renderer;
566 GtkTreeViewColumn *column;
567 gchar *mnemonic_desc = NULL;
569 builder = gtk_builder_new();
570 gnc_builder_add_from_file (builder,
"assistant-csv-account-import.glade",
"num_hrows_adj");
571 gnc_builder_add_from_file (builder,
"assistant-csv-account-import.glade",
"csv_account_import_assistant");
572 info->assistant = GTK_WIDGET(gtk_builder_get_object (builder,
"csv_account_import_assistant"));
575 gtk_widget_set_name (GTK_WIDGET(info->assistant),
"gnc-id-assistant-csv-account-import");
576 gnc_widget_style_context_add_class (GTK_WIDGET(info->assistant),
"gnc-class-imports");
579 load_settings (info);
582 gtk_assistant_set_page_complete (GTK_ASSISTANT(info->assistant),
583 GTK_WIDGET(gtk_builder_get_object(builder,
"start_page")),
585 gtk_assistant_set_page_complete (GTK_ASSISTANT(info->assistant),
586 GTK_WIDGET(gtk_builder_get_object(builder,
"file_page")),
588 gtk_assistant_set_page_complete (GTK_ASSISTANT(info->assistant),
589 GTK_WIDGET(gtk_builder_get_object(builder,
"import_tree_page")),
591 gtk_assistant_set_page_complete (GTK_ASSISTANT(info->assistant),
592 GTK_WIDGET(gtk_builder_get_object(builder,
"end_page")),
594 gtk_assistant_set_page_complete (GTK_ASSISTANT(info->assistant),
595 GTK_WIDGET(gtk_builder_get_object(builder,
"summary_page")),
601 info->file_page = GTK_WIDGET(gtk_builder_get_object(builder,
"file_page"));
602 info->file_chooser = gtk_file_chooser_widget_new (GTK_FILE_CHOOSER_ACTION_OPEN);
603 g_signal_connect (G_OBJECT(info->file_chooser),
"selection-changed",
604 G_CALLBACK(csv_import_file_chooser_selection_changed_cb), info);
605 g_signal_connect (G_OBJECT(info->file_chooser),
"file-activated",
606 G_CALLBACK(csv_import_file_chooser_file_activated_cb), info);
608 gtk_box_pack_start (GTK_BOX(info->file_page), info->file_chooser, TRUE, TRUE, 6);
609 gtk_widget_show (info->file_chooser);
612 info->account_page = GTK_WIDGET(gtk_builder_get_object(builder,
"import_tree_page"));
613 info->header_row_spin = GTK_WIDGET(gtk_builder_get_object (builder,
"num_hrows"));
614 info->tree_view = GTK_WIDGET(gtk_builder_get_object (builder,
"treeview"));
617 info->regexp = g_string_new (
"");
618 create_regex (info->regexp,
",");
621 info->store = gtk_list_store_new (N_COLUMNS,
622 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
623 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
624 gtk_tree_view_set_model (GTK_TREE_VIEW(info->tree_view), GTK_TREE_MODEL(info->store));
625 #define CREATE_COLUMN(description,column_id) \ 626 renderer = gtk_cell_renderer_text_new (); \ 627 mnemonic_desc = mnemonic_escape (_(description)); \ 628 column = gtk_tree_view_column_new_with_attributes (mnemonic_desc, renderer, "text", column_id, NULL); \ 629 gtk_tree_view_column_add_attribute (column, renderer, "background", ROW_COLOR); \ 630 gtk_tree_view_column_set_resizable (column, TRUE); \ 631 gtk_tree_view_append_column (GTK_TREE_VIEW(info->tree_view), column); \ 632 g_free (mnemonic_desc); 633 CREATE_COLUMN (
"Type", TYPE);
634 CREATE_COLUMN (
"Account Full Name", FULL_NAME);
635 CREATE_COLUMN (
"Account Name", NAME);
636 CREATE_COLUMN (
"Account Code", CODE);
637 CREATE_COLUMN (
"Description", DESCRIPTION);
638 CREATE_COLUMN (
"Account Color", COLOR);
639 CREATE_COLUMN (
"Notes", NOTES);
640 CREATE_COLUMN (
"Symbol", SYMBOL);
641 CREATE_COLUMN (
"Namespace", NAMESPACE);
642 CREATE_COLUMN (
"Hidden", HIDDEN);
643 CREATE_COLUMN (
"Tax Info", TAX);
644 CREATE_COLUMN (
"Placeholder", PLACE_HOLDER);
647 info->finish_label = GTK_WIDGET(gtk_builder_get_object (builder,
"end_page"));
649 info->summary_label = GTK_WIDGET(gtk_builder_get_object (builder,
"summary_label"));
650 info->summary_error_view = GTK_WIDGET(gtk_builder_get_object (builder,
"summary_error_view"));
652 g_signal_connect (G_OBJECT(info->assistant),
"destroy",
653 G_CALLBACK(csv_import_assistant_destroy_cb), info);
655 gnc_restore_window_size (GNC_PREFS_GROUP,
658 gtk_builder_connect_signals (builder, info);
659 g_object_unref (G_OBJECT(builder));
660 return info->assistant;
680 info->new_book = gnc_is_new_book();
682 csv_import_assistant_create (info);
684 gnc_register_gui_component (ASSISTANT_CSV_IMPORT_CM_CLASS,
685 NULL, csv_import_close_handler,
688 gtk_widget_show_all (info->assistant);
690 gnc_window_adjust_for_screen (GTK_WINDOW(info->assistant));
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
utility functions for the GnuCash UI
#define DEBUG(format, args...)
Print a debugging message.
gchar * gnc_uri_get_path(const gchar *uri)
Extracts the path part from a uri.
void gnc_file_csv_account_import(void)
The gnc_file_csv_account_import() will let the user import accounts from a delimited file...
#define LEAVE(format, args...)
Print a function exit debugging message.
Utility functions for convert uri in separate components and back.