GnuCash 2.4.99
assistant-ab-initial.c
00001 /*
00002  * assistant-ab-initial.c -- Initialise the AqBanking wizard
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of
00007  * the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, contact:
00016  *
00017  * Free Software Foundation           Voice:  +1-617-542-5942
00018  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
00019  * Boston, MA  02110-1301,  USA       gnu@gnu.org
00020  */
00021 
00032 #include "config.h"
00033 
00034 #include <aqbanking/banking.h>
00035 #include <glib.h>
00036 #include <glib/gi18n.h>
00037 #include <glib/gstdio.h>
00038 #include <gdk/gdkkeysyms.h>
00039 #ifdef HAVE_SYS_WAIT_H
00040 #    include <sys/wait.h>
00041 #endif
00042 #include <fcntl.h>
00043 #include <unistd.h>
00044 
00045 #include "dialog-utils.h"
00046 #include "assistant-ab-initial.h"
00047 #include "assistant-utils.h"
00048 #include "gnc-ab-kvp.h"
00049 #include "gnc-ab-utils.h"
00050 #include "gnc-component-manager.h"
00051 #include "gnc-glib-utils.h"
00052 #include "gnc-ui.h"
00053 #include "gnc-ui-util.h"
00054 #include "gnc-session.h"
00055 #include "import-account-matcher.h"
00056 
00057 #if AQBANKING_VERSION_INT > 49908
00058 /* For aqbanking > 4.99.8. See below. */
00059 # include <aqbanking/dlg_setup.h>
00060 #endif
00061 
00062 /* This static indicates the debugging module that this .o belongs to.  */
00063 static QofLogModule log_module = GNC_MOD_ASSISTANT;
00064 
00065 #define ASSISTANT_AB_INITIAL_CM_CLASS "assistant-ab-initial"
00066 
00067 typedef struct _ABInitialInfo ABInitialInfo;
00068 typedef struct _DeferredInfo DeferredInfo;
00069 typedef struct _AccCbData AccCbData;
00070 typedef struct _RevLookupData RevLookupData;
00071 
00072 void aai_on_prepare (GtkAssistant  *assistant, GtkWidget *page,
00073                      gpointer user_data);
00074 
00075 void aai_on_finish (GtkAssistant *gtkassistant, gpointer user_data);
00076 void aai_on_cancel (GtkAssistant *assistant, gpointer user_data);
00077 void aai_destroy_cb(GtkObject *object, gpointer user_data);
00078 
00079 gboolean aai_key_press_event_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
00080 
00081 void aai_wizard_page_prepare (GtkAssistant *assistant, gpointer user_data);
00082 void aai_wizard_button_clicked_cb(GtkButton *button, gpointer user_data);
00083 
00084 void aai_match_page_prepare (GtkAssistant *assistant, gpointer user_data);
00085 
00086 static gboolean banking_has_accounts(AB_BANKING *banking);
00087 static void hash_from_kvp_acc_cb(Account *gnc_acc, gpointer user_data);
00088 
00089 static void child_exit_cb(GPid pid, gint status, gpointer data);
00090 static gchar *ab_account_longname(const AB_ACCOUNT *ab_acc);
00091 static AB_ACCOUNT *update_account_list_acc_cb(AB_ACCOUNT *ab_acc, gpointer user_data);
00092 static void update_account_list(ABInitialInfo *info);
00093 static gboolean find_gnc_acc_cb(gpointer key, gpointer value, gpointer user_data);
00094 static gboolean clear_line_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data);
00095 static void account_list_clicked_cb (GtkTreeView *view, GtkTreePath *path,
00096                                      GtkTreeViewColumn  *col, gpointer user_data);
00097 static void clear_kvp_acc_cb(Account *gnc_acc, gpointer user_data);
00098 static void save_kvp_acc_cb(gpointer key, gpointer value, gpointer user_data);
00099 static void aai_close_handler(gpointer user_data);
00100 
00101 struct _ABInitialInfo
00102 {
00103     GtkWidget *window;
00104     GtkWidget *assistant;
00105 
00106     /* account match page */
00107     gboolean match_page_prepared;
00108     GtkTreeView *account_view;
00109     GtkListStore *account_store;
00110 
00111     /* managed by child_exit_cb */
00112     DeferredInfo *deferred_info;
00113 
00114     /* AqBanking stuff */
00115     AB_BANKING *api;
00116     /* AB_ACCOUNT* -> Account* -- DO NOT DELETE THE KEYS! */
00117     GHashTable *gnc_hash;
00118 };
00119 
00120 struct _DeferredInfo
00121 {
00122     ABInitialInfo *initial_info;
00123     gchar *wizard_path;
00124     gboolean qt_probably_unavailable;
00125 };
00126 
00127 struct _AccCbData
00128 {
00129     AB_BANKING *api;
00130     GHashTable *hash;
00131 };
00132 
00133 struct _RevLookupData
00134 {
00135     Account *gnc_acc;
00136     AB_ACCOUNT *ab_acc;
00137 };
00138 
00139 enum account_list_cols
00140 {
00141     ACCOUNT_LIST_COL_INDEX = 0,
00142     ACCOUNT_LIST_COL_AB_NAME,
00143     ACCOUNT_LIST_COL_AB_ACCT,
00144     ACCOUNT_LIST_COL_GNC_NAME,
00145     ACCOUNT_LIST_COL_CHECKED,
00146     NUM_ACCOUNT_LIST_COLS
00147 };
00148 
00149 gboolean
00150 aai_key_press_event_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
00151 {
00152     if (event->keyval == GDK_Escape)
00153     {
00154         gtk_widget_destroy(widget);
00155         return TRUE;
00156     }
00157     else
00158     {
00159         return FALSE;
00160     }
00161 }
00162 
00163 void
00164 aai_on_cancel (GtkAssistant *gtkassistant, gpointer user_data)
00165 {
00166     ABInitialInfo *info = user_data;
00167 
00168     gtk_widget_destroy(info->window);
00169 }
00170 
00171 void
00172 aai_destroy_cb(GtkObject *object, gpointer user_data)
00173 {
00174     ABInitialInfo *info = user_data;
00175 
00176     gnc_unregister_gui_component_by_data(ASSISTANT_AB_INITIAL_CM_CLASS, info);
00177 
00178     if (info->deferred_info)
00179     {
00180         g_message("Online Banking assistant is being closed but the wizard is still "
00181                   "running.  Inoring.");
00182 
00183         /* Tell child_exit_cb() that there is no assistant anymore */
00184         info->deferred_info->initial_info = NULL;
00185     }
00186 
00187     if (info->gnc_hash)
00188     {
00189 #ifdef AQBANKING_VERSION_4_EXACTLY
00190         AB_Banking_OnlineFini(info->api, 0);
00191 #else
00192         AB_Banking_OnlineFini(info->api);
00193 #endif
00194         g_hash_table_destroy(info->gnc_hash);
00195         info->gnc_hash = NULL;
00196     }
00197 
00198     if (info->api)
00199     {
00200         gnc_AB_BANKING_delete(info->api);
00201         info->api = NULL;
00202     }
00203 
00204     gtk_widget_destroy(info->window);
00205     info->window = NULL;
00206 
00207     g_free(info);
00208 }
00209 
00210 void
00211 aai_wizard_page_prepare (GtkAssistant *assistant, gpointer user_data)
00212 {
00213     ABInitialInfo *info = user_data;
00214     gint num = gtk_assistant_get_current_page (assistant);
00215     GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
00216 
00217     g_return_if_fail(info->api);
00218 
00219     /* Enable the Assistant Buttons if we accounts */
00220     if (banking_has_accounts(info->api))
00221         gtk_assistant_set_page_complete (assistant, page, TRUE);
00222     else
00223         gtk_assistant_set_page_complete (assistant, page, FALSE);
00224 }
00225 
00226 void
00227 aai_wizard_button_clicked_cb(GtkButton *button, gpointer user_data)
00228 {
00229     ABInitialInfo *info = user_data;
00230     gint num = gtk_assistant_get_current_page (GTK_ASSISTANT(info->window));
00231     GtkWidget *page = gtk_assistant_get_nth_page (GTK_ASSISTANT(info->window), num);
00232 
00233     AB_BANKING *banking = info->api;
00234     GWEN_BUFFER *buf;
00235     gboolean wizard_exists;
00236     const gchar *wizard_path;
00237     gboolean qt_probably_unavailable = FALSE;
00238 
00239     g_return_if_fail(banking);
00240 
00241     ENTER("user_data: %p", user_data);
00242 
00243     if (info->deferred_info)
00244     {
00245         LEAVE("Wizard is still running");
00246         return;
00247     }
00248 
00249 #if AQBANKING_VERSION_INT > 49908
00250     /* For aqbanking5 > 4.99.8: Use AB_Banking_GetNewUserDialog(). */
00251     {
00252         GWEN_DIALOG *dlg =
00253             AB_SetupDialog_new(banking);
00254 
00255         if (AB_Banking_OnlineInit(banking) != 0)
00256         {
00257             PERR("Got error on AB_Banking_OnlineInit!");
00258         }
00259 
00260         if (!dlg)
00261         {
00262             PERR("Could not lookup Setup Dialog of aqbanking!");
00263         }
00264         else
00265         {
00266             int rv = GWEN_Gui_ExecDialog(dlg, 0);
00267             if (rv <= 0)
00268             {
00269                 /* Dialog was aborted/rejected */
00270                 PERR("Setup Dialog of aqbanking aborted/rejected !");
00271             }
00272             GWEN_Dialog_free(dlg);
00273         }
00274 
00275         if (AB_Banking_OnlineFini(banking) != 0)
00276         {
00277             PERR("Got error on AB_Banking_OnlineFini!");
00278         }
00279     }
00280 #else
00281     /* Previous implementation for aqbanking <= 4.99.8: Use the
00282      * external application. */
00283 
00284 
00285     /* This is the point where we look for and start an external
00286      * application shipped with aqbanking that contains the setup assistant
00287      * for AqBanking related stuff.  It requires qt (but not kde).  This
00288      * application contains the very verbose step-by-step setup wizard
00289      * for the AqBanking account, and the application is shared with
00290      * other AqBanking-based financial managers that offer the AqBanking
00291      * features (e.g. KMyMoney).  See gnucash-devel discussion here
00292      * https://lists.gnucash.org/pipermail/gnucash-devel/2004-December/012351.html
00293      */
00294     buf = GWEN_Buffer_new(NULL, 300, 0, 0);
00295     AB_Banking_FindWizard(banking, "", NULL, buf);
00296     wizard_exists = *GWEN_Buffer_GetStart(buf) != 0;
00297     wizard_path = GWEN_Buffer_GetStart(buf);
00298 
00299     if (wizard_exists)
00300     {
00301         /* Really check whether the file exists */
00302         gint fd = g_open(wizard_path, O_RDONLY, 0);
00303         if (fd == -1)
00304             wizard_exists = FALSE;
00305         else
00306             close(fd);
00307     }
00308 
00309 #ifdef G_OS_WIN32
00310     {
00311         const char *check_file = "qtdemo.exe";
00312         gchar *found_program = g_find_program_in_path(check_file);
00313         if (found_program)
00314         {
00315             g_debug("Yes, we found the Qt demo program in %s\n", found_program);
00316             g_free(found_program);
00317         }
00318         else
00319         {
00320             g_warning("Ouch, no Qt demo program was found. Qt not installed?\n");
00321             qt_probably_unavailable = TRUE;
00322         }
00323     }
00324 #endif
00325 
00326     if (wizard_exists)
00327     {
00328         /* Call the qt wizard. See the note above about why this
00329          * approach is chosen. */
00330 
00331         GPid pid;
00332         GError *error = NULL;
00333         gchar *argv[2];
00334         gboolean spawned;
00335 
00336         argv[0] = g_strdup (wizard_path);
00337         argv[1] = NULL;
00338         spawned = g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
00339                                  NULL, NULL, &pid, &error);
00340         g_free (argv[0]);
00341 
00342         if (error)
00343             g_critical(
00344                 "Error on starting AqBanking setup wizard: Code %d: %s",
00345                 error->code, error->message ? error->message : "(null)");
00346 
00347         if (!spawned)
00348         {
00349             g_critical("Could not start AqBanking setup wizard: %s",
00350                        error->message ? error->message : "(null)");
00351             g_error_free (error);
00352         }
00353         else
00354         {
00355             /* Keep a reference to info that can survive info */
00356             info->deferred_info = g_new0(DeferredInfo, 1);
00357             info->deferred_info->initial_info = info;
00358             info->deferred_info->wizard_path = g_strdup(wizard_path);
00359             info->deferred_info->qt_probably_unavailable =
00360                 qt_probably_unavailable;
00361 
00362             g_child_watch_add (pid, child_exit_cb, info->deferred_info);
00363         }
00364     }
00365     else
00366     {
00367         g_warning("on_aqhbci_button: Oops, no aqhbci setup wizard found.");
00368         gnc_error_dialog
00369         (info->window,
00370          _("The external program \"AqBanking Setup Wizard\" has not "
00371            "been found. \n\n"
00372            "The %s package should include the "
00373            "program \"qt3-wizard\".  Please check your installation to "
00374            "ensure this program is present.  On some distributions this "
00375            "may require installing additional packages."),
00376          QT3_WIZARD_PACKAGE);
00377     }
00378 
00379     GWEN_Buffer_free(buf);
00380 #endif
00381 
00382     /* Enable the Assistant Buttons if we accounts */
00383     if (banking_has_accounts(info->api))
00384         gtk_assistant_set_page_complete (GTK_ASSISTANT(info->window), page, TRUE);
00385     else
00386         gtk_assistant_set_page_complete (GTK_ASSISTANT(info->window), page, FALSE);
00387 
00388     LEAVE(" ");
00389 }
00390 
00391 void
00392 aai_match_page_prepare (GtkAssistant *assistant, gpointer user_data)
00393 {
00394     ABInitialInfo *info = user_data;
00395     gint num = gtk_assistant_get_current_page (assistant);
00396     GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
00397 
00398     Account *root;
00399     AccCbData data;
00400 
00401     g_return_if_fail(info && info->api);
00402 
00403     /* Do not run this twice */
00404     if (!info->match_page_prepared)
00405     {
00406         /* Load aqbanking accounts */
00407 #ifdef AQBANKING_VERSION_4_EXACTLY
00408         AB_Banking_OnlineInit(info->api, 0);
00409 #else
00410         AB_Banking_OnlineInit(info->api);
00411 #endif
00412         /* Determine current mapping */
00413         root = gnc_book_get_root_account(gnc_get_current_book());
00414         info->gnc_hash = g_hash_table_new(&g_direct_hash, &g_direct_equal);
00415         data.api = info->api;
00416         data.hash = info->gnc_hash;
00417         gnc_account_foreach_descendant(
00418             root, (AccountCb) hash_from_kvp_acc_cb, &data);
00419 
00420         info->match_page_prepared = TRUE;
00421     }
00422     /* Update the graphical representation */
00423     update_account_list(info);
00424 
00425     /* Enable the Assistant Buttons */
00426     gtk_assistant_set_page_complete (assistant, page, TRUE);
00427 }
00428 
00429 void
00430 aai_on_finish (GtkAssistant *assistant, gpointer user_data)
00431 {
00432     ABInitialInfo *info = user_data;
00433     Account *root;
00434 
00435     g_return_if_fail(info && info->gnc_hash);
00436 
00437     /* Commit the changes */
00438     root = gnc_book_get_root_account(gnc_get_current_book());
00439     gnc_account_foreach_descendant(root, (AccountCb) clear_kvp_acc_cb, NULL);
00440     g_hash_table_foreach(info->gnc_hash, (GHFunc) save_kvp_acc_cb, NULL);
00441 
00442     gtk_widget_destroy(info->window);
00443 }
00444 
00445 static gboolean
00446 banking_has_accounts(AB_BANKING *banking)
00447 {
00448     AB_ACCOUNT_LIST2 *accl;
00449     gboolean result;
00450 
00451     g_return_val_if_fail(banking, FALSE);
00452 
00453 #ifdef AQBANKING_VERSION_4_EXACTLY
00454     AB_Banking_OnlineInit(banking, 0);
00455 #else
00456     AB_Banking_OnlineInit(banking);
00457 #endif
00458 
00459     accl = AB_Banking_GetAccounts(banking);
00460     if (accl && (AB_Account_List2_GetSize(accl) > 0))
00461         result = TRUE;
00462     else
00463         result = FALSE;
00464 
00465     if (accl)
00466         AB_Account_List2_free(accl);
00467 
00468 #ifdef AQBANKING_VERSION_4_EXACTLY
00469     AB_Banking_OnlineFini(banking, 0);
00470 #else
00471     AB_Banking_OnlineFini(banking);
00472 #endif
00473 
00474     return result;
00475 }
00476 
00477 static void
00478 hash_from_kvp_acc_cb(Account *gnc_acc, gpointer user_data)
00479 {
00480     AccCbData *data = user_data;
00481     AB_ACCOUNT *ab_acc;
00482 
00483     ab_acc = gnc_ab_get_ab_account(data->api, gnc_acc);
00484     if (ab_acc)
00485         g_hash_table_insert(data->hash, ab_acc, gnc_acc);
00486 }
00487 
00488 static void
00489 child_exit_cb(GPid pid, gint status, gpointer data)
00490 {
00491     DeferredInfo *deferred_info = data;
00492     ABInitialInfo *info = deferred_info->initial_info;
00493     gint num = gtk_assistant_get_current_page (GTK_ASSISTANT(info->window));
00494     GtkWidget *page = gtk_assistant_get_nth_page (GTK_ASSISTANT(info->window), num);
00495 
00496     gint exit_status;
00497 
00498 #ifdef G_OS_WIN32
00499     exit_status = status;
00500 #else
00501     exit_status = WEXITSTATUS(status);
00502 #endif
00503 
00504     g_spawn_close_pid(pid);
00505 
00506     if (!info)
00507     {
00508         g_message("Online Banking wizard exited, but the assistant has been "
00509                   "destroyed already");
00510         goto cleanup_child_exit_cb;
00511     }
00512 
00513     if (exit_status == 0)
00514     {
00515         gtk_assistant_set_page_complete (GTK_ASSISTANT(info->window), page, TRUE);
00516     }
00517     else
00518     {
00519         if (deferred_info->qt_probably_unavailable)
00520         {
00521             g_warning("on_aqhbci_button: Oops, aqhbci wizard return nonzero "
00522                       "value: %d. The called program was \"%s\".\n",
00523                       exit_status, deferred_info->wizard_path);
00524             gnc_error_dialog
00525             (info->window, "%s",
00526              _("The external program \"AqBanking Setup Wizard\" failed "
00527                "to run successfully because the "
00528                "additional software \"Qt\" was not found.  "
00529                "Please install the \"Qt/Windows Open Source Edition\" "
00530                "from Trolltech by downloading it from www.trolltech.com"
00531                "\n\n"
00532                "If you have installed Qt already, you will have to adapt "
00533                "the PATH variable of your system appropriately.  "
00534                "Contact the GnuCash developers if you need further "
00535                "assistance on how to install Qt correctly."
00536                "\n\n"
00537                "Online Banking cannot be setup without Qt.  Press \"Close\" "
00538                "now, then \"Cancel\" to cancel the Online Banking setup."));
00539         }
00540         else
00541         {
00542             g_warning("on_aqhbci_button: Oops, aqhbci wizard return nonzero "
00543                       "value: %d. The called program was \"%s\".\n",
00544                       exit_status, deferred_info->wizard_path);
00545             gnc_error_dialog
00546             (info->window, "%s",
00547              _("The external program \"AqBanking Setup Wizard\" failed "
00548                "to run successfully.  Online Banking can only be setup "
00549                "if this wizard has run successfully.  "
00550                "Please try running the \"AqBanking Setup Wizard\" again."));
00551         }
00552         gtk_assistant_set_page_complete (GTK_ASSISTANT(info->window), page, FALSE);
00553     }
00554 
00555 cleanup_child_exit_cb:
00556     g_free(deferred_info->wizard_path);
00557     g_free(deferred_info);
00558     if (info)
00559         info->deferred_info = NULL;
00560 }
00561 
00562 static gchar *
00563 ab_account_longname(const AB_ACCOUNT *ab_acc)
00564 {
00565     gchar *bankname;
00566     gchar *result;
00567     const char *ab_bankname, *bankcode;
00568 
00569     g_return_val_if_fail(ab_acc, NULL);
00570 
00571     ab_bankname = AB_Account_GetBankName(ab_acc);
00572     bankname = ab_bankname ? gnc_utf8_strip_invalid_strdup(ab_bankname) : NULL;
00573     bankcode = AB_Account_GetBankCode(ab_acc);
00574 
00575     /* Translators: Strings are 1. Account code, 2. Bank name, 3. Bank code. */
00576     if (bankname && *bankname)
00577         result = g_strdup_printf(_("%s at %s (code %s)"),
00578                                  AB_Account_GetAccountNumber(ab_acc),
00579                                  bankname,
00580                                  bankcode);
00581     else
00582         result = g_strdup_printf(_("%s at bank code %s"),
00583                                  AB_Account_GetAccountNumber(ab_acc),
00584                                  bankcode);
00585     g_free(bankname);
00586 
00587     return result;
00588 
00589 }
00590 
00591 static AB_ACCOUNT *
00592 update_account_list_acc_cb(AB_ACCOUNT *ab_acc, gpointer user_data)
00593 {
00594     ABInitialInfo *info = user_data;
00595     gchar *gnc_name, *ab_name;
00596     Account *gnc_acc;
00597     GtkTreeIter iter;
00598 
00599     g_return_val_if_fail(ab_acc && info, NULL);
00600 
00601     ab_name = ab_account_longname(ab_acc);
00602 
00603     /* Get corresponding gnucash account */
00604     gnc_acc = g_hash_table_lookup(info->gnc_hash, ab_acc);
00605 
00606     /* Build the text for the gnucash account. */
00607     if (gnc_acc)
00608         gnc_name = gnc_account_get_full_name(gnc_acc);
00609     else
00610         gnc_name = g_strdup("");
00611 
00612     /* Add item to the list store */
00613     gtk_list_store_append(info->account_store, &iter);
00614     gtk_list_store_set(info->account_store, &iter,
00615                        ACCOUNT_LIST_COL_AB_NAME, ab_name,
00616                        ACCOUNT_LIST_COL_AB_ACCT, ab_acc,
00617                        ACCOUNT_LIST_COL_GNC_NAME, gnc_name,
00618                        ACCOUNT_LIST_COL_CHECKED, FALSE,
00619                        -1);
00620     g_free(gnc_name);
00621     g_free(ab_name);
00622 
00623     return NULL;
00624 }
00625 
00626 static void
00627 update_account_list(ABInitialInfo *info)
00628 {
00629     AB_ACCOUNT_LIST2 *acclist;
00630 
00631     g_return_if_fail(info && info->api && info->gnc_hash);
00632 
00633     /* Detach model from view while updating */
00634     g_object_ref(info->account_store);
00635     gtk_tree_view_set_model(info->account_view, NULL);
00636 
00637     /* Refill the list */
00638     gtk_list_store_clear(info->account_store);
00639     acclist = AB_Banking_GetAccounts(info->api);
00640     if (acclist)
00641         AB_Account_List2_ForEach(acclist, update_account_list_acc_cb, info);
00642     else
00643         g_warning("update_account_list: Oops, account list from AB_Banking "
00644                   "is NULL");
00645 
00646     /* Attach model to view again */
00647     gtk_tree_view_set_model(info->account_view,
00648                             GTK_TREE_MODEL(info->account_store));
00649 
00650     g_object_unref(info->account_store);
00651 }
00652 
00653 static gboolean
00654 find_gnc_acc_cb(gpointer key, gpointer value, gpointer user_data)
00655 {
00656     RevLookupData *data = user_data;
00657 
00658     g_return_val_if_fail(data, TRUE);
00659 
00660     if (value == data->gnc_acc)
00661     {
00662         data->ab_acc = (AB_ACCOUNT*) key;
00663         return TRUE;
00664     }
00665     return FALSE;
00666 }
00667 
00668 static gboolean
00669 clear_line_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
00670               gpointer user_data)
00671 {
00672     RevLookupData *data = user_data;
00673     GtkListStore *store = GTK_LIST_STORE(model);
00674     gpointer ab_acc;
00675 
00676     g_return_val_if_fail(data && store, FALSE);
00677 
00678     gtk_tree_model_get(model, iter, ACCOUNT_LIST_COL_AB_ACCT, &ab_acc, -1);
00679 
00680     if (ab_acc == data->ab_acc)
00681     {
00682         gtk_list_store_set(store, iter, ACCOUNT_LIST_COL_GNC_NAME, "",
00683                            ACCOUNT_LIST_COL_CHECKED, TRUE, -1);
00684         return TRUE;
00685     }
00686     return FALSE;
00687 }
00688 
00689 static void
00690 account_list_clicked_cb (GtkTreeView *view, GtkTreePath *path,
00691                          GtkTreeViewColumn  *col, gpointer user_data)
00692 {
00693     ABInitialInfo *info = user_data;
00694     GtkTreeSelection *selection;
00695     GtkTreeModel *model;
00696     GtkTreeIter iter;
00697     AB_ACCOUNT *ab_acc;
00698     gchar *longname, *gnc_name;
00699     Account *old_value, *gnc_acc;
00700     const gchar *currency;
00701     gnc_commodity *commodity = NULL;
00702     gboolean ok_pressed;
00703 
00704     g_return_if_fail(info);
00705 
00706     PINFO("Row has been double-clicked.");
00707 
00708     model = gtk_tree_view_get_model(view);
00709     selection = gtk_tree_view_get_selection(info->account_view);
00710 
00711     if (!gtk_tree_model_get_iter(model, &iter, path))
00712         return; /* path describes a non-existing row - should not happen */
00713 
00714     gtk_tree_model_get(model, &iter, ACCOUNT_LIST_COL_AB_ACCT, &ab_acc, -1);
00715 
00716     if (ab_acc)
00717     {
00718         old_value = g_hash_table_lookup(info->gnc_hash, ab_acc);
00719 
00720         longname = ab_account_longname(ab_acc);
00721         currency = AB_Account_GetCurrency(ab_acc);
00722         if (currency && *currency)
00723         {
00724             commodity = gnc_commodity_table_lookup(
00725                             gnc_commodity_table_get_table(gnc_get_current_book()),
00726                             GNC_COMMODITY_NS_CURRENCY,
00727                             currency);
00728         }
00729 
00730         gnc_acc = gnc_import_select_account(info->window, NULL, TRUE,
00731                                             longname, commodity, ACCT_TYPE_BANK,
00732                                             old_value, &ok_pressed);
00733         g_free(longname);
00734 
00735         if (ok_pressed && old_value != gnc_acc)
00736         {
00737             if (gnc_acc)
00738             {
00739                 RevLookupData data;
00740 
00741                 /* Lookup and clear other mappings to gnc_acc */
00742                 data.gnc_acc = gnc_acc;
00743                 data.ab_acc = NULL;
00744                 g_hash_table_find(info->gnc_hash, (GHRFunc) find_gnc_acc_cb,
00745                                   &data);
00746                 if (data.ab_acc)
00747                 {
00748                     g_hash_table_remove(info->gnc_hash, data.ab_acc);
00749                     gtk_tree_model_foreach(
00750                         GTK_TREE_MODEL(info->account_store),
00751                         (GtkTreeModelForeachFunc) clear_line_cb,
00752                         &data);
00753                 }
00754 
00755                 /* Map ab_acc to gnc_acc */
00756                 g_hash_table_insert(info->gnc_hash, ab_acc, gnc_acc);
00757                 gnc_name = gnc_account_get_full_name(gnc_acc);
00758                 gtk_list_store_set(info->account_store, &iter,
00759                                    ACCOUNT_LIST_COL_GNC_NAME, gnc_name,
00760                                    ACCOUNT_LIST_COL_CHECKED, TRUE,
00761                                    -1);
00762                 g_free(gnc_name);
00763 
00764             }
00765             else
00766             {
00767                 g_hash_table_remove(info->gnc_hash, ab_acc);
00768                 gtk_list_store_set(info->account_store, &iter,
00769                                    ACCOUNT_LIST_COL_GNC_NAME, "",
00770                                    ACCOUNT_LIST_COL_CHECKED, TRUE,
00771                                    -1);
00772             }
00773         }
00774     }
00775 }
00776 
00777 static void
00778 clear_kvp_acc_cb(Account *gnc_acc, gpointer user_data)
00779 {
00780     if (gnc_ab_get_account_uid(gnc_acc))
00781         gnc_ab_set_account_uid(gnc_acc, 0);
00782     if (gnc_ab_get_account_accountid(gnc_acc))
00783         gnc_ab_set_account_accountid(gnc_acc, "");
00784     if (gnc_ab_get_account_bankcode(gnc_acc))
00785         gnc_ab_set_account_bankcode(gnc_acc, "");
00786 }
00787 
00788 static void
00789 save_kvp_acc_cb(gpointer key, gpointer value, gpointer user_data)
00790 {
00791     AB_ACCOUNT *ab_acc = key;
00792     Account *gnc_acc = value;
00793     guint32 ab_account_uid;
00794     const gchar *ab_accountid, *gnc_accountid;
00795     const gchar *ab_bankcode, *gnc_bankcode;
00796 
00797     g_return_if_fail(ab_acc && gnc_acc);
00798 
00799     ab_account_uid = AB_Account_GetUniqueId(ab_acc);
00800     if (gnc_ab_get_account_uid(gnc_acc) != ab_account_uid)
00801         gnc_ab_set_account_uid(gnc_acc, ab_account_uid);
00802 
00803     ab_accountid = AB_Account_GetAccountNumber(ab_acc);
00804     gnc_accountid = gnc_ab_get_account_accountid(gnc_acc);
00805     if (ab_accountid
00806             && (!gnc_accountid
00807                 || (strcmp(ab_accountid, gnc_accountid) != 0)))
00808         gnc_ab_set_account_accountid(gnc_acc, ab_accountid);
00809 
00810     ab_bankcode = AB_Account_GetBankCode(ab_acc);
00811     gnc_bankcode = gnc_ab_get_account_bankcode(gnc_acc);
00812     if (ab_bankcode
00813             && (!gnc_bankcode
00814                 || (strcmp(gnc_bankcode, ab_bankcode) != 0)))
00815         gnc_ab_set_account_bankcode(gnc_acc, ab_bankcode);
00816 }
00817 
00818 static void
00819 aai_close_handler(gpointer user_data)
00820 {
00821     ABInitialInfo *info = user_data;
00822 
00823     gtk_widget_destroy(info->window);
00824 }
00825 
00826 void aai_on_prepare (GtkAssistant  *assistant, GtkWidget *page,
00827                      gpointer user_data)
00828 {
00829     ABInitialInfo *info = user_data;
00830     gint currentpage = gtk_assistant_get_current_page(assistant);
00831 
00832     switch (gtk_assistant_get_current_page(assistant))
00833     {
00834     case 1:
00835         /* Current page is wizard button page */
00836         aai_wizard_page_prepare (assistant , user_data );
00837         break;
00838     case 2:
00839         /* Current page is match page */
00840         aai_match_page_prepare (assistant , user_data );
00841         break;
00842     }
00843 }
00844 
00845 void
00846 gnc_ab_initial_assistant(void)
00847 {
00848     ABInitialInfo *info;
00849     GtkBuilder *builder;
00850     GtkTreeViewColumn *column;
00851     GtkTreeSelection *selection;
00852     gint component_id;
00853 
00854     info = g_new0(ABInitialInfo, 1);
00855     builder = gtk_builder_new();
00856     gnc_builder_add_from_file (builder, "assistant-ab-initial.glade", "AqBanking Init Assistant");
00857 
00858     info->window = GTK_WIDGET(gtk_builder_get_object (builder, "AqBanking Init Assistant"));
00859 
00860     gnc_assistant_set_colors (GTK_ASSISTANT (info->assistant));
00861 
00862     info->api = gnc_AB_BANKING_new();
00863     info->deferred_info = NULL;
00864     info->gnc_hash = NULL;
00865 
00866     info->match_page_prepared = FALSE;
00867     info->account_view =
00868         GTK_TREE_VIEW(gtk_builder_get_object (builder, "account_page_view"));
00869 
00870     info->account_store = gtk_list_store_new(NUM_ACCOUNT_LIST_COLS,
00871                           G_TYPE_INT, G_TYPE_STRING,
00872                           G_TYPE_POINTER, G_TYPE_STRING,
00873                           G_TYPE_BOOLEAN);
00874     gtk_tree_view_set_model(info->account_view,
00875                             GTK_TREE_MODEL(info->account_store));
00876     g_object_unref(info->account_store);
00877 
00878     column = gtk_tree_view_column_new_with_attributes(
00879                  _("Online Banking Account Name"), gtk_cell_renderer_text_new(),
00880                  "text", ACCOUNT_LIST_COL_AB_NAME, (gchar*) NULL);
00881     gtk_tree_view_append_column(info->account_view, column);
00882 
00883     column = gtk_tree_view_column_new_with_attributes(
00884                  _("GnuCash Account Name"), gtk_cell_renderer_text_new(),
00885                  "text", ACCOUNT_LIST_COL_GNC_NAME, (gchar*) NULL);
00886     gtk_tree_view_column_set_expand(column, TRUE);
00887     gtk_tree_view_append_column(info->account_view, column);
00888 
00889     column = gtk_tree_view_column_new_with_attributes(
00890                  _("New?"), gtk_cell_renderer_toggle_new(),
00891                  "active", ACCOUNT_LIST_COL_CHECKED, (gchar*) NULL);
00892     gtk_tree_view_append_column(info->account_view, column);
00893 
00894     selection = gtk_tree_view_get_selection(info->account_view);
00895     gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
00896 
00897     g_signal_connect(info->account_view, "row-activated",
00898                      G_CALLBACK(account_list_clicked_cb), info);
00899 
00900     g_signal_connect (G_OBJECT(info->window), "destroy",
00901                       G_CALLBACK (aai_destroy_cb), info);
00902 
00903     gtk_builder_connect_signals(builder, info);
00904     g_object_unref(G_OBJECT(builder));
00905 
00906     component_id = gnc_register_gui_component(ASSISTANT_AB_INITIAL_CM_CLASS,
00907                    NULL, aai_close_handler, info);
00908 
00909     gnc_gui_component_set_session(component_id, gnc_get_current_session());
00910 
00911     gtk_widget_show(info->window);
00912 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines