|
GnuCash 2.4.99
|
00001 /********************************************************************\ 00002 * gnc-tree-view-account.c -- GtkTreeView implementation to display * 00003 * accounts in a GtkTreeView. * 00004 * Copyright (C) 2003,2005,2006 David Hampton <hampton@employees.org> * 00005 * * 00006 * This program is free software; you can redistribute it and/or * 00007 * modify it under the terms of the GNU General Public License as * 00008 * published by the Free Software Foundation; either version 2 of * 00009 * the License, or (at your option) any later version. * 00010 * * 00011 * This program is distributed in the hope that it will be useful, * 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00014 * GNU General Public License for more details. * 00015 * * 00016 * You should have received a copy of the GNU General Public License* 00017 * along with this program; if not, contact: * 00018 * * 00019 * Free Software Foundation Voice: +1-617-542-5942 * 00020 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * 00021 * Boston, MA 02110-1301, USA gnu@gnu.org * 00022 * * 00023 \********************************************************************/ 00024 00025 #include "config.h" 00026 00027 #include <gtk/gtk.h> 00028 #include <glib/gi18n.h> 00029 #include <string.h> 00030 00031 #include "gnc-tree-view.h" 00032 #include "gnc-tree-model-account.h" 00033 #include "gnc-tree-model-account-types.h" 00034 #include "gnc-tree-view-account.h" 00035 00036 #include "Account.h" 00037 #include "gnc-accounting-period.h" 00038 #include "gnc-commodity.h" 00039 #include "gnc-component-manager.h" 00040 #include "gnc-engine.h" 00041 #include "gnc-glib-utils.h" 00042 #include "gnc-gobject-utils.h" 00043 #include "gnc-hooks.h" 00044 #include "gnc-session.h" 00045 #include "gnc-icons.h" 00046 #include "gnc-ui-balances.h" 00047 #include "dialog-utils.h" 00048 #include "window-main-summarybar.h" 00049 00050 #define SAMPLE_ACCOUNT_VALUE "$1,000,000.00" 00051 00054 /* This static indicates the debugging module that this .o belongs to. */ 00055 static QofLogModule log_module = GNC_MOD_GUI; 00056 00058 static void gnc_tree_view_account_class_init (GncTreeViewAccountClass *klass); 00059 static void gnc_tree_view_account_init (GncTreeViewAccount *view); 00060 static void gnc_tree_view_account_finalize (GObject *object); 00061 00062 static void gtva_update_column_names (GncTreeView *view); 00063 static void gtva_currency_changed_cb (void); 00064 00065 static gboolean gnc_tree_view_account_filter_helper (GtkTreeModel *model, 00066 GtkTreeIter *iter, 00067 gpointer data); 00068 00069 static void gtva_setup_column_renderer_edited_cb(GncTreeViewAccount *account_view, 00070 GtkTreeViewColumn *column, 00071 GtkCellRenderer *renderer, 00072 GncTreeViewAccountColumnTextEdited col_edited_cb); 00073 00074 static void tax_info_data_func (GtkTreeViewColumn *col, 00075 GtkCellRenderer *renderer, 00076 GtkTreeModel *model, 00077 GtkTreeIter *iter, 00078 gpointer view); 00079 00080 typedef struct GncTreeViewAccountPrivate 00081 { 00082 AccountViewInfo avi; 00083 00084 gnc_tree_view_account_filter_func filter_fn; 00085 gpointer filter_data; 00086 GtkFunction filter_destroy; 00087 00088 GtkTreeViewColumn *name_column; 00089 GtkTreeViewColumn *code_column; 00090 GtkTreeViewColumn *desc_column; 00091 GtkTreeViewColumn *present_report_column; 00092 GtkTreeViewColumn *balance_report_column; 00093 GtkTreeViewColumn *cleared_report_column; 00094 GtkTreeViewColumn *reconciled_report_column; 00095 GtkTreeViewColumn *future_min_report_column; 00096 GtkTreeViewColumn *total_report_column; 00097 GtkTreeViewColumn *notes_column; 00098 } GncTreeViewAccountPrivate; 00099 00100 #define GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(o) \ 00101 (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_TREE_VIEW_ACCOUNT, GncTreeViewAccountPrivate)) 00102 00103 00104 /************************************************************/ 00105 /* g_object required functions */ 00106 /************************************************************/ 00107 00108 static GObjectClass *parent_class = NULL; 00109 00110 GType 00111 gnc_tree_view_account_get_type (void) 00112 { 00113 static GType gnc_tree_view_account_type = 0; 00114 00115 if (gnc_tree_view_account_type == 0) 00116 { 00117 static const GTypeInfo our_info = 00118 { 00119 sizeof (GncTreeViewAccountClass), 00120 NULL, 00121 NULL, 00122 (GClassInitFunc) gnc_tree_view_account_class_init, 00123 NULL, 00124 NULL, 00125 sizeof (GncTreeViewAccount), 00126 0, 00127 (GInstanceInitFunc) gnc_tree_view_account_init 00128 }; 00129 00130 gnc_tree_view_account_type = g_type_register_static ( 00131 GNC_TYPE_TREE_VIEW, GNC_TREE_VIEW_ACCOUNT_NAME, 00132 &our_info, 0); 00133 } 00134 00135 return gnc_tree_view_account_type; 00136 } 00137 00138 static void 00139 gnc_tree_view_account_class_init (GncTreeViewAccountClass *klass) 00140 { 00141 GObjectClass *o_class; 00142 00143 parent_class = g_type_class_peek_parent (klass); 00144 00145 /* GObject signals */ 00146 o_class = G_OBJECT_CLASS (klass); 00147 o_class->finalize = gnc_tree_view_account_finalize; 00148 00149 g_type_class_add_private(klass, sizeof(GncTreeViewAccountPrivate)); 00150 00151 gnc_hook_add_dangler(HOOK_CURRENCY_CHANGED, 00152 (GFunc)gtva_currency_changed_cb, NULL); 00153 } 00154 00155 /********************************************************************\ 00156 * gnc_init_account_view_info * 00157 * initialize an account view info structure with default values * 00158 * * 00159 * Args: avi - structure to initialize * 00160 * Returns: nothing * 00161 \********************************************************************/ 00162 static void 00163 gnc_init_account_view_info(AccountViewInfo *avi) 00164 { 00165 int i; 00166 00167 for (i = 0; i < NUM_ACCOUNT_TYPES; i++) 00168 avi->include_type[i] = TRUE; 00169 avi->show_hidden = FALSE; 00170 } 00171 00172 static void 00173 gnc_tree_view_account_init (GncTreeViewAccount *view) 00174 { 00175 GncTreeViewAccountPrivate *priv; 00176 00177 priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(view); 00178 gnc_init_account_view_info(&priv->avi); 00179 } 00180 00181 static void 00182 gnc_tree_view_account_finalize (GObject *object) 00183 { 00184 GncTreeViewAccount *account_view; 00185 GncTreeViewAccountPrivate *priv; 00186 00187 ENTER("view %p", object); 00188 g_return_if_fail (object != NULL); 00189 g_return_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (object)); 00190 00191 account_view = GNC_TREE_VIEW_ACCOUNT (object); 00192 00193 priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(account_view); 00194 if (priv->filter_destroy) 00195 { 00196 priv->filter_destroy(priv->filter_data); 00197 priv->filter_destroy = NULL; 00198 } 00199 priv->filter_fn = NULL; 00200 00201 if (G_OBJECT_CLASS (parent_class)->finalize) 00202 (* G_OBJECT_CLASS (parent_class)->finalize) (object); 00203 LEAVE(" "); 00204 } 00205 00206 00207 /************************************************************ 00208 * Callbacks * 00209 ************************************************************/ 00210 static void 00211 gnc_tree_view_account_placeholder_toggled (GtkCellRendererToggle *cell, 00212 const gchar *s_path_str, 00213 gpointer user_data) 00214 { 00215 GncTreeViewAccount *tree_view; 00216 GtkTreePath *s_path; 00217 Account *account; 00218 gboolean placeholder; 00219 00220 /* Change the requested account */ 00221 tree_view = user_data; 00222 s_path = gtk_tree_path_new_from_string (s_path_str); 00223 account = gnc_tree_view_account_get_account_from_path (tree_view, s_path); 00224 if (account) 00225 { 00226 placeholder = !gtk_cell_renderer_toggle_get_active (cell); // hasn't changed yet. 00227 xaccAccountSetPlaceholder (account, placeholder); 00228 } 00229 00230 /* Clean up */ 00231 gtk_tree_path_free (s_path); 00232 } 00233 00234 00235 /************************************************************/ 00236 /* sort functions */ 00237 /************************************************************/ 00238 00239 static GtkTreeModel * 00240 sort_cb_setup_w_iters (GtkTreeModel *f_model, 00241 GtkTreeIter *f_iter_a, 00242 GtkTreeIter *f_iter_b, 00243 GtkTreeIter *iter_a, 00244 GtkTreeIter *iter_b, 00245 const Account **account_a, 00246 const Account **account_b) 00247 { 00248 GtkTreeModel *model; 00249 00250 model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model)); 00251 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(f_model), 00252 iter_a, 00253 f_iter_a); 00254 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(f_model), 00255 iter_b, 00256 f_iter_b); 00257 *account_a = gnc_tree_model_account_get_account (GNC_TREE_MODEL_ACCOUNT(model), iter_a); 00258 *account_b = gnc_tree_model_account_get_account (GNC_TREE_MODEL_ACCOUNT(model), iter_b); 00259 return model; 00260 } 00261 00262 static void 00263 sort_cb_setup (GtkTreeModel *f_model, 00264 GtkTreeIter *f_iter_a, 00265 GtkTreeIter *f_iter_b, 00266 const Account **account_a, 00267 const Account **account_b) 00268 { 00269 GtkTreeIter iter_a, iter_b; 00270 00271 sort_cb_setup_w_iters (f_model, f_iter_a, f_iter_b, 00272 &iter_a, &iter_b, account_a, account_b); 00273 } 00274 00275 static gint 00276 sort_by_string (GtkTreeModel *f_model, 00277 GtkTreeIter *f_iter1, 00278 GtkTreeIter *f_iter2, 00279 gpointer user_data) 00280 { 00281 GtkTreeModel *model; 00282 GtkTreeIter iter1, iter2; 00283 const Account *account1, *account2; 00284 gchar *str1, *str2; 00285 gint column = GPOINTER_TO_INT(user_data); 00286 gint result; 00287 00288 model = sort_cb_setup_w_iters(f_model, f_iter1, f_iter2, &iter1, &iter2, &account1, &account2); 00289 00290 /* Get the strings. */ 00291 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter1, column, &str1, -1); 00292 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter2, column, &str2, -1); 00293 00294 result = safe_utf8_collate(str1, str2); 00295 g_free(str1); 00296 g_free(str2); 00297 if (result != 0) 00298 return result; 00299 return xaccAccountOrder(account1, account2); 00300 } 00301 00302 static gint 00303 sort_by_code (GtkTreeModel *f_model, 00304 GtkTreeIter *f_iter_a, 00305 GtkTreeIter *f_iter_b, 00306 gpointer user_data) 00307 { 00308 const Account *account_a, *account_b; 00309 00310 sort_cb_setup (f_model, f_iter_a, f_iter_b, &account_a, &account_b); 00311 00312 /* Default ordering uses this column first. */ 00313 return xaccAccountOrder(account_a, account_b); 00314 } 00315 00316 static gint 00317 sort_by_xxx_value (xaccGetBalanceInCurrencyFn fn, 00318 gboolean recurse, 00319 GtkTreeModel *f_model, 00320 GtkTreeIter *f_iter_a, 00321 GtkTreeIter *f_iter_b, 00322 gpointer user_data) 00323 { 00324 const Account *account_a, *account_b; 00325 gnc_numeric balance_a, balance_b; 00326 gint result; 00327 00328 /* Find the accounts */ 00329 sort_cb_setup (f_model, f_iter_a, f_iter_b, &account_a, &account_b); 00330 00331 /* Get balances */ 00332 balance_a = gnc_ui_account_get_balance_full(fn, account_a, recurse, NULL, NULL); 00333 balance_b = gnc_ui_account_get_balance_full(fn, account_b, recurse, NULL, NULL); 00334 00335 result = gnc_numeric_compare(balance_a, balance_b); 00336 if (result != 0) 00337 return result; 00338 return xaccAccountOrder(account_a, account_b); 00339 } 00340 00341 static gint 00342 sort_by_present_value (GtkTreeModel *f_model, 00343 GtkTreeIter *f_iter_a, 00344 GtkTreeIter *f_iter_b, 00345 gpointer user_data) 00346 { 00347 return sort_by_xxx_value (xaccAccountGetPresentBalanceInCurrency, TRUE, 00348 f_model, f_iter_a, f_iter_b, user_data); 00349 } 00350 00351 static gint 00352 sort_by_balance_value (GtkTreeModel *f_model, 00353 GtkTreeIter *f_iter_a, 00354 GtkTreeIter *f_iter_b, 00355 gpointer user_data) 00356 { 00357 return sort_by_xxx_value (xaccAccountGetBalanceInCurrency, TRUE, 00358 f_model, f_iter_a, f_iter_b, user_data); 00359 } 00360 00361 static gint 00362 sort_by_cleared_value (GtkTreeModel *f_model, 00363 GtkTreeIter *f_iter_a, 00364 GtkTreeIter *f_iter_b, 00365 gpointer user_data) 00366 { 00367 return sort_by_xxx_value (xaccAccountGetClearedBalanceInCurrency, TRUE, 00368 f_model, f_iter_a, f_iter_b, user_data); 00369 } 00370 00371 static gint 00372 sort_by_reconciled_value (GtkTreeModel *f_model, 00373 GtkTreeIter *f_iter_a, 00374 GtkTreeIter *f_iter_b, 00375 gpointer user_data) 00376 { 00377 return sort_by_xxx_value (xaccAccountGetReconciledBalanceInCurrency, TRUE, 00378 f_model, f_iter_a, f_iter_b, user_data); 00379 } 00380 00381 static gint 00382 sort_by_future_min_value (GtkTreeModel *f_model, 00383 GtkTreeIter *f_iter_a, 00384 GtkTreeIter *f_iter_b, 00385 gpointer user_data) 00386 { 00387 return sort_by_xxx_value (xaccAccountGetProjectedMinimumBalanceInCurrency, TRUE, 00388 f_model, f_iter_a, f_iter_b, user_data); 00389 } 00390 00391 static gint 00392 sort_by_total_value (GtkTreeModel *f_model, 00393 GtkTreeIter *f_iter_a, 00394 GtkTreeIter *f_iter_b, 00395 gpointer user_data) 00396 { 00397 return sort_by_xxx_value (xaccAccountGetBalanceInCurrency, TRUE, 00398 f_model, f_iter_a, f_iter_b, user_data); 00399 } 00400 00401 static gint 00402 sort_by_placeholder (GtkTreeModel *f_model, 00403 GtkTreeIter *f_iter_a, 00404 GtkTreeIter *f_iter_b, 00405 gpointer user_data) 00406 { 00407 const Account *account_a, *account_b; 00408 gboolean flag_a, flag_b; 00409 00410 /* Find the accounts */ 00411 sort_cb_setup (f_model, f_iter_a, f_iter_b, &account_a, &account_b); 00412 00413 /* Get the placeholder flags. */ 00414 flag_a = xaccAccountGetPlaceholder(account_a); 00415 flag_b = xaccAccountGetPlaceholder(account_b); 00416 00417 if (flag_a > flag_b) 00418 return -1; 00419 else if (flag_a < flag_b) 00420 return 1; 00421 return xaccAccountOrder(account_a, account_b); 00422 } 00423 00424 static gint 00425 sort_by_xxx_period_value (GtkTreeModel *f_model, 00426 GtkTreeIter *f_iter_a, 00427 GtkTreeIter *f_iter_b, 00428 gboolean recurse) 00429 { 00430 Account *acct1, *acct2; 00431 time_t t1, t2; 00432 gnc_numeric b1, b2; 00433 gint result; 00434 00435 sort_cb_setup (f_model, f_iter_a, f_iter_b, 00436 (const Account **)&acct1, (const Account **)&acct2); 00437 00438 t1 = gnc_accounting_period_fiscal_start(); 00439 t2 = gnc_accounting_period_fiscal_end(); 00440 00441 b1 = xaccAccountGetBalanceChangeForPeriod(acct1, t1, t2, recurse); 00442 b2 = xaccAccountGetBalanceChangeForPeriod(acct2, t1, t2, recurse); 00443 00444 result = gnc_numeric_compare(b1, b2); 00445 if (result != 0) 00446 return result; 00447 return xaccAccountOrder(acct1, acct2); 00448 } 00449 00450 static gint 00451 sort_by_balance_period_value (GtkTreeModel *f_model, 00452 GtkTreeIter *f_iter_a, 00453 GtkTreeIter *f_iter_b, 00454 gpointer user_data) 00455 { 00456 return sort_by_xxx_period_value (f_model, f_iter_a, f_iter_b, FALSE); 00457 } 00458 00459 static gint 00460 sort_by_total_period_value (GtkTreeModel *f_model, 00461 GtkTreeIter *f_iter_a, 00462 GtkTreeIter *f_iter_b, 00463 gpointer user_data) 00464 { 00465 return sort_by_xxx_period_value (f_model, f_iter_a, f_iter_b, TRUE); 00466 } 00467 00468 /************************************************************/ 00469 /* Tax_Info data function */ 00470 /************************************************************/ 00471 00472 /* 00473 * The tax-info column in the account tree view is based on the 00474 * combination of two columns in the account tree model. The data 00475 * function displays only the the data in the 00476 * GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO model column if the row is 00477 * expanded; otherwise it combines it with the data 00478 * in the GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO_SUB_ACCT model column. 00479 */ 00480 static void 00481 tax_info_data_func (GtkTreeViewColumn *col, 00482 GtkCellRenderer *renderer, 00483 GtkTreeModel *model, 00484 GtkTreeIter *iter, 00485 gpointer view) 00486 { 00487 gchar *tax_info = NULL; 00488 GtkTreePath *path; 00489 00490 gtk_tree_model_get(model, 00491 iter, 00492 GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO, 00493 &tax_info, 00494 -1); 00495 00496 path = gtk_tree_model_get_path(model, iter); 00497 if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(view), path)) 00498 g_object_set(renderer, "text", 00499 (tax_info == NULL ? "" : tax_info), NULL); 00500 else 00501 { 00502 gchar *tax_info_sub_acct = NULL; 00503 00504 gtk_tree_model_get(model, 00505 iter, 00506 GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO_SUB_ACCT, 00507 &tax_info_sub_acct, 00508 -1); 00509 if ((safe_strcmp (tax_info_sub_acct, "") == 0) || 00510 (tax_info_sub_acct == NULL)) 00511 g_object_set(renderer, "text", 00512 (tax_info == NULL ? "" : tax_info), NULL); 00513 else 00514 { 00515 if ((safe_strcmp (tax_info, "") == 0) || 00516 (tax_info == NULL)) 00517 g_object_set(renderer, "text", 00518 (tax_info_sub_acct == NULL ? "" : tax_info_sub_acct), 00519 NULL); 00520 else 00521 { 00522 gchar *combined_tax_info; 00523 combined_tax_info = g_strdup_printf ("%s; %s", 00524 (tax_info == NULL ? "" : tax_info), 00525 (tax_info_sub_acct == NULL ? "" : 00526 tax_info_sub_acct)); 00527 g_object_set(renderer, "text", combined_tax_info, NULL); 00528 g_free(combined_tax_info); 00529 } 00530 } 00531 g_free(tax_info_sub_acct); 00532 } 00533 g_free(tax_info); 00534 gtk_tree_path_free(path); 00535 } 00536 00537 /************************************************************/ 00538 /* New View Creation */ 00539 /************************************************************/ 00540 00541 /* 00542 * Create a new account tree view with (optional) top level root node. 00543 * This view will be based on a model that is common to all view of 00544 * the same set of books, but will have its own private filter on that 00545 * model. 00546 */ 00547 GtkTreeView * 00548 gnc_tree_view_account_new_with_root (Account *root, gboolean show_root) 00549 { 00550 GncTreeView *view; 00551 GtkTreeModel *model, *f_model, *s_model; 00552 GtkTreePath *virtual_root_path = NULL; 00553 const gchar *sample_type, *sample_commodity; 00554 GncTreeViewAccountPrivate *priv; 00555 GtkTreeViewColumn *tax_info_column; 00556 GtkCellRenderer *renderer; 00557 00558 ENTER(" "); 00559 /* Create our view */ 00560 view = g_object_new (GNC_TYPE_TREE_VIEW_ACCOUNT, 00561 "name", "account_tree", NULL); 00562 00563 priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(GNC_TREE_VIEW_ACCOUNT (view)); 00564 00565 /* Create/get a pointer to the existing model for this set of books. */ 00566 model = gnc_tree_model_account_new (root); 00567 00568 /* Set up the view private filter layer on the common model. */ 00569 if (!show_root) 00570 virtual_root_path = gtk_tree_path_new_first (); 00571 f_model = gtk_tree_model_filter_new (model, virtual_root_path); 00572 /* A GncTreeModelAccount is based on a GncTreeModel, which is a 00573 * GObject that provides a GtkTreeModel interface. */ 00574 g_object_unref(G_OBJECT(model)); 00575 if (virtual_root_path) 00576 gtk_tree_path_free(virtual_root_path); 00577 00578 /* Set up the view private sort layer on the common model. */ 00579 s_model = gtk_tree_model_sort_new_with_model(f_model); 00580 g_object_unref(G_OBJECT(f_model)); 00581 gnc_tree_view_set_model (view, s_model); 00582 g_object_unref(G_OBJECT(s_model)); 00583 00584 /* Set default visibilities */ 00585 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(view), FALSE); 00586 00587 sample_type = xaccAccountGetTypeStr(ACCT_TYPE_CREDIT); 00588 sample_commodity = gnc_commodity_get_fullname(gnc_default_currency()); 00589 00590 priv->name_column 00591 = gnc_tree_view_add_text_column(view, _("Account Name"), "name", 00592 GNC_STOCK_ACCOUNT, "Expenses:Entertainment", 00593 GNC_TREE_MODEL_ACCOUNT_COL_NAME, 00594 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00595 sort_by_string); 00596 gnc_tree_view_add_text_column(view, _("Type"), "type", NULL, sample_type, 00597 GNC_TREE_MODEL_ACCOUNT_COL_TYPE, 00598 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00599 sort_by_string); 00600 gnc_tree_view_add_text_column(view, _("Commodity"), "commodity", NULL, 00601 sample_commodity, 00602 GNC_TREE_MODEL_ACCOUNT_COL_COMMODITY, 00603 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00604 sort_by_string); 00605 priv->code_column 00606 = gnc_tree_view_add_text_column(view, _("Account Code"), "account-code", NULL, 00607 "1-123-1234", 00608 GNC_TREE_MODEL_ACCOUNT_COL_CODE, 00609 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00610 sort_by_code); 00611 priv->desc_column 00612 = gnc_tree_view_add_text_column(view, _("Description"), "description", NULL, 00613 "Sample account description.", 00614 GNC_TREE_MODEL_ACCOUNT_COL_DESCRIPTION, 00615 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00616 sort_by_string); 00617 gnc_tree_view_add_numeric_column(view, _("Last Num"), "lastnum", "12345", 00618 GNC_TREE_MODEL_ACCOUNT_COL_LASTNUM, 00619 GNC_TREE_VIEW_COLUMN_COLOR_NONE, 00620 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00621 sort_by_string); 00622 gnc_tree_view_add_numeric_column(view, _("Present"), "present", 00623 SAMPLE_ACCOUNT_VALUE, 00624 GNC_TREE_MODEL_ACCOUNT_COL_PRESENT, 00625 GNC_TREE_MODEL_ACCOUNT_COL_COLOR_PRESENT, 00626 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00627 sort_by_present_value); 00628 priv->present_report_column 00629 = gnc_tree_view_add_numeric_column(view, _("Present (Report)"), "present_report", 00630 SAMPLE_ACCOUNT_VALUE, 00631 GNC_TREE_MODEL_ACCOUNT_COL_PRESENT_REPORT, 00632 GNC_TREE_MODEL_ACCOUNT_COL_COLOR_PRESENT, 00633 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00634 sort_by_present_value); 00635 gnc_tree_view_add_numeric_column(view, _("Balance"), "balance", 00636 SAMPLE_ACCOUNT_VALUE, 00637 GNC_TREE_MODEL_ACCOUNT_COL_BALANCE, 00638 GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE, 00639 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00640 sort_by_balance_value); 00641 priv->balance_report_column 00642 = gnc_tree_view_add_numeric_column(view, _("Balance (Report)"), "balance_report", 00643 SAMPLE_ACCOUNT_VALUE, 00644 GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_REPORT, 00645 GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE, 00646 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00647 sort_by_balance_value); 00648 00649 gnc_tree_view_add_numeric_column(view, _("Balance (Period)"), "balance-period", 00650 SAMPLE_ACCOUNT_VALUE, 00651 GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_PERIOD, 00652 GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE_PERIOD, 00653 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00654 sort_by_balance_period_value); 00655 gnc_tree_view_add_numeric_column(view, _("Cleared"), "cleared", 00656 SAMPLE_ACCOUNT_VALUE, 00657 GNC_TREE_MODEL_ACCOUNT_COL_CLEARED, 00658 GNC_TREE_MODEL_ACCOUNT_COL_COLOR_CLEARED, 00659 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00660 sort_by_cleared_value); 00661 priv->cleared_report_column 00662 = gnc_tree_view_add_numeric_column(view, _("Cleared (Report)"), "cleared_report", 00663 SAMPLE_ACCOUNT_VALUE, 00664 GNC_TREE_MODEL_ACCOUNT_COL_CLEARED_REPORT, 00665 GNC_TREE_MODEL_ACCOUNT_COL_COLOR_CLEARED, 00666 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00667 sort_by_cleared_value); 00668 gnc_tree_view_add_numeric_column(view, _("Reconciled"), "reconciled", 00669 SAMPLE_ACCOUNT_VALUE, 00670 GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED, 00671 GNC_TREE_MODEL_ACCOUNT_COL_COLOR_RECONCILED, 00672 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00673 sort_by_reconciled_value); 00674 priv->reconciled_report_column 00675 = gnc_tree_view_add_numeric_column(view, _("Reconciled (Report)"), "reconciled_report", 00676 SAMPLE_ACCOUNT_VALUE, 00677 GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED_REPORT, 00678 GNC_TREE_MODEL_ACCOUNT_COL_COLOR_RECONCILED, 00679 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00680 sort_by_reconciled_value); 00681 gnc_tree_view_add_text_column(view, _("Last Reconcile Date"), "last-recon-date", NULL, 00682 "Last Reconcile Date", 00683 GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED_DATE, 00684 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00685 sort_by_string); 00686 gnc_tree_view_add_numeric_column(view, _("Future Minimum"), "future_min", 00687 SAMPLE_ACCOUNT_VALUE, 00688 GNC_TREE_MODEL_ACCOUNT_COL_FUTURE_MIN, 00689 GNC_TREE_MODEL_ACCOUNT_COL_COLOR_FUTURE_MIN, 00690 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00691 sort_by_future_min_value); 00692 priv->future_min_report_column 00693 = gnc_tree_view_add_numeric_column(view, _("Future Minimum (Report)"), "future_min_report", 00694 SAMPLE_ACCOUNT_VALUE, 00695 GNC_TREE_MODEL_ACCOUNT_COL_FUTURE_MIN_REPORT, 00696 GNC_TREE_MODEL_ACCOUNT_COL_COLOR_FUTURE_MIN, 00697 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00698 sort_by_future_min_value); 00699 gnc_tree_view_add_numeric_column(view, _("Total"), "total", 00700 SAMPLE_ACCOUNT_VALUE, 00701 GNC_TREE_MODEL_ACCOUNT_COL_TOTAL, 00702 GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL, 00703 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00704 sort_by_total_value); 00705 priv->total_report_column 00706 = gnc_tree_view_add_numeric_column(view, _("Total (Report)"), "total_report", 00707 SAMPLE_ACCOUNT_VALUE, 00708 GNC_TREE_MODEL_ACCOUNT_COL_TOTAL_REPORT, 00709 GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL, 00710 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00711 sort_by_total_value); 00712 gnc_tree_view_add_numeric_column(view, _("Total (Period)"), "total-period", 00713 SAMPLE_ACCOUNT_VALUE, 00714 GNC_TREE_MODEL_ACCOUNT_COL_TOTAL_PERIOD, 00715 GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL_PERIOD, 00716 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00717 sort_by_total_period_value); 00718 priv->notes_column 00719 = gnc_tree_view_add_text_column(view, _("Notes"), "notes", NULL, 00720 "Sample account notes.", 00721 GNC_TREE_MODEL_ACCOUNT_COL_NOTES, 00722 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00723 sort_by_string); 00724 tax_info_column 00725 = gnc_tree_view_add_text_column(view, _("Tax Info"), "tax-info", NULL, 00726 "Sample tax info.", 00727 GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO, 00728 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00729 sort_by_string); 00730 renderer = gnc_tree_view_column_get_renderer(tax_info_column); 00731 gtk_tree_view_column_set_cell_data_func(tax_info_column, 00732 renderer, 00733 tax_info_data_func, 00734 GTK_TREE_VIEW(view), 00735 NULL); 00736 gnc_tree_view_add_toggle_column(view, _("Placeholder"), 00737 /* Translators: This string has a context prefix; the translation 00738 must only contain the part after the | character. */ 00739 Q_("Column letter for 'Placeholder'|P"), 00740 "placeholder", 00741 GNC_TREE_MODEL_ACCOUNT_COL_PLACEHOLDER, 00742 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 00743 sort_by_placeholder, 00744 gnc_tree_view_account_placeholder_toggled); 00745 00746 /* Update column titles to use the currency name. */ 00747 gtva_update_column_names(view); 00748 00749 /* By default only the first column is visible. */ 00750 gnc_tree_view_configure_columns(view); 00751 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (f_model), 00752 gnc_tree_view_account_filter_helper, 00753 view, 00754 NULL); 00755 00756 /* Default the sorting to account name */ 00757 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(s_model), 00758 GNC_TREE_MODEL_ACCOUNT_COL_NAME, 00759 GTK_SORT_ASCENDING); 00760 00761 gtk_widget_show(GTK_WIDGET(view)); 00762 LEAVE("%p", view); 00763 return GTK_TREE_VIEW(view); 00764 } 00765 00766 /* 00767 * Create a new account tree view with (optional) top level root node. 00768 * This view will be based on a model that is common to all view of 00769 * the same set of books, but will have its own private filter on that 00770 * model. 00771 */ 00772 GtkTreeView * 00773 gnc_tree_view_account_new (gboolean show_root) 00774 { 00775 Account *root; 00776 00777 root = gnc_book_get_root_account (gnc_get_current_book ()); 00778 return gnc_tree_view_account_new_with_root (root, show_root); 00779 } 00780 00781 /************************************************************/ 00782 /* Auxiliary Functions */ 00783 /************************************************************/ 00784 00785 #define debug_path(fn, path) { \ 00786 gchar *path_string = gtk_tree_path_to_string(path); \ 00787 fn("tree path %s", path_string); \ 00788 g_free(path_string); \ 00789 } 00790 00791 static GtkTreePath * 00792 gnc_tree_view_account_get_path_from_account (GncTreeViewAccount *view, 00793 Account *account) 00794 { 00795 GtkTreeModel *model, *f_model, *s_model; 00796 GtkTreePath *path, *f_path, *s_path; 00797 00798 ENTER("view %p, account %p (%s)", view, account, xaccAccountGetName(account)); 00799 00800 if (account == NULL) 00801 { 00802 LEAVE("no account"); 00803 return NULL; 00804 } 00805 00806 /* Reach down to the real model and get a path for this account */ 00807 s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view)); 00808 f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model)); 00809 model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model)); 00810 path = gnc_tree_model_account_get_path_from_account (GNC_TREE_MODEL_ACCOUNT(model), account); 00811 if (path == NULL) 00812 { 00813 LEAVE("no path"); 00814 return NULL; 00815 } 00816 00817 /* convert back to a filtered path */ 00818 f_path = gtk_tree_model_filter_convert_child_path_to_path (GTK_TREE_MODEL_FILTER (f_model), path); 00819 gtk_tree_path_free(path); 00820 if (!f_path) 00821 { 00822 LEAVE("no filter path"); 00823 return NULL; 00824 } 00825 00826 /* convert back to a sorted path */ 00827 s_path = gtk_tree_model_sort_convert_child_path_to_path (GTK_TREE_MODEL_SORT (s_model), f_path); 00828 gtk_tree_path_free(f_path); 00829 debug_path(LEAVE, s_path); 00830 return s_path; 00831 } 00832 00833 static gboolean 00834 gnc_tree_view_account_get_iter_from_account (GncTreeViewAccount *view, 00835 Account *account, 00836 GtkTreeIter *s_iter) 00837 { 00838 GtkTreeModel *model, *f_model, *s_model; 00839 GtkTreeIter iter, f_iter; 00840 00841 g_return_val_if_fail(GNC_IS_TREE_VIEW_ACCOUNT(view), FALSE); 00842 g_return_val_if_fail(account != NULL, FALSE); 00843 g_return_val_if_fail(s_iter != NULL, FALSE); 00844 00845 ENTER("view %p, account %p (%s)", view, account, xaccAccountGetName(account)); 00846 00847 /* Reach down to the real model and get an iter for this account */ 00848 s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view)); 00849 f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model)); 00850 model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model)); 00851 if (!gnc_tree_model_account_get_iter_from_account ( 00852 GNC_TREE_MODEL_ACCOUNT(model), account, &iter)) 00853 { 00854 LEAVE("model_get_iter_from_account failed"); 00855 return FALSE; 00856 } 00857 00858 /* convert back to a sort iter */ 00859 gtk_tree_model_filter_convert_child_iter_to_iter ( 00860 GTK_TREE_MODEL_FILTER(f_model), &f_iter, &iter); 00861 gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT(s_model), 00862 s_iter, &f_iter); 00863 LEAVE(" "); 00864 return TRUE; 00865 } 00866 00867 gint 00868 gnc_tree_view_account_count_children (GncTreeViewAccount *view, 00869 Account *account) 00870 { 00871 GtkTreeModel *s_model; 00872 GtkTreeIter s_iter; 00873 gint num_children; 00874 00875 ENTER("view %p, account %p (%s)", view, account, xaccAccountGetName(account)); 00876 00877 if (account == NULL) 00878 { 00879 LEAVE("no account"); 00880 return 0; 00881 } 00882 00883 if (!gnc_tree_view_account_get_iter_from_account (view, account, &s_iter)) 00884 { 00885 LEAVE("view_get_iter_from_account failed"); 00886 return 0; 00887 } 00888 00889 /* Any children? */ 00890 s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view)); 00891 num_children = gtk_tree_model_iter_n_children(s_model, &s_iter); 00892 LEAVE("%d children", num_children); 00893 return num_children; 00894 } 00895 00896 00897 /************************************************************/ 00898 /* Account Tree View Filter Functions */ 00899 /************************************************************/ 00900 00901 /* 00902 * Get a copy of the account view info structure in use by the 00903 * specified tree. 00904 */ 00905 void 00906 gnc_tree_view_account_get_view_info (GncTreeViewAccount *account_view, 00907 AccountViewInfo *avi) 00908 { 00909 GncTreeViewAccountPrivate *priv; 00910 00911 g_return_if_fail(GNC_IS_TREE_VIEW_ACCOUNT(account_view)); 00912 g_return_if_fail(avi != NULL); 00913 00914 priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(account_view); 00915 00916 *avi = priv->avi; 00917 } 00918 00919 /* 00920 * Set the account view info data in use by the specified tree to 00921 * match the callers request. 00922 * 00923 * DRH - COMPATABILITY WARNING 00924 * 00925 * This function does not do anything with the 'include_type' field. 00926 * Should there be a automatic filter for backward compatability 00927 * that uses these flags, or should all uses of this be converted to 00928 * a GtkTreeModelFilter? 00929 * 00930 * CAS - For now, I'll try the automatic filter approach by making 00931 * this function use GtkTreeModelFilter. 00932 */ 00933 void 00934 gnc_tree_view_account_set_view_info (GncTreeViewAccount *account_view, 00935 AccountViewInfo *avi) 00936 { 00937 GncTreeViewAccountPrivate *priv; 00938 gint i; 00939 guint sel_bits = 0; 00940 00941 ENTER("%p", account_view); 00942 g_return_if_fail(GNC_IS_TREE_VIEW_ACCOUNT(account_view)); 00943 g_return_if_fail(avi != NULL); 00944 00945 priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(account_view); 00946 priv->avi = *avi; 00947 00948 for (i = 0; i < NUM_ACCOUNT_TYPES; i++) 00949 { 00950 sel_bits |= avi->include_type[i] ? (1 << i) : 0; 00951 } 00952 00953 gnc_tree_view_account_set_filter( 00954 account_view, gnc_tree_view_account_filter_by_view_info, 00955 &priv->avi, NULL); 00956 00957 LEAVE(" "); 00958 } 00959 00960 static gboolean 00961 gnc_tree_view_account_filter_helper (GtkTreeModel *model, 00962 GtkTreeIter *iter, 00963 gpointer data) 00964 { 00965 Account *account; 00966 GncTreeViewAccount *view = data; 00967 GncTreeViewAccountPrivate *priv; 00968 00969 g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), FALSE); 00970 g_return_val_if_fail (iter != NULL, FALSE); 00971 00972 account = gnc_tree_model_account_get_account ( 00973 GNC_TREE_MODEL_ACCOUNT(model), iter); 00974 00975 priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(view); 00976 if (priv->filter_fn) 00977 return priv->filter_fn(account, priv->filter_data); 00978 else return TRUE; 00979 } 00980 00981 /* 00982 * Set an GtkTreeModel visible filter on this account. This filter will be 00983 * called for each account that the tree is about to show, and the 00984 * account will be passed to the callback function. 00985 * 00986 * Use NULL as func to remove filter. 00987 */ 00988 void 00989 gnc_tree_view_account_set_filter (GncTreeViewAccount *view, 00990 gnc_tree_view_account_filter_func func, 00991 gpointer data, 00992 GtkFunction destroy) 00993 { 00994 GncTreeViewAccountPrivate *priv; 00995 00996 ENTER("view %p, filter func %p, data %p, destroy %p", 00997 view, func, data, destroy); 00998 00999 g_return_if_fail(GNC_IS_TREE_VIEW_ACCOUNT(view)); 01000 01001 priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(view); 01002 if (priv->filter_destroy) 01003 { 01004 priv->filter_destroy(priv->filter_data); 01005 } 01006 priv->filter_destroy = destroy; 01007 priv->filter_data = data; 01008 priv->filter_fn = func; 01009 01010 gnc_tree_view_account_refilter(view); 01011 LEAVE(" "); 01012 } 01013 01014 /* 01015 * Forces the entire account tree to be re-evaluated for visibility. 01016 */ 01017 void 01018 gnc_tree_view_account_refilter (GncTreeViewAccount *view) 01019 { 01020 GtkTreeModel *f_model, *s_model; 01021 01022 g_return_if_fail(GNC_IS_TREE_VIEW_ACCOUNT(view)); 01023 01024 s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view)); 01025 f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model)); 01026 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (f_model)); 01027 } 01028 01029 gboolean 01030 gnc_tree_view_account_filter_by_view_info(Account* acct, gpointer data) 01031 { 01032 GNCAccountType acct_type; 01033 AccountViewInfo* avi = (AccountViewInfo*)data; 01034 01035 g_return_val_if_fail(GNC_IS_ACCOUNT(acct), FALSE); 01036 acct_type = xaccAccountGetType(acct); 01037 01038 if (!avi->include_type[acct_type]) return FALSE; 01039 if (!avi->show_hidden && xaccAccountIsHidden(acct)) return FALSE; 01040 return TRUE; 01041 } 01042 01043 /************************************************************/ 01044 /* Account Tree View Get/Set Functions */ 01045 /************************************************************/ 01046 01047 /* 01048 * Retrieve the selected account from an account tree view. The 01049 * account tree must be in single selection mode. 01050 */ 01051 Account * 01052 gnc_tree_view_account_get_account_from_path (GncTreeViewAccount *view, 01053 GtkTreePath *s_path) 01054 { 01055 GtkTreeModel *model, *f_model, *s_model; 01056 GtkTreePath *path, *f_path; 01057 GtkTreeIter iter; 01058 Account *account; 01059 01060 ENTER("view %p", view); 01061 g_return_val_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view), NULL); 01062 g_return_val_if_fail (s_path != NULL, NULL); 01063 01064 s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view)); 01065 f_path = gtk_tree_model_sort_convert_path_to_child_path ( 01066 GTK_TREE_MODEL_SORT (s_model), s_path); 01067 if (!f_path) 01068 { 01069 LEAVE("no filter path"); 01070 return NULL; 01071 } 01072 01073 f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model)); 01074 path = gtk_tree_model_filter_convert_path_to_child_path ( 01075 GTK_TREE_MODEL_FILTER (f_model), f_path); 01076 gtk_tree_path_free(f_path); 01077 if (!path) 01078 { 01079 LEAVE("no path"); 01080 return NULL; 01081 } 01082 01083 model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model)); 01084 if (!gtk_tree_model_get_iter (model, &iter, path)) 01085 { 01086 LEAVE("no iter"); 01087 return NULL; 01088 } 01089 01090 account = iter.user_data; 01091 gtk_tree_path_free(path); 01092 LEAVE("account %p (%s)", account, xaccAccountGetName (account)); 01093 return account; 01094 } 01095 01096 01097 Account * 01098 gnc_tree_view_account_get_account_from_iter (GtkTreeModel *s_model, 01099 GtkTreeIter *s_iter) 01100 { 01101 GtkTreeModel *model, *f_model; 01102 GtkTreeIter iter, f_iter; 01103 Account *account; 01104 01105 g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT(s_model), NULL); 01106 g_return_val_if_fail (s_iter != NULL, NULL); 01107 01108 ENTER("model %p, iter %p", s_model, s_iter); 01109 01110 gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT(s_model), 01111 &f_iter, 01112 s_iter); 01113 f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model)); 01114 gtk_tree_model_filter_convert_iter_to_child_iter ( 01115 GTK_TREE_MODEL_FILTER(f_model), &iter, &f_iter); 01116 model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model)); 01117 account = gnc_tree_model_account_get_account ( 01118 GNC_TREE_MODEL_ACCOUNT(model), &iter); 01119 LEAVE("account %p (%s)", account, xaccAccountGetName (account)); 01120 return account; 01121 } 01122 01123 01124 /* 01125 * Retrieve the selected account from an account tree view. The 01126 * account tree must be in single selection mode. 01127 */ 01128 Account * 01129 gnc_tree_view_account_get_selected_account (GncTreeViewAccount *view) 01130 { 01131 GtkTreeSelection *selection; 01132 GtkTreeModel *f_model, *s_model; 01133 GtkTreeIter iter, f_iter, s_iter; 01134 Account *account; 01135 GtkSelectionMode mode; 01136 01137 ENTER("view %p", view); 01138 g_return_val_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view), NULL); 01139 01140 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view)); 01141 mode = gtk_tree_selection_get_mode(selection); 01142 if ((mode != GTK_SELECTION_SINGLE) && (mode != GTK_SELECTION_BROWSE)) 01143 { 01144 return NULL; 01145 } 01146 if (!gtk_tree_selection_get_selected (selection, &s_model, &s_iter)) 01147 { 01148 LEAVE("no account, get_selected failed"); 01149 return FALSE; 01150 } 01151 01152 gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model), 01153 &f_iter, &s_iter); 01154 01155 f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model)); 01156 gtk_tree_model_filter_convert_iter_to_child_iter ( 01157 GTK_TREE_MODEL_FILTER (f_model), &iter, &f_iter); 01158 01159 account = iter.user_data; 01160 LEAVE("account %p (%s)", account, xaccAccountGetName (account)); 01161 return account; 01162 } 01163 01164 /* 01165 * Selects a single account in the account tree view. The account 01166 * tree must be in single selection mode. 01167 */ 01168 void 01169 gnc_tree_view_account_set_selected_account (GncTreeViewAccount *view, 01170 Account *account) 01171 { 01172 GtkTreeModel *model, *f_model, *s_model; 01173 GtkTreePath *path, *f_path, *s_path, *parent_path; 01174 GtkTreeSelection *selection; 01175 01176 ENTER("view %p, account %p (%s)", view, 01177 account, xaccAccountGetName (account)); 01178 g_return_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view)); 01179 01180 /* Clear any existing selection. */ 01181 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); 01182 gtk_tree_selection_unselect_all (selection); 01183 01184 if (account == NULL) 01185 return; 01186 01187 s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view)); 01188 f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model)); 01189 model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model)); 01190 01191 path = gnc_tree_model_account_get_path_from_account ( 01192 GNC_TREE_MODEL_ACCOUNT(model), account); 01193 if (path == NULL) 01194 { 01195 LEAVE("no path"); 01196 return; 01197 } 01198 debug_path(DEBUG, path); 01199 01200 f_path = gtk_tree_model_filter_convert_child_path_to_path ( 01201 GTK_TREE_MODEL_FILTER (f_model), path); 01202 gtk_tree_path_free(path); 01203 if (f_path == NULL) 01204 { 01205 LEAVE("no filter path"); 01206 return; 01207 } 01208 debug_path(DEBUG, f_path); 01209 01210 s_path = gtk_tree_model_sort_convert_child_path_to_path (GTK_TREE_MODEL_SORT (s_model), 01211 f_path); 01212 gtk_tree_path_free(f_path); 01213 if (s_path == NULL) 01214 { 01215 LEAVE("no sort path"); 01216 return; 01217 } 01218 01219 /* gtk_tree_view requires that a row be visible before it can be selected */ 01220 parent_path = gtk_tree_path_copy (s_path); 01221 if (gtk_tree_path_up (parent_path)) 01222 { 01223 /* This function is misnamed. It expands the actual item 01224 * specified, not the path to the item specified. I.E. It expands 01225 * one level too many, thus the get of the parent. */ 01226 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(view), parent_path); 01227 } 01228 gtk_tree_path_free(parent_path); 01229 01230 gtk_tree_selection_select_path (selection, s_path); 01231 01232 /* give gtk+ a chance to resize the tree view first by handling pending 01233 * configure events */ 01234 while (gtk_events_pending ()) 01235 gtk_main_iteration (); 01236 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW(view), s_path, NULL, FALSE, 0.0, 0.0); 01237 debug_path(LEAVE, s_path); 01238 gtk_tree_path_free(s_path); 01239 } 01240 01241 /* Information re selection process */ 01242 typedef struct 01243 { 01244 GList* return_list; 01245 GncTreeViewAccountPrivate* priv; 01246 } GncTreeViewSelectionInfo; 01247 01248 /* 01249 * This helper function is called once for each row in the tree view 01250 * that is currently selected. Its task is to append the corresponding 01251 * account to the end of a glist. 01252 */ 01253 static void 01254 get_selected_accounts_helper (GtkTreeModel *s_model, 01255 GtkTreePath *s_path, 01256 GtkTreeIter *s_iter, 01257 gpointer data) 01258 { 01259 GncTreeViewSelectionInfo *gtvsi = data; 01260 GtkTreeModel *f_model; 01261 GtkTreeIter iter, f_iter; 01262 Account *account; 01263 01264 gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model), 01265 &f_iter, s_iter); 01266 01267 f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model)); 01268 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (f_model), 01269 &iter, &f_iter); 01270 account = iter.user_data; 01271 01272 /* Only selected if it passes the filter */ 01273 if (gtvsi->priv->filter_fn == NULL || gtvsi->priv->filter_fn(account, gtvsi->priv->filter_data)) 01274 { 01275 gtvsi->return_list = g_list_append(gtvsi->return_list, account); 01276 } 01277 } 01278 01279 /* 01280 * Given an account tree view, return a list of the selected accounts. The 01281 * account tree must be in multiple selection mode. 01282 * 01283 * Note: It is the responsibility of the caller to free the returned 01284 * list. 01285 */ 01286 GList * 01287 gnc_tree_view_account_get_selected_accounts (GncTreeViewAccount *view) 01288 { 01289 GtkTreeSelection *selection; 01290 GncTreeViewSelectionInfo info; 01291 01292 g_return_val_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view), NULL); 01293 01294 info.return_list = NULL; 01295 info.priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(view); 01296 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view)); 01297 gtk_tree_selection_selected_foreach(selection, get_selected_accounts_helper, &info); 01298 return info.return_list; 01299 } 01300 01301 /* 01302 * Given an account tree view and a list of accounts, select those 01303 * accounts in the tree view. 01304 */ 01305 void 01306 gnc_tree_view_account_set_selected_accounts (GncTreeViewAccount *view, 01307 GList *account_list, 01308 gboolean show_last) 01309 { 01310 GtkTreeModel *model, *f_model, *s_model; 01311 GtkTreePath *path, *f_path, *s_path, *parent_path; 01312 GtkTreeSelection *selection; 01313 GList *element; 01314 Account *account; 01315 01316 g_return_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view)); 01317 01318 s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view)); 01319 f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model)); 01320 model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model)); 01321 01322 /* Clear any existing selection. */ 01323 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); 01324 gtk_tree_selection_unselect_all (selection); 01325 gtk_tree_view_collapse_all (GTK_TREE_VIEW(view)); 01326 01327 /* Now go select what the user requested. */ 01328 for (element = account_list; element; ) 01329 { 01330 account = element->data; 01331 element = g_list_next(element); 01332 01333 path = gnc_tree_model_account_get_path_from_account (GNC_TREE_MODEL_ACCOUNT(model), account); 01334 if (path == NULL) 01335 { 01336 /* 01337 * Oops. Someone must have deleted this account and not cleaned 01338 * up all references to it. 01339 */ 01340 continue; 01341 } 01342 01343 f_path = gtk_tree_model_filter_convert_child_path_to_path (GTK_TREE_MODEL_FILTER (f_model), 01344 path); 01345 gtk_tree_path_free(path); 01346 if (f_path == NULL) 01347 continue; 01348 01349 s_path = gtk_tree_model_sort_convert_child_path_to_path (GTK_TREE_MODEL_SORT (s_model), 01350 f_path); 01351 gtk_tree_path_free(f_path); 01352 if (s_path == NULL) 01353 continue; 01354 01355 /* gtk_tree_view requires that a row be visible before it can be selected */ 01356 parent_path = gtk_tree_path_copy (s_path); 01357 if (gtk_tree_path_up (parent_path)) 01358 { 01359 /* This function is misnamed. It expands the actual item 01360 * specified, not the path to the item specified. I.E. It 01361 * expands one level too many, thus the get of the parent. */ 01362 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(view), parent_path); 01363 } 01364 gtk_tree_path_free(parent_path); 01365 01366 gtk_tree_selection_select_path (selection, s_path); 01367 if (show_last && (element == NULL)) 01368 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW(view), s_path, NULL, FALSE, 0.0, 0.0); 01369 gtk_tree_path_free(s_path); 01370 } 01371 } 01372 01373 /* 01374 * Selects all sub-accounts of an acccount. 01375 */ 01376 void 01377 gnc_tree_view_account_select_subaccounts (GncTreeViewAccount *view, 01378 Account *account) 01379 { 01380 GtkTreeModel *s_model; 01381 GtkTreeSelection *selection; 01382 GtkTreePath *sp_account, *sp_start, *sp_end; 01383 GtkTreeIter si_account, si_start, si_end; 01384 gboolean have_start, have_end; 01385 gint num_children; 01386 01387 ENTER("view %p, account %p (%s)", view, account, xaccAccountGetName(account)); 01388 01389 g_return_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view)); 01390 01391 if (account == NULL) 01392 { 01393 LEAVE("no account"); 01394 return; 01395 } 01396 01397 if (!gnc_tree_view_account_get_iter_from_account (view, account, &si_account)) 01398 { 01399 LEAVE("view_get_iter_from_account failed"); 01400 return; 01401 } 01402 01403 /* Any children? */ 01404 s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view)); 01405 num_children = gtk_tree_model_iter_n_children(s_model, &si_account); 01406 if (num_children == 0) 01407 { 01408 LEAVE("no children"); 01409 return; 01410 } 01411 01412 /* Expand the tree. Required for selection to work */ 01413 sp_account = gtk_tree_model_get_path (s_model, &si_account); 01414 gtk_tree_view_expand_row (GTK_TREE_VIEW(view), sp_account, TRUE); 01415 01416 /* compute start/end paths */ 01417 have_start = gtk_tree_model_iter_nth_child(s_model, &si_start, &si_account, 0); 01418 si_end = si_account; 01419 while (num_children) 01420 { 01421 GtkTreeIter tmp_iter = si_end; 01422 have_end = gtk_tree_model_iter_nth_child(s_model, &si_end, &tmp_iter, 01423 num_children - 1); 01424 if (have_end) 01425 num_children = gtk_tree_model_iter_n_children(s_model, &si_end); 01426 else 01427 num_children = 0; 01428 } 01429 01430 if (have_start && have_end) 01431 { 01432 sp_start = gtk_tree_model_get_path (s_model, &si_start); 01433 sp_end = gtk_tree_model_get_path (s_model, &si_end); 01434 01435 /* select everything between */ 01436 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); 01437 gtk_tree_selection_select_range (selection, sp_start, sp_end); 01438 01439 /* clean up */ 01440 gtk_tree_path_free(sp_start); 01441 gtk_tree_path_free(sp_end); 01442 } 01443 gtk_tree_path_free(sp_account); 01444 LEAVE(" "); 01445 return; 01446 } 01447 01448 void 01449 gnc_tree_view_account_expand_to_account (GncTreeViewAccount *view, 01450 Account *account) 01451 { 01452 GtkTreePath *path; 01453 01454 g_return_if_fail(view != NULL); 01455 g_return_if_fail(GNC_IS_TREE_VIEW_ACCOUNT(view)); 01456 ENTER("view %p, account %p", view, account); 01457 01458 path = gnc_tree_view_account_get_path_from_account(view, account); 01459 if (path) 01460 { 01461 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(view), path); 01462 gtk_tree_path_free(path); 01463 } 01464 LEAVE(" "); 01465 } 01466 01467 01468 /* 01469 * Retrieve the account currently under the cursor. 01470 */ 01471 Account * 01472 gnc_tree_view_account_get_cursor_account (GncTreeViewAccount *view) 01473 { 01474 GtkTreeModel *s_model; 01475 GtkTreePath *s_path; 01476 Account *account; 01477 01478 ENTER("view %p", view); 01479 g_return_val_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view), NULL); 01480 01481 s_model = gtk_tree_view_get_model (GTK_TREE_VIEW(view)); 01482 gtk_tree_view_get_cursor (GTK_TREE_VIEW(view), &s_path, NULL); 01483 if (!s_path) 01484 { 01485 LEAVE("no account"); 01486 return NULL; 01487 } 01488 01489 account = gnc_tree_view_account_get_account_from_path (view, s_path); 01490 gtk_tree_path_free(s_path); 01491 LEAVE("account %p (%s)", account, xaccAccountGetName (account)); 01492 return account; 01493 } 01494 01495 01496 /************************************************************/ 01497 /* Account Tree View Add Column Functions */ 01498 /************************************************************/ 01499 01500 static void 01501 gtva_update_column_name (GtkTreeViewColumn *column, 01502 const gchar *fmt, 01503 const gchar *mnemonic) 01504 { 01505 gchar *name; 01506 01507 g_return_if_fail(column); 01508 01509 name = g_strdup_printf(fmt, mnemonic); 01510 gtk_tree_view_column_set_title(column, name); 01511 g_free(name); 01512 } 01513 01514 01515 static void 01516 gtva_update_column_names (GncTreeView *view) 01517 { 01518 GncTreeViewAccountPrivate *priv; 01519 const gchar *mnemonic; 01520 01521 priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(view); 01522 mnemonic = gnc_commodity_get_mnemonic(gnc_default_report_currency()); 01523 01524 gtva_update_column_name(priv->present_report_column, 01525 /* Translators: %s is a currency mnemonic.*/ 01526 _("Present (%s)"), mnemonic); 01527 gtva_update_column_name(priv->balance_report_column, 01528 /* Translators: %s is a currency mnemonic.*/ 01529 _("Balance (%s)"), mnemonic); 01530 gtva_update_column_name(priv->cleared_report_column, 01531 /* Translators: %s is a currency mnemonic.*/ 01532 _("Cleared (%s)"), mnemonic); 01533 gtva_update_column_name(priv->reconciled_report_column, 01534 /* Translators: %s is a currency mnemonic.*/ 01535 _("Reconciled (%s)"), mnemonic); 01536 gtva_update_column_name(priv->future_min_report_column, 01537 /* Translators: %s is a currency mnemonic.*/ 01538 _("Future Minimum (%s)"), mnemonic); 01539 gtva_update_column_name(priv->total_report_column, 01540 /* Translators: %s is a currency mnemonic.*/ 01541 _("Total (%s)"), mnemonic); 01542 gnc_tree_view_set_show_column_menu(view, FALSE); 01543 gnc_tree_view_set_show_column_menu(view, TRUE); 01544 } 01545 01546 01547 static void 01548 gtva_currency_changed_cb (void) 01549 { 01550 const GList *views, *ptr; 01551 01552 views = gnc_gobject_tracking_get_list (GNC_TREE_VIEW_ACCOUNT_NAME); 01553 for (ptr = views; ptr; ptr = g_list_next(ptr)) 01554 { 01555 gtva_update_column_names (ptr->data); 01556 } 01557 } 01558 /* This function implements a custom mapping between an account's KVP 01559 * and the cell renderer's 'text' property. */ 01560 static void 01561 account_cell_kvp_data_func (GtkTreeViewColumn *tree_column, 01562 GtkCellRenderer *cell, 01563 GtkTreeModel *s_model, 01564 GtkTreeIter *s_iter, 01565 gpointer key) 01566 { 01567 Account *account; 01568 kvp_frame * frame; 01569 01570 g_return_if_fail (GTK_IS_TREE_MODEL_SORT (s_model)); 01571 account = gnc_tree_view_account_get_account_from_iter(s_model, s_iter); 01572 frame = xaccAccountGetSlots(account); 01573 01574 g_object_set (G_OBJECT (cell), 01575 "text", kvp_frame_get_string(frame, (gchar *)key), 01576 "xalign", 0.0, 01577 NULL); 01578 01579 } 01580 01581 01582 GtkTreeViewColumn * 01583 gnc_tree_view_account_add_kvp_column (GncTreeViewAccount *view, 01584 const gchar *column_title, 01585 const gchar *kvp_key) 01586 { 01587 GtkCellRenderer *renderer; 01588 GtkTreeViewColumn *column; 01589 01590 g_return_val_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view), NULL); 01591 g_return_val_if_fail (kvp_key != NULL, NULL); 01592 01593 column = gnc_tree_view_add_text_column(GNC_TREE_VIEW(view), column_title, 01594 kvp_key, NULL, "Sample text", 01595 -1, -1, NULL); 01596 01597 /* This new kvp column has only had one renderer added to it so 01598 * far. Find that renderer. */ 01599 renderer = gnc_tree_view_column_get_renderer(column); 01600 g_object_set (G_OBJECT (renderer), "xalign", 1.0, NULL); 01601 01602 gtk_tree_view_column_set_cell_data_func (column, renderer, 01603 account_cell_kvp_data_func, 01604 g_strdup(kvp_key), g_free); 01605 return column; 01606 } 01607 01608 static void col_edited_helper(GtkCellRendererText *cell, gchar *path_string, 01609 gchar *new_text, gpointer _s_model) 01610 { 01611 Account *account; 01612 GtkTreeModel *s_model; 01613 GtkTreeIter s_iter; 01614 GncTreeViewAccountColumnTextEdited col_edited_cb; 01615 GtkTreeViewColumn *col; 01616 01617 col_edited_cb = g_object_get_data(G_OBJECT(cell), 01618 "column_edited_callback"); 01619 col = GTK_TREE_VIEW_COLUMN(g_object_get_data(G_OBJECT(cell), 01620 "column_view")); 01621 s_model = GTK_TREE_MODEL(_s_model); 01622 01623 if (!gtk_tree_model_get_iter_from_string(s_model, &s_iter, path_string)) 01624 return; 01625 01626 account = gnc_tree_view_account_get_account_from_iter(s_model, &s_iter); 01627 col_edited_cb(account, col, new_text); 01628 } 01629 01630 static void col_source_helper(GtkTreeViewColumn *col, GtkCellRenderer *cell, 01631 GtkTreeModel *s_model, GtkTreeIter *s_iter, 01632 gpointer _col_source_cb) 01633 { 01634 Account *account; 01635 gchar *text; 01636 GncTreeViewAccountColumnSource col_source_cb; 01637 01638 g_return_if_fail (GTK_IS_TREE_MODEL_SORT (s_model)); 01639 col_source_cb = (GncTreeViewAccountColumnSource) _col_source_cb; 01640 account = gnc_tree_view_account_get_account_from_iter(s_model, s_iter); 01641 text = col_source_cb(account, col, cell); 01642 g_object_set (G_OBJECT (cell), "text", text, "xalign", 1.0, NULL); 01643 g_free(text); 01644 } 01645 01650 void 01651 gtva_setup_column_renderer_edited_cb(GncTreeViewAccount *account_view, 01652 GtkTreeViewColumn *column, 01653 GtkCellRenderer *renderer, 01654 GncTreeViewAccountColumnTextEdited col_edited_cb) 01655 { 01656 GtkTreeModel *s_model; 01657 01658 if (col_edited_cb == NULL) 01659 { 01660 g_object_set(G_OBJECT(renderer), "editable", FALSE, NULL); 01661 g_object_set_data(G_OBJECT(renderer), "column_edited_callback", col_edited_cb); 01662 s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(account_view)); 01663 g_signal_handlers_disconnect_by_func(G_OBJECT(renderer), col_edited_cb, s_model); 01664 g_object_set_data(G_OBJECT(renderer), "column_view", column); 01665 } 01666 else 01667 { 01668 g_object_set(G_OBJECT(renderer), "editable", TRUE, NULL); 01669 g_object_set_data(G_OBJECT(renderer), "column_edited_callback", 01670 col_edited_cb); 01671 s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(account_view)); 01672 g_signal_connect(G_OBJECT(renderer), "edited", 01673 (GCallback) col_edited_helper, s_model); 01674 g_object_set_data(G_OBJECT(renderer), "column_view", column); 01675 } 01676 } 01677 01678 GtkTreeViewColumn * 01679 gnc_tree_view_account_add_custom_column(GncTreeViewAccount *account_view, 01680 const gchar *column_title, 01681 GncTreeViewAccountColumnSource 01682 col_source_cb, 01683 GncTreeViewAccountColumnTextEdited 01684 col_edited_cb) 01685 { 01686 GtkCellRenderer *renderer; 01687 GtkTreeViewColumn *column; 01688 01689 g_return_val_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (account_view), NULL); 01690 01691 renderer = gtk_cell_renderer_text_new (); 01692 g_object_set (G_OBJECT (renderer), "xalign", 1.0, NULL); 01693 01694 column = gtk_tree_view_column_new_with_attributes (column_title, 01695 renderer, NULL); 01696 if (col_edited_cb) 01697 { 01698 gtva_setup_column_renderer_edited_cb(account_view, column, 01699 renderer, col_edited_cb); 01700 } 01701 gtk_tree_view_column_set_cell_data_func (column, renderer, 01702 col_source_helper, 01703 col_source_cb, NULL); 01704 gnc_tree_view_append_column (GNC_TREE_VIEW(account_view), column); 01705 return column; 01706 } 01707 01708 01709 /* BEGIN FILTER FUNCTIONS */ 01710 #define FILTER_TREE_VIEW "types_tree_view" 01711 01723 gboolean 01724 gnc_plugin_page_account_tree_filter_accounts (Account *account, 01725 gpointer user_data) 01726 { 01727 AccountFilterDialog *fd = user_data; 01728 GNCAccountType acct_type; 01729 gnc_numeric total; 01730 gboolean result; 01731 01732 ENTER("account %p:%s", account, xaccAccountGetName(account)); 01733 01734 if (!fd->show_hidden && xaccAccountIsHidden (account)) 01735 { 01736 LEAVE(" hide: hidden"); 01737 return FALSE; 01738 } 01739 01740 if (!fd->show_zero_total) 01741 { 01742 total = xaccAccountGetBalanceInCurrency (account, NULL, TRUE); 01743 if (gnc_numeric_zero_p(total)) 01744 { 01745 LEAVE(" hide: zero balance"); 01746 return FALSE; 01747 } 01748 } 01749 01750 acct_type = xaccAccountGetType(account); 01751 result = (fd->visible_types & (1 << acct_type)) ? TRUE : FALSE; 01752 LEAVE(" %s", result ? "show" : "hide"); 01753 return result; 01754 } 01755 01763 void 01764 gppat_filter_show_hidden_toggled_cb (GtkToggleButton *button, 01765 AccountFilterDialog *fd) 01766 { 01767 g_return_if_fail(GTK_IS_TOGGLE_BUTTON(button)); 01768 01769 ENTER("button %p", button); 01770 fd->show_hidden = gtk_toggle_button_get_active(button); 01771 gnc_tree_view_account_refilter(fd->tree_view); 01772 LEAVE("show_hidden %d", fd->show_hidden); 01773 } 01774 01782 void 01783 gppat_filter_show_zero_toggled_cb (GtkToggleButton *button, 01784 AccountFilterDialog *fd) 01785 { 01786 g_return_if_fail(GTK_IS_TOGGLE_BUTTON(button)); 01787 01788 ENTER("button %p", button); 01789 fd->show_zero_total = gtk_toggle_button_get_active(button); 01790 gnc_tree_view_account_refilter(fd->tree_view); 01791 LEAVE("show_zero %d", fd->show_zero_total); 01792 } 01793 01802 void 01803 gppat_filter_clear_all_cb (GtkWidget *button, 01804 AccountFilterDialog *fd) 01805 { 01806 g_return_if_fail(GTK_IS_BUTTON(button)); 01807 01808 ENTER("button %p", button); 01809 fd->visible_types = 0; 01810 gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(fd->model)); 01811 gnc_tree_view_account_refilter(fd->tree_view); 01812 LEAVE("types 0x%x", fd->visible_types); 01813 } 01814 01821 void 01822 gppat_filter_select_all_cb (GtkWidget *button, 01823 AccountFilterDialog *fd) 01824 { 01825 g_return_if_fail(GTK_IS_BUTTON(button)); 01826 01827 ENTER("button %p", button); 01828 fd->visible_types = -1; 01829 gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(fd->model)); 01830 gnc_tree_view_account_refilter(fd->tree_view); 01831 LEAVE("types 0x%x", fd->visible_types); 01832 } 01833 01862 static void 01863 gppat_filter_visible_set_func (GtkTreeViewColumn *column, 01864 GtkCellRenderer *renderer, 01865 GtkTreeModel *model, 01866 GtkTreeIter *iter, 01867 gpointer data) 01868 { 01869 AccountFilterDialog *fd = data; 01870 GNCAccountType type; 01871 gboolean active; 01872 01873 gtk_tree_model_get(model, iter, GNC_TREE_MODEL_ACCOUNT_TYPES_COL_TYPE, &type, -1); 01874 01875 active = (fd->visible_types & (1 << type)) ? TRUE : FALSE; 01876 g_object_set (G_OBJECT (renderer), "active", active, NULL); 01877 } 01878 01884 static void 01885 gppat_filter_visible_toggled_cb (GtkCellRendererToggle *renderer, 01886 gchar *path_str, 01887 AccountFilterDialog *fd) 01888 { 01889 GtkTreeModel *model = fd->model; 01890 GtkTreeIter iter; 01891 GtkTreePath *path; 01892 GNCAccountType type; 01893 01894 ENTER("toggled %p", path_str); 01895 path = gtk_tree_path_new_from_string(path_str); 01896 01897 if (gtk_tree_model_get_iter(model, &iter, path)) 01898 { 01899 gtk_tree_model_get(model, &iter, GNC_TREE_MODEL_ACCOUNT_TYPES_COL_TYPE, &type, -1); 01900 fd->visible_types ^= (1 << type); 01901 gnc_tree_view_account_refilter(fd->tree_view); 01902 } 01903 gtk_tree_path_free(path); 01904 LEAVE("types 0x%x", fd->visible_types); 01905 } 01906 01917 void 01918 gppat_filter_response_cb (GtkWidget *dialog, 01919 gint response, 01920 AccountFilterDialog *fd) 01921 { 01922 gpointer gptemp; 01923 01924 g_return_if_fail(GTK_IS_DIALOG(dialog)); 01925 01926 ENTER("dialog %p, response %d", dialog, response); 01927 01928 if (response != GTK_RESPONSE_OK) 01929 { 01930 fd->visible_types = fd->original_visible_types; 01931 fd->show_hidden = fd->original_show_hidden; 01932 fd->show_zero_total = fd->original_show_zero_total; 01933 gnc_tree_view_account_refilter(fd->tree_view); 01934 } 01935 01936 /* Clean up and delete dialog */ 01937 gptemp = (gpointer *)fd->dialog; 01938 g_atomic_pointer_compare_and_exchange(&gptemp, 01939 dialog, NULL); 01940 fd->dialog = gptemp; 01941 gtk_widget_destroy(dialog); 01942 LEAVE("types 0x%x", fd->visible_types); 01943 } 01944 01945 void 01946 account_filter_dialog_create(AccountFilterDialog *fd, GncPluginPage *page) 01947 { 01948 GtkWidget *dialog, *button; 01949 GtkTreeView *view; 01950 GtkCellRenderer *renderer; 01951 GtkBuilder *builder; 01952 gchar *title; 01953 01954 ENTER("(fd %p, page %p)", fd, page); 01955 01956 if (fd->dialog) 01957 { 01958 gtk_window_present(GTK_WINDOW(fd->dialog)); 01959 LEAVE("existing dialog"); 01960 return; 01961 } 01962 01963 /* Create the dialog */ 01964 builder = gtk_builder_new(); 01965 gnc_builder_add_from_file (builder, "dialog-account.glade", "Filter By"); 01966 dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Filter By")); 01967 fd->dialog = dialog; 01968 gtk_window_set_transient_for(GTK_WINDOW(dialog), 01969 GTK_WINDOW(GNC_PLUGIN_PAGE(page)->window)); 01970 /* Translators: The %s is the name of the plugin page */ 01971 title = g_strdup_printf(_("Filter %s by..."), 01972 gnc_plugin_page_get_page_name(GNC_PLUGIN_PAGE(page))); 01973 gtk_window_set_title(GTK_WINDOW(dialog), title); 01974 g_free(title); 01975 01976 /* Remember current state */ 01977 fd->original_visible_types = fd->visible_types; 01978 fd->original_show_hidden = fd->show_hidden; 01979 fd->original_show_zero_total = fd->show_zero_total; 01980 01981 /* Update the dialog widgets for the current state */ 01982 button = GTK_WIDGET(gtk_builder_get_object (builder, "show_hidden")); 01983 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), 01984 fd->show_hidden); 01985 button = GTK_WIDGET(gtk_builder_get_object (builder, "show_zero")); 01986 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), 01987 fd->show_zero_total); 01988 01989 /* Set up the tree view and model */ 01990 view = GTK_TREE_VIEW(gtk_builder_get_object (builder, FILTER_TREE_VIEW)); 01991 01992 fd->model = gnc_tree_model_account_types_filter_using_mask 01993 (~(1 << ACCT_TYPE_ROOT)); 01994 gtk_tree_view_set_model(view, fd->model); 01995 g_object_unref (fd->model); 01996 01997 renderer = gtk_cell_renderer_toggle_new(); 01998 01999 g_signal_connect(renderer, "toggled", 02000 G_CALLBACK(gppat_filter_visible_toggled_cb), fd); 02001 02002 gtk_tree_view_insert_column_with_data_func 02003 (view, 02004 -1, NULL, renderer, 02005 gppat_filter_visible_set_func, fd, NULL); 02006 02007 gtk_tree_view_insert_column_with_attributes 02008 (view, 02009 -1, _("Account Types"), gtk_cell_renderer_text_new(), 02010 "text", GNC_TREE_MODEL_ACCOUNT_TYPES_COL_NAME, NULL); 02011 02012 /* Wire up the rest of the callbacks */ 02013 gtk_builder_connect_signals(builder, fd); 02014 g_object_unref(G_OBJECT(builder)); 02015 02016 /* Show it */ 02017 gtk_widget_show_all(dialog); 02018 LEAVE(" "); 02019 } 02020 02021 #define ACCT_COUNT "NumberOfOpenAccounts" 02022 #define ACCT_OPEN "OpenAccount%d" 02023 #define ACCT_SELECTED "SelectedAccount" 02024 #define SHOW_HIDDEN "ShowHidden" 02025 #define SHOW_ZERO "ShowZeroTotal" 02026 #define ACCT_TYPES "AccountTypes" 02027 02028 typedef struct foo 02029 { 02030 GKeyFile *key_file; 02031 const gchar *group_name; 02032 int count; 02033 } bar_t; 02034 02046 static void 02047 tree_save_expanded_row (GncTreeViewAccount *view, 02048 GtkTreePath *path, 02049 gpointer user_data) 02050 { 02051 Account *account; 02052 bar_t *bar = user_data; 02053 gchar *key; 02054 gchar *account_name; 02055 02056 account = gnc_tree_view_account_get_account_from_path (view, path); 02057 if (account == NULL) 02058 return; 02059 02060 account_name = gnc_account_get_full_name(account); 02061 if (account_name == NULL) 02062 return; 02063 02064 key = g_strdup_printf(ACCT_OPEN, ++bar->count); 02065 g_key_file_set_string(bar->key_file, bar->group_name, key, account_name); 02066 g_free(key); 02067 g_free(account_name); 02068 } 02069 02070 02081 static void 02082 tree_save_selected_row (GncTreeViewAccount *view, 02083 gpointer user_data) 02084 { 02085 Account *account; 02086 bar_t *bar = user_data; 02087 gchar *account_name; 02088 02089 account = gnc_tree_view_account_get_selected_account(view); 02090 if (account == NULL) 02091 return; 02092 02093 account_name = gnc_account_get_full_name (account); 02094 if (account_name == NULL) 02095 return; 02096 02097 g_key_file_set_string(bar->key_file, bar->group_name, ACCT_SELECTED, 02098 account_name); 02099 g_free(account_name); 02100 } 02101 02102 void 02103 gnc_tree_view_account_save(GncTreeViewAccount *view, 02104 AccountFilterDialog *fd, 02105 GKeyFile *key_file, const gchar *group_name) 02106 { 02107 bar_t bar; 02108 02109 g_return_if_fail (key_file != NULL); 02110 g_return_if_fail (group_name != NULL); 02111 02112 ENTER("view %p, key_file %p, group_name %s", view, key_file, 02113 group_name); 02114 02115 g_key_file_set_integer(key_file, group_name, ACCT_TYPES, 02116 fd->visible_types); 02117 g_key_file_set_boolean(key_file, group_name, SHOW_HIDDEN, 02118 fd->show_hidden); 02119 g_key_file_set_boolean(key_file, group_name, SHOW_ZERO, 02120 fd->show_zero_total); 02121 02122 bar.key_file = key_file; 02123 bar.group_name = group_name; 02124 bar.count = 0; 02125 tree_save_selected_row(view, &bar); 02126 gtk_tree_view_map_expanded_rows( 02127 GTK_TREE_VIEW(view), (GtkTreeViewMappingFunc) tree_save_expanded_row, 02128 &bar); 02129 g_key_file_set_integer(key_file, group_name, ACCT_COUNT, bar.count); 02130 LEAVE(" "); 02131 02132 } 02133 02141 static void 02142 tree_restore_expanded_row (GncTreeViewAccount *view, 02143 const gchar *account_name) 02144 { 02145 Account *account; 02146 QofBook *book; 02147 02148 book = qof_session_get_book(gnc_get_current_session()); 02149 account = gnc_account_lookup_by_full_name(gnc_book_get_root_account(book), 02150 account_name); 02151 if (account) 02152 gnc_tree_view_account_expand_to_account(view, account); 02153 } 02154 02155 02163 static void 02164 tree_restore_selected_row (GncTreeViewAccount *view, 02165 const gchar *account_name) 02166 { 02167 Account *account; 02168 QofBook *book; 02169 02170 book = qof_session_get_book(gnc_get_current_session()); 02171 account = gnc_account_lookup_by_full_name(gnc_book_get_root_account(book), 02172 account_name); 02173 if (account) 02174 gnc_tree_view_account_set_selected_account(view, account); 02175 } 02176 02177 void 02178 gnc_tree_view_account_restore(GncTreeViewAccount *view, 02179 AccountFilterDialog *fd, 02180 GKeyFile *key_file, const gchar *group_name) 02181 { 02182 GError *error = NULL; 02183 gchar *key, *value; 02184 gint i, count; 02185 gboolean show; 02186 02187 /* Filter information. Ignore missing keys. */ 02188 show = g_key_file_get_boolean(key_file, group_name, SHOW_HIDDEN, &error); 02189 if (error) 02190 { 02191 g_warning("error reading group %s key %s: %s", 02192 group_name, SHOW_HIDDEN, error->message); 02193 g_error_free(error); 02194 error = NULL; 02195 show = TRUE; 02196 } 02197 fd->show_hidden = show; 02198 02199 show = g_key_file_get_boolean(key_file, group_name, SHOW_ZERO, &error); 02200 if (error) 02201 { 02202 g_warning("error reading group %s key %s: %s", 02203 group_name, SHOW_ZERO, error->message); 02204 g_error_free(error); 02205 error = NULL; 02206 show = TRUE; 02207 } 02208 fd->show_zero_total = show; 02209 02210 i = g_key_file_get_integer(key_file, group_name, ACCT_TYPES, &error); 02211 if (error) 02212 { 02213 g_warning("error reading group %s key %s: %s", 02214 group_name, ACCT_TYPES, error->message); 02215 g_error_free(error); 02216 error = NULL; 02217 i = -1; 02218 } 02219 fd->visible_types = i; 02220 02221 /* Expanded accounts. Skip if count key missing. */ 02222 count = g_key_file_get_integer(key_file, group_name, ACCT_COUNT, &error); 02223 if (error == NULL) 02224 { 02225 for (i = 1; i <= count; i++) 02226 { 02227 key = g_strdup_printf(ACCT_OPEN, i); 02228 value = g_key_file_get_string(key_file, group_name, key, &error); 02229 if (error) 02230 { 02231 g_warning("error reading group %s key %s: %s", 02232 group_name, key, error->message); 02233 g_error_free(error); 02234 error = NULL; 02235 } 02236 else 02237 { 02238 tree_restore_expanded_row(view, value); 02239 g_free(value); 02240 } 02241 g_free(key); 02242 } 02243 } 02244 else 02245 { 02246 g_warning("error reading group %s key %s: %s", 02247 group_name, ACCT_COUNT, error->message); 02248 g_error_free(error); 02249 } 02250 02251 /* Selected account (if any) */ 02252 value = g_key_file_get_string(key_file, group_name, ACCT_SELECTED, NULL); 02253 if (value) 02254 { 02255 tree_restore_selected_row(view, value); 02256 g_free(value); 02257 } 02258 02259 /* Update tree view for any changes */ 02260 gnc_tree_view_account_refilter(view); 02261 } 02262 02263 // @@fixme -- factor this app-not-gui-specific-logic out. 02264 void 02265 gnc_tree_view_account_name_edited_cb(Account *account, GtkTreeViewColumn *col, const gchar *new_name) 02266 { 02267 // check for accounts with the same name among our parent's children. 02268 // should probably factor this consistency check out to the account 02269 // itself.... 02270 { 02271 Account *parent = gnc_account_get_parent(account); 02272 Account *existing = gnc_account_lookup_by_name(parent, new_name); 02273 if (existing != NULL && existing != account) 02274 { 02275 PERR("account with the same name [%s] already exists.", new_name); 02276 return; 02277 } 02278 } 02279 xaccAccountSetName(account, new_name); 02280 } 02281 02282 void 02283 gnc_tree_view_account_code_edited_cb(Account *account, GtkTreeViewColumn *col, const gchar *new_code) 02284 { 02285 if (safe_strcmp(xaccAccountGetCode(account), new_code) == 0) 02286 return; 02287 xaccAccountSetCode(account, new_code); 02288 } 02289 02290 void 02291 gnc_tree_view_account_description_edited_cb(Account *account, GtkTreeViewColumn *col, const gchar *new_desc) 02292 { 02293 if (safe_strcmp(xaccAccountGetDescription(account), new_desc) == 0) 02294 return; 02295 xaccAccountSetDescription(account, new_desc); 02296 } 02297 02298 void 02299 gnc_tree_view_account_notes_edited_cb(Account *account, GtkTreeViewColumn *col, const gchar *new_notes) 02300 { 02301 if (safe_strcmp(xaccAccountGetNotes(account), new_notes) == 0) 02302 return; 02303 xaccAccountSetNotes(account, new_notes); 02304 } 02305 02306 static void 02307 gtva_set_column_editor(GncTreeViewAccount *view, 02308 GtkTreeViewColumn *column, 02309 GncTreeViewAccountColumnTextEdited edited_cb) 02310 { 02311 GList *renderers_orig, *renderers; 02312 GtkCellRenderer *renderer; 02313 02314 // look for the first text-renderer; on the 0th column of the account tree, 02315 // there are two renderers: pixbuf and text. So find the text one. 02316 for (renderers_orig = renderers = gtk_tree_view_column_get_cell_renderers(column); 02317 renderers && !GTK_IS_CELL_RENDERER_TEXT(renderers->data); 02318 renderers = renderers->next); 02319 renderer = GTK_CELL_RENDERER(renderers->data); 02320 g_list_free(renderers_orig); 02321 g_return_if_fail(renderer != NULL); 02322 gtva_setup_column_renderer_edited_cb(GNC_TREE_VIEW_ACCOUNT(view), column, renderer, edited_cb); 02323 } 02324 02325 void 02326 gnc_tree_view_account_set_name_edited(GncTreeViewAccount *view, 02327 GncTreeViewAccountColumnTextEdited edited_cb) 02328 { 02329 GncTreeViewAccountPrivate *priv; 02330 priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(view); 02331 gtva_set_column_editor(view, priv->name_column, edited_cb); 02332 } 02333 02334 void 02335 gnc_tree_view_account_set_code_edited(GncTreeViewAccount *view, 02336 GncTreeViewAccountColumnTextEdited edited_cb) 02337 { 02338 GncTreeViewAccountPrivate *priv; 02339 priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(view); 02340 gtva_set_column_editor(view, priv->code_column, edited_cb); 02341 } 02342 02343 void 02344 gnc_tree_view_account_set_description_edited(GncTreeViewAccount *view, 02345 GncTreeViewAccountColumnTextEdited edited_cb) 02346 { 02347 GncTreeViewAccountPrivate *priv; 02348 priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(view); 02349 gtva_set_column_editor(view, priv->desc_column, edited_cb); 02350 } 02351 02352 void 02353 gnc_tree_view_account_set_notes_edited(GncTreeViewAccount *view, 02354 GncTreeViewAccountColumnTextEdited edited_cb) 02355 { 02356 GncTreeViewAccountPrivate *priv; 02357 priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(view); 02358 gtva_set_column_editor(view, priv->notes_column, edited_cb); 02359 }
1.7.4