GnuCash 2.4.99
import-account-matcher.c
00001 /********************************************************************\
00002  * import-account-matcher.c - flexible account picker/matcher       *
00003  *                                                                  *
00004  * Copyright (C) 2002 Benoit Grégoire <bock@step.polymtl.ca>        *
00005  * Copyright (C) 2012 Robert Fewell                                 *
00006  *                                                                  *
00007  * This program is free software; you can redistribute it and/or    *
00008  * modify it under the terms of the GNU General Public License as   *
00009  * published by the Free Software Foundation; either version 2 of   *
00010  * the License, or (at your option) any later version.              *
00011  *                                                                  *
00012  * This program is distributed in the hope that it will be useful,  *
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00015  * GNU General Public License for more details.                     *
00016  *                                                                  *
00017  * You should have received a copy of the GNU General Public License*
00018  * along with this program; if not, contact:                        *
00019  *                                                                  *
00020  * Free Software Foundation           Voice:  +1-617-542-5942       *
00021  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00022  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00023 \********************************************************************/
00031 #include "config.h"
00032 
00033 #include <gtk/gtk.h>
00034 #include <glib/gi18n.h>
00035 
00036 #include "import-account-matcher.h"
00037 #include "import-utilities.h"
00038 #include "dialog-account.h"
00039 #include "dialog-utils.h"
00040 
00041 #include "gnc-commodity.h"
00042 #include "gnc-engine.h"
00043 #include "gnc-tree-view-account.h"
00044 #include "gnc-ui.h"
00045 
00046 static QofLogModule log_module = GNC_MOD_IMPORT;
00047 
00048 #define GCONF_SECTION "dialogs/import/generic_matcher/account_matcher"
00049 
00050 /*-******************************************************************\
00051  * Functions needed by gnc_import_select_account
00052  *
00053 \********************************************************************/
00057 static AccountPickerDialog* gnc_import_new_account_picker(void)
00058 {
00059     AccountPickerDialog* picker = g_new(AccountPickerDialog, 1);
00060     picker->dialog = NULL;
00061     picker->assistant = NULL;
00062     picker->account_tree = NULL;
00063     picker->account_tree_sw = NULL;
00064     picker->auto_create = TRUE;
00065     picker->account_human_description = NULL;
00066     picker->account_online_id_value = NULL;
00067     picker->account_online_id_label = NULL;
00068     picker->new_account_default_commodity = NULL;
00069     picker->new_account_default_type = 0;
00070     picker->default_account = NULL;
00071     picker->retAccount = NULL;
00072     return picker;
00073 }
00074 
00075 
00076 /**************************************************
00077  * test_acct_online_id_match
00078  *
00079  * test for match of kvp_frame of account
00080  **************************************************/
00081 static gpointer test_acct_online_id_match(Account *acct, gpointer param_online_id)
00082 {
00083     const gchar * current_online_id = gnc_import_get_acc_online_id(acct);
00084     if ( (current_online_id != NULL
00085             && param_online_id != NULL )
00086             && strcmp( current_online_id, param_online_id ) == 0 )
00087     {
00088         return (gpointer *) acct;
00089     }
00090     else
00091     {
00092         return NULL;
00093     }
00094 }
00095 
00096 
00097 /***********************************************************
00098  * build_acct_tree
00099  *
00100  * build the account tree with the custome column, online_id
00101  ************************************************************/
00102 static void
00103 build_acct_tree(AccountPickerDialog *picker)
00104 {
00105     GtkTreeView *account_tree;
00106     GtkTreeViewColumn *col;
00107 
00108     /* Build a new account tree */
00109     DEBUG("Begin");
00110     account_tree = gnc_tree_view_account_new(FALSE);
00111     picker->account_tree = GNC_TREE_VIEW_ACCOUNT(account_tree);
00112     gtk_tree_view_set_headers_visible (account_tree, TRUE);
00113     col = gnc_tree_view_find_column_by_name(GNC_TREE_VIEW(account_tree), "type");
00114     g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
00115 
00116     /* Add our custom column. */
00117     col = gnc_tree_view_account_add_kvp_column (picker->account_tree,
00118             _("Account ID"), "online_id");
00119     g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
00120 
00121     gtk_container_add(GTK_CONTAINER(picker->account_tree_sw),
00122                       GTK_WIDGET(picker->account_tree));
00123 
00124     /* Configure the columns */
00125     gnc_tree_view_configure_columns (GNC_TREE_VIEW(picker->account_tree));
00126     g_object_set(account_tree,
00127                  "gconf-section", GCONF_SECTION,
00128                  "show-column-menu", TRUE,
00129                  (gchar*) NULL);
00130 }
00131 
00132 
00133 /*******************************************************
00134  * gnc_import_add_account
00135  *
00136  * Callback for when user clicks to create a new account
00137  *******************************************************/
00138 static void
00139 gnc_import_add_account(GtkWidget *button, AccountPickerDialog *picker)
00140 {
00141     Account *selected_account, *new_account;
00142     GList * valid_types = NULL;
00143     /*DEBUG("Begin");  */
00144     if (picker->new_account_default_type != ACCT_TYPE_NONE)
00145     {
00146         /*Yes, this is weird, but we really DO want to pass the value instead of the pointer...*/
00147         valid_types = g_list_prepend(valid_types, GINT_TO_POINTER(picker->new_account_default_type));
00148     }
00149     selected_account = gnc_tree_view_account_get_selected_account(picker->account_tree);
00150     new_account = gnc_ui_new_accounts_from_name_with_defaults ( picker->account_human_description,
00151                   valid_types,
00152                   picker->new_account_default_commodity,
00153                   selected_account);
00154     g_list_free(valid_types);
00155     gnc_tree_view_account_set_selected_account(picker->account_tree, new_account);
00156 }
00157 
00158 
00159 /*******************************************************
00160  * account_tree_row_activated_cb
00161  *
00162  * Callback for when user double clicks on an account
00163  *******************************************************/
00164 static void
00165 account_tree_row_activated_cb(GtkTreeView *view, GtkTreePath *path,
00166                               GtkTreeViewColumn *column,
00167                               AccountPickerDialog *picker)
00168 {
00169     const gchar *retval_name = NULL;
00170     Account *old_id_acc;
00171 
00172     /* See if we have a dialog, if not we are an assistant */
00173     if (picker->dialog == NULL)
00174     {
00175         GtkAssistant *assistant = GTK_ASSISTANT(picker->assistant);
00176         gint num = gtk_assistant_get_current_page (assistant);
00177         GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
00178 
00179         picker->retAccount = gnc_tree_view_account_get_selected_account(picker->account_tree);
00180         if (picker->retAccount)
00181             retval_name = xaccAccountGetName(picker->retAccount);
00182         if (!retval_name)
00183             retval_name = "(null)";
00184         DEBUG("Selected account %p, %s", picker->retAccount, retval_name);
00185 
00186         /* See if the selected account is a placeholder. */
00187         if (picker->retAccount && xaccAccountGetPlaceholder (picker->retAccount))
00188         {
00189             gnc_error_dialog (picker->dialog,
00190                               _("The account %s is a placeholder account and does not allow "
00191                                 "transactions. Please choose a different account."),
00192                               retval_name);
00193         }
00194         else if ( picker->account_online_id_value != NULL)
00195         {
00196             /* find the old account for this on line id value and reset it */
00197             old_id_acc =
00198                 gnc_account_foreach_descendant_until(gnc_get_current_root_account (),
00199                         test_acct_online_id_match,
00200                         /* This argument will only be used as a "const char*" */
00201                         (void*)picker->account_online_id_value);
00202 
00203             if (old_id_acc != NULL)
00204                 gnc_import_set_acc_online_id(old_id_acc, "");
00205 
00206             gnc_import_set_acc_online_id(picker->retAccount, picker->account_online_id_value);
00207             gtk_assistant_set_page_complete (assistant, page, TRUE);
00208         }
00209         else
00210             gtk_assistant_set_page_complete (assistant, page, TRUE);
00211     }
00212     else
00213     {
00214         gtk_dialog_response(GTK_DIALOG(picker->dialog), GTK_RESPONSE_OK);
00215     }
00216 }
00217 
00218 
00219 /*******************************************************
00220  * gnc_import_select_account
00221  *
00222  * Main call for use with a dialog
00223  *******************************************************/
00224 Account * gnc_import_select_account(GtkWidget *parent,
00225                                     const gchar * account_online_id_value,
00226                                     gboolean auto_create,
00227                                     const gchar * account_human_description,
00228                                     const gnc_commodity * new_account_default_commodity,
00229                                     GNCAccountType new_account_default_type,
00230                                     Account * default_selection,
00231                                     gboolean * ok_pressed)
00232 {
00233 #define ACCOUNT_DESCRIPTION_MAX_SIZE 255
00234     AccountPickerDialog * picker;
00235     gint response;
00236     Account * retval = NULL;
00237     const gchar *retval_name = NULL;
00238     GtkBuilder *builder;
00239     GtkWidget * online_id_label, *button, *box, *pbox;
00240     gchar account_description_text[ACCOUNT_DESCRIPTION_MAX_SIZE] = "";
00241     gboolean ok_pressed_retval = FALSE;
00242 
00243     ENTER("Default commodity received: %s", gnc_commodity_get_fullname( new_account_default_commodity));
00244     DEBUG("Default account type received: %s", xaccAccountGetTypeStr( new_account_default_type));
00245     picker = g_new0(AccountPickerDialog, 1);
00246 
00247     picker->account_online_id_value = account_online_id_value;
00248     picker->account_human_description =  account_human_description;
00249     picker->new_account_default_commodity = new_account_default_commodity;
00250     picker->new_account_default_type = new_account_default_type;
00251 
00252     /*DEBUG("Looking for account with online_id: %s", account_online_id_value);*/
00253     if (account_online_id_value != NULL)
00254     {
00255         retval =
00256             gnc_account_foreach_descendant_until(gnc_get_current_root_account (),
00257                     test_acct_online_id_match,
00258                     /* This argument will only be used as a "const char*" */
00259                     (void*)account_online_id_value);
00260     }
00261     if (retval == NULL && auto_create != 0)
00262     {
00263         /* load the interface */
00264         builder = gtk_builder_new();
00265         gnc_builder_add_from_file (builder, "dialog-import.glade", "account_picker");
00266         gnc_builder_add_from_file (builder, "dialog-import.glade", "account_picker_content");
00267         /* connect the signals in the interface */
00268         if (builder == NULL)
00269         {
00270             PERR("Error opening the glade builder interface");
00271         }
00272         picker->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "account_picker"));
00273         if (parent)
00274             gtk_window_set_transient_for (GTK_WINDOW (picker->dialog),
00275                                           GTK_WINDOW (parent));
00276 
00277         /* Pack the content into the dialog vbox */
00278         pbox = GTK_WIDGET(gtk_builder_get_object (builder, "account_picker_vbox"));
00279         box = GTK_WIDGET(gtk_builder_get_object (builder, "account_picker_content"));
00280         gtk_box_pack_start( GTK_BOX(pbox), box, TRUE, TRUE, 0);
00281 
00282         picker->account_tree_sw = GTK_WIDGET(gtk_builder_get_object (builder, "account_tree_sw"));
00283         online_id_label = GTK_WIDGET(gtk_builder_get_object (builder, "online_id_label"));
00284         button = GTK_WIDGET(gtk_builder_get_object (builder, "newbutton"));
00285         gtk_button_set_use_stock (GTK_BUTTON(button), TRUE);
00286 
00287         //printf("gnc_import_select_account(): Fin get widget\n");
00288 
00289         if (account_human_description != NULL)
00290         {
00291             strncat(account_description_text, account_human_description,
00292                     ACCOUNT_DESCRIPTION_MAX_SIZE - strlen(account_description_text));
00293             strncat(account_description_text, "\n",
00294                     ACCOUNT_DESCRIPTION_MAX_SIZE - strlen(account_description_text));
00295         }
00296         if (account_online_id_value != NULL)
00297         {
00298             strncat(account_description_text, _("(Full account ID: "),
00299                     ACCOUNT_DESCRIPTION_MAX_SIZE - strlen(account_description_text));
00300             strncat(account_description_text, account_online_id_value,
00301                     ACCOUNT_DESCRIPTION_MAX_SIZE - strlen(account_description_text));
00302             strncat(account_description_text, ")",
00303                     ACCOUNT_DESCRIPTION_MAX_SIZE - strlen(account_description_text));
00304         }
00305         gtk_label_set_text((GtkLabel*)online_id_label, account_description_text);
00306         build_acct_tree(picker);
00307         gnc_tree_view_account_set_selected_account(picker->account_tree, default_selection);
00308 
00309         gtk_window_set_modal(GTK_WINDOW(picker->dialog), TRUE);
00310         g_signal_connect(picker->account_tree, "row-activated",
00311                          G_CALLBACK(account_tree_row_activated_cb), picker);
00312         do
00313         {
00314             response = gtk_dialog_run(GTK_DIALOG(picker->dialog));
00315             switch (response)
00316             {
00317             case GTK_RESPONSE_OK:
00318                 retval = gnc_tree_view_account_get_selected_account(picker->account_tree);
00319                 if (retval)
00320                     retval_name = xaccAccountGetName(retval);
00321                 if (!retval_name)
00322                     retval_name = "(null)";
00323                 DEBUG("Selected account %p, %s", retval, retval_name);
00324 
00325                 /* See if the selected account is a placeholder. */
00326                 if (retval && xaccAccountGetPlaceholder (retval))
00327                 {
00328                     gnc_error_dialog
00329                     (picker->dialog,
00330                      _("The account %s is a placeholder account and does not allow "
00331                        "transactions. Please choose a different account."),
00332                      retval_name);
00333                     response = GNC_RESPONSE_NEW;
00334                     break;
00335                 }
00336 
00337                 if ( account_online_id_value != NULL)
00338                 {
00339                     gnc_import_set_acc_online_id(retval, account_online_id_value);
00340                 }
00341                 ok_pressed_retval = TRUE;
00342                 break;
00343             case GNC_RESPONSE_NEW:
00344                 gnc_import_add_account(NULL, picker);
00345                 ok_pressed_retval = TRUE;
00346                 break;
00347             default:
00348                 ok_pressed_retval = FALSE;
00349                 break;
00350             }
00351         }
00352         while (response == GNC_RESPONSE_NEW);
00353 
00354         g_object_unref(G_OBJECT(builder));
00355         gtk_widget_destroy(picker->dialog);
00356     }
00357     else
00358     {
00359         retval_name = retval ? xaccAccountGetName(retval) : NULL;
00360         ok_pressed_retval = TRUE; /* There was no dialog involved, so the computer "pressed" ok */
00361     }
00362     /*FIXME: DEBUG("WRITEME: gnc_import_select_account() Here we should check if account type is compatible, currency matches, etc.\n"); */
00363     g_free(picker);
00364     /*DEBUG("Return value: %p%s%s%s",retval,", account name:",xaccAccountGetName(retval),"\n");*/
00365     if (ok_pressed != NULL)
00366     {
00367         *ok_pressed = ok_pressed_retval;
00368     }
00369     LEAVE("Selected account %p, %s", retval, retval_name ? retval_name : "(null)");
00370     return retval;
00371 }
00372 
00373 
00374 /**********************************************************************
00375  * These are the routines for use with an Assistant page
00376  **********************************************************************/
00377 
00378 /*******************************************************
00379  * gnc_import_account_assist_setup
00380  *
00381  * Main call for page setup in an assistant
00382  *******************************************************/
00383 AccountPickerDialog* gnc_import_account_assist_setup(GtkWidget *parent)
00384 {
00385     AccountPickerDialog * picker;
00386     GtkBuilder *builder;
00387     GtkWidget  *button, *box;
00388 
00389     /* Init the account picker structure */
00390     picker = gnc_import_new_account_picker();
00391 
00392     /* load the interface */
00393     builder = gtk_builder_new();
00394     gnc_builder_add_from_file (builder, "dialog-import.glade", "account_picker_content");
00395     /* connect the signals in the interface */
00396     if (builder == NULL)
00397     {
00398         PERR("Error opening the glade builder interface");
00399     }
00400 
00401     picker->assistant = gtk_widget_get_parent(parent);
00402     /* Pack content into Assistant page widget */
00403     box = GTK_WIDGET(gtk_builder_get_object (builder, "account_picker_content"));
00404     gtk_box_pack_start( GTK_BOX(parent), box, TRUE, TRUE, 6);
00405 
00406     picker->account_tree_sw = GTK_WIDGET(gtk_builder_get_object (builder, "account_tree_sw"));
00407     picker->account_online_id_label = GTK_WIDGET(gtk_builder_get_object (builder, "online_id_label"));
00408 
00409     /* Add the New Account Button */
00410     button = gtk_button_new_with_mnemonic ("_New Account");
00411     gtk_box_pack_start( GTK_BOX(box), button, FALSE, FALSE, 6);
00412     gtk_button_set_use_stock (GTK_BUTTON(button), TRUE);
00413     gtk_widget_show (button);
00414     g_signal_connect(button, "clicked",
00415                      G_CALLBACK(gnc_import_add_account), picker);
00416 
00417     build_acct_tree(picker);
00418 
00419     g_signal_connect(picker->account_tree, "row-activated",
00420                      G_CALLBACK(account_tree_row_activated_cb), picker);
00421 
00422     g_object_unref(G_OBJECT(builder));
00423     return picker;
00424 }
00425 
00426 
00427 /*******************************************************
00428  * gnc_import_account_assist_update
00429  *
00430  * updates the page and returns account found.
00431  *******************************************************/
00432 Account * gnc_import_account_assist_update (AccountPickerDialog *picker)
00433 {
00434 #define ACCOUNT_DESCRIPTION_MAX_SIZE 255
00435 
00436     const gchar *retval_name = NULL;
00437     gchar account_description_text[ACCOUNT_DESCRIPTION_MAX_SIZE] = "";
00438 
00439     ENTER("Default commodity received: %s", gnc_commodity_get_fullname( picker->new_account_default_commodity));
00440     DEBUG("Default account type received: %s", xaccAccountGetTypeStr( picker->new_account_default_type));
00441 
00442     /*DEBUG("Looking for account with online_id: %s", picker->account_online_id_value);*/
00443     if (picker->account_online_id_value != NULL)
00444     {
00445         picker->retAccount =
00446             gnc_account_foreach_descendant_until(gnc_get_current_root_account (),
00447                     test_acct_online_id_match,
00448                     /* This argument will only be used as a "const char*" */
00449                     (void*)picker->account_online_id_value);
00450     }
00451 
00452     if (picker->account_human_description != NULL)
00453     {
00454         strncat(account_description_text, picker->account_human_description,
00455                 ACCOUNT_DESCRIPTION_MAX_SIZE - strlen(account_description_text));
00456         strncat(account_description_text, "\n",
00457                 ACCOUNT_DESCRIPTION_MAX_SIZE - strlen(account_description_text));
00458     }
00459     if (picker->account_online_id_value != NULL)
00460     {
00461         strncat(account_description_text, _("(Full account ID: "),
00462                 ACCOUNT_DESCRIPTION_MAX_SIZE - strlen(account_description_text));
00463         strncat(account_description_text, picker->account_online_id_value,
00464                 ACCOUNT_DESCRIPTION_MAX_SIZE - strlen(account_description_text));
00465         strncat(account_description_text, ")",
00466                 ACCOUNT_DESCRIPTION_MAX_SIZE - strlen(account_description_text));
00467     }
00468     gtk_label_set_text(GTK_LABEL( picker->account_online_id_label), account_description_text);
00469 
00470     if (picker->default_account == NULL)
00471         gnc_tree_view_account_set_selected_account(picker->account_tree, picker->retAccount);
00472     else
00473         gnc_tree_view_account_set_selected_account(picker->account_tree, picker->default_account);
00474 
00475     /*FIXME: DEBUG("WRITEME: Here we should check if an account type is compatible, currency matches, etc.\n"); */
00476 
00477     /*DEBUG("Return value: %p%s%s%s",picker->retAccount,", account name:",xaccAccountGetName(picker->retAccount),"\n");*/
00478     retval_name = picker->retAccount ? xaccAccountGetName(picker->retAccount) : NULL;
00479     LEAVE("Selected account %p, %s", picker->retAccount, retval_name ? retval_name : "(null)");
00480     return picker->retAccount;
00481 }
00482 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines