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>
77namespace 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"
84static QofLogModule log_module = GNC_MOD_ASSISTANT;
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 GtkCheckButton *escape_cbutton;
246 GtkWidget *fw_instructions_hbox;
247 GtkCheckButton *custom_cbutton;
248 GtkEntry *custom_entry;
249 GtkComboBoxText *date_format_combo;
250 GtkComboBoxText *currency_format_combo;
251 GtkTreeView *treeview;
252 GtkLabel *instructions_label;
253 GtkImage *instructions_image;
254 bool encoding_selected_called;
256 int fixed_context_col;
257 int fixed_context_offset;
260 GtkWidget *account_match_page;
261 GtkWidget *account_match_view;
262 GtkWidget *account_match_label;
263 GtkWidget *account_match_btn;
267 GtkWidget *match_page;
268 GtkWidget *match_label;
269 GNCImportMainMatcher *gnc_csv_importer_gui;
270 GtkWidget *help_button;
271 GtkWidget *cancel_button;
273 GtkWidget *summary_page;
274 GtkWidget *summary_label;
277 std::unique_ptr<GncTxImport> tx_imp;
279 bool m_req_mapped_accts;
289void csv_tximp_assist_prepare_cb (GtkAssistant *assistant, GtkWidget *page,
CsvImpTransAssist* info);
290void csv_tximp_assist_close_cb (GtkAssistant *gtkassistant,
CsvImpTransAssist* info);
291void csv_tximp_assist_finish_cb (GtkAssistant *gtkassistant,
CsvImpTransAssist* info);
292void csv_tximp_file_activated_cb (GtkFileChooser *chooser,
CsvImpTransAssist *info);
293void csv_tximp_file_selection_changed_cb (GtkFileChooser *chooser,
CsvImpTransAssist *info);
294void csv_tximp_preview_del_settings_cb (GtkWidget *button,
CsvImpTransAssist *info);
295void csv_tximp_preview_save_settings_cb (GtkWidget *button,
CsvImpTransAssist *info);
296void csv_tximp_preview_settings_sel_changed_cb (GtkComboBox *combo,
CsvImpTransAssist *info);
297void csv_tximp_preview_settings_text_inserted_cb (GtkEditable *entry, gchar *new_text,
299void csv_tximp_preview_settings_text_changed_cb (GtkEntry *entry,
CsvImpTransAssist *info);
302void csv_tximp_preview_skiprows_cb (GtkToggleButton *checkbox,
CsvImpTransAssist *info);
303void csv_tximp_preview_skiperrors_cb (GtkToggleButton *checkbox,
CsvImpTransAssist *info);
304void csv_tximp_preview_multisplit_cb (GtkToggleButton *checkbox,
CsvImpTransAssist *info);
305void csv_tximp_preview_sep_button_cb (GtkWidget* widget,
CsvImpTransAssist* info);
306void csv_tximp_preview_sep_fixed_sel_cb (GtkToggleButton* csv_button,
CsvImpTransAssist* info);
308void csv_tximp_preview_enc_sel_cb (GOCharmapSel* selector,
const char* encoding,
310void csv_tximp_acct_match_button_clicked_cb (GtkWidget *widget,
CsvImpTransAssist* info);
311bool csv_tximp_acct_match_view_clicked_cb (GtkWidget *widget, GdkEventButton *event,
CsvImpTransAssist* info);
315csv_tximp_assist_prepare_cb (GtkAssistant *assistant, GtkWidget *page,
318 info->assist_prepare_cb(page);
324 gnc_close_gui_component_by_data (ASSISTANT_CSV_IMPORT_TRANS_CM_CLASS, info);
330 info->assist_finish ();
333void csv_tximp_file_activated_cb (GtkFileChooser *chooser,
CsvImpTransAssist *info)
335 info->file_activated_cb();
338void csv_tximp_file_selection_changed_cb (GtkFileChooser *chooser,
CsvImpTransAssist *info)
340 info->file_selection_changed_cb();
343void csv_tximp_preview_del_settings_cb (GtkWidget *button,
CsvImpTransAssist *info)
345 info->preview_settings_delete();
348void csv_tximp_preview_save_settings_cb (GtkWidget *button,
CsvImpTransAssist *info)
350 info->preview_settings_save();
353void csv_tximp_preview_settings_sel_changed_cb (GtkComboBox *combo,
CsvImpTransAssist *info)
355 info->preview_settings_load();
359csv_tximp_preview_settings_text_inserted_cb (GtkEditable *entry, gchar *new_text,
366 auto base_txt = std::string (new_text);
367 auto mod_txt = base_txt;
368 std::replace (mod_txt.begin(), mod_txt.end(),
'[',
'(');
369 std::replace (mod_txt.begin(), mod_txt.end(),
']',
')');
370 if (base_txt == mod_txt)
372 g_signal_handlers_block_by_func (entry, (gpointer) csv_tximp_preview_settings_text_inserted_cb, info);
373 gtk_editable_insert_text (entry, mod_txt.c_str(), mod_txt.size() , position);
374 g_signal_handlers_unblock_by_func (entry, (gpointer) csv_tximp_preview_settings_text_inserted_cb, info);
376 g_signal_stop_emission_by_name (entry,
"insert_text");
380csv_tximp_preview_settings_text_changed_cb (GtkEntry *entry,
CsvImpTransAssist *info)
382 info->preview_settings_name(entry);
387 info->preview_update_skipped_rows();
392 info->preview_update_skipped_rows();
395void csv_tximp_preview_skiprows_cb (GtkToggleButton *checkbox,
CsvImpTransAssist *info)
397 info->preview_update_skipped_rows();
400void csv_tximp_preview_skiperrors_cb (GtkToggleButton *checkbox,
CsvImpTransAssist *info)
402 info->preview_update_skipped_rows();
405void csv_tximp_preview_multisplit_cb (GtkToggleButton *checkbox,
CsvImpTransAssist *info)
407 info->preview_multi_split (gtk_toggle_button_get_active (checkbox));
412 info->preview_update_separators(widget);
415void csv_tximp_preview_sep_fixed_sel_cb (GtkToggleButton* csv_button,
CsvImpTransAssist* info)
417 info->preview_update_file_format();
422 info->preview_update_account();
425void csv_tximp_preview_enc_sel_cb (GOCharmapSel* selector,
const char* encoding,
428 info->preview_update_encoding(encoding);
431static void csv_tximp_preview_date_fmt_sel_cb (GtkComboBox* format_selector,
CsvImpTransAssist* info)
433 info->preview_update_date_format();
436static void csv_tximp_preview_currency_fmt_sel_cb (GtkComboBox* format_selector,
CsvImpTransAssist* info)
438 info->preview_update_currency_format();
441static void csv_tximp_preview_col_type_changed_cb (GtkComboBox* cbox,
CsvImpTransAssist* info)
443 info->preview_update_col_type (cbox);
447csv_tximp_preview_treeview_clicked_cb (GtkTreeView* treeview, GdkEventButton* event,
450 info->preview_update_fw_columns(treeview, event);
455void csv_tximp_acct_match_button_clicked_cb (GtkWidget *widget,
CsvImpTransAssist* info)
457 info->acct_match_via_button();
460bool csv_tximp_acct_match_view_clicked_cb (GtkWidget *widget, GdkEventButton *event,
CsvImpTransAssist* info)
462 return info->acct_match_via_view_dblclick(event);
469CsvImpTransAssist::CsvImpTransAssist ()
471 auto builder = gtk_builder_new();
472 gnc_builder_add_from_file (builder ,
"assistant-csv-trans-import.glade",
"start_row_adj");
473 gnc_builder_add_from_file (builder ,
"assistant-csv-trans-import.glade",
"end_row_adj");
474 gnc_builder_add_from_file (builder ,
"assistant-csv-trans-import.glade",
"account_match_store");
475 gnc_builder_add_from_file (builder ,
"assistant-csv-trans-import.glade",
"csv_transaction_assistant");
476 csv_imp_asst = GTK_ASSISTANT(gtk_builder_get_object (builder,
"csv_transaction_assistant"));
479 gtk_widget_set_name (GTK_WIDGET(csv_imp_asst),
"gnc-id-assistant-csv-transaction-import");
480 gnc_widget_style_context_add_class (GTK_WIDGET(csv_imp_asst),
"gnc-class-imports");
483 gtk_assistant_set_page_complete (csv_imp_asst,
484 GTK_WIDGET(gtk_builder_get_object (builder,
"start_page")),
486 gtk_assistant_set_page_complete (csv_imp_asst,
487 GTK_WIDGET(gtk_builder_get_object (builder,
"file_page")),
489 gtk_assistant_set_page_complete (csv_imp_asst,
490 GTK_WIDGET(gtk_builder_get_object (builder,
"preview_page")),
492 gtk_assistant_set_page_complete (csv_imp_asst,
493 GTK_WIDGET(gtk_builder_get_object (builder,
"account_match_page")),
495 gtk_assistant_set_page_complete (csv_imp_asst,
496 GTK_WIDGET(gtk_builder_get_object (builder,
"doc_page")),
498 gtk_assistant_set_page_complete (csv_imp_asst,
499 GTK_WIDGET(gtk_builder_get_object (builder,
"match_page")),
501 gtk_assistant_set_page_complete (csv_imp_asst,
502 GTK_WIDGET(gtk_builder_get_object (builder,
"summary_page")),
506 file_page = GTK_WIDGET(gtk_builder_get_object (builder,
"file_page"));
507 file_chooser = gtk_file_chooser_widget_new (GTK_FILE_CHOOSER_ACTION_OPEN);
508 g_signal_connect (G_OBJECT(file_chooser),
"selection-changed",
509 G_CALLBACK(csv_tximp_file_selection_changed_cb),
this);
510 g_signal_connect (G_OBJECT(file_chooser),
"file-activated",
511 G_CALLBACK(csv_tximp_file_activated_cb),
this);
513 auto box = GTK_WIDGET(gtk_builder_get_object (builder,
"file_page"));
514 gtk_box_pack_start (GTK_BOX(box), file_chooser, TRUE, TRUE, 6);
515 gtk_widget_show (file_chooser);
519 preview_page = GTK_WIDGET(gtk_builder_get_object (builder,
"preview_page"));
522 auto settings_store = gtk_list_store_new (2, G_TYPE_POINTER, G_TYPE_STRING);
523 settings_combo = GTK_COMBO_BOX(gtk_combo_box_new_with_model_and_entry (GTK_TREE_MODEL(settings_store)));
524 g_object_unref (settings_store);
525 gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX(settings_combo), SET_NAME);
526 gtk_combo_box_set_active (GTK_COMBO_BOX(settings_combo), 0);
528 combo_hbox = GTK_WIDGET(gtk_builder_get_object (builder,
"combo_hbox"));
529 gtk_box_pack_start (GTK_BOX(combo_hbox), GTK_WIDGET(settings_combo),
true,
true, 6);
530 gtk_widget_show (GTK_WIDGET(settings_combo));
532 g_signal_connect (G_OBJECT(settings_combo),
"changed",
533 G_CALLBACK(csv_tximp_preview_settings_sel_changed_cb),
this);
536 auto emb_entry = gtk_bin_get_child (GTK_BIN (settings_combo));
537 g_signal_connect (G_OBJECT(emb_entry),
"changed",
538 G_CALLBACK(csv_tximp_preview_settings_text_changed_cb),
this);
539 g_signal_connect (G_OBJECT(emb_entry),
"insert-text",
540 G_CALLBACK(csv_tximp_preview_settings_text_inserted_cb),
this);
543 save_button = GTK_WIDGET(gtk_builder_get_object (builder,
"save_settings"));
546 del_button = GTK_WIDGET(gtk_builder_get_object (builder,
"delete_settings"));
549 start_row_spin = GTK_SPIN_BUTTON(gtk_builder_get_object (builder,
"start_row"));
550 end_row_spin = GTK_SPIN_BUTTON(gtk_builder_get_object (builder,
"end_row"));
551 skip_alt_rows_button = GTK_WIDGET(gtk_builder_get_object (builder,
"skip_rows"));
552 skip_errors_button = GTK_WIDGET(gtk_builder_get_object (builder,
"skip_errors_button"));
553 multi_split_cbutton = GTK_WIDGET(gtk_builder_get_object (builder,
"multi_split_button"));
554 separator_table = GTK_WIDGET(gtk_builder_get_object (builder,
"separator_table"));
555 fw_instructions_hbox = GTK_WIDGET(gtk_builder_get_object (builder,
"fw_instructions_hbox"));
559 const char* sep_button_names[] = {
567 for (
int i = 0; i < SEP_NUM_OF_TYPES; i++)
569 = GTK_CHECK_BUTTON(gtk_builder_get_object (builder, sep_button_names[i]));
574 = GTK_CHECK_BUTTON(gtk_builder_get_object (builder,
"custom_cbutton"));
578 custom_entry = GTK_ENTRY(gtk_builder_get_object (builder,
"custom_entry"));
583 = GTK_CHECK_BUTTON(gtk_builder_get_object (builder,
"escape_cbutton"));
586 acct_selector = gnc_account_sel_new();
587 auto account_hbox = GTK_WIDGET(gtk_builder_get_object (builder,
"account_hbox"));
588 gtk_box_pack_start (GTK_BOX(account_hbox), acct_selector, TRUE, TRUE, 6);
589 gtk_widget_show (acct_selector);
591 g_signal_connect(G_OBJECT(acct_selector),
"account_sel_changed",
592 G_CALLBACK(csv_tximp_preview_acct_sel_cb),
this);
596 encselector = GO_CHARMAP_SEL(go_charmap_sel_new(GO_CHARMAP_SEL_TO_UTF8));
598 g_signal_connect (G_OBJECT(encselector),
"charmap_changed",
599 G_CALLBACK(csv_tximp_preview_enc_sel_cb),
this);
601 auto encoding_container = GTK_CONTAINER(gtk_builder_get_object (builder,
"encoding_container"));
602 gtk_container_add (encoding_container, GTK_WIDGET(encselector));
603 gtk_widget_set_hexpand (GTK_WIDGET(encselector),
true);
604 gtk_widget_show_all (GTK_WIDGET(encoding_container));
607 instructions_label = GTK_LABEL(gtk_builder_get_object (builder,
"instructions_label"));
608 instructions_image = GTK_IMAGE(gtk_builder_get_object (builder,
"instructions_image"));
611 date_format_combo = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new());
612 for (
auto& date_fmt :
GncDate::c_formats)
613 gtk_combo_box_text_append_text (date_format_combo,
_(date_fmt.m_fmt.c_str()));
614 gtk_combo_box_set_active (GTK_COMBO_BOX(date_format_combo), 0);
615 g_signal_connect (G_OBJECT(date_format_combo),
"changed",
616 G_CALLBACK(csv_tximp_preview_date_fmt_sel_cb),
this);
619 auto date_format_container = GTK_CONTAINER(gtk_builder_get_object (builder,
"date_format_container"));
620 gtk_container_add (date_format_container, GTK_WIDGET(date_format_combo));
621 gtk_widget_set_hexpand (GTK_WIDGET(date_format_combo),
true);
622 gtk_widget_show_all (GTK_WIDGET(date_format_container));
625 currency_format_combo = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new());
626 for (
int i = 0; i < num_currency_formats; i++)
628 gtk_combo_box_text_append_text (currency_format_combo,
_(currency_format_user[i]));
631 gtk_combo_box_set_active (GTK_COMBO_BOX(currency_format_combo), 0);
632 g_signal_connect (G_OBJECT(currency_format_combo),
"changed",
633 G_CALLBACK(csv_tximp_preview_currency_fmt_sel_cb),
this);
636 auto currency_format_container = GTK_CONTAINER(gtk_builder_get_object (builder,
"currency_format_container"));
637 gtk_container_add (currency_format_container, GTK_WIDGET(currency_format_combo));
638 gtk_widget_set_hexpand (GTK_WIDGET(currency_format_combo),
true);
639 gtk_widget_show_all (GTK_WIDGET(currency_format_container));
642 csv_button = GTK_WIDGET(gtk_builder_get_object (builder,
"csv_button"));
643 fixed_button = GTK_WIDGET(gtk_builder_get_object (builder,
"fixed_button"));
646 treeview = GTK_TREE_VIEW(gtk_builder_get_object (builder,
"treeview"));
647 gtk_tree_view_set_headers_clickable (treeview,
true);
651 encoding_selected_called =
false;
655 account_match_page = GTK_WIDGET(gtk_builder_get_object (builder,
"account_match_page"));
656 account_match_view = GTK_WIDGET(gtk_builder_get_object (builder,
"account_match_view"));
657 account_match_label = GTK_WIDGET(gtk_builder_get_object (builder,
"account_match_label"));
658 account_match_btn = GTK_WIDGET(gtk_builder_get_object (builder,
"account_match_change"));
661 doc_page = GTK_WIDGET(gtk_builder_get_object (builder,
"doc_page"));
664 match_page = GTK_WIDGET(gtk_builder_get_object (builder,
"match_page"));
665 match_label = GTK_WIDGET(gtk_builder_get_object (builder,
"match_label"));
672 match_page,
nullptr,
false, 42);
675 summary_page = GTK_WIDGET(gtk_builder_get_object (builder,
"summary_page"));
676 summary_label = GTK_WIDGET(gtk_builder_get_object (builder,
"summary_label"));
678 gnc_restore_window_size (GNC_PREFS_GROUP,
681 gtk_builder_connect_signals (builder,
this);
682 g_object_unref (G_OBJECT(builder));
684 gtk_widget_show_all (GTK_WIDGET(csv_imp_asst));
685 gnc_window_adjust_for_screen (GTK_WINDOW(csv_imp_asst));
689 new_book = gnc_is_new_book();
696CsvImpTransAssist::~CsvImpTransAssist ()
702 gnc_csv_importer_gui =
nullptr;
703 gtk_widget_destroy (GTK_WIDGET(csv_imp_asst));
714CsvImpTransAssist::check_for_valid_filename ()
716 auto file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(file_chooser));
717 if (!file_name || g_file_test (file_name, G_FILE_TEST_IS_DIR))
724 auto starting_dir = g_path_get_dirname (filepath);
726 m_fc_file_name = file_name;
727 gnc_set_default_directory (GNC_PREFS_GROUP, starting_dir);
729 DEBUG(
"file_name selected is %s", m_fc_file_name.c_str());
730 DEBUG(
"starting directory is %s", starting_dir);
734 g_free (starting_dir);
744CsvImpTransAssist::file_activated_cb ()
746 gtk_assistant_set_page_complete (csv_imp_asst, file_page,
false);
749 if (check_for_valid_filename ())
751 gtk_assistant_set_page_complete (csv_imp_asst, file_page,
true);
752 gtk_assistant_next_page (csv_imp_asst);
761CsvImpTransAssist::file_selection_changed_cb ()
764 gtk_assistant_set_page_complete (csv_imp_asst, file_page,
765 check_for_valid_filename ());
775void CsvImpTransAssist::preview_populate_settings_combo()
778 auto model = gtk_combo_box_get_model (settings_combo);
779 gtk_list_store_clear (GTK_LIST_STORE(model));
783 for (
auto preset : presets)
786 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
793 gtk_list_store_set (GTK_LIST_STORE(model), &iter, SET_GROUP, preset.get(), SET_NAME,
_(preset->m_name.c_str()), -1);
800void CsvImpTransAssist::preview_handle_save_del_sensitivity (GtkComboBox* combo)
803 auto can_delete =
false;
804 auto can_save =
false;
805 auto entry = gtk_bin_get_child (GTK_BIN(combo));
806 auto entry_text = gtk_entry_get_text (GTK_ENTRY(entry));
808 if (gtk_combo_box_get_active_iter (combo, &iter))
811 GtkTreeModel *model = gtk_combo_box_get_model (combo);
812 gtk_tree_model_get (model, &iter, SET_GROUP, &preset, -1);
821 else if (entry_text && (strlen (entry_text) > 0) &&
825 gtk_widget_set_sensitive (save_button, can_save);
826 gtk_widget_set_sensitive (del_button, can_delete);
831CsvImpTransAssist::preview_settings_name (GtkEntry* entry)
833 auto text = gtk_entry_get_text (entry);
835 tx_imp->settings_name(text);
837 auto box = gtk_widget_get_parent (GTK_WIDGET(entry));
838 auto combo = gtk_widget_get_parent (GTK_WIDGET(box));
840 preview_handle_save_del_sensitivity (GTK_COMBO_BOX(combo));
848CsvImpTransAssist::preview_settings_load ()
852 if (!gtk_combo_box_get_active_iter (settings_combo, &iter))
856 auto model = gtk_combo_box_get_model (settings_combo);
857 gtk_tree_model_get (model, &iter, SET_GROUP, &preset, -1);
862 tx_imp->settings (*preset);
863 if (preset->m_load_error)
864 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
865 "%s",
_(
"There were problems reading some saved settings, continuing to load.\n"
866 "Please review and save again."));
869 preview_handle_save_del_sensitivity (settings_combo);
875CsvImpTransAssist::preview_settings_delete ()
879 if (!gtk_combo_box_get_active_iter (settings_combo, &iter))
883 auto model = gtk_combo_box_get_model (settings_combo);
884 gtk_tree_model_get (model, &iter, SET_GROUP, &preset, -1);
886 auto response = gnc_ok_cancel_dialog (GTK_WINDOW (csv_imp_asst),
888 "%s",
_(
"Delete the Import Settings."));
889 if (response == GTK_RESPONSE_OK)
892 preview_populate_settings_combo();
893 gtk_combo_box_set_active (settings_combo, 0);
901CsvImpTransAssist::preview_settings_save ()
903 auto new_name = tx_imp->settings_name();
907 if (!gtk_combo_box_get_active_iter (settings_combo, &iter))
910 auto model = gtk_combo_box_get_model (settings_combo);
911 bool valid = gtk_tree_model_get_iter_first (model, &iter);
916 gtk_tree_model_get (model, &iter, SET_GROUP, &preset, -1);
918 if (preset && (preset->m_name == std::string(new_name)))
920 auto response = gnc_ok_cancel_dialog (GTK_WINDOW (csv_imp_asst),
922 "%s",
_(
"Setting name already exists, overwrite?"));
923 if (response != GTK_RESPONSE_OK)
928 valid = gtk_tree_model_iter_next (model, &iter);
933 if (!tx_imp->save_settings())
935 gnc_info_dialog (GTK_WINDOW (csv_imp_asst),
936 "%s",
_(
"The settings have been saved."));
939 preview_populate_settings_combo();
940 auto model = gtk_combo_box_get_model (settings_combo);
944 bool valid = gtk_tree_model_get_iter_first (model, &iter);
948 gchar *name =
nullptr;
949 gtk_tree_model_get (model, &iter, SET_NAME, &name, -1);
951 if (g_strcmp0 (name, new_name.c_str()) == 0)
952 gtk_combo_box_set_active_iter (settings_combo, &iter);
956 valid = gtk_tree_model_iter_next (model, &iter);
960 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
961 "%s",
_(
"There was a problem saving the settings, please try again."));
966void CsvImpTransAssist::preview_update_skipped_rows ()
969 tx_imp->update_skipped_lines (gtk_spin_button_get_value_as_int (start_row_spin),
970 gtk_spin_button_get_value_as_int (end_row_spin),
971 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(skip_alt_rows_button)),
972 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(skip_errors_button)));
975 auto adj = gtk_spin_button_get_adjustment (end_row_spin);
976 gtk_adjustment_set_upper (adj, tx_imp->m_parsed_lines.size()
977 - tx_imp->skip_start_lines() -1);
979 adj = gtk_spin_button_get_adjustment (start_row_spin);
980 gtk_adjustment_set_upper (adj, tx_imp->m_parsed_lines.size()
981 - tx_imp->skip_end_lines() - 1);
983 preview_refresh_table ();
986void CsvImpTransAssist::preview_multi_split (
bool multi)
988 tx_imp->multi_split(multi);
1004 if (tx_imp->file_format() != GncImpFileFormat::CSV)
1009 auto checked_separators = std::string();
1010 const auto stock_sep_chars = std::string (
" \t,:;-");
1011 for (
int i = 0; i < SEP_NUM_OF_TYPES; i++)
1013 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(sep_button[i])))
1014 checked_separators += stock_sep_chars[i];
1018 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(custom_cbutton)))
1020 auto custom_sep = gtk_entry_get_text (custom_entry);
1021 if (custom_sep[0] !=
'\0')
1022 checked_separators += custom_sep;
1026 tx_imp->separators (checked_separators);
1027 tx_imp->enable_escape (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(escape_cbutton)));
1034 tx_imp->tokenize (
false);
1035 preview_refresh_table ();
1037 catch (std::range_error &e)
1042 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
"Error in parsing");
1048 if (widget == GTK_WIDGET(custom_entry))
1049 gtk_entry_set_text (GTK_ENTRY(widget),
"");
1052 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget),
1053 !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)));
1067 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(csv_button)))
1069 tx_imp->file_format (GncImpFileFormat::CSV);
1070 g_signal_handlers_disconnect_by_func(G_OBJECT(treeview),
1071 (gpointer)csv_tximp_preview_treeview_clicked_cb, (gpointer)
this);
1072 gtk_widget_set_visible (separator_table,
true);
1073 gtk_widget_set_visible (fw_instructions_hbox,
false);
1077 tx_imp->file_format (GncImpFileFormat::FIXED_WIDTH);
1079 g_signal_connect (G_OBJECT(treeview),
"button-press-event",
1080 G_CALLBACK(csv_tximp_preview_treeview_clicked_cb), (gpointer)
this);
1081 gtk_widget_set_visible (separator_table,
false);
1082 gtk_widget_set_visible (fw_instructions_hbox,
true);
1086 tx_imp->tokenize (
false);
1087 preview_refresh_table ();
1089 catch (std::range_error &e)
1092 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
"%s", e.what());
1098 PWARN(
"Got an error during file loading");
1103void CsvImpTransAssist::preview_update_account ()
1105 auto acct = gnc_account_sel_get_account( GNC_ACCOUNT_SEL(acct_selector) );
1106 tx_imp->base_account(acct);
1107 preview_refresh_table ();
1124 if (encoding_selected_called)
1126 std::string previous_encoding = tx_imp->m_tokenizer->encoding();
1130 tx_imp->encoding (encoding);
1131 preview_refresh_table ();
1136 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
"%s", _(
"Invalid encoding selected"));
1137 go_charmap_sel_set_encoding (encselector, previous_encoding.c_str());
1141 encoding_selected_called = !encoding_selected_called;
1146CsvImpTransAssist::preview_update_date_format ()
1148 tx_imp->date_format (gtk_combo_box_get_active (GTK_COMBO_BOX(date_format_combo)));
1149 preview_refresh_table ();
1154CsvImpTransAssist::preview_update_currency_format ()
1156 tx_imp->currency_format (gtk_combo_box_get_active (GTK_COMBO_BOX(currency_format_combo)));
1157 preview_refresh_table ();
1163 assist->preview_refresh_table ();
1170enum PreviewHeaderComboCols { COL_TYPE_NAME, COL_TYPE_ID };
1174enum PreviewDataTableCols {
1180 PREV_N_FIXED_COLS };
1192 auto model = gtk_combo_box_get_model (cbox);
1193 gtk_combo_box_get_active_iter (cbox, &iter);
1194 auto new_col_type = GncTransPropType::NONE;
1195 gtk_tree_model_get (model, &iter, COL_TYPE_ID, &new_col_type, -1);
1197 auto col_num = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT(cbox),
"col-num"));
1198 tx_imp->set_column_type (col_num, new_col_type);
1203 g_idle_add ((GSourceFunc)csv_imp_preview_queue_rebuild_table,
this);
1236 CONTEXT_STF_IMPORT_MERGE_LEFT = 1,
1237 CONTEXT_STF_IMPORT_MERGE_RIGHT = 2,
1238 CONTEXT_STF_IMPORT_SPLIT = 3,
1239 CONTEXT_STF_IMPORT_WIDEN = 4,
1240 CONTEXT_STF_IMPORT_NARROW = 5
1246 N_(
"Merge with column on _left"),
"list-remove",
1247 0, 1 << CONTEXT_STF_IMPORT_MERGE_LEFT, CONTEXT_STF_IMPORT_MERGE_LEFT
1250 N_(
"Merge with column on _right"),
"list-remove",
1251 0, 1 << CONTEXT_STF_IMPORT_MERGE_RIGHT, CONTEXT_STF_IMPORT_MERGE_RIGHT
1253 {
"",
nullptr, 0, 0, 0 },
1255 N_(
"_Split this column"),
nullptr,
1256 0, 1 << CONTEXT_STF_IMPORT_SPLIT, CONTEXT_STF_IMPORT_SPLIT
1258 {
"",
nullptr, 0, 0, 0 },
1260 N_(
"_Widen this column"),
"go-next",
1261 0, 1 << CONTEXT_STF_IMPORT_WIDEN, CONTEXT_STF_IMPORT_WIDEN
1264 N_(
"_Narrow this column"),
"go-previous",
1265 0, 1 << CONTEXT_STF_IMPORT_NARROW, CONTEXT_STF_IMPORT_NARROW
1267 {
nullptr,
nullptr, 0, 0, 0 },
1270uint32_t CsvImpTransAssist::get_new_col_rel_pos (GtkTreeViewColumn *tcol,
int dx)
1272 auto renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT(tcol));
1273 auto cell = GTK_CELL_RENDERER(renderers->data);
1274 g_list_free (renderers);
1275 PangoFontDescription *font_desc;
1276 g_object_get (G_OBJECT(cell),
"font_desc", &font_desc,
nullptr);
1278 PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET(treeview),
"x");
1279 pango_layout_set_font_description (layout, font_desc);
1281 pango_layout_get_pixel_size (layout, &width,
nullptr);
1282 if (width < 1) width = 1;
1283 uint32_t charindex = (dx + width / 2) / width;
1284 g_object_unref (layout);
1285 pango_font_description_free (font_desc);
1295 auto fwtok =
dynamic_cast<GncFwTokenizer*
>(info->tx_imp->m_tokenizer.get());
1297 switch (element->index)
1299 case CONTEXT_STF_IMPORT_MERGE_LEFT:
1300 fwtok->col_delete (info->fixed_context_col - 1);
1302 case CONTEXT_STF_IMPORT_MERGE_RIGHT:
1303 fwtok->col_delete (info->fixed_context_col);
1305 case CONTEXT_STF_IMPORT_SPLIT:
1306 fwtok->col_split (info->fixed_context_col, info->fixed_context_offset);
1308 case CONTEXT_STF_IMPORT_WIDEN:
1309 fwtok->col_widen (info->fixed_context_col);
1311 case CONTEXT_STF_IMPORT_NARROW:
1312 fwtok->col_narrow (info->fixed_context_col);
1320 info->tx_imp->tokenize (
false);
1322 catch(std::range_error& e)
1324 gnc_error_dialog (GTK_WINDOW (info->csv_imp_asst),
"%s", e.what());
1327 info->preview_refresh_table ();
1332CsvImpTransAssist::fixed_context_menu (GdkEventButton *event,
1333 int col,
int offset)
1335 auto fwtok =
dynamic_cast<GncFwTokenizer*
>(tx_imp->m_tokenizer.get());
1336 fixed_context_col = col;
1337 fixed_context_offset = offset;
1339 int sensitivity_filter = 0;
1340 if (!fwtok->col_can_delete (col - 1))
1341 sensitivity_filter |= (1 << CONTEXT_STF_IMPORT_MERGE_LEFT);
1342 if (!fwtok->col_can_delete (col))
1343 sensitivity_filter |= (1 << CONTEXT_STF_IMPORT_MERGE_RIGHT);
1344 if (!fwtok->col_can_split (col, offset))
1345 sensitivity_filter |= (1 << CONTEXT_STF_IMPORT_SPLIT);
1346 if (!fwtok->col_can_widen (col))
1347 sensitivity_filter |= (1 << CONTEXT_STF_IMPORT_WIDEN);
1348 if (!fwtok->col_can_narrow (col))
1349 sensitivity_filter |= (1 << CONTEXT_STF_IMPORT_NARROW);
1351 gnumeric_create_popup_menu (popup_elements, &fixed_context_menu_handler,
1353 sensitivity_filter, event);
1359CsvImpTransAssist::preview_split_column (
int col,
int offset)
1361 auto fwtok =
dynamic_cast<GncFwTokenizer*
>(tx_imp->m_tokenizer.get());
1362 fwtok->col_split (col, offset);
1365 tx_imp->tokenize (
false);
1367 catch (std::range_error& e)
1369 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
"%s", e.what());
1372 preview_refresh_table();
1385 if (event->window != gtk_tree_view_get_bin_window (treeview))
1389 GtkTreeViewColumn *tcol =
nullptr;
1391 auto success = gtk_tree_view_get_path_at_pos (treeview,
1392 (
int)event->x, (
int)event->y,
1393 nullptr, &tcol, &cell_x,
nullptr);
1399 auto tcol_list = gtk_tree_view_get_columns(treeview);
1400 auto tcol_num = g_list_index (tcol_list, tcol);
1401 g_list_free (tcol_list);
1408 auto dcol = tcol_num - 1;
1409 auto offset = get_new_col_rel_pos (tcol, cell_x);
1410 if (event->type == GDK_2BUTTON_PRESS && event->button == 1)
1412 preview_split_column (dcol, offset);
1413 else if (event->type == GDK_BUTTON_PRESS && event->button == 3)
1415 fixed_context_menu (event, dcol, offset);
1421CsvImpTransAssist::preview_row_fill_state_cells (GtkListStore *store, GtkTreeIter *iter,
1422 ErrMap& err_msgs,
bool skip)
1425 auto err_msg = std::string();
1426 const char *icon_name =
nullptr;
1427 const char *fcolor =
nullptr;
1428 const char *bcolor =
nullptr;
1431 auto non_acct_error = [](ErrPair curr_err)
1433 return !((curr_err.first == GncTransPropType::ACCOUNT) ||
1434 (curr_err.first == GncTransPropType::TACCOUNT));
1436 if (!skip && std::any_of(err_msgs.cbegin(), err_msgs.cend(), non_acct_error))
1440 err_msg = std::string(
_(
"This line has the following parse issues:"));
1441 auto add_non_acct_err_bullet = [](std::string& a, ErrMap::value_type& b)->std::string
1443 if ((b.first == GncTransPropType::ACCOUNT) ||
1444 (b.first == GncTransPropType::TACCOUNT))
1445 return std::move(a);
1447 return std::move(a) +
"\n• " + b.second;
1450 err_msg = std::accumulate (err_msgs.begin(), err_msgs.end(),
1451 std::move (err_msg), add_non_acct_err_bullet);
1452 icon_name =
"dialog-error";
1454 gtk_list_store_set (store, iter,
1455 PREV_COL_FCOLOR, fcolor,
1456 PREV_COL_BCOLOR, bcolor,
1457 PREV_COL_STRIKE, skip,
1458 PREV_COL_ERROR, err_msg.c_str(),
1459 PREV_COL_ERR_ICON, icon_name, -1);
1466CsvImpTransAssist::preview_cbox_factory (GtkTreeModel* model, uint32_t colnum)
1469 auto cbox = gtk_combo_box_new_with_model(model);
1472 auto renderer = gtk_cell_renderer_text_new();
1473 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(cbox),
1475 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT(cbox),
1476 renderer,
"text", COL_TYPE_NAME);
1478 auto valid = gtk_tree_model_get_iter_first (model, &iter);
1481 gint stored_col_type;
1482 gtk_tree_model_get (model, &iter,
1483 COL_TYPE_ID, &stored_col_type, -1);
1484 if (stored_col_type ==
static_cast<int>( tx_imp->column_types()[colnum]))
1486 valid = gtk_tree_model_iter_next(model, &iter);
1489 gtk_combo_box_set_active_iter (GTK_COMBO_BOX(cbox), &iter);
1491 g_object_set_data (G_OBJECT(cbox),
"col-num", GUINT_TO_POINTER(colnum));
1492 g_signal_connect (G_OBJECT(cbox),
"changed",
1493 G_CALLBACK(csv_tximp_preview_col_type_changed_cb), (gpointer)
this);
1495 gtk_widget_show (cbox);
1500CsvImpTransAssist::preview_style_column (uint32_t col_num, GtkTreeModel* model)
1502 auto col = gtk_tree_view_get_column (treeview, col_num);
1503 auto renderer =
static_cast<GtkCellRenderer*
>(gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(col))->data);
1507 gtk_tree_view_column_set_attributes (col, renderer,
1508 "icon-name", PREV_COL_ERR_ICON,
1509 "cell-background", PREV_COL_BCOLOR,
nullptr);
1510 g_object_set (G_OBJECT(renderer),
"stock-size", GTK_ICON_SIZE_MENU,
nullptr);
1511 g_object_set (G_OBJECT(col),
"sizing", GTK_TREE_VIEW_COLUMN_FIXED,
1512 "fixed-width", 20,
nullptr);
1513 gtk_tree_view_column_set_resizable (col,
false);
1517 gtk_tree_view_column_set_attributes (col, renderer,
1518 "foreground", PREV_COL_FCOLOR,
1519 "background", PREV_COL_BCOLOR,
1520 "strikethrough", PREV_COL_STRIKE,
1521 "text", col_num + PREV_N_FIXED_COLS -1,
nullptr);
1524 g_object_set (G_OBJECT(renderer),
"family",
"monospace",
nullptr);
1529 auto cbox = preview_cbox_factory (GTK_TREE_MODEL(model), col_num - 1);
1530 gtk_tree_view_column_set_widget (col, cbox);
1533 gtk_tree_view_column_set_resizable (col,
true);
1534 gtk_tree_view_column_set_clickable (col,
true);
1542make_column_header_model (
bool multi_split)
1544 auto combostore = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
1545 for (
auto col_type : gnc_csv_col_type_strs)
1550 if (sanitize_trans_prop(col_type.first, multi_split) == col_type.first)
1553 gtk_list_store_append (combostore, &iter);
1554 gtk_list_store_set (combostore, &iter,
1555 COL_TYPE_NAME,
_(col_type.second),
1556 COL_TYPE_ID,
static_cast<int>(col_type.first), -1);
1559 return GTK_TREE_MODEL(combostore);
1565void CsvImpTransAssist::preview_refresh_table ()
1567 preview_validate_settings ();
1572 auto ncols = PREV_N_FIXED_COLS + tx_imp->column_types().size();
1573 auto model_col_types = g_new (GType, ncols);
1574 model_col_types[PREV_COL_FCOLOR] = G_TYPE_STRING;
1575 model_col_types[PREV_COL_BCOLOR] = G_TYPE_STRING;
1576 model_col_types[PREV_COL_ERROR] = G_TYPE_STRING;
1577 model_col_types[PREV_COL_ERR_ICON] = G_TYPE_STRING;
1578 model_col_types[PREV_COL_STRIKE] = G_TYPE_BOOLEAN;
1579 for (guint i = PREV_N_FIXED_COLS; i < ncols; i++)
1580 model_col_types[i] = G_TYPE_STRING;
1581 auto store = gtk_list_store_newv (ncols, model_col_types);
1582 g_free (model_col_types);
1585 for (
auto parse_line : tx_imp->m_parsed_lines)
1589 gtk_list_store_append (store, &iter);
1590 preview_row_fill_state_cells (store, &iter,
1591 std::get<PL_ERROR>(parse_line), std::get<PL_SKIP>(parse_line));
1594 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++)
1596 uint32_t pos = PREV_N_FIXED_COLS + cell_str_it - std::get<PL_INPUT>(parse_line).cbegin();
1597 gtk_list_store_set (store, &iter, pos, cell_str_it->c_str(), -1);
1600 gtk_tree_view_set_model (treeview, GTK_TREE_MODEL(store));
1601 gtk_tree_view_set_tooltip_column (treeview, PREV_COL_ERROR);
1610 auto ntcols = gtk_tree_view_get_n_columns (treeview);
1616 while (ntcols > ncols - PREV_N_FIXED_COLS + 1)
1618 auto col = gtk_tree_view_get_column (treeview, ntcols - 1);
1619 gtk_tree_view_column_clear (col);
1620 ntcols = gtk_tree_view_remove_column(treeview, col);
1624 while (ntcols < ncols - PREV_N_FIXED_COLS + 1)
1627 auto renderer = gtk_cell_renderer_text_new();
1629 renderer = gtk_cell_renderer_pixbuf_new();
1630 auto col = gtk_tree_view_column_new ();
1631 gtk_tree_view_column_pack_start (col, renderer,
false);
1632 ntcols = gtk_tree_view_append_column (treeview, col);
1636 auto combostore = make_column_header_model (tx_imp->multi_split());
1637 for (uint32_t i = 0; i < ntcols; i++)
1638 preview_style_column (i, combostore);
1641 g_object_unref (store);
1642 g_object_unref (combostore);
1645 auto base_acct = gnc_account_sel_get_account(GNC_ACCOUNT_SEL(acct_selector));
1646 if (tx_imp->base_account() != base_acct)
1648 g_signal_handlers_block_by_func (acct_selector, (gpointer) csv_tximp_preview_acct_sel_cb,
this);
1649 gnc_account_sel_set_account(GNC_ACCOUNT_SEL(acct_selector),
1650 tx_imp->base_account() ,
false);
1651 g_signal_handlers_unblock_by_func (acct_selector, (gpointer) csv_tximp_preview_acct_sel_cb,
this);
1655 gtk_widget_show_all (GTK_WIDGET(treeview));
1662CsvImpTransAssist::preview_refresh ()
1671 auto skip_start_lines = tx_imp->skip_start_lines();
1672 auto skip_end_lines = tx_imp->skip_end_lines();
1673 auto skip_alt_lines = tx_imp->skip_alt_lines();
1676 auto adj = gtk_spin_button_get_adjustment (start_row_spin);
1677 gtk_adjustment_set_upper (adj, tx_imp->m_parsed_lines.size());
1678 gtk_spin_button_set_value (start_row_spin, skip_start_lines);
1681 adj = gtk_spin_button_get_adjustment (end_row_spin);
1682 gtk_adjustment_set_upper (adj, tx_imp->m_parsed_lines.size());
1683 gtk_spin_button_set_value (end_row_spin, skip_end_lines);
1686 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(skip_alt_rows_button),
1690 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(multi_split_cbutton),
1691 tx_imp->multi_split());
1692 gtk_widget_set_sensitive (acct_selector, !tx_imp->multi_split());
1695 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(csv_button),
1696 (tx_imp->file_format() == GncImpFileFormat::CSV));
1697 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(fixed_button),
1698 (tx_imp->file_format() != GncImpFileFormat::CSV));
1701 gtk_combo_box_set_active (GTK_COMBO_BOX(date_format_combo),
1702 tx_imp->date_format());
1703 gtk_combo_box_set_active (GTK_COMBO_BOX(currency_format_combo),
1704 tx_imp->currency_format());
1705 go_charmap_sel_set_encoding (encselector, tx_imp->encoding().c_str());
1711 if (tx_imp->file_format() == GncImpFileFormat::CSV)
1713 auto separators = tx_imp->separators();
1714 auto enable_escape = tx_imp->enable_escape();
1715 const auto stock_sep_chars = std::string (
" \t,:;-");
1716 for (
int i = 0; i < SEP_NUM_OF_TYPES; i++)
1718 g_signal_handlers_block_by_func (sep_button[i], (gpointer) csv_tximp_preview_sep_button_cb,
this);
1719 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(sep_button[i]),
1720 separators.find (stock_sep_chars[i]) != std::string::npos);
1721 g_signal_handlers_unblock_by_func (sep_button[i], (gpointer) csv_tximp_preview_sep_button_cb,
this);
1726 auto pos = separators.find_first_of (stock_sep_chars);
1727 while (!separators.empty() && pos != std::string::npos)
1729 separators.erase(pos);
1730 pos = separators.find_first_of (stock_sep_chars);
1732 g_signal_handlers_block_by_func (custom_cbutton, (gpointer) csv_tximp_preview_sep_button_cb,
this);
1733 g_signal_handlers_block_by_func (custom_entry, (gpointer) csv_tximp_preview_sep_button_cb,
this);
1734 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(custom_cbutton),
1735 !separators.empty());
1736 gtk_entry_set_text (GTK_ENTRY(custom_entry), separators.c_str());
1738 g_signal_handlers_block_by_func (escape_cbutton, (gpointer) csv_tximp_preview_sep_button_cb,
this);
1739 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(escape_cbutton),
1741 g_signal_handlers_unblock_by_func (escape_cbutton, (gpointer) csv_tximp_preview_sep_button_cb,
this);
1743 g_signal_handlers_unblock_by_func (custom_cbutton, (gpointer) csv_tximp_preview_sep_button_cb,
this);
1744 g_signal_handlers_unblock_by_func (custom_entry, (gpointer) csv_tximp_preview_sep_button_cb,
this);
1745 g_signal_handlers_unblock_by_func (custom_cbutton, (gpointer) csv_tximp_preview_sep_button_cb,
this);
1748 tx_imp->tokenize (
false);
1750 catch(std::range_error& err)
1752 PERR(
"CSV Tokenization Failed: %s", err.what());
1757 preview_refresh_table ();
1762void CsvImpTransAssist::preview_validate_settings ()
1765 auto has_non_acct_errors = !tx_imp->verify (
false).empty();
1766 auto error_msg = tx_imp->verify (m_req_mapped_accts);
1767 gtk_assistant_set_page_complete (csv_imp_asst, preview_page, !has_non_acct_errors);
1768 gtk_label_set_markup(GTK_LABEL(instructions_label), error_msg.c_str());
1769 gtk_widget_set_visible (GTK_WIDGET(instructions_image), !error_msg.empty());
1775 if (!has_non_acct_errors)
1776 gtk_widget_set_visible (GTK_WIDGET(account_match_page),
1777 !tx_imp->accounts().empty());
1788void CsvImpTransAssist::acct_match_set_accounts ()
1790 auto store = gtk_tree_view_get_model (GTK_TREE_VIEW(account_match_view));
1791 gtk_list_store_clear (GTK_LIST_STORE(store));
1793 auto accts = tx_imp->accounts();
1794 for (
auto acct : accts)
1796 GtkTreeIter acct_iter;
1797 gtk_list_store_append (GTK_LIST_STORE(store), &acct_iter);
1798 gtk_list_store_set (GTK_LIST_STORE(store), &acct_iter, MAPPING_STRING, acct.c_str(),
1799 MAPPING_FULLPATH,
_(
"No Linked Account"), MAPPING_ACCOUNT,
nullptr, -1);
1804csv_tximp_acct_match_load_mappings (GtkTreeModel *mappings_store)
1808 auto valid = gtk_tree_model_get_iter_first (mappings_store, &iter);
1816 gtk_tree_model_get (GTK_TREE_MODEL(mappings_store), &iter, MAPPING_STRING, &map_string, MAPPING_ACCOUNT, &account, -1);
1823 (account = gnc_account_imap_find_any (gnc_get_current_book(), IMAP_CAT_CSV, map_string)) ||
1827 gtk_list_store_set (GTK_LIST_STORE(mappings_store), &iter, MAPPING_FULLPATH, fullpath, -1);
1828 gtk_list_store_set (GTK_LIST_STORE(mappings_store), &iter, MAPPING_ACCOUNT, account, -1);
1832 g_free (map_string);
1833 valid = gtk_tree_model_iter_next (mappings_store, &iter);
1838csv_tximp_acct_match_check_all (GtkTreeModel *model)
1842 auto valid = gtk_tree_model_get_iter_first (model, &iter);
1848 gtk_tree_model_get (model, &iter, MAPPING_ACCOUNT, &account, -1);
1852 valid = gtk_tree_model_iter_next (model, &iter);
1865csv_tximp_acct_match_text_parse (std::string acct_name)
1868 auto sep_pos = acct_name.rfind(sep);
1869 if (sep_pos == std::string::npos)
1873 auto parent = acct_name.substr(0, sep_pos);
1874 auto root = gnc_get_current_root_account ();
1884 const gchar *alt_sep;
1885 if (g_strcmp0 (sep,
":") == 0)
1889 for (sep_pos = acct_name.find(sep); sep_pos != std::string::npos;
1890 sep_pos = acct_name.find(sep))
1891 acct_name.replace (sep_pos, strlen(sep), alt_sep);
1897CsvImpTransAssist::acct_match_select(GtkTreeModel *model, GtkTreeIter* iter)
1900 gchar *text =
nullptr;
1902 gtk_tree_model_get (model, iter, MAPPING_STRING, &text,
1903 MAPPING_ACCOUNT, &account, -1);
1905 auto acct_name = csv_tximp_acct_match_text_parse (text);
1912 gtk_list_store_set (GTK_LIST_STORE(model), iter,
1913 MAPPING_ACCOUNT, gnc_acc,
1914 MAPPING_FULLPATH, fullpath, -1);
1919 gnc_account_imap_delete_account (account, IMAP_CAT_CSV, text);
1920 gnc_account_imap_add_account (gnc_acc, IMAP_CAT_CSV, text, gnc_acc);
1924 auto col_types = tx_imp->column_types();
1925 auto col_type_it = std::find (col_types.cbegin(),
1926 col_types.cend(), GncTransPropType::ACCOUNT);
1927 if (col_type_it != col_types.cend())
1928 tx_imp->set_column_type(col_type_it - col_types.cbegin(),
1929 GncTransPropType::ACCOUNT,
true);
1930 col_type_it = std::find (col_types.cbegin(),
1931 col_types.cend(), GncTransPropType::TACCOUNT);
1932 if (col_type_it != col_types.cend())
1933 tx_imp->set_column_type(col_type_it - col_types.cbegin(),
1934 GncTransPropType::TACCOUNT,
true);
1942 auto all_checked = csv_tximp_acct_match_check_all (model);
1943 gtk_assistant_set_page_complete (csv_imp_asst, account_match_page,
1947 m_req_mapped_accts = all_checked;
1948 auto errs = tx_imp->verify(m_req_mapped_accts);
1949 gtk_label_set_text (GTK_LABEL(account_match_label), errs.c_str());
1953CsvImpTransAssist::acct_match_via_button ()
1955 auto model = gtk_tree_view_get_model (GTK_TREE_VIEW(account_match_view));
1956 auto selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(account_match_view));
1959 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1960 acct_match_select (model, &iter);
1966CsvImpTransAssist::acct_match_via_view_dblclick (GdkEventButton *event)
1969 if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1971 auto window = gtk_tree_view_get_bin_window (GTK_TREE_VIEW (account_match_view));
1972 if (event->window != window)
1977 if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (account_match_view), (gint) event->x, (gint) event->y,
1978 &path,
nullptr,
nullptr,
nullptr))
1980 DEBUG(
"event->x is %d and event->y is %d", (gint)event->x, (gint)event->y);
1982 auto model = gtk_tree_view_get_model (GTK_TREE_VIEW(account_match_view));
1984 if (gtk_tree_model_get_iter (model, &iter, path))
1985 acct_match_select (model, &iter);
1986 gtk_tree_path_free (path);
1999CsvImpTransAssist::assist_file_page_prepare ()
2002 if (!m_final_file_name.empty())
2003 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER(file_chooser),
2004 m_final_file_name.c_str());
2007 auto starting_dir = gnc_get_default_directory (GNC_PREFS_GROUP);
2010 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(file_chooser), starting_dir);
2011 g_free (starting_dir);
2016 gtk_assistant_set_page_complete (csv_imp_asst, account_match_page,
false);
2021CsvImpTransAssist::assist_preview_page_prepare ()
2023 auto go_back =
false;
2025 if (m_final_file_name != m_fc_file_name)
2027 tx_imp = std::unique_ptr<GncTxImport>(
new GncTxImport);
2032 tx_imp->file_format (GncImpFileFormat::CSV);
2033 tx_imp->load_file (m_fc_file_name);
2034 tx_imp->tokenize (
true);
2035 m_req_mapped_accts =
false;
2038 preview_populate_settings_combo();
2039 gtk_combo_box_set_active (settings_combo, 0);
2042 gtk_assistant_set_page_complete (csv_imp_asst, preview_page,
false);
2044 catch (std::ifstream::failure& e)
2047 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
"%s", e.what());
2050 catch (std::range_error &e)
2053 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
"%s",
_(e.what()));
2060 gtk_assistant_previous_page (csv_imp_asst);
2063 m_final_file_name = m_fc_file_name;
2067 g_idle_add ((GSourceFunc)csv_imp_preview_queue_rebuild_table,
this);
2071CsvImpTransAssist::assist_account_match_page_prepare ()
2075 acct_match_set_accounts ();
2078 auto store = gtk_tree_view_get_model (GTK_TREE_VIEW(account_match_view));
2079 csv_tximp_acct_match_load_mappings (store);
2082 gtk_widget_set_sensitive (account_match_view,
true);
2083 gtk_widget_set_sensitive (account_match_btn,
true);
2086 auto all_checked = csv_tximp_acct_match_check_all (store);
2087 gtk_assistant_set_page_complete (csv_imp_asst, account_match_page,
2091 m_req_mapped_accts = all_checked;
2092 auto text = tx_imp->verify (m_req_mapped_accts);
2093 gtk_label_set_text (GTK_LABEL(account_match_label), text.c_str());
2098CsvImpTransAssist::assist_doc_page_prepare ()
2100 if (!tx_imp->verify (
true).empty())
2106 gtk_assistant_set_current_page (csv_imp_asst, 2);
2110 gtk_assistant_commit (csv_imp_asst);
2115 new_book = gnc_new_book_option_display (GTK_WIDGET(csv_imp_asst));
2118 cancel_button = gtk_button_new_with_mnemonic (
_(
"_Cancel"));
2119 gtk_assistant_add_action_widget (csv_imp_asst, cancel_button);
2120 auto button_area = gtk_widget_get_parent (cancel_button);
2122 if (GTK_IS_HEADER_BAR(button_area))
2123 gtk_container_child_set (GTK_CONTAINER(button_area),
2125 "pack-type", GTK_PACK_START,
2128 g_signal_connect (cancel_button,
"clicked",
2129 G_CALLBACK(csv_tximp_assist_close_cb),
this);
2130 gtk_widget_show (GTK_WIDGET(cancel_button));
2135CsvImpTransAssist::assist_match_page_prepare ()
2140 tx_imp->create_transactions ();
2147 auto err_msg = std::string(err.what());
2148 auto err_msgs = err.errors();
2149 auto add_bullet_item = [](std::string& a, ErrMap::value_type& b)->std::string {
return std::move(a) +
"\n• " + b.second; };
2150 err_msg = std::accumulate (err_msgs.begin(), err_msgs.end(), std::move (err_msg), add_bullet_item);
2152 gnc_error_dialog (GTK_WINDOW (csv_imp_asst),
2153 _(
"An unexpected error has occurred while creating transactions. Please report this as a bug.\n\n"
2154 "Error message:\n%s"), err_msg.c_str());
2155 gtk_assistant_set_current_page (csv_imp_asst, 2);
2159 gtk_assistant_commit (csv_imp_asst);
2161 auto text = std::string(
"<span size=\"medium\" color=\"red\"><b>");
2162 text +=
_(
"Double click on rows to change, then click on Apply to Import");
2163 text +=
"</b></span>";
2164 gtk_label_set_markup (GTK_LABEL(match_label), text.c_str());
2167 help_button = gtk_button_new_with_mnemonic (
_(
"_Help"));
2168 gtk_assistant_add_action_widget (csv_imp_asst, help_button);
2169 auto button_area = gtk_widget_get_parent (help_button);
2171 if (GTK_IS_HEADER_BAR(button_area))
2173 gtk_container_child_set (GTK_CONTAINER(button_area),
2175 "pack-type", GTK_PACK_START,
2181 gtk_widget_set_halign (GTK_WIDGET(button_area), GTK_ALIGN_FILL);
2182 gtk_widget_set_hexpand (GTK_WIDGET(button_area), TRUE);
2183 gtk_box_set_child_packing (GTK_BOX(button_area), help_button,
2184 FALSE, FALSE, 0, GTK_PACK_START);
2186 g_signal_connect (help_button,
"clicked",
2189 gtk_widget_show (GTK_WIDGET(help_button));
2192 for (
auto trans_it : tx_imp->m_transactions)
2194 auto draft_trans = trans_it.second;
2195 if (draft_trans->trans)
2198 draft_trans->m_price ?
static_cast<gnc_numeric
>(*draft_trans->m_price) : gnc_numeric{0, 0},
2199 draft_trans->m_taction ? draft_trans->m_taction->c_str() : nullptr,
2200 draft_trans->m_tmemo ? draft_trans->m_tmemo->c_str() : nullptr,
2201 draft_trans->m_tamount ? static_cast<gnc_numeric>(*draft_trans->m_tamount) : gnc_numeric{0, 0},
2202 draft_trans->m_taccount ? *draft_trans->m_taccount : nullptr,
2203 draft_trans->m_trec_state ? *draft_trans->m_trec_state :
'\0',
2204 draft_trans->m_trec_date ? static_cast<
time64>(
GncDateTime(*draft_trans->m_trec_date, DayPart::neutral)) : 0,
2213 draft_trans->trans =
nullptr;
2222CsvImpTransAssist::assist_summary_page_prepare ()
2225 gtk_assistant_remove_action_widget (csv_imp_asst, help_button);
2226 gtk_assistant_remove_action_widget (csv_imp_asst, cancel_button);
2228 auto text = std::string(
"<span size=\"medium\"><b>");
2232 text += (bl::format (std::string{
_(
"The transactions were imported from file '{1}'.")}) % m_final_file_name).str();
2233 text +=
"</b></span>";
2235 catch (
const bl::conv::conversion_error& err)
2237 PERR(
"Transcoding error: %s", err.what());
2238 text +=
"The transactions were imported from the file.</b></span>";
2240 catch (
const bl::conv::invalid_charset_error& err)
2242 PERR(
"Invalid charset error: %s", err.what());
2243 text +=
"The transactions were imported from the file.</b></span>";
2245 gtk_label_set_markup (GTK_LABEL(summary_label), text.c_str());
2250CsvImpTransAssist::assist_prepare_cb (GtkWidget *page)
2252 if (page == file_page)
2253 assist_file_page_prepare ();
2254 else if (page == preview_page)
2255 assist_preview_page_prepare ();
2256 else if (page == account_match_page)
2257 assist_account_match_page_prepare ();
2258 else if (page == doc_page)
2259 assist_doc_page_prepare ();
2260 else if (page == match_page)
2261 assist_match_page_prepare ();
2262 else if (page == summary_page)
2263 assist_summary_page_prepare ();
2268CsvImpTransAssist::assist_finish ()
2271 if (!tx_imp->m_transactions.empty())
2279 auto local_csv_imp_gui = gnc_csv_importer_gui;
2280 gnc_csv_importer_gui =
nullptr;
2287CsvImpTransAssist::assist_compmgr_close ()
2289 gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(csv_imp_asst));
2294csv_tximp_close_handler (gpointer user_data)
2297 gnc_unregister_gui_component_by_data (ASSISTANT_CSV_IMPORT_TRANS_CM_CLASS, info);
2298 info->assist_compmgr_close();
2313 gnc_register_gui_component (ASSISTANT_CSV_IMPORT_TRANS_CM_CLASS,
2314 nullptr, csv_tximp_close_handler,
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...
void preview_update_separators(GtkWidget *widget)
Event handler for separator changes.
void preview_update_file_format()
Event handler for clicking one of the format type radio buttons.
void preview_update_encoding(const char *encoding)
Event handler for a new encoding.
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.
The actual TxImport class It's intended to use in the following sequence of actions:
const preset_vec_trans & get_import_presets_trans(void)
Creates a vector of CsvTransImpSettings which combines.
bool preset_is_reserved_name(const std::string &name)
Check whether name can be used as a preset name.
Class to import transactions from CSV or fixed width files.
Functions to load, save and get gui state.
Class to convert a csv file into vector of string vectors.
Class convert a file with fixed with delimited contents into vector of string vectors.
utility functions for the GnuCash UI
Utility functions for convert uri in separate components and back.
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...
const gchar * gnc_get_account_separator_string(void)
Returns the account separation character chosen by the user.
@ ACCT_TYPE_NONE
Not a type.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction's split list.
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,...
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
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.
void gnc_gen_trans_list_show_all(GNCImportMainMatcher *info)
Shows widgets.
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.
void gnc_gen_trans_assist_start(GNCImportMainMatcher *info)
This starts the import process for transaction from an assistant.
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.
void gnc_gen_trans_list_delete(GNCImportMainMatcher *info)
Deletes the given object.
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.
#define DEBUG(format, args...)
Print a debugging message.
#define PERR(format, args...)
Log a serious error.
#define PWARN(format, args...)
Log a warning.
gchar * gnc_uri_get_path(const gchar *uri)
Extracts the path part from a uri.
Generic and very flexible account matcher/picker.
Generic importer backend interface.
Transaction matcher main window.
void remove(void)
Remove the preset from the state file.
Exception that will be thrown whenever a parsing error is encountered.