34 #include <aqbanking/banking.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>
45 #include "dialog-utils.h"
47 #include "assistant-utils.h"
50 #include "gnc-component-manager.h"
54 #include "gnc-session.h"
57 #if AQBANKING_VERSION_INT > 49908
59 # include <aqbanking/dlg_setup.h>
65 #define GNC_PREFS_GROUP "dialogs.ab-initial"
66 #define ASSISTANT_AB_INITIAL_CM_CLASS "assistant-ab-initial"
73 void aai_on_prepare (GtkAssistant *assistant, GtkWidget *page,
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);
80 gboolean aai_key_press_event_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
82 void aai_wizard_page_prepare (GtkAssistant *assistant, gpointer user_data);
83 void aai_wizard_button_clicked_cb(GtkButton *button, gpointer user_data);
85 void aai_match_page_prepare (GtkAssistant *assistant, gpointer user_data);
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);
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);
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);
106 GtkWidget *assistant;
109 gboolean match_page_prepared;
110 GtkTreeView *account_view;
111 GtkListStore *account_store;
119 GHashTable *gnc_hash;
126 gboolean qt_probably_unavailable;
141 enum account_list_cols
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
152 aai_key_press_event_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
154 if (event->keyval == GDK_Escape)
156 gtk_widget_destroy(widget);
166 aai_on_cancel (GtkAssistant *gtkassistant, gpointer user_data)
170 gtk_widget_destroy(info->window);
174 aai_destroy_cb(GtkObject *
object, gpointer user_data)
178 gnc_unregister_gui_component_by_data(ASSISTANT_AB_INITIAL_CM_CLASS, info);
180 if (info->deferred_info)
182 g_message(
"Online Banking assistant is being closed but the wizard is still "
183 "running. Inoring.");
186 info->deferred_info->initial_info = NULL;
191 #ifdef AQBANKING_VERSION_4_EXACTLY
192 AB_Banking_OnlineFini(info->api, 0);
194 AB_Banking_OnlineFini(info->api);
196 g_hash_table_destroy(info->gnc_hash);
197 info->gnc_hash = NULL;
206 gtk_widget_destroy(info->window);
213 aai_wizard_page_prepare (GtkAssistant *assistant, gpointer user_data)
216 gint num = gtk_assistant_get_current_page (assistant);
217 GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
219 g_return_if_fail(info->api);
222 if (banking_has_accounts(info->api))
223 gtk_assistant_set_page_complete (assistant, page, TRUE);
225 gtk_assistant_set_page_complete (assistant, page, FALSE);
229 aai_wizard_button_clicked_cb(GtkButton *button, gpointer 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);
235 AB_BANKING *banking = info->api;
236 #if AQBANKING_VERSION_INT <= 49908
238 gboolean wizard_exists;
239 const gchar *wizard_path;
240 gboolean qt_probably_unavailable = FALSE;
242 g_return_if_fail(banking);
244 ENTER(
"user_data: %p", user_data);
246 if (info->deferred_info)
248 LEAVE(
"Wizard is still running");
252 #if AQBANKING_VERSION_INT > 49908
256 AB_SetupDialog_new(banking);
258 if (AB_Banking_OnlineInit(banking) != 0)
260 PERR(
"Got error on AB_Banking_OnlineInit!");
265 PERR(
"Could not lookup Setup Dialog of aqbanking!");
269 int rv = GWEN_Gui_ExecDialog(dlg, 0);
273 PERR(
"Setup Dialog of aqbanking aborted/rejected !");
275 GWEN_Dialog_free(dlg);
278 if (AB_Banking_OnlineFini(banking) != 0)
280 PERR(
"Got error on AB_Banking_OnlineFini!");
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);
305 gint fd = g_open(wizard_path, O_RDONLY, 0);
307 wizard_exists = FALSE;
314 const char *check_file =
"qtdemo.exe";
315 gchar *found_program = g_find_program_in_path(check_file);
318 g_debug(
"Yes, we found the Qt demo program in %s\n", found_program);
319 g_free(found_program);
323 g_warning(
"Ouch, no Qt demo program was found. Qt not installed?\n");
324 qt_probably_unavailable = TRUE;
335 GError *error = NULL;
339 argv[0] = g_strdup (wizard_path);
341 spawned = g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
342 NULL, NULL, &pid, &error);
347 "Error on starting AqBanking setup wizard: Code %d: %s",
348 error->code, error->message ? error->message :
"(null)");
352 g_critical(
"Could not start AqBanking setup wizard: %s",
353 error->message ? error->message :
"(null)");
354 g_error_free (error);
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;
365 g_child_watch_add (pid, child_exit_cb, info->deferred_info);
370 g_warning(
"on_aqhbci_button: Oops, no aqhbci setup wizard found.");
373 _(
"The external program \"AqBanking Setup Wizard\" has not "
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."),
382 GWEN_Buffer_free(buf);
386 if (banking_has_accounts(info->api))
387 gtk_assistant_set_page_complete (GTK_ASSISTANT(info->window), page, TRUE);
389 gtk_assistant_set_page_complete (GTK_ASSISTANT(info->window), page, FALSE);
395 aai_match_page_prepare (GtkAssistant *assistant, gpointer user_data)
398 gint num = gtk_assistant_get_current_page (assistant);
399 GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
404 g_return_if_fail(info && info->api);
407 if (!info->match_page_prepared)
410 #ifdef AQBANKING_VERSION_4_EXACTLY
411 AB_Banking_OnlineInit(info->api, 0);
413 AB_Banking_OnlineInit(info->api);
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);
423 info->match_page_prepared = TRUE;
426 update_account_list(info);
429 gtk_assistant_set_page_complete (assistant, page, TRUE);
433 aai_on_finish (GtkAssistant *assistant, gpointer user_data)
438 g_return_if_fail(info && info->gnc_hash);
441 root = gnc_book_get_root_account(gnc_get_current_book());
443 g_hash_table_foreach(info->gnc_hash, (GHFunc) save_kvp_acc_cb, NULL);
445 gtk_widget_destroy(info->window);
449 banking_has_accounts(AB_BANKING *banking)
451 AB_ACCOUNT_LIST2 *accl;
454 g_return_val_if_fail(banking, FALSE);
456 #ifdef AQBANKING_VERSION_4_EXACTLY
457 AB_Banking_OnlineInit(banking, 0);
459 AB_Banking_OnlineInit(banking);
462 accl = AB_Banking_GetAccounts(banking);
463 if (accl && (AB_Account_List2_GetSize(accl) > 0))
469 AB_Account_List2_free(accl);
471 #ifdef AQBANKING_VERSION_4_EXACTLY
472 AB_Banking_OnlineFini(banking, 0);
474 AB_Banking_OnlineFini(banking);
481 hash_from_kvp_acc_cb(
Account *gnc_acc, gpointer user_data)
488 g_hash_table_insert(data->hash, ab_acc, gnc_acc);
491 #if AQBANKING_VERSION_INT <= 49908
493 child_exit_cb(GPid pid, gint status, gpointer data)
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);
503 exit_status = status;
505 exit_status = WEXITSTATUS(status);
508 g_spawn_close_pid(pid);
512 g_message(
"Online Banking wizard exited, but the assistant has been "
513 "destroyed already");
514 goto cleanup_child_exit_cb;
517 if (exit_status == 0)
519 gtk_assistant_set_page_complete (GTK_ASSISTANT(info->window), page, TRUE);
523 if (deferred_info->qt_probably_unavailable)
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);
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"
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."
541 "Online Banking cannot be setup without Qt. Press \"Close\" "
542 "now, then \"Cancel\" to cancel the Online Banking setup."));
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);
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."));
556 gtk_assistant_set_page_complete (GTK_ASSISTANT(info->window), page, FALSE);
559 cleanup_child_exit_cb:
560 g_free(deferred_info->wizard_path);
561 g_free(deferred_info);
563 info->deferred_info = NULL;
568 ab_account_longname(
const AB_ACCOUNT *ab_acc)
572 const char *ab_bankname, *bankcode, *subAccountId;
574 g_return_val_if_fail(ab_acc, NULL);
576 ab_bankname = AB_Account_GetBankName(ab_acc);
578 bankcode = AB_Account_GetBankCode(ab_acc);
579 subAccountId = AB_Account_GetSubAccountId(ab_acc);
582 result = g_strdup_printf(_(
"Bank code %s (%s), Account %s (%s)"),
584 bankname ? bankname :
"",
585 AB_Account_GetAccountNumber(ab_acc),
586 subAccountId ? subAccountId :
"");
594 update_account_list_acc_cb(AB_ACCOUNT *ab_acc, gpointer user_data)
597 gchar *gnc_name, *ab_name;
601 g_return_val_if_fail(ab_acc && info, NULL);
603 ab_name = ab_account_longname(ab_acc);
606 gnc_acc = g_hash_table_lookup(info->gnc_hash, ab_acc);
612 gnc_name = g_strdup(
"");
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,
631 AB_ACCOUNT_LIST2 *acclist;
633 g_return_if_fail(info && info->api && info->gnc_hash);
636 g_object_ref(info->account_store);
637 gtk_tree_view_set_model(info->account_view, NULL);
640 gtk_list_store_clear(info->account_store);
641 acclist = AB_Banking_GetAccounts(info->api);
643 AB_Account_List2_ForEach(acclist, update_account_list_acc_cb, info);
645 g_warning(
"update_account_list: Oops, account list from AB_Banking "
649 gtk_tree_view_set_model(info->account_view,
650 GTK_TREE_MODEL(info->account_store));
652 g_object_unref(info->account_store);
656 find_gnc_acc_cb(gpointer key, gpointer value, gpointer user_data)
660 g_return_val_if_fail(data, TRUE);
662 if (value == data->gnc_acc)
664 data->ab_acc = (AB_ACCOUNT*) key;
671 clear_line_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
675 GtkListStore *store = GTK_LIST_STORE(model);
678 g_return_val_if_fail(data && store, FALSE);
680 gtk_tree_model_get(model, iter, ACCOUNT_LIST_COL_AB_ACCT, &ab_acc, -1);
682 if (ab_acc == data->ab_acc)
684 gtk_list_store_set(store, iter, ACCOUNT_LIST_COL_GNC_NAME,
"",
685 ACCOUNT_LIST_COL_CHECKED, TRUE, -1);
692 account_list_clicked_cb (GtkTreeView *view, GtkTreePath *path,
693 GtkTreeViewColumn *col, gpointer user_data)
699 gchar *longname, *gnc_name;
701 const gchar *currency;
705 g_return_if_fail(info);
707 PINFO(
"Row has been double-clicked.");
709 model = gtk_tree_view_get_model(view);
711 if (!gtk_tree_model_get_iter(model, &iter, path))
714 gtk_tree_model_get(model, &iter, ACCOUNT_LIST_COL_AB_ACCT, &ab_acc, -1);
718 old_value = g_hash_table_lookup(info->gnc_hash, ab_acc);
720 longname = ab_account_longname(ab_acc);
721 currency = AB_Account_GetCurrency(ab_acc);
722 if (currency && *currency)
724 commodity = gnc_commodity_table_lookup(
726 GNC_COMMODITY_NS_CURRENCY,
732 old_value, &ok_pressed);
735 if (ok_pressed && old_value != gnc_acc)
742 data.gnc_acc = gnc_acc;
744 g_hash_table_find(info->gnc_hash, (GHRFunc) find_gnc_acc_cb,
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,
756 g_hash_table_insert(info->gnc_hash, ab_acc, 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,
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,
778 clear_kvp_acc_cb(
Account *gnc_acc, gpointer user_data)
789 save_kvp_acc_cb(gpointer key, gpointer value, gpointer user_data)
791 AB_ACCOUNT *ab_acc = key;
793 guint32 ab_account_uid;
794 const gchar *ab_accountid, *gnc_accountid;
795 const gchar *ab_bankcode, *gnc_bankcode;
797 g_return_if_fail(ab_acc && gnc_acc);
799 ab_account_uid = AB_Account_GetUniqueId(ab_acc);
803 ab_accountid = AB_Account_GetAccountNumber(ab_acc);
807 || (strcmp(ab_accountid, gnc_accountid) != 0)))
810 ab_bankcode = AB_Account_GetBankCode(ab_acc);
814 || (strcmp(gnc_bankcode, ab_bankcode) != 0)))
819 aai_close_handler(gpointer user_data)
823 gnc_save_window_size(GNC_PREFS_GROUP, GTK_WINDOW(info->window));
824 gtk_widget_destroy(info->window);
827 void aai_on_prepare (GtkAssistant *assistant, GtkWidget *page,
830 switch (gtk_assistant_get_current_page(assistant))
834 aai_wizard_page_prepare (assistant , user_data );
838 aai_match_page_prepare (assistant , user_data );
848 GtkTreeViewColumn *column;
849 GtkTreeSelection *selection;
853 builder = gtk_builder_new();
854 gnc_builder_add_from_file (builder,
"assistant-ab-initial.glade",
"AqBanking Init Assistant");
856 info->window = GTK_WIDGET(gtk_builder_get_object (builder,
"AqBanking Init Assistant"));
858 gnc_assistant_set_colors (GTK_ASSISTANT (info->assistant));
861 info->deferred_info = NULL;
862 info->gnc_hash = NULL;
864 info->match_page_prepared = FALSE;
866 GTK_TREE_VIEW(gtk_builder_get_object (builder,
"account_page_view"));
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,
872 gtk_tree_view_set_model(info->account_view,
873 GTK_TREE_MODEL(info->account_store));
874 g_object_unref(info->account_store);
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);
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);
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);
892 selection = gtk_tree_view_get_selection(info->account_view);
893 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
895 gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(info->window));
897 g_signal_connect(info->account_view,
"row-activated",
898 G_CALLBACK(account_list_clicked_cb), info);
900 g_signal_connect (G_OBJECT(info->window),
"destroy",
901 G_CALLBACK (aai_destroy_cb), info);
903 gtk_builder_connect_signals(builder, info);
904 g_object_unref(G_OBJECT(builder));
906 component_id = gnc_register_gui_component(ASSISTANT_AB_INITIAL_CM_CLASS,
907 NULL, aai_close_handler, info);
909 gnc_gui_component_set_session(component_id, gnc_get_current_session());
911 gtk_widget_show(info->window);
guint32 gnc_ab_get_account_uid(const Account *a)
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
utility functions for the GnuCash UI
#define PINFO(format, args...)
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...)
const gchar * gnc_ab_get_account_bankcode(const Account *a)
#define ENTER(format, args...)
gchar * gnc_account_get_full_name(const Account *account)
void gnc_ab_set_account_accountid(Account *a, const gchar *id)
void gnc_ab_set_account_uid(Account *a, guint32 uid)
AB_BANKING * gnc_AB_BANKING_new(void)
void gnc_AB_BANKING_delete(AB_BANKING *api)
gchar * gnc_utf8_strip_invalid_strdup(const gchar *str)
AB_ACCOUNT * gnc_ab_get_ab_account(const AB_BANKING *api, Account *gnc_acc)
#define LEAVE(format, args...)
void gnc_ab_initial_assistant(void)
const gchar * gnc_ab_get_account_accountid(const Account *a)
void gnc_ab_set_account_bankcode(Account *a, const gchar *code)
AqBanking utility functions.
const gchar * QofLogModule