dialog-account.c

00001 /********************************************************************\
00002  * dialog-account.c -- window for creating and editing accounts for *
00003  *                     GnuCash                                      *
00004  * Copyright (C) 2000 Dave Peticolas <dave@krondo.com>              *
00005  * Copyright (C) 2003,2005 David Hampton <hampton@employees.org>    *
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  * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
00022  * Boston, MA  02111-1307,  USA       gnu@gnu.org                   *
00023 \********************************************************************/
00024 
00025 #include "config.h"
00026 
00027 #include <gnome.h>
00028 #include <math.h>
00029 #include <string.h>
00030 
00031 #include "Transaction.h"
00032 #include "dialog-account.h"
00033 #include "dialog-commodity.h"
00034 #include "dialog-utils.h"
00035 #include "global-options.h"
00036 #include "gnc-amount-edit.h"
00037 #include "gnc-general-select.h"
00038 #include "gnc-commodity.h"
00039 #include "gnc-commodity-edit.h"
00040 #include "gnc-component-manager.h"
00041 #include "gnc-engine-util.h"
00042 #include "gnc-engine.h"
00043 #include "gnc-gui-query.h"
00044 #include "gnc-session.h"
00045 #include "gnc-tree-view-account.h"
00046 #include "gnc-ui.h"
00047 #include "gnc-ui-util.h"
00048 #include "messages.h"
00049 
00050 
00051 #define DIALOG_NEW_ACCOUNT_CM_CLASS "dialog-new-account"
00052 #define DIALOG_EDIT_ACCOUNT_CM_CLASS "dialog-edit-account"
00053 #define GCONF_SECTION "dialogs/account"
00054 
00055 typedef enum
00056 {
00057   NEW_ACCOUNT,
00058   EDIT_ACCOUNT
00059 } AccountDialogType;
00060 
00061 
00062 typedef struct _AccountWindow
00063 {
00064   gboolean modal;
00065   GtkWidget *dialog;
00066 
00067   AccountDialogType dialog_type;
00068 
00069   GUID    account;
00070   Account *top_level_account; /* owned by the model */
00071   Account *created_account;
00072 
00073   GList *subaccount_names;
00074 
00075   GNCAccountType type;
00076 
00077   GtkWidget * notebook;
00078 
00079   GtkWidget * name_entry;
00080   GtkWidget * description_entry;
00081   GtkWidget * code_entry;
00082   GtkTextBuffer * notes_text_buffer;
00083 
00084   GtkWidget * commodity_edit;
00085   dialog_commodity_mode commodity_mode;
00086   GtkWidget * account_scu;
00087   
00088   GList * valid_types;
00089   GtkWidget * type_list;
00090   GtkTreeView * parent_tree;
00091 
00092   GtkWidget * opening_balance_edit;
00093   GtkWidget * opening_balance_date_edit;
00094   GtkWidget * opening_balance_page;
00095 
00096   GtkWidget * opening_equity_radio;
00097   GtkWidget * transfer_account_frame;
00098   GtkWidget * transfer_tree;
00099 
00100   GtkWidget * tax_related_button;
00101   GtkWidget * placeholder_button;
00102 
00103   gint component_id;
00104 } AccountWindow;
00105 
00106 
00108 static short module = MOD_GUI;
00109 
00110 static int last_used_account_type = BANK;
00111 
00112 static GList *ac_destroy_cb_list = NULL;
00113 
00115 static void gnc_account_window_set_name (AccountWindow *aw);
00116 static void make_account_changes(GHashTable *change_type);
00117 
00118 
00121 static void
00122 aw_call_destroy_callbacks (Account* acc)
00123 {
00124   GList *node;
00125   void (*cb)(Account*);
00126 
00127   for (node = ac_destroy_cb_list; node; node = node->next) {
00128     cb = node->data;
00129     (cb)(acc);
00130   }
00131 }
00132 
00133 static Account *
00134 aw_get_account (AccountWindow *aw)
00135 {
00136   if (!aw)
00137     return NULL;
00138 
00139   return xaccAccountLookup (&aw->account, gnc_get_current_book ());
00140 }
00141 
00142 static void
00143 gnc_account_commodity_from_type (AccountWindow * aw, gboolean update)
00144 {
00145   dialog_commodity_mode new_mode;
00146 
00147   if ((aw->type == STOCK) || (aw->type == MUTUAL))
00148     new_mode = DIAG_COMM_NON_CURRENCY;
00149   else
00150     new_mode = DIAG_COMM_CURRENCY;
00151 
00152   if (update && (new_mode != aw->commodity_mode)) {
00153     gnc_general_select_set_selected(GNC_GENERAL_SELECT (aw->commodity_edit),
00154                                     NULL);
00155   }
00156 
00157   aw->commodity_mode = new_mode;
00158 }
00159 
00160 /* Copy the account values to the GUI widgets */
00161 static void
00162 gnc_account_to_ui(AccountWindow *aw)
00163 {
00164   Account *account;
00165   gnc_commodity * commodity;
00166   const char *string;
00167   gboolean tax_related, placeholder, nonstd_scu;
00168   gint index;
00169 
00170   ENTER("%p", aw);
00171   account = aw_get_account (aw);
00172   if (!account) {
00173     LEAVE("no account");
00174     return;
00175   }
00176 
00177   string = xaccAccountGetName (account);
00178   if (string == NULL) string = "";
00179   gtk_entry_set_text(GTK_ENTRY(aw->name_entry), string);
00180 
00181   string = xaccAccountGetDescription (account);
00182   if (string == NULL) string = "";
00183   gtk_entry_set_text(GTK_ENTRY(aw->description_entry), string);
00184 
00185   commodity = xaccAccountGetCommodity (account);
00186   gnc_general_select_set_selected (GNC_GENERAL_SELECT (aw->commodity_edit),
00187                                     commodity);
00188   gnc_account_commodity_from_type (aw, FALSE);
00189 
00190   nonstd_scu = xaccAccountGetNonStdSCU (account);
00191   if (nonstd_scu) {
00192     index = xaccAccountGetCommoditySCUi(account);
00193     index = log10(index) + 1;
00194   } else {
00195     index = 0;
00196   }
00197   gtk_option_menu_set_history(GTK_OPTION_MENU(aw->account_scu), index);
00198 
00199   string = xaccAccountGetCode (account);
00200   if (string == NULL) string = "";
00201   gtk_entry_set_text(GTK_ENTRY(aw->code_entry), string);
00202 
00203   string = xaccAccountGetNotes (account);
00204   if (string == NULL) string = "";
00205 
00206   gtk_text_buffer_set_text (aw->notes_text_buffer, string, strlen(string));
00207 
00208   tax_related = xaccAccountGetTaxRelated (account);
00209   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aw->tax_related_button),
00210                                 tax_related);
00211 
00212   placeholder = xaccAccountGetPlaceholder (account);
00213   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aw->placeholder_button),
00214                                 placeholder);
00215 
00216   gtk_tree_view_collapse_all (aw->parent_tree);
00217   gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT(aw->parent_tree), account);
00218   LEAVE(" ");
00219 }
00220 
00221 
00222 static gboolean
00223 gnc_account_create_transfer_balance (Account *account,
00224                                      Account *transfer,
00225                                      gnc_numeric balance,
00226                                      time_t date)
00227 {
00228   Transaction *trans;
00229   Split *split;
00230 
00231   if (gnc_numeric_zero_p (balance))
00232     return TRUE;
00233 
00234   g_return_val_if_fail (account != NULL, FALSE);
00235   g_return_val_if_fail (transfer != NULL, FALSE);
00236 
00237   xaccAccountBeginEdit (account);
00238   xaccAccountBeginEdit (transfer);
00239 
00240   trans = xaccMallocTransaction (gnc_get_current_book ());
00241 
00242   xaccTransBeginEdit (trans);
00243 
00244   xaccTransSetCurrency (trans, xaccAccountGetCommodity (account));
00245   xaccTransSetDateSecs (trans, date);
00246   xaccTransSetDescription (trans, _("Opening Balance"));
00247 
00248   split = xaccMallocSplit (gnc_get_current_book ());
00249 
00250   xaccTransAppendSplit (trans, split);
00251   xaccAccountInsertSplit (account, split);
00252 
00253   xaccSplitSetAmount (split, balance);
00254   xaccSplitSetValue (split, balance);
00255 
00256   balance = gnc_numeric_neg (balance);
00257 
00258   split = xaccMallocSplit (gnc_get_current_book ());
00259 
00260   xaccTransAppendSplit (trans, split);
00261   xaccAccountInsertSplit (transfer, split);
00262 
00263   xaccSplitSetAmount (split, balance);
00264   xaccSplitSetValue (split, balance);
00265 
00266   xaccTransCommitEdit (trans);
00267   xaccAccountCommitEdit (transfer);
00268   xaccAccountCommitEdit (account);
00269 
00270   return TRUE;
00271 }
00272 
00273 /* Record the GUI values into the Account structure */
00274 static void
00275 gnc_ui_to_account(AccountWindow *aw)
00276 {
00277   Account *account;
00278   gnc_commodity *commodity;
00279   Account *parent_account;
00280   const char *old_string;
00281   const char *string;
00282   gboolean tax_related, placeholder;
00283   gnc_numeric balance;
00284   gboolean use_equity, nonstd;
00285   time_t date;
00286   gint index, old_scu, new_scu;
00287   GtkTextIter start, end;
00288 
00289   account = aw_get_account (aw);
00290   if (!account) {
00291     LEAVE("no account");
00292     return;
00293   }
00294 
00295   xaccAccountBeginEdit (account);
00296 
00297   if (aw->type != xaccAccountGetType (account))
00298     xaccAccountSetType (account, aw->type);
00299 
00300   string = gtk_entry_get_text (GTK_ENTRY(aw->name_entry));
00301   old_string = xaccAccountGetName (account);
00302   if (safe_strcmp (string, old_string) != 0)
00303     xaccAccountSetName (account, string);
00304 
00305   string = gtk_entry_get_text (GTK_ENTRY(aw->description_entry));
00306   old_string = xaccAccountGetDescription (account);
00307   if (safe_strcmp (string, old_string) != 0)
00308     xaccAccountSetDescription (account, string);
00309 
00310   commodity = (gnc_commodity *)
00311     gnc_general_select_get_selected (GNC_GENERAL_SELECT (aw->commodity_edit));
00312   if (commodity &&
00313       !gnc_commodity_equiv(commodity, xaccAccountGetCommodity (account))) {
00314     xaccAccountSetCommodity (account, commodity);
00315     old_scu = 0;
00316   } else {
00317     old_scu = xaccAccountGetCommoditySCU(account);
00318   }
00319 
00320   index = gnc_option_menu_get_active(aw->account_scu);
00321   nonstd = (index != 0);
00322   if (nonstd != xaccAccountGetNonStdSCU(account))
00323     xaccAccountSetNonStdSCU(account, nonstd);
00324   new_scu = (nonstd ? pow(10,index-1) : gnc_commodity_get_fraction(commodity));
00325   if (old_scu != new_scu)
00326     xaccAccountSetCommoditySCU(account, new_scu);
00327 
00328   string = gtk_entry_get_text (GTK_ENTRY(aw->code_entry));
00329   old_string = xaccAccountGetCode (account);
00330   if (safe_strcmp (string, old_string) != 0)
00331     xaccAccountSetCode (account, string);
00332 
00333   gtk_text_buffer_get_start_iter (aw->notes_text_buffer, &start);
00334   gtk_text_buffer_get_end_iter (aw->notes_text_buffer, &end);
00335   string = gtk_text_buffer_get_text (aw->notes_text_buffer, &start, &end, FALSE);
00336   old_string = xaccAccountGetNotes (account);
00337   if (safe_strcmp (string, old_string) != 0)
00338     xaccAccountSetNotes (account, string);
00339 
00340   tax_related =
00341     gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (aw->tax_related_button));
00342   xaccAccountSetTaxRelated (account, tax_related);
00343 
00344   placeholder =
00345     gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (aw->placeholder_button));
00346   xaccAccountSetPlaceholder (account, placeholder);
00347 
00348   parent_account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT (aw->parent_tree));
00349   if (parent_account == aw->top_level_account)
00350     parent_account = NULL;
00351 
00352   xaccAccountBeginEdit (parent_account);
00353 
00354   if (parent_account != NULL)
00355   {
00356     if (parent_account != xaccAccountGetParentAccount (account))
00357       xaccAccountInsertSubAccount (parent_account, account);
00358   }
00359   else
00360     xaccGroupInsertAccount (gnc_get_current_group (), account);
00361 
00362   xaccAccountCommitEdit (parent_account);
00363   xaccAccountCommitEdit (account);
00364 
00365   balance = gnc_amount_edit_get_amount
00366     (GNC_AMOUNT_EDIT (aw->opening_balance_edit));
00367 
00368   if (gnc_numeric_zero_p (balance)) {
00369     LEAVE("zero balance");
00370     return;
00371   }
00372 
00373   if (gnc_reverse_balance (account))
00374     balance = gnc_numeric_neg (balance);
00375 
00376   date = gnome_date_edit_get_time (
00377                   GNOME_DATE_EDIT (aw->opening_balance_date_edit));
00378 
00379   use_equity = gtk_toggle_button_get_active
00380     (GTK_TOGGLE_BUTTON (aw->opening_equity_radio));
00381 
00382   if (use_equity)
00383   {
00384     if (!gnc_account_create_opening_balance (account, balance, date,
00385                                              gnc_get_current_book ()))
00386     {
00387       const char *message = _("Could not create opening balance.");
00388       gnc_error_dialog(aw->dialog, message);
00389     }
00390   }
00391   else
00392   {
00393     Account *transfer = NULL;
00394 
00395     transfer = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT (aw->transfer_tree));
00396     if (!transfer) {
00397       LEAVE("no transfer account");
00398       return;
00399     }
00400 
00401     gnc_account_create_transfer_balance (account, transfer, balance, date);
00402   }
00403     LEAVE(" ");
00404 }
00405 
00406 
00407 static void 
00408 gnc_finish_ok (AccountWindow *aw,
00409                GHashTable *change_type)
00410 {
00411   ENTER("aw %p, hash table %p", aw, change_type);
00412   gnc_suspend_gui_refresh ();
00413 
00414   /* make the account changes */
00415   make_account_changes (change_type);
00416   gnc_ui_to_account (aw);
00417 
00418   gnc_resume_gui_refresh ();
00419 
00420   /* do it all again, if needed */
00421   if (aw->dialog_type == NEW_ACCOUNT && aw->subaccount_names)
00422   {
00423     gnc_commodity *commodity;
00424     Account *parent;
00425     Account *account;
00426     GList *node;
00427 
00428     gnc_suspend_gui_refresh ();
00429 
00430     parent = aw_get_account (aw);
00431     account = xaccMallocAccount (gnc_get_current_book ());
00432     aw->account = *xaccAccountGetGUID (account);
00433     aw->type = xaccAccountGetType (parent);
00434 
00435     xaccAccountSetName (account, aw->subaccount_names->data);
00436 
00437     node = aw->subaccount_names;
00438     aw->subaccount_names = g_list_remove_link (aw->subaccount_names, node);
00439     g_free (node->data);
00440     g_list_free_1 (node);
00441 
00442     gnc_account_to_ui (aw);
00443 
00444     gnc_account_window_set_name (aw);
00445 
00446     commodity = xaccAccountGetCommodity (parent);
00447     gnc_general_select_set_selected (GNC_GENERAL_SELECT (aw->commodity_edit),
00448                                       commodity);
00449     gnc_account_commodity_from_type (aw, FALSE);
00450 
00451     /*gnc_account_tree_select_account (GNC_ACCOUNT_TREE(aw->parent_tree),
00452                                      parent, TRUE);*/
00453 
00454     gnc_resume_gui_refresh ();
00455     LEAVE("1");
00456     return;
00457   }
00458 
00459   /* save for posterity */
00460   aw->created_account = aw_get_account (aw);
00461 
00462   /* so it doesn't get freed on close */
00463   aw->account = *xaccGUIDNULL ();
00464 
00465   gnc_close_gui_component (aw->component_id);
00466   LEAVE("2");
00467 }
00468 
00469 
00470 /* Record all of the children of the given account as needing their
00471  * type changed to the one specified. */
00472 static void
00473 gnc_edit_change_account_types(GHashTable *change_type, Account *account,
00474                               Account *except, GNCAccountType type)
00475 {
00476   AccountGroup *children;
00477   GList *list;
00478   GList *node;
00479 
00480   if ((change_type == NULL) || (account == NULL))
00481     return;
00482 
00483   if (account == except)
00484     return;
00485 
00486   g_hash_table_insert(change_type, account, GINT_TO_POINTER(type));
00487 
00488   children = xaccAccountGetChildren(account);
00489   if (children == NULL)
00490     return;
00491 
00492   list = xaccGroupGetAccountList (children);
00493 
00494   for (node= list; node; node = node->next)
00495   {
00496     account = node->data;
00497     gnc_edit_change_account_types(change_type, account, except, type);
00498   }
00499 }
00500 
00501 
00502 /* helper function to perform changes to accounts */
00503 static void
00504 change_func (gpointer key, gpointer value, gpointer unused)
00505 {
00506   Account *account = key;
00507   int type;
00508  
00509   if (account == NULL)
00510     return;
00511 
00512   xaccAccountBeginEdit(account);
00513 
00514   type = GPOINTER_TO_INT(value);
00515 
00516   if (type == xaccAccountGetType(account))
00517     return;
00518 
00519   /* Just refreshing won't work. */
00520   aw_call_destroy_callbacks (account);
00521 
00522   xaccAccountSetType(account, type);
00523 
00524   xaccAccountCommitEdit(account);
00525 }
00526 
00527 
00528 /* Perform the changes to accounts dictated by the hash tables */
00529 static void
00530 make_account_changes(GHashTable *change_type)
00531 {
00532   if (change_type != NULL)
00533     g_hash_table_foreach(change_type, change_func, NULL);
00534 }
00535 
00536 
00537 typedef struct
00538 {
00539   Account *account;
00540   GtkCList *list;
00541   guint count;
00542 } FillStruct;
00543 
00544 static void
00545 fill_helper(gpointer key, gpointer value, gpointer data)
00546 {
00547   Account *account = key;
00548   FillStruct *fs = data;
00549   gchar *full_name;
00550   gchar *account_field_name;
00551   gchar *account_field_value;
00552   gchar *value_str;
00553 
00554   if (fs == NULL) return;
00555   if (fs->account == account) return;
00556 
00557   full_name = xaccAccountGetFullName(account, gnc_get_account_separator());
00558   if(!full_name)
00559     full_name = g_strdup("");
00560 
00561   account_field_name = g_strdup("Type");
00562   if (!account_field_name)
00563     account_field_name = g_strdup("");
00564 
00565   account_field_value =
00566     g_strdup (xaccAccountGetTypeStr(xaccAccountGetType(account)));
00567   if (!account_field_value)
00568     account_field_value = g_strdup("");
00569 
00570   value_str = g_strdup(xaccAccountGetTypeStr(GPOINTER_TO_INT(value)));
00571 
00572   {  
00573     gchar *strings[5];
00574 
00575     strings[0] = full_name;
00576     strings[1] = account_field_name;
00577     strings[2] = account_field_value;
00578     strings[3] = value_str;
00579     strings[4] = NULL; 
00580 
00581     gtk_clist_append(fs->list, strings);
00582   }
00583 
00584   g_free(full_name);
00585   g_free(account_field_name);
00586   g_free(account_field_value);
00587   g_free(value_str);
00588   fs->count++;
00589 }
00590 
00591 static guint
00592 fill_list(Account *account, GtkCList *list,
00593           GHashTable *change)
00594 {
00595   FillStruct fs;
00596 
00597   if (change == NULL)
00598     return 0;
00599 
00600   fs.account = account;
00601   fs.list = list;
00602   fs.count = 0;
00603 
00604   g_hash_table_foreach(change, fill_helper, &fs);
00605 
00606   return fs.count;
00607 }
00608 
00609 
00610 /* Present a dialog of proposed account changes for the user's ok */
00611 static gboolean
00612 extra_change_verify (AccountWindow *aw,
00613                      GHashTable *change_type)
00614 {
00615   Account *account;
00616   GtkCList *list;
00617   gchar *titles[5];
00618   gboolean result;
00619   guint size;
00620 
00621   if (aw == NULL)
00622     return FALSE;
00623 
00624   account = aw_get_account (aw);
00625   if (!account)
00626     return FALSE;
00627 
00628   titles[0] = _("Account");
00629   titles[1] = _("Field");
00630   titles[2] = _("Old Value");
00631   titles[3] = _("New Value");
00632   titles[4] = NULL;
00633 
00634   list = GTK_CLIST(gtk_clist_new_with_titles(4, titles));
00635 
00636   size = 0;
00637   size += fill_list(account, list, change_type);
00638 
00639   if (size == 0)
00640   {
00641     gtk_widget_destroy(GTK_WIDGET(list));
00642     return TRUE;
00643   }
00644 
00645   gtk_clist_column_titles_passive(list);
00646   gtk_clist_set_sort_column(list, 0);
00647   gtk_clist_sort(list);
00648   gtk_clist_columns_autosize(list);
00649 
00650   {
00651     GtkWidget *dialog;
00652     GtkWidget *scroll;
00653     GtkWidget *label;
00654     GtkWidget *frame;
00655     GtkWidget *vbox;
00656 
00657     dialog = gtk_dialog_new_with_buttons (_("Verify Changes"),
00658                                           GTK_WINDOW(aw->dialog),
00659                                           GTK_DIALOG_DESTROY_WITH_PARENT |
00660                                           GTK_DIALOG_MODAL,
00661                                           GTK_STOCK_OK, GTK_RESPONSE_OK,
00662                                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
00663                                           NULL);
00664 
00665     gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
00666     gtk_window_set_default_size (GTK_WINDOW (dialog), 0, 300);
00667 
00668     vbox = GTK_DIALOG (dialog)->vbox;
00669 
00670     label = gtk_label_new(_("The following changes must be made. Continue?"));
00671     gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
00672 
00673     frame = gtk_frame_new(NULL);
00674     gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
00675 
00676     scroll = gtk_scrolled_window_new(NULL, NULL);
00677     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
00678                                    GTK_POLICY_NEVER, 
00679                                    GTK_POLICY_AUTOMATIC);
00680 
00681     gtk_container_add(GTK_CONTAINER(frame), scroll);
00682     gtk_container_border_width(GTK_CONTAINER(scroll), 5);
00683     gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(list));
00684 
00685     gtk_widget_show_all(vbox);
00686 
00687     result = (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK);
00688 
00689     gtk_widget_destroy(dialog);
00690   }
00691 
00692   return result;
00693 }
00694 
00695 
00696 static gboolean
00697 gnc_filter_parent_accounts (Account *account, gpointer data)
00698 {
00699   AccountWindow *aw = data;
00700   Account *aw_account = aw_get_account (aw);
00701 
00702   if (account == NULL)
00703     return FALSE;
00704 
00705   if (aw_account == NULL)
00706     return FALSE;
00707 
00708   if (account == aw->top_level_account)
00709     return TRUE;
00710 
00711   if (account == aw_account)
00712     return FALSE;
00713 
00714   if (xaccAccountHasAncestor(account, aw_account))
00715     return FALSE;
00716 
00717   return TRUE;
00718 }
00719 
00720 
00721 static void
00722 gnc_edit_account_ok(AccountWindow *aw)
00723 {
00724   GHashTable *change_type;
00725 
00726   gboolean change_children;
00727   gboolean has_children;
00728   gboolean change_all;
00729 
00730   Account *new_parent;
00731   Account *account;
00732   AccountGroup *children;
00733 
00734   GNCAccountType current_type;
00735 
00736   const char *name;
00737   gnc_commodity * commodity;
00738 
00739   /* check for valid name */
00740   ENTER("aw %p", aw);
00741   name = gtk_entry_get_text(GTK_ENTRY(aw->name_entry));
00742   if (safe_strcmp(name, "") == 0)
00743   {
00744     const char *message = _("The account must be given a name.");
00745     gnc_error_dialog(aw->dialog, message);
00746     LEAVE(" ");
00747     return;
00748   }
00749 
00750   /* check for valid type */
00751   if (aw->type == BAD_TYPE)
00752   {
00753     const char *message = _("You must select an account type.");
00754     gnc_error_dialog(aw->dialog, message);
00755     LEAVE(" ");
00756     return;
00757   }
00758 
00759   new_parent = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT (aw->parent_tree));
00760 
00761   /* Parent check, probably not needed, but be safe */
00762   if (!gnc_filter_parent_accounts(new_parent, aw))
00763   {
00764     const char *message = _("You must choose a valid parent account.");
00765     gnc_error_dialog(aw->dialog, message);
00766     LEAVE(" ");
00767     return;
00768   }
00769 
00770   commodity = (gnc_commodity *)
00771     gnc_general_select_get_selected (GNC_GENERAL_SELECT (aw->commodity_edit));
00772 
00773   if (!commodity)
00774   {
00775     const char *message = _("You must choose a commodity.");
00776     gnc_error_dialog(aw->dialog, message);
00777     LEAVE(" ");
00778     return;
00779   }
00780 
00781   account = aw_get_account (aw);
00782   if (!account) {
00783     LEAVE(" ");
00784     return;
00785   }
00786 
00787   change_type = g_hash_table_new (NULL, NULL);
00788 
00789   children = xaccAccountGetChildren(account);
00790   if (children == NULL)
00791     has_children = FALSE;
00792   else if (xaccGroupGetNumAccounts(children) == 0)
00793     has_children = FALSE;
00794   else
00795     has_children = TRUE;
00796 
00797   current_type = xaccAccountGetType(account);
00798 
00799   /* If the account has children and the new type isn't compatible
00800    * with the old type, the children's types must be changed. */
00801   change_children = (has_children &&
00802                      !xaccAccountTypesCompatible(current_type, aw->type));
00803 
00804   /* If the new parent's type is not compatible with the new type,
00805    * the whole sub-tree containing the account must be re-typed. */
00806   if (new_parent != aw->top_level_account)
00807   {
00808     int parent_type;
00809 
00810     parent_type = xaccAccountGetType(new_parent);
00811 
00812     if (!xaccAccountTypesCompatible(parent_type, aw->type))
00813       change_all = TRUE;
00814     else
00815       change_all = FALSE;
00816   }
00817   else
00818     change_all = FALSE;
00819 
00820   if (change_children)
00821     gnc_edit_change_account_types(change_type, account, NULL, aw->type);
00822 
00823   if (change_all)
00824   {
00825     Account *ancestor;
00826     Account *temp;
00827 
00828     temp = new_parent;
00829 
00830     do
00831     {
00832       ancestor = temp;
00833       temp = xaccAccountGetParentAccount(ancestor);
00834     } while (temp != NULL);
00835 
00836     gnc_edit_change_account_types(change_type, ancestor, account, aw->type);
00837   }
00838 
00839   if (!extra_change_verify(aw, change_type))
00840   {
00841     g_hash_table_destroy(change_type);
00842     LEAVE(" ");
00843     return;
00844   }
00845 
00846   if (current_type != aw->type)
00847     /* Just refreshing won't work. */
00848     aw_call_destroy_callbacks (account);
00849 
00850   gnc_finish_ok (aw, change_type);
00851 
00852   g_hash_table_destroy (change_type);
00853     LEAVE(" ");
00854 }
00855 
00856 
00857 static void
00858 gnc_new_account_ok (AccountWindow *aw)
00859 {
00860   const gnc_commodity * commodity;
00861   Account *parent_account;
00862   gnc_numeric balance;
00863   const gchar *name;
00864 
00865   /* check for valid name */
00866   ENTER("aw %p", aw);
00867   name = gtk_entry_get_text(GTK_ENTRY(aw->name_entry));
00868   if (safe_strcmp(name, "") == 0)
00869   {
00870     const char *message = _("The account must be given a name.");
00871     gnc_error_dialog(aw->dialog, message);
00872     LEAVE(" ");
00873     return;
00874   }
00875 
00876   parent_account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT (aw->parent_tree));
00877 
00878   if (parent_account == aw->top_level_account)
00879     parent_account = NULL;
00880 
00881   /* check for a duplicate name */
00882   {
00883     Account *account;
00884     AccountGroup *group;
00885     char separator;
00886 
00887     group = gnc_get_current_group ();
00888 
00889     separator = gnc_get_account_separator();
00890 
00891     if (parent_account == NULL)
00892       account = xaccGetAccountFromFullName(group, name, separator);
00893     else
00894     {
00895       char *fullname_parent;
00896       char *fullname;
00897       char sep_string[2];
00898 
00899       sep_string[0] = separator;
00900       sep_string[1] = '\0';
00901 
00902       fullname_parent = xaccAccountGetFullName(parent_account, separator);
00903       fullname = g_strconcat(fullname_parent, sep_string, name, NULL);
00904 
00905       account = xaccGetAccountFromFullName(group, fullname, separator);
00906 
00907       g_free(fullname_parent);
00908       g_free(fullname);
00909     }
00910 
00911     if (account != NULL)
00912     {
00913       const char *message = _("There is already an account with that name.");
00914       gnc_error_dialog(aw->dialog, message);
00915       LEAVE(" ");
00916       return;
00917     }
00918   }
00919 
00920   /* check for valid type */
00921   if (aw->type == BAD_TYPE)
00922   {
00923     const char *message = _("You must select an account type.");
00924     gnc_error_dialog(aw->dialog, message);
00925     LEAVE(" ");
00926     return;
00927   }
00928 
00929   /* check for commodity */
00930   commodity = (gnc_commodity *)
00931     gnc_general_select_get_selected (GNC_GENERAL_SELECT (aw->commodity_edit));
00932 
00933   if (!commodity)
00934   {
00935     const char *message = _("You must choose a commodity.");
00936     gnc_error_dialog(aw->dialog, message);
00937     LEAVE(" ");
00938     return;
00939   }
00940 
00941   if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (aw->opening_balance_edit)))
00942   {
00943     const char *message = _("You must enter a valid opening balance "
00944                             "or leave it blank.");
00945     gnc_error_dialog(aw->dialog, message);
00946     LEAVE(" ");
00947     return;
00948   }
00949 
00950   balance = gnc_amount_edit_get_amount
00951     (GNC_AMOUNT_EDIT (aw->opening_balance_edit));
00952 
00953   if (!gnc_numeric_zero_p (balance))
00954   {
00955     gboolean use_equity;
00956 
00957     use_equity = gtk_toggle_button_get_active
00958       (GTK_TOGGLE_BUTTON (aw->opening_equity_radio));
00959 
00960     if (!use_equity)
00961     {
00962       Account *transfer = NULL;
00963 
00964       transfer = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT (aw->transfer_tree));
00965       if (!transfer)
00966       {
00967         const char *message = _("You must select a transfer account or choose"
00968                                 "\nthe opening balances equity account.");
00969         gnc_error_dialog(aw->dialog, message);
00970         LEAVE(" ");
00971         return;
00972       }
00973     }
00974   }
00975 
00976   gnc_finish_ok (aw, NULL);
00977   LEAVE(" ");
00978 }
00979 
00980 static void
00981 gnc_account_window_response_cb (GtkDialog *dialog,
00982                                 gint response,
00983                                 gpointer data)
00984 {
00985         AccountWindow *aw = data; 
00986 
00987         ENTER("dialog %p, response %d, aw %p", dialog, response, aw);
00988         switch (response) {
00989                 case GTK_RESPONSE_OK:
00990                         switch (aw->dialog_type) {
00991                                 case NEW_ACCOUNT:
00992                                         DEBUG("new acct dialog, OK");
00993                                         gnc_new_account_ok (aw);
00994                                         break;
00995                                 case EDIT_ACCOUNT:
00996                                         DEBUG("edit acct dialog, OK");
00997                                         gnc_edit_account_ok (aw);
00998                                         break;
00999                                 default:
01000                                         g_assert_not_reached ();
01001                                         return;
01002                         }
01003                         break;
01004                 case GTK_RESPONSE_HELP:
01005                         switch (aw->dialog_type) {
01006                                 case NEW_ACCOUNT:
01007                                         DEBUG("new acct dialog, HELP");
01008                                         gnc_gnome_help(HF_USAGE, HL_ACC);
01009                                         break;
01010                                 case EDIT_ACCOUNT:
01011                                         DEBUG("edit acct dialog, HELP");
01012                                         gnc_gnome_help(HF_USAGE, HL_ACCEDIT);
01013                                         break;
01014                                 default:
01015                                         g_assert_not_reached ();
01016                                         return;
01017                         }
01018                         break;
01019                 case GTK_RESPONSE_CANCEL:
01020                 default:
01021                         DEBUG("CANCEL");
01022                         gnc_close_gui_component (aw->component_id);
01023                         break;
01024         }
01025         LEAVE(" ");
01026 }
01027 
01028 static void
01029 gnc_account_window_destroy_cb (GtkObject *object, gpointer data)
01030 {
01031   AccountWindow *aw = data;
01032   Account *account;
01033 
01034   ENTER("object %p, aw %p", object, aw);
01035   account = aw_get_account (aw);
01036 
01037   gnc_suspend_gui_refresh ();
01038 
01039   switch (aw->dialog_type)
01040   {
01041     case NEW_ACCOUNT:
01042       if (account != NULL)
01043       {
01044         xaccAccountBeginEdit (account);
01045         xaccAccountDestroy (account);
01046         aw->account = *xaccGUIDNULL ();
01047       }
01048 
01049       DEBUG ("account add window destroyed\n");
01050       break;
01051 
01052     case EDIT_ACCOUNT:
01053       break;
01054 
01055     default:
01056       PERR ("unexpected dialog type\n");
01057       gnc_resume_gui_refresh ();
01058       LEAVE(" ");
01059       return;
01060   }
01061 
01062   gnc_unregister_gui_component (aw->component_id);
01063 
01064   aw->top_level_account = NULL;
01065 
01066   gnc_resume_gui_refresh ();
01067 
01068   if (aw->subaccount_names)
01069   {
01070     GList *node;
01071     for (node = aw->subaccount_names; node; node = node->next)
01072       g_free (node->data);
01073     g_list_free (aw->subaccount_names);
01074     aw->subaccount_names = NULL;
01075   }
01076 
01077   g_list_free (aw->valid_types);
01078   g_free (aw);
01079   LEAVE(" ");
01080 }
01081 
01082 
01083 static void 
01084 gnc_type_list_select_cb(GtkCList * type_list, gint row, gint column,
01085                         GdkEventButton * event, gpointer data)
01086 {
01087   AccountWindow * aw = data;
01088   gboolean sensitive;
01089 
01090   if (aw == NULL)
01091     return;
01092 
01093   if (!gtk_clist_get_selectable(type_list, row))
01094   {
01095     gtk_clist_unselect_row(type_list, row, 0);
01096     return;
01097   }
01098 
01099   aw->type = (GNCAccountType)gtk_clist_get_row_data(type_list, row);
01100 
01101   last_used_account_type = aw->type;
01102 
01103   sensitive = (aw->type != EQUITY &&
01104                aw->type != CURRENCY &&
01105                aw->type != STOCK &&
01106                aw->type != MUTUAL);
01107 
01108   gnc_account_commodity_from_type (aw, TRUE);
01109   gtk_widget_set_sensitive(aw->opening_balance_page, sensitive);
01110   if (!sensitive)
01111   {
01112     gtk_notebook_set_page (GTK_NOTEBOOK (aw->notebook), 0);
01113     gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (aw->opening_balance_edit),
01114                                 gnc_numeric_zero ());
01115   }
01116 }
01117 
01118 
01119 static void 
01120 gnc_type_list_unselect_cb(GtkCList * type_list, gint row, gint column,
01121                           GdkEventButton * event, gpointer data)
01122 {
01123   AccountWindow * aw = data;
01124 
01125   aw->type = BAD_TYPE;
01126 }
01127 
01128 
01129 static void
01130 gnc_account_list_fill(GtkCList *type_list, GList *types)
01131 {
01132   gint row, acct_type;
01133   gchar *text[2] = { NULL, NULL };
01134 
01135   gtk_clist_freeze(type_list);
01136   gtk_clist_clear(type_list);
01137 
01138   if (types == NULL)
01139   {
01140     for (acct_type = 0; acct_type < NUM_ACCOUNT_TYPES; acct_type++) 
01141     {
01142       text[0] = (gchar *) xaccAccountGetTypeStr(acct_type);
01143       row = gtk_clist_append(type_list, text);
01144       gtk_clist_set_row_data(type_list, row, GINT_TO_POINTER(acct_type));
01145     }
01146   }
01147   else
01148   {
01149     for ( ; types != NULL; types = types->next )
01150     {
01151       text[0] = (gchar *) xaccAccountGetTypeStr
01152         ((GNCAccountType) (types->data));
01153       row = gtk_clist_append (type_list, text);
01154       gtk_clist_set_row_data(type_list, row, (gpointer)types->data);
01155     }
01156   }
01157   gtk_clist_thaw(type_list);
01158 }
01159 
01160 static GNCAccountType
01161 gnc_account_choose_new_acct_type (AccountWindow *aw)
01162 {
01163   
01164   if (aw->valid_types == NULL)
01165     return last_used_account_type;
01166 
01167   if (g_list_index (aw->valid_types, GINT_TO_POINTER(last_used_account_type)) != -1)
01168     return last_used_account_type;
01169 
01170   return ((GNCAccountType)(aw->valid_types->data));
01171 }
01172 
01173 static void
01174 gnc_account_type_list_create(AccountWindow *aw)
01175 {
01176   int row;
01177 
01178   gnc_account_list_fill(GTK_CLIST(aw->type_list), aw->valid_types);
01179 
01180   gtk_clist_columns_autosize(GTK_CLIST(aw->type_list));
01181 
01182   gtk_clist_sort(GTK_CLIST(aw->type_list));
01183 
01184   g_signal_connect(GTK_OBJECT(aw->type_list), "select-row",
01185                    G_CALLBACK(gnc_type_list_select_cb), aw);
01186 
01187   g_signal_connect(GTK_OBJECT(aw->type_list), "unselect-row",
01188                    G_CALLBACK(gnc_type_list_unselect_cb), aw);
01189 
01190   switch (aw->dialog_type)
01191   {
01192     case NEW_ACCOUNT:
01193       aw->type = gnc_account_choose_new_acct_type (aw);
01194       break;
01195     case EDIT_ACCOUNT:
01196       aw->type = xaccAccountGetType (aw_get_account (aw));
01197       break;
01198   }
01199 
01200   row = gtk_clist_find_row_from_data(GTK_CLIST(aw->type_list),
01201                                      (gpointer)aw->type);
01202   gtk_clist_select_row(GTK_CLIST(aw->type_list), row, 0);
01203   gtk_clist_moveto(GTK_CLIST(aw->type_list), row, 0, 0.5, 0);
01204 }
01205 
01206 static void
01207 gnc_account_name_changed_cb(GtkWidget *widget, gpointer data)
01208 {
01209   AccountWindow *aw = data;
01210 
01211   gnc_account_window_set_name (aw);
01212 }
01213 
01214 static void
01215 commodity_changed_cb (GNCGeneralSelect *gsl, gpointer data)
01216 {
01217   AccountWindow *aw = data;
01218   gnc_commodity *currency;
01219   GtkTreeSelection *selection;
01220 
01221   currency = (gnc_commodity *) gnc_general_select_get_selected (gsl);
01222   if (!currency)
01223     return;
01224 
01225   gnc_amount_edit_set_fraction (GNC_AMOUNT_EDIT (aw->opening_balance_edit),
01226                                 gnc_commodity_get_fraction (currency));
01227   gnc_amount_edit_set_print_info (GNC_AMOUNT_EDIT (aw->opening_balance_edit),
01228                                   gnc_commodity_print_info (currency, FALSE));
01229 
01230   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (aw->transfer_tree));
01231   gtk_tree_selection_unselect_all (selection);
01232 }
01233 
01234 static gboolean
01235 account_commodity_filter (GtkTreeSelection *selection,
01236                           GtkTreeModel *unused_model,
01237                           GtkTreePath *s_path,
01238                           gboolean path_currently_selected,
01239                           gpointer user_data)
01240 {
01241   gnc_commodity *commodity;
01242   AccountWindow *aw;
01243   Account *account;
01244 
01245   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
01246 
01247   aw = user_data;
01248 
01249   if (path_currently_selected) {
01250     /* already selected, don't waste time. */
01251     return TRUE;
01252   }
01253 
01254   account = gnc_tree_view_account_get_account_from_path (GNC_TREE_VIEW_ACCOUNT (aw->transfer_tree), s_path);
01255   if (!account) {
01256     return FALSE;
01257   }
01258 
01259   commodity = (gnc_commodity *)
01260     gnc_general_select_get_selected (GNC_GENERAL_SELECT (aw->commodity_edit));
01261 
01262   return gnc_commodity_equiv (xaccAccountGetCommodity (account), commodity);
01263 }
01264 
01265 static void
01266 opening_equity_cb (GtkWidget *w, gpointer data)
01267 {
01268   AccountWindow *aw = data;
01269   gboolean use_equity;
01270 
01271   use_equity = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
01272 
01273   gtk_widget_set_sensitive (aw->transfer_account_frame, !use_equity);
01274 }
01275 
01276 /********************************************************************\
01277  * gnc_account_window_create                                        *
01278  *   creates a window to create a new account.                      *
01279  *                                                                  * 
01280  * Args:   aw - the information structure for this window           *
01281  * Return: the created window                                       *
01282  \*******************************************************************/
01283 static void
01284 gnc_account_window_create(AccountWindow *aw)
01285 {
01286   GtkDialog *awd;
01287   GtkWidget *amount;
01288   GObject *awo;
01289   GtkWidget *box;
01290   GladeXML  *xml;
01291   GtkTreeSelection *selection;
01292 
01293   ENTER("aw %p, modal %d", aw, aw->modal);
01294   xml = gnc_glade_xml_new ("account.glade", "Account Dialog");
01295 
01296   aw->dialog = glade_xml_get_widget (xml, "Account Dialog");
01297   awo = G_OBJECT (aw->dialog);
01298   awd = GTK_DIALOG (awo);
01299 
01300   g_object_set_data (awo, "dialog_info", aw);
01301 
01302   /* default to ok */
01303   gtk_dialog_set_default_response (awd, GTK_RESPONSE_OK);
01304 
01305   g_signal_connect (awo, "destroy",
01306                     G_CALLBACK (gnc_account_window_destroy_cb), aw);
01307 
01308   if (!aw->modal)
01309     g_signal_connect (awo, "response",
01310                       G_CALLBACK (gnc_account_window_response_cb), aw);
01311   else 
01312     gtk_window_set_modal (GTK_WINDOW (aw->dialog), TRUE);
01313 
01314   aw->notebook = glade_xml_get_widget (xml, "account_notebook");
01315 
01316   aw->name_entry = glade_xml_get_widget (xml, "name_entry");
01317   g_signal_connect (G_OBJECT (aw->name_entry), "changed",
01318                     G_CALLBACK (gnc_account_name_changed_cb), aw);
01319 
01320   aw->description_entry = glade_xml_get_widget (xml, "description_entry");
01321   aw->code_entry =        glade_xml_get_widget (xml, "code_entry");
01322   aw->notes_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (glade_xml_get_widget (xml, "notes_text")));
01323 
01324   box = glade_xml_get_widget (xml, "commodity_hbox");
01325   aw->commodity_edit = gnc_general_select_new (GNC_GENERAL_SELECT_TYPE_SELECT,
01326                                                gnc_commodity_edit_get_string,
01327                                                gnc_commodity_edit_new_select,
01328                                                &aw->commodity_mode);
01329   gtk_box_pack_start(GTK_BOX(box), aw->commodity_edit, TRUE, TRUE, 0);
01330   gtk_widget_show (aw->commodity_edit);
01331 
01332   g_signal_connect (G_OBJECT (aw->commodity_edit), "changed",
01333                     G_CALLBACK (commodity_changed_cb), aw);
01334 
01335   aw->account_scu = glade_xml_get_widget (xml, "account_scu");
01336   gnc_option_menu_init(aw->account_scu);
01337 
01338   box = glade_xml_get_widget (xml, "parent_scroll");
01339 
01340   //  group = gnc_book_get_group (gnc_get_current_book ());
01341   aw->parent_tree = gnc_tree_view_account_new(TRUE);
01342   gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(aw->parent_tree));
01343   gnc_tree_view_configure_columns (GNC_TREE_VIEW(aw->parent_tree), NULL);
01344   gtk_widget_show(GTK_WIDGET(aw->parent_tree));
01345   aw->top_level_account =
01346     gnc_tree_view_account_get_top_level (GNC_TREE_VIEW_ACCOUNT(aw->parent_tree));
01347 
01348   aw->tax_related_button = glade_xml_get_widget (xml, "tax_related_button");
01349   aw->placeholder_button = glade_xml_get_widget (xml, "placeholder_button");
01350 
01351   box = glade_xml_get_widget (xml, "opening_balance_box");
01352   amount = gnc_amount_edit_new ();
01353   aw->opening_balance_edit = amount;
01354   gtk_box_pack_start(GTK_BOX(box), amount, TRUE, TRUE, 0);
01355   gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (amount), TRUE);
01356   gtk_widget_show (amount);
01357 
01358   box = glade_xml_get_widget (xml, "opening_balance_date_box");
01359   aw->opening_balance_date_edit = glade_xml_get_widget (xml, "opening_balance_date_edit");
01360 
01361   aw->opening_balance_page =
01362     gtk_notebook_get_nth_page (GTK_NOTEBOOK (aw->notebook), 1);
01363 
01364   aw->opening_equity_radio = glade_xml_get_widget (xml,
01365                                                    "opening_equity_radio");
01366   g_signal_connect (G_OBJECT (aw->opening_equity_radio), "toggled",
01367                     G_CALLBACK (opening_equity_cb), aw);
01368 
01369   aw->transfer_account_frame =
01370     glade_xml_get_widget (xml, "transfer_account_frame");
01371 
01372   box = glade_xml_get_widget (xml, "transfer_account_scroll");
01373 
01374   aw->transfer_tree = GTK_WIDGET(gnc_tree_view_account_new(FALSE));
01375   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(aw->transfer_tree));
01376   gtk_tree_selection_set_select_function(selection, account_commodity_filter, aw, NULL);
01377 
01378   gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(aw->transfer_tree));
01379   gtk_widget_show (GTK_WIDGET(aw->transfer_tree));
01380 
01381   /* This goes at the end so the select callback has good data. */
01382   aw->type_list = glade_xml_get_widget (xml, "type_list");
01383   gnc_account_type_list_create (aw);
01384 
01385   gnc_restore_window_size (GCONF_SECTION, GTK_WINDOW(aw->dialog));
01386 
01387   gtk_widget_grab_focus(GTK_WIDGET(aw->name_entry));
01388   LEAVE(" ");
01389 }
01390 
01391 
01392 static char *
01393 get_ui_fullname (AccountWindow *aw)
01394 {
01395   Account *parent_account;
01396   char *fullname;
01397   const gchar *name;
01398 
01399   name = gtk_entry_get_text (GTK_ENTRY(aw->name_entry));
01400   if (!name || *name == '\0')
01401     name = _("<No name>");
01402 
01403   parent_account = NULL;
01404 
01405   parent_account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT (aw->parent_tree));
01406   if (parent_account == aw->top_level_account)
01407     parent_account = NULL;
01408 
01409   if (parent_account)
01410   {
01411     char *parent_name;
01412     char sep_string[2];
01413 
01414     parent_name = xaccAccountGetFullName (parent_account,
01415                                           gnc_get_account_separator());
01416 
01417     sep_string[0] = gnc_get_account_separator ();
01418     sep_string[1] = '\0';
01419 
01420     fullname = g_strconcat (parent_name, sep_string, name, NULL);
01421 
01422     g_free (parent_name);
01423   }
01424   else 
01425     fullname = g_strdup (name);
01426 
01427   return fullname;
01428 }
01429 
01430 static void
01431 gnc_account_window_set_name (AccountWindow *aw)
01432 {
01433   char *fullname;
01434   char *title;
01435 
01436   if (!aw || !aw->parent_tree)
01437     return;
01438 
01439   fullname = get_ui_fullname (aw);
01440 
01441   if (aw->dialog_type == EDIT_ACCOUNT)
01442     title = g_strconcat(_("Edit Account"), " - ", fullname, NULL);
01443   else if (g_list_length (aw->subaccount_names) > 0)
01444   {
01445     const char *format = _("(%d) New Accounts");
01446     char *prefix;
01447 
01448     prefix = g_strdup_printf (format,
01449                               g_list_length (aw->subaccount_names) + 1);
01450 
01451     title = g_strconcat (prefix, " - ", fullname, " ...", NULL);
01452 
01453     g_free (prefix);
01454   }
01455   else
01456     title = g_strconcat (_("New Account"), " - ", fullname, NULL);
01457 
01458   gtk_window_set_title (GTK_WINDOW(aw->dialog), title);
01459 
01460   g_free (fullname);
01461   g_free (title);
01462 }
01463 
01464 
01465 static void
01466 close_handler (gpointer user_data)
01467 {
01468   AccountWindow *aw = user_data;
01469 
01470   ENTER("aw %p, modal %d", aw, aw->modal);
01471   gnc_save_window_size (GCONF_SECTION, GTK_WINDOW(aw->dialog));
01472 
01473   gtk_widget_destroy (GTK_WIDGET (aw->dialog));
01474   LEAVE(" ");
01475 }
01476 
01477 
01478 /********************************************************************\
01479  * gnc_ui_refresh_account_window                                    *
01480  *   refreshes the edit window                                      *
01481  *                                                                  *
01482  * Args:   aw - the account window to refresh                       *
01483  * Return: none                                                     *
01484 \********************************************************************/
01485 static void
01486 gnc_ui_refresh_account_window (AccountWindow *aw)
01487 {
01488   if (aw == NULL)
01489     return;
01490 
01491 /*  gnc_account_tree_refresh (GNC_ACCOUNT_TREE(aw->parent_tree));*/
01492 
01493   gnc_account_window_set_name (aw);
01494 }
01495 
01496 
01497 static void
01498 refresh_handler (GHashTable *changes, gpointer user_data)
01499 {
01500   AccountWindow *aw = user_data;
01501   const EventInfo *info;
01502   Account *account;
01503 
01504   account = aw_get_account (aw);
01505   if (!account)
01506   {
01507     gnc_close_gui_component (aw->component_id);
01508     return;
01509   }
01510 
01511   if (changes)
01512   {
01513     info = gnc_gui_get_entity_events (changes, &aw->account);
01514     if (info && (info->event_mask & GNC_EVENT_DESTROY))
01515     {
01516       gnc_close_gui_component (aw->component_id);
01517       return;
01518     }
01519   }
01520 
01521   gnc_ui_refresh_account_window (aw);
01522 }
01523 
01524 
01525 static AccountWindow *
01526 gnc_ui_new_account_window_internal (Account *base_account,
01527                                     GList *subaccount_names,
01528                                     GList *valid_types,
01529                                     gnc_commodity * default_commodity,
01530                                     gboolean modal)
01531 {
01532   gnc_commodity *commodity;
01533   AccountWindow *aw;
01534   Account *account;
01535 
01536   aw = g_new0 (AccountWindow, 1);
01537 
01538   aw->modal = modal;
01539   aw->dialog_type = NEW_ACCOUNT;
01540   aw->valid_types = g_list_copy (valid_types);
01541 
01542   account = xaccMallocAccount (gnc_get_current_book ());
01543   aw->account = *xaccAccountGetGUID (account);
01544 
01545   if (base_account)
01546     aw->type = xaccAccountGetType (base_account);
01547   else
01548     aw->type = last_used_account_type;
01549 
01550   gnc_suspend_gui_refresh ();
01551 
01552   if (subaccount_names)
01553   {
01554     GList *node;
01555 
01556     xaccAccountSetName (account, subaccount_names->data);
01557 
01558     aw->subaccount_names = g_list_copy (subaccount_names->next);
01559     for (node = aw->subaccount_names; node; node = node->next)
01560       node->data = g_strdup (node->data);
01561   }
01562 
01563   gnc_account_window_create (aw);
01564   gnc_account_to_ui (aw);
01565 
01566   gnc_resume_gui_refresh ();
01567 
01568   if (default_commodity != NULL) {
01569     commodity = default_commodity;
01570   } else if ((aw->type != STOCK) && (aw->type != MUTUAL)) {
01571     commodity = gnc_default_currency ();
01572   } else {
01573     commodity = NULL;
01574   }
01575   gnc_general_select_set_selected (GNC_GENERAL_SELECT (aw->commodity_edit),
01576                                     commodity);
01577   gnc_account_commodity_from_type (aw, FALSE);
01578 
01579   gtk_widget_show (aw->dialog);
01580 
01581   if (base_account == NULL) {
01582           base_account = aw->top_level_account;
01583   }
01584 
01585   gtk_tree_view_collapse_all (aw->parent_tree);
01586   gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT (aw->parent_tree),
01587                                               base_account);
01588 
01589   gnc_window_adjust_for_screen (GTK_WINDOW(aw->dialog));
01590 
01591   gnc_account_window_set_name (aw);
01592 
01593   aw->component_id = gnc_register_gui_component (DIALOG_NEW_ACCOUNT_CM_CLASS,
01594                                                  refresh_handler,
01595                                                  modal ? NULL : close_handler,
01596                                                  aw);
01597 
01598   gnc_gui_component_set_session (aw->component_id, gnc_get_current_session());
01599   gnc_gui_component_watch_entity_type (aw->component_id,
01600                                        GNC_ID_ACCOUNT,
01601                                        GNC_EVENT_MODIFY | GNC_EVENT_DESTROY);
01602   return aw;
01603 }
01604 
01605 
01606 static GList *
01607 gnc_split_account_name (const char *in_name, Account **base_account)
01608 {
01609   AccountGroup *group;
01610   GList *names;
01611   char separator;
01612   char *name;
01613 
01614   names = NULL;
01615   name = g_strdup (in_name);
01616   *base_account = NULL;
01617   group = gnc_get_current_group ();
01618 
01619   separator = gnc_get_account_separator ();
01620 
01621   while (name && *name != '\0')
01622   {
01623     Account *account;
01624     char *p;
01625 
01626     account = xaccGetAccountFromFullName (group, name, separator);
01627     if (account)
01628     {
01629       *base_account = account;
01630       break;
01631     }
01632 
01633     p = strrchr (name, separator);
01634     if (p)
01635     {
01636       *p++ = '\0';
01637 
01638       if (*p == '\0')
01639       {
01640         GList *node;
01641         for (node = names; node; node = node->next)
01642           g_free (node->data);
01643         g_list_free (names);
01644         return NULL;
01645       }
01646 
01647       names = g_list_prepend (names, g_strdup (p));
01648     }
01649     else
01650     {
01651       names = g_list_prepend (names, g_strdup (name));
01652       break;
01653     }
01654   }
01655 
01656   g_free (name);
01657 
01658   return names;
01659 }
01660 
01661 
01662 /************************************************************
01663  *              Entry points for a Modal Dialog             *
01664  ************************************************************/
01665 
01666 Account *
01667 gnc_ui_new_accounts_from_name_window (const char *name)
01668 {
01669   return  gnc_ui_new_accounts_from_name_with_defaults (name, NULL, NULL, NULL);
01670 }
01671 
01672 Account *
01673 gnc_ui_new_accounts_from_name_window_with_types (const char *name,
01674                                                  GList *valid_types)
01675 {
01676   return gnc_ui_new_accounts_from_name_with_defaults(name, valid_types, NULL, NULL);
01677 }
01678 
01679 Account * gnc_ui_new_accounts_from_name_with_defaults (const char *name,
01680                                                        GList *valid_types,
01681                                                        gnc_commodity * default_commodity,
01682                                                        Account * parent)
01683 {
01684   AccountWindow *aw;
01685   Account *base_account;
01686   Account *created_account = NULL;
01687   GList * subaccount_names;
01688   GList * node;
01689   gint response;
01690 
01691   ENTER("name %s, valid %p, commodity %p, account %p",
01692         name, valid_types, default_commodity, parent);
01693   if (!name || *name == '\0')
01694   {
01695     subaccount_names = NULL;
01696     base_account = NULL;
01697   }
01698   else
01699     subaccount_names = gnc_split_account_name (name, &base_account);
01700 
01701   if (parent != NULL)
01702     {
01703       base_account=parent;
01704     }
01705   aw = gnc_ui_new_account_window_internal (base_account, subaccount_names, 
01706                                            valid_types, default_commodity,
01707                                            TRUE);
01708 
01709   for (node = subaccount_names; node; node = node->next)
01710     g_free (node->data);
01711   g_list_free (subaccount_names);
01712 
01713   do {
01714     response = gtk_dialog_run (GTK_DIALOG(aw->dialog));
01715 
01716     /* This can destroy the dialog */
01717     gnc_account_window_response_cb (GTK_DIALOG(aw->dialog), response, (gpointer)aw);
01718 
01719     if (response == GTK_RESPONSE_OK)
01720       created_account = aw->created_account;
01721   } while ((response == GTK_RESPONSE_HELP) || (response == GNC_RESPONSE_NEW));
01722 
01723   close_handler(aw);
01724   LEAVE("created %s (%p)", xaccAccountGetName(created_account), created_account);
01725   return created_account;
01726 }
01727 
01728 /************************************************************
01729  *            Entry points for a non-Modal Dialog           *
01730  ************************************************************/
01731 
01732 static gboolean
01733 find_by_account (gpointer find_data, gpointer user_data)
01734 {
01735   Account *account = find_data;
01736   AccountWindow *aw = user_data;
01737 
01738   if (!aw)
01739     return FALSE;
01740 
01741   return guid_equal (&aw->account, xaccAccountGetGUID (account));
01742 }
01743 
01744 /*
01745  * opens up a window to edit an account
01746  * 
01747  * Args:   account - the account to edit
01748  * Return: EditAccountWindow object
01749  */
01750 void
01751 gnc_ui_edit_account_window(Account *account)
01752 {
01753   AccountWindow * aw;
01754   Account *parent;
01755 
01756   if (account == NULL)
01757     return;
01758 
01759   aw = gnc_find_first_gui_component (DIALOG_EDIT_ACCOUNT_CM_CLASS,
01760                                      find_by_account, account);
01761   if (aw) {
01762     gtk_window_present(GTK_WINDOW(aw->dialog));
01763     return;
01764   }
01765 
01766   aw = g_new0 (AccountWindow, 1);
01767 
01768   aw->modal = FALSE;
01769   aw->dialog_type = EDIT_ACCOUNT;
01770   aw->account = *xaccAccountGetGUID (account);
01771   aw->subaccount_names = NULL;
01772 
01773   gnc_suspend_gui_refresh ();
01774 
01775   gnc_account_window_create (aw);
01776   gnc_account_to_ui (aw);
01777 
01778   gnc_resume_gui_refresh ();
01779 
01780   gtk_widget_show_all (aw->dialog);
01781   gtk_widget_hide (aw->opening_balance_page);
01782 
01783   parent = xaccAccountGetParentAccount (account);
01784   if (parent == NULL)
01785     parent = aw->top_level_account;
01786 
01787   gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT(aw->parent_tree), parent);
01788 
01789   gnc_account_window_set_name (aw);
01790 
01791   gnc_window_adjust_for_screen(GTK_WINDOW(aw->dialog));
01792 
01793   aw->component_id = gnc_register_gui_component (DIALOG_EDIT_ACCOUNT_CM_CLASS,
01794                                                  refresh_handler,
01795                                                  close_handler, aw);
01796 
01797   gnc_gui_component_set_session (aw->component_id, gnc_get_current_session());
01798   gnc_gui_component_watch_entity_type (aw->component_id,
01799                                        GNC_ID_ACCOUNT,
01800                                        GNC_EVENT_MODIFY | GNC_EVENT_DESTROY);
01801 
01802   gtk_window_present(GTK_WINDOW(aw->dialog));
01803 }
01804 
01805 
01806 /*
01807  * opens up a window to create a new account
01808  * 
01809  * Args:   group - not used
01810  */
01811 void
01812 gnc_ui_new_account_window (AccountGroup *this_is_not_used) 
01813 {
01814   /* FIXME get_current_account went away. */
01815   gnc_ui_new_account_window_internal (NULL, NULL, NULL, NULL, FALSE);
01816 }
01817 
01818 /*
01819  * opens up a window to create a new account
01820  * 
01821  * Args:   group - not used
01822  *        parent - The initial parent for the new account
01823  */
01824 void
01825 gnc_ui_new_account_window_with_default(AccountGroup *this_is_not_used,
01826                                        Account * parent)
01827 {
01828   gnc_ui_new_account_window_internal (parent, NULL, NULL, NULL, FALSE);
01829 }
01830 
01831 void
01832 gnc_ui_new_account_with_types( AccountGroup *unused,
01833                                GList *valid_types )
01834 {
01835   GList *validTypesCopy = g_list_copy( valid_types );
01836   AccountWindow *aw;
01837 
01838   aw = gnc_ui_new_account_window_internal( NULL, NULL, validTypesCopy, NULL, FALSE );
01839   if ( validTypesCopy != NULL ) {
01840     /* Attach it with "[...]_full" so we can set the appropriate
01841      * GtkDestroyNotify func. */
01842     gtk_object_set_data_full( GTK_OBJECT(aw->dialog), "validTypesListCopy",
01843                               validTypesCopy, (GDestroyNotify)g_list_free );
01844   }
01845 }
01846 
01847 /************************************************************
01848  *             Callbacks for a non-Modal Dialog             *
01849  ************************************************************/
01850 
01851 /*
01852  * register a callback that get's called when the account has changed
01853  * so significantly that you need to destroy yourself.  In particular
01854  * this is used by the ledger display to destroy ledgers when the
01855  * account type has changed.
01856  */
01857 void
01858 gnc_ui_register_account_destroy_callback (void (*cb)(Account *))
01859 {
01860   if (!cb)
01861     return;
01862 
01863   if (g_list_index (ac_destroy_cb_list, cb) == -1)
01864     ac_destroy_cb_list = g_list_append (ac_destroy_cb_list, cb);
01865 
01866   return;
01867 }

Generated on Sun Sep 4 18:07:34 2005 for GnuCash by  doxygen 1.4.3-20050530