31 #include <glib/gi18n.h>
33 #include "dialog-utils.h"
38 #include "gnc-component-manager.h"
40 #include "assistant-utils.h"
42 #include "csv-account-import.h"
44 #define GNC_PREFS_GROUP "dialogs.import.csv"
45 #define ASSISTANT_CSV_IMPORT_CM_CLASS "assistant-csv-account-import"
52 void csv_import_assistant_prepare (GtkAssistant *assistant, GtkWidget *page, gpointer user_data);
53 void csv_import_assistant_finish (GtkAssistant *gtkassistant, gpointer user_data);
54 void csv_import_assistant_cancel (GtkAssistant *gtkassistant, gpointer user_data);
55 void csv_import_assistant_close (GtkAssistant *gtkassistant, gpointer user_data);
57 void csv_import_assistant_start_page_prepare (GtkAssistant *gtkassistant, gpointer user_data);
58 void csv_import_assistant_account_page_prepare (GtkAssistant *gtkassistant, gpointer user_data);
59 void csv_import_assistant_file_page_prepare (GtkAssistant *assistant, gpointer user_data);
60 void csv_import_assistant_finish_page_prepare (GtkAssistant *assistant, gpointer user_data);
61 void csv_import_assistant_summary_page_prepare (GtkAssistant *assistant, gpointer user_data);
63 void csv_import_sep_cb (GtkWidget *radio, gpointer user_data );
64 void csv_import_hrows_cb (GtkWidget *spin, gpointer user_data );
66 void csv_import_file_chooser_confirm_cb (GtkWidget *button,
CsvImportInfo *info);
68 static gchar *gnc_input_dialog (GtkWidget *parent,
const gchar *title,
const gchar *msg,
const gchar *default_input);
70 static const gchar *finish_tree_string = N_(
71 "The accounts will be imported from the file '%s' when you click 'Apply'.\n\n"
72 "You can verify your selections by clicking on 'Back' or 'Cancel' to Abort Import.\n");
74 static const gchar *new_book_finish_tree_string = N_(
75 "The accounts will be imported from the file '%s' when you click 'Apply'.\n\n"
76 "You can verify your selections by clicking on 'Back' or 'Cancel' to Abort Import.\n\n"
77 "If this is your initial import into a new file, you will first see "
78 "a dialog for setting book options, since these can affect how "
79 "imported data is converted to GnuCash transactions.\n"
80 "Note: After import, you may need to use 'View / Filter By / Other' menu option "
81 "and select to show unused Accounts.\n");
84 static gchar *mnemonic_escape (
const gchar *source);
85 static gchar *mnemonic_escape (
const gchar *source)
91 g_return_val_if_fail (source != NULL, NULL);
93 p = (guchar *) source;
94 q = dest = g_malloc (strlen (source) * 2 + 1);
115 void create_regex (GString *regex_str,
const gchar *sep)
119 g_string_printf (regex_str,
120 "\\G(?<type>[^%s]*)%s"
121 "(?<full_name>\"(?:[^\"]|\"\")*\"|[^%s]*)%s"
122 "(?<name>\"(?:[^\"]|\"\")*\"|[^%s]*)%s"
123 "(?<code>\"(?:[^\"]|\"\")*\"|[^%s]*)%s?"
124 "(?<description>\"(?:[^\"]|\"\")*\"|[^%s]*)%s"
126 "(?<notes>\"(?:[^\"]|\"\")*\"|[^%s]*)%s"
127 "(?<commoditym>\"(?:[^\"]|\"\")*\"|[^%s]*)%s"
128 "(?<commodityn>\"(?:[^\"]|\"\")*\"|[^%s]*)%s"
129 "(?<hidden>[^%s]*)%s"
131 "(?<place_holder>[^%s[:cntrl:]]*)(?:\\R*)",
132 sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep,
133 sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep);
145 csv_import_file_chooser_confirm_cb (GtkWidget *button,
CsvImportInfo *info)
147 GtkAssistant *assistant = GTK_ASSISTANT(info->window);
148 gint num = gtk_assistant_get_current_page (assistant);
149 GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
152 csv_import_result res;
154 gtk_assistant_set_page_complete (assistant, page, FALSE);
156 file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(info->file_chooser));
161 gchar *filedir = g_path_get_dirname (filepath);
162 info->starting_dir = g_strdup (filedir);
166 info->file_name = g_strdup (file_name);
169 gtk_list_store_clear (info->store);
170 res = csv_import_read_file (info->file_name, info->regexp->str, info->store, 1 );
171 if (res == RESULT_OPEN_FAILED)
172 gnc_error_dialog (info->window, _(
"The input file can not be opened."));
173 else if (res == RESULT_OK)
174 gtk_assistant_set_page_complete (assistant, page, TRUE);
175 else if (res == MATCH_FOUND)
176 gtk_assistant_set_page_complete (assistant, page, TRUE);
180 DEBUG(
"file_name selected is %s", info->file_name);
181 DEBUG(
"starting directory is %s", info->starting_dir);
184 if(gtk_assistant_get_page_complete (assistant, page))
185 gtk_assistant_set_current_page (assistant, num + 1);
195 void csv_import_hrows_cb (GtkWidget *spin, gpointer user_data)
204 info->header_rows = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spin));
207 num_rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL(info->store), NULL);
210 if (info->header_rows == 0)
212 valid = gtk_tree_model_iter_nth_child (GTK_TREE_MODEL(info->store), &iter, NULL, 0 );
214 gtk_list_store_set (info->store, &iter, ROW_COLOR, NULL, -1);
218 if (info->header_rows - 1 < num_rows)
220 valid = gtk_tree_model_iter_nth_child (GTK_TREE_MODEL(info->store), &iter, NULL, info->header_rows - 1 );
222 gtk_list_store_set (info->store, &iter, ROW_COLOR,
"pink", -1);
223 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(info->store), &iter);
225 gtk_list_store_set (info->store, &iter, ROW_COLOR, NULL, -1);
236 void csv_import_sep_cb (GtkWidget *radio, gpointer user_data)
243 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(radio)))
245 LEAVE(
"1st callback of pair. Defer to 2nd callback.");
249 name = gtk_buildable_get_name (GTK_BUILDABLE(radio));
250 if (g_strcmp0 (name,
"radio_semi") == 0)
252 else if (g_strcmp0 (name,
"radio_colon") == 0)
257 create_regex (info->regexp, sep);
259 if (g_strcmp0 (name,
"radio_custom") == 0)
261 temp = gnc_input_dialog (0, _(
"Adjust regular expression used for import"), _(
"This regular expression is used to parse the import file. Modify according to your needs.\n"), info->regexp->str);
264 g_string_assign (info->regexp, temp);
270 gtk_list_store_clear (info->store);
272 if (csv_import_read_file (info->file_name, info->regexp->str, info->store, 11) == MATCH_FOUND)
273 gtk_widget_set_sensitive (info->header_row_spin, TRUE);
275 gtk_widget_set_sensitive (info->header_row_spin, FALSE);
278 gtk_spin_button_set_value (GTK_SPIN_BUTTON(info->header_row_spin), 0);
290 info->header_rows = 0;
292 info->starting_dir = NULL;
293 info->file_name = NULL;
297 info->starting_dir = gnc_get_default_directory (GNC_PREFS_GROUP);
319 gnc_input_dialog (GtkWidget *parent,
const gchar *title,
const gchar *msg,
const gchar *default_input)
321 GtkWidget *dialog, *label, *content_area;
324 GtkTextBuffer *buffer;
326 GtkTextIter start, end;
329 dialog = gtk_dialog_new_with_buttons (title, GTK_WINDOW(parent),
330 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
331 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
332 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
335 content_area = gtk_dialog_get_content_area (GTK_DIALOG(dialog));
338 label = gtk_label_new (msg);
339 gtk_container_add (GTK_CONTAINER(content_area), label);
342 view = gtk_text_view_new ();
343 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW(view), GTK_WRAP_WORD_CHAR);
344 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(view));
345 gtk_text_buffer_set_text (buffer, default_input, -1);
346 gtk_container_add (GTK_CONTAINER(content_area), view);
349 gtk_widget_show_all (dialog);
350 result = gtk_dialog_run (GTK_DIALOG(dialog));
352 if (result == GTK_RESPONSE_REJECT)
356 gtk_text_buffer_get_start_iter (buffer, &start);
357 gtk_text_buffer_get_end_iter (buffer, &end);
358 user_input = gtk_text_buffer_get_text (buffer,
359 &start, &end, FALSE);
362 gtk_widget_destroy (dialog);
375 csv_import_assistant_start_page_prepare (GtkAssistant *assistant,
378 gint num = gtk_assistant_get_current_page (assistant);
379 GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
382 gtk_assistant_set_page_complete (assistant, page, TRUE);
387 csv_import_assistant_file_page_prepare (GtkAssistant *assistant,
391 gint num = gtk_assistant_get_current_page (assistant);
392 GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
395 if (info->starting_dir)
396 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(info->file_chooser), info->starting_dir);
399 gtk_assistant_set_page_complete (assistant, page, FALSE);
404 csv_import_assistant_account_page_prepare (GtkAssistant *assistant,
409 gtk_list_store_clear (info->store);
411 if (csv_import_read_file (info->file_name, info->regexp->str, info->store, 11 ) == MATCH_FOUND)
412 gtk_widget_set_sensitive (info->header_row_spin, TRUE);
414 gtk_widget_set_sensitive (info->header_row_spin, FALSE);
419 csv_import_assistant_finish_page_prepare (GtkAssistant *assistant,
423 gint num = gtk_assistant_get_current_page (assistant);
424 GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
432 text = g_strdup_printf (gettext (new_book_finish_tree_string), info->file_name);
436 text = g_strdup_printf (gettext (finish_tree_string), info->file_name);
438 gtk_label_set_text (GTK_LABEL(info->finish_label), text);
442 gnc_set_default_directory (GNC_PREFS_GROUP, info->starting_dir);
445 gtk_assistant_set_page_complete (assistant, page, TRUE);
450 csv_import_assistant_summary_page_prepare (GtkAssistant *assistant,
454 gchar *text, *errtext, *mtext;
459 info->
new_book = gnc_new_book_option_display (info->window);
461 if (!g_strcmp0 (info->error,
"") == 0)
463 GtkTextBuffer *buffer;
465 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(info->summary_error_view));
466 text = g_strdup_printf (gettext (
"Import completed but with errors!\n\nThe number of Accounts added was %u and "
467 "%u were updated.\n\nSee below for errors..."), info->num_new, info->num_updates);
468 errtext = g_strdup_printf (
"%s", info->error);
469 gtk_text_buffer_set_text (buffer, errtext, -1);
471 g_free (info->error);
474 text = g_strdup_printf (gettext (
"Import completed successfully!\n\nThe number of Accounts added was %u and "
475 "%u were updated.\n"), info->num_new, info->num_updates);
477 mtext = g_strdup_printf (
"<span size=\"medium\"><b>%s</b></span>", text);
478 gtk_label_set_markup (GTK_LABEL(info->summary_label), mtext);
486 csv_import_assistant_prepare (GtkAssistant *assistant, GtkWidget *page,
489 gint currentpage = gtk_assistant_get_current_page (assistant);
495 csv_import_assistant_start_page_prepare (assistant, user_data);
499 csv_import_assistant_file_page_prepare (assistant, user_data);
503 csv_import_assistant_account_page_prepare (assistant, user_data);
507 csv_import_assistant_finish_page_prepare (assistant, user_data);
511 csv_import_assistant_summary_page_prepare (assistant, user_data);
521 csv_import_assistant_destroy_cb (GtkObject *
object, gpointer user_data)
524 gnc_unregister_gui_component_by_data (ASSISTANT_CSV_IMPORT_CM_CLASS, info);
529 csv_import_assistant_cancel (GtkAssistant *assistant, gpointer user_data)
532 gnc_close_gui_component_by_data (ASSISTANT_CSV_IMPORT_CM_CLASS, info);
536 csv_import_assistant_close (GtkAssistant *assistant, gpointer user_data)
539 gnc_close_gui_component_by_data (ASSISTANT_CSV_IMPORT_CM_CLASS, info);
543 csv_import_assistant_finish (GtkAssistant *assistant, gpointer user_data)
547 gtk_list_store_clear (info->store);
548 csv_import_read_file (info->file_name, info->regexp->str, info->store, 0 );
549 csv_account_import (info);
553 csv_import_close_handler (gpointer user_data)
557 g_free (info->starting_dir);
558 g_free (info->file_name);
559 g_string_free (info->regexp, TRUE);
561 gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(info->window));
562 gtk_widget_destroy (info->window);
573 GtkWidget *box, *h_box;
575 GtkCellRenderer *renderer;
576 GtkTreeViewColumn *column;
577 gchar *mnemonic_desc = NULL;
579 builder = gtk_builder_new();
580 gnc_builder_add_from_file (builder,
"assistant-csv-account-import.glade",
"num_hrows_adj");
581 gnc_builder_add_from_file (builder,
"assistant-csv-account-import.glade",
"CSV Account Import Assistant");
582 window = GTK_WIDGET(gtk_builder_get_object (builder,
"CSV Account Import Assistant"));
583 info->window = window;
586 gnc_assistant_set_colors (GTK_ASSISTANT (info->window));
589 load_settings (info);
592 gtk_assistant_set_page_complete (GTK_ASSISTANT(window),
593 GTK_WIDGET(gtk_builder_get_object(builder,
"start_page")),
595 gtk_assistant_set_page_complete (GTK_ASSISTANT(window),
596 GTK_WIDGET(gtk_builder_get_object(builder,
"file_page")),
598 gtk_assistant_set_page_complete (GTK_ASSISTANT(window),
599 GTK_WIDGET(gtk_builder_get_object(builder,
"import_tree_page")),
601 gtk_assistant_set_page_complete (GTK_ASSISTANT(window),
602 GTK_WIDGET(gtk_builder_get_object(builder,
"end_page")),
604 gtk_assistant_set_page_complete (GTK_ASSISTANT(window),
605 GTK_WIDGET(gtk_builder_get_object(builder,
"summary_page")),
611 info->file_chooser = gtk_file_chooser_widget_new (GTK_FILE_CHOOSER_ACTION_OPEN);
612 g_signal_connect (G_OBJECT(info->file_chooser),
"file-activated",
613 G_CALLBACK(csv_import_file_chooser_confirm_cb), info);
614 button = gtk_button_new_from_stock (GTK_STOCK_OK);
615 gtk_widget_set_size_request (button, 100, -1);
616 gtk_widget_show (button);
617 h_box = gtk_hbox_new (TRUE, 0);
618 gtk_box_pack_start (GTK_BOX(h_box), button, FALSE, FALSE, 0);
619 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(info->file_chooser), h_box);
620 g_signal_connect (G_OBJECT(button),
"clicked",
621 G_CALLBACK(csv_import_file_chooser_confirm_cb), info);
623 box = GTK_WIDGET(gtk_builder_get_object(builder,
"file_page"));
624 gtk_box_pack_start (GTK_BOX(box), info->file_chooser, TRUE, TRUE, 6);
625 gtk_widget_show (info->file_chooser);
628 info->header_row_spin = GTK_WIDGET(gtk_builder_get_object (builder,
"num_hrows"));
629 info->tree_view = GTK_WIDGET(gtk_builder_get_object (builder,
"treeview"));
632 info->regexp = g_string_new (
"");
633 create_regex (info->regexp,
",");
636 info->store = gtk_list_store_new (N_COLUMNS,
637 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
638 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
639 gtk_tree_view_set_model (GTK_TREE_VIEW(info->tree_view), GTK_TREE_MODEL(info->store));
640 #define CREATE_COLUMN(description,column_id) \
641 renderer = gtk_cell_renderer_text_new (); \
642 mnemonic_desc = mnemonic_escape (_(description)); \
643 column = gtk_tree_view_column_new_with_attributes (mnemonic_desc, renderer, "text", column_id, NULL); \
644 gtk_tree_view_column_add_attribute (column, renderer, "background", ROW_COLOR); \
645 gtk_tree_view_column_set_resizable (column, TRUE); \
646 gtk_tree_view_append_column (GTK_TREE_VIEW(info->tree_view), column); \
647 g_free (mnemonic_desc);
648 CREATE_COLUMN (
"type", TYPE);
649 CREATE_COLUMN (
"full_name", FULL_NAME);
650 CREATE_COLUMN (
"name", NAME);
651 CREATE_COLUMN (
"code", CODE);
652 CREATE_COLUMN (
"description", DESCRIPTION);
653 CREATE_COLUMN (
"color", COLOR);
654 CREATE_COLUMN (
"notes", NOTES);
655 CREATE_COLUMN (
"commoditym", COMMODITYM);
656 CREATE_COLUMN (
"commodityn", COMMODITYN);
657 CREATE_COLUMN (
"hidden", HIDDEN);
658 CREATE_COLUMN (
"tax", TAX);
659 CREATE_COLUMN (
"place_holder", PLACE_HOLDER);
662 info->finish_label = GTK_WIDGET(gtk_builder_get_object (builder,
"end_page"));
664 info->summary_label = GTK_WIDGET(gtk_builder_get_object (builder,
"summary_label"));
665 info->summary_error_view = GTK_WIDGET(gtk_builder_get_object (builder,
"summary_error_view"));
667 g_signal_connect (G_OBJECT(window),
"destroy",
668 G_CALLBACK(csv_import_assistant_destroy_cb), info);
670 gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(info->window));
672 gtk_builder_connect_signals (builder, info);
673 g_object_unref (G_OBJECT(builder));
696 csv_import_assistant_create (info);
698 gnc_register_gui_component (ASSISTANT_CSV_IMPORT_CM_CLASS,
699 NULL, csv_import_close_handler,
702 gtk_widget_show_all (info->window);
704 gnc_window_adjust_for_screen (GTK_WINDOW(info->window));
utility functions for the GnuCash UI
#define DEBUG(format, args...)
gchar * gnc_uri_get_path(const gchar *uri)
void gnc_file_csv_account_import(void)
#define LEAVE(format, args...)
Utility functions for convert uri in separate components and back.
const gchar * QofLogModule