GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
import-main-matcher.c
1 /********************************************************************\
2  * import-main-matcher.c - Transaction matcher main window *
3  * *
4  * Copyright (C) 2002 Benoit GrĂ©goire <[email protected]> *
5  * Copyright (C) 2002 Christian Stimming *
6  * Copyright (c) 2006 David Hampton <[email protected]> *
7  * Copyright (C) 2012 Robert Fewell *
8  * *
9  * This program is free software; you can redistribute it and/or *
10  * modify it under the terms of the GNU General Public License as *
11  * published by the Free Software Foundation; either version 2 of *
12  * the License, or (at your option) any later version. *
13  * *
14  * This program is distributed in the hope that it will be useful, *
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17  * GNU General Public License for more details. *
18  * *
19  * You should have received a copy of the GNU General Public License*
20  * along with this program; if not, contact: *
21  * *
22  * Free Software Foundation Voice: +1-617-542-5942 *
23  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
24  * Boston, MA 02110-1301, USA [email protected] *
25 \********************************************************************/
35 #include "config.h"
36 
37 #include <gtk/gtk.h>
38 #include <glib/gi18n.h>
39 
40 #include "import-main-matcher.h"
41 
42 #include "dialog-utils.h"
43 #include "gnc-ui.h"
44 #include "gnc-ui-util.h"
45 #include "gnc-engine.h"
46 #include "import-settings.h"
47 #include "import-match-picker.h"
48 #include "import-backend.h"
49 #include "import-account-matcher.h"
50 #include "app-utils/gnc-component-manager.h"
51 
52 #define GNC_PREFS_GROUP "dialogs.import.generic.transaction-list"
53 
55 {
56  GtkWidget *dialog;
57  GtkWidget *assistant;
58  GtkTreeView *view;
59  GNCImportSettings *user_settings;
60  GdkColor color_back_red;
61  GdkColor color_back_green;
62  GdkColor color_back_yellow;
63  int selected_row;
64  GNCTransactionProcessedCB transaction_processed_cb;
65  gpointer user_data;
66 };
67 
68 enum downloaded_cols
69 {
70  DOWNLOADED_COL_DATE = 0,
71  DOWNLOADED_COL_ACCOUNT,
72  DOWNLOADED_COL_AMOUNT,
73  DOWNLOADED_COL_DESCRIPTION,
74  DOWNLOADED_COL_MEMO,
75  DOWNLOADED_COL_ACTION_ADD,
76  DOWNLOADED_COL_ACTION_CLEAR,
77  DOWNLOADED_COL_ACTION_UPDATE,
78  DOWNLOADED_COL_ACTION_INFO,
79  DOWNLOADED_COL_ACTION_PIXBUF,
80  DOWNLOADED_COL_DATA,
81  DOWNLOADED_COL_COLOR,
82  NUM_DOWNLOADED_COLS
83 };
84 
85 #define COLOR_RED "brown1"
86 #define COLOR_YELLOW "gold"
87 #define COLOR_GREEN "DarkSeaGreen1"
88 
89 static QofLogModule log_module = GNC_MOD_IMPORT;
90 
91 void on_matcher_ok_clicked (GtkButton *button, GNCImportMainMatcher *info);
92 void on_matcher_cancel_clicked (GtkButton *button, gpointer user_data);
93 void on_matcher_help_clicked (GtkButton *button, gpointer user_data);
94 void on_matcher_help_close_clicked (GtkButton *button, gpointer user_data);
95 
96 /* Local prototypes */
97 static void
98 automatch_store_transactions(GNCImportMainMatcher *info,
99  GtkTreeModel *model,
100  GtkTreeIter *iter,
101  GNCImportTransInfo *trans_info);
102 static void
103 refresh_model_row(GNCImportMainMatcher *gui, GtkTreeModel *model,
104  GtkTreeIter *iter, GNCImportTransInfo *info);
105 
107 {
108  GtkTreeModel *model;
109  GtkTreeIter iter;
110  GNCImportTransInfo *trans_info;
111 
112  if (info == NULL)
113  return;
114 
115  model = gtk_tree_view_get_model(info->view);
116  if (gtk_tree_model_get_iter_first(model, &iter))
117  {
118  do
119  {
120  gtk_tree_model_get(model, &iter,
121  DOWNLOADED_COL_DATA, &trans_info,
122  -1);
123 
124  if (info->transaction_processed_cb)
125  {
126  info->transaction_processed_cb(trans_info,
127  FALSE,
128  info->user_data);
129  }
130 
131  gnc_import_TransInfo_delete(trans_info);
132  }
133  while (gtk_tree_model_iter_next (model, &iter));
134  }
135 
136 
137  if (!(info->dialog == NULL))
138  {
139  gnc_save_window_size(GNC_PREFS_GROUP, GTK_WINDOW(info->dialog));
140  gnc_import_Settings_delete (info->user_settings);
141  gtk_widget_destroy (GTK_WIDGET (info->dialog));
142  }
143  else
144  gnc_import_Settings_delete (info->user_settings);
145  g_free (info);
146 }
147 
148 void
149 on_matcher_ok_clicked (GtkButton *button,
150  GNCImportMainMatcher *info)
151 {
152  GtkTreeModel *model;
153  GtkTreePath *path;
154  GtkTreeRowReference *ref;
155  GtkTreeIter iter;
156  GNCImportTransInfo *trans_info;
157  GSList *refs_list = NULL;
158 
159  g_assert (info);
160 
161  /* DEBUG ("Begin") */
162 
163  model = gtk_tree_view_get_model(info->view);
164  if (!gtk_tree_model_get_iter_first(model, &iter))
165  return;
166 
167  /* Don't run any queries and/or split sorts while processing the matcher
168  results. */
169  gnc_suspend_gui_refresh();
170 
171  do
172  {
173  gtk_tree_model_get(model, &iter,
174  DOWNLOADED_COL_DATA, &trans_info,
175  -1);
176 
177  if (gnc_import_process_trans_item(NULL, trans_info))
178  {
179  path = gtk_tree_model_get_path(model, &iter);
180  ref = gtk_tree_row_reference_new(model, path);
181  refs_list = g_slist_append(refs_list, ref);
182  gtk_tree_path_free(path);
183 
184  if (info->transaction_processed_cb)
185  {
186  info->transaction_processed_cb(trans_info,
187  TRUE,
188  info->user_data);
189  }
190  }
191  }
192  while (gtk_tree_model_iter_next (model, &iter));
193 
194  /* Allow GUI refresh again. */
195  gnc_resume_gui_refresh();
196 
198  /* DEBUG ("End") */
199 }
200 
201 void
202 on_matcher_cancel_clicked (GtkButton *button, gpointer user_data)
203 {
204  GNCImportMainMatcher *info = user_data;
206 }
207 
208 void
209 on_matcher_help_close_clicked (GtkButton *button, gpointer user_data)
210 {
211  GtkWidget *help_dialog = user_data;
212 
213  gtk_widget_destroy(help_dialog);
214 }
215 
216 void
217 on_matcher_help_clicked (GtkButton *button, gpointer user_data)
218 {
219  GNCImportMainMatcher *info = user_data;
220  GtkBuilder *builder;
221  GtkWidget *help_dialog, *box;
222 
223  builder = gtk_builder_new();
224  gnc_builder_add_from_file (builder, "dialog-import.glade", "textbuffer2");
225  gnc_builder_add_from_file (builder, "dialog-import.glade", "textbuffer3");
226  gnc_builder_add_from_file (builder, "dialog-import.glade", "textbuffer4");
227  gnc_builder_add_from_file (builder, "dialog-import.glade", "textbuffer5");
228  gnc_builder_add_from_file (builder, "dialog-import.glade", "matcher_help");
229 
230  box = GTK_WIDGET(gtk_builder_get_object (builder, "red"));
231  gtk_widget_modify_bg(box, GTK_STATE_NORMAL, &info->color_back_red);
232  box = GTK_WIDGET(gtk_builder_get_object (builder, "yellow"));
233  gtk_widget_modify_bg(box, GTK_STATE_NORMAL, &info->color_back_yellow);
234  box = GTK_WIDGET(gtk_builder_get_object (builder, "green"));
235  gtk_widget_modify_bg(box, GTK_STATE_NORMAL, &info->color_back_green);
236 
237  help_dialog = GTK_WIDGET(gtk_builder_get_object (builder, "matcher_help"));
238  gtk_window_set_transient_for(GTK_WINDOW(help_dialog),
239  GTK_WINDOW(info->dialog));
240 
241  /* Connect the signals */
242  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, help_dialog);
243 
244  g_object_unref(G_OBJECT(builder));
245 
246  gtk_widget_show(help_dialog);
247 }
248 
249 static void
250 run_account_picker_dialog (GNCImportMainMatcher *info,
251  GtkTreeModel *model,
252  GtkTreeIter *iter,
253  GNCImportTransInfo *trans_info)
254 {
255  Account *old_acc, *new_acc;
256  gboolean ok_pressed;
257  g_assert (trans_info);
258  old_acc = gnc_import_TransInfo_get_destacc (trans_info);
259  new_acc = gnc_import_select_account(info->dialog,
260  NULL,
261  TRUE,
262  _("Destination account for the auto-balance split."),
265  old_acc,
266  &ok_pressed);
267  if (ok_pressed)
268  {
270  new_acc,
271  TRUE);
272 
273  /* Iterate through the transactions in a given clist to auto match them */
274  automatch_store_transactions(info, model, iter, trans_info);
275  }
276 }
277 
278 static void
279 run_match_dialog (GNCImportMainMatcher *info,
280  GNCImportTransInfo *trans_info)
281 {
283 }
284 
285 static void
286 gnc_gen_trans_add_toggled_cb (GtkCellRendererToggle *cell_renderer,
287  gchar *path,
289 {
290  GtkTreeModel *model;
291  GtkTreeIter iter;
292  GNCImportTransInfo *trans_info;
293 
294  model = gtk_tree_view_get_model(gui->view);
295  if (!gtk_tree_model_get_iter_from_string(model, &iter, path))
296  return;
297  gtk_tree_model_get(model, &iter, DOWNLOADED_COL_DATA, &trans_info, -1);
298 
299  if ( gnc_import_TransInfo_get_action(trans_info) == GNCImport_ADD
300  && gnc_import_Settings_get_action_skip_enabled (gui->user_settings) == TRUE)
301  {
302  gnc_import_TransInfo_set_action(trans_info, GNCImport_SKIP);
303  }
304  else
305  {
306  gnc_import_TransInfo_set_action(trans_info, GNCImport_ADD);
307  }
308  refresh_model_row(gui, model, &iter, trans_info);
309 }
310 
311 static void
312 gnc_gen_trans_clear_toggled_cb (GtkCellRendererToggle *cell_renderer,
313  gchar *path,
315 {
316  GtkTreeModel *model;
317  GtkTreeIter iter;
318  GNCImportTransInfo *trans_info;
319 
320  model = gtk_tree_view_get_model(gui->view);
321  if (!gtk_tree_model_get_iter_from_string(model, &iter, path))
322  return;
323  gtk_tree_model_get(model, &iter, DOWNLOADED_COL_DATA, &trans_info, -1);
324 
325  if ( gnc_import_TransInfo_get_action(trans_info) == GNCImport_CLEAR
326  && gnc_import_Settings_get_action_skip_enabled (gui->user_settings) == TRUE)
327  {
328  gnc_import_TransInfo_set_action(trans_info, GNCImport_SKIP);
329  }
330  else
331  {
332  gnc_import_TransInfo_set_action(trans_info, GNCImport_CLEAR);
333  }
334  refresh_model_row(gui, model, &iter, trans_info);
335 }
336 
337 static void
338 gnc_gen_trans_update_toggled_cb (GtkCellRendererToggle *cell_renderer,
339  gchar *path,
341 {
342  GtkTreeModel *model;
343  GtkTreeIter iter;
344  GNCImportTransInfo *trans_info;
345 
346  model = gtk_tree_view_get_model(gui->view);
347  if (!gtk_tree_model_get_iter_from_string(model, &iter, path))
348  return;
349  gtk_tree_model_get(model, &iter, DOWNLOADED_COL_DATA, &trans_info, -1);
350 
351  if ( gnc_import_TransInfo_get_action(trans_info) == GNCImport_UPDATE
352  && gnc_import_Settings_get_action_skip_enabled (gui->user_settings) == TRUE)
353  {
354  gnc_import_TransInfo_set_action(trans_info, GNCImport_SKIP);
355  }
356  else
357  {
358  gnc_import_TransInfo_set_action(trans_info, GNCImport_UPDATE);
359  }
360  refresh_model_row(gui, model, &iter, trans_info);
361 }
362 
363 static void
364 gnc_gen_trans_row_activated_cb (GtkTreeView *view,
365  GtkTreePath *path,
366  GtkTreeViewColumn *column,
368 {
369  GtkTreeModel *model;
370  GtkTreeIter iter;
371  GNCImportTransInfo *trans_info;
372 
373  model = gtk_tree_view_get_model(gui->view);
374  if (!gtk_tree_model_get_iter(model, &iter, path))
375  return;
376  gtk_tree_model_get(model, &iter, DOWNLOADED_COL_DATA, &trans_info, -1);
377 
378  switch (gnc_import_TransInfo_get_action (trans_info))
379  {
380  case GNCImport_ADD:
381  if (gnc_import_TransInfo_is_balanced(trans_info) == FALSE)
382  {
383  run_account_picker_dialog (gui, model, &iter, trans_info);
384  }
385  break;
386  case GNCImport_CLEAR:
387  case GNCImport_UPDATE:
388  run_match_dialog (gui, trans_info);
389  break;
390  case GNCImport_SKIP:
391  /*The information displayed is only informative, until you select an action*/
392  break;
393  default:
394  PERR("I don't know what to do! (Yet...)");
395  break;
396  }
397  refresh_model_row(gui, model, &iter, trans_info);
398 }
399 
400 static void
401 gnc_gen_trans_row_changed_cb (GtkTreeSelection *selection,
403 {
404  GtkTreeModel *model;
405  GtkTreeIter iter;
406 
407  if (!gtk_tree_selection_get_selected(selection, &model, &iter))
408  return;
409  gtk_tree_selection_unselect_iter(selection, &iter);
410 }
411 
412 static GtkTreeViewColumn *
413 add_text_column(GtkTreeView *view, const gchar *title, int col_num)
414 {
415  GtkCellRenderer *renderer;
416  GtkTreeViewColumn *column;
417 
418  renderer = gtk_cell_renderer_text_new();
419  g_object_set(G_OBJECT(renderer),
420  "foreground", "black",
421  "foreground-set", TRUE,
422  NULL);
423  column = gtk_tree_view_column_new_with_attributes
424  (title, renderer,
425  "text", col_num,
426  "background", DOWNLOADED_COL_COLOR,
427  NULL);
428  gtk_tree_view_column_set_sort_column_id(column, col_num);
429  g_object_set(G_OBJECT(column),
430  "reorderable", TRUE,
431  "resizable", TRUE,
432  NULL);
433  gtk_tree_view_append_column(view, column);
434  return column;
435 }
436 
437 static GtkTreeViewColumn *
438 add_toggle_column(GtkTreeView *view, const gchar *title, int col_num,
439  GCallback cb_fn, gpointer cb_arg)
440 {
441  GtkCellRenderer *renderer;
442  GtkTreeViewColumn *column;
443 
444  renderer = gtk_cell_renderer_toggle_new();
445  column = gtk_tree_view_column_new_with_attributes
446  (title, renderer,
447  "active", col_num,
448  "cell-background", DOWNLOADED_COL_COLOR,
449  NULL);
450  gtk_tree_view_column_set_sort_column_id(column, col_num);
451  g_object_set(G_OBJECT(column),
452  "reorderable", TRUE,
453  NULL);
454  g_signal_connect(renderer, "toggled", cb_fn, cb_arg);
455  gtk_tree_view_append_column(view, column);
456  return column;
457 }
458 
459 static void
460 gnc_gen_trans_init_view (GNCImportMainMatcher *info,
461  gboolean show_account,
462  gboolean show_update)
463 {
464  GtkTreeView *view;
465  GtkListStore *store;
466  GtkCellRenderer *renderer;
467  GtkTreeViewColumn *column;
468  GtkTreeSelection *selection;
469 
470  view = info->view;
471  store = gtk_list_store_new(NUM_DOWNLOADED_COLS,
472  G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
473  G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN,
474  G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_STRING,
475  GDK_TYPE_PIXBUF, G_TYPE_POINTER, G_TYPE_STRING);
476  gtk_tree_view_set_model(view, GTK_TREE_MODEL(store));
477  g_object_unref(store);
478 
479  /* Add the columns */
480  add_text_column(view, _("Date"), DOWNLOADED_COL_DATE);
481  column = add_text_column(view, _("Account"), DOWNLOADED_COL_ACCOUNT);
482  gtk_tree_view_column_set_visible(column, show_account);
483  add_text_column(view, _("Amount"), DOWNLOADED_COL_AMOUNT);
484  add_text_column(view, _("Description"), DOWNLOADED_COL_DESCRIPTION);
485  add_text_column(view, _("Memo"), DOWNLOADED_COL_MEMO);
486  add_toggle_column(view, _("A"), DOWNLOADED_COL_ACTION_ADD,
487  G_CALLBACK(gnc_gen_trans_add_toggled_cb), info);
488  column = add_toggle_column(view, _("U+R"), DOWNLOADED_COL_ACTION_UPDATE,
489  G_CALLBACK(gnc_gen_trans_update_toggled_cb), info);
490  gtk_tree_view_column_set_visible(column, show_update);
491  add_toggle_column(view, _("R"), DOWNLOADED_COL_ACTION_CLEAR,
492  G_CALLBACK(gnc_gen_trans_clear_toggled_cb), info);
493 
494  /* The last column has multiple renderers */
495  renderer = gtk_cell_renderer_pixbuf_new();
496  g_object_set(renderer, "xalign", 0.0, NULL);
497  column = gtk_tree_view_column_new_with_attributes(_("Info"), renderer,
498  "pixbuf", DOWNLOADED_COL_ACTION_PIXBUF,
499  "cell-background", DOWNLOADED_COL_COLOR,
500  NULL);
501  renderer = gtk_cell_renderer_text_new();
502  g_object_set(G_OBJECT(renderer),
503  "foreground", "black",
504  "foreground-set", TRUE,
505  NULL);
506  gtk_tree_view_column_pack_start(column, renderer, TRUE);
507  gtk_tree_view_column_set_attributes(column, renderer,
508  "text", DOWNLOADED_COL_ACTION_INFO,
509  "background", DOWNLOADED_COL_COLOR,
510  NULL);
511  gtk_tree_view_column_set_sort_column_id(column, DOWNLOADED_COL_ACTION_INFO);
512  g_object_set(G_OBJECT(column),
513  "reorderable", TRUE,
514  "resizable", TRUE,
515  NULL);
516  gtk_tree_view_append_column(info->view, column);
517 
518 
519  selection = gtk_tree_view_get_selection(info->view);
520  g_signal_connect(info->view, "row-activated",
521  G_CALLBACK(gnc_gen_trans_row_activated_cb), info);
522  g_signal_connect(selection, "changed",
523  G_CALLBACK(gnc_gen_trans_row_changed_cb), info);
524 }
525 
527  const gchar* heading,
528  gboolean all_from_same_account,
529  gint match_date_hardlimit)
530 {
531  GNCImportMainMatcher *info;
532  GtkBuilder *builder;
533  GtkWidget *heading_label;
534  GtkWidget *box, *pbox;
535  gboolean show_update;
536 
537  info = g_new0 (GNCImportMainMatcher, 1);
538 
539  /* Initialize user Settings. */
540  info->user_settings = gnc_import_Settings_new ();
541  gnc_import_Settings_set_match_date_hardlimit (info->user_settings, match_date_hardlimit);
542 
543  /* Initialize the GtkDialog. */
544  builder = gtk_builder_new();
545  gnc_builder_add_from_file (builder, "dialog-import.glade", "transaction_matcher");
546  gnc_builder_add_from_file (builder, "dialog-import.glade", "transaction_matcher_content");
547  info->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "transaction_matcher"));
548  g_assert (info->dialog != NULL);
549 
550  /* Pack the content into the dialog vbox */
551  pbox = GTK_WIDGET(gtk_builder_get_object (builder, "transaction_matcher_vbox"));
552  box = GTK_WIDGET(gtk_builder_get_object (builder, "transaction_matcher_content"));
553  gtk_box_pack_start( GTK_BOX(pbox), box, TRUE, TRUE, 0);
554 
555  /* Get the view */
556  info->view = GTK_TREE_VIEW(gtk_builder_get_object (builder, "downloaded_view"));
557  g_assert (info->view != NULL);
558 
559  show_update = gnc_import_Settings_get_action_update_enabled(info->user_settings);
560  gnc_gen_trans_init_view(info, all_from_same_account, show_update);
561  heading_label = GTK_WIDGET(gtk_builder_get_object (builder, "heading_label"));
562  g_assert (heading_label != NULL);
563 
564  /* if (parent)
565  gtk_window_set_transient_for (GTK_WINDOW (info->dialog),
566  GTK_WINDOW (parent));*/
567 
568  /*Initialise the colors */
569  gdk_color_parse(COLOR_RED, &info->color_back_red);
570  gdk_color_parse(COLOR_YELLOW, &info->color_back_yellow);
571  gdk_color_parse(COLOR_GREEN, &info->color_back_green);
572 
573  if (heading)
574  gtk_label_set_text (GTK_LABEL (heading_label), heading);
575 
576  gnc_restore_window_size(GNC_PREFS_GROUP, GTK_WINDOW(info->dialog));
577  gtk_widget_show_all (GTK_WIDGET (info->dialog));
578 
579  info->transaction_processed_cb = NULL;
580 
581  /* Connect the signals */
582  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, info);
583 
584  g_object_unref(G_OBJECT(builder));
585 
586  return info;
587 }
588 
589 /*****************************************************************
590  * Assistant routines Start *
591  *****************************************************************/
592 
594  const gchar* heading,
595  gboolean all_from_same_account,
596  gint match_date_hardlimit)
597 {
598  GNCImportMainMatcher *info;
599  GtkBuilder *builder;
600  GtkWidget *heading_label;
601  GtkWidget *box;
602  gboolean show_update;
603 
604  info = g_new0 (GNCImportMainMatcher, 1);
605 
606  /* Initialize user Settings. */
607  info->user_settings = gnc_import_Settings_new ();
608  gnc_import_Settings_set_match_date_hardlimit (info->user_settings, match_date_hardlimit);
609 
610  /* load the interface */
611  builder = gtk_builder_new();
612  gnc_builder_add_from_file (builder, "dialog-import.glade", "transaction_matcher_content");
613  if (builder == NULL)
614  {
615  PERR("Error opening the glade builder interface");
616  }
617  /* Pack content into Assistant page widget */
618  box = GTK_WIDGET(gtk_builder_get_object (builder, "transaction_matcher_content"));
619  gtk_box_pack_start( GTK_BOX(parent), box, TRUE, TRUE, 6);
620 
621  /* Get the view */
622  info->view = GTK_TREE_VIEW(gtk_builder_get_object (builder, "downloaded_view"));
623  g_assert (info->view != NULL);
624 
625  show_update = gnc_import_Settings_get_action_update_enabled(info->user_settings);
626  gnc_gen_trans_init_view(info, all_from_same_account, show_update);
627  heading_label = GTK_WIDGET(gtk_builder_get_object (builder, "heading_label"));
628  g_assert (heading_label != NULL);
629 
630  /*Initialise the colors */
631  gdk_color_parse(COLOR_RED, &info->color_back_red);
632  gdk_color_parse(COLOR_YELLOW, &info->color_back_yellow);
633  gdk_color_parse(COLOR_GREEN, &info->color_back_green);
634 
635  if (heading)
636  gtk_label_set_text (GTK_LABEL (heading_label), heading);
637 
638  info->transaction_processed_cb = NULL;
639 
640  /* Connect the signals */
641  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, info);
642 
643  g_object_unref(G_OBJECT(builder));
644 
645  return info;
646 }
647 
649 {
650  on_matcher_ok_clicked (NULL, info);
651 }
652 
653 /*****************************************************************
654  * Assistant routines End *
655  *****************************************************************/
656 
658  GNCTransactionProcessedCB trans_processed_cb,
659  gpointer user_data)
660 {
661  info->user_data = user_data;
662  info->transaction_processed_cb = trans_processed_cb;
663 }
664 
666 {
667  gboolean result;
668 
669  /* DEBUG("Begin"); */
670  result = gtk_dialog_run (GTK_DIALOG (info->dialog));
671  /* DEBUG("Result was %d", result); */
672 
673  /* No destroying here since the dialog was already destroyed through
674  the ok_clicked handlers. */
675 
676  return result;
677 }
678 
679 static void
680 refresh_model_row (GNCImportMainMatcher *gui,
681  GtkTreeModel *model,
682  GtkTreeIter *iter,
683  GNCImportTransInfo *info)
684 {
685  GtkListStore *store;
686  GtkTreeSelection *selection;
687  gchar *tmp, *imbalance, *text, *color;
688  const gchar *ro_text;
689  Split *split;
690  g_assert (gui);
691  g_assert (model);
692  g_assert (info);
693  /*DEBUG("Begin");*/
694 
695  store = GTK_LIST_STORE(model);
696  gtk_list_store_set(store, iter, DOWNLOADED_COL_DATA, info, -1);
697 
698  /*Account:*/
699  split = gnc_import_TransInfo_get_fsplit (info);
700  g_assert(split); // Must not be NULL
701  ro_text = xaccAccountGetName(xaccSplitGetAccount(split));
702  gtk_list_store_set(store, iter, DOWNLOADED_COL_ACCOUNT, ro_text, -1);
703 
704  /*Date*/
706  gtk_list_store_set(store, iter, DOWNLOADED_COL_DATE, text, -1);
707  g_free(text);
708 
709  /*Amount*/
710  ro_text = xaccPrintAmount
711  (xaccSplitGetAmount (split),
712  gnc_split_amount_print_info(split, TRUE)
713  );
714  gtk_list_store_set(store, iter, DOWNLOADED_COL_AMOUNT, ro_text, -1);
715 
716  /*Description*/
718  gtk_list_store_set(store, iter, DOWNLOADED_COL_DESCRIPTION, ro_text, -1);
719 
720  /*Memo*/
721  ro_text = xaccSplitGetMemo(split);
722  gtk_list_store_set(store, iter, DOWNLOADED_COL_MEMO, ro_text, -1);
723 
724  /*Actions*/
725 
726  /* Action informations */
727  ro_text = text = color = NULL;
728  switch (gnc_import_TransInfo_get_action(info))
729  {
730  case GNCImport_ADD:
731  if (gnc_import_TransInfo_is_balanced(info) == TRUE)
732  {
733  ro_text = _("New, already balanced");
734  color = COLOR_GREEN;
735  }
736  else
737  {
738  /* Assume that importers won't create transactions in two or more
739  currencies so we can use xaccTransGetImbalanceValue */
740  imbalance =
741  g_strdup
742  (xaccPrintAmount
745  gnc_commodity_print_info
747  TRUE) ));
748  if (gnc_import_TransInfo_get_destacc (info) != NULL)
749  {
750  color = COLOR_GREEN;
754  == TRUE)
755  {
756  text =
757  /* Translators: %1$s is the amount to be
758  transferred. %2$s is the destination account. */
759  g_strdup_printf(_("New, transfer %s to (manual) \"%s\""),
760  imbalance, tmp);
761  }
762  else
763  {
764  text =
765  /* Translators: %1$s is the amount to be
766  transferred. %2$s is the destination account. */
767  g_strdup_printf(_("New, transfer %s to (auto) \"%s\""),
768  imbalance, tmp);
769  }
770  g_free (tmp);
771 
772  }
773  else
774  {
775  color = COLOR_YELLOW;
776  text =
777  /* Translators: %s is the amount to be transferred. */
778  g_strdup_printf(_("New, UNBALANCED (need acct to transfer %s)!"),
779  imbalance);
780  }
781  g_free (imbalance);
782  }
783  break;
784  case GNCImport_CLEAR:
786  {
787  color = COLOR_GREEN;
789  {
790  ro_text = _("Reconcile (manual) match");
791  }
792  else
793  {
794  ro_text = _("Reconcile (auto) match");
795  }
796  }
797  else
798  {
799  color = COLOR_RED;
800  ro_text = _("Match missing!");
801  }
802  break;
803  case GNCImport_UPDATE:
805  {
806  color = COLOR_GREEN;
808  {
809  ro_text = _("Update and reconcile (manual) match");
810  }
811  else
812  {
813  ro_text = _("Update and reconcile (auto) match");
814  }
815  }
816  else
817  {
818  color = COLOR_RED;
819  ro_text = _("Match missing!");
820  }
821  break;
822  case GNCImport_SKIP:
823  color = COLOR_RED;
824  ro_text = _("Do not import (no action selected)");
825  break;
826  default:
827  color = "white";
828  ro_text = "WRITEME, this is an unknown action";
829  break;
830  }
831 
832  gtk_list_store_set(store, iter,
833  DOWNLOADED_COL_COLOR, color,
834  DOWNLOADED_COL_ACTION_INFO, ro_text ? ro_text : text,
835  -1);
836  if (text)
837  g_free(text);
838 
839  /* Set the pixmaps */
840  gtk_list_store_set(store, iter,
841  DOWNLOADED_COL_ACTION_ADD,
842  gnc_import_TransInfo_get_action(info) == GNCImport_ADD,
843  -1);
844  if (gnc_import_TransInfo_get_action(info) == GNCImport_SKIP)
845  {
846  /*Show the best match's confidence pixmap in the info column*/
847  gtk_list_store_set(store, iter,
848  DOWNLOADED_COL_ACTION_PIXBUF,
851  gui->user_settings,
852  GTK_WIDGET(gui->view)),
853  -1);
854  }
855 
856  gtk_list_store_set(store, iter,
857  DOWNLOADED_COL_ACTION_CLEAR,
858  gnc_import_TransInfo_get_action(info) == GNCImport_CLEAR,
859  -1);
860  if (gnc_import_TransInfo_get_action(info) == GNCImport_CLEAR)
861  {
862  /*Show the best match's confidence pixmap in the info column*/
863  gtk_list_store_set(store, iter,
864  DOWNLOADED_COL_ACTION_PIXBUF,
867  gui->user_settings,
868  GTK_WIDGET(gui->view)),
869  -1);
870  }
871 
872  gtk_list_store_set(store, iter,
873  DOWNLOADED_COL_ACTION_UPDATE,
874  gnc_import_TransInfo_get_action(info) == GNCImport_UPDATE,
875  -1);
876  if (gnc_import_TransInfo_get_action(info) == GNCImport_UPDATE)
877  {
878  /*Show the best match's confidence pixmap in the info column*/
879  gtk_list_store_set(store, iter,
880  DOWNLOADED_COL_ACTION_PIXBUF,
883  gui->user_settings,
884  GTK_WIDGET(gui->view)),
885  -1);
886  }
887 
888  selection = gtk_tree_view_get_selection(gui->view);
889  gtk_tree_selection_unselect_all(selection);
890 }
891 
893 {
895  return;
896 }/* end gnc_import_add_trans() */
897 
899 {
900  GNCImportTransInfo * transaction_info = NULL;
901  GtkTreeModel *model;
902  GtkTreeIter iter;
903  g_assert (gui);
904  g_assert (trans);
905 
906 
907  if (gnc_import_exists_online_id (trans))
908  return;
909  else
910  {
911  transaction_info = gnc_import_TransInfo_new(trans, NULL);
912  gnc_import_TransInfo_set_ref_id(transaction_info, ref_id);
913 
914  gnc_import_TransInfo_init_matches(transaction_info,
915  gui->user_settings);
916 
917  model = gtk_tree_view_get_model(gui->view);
918  gtk_list_store_append(GTK_LIST_STORE(model), &iter);
919  refresh_model_row (gui, model, &iter, transaction_info);
920  }
921  return;
922 }/* end gnc_import_add_trans_with_ref_id() */
923 
924 /* Iterate through the rows of the clist and try to automatch each of them */
925 static void
926 automatch_store_transactions (GNCImportMainMatcher *info,
927  GtkTreeModel *model,
928  GtkTreeIter *iter,
929  GNCImportTransInfo *trans_info)
930 {
931  /* returns TRUE if we changed this row, so update it */
932  if (gnc_import_TransInfo_refresh_destacc(trans_info, NULL))
933  {
934  refresh_model_row(info, model, iter, trans_info);
935  }
936 }
937 
939 {
940  g_assert(info);
941  return info->dialog;
942 }
943 
void gnc_import_match_picker_run_and_close(GNCImportTransInfo *transaction_info)
GNCImportTransInfo * gnc_import_TransInfo_new(Transaction *trans, GncImportMatchMap *matchmap)
time64 xaccTransGetDate(const Transaction *trans)
Definition: Transaction.c:2215
utility functions for the GnuCash UI
GNCImportSettings * gnc_import_Settings_new(void)
void gnc_import_TransInfo_delete(GNCImportTransInfo *info)
gnc_numeric gnc_numeric_neg(gnc_numeric a)
void gnc_import_TransInfo_set_ref_id(GNCImportTransInfo *info, guint32 ref_id)
void gnc_import_Settings_delete(GNCImportSettings *settings)
Generic importer backend interface.
Split * gnc_import_TransInfo_get_fsplit(const GNCImportTransInfo *info)
GdkPixbuf * gen_probability_pixbuf(gint score_original, GNCImportSettings *settings, GtkWidget *widget)
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)
void on_matcher_help_clicked(GtkButton *button, gpointer user_data)
Transaction matcher main window.
Transaction * gnc_import_TransInfo_get_trans(const GNCImportTransInfo *info)
void gnc_gen_trans_list_add_tp_cb(GNCImportMainMatcher *info, GNCTransactionProcessedCB trans_processed_cb, gpointer user_data)
Generic and very flexible account matcher/picker.
void gnc_import_TransInfo_set_destacc(GNCImportTransInfo *info, Account *acc, gboolean selected_manually)
Import preference handling. User preference interface for transaction matching (for both the gui and ...
#define PERR(format, args...)
Definition: qoflog.h:237
GNCImportMainMatcher * gnc_gen_trans_list_new(GtkWidget *parent, const gchar *heading, gboolean all_from_same_account, gint match_date_hardlimit)
void gnc_gen_trans_list_add_trans(GNCImportMainMatcher *gui, Transaction *trans)
void gnc_import_TransInfo_init_matches(GNCImportTransInfo *trans_info, GNCImportSettings *settings)
gboolean gnc_gen_trans_list_run(GNCImportMainMatcher *info)
GNCImportAction gnc_import_TransInfo_get_action(const GNCImportTransInfo *info)
char * qof_print_date(time64 secs)
gint gnc_import_MatchInfo_get_probability(const GNCImportMatchInfo *info)
gchar * gnc_account_get_full_name(const Account *account)
Definition: Account.c:3038
The transaction match picker dialog interface.
GtkWidget * gnc_gen_trans_list_widget(GNCImportMainMatcher *info)
gnc_numeric xaccTransGetImbalanceValue(const Transaction *trans)
Definition: Transaction.c:1036
void gnc_gen_trans_assist_start(GNCImportMainMatcher *info)
gboolean gnc_import_process_trans_item(GncImportMatchMap *matchmap, GNCImportTransInfo *trans_info)
void gnc_import_TransInfo_set_action(GNCImportTransInfo *info, GNCImportAction action)
void gnc_import_Settings_set_match_date_hardlimit(GNCImportSettings *s, gint m)
gboolean gnc_import_TransInfo_refresh_destacc(GNCImportTransInfo *transaction_info, GncImportMatchMap *matchmap)
const char * xaccTransGetDescription(const Transaction *trans)
Definition: Transaction.c:2184
gboolean gnc_import_exists_online_id(Transaction *trans)
All type declarations for the whole Gnucash engine.
void gnc_gen_trans_list_add_trans_with_ref_id(GNCImportMainMatcher *gui, Transaction *trans, guint32 ref_id)
gboolean gnc_import_Settings_get_action_update_enabled(GNCImportSettings *settings)
gboolean gnc_import_TransInfo_get_match_selected_manually(const GNCImportTransInfo *info)
Definition: SplitP.h:71
Account * xaccSplitGetAccount(const Split *s)
Definition: Split.c:968
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Definition: Transaction.c:1348
void gnc_gen_trans_list_delete(GNCImportMainMatcher *info)
Account * gnc_import_TransInfo_get_destacc(const GNCImportTransInfo *info)
const char * xaccSplitGetMemo(const Split *split)
Definition: Split.c:1968
GNCImportMatchInfo * gnc_import_TransInfo_get_selected_match(const GNCImportTransInfo *info)
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:3031
gboolean gnc_import_Settings_get_action_skip_enabled(GNCImportSettings *settings)
gboolean gnc_import_TransInfo_is_balanced(const GNCImportTransInfo *info)
GNCImportMainMatcher * gnc_gen_trans_assist_new(GtkWidget *parent, const gchar *heading, gboolean all_from_same_account, gint match_date_hardlimit)
const gchar * QofLogModule
Definition: qofid.h:89
gnc_numeric xaccSplitGetAmount(const Split *split)
Definition: Split.c:1987
gboolean gnc_import_TransInfo_get_destacc_selected_manually(const GNCImportTransInfo *info)