GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 [email protected]
20  */
21 
32 #include "config.h"
33 
34 #include <aqbanking/banking.h>
35 #include <glib.h>
36 #include <glib/gi18n.h>
37 #include <glib/gstdio.h>
38 #include <gdk/gdkkeysyms.h>
39 #ifdef HAVE_SYS_WAIT_H
40 # include <sys/wait.h>
41 #endif
42 #include <fcntl.h>
43 #include <unistd.h>
44 
45 #include "dialog-utils.h"
46 #include "assistant-ab-initial.h"
47 #include "assistant-utils.h"
48 #include "gnc-ab-kvp.h"
49 #include "gnc-ab-utils.h"
50 #include "gnc-component-manager.h"
51 #include "gnc-glib-utils.h"
52 #include "gnc-ui.h"
53 #include "gnc-ui-util.h"
54 #include "gnc-session.h"
55 #include "import-account-matcher.h"
56 
57 #if AQBANKING_VERSION_INT > 49908
58 /* For aqbanking > 4.99.8. See below. */
59 # include <aqbanking/dlg_setup.h>
60 #endif
61 
62 /* This static indicates the debugging module that this .o belongs to. */
63 static QofLogModule log_module = GNC_MOD_ASSISTANT;
64 
65 #define GNC_PREFS_GROUP "dialogs.ab-initial"
66 #define ASSISTANT_AB_INITIAL_CM_CLASS "assistant-ab-initial"
67 
68 typedef struct _ABInitialInfo ABInitialInfo;
69 typedef struct _DeferredInfo DeferredInfo;
70 typedef struct _AccCbData AccCbData;
71 typedef struct _RevLookupData RevLookupData;
72 
73 void aai_on_prepare (GtkAssistant *assistant, GtkWidget *page,
74  gpointer user_data);
75 
76 void aai_on_finish (GtkAssistant *gtkassistant, gpointer user_data);
77 void aai_on_cancel (GtkAssistant *assistant, gpointer user_data);
78 void aai_destroy_cb(GtkObject *object, gpointer user_data);
79 
80 gboolean aai_key_press_event_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
81 
82 void aai_wizard_page_prepare (GtkAssistant *assistant, gpointer user_data);
83 void aai_wizard_button_clicked_cb(GtkButton *button, gpointer user_data);
84 
85 void aai_match_page_prepare (GtkAssistant *assistant, gpointer user_data);
86 
87 static gboolean banking_has_accounts(AB_BANKING *banking);
88 static void hash_from_kvp_acc_cb(Account *gnc_acc, gpointer user_data);
89 #if AQBANKING_VERSION_INT <= 49908
90 static void child_exit_cb(GPid pid, gint status, gpointer data);
91 #endif
92 static gchar *ab_account_longname(const AB_ACCOUNT *ab_acc);
93 static AB_ACCOUNT *update_account_list_acc_cb(AB_ACCOUNT *ab_acc, gpointer user_data);
94 static void update_account_list(ABInitialInfo *info);
95 static gboolean find_gnc_acc_cb(gpointer key, gpointer value, gpointer user_data);
96 static gboolean clear_line_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data);
97 static void account_list_clicked_cb (GtkTreeView *view, GtkTreePath *path,
98  GtkTreeViewColumn *col, gpointer user_data);
99 static void clear_kvp_acc_cb(Account *gnc_acc, gpointer user_data);
100 static void save_kvp_acc_cb(gpointer key, gpointer value, gpointer user_data);
101 static void aai_close_handler(gpointer user_data);
102 
104 {
105  GtkWidget *window;
106  GtkWidget *assistant;
107 
108  /* account match page */
109  gboolean match_page_prepared;
110  GtkTreeView *account_view;
111  GtkListStore *account_store;
112 
113  /* managed by child_exit_cb */
114  DeferredInfo *deferred_info;
115 
116  /* AqBanking stuff */
117  AB_BANKING *api;
118  /* AB_ACCOUNT* -> Account* -- DO NOT DELETE THE KEYS! */
119  GHashTable *gnc_hash;
120 };
121 
123 {
124  ABInitialInfo *initial_info;
125  gchar *wizard_path;
126  gboolean qt_probably_unavailable;
127 };
128 
130 {
131  AB_BANKING *api;
132  GHashTable *hash;
133 };
134 
136 {
137  Account *gnc_acc;
138  AB_ACCOUNT *ab_acc;
139 };
140 
141 enum account_list_cols
142 {
143  ACCOUNT_LIST_COL_INDEX = 0,
144  ACCOUNT_LIST_COL_AB_NAME,
145  ACCOUNT_LIST_COL_AB_ACCT,
146  ACCOUNT_LIST_COL_GNC_NAME,
147  ACCOUNT_LIST_COL_CHECKED,
148  NUM_ACCOUNT_LIST_COLS
149 };
150 
151 gboolean
152 aai_key_press_event_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
153 {
154  if (event->keyval == GDK_Escape)
155  {
156  gtk_widget_destroy(widget);
157  return TRUE;
158  }
159  else
160  {
161  return FALSE;
162  }
163 }
164 
165 void
166 aai_on_cancel (GtkAssistant *gtkassistant, gpointer user_data)
167 {
168  ABInitialInfo *info = user_data;
169 
170  gtk_widget_destroy(info->window);
171 }
172 
173 void
174 aai_destroy_cb(GtkObject *object, gpointer user_data)
175 {
176  ABInitialInfo *info = user_data;
177 
178  gnc_unregister_gui_component_by_data(ASSISTANT_AB_INITIAL_CM_CLASS, info);
179 
180  if (info->deferred_info)
181  {
182  g_message("Online Banking assistant is being closed but the wizard is still "
183  "running. Inoring.");
184 
185  /* Tell child_exit_cb() that there is no assistant anymore */
186  info->deferred_info->initial_info = NULL;
187  }
188 
189  if (info->gnc_hash)
190  {
191 #ifdef AQBANKING_VERSION_4_EXACTLY
192  AB_Banking_OnlineFini(info->api, 0);
193 #else
194  AB_Banking_OnlineFini(info->api);
195 #endif
196  g_hash_table_destroy(info->gnc_hash);
197  info->gnc_hash = NULL;
198  }
199 
200  if (info->api)
201  {
202  gnc_AB_BANKING_delete(info->api);
203  info->api = NULL;
204  }
205 
206  gtk_widget_destroy(info->window);
207  info->window = NULL;
208 
209  g_free(info);
210 }
211 
212 void
213 aai_wizard_page_prepare (GtkAssistant *assistant, gpointer user_data)
214 {
215  ABInitialInfo *info = user_data;
216  gint num = gtk_assistant_get_current_page (assistant);
217  GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
218 
219  g_return_if_fail(info->api);
220 
221  /* Enable the Assistant Buttons if we accounts */
222  if (banking_has_accounts(info->api))
223  gtk_assistant_set_page_complete (assistant, page, TRUE);
224  else
225  gtk_assistant_set_page_complete (assistant, page, FALSE);
226 }
227 
228 void
229 aai_wizard_button_clicked_cb(GtkButton *button, gpointer user_data)
230 {
231  ABInitialInfo *info = user_data;
232  gint num = gtk_assistant_get_current_page (GTK_ASSISTANT(info->window));
233  GtkWidget *page = gtk_assistant_get_nth_page (GTK_ASSISTANT(info->window), num);
234 
235  AB_BANKING *banking = info->api;
236 #if AQBANKING_VERSION_INT <= 49908
237  GWEN_BUFFER *buf;
238  gboolean wizard_exists;
239  const gchar *wizard_path;
240  gboolean qt_probably_unavailable = FALSE;
241 #endif /* AQBANKING_VERSION_INT */
242  g_return_if_fail(banking);
243 
244  ENTER("user_data: %p", user_data);
245 
246  if (info->deferred_info)
247  {
248  LEAVE("Wizard is still running");
249  return;
250  }
251 
252 #if AQBANKING_VERSION_INT > 49908
253  /* For aqbanking5 > 4.99.8: Use AB_Banking_GetNewUserDialog(). */
254  {
255  GWEN_DIALOG *dlg =
256  AB_SetupDialog_new(banking);
257 
258  if (AB_Banking_OnlineInit(banking) != 0)
259  {
260  PERR("Got error on AB_Banking_OnlineInit!");
261  }
262 
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 !");
274  }
275  GWEN_Dialog_free(dlg);
276  }
277 
278  if (AB_Banking_OnlineFini(banking) != 0)
279  {
280  PERR("Got error on AB_Banking_OnlineFini!");
281  }
282  }
283 #else
284  /* Previous implementation for aqbanking <= 4.99.8: Use the
285  * external application. */
286 
287 
288  /* This is the point where we look for and start an external
289  * application shipped with aqbanking that contains the setup assistant
290  * for AqBanking related stuff. It requires qt (but not kde). This
291  * application contains the very verbose step-by-step setup wizard
292  * for the AqBanking account, and the application is shared with
293  * other AqBanking-based financial managers that offer the AqBanking
294  * features (e.g. KMyMoney). See gnucash-devel discussion here
295  * https://lists.gnucash.org/pipermail/gnucash-devel/2004-December/012351.html
296  */
297  buf = GWEN_Buffer_new(NULL, 300, 0, 0);
298  AB_Banking_FindWizard(banking, "", NULL, buf);
299  wizard_exists = *GWEN_Buffer_GetStart(buf) != 0;
300  wizard_path = GWEN_Buffer_GetStart(buf);
301 
302  if (wizard_exists)
303  {
304  /* Really check whether the file exists */
305  gint fd = g_open(wizard_path, O_RDONLY, 0);
306  if (fd == -1)
307  wizard_exists = FALSE;
308  else
309  close(fd);
310  }
311 
312 #ifdef G_OS_WIN32
313  {
314  const char *check_file = "qtdemo.exe";
315  gchar *found_program = g_find_program_in_path(check_file);
316  if (found_program)
317  {
318  g_debug("Yes, we found the Qt demo program in %s\n", found_program);
319  g_free(found_program);
320  }
321  else
322  {
323  g_warning("Ouch, no Qt demo program was found. Qt not installed?\n");
324  qt_probably_unavailable = TRUE;
325  }
326  }
327 #endif
328 
329  if (wizard_exists)
330  {
331  /* Call the qt wizard. See the note above about why this
332  * approach is chosen. */
333 
334  GPid pid;
335  GError *error = NULL;
336  gchar *argv[2];
337  gboolean spawned;
338 
339  argv[0] = g_strdup (wizard_path);
340  argv[1] = NULL;
341  spawned = g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
342  NULL, NULL, &pid, &error);
343  g_free (argv[0]);
344 
345  if (error)
346  g_critical(
347  "Error on starting AqBanking setup wizard: Code %d: %s",
348  error->code, error->message ? error->message : "(null)");
349 
350  if (!spawned)
351  {
352  g_critical("Could not start AqBanking setup wizard: %s",
353  error->message ? error->message : "(null)");
354  g_error_free (error);
355  }
356  else
357  {
358  /* Keep a reference to info that can survive info */
359  info->deferred_info = g_new0(DeferredInfo, 1);
360  info->deferred_info->initial_info = info;
361  info->deferred_info->wizard_path = g_strdup(wizard_path);
362  info->deferred_info->qt_probably_unavailable =
363  qt_probably_unavailable;
364 
365  g_child_watch_add (pid, child_exit_cb, info->deferred_info);
366  }
367  }
368  else
369  {
370  g_warning("on_aqhbci_button: Oops, no aqhbci setup wizard found.");
371  gnc_error_dialog
372  (info->window,
373  _("The external program \"AqBanking Setup Wizard\" has not "
374  "been found. \n\n"
375  "The %s package should include the "
376  "program \"qt3-wizard\". Please check your installation to "
377  "ensure this program is present. On some distributions this "
378  "may require installing additional packages."),
379  QT3_WIZARD_PACKAGE);
380  }
381 
382  GWEN_Buffer_free(buf);
383 #endif
384 
385  /* Enable the Assistant Buttons if we accounts */
386  if (banking_has_accounts(info->api))
387  gtk_assistant_set_page_complete (GTK_ASSISTANT(info->window), page, TRUE);
388  else
389  gtk_assistant_set_page_complete (GTK_ASSISTANT(info->window), page, FALSE);
390 
391  LEAVE(" ");
392 }
393 
394 void
395 aai_match_page_prepare (GtkAssistant *assistant, gpointer user_data)
396 {
397  ABInitialInfo *info = user_data;
398  gint num = gtk_assistant_get_current_page (assistant);
399  GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
400 
401  Account *root;
402  AccCbData data;
403 
404  g_return_if_fail(info && info->api);
405 
406  /* Do not run this twice */
407  if (!info->match_page_prepared)
408  {
409  /* Load aqbanking accounts */
410 #ifdef AQBANKING_VERSION_4_EXACTLY
411  AB_Banking_OnlineInit(info->api, 0);
412 #else
413  AB_Banking_OnlineInit(info->api);
414 #endif
415  /* Determine current mapping */
416  root = gnc_book_get_root_account(gnc_get_current_book());
417  info->gnc_hash = g_hash_table_new(&g_direct_hash, &g_direct_equal);
418  data.api = info->api;
419  data.hash = info->gnc_hash;
421  root, (AccountCb) hash_from_kvp_acc_cb, &data);
422 
423  info->match_page_prepared = TRUE;
424  }
425  /* Update the graphical representation */
426  update_account_list(info);
427 
428  /* Enable the Assistant Buttons */
429  gtk_assistant_set_page_complete (assistant, page, TRUE);
430 }
431 
432 void
433 aai_on_finish (GtkAssistant *assistant, gpointer user_data)
434 {
435  ABInitialInfo *info = user_data;
436  Account *root;
437 
438  g_return_if_fail(info && info->gnc_hash);
439 
440  /* Commit the changes */
441  root = gnc_book_get_root_account(gnc_get_current_book());
442  gnc_account_foreach_descendant(root, (AccountCb) clear_kvp_acc_cb, NULL);
443  g_hash_table_foreach(info->gnc_hash, (GHFunc) save_kvp_acc_cb, NULL);
444 
445  gtk_widget_destroy(info->window);
446 }
447 
448 static gboolean
449 banking_has_accounts(AB_BANKING *banking)
450 {
451  AB_ACCOUNT_LIST2 *accl;
452  gboolean result;
453 
454  g_return_val_if_fail(banking, FALSE);
455 
456 #ifdef AQBANKING_VERSION_4_EXACTLY
457  AB_Banking_OnlineInit(banking, 0);
458 #else
459  AB_Banking_OnlineInit(banking);
460 #endif
461 
462  accl = AB_Banking_GetAccounts(banking);
463  if (accl && (AB_Account_List2_GetSize(accl) > 0))
464  result = TRUE;
465  else
466  result = FALSE;
467 
468  if (accl)
469  AB_Account_List2_free(accl);
470 
471 #ifdef AQBANKING_VERSION_4_EXACTLY
472  AB_Banking_OnlineFini(banking, 0);
473 #else
474  AB_Banking_OnlineFini(banking);
475 #endif
476 
477  return result;
478 }
479 
480 static void
481 hash_from_kvp_acc_cb(Account *gnc_acc, gpointer user_data)
482 {
483  AccCbData *data = user_data;
484  AB_ACCOUNT *ab_acc;
485 
486  ab_acc = gnc_ab_get_ab_account(data->api, gnc_acc);
487  if (ab_acc)
488  g_hash_table_insert(data->hash, ab_acc, gnc_acc);
489 }
490 
491 #if AQBANKING_VERSION_INT <= 49908
492 static void
493 child_exit_cb(GPid pid, gint status, gpointer data)
494 {
495  DeferredInfo *deferred_info = data;
496  ABInitialInfo *info = deferred_info->initial_info;
497  gint num = gtk_assistant_get_current_page (GTK_ASSISTANT(info->window));
498  GtkWidget *page = gtk_assistant_get_nth_page (GTK_ASSISTANT(info->window), num);
499 
500  gint exit_status;
501 
502 #ifdef G_OS_WIN32
503  exit_status = status;
504 #else
505  exit_status = WEXITSTATUS(status);
506 #endif
507 
508  g_spawn_close_pid(pid);
509 
510  if (!info)
511  {
512  g_message("Online Banking wizard exited, but the assistant has been "
513  "destroyed already");
514  goto cleanup_child_exit_cb;
515  }
516 
517  if (exit_status == 0)
518  {
519  gtk_assistant_set_page_complete (GTK_ASSISTANT(info->window), page, TRUE);
520  }
521  else
522  {
523  if (deferred_info->qt_probably_unavailable)
524  {
525  g_warning("on_aqhbci_button: Oops, aqhbci wizard return nonzero "
526  "value: %d. The called program was \"%s\".\n",
527  exit_status, deferred_info->wizard_path);
528  gnc_error_dialog
529  (info->window, "%s",
530  _("The external program \"AqBanking Setup Wizard\" failed "
531  "to run successfully because the "
532  "additional software \"Qt\" was not found. "
533  "Please install the \"Qt/Windows Open Source Edition\" "
534  "from Trolltech by downloading it from www.trolltech.com"
535  "\n\n"
536  "If you have installed Qt already, you will have to adapt "
537  "the PATH variable of your system appropriately. "
538  "Contact the GnuCash developers if you need further "
539  "assistance on how to install Qt correctly."
540  "\n\n"
541  "Online Banking cannot be setup without Qt. Press \"Close\" "
542  "now, then \"Cancel\" to cancel the Online Banking setup."));
543  }
544  else
545  {
546  g_warning("on_aqhbci_button: Oops, aqhbci wizard return nonzero "
547  "value: %d. The called program was \"%s\".\n",
548  exit_status, deferred_info->wizard_path);
549  gnc_error_dialog
550  (info->window, "%s",
551  _("The external program \"AqBanking Setup Wizard\" failed "
552  "to run successfully. Online Banking can only be setup "
553  "if this wizard has run successfully. "
554  "Please try running the \"AqBanking Setup Wizard\" again."));
555  }
556  gtk_assistant_set_page_complete (GTK_ASSISTANT(info->window), page, FALSE);
557  }
558 
559 cleanup_child_exit_cb:
560  g_free(deferred_info->wizard_path);
561  g_free(deferred_info);
562  if (info)
563  info->deferred_info = NULL;
564 }
565 #endif /* AQBANKING_VERSION_INT <= 49908 */
566 
567 static gchar *
568 ab_account_longname(const AB_ACCOUNT *ab_acc)
569 {
570  gchar *bankname;
571  gchar *result;
572  const char *ab_bankname, *bankcode, *subAccountId;
573 
574  g_return_val_if_fail(ab_acc, NULL);
575 
576  ab_bankname = AB_Account_GetBankName(ab_acc);
577  bankname = ab_bankname ? gnc_utf8_strip_invalid_strdup(ab_bankname) : NULL;
578  bankcode = AB_Account_GetBankCode(ab_acc);
579  subAccountId = AB_Account_GetSubAccountId(ab_acc);
580 
581  /* Translators: Strings are 1. Account code, 2. Bank name, 3. Bank code. */
582  result = g_strdup_printf(_("Bank code %s (%s), Account %s (%s)"),
583  bankcode,
584  bankname ? bankname : "",
585  AB_Account_GetAccountNumber(ab_acc),
586  subAccountId ? subAccountId : "");
587  g_free(bankname);
588 
589  return result;
590 
591 }
592 
593 static AB_ACCOUNT *
594 update_account_list_acc_cb(AB_ACCOUNT *ab_acc, gpointer user_data)
595 {
596  ABInitialInfo *info = user_data;
597  gchar *gnc_name, *ab_name;
598  Account *gnc_acc;
599  GtkTreeIter iter;
600 
601  g_return_val_if_fail(ab_acc && info, NULL);
602 
603  ab_name = ab_account_longname(ab_acc);
604 
605  /* Get corresponding gnucash account */
606  gnc_acc = g_hash_table_lookup(info->gnc_hash, ab_acc);
607 
608  /* Build the text for the gnucash account. */
609  if (gnc_acc)
610  gnc_name = gnc_account_get_full_name(gnc_acc);
611  else
612  gnc_name = g_strdup("");
613 
614  /* Add item to the list store */
615  gtk_list_store_append(info->account_store, &iter);
616  gtk_list_store_set(info->account_store, &iter,
617  ACCOUNT_LIST_COL_AB_NAME, ab_name,
618  ACCOUNT_LIST_COL_AB_ACCT, ab_acc,
619  ACCOUNT_LIST_COL_GNC_NAME, gnc_name,
620  ACCOUNT_LIST_COL_CHECKED, FALSE,
621  -1);
622  g_free(gnc_name);
623  g_free(ab_name);
624 
625  return NULL;
626 }
627 
628 static void
629 update_account_list(ABInitialInfo *info)
630 {
631  AB_ACCOUNT_LIST2 *acclist;
632 
633  g_return_if_fail(info && info->api && info->gnc_hash);
634 
635  /* Detach model from view while updating */
636  g_object_ref(info->account_store);
637  gtk_tree_view_set_model(info->account_view, NULL);
638 
639  /* Refill the list */
640  gtk_list_store_clear(info->account_store);
641  acclist = AB_Banking_GetAccounts(info->api);
642  if (acclist)
643  AB_Account_List2_ForEach(acclist, update_account_list_acc_cb, info);
644  else
645  g_warning("update_account_list: Oops, account list from AB_Banking "
646  "is NULL");
647 
648  /* Attach model to view again */
649  gtk_tree_view_set_model(info->account_view,
650  GTK_TREE_MODEL(info->account_store));
651 
652  g_object_unref(info->account_store);
653 }
654 
655 static gboolean
656 find_gnc_acc_cb(gpointer key, gpointer value, gpointer user_data)
657 {
658  RevLookupData *data = user_data;
659 
660  g_return_val_if_fail(data, TRUE);
661 
662  if (value == data->gnc_acc)
663  {
664  data->ab_acc = (AB_ACCOUNT*) key;
665  return TRUE;
666  }
667  return FALSE;
668 }
669 
670 static gboolean
671 clear_line_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
672  gpointer user_data)
673 {
674  RevLookupData *data = user_data;
675  GtkListStore *store = GTK_LIST_STORE(model);
676  gpointer ab_acc;
677 
678  g_return_val_if_fail(data && store, FALSE);
679 
680  gtk_tree_model_get(model, iter, ACCOUNT_LIST_COL_AB_ACCT, &ab_acc, -1);
681 
682  if (ab_acc == data->ab_acc)
683  {
684  gtk_list_store_set(store, iter, ACCOUNT_LIST_COL_GNC_NAME, "",
685  ACCOUNT_LIST_COL_CHECKED, TRUE, -1);
686  return TRUE;
687  }
688  return FALSE;
689 }
690 
691 static void
692 account_list_clicked_cb (GtkTreeView *view, GtkTreePath *path,
693  GtkTreeViewColumn *col, gpointer user_data)
694 {
695  ABInitialInfo *info = user_data;
696  GtkTreeModel *model;
697  GtkTreeIter iter;
698  AB_ACCOUNT *ab_acc;
699  gchar *longname, *gnc_name;
700  Account *old_value, *gnc_acc;
701  const gchar *currency;
702  gnc_commodity *commodity = NULL;
703  gboolean ok_pressed;
704 
705  g_return_if_fail(info);
706 
707  PINFO("Row has been double-clicked.");
708 
709  model = gtk_tree_view_get_model(view);
710 
711  if (!gtk_tree_model_get_iter(model, &iter, path))
712  return; /* path describes a non-existing row - should not happen */
713 
714  gtk_tree_model_get(model, &iter, ACCOUNT_LIST_COL_AB_ACCT, &ab_acc, -1);
715 
716  if (ab_acc)
717  {
718  old_value = g_hash_table_lookup(info->gnc_hash, ab_acc);
719 
720  longname = ab_account_longname(ab_acc);
721  currency = AB_Account_GetCurrency(ab_acc);
722  if (currency && *currency)
723  {
724  commodity = gnc_commodity_table_lookup(
725  gnc_commodity_table_get_table(gnc_get_current_book()),
726  GNC_COMMODITY_NS_CURRENCY,
727  currency);
728  }
729 
730  gnc_acc = gnc_import_select_account(info->window, NULL, TRUE,
731  longname, commodity, ACCT_TYPE_BANK,
732  old_value, &ok_pressed);
733  g_free(longname);
734 
735  if (ok_pressed && old_value != gnc_acc)
736  {
737  if (gnc_acc)
738  {
739  RevLookupData data;
740 
741  /* Lookup and clear other mappings to gnc_acc */
742  data.gnc_acc = gnc_acc;
743  data.ab_acc = NULL;
744  g_hash_table_find(info->gnc_hash, (GHRFunc) find_gnc_acc_cb,
745  &data);
746  if (data.ab_acc)
747  {
748  g_hash_table_remove(info->gnc_hash, data.ab_acc);
749  gtk_tree_model_foreach(
750  GTK_TREE_MODEL(info->account_store),
751  (GtkTreeModelForeachFunc) clear_line_cb,
752  &data);
753  }
754 
755  /* Map ab_acc to gnc_acc */
756  g_hash_table_insert(info->gnc_hash, ab_acc, gnc_acc);
757  gnc_name = gnc_account_get_full_name(gnc_acc);
758  gtk_list_store_set(info->account_store, &iter,
759  ACCOUNT_LIST_COL_GNC_NAME, gnc_name,
760  ACCOUNT_LIST_COL_CHECKED, TRUE,
761  -1);
762  g_free(gnc_name);
763 
764  }
765  else
766  {
767  g_hash_table_remove(info->gnc_hash, ab_acc);
768  gtk_list_store_set(info->account_store, &iter,
769  ACCOUNT_LIST_COL_GNC_NAME, "",
770  ACCOUNT_LIST_COL_CHECKED, TRUE,
771  -1);
772  }
773  }
774  }
775 }
776 
777 static void
778 clear_kvp_acc_cb(Account *gnc_acc, gpointer user_data)
779 {
780  if (gnc_ab_get_account_uid(gnc_acc))
781  gnc_ab_set_account_uid(gnc_acc, 0);
782  if (gnc_ab_get_account_accountid(gnc_acc))
783  gnc_ab_set_account_accountid(gnc_acc, "");
784  if (gnc_ab_get_account_bankcode(gnc_acc))
785  gnc_ab_set_account_bankcode(gnc_acc, "");
786 }
787 
788 static void
789 save_kvp_acc_cb(gpointer key, gpointer value, gpointer user_data)
790 {
791  AB_ACCOUNT *ab_acc = key;
792  Account *gnc_acc = value;
793  guint32 ab_account_uid;
794  const gchar *ab_accountid, *gnc_accountid;
795  const gchar *ab_bankcode, *gnc_bankcode;
796 
797  g_return_if_fail(ab_acc && gnc_acc);
798 
799  ab_account_uid = AB_Account_GetUniqueId(ab_acc);
800  if (gnc_ab_get_account_uid(gnc_acc) != ab_account_uid)
801  gnc_ab_set_account_uid(gnc_acc, ab_account_uid);
802 
803  ab_accountid = AB_Account_GetAccountNumber(ab_acc);
804  gnc_accountid = gnc_ab_get_account_accountid(gnc_acc);
805  if (ab_accountid
806  && (!gnc_accountid
807  || (strcmp(ab_accountid, gnc_accountid) != 0)))
808  gnc_ab_set_account_accountid(gnc_acc, ab_accountid);
809 
810  ab_bankcode = AB_Account_GetBankCode(ab_acc);
811  gnc_bankcode = gnc_ab_get_account_bankcode(gnc_acc);
812  if (ab_bankcode
813  && (!gnc_bankcode
814  || (strcmp(gnc_bankcode, ab_bankcode) != 0)))
815  gnc_ab_set_account_bankcode(gnc_acc, ab_bankcode);
816 }
817 
818 static void
819 aai_close_handler(gpointer user_data)
820 {
821  ABInitialInfo *info = user_data;
822 
823  gnc_save_window_size(GNC_PREFS_GROUP, GTK_WINDOW(info->window));
824  gtk_widget_destroy(info->window);
825 }
826 
827 void aai_on_prepare (GtkAssistant *assistant, GtkWidget *page,
828  gpointer user_data)
829 {
830  switch (gtk_assistant_get_current_page(assistant))
831  {
832  case 1:
833  /* Current page is wizard button page */
834  aai_wizard_page_prepare (assistant , user_data );
835  break;
836  case 2:
837  /* Current page is match page */
838  aai_match_page_prepare (assistant , user_data );
839  break;
840  }
841 }
842 
843 void
845 {
846  ABInitialInfo *info;
847  GtkBuilder *builder;
848  GtkTreeViewColumn *column;
849  GtkTreeSelection *selection;
850  gint component_id;
851 
852  info = g_new0(ABInitialInfo, 1);
853  builder = gtk_builder_new();
854  gnc_builder_add_from_file (builder, "assistant-ab-initial.glade", "AqBanking Init Assistant");
855 
856  info->window = GTK_WIDGET(gtk_builder_get_object (builder, "AqBanking Init Assistant"));
857 
858  gnc_assistant_set_colors (GTK_ASSISTANT (info->assistant));
859 
860  info->api = gnc_AB_BANKING_new();
861  info->deferred_info = NULL;
862  info->gnc_hash = NULL;
863 
864  info->match_page_prepared = FALSE;
865  info->account_view =
866  GTK_TREE_VIEW(gtk_builder_get_object (builder, "account_page_view"));
867 
868  info->account_store = gtk_list_store_new(NUM_ACCOUNT_LIST_COLS,
869  G_TYPE_INT, G_TYPE_STRING,
870  G_TYPE_POINTER, G_TYPE_STRING,
871  G_TYPE_BOOLEAN);
872  gtk_tree_view_set_model(info->account_view,
873  GTK_TREE_MODEL(info->account_store));
874  g_object_unref(info->account_store);
875 
876  column = gtk_tree_view_column_new_with_attributes(
877  _("Online Banking Account Name"), gtk_cell_renderer_text_new(),
878  "text", ACCOUNT_LIST_COL_AB_NAME, (gchar*) NULL);
879  gtk_tree_view_append_column(info->account_view, column);
880 
881  column = gtk_tree_view_column_new_with_attributes(
882  _("GnuCash Account Name"), gtk_cell_renderer_text_new(),
883  "text", ACCOUNT_LIST_COL_GNC_NAME, (gchar*) NULL);
884  gtk_tree_view_column_set_expand(column, TRUE);
885  gtk_tree_view_append_column(info->account_view, column);
886 
887  column = gtk_tree_view_column_new_with_attributes(
888  _("New?"), gtk_cell_renderer_toggle_new(),
889  "active", ACCOUNT_LIST_COL_CHECKED, (gchar*) NULL);
890  gtk_tree_view_append_column(info->account_view, column);
891 
892  selection = gtk_tree_view_get_selection(info->account_view);
893  gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
894 
895  gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(info->window));
896 
897  g_signal_connect(info->account_view, "row-activated",
898  G_CALLBACK(account_list_clicked_cb), info);
899 
900  g_signal_connect (G_OBJECT(info->window), "destroy",
901  G_CALLBACK (aai_destroy_cb), info);
902 
903  gtk_builder_connect_signals(builder, info);
904  g_object_unref(G_OBJECT(builder));
905 
906  component_id = gnc_register_gui_component(ASSISTANT_AB_INITIAL_CM_CLASS,
907  NULL, aai_close_handler, info);
908 
909  gnc_gui_component_set_session(component_id, gnc_get_current_session());
910 
911  gtk_widget_show(info->window);
912 }
guint32 gnc_ab_get_account_uid(const Account *a)
Definition: gnc-ab-kvp.c:79
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
Definition: Account.c:2958
utility functions for the GnuCash UI
#define PINFO(format, args...)
Definition: qoflog.h:249
AqBanking setup functionality.
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)
Generic and very flexible account matcher/picker.
#define PERR(format, args...)
Definition: qoflog.h:237
const gchar * gnc_ab_get_account_bankcode(const Account *a)
Definition: gnc-ab-kvp.c:59
#define ENTER(format, args...)
Definition: qoflog.h:261
gchar * gnc_account_get_full_name(const Account *account)
Definition: Account.c:3038
void gnc_ab_set_account_accountid(Account *a, const gchar *id)
Definition: gnc-ab-kvp.c:49
void gnc_ab_set_account_uid(Account *a, guint32 uid)
Definition: gnc-ab-kvp.c:89
AB_BANKING * gnc_AB_BANKING_new(void)
Definition: gnc-ab-utils.c:137
GLib helper routines.
void gnc_AB_BANKING_delete(AB_BANKING *api)
Definition: gnc-ab-utils.c:218
gchar * gnc_utf8_strip_invalid_strdup(const gchar *str)
AB_ACCOUNT * gnc_ab_get_ab_account(const AB_BANKING *api, Account *gnc_acc)
Definition: gnc-ab-utils.c:264
#define LEAVE(format, args...)
Definition: qoflog.h:271
void gnc_ab_initial_assistant(void)
const gchar * gnc_ab_get_account_accountid(const Account *a)
Definition: gnc-ab-kvp.c:39
void gnc_ab_set_account_bankcode(Account *a, const gchar *code)
Definition: gnc-ab-kvp.c:69
AqBanking KVP handling.
AqBanking utility functions.
const gchar * QofLogModule
Definition: qofid.h:89