42#include <aqbanking/banking.h>
43#include <aqbanking/types/account_spec.h>
44#include <gwenhywfar/gui.h>
46#include <glib/gi18n.h>
47#include <glib/gstdio.h>
48#include <gdk/gdkkeysyms.h>
56#include "dialog-utils.h"
60#include "gnc-component-manager.h"
64#include "gnc-session.h"
67static QofLogModule log_module = GNC_MOD_ASSISTANT;
69#define GNC_PREFS_GROUP "dialogs.ab-initial"
70#define ASSISTANT_AB_INITIAL_CM_CLASS "assistant-ab-initial"
77void aai_on_prepare (GtkAssistant *assistant, GtkWidget *page,
80void aai_on_finish (GtkAssistant *gtkassistant, gpointer user_data);
81void aai_on_cancel (GtkAssistant *assistant, gpointer user_data);
82void aai_destroy_cb(GtkWidget *
object, gpointer user_data);
84gboolean aai_key_press_event_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
86void aai_page_prepare (GtkAssistant *assistant, gpointer user_data);
87void aai_button_clicked_cb(GtkButton *button, gpointer user_data);
88void aai_match_delete_button_clicked_cb(GtkButton *button, gpointer user_data);
90static guint aai_ab_account_hash(gconstpointer v);
91static gboolean aai_ab_account_equal(gconstpointer v1, gconstpointer v2);
92void aai_match_page_prepare (GtkAssistant *assistant, gpointer user_data);
94static gboolean banking_has_accounts(AB_BANKING *banking);
95static void hash_from_kvp_acc_cb(
Account *gnc_acc, gpointer user_data);
96static ABInitialInfo *single_info = NULL;
97static gchar *ab_account_longname(
const GNC_AB_ACCOUNT_SPEC *ab_acc);
98static GNC_AB_ACCOUNT_SPEC *update_account_list_acc_cb(GNC_AB_ACCOUNT_SPEC *ab_acc, gpointer user_data);
99static void update_account_list(ABInitialInfo *info);
100static gboolean find_gnc_acc_cb(gpointer key, gpointer value, gpointer user_data);
101static gboolean clear_line_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data);
102static void account_list_clicked_cb (GtkTreeView *view, GtkTreePath *path,
103 GtkTreeViewColumn *col, gpointer user_data);
104static void delete_account_match(ABInitialInfo *info, RevLookupData *data);
105static void delete_selected_match_cb(gpointer data, gpointer user_data);
106static void insert_acc_into_revhash_cb(gpointer ab_acc, gpointer gnc_acc, gpointer revhash);
107static void remove_acc_from_revhash_cb(gpointer ab_acc, gpointer gnc_acc, gpointer revhash);
108static void clear_kvp_acc_cb(gpointer key, gpointer value, gpointer user_data);
109static void save_kvp_acc_cb(gpointer key, gpointer value, gpointer user_data);
110static void aai_close_handler(gpointer user_data);
115 GtkWidget *assistant;
118 gboolean match_page_prepared;
119 GtkTreeView *account_view;
120 GtkListStore *account_store;
123 DeferredInfo *deferred_info;
128 GHashTable *gnc_hash;
130 GHashTable *gnc_revhash;
135 ABInitialInfo *initial_info;
137 gboolean qt_probably_unavailable;
149 GNC_AB_ACCOUNT_SPEC *ab_acc;
152enum account_list_cols
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
163aai_key_press_event_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
165 if (event->keyval == GDK_KEY_Escape)
167 gtk_widget_destroy(widget);
177aai_on_cancel (GtkAssistant *gtkassistant, gpointer user_data)
179 ABInitialInfo *info = user_data;
181 gtk_widget_destroy(info->window);
185aai_destroy_cb(GtkWidget *
object, gpointer user_data)
187 ABInitialInfo *info = user_data;
188 g_return_if_fail (single_info && info == single_info);
190 gnc_unregister_gui_component_by_data(ASSISTANT_AB_INITIAL_CM_CLASS, info);
192 if (info->deferred_info)
194 PINFO(
"Online Banking assistant is being closed but the wizard is still "
195 "running. Inoring.");
198 info->deferred_info->initial_info = NULL;
203 g_hash_table_destroy(info->gnc_hash);
204 info->gnc_hash = NULL;
207 if (info->gnc_revhash)
209 g_hash_table_destroy(info->gnc_revhash);
210 info->gnc_revhash = NULL;
219 gtk_widget_destroy(info->window);
227aai_page_prepare (GtkAssistant *assistant, gpointer user_data)
229 ABInitialInfo *info = user_data;
230 gint num = gtk_assistant_get_current_page (assistant);
231 GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
233 g_return_if_fail(info->api);
236 if (banking_has_accounts(info->api))
237 gtk_assistant_set_page_complete (assistant, page, TRUE);
239 gtk_assistant_set_page_complete (assistant, page, FALSE);
243aai_button_clicked_cb(GtkButton *button, gpointer user_data)
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);
249 AB_BANKING *banking = info->api;
250 g_return_if_fail(banking);
252 ENTER(
"user_data: %p", user_data);
254 if (info->deferred_info)
256 LEAVE(
"Wizard is still running");
261 GWEN_DIALOG *dlg = AB_Banking_CreateSetupDialog(banking);
264 PERR(
"Could not lookup Setup Dialog of aqbanking!");
268 int rv = GWEN_Gui_ExecDialog(dlg, 0);
272 PERR(
"Setup Dialog of aqbanking aborted/rejected, code %d", rv);
274 GWEN_Dialog_free(dlg);
279 if (banking_has_accounts(info->api))
280 gtk_assistant_set_page_complete (GTK_ASSISTANT(info->window), page, TRUE);
282 gtk_assistant_set_page_complete (GTK_ASSISTANT(info->window), page, FALSE);
287static void delete_account_match(ABInitialInfo *info, RevLookupData *data)
289 g_return_if_fail(info && info->gnc_hash &&
290 info->account_view && data && data->ab_acc);
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,
300delete_selected_match_cb(gpointer data, gpointer user_data)
303 GtkTreeModel *model = NULL;
304 RevLookupData revLookupData = {NULL, NULL};
306 GtkTreePath *path = (GtkTreePath *) data;
307 ABInitialInfo *info = (ABInitialInfo *) user_data;
308 g_return_if_fail(path && info && info->account_view);
310 model = gtk_tree_view_get_model(info->account_view);
311 g_return_if_fail(model);
313 if (gtk_tree_model_get_iter(model, &iter, path))
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);
322aai_match_delete_button_clicked_cb(GtkButton *button, gpointer user_data)
324 GList *selected_matches = NULL;
325 GtkTreeSelection *selection = NULL;
326 ABInitialInfo *info = (ABInitialInfo *) user_data;
328 g_return_if_fail(info && info->api && info->account_view && info->gnc_hash);
330 PINFO(
"Selected account matches are deleted");
332 selection = gtk_tree_view_get_selection (info->account_view);
335 selected_matches = gtk_tree_selection_get_selected_rows (selection, NULL);
336 if (selected_matches)
338 g_list_foreach (selected_matches, delete_selected_match_cb, info);
341 (GDestroyNotify) gtk_tree_path_free);
347aai_ab_account_hash (gconstpointer v)
353 return AB_AccountSpec_GetUniqueId((
const GNC_AB_ACCOUNT_SPEC *) v);
357aai_ab_account_equal (gconstpointer v1, gconstpointer v2)
359 if (v1 == NULL || v2 == NULL)
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);
371insert_acc_into_revhash_cb(gpointer ab_acc, gpointer gnc_acc, gpointer revhash)
373 g_return_if_fail(revhash && gnc_acc && ab_acc);
374 g_hash_table_insert((GHashTable *) revhash, gnc_acc, ab_acc);
378remove_acc_from_revhash_cb(gpointer ab_acc, gpointer gnc_acc, gpointer revhash)
380 g_return_if_fail(revhash && gnc_acc);
381 g_hash_table_remove((GHashTable *) revhash, gnc_acc);
385aai_match_page_prepare (GtkAssistant *assistant, gpointer user_data)
387 ABInitialInfo *info = user_data;
388 gint num = gtk_assistant_get_current_page (assistant);
389 GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
394 g_return_if_fail(info && info->api);
397 if (!info->match_page_prepared)
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);
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);
409 info->match_page_prepared = TRUE;
412 update_account_list(info);
415 gtk_assistant_set_page_complete (assistant, page, TRUE);
419aai_on_finish (GtkAssistant *assistant, gpointer user_data)
421 ABInitialInfo *info = user_data;
423 g_return_if_fail(info && info->gnc_hash && info->gnc_revhash);
430 g_hash_table_foreach(info->gnc_hash, (GHFunc) remove_acc_from_revhash_cb, info->gnc_revhash);
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);
435 gtk_widget_destroy(info->window);
439banking_has_accounts(AB_BANKING *banking)
441 GNC_AB_ACCOUNT_SPEC_LIST *accl = NULL;
442 gboolean result = FALSE;
444 g_return_val_if_fail(banking, FALSE);
446 if (AB_Banking_GetAccountSpecList (banking, &accl) >= 0 &&
447 accl && AB_AccountSpec_List_GetCount (accl))
450 AB_AccountSpec_List_free (accl);
456hash_from_kvp_acc_cb(
Account *gnc_acc, gpointer user_data)
458 AccCbData *data = user_data;
459 GNC_AB_ACCOUNT_SPEC *ab_acc;
463 g_hash_table_insert(data->hash, ab_acc, gnc_acc);
467ab_account_longname(
const GNC_AB_ACCOUNT_SPEC *ab_acc)
469 gchar *bankname = NULL;
470 gchar *result = NULL;
471 const char *bankcode, *subAccountId, *account_number;
473 g_return_val_if_fail(ab_acc, NULL);
475 bankcode = AB_AccountSpec_GetBankCode(ab_acc);
476 subAccountId = AB_AccountSpec_GetSubAccountNumber(ab_acc);
477 account_number = AB_AccountSpec_GetAccountNumber (ab_acc);
480 result = g_strdup_printf(
_(
"Bank code %s (%s), Account %s (%s)"),
482 bankname ? bankname :
"",
484 subAccountId ? subAccountId :
"");
491static GNC_AB_ACCOUNT_SPEC *
492update_account_list_acc_cb(GNC_AB_ACCOUNT_SPEC *ab_acc, gpointer user_data)
494 ABInitialInfo *info = user_data;
495 gchar *gnc_name, *ab_name;
499 g_return_val_if_fail(ab_acc && info, NULL);
501 ab_name = ab_account_longname(ab_acc);
504 gnc_acc = g_hash_table_lookup(info->gnc_hash, ab_acc);
510 gnc_name = g_strdup(
"");
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,
527update_account_list(ABInitialInfo *info)
529 GNC_AB_ACCOUNT_SPEC_LIST *acclist = NULL;
531 g_return_if_fail(info && info->api && info->gnc_hash);
534 g_object_ref(info->account_store);
535 gtk_tree_view_set_model(info->account_view, NULL);
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);
542 g_warning(
"update_account_list: Oops, account list from AB_Banking "
546 gtk_tree_view_set_model(info->account_view,
547 GTK_TREE_MODEL(info->account_store));
549 g_object_unref(info->account_store);
553find_gnc_acc_cb(gpointer key, gpointer value, gpointer user_data)
555 RevLookupData *data = user_data;
557 g_return_val_if_fail(data, TRUE);
559 if (value == data->gnc_acc)
561 data->ab_acc = (GNC_AB_ACCOUNT_SPEC*) key;
568clear_line_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
571 RevLookupData *data = user_data;
572 GtkListStore *store = GTK_LIST_STORE(model);
575 g_return_val_if_fail(data && store, FALSE);
577 gtk_tree_model_get(model, iter, ACCOUNT_LIST_COL_AB_ACCT, &ab_acc, -1);
579 if (aai_ab_account_equal(ab_acc, data->ab_acc))
581 gtk_list_store_set(store, iter, ACCOUNT_LIST_COL_GNC_NAME,
"",
582 ACCOUNT_LIST_COL_CHECKED, TRUE, -1);
589account_list_clicked_cb (GtkTreeView *view, GtkTreePath *path,
590 GtkTreeViewColumn *col, gpointer user_data)
592 ABInitialInfo *info = user_data;
595 GNC_AB_ACCOUNT_SPEC *ab_acc;
596 gchar *longname, *gnc_name;
598 const gchar *currency;
599 gnc_commodity *commodity = NULL;
602 g_return_if_fail(info);
604 PINFO(
"Row has been double-clicked.");
606 model = gtk_tree_view_get_model(view);
608 if (!gtk_tree_model_get_iter(model, &iter, path))
611 gtk_tree_model_get(model, &iter, ACCOUNT_LIST_COL_AB_ACCT, &ab_acc, -1);
615 old_value = g_hash_table_lookup(info->gnc_hash, ab_acc);
617 longname = ab_account_longname(ab_acc);
618 currency = AB_AccountSpec_GetCurrency(ab_acc);
619 if (currency && *currency)
621 commodity = gnc_commodity_table_lookup(
623 GNC_COMMODITY_NS_CURRENCY,
628 longname, commodity, ACCT_TYPE_BANK,
629 old_value, &ok_pressed);
632 if (ok_pressed && old_value != gnc_acc)
639 data.gnc_acc = gnc_acc;
641 g_hash_table_find(info->gnc_hash, (GHRFunc) find_gnc_acc_cb,
644 delete_account_match(info, &data);
647 g_hash_table_insert(info->gnc_hash, ab_acc, 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,
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,
669clear_kvp_acc_cb(gpointer gnc_acc, gpointer ab_acc, gpointer user_data)
671 g_return_if_fail(gnc_acc);
678save_kvp_acc_cb(gpointer key, gpointer value, gpointer user_data)
680 GNC_AB_ACCOUNT_SPEC *ab_acc = key;
682 guint32 ab_account_uid;
683 const gchar *ab_accountid, *gnc_accountid;
684 const gchar *ab_bankcode, *gnc_bankcode;
686 const gchar *gnc_online_id;
688 g_return_if_fail(ab_acc && gnc_acc);
690 ab_account_uid = AB_AccountSpec_GetUniqueId(ab_acc);
694 ab_accountid = AB_AccountSpec_GetAccountNumber(ab_acc);
698 || (strcmp(ab_accountid, gnc_accountid) != 0)))
701 ab_bankcode = AB_AccountSpec_GetBankCode(ab_acc);
705 || (strcmp(gnc_bankcode, ab_bankcode) != 0)))
710 if (ab_online_id && (!gnc_online_id || (strcmp(ab_online_id, gnc_online_id) != 0)))
712 g_free(ab_online_id);
716aai_close_handler(gpointer user_data)
718 ABInitialInfo *info = user_data;
720 gnc_save_window_size(GNC_PREFS_GROUP, GTK_WINDOW(info->window));
721 gtk_widget_destroy(info->window);
724void aai_on_prepare (GtkAssistant *assistant, GtkWidget *page,
727 switch (gtk_assistant_get_current_page(assistant))
731 aai_page_prepare (assistant , user_data );
735 aai_match_page_prepare (assistant , user_data );
740static ABInitialInfo *
741gnc_ab_initial_assistant_new(
void)
744 GtkTreeViewColumn *column;
745 GtkTreeSelection *selection;
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");
752 info->window = GTK_WIDGET(gtk_builder_get_object (builder,
"aqbanking_init_assistant"));
755 info->deferred_info = NULL;
756 info->gnc_hash = NULL;
758 info->match_page_prepared = FALSE;
760 GTK_TREE_VIEW(gtk_builder_get_object (builder,
"account_page_view"));
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,
766 gtk_tree_view_set_model(info->account_view,
767 GTK_TREE_MODEL(info->account_store));
768 g_object_unref(info->account_store);
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);
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);
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);
786 selection = gtk_tree_view_get_selection(info->account_view);
787 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
789 gnc_restore_window_size (GNC_PREFS_GROUP,
792 g_signal_connect(info->account_view,
"row-activated",
793 G_CALLBACK(account_list_clicked_cb), info);
795 g_signal_connect (G_OBJECT(info->window),
"destroy",
796 G_CALLBACK (aai_destroy_cb), info);
798 gtk_builder_connect_signals(builder, info);
799 g_object_unref(G_OBJECT(builder));
801 component_id = gnc_register_gui_component(ASSISTANT_AB_INITIAL_CM_CLASS,
802 NULL, aai_close_handler, info);
804 gnc_gui_component_set_session(component_id, gnc_get_current_session());
812 single_info = gnc_ab_initial_assistant_new();
813 gtk_widget_show(single_info->window);
AqBanking setup functionality.
AqBanking utility functions.
utility functions for the GnuCash UI
void xaccAccountSetOnlineID(Account *acc, const char *id)
Set the account's online_id, the identifier (e.g.
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...
const char * xaccAccountGetOnlineID(const Account *acc)
Get the account's online_id (see xaccAccountSetOnlineID).
const gchar * gnc_ab_get_account_bankcode(const Account *a)
Return the bankcode string in the Account a.
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.
void gnc_ab_initial_assistant(void)
Create and show an assistant for the aqbanking setup.
gchar * gnc_ab_create_online_id(const gchar *bankcode, const gchar *accountnumber)
Creates an online ID from bank code and account number.
void gnc_ab_set_account_bankcode(Account *a, const gchar *code)
Set the bankcode string in the Account a to code.
void gnc_ab_set_account_accountid(Account *a, const gchar *id)
Set the accountid string in the Account a to id.
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.
void gnc_AB_BANKING_delete(AB_BANKING *api)
Delete the AB_BANKING api.
const gchar * gnc_ab_get_account_accountid(const Account *a)
Return accountid string in the Account a.
guint32 gnc_ab_get_account_uid(const Account *a)
Return the unique id for the AB_BANKING account in the Account a.
AB_BANKING * gnc_AB_BANKING_new(void)
If there is a cached AB_BANKING object, return it initialized.
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 ...
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
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.
#define PINFO(format, args...)
Print an informational note.
#define LEAVE(format, args...)
Print a function exit debugging message.
#define PERR(format, args...)
Log a serious error.
#define ENTER(format, args...)
Print a function entry debugging message.
Generic and very flexible account matcher/picker.