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