38 #include <glib/gi18n.h> 42 #include "dialog-utils.h" 53 #include "gnc-component-manager.h" 55 #include "gnc-session.h" 59 #define GNC_PREFS_GROUP "dialogs.import.generic.transaction-list" 60 #define IMPORT_MAIN_MATCHER_CM_CLASS "transaction-matcher-dialog" 64 GtkWidget *main_widget;
66 GNCImportSettings *user_settings;
69 GNCTransactionProcessedCB transaction_processed_cb;
71 GNCImportPendingMatches *pending_matches;
72 GtkTreeViewColumn *account_column;
73 GtkTreeViewColumn *memo_column;
74 GtkWidget *show_account_column;
75 GtkWidget *show_matched_info;
76 GtkWidget *append_text;
77 GtkWidget *reconcile_after_close;
80 GSList* temp_trans_list;
81 GHashTable* acct_id_hash;
82 GSList* edited_accounts;
87 DOWNLOADED_COL_DATE_TXT = 0,
88 DOWNLOADED_COL_DATE_INT64,
89 DOWNLOADED_COL_ACCOUNT,
90 DOWNLOADED_COL_AMOUNT,
91 DOWNLOADED_COL_AMOUNT_DOUBLE,
92 DOWNLOADED_COL_DESCRIPTION,
94 DOWNLOADED_COL_ACTION_ADD,
95 DOWNLOADED_COL_ACTION_CLEAR,
96 DOWNLOADED_COL_ACTION_UPDATE,
97 DOWNLOADED_COL_ACTION_INFO,
98 DOWNLOADED_COL_ACTION_PIXBUF,
100 DOWNLOADED_COL_COLOR,
101 DOWNLOADED_COL_ENABLE,
105 #define CSS_INT_REQUIRED_CLASS "gnc-class-intervention-required" 106 #define CSS_INT_PROB_REQUIRED_CLASS "gnc-class-intervention-probably-required" 107 #define CSS_INT_NOT_REQUIRED_CLASS "gnc-class-intervention-not-required" 110 #define G_MOD_IMPORT_MATCHER "gnc.import.main-matcher" 112 static QofLogModule log_module = G_MOD_IMPORT_MATCHER;
114 void on_matcher_ok_clicked (GtkButton *button, GNCImportMainMatcher *info);
115 void on_matcher_cancel_clicked (GtkButton *button, gpointer user_data);
116 gboolean on_matcher_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data);
118 void on_matcher_help_close_clicked (GtkButton *button, gpointer user_data);
120 static void gnc_gen_trans_list_create_matches (GNCImportMainMatcher *gui);
123 static void gnc_gen_trans_assign_transfer_account (GtkTreeView *treeview,
125 gboolean is_selection,
128 GNCImportMainMatcher *info);
129 static void gnc_gen_trans_assign_transfer_account_to_selection_cb (GtkMenuItem *menuitem,
130 GNCImportMainMatcher *info);
131 static void gnc_gen_trans_view_popup_menu (GtkTreeView *treeview,
133 GNCImportMainMatcher *info,
134 gboolean show_edit_actions);
135 static gboolean gnc_gen_trans_onButtonPressed_cb (GtkTreeView *treeview,
137 GNCImportMainMatcher *info);
138 static gboolean gnc_gen_trans_onPopupMenu_cb (GtkTreeView *treeview,
139 GNCImportMainMatcher *info);
140 static void refresh_model_row (GNCImportMainMatcher *gui,
143 GNCImportTransInfo *info);
144 static gboolean query_tooltip_tree_view_cb (GtkWidget *widget, gint x, gint y,
145 gboolean keyboard_tip,
151 gboolean delete_hash (gpointer key, gpointer value, gpointer user_data)
154 g_hash_table_destroy (value);
159 update_all_balances (GNCImportMainMatcher *info)
161 for (GSList* iter = info->edited_accounts; iter; iter=iter->next)
166 g_slist_free (info->edited_accounts);
167 info->edited_accounts = NULL;
171 defer_bal_computation (GNCImportMainMatcher *info,
Account* acc)
176 info->edited_accounts = g_slist_prepend (info->edited_accounts, acc);
185 GNCImportTransInfo *trans_info;
190 model = gtk_tree_view_get_model (info->view);
191 if (gtk_tree_model_get_iter_first (model, &iter))
195 gtk_tree_model_get (model, &iter,
196 DOWNLOADED_COL_DATA, &trans_info,
199 if (info->transaction_processed_cb)
201 info->transaction_processed_cb (trans_info, FALSE,
205 while (gtk_tree_model_iter_next (model, &iter));
208 if (GTK_IS_DIALOG(info->main_widget))
210 gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(info->main_widget));
212 gnc_unregister_gui_component (info->id);
213 gtk_widget_destroy (GTK_WIDGET(info->main_widget));
219 info->temp_trans_list = NULL;
222 update_all_balances (info);
224 g_hash_table_foreach_remove (info->acct_id_hash, delete_hash, NULL);
225 info->acct_id_hash = NULL;
234 GNCImportTransInfo *trans_info;
236 model = gtk_tree_view_get_model (info->view);
238 return !gtk_tree_model_get_iter_first (model, &iter) && !info->temp_trans_list;
242 gnc_gen_trans_list_show_accounts_column (GNCImportMainMatcher *info)
246 GNCImportTransInfo *trans_info;
247 gboolean multiple_accounts = FALSE;
252 model = gtk_tree_view_get_model (info->view);
254 if (gtk_tree_model_iter_n_children (model, NULL) > 1)
257 valid = gtk_tree_model_get_iter_first (model, &iter);
261 gtk_tree_model_get (model, &iter, DOWNLOADED_COL_ACCOUNT, &account_name, -1);
263 valid = gtk_tree_model_iter_next (model, &iter);
267 gchar *test_account_name;
269 gtk_tree_model_get (model, &iter, DOWNLOADED_COL_ACCOUNT, &test_account_name, -1);
270 if (g_strcmp0 (account_name, test_account_name) != 0)
272 multiple_accounts = TRUE;
273 g_free (test_account_name);
276 valid = gtk_tree_model_iter_next (model, &iter);
277 g_free (test_account_name);
279 g_free (account_name);
282 if (multiple_accounts)
284 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(info->show_account_column), TRUE);
285 gtk_tree_view_expand_all (info->view);
289 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(info->show_account_column), FALSE);
290 gtk_tree_view_collapse_all (info->view);
297 get_top_trans_match_id (GList* match_list)
299 Transaction* trans = NULL;
301 if (!match_list || !match_list->data)
return NULL;
302 match_info = match_list->data;
303 trans = match_info->trans;
309 get_top_trans_match_score (GList* match_list)
312 if (!match_list || !match_list->data)
return 0;
313 match_info = match_list->data;
314 return match_info->probability;
318 get_trans_match_list (GtkTreeModel* model, GtkTreeIter* iter)
320 GNCImportTransInfo* transaction_info;
321 gtk_tree_model_get (model, iter,
322 DOWNLOADED_COL_DATA, &transaction_info,
327 static GNCImportTransInfo*
328 get_trans_info (GtkTreeModel* model, GtkTreeIter* iter)
330 GNCImportTransInfo* transaction_info;
331 gtk_tree_model_get (model, iter,
332 DOWNLOADED_COL_DATA, &transaction_info,
334 return transaction_info;
342 get_conflict_list (GtkTreeModel* model, GtkTreeIter import_iter,
GncGUID*
id, gint best_match)
344 GtkTreeIter iter = import_iter;
345 GNCImportTransInfo* best_import = get_trans_info (model, &import_iter);
346 GList* conflicts = g_list_prepend (NULL, best_import);
348 while (gtk_tree_model_iter_next (model, &iter))
350 gint match_score = 0;
351 GNCImportTransInfo* trans_info;
354 GList* register_iter = get_trans_match_list (model, &iter);
355 if (!register_iter || !register_iter->data)
358 id2 = *get_top_trans_match_id (register_iter);
363 match_score = get_top_trans_match_score (register_iter);
364 trans_info = get_trans_info (model, &iter);
365 conflicts = g_list_prepend (conflicts, trans_info);
367 if (match_score > best_match)
370 best_match = match_score;
371 best_import = trans_info;
376 conflicts = g_list_remove (conflicts, best_import);
381 remove_top_matches (GNCImportMainMatcher* gui, GtkTreeModel* model, GList* conflicts)
383 GList* iter = conflicts;
384 for (; iter && iter->data; iter=iter->next)
386 GNCImportTransInfo* trans_info = iter->data;
388 match_trans = g_list_remove (match_trans, match_trans->data);
392 g_list_free (conflicts);
396 resolve_conflicts (GNCImportMainMatcher *info)
398 GtkTreeModel* model = gtk_tree_view_get_model (info->view);
399 GtkTreeIter import_iter, best_import;
405 gboolean valid = gtk_tree_model_get_iter_first (model, &import_iter);
408 GList* conflicts = NULL;
410 GList* match_list = get_trans_match_list (model, &import_iter);
411 if (!match_list || !match_list->data)
413 valid = gtk_tree_model_iter_next (model, &import_iter);
418 id = *get_top_trans_match_id (match_list);
419 best_match = get_top_trans_match_score (match_list);
420 best_import = import_iter;
423 conflicts = get_conflict_list (model, import_iter, &
id, best_match);
427 remove_top_matches (info, model, conflicts);
430 valid = gtk_tree_model_get_iter_first (model, &import_iter);
433 valid = gtk_tree_model_iter_next (model, &import_iter);
439 valid = gtk_tree_model_get_iter_first (model, &import_iter);
442 refresh_model_row (info, model, &import_iter, get_trans_info (model, &import_iter));
443 valid = gtk_tree_model_iter_next (model, &import_iter);
450 GNCImportTransInfo* trans_info;
453 GSList* temp_trans_list;
459 temp_trans_list = info->temp_trans_list;
460 if (!temp_trans_list)
462 gnc_info_dialog (GTK_WINDOW (info->main_widget), _(
"No new transactions were found in this import."));
465 trans_info = temp_trans_list->data;
468 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (info->append_text),
471 gnc_gen_trans_list_create_matches (info);
472 resolve_conflicts (info);
473 gtk_widget_show_all (GTK_WIDGET(info->main_widget));
474 gnc_gen_trans_list_show_accounts_column (info);
478 on_matcher_ok_clicked (GtkButton *button, GNCImportMainMatcher *info)
482 GNCImportTransInfo *trans_info;
483 gboolean append_text = gtk_toggle_button_get_active ((GtkToggleButton*) info->append_text);
484 gboolean first_tran = TRUE;
485 gpointer user_data = info->user_data;
491 model = gtk_tree_view_get_model (info->view);
492 if (!gtk_tree_model_get_iter_first (model, &iter))
501 gnc_suspend_gui_refresh ();
504 gtk_tree_model_get (model, &iter,
505 DOWNLOADED_COL_DATA, &trans_info,
527 if (info->transaction_processed_cb)
529 info->transaction_processed_cb (trans_info, TRUE,
534 while (gtk_tree_model_iter_next (model, &iter));
539 gnc_resume_gui_refresh ();
545 on_matcher_cancel_clicked (GtkButton *button, gpointer user_data)
547 GNCImportMainMatcher *info = user_data;
552 on_matcher_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
554 GNCImportMainMatcher *info = data;
560 on_matcher_help_close_clicked (GtkButton *button, gpointer user_data)
562 GtkWidget *help_dialog = user_data;
564 gtk_widget_destroy (help_dialog);
570 GNCImportMainMatcher *info = user_data;
572 GtkWidget *help_dialog, *box;
573 gchar *int_required_class, *int_prob_required_class, *int_not_required_class;
574 gchar *class_extension = NULL;
576 builder = gtk_builder_new ();
577 gnc_builder_add_from_file (builder,
"dialog-import.glade",
"textbuffer2");
578 gnc_builder_add_from_file (builder,
"dialog-import.glade",
"textbuffer3");
579 gnc_builder_add_from_file (builder,
"dialog-import.glade",
"textbuffer4");
580 gnc_builder_add_from_file (builder,
"dialog-import.glade",
"textbuffer5");
581 gnc_builder_add_from_file (builder,
"dialog-import.glade",
"textbuffer1");
582 gnc_builder_add_from_file (builder,
"dialog-import.glade",
"matcher_help_dialog");
584 if (info->dark_theme == TRUE)
585 class_extension =
"-dark";
587 int_required_class = g_strconcat (CSS_INT_REQUIRED_CLASS, class_extension, NULL);
588 int_prob_required_class = g_strconcat (CSS_INT_PROB_REQUIRED_CLASS, class_extension, NULL);
589 int_not_required_class = g_strconcat (CSS_INT_NOT_REQUIRED_CLASS, class_extension, NULL);
591 box = GTK_WIDGET(gtk_builder_get_object (builder,
"intervention_required_box"));
592 gnc_widget_style_context_add_class (GTK_WIDGET(box), int_required_class);
594 box = GTK_WIDGET(gtk_builder_get_object (builder,
"intervention_probably_required_box"));
595 gnc_widget_style_context_add_class (GTK_WIDGET(box), int_prob_required_class);
597 box = GTK_WIDGET(gtk_builder_get_object (builder,
"intervention_not_required_box"));
598 gnc_widget_style_context_add_class (GTK_WIDGET(box), int_not_required_class);
600 help_dialog = GTK_WIDGET(gtk_builder_get_object (builder,
"matcher_help_dialog"));
601 gtk_window_set_transient_for (GTK_WINDOW(help_dialog), GTK_WINDOW(info->main_widget));
604 gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, help_dialog);
606 g_object_unref (G_OBJECT(builder));
608 g_free (int_required_class);
609 g_free (int_prob_required_class);
610 g_free (int_not_required_class);
612 gtk_widget_show (help_dialog);
616 run_account_picker_dialog (GNCImportMainMatcher *info,
619 GNCImportTransInfo *trans_info)
623 g_assert (trans_info);
630 _(
"Destination account for the auto-balance split."),
638 defer_bal_computation (info, new_acc);
643 run_match_dialog (GNCImportMainMatcher *info,
644 GNCImportTransInfo *trans_info)
647 trans_info, info->pending_matches);
651 gnc_gen_trans_add_toggled_cb (GtkCellRendererToggle *cell_renderer,
653 GNCImportMainMatcher *gui)
657 GNCImportTransInfo *trans_info;
660 model = gtk_tree_view_get_model (gui->view);
661 if (!gtk_tree_model_get_iter_from_string (model, &iter, path))
663 gtk_tree_model_get (model, &iter, DOWNLOADED_COL_DATA, &trans_info, -1);
674 refresh_model_row (gui, model, &iter, trans_info);
679 gnc_gen_trans_clear_toggled_cb (GtkCellRendererToggle *cell_renderer,
681 GNCImportMainMatcher *gui)
685 GNCImportTransInfo *trans_info;
688 model = gtk_tree_view_get_model (gui->view);
690 if (!gtk_tree_model_get_iter_from_string (model, &iter, path))
692 gtk_tree_model_get (model, &iter, DOWNLOADED_COL_DATA, &trans_info, -1);
703 refresh_model_row (gui, model, &iter, trans_info);
708 gnc_gen_trans_update_toggled_cb (GtkCellRendererToggle *cell_renderer,
710 GNCImportMainMatcher *gui)
714 GNCImportTransInfo *trans_info;
717 model = gtk_tree_view_get_model (gui->view);
719 if (!gtk_tree_model_get_iter_from_string (model, &iter, path))
721 gtk_tree_model_get (model, &iter, DOWNLOADED_COL_DATA, &trans_info, -1);
732 refresh_model_row (gui, model, &iter, trans_info);
737 gnc_gen_trans_assign_transfer_account (GtkTreeView *treeview,
739 gboolean is_selection,
742 GNCImportMainMatcher *info)
746 GNCImportTransInfo *trans_info;
749 gchar *path_str = gtk_tree_path_to_string (path);
753 DEBUG(
"first = %s", *first ?
"true" :
"false");
754 DEBUG(
"is_selection = %s", is_selection ?
"true" :
"false");
755 DEBUG(
"path = %s", path_str);
757 DEBUG(
"account passed in = %s", acct_str);
761 if (gtk_tree_path_get_depth (path) != 1)
764 model = gtk_tree_view_get_model (treeview);
765 if (gtk_tree_model_get_iter (model, &iter, path))
767 gtk_tree_model_get (model, &iter, DOWNLOADED_COL_DATA, &trans_info, -1);
783 _(
"Destination account for the auto-balance split."),
791 DEBUG(
"account selected = %s", acc_full_name);
792 g_free (acc_full_name);
797 defer_bal_computation (info, *new_acc);
801 case GNCImport_CLEAR:
802 case GNCImport_UPDATE:
803 if (*first && !is_selection)
804 run_match_dialog (info, trans_info);
809 PERR(
"InvalidGNCImportValue");
812 refresh_model_row (info, model, &iter, trans_info);
818 gnc_gen_trans_assign_transfer_account_to_selection_cb (GtkMenuItem *menuitem,
819 GNCImportMainMatcher *info)
821 GtkTreeView *treeview;
822 GtkTreeSelection *selection;
825 GNCImportTransInfo *trans_info;
827 GList *selected_rows, *l;
828 gboolean first, is_selection;
831 ENTER(
"assign_transfer_account_to_selection_cb");
832 treeview = GTK_TREE_VIEW(info->view);
833 model = gtk_tree_view_get_model (treeview);
834 selection = gtk_tree_view_get_selection (treeview);
835 selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
836 assigned_account = NULL;
840 DEBUG(
"Rows in selection = %i",
841 gtk_tree_selection_count_selected_rows (selection));
842 DEBUG(
"Entering loop over selection");
844 if (gtk_tree_selection_count_selected_rows (selection) > 0)
846 for (l = selected_rows; l != NULL; l = l->next)
848 gchar *path_str = gtk_tree_path_to_string (l->data);
849 GtkTreeRowReference *ref = gtk_tree_row_reference_new (model, l->data);
851 DEBUG(
"passing first = %s", first ?
"true" :
"false");
852 DEBUG(
"passing is_selection = %s", is_selection ?
"true" :
"false");
853 DEBUG(
"passing path = %s", path_str);
855 refs = g_list_prepend (refs, ref);
857 DEBUG(
"passing account value = %s", fullname);
859 gnc_gen_trans_assign_transfer_account (treeview,
860 &first, is_selection, l->data,
861 &assigned_account, info);
863 DEBUG(
"returned value of account = %s", fullname);
864 DEBUG(
"returned value of first = %s", first ?
"true" :
"false");
866 if (assigned_account == NULL)
871 g_list_free_full (selected_rows, (GDestroyNotify)gtk_tree_path_free);
874 for (l = refs; l != NULL; l = l->next)
876 GtkTreePath *path = gtk_tree_row_reference_get_path (l->data);
878 gtk_tree_selection_select_path (selection, path);
880 gtk_tree_path_free (path);
881 gtk_tree_row_reference_free (l->data);
896 gnc_gen_trans_edit_fields (GtkMenuItem *menuitem, GNCImportMainMatcher *info,
899 GtkTreeView *treeview;
900 GtkTreeSelection *selection;
902 GList *selected_rows;
905 GNCImportTransInfo *trans_info;
909 g_return_if_fail (info != NULL);
910 ENTER(
"assign_transfer_account_to_selection_cb");
912 treeview = GTK_TREE_VIEW(info->view);
913 model = gtk_tree_view_get_model (treeview);
914 store = GTK_TREE_STORE (model);
915 selection = gtk_tree_view_get_selection (treeview);
916 selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
920 LEAVE (
"No selected rows");
924 if (selected_rows->next)
926 LEAVE (
"User selected multiple rows, not supported");
930 g_return_if_fail (gtk_tree_model_get_iter (model, &iter,
931 selected_rows->data));
933 gtk_tree_model_get (model, &iter, DOWNLOADED_COL_DATA,
942 gnc_input_dialog_with_entry(info->main_widget,
"",
943 _(
"Enter new Description"),
945 if (!new_field)
break;
947 gtk_tree_store_set (store, &iter, DOWNLOADED_COL_DESCRIPTION,
957 gnc_input_dialog_with_entry(info->main_widget,
"",
960 if (!new_field)
break;
962 gtk_tree_store_set (store, &iter,
963 DOWNLOADED_COL_MEMO, new_field, -1);
970 gnc_input_dialog_with_entry(info->main_widget,
"",
971 _(
"Enter new Notes"),
973 if (!new_field)
break;
979 g_list_free_full (selected_rows, (GDestroyNotify)gtk_tree_path_free);
984 gnc_gen_trans_edit_description_cb (GtkMenuItem *menuitem, GNCImportMainMatcher *info)
986 gnc_gen_trans_edit_fields (menuitem, info, DESCRIPTION);
990 gnc_gen_trans_edit_memo_cb (GtkMenuItem *menuitem, GNCImportMainMatcher *info)
992 gnc_gen_trans_edit_fields (menuitem, info, MEMO);
996 gnc_gen_trans_edit_notes_cb (GtkMenuItem *menuitem, GNCImportMainMatcher *info)
998 gnc_gen_trans_edit_fields (menuitem, info, NOTES);
1002 gnc_gen_trans_row_activated_cb (GtkTreeView *treeview,
1004 GtkTreeViewColumn *column,
1005 GNCImportMainMatcher *info)
1008 gboolean first, is_selection;
1012 assigned_account = NULL;
1014 is_selection = FALSE;
1015 gnc_gen_trans_assign_transfer_account (treeview,
1016 &first, is_selection, path,
1017 &assigned_account, info);
1019 gtk_tree_selection_select_path (gtk_tree_view_get_selection (treeview), path);
1022 DEBUG(
"account returned = %s", namestr);
1027 static GNCImportAction
1028 get_action_for_path (GtkTreePath* path, GtkTreeModel *model)
1030 GNCImportTransInfo *trans_info;
1032 gtk_tree_model_get_iter (model, &iter, path);
1033 gtk_tree_model_get (model, &iter, DOWNLOADED_COL_DATA, &trans_info, -1);
1037 return GNCImport_INVALID_ACTION;
1042 gnc_gen_trans_row_changed_cb (GtkTreeSelection *selection,
1043 GNCImportMainMatcher *info)
1045 GtkTreeModel *model;
1047 GtkSelectionMode mode;
1050 mode = gtk_tree_selection_get_mode (selection);
1051 if (gtk_tree_selection_count_selected_rows (selection) >= 2)
1054 GList* list = gtk_tree_selection_get_selected_rows (selection, &model);
1055 for ( ; list; list=list->next)
1057 if (get_action_for_path (list->data, model) != GNCImport_ADD)
1058 gtk_tree_selection_unselect_path (selection, list->data);
1060 g_list_free_full (list, (GDestroyNotify)gtk_tree_path_free);
1065 case GTK_SELECTION_MULTIPLE:
1066 DEBUG(
"mode = GTK_SELECTION_MULTIPLE, no action");
1068 case GTK_SELECTION_NONE:
1069 DEBUG(
"mode = GTK_SELECTION_NONE, no action");
1071 case GTK_SELECTION_BROWSE:
1072 DEBUG(
"mode = GTK_SELECTION_BROWSE->default");
1073 case GTK_SELECTION_SINGLE:
1074 DEBUG(
"mode = GTK_SELECTION_SINGLE->default");
1076 DEBUG(
"mode = default unselect selected row");
1077 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1079 gtk_tree_selection_unselect_iter (selection, &iter);
1086 gnc_gen_trans_view_popup_menu (GtkTreeView *treeview,
1088 GNCImportMainMatcher *info,
1089 gboolean show_edit_actions)
1091 GtkWidget *menu, *menuitem;
1092 GdkEventButton *event_button;
1095 menu = gtk_menu_new();
1096 menuitem = gtk_menu_item_new_with_label (
1097 _(
"Assign a transfer account to the selection."));
1098 g_signal_connect (menuitem,
"activate",
1100 gnc_gen_trans_assign_transfer_account_to_selection_cb),
1102 DEBUG(
"Callback to assign destination account to selection connected");
1103 gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
1105 if (show_edit_actions)
1107 menuitem = gtk_menu_item_new_with_label (
1108 _(
"Edit description."));
1109 g_signal_connect (menuitem,
"activate",
1110 G_CALLBACK (gnc_gen_trans_edit_description_cb),
1112 DEBUG(
"Callback to edit description");
1113 gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
1115 menuitem = gtk_menu_item_new_with_label (
1117 g_signal_connect (menuitem,
"activate",
1118 G_CALLBACK (gnc_gen_trans_edit_memo_cb),
1120 DEBUG(
"Callback to edit memo");
1121 gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
1123 menuitem = gtk_menu_item_new_with_label (
1125 g_signal_connect (menuitem,
"activate",
1126 G_CALLBACK (gnc_gen_trans_edit_notes_cb),
1128 DEBUG(
"Callback to edit notes");
1129 gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
1131 gtk_widget_show_all (menu);
1132 event_button = (GdkEventButton *) event;
1134 gtk_menu_popup_at_pointer (GTK_MENU(menu), (GdkEvent*)event);
1140 gnc_gen_trans_onButtonPressed_cb (GtkTreeView *treeview,
1142 GNCImportMainMatcher *info)
1144 GdkEventButton *event_button;
1145 GtkTreeSelection *selection;
1147 g_return_val_if_fail (treeview != NULL, FALSE);
1148 g_return_val_if_fail (event != NULL, FALSE);
1150 if (event->type == GDK_BUTTON_PRESS)
1152 event_button = (GdkEventButton *) event;
1153 if (event_button->button == GDK_BUTTON_SECONDARY)
1156 DEBUG(
"Right mouseClick detected- popup the menu.");
1159 selection = gtk_tree_view_get_selection (treeview);
1160 count = gtk_tree_selection_count_selected_rows (selection);
1162 gnc_gen_trans_view_popup_menu (treeview, event, info, FALSE);
1166 GtkTreeModel *model;
1167 selected = gtk_tree_selection_get_selected_rows (selection, &model);
1168 if (get_action_for_path (selected->data, model) == GNCImport_ADD)
1169 gnc_gen_trans_view_popup_menu (treeview, event, info, TRUE);
1170 g_list_free_full (selected, (GDestroyNotify)gtk_tree_path_free);
1172 LEAVE(
"return TRUE");
1176 LEAVE(
"return FALSE");
1181 gnc_gen_trans_onPopupMenu_cb (GtkTreeView *treeview,
1182 GNCImportMainMatcher *info)
1184 GtkTreeSelection *selection;
1185 ENTER(
"onPopupMenu_cb");
1187 selection = gtk_tree_view_get_selection (treeview);
1188 if (gtk_tree_selection_count_selected_rows (selection) > 0)
1190 gnc_gen_trans_view_popup_menu (treeview, NULL, info, TRUE);
1198 static GtkTreeViewColumn *
1199 add_text_column (GtkTreeView *view,
const gchar *title,
int col_num, gboolean ellipsize)
1201 GtkCellRenderer *renderer;
1202 GtkTreeViewColumn *column;
1204 renderer = gtk_cell_renderer_text_new ();
1205 column = gtk_tree_view_column_new_with_attributes (title,
1208 "background", DOWNLOADED_COL_COLOR,
1212 g_object_set (renderer,
"ellipsize", PANGO_ELLIPSIZE_END, NULL);
1215 if (col_num == DOWNLOADED_COL_DATE_TXT)
1216 gtk_tree_view_column_set_sort_column_id(column, DOWNLOADED_COL_DATE_INT64);
1217 else if (col_num == DOWNLOADED_COL_AMOUNT)
1219 gtk_cell_renderer_set_alignment (renderer, 1.0, 0.5);
1220 gtk_cell_renderer_set_padding (renderer, 5, 0);
1221 gtk_tree_view_column_set_sort_column_id (column, DOWNLOADED_COL_AMOUNT_DOUBLE);
1224 gtk_tree_view_column_set_sort_column_id (column, col_num);
1226 g_object_set (G_OBJECT(column),
1227 "reorderable", TRUE,
1230 gtk_tree_view_append_column (view, column);
1234 static GtkTreeViewColumn *
1235 add_toggle_column (GtkTreeView *view,
const gchar *title,
int col_num,
1236 GCallback cb_fn, gpointer cb_arg)
1238 GtkCellRenderer *renderer;
1239 GtkTreeViewColumn *column;
1241 renderer = gtk_cell_renderer_toggle_new ();
1242 column = gtk_tree_view_column_new_with_attributes (title, renderer,
1244 "cell-background", DOWNLOADED_COL_COLOR,
1245 "activatable", DOWNLOADED_COL_ENABLE,
1246 "visible", DOWNLOADED_COL_ENABLE,
1248 gtk_tree_view_column_set_sort_column_id (column, col_num);
1249 g_object_set (G_OBJECT(column),
"reorderable", TRUE, NULL);
1250 g_signal_connect (renderer,
"toggled", cb_fn, cb_arg);
1251 gtk_tree_view_append_column (view, column);
1256 gnc_gen_trans_init_view (GNCImportMainMatcher *info,
1257 gboolean show_account,
1258 gboolean show_update)
1261 GtkTreeStore *store;
1262 GtkCellRenderer *renderer;
1263 GtkTreeViewColumn *column;
1264 GtkTreeSelection *selection;
1267 store = gtk_tree_store_new (NUM_DOWNLOADED_COLS, G_TYPE_STRING, G_TYPE_INT64,
1268 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_DOUBLE,
1269 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN,
1270 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_STRING,
1271 GDK_TYPE_PIXBUF, G_TYPE_POINTER, G_TYPE_STRING,
1273 gtk_tree_view_set_model (view, GTK_TREE_MODEL(store));
1274 g_object_unref (store);
1277 gtk_tree_view_set_reorderable (view, FALSE);
1280 add_text_column (view, _(
"Date"), DOWNLOADED_COL_DATE_TXT, FALSE);
1281 info->account_column = add_text_column (view, _(
"Account"), DOWNLOADED_COL_ACCOUNT, FALSE);
1282 gtk_tree_view_column_set_visible (info->account_column, show_account);
1283 add_text_column (view, _(
"Amount"), DOWNLOADED_COL_AMOUNT, FALSE);
1284 add_text_column (view, _(
"Description"), DOWNLOADED_COL_DESCRIPTION, FALSE);
1285 info->memo_column = add_text_column (view, _(
"Memo"), DOWNLOADED_COL_MEMO, TRUE);
1286 add_toggle_column (view, C_(
"Column header for 'Adding transaction'",
"A"),
1287 DOWNLOADED_COL_ACTION_ADD,
1288 G_CALLBACK(gnc_gen_trans_add_toggled_cb), info);
1289 column = add_toggle_column (view, C_(
"Column header for 'Updating plus Clearing transaction'",
"U+C"),
1290 DOWNLOADED_COL_ACTION_UPDATE,
1291 G_CALLBACK(gnc_gen_trans_update_toggled_cb), info);
1292 gtk_tree_view_column_set_visible (column, show_update);
1293 add_toggle_column (view, C_(
"Column header for 'Clearing transaction'",
"C"),
1294 DOWNLOADED_COL_ACTION_CLEAR,
1295 G_CALLBACK(gnc_gen_trans_clear_toggled_cb), info);
1298 renderer = gtk_cell_renderer_pixbuf_new ();
1299 g_object_set (renderer,
"xalign", 0.0, NULL);
1300 column = gtk_tree_view_column_new_with_attributes (_(
"Info"), renderer,
1301 "pixbuf", DOWNLOADED_COL_ACTION_PIXBUF,
1302 "cell-background", DOWNLOADED_COL_COLOR,
1305 gtk_tree_view_append_column (info->view, column);
1307 column = add_text_column (view, _(
"Additional Comments"), DOWNLOADED_COL_ACTION_INFO, FALSE);
1308 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1311 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(store),
1312 DOWNLOADED_COL_DATE_INT64,
1313 GTK_SORT_ASCENDING);
1314 selection = gtk_tree_view_get_selection (info->view);
1316 g_object_set (info->view,
"has-tooltip", TRUE, NULL);
1318 g_signal_connect (G_OBJECT(info->view),
"query-tooltip",
1319 G_CALLBACK(query_tooltip_tree_view_cb), info);
1320 g_signal_connect (info->view,
"row-activated",
1321 G_CALLBACK(gnc_gen_trans_row_activated_cb), info);
1322 g_signal_connect (selection,
"changed",
1323 G_CALLBACK(gnc_gen_trans_row_changed_cb), info);
1324 g_signal_connect (view,
"button-press-event",
1325 G_CALLBACK(gnc_gen_trans_onButtonPressed_cb), info);
1326 g_signal_connect (view,
"popup-menu",
1327 G_CALLBACK(gnc_gen_trans_onPopupMenu_cb), info);
1329 info->acct_id_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
1333 show_account_column_toggled_cb (GtkToggleButton *togglebutton,
1334 GNCImportMainMatcher *info)
1336 gtk_tree_view_column_set_visible (info->account_column,
1337 gtk_toggle_button_get_active (togglebutton));
1341 show_memo_column_toggled_cb (GtkToggleButton *togglebutton,
1342 GNCImportMainMatcher *info)
1344 gtk_tree_view_column_set_visible (info->memo_column,
1345 gtk_toggle_button_get_active (togglebutton));
1349 show_matched_info_toggled_cb (GtkToggleButton *togglebutton,
1350 GNCImportMainMatcher *info)
1352 if (gtk_toggle_button_get_active (togglebutton))
1354 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(info->show_account_column), TRUE);
1355 gtk_tree_view_expand_all (info->view);
1359 gtk_tree_view_column_set_visible (info->account_column,
1360 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(info->show_account_column)));
1361 gtk_tree_view_collapse_all (info->view);
1366 gnc_gen_trans_common_setup (GNCImportMainMatcher *info,
1368 GtkBuilder *builder,
1369 const gchar* heading,
1370 gboolean all_from_same_account,
1371 gint match_date_hardlimit)
1373 GtkStyleContext *stylectxt;
1375 GtkWidget *heading_label, *button;
1376 gboolean show_update;
1378 info->pending_matches = gnc_import_PendingMatches_new ();
1384 stylectxt = gtk_widget_get_style_context (GTK_WIDGET(parent));
1385 gtk_style_context_get_color (stylectxt, GTK_STATE_FLAG_NORMAL, &color);
1389 info->view = GTK_TREE_VIEW(gtk_builder_get_object (builder,
"downloaded_view"));
1390 g_assert (info->view != NULL);
1392 info->show_account_column = GTK_WIDGET(gtk_builder_get_object (builder,
"show_source_account_button"));
1393 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(info->show_account_column), all_from_same_account);
1394 g_signal_connect (G_OBJECT(info->show_account_column),
"toggled",
1395 G_CALLBACK(show_account_column_toggled_cb), info);
1397 button = GTK_WIDGET(gtk_builder_get_object (builder,
"show_memo_column_button"));
1398 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button), TRUE);
1399 g_signal_connect (G_OBJECT(button),
"toggled",
1400 G_CALLBACK(show_memo_column_toggled_cb), info);
1402 info->show_matched_info = GTK_WIDGET(gtk_builder_get_object (builder,
"show_matched_info_button"));
1403 g_signal_connect (G_OBJECT(info->show_matched_info),
"toggled",
1404 G_CALLBACK(show_matched_info_toggled_cb), info);
1406 info->append_text = GTK_WIDGET(gtk_builder_get_object (builder,
"append_desc_notes_button"));
1409 info->reconcile_after_close = GTK_WIDGET(gtk_builder_get_object (builder,
"reconcile_after_close_button"));
1412 gnc_gen_trans_init_view (info, all_from_same_account, show_update);
1413 heading_label = GTK_WIDGET(gtk_builder_get_object (builder,
"heading_label"));
1414 g_assert (heading_label != NULL);
1417 gtk_label_set_text (GTK_LABEL(heading_label), heading);
1419 info->transaction_processed_cb = NULL;
1422 gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, info);
1424 g_object_unref (G_OBJECT(builder));
1428 GNCImportMainMatcher *
1430 const gchar* heading,
1431 gboolean all_from_same_account,
1432 gint match_date_hardlimit,
1435 GNCImportMainMatcher *info;
1436 GtkBuilder *builder;
1437 GtkWidget *box, *pbox;
1439 info = g_new0 (GNCImportMainMatcher, 1);
1442 builder = gtk_builder_new ();
1443 gnc_builder_add_from_file (builder,
"dialog-import.glade",
"transaction_matcher_dialog");
1444 gnc_builder_add_from_file (builder,
"dialog-import.glade",
"transaction_matcher_content");
1446 info->main_widget = GTK_WIDGET(gtk_builder_get_object (builder,
"transaction_matcher_dialog"));
1447 g_assert (info->main_widget != NULL);
1450 pbox = GTK_WIDGET(gtk_builder_get_object (builder,
"transaction_matcher_vbox"));
1451 box = GTK_WIDGET(gtk_builder_get_object (builder,
"transaction_matcher_content"));
1452 gtk_box_pack_start (GTK_BOX(pbox), box, TRUE, TRUE, 0);
1455 gnc_gen_trans_common_setup (info, parent, builder, heading,
1456 all_from_same_account, match_date_hardlimit);
1459 gtk_window_set_transient_for (GTK_WINDOW(info->main_widget), GTK_WINDOW(parent));
1461 gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(info->main_widget), GTK_WINDOW(parent));
1464 gtk_widget_show_all (GTK_WIDGET(info->main_widget));
1467 info->id = gnc_register_gui_component (IMPORT_MAIN_MATCHER_CM_CLASS,
1472 gnc_gui_component_set_session (info->id, gnc_get_current_session());
1480 GNCImportMainMatcher *
1482 GtkWidget *assistant_page,
1483 const gchar* heading,
1484 gboolean all_from_same_account,
1485 gint match_date_hardlimit)
1487 GNCImportMainMatcher *info;
1488 GtkBuilder *builder;
1491 info = g_new0 (GNCImportMainMatcher, 1);
1492 info->main_widget = GTK_WIDGET(parent);
1495 builder = gtk_builder_new ();
1496 gnc_builder_add_from_file (builder,
"dialog-import.glade",
"transaction_matcher_content");
1499 box = GTK_WIDGET(gtk_builder_get_object (builder,
"transaction_matcher_content"));
1500 g_assert (box != NULL);
1501 gtk_box_pack_start (GTK_BOX(assistant_page), box, TRUE, TRUE, 6);
1504 gnc_gen_trans_common_setup (info, parent, builder, heading,
1505 all_from_same_account, match_date_hardlimit);
1513 on_matcher_ok_clicked (NULL, info);
1522 GNCTransactionProcessedCB trans_processed_cb,
1525 info->user_data = user_data;
1526 info->transaction_processed_cb = trans_processed_cb;
1535 result = gtk_dialog_run (GTK_DIALOG (info->main_widget));
1545 get_required_color (
const gchar *class_name)
1548 static gchar *strbuf = NULL;
1549 GtkWidget *label = gtk_label_new (
"Color");
1550 GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET(label));
1551 gtk_style_context_add_class (context, class_name);
1555 strbuf = gdk_rgba_to_string (&color);
1560 remove_child_row (GtkTreeModel *model, GtkTreeIter *iter)
1562 if (gtk_tree_model_iter_has_child (model, iter))
1565 gtk_tree_model_iter_nth_child (model, &child, iter, 0);
1566 gtk_tree_store_remove (GTK_TREE_STORE(model), &child);
1571 update_child_row (
GNCImportMatchInfo *sel_match, GtkTreeModel *model, GtkTreeIter *iter)
1573 GtkTreeStore *store;
1576 const gchar *ro_text;
1581 store = GTK_TREE_STORE(model);
1583 if (!gtk_tree_model_iter_has_child (model, iter))
1584 gtk_tree_store_append (GTK_TREE_STORE(model), &child, iter);
1586 gtk_tree_model_iter_nth_child (model, &child, iter, 0);
1588 gtk_tree_store_set (store, &child, DOWNLOADED_COL_DATE_TXT, text, -1);
1594 gtk_tree_store_set (store, &child, DOWNLOADED_COL_ACCOUNT, _(
"-- Split Transaction --"), -1);
1597 gnc_split_amount_print_info (sel_match->split, TRUE));
1599 gtk_tree_store_set (store, &child, DOWNLOADED_COL_AMOUNT, ro_text, -1);
1600 gtk_tree_store_set (store, &child, DOWNLOADED_COL_MEMO, memo, -1);
1601 gtk_tree_store_set (store, &child, DOWNLOADED_COL_DESCRIPTION, desc, -1);
1603 gtk_tree_store_set (store, &child, DOWNLOADED_COL_ENABLE, FALSE, -1);
1608 get_peer_acct_names (Split *split)
1610 GList *names = NULL, *accounts_seen = NULL;
1611 gchar *retval, *name;
1615 if ((n->data == split) ||
1617 (g_list_find (accounts_seen, account)))
1620 names = g_list_prepend (names, g_strdup_printf (
"\"%s\"", name));
1621 accounts_seen = g_list_prepend (accounts_seen, account);
1625 g_list_free_full (names, g_free);
1626 g_list_free (accounts_seen);
1631 refresh_model_row (GNCImportMainMatcher *gui,
1632 GtkTreeModel *model,
1634 GNCImportTransInfo *info)
1636 GtkTreeStore *store;
1637 GtkTreeSelection *selection;
1638 gchar *tmp, *imbalance, *text;
1639 const gchar *ro_text, *color = NULL;
1640 gchar *int_required_class, *int_prob_required_class, *int_not_required_class;
1641 gchar *class_extension = NULL;
1642 gboolean show_pixbuf = TRUE;
1651 store = GTK_TREE_STORE(model);
1652 gtk_tree_store_set (store, iter, DOWNLOADED_COL_DATA, info, -1);
1654 if (gui->dark_theme == TRUE)
1655 class_extension =
"-dark";
1657 int_required_class = g_strconcat (CSS_INT_REQUIRED_CLASS, class_extension, NULL);
1658 int_prob_required_class = g_strconcat (CSS_INT_PROB_REQUIRED_CLASS, class_extension, NULL);
1659 int_not_required_class = g_strconcat (CSS_INT_NOT_REQUIRED_CLASS, class_extension, NULL);
1662 gtk_tree_store_set (store, iter, DOWNLOADED_COL_ENABLE, TRUE, -1);
1668 gtk_tree_store_set (store, iter, DOWNLOADED_COL_ACCOUNT, ro_text, -1);
1673 gtk_tree_store_set (store, iter, DOWNLOADED_COL_DATE_TXT, text, -1);
1674 gtk_tree_store_set (store, iter, DOWNLOADED_COL_DATE_INT64, date, -1);
1679 ro_text =
xaccPrintAmount (amount, gnc_split_amount_print_info (split, TRUE));
1680 gtk_tree_store_set (store, iter, DOWNLOADED_COL_AMOUNT, ro_text, -1);
1685 gtk_tree_store_set (store, iter, DOWNLOADED_COL_DESCRIPTION, ro_text, -1);
1689 gtk_tree_store_set (store, iter, DOWNLOADED_COL_MEMO, ro_text, -1);
1694 ro_text = text = NULL;
1700 ro_text = _(
"New, already balanced");
1701 color = get_required_color (int_not_required_class);
1712 gnc_commodity_print_info
1717 color = get_required_color (int_not_required_class);
1726 g_strdup_printf (_(
"New, transfer %s to (manual) \"%s\""),
1734 g_strdup_printf (_(
"New, transfer %s to (auto) \"%s\""),
1742 color = get_required_color (int_prob_required_class);
1745 g_strdup_printf (_(
"New, UNBALANCED (need acct to transfer %s)!"),
1748 remove_child_row (model, iter);
1753 case GNCImport_CLEAR:
1759 gchar *full_names = get_peer_acct_names (sel_match->split);
1760 color = get_required_color (int_not_required_class);
1763 text = g_strdup_printf (_(
"Reconcile (manual) match to %s"),
1768 text = g_strdup_printf (_(
"Reconcile (auto) match to %s"),
1771 g_free (full_names);
1772 update_child_row (sel_match, model, iter);
1776 color = get_required_color (int_required_class);
1777 ro_text = _(
"Match missing!");
1778 show_pixbuf = FALSE;
1779 remove_child_row (model, iter);
1783 case GNCImport_UPDATE:
1789 gchar *full_names = get_peer_acct_names (sel_match->split);
1790 color = get_required_color (int_not_required_class);
1793 text = g_strdup_printf (_(
"Update and reconcile (manual) match to %s"),
1798 text = g_strdup_printf (_(
"Update and reconcile (auto) match to %s"),
1801 g_free (full_names);
1802 update_child_row (sel_match, model, iter);
1806 color = get_required_color (int_required_class);
1807 ro_text = _(
"Match missing!");
1808 show_pixbuf = FALSE;
1809 remove_child_row (model, iter);
1813 case GNCImport_SKIP:
1814 color = get_required_color (int_required_class);
1815 ro_text = _(
"Do not import (no action selected)");
1816 show_pixbuf = FALSE;
1817 remove_child_row (model, iter);
1821 ro_text =
"WRITEME, this is an unknown action";
1822 show_pixbuf = FALSE;
1826 gtk_tree_store_set (store, iter,
1827 DOWNLOADED_COL_COLOR, color,
1828 DOWNLOADED_COL_ACTION_INFO, ro_text ? ro_text : text,
1833 g_free (int_required_class);
1834 g_free (int_prob_required_class);
1835 g_free (int_not_required_class);
1838 gtk_tree_store_set (store, iter,
1839 DOWNLOADED_COL_ACTION_ADD,
1845 gtk_tree_store_set (store, iter, DOWNLOADED_COL_ACTION_PIXBUF, NULL, -1);
1848 gtk_tree_store_set (store, iter,
1849 DOWNLOADED_COL_ACTION_CLEAR,
1856 gtk_tree_store_set (store, iter,
1857 DOWNLOADED_COL_ACTION_PIXBUF,
1861 GTK_WIDGET(gui->view)),
1864 gtk_tree_store_set (store, iter, DOWNLOADED_COL_ACTION_PIXBUF, NULL, -1);
1867 gtk_tree_store_set (store, iter,
1868 DOWNLOADED_COL_ACTION_UPDATE,
1875 gtk_tree_store_set (store, iter,
1876 DOWNLOADED_COL_ACTION_PIXBUF,
1880 GTK_WIDGET(gui->view)),
1883 gtk_tree_store_set (store, iter, DOWNLOADED_COL_ACTION_PIXBUF, NULL, -1);
1887 if (gtk_tree_model_iter_has_child (model, iter))
1889 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(gui->show_matched_info)))
1891 GtkTreePath *path = gtk_tree_model_get_path (model, iter);
1893 gtk_tree_view_column_set_visible (gui->account_column, TRUE);
1894 gtk_tree_view_column_set_visible (gui->memo_column, TRUE);
1896 gtk_tree_view_expand_row (GTK_TREE_VIEW(gui->view), path, TRUE);
1897 gtk_tree_path_free (path);
1900 selection = gtk_tree_view_get_selection (gui->view);
1901 gtk_tree_selection_unselect_all (selection);
1908 Split* split = NULL;
1913 defer_bal_computation (gui, acc);
1921 gboolean reconcile_after_close,
1924 gtk_widget_set_visible (info->reconcile_after_close, reconcile_after_close);
1925 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (info->reconcile_after_close), active);
1931 return info->reconcile_after_close;
1937 GNCImportTransInfo * transaction_info = NULL;
1938 GtkTreeModel *model;
1951 gui->temp_trans_list = g_slist_prepend (gui->temp_trans_list, transaction_info);
1960 query_imported_transaction_accounts (GNCImportMainMatcher *gui)
1962 static const int secs_per_day = 86400;
1963 GList* query_results = NULL;
1964 GList* all_accounts = NULL;
1965 GList* retval = NULL;
1966 gint match_date_limit =
1968 time64 min_time=G_MAXINT64, max_time=0;
1969 time64 match_timelimit = match_date_limit * secs_per_day;
1970 Query *query = qof_query_create_for (GNC_ID_SPLIT);
1975 for (GSList* txn = gui->temp_trans_list; txn != NULL;
1976 txn = g_slist_next (txn))
1978 GNCImportTransInfo* txn_info = txn->data;
1983 all_accounts = g_list_prepend (all_accounts, txn_account);
1984 min_time = MIN(min_time, txn_time);
1985 max_time = MAX(max_time, txn_time);
1990 xaccQueryAddAccountMatch (query, all_accounts,
1992 xaccQueryAddDateMatchTT (query,
1993 TRUE, min_time - match_timelimit,
1994 TRUE, max_time + match_timelimit,
1997 g_list_free (all_accounts);
1998 retval = g_list_copy (query_results);
2008 create_hash_of_potential_matches (GList *candidate_txns,
2009 GHashTable *account_hash)
2011 for (GList* candidate = candidate_txns; candidate != NULL;
2012 candidate = g_list_next (candidate))
2016 if (gnc_import_split_has_online_id (candidate->data))
2022 split_list = g_hash_table_lookup (account_hash, split_account);
2023 g_hash_table_steal (account_hash, split_account);
2024 split_list = g_slist_prepend (split_list, candidate->data);
2025 g_hash_table_insert (account_hash, split_account, split_list);
2027 return account_hash;
2030 typedef struct _match_struct
2032 GNCImportTransInfo* transaction_info;
2033 gint display_threshold;
2034 gint date_threshold;
2035 gint date_not_threshold;
2036 double fuzzy_amount;
2043 s->display_threshold,
2045 s->date_not_threshold,
2055 perform_matching (GNCImportMainMatcher *gui, GHashTable *account_hash)
2057 GtkTreeModel* model = gtk_tree_view_get_model (gui->view);
2058 gint display_threshold =
2060 gint date_threshold =
2061 gnc_import_Settings_get_date_threshold (gui->user_settings);
2062 gint date_not_threshold =
2063 gnc_import_Settings_get_date_not_threshold (gui->user_settings);
2064 double fuzzy_amount =
2067 for (GSList *imported_txn = gui->temp_trans_list; imported_txn !=NULL;
2068 imported_txn = g_slist_next (imported_txn))
2072 gboolean match_selected_manually;
2073 GNCImportTransInfo* txn_info = imported_txn->data;
2075 match_struct s = {txn_info, display_threshold, date_threshold, date_not_threshold, fuzzy_amount};
2077 g_slist_foreach (g_hash_table_lookup (account_hash, importaccount),
2078 (GFunc) match_helper, &s);
2084 match_selected_manually =
2088 gnc_import_PendingMatches_add_match (gui->pending_matches,
2090 match_selected_manually);
2092 gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
2093 refresh_model_row (gui, model, &iter, txn_info);
2098 gnc_gen_trans_list_create_matches (GNCImportMainMatcher *gui)
2100 GHashTable* account_hash =
2101 g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
2102 (GDestroyNotify)g_slist_free);
2103 GList *candidate_txns;
2105 candidate_txns = query_imported_transaction_accounts (gui);
2107 create_hash_of_potential_matches (candidate_txns, account_hash);
2108 perform_matching (gui, account_hash);
2110 g_list_free (candidate_txns);
2111 g_hash_table_destroy (account_hash);
2119 return info->main_widget;
2126 return info->append_text;
2130 query_tooltip_tree_view_cb (GtkWidget *widget, gint x, gint y,
2131 gboolean keyboard_tip,
2132 GtkTooltip *tooltip,
2135 GtkTreeView *tree_view = GTK_TREE_VIEW(widget);
2136 GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
2137 GtkTreePath *path = NULL;
2138 GtkTreeViewColumn *column = NULL;
2140 gboolean show_tooltip = FALSE;
2142 gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, x, y, &x, &y);
2143 if (keyboard_tip || !gtk_tree_view_get_path_at_pos (tree_view, x, y, &path,
2144 &column, NULL, NULL))
2146 gtk_tree_path_free (path);
2151 if (gtk_tree_model_get_iter(model, &iter, path) && column)
2153 const gchar *tooltip_text = NULL;
2156 gint num_col = gtk_tree_view_column_get_sort_column_id (column);
2159 case DOWNLOADED_COL_DESCRIPTION:
2160 gtk_tree_model_get (model, &iter, DOWNLOADED_COL_DESCRIPTION, &tooltip_text, -1);
2162 case DOWNLOADED_COL_MEMO:
2163 gtk_tree_model_get (model, &iter, DOWNLOADED_COL_MEMO, &tooltip_text, -1);
2170 if (tooltip_text && *tooltip_text)
2172 show_tooltip = TRUE;
2173 gtk_tooltip_set_text (tooltip, tooltip_text);
2174 gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, column, NULL);
2178 gtk_tree_path_free (path);
2179 return show_tooltip;
void gnc_gen_trans_list_show_reconcile_after_close_button(GNCImportMainMatcher *info, gboolean reconcile_after_close, gboolean active)
Show and set the reconcile after close check button.
GNCImportMainMatcher * gnc_gen_trans_list_new(GtkWidget *parent, const gchar *heading, gboolean all_from_same_account, gint match_date_hardlimit, gboolean show_all)
Create a new generic transaction dialog window and return it.
GNCImportTransInfo * gnc_import_TransInfo_new(Transaction *trans, GncImportMatchMap *matchmap)
Create a new object of GNCImportTransInfo here.
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction's split list.
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
void split_find_match(GNCImportTransInfo *trans_info, Split *split, gint display_threshold, gint date_threshold, gint date_not_threshold, double fuzzy_amount_difference)
The transaction matching heuristics are here.
gchar * gnc_g_list_stringjoin(GList *list_of_strings, const gchar *sep)
Return a string joining a GList whose elements are gchar* strings.
void gnc_gen_trans_list_show_all(GNCImportMainMatcher *info)
Shows widgets.
utility functions for the GnuCash UI
GNCImportSettings * gnc_import_Settings_new(void)
Allocates a new GNCImportSettings object, and initialize it with the appropriate user prefs...
GdkPixbuf * gen_probability_pixbuf(gint score_original, GNCImportSettings *settings, GtkWidget *widget)
This function generates a new pixmap representing a match score.
void gnc_import_TransInfo_delete(GNCImportTransInfo *info)
Destructor.
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
void xaccTransSetNotes(Transaction *trans, const char *notes)
Sets the transaction Notes.
gint gnc_import_Settings_get_display_threshold(GNCImportSettings *settings)
Return the selected threshold.
gboolean xaccAccountGetAppendText(const Account *acc)
Get the "import-append-text" flag for an account.
void gnc_import_TransInfo_set_ref_id(GNCImportTransInfo *info, guint32 ref_id)
Set the reference id for this TransInfo.
Tracking container for pending match status.
void gnc_import_Settings_delete(GNCImportSettings *settings)
Destructor.
#define DEBUG(format, args...)
Print a debugging message.
Generic importer backend interface.
const char * xaccPrintAmount(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
globally unique ID User API
Split * gnc_import_TransInfo_get_fsplit(const GNCImportTransInfo *info)
Returns the first split of the transaction of this TransInfo.
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
Account * gnc_import_select_account(GtkWidget *parent, const gchar *account_online_id_value, gboolean auto_create, 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 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.
Transaction * gnc_import_TransInfo_get_trans(const GNCImportTransInfo *info)
Returns the transaction of this TransInfo.
gboolean gnc_is_dark_theme(GdkRGBA *fg_color)
Return whether the current gtk theme is a dark one.
gint gnc_import_Settings_get_match_date_hardlimit(const GNCImportSettings *s)
Returns the hard-limiting number of days that a matching split may differ.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
void gnc_gen_trans_list_add_tp_cb(GNCImportMainMatcher *info, GNCTransactionProcessedCB trans_processed_cb, gpointer user_data)
Add transaction processed callback to the transaction importer.
Generic and very flexible account matcher/picker.
GtkWidget * gnc_gen_trans_list_append_text_widget(GNCImportMainMatcher *info)
Returns the append_text widget of this dialog.
void gnc_import_TransInfo_set_destacc(GNCImportTransInfo *info, Account *acc, gboolean selected_manually)
Set the 'other account' of this transaction (used for auto-balance if needed).
Import preference handling.
These expect a single object and expect the QofAccessFunc returns GncGUID*.
#define PERR(format, args...)
Log a serious error.
#define ENTER(format, args...)
Print a function entry debugging message.
void gnc_style_context_get_background_color(GtkStyleContext *context, GtkStateFlags state, GdkRGBA *color)
Wrapper to get the background color of a widget for a given state.
void gnc_gen_trans_list_add_trans(GNCImportMainMatcher *gui, Transaction *trans)
Add a newly imported Transaction to the Transaction Importer.
void gnc_import_TransInfo_init_matches(GNCImportTransInfo *trans_info, GNCImportSettings *settings)
Iterates through all splits of the originating account of trans_info.
gboolean gnc_gen_trans_list_run(GNCImportMainMatcher *info)
Run this dialog and return only after the user pressed Ok, Cancel, or closed the window.
GNCImportAction gnc_import_TransInfo_get_action(const GNCImportTransInfo *info)
Returns the currently selected action for this TransInfo.
Account used to record multiple commodity transactions.
const char * xaccTransGetNotes(const Transaction *trans)
Gets the transaction Notes.
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
gchar * gnc_get_account_name_for_register(const Account *account)
Get either the full name of the account or the simple name, depending on the configuration parameter ...
double gnc_numeric_to_double(gnc_numeric in)
Convert numeric to floating-point value.
char * qof_print_date(time64 secs)
Convenience; calls through to qof_print_date_dmy_buff().
gint gnc_import_MatchInfo_get_probability(const GNCImportMatchInfo *info)
Get the probability (confidence level) of this MatchInfo.
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...
void qof_query_destroy(QofQuery *query)
Frees the resources associate with a Query object.
GtkWidget * gnc_gen_trans_list_get_reconcile_after_close_button(GNCImportMainMatcher *info)
Returns the reconcile after close check button.
The transaction match picker dialog interface.
GtkWidget * gnc_gen_trans_list_widget(GNCImportMainMatcher *info)
Returns the widget of this dialog.
gnc_numeric xaccTransGetImbalanceValue(const Transaction *trans)
The xaccTransGetImbalanceValue() method returns the total value of the transaction.
gboolean guid_equal(const GncGUID *guid_1, const GncGUID *guid_2)
Given two GUIDs, return TRUE if they are non-NULL and equal.
void gnc_gen_trans_assist_start(GNCImportMainMatcher *info)
This starts the import process for transaction from an assistant.
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
void qof_query_set_book(QofQuery *query, QofBook *book)
Set the book to be searched.
gboolean gnc_gen_trans_list_empty(GNCImportMainMatcher *info)
Checks whether there are no transactions to match.
gboolean gnc_import_process_trans_item(GncImportMatchMap *matchmap, GNCImportTransInfo *trans_info)
/brief – Processes one match according to its selected action.
void gnc_import_TransInfo_set_action(GNCImportTransInfo *info, GNCImportAction action)
Set the action for this TransInfo.
void gnc_import_Settings_set_match_date_hardlimit(GNCImportSettings *s, gint m)
void xaccAccountRecomputeBalance(Account *acc)
The following recompute the partial balances (stored with the transaction) and the total balance...
gboolean gnc_import_exists_online_id(Transaction *trans, GHashTable *acct_id_hash)
Checks whether the given transaction's online_id already exists in its parent account.
double gnc_import_Settings_get_fuzzy_amount(GNCImportSettings *settings)
Return the allowed amount range for fuzzy amount matching.
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
gboolean gnc_account_get_defer_bal_computation(Account *acc)
Get the account's flag for deferred balance computation.
void gnc_import_TransInfo_set_append_text(GNCImportTransInfo *info, gboolean append_text)
Set the append_text for this TransInfo.
All type declarations for the whole Gnucash engine.
void xaccAccountSetAppendText(Account *acc, gboolean val)
Set the "import-append-text" flag for an account.
#define xaccTransGetGUID(X)
void gnc_import_TransInfo_set_match_list(GNCImportTransInfo *info, GList *match_list)
Assigns the list of possible matches.
void gnc_gen_trans_list_add_trans_with_ref_id(GNCImportMainMatcher *gui, Transaction *trans, guint32 ref_id)
Add a newly imported Transaction to the Transaction Importer and provide an external reference id for...
gboolean gnc_import_Settings_get_action_update_enabled(GNCImportSettings *settings)
Return the selected action is enable state.
gboolean gnc_import_TransInfo_get_match_selected_manually(const GNCImportTransInfo *info)
Returns if the currently selected match was selected by the user.
GList * qof_query_run(QofQuery *query)
Perform the query, return the results.
GNCImportMainMatcher * gnc_gen_trans_assist_new(GtkWidget *parent, GtkWidget *assistant_page, const gchar *heading, gboolean all_from_same_account, gint match_date_hardlimit)
Add the Transaction matcher to an existing page of an assistant.
void gnc_import_match_picker_run_and_close(GtkWidget *parent, GNCImportTransInfo *transaction_info, GNCImportPendingMatches *pending_matches)
Run a match_picker dialog so that the selected-MatchInfo in the given trans_info is updated according...
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
void gnc_gen_trans_list_delete(GNCImportMainMatcher *info)
Deletes the given object.
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits...
#define LEAVE(format, args...)
Print a function exit debugging message.
Account * gnc_import_TransInfo_get_destacc(const GNCImportTransInfo *info)
Returns the 'other account' of this transaction.
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
GList * gnc_import_TransInfo_get_match_list(const GNCImportTransInfo *info)
Returns the stored list of possible matches.
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
GNCImportMatchInfo * gnc_import_TransInfo_get_selected_match(const GNCImportTransInfo *info)
Returns the currently selected match in this TransInfo.
void gnc_account_set_defer_bal_computation(Account *acc, gboolean defer)
Set the defer balance flag.
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
The type used to store guids in C.
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
gboolean gnc_import_Settings_get_action_skip_enabled(GNCImportSettings *settings)
Return the selected action is enable state.
gboolean gnc_import_TransInfo_is_balanced(const GNCImportTransInfo *info)
Returns if the transaction stored in the TransInfo is currently balanced.
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
gboolean gnc_import_TransInfo_get_destacc_selected_manually(const GNCImportTransInfo *info)
Returns if the currently selected destination account for auto-matching was selected by the user...