GnuCash  5.6-150-g038405b370+
assistant-ab-initial.c
1 /*
2  * assistant-ab-initial.c -- Initialise the AqBanking wizard
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, contact:
16  *
17  * Free Software Foundation Voice: +1-617-542-5942
18  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
19  * Boston, MA 02110-1301, USA gnu@gnu.org
20  */
21 
33 #include <config.h>
34 
35 #include <platform.h>
36 #if PLATFORM(WINDOWS)
37 #include <windows.h>
38 #endif
39 
40 #include "gnc-ab-utils.h" /* For version macros */
41 
42 #include <aqbanking/banking.h>
43 #include <aqbanking/types/account_spec.h>
44 #include <gwenhywfar/gui.h>
45 #include <glib.h>
46 #include <glib/gi18n.h>
47 #include <glib/gstdio.h>
48 #include <gdk/gdkkeysyms.h>
49 #ifdef HAVE_SYS_WAIT_H
50 # include <sys/wait.h>
51 #endif
52 #include <fcntl.h>
53 #include <unistd.h>
54 #include <stdint.h>
55 
56 #include "dialog-utils.h"
57 #include "assistant-ab-initial.h"
58 #include "gnc-ab-kvp.h"
59 #include "gnc-ab-utils.h"
60 #include "gnc-component-manager.h"
61 #include "gnc-glib-utils.h"
62 #include "gnc-ui.h"
63 #include "gnc-ui-util.h"
64 #include "gnc-session.h"
65 #include "import-account-matcher.h"
66 #include "import-utilities.h"
67 /* This static indicates the debugging module that this .o belongs to. */
68 static QofLogModule log_module = GNC_MOD_ASSISTANT;
69 
70 #define GNC_PREFS_GROUP "dialogs.ab-initial"
71 #define ASSISTANT_AB_INITIAL_CM_CLASS "assistant-ab-initial"
72 
73 typedef struct _ABInitialInfo ABInitialInfo;
74 typedef struct _DeferredInfo DeferredInfo;
75 typedef struct _AccCbData AccCbData;
76 typedef struct _RevLookupData RevLookupData;
77 
78 void aai_on_prepare (GtkAssistant *assistant, GtkWidget *page,
79  gpointer user_data);
80 
81 void aai_on_finish (GtkAssistant *gtkassistant, gpointer user_data);
82 void aai_on_cancel (GtkAssistant *assistant, gpointer user_data);
83 void aai_destroy_cb(GtkWidget *object, gpointer user_data);
84 
85 gboolean aai_key_press_event_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
86 
87 void aai_page_prepare (GtkAssistant *assistant, gpointer user_data);
88 void aai_button_clicked_cb(GtkButton *button, gpointer user_data);
89 void aai_match_delete_button_clicked_cb(GtkButton *button, gpointer user_data);
90 
91 static guint aai_ab_account_hash(gconstpointer v);
92 static gboolean aai_ab_account_equal(gconstpointer v1, gconstpointer v2);
93 void aai_match_page_prepare (GtkAssistant *assistant, gpointer user_data);
94 
95 static gboolean banking_has_accounts(AB_BANKING *banking);
96 static void hash_from_kvp_acc_cb(Account *gnc_acc, gpointer user_data);
97 static ABInitialInfo *single_info = NULL;
98 static gchar *ab_account_longname(const GNC_AB_ACCOUNT_SPEC *ab_acc);
99 static GNC_AB_ACCOUNT_SPEC *update_account_list_acc_cb(GNC_AB_ACCOUNT_SPEC *ab_acc, gpointer user_data);
100 static void update_account_list(ABInitialInfo *info);
101 static gboolean find_gnc_acc_cb(gpointer key, gpointer value, gpointer user_data);
102 static gboolean clear_line_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data);
103 static void account_list_clicked_cb (GtkTreeView *view, GtkTreePath *path,
104  GtkTreeViewColumn *col, gpointer user_data);
105 static void delete_account_match(ABInitialInfo *info, RevLookupData *data);
106 static void delete_selected_match_cb(gpointer data, gpointer user_data);
107 static void insert_acc_into_revhash_cb(gpointer ab_acc, gpointer gnc_acc, gpointer revhash);
108 static void remove_acc_from_revhash_cb(gpointer ab_acc, gpointer gnc_acc, gpointer revhash);
109 static void clear_kvp_acc_cb(gpointer key, gpointer value, gpointer user_data);
110 static void save_kvp_acc_cb(gpointer key, gpointer value, gpointer user_data);
111 static void aai_close_handler(gpointer user_data);
112 
114 {
115  GtkWidget *window;
116  GtkWidget *assistant;
117 
118  /* account match page */
119  gboolean match_page_prepared;
120  GtkTreeView *account_view;
121  GtkListStore *account_store;
122 
123  /* managed by child_exit_cb */
124  DeferredInfo *deferred_info;
125 
126  /* AqBanking stuff */
127  AB_BANKING *api;
128  /* AB_ACCOUNT* -> Account* -- DO NOT DELETE THE KEYS! */
129  GHashTable *gnc_hash;
130  /* Reverse hash table for lookup of matched GnuCash accounts */
131  GHashTable *gnc_revhash;
132 };
133 
135 {
136  ABInitialInfo *initial_info;
137  gchar *wizard_path;
138  gboolean qt_probably_unavailable;
139 };
140 
142 {
143  AB_BANKING *api;
144  GHashTable *hash;
145 };
146 
148 {
149  Account *gnc_acc;
150  GNC_AB_ACCOUNT_SPEC *ab_acc;
151 };
152 
153 enum account_list_cols
154 {
155  ACCOUNT_LIST_COL_INDEX = 0,
156  ACCOUNT_LIST_COL_AB_NAME,
157  ACCOUNT_LIST_COL_AB_ACCT,
158  ACCOUNT_LIST_COL_GNC_NAME,
159  ACCOUNT_LIST_COL_CHECKED,
160  NUM_ACCOUNT_LIST_COLS
161 };
162 
163 gboolean
164 aai_key_press_event_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
165 {
166  if (event->keyval == GDK_KEY_Escape)
167  {
168  gtk_widget_destroy(widget);
169  return TRUE;
170  }
171  else
172  {
173  return FALSE;
174  }
175 }
176 
177 void
178 aai_on_cancel (GtkAssistant *gtkassistant, gpointer user_data)
179 {
180  ABInitialInfo *info = user_data;
181 
182  gtk_widget_destroy(info->window);
183 }
184 
185 void
186 aai_destroy_cb(GtkWidget *object, gpointer user_data)
187 {
188  ABInitialInfo *info = user_data;
189  g_return_if_fail (single_info && info == single_info);
190 
191  gnc_unregister_gui_component_by_data(ASSISTANT_AB_INITIAL_CM_CLASS, info);
192 
193  if (info->deferred_info)
194  {
195  PINFO("Online Banking assistant is being closed but the wizard is still "
196  "running. Inoring.");
197 
198  /* Tell child_exit_cb() that there is no assistant anymore */
199  info->deferred_info->initial_info = NULL;
200  }
201 
202  if (info->gnc_hash)
203  {
204  g_hash_table_destroy(info->gnc_hash);
205  info->gnc_hash = NULL;
206  }
207 
208  if (info->gnc_revhash)
209  {
210  g_hash_table_destroy(info->gnc_revhash);
211  info->gnc_revhash = NULL;
212  }
213 
214  if (info->api)
215  {
216  gnc_AB_BANKING_delete(info->api);
217  info->api = NULL;
218  }
219 
220  gtk_widget_destroy(info->window);
221  info->window = NULL;
222 
223  g_free(info);
224  single_info = NULL;
225 }
226 
227 void
228 aai_page_prepare (GtkAssistant *assistant, gpointer user_data)
229 {
230  ABInitialInfo *info = user_data;
231  gint num = gtk_assistant_get_current_page (assistant);
232  GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
233 
234  g_return_if_fail(info->api);
235 
236  /* Enable the Assistant Buttons if we accounts */
237  if (banking_has_accounts(info->api))
238  gtk_assistant_set_page_complete (assistant, page, TRUE);
239  else
240  gtk_assistant_set_page_complete (assistant, page, FALSE);
241 }
242 
243 void
244 aai_button_clicked_cb(GtkButton *button, gpointer user_data)
245 {
246  ABInitialInfo *info = user_data;
247  gint num = gtk_assistant_get_current_page (GTK_ASSISTANT(info->window));
248  GtkWidget *page = gtk_assistant_get_nth_page (GTK_ASSISTANT(info->window), num);
249 
250  AB_BANKING *banking = info->api;
251  g_return_if_fail(banking);
252 
253  ENTER("user_data: %p", user_data);
254 
255  if (info->deferred_info)
256  {
257  LEAVE("Wizard is still running");
258  return;
259  }
260 
261  {
262  GWEN_DIALOG *dlg = AB_Banking_CreateSetupDialog(banking);
263  if (!dlg)
264  {
265  PERR("Could not lookup Setup Dialog of aqbanking!");
266  }
267  else
268  {
269  int rv = GWEN_Gui_ExecDialog(dlg, 0);
270  if (rv <= 0)
271  {
272  /* Dialog was aborted/rejected */
273  PERR("Setup Dialog of aqbanking aborted/rejected, code %d", rv);
274  }
275  GWEN_Dialog_free(dlg);
276  }
277  }
278 
279  /* Enable the Assistant Buttons if we accounts */
280  if (banking_has_accounts(info->api))
281  gtk_assistant_set_page_complete (GTK_ASSISTANT(info->window), page, TRUE);
282  else
283  gtk_assistant_set_page_complete (GTK_ASSISTANT(info->window), page, FALSE);
284 
285  LEAVE(" ");
286 }
287 
288 static void delete_account_match(ABInitialInfo *info, RevLookupData *data)
289 {
290  g_return_if_fail(info && info->gnc_hash &&
291  info->account_view && data && data->ab_acc);
292 
293  g_hash_table_remove(info->gnc_hash, data->ab_acc);
294  gtk_tree_model_foreach(
295  GTK_TREE_MODEL(info->account_store),
296  (GtkTreeModelForeachFunc) clear_line_cb,
297  data);
298 }
299 
300 static void
301 delete_selected_match_cb(gpointer data, gpointer user_data)
302 {
303  GtkTreeIter iter;
304  GtkTreeModel *model = NULL;
305  RevLookupData revLookupData = {NULL, NULL};
306 
307  GtkTreePath *path = (GtkTreePath *) data;
308  ABInitialInfo *info = (ABInitialInfo *) user_data;
309  g_return_if_fail(path && info && info->account_view);
310 
311  model = gtk_tree_view_get_model(info->account_view);
312  g_return_if_fail(model);
313 
314  if (gtk_tree_model_get_iter(model, &iter, path))
315  {
316  gtk_tree_model_get(model, &iter, ACCOUNT_LIST_COL_AB_ACCT, &revLookupData.ab_acc, -1);
317  if (revLookupData.ab_acc)
318  delete_account_match(info, &revLookupData);
319  }
320 }
321 
322 void
323 aai_match_delete_button_clicked_cb(GtkButton *button, gpointer user_data)
324 {
325  GList *selected_matches = NULL;
326  GtkTreeSelection *selection = NULL;
327  ABInitialInfo *info = (ABInitialInfo *) user_data;
328 
329  g_return_if_fail(info && info->api && info->account_view && info->gnc_hash);
330 
331  PINFO("Selected account matches are deleted");
332 
333  selection = gtk_tree_view_get_selection (info->account_view);
334  if (selection)
335  {
336  selected_matches = gtk_tree_selection_get_selected_rows (selection, NULL);
337  if (selected_matches)
338  {
339  g_list_foreach (selected_matches, delete_selected_match_cb, info);
340  g_list_free_full (
341  selected_matches,
342  (GDestroyNotify) gtk_tree_path_free);
343  }
344  }
345 }
346 
347 static guint
348 aai_ab_account_hash (gconstpointer v)
349 {
350  if (v == NULL)
351  return 0;
352  else
353  /* Use the account unique id as hash value */
354  return AB_AccountSpec_GetUniqueId((const GNC_AB_ACCOUNT_SPEC *) v);
355 }
356 
357 static gboolean
358 aai_ab_account_equal (gconstpointer v1, gconstpointer v2)
359 {
360  if (v1 == NULL || v2 == NULL)
361  return v1 == v2;
362  else
363  {
364  /* Use the account unique id to check for equality */
365  uint32_t uid1 = AB_AccountSpec_GetUniqueId((const GNC_AB_ACCOUNT_SPEC *) v1);
366  uint32_t uid2 = AB_AccountSpec_GetUniqueId((const GNC_AB_ACCOUNT_SPEC *) v2);
367  return uid1 == uid2;
368  }
369 }
370 
371 static void
372 insert_acc_into_revhash_cb(gpointer ab_acc, gpointer gnc_acc, gpointer revhash)
373 {
374  g_return_if_fail(revhash && gnc_acc && ab_acc);
375  g_hash_table_insert((GHashTable *) revhash, gnc_acc, ab_acc);
376 }
377 
378 static void
379 remove_acc_from_revhash_cb(gpointer ab_acc, gpointer gnc_acc, gpointer revhash)
380 {
381  g_return_if_fail(revhash && gnc_acc);
382  g_hash_table_remove((GHashTable *) revhash, gnc_acc);
383 }
384 
385 void
386 aai_match_page_prepare (GtkAssistant *assistant, gpointer user_data)
387 {
388  ABInitialInfo *info = user_data;
389  gint num = gtk_assistant_get_current_page (assistant);
390  GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
391 
392  Account *root;
393  AccCbData data;
394 
395  g_return_if_fail(info && info->api);
396 
397  /* Do not run this twice */
398  if (!info->match_page_prepared)
399  {
400  /* Determine current mapping */
401  root = gnc_book_get_root_account(gnc_get_current_book());
402  info->gnc_hash = g_hash_table_new(&aai_ab_account_hash, &aai_ab_account_equal);
403  data.api = info->api;
404  data.hash = info->gnc_hash;
405  gnc_account_foreach_descendant(root, (AccountCb) hash_from_kvp_acc_cb, &data);
406  /* Memorize initial matches in reverse hash table */
407  info->gnc_revhash = g_hash_table_new(NULL, NULL);
408  g_hash_table_foreach(data.hash, (GHFunc) insert_acc_into_revhash_cb, (gpointer) info->gnc_revhash);
409 
410  info->match_page_prepared = TRUE;
411  }
412  /* Update the graphical representation */
413  update_account_list(info);
414 
415  /* Enable the Assistant Buttons */
416  gtk_assistant_set_page_complete (assistant, page, TRUE);
417 }
418 
419 void
420 aai_on_finish (GtkAssistant *assistant, gpointer user_data)
421 {
422  ABInitialInfo *info = user_data;
423 
424  g_return_if_fail(info && info->gnc_hash && info->gnc_revhash);
425 
426  /* Remove GnuCash accounts from reverse hash table which are still
427  * matched to an AqBanking account. For the remaining GnuCash accounts
428  * the KVPs must be cleared (i.e. deleted).
429  * Please note that the value (i.e. the GnuCash account) stored in info->gnc_hash
430  * is used as key for info->gnc_revhash */
431  g_hash_table_foreach(info->gnc_hash, (GHFunc) remove_acc_from_revhash_cb, info->gnc_revhash);
432  /* Commit the changes */
433  g_hash_table_foreach(info->gnc_revhash, (GHFunc) clear_kvp_acc_cb, NULL);
434  g_hash_table_foreach(info->gnc_hash, (GHFunc) save_kvp_acc_cb, NULL);
435 
436  gtk_widget_destroy(info->window);
437 }
438 
439 static gboolean
440 banking_has_accounts(AB_BANKING *banking)
441 {
442  GNC_AB_ACCOUNT_SPEC_LIST *accl = NULL;
443  gboolean result = FALSE;
444 
445  g_return_val_if_fail(banking, FALSE);
446 
447  if (AB_Banking_GetAccountSpecList (banking, &accl) >= 0 &&
448  accl && AB_AccountSpec_List_GetCount (accl))
449  result = TRUE;
450  if (accl)
451  AB_AccountSpec_List_free (accl);
452 
453  return result;
454 }
455 
456 static void
457 hash_from_kvp_acc_cb(Account *gnc_acc, gpointer user_data)
458 {
459  AccCbData *data = user_data;
460  GNC_AB_ACCOUNT_SPEC *ab_acc;
461 
462  ab_acc = gnc_ab_get_ab_account(data->api, gnc_acc);
463  if (ab_acc)
464  g_hash_table_insert(data->hash, ab_acc, gnc_acc);
465 }
466 
467 static gchar *
468 ab_account_longname(const GNC_AB_ACCOUNT_SPEC *ab_acc)
469 {
470  gchar *bankname = NULL;
471  gchar *result = NULL;
472  const char *bankcode, *subAccountId, *account_number;
473 
474  g_return_val_if_fail(ab_acc, NULL);
475 
476  bankcode = AB_AccountSpec_GetBankCode(ab_acc);
477  subAccountId = AB_AccountSpec_GetSubAccountNumber(ab_acc);
478  account_number = AB_AccountSpec_GetAccountNumber (ab_acc);
479  /* Translators: Strings are 1. Bank code, 2. Bank name,
480  3. Account Number, 4. Subaccount ID */
481  result = g_strdup_printf(_("Bank code %s (%s), Account %s (%s)"),
482  bankcode,
483  bankname ? bankname : "",
484  account_number,
485  subAccountId ? subAccountId : "");
486  g_free(bankname);
487 
488  return result;
489 
490 }
491 
492 static GNC_AB_ACCOUNT_SPEC *
493 update_account_list_acc_cb(GNC_AB_ACCOUNT_SPEC *ab_acc, gpointer user_data)
494 {
495  ABInitialInfo *info = user_data;
496  gchar *gnc_name, *ab_name;
497  Account *gnc_acc;
498  GtkTreeIter iter;
499 
500  g_return_val_if_fail(ab_acc && info, NULL);
501 
502  ab_name = ab_account_longname(ab_acc);
503 
504  /* Get corresponding gnucash account */
505  gnc_acc = g_hash_table_lookup(info->gnc_hash, ab_acc);
506 
507  /* Build the text for the gnucash account. */
508  if (gnc_acc)
509  gnc_name = gnc_account_get_full_name(gnc_acc);
510  else
511  gnc_name = g_strdup("");
512 
513  /* Add item to the list store */
514  gtk_list_store_append(info->account_store, &iter);
515  gtk_list_store_set(info->account_store, &iter,
516  ACCOUNT_LIST_COL_AB_NAME, ab_name,
517  ACCOUNT_LIST_COL_AB_ACCT, ab_acc,
518  ACCOUNT_LIST_COL_GNC_NAME, gnc_name,
519  ACCOUNT_LIST_COL_CHECKED, FALSE,
520  -1);
521  g_free(gnc_name);
522  g_free(ab_name);
523 
524  return NULL;
525 }
526 
527 static void
528 update_account_list(ABInitialInfo *info)
529 {
530  GNC_AB_ACCOUNT_SPEC_LIST *acclist = NULL;
531 
532  g_return_if_fail(info && info->api && info->gnc_hash);
533 
534  /* Detach model from view while updating */
535  g_object_ref(info->account_store);
536  gtk_tree_view_set_model(info->account_view, NULL);
537 
538  /* Refill the list */
539  gtk_list_store_clear(info->account_store);
540  if (AB_Banking_GetAccountSpecList(info->api, &acclist) >= 0 && acclist)
541  AB_AccountSpec_List_ForEach(acclist, update_account_list_acc_cb, info);
542  else
543  g_warning("update_account_list: Oops, account list from AB_Banking "
544  "is NULL");
545 
546  /* Attach model to view again */
547  gtk_tree_view_set_model(info->account_view,
548  GTK_TREE_MODEL(info->account_store));
549 
550  g_object_unref(info->account_store);
551 }
552 
553 static gboolean
554 find_gnc_acc_cb(gpointer key, gpointer value, gpointer user_data)
555 {
556  RevLookupData *data = user_data;
557 
558  g_return_val_if_fail(data, TRUE);
559 
560  if (value == data->gnc_acc)
561  {
562  data->ab_acc = (GNC_AB_ACCOUNT_SPEC*) key;
563  return TRUE;
564  }
565  return FALSE;
566 }
567 
568 static gboolean
569 clear_line_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
570  gpointer user_data)
571 {
572  RevLookupData *data = user_data;
573  GtkListStore *store = GTK_LIST_STORE(model);
574  gpointer ab_acc;
575 
576  g_return_val_if_fail(data && store, FALSE);
577 
578  gtk_tree_model_get(model, iter, ACCOUNT_LIST_COL_AB_ACCT, &ab_acc, -1);
579 
580  if (aai_ab_account_equal(ab_acc, data->ab_acc))
581  {
582  gtk_list_store_set(store, iter, ACCOUNT_LIST_COL_GNC_NAME, "",
583  ACCOUNT_LIST_COL_CHECKED, TRUE, -1);
584  return TRUE;
585  }
586  return FALSE;
587 }
588 
589 static void
590 account_list_clicked_cb (GtkTreeView *view, GtkTreePath *path,
591  GtkTreeViewColumn *col, gpointer user_data)
592 {
593  ABInitialInfo *info = user_data;
594  GtkTreeModel *model;
595  GtkTreeIter iter;
596  GNC_AB_ACCOUNT_SPEC *ab_acc;
597  gchar *longname, *gnc_name;
598  Account *old_value, *gnc_acc;
599  const gchar *currency;
600  gnc_commodity *commodity = NULL;
601  gboolean ok_pressed;
602 
603  g_return_if_fail(info);
604 
605  PINFO("Row has been double-clicked.");
606 
607  model = gtk_tree_view_get_model(view);
608 
609  if (!gtk_tree_model_get_iter(model, &iter, path))
610  return; /* path describes a non-existing row - should not happen */
611 
612  gtk_tree_model_get(model, &iter, ACCOUNT_LIST_COL_AB_ACCT, &ab_acc, -1);
613 
614  if (ab_acc)
615  {
616  old_value = g_hash_table_lookup(info->gnc_hash, ab_acc);
617 
618  longname = ab_account_longname(ab_acc);
619  currency = AB_AccountSpec_GetCurrency(ab_acc);
620  if (currency && *currency)
621  {
622  commodity = gnc_commodity_table_lookup(
623  gnc_commodity_table_get_table(gnc_get_current_book()),
624  GNC_COMMODITY_NS_CURRENCY,
625  currency);
626  }
627 
628  gnc_acc = gnc_import_select_account(info->window, NULL, TRUE,
629  longname, commodity, ACCT_TYPE_BANK,
630  old_value, &ok_pressed);
631  g_free(longname);
632 
633  if (ok_pressed && old_value != gnc_acc)
634  {
635  if (gnc_acc)
636  {
637  RevLookupData data;
638 
639  /* Lookup and clear other mappings to gnc_acc */
640  data.gnc_acc = gnc_acc;
641  data.ab_acc = NULL;
642  g_hash_table_find(info->gnc_hash, (GHRFunc) find_gnc_acc_cb,
643  &data);
644  if (data.ab_acc)
645  delete_account_match(info, &data);
646 
647  /* Map ab_acc to gnc_acc */
648  g_hash_table_insert(info->gnc_hash, ab_acc, gnc_acc);
649  gnc_name = gnc_account_get_full_name(gnc_acc);
650  gtk_list_store_set(info->account_store, &iter,
651  ACCOUNT_LIST_COL_GNC_NAME, gnc_name,
652  ACCOUNT_LIST_COL_CHECKED, TRUE,
653  -1);
654  g_free(gnc_name);
655 
656  }
657  else
658  {
659  g_hash_table_remove(info->gnc_hash, ab_acc);
660  gtk_list_store_set(info->account_store, &iter,
661  ACCOUNT_LIST_COL_GNC_NAME, "",
662  ACCOUNT_LIST_COL_CHECKED, TRUE,
663  -1);
664  }
665  }
666  }
667 }
668 
669 static void
670 clear_kvp_acc_cb(gpointer gnc_acc, gpointer ab_acc, gpointer user_data)
671 {
672  g_return_if_fail(gnc_acc);
673  /* Delete "online-id" and complete "hbci..." KVPs for GnuCash account */
674  gnc_account_delete_map_entry((Account *) gnc_acc, "online_id", NULL, NULL, FALSE);
675  gnc_account_delete_map_entry((Account *) gnc_acc, "hbci", NULL, NULL, FALSE);
676 }
677 
678 static void
679 save_kvp_acc_cb(gpointer key, gpointer value, gpointer user_data)
680 {
681  GNC_AB_ACCOUNT_SPEC *ab_acc = key;
682  Account *gnc_acc = value;
683  guint32 ab_account_uid;
684  const gchar *ab_accountid, *gnc_accountid;
685  const gchar *ab_bankcode, *gnc_bankcode;
686  gchar *ab_online_id;
687  gchar *gnc_online_id;
688 
689  g_return_if_fail(ab_acc && gnc_acc);
690 
691  ab_account_uid = AB_AccountSpec_GetUniqueId(ab_acc);
692  if (gnc_ab_get_account_uid(gnc_acc) != ab_account_uid)
693  gnc_ab_set_account_uid(gnc_acc, ab_account_uid);
694 
695  ab_accountid = AB_AccountSpec_GetAccountNumber(ab_acc);
696  gnc_accountid = gnc_ab_get_account_accountid(gnc_acc);
697  if (ab_accountid
698  && (!gnc_accountid
699  || (strcmp(ab_accountid, gnc_accountid) != 0)))
700  gnc_ab_set_account_accountid(gnc_acc, ab_accountid);
701 
702  ab_bankcode = AB_AccountSpec_GetBankCode(ab_acc);
703  gnc_bankcode = gnc_ab_get_account_bankcode(gnc_acc);
704  if (ab_bankcode
705  && (!gnc_bankcode
706  || (strcmp(gnc_bankcode, ab_bankcode) != 0)))
707  gnc_ab_set_account_bankcode(gnc_acc, ab_bankcode);
708 
709  ab_online_id = gnc_ab_create_online_id(ab_bankcode, ab_accountid);
710  gnc_online_id = gnc_import_get_acc_online_id(gnc_acc);
711  if (ab_online_id && (!gnc_online_id || (strcmp(ab_online_id, gnc_online_id) != 0)))
712  gnc_import_set_acc_online_id(gnc_acc, ab_online_id);
713  g_free(ab_online_id);
714  g_free (gnc_online_id);
715 }
716 
717 static void
718 aai_close_handler(gpointer user_data)
719 {
720  ABInitialInfo *info = user_data;
721 
722  gnc_save_window_size(GNC_PREFS_GROUP, GTK_WINDOW(info->window));
723  gtk_widget_destroy(info->window);
724 }
725 
726 void aai_on_prepare (GtkAssistant *assistant, GtkWidget *page,
727  gpointer user_data)
728 {
729  switch (gtk_assistant_get_current_page(assistant))
730  {
731  case 1:
732  /* Current page is wizard button page */
733  aai_page_prepare (assistant , user_data );
734  break;
735  case 2:
736  /* Current page is match page */
737  aai_match_page_prepare (assistant , user_data );
738  break;
739  }
740 }
741 
742 static ABInitialInfo *
743 gnc_ab_initial_assistant_new(void)
744 {
745  GtkBuilder *builder;
746  GtkTreeViewColumn *column;
747  GtkTreeSelection *selection;
748  gint component_id;
749 
750  ABInitialInfo *info = g_new0(ABInitialInfo, 1);
751  builder = gtk_builder_new();
752  gnc_builder_add_from_file (builder, "assistant-ab-initial.glade", "aqbanking_init_assistant");
753 
754  info->window = GTK_WIDGET(gtk_builder_get_object (builder, "aqbanking_init_assistant"));
755 
756  info->api = gnc_AB_BANKING_new();
757  info->deferred_info = NULL;
758  info->gnc_hash = NULL;
759 
760  info->match_page_prepared = FALSE;
761  info->account_view =
762  GTK_TREE_VIEW(gtk_builder_get_object (builder, "account_page_view"));
763 
764  info->account_store = gtk_list_store_new(NUM_ACCOUNT_LIST_COLS,
765  G_TYPE_INT, G_TYPE_STRING,
766  G_TYPE_POINTER, G_TYPE_STRING,
767  G_TYPE_BOOLEAN);
768  gtk_tree_view_set_model(info->account_view,
769  GTK_TREE_MODEL(info->account_store));
770  g_object_unref(info->account_store);
771 
772  column = gtk_tree_view_column_new_with_attributes(
773  _("Online Banking Account Name"), gtk_cell_renderer_text_new(),
774  "text", ACCOUNT_LIST_COL_AB_NAME, (gchar*) NULL);
775  gtk_tree_view_append_column(info->account_view, column);
776 
777  column = gtk_tree_view_column_new_with_attributes(
778  _("GnuCash Account Name"), gtk_cell_renderer_text_new(),
779  "text", ACCOUNT_LIST_COL_GNC_NAME, (gchar*) NULL);
780  gtk_tree_view_column_set_expand(column, TRUE);
781  gtk_tree_view_append_column(info->account_view, column);
782 
783  column = gtk_tree_view_column_new_with_attributes(
784  _("New?"), gtk_cell_renderer_toggle_new(),
785  "active", ACCOUNT_LIST_COL_CHECKED, (gchar*) NULL);
786  gtk_tree_view_append_column(info->account_view, column);
787 
788  selection = gtk_tree_view_get_selection(info->account_view);
789  gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
790 
791  gnc_restore_window_size (GNC_PREFS_GROUP,
792  GTK_WINDOW(info->window), gnc_ui_get_main_window(NULL));
793 
794  g_signal_connect(info->account_view, "row-activated",
795  G_CALLBACK(account_list_clicked_cb), info);
796 
797  g_signal_connect (G_OBJECT(info->window), "destroy",
798  G_CALLBACK (aai_destroy_cb), info);
799 
800  gtk_builder_connect_signals(builder, info);
801  g_object_unref(G_OBJECT(builder));
802 
803  component_id = gnc_register_gui_component(ASSISTANT_AB_INITIAL_CM_CLASS,
804  NULL, aai_close_handler, info);
805 
806  gnc_gui_component_set_session(component_id, gnc_get_current_session());
807  return info;
808 }
809 
810 void
812 {
813  if (!single_info)
814  single_info = gnc_ab_initial_assistant_new();
815  gtk_widget_show(single_info->window);
816 }
817 
guint32 gnc_ab_get_account_uid(const Account *a)
Return the unique id for the AB_BANKING account in the Account a.
Definition: gnc-ab-kvp.c:79
gchar * gnc_ab_create_online_id(const gchar *bankcode, const gchar *accountnumber)
Creates an online ID from bank code and account number.
Definition: gnc-ab-utils.c:295
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Returns the commodity table associated with a book.
void gnc_account_delete_map_entry(Account *acc, char *head, char *category, char *match_string, gboolean empty)
Delete the entry for Account pointed to by head,category and match_string, if empty is TRUE then use ...
Definition: Account.cpp:5691
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
utility functions for the GnuCash UI
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
AqBanking setup functionality.
STRUCTS.
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.
Generic and very flexible account matcher/picker.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
const gchar * gnc_ab_get_account_bankcode(const Account *a)
Return the bankcode string in the Account a.
Definition: gnc-ab-kvp.c:59
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
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...
Definition: Account.cpp:3275
void gnc_ab_set_account_accountid(Account *a, const gchar *id)
Set the accountid string in the Account a to id.
Definition: gnc-ab-kvp.c:49
void gnc_ab_set_account_uid(Account *a, guint32 uid)
Set the unique id for the AB_BANKING account in the Account a to uid.
Definition: gnc-ab-kvp.c:89
The bank account type denotes a savings or checking account held at a bank.
Definition: Account.h:107
AB_BANKING * gnc_AB_BANKING_new(void)
If there is a cached AB_BANKING object, return it initialized.
Definition: gnc-ab-utils.c:163
GLib helper routines.
void gnc_AB_BANKING_delete(AB_BANKING *api)
Delete the AB_BANKING api.
Definition: gnc-ab-utils.c:207
Utility functions for writing import modules.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
GNC_AB_ACCOUNT_SPEC * gnc_ab_get_ab_account(const AB_BANKING *api, Account *gnc_acc)
Get the corresponding AqBanking account to the GnuCash account gnc_acc.
Definition: gnc-ab-utils.c:249
void gnc_ab_initial_assistant(void)
Create and show an assistant for the aqbanking setup.
const gchar * gnc_ab_get_account_accountid(const Account *a)
Return accountid string in the Account a.
Definition: gnc-ab-kvp.c:39
void gnc_ab_set_account_bankcode(Account *a, const gchar *code)
Set the bankcode string in the Account a to code.
Definition: gnc-ab-kvp.c:69
AqBanking KVP handling.
AqBanking utility functions.