36 #include <glib/gi18n.h> 45 #include "dialog-utils.h" 47 #include "gnc-component-manager.h" 56 #include "gnc-account-sel.h" 58 #include "gnc-csv-gnumeric-popup.h" 59 #include "go-charmap-sel.h" 74 #include <gnc-locale-utils.hpp> 75 #include <boost/locale.hpp> 77 namespace bl = boost::locale;
79 #define MIN_COL_WIDTH 70 80 #define GNC_PREFS_GROUP "dialogs.import.csv" 81 #define ASSISTANT_CSV_IMPORT_TRANS_CM_CLASS "assistant-csv-trans-import" 84 static QofLogModule log_module = GNC_MOD_ASSISTANT;
86 enum GncImportColumn {
165 void assist_prepare_cb (GtkWidget *page);
166 void assist_file_page_prepare ();
167 void assist_preview_page_prepare ();
168 void assist_account_match_page_prepare ();
169 void assist_doc_page_prepare ();
170 void assist_match_page_prepare ();
171 void assist_summary_page_prepare ();
172 void assist_finish ();
173 void assist_compmgr_close ();
175 void file_activated_cb ();
176 void file_selection_changed_cb ();
178 void preview_settings_delete ();
179 void preview_settings_save ();
180 void preview_settings_name (GtkEntry* entry);
181 void preview_settings_load ();
182 void preview_update_skipped_rows ();
183 void preview_multi_split (
bool multi);
186 void preview_update_account ();
188 void preview_update_date_format ();
189 void preview_update_currency_format ();
193 void preview_populate_settings_combo();
194 void preview_handle_save_del_sensitivity (GtkComboBox* combo);
195 void preview_split_column (
int col,
int offset);
196 void preview_refresh_table ();
197 void preview_refresh ();
198 void preview_validate_settings ();
200 void acct_match_via_button ();
201 bool acct_match_via_view_dblclick (GdkEventButton *event);
202 void acct_match_select(GtkTreeModel *model, GtkTreeIter* iter);
203 void acct_match_set_accounts ();
210 uint32_t get_new_col_rel_pos (GtkTreeViewColumn *tcol,
int dx);
211 void fixed_context_menu (GdkEventButton *event,
int col,
int dx);
213 void preview_row_fill_state_cells (GtkListStore *store, GtkTreeIter *iter,
214 ErrMap& err_msg,
bool skip);
216 GtkWidget* preview_cbox_factory (GtkTreeModel* model, uint32_t colnum);
218 void preview_style_column (uint32_t col_num, GtkTreeModel* model);
220 bool check_for_valid_filename ();
222 GtkAssistant *csv_imp_asst;
224 GtkWidget *file_page;
225 GtkWidget *file_chooser;
226 std::string m_fc_file_name;
227 std::string m_final_file_name;
229 GtkWidget *preview_page;
230 GtkComboBox *settings_combo;
231 GtkWidget *save_button;
232 GtkWidget *del_button;
233 GtkWidget *acct_selector;
234 GtkWidget *combo_hbox;
235 GtkSpinButton *start_row_spin;
236 GtkSpinButton *end_row_spin;
237 GtkWidget *skip_alt_rows_button;
238 GtkWidget *skip_errors_button;
239 GtkWidget *csv_button;
240 GtkWidget *fixed_button;
241 GtkWidget *multi_split_cbutton;
242 GOCharmapSel *encselector;
243 GtkWidget *separator_table;
244 GtkCheckButton *sep_button[SEP_NUM_OF_TYPES];
245 GtkWidget *fw_instructions_hbox;
246 GtkCheckButton *custom_cbutton;
247 GtkEntry *custom_entry;
248 GtkComboBoxText *date_format_combo;
249 GtkComboBoxText *currency_format_combo;
250 GtkTreeView *treeview;
251 GtkLabel *instructions_label;
252 GtkImage *instructions_image;
253 bool encoding_selected_called;
255 int fixed_context_col;
256 int fixed_context_offset;
259 GtkWidget *account_match_page;
260 GtkWidget *account_match_view;
261 GtkWidget *account_match_label;
262 GtkWidget *account_match_btn;
266 GtkWidget *match_page;
267 GtkWidget *match_label;
268 GNCImportMainMatcher *gnc_csv_importer_gui;
269 GtkWidget *help_button;
270 GtkWidget *cancel_button;
272 GtkWidget *summary_page;
273 GtkWidget *summary_label;
276 std::unique_ptr<GncTxImport> tx_imp;
278 bool m_req_mapped_accts;
288 void csv_tximp_assist_prepare_cb (GtkAssistant *assistant, GtkWidget *page,
CsvImpTransAssist* info);
289 void csv_tximp_assist_close_cb (GtkAssistant *gtkassistant,
CsvImpTransAssist* info);
290 void csv_tximp_assist_finish_cb (GtkAssistant *gtkassistant,
CsvImpTransAssist* info);
291 void csv_tximp_file_activated_cb (GtkFileChooser *chooser,
CsvImpTransAssist *info);
292 void csv_tximp_file_selection_changed_cb (GtkFileChooser *chooser,
CsvImpTransAssist *info);
293 void csv_tximp_preview_del_settings_cb (GtkWidget *button,
CsvImpTransAssist *info);
294 void csv_tximp_preview_save_settings_cb (GtkWidget *button,
CsvImpTransAssist *info);
295 void csv_tximp_preview_settings_sel_changed_cb (GtkComboBox *combo,
CsvImpTransAssist *info);
296 void csv_tximp_preview_settings_text_inserted_cb (GtkEditable *entry, gchar *new_text,
298 void csv_tximp_preview_settings_text_changed_cb (GtkEntry *entry,
CsvImpTransAssist *info);
301 void csv_tximp_preview_skiprows_cb (GtkToggleButton *checkbox,
CsvImpTransAssist *info);
302 void csv_tximp_preview_skiperrors_cb (GtkToggleButton *checkbox,
CsvImpTransAssist *info);
303 void csv_tximp_preview_multisplit_cb (GtkToggleButton *checkbox,
CsvImpTransAssist *info);
304 void csv_tximp_preview_sep_button_cb (GtkWidget* widget,
CsvImpTransAssist* info);
305 void csv_tximp_preview_sep_fixed_sel_cb (GtkToggleButton* csv_button,
CsvImpTransAssist* info);
307 void csv_tximp_preview_enc_sel_cb (GOCharmapSel* selector,
const char* encoding,
309 void csv_tximp_acct_match_button_clicked_cb (GtkWidget *widget,
CsvImpTransAssist* info);
310 bool csv_tximp_acct_match_view_clicked_cb (GtkWidget *widget, GdkEventButton *event,
CsvImpTransAssist* info);
314 csv_tximp_assist_prepare_cb (GtkAssistant *assistant, GtkWidget *page,
317 info->assist_prepare_cb(page);
323 gnc_close_gui_component_by_data (ASSISTANT_CSV_IMPORT_TRANS_CM_CLASS, info);
329 info->assist_finish ();
332 void csv_tximp_file_activated_cb (GtkFileChooser *chooser,
CsvImpTransAssist *info)
334 info->file_activated_cb();
337 void csv_tximp_file_selection_changed_cb (GtkFileChooser *chooser,
CsvImpTransAssist *info)
339 info->file_selection_changed_cb();
342 void csv_tximp_preview_del_settings_cb (GtkWidget *button,
CsvImpTransAssist *info)
344 info->preview_settings_delete();
347 void csv_tximp_preview_save_settings_cb (GtkWidget *button,
CsvImpTransAssist *info)
349 info->preview_settings_save();
352 void csv_tximp_preview_settings_sel_changed_cb (GtkComboBox *combo,
CsvImpTransAssist *info)
354 info->preview_settings_load();
358 csv_tximp_preview_settings_text_inserted_cb (GtkEditable *entry, gchar *new_text,
365 auto base_txt = std::string (new_text);
366 auto mod_txt = base_txt;
367 std::replace (mod_txt.begin(), mod_txt.end(),
'[',
'(');
368 std::replace (mod_txt.begin(), mod_txt.end(),
']',
')');
369 if (base_txt == mod_txt)
371 g_signal_handlers_block_by_func (entry, (gpointer) csv_tximp_preview_settings_text_inserted_cb, info);
372 gtk_editable_insert_text (entry, mod_txt.c_str(), mod_txt.size() , position);
373 g_signal_handlers_unblock_by_func (entry, (gpointer) csv_tximp_preview_settings_text_inserted_cb, info);
375 g_signal_stop_emission_by_name (entry,
"insert_text");
379 csv_tximp_preview_settings_text_changed_cb (GtkEntry *entry,
CsvImpTransAssist *info)
381 info->preview_settings_name(entry);
386 info->preview_update_skipped_rows();
391 info->preview_update_skipped_rows();
394 void csv_tximp_preview_skiprows_cb (GtkToggleButton *checkbox,
CsvImpTransAssist *info)
396 info->preview_update_skipped_rows();
399 void csv_tximp_preview_skiperrors_cb (GtkToggleButton *checkbox,
CsvImpTransAssist *info)
401 info->preview_update_skipped_rows();
404 void csv_tximp_preview_multisplit_cb (GtkToggleButton *checkbox,
CsvImpTransAssist *info)
406 info->preview_multi_split (gtk_toggle_button_get_active (checkbox));
409 void csv_tximp_preview_sep_button_cb (GtkWidget* widget,
CsvImpTransAssist* info)
411 info->preview_update_separators(widget);
414 void csv_tximp_preview_sep_fixed_sel_cb (GtkToggleButton* csv_button,
CsvImpTransAssist* info)
416 info->preview_update_file_format();
421 info->preview_update_account();
424 void csv_tximp_preview_enc_sel_cb (GOCharmapSel* selector,
const char* encoding,
427 info->preview_update_encoding(encoding);
430 static void csv_tximp_preview_date_fmt_sel_cb (GtkComboBox* format_selector,
CsvImpTransAssist* info)
432 info->preview_update_date_format();
435 static void csv_tximp_preview_currency_fmt_sel_cb (GtkComboBox* format_selector,
CsvImpTransAssist* info)
437 info->preview_update_currency_format();
440 static void csv_tximp_preview_col_type_changed_cb (GtkComboBox* cbox,
CsvImpTransAssist* info)
442 info->preview_update_col_type (cbox);
446 csv_tximp_preview_treeview_clicked_cb (GtkTreeView* treeview, GdkEventButton* event,
449 info->preview_update_fw_columns(treeview, event);
454 void csv_tximp_acct_match_button_clicked_cb (GtkWidget *widget,
CsvImpTransAssist* info)
456 info->acct_match_via_button();
459 bool csv_tximp_acct_match_view_clicked_cb (GtkWidget *widget, GdkEventButton *event,
CsvImpTransAssist* info)
461 return info->acct_match_via_view_dblclick(event);
468 CsvImpTransAssist::CsvImpTransAssist ()
470 auto builder = gtk_builder_new();
471 gnc_builder_add_from_file (builder ,
"assistant-csv-trans-import.glade",
"start_row_adj");
472 gnc_builder_add_from_file (builder ,
"assistant-csv-trans-import.glade",
"end_row_adj");
473 gnc_builder_add_from_file (builder ,
"assistant-csv-trans-import.glade",
"account_match_store");
474 gnc_builder_add_from_file (builder ,
"assistant-csv-trans-import.glade",
"csv_transaction_assistant");
475 csv_imp_asst = GTK_ASSISTANT(gtk_builder_get_object (builder,
"csv_transaction_assistant"));
478 gtk_widget_set_name (GTK_WIDGET(csv_imp_asst),
"gnc-id-assistant-csv-transaction-import");
479 gnc_widget_style_context_add_class (GTK_WIDGET(csv_imp_asst),
"gnc-class-imports");
482 gtk_assistant_set_page_complete (csv_imp_asst,
483 GTK_WIDGET(gtk_builder_get_object (builder,
"start_page")),
485 gtk_assistant_set_page_complete (csv_imp_asst,
486 GTK_WIDGET(gtk_builder_get_object (builder,
"file_page")),
488 gtk_assistant_set_page_complete (csv_imp_asst,
489 GTK_WIDGET(gtk_builder_get_object (builder,
"preview_page")),
491 gtk_assistant_set_page_complete (csv_imp_asst,
492 GTK_WIDGET(gtk_builder_get_object (builder,
"account_match_page")),
494 gtk_assistant_set_page_complete (csv_imp_asst,
495 GTK_WIDGET(gtk_builder_get_object (builder,
"doc_page")),
497 gtk_assistant_set_page_complete (csv_imp_asst,
498 GTK_WIDGET(gtk_builder_get_object (builder,
"match_page")),
500 gtk_assistant_set_page_complete (csv_imp_asst,
501 GTK_WIDGET(gtk_builder_get_object (builder,
"summary_page")),
505 file_page = GTK_WIDGET(gtk_builder_get_object (builder,
"file_page"));
506 file_chooser = gtk_file_chooser_widget_new (GTK_FILE_CHOOSER_ACTION_OPEN);
507 g_signal_connect (G_OBJECT(file_chooser),
"selection-changed",
508 G_CALLBACK(csv_tximp_file_selection_changed_cb),
this);
509 g_signal_connect (G_OBJECT(file_chooser),
"file-activated",
510 G_CALLBACK(csv_tximp_file_activated_cb),
this);
512 auto box = GTK_WIDGET(gtk_builder_get_object (builder,
"file_page"));
513 gtk_box_pack_start (GTK_BOX(box), file_chooser, TRUE, TRUE, 6);
514 gtk_widget_show (file_chooser);
518 preview_page = GTK_WIDGET(gtk_builder_get_object (builder,
"preview_page"));
521 auto settings_store = gtk_list_store_new (2, G_TYPE_POINTER, G_TYPE_STRING);
522 settings_combo = GTK_COMBO_BOX(gtk_combo_box_new_with_model_and_entry (GTK_TREE_MODEL(settings_store)));
523 g_object_unref (settings_store);
524 gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX(settings_combo), SET_NAME);
525 gtk_combo_box_set_active (GTK_COMBO_BOX(settings_combo), 0);
527 combo_hbox = GTK_WIDGET(gtk_builder_get_object (builder,
"combo_hbox"));
528 gtk_box_pack_start (GTK_BOX(combo_hbox), GTK_WIDGET(settings_combo),
true,
true, 6);
529 gtk_widget_show (GTK_WIDGET(settings_combo));
531 g_signal_connect (G_OBJECT(settings_combo),
"changed",
532 G_CALLBACK(csv_tximp_preview_settings_sel_changed_cb),
this);
535 auto emb_entry = gtk_bin_get_child (GTK_BIN (settings_combo));
536 g_signal_connect (G_OBJECT(emb_entry),
"changed",
537 G_CALLBACK(csv_tximp_preview_settings_text_changed_cb),
this);
538 g_signal_connect (G_OBJECT(emb_entry),
"insert-text",
539 G_CALLBACK(csv_tximp_preview_settings_text_inserted_cb),
this);
542 save_button = GTK_WIDGET(gtk_builder_get_object (builder,
"save_settings"));
545 del_button = GTK_WIDGET(gtk_builder_get_object (builder,
"delete_settings"));
548 start_row_spin = GTK_SPIN_BUTTON(gtk_builder_get_object (builder,
"start_row"));
549 end_row_spin = GTK_SPIN_BUTTON(gtk_builder_get_object (builder,
"end_row"));
550 skip_alt_rows_button = GTK_WIDGET(gtk_builder_get_object (builder,
"skip_rows"));
551 skip_errors_button = GTK_WIDGET(gtk_builder_get_object (builder,
"skip_errors_button"));
552 multi_split_cbutton = GTK_WIDGET(gtk_builder_get_object (builder,
"multi_split_button"));
553 separator_table = GTK_WIDGET(gtk_builder_get_object (builder,
"separator_table"));
554 fw_instructions_hbox = GTK_WIDGET(gtk_builder_get_object (builder,
"fw_instructions_hbox"));
558 const char* sep_button_names[] = {
566 for (
int i = 0; i < SEP_NUM_OF_TYPES; i++)
568 = (GtkCheckButton*)GTK_WIDGET(gtk_builder_get_object (builder, sep_button_names[i]));
573 = (GtkCheckButton*)GTK_WIDGET(gtk_builder_get_object (builder,
"custom_cbutton"));
577 custom_entry = (GtkEntry*)GTK_WIDGET(gtk_builder_get_object (builder,
"custom_entry"));
580 acct_selector = gnc_account_sel_new();
581 auto account_hbox = GTK_WIDGET(gtk_builder_get_object (builder,
"account_hbox"));
582 gtk_box_pack_start (GTK_BOX(account_hbox), acct_selector, TRUE, TRUE, 6);
583 gtk_widget_show (acct_selector);
585 g_signal_connect(G_OBJECT(acct_selector),
"account_sel_changed",
586 G_CALLBACK(csv_tximp_preview_acct_sel_cb),
this);
590 encselector = GO_CHARMAP_SEL(go_charmap_sel_new(GO_CHARMAP_SEL_TO_UTF8));
592 g_signal_connect (G_OBJECT(encselector),
"charmap_changed",
593 G_CALLBACK(csv_tximp_preview_enc_sel_cb),
this);
595 auto encoding_container = GTK_CONTAINER(gtk_builder_get_object (builder,
"encoding_container"));
596 gtk_container_add (encoding_container, GTK_WIDGET(encselector));
597 gtk_widget_set_hexpand (GTK_WIDGET(encselector),
true);
598 gtk_widget_show_all (GTK_WIDGET(encoding_container));
601 instructions_label = GTK_LABEL(gtk_builder_get_object (builder,
"instructions_label"));
602 instructions_image = GTK_IMAGE(gtk_builder_get_object (builder,
"instructions_image"));
605 date_format_combo = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new());
607 gtk_combo_box_text_append_text (date_format_combo, _(date_fmt.m_fmt.c_str()));
608 gtk_combo_box_set_active (GTK_COMBO_BOX(date_format_combo), 0);
609 g_signal_connect (G_OBJECT(date_format_combo),
"changed",
610 G_CALLBACK(csv_tximp_preview_date_fmt_sel_cb),
this);
613 auto date_format_container = GTK_CONTAINER(gtk_builder_get_object (builder,
"date_format_container"));
614 gtk_container_add (date_format_container, GTK_WIDGET(date_format_combo));
615 gtk_widget_set_hexpand (GTK_WIDGET(date_format_combo),
true);
616 gtk_widget_show_all (GTK_WIDGET(date_format_container));
619 currency_format_combo = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new());
620 for (
int i = 0; i < num_currency_formats; i++)
622 gtk_combo_box_text_append_text (currency_format_combo, _(currency_format_user[i]));
625 gtk_combo_box_set_active (GTK_COMBO_BOX(currency_format_combo), 0);
626 g_signal_connect (G_OBJECT(currency_format_combo),
"changed",
627 G_CALLBACK(csv_tximp_preview_currency_fmt_sel_cb),
this);
630 auto currency_format_container = GTK_CONTAINER(gtk_builder_get_object (builder,
"currency_format_container"));
631 gtk_container_add (currency_format_container, GTK_WIDGET(currency_format_combo));
632 gtk_widget_set_hexpand (GTK_WIDGET(currency_format_combo),
true);
633 gtk_widget_show_all (GTK_WIDGET(currency_format_container));
636 csv_button = GTK_WIDGET(gtk_builder_get_object (builder,
"csv_button"));
637 fixed_button = GTK_WIDGET(gtk_builder_get_object (builder,
"fixed_button"));
640 treeview = (GtkTreeView*)GTK_WIDGET(gtk_builder_get_object (builder,
"treeview"));
641 gtk_tree_view_set_headers_clickable (treeview,
true);
645 encoding_selected_called =
false;
649 account_match_page = GTK_WIDGET(gtk_builder_get_object (builder,
"account_match_page"));
650 account_match_view = GTK_WIDGET(gtk_builder_get_object (builder,
"account_match_view"));
651 account_match_label = GTK_WIDGET(gtk_builder_get_object (builder,
"account_match_label"));
652 account_match_btn = GTK_WIDGET(gtk_builder_get_object (builder,
"account_match_change"));
655 doc_page = GTK_WIDGET(gtk_builder_get_object (builder,
"doc_page"));
658 match_page = GTK_WIDGET(gtk_builder_get_object (builder,
"match_page"));
659 match_label = GTK_WIDGET(gtk_builder_get_object (builder,
"match_label"));
666 match_page,
nullptr,
false, 42);
669 summary_page = GTK_WIDGET(gtk_builder_get_object (builder,
"summary_page"));
670 summary_label = GTK_WIDGET(gtk_builder_get_object (builder,
"summary_label"));
672 gnc_restore_window_size (GNC_PREFS_GROUP,
675 gtk_builder_connect_signals (builder,
this);
676 g_object_unref (G_OBJECT(builder));
678 gtk_widget_show_all (GTK_WIDGET(csv_imp_asst));
679 gnc_window_adjust_for_screen (GTK_WINDOW(csv_imp_asst));
683 new_book = gnc_is_new_book();
690 CsvImpTransAssist::~CsvImpTransAssist ()
696 gnc_csv_importer_gui =
nullptr;
697 gtk_widget_destroy (GTK_WIDGET(csv_imp_asst));
708 CsvImpTransAssist::check_for_valid_filename ()
710 auto file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(file_chooser));
711 if (!file_name || g_file_test (file_name, G_FILE_TEST_IS_DIR))
718 auto starting_dir = g_path_get_dirname (filepath);
720 m_fc_file_name = file_name;
721 gnc_set_default_directory (GNC_PREFS_GROUP, starting_dir);
723 DEBUG(
"file_name selected is %s", m_fc_file_name.c_str());
724 DEBUG(
"starting directory is %s", starting_dir);
728 g_free (starting_dir);
738 CsvImpTransAssist::file_activated_cb ()
740 gtk_assistant_set_page_complete (csv_imp_asst, file_page,
false);
743 if (check_for_valid_filename ())
745 gtk_assistant_set_page_complete (csv_imp_asst, file_page,
true);
746 gtk_assistant_next_page (csv_imp_asst);
755 CsvImpTransAssist::file_selection_changed_cb ()
758 gtk_assistant_set_page_complete (csv_imp_asst, file_page,
759 check_for_valid_filename ());
769 void CsvImpTransAssist::preview_populate_settings_combo()
772 auto model = gtk_combo_box_get_model (settings_combo);
773 gtk_list_store_clear (GTK_LIST_STORE(model));
777 for (
auto preset : presets)
780 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
787 gtk_list_store_set (GTK_LIST_STORE(model), &iter, SET_GROUP, preset.get(), SET_NAME, _(preset->m_name.c_str()), -1);
794 void CsvImpTransAssist::preview_handle_save_del_sensitivity (GtkComboBox* combo)
797 auto can_delete =
false;
798 auto can_save =
false;
799 auto entry = gtk_bin_get_child (GTK_BIN(combo));
800 auto entry_text = gtk_entry_get_text (GTK_ENTRY(entry));
802 if (gtk_combo_box_get_active_iter (combo, &iter))
805 GtkTreeModel *model = gtk_combo_box_get_model (combo);
806 gtk_tree_model_get (model, &iter, SET_GROUP, &preset, -1);
815 else if (entry_text && (strlen (entry_text) > 0) &&
819 gtk_widget_set_sensitive (save_button, can_save);
820 gtk_widget_set_sensitive (del_button, can_delete);
825 CsvImpTransAssist::preview_settings_name (GtkEntry* entry)
827 auto text = gtk_entry_get_text (entry);
829 tx_imp->settings_name(text);
831 auto box = gtk_widget_get_parent (GTK_WIDGET(entry));
832 auto combo = gtk_widget_get_parent (GTK_WIDGET(box));
834 preview_handle_save_del_sensitivity (GTK_COMBO_BOX(combo));
842 CsvImpTransAssist::preview_settings_load ()
846 if (!gtk_combo_box_get_active_iter (settings_combo, &iter))
850 auto model = gtk_combo_box_get_model (settings_combo);
851 gtk_tree_model_get (model, &iter, SET_GROUP, &preset, -1);
856 tx_imp->settings (*preset);
857 if (preset->m_load_error)
858 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
859 "%s", _(
"There were problems reading some saved settings, continuing to load.\n" 860 "Please review and save again."));
863 preview_handle_save_del_sensitivity (settings_combo);
869 CsvImpTransAssist::preview_settings_delete ()
873 if (!gtk_combo_box_get_active_iter (settings_combo, &iter))
877 auto model = gtk_combo_box_get_model (settings_combo);
878 gtk_tree_model_get (model, &iter, SET_GROUP, &preset, -1);
880 auto response = gnc_ok_cancel_dialog (GTK_WINDOW (csv_imp_asst),
882 "%s", _(
"Delete the Import Settings."));
883 if (response == GTK_RESPONSE_OK)
886 preview_populate_settings_combo();
887 gtk_combo_box_set_active (settings_combo, 0);
895 CsvImpTransAssist::preview_settings_save ()
897 auto new_name = tx_imp->settings_name();
901 if (!gtk_combo_box_get_active_iter (settings_combo, &iter))
904 auto model = gtk_combo_box_get_model (settings_combo);
905 bool valid = gtk_tree_model_get_iter_first (model, &iter);
910 gtk_tree_model_get (model, &iter, SET_GROUP, &preset, -1);
912 if (preset && (preset->m_name == std::string(new_name)))
914 auto response = gnc_ok_cancel_dialog (GTK_WINDOW (csv_imp_asst),
916 "%s", _(
"Setting name already exists, overwrite?"));
917 if (response != GTK_RESPONSE_OK)
922 valid = gtk_tree_model_iter_next (model, &iter);
927 if (!tx_imp->save_settings())
929 gnc_info_dialog (GTK_WINDOW (csv_imp_asst),
930 "%s", _(
"The settings have been saved."));
933 preview_populate_settings_combo();
934 auto model = gtk_combo_box_get_model (settings_combo);
938 bool valid = gtk_tree_model_get_iter_first (model, &iter);
942 gchar *name =
nullptr;
943 gtk_tree_model_get (model, &iter, SET_NAME, &name, -1);
945 if (g_strcmp0 (name, new_name.c_str()) == 0)
946 gtk_combo_box_set_active_iter (settings_combo, &iter);
950 valid = gtk_tree_model_iter_next (model, &iter);
954 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
955 "%s", _(
"There was a problem saving the settings, please try again."));
960 void CsvImpTransAssist::preview_update_skipped_rows ()
963 tx_imp->update_skipped_lines (gtk_spin_button_get_value_as_int (start_row_spin),
964 gtk_spin_button_get_value_as_int (end_row_spin),
965 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(skip_alt_rows_button)),
966 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(skip_errors_button)));
969 auto adj = gtk_spin_button_get_adjustment (end_row_spin);
970 gtk_adjustment_set_upper (adj, tx_imp->m_parsed_lines.size()
971 - tx_imp->skip_start_lines() -1);
973 adj = gtk_spin_button_get_adjustment (start_row_spin);
974 gtk_adjustment_set_upper (adj, tx_imp->m_parsed_lines.size()
975 - tx_imp->skip_end_lines() - 1);
977 preview_refresh_table ();
980 void CsvImpTransAssist::preview_multi_split (
bool multi)
982 tx_imp->multi_split(multi);
998 if (tx_imp->file_format() != GncImpFileFormat::CSV)
1003 auto checked_separators = std::string();
1004 const auto stock_sep_chars = std::string (
" \t,:;-");
1005 for (
int i = 0; i < SEP_NUM_OF_TYPES; i++)
1007 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(sep_button[i])))
1008 checked_separators += stock_sep_chars[i];
1012 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(custom_cbutton)))
1014 auto custom_sep = gtk_entry_get_text (custom_entry);
1015 if (custom_sep[0] !=
'\0')
1016 checked_separators += custom_sep;
1020 tx_imp->separators (checked_separators);
1027 tx_imp->tokenize (
false);
1028 preview_refresh_table ();
1030 catch (std::range_error &e)
1035 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
"Error in parsing");
1041 if (widget == GTK_WIDGET(custom_entry))
1042 gtk_entry_set_text (GTK_ENTRY(widget),
"");
1045 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget),
1046 !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)));
1060 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(csv_button)))
1062 tx_imp->file_format (GncImpFileFormat::CSV);
1063 g_signal_handlers_disconnect_by_func(G_OBJECT(treeview),
1064 (gpointer)csv_tximp_preview_treeview_clicked_cb, (gpointer)
this);
1065 gtk_widget_set_visible (separator_table,
true);
1066 gtk_widget_set_visible (fw_instructions_hbox,
false);
1070 tx_imp->file_format (GncImpFileFormat::FIXED_WIDTH);
1072 g_signal_connect (G_OBJECT(treeview),
"button-press-event",
1073 G_CALLBACK(csv_tximp_preview_treeview_clicked_cb), (gpointer)
this);
1074 gtk_widget_set_visible (separator_table,
false);
1075 gtk_widget_set_visible (fw_instructions_hbox,
true);
1079 tx_imp->tokenize (
false);
1080 preview_refresh_table ();
1082 catch (std::range_error &e)
1085 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
"%s", e.what());
1091 PWARN(
"Got an error during file loading");
1096 void CsvImpTransAssist::preview_update_account ()
1098 auto acct = gnc_account_sel_get_account( GNC_ACCOUNT_SEL(acct_selector) );
1099 tx_imp->base_account(acct);
1100 preview_refresh_table ();
1117 if (encoding_selected_called)
1119 std::string previous_encoding = tx_imp->m_tokenizer->encoding();
1123 tx_imp->encoding (encoding);
1124 preview_refresh_table ();
1129 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
"%s", _(
"Invalid encoding selected"));
1130 go_charmap_sel_set_encoding (encselector, previous_encoding.c_str());
1134 encoding_selected_called = !encoding_selected_called;
1139 CsvImpTransAssist::preview_update_date_format ()
1141 tx_imp->date_format (gtk_combo_box_get_active (GTK_COMBO_BOX(date_format_combo)));
1142 preview_refresh_table ();
1147 CsvImpTransAssist::preview_update_currency_format ()
1149 tx_imp->currency_format (gtk_combo_box_get_active (GTK_COMBO_BOX(currency_format_combo)));
1150 preview_refresh_table ();
1156 assist->preview_refresh_table ();
1163 enum PreviewHeaderComboCols { COL_TYPE_NAME, COL_TYPE_ID };
1167 enum PreviewDataTableCols {
1173 PREV_N_FIXED_COLS };
1185 auto model = gtk_combo_box_get_model (cbox);
1186 gtk_combo_box_get_active_iter (cbox, &iter);
1187 auto new_col_type = GncTransPropType::NONE;
1188 gtk_tree_model_get (model, &iter, COL_TYPE_ID, &new_col_type, -1);
1190 auto col_num = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT(cbox),
"col-num"));
1191 tx_imp->set_column_type (col_num, new_col_type);
1196 g_idle_add ((GSourceFunc)csv_imp_preview_queue_rebuild_table,
this);
1229 CONTEXT_STF_IMPORT_MERGE_LEFT = 1,
1230 CONTEXT_STF_IMPORT_MERGE_RIGHT = 2,
1231 CONTEXT_STF_IMPORT_SPLIT = 3,
1232 CONTEXT_STF_IMPORT_WIDEN = 4,
1233 CONTEXT_STF_IMPORT_NARROW = 5
1239 N_(
"Merge with column on _left"),
"list-remove",
1240 0, 1 << CONTEXT_STF_IMPORT_MERGE_LEFT, CONTEXT_STF_IMPORT_MERGE_LEFT
1243 N_(
"Merge with column on _right"),
"list-remove",
1244 0, 1 << CONTEXT_STF_IMPORT_MERGE_RIGHT, CONTEXT_STF_IMPORT_MERGE_RIGHT
1246 {
"",
nullptr, 0, 0, 0 },
1248 N_(
"_Split this column"),
nullptr,
1249 0, 1 << CONTEXT_STF_IMPORT_SPLIT, CONTEXT_STF_IMPORT_SPLIT
1251 {
"",
nullptr, 0, 0, 0 },
1253 N_(
"_Widen this column"),
"go-next",
1254 0, 1 << CONTEXT_STF_IMPORT_WIDEN, CONTEXT_STF_IMPORT_WIDEN
1257 N_(
"_Narrow this column"),
"go-previous",
1258 0, 1 << CONTEXT_STF_IMPORT_NARROW, CONTEXT_STF_IMPORT_NARROW
1260 {
nullptr,
nullptr, 0, 0, 0 },
1263 uint32_t CsvImpTransAssist::get_new_col_rel_pos (GtkTreeViewColumn *tcol,
int dx)
1265 auto renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT(tcol));
1266 auto cell = GTK_CELL_RENDERER(renderers->data);
1267 g_list_free (renderers);
1268 PangoFontDescription *font_desc;
1269 g_object_get (G_OBJECT(cell),
"font_desc", &font_desc,
nullptr);
1271 PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET(treeview),
"x");
1272 pango_layout_set_font_description (layout, font_desc);
1274 pango_layout_get_pixel_size (layout, &width,
nullptr);
1275 if (width < 1) width = 1;
1276 uint32_t charindex = (dx + width / 2) / width;
1277 g_object_unref (layout);
1278 pango_font_description_free (font_desc);
1288 auto fwtok =
dynamic_cast<GncFwTokenizer*
>(info->tx_imp->m_tokenizer.get());
1290 switch (element->index)
1292 case CONTEXT_STF_IMPORT_MERGE_LEFT:
1293 fwtok->col_delete (info->fixed_context_col - 1);
1295 case CONTEXT_STF_IMPORT_MERGE_RIGHT:
1296 fwtok->col_delete (info->fixed_context_col);
1298 case CONTEXT_STF_IMPORT_SPLIT:
1299 fwtok->col_split (info->fixed_context_col, info->fixed_context_offset);
1301 case CONTEXT_STF_IMPORT_WIDEN:
1302 fwtok->col_widen (info->fixed_context_col);
1304 case CONTEXT_STF_IMPORT_NARROW:
1305 fwtok->col_narrow (info->fixed_context_col);
1313 info->tx_imp->tokenize (
false);
1315 catch(std::range_error& e)
1317 gnc_error_dialog (GTK_WINDOW (info->csv_imp_asst),
"%s", e.what());
1320 info->preview_refresh_table ();
1325 CsvImpTransAssist::fixed_context_menu (GdkEventButton *event,
1326 int col,
int offset)
1328 auto fwtok =
dynamic_cast<GncFwTokenizer*
>(tx_imp->m_tokenizer.get());
1329 fixed_context_col = col;
1330 fixed_context_offset = offset;
1332 int sensitivity_filter = 0;
1333 if (!fwtok->col_can_delete (col - 1))
1334 sensitivity_filter |= (1 << CONTEXT_STF_IMPORT_MERGE_LEFT);
1335 if (!fwtok->col_can_delete (col))
1336 sensitivity_filter |= (1 << CONTEXT_STF_IMPORT_MERGE_RIGHT);
1337 if (!fwtok->col_can_split (col, offset))
1338 sensitivity_filter |= (1 << CONTEXT_STF_IMPORT_SPLIT);
1339 if (!fwtok->col_can_widen (col))
1340 sensitivity_filter |= (1 << CONTEXT_STF_IMPORT_WIDEN);
1341 if (!fwtok->col_can_narrow (col))
1342 sensitivity_filter |= (1 << CONTEXT_STF_IMPORT_NARROW);
1344 gnumeric_create_popup_menu (popup_elements, &fixed_context_menu_handler,
1346 sensitivity_filter, event);
1352 CsvImpTransAssist::preview_split_column (
int col,
int offset)
1354 auto fwtok =
dynamic_cast<GncFwTokenizer*
>(tx_imp->m_tokenizer.get());
1355 fwtok->col_split (col, offset);
1358 tx_imp->tokenize (
false);
1360 catch (std::range_error& e)
1362 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
"%s", e.what());
1365 preview_refresh_table();
1378 if (event->window != gtk_tree_view_get_bin_window (treeview))
1382 GtkTreeViewColumn *tcol =
nullptr;
1384 auto success = gtk_tree_view_get_path_at_pos (treeview,
1385 (
int)event->x, (
int)event->y,
1386 nullptr, &tcol, &cell_x,
nullptr);
1392 auto tcol_list = gtk_tree_view_get_columns(treeview);
1393 auto tcol_num = g_list_index (tcol_list, tcol);
1394 g_list_free (tcol_list);
1401 auto dcol = tcol_num - 1;
1402 auto offset = get_new_col_rel_pos (tcol, cell_x);
1403 if (event->type == GDK_2BUTTON_PRESS && event->button == 1)
1405 preview_split_column (dcol, offset);
1406 else if (event->type == GDK_BUTTON_PRESS && event->button == 3)
1408 fixed_context_menu (event, dcol, offset);
1414 CsvImpTransAssist::preview_row_fill_state_cells (GtkListStore *store, GtkTreeIter *iter,
1415 ErrMap& err_msgs,
bool skip)
1418 auto err_msg = std::string();
1419 const char *icon_name =
nullptr;
1420 const char *fcolor =
nullptr;
1421 const char *bcolor =
nullptr;
1424 auto non_acct_error = [](ErrPair curr_err)
1426 return !((curr_err.first == GncTransPropType::ACCOUNT) ||
1427 (curr_err.first == GncTransPropType::TACCOUNT));
1429 if (!skip && std::any_of(err_msgs.cbegin(), err_msgs.cend(), non_acct_error))
1433 err_msg = std::string(_(
"This line has the following parse issues:"));
1434 auto add_non_acct_err_bullet = [](std::string& a, ErrMap::value_type& b)->std::string
1436 if ((b.first == GncTransPropType::ACCOUNT) ||
1437 (b.first == GncTransPropType::TACCOUNT))
1438 return std::move(a);
1440 return std::move(a) +
"\n• " + b.second;
1443 err_msg = std::accumulate (err_msgs.begin(), err_msgs.end(),
1444 std::move (err_msg), add_non_acct_err_bullet);
1445 icon_name =
"dialog-error";
1447 gtk_list_store_set (store, iter,
1448 PREV_COL_FCOLOR, fcolor,
1449 PREV_COL_BCOLOR, bcolor,
1450 PREV_COL_STRIKE, skip,
1451 PREV_COL_ERROR, err_msg.c_str(),
1452 PREV_COL_ERR_ICON, icon_name, -1);
1459 CsvImpTransAssist::preview_cbox_factory (GtkTreeModel* model, uint32_t colnum)
1462 auto cbox = gtk_combo_box_new_with_model(model);
1465 auto renderer = gtk_cell_renderer_text_new();
1466 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(cbox),
1468 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT(cbox),
1469 renderer,
"text", COL_TYPE_NAME);
1471 auto valid = gtk_tree_model_get_iter_first (model, &iter);
1474 gint stored_col_type;
1475 gtk_tree_model_get (model, &iter,
1476 COL_TYPE_ID, &stored_col_type, -1);
1477 if (stored_col_type == static_cast<int>( tx_imp->column_types()[colnum]))
1479 valid = gtk_tree_model_iter_next(model, &iter);
1482 gtk_combo_box_set_active_iter (GTK_COMBO_BOX(cbox), &iter);
1484 g_object_set_data (G_OBJECT(cbox),
"col-num", GUINT_TO_POINTER(colnum));
1485 g_signal_connect (G_OBJECT(cbox),
"changed",
1486 G_CALLBACK(csv_tximp_preview_col_type_changed_cb), (gpointer)
this);
1488 gtk_widget_show (cbox);
1493 CsvImpTransAssist::preview_style_column (uint32_t col_num, GtkTreeModel* model)
1495 auto col = gtk_tree_view_get_column (treeview, col_num);
1496 auto renderer =
static_cast<GtkCellRenderer*
>(gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(col))->data);
1500 gtk_tree_view_column_set_attributes (col, renderer,
1501 "icon-name", PREV_COL_ERR_ICON,
1502 "cell-background", PREV_COL_BCOLOR,
nullptr);
1503 g_object_set (G_OBJECT(renderer),
"stock-size", GTK_ICON_SIZE_MENU,
nullptr);
1504 g_object_set (G_OBJECT(col),
"sizing", GTK_TREE_VIEW_COLUMN_FIXED,
1505 "fixed-width", 20,
nullptr);
1506 gtk_tree_view_column_set_resizable (col,
false);
1510 gtk_tree_view_column_set_attributes (col, renderer,
1511 "foreground", PREV_COL_FCOLOR,
1512 "background", PREV_COL_BCOLOR,
1513 "strikethrough", PREV_COL_STRIKE,
1514 "text", col_num + PREV_N_FIXED_COLS -1,
nullptr);
1517 g_object_set (G_OBJECT(renderer),
"family",
"monospace",
nullptr);
1522 auto cbox = preview_cbox_factory (GTK_TREE_MODEL(model), col_num - 1);
1523 gtk_tree_view_column_set_widget (col, cbox);
1526 gtk_tree_view_column_set_resizable (col,
true);
1527 gtk_tree_view_column_set_clickable (col,
true);
1534 static GtkTreeModel*
1535 make_column_header_model (
bool multi_split)
1537 auto combostore = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
1538 for (
auto col_type : gnc_csv_col_type_strs)
1543 if (sanitize_trans_prop(col_type.first, multi_split) == col_type.first)
1546 gtk_list_store_append (combostore, &iter);
1547 gtk_list_store_set (combostore, &iter,
1548 COL_TYPE_NAME, _(col_type.second),
1549 COL_TYPE_ID, static_cast<int>(col_type.first), -1);
1552 return GTK_TREE_MODEL(combostore);
1558 void CsvImpTransAssist::preview_refresh_table ()
1560 preview_validate_settings ();
1565 auto ncols = PREV_N_FIXED_COLS + tx_imp->column_types().size();
1566 auto model_col_types = g_new (GType, ncols);
1567 model_col_types[PREV_COL_FCOLOR] = G_TYPE_STRING;
1568 model_col_types[PREV_COL_BCOLOR] = G_TYPE_STRING;
1569 model_col_types[PREV_COL_ERROR] = G_TYPE_STRING;
1570 model_col_types[PREV_COL_ERR_ICON] = G_TYPE_STRING;
1571 model_col_types[PREV_COL_STRIKE] = G_TYPE_BOOLEAN;
1572 for (guint i = PREV_N_FIXED_COLS; i < ncols; i++)
1573 model_col_types[i] = G_TYPE_STRING;
1574 auto store = gtk_list_store_newv (ncols, model_col_types);
1575 g_free (model_col_types);
1578 for (
auto parse_line : tx_imp->m_parsed_lines)
1582 gtk_list_store_append (store, &iter);
1583 preview_row_fill_state_cells (store, &iter,
1584 std::get<PL_ERROR>(parse_line), std::get<PL_SKIP>(parse_line));
1587 for (
auto cell_str_it = std::get<PL_INPUT>(parse_line).cbegin(); cell_str_it != std::get<PL_INPUT>(parse_line).cend(); cell_str_it++)
1589 uint32_t pos = PREV_N_FIXED_COLS + cell_str_it - std::get<PL_INPUT>(parse_line).cbegin();
1590 gtk_list_store_set (store, &iter, pos, cell_str_it->c_str(), -1);
1593 gtk_tree_view_set_model (treeview, GTK_TREE_MODEL(store));
1594 gtk_tree_view_set_tooltip_column (treeview, PREV_COL_ERROR);
1603 auto ntcols = gtk_tree_view_get_n_columns (treeview);
1609 while (ntcols > ncols - PREV_N_FIXED_COLS + 1)
1611 auto col = gtk_tree_view_get_column (treeview, ntcols - 1);
1612 gtk_tree_view_column_clear (col);
1613 ntcols = gtk_tree_view_remove_column(treeview, col);
1617 while (ntcols < ncols - PREV_N_FIXED_COLS + 1)
1620 auto renderer = gtk_cell_renderer_text_new();
1622 renderer = gtk_cell_renderer_pixbuf_new();
1623 auto col = gtk_tree_view_column_new ();
1624 gtk_tree_view_column_pack_start (col, renderer,
false);
1625 ntcols = gtk_tree_view_append_column (treeview, col);
1629 auto combostore = make_column_header_model (tx_imp->multi_split());
1630 for (uint32_t i = 0; i < ntcols; i++)
1631 preview_style_column (i, combostore);
1634 g_object_unref (store);
1635 g_object_unref (combostore);
1638 auto base_acct = gnc_account_sel_get_account(GNC_ACCOUNT_SEL(acct_selector));
1639 if (tx_imp->base_account() != base_acct)
1641 g_signal_handlers_block_by_func (acct_selector, (gpointer) csv_tximp_preview_acct_sel_cb,
this);
1642 gnc_account_sel_set_account(GNC_ACCOUNT_SEL(acct_selector),
1643 tx_imp->base_account() ,
false);
1644 g_signal_handlers_unblock_by_func (acct_selector, (gpointer) csv_tximp_preview_acct_sel_cb,
this);
1648 gtk_widget_show_all (GTK_WIDGET(treeview));
1655 CsvImpTransAssist::preview_refresh ()
1664 auto skip_start_lines = tx_imp->skip_start_lines();
1665 auto skip_end_lines = tx_imp->skip_end_lines();
1666 auto skip_alt_lines = tx_imp->skip_alt_lines();
1669 auto adj = gtk_spin_button_get_adjustment (start_row_spin);
1670 gtk_adjustment_set_upper (adj, tx_imp->m_parsed_lines.size());
1671 gtk_spin_button_set_value (start_row_spin, skip_start_lines);
1674 adj = gtk_spin_button_get_adjustment (end_row_spin);
1675 gtk_adjustment_set_upper (adj, tx_imp->m_parsed_lines.size());
1676 gtk_spin_button_set_value (end_row_spin, skip_end_lines);
1679 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(skip_alt_rows_button),
1683 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(multi_split_cbutton),
1684 tx_imp->multi_split());
1685 gtk_widget_set_sensitive (acct_selector, !tx_imp->multi_split());
1688 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(csv_button),
1689 (tx_imp->file_format() == GncImpFileFormat::CSV));
1690 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(fixed_button),
1691 (tx_imp->file_format() != GncImpFileFormat::CSV));
1694 gtk_combo_box_set_active (GTK_COMBO_BOX(date_format_combo),
1695 tx_imp->date_format());
1696 gtk_combo_box_set_active (GTK_COMBO_BOX(currency_format_combo),
1697 tx_imp->currency_format());
1698 go_charmap_sel_set_encoding (encselector, tx_imp->encoding().c_str());
1704 if (tx_imp->file_format() == GncImpFileFormat::CSV)
1706 auto separators = tx_imp->separators();
1707 const auto stock_sep_chars = std::string (
" \t,:;-");
1708 for (
int i = 0; i < SEP_NUM_OF_TYPES; i++)
1710 g_signal_handlers_block_by_func (sep_button[i], (gpointer) csv_tximp_preview_sep_button_cb,
this);
1711 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(sep_button[i]),
1712 separators.find (stock_sep_chars[i]) != std::string::npos);
1713 g_signal_handlers_unblock_by_func (sep_button[i], (gpointer) csv_tximp_preview_sep_button_cb,
this);
1718 auto pos = separators.find_first_of (stock_sep_chars);
1719 while (!separators.empty() && pos != std::string::npos)
1721 separators.erase(pos);
1722 pos = separators.find_first_of (stock_sep_chars);
1724 g_signal_handlers_block_by_func (custom_cbutton, (gpointer) csv_tximp_preview_sep_button_cb,
this);
1725 g_signal_handlers_block_by_func (custom_entry, (gpointer) csv_tximp_preview_sep_button_cb,
this);
1726 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(custom_cbutton),
1727 !separators.empty());
1728 gtk_entry_set_text (GTK_ENTRY(custom_entry), separators.c_str());
1729 g_signal_handlers_unblock_by_func (custom_cbutton, (gpointer) csv_tximp_preview_sep_button_cb,
this);
1730 g_signal_handlers_unblock_by_func (custom_entry, (gpointer) csv_tximp_preview_sep_button_cb,
this);
1733 tx_imp->tokenize (
false);
1735 catch(std::range_error& err)
1737 PERR(
"CSV Tokenization Failed: %s", err.what());
1742 preview_refresh_table ();
1747 void CsvImpTransAssist::preview_validate_settings ()
1750 auto has_non_acct_errors = !tx_imp->verify (
false).empty();
1751 auto error_msg = tx_imp->verify (m_req_mapped_accts);
1752 gtk_assistant_set_page_complete (csv_imp_asst, preview_page, !has_non_acct_errors);
1753 gtk_label_set_markup(GTK_LABEL(instructions_label), error_msg.c_str());
1754 gtk_widget_set_visible (GTK_WIDGET(instructions_image), !error_msg.empty());
1760 if (!has_non_acct_errors)
1761 gtk_widget_set_visible (GTK_WIDGET(account_match_page),
1762 !tx_imp->accounts().empty());
1773 void CsvImpTransAssist::acct_match_set_accounts ()
1775 auto store = gtk_tree_view_get_model (GTK_TREE_VIEW(account_match_view));
1776 gtk_list_store_clear (GTK_LIST_STORE(store));
1778 auto accts = tx_imp->accounts();
1779 for (
auto acct : accts)
1781 GtkTreeIter acct_iter;
1782 gtk_list_store_append (GTK_LIST_STORE(store), &acct_iter);
1783 gtk_list_store_set (GTK_LIST_STORE(store), &acct_iter, MAPPING_STRING, acct.c_str(),
1784 MAPPING_FULLPATH, _(
"No Linked Account"), MAPPING_ACCOUNT,
nullptr, -1);
1789 csv_tximp_acct_match_load_mappings (GtkTreeModel *mappings_store)
1793 auto valid = gtk_tree_model_get_iter_first (mappings_store, &iter);
1801 gtk_tree_model_get (GTK_TREE_MODEL(mappings_store), &iter, MAPPING_STRING, &map_string, MAPPING_ACCOUNT, &account, -1);
1808 (account = gnc_account_imap_find_any (gnc_get_current_book(), IMAP_CAT_CSV, map_string)) ||
1812 gtk_list_store_set (GTK_LIST_STORE(mappings_store), &iter, MAPPING_FULLPATH, fullpath, -1);
1813 gtk_list_store_set (GTK_LIST_STORE(mappings_store), &iter, MAPPING_ACCOUNT, account, -1);
1817 g_free (map_string);
1818 valid = gtk_tree_model_iter_next (mappings_store, &iter);
1823 csv_tximp_acct_match_check_all (GtkTreeModel *model)
1827 auto valid = gtk_tree_model_get_iter_first (model, &iter);
1833 gtk_tree_model_get (model, &iter, MAPPING_ACCOUNT, &account, -1);
1837 valid = gtk_tree_model_iter_next (model, &iter);
1850 csv_tximp_acct_match_text_parse (std::string acct_name)
1853 auto sep_pos = acct_name.rfind(sep);
1854 if (sep_pos == std::string::npos)
1858 auto parent = acct_name.substr(0, sep_pos);
1859 auto root = gnc_get_current_root_account ();
1869 const gchar *alt_sep;
1870 if (g_strcmp0 (sep,
":") == 0)
1874 for (sep_pos = acct_name.find(sep); sep_pos != std::string::npos;
1875 sep_pos = acct_name.find(sep))
1876 acct_name.replace (sep_pos, strlen(sep), alt_sep);
1882 CsvImpTransAssist::acct_match_select(GtkTreeModel *model, GtkTreeIter* iter)
1885 gchar *text =
nullptr;
1887 gtk_tree_model_get (model, iter, MAPPING_STRING, &text,
1888 MAPPING_ACCOUNT, &account, -1);
1890 auto acct_name = csv_tximp_acct_match_text_parse (text);
1897 gtk_list_store_set (GTK_LIST_STORE(model), iter,
1898 MAPPING_ACCOUNT, gnc_acc,
1899 MAPPING_FULLPATH, fullpath, -1);
1904 gnc_account_imap_delete_account (account, IMAP_CAT_CSV, text);
1905 gnc_account_imap_add_account (gnc_acc, IMAP_CAT_CSV, text, gnc_acc);
1909 auto col_types = tx_imp->column_types();
1910 auto col_type_it = std::find (col_types.cbegin(),
1911 col_types.cend(), GncTransPropType::ACCOUNT);
1912 if (col_type_it != col_types.cend())
1913 tx_imp->set_column_type(col_type_it - col_types.cbegin(),
1914 GncTransPropType::ACCOUNT,
true);
1915 col_type_it = std::find (col_types.cbegin(),
1916 col_types.cend(), GncTransPropType::TACCOUNT);
1917 if (col_type_it != col_types.cend())
1918 tx_imp->set_column_type(col_type_it - col_types.cbegin(),
1919 GncTransPropType::TACCOUNT,
true);
1927 auto all_checked = csv_tximp_acct_match_check_all (model);
1928 gtk_assistant_set_page_complete (csv_imp_asst, account_match_page,
1932 m_req_mapped_accts = all_checked;
1933 auto errs = tx_imp->verify(m_req_mapped_accts);
1934 gtk_label_set_text (GTK_LABEL(account_match_label), errs.c_str());
1938 CsvImpTransAssist::acct_match_via_button ()
1940 auto model = gtk_tree_view_get_model (GTK_TREE_VIEW(account_match_view));
1941 auto selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(account_match_view));
1944 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1945 acct_match_select (model, &iter);
1951 CsvImpTransAssist::acct_match_via_view_dblclick (GdkEventButton *event)
1954 if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1956 auto window = gtk_tree_view_get_bin_window (GTK_TREE_VIEW (account_match_view));
1957 if (event->window != window)
1962 if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (account_match_view), (gint) event->x, (gint) event->y,
1963 &path,
nullptr,
nullptr,
nullptr))
1965 DEBUG(
"event->x is %d and event->y is %d", (gint)event->x, (gint)event->y);
1967 auto model = gtk_tree_view_get_model (GTK_TREE_VIEW(account_match_view));
1969 if (gtk_tree_model_get_iter (model, &iter, path))
1970 acct_match_select (model, &iter);
1971 gtk_tree_path_free (path);
1984 CsvImpTransAssist::assist_file_page_prepare ()
1987 if (!m_final_file_name.empty())
1988 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER(file_chooser),
1989 m_final_file_name.c_str());
1992 auto starting_dir = gnc_get_default_directory (GNC_PREFS_GROUP);
1995 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(file_chooser), starting_dir);
1996 g_free (starting_dir);
2001 gtk_assistant_set_page_complete (csv_imp_asst, account_match_page,
false);
2006 CsvImpTransAssist::assist_preview_page_prepare ()
2008 auto go_back =
false;
2010 if (m_final_file_name != m_fc_file_name)
2012 tx_imp = std::unique_ptr<GncTxImport>(
new GncTxImport);
2017 tx_imp->file_format (GncImpFileFormat::CSV);
2018 tx_imp->load_file (m_fc_file_name);
2019 tx_imp->tokenize (
true);
2020 m_req_mapped_accts =
false;
2023 preview_populate_settings_combo();
2024 gtk_combo_box_set_active (settings_combo, 0);
2027 gtk_assistant_set_page_complete (csv_imp_asst, preview_page,
false);
2029 catch (std::ifstream::failure& e)
2032 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
"%s", e.what());
2035 catch (std::range_error &e)
2038 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
"%s", _(e.what()));
2044 gtk_assistant_previous_page (csv_imp_asst);
2047 m_final_file_name = m_fc_file_name;
2051 g_idle_add ((GSourceFunc)csv_imp_preview_queue_rebuild_table,
this);
2055 CsvImpTransAssist::assist_account_match_page_prepare ()
2059 acct_match_set_accounts ();
2062 auto store = gtk_tree_view_get_model (GTK_TREE_VIEW(account_match_view));
2063 csv_tximp_acct_match_load_mappings (store);
2066 gtk_widget_set_sensitive (account_match_view,
true);
2067 gtk_widget_set_sensitive (account_match_btn,
true);
2070 auto all_checked = csv_tximp_acct_match_check_all (store);
2071 gtk_assistant_set_page_complete (csv_imp_asst, account_match_page,
2075 m_req_mapped_accts = all_checked;
2076 auto text = tx_imp->verify (m_req_mapped_accts);
2077 gtk_label_set_text (GTK_LABEL(account_match_label), text.c_str());
2082 CsvImpTransAssist::assist_doc_page_prepare ()
2084 if (!tx_imp->verify (
true).empty())
2090 gtk_assistant_set_current_page (csv_imp_asst, 2);
2094 gtk_assistant_commit (csv_imp_asst);
2099 new_book = gnc_new_book_option_display (GTK_WIDGET(csv_imp_asst));
2102 cancel_button = gtk_button_new_with_mnemonic (_(
"_Cancel"));
2103 gtk_assistant_add_action_widget (csv_imp_asst, cancel_button);
2104 auto button_area = gtk_widget_get_parent (cancel_button);
2106 if (GTK_IS_HEADER_BAR(button_area))
2107 gtk_container_child_set (GTK_CONTAINER(button_area),
2109 "pack-type", GTK_PACK_START,
2112 g_signal_connect (cancel_button,
"clicked",
2113 G_CALLBACK(csv_tximp_assist_close_cb),
this);
2114 gtk_widget_show (GTK_WIDGET(cancel_button));
2119 CsvImpTransAssist::assist_match_page_prepare ()
2124 tx_imp->create_transactions ();
2131 auto err_msg = std::string(err.what());
2132 auto err_msgs = err.errors();
2133 auto add_bullet_item = [](std::string& a, ErrMap::value_type& b)->std::string {
return std::move(a) +
"\n• " + b.second; };
2134 err_msg = std::accumulate (err_msgs.begin(), err_msgs.end(), std::move (err_msg), add_bullet_item);
2136 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
2137 _(
"An unexpected error has occurred while creating transactions. Please report this as a bug.\n\n" 2138 "Error message:\n%s"), err_msg.c_str());
2139 gtk_assistant_set_current_page (csv_imp_asst, 2);
2143 gtk_assistant_commit (csv_imp_asst);
2145 auto text = std::string(
"<span size=\"medium\" color=\"red\"><b>");
2146 text += _(
"Double click on rows to change, then click on Apply to Import");
2147 text +=
"</b></span>";
2148 gtk_label_set_markup (GTK_LABEL(match_label), text.c_str());
2151 help_button = gtk_button_new_with_mnemonic (_(
"_Help"));
2152 gtk_assistant_add_action_widget (csv_imp_asst, help_button);
2153 auto button_area = gtk_widget_get_parent (help_button);
2155 if (GTK_IS_HEADER_BAR(button_area))
2157 gtk_container_child_set (GTK_CONTAINER(button_area),
2159 "pack-type", GTK_PACK_START,
2165 gtk_widget_set_halign (GTK_WIDGET(button_area), GTK_ALIGN_FILL);
2166 gtk_widget_set_hexpand (GTK_WIDGET(button_area), TRUE);
2167 gtk_box_set_child_packing (GTK_BOX(button_area), help_button,
2168 FALSE, FALSE, 0, GTK_PACK_START);
2170 g_signal_connect (help_button,
"clicked",
2173 gtk_widget_show (GTK_WIDGET(help_button));
2176 for (
auto trans_it : tx_imp->m_transactions)
2178 auto draft_trans = trans_it.second;
2179 if (draft_trans->trans)
2182 draft_trans->m_price ?
static_cast<gnc_numeric
>(*draft_trans->m_price) : gnc_numeric{0, 0},
2183 draft_trans->m_taction ? draft_trans->m_taction->c_str() :
nullptr,
2184 draft_trans->m_tmemo ? draft_trans->m_tmemo->c_str() :
nullptr,
2185 draft_trans->m_tamount ?
static_cast<gnc_numeric
>(*draft_trans->m_tamount) : gnc_numeric{0, 0},
2186 draft_trans->m_taccount ? *draft_trans->m_taccount :
nullptr,
2187 draft_trans->m_trec_state ? *draft_trans->m_trec_state :
'\0',
2188 draft_trans->m_trec_date ?
static_cast<time64>(
GncDateTime(*draft_trans->m_trec_date, DayPart::neutral)) : 0,
2197 draft_trans->trans =
nullptr;
2206 CsvImpTransAssist::assist_summary_page_prepare ()
2209 gtk_assistant_remove_action_widget (csv_imp_asst, help_button);
2210 gtk_assistant_remove_action_widget (csv_imp_asst, cancel_button);
2212 auto text = std::string(
"<span size=\"medium\"><b>");
2216 text += (bl::format (std::string{_(
"The transactions were imported from file '{1}'.")}) % m_final_file_name).str();
2217 text +=
"</b></span>";
2219 catch (
const bl::conv::conversion_error& err)
2221 PERR(
"Transcoding error: %s", err.what());
2222 text +=
"The transactions were imported from the file.</b></span>";
2224 catch (
const bl::conv::invalid_charset_error& err)
2226 PERR(
"Invalid charset error: %s", err.what());
2227 text +=
"The transactions were imported from the file.</b></span>";
2229 gtk_label_set_markup (GTK_LABEL(summary_label), text.c_str());
2234 CsvImpTransAssist::assist_prepare_cb (GtkWidget *page)
2236 if (page == file_page)
2237 assist_file_page_prepare ();
2238 else if (page == preview_page)
2239 assist_preview_page_prepare ();
2240 else if (page == account_match_page)
2241 assist_account_match_page_prepare ();
2242 else if (page == doc_page)
2243 assist_doc_page_prepare ();
2244 else if (page == match_page)
2245 assist_match_page_prepare ();
2246 else if (page == summary_page)
2247 assist_summary_page_prepare ();
2252 CsvImpTransAssist::assist_finish ()
2255 if (!tx_imp->m_transactions.empty())
2263 auto local_csv_imp_gui = gnc_csv_importer_gui;
2264 gnc_csv_importer_gui =
nullptr;
2271 CsvImpTransAssist::assist_compmgr_close ()
2273 gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(csv_imp_asst));
2278 csv_tximp_close_handler (gpointer user_data)
2281 gnc_unregister_gui_component_by_data (ASSISTANT_CSV_IMPORT_TRANS_CM_CLASS, info);
2282 info->assist_compmgr_close();
2297 gnc_register_gui_component (ASSISTANT_CSV_IMPORT_TRANS_CM_CLASS,
2298 nullptr, csv_tximp_close_handler,
Functions to load, save and get gui state.
void gnc_file_csv_trans_import(void)
The gnc_file_csv_trans_import() will let the user import the account tree or transactions to a delimi...
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction's split list.
void gnc_gen_trans_list_show_all(GNCImportMainMatcher *info)
Shows widgets.
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
Class to convert a csv file into vector of string vectors.
#define DEBUG(format, args...)
Print a debugging message.
Exception that will be thrown whenever a parsing error is encountered.
Generic importer backend interface.
void remove(void)
Remove the preset from the state file.
void on_matcher_help_clicked(GtkButton *button, gpointer user_data)
This allows for the transaction help dialog to be started from the assistant button callback...
Transaction matcher main window.
void preview_update_separators(GtkWidget *widget)
Event handler for separator changes.
gchar * gnc_uri_get_path(const gchar *uri)
Extracts the path part from a uri.
Account * gnc_import_select_account(GtkWidget *parent, const gchar *account_online_id_value, gboolean prompt_on_no_match, const gchar *account_human_description, const gnc_commodity *new_account_default_commodity, GNCAccountType new_account_default_type, Account *default_selection, gboolean *ok_pressed)
Must be called with a string containing a unique identifier for the account.
Class to import transactions from CSV or fixed width files.
Generic and very flexible account matcher/picker.
GNCImportMainMatcher * gnc_gen_trans_assist_new(GtkWidget *parent, GtkWidget *assistant_page, const gchar *heading, bool all_from_same_account, gint match_date_hardlimit)
Add the Transaction matcher to an existing page of an assistant.
#define PERR(format, args...)
Log a serious error.
void preview_update_encoding(const char *encoding)
Event handler for a new encoding.
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
#define PWARN(format, args...)
Log a warning.
void gnc_gen_trans_list_add_trans_with_split_data(GNCImportMainMatcher *gui, Transaction *trans, GNCImportLastSplitInfo *lsplit)
Add a newly imported Transaction to the Transaction Importer.
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
bool preset_is_reserved_name(const std::string &name)
Check whether name can be used as a preset name.
void gnc_gen_trans_assist_start(GNCImportMainMatcher *info)
This starts the import process for transaction from an assistant.
Account * gnc_account_lookup_by_full_name(const Account *any_acc, const gchar *name)
The gnc_account_lookup_full_name() subroutine works like gnc_account_lookup_by_name, but uses fully-qualified names using the given separator.
The actual TxImport class It's intended to use in the following sequence of actions: ...
Class convert a file with fixed with delimited contents into vector of string vectors.
void preview_update_fw_columns(GtkTreeView *treeview, GdkEventButton *event)
Event handler for clicking on column headers.
void preview_update_col_type(GtkComboBox *cbox)
Event handler for the user selecting a new column type.
const preset_vec_trans & get_import_presets_trans(void)
Creates a vector of CsvTransImpSettings which combines.
void gnc_gen_trans_list_delete(GNCImportMainMatcher *info)
Deletes the given object.
Utility functions for convert uri in separate components and back.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
static const std::vector< GncDateFormat > c_formats
A vector with all the date formats supported by the string constructor.
const gchar * gnc_get_account_separator_string(void)
Returns the account separation character chosen by the user.
void preview_update_file_format()
Event handler for clicking one of the format type radio buttons.