|
GnuCash 2.4.99
|
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,2006 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 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * 00022 * Boston, MA 02110-1301, USA gnu@gnu.org * 00023 \********************************************************************/ 00024 00025 #include "config.h" 00026 00027 #include <gtk/gtk.h> 00028 #include <glib/gi18n.h> 00029 #include <math.h> 00030 #ifdef G_OS_WIN32 00031 #include <pow.h> 00032 #endif 00033 #include <string.h> 00034 00035 #include "Transaction.h" 00036 #include "dialog-account.h" 00037 #include "dialog-commodity.h" 00038 #include "dialog-utils.h" 00039 #include "gnc-amount-edit.h" 00040 #include "gnc-general-select.h" 00041 #include "gnc-commodity.h" 00042 #include "gnc-commodity-edit.h" 00043 #include "gnc-component-manager.h" 00044 #include "gnc-date-edit.h" 00045 #include "gnc-engine.h" 00046 #include "gnc-gui-query.h" 00047 #include "gnc-session.h" 00048 #include "gnc-tree-model-account-types.h" 00049 #include "gnc-tree-view-account.h" 00050 #include "gnc-ui.h" 00051 #include "gnc-ui-util.h" 00052 00053 00054 #define DIALOG_NEW_ACCOUNT_CM_CLASS "dialog-new-account" 00055 #define DIALOG_EDIT_ACCOUNT_CM_CLASS "dialog-edit-account" 00056 #define GCONF_SECTION "dialogs/account" 00057 #define DEFAULT_COLOR "#ededececebeb" 00058 00059 enum account_cols 00060 { 00061 ACCOUNT_COL_FULLNAME = 0, 00062 ACCOUNT_COL_FIELDNAME, 00063 ACCOUNT_COL_OLD_VALUE, 00064 ACCOUNT_COL_NEW_VALUE, 00065 NUM_ACCOUNT_COLS 00066 }; 00067 00068 typedef enum 00069 { 00070 NEW_ACCOUNT, 00071 EDIT_ACCOUNT 00072 } AccountDialogType; 00073 00074 typedef struct _AccountWindow 00075 { 00076 QofBook *book; 00077 gboolean modal; 00078 GtkWidget *dialog; 00079 00080 AccountDialogType dialog_type; 00081 00082 GncGUID account; 00083 Account *created_account; 00084 00085 gchar **subaccount_names; 00086 gchar **next_name; 00087 00088 GNCAccountType type; 00089 00090 GtkWidget * notebook; 00091 00092 GtkWidget * name_entry; 00093 GtkWidget * description_entry; 00094 GtkWidget * color_entry_button; 00095 GtkWidget * color_default_button; 00096 GtkWidget * code_entry; 00097 GtkTextBuffer * notes_text_buffer; 00098 00099 GtkWidget * commodity_edit; 00100 dialog_commodity_mode commodity_mode; 00101 GtkWidget * account_scu; 00102 00103 guint32 valid_types; 00104 GNCAccountType preferred_account_type; 00105 GtkWidget * type_view; 00106 GtkTreeView * parent_tree; 00107 00108 GtkWidget * opening_balance_edit; 00109 GtkWidget * opening_balance_date_edit; 00110 GtkWidget * opening_balance_page; 00111 00112 GtkWidget * opening_equity_radio; 00113 GtkWidget * transfer_account_scroll; 00114 GtkWidget * transfer_tree; 00115 00116 GtkWidget * tax_related_button; 00117 GtkWidget * placeholder_button; 00118 GtkWidget * hidden_button; 00119 00120 gint component_id; 00121 } AccountWindow; 00122 00123 typedef struct _RenumberDialog 00124 { 00125 GtkWidget *dialog; 00126 GtkWidget *prefix; 00127 GtkWidget *interval; 00128 GtkWidget *example1; 00129 GtkWidget *example2; 00130 00131 Account *parent; 00132 gint num_children; 00133 } RenumberDialog; 00134 00136 static QofLogModule log_module = GNC_MOD_GUI; 00137 00138 static GNCAccountType last_used_account_type = ACCT_TYPE_BANK; 00139 00140 static GList *ac_destroy_cb_list = NULL; 00141 00143 static void gnc_account_window_set_name (AccountWindow *aw); 00144 00145 void gnc_account_renumber_prefix_changed_cb (GtkEditable *editable, RenumberDialog *data); 00146 void gnc_account_renumber_interval_changed_cb (GtkSpinButton *spinbutton, RenumberDialog *data); 00147 void gnc_account_renumber_response_cb (GtkDialog *dialog, gint response, RenumberDialog *data); 00148 00149 void gnc_account_window_destroy_cb (GtkObject *object, gpointer data); 00150 void opening_equity_cb (GtkWidget *w, gpointer data); 00151 void gnc_account_name_changed_cb(GtkWidget *widget, gpointer data); 00152 void gnc_account_color_default_cb(GtkWidget *widget, gpointer data); 00153 void gnc_account_name_insert_text_cb (GtkWidget *entry, 00154 const gchar *text, 00155 gint length, 00156 gint *position, 00157 gpointer data); 00158 00161 static void 00162 aw_call_destroy_callbacks (Account* acc) 00163 { 00164 GList *node; 00165 void (*cb)(Account*); 00166 00167 for (node = ac_destroy_cb_list; node; node = node->next) 00168 { 00169 cb = node->data; 00170 (cb)(acc); 00171 } 00172 } 00173 00174 static Account * 00175 aw_get_account (AccountWindow *aw) 00176 { 00177 if (!aw) 00178 return NULL; 00179 00180 return xaccAccountLookup (&aw->account, aw->book); 00181 } 00182 00183 static void 00184 gnc_account_commodity_from_type (AccountWindow * aw, gboolean update) 00185 { 00186 dialog_commodity_mode new_mode; 00187 00188 if (aw->type == ACCT_TYPE_TRADING) 00189 new_mode = DIAG_COMM_ALL; 00190 else if ((aw->type == ACCT_TYPE_STOCK) || (aw->type == ACCT_TYPE_MUTUAL)) 00191 new_mode = DIAG_COMM_NON_CURRENCY; 00192 else 00193 new_mode = DIAG_COMM_CURRENCY; 00194 00195 if (update && (new_mode != aw->commodity_mode)) 00196 { 00197 gnc_general_select_set_selected(GNC_GENERAL_SELECT (aw->commodity_edit), 00198 NULL); 00199 } 00200 00201 aw->commodity_mode = new_mode; 00202 } 00203 00204 /* Copy the account values to the GUI widgets */ 00205 static void 00206 gnc_account_to_ui(AccountWindow *aw) 00207 { 00208 Account *account; 00209 gnc_commodity * commodity; 00210 const char *string; 00211 GdkColor color; 00212 gboolean flag, nonstd_scu; 00213 gint index; 00214 00215 ENTER("%p", aw); 00216 account = aw_get_account (aw); 00217 if (!account) 00218 { 00219 LEAVE("no account"); 00220 return; 00221 } 00222 00223 string = xaccAccountGetName (account); 00224 if (string == NULL) string = ""; 00225 gtk_entry_set_text(GTK_ENTRY(aw->name_entry), string); 00226 00227 string = xaccAccountGetDescription (account); 00228 if (string == NULL) string = ""; 00229 gtk_entry_set_text(GTK_ENTRY(aw->description_entry), string); 00230 00231 string = xaccAccountGetColor (account); 00232 if (string == NULL) string = ""; 00233 if (gdk_color_parse(string, &color)) 00234 { 00235 gtk_color_button_set_color(GTK_COLOR_BUTTON(aw->color_entry_button), &color); 00236 } 00237 00238 commodity = xaccAccountGetCommodity (account); 00239 gnc_general_select_set_selected (GNC_GENERAL_SELECT (aw->commodity_edit), 00240 commodity); 00241 gnc_account_commodity_from_type (aw, FALSE); 00242 00243 nonstd_scu = xaccAccountGetNonStdSCU (account); 00244 if (nonstd_scu) 00245 { 00246 index = xaccAccountGetCommoditySCUi(account); 00247 index = log10(index) + 1; 00248 } 00249 else 00250 { 00251 index = 0; 00252 } 00253 gtk_combo_box_set_active(GTK_COMBO_BOX(aw->account_scu), index); 00254 00255 string = xaccAccountGetCode (account); 00256 if (string == NULL) string = ""; 00257 gtk_entry_set_text(GTK_ENTRY(aw->code_entry), string); 00258 00259 string = xaccAccountGetNotes (account); 00260 if (string == NULL) string = ""; 00261 00262 gtk_text_buffer_set_text (aw->notes_text_buffer, string, strlen(string)); 00263 00264 flag = xaccAccountGetTaxRelated (account); 00265 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aw->tax_related_button), 00266 flag); 00267 00268 flag = xaccAccountGetPlaceholder (account); 00269 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aw->placeholder_button), 00270 flag); 00271 00272 flag = xaccAccountGetHidden (account); 00273 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aw->hidden_button), 00274 flag); 00275 LEAVE(" "); 00276 } 00277 00278 00279 static gboolean 00280 gnc_account_create_transfer_balance (QofBook *book, 00281 Account *account, 00282 Account *transfer, 00283 gnc_numeric balance, 00284 time_t date) 00285 { 00286 Transaction *trans; 00287 Split *split; 00288 00289 if (gnc_numeric_zero_p (balance)) 00290 return TRUE; 00291 00292 g_return_val_if_fail (account != NULL, FALSE); 00293 g_return_val_if_fail (transfer != NULL, FALSE); 00294 00295 xaccAccountBeginEdit (account); 00296 xaccAccountBeginEdit (transfer); 00297 00298 trans = xaccMallocTransaction (book); 00299 00300 xaccTransBeginEdit (trans); 00301 00302 xaccTransSetCurrency (trans, xaccAccountGetCommodity (account)); 00303 xaccTransSetDatePostedSecs (trans, date); 00304 xaccTransSetDescription (trans, _("Opening Balance")); 00305 00306 split = xaccMallocSplit (book); 00307 00308 xaccTransAppendSplit (trans, split); 00309 xaccAccountInsertSplit (account, split); 00310 00311 xaccSplitSetAmount (split, balance); 00312 xaccSplitSetValue (split, balance); 00313 00314 balance = gnc_numeric_neg (balance); 00315 00316 split = xaccMallocSplit (book); 00317 00318 xaccTransAppendSplit (trans, split); 00319 xaccAccountInsertSplit (transfer, split); 00320 00321 xaccSplitSetAmount (split, balance); 00322 xaccSplitSetValue (split, balance); 00323 00324 xaccTransCommitEdit (trans); 00325 xaccAccountCommitEdit (transfer); 00326 xaccAccountCommitEdit (account); 00327 00328 return TRUE; 00329 } 00330 00331 /* Record the GUI values into the Account structure */ 00332 static void 00333 gnc_ui_to_account(AccountWindow *aw) 00334 { 00335 Account *account; 00336 gnc_commodity *commodity; 00337 Account *parent_account; 00338 const char *old_string; 00339 const char *string; 00340 GdkColor color; 00341 gboolean flag; 00342 gnc_numeric balance; 00343 gboolean use_equity, nonstd; 00344 time_t date; 00345 gint index, old_scu, new_scu; 00346 GtkTextIter start, end; 00347 00348 account = aw_get_account (aw); 00349 if (!account) 00350 { 00351 LEAVE("no account"); 00352 return; 00353 } 00354 00355 if (aw->dialog_type == EDIT_ACCOUNT 00356 && aw->type != xaccAccountGetType (account)) 00357 { 00358 /* Just refreshing won't work. */ 00359 aw_call_destroy_callbacks (account); 00360 } 00361 00362 xaccAccountBeginEdit (account); 00363 00364 if (aw->type != xaccAccountGetType (account)) 00365 xaccAccountSetType (account, aw->type); 00366 00367 last_used_account_type = aw->type; 00368 00369 string = gtk_entry_get_text (GTK_ENTRY(aw->name_entry)); 00370 old_string = xaccAccountGetName (account); 00371 if (safe_strcmp (string, old_string) != 0) 00372 xaccAccountSetName (account, string); 00373 00374 string = gtk_entry_get_text (GTK_ENTRY(aw->description_entry)); 00375 old_string = xaccAccountGetDescription (account); 00376 if (safe_strcmp (string, old_string) != 0) 00377 xaccAccountSetDescription (account, string); 00378 00379 gtk_color_button_get_color(GTK_COLOR_BUTTON(aw->color_entry_button), &color ); 00380 string = gdk_color_to_string(&color); 00381 if (safe_strcmp (string, DEFAULT_COLOR) == 0) 00382 string = "Not Set"; 00383 00384 old_string = xaccAccountGetColor (account); 00385 if (safe_strcmp (string, old_string) != 0) 00386 xaccAccountSetColor (account, string); 00387 00388 commodity = (gnc_commodity *) 00389 gnc_general_select_get_selected (GNC_GENERAL_SELECT (aw->commodity_edit)); 00390 if (commodity && 00391 !gnc_commodity_equiv(commodity, xaccAccountGetCommodity (account))) 00392 { 00393 xaccAccountSetCommodity (account, commodity); 00394 old_scu = 0; 00395 } 00396 else 00397 { 00398 old_scu = xaccAccountGetCommoditySCU(account); 00399 } 00400 00401 index = gtk_combo_box_get_active(GTK_COMBO_BOX(aw->account_scu)); 00402 nonstd = (index != 0); 00403 if (nonstd != xaccAccountGetNonStdSCU(account)) 00404 xaccAccountSetNonStdSCU(account, nonstd); 00405 new_scu = (nonstd ? pow(10, index - 1) : gnc_commodity_get_fraction(commodity)); 00406 if (old_scu != new_scu) 00407 xaccAccountSetCommoditySCU(account, new_scu); 00408 00409 string = gtk_entry_get_text (GTK_ENTRY(aw->code_entry)); 00410 old_string = xaccAccountGetCode (account); 00411 if (safe_strcmp (string, old_string) != 0) 00412 xaccAccountSetCode (account, string); 00413 00414 gtk_text_buffer_get_start_iter (aw->notes_text_buffer, &start); 00415 gtk_text_buffer_get_end_iter (aw->notes_text_buffer, &end); 00416 string = gtk_text_buffer_get_text (aw->notes_text_buffer, &start, &end, FALSE); 00417 old_string = xaccAccountGetNotes (account); 00418 if (null_strcmp (string, old_string) != 0) 00419 xaccAccountSetNotes (account, string); 00420 00421 flag = 00422 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (aw->tax_related_button)); 00423 if (xaccAccountGetTaxRelated (account) != flag) 00424 xaccAccountSetTaxRelated (account, flag); 00425 00426 flag = 00427 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (aw->placeholder_button)); 00428 if (xaccAccountGetPlaceholder (account) != flag) 00429 xaccAccountSetPlaceholder (account, flag); 00430 00431 flag = 00432 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (aw->hidden_button)); 00433 if (xaccAccountGetHidden (account) != flag) 00434 xaccAccountSetHidden (account, flag); 00435 00436 parent_account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT (aw->parent_tree)); 00437 00438 if (parent_account == NULL) 00439 parent_account = gnc_book_get_root_account(aw->book); 00440 if (parent_account != gnc_account_get_parent (account)) 00441 gnc_account_append_child (parent_account, account); 00442 00443 xaccAccountCommitEdit (account); 00444 00445 balance = gnc_amount_edit_get_amount 00446 (GNC_AMOUNT_EDIT (aw->opening_balance_edit)); 00447 00448 if (gnc_numeric_zero_p (balance)) 00449 { 00450 LEAVE("zero balance"); 00451 return; 00452 } 00453 00454 if (gnc_reverse_balance (account)) 00455 balance = gnc_numeric_neg (balance); 00456 00457 date = gnc_date_edit_get_date ( 00458 GNC_DATE_EDIT (aw->opening_balance_date_edit)); 00459 00460 use_equity = gtk_toggle_button_get_active 00461 (GTK_TOGGLE_BUTTON (aw->opening_equity_radio)); 00462 00463 if (use_equity) 00464 { 00465 if (!gnc_account_create_opening_balance (account, balance, date, aw->book)) 00466 { 00467 const char *message = _("Could not create opening balance."); 00468 gnc_error_dialog(aw->dialog, "%s", message); 00469 } 00470 } 00471 else 00472 { 00473 Account *transfer = NULL; 00474 00475 transfer = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT (aw->transfer_tree)); 00476 if (!transfer) 00477 { 00478 LEAVE("no transfer account"); 00479 return; 00480 } 00481 00482 gnc_account_create_transfer_balance (aw->book, account, transfer, balance, date); 00483 } 00484 LEAVE(" "); 00485 } 00486 00487 00488 static void 00489 set_children_types (Account *account, GNCAccountType type) 00490 { 00491 GList *children, *iter; 00492 00493 children = gnc_account_get_children(account); 00494 if (children == NULL) 00495 return; 00496 00497 for (iter = children; iter; iter = iter->next) 00498 { 00499 account = iter->data; 00500 if (type == xaccAccountGetType(account)) 00501 continue; 00502 00503 /* Just refreshing won't work. */ 00504 aw_call_destroy_callbacks (account); 00505 00506 xaccAccountBeginEdit (account); 00507 xaccAccountSetType (account, type); 00508 xaccAccountCommitEdit (account); 00509 00510 set_children_types (account, type); 00511 } 00512 g_list_free(children); 00513 } 00514 00515 static void 00516 make_children_compatible (AccountWindow *aw) 00517 { 00518 Account *account; 00519 00520 g_return_if_fail (aw); 00521 00522 if (aw->dialog_type == NEW_ACCOUNT) 00523 return; 00524 00525 account = aw_get_account (aw); 00526 g_return_if_fail (account); 00527 00528 if (xaccAccountTypesCompatible (xaccAccountGetType (account), aw->type)) 00529 return; 00530 00531 set_children_types (account, aw->type); 00532 } 00533 00534 00535 static void 00536 gnc_finish_ok (AccountWindow *aw) 00537 { 00538 ENTER("aw %p", aw); 00539 gnc_suspend_gui_refresh (); 00540 00541 /* make the account changes */ 00542 make_children_compatible (aw); 00543 gnc_ui_to_account (aw); 00544 00545 gnc_resume_gui_refresh (); 00546 00547 /* do it all again, if needed */ 00548 if ((aw->dialog_type == NEW_ACCOUNT) && aw->next_name && *aw->next_name) 00549 { 00550 gnc_commodity *commodity; 00551 Account *parent; 00552 Account *account; 00553 00554 gnc_suspend_gui_refresh (); 00555 00556 parent = aw_get_account (aw); 00557 account = xaccMallocAccount (aw->book); 00558 aw->account = *xaccAccountGetGUID (account); 00559 aw->type = xaccAccountGetType (parent); 00560 00561 xaccAccountSetName (account, *aw->next_name); 00562 aw->next_name++; 00563 00564 gnc_account_to_ui (aw); 00565 00566 gnc_account_window_set_name (aw); 00567 00568 commodity = xaccAccountGetCommodity (parent); 00569 gnc_general_select_set_selected (GNC_GENERAL_SELECT (aw->commodity_edit), 00570 commodity); 00571 gnc_account_commodity_from_type (aw, FALSE); 00572 00573 gnc_tree_view_account_set_selected_account ( 00574 GNC_TREE_VIEW_ACCOUNT (aw->parent_tree), parent); 00575 00576 gnc_resume_gui_refresh (); 00577 LEAVE("1"); 00578 return; 00579 } 00580 00581 /* save for posterity */ 00582 aw->created_account = aw_get_account (aw); 00583 00584 /* so it doesn't get freed on close */ 00585 aw->account = *guid_null (); 00586 00587 gnc_close_gui_component (aw->component_id); 00588 LEAVE("2"); 00589 } 00590 00591 00592 static void 00593 add_children_to_expander (GObject *object, GParamSpec *param_spec, gpointer data) 00594 { 00595 GtkExpander *expander = GTK_EXPANDER (object); 00596 Account *account = data; 00597 GtkWidget *scrolled_window; 00598 GtkTreeView *view; 00599 00600 if (gtk_expander_get_expanded (expander) && 00601 !gtk_bin_get_child (GTK_BIN (expander))) 00602 { 00603 00604 view = gnc_tree_view_account_new_with_root (account, FALSE); 00605 00606 scrolled_window = gtk_scrolled_window_new (NULL, NULL); 00607 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), 00608 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 00609 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), 00610 GTK_SHADOW_IN); 00611 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (view)); 00612 00613 gtk_container_add (GTK_CONTAINER (expander), scrolled_window); 00614 gtk_widget_show_all (scrolled_window); 00615 } 00616 } 00617 00618 /* Check whether there are children needing a type adjustment because of a 00619 a change to an incompatible type (like after some reparenting) and let the 00620 user decide whether he wants that */ 00621 static gboolean 00622 verify_children_compatible (AccountWindow *aw) 00623 { 00624 Account *account; 00625 GtkWidget *dialog, *vbox, *hbox, *label, *expander; 00626 gchar *str; 00627 gboolean result; 00628 00629 if (aw == NULL) 00630 return FALSE; 00631 00632 account = aw_get_account (aw); 00633 if (!account) 00634 return FALSE; 00635 00636 if (xaccAccountTypesCompatible (xaccAccountGetType (account), aw->type)) 00637 return TRUE; 00638 00639 if (gnc_account_n_children(account) == 0) 00640 return TRUE; 00641 00642 dialog = gtk_dialog_new_with_buttons ("", 00643 GTK_WINDOW(aw->dialog), 00644 GTK_DIALOG_DESTROY_WITH_PARENT | 00645 GTK_DIALOG_MODAL, 00646 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 00647 GTK_STOCK_OK, GTK_RESPONSE_OK, 00648 NULL); 00649 00650 gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), TRUE); 00651 00652 hbox = gtk_hbox_new (FALSE, 12); 00653 vbox = gtk_vbox_new (FALSE, 12); 00654 00655 gtk_box_pack_start ( 00656 GTK_BOX (hbox), 00657 gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG), 00658 FALSE, FALSE, 0); 00659 00660 /* primary label */ 00661 label = gtk_label_new (_("Give the children the same type?")); 00662 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); 00663 gtk_label_set_selectable (GTK_LABEL (label), TRUE); 00664 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); 00665 { 00666 gint size; 00667 PangoFontDescription *font_desc; 00668 00669 size = pango_font_description_get_size (label->style->font_desc); 00670 font_desc = pango_font_description_new (); 00671 pango_font_description_set_weight (font_desc, PANGO_WEIGHT_BOLD); 00672 pango_font_description_set_size (font_desc, size * PANGO_SCALE_LARGE); 00673 gtk_widget_modify_font (label, font_desc); 00674 pango_font_description_free (font_desc); 00675 } 00676 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); 00677 00678 /* secondary label */ 00679 str = g_strdup_printf (_("The children of the edited account have to be " 00680 "changed to type \"%s\" to make them compatible."), 00681 xaccAccountGetTypeStr (aw->type)); 00682 label = gtk_label_new (str); 00683 g_free (str); 00684 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); 00685 gtk_label_set_selectable (GTK_LABEL (label), TRUE); 00686 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); 00687 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); 00688 00689 /* children */ 00690 expander = gtk_expander_new_with_mnemonic (_("_Show children accounts")); 00691 gtk_expander_set_spacing (GTK_EXPANDER (expander), 6); 00692 g_signal_connect (G_OBJECT (expander), "notify::expanded", 00693 G_CALLBACK (add_children_to_expander), account); 00694 gtk_box_pack_start (GTK_BOX (vbox), expander, TRUE, TRUE, 0); 00695 00696 gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); 00697 00698 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, 00699 TRUE, TRUE, 0); 00700 00701 /* spacings */ 00702 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); 00703 gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); 00704 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 14); 00705 gtk_container_set_border_width ( 00706 GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 5); 00707 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->action_area), 6); 00708 00709 gtk_widget_show_all (hbox); 00710 00711 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); 00712 00713 result = (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK); 00714 00715 gtk_widget_destroy(dialog); 00716 00717 return result; 00718 } 00719 00720 00721 static gboolean 00722 gnc_filter_parent_accounts (Account *account, gpointer data) 00723 { 00724 AccountWindow *aw = data; 00725 Account *aw_account = aw_get_account (aw); 00726 00727 if (account == NULL) 00728 return FALSE; 00729 00730 if (aw_account == NULL) 00731 return FALSE; 00732 00733 if (gnc_account_is_root(account)) 00734 return TRUE; 00735 00736 if (account == aw_account) 00737 return FALSE; 00738 00739 if (xaccAccountHasAncestor(account, aw_account)) 00740 return FALSE; 00741 00742 return TRUE; 00743 } 00744 00745 00746 static gboolean 00747 gnc_common_ok (AccountWindow *aw) 00748 { 00749 Account *root, *account, *parent; 00750 gnc_commodity * commodity; 00751 gchar *fullname, *fullname_parent; 00752 const gchar *name, *separator; 00753 00754 ENTER("aw %p", aw); 00755 root = gnc_book_get_root_account (aw->book); 00756 00757 separator = gnc_get_account_separator_string(); 00758 00759 /* check for valid name */ 00760 name = gtk_entry_get_text(GTK_ENTRY(aw->name_entry)); 00761 if (safe_strcmp(name, "") == 0) 00762 { 00763 const char *message = _("The account must be given a name."); 00764 gnc_error_dialog(aw->dialog, "%s", message); 00765 LEAVE("bad name"); 00766 return FALSE; 00767 } 00768 00769 /* check for a duplicate name */ 00770 parent = gnc_tree_view_account_get_selected_account 00771 (GNC_TREE_VIEW_ACCOUNT (aw->parent_tree)); 00772 if (parent == NULL) 00773 { 00774 account = gnc_account_lookup_by_full_name(root, name); 00775 } 00776 else 00777 { 00778 fullname_parent = gnc_account_get_full_name(parent); 00779 fullname = g_strconcat(fullname_parent, separator, name, NULL); 00780 00781 account = gnc_account_lookup_by_full_name(root, fullname); 00782 00783 g_free(fullname_parent); 00784 g_free(fullname); 00785 } 00786 if ((account != NULL) && 00787 !guid_equal(&aw->account, xaccAccountGetGUID (account))) 00788 { 00789 const char *message = _("There is already an account with that name."); 00790 gnc_error_dialog(aw->dialog, "%s", message); 00791 LEAVE("duplicate name"); 00792 return FALSE; 00793 } 00794 00795 /* Parent check, probably not needed, but be safe */ 00796 if (!gnc_filter_parent_accounts(parent, aw)) 00797 { 00798 const char *message = _("You must choose a valid parent account."); 00799 gnc_error_dialog(aw->dialog, "%s", message); 00800 LEAVE("invalid parent"); 00801 return FALSE; 00802 } 00803 00804 /* check for valid type */ 00805 if (aw->type == ACCT_TYPE_INVALID) 00806 { 00807 const char *message = _("You must select an account type."); 00808 gnc_error_dialog(aw->dialog, "%s", message); 00809 LEAVE("invalid type"); 00810 return FALSE; 00811 } 00812 00813 /* check whether the types of child and parent are compatible */ 00814 if (!xaccAccountTypesCompatible (aw->type, xaccAccountGetType (parent))) 00815 { 00816 const char *message = _("The selected account type is incompatible with " 00817 "the one of the selected parent."); 00818 gnc_error_dialog(aw->dialog, "%s", message); 00819 LEAVE("incompatible types"); 00820 return FALSE; 00821 } 00822 00823 /* check for commodity */ 00824 commodity = (gnc_commodity *) 00825 gnc_general_select_get_selected (GNC_GENERAL_SELECT (aw->commodity_edit)); 00826 if (!commodity) 00827 { 00828 const char *message = _("You must choose a commodity."); 00829 gnc_error_dialog(aw->dialog, "%s", message); 00830 LEAVE("invalid commodity"); 00831 return FALSE; 00832 } 00833 00834 LEAVE("passed"); 00835 return TRUE; 00836 } 00837 00838 static void 00839 gnc_edit_account_ok(AccountWindow *aw) 00840 { 00841 Account *account; 00842 00843 ENTER("aw %p", aw); 00844 00845 account = aw_get_account (aw); 00846 if (!account) 00847 { 00848 LEAVE(" "); 00849 return; 00850 } 00851 00852 if (!gnc_common_ok(aw)) 00853 { 00854 LEAVE(" "); 00855 return; 00856 } 00857 00858 if (!verify_children_compatible (aw)) 00859 { 00860 LEAVE(" "); 00861 return; 00862 } 00863 00864 gnc_finish_ok (aw); 00865 LEAVE(" "); 00866 } 00867 00868 00869 static void 00870 gnc_new_account_ok (AccountWindow *aw) 00871 { 00872 gnc_numeric balance; 00873 00874 ENTER("aw %p", aw); 00875 00876 if (!gnc_common_ok(aw)) 00877 { 00878 LEAVE(" "); 00879 return; 00880 } 00881 00882 if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (aw->opening_balance_edit))) 00883 { 00884 const char *message = _("You must enter a valid opening balance " 00885 "or leave it blank."); 00886 gnc_error_dialog(aw->dialog, "%s", message); 00887 LEAVE(" "); 00888 return; 00889 } 00890 00891 balance = gnc_amount_edit_get_amount 00892 (GNC_AMOUNT_EDIT (aw->opening_balance_edit)); 00893 00894 if (!gnc_numeric_zero_p (balance)) 00895 { 00896 gboolean use_equity; 00897 00898 use_equity = gtk_toggle_button_get_active 00899 (GTK_TOGGLE_BUTTON (aw->opening_equity_radio)); 00900 00901 if (!use_equity) 00902 { 00903 Account *transfer = NULL; 00904 00905 transfer = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT (aw->transfer_tree)); 00906 if (!transfer) 00907 { 00908 const char *message = _("You must select a transfer account or choose" 00909 " the opening balances equity account."); 00910 gnc_error_dialog(aw->dialog, "%s", message); 00911 LEAVE(" "); 00912 return; 00913 } 00914 } 00915 } 00916 00917 gnc_finish_ok (aw); 00918 LEAVE(" "); 00919 } 00920 00921 static void 00922 gnc_account_window_response_cb (GtkDialog *dialog, 00923 gint response, 00924 gpointer data) 00925 { 00926 AccountWindow *aw = data; 00927 00928 ENTER("dialog %p, response %d, aw %p", dialog, response, aw); 00929 switch (response) 00930 { 00931 case GTK_RESPONSE_OK: 00932 switch (aw->dialog_type) 00933 { 00934 case NEW_ACCOUNT: 00935 DEBUG("new acct dialog, OK"); 00936 gnc_new_account_ok (aw); 00937 break; 00938 case EDIT_ACCOUNT: 00939 DEBUG("edit acct dialog, OK"); 00940 gnc_edit_account_ok (aw); 00941 break; 00942 default: 00943 g_assert_not_reached (); 00944 return; 00945 } 00946 break; 00947 case GTK_RESPONSE_HELP: 00948 switch (aw->dialog_type) 00949 { 00950 case NEW_ACCOUNT: 00951 DEBUG("new acct dialog, HELP"); 00952 gnc_gnome_help(HF_HELP, HL_ACC); 00953 break; 00954 case EDIT_ACCOUNT: 00955 DEBUG("edit acct dialog, HELP"); 00956 gnc_gnome_help(HF_HELP, HL_ACCEDIT); 00957 break; 00958 default: 00959 g_assert_not_reached (); 00960 return; 00961 } 00962 break; 00963 case GTK_RESPONSE_CANCEL: 00964 default: 00965 DEBUG("CANCEL"); 00966 gnc_close_gui_component (aw->component_id); 00967 break; 00968 } 00969 LEAVE(" "); 00970 } 00971 00972 void 00973 gnc_account_window_destroy_cb (GtkObject *object, gpointer data) 00974 { 00975 AccountWindow *aw = data; 00976 Account *account; 00977 00978 ENTER("object %p, aw %p", object, aw); 00979 account = aw_get_account (aw); 00980 00981 gnc_suspend_gui_refresh (); 00982 00983 switch (aw->dialog_type) 00984 { 00985 case NEW_ACCOUNT: 00986 if (account != NULL) 00987 { 00988 xaccAccountBeginEdit (account); 00989 xaccAccountDestroy (account); 00990 aw->account = *guid_null (); 00991 } 00992 00993 DEBUG ("account add window destroyed\n"); 00994 break; 00995 00996 case EDIT_ACCOUNT: 00997 break; 00998 00999 default: 01000 PERR ("unexpected dialog type\n"); 01001 gnc_resume_gui_refresh (); 01002 LEAVE(" "); 01003 return; 01004 } 01005 01006 gnc_unregister_gui_component (aw->component_id); 01007 01008 gnc_resume_gui_refresh (); 01009 01010 if (aw->subaccount_names) 01011 { 01012 g_strfreev(aw->subaccount_names); 01013 aw->subaccount_names = NULL; 01014 aw->next_name = NULL; 01015 } 01016 01017 g_free (aw); 01018 LEAVE(" "); 01019 } 01020 01021 static void 01022 gnc_account_parent_changed_cb (GtkTreeSelection *selection, gpointer data) 01023 { 01024 AccountWindow *aw = data; 01025 Account *parent_account; 01026 guint32 types, old_types; 01027 GtkTreeModel *type_model; 01028 GtkTreeSelection *type_selection; 01029 gboolean scroll_to = FALSE; 01030 01031 g_return_if_fail (aw); 01032 01033 parent_account = gnc_tree_view_account_get_selected_account ( 01034 GNC_TREE_VIEW_ACCOUNT (aw->parent_tree)); 01035 if (!parent_account) 01036 return; 01037 01038 if (gnc_account_is_root(parent_account)) 01039 { 01040 types = aw->valid_types; 01041 } 01042 else 01043 { 01044 types = aw->valid_types & 01045 xaccParentAccountTypesCompatibleWith (xaccAccountGetType (parent_account)); 01046 } 01047 01048 type_model = gtk_tree_view_get_model (GTK_TREE_VIEW (aw->type_view)); 01049 if (!type_model) 01050 return; 01051 01052 if (aw->type != aw->preferred_account_type && 01053 (types & (1 << aw->preferred_account_type)) != 0) 01054 { 01055 /* we can change back to the preferred account type */ 01056 aw->type = aw->preferred_account_type; 01057 scroll_to = TRUE; 01058 } 01059 else if ((types & (1 << aw->type)) == 0) 01060 { 01061 /* our type is invalid now */ 01062 aw->type = ACCT_TYPE_INVALID; 01063 } 01064 else 01065 { 01066 /* no type change, but maybe list of valid types changed */ 01067 old_types = gnc_tree_model_account_types_get_mask (type_model); 01068 if (old_types != types) 01069 scroll_to = TRUE; 01070 } 01071 01072 gnc_tree_model_account_types_set_mask (type_model, types); 01073 01074 if (scroll_to) 01075 { 01076 type_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (aw->type_view)); 01077 gnc_tree_model_account_types_set_selection(type_selection, 1 << aw->type); 01078 } 01079 01080 gnc_account_window_set_name(aw); 01081 } 01082 01083 static void 01084 gnc_account_type_changed_cb (GtkTreeSelection *selection, gpointer data) 01085 { 01086 AccountWindow *aw = data; 01087 gboolean sensitive; 01088 GNCAccountType type_id; 01089 01090 g_return_if_fail (aw != NULL); 01091 01092 sensitive = FALSE; 01093 01094 type_id = gnc_tree_model_account_types_get_selection_single(selection); 01095 if (type_id == ACCT_TYPE_NONE) 01096 { 01097 aw->type = ACCT_TYPE_INVALID; 01098 } 01099 else 01100 { 01101 aw->type = type_id; 01102 aw->preferred_account_type = type_id; 01103 01104 gnc_account_commodity_from_type (aw, TRUE); 01105 01106 sensitive = (aw->type != ACCT_TYPE_EQUITY && 01107 aw->type != ACCT_TYPE_CURRENCY && 01108 aw->type != ACCT_TYPE_STOCK && 01109 aw->type != ACCT_TYPE_MUTUAL && 01110 aw->type != ACCT_TYPE_TRADING); 01111 } 01112 01113 gtk_widget_set_sensitive (aw->opening_balance_page, sensitive); 01114 01115 if (!sensitive) 01116 { 01117 gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (aw->opening_balance_edit), 01118 gnc_numeric_zero ()); 01119 } 01120 } 01121 01122 static void 01123 gnc_account_type_view_create (AccountWindow *aw) 01124 { 01125 GtkTreeModel *model; 01126 GtkTreeSelection *selection; 01127 GtkCellRenderer *renderer; 01128 GtkTreeView *view; 01129 01130 if (aw->valid_types == 0) 01131 { 01132 /* no type restrictions, choose aw->type */ 01133 aw->valid_types = xaccAccountTypesValid () | (1 << aw->type); 01134 aw->preferred_account_type = aw->type; 01135 } 01136 else if ((aw->valid_types & (1 << aw->type)) != 0) 01137 { 01138 /* aw->type is valid */ 01139 aw->preferred_account_type = aw->type; 01140 } 01141 else if ((aw->valid_types & (1 << last_used_account_type)) != 0) 01142 { 01143 /* last used account type is valid */ 01144 aw->type = last_used_account_type; 01145 aw->preferred_account_type = last_used_account_type; 01146 } 01147 else 01148 { 01149 /* choose first valid account type */ 01150 int i; 01151 aw->preferred_account_type = aw->type; 01152 aw->type = ACCT_TYPE_INVALID; 01153 for (i = 0; i < 32; i++) 01154 if ((aw->valid_types & (1 << i)) != 0) 01155 { 01156 aw->type = i; 01157 break; 01158 } 01159 } 01160 01161 model = gnc_tree_model_account_types_filter_using_mask (aw->valid_types); 01162 01163 view = GTK_TREE_VIEW (aw->type_view); 01164 gtk_tree_view_set_model (view, model); 01165 g_object_unref (G_OBJECT (model)); 01166 01167 renderer = gtk_cell_renderer_text_new (); 01168 gtk_tree_view_insert_column_with_attributes ( 01169 view, -1, NULL, renderer, 01170 "text", GNC_TREE_MODEL_ACCOUNT_TYPES_COL_NAME, 01171 NULL); 01172 gtk_tree_view_set_search_column (view, GNC_TREE_MODEL_ACCOUNT_TYPES_COL_NAME); 01173 01174 selection = gtk_tree_view_get_selection (view); 01175 g_signal_connect (G_OBJECT (selection), "changed", 01176 G_CALLBACK (gnc_account_type_changed_cb), aw); 01177 01178 gnc_tree_model_account_types_set_selection(selection, 1 << aw->type); 01179 } 01180 01181 void 01182 gnc_account_name_insert_text_cb (GtkWidget *entry, 01183 const gchar *text, 01184 gint length, 01185 gint *position, 01186 gpointer data) 01187 { 01188 GtkEditable *editable = GTK_EDITABLE( entry ); 01189 const gchar *separator = NULL; 01190 gchar **strsplit; 01191 01192 separator = gnc_get_account_separator_string(); 01193 strsplit = g_strsplit ( text, separator, 0 ); 01194 if ( strsplit[1] != NULL ) 01195 { 01196 gchar *result = g_strjoinv ( NULL, strsplit ); 01197 g_signal_handlers_block_by_func ( G_OBJECT ( editable ), 01198 G_CALLBACK ( gnc_account_name_insert_text_cb ), 01199 data ); 01200 gtk_editable_insert_text ( editable, result, g_utf8_strlen ( result, -1 ), position ); 01201 g_signal_handlers_unblock_by_func ( G_OBJECT ( editable ), 01202 G_CALLBACK ( gnc_account_name_insert_text_cb ), 01203 data ); 01204 g_signal_stop_emission_by_name (G_OBJECT ( editable ), "insert_text"); 01205 g_free (result); 01206 } 01207 01208 g_strfreev ( strsplit ); 01209 } 01210 01211 void 01212 gnc_account_name_changed_cb(GtkWidget *widget, gpointer data) 01213 { 01214 AccountWindow *aw = data; 01215 01216 gnc_account_window_set_name (aw); 01217 } 01218 01219 void 01220 gnc_account_color_default_cb(GtkWidget *widget, gpointer data) 01221 { 01222 GdkColor color; 01223 AccountWindow *aw = data; 01224 01225 gdk_color_parse( DEFAULT_COLOR, &color); 01226 gtk_color_button_set_color(GTK_COLOR_BUTTON(aw->color_entry_button), &color); 01227 01228 } 01229 01230 static void 01231 commodity_changed_cb (GNCGeneralSelect *gsl, gpointer data) 01232 { 01233 AccountWindow *aw = data; 01234 gnc_commodity *currency; 01235 GtkTreeSelection *selection; 01236 01237 currency = (gnc_commodity *) gnc_general_select_get_selected (gsl); 01238 if (!currency) 01239 return; 01240 01241 gnc_amount_edit_set_fraction (GNC_AMOUNT_EDIT (aw->opening_balance_edit), 01242 gnc_commodity_get_fraction (currency)); 01243 gnc_amount_edit_set_print_info (GNC_AMOUNT_EDIT (aw->opening_balance_edit), 01244 gnc_commodity_print_info (currency, FALSE)); 01245 01246 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (aw->transfer_tree)); 01247 gtk_tree_selection_unselect_all (selection); 01248 } 01249 01250 static gboolean 01251 account_commodity_filter (GtkTreeSelection *selection, 01252 GtkTreeModel *unused_model, 01253 GtkTreePath *s_path, 01254 gboolean path_currently_selected, 01255 gpointer user_data) 01256 { 01257 gnc_commodity *commodity; 01258 AccountWindow *aw; 01259 Account *account; 01260 01261 g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE); 01262 01263 aw = user_data; 01264 01265 if (path_currently_selected) 01266 { 01267 /* already selected, don't waste time. */ 01268 return TRUE; 01269 } 01270 01271 account = gnc_tree_view_account_get_account_from_path (GNC_TREE_VIEW_ACCOUNT (aw->transfer_tree), s_path); 01272 if (!account) 01273 { 01274 return FALSE; 01275 } 01276 01277 commodity = (gnc_commodity *) 01278 gnc_general_select_get_selected (GNC_GENERAL_SELECT (aw->commodity_edit)); 01279 01280 return gnc_commodity_equiv (xaccAccountGetCommodity (account), commodity); 01281 } 01282 01283 void 01284 opening_equity_cb (GtkWidget *w, gpointer data) 01285 { 01286 AccountWindow *aw = data; 01287 gboolean use_equity; 01288 01289 use_equity = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)); 01290 01291 gtk_widget_set_sensitive (aw->transfer_account_scroll, !use_equity); 01292 } 01293 01294 /********************************************************************\ 01295 * gnc_account_window_create * 01296 * creates a window to create a new account. * 01297 * * 01298 * Args: aw - the information structure for this window * 01299 * Return: the created window * 01300 \*******************************************************************/ 01301 static void 01302 gnc_account_window_create(AccountWindow *aw) 01303 { 01304 GtkWidget *amount; 01305 GtkWidget *date_edit; 01306 GObject *awo; 01307 GtkWidget *box; 01308 GtkWidget *label; 01309 GtkBuilder *builder; 01310 GtkTreeSelection *selection; 01311 01312 ENTER("aw %p, modal %d", aw, aw->modal); 01313 builder = gtk_builder_new(); 01314 gnc_builder_add_from_file (builder, "dialog-account.glade", "fraction_liststore"); 01315 gnc_builder_add_from_file (builder, "dialog-account.glade", "Account Dialog"); 01316 01317 aw->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Account Dialog")); 01318 awo = G_OBJECT (aw->dialog); 01319 01320 g_object_set_data (awo, "dialog_info", aw); 01321 01322 if (!aw->modal) 01323 g_signal_connect (awo, "response", 01324 G_CALLBACK (gnc_account_window_response_cb), aw); 01325 else 01326 gtk_window_set_modal (GTK_WINDOW (aw->dialog), TRUE); 01327 01328 aw->notebook = GTK_WIDGET(gtk_builder_get_object (builder, "account_notebook")); 01329 aw->name_entry = GTK_WIDGET(gtk_builder_get_object (builder, "name_entry")); 01330 aw->description_entry = GTK_WIDGET(gtk_builder_get_object (builder, "description_entry")); 01331 aw->color_entry_button = GTK_WIDGET(gtk_builder_get_object (builder, "color_entry_button")); 01332 aw->color_default_button = GTK_WIDGET(gtk_builder_get_object (builder, "color_default_button")); 01333 aw->code_entry = GTK_WIDGET(gtk_builder_get_object (builder, "code_entry")); 01334 aw->notes_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (GTK_WIDGET(gtk_builder_get_object (builder, "notes_text")))); 01335 01336 box = GTK_WIDGET(gtk_builder_get_object (builder, "commodity_hbox")); 01337 aw->commodity_edit = gnc_general_select_new (GNC_GENERAL_SELECT_TYPE_SELECT, 01338 gnc_commodity_edit_get_string, 01339 gnc_commodity_edit_new_select, 01340 &aw->commodity_mode); 01341 gtk_box_pack_start(GTK_BOX(box), aw->commodity_edit, TRUE, TRUE, 0); 01342 gtk_widget_show (aw->commodity_edit); 01343 01344 label = GTK_WIDGET(gtk_builder_get_object (builder, "security_label")); 01345 gnc_general_select_make_mnemonic_target (GNC_GENERAL_SELECT(aw->commodity_edit), label); 01346 01347 g_signal_connect (G_OBJECT (aw->commodity_edit), "changed", 01348 G_CALLBACK (commodity_changed_cb), aw); 01349 01350 aw->account_scu = GTK_WIDGET(gtk_builder_get_object (builder, "account_scu")); 01351 01352 box = GTK_WIDGET(gtk_builder_get_object (builder, "parent_scroll")); 01353 01354 aw->parent_tree = gnc_tree_view_account_new(TRUE); 01355 gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(aw->parent_tree)); 01356 gtk_widget_show(GTK_WIDGET(aw->parent_tree)); 01357 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (aw->parent_tree)); 01358 g_signal_connect (G_OBJECT (selection), "changed", 01359 G_CALLBACK (gnc_account_parent_changed_cb), aw); 01360 01361 aw->tax_related_button = GTK_WIDGET(gtk_builder_get_object (builder, "tax_related_button")); 01362 aw->placeholder_button = GTK_WIDGET(gtk_builder_get_object (builder, "placeholder_button")); 01363 aw->hidden_button = GTK_WIDGET(gtk_builder_get_object (builder, "hidden_button")); 01364 01365 box = GTK_WIDGET(gtk_builder_get_object (builder, "opening_balance_box")); 01366 amount = gnc_amount_edit_new (); 01367 aw->opening_balance_edit = amount; 01368 gtk_box_pack_start(GTK_BOX(box), amount, TRUE, TRUE, 0); 01369 gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (amount), TRUE); 01370 gtk_widget_show (amount); 01371 01372 label = GTK_WIDGET(gtk_builder_get_object (builder, "balance_label")); 01373 gtk_label_set_mnemonic_widget (GTK_LABEL(label), amount); 01374 01375 box = GTK_WIDGET(gtk_builder_get_object (builder, "opening_balance_date_box")); 01376 date_edit = gnc_date_edit_new (time (NULL), 1, 1); 01377 aw->opening_balance_date_edit = date_edit; 01378 gtk_box_pack_start(GTK_BOX(box), date_edit, TRUE, TRUE, 0); 01379 gtk_widget_show (date_edit); 01380 01381 aw->opening_balance_page = 01382 gtk_notebook_get_nth_page (GTK_NOTEBOOK (aw->notebook), 1); 01383 01384 aw->opening_equity_radio = GTK_WIDGET(gtk_builder_get_object (builder, 01385 "opening_equity_radio")); 01386 01387 box = GTK_WIDGET(gtk_builder_get_object (builder, "transfer_account_scroll")); 01388 aw->transfer_account_scroll = box; 01389 01390 aw->transfer_tree = GTK_WIDGET(gnc_tree_view_account_new(FALSE)); 01391 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(aw->transfer_tree)); 01392 gtk_tree_selection_set_select_function(selection, account_commodity_filter, aw, NULL); 01393 01394 gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(aw->transfer_tree)); 01395 gtk_widget_show (GTK_WIDGET(aw->transfer_tree)); 01396 01397 label = GTK_WIDGET(gtk_builder_get_object (builder, "parent_label")); 01398 gtk_label_set_mnemonic_widget (GTK_LABEL(label), GTK_WIDGET(aw->parent_tree)); 01399 01400 /* This goes at the end so the select callback has good data. */ 01401 aw->type_view = GTK_WIDGET(gtk_builder_get_object (builder, "type_view")); 01402 gnc_account_type_view_create (aw); 01403 01404 gnc_restore_window_size (GCONF_SECTION, GTK_WINDOW(aw->dialog)); 01405 01406 gtk_widget_grab_focus(GTK_WIDGET(aw->name_entry)); 01407 01408 gtk_builder_connect_signals(builder, aw); 01409 g_object_unref(G_OBJECT(builder)); 01410 01411 LEAVE(" "); 01412 } 01413 01414 01415 static char * 01416 get_ui_fullname (AccountWindow *aw) 01417 { 01418 Account *parent_account; 01419 char *fullname; 01420 const gchar *name; 01421 01422 name = gtk_entry_get_text (GTK_ENTRY(aw->name_entry)); 01423 if (!name || *name == '\0') 01424 name = _("<No name>"); 01425 01426 parent_account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT (aw->parent_tree)); 01427 01428 if (parent_account && !gnc_account_is_root(parent_account)) 01429 { 01430 char *parent_name; 01431 const gchar *separator; 01432 01433 parent_name = gnc_account_get_full_name (parent_account); 01434 01435 separator = gnc_get_account_separator_string (); 01436 fullname = g_strconcat (parent_name, separator, name, NULL); 01437 01438 g_free (parent_name); 01439 } 01440 else 01441 fullname = g_strdup (name); 01442 01443 return fullname; 01444 } 01445 01446 static void 01447 gnc_account_window_set_name (AccountWindow *aw) 01448 { 01449 char *fullname; 01450 char *title; 01451 01452 if (!aw || !aw->parent_tree) 01453 return; 01454 01455 fullname = get_ui_fullname (aw); 01456 01457 if (aw->dialog_type == EDIT_ACCOUNT) 01458 title = g_strconcat(_("Edit Account"), " - ", fullname, NULL); 01459 else if (aw->next_name && (g_strv_length(aw->next_name) > 0)) 01460 { 01461 const char *format = _("(%d) New Accounts"); 01462 char *prefix; 01463 01464 prefix = g_strdup_printf (format, g_strv_length(aw->next_name) + 1); 01465 01466 title = g_strconcat (prefix, " - ", fullname, " ...", NULL); 01467 01468 g_free (prefix); 01469 } 01470 else 01471 title = g_strconcat (_("New Account"), " - ", fullname, NULL); 01472 01473 gtk_window_set_title (GTK_WINDOW(aw->dialog), title); 01474 01475 g_free (fullname); 01476 g_free (title); 01477 } 01478 01479 01480 static void 01481 close_handler (gpointer user_data) 01482 { 01483 AccountWindow *aw = user_data; 01484 01485 ENTER("aw %p, modal %d", aw, aw->modal); 01486 gnc_save_window_size (GCONF_SECTION, GTK_WINDOW(aw->dialog)); 01487 01488 gtk_widget_destroy (GTK_WIDGET (aw->dialog)); 01489 LEAVE(" "); 01490 } 01491 01492 01493 /********************************************************************\ 01494 * gnc_ui_refresh_account_window * 01495 * refreshes the edit window * 01496 * * 01497 * Args: aw - the account window to refresh * 01498 * Return: none * 01499 \********************************************************************/ 01500 static void 01501 gnc_ui_refresh_account_window (AccountWindow *aw) 01502 { 01503 if (aw == NULL) 01504 return; 01505 01506 /* gnc_account_tree_refresh (GNC_ACCOUNT_TREE(aw->parent_tree));*/ 01507 01508 gnc_account_window_set_name (aw); 01509 } 01510 01511 01512 static void 01513 refresh_handler (GHashTable *changes, gpointer user_data) 01514 { 01515 AccountWindow *aw = user_data; 01516 const EventInfo *info; 01517 Account *account; 01518 01519 account = aw_get_account (aw); 01520 if (!account) 01521 { 01522 gnc_close_gui_component (aw->component_id); 01523 return; 01524 } 01525 01526 if (changes) 01527 { 01528 info = gnc_gui_get_entity_events (changes, &aw->account); 01529 if (info && (info->event_mask & QOF_EVENT_DESTROY)) 01530 { 01531 gnc_close_gui_component (aw->component_id); 01532 return; 01533 } 01534 } 01535 01536 gnc_ui_refresh_account_window (aw); 01537 } 01538 01539 01540 static AccountWindow * 01541 gnc_ui_new_account_window_internal (QofBook *book, 01542 Account *base_account, 01543 gchar **subaccount_names, 01544 GList *valid_types, 01545 const gnc_commodity * default_commodity, 01546 gboolean modal) 01547 { 01548 const gnc_commodity *commodity, *parent_commodity; 01549 AccountWindow *aw; 01550 Account *account; 01551 GList *list; 01552 01553 g_return_val_if_fail(book, NULL); 01554 01555 aw = g_new0 (AccountWindow, 1); 01556 01557 aw->book = book; 01558 aw->modal = modal; 01559 aw->dialog_type = NEW_ACCOUNT; 01560 01561 aw->valid_types = 0; 01562 for (list = valid_types; list; list = list->next) 01563 aw->valid_types |= (1 << GPOINTER_TO_INT (list->data)); 01564 01565 account = xaccMallocAccount (book); 01566 aw->account = *xaccAccountGetGUID (account); 01567 01568 if (base_account) 01569 { 01570 aw->type = xaccAccountGetType (base_account); 01571 parent_commodity = xaccAccountGetCommodity (base_account); 01572 } 01573 else 01574 { 01575 aw->type = last_used_account_type; 01576 parent_commodity = gnc_default_currency (); 01577 } 01578 01579 gnc_suspend_gui_refresh (); 01580 01581 if (subaccount_names && *subaccount_names) 01582 { 01583 xaccAccountSetName (account, subaccount_names[0]); 01584 aw->subaccount_names = subaccount_names; 01585 aw->next_name = subaccount_names + 1; 01586 } 01587 01588 gnc_account_window_create (aw); 01589 gnc_account_to_ui (aw); 01590 01591 gnc_resume_gui_refresh (); 01592 01593 if (default_commodity != NULL) 01594 { 01595 commodity = default_commodity; 01596 if ((aw->type == ACCT_TYPE_STOCK) || (aw->type == ACCT_TYPE_MUTUAL)) 01597 { 01598 gtk_entry_set_text(GTK_ENTRY(aw->name_entry), 01599 (gpointer) gnc_commodity_get_mnemonic(commodity)); 01600 gtk_entry_set_text(GTK_ENTRY(aw->description_entry), 01601 (gpointer) gnc_commodity_get_fullname(commodity)); 01602 } 01603 } 01604 else if ((aw->type != ACCT_TYPE_STOCK) && (aw->type != ACCT_TYPE_MUTUAL)) 01605 { 01606 commodity = parent_commodity; 01607 } 01608 else 01609 { 01610 commodity = NULL; 01611 } 01612 gnc_general_select_set_selected (GNC_GENERAL_SELECT (aw->commodity_edit), 01613 (gpointer) commodity); 01614 gnc_account_commodity_from_type (aw, FALSE); 01615 01616 if (base_account == NULL) 01617 { 01618 base_account = gnc_book_get_root_account(book); 01619 } 01620 01621 gtk_tree_view_collapse_all (aw->parent_tree); 01622 gnc_tree_view_account_set_selected_account ( 01623 GNC_TREE_VIEW_ACCOUNT (aw->parent_tree), base_account); 01624 01625 gtk_widget_show (aw->dialog); 01626 01627 gnc_window_adjust_for_screen (GTK_WINDOW(aw->dialog)); 01628 01629 gnc_account_window_set_name (aw); 01630 01631 aw->component_id = gnc_register_gui_component (DIALOG_NEW_ACCOUNT_CM_CLASS, 01632 refresh_handler, 01633 modal ? NULL : close_handler, 01634 aw); 01635 01636 gnc_gui_component_set_session (aw->component_id, gnc_get_current_session()); 01637 gnc_gui_component_watch_entity_type (aw->component_id, 01638 GNC_ID_ACCOUNT, 01639 QOF_EVENT_MODIFY | QOF_EVENT_DESTROY); 01640 return aw; 01641 } 01642 01643 01644 static gchar ** 01645 gnc_split_account_name (QofBook *book, const char *in_name, Account **base_account) 01646 { 01647 Account *root, *account; 01648 gchar **names, **ptr, **out_names; 01649 GList *list, *node; 01650 01651 root = gnc_book_get_root_account (book); 01652 list = gnc_account_get_children(root); 01653 names = g_strsplit(in_name, gnc_get_account_separator_string(), -1); 01654 01655 for (ptr = names; *ptr; ptr++) 01656 { 01657 /* Stop if there are no children at the current level. */ 01658 if (list == NULL) 01659 break; 01660 01661 /* Look for the first name in the children. */ 01662 for (node = list; node; node = g_list_next(node)) 01663 { 01664 account = node->data; 01665 01666 if (safe_strcmp(xaccAccountGetName (account), *ptr) == 0) 01667 { 01668 /* We found an account. */ 01669 *base_account = account; 01670 break; 01671 } 01672 } 01673 01674 /* Was there a match? If no, stop the traversal. */ 01675 if (node == NULL) 01676 break; 01677 01678 g_list_free(list); 01679 list = gnc_account_get_children (account); 01680 } 01681 01682 out_names = g_strdupv(ptr); 01683 g_strfreev(names); 01684 if (list) 01685 g_list_free(list); 01686 return out_names; 01687 } 01688 01689 01690 /************************************************************ 01691 * Entry points for a Modal Dialog * 01692 ************************************************************/ 01693 01694 Account * 01695 gnc_ui_new_accounts_from_name_window (const char *name) 01696 { 01697 return gnc_ui_new_accounts_from_name_with_defaults (name, NULL, NULL, NULL); 01698 } 01699 01700 Account * 01701 gnc_ui_new_accounts_from_name_window_with_types (const char *name, 01702 GList *valid_types) 01703 { 01704 return gnc_ui_new_accounts_from_name_with_defaults(name, valid_types, NULL, NULL); 01705 } 01706 01707 Account * 01708 gnc_ui_new_accounts_from_name_with_defaults (const char *name, 01709 GList *valid_types, 01710 const gnc_commodity * default_commodity, 01711 Account * parent) 01712 { 01713 QofBook *book; 01714 AccountWindow *aw; 01715 Account *base_account = NULL; 01716 Account *created_account = NULL; 01717 gchar ** subaccount_names; 01718 gint response; 01719 gboolean done = FALSE; 01720 01721 ENTER("name %s, valid %p, commodity %p, account %p", 01722 name, valid_types, default_commodity, parent); 01723 book = gnc_get_current_book(); 01724 if (!name || *name == '\0') 01725 { 01726 subaccount_names = NULL; 01727 base_account = NULL; 01728 } 01729 else 01730 subaccount_names = gnc_split_account_name (book, name, &base_account); 01731 01732 if (parent != NULL) 01733 { 01734 base_account = parent; 01735 } 01736 aw = gnc_ui_new_account_window_internal (book, base_account, subaccount_names, 01737 valid_types, default_commodity, 01738 TRUE); 01739 01740 while (!done) 01741 { 01742 response = gtk_dialog_run (GTK_DIALOG(aw->dialog)); 01743 01744 /* This can destroy the dialog */ 01745 gnc_account_window_response_cb (GTK_DIALOG(aw->dialog), response, (gpointer)aw); 01746 01747 switch (response) 01748 { 01749 case GTK_RESPONSE_OK: 01750 created_account = aw->created_account; 01751 done = (created_account != NULL); 01752 break; 01753 01754 case GTK_RESPONSE_HELP: 01755 done = FALSE; 01756 break; 01757 01758 default: 01759 done = TRUE; 01760 break; 01761 } 01762 } 01763 01764 close_handler(aw); 01765 LEAVE("created %s (%p)", xaccAccountGetName(created_account), created_account); 01766 return created_account; 01767 } 01768 01769 /************************************************************ 01770 * Entry points for a non-Modal Dialog * 01771 ************************************************************/ 01772 01773 static gboolean 01774 find_by_account (gpointer find_data, gpointer user_data) 01775 { 01776 Account *account = find_data; 01777 AccountWindow *aw = user_data; 01778 01779 if (!aw) 01780 return FALSE; 01781 01782 return guid_equal (&aw->account, xaccAccountGetGUID (account)); 01783 } 01784 01785 /* 01786 * opens up a window to edit an account 01787 * 01788 * Args: account - the account to edit 01789 * Return: EditAccountWindow object 01790 */ 01791 void 01792 gnc_ui_edit_account_window(Account *account) 01793 { 01794 AccountWindow * aw; 01795 Account *parent; 01796 01797 if (account == NULL) 01798 return; 01799 01800 aw = gnc_find_first_gui_component (DIALOG_EDIT_ACCOUNT_CM_CLASS, 01801 find_by_account, account); 01802 if (aw) 01803 { 01804 gtk_window_present(GTK_WINDOW(aw->dialog)); 01805 return; 01806 } 01807 01808 aw = g_new0 (AccountWindow, 1); 01809 01810 aw->book = gnc_account_get_book(account); 01811 aw->modal = FALSE; 01812 aw->dialog_type = EDIT_ACCOUNT; 01813 aw->account = *xaccAccountGetGUID (account); 01814 aw->subaccount_names = NULL; 01815 aw->type = xaccAccountGetType (account); 01816 01817 gnc_suspend_gui_refresh (); 01818 01819 gnc_account_window_create (aw); 01820 gnc_account_to_ui (aw); 01821 01822 gnc_resume_gui_refresh (); 01823 01824 gtk_widget_show_all (aw->dialog); 01825 gtk_widget_hide (aw->opening_balance_page); 01826 01827 parent = gnc_account_get_parent (account); 01828 if (parent == NULL) 01829 parent = account; /* must be at the root */ 01830 01831 gtk_tree_view_collapse_all (aw->parent_tree); 01832 gnc_tree_view_account_set_selected_account ( 01833 GNC_TREE_VIEW_ACCOUNT(aw->parent_tree), parent); 01834 01835 gnc_account_window_set_name (aw); 01836 01837 gnc_window_adjust_for_screen(GTK_WINDOW(aw->dialog)); 01838 01839 aw->component_id = gnc_register_gui_component (DIALOG_EDIT_ACCOUNT_CM_CLASS, 01840 refresh_handler, 01841 close_handler, aw); 01842 01843 gnc_gui_component_set_session (aw->component_id, gnc_get_current_session()); 01844 gnc_gui_component_watch_entity_type (aw->component_id, 01845 GNC_ID_ACCOUNT, 01846 QOF_EVENT_MODIFY | QOF_EVENT_DESTROY); 01847 01848 gtk_window_present(GTK_WINDOW(aw->dialog)); 01849 } 01850 01851 01852 /* 01853 * opens up a window to create a new account 01854 * 01855 * Args: book - containing book for the new account 01856 * parent - The initial parent for the new account (optional) 01857 */ 01858 void 01859 gnc_ui_new_account_window(QofBook *book, Account *parent) 01860 { 01861 g_return_if_fail(book != NULL); 01862 if (parent && book) 01863 g_return_if_fail(gnc_account_get_book(parent) == book); 01864 01865 gnc_ui_new_account_window_internal (book, parent, NULL, NULL, NULL, FALSE); 01866 } 01867 01868 void 01869 gnc_ui_new_account_with_types( QofBook *book, 01870 GList *valid_types ) 01871 { 01872 gnc_ui_new_account_window_internal( book, NULL, NULL, valid_types, NULL, FALSE ); 01873 } 01874 01875 /************************************************************ 01876 * Callbacks for a non-Modal Dialog * 01877 ************************************************************/ 01878 01879 /* 01880 * register a callback that gets called when the account has changed 01881 * so significantly that you need to destroy yourself. In particular 01882 * this is used by the ledger display to destroy ledgers when the 01883 * account type has changed. 01884 */ 01885 void 01886 gnc_ui_register_account_destroy_callback (void (*cb)(Account *)) 01887 { 01888 if (!cb) 01889 return; 01890 01891 if (g_list_index (ac_destroy_cb_list, cb) == -1) 01892 ac_destroy_cb_list = g_list_append (ac_destroy_cb_list, cb); 01893 01894 return; 01895 } 01896 01897 /**************************************************/ 01898 01899 static void 01900 gnc_account_renumber_update_examples (RenumberDialog *data) 01901 { 01902 gchar *str; 01903 gchar *prefix; 01904 gint interval, num_digits; 01905 01906 prefix = gtk_editable_get_chars(GTK_EDITABLE(data->prefix), 0, -1); 01907 interval = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->interval)); 01908 num_digits = log10(data->num_children * interval) + 1; 01909 01910 str = g_strdup_printf("%s-%0*d", prefix, num_digits, interval); 01911 gtk_label_set_text(GTK_LABEL(data->example1), str); 01912 g_free(str); 01913 01914 str = g_strdup_printf("%s-%0*d", prefix, num_digits, 01915 interval * data->num_children); 01916 gtk_label_set_text(GTK_LABEL(data->example2), str); 01917 g_free(str); 01918 01919 g_free(prefix); 01920 } 01921 01922 void 01923 gnc_account_renumber_prefix_changed_cb (GtkEditable *editable, 01924 RenumberDialog *data) 01925 { 01926 gnc_account_renumber_update_examples(data); 01927 } 01928 01929 void 01930 gnc_account_renumber_interval_changed_cb (GtkSpinButton *spinbutton, 01931 RenumberDialog *data) 01932 { 01933 gnc_account_renumber_update_examples(data); 01934 } 01935 01936 void 01937 gnc_account_renumber_response_cb (GtkDialog *dialog, 01938 gint response, 01939 RenumberDialog *data) 01940 { 01941 GList *children, *tmp; 01942 gchar *str; 01943 gchar *prefix; 01944 gint interval, num_digits, i; 01945 01946 if (response == GTK_RESPONSE_OK) 01947 { 01948 gtk_widget_hide(data->dialog); 01949 children = gnc_account_get_children(data->parent); 01950 prefix = gtk_editable_get_chars(GTK_EDITABLE(data->prefix), 0, -1); 01951 interval = 01952 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->interval)); 01953 num_digits = log10(data->num_children * interval) + 1; 01954 01955 gnc_set_busy_cursor (NULL, TRUE); 01956 for (tmp = children, i = 1; tmp; tmp = g_list_next(tmp), i += 1) 01957 { 01958 str = g_strdup_printf("%s-%0*d", prefix, num_digits, interval * i); 01959 xaccAccountSetCode(tmp->data, str); 01960 g_free(str); 01961 } 01962 gnc_unset_busy_cursor (NULL); 01963 g_list_free(children); 01964 } 01965 01966 gtk_widget_destroy(data->dialog); 01967 g_free(data); 01968 } 01969 01970 void 01971 gnc_account_renumber_create_dialog (GtkWidget *window, Account *account) 01972 { 01973 RenumberDialog *data; 01974 GtkBuilder *builder; 01975 GtkWidget *widget; 01976 gchar *string; 01977 01978 data = g_new(RenumberDialog, 1); 01979 data->parent = account; 01980 data->num_children = gnc_account_n_children(account); 01981 01982 builder = gtk_builder_new(); 01983 gnc_builder_add_from_file (builder, "dialog-account.glade", "interval_adjustment"); 01984 gnc_builder_add_from_file (builder, "dialog-account.glade", "Renumber Accounts"); 01985 data->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Renumber Accounts")); 01986 gtk_window_set_transient_for(GTK_WINDOW(data->dialog), GTK_WINDOW(window)); 01987 g_object_set_data_full(G_OBJECT(data->dialog), "builder", builder, g_object_unref); 01988 01989 widget = GTK_WIDGET(gtk_builder_get_object (builder, "header_label")); 01990 string = g_strdup_printf(_( "Renumber the immediate sub-accounts of %s? " 01991 "This will replace the account code field of " 01992 "each child account with a newly generated code."), 01993 gnc_account_get_full_name(account)); 01994 gtk_label_set_text(GTK_LABEL(widget), string); 01995 g_free(string); 01996 01997 data->prefix = GTK_WIDGET(gtk_builder_get_object (builder, "prefix_entry")); 01998 data->interval = GTK_WIDGET(gtk_builder_get_object (builder, "interval_spin")); 01999 data->example1 = GTK_WIDGET(gtk_builder_get_object (builder, "example1_label")); 02000 data->example2 = GTK_WIDGET(gtk_builder_get_object (builder, "example2_label")); 02001 02002 gtk_entry_set_text(GTK_ENTRY(data->prefix), xaccAccountGetCode(account)); 02003 gnc_account_renumber_update_examples(data); 02004 02005 gtk_builder_connect_signals(builder, data); 02006 02007 gtk_widget_show_all(data->dialog); 02008 }
1.7.4