|
GnuCash 2.4.99
|
00001 /* 00002 * gnc-tree-model-account.c -- GtkTreeModel implementation to 00003 * display accounts in a GtkTreeView. 00004 * 00005 * Copyright (C) 2003 Jan Arne Petersen <jpetersen@uni-bonn.de> 00006 * Copyright (C) 2003 David Hampton <hampton@employees.org> 00007 * 00008 * This program is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU General Public License as 00010 * published by the Free Software Foundation; either version 2 of 00011 * the License, or (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, contact: 00020 * 00021 * Free Software Foundation Voice: +1-617-542-5942 00022 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 00023 * Boston, MA 02110-1301, USA gnu@gnu.org 00024 */ 00025 00026 #include "config.h" 00027 00028 #include <gtk/gtk.h> 00029 #include <glib/gi18n.h> 00030 #include <string.h> 00031 00032 #include "gnc-tree-model-account.h" 00033 #include "gnc-component-manager.h" 00034 #include "Account.h" 00035 #include "gnc-accounting-period.h" 00036 #include "gnc-commodity.h" 00037 #include "gnc-gconf-utils.h" 00038 #include "gnc-engine.h" 00039 #include "gnc-event.h" 00040 #include "gnc-gobject-utils.h" 00041 #include "gnc-ui-balances.h" 00042 #include "gnc-ui-util.h" 00043 00044 #define TREE_MODEL_ACCOUNT_CM_CLASS "tree-model-account" 00045 00047 static QofLogModule log_module = GNC_MOD_GUI; 00048 00050 static void gnc_tree_model_account_class_init (GncTreeModelAccountClass *klass); 00051 static void gnc_tree_model_account_init (GncTreeModelAccount *model); 00052 static void gnc_tree_model_account_finalize (GObject *object); 00053 static void gnc_tree_model_account_dispose (GObject *object); 00054 00056 static void gnc_tree_model_account_tree_model_init (GtkTreeModelIface *iface); 00057 static GtkTreeModelFlags gnc_tree_model_account_get_flags (GtkTreeModel *tree_model); 00058 static int gnc_tree_model_account_get_n_columns (GtkTreeModel *tree_model); 00059 static GType gnc_tree_model_account_get_column_type (GtkTreeModel *tree_model, 00060 int index); 00061 static gboolean gnc_tree_model_account_get_iter (GtkTreeModel *tree_model, 00062 GtkTreeIter *iter, 00063 GtkTreePath *path); 00064 static GtkTreePath *gnc_tree_model_account_get_path (GtkTreeModel *tree_model, 00065 GtkTreeIter *iter); 00066 static void gnc_tree_model_account_get_value (GtkTreeModel *tree_model, 00067 GtkTreeIter *iter, 00068 int column, 00069 GValue *value); 00070 static gboolean gnc_tree_model_account_iter_next (GtkTreeModel *tree_model, 00071 GtkTreeIter *iter); 00072 static gboolean gnc_tree_model_account_iter_children (GtkTreeModel *tree_model, 00073 GtkTreeIter *iter, 00074 GtkTreeIter *parent); 00075 static gboolean gnc_tree_model_account_iter_has_child (GtkTreeModel *tree_model, 00076 GtkTreeIter *iter); 00077 static int gnc_tree_model_account_iter_n_children (GtkTreeModel *tree_model, 00078 GtkTreeIter *iter); 00079 static gboolean gnc_tree_model_account_iter_nth_child (GtkTreeModel *tree_model, 00080 GtkTreeIter *iter, 00081 GtkTreeIter *parent, 00082 int n); 00083 static gboolean gnc_tree_model_account_iter_parent (GtkTreeModel *tree_model, 00084 GtkTreeIter *iter, 00085 GtkTreeIter *child); 00086 00088 static void gnc_tree_model_account_event_handler (QofInstance *entity, 00089 QofEventId event_type, 00090 GncTreeModelAccount *model, 00091 GncEventData *ed); 00092 00094 typedef struct GncTreeModelAccountPrivate 00095 { 00096 QofBook *book; 00097 Account *root; 00098 gint event_handler_id; 00099 const gchar *negative_color; 00100 } GncTreeModelAccountPrivate; 00101 00102 #define GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(o) \ 00103 (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_TREE_MODEL_ACCOUNT, GncTreeModelAccountPrivate)) 00104 00105 00106 /************************************************************/ 00107 /* Account Tree Model - Misc Functions */ 00108 /************************************************************/ 00109 00116 static void 00117 gnc_tree_model_account_update_color (GConfEntry *entry, gpointer user_data) 00118 { 00119 GncTreeModelAccountPrivate *priv; 00120 GncTreeModelAccount *model; 00121 GConfValue *value; 00122 gboolean use_red; 00123 00124 g_return_if_fail(GNC_IS_TREE_MODEL_ACCOUNT(user_data)); 00125 model = user_data; 00126 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 00127 value = gconf_entry_get_value(entry); 00128 use_red = gconf_value_get_bool(value); 00129 priv->negative_color = use_red ? "red" : "black"; 00130 } 00131 /************************************************************/ 00132 /* g_object required functions */ 00133 /************************************************************/ 00134 00136 static GtkObjectClass *parent_class = NULL; 00137 00138 GType 00139 gnc_tree_model_account_get_type (void) 00140 { 00141 static GType gnc_tree_model_account_type = 0; 00142 00143 if (gnc_tree_model_account_type == 0) 00144 { 00145 static const GTypeInfo our_info = 00146 { 00147 sizeof (GncTreeModelAccountClass), /* class_size */ 00148 NULL, /* base_init */ 00149 NULL, /* base_finalize */ 00150 (GClassInitFunc) gnc_tree_model_account_class_init, 00151 NULL, /* class_finalize */ 00152 NULL, /* class_data */ 00153 sizeof (GncTreeModelAccount), /* */ 00154 0, /* n_preallocs */ 00155 (GInstanceInitFunc) gnc_tree_model_account_init 00156 }; 00157 00158 static const GInterfaceInfo tree_model_info = 00159 { 00160 (GInterfaceInitFunc) gnc_tree_model_account_tree_model_init, 00161 NULL, 00162 NULL 00163 }; 00164 00165 gnc_tree_model_account_type = g_type_register_static (GNC_TYPE_TREE_MODEL, 00166 GNC_TREE_MODEL_ACCOUNT_NAME, 00167 &our_info, 0); 00168 00169 g_type_add_interface_static (gnc_tree_model_account_type, 00170 GTK_TYPE_TREE_MODEL, 00171 &tree_model_info); 00172 } 00173 00174 return gnc_tree_model_account_type; 00175 } 00176 00177 static void 00178 gnc_tree_model_account_class_init (GncTreeModelAccountClass *klass) 00179 { 00180 GObjectClass *o_class; 00181 00182 parent_class = g_type_class_peek_parent (klass); 00183 00184 o_class = G_OBJECT_CLASS (klass); 00185 00186 /* GObject signals */ 00187 o_class->finalize = gnc_tree_model_account_finalize; 00188 o_class->dispose = gnc_tree_model_account_dispose; 00189 00190 g_type_class_add_private(klass, sizeof(GncTreeModelAccountPrivate)); 00191 } 00192 00193 static void 00194 gnc_tree_model_account_init (GncTreeModelAccount *model) 00195 { 00196 GncTreeModelAccountPrivate *priv; 00197 gboolean red; 00198 00199 ENTER("model %p", model); 00200 while (model->stamp == 0) 00201 { 00202 model->stamp = g_random_int (); 00203 } 00204 00205 red = gnc_gconf_get_bool(GCONF_GENERAL, KEY_NEGATIVE_IN_RED, NULL); 00206 00207 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 00208 priv->book = NULL; 00209 priv->root = NULL; 00210 priv->negative_color = red ? "red" : "black"; 00211 00212 gnc_gconf_general_register_cb(KEY_NEGATIVE_IN_RED, 00213 gnc_tree_model_account_update_color, 00214 model); 00215 00216 LEAVE(" "); 00217 } 00218 00219 static void 00220 gnc_tree_model_account_finalize (GObject *object) 00221 { 00222 GncTreeModelAccountPrivate *priv; 00223 GncTreeModelAccount *model; 00224 00225 g_return_if_fail (object != NULL); 00226 g_return_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (object)); 00227 00228 ENTER("model %p", object); 00229 00230 model = GNC_TREE_MODEL_ACCOUNT (object); 00231 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 00232 00233 gnc_gconf_general_remove_cb(KEY_NEGATIVE_IN_RED, 00234 gnc_tree_model_account_update_color, 00235 model); 00236 00237 priv->book = NULL; 00238 00239 if (G_OBJECT_CLASS (parent_class)->finalize) 00240 G_OBJECT_CLASS(parent_class)->finalize (object); 00241 LEAVE(" "); 00242 } 00243 00244 static void 00245 gnc_tree_model_account_dispose (GObject *object) 00246 { 00247 GncTreeModelAccountPrivate *priv; 00248 GncTreeModelAccount *model; 00249 00250 g_return_if_fail (object != NULL); 00251 g_return_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (object)); 00252 00253 ENTER("model %p", object); 00254 00255 model = GNC_TREE_MODEL_ACCOUNT (object); 00256 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 00257 00258 if (priv->event_handler_id) 00259 { 00260 qof_event_unregister_handler (priv->event_handler_id); 00261 priv->event_handler_id = 0; 00262 } 00263 00264 gnc_gconf_general_remove_cb(KEY_NEGATIVE_IN_RED, 00265 gnc_tree_model_account_update_color, 00266 model); 00267 00268 if (G_OBJECT_CLASS (parent_class)->dispose) 00269 G_OBJECT_CLASS (parent_class)->dispose (object); 00270 LEAVE(" "); 00271 } 00272 00273 00274 /************************************************************/ 00275 /* New Model Creation */ 00276 /************************************************************/ 00277 00278 GtkTreeModel * 00279 gnc_tree_model_account_new (Account *root) 00280 { 00281 GncTreeModelAccount *model; 00282 GncTreeModelAccountPrivate *priv; 00283 const GList *item; 00284 00285 ENTER("root %p", root); 00286 item = gnc_gobject_tracking_get_list(GNC_TREE_MODEL_ACCOUNT_NAME); 00287 for ( ; item; item = g_list_next(item)) 00288 { 00289 model = (GncTreeModelAccount *)item->data; 00290 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 00291 if (priv->root == root) 00292 { 00293 g_object_ref(G_OBJECT(model)); 00294 LEAVE("returning existing model %p", model); 00295 return GTK_TREE_MODEL(model); 00296 } 00297 } 00298 00299 model = g_object_new (GNC_TYPE_TREE_MODEL_ACCOUNT, 00300 NULL); 00301 00302 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 00303 priv->book = gnc_get_current_book(); 00304 priv->root = root; 00305 00306 priv->event_handler_id = qof_event_register_handler 00307 ((QofEventHandler)gnc_tree_model_account_event_handler, model); 00308 00309 LEAVE("model %p", model); 00310 return GTK_TREE_MODEL (model); 00311 } 00312 00313 00314 /************************************************************/ 00315 /* Gnc Tree Model Debugging Utility Function */ 00316 /************************************************************/ 00317 00318 #define ITER_STRING_LEN 128 00319 00320 static const gchar * 00321 iter_to_string (GtkTreeIter *iter) 00322 { 00323 #ifdef G_THREADS_ENABLED 00324 static GStaticPrivate gtmits_buffer_key = G_STATIC_PRIVATE_INIT; 00325 gchar *string; 00326 00327 string = g_static_private_get (>mits_buffer_key); 00328 if (string == NULL) 00329 { 00330 string = g_malloc(ITER_STRING_LEN + 1); 00331 g_static_private_set (>mits_buffer_key, string, g_free); 00332 } 00333 #else 00334 static char string[ITER_STRING_LEN + 1]; 00335 #endif 00336 00337 if (iter) 00338 snprintf(string, ITER_STRING_LEN, 00339 "[stamp:%x data:%p (%s), %p, %d]", 00340 iter->stamp, iter->user_data, 00341 xaccAccountGetName ((Account *) iter->user_data), 00342 iter->user_data2, GPOINTER_TO_INT(iter->user_data3)); 00343 else 00344 strcpy(string, "(null)"); 00345 return string; 00346 } 00347 00348 00349 /************************************************************/ 00350 /* Gtk Tree Model Required Interface Functions */ 00351 /************************************************************/ 00352 00353 static void 00354 gnc_tree_model_account_tree_model_init (GtkTreeModelIface *iface) 00355 { 00356 iface->get_flags = gnc_tree_model_account_get_flags; 00357 iface->get_n_columns = gnc_tree_model_account_get_n_columns; 00358 iface->get_column_type = gnc_tree_model_account_get_column_type; 00359 iface->get_iter = gnc_tree_model_account_get_iter; 00360 iface->get_path = gnc_tree_model_account_get_path; 00361 iface->get_value = gnc_tree_model_account_get_value; 00362 iface->iter_next = gnc_tree_model_account_iter_next; 00363 iface->iter_children = gnc_tree_model_account_iter_children; 00364 iface->iter_has_child = gnc_tree_model_account_iter_has_child; 00365 iface->iter_n_children = gnc_tree_model_account_iter_n_children; 00366 iface->iter_nth_child = gnc_tree_model_account_iter_nth_child; 00367 iface->iter_parent = gnc_tree_model_account_iter_parent; 00368 } 00369 00370 static GtkTreeModelFlags 00371 gnc_tree_model_account_get_flags (GtkTreeModel *tree_model) 00372 { 00373 return 0; 00374 } 00375 00376 static int 00377 gnc_tree_model_account_get_n_columns (GtkTreeModel *tree_model) 00378 { 00379 g_return_val_if_fail(GNC_IS_TREE_MODEL_ACCOUNT(tree_model), -1); 00380 00381 return GNC_TREE_MODEL_ACCOUNT_NUM_COLUMNS; 00382 } 00383 00384 static GType 00385 gnc_tree_model_account_get_column_type (GtkTreeModel *tree_model, 00386 int index) 00387 { 00388 g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), G_TYPE_INVALID); 00389 g_return_val_if_fail ((index < GNC_TREE_MODEL_ACCOUNT_NUM_COLUMNS) && (index >= 0), G_TYPE_INVALID); 00390 00391 switch (index) 00392 { 00393 case GNC_TREE_MODEL_ACCOUNT_COL_NAME: 00394 case GNC_TREE_MODEL_ACCOUNT_COL_TYPE: 00395 case GNC_TREE_MODEL_ACCOUNT_COL_COMMODITY: 00396 case GNC_TREE_MODEL_ACCOUNT_COL_CODE: 00397 case GNC_TREE_MODEL_ACCOUNT_COL_DESCRIPTION: 00398 case GNC_TREE_MODEL_ACCOUNT_COL_PRESENT: 00399 case GNC_TREE_MODEL_ACCOUNT_COL_PRESENT_REPORT: 00400 case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE: 00401 case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_REPORT: 00402 case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_PERIOD: 00403 case GNC_TREE_MODEL_ACCOUNT_COL_CLEARED: 00404 case GNC_TREE_MODEL_ACCOUNT_COL_CLEARED_REPORT: 00405 case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED: 00406 case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED_REPORT: 00407 case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED_DATE: 00408 case GNC_TREE_MODEL_ACCOUNT_COL_FUTURE_MIN: 00409 case GNC_TREE_MODEL_ACCOUNT_COL_FUTURE_MIN_REPORT: 00410 case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL: 00411 case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL_REPORT: 00412 case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL_PERIOD: 00413 case GNC_TREE_MODEL_ACCOUNT_COL_NOTES: 00414 case GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO: 00415 case GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO_SUB_ACCT: 00416 case GNC_TREE_MODEL_ACCOUNT_COL_LASTNUM: 00417 00418 case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_PRESENT: 00419 case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE: 00420 case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE_PERIOD: 00421 case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_CLEARED: 00422 case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_RECONCILED: 00423 case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_FUTURE_MIN: 00424 case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL: 00425 case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL_PERIOD: 00426 return G_TYPE_STRING; 00427 00428 case GNC_TREE_MODEL_ACCOUNT_COL_PLACEHOLDER: 00429 return G_TYPE_BOOLEAN; 00430 00431 default: 00432 g_assert_not_reached (); 00433 return G_TYPE_INVALID; 00434 } 00435 } 00436 00437 static gboolean 00438 gnc_tree_model_account_get_iter (GtkTreeModel *tree_model, 00439 GtkTreeIter *iter, 00440 GtkTreePath *path) 00441 { 00442 GncTreeModelAccountPrivate *priv; 00443 GncTreeModelAccount *model; 00444 Account *account, *parent; 00445 gint i, *indices; 00446 00447 g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE); 00448 00449 { 00450 gchar *path_string = gtk_tree_path_to_string(path); 00451 ENTER("model %p, iter %p, path %s", tree_model, iter, path_string); 00452 g_free(path_string); 00453 } 00454 00455 model = GNC_TREE_MODEL_ACCOUNT (tree_model); 00456 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 00457 00458 if (gtk_tree_path_get_depth (path) <= 0) 00459 { 00460 LEAVE("bad depth"); 00461 return FALSE; 00462 } 00463 00464 indices = gtk_tree_path_get_indices (path); 00465 if (indices[0] != 0) 00466 { 00467 LEAVE("bad root index"); 00468 return FALSE; 00469 } 00470 00471 parent = NULL; 00472 account = priv->root; 00473 for (i = 1; i < gtk_tree_path_get_depth (path); i++) 00474 { 00475 parent = account; 00476 account = gnc_account_nth_child(parent, indices[i]); 00477 if (account == NULL) 00478 { 00479 iter->stamp = 0; 00480 LEAVE("bad index"); 00481 return FALSE; 00482 } 00483 } 00484 00485 iter->stamp = model->stamp; 00486 iter->user_data = account; 00487 iter->user_data2 = parent; 00488 iter->user_data3 = GINT_TO_POINTER (indices[i - 1]); 00489 00490 LEAVE("iter %s", iter_to_string(iter)); 00491 return TRUE; 00492 } 00493 00494 static GtkTreePath * 00495 gnc_tree_model_account_get_path (GtkTreeModel *tree_model, 00496 GtkTreeIter *iter) 00497 { 00498 GncTreeModelAccount *model = GNC_TREE_MODEL_ACCOUNT (tree_model); 00499 GncTreeModelAccountPrivate *priv; 00500 Account *account, *parent; 00501 GtkTreePath *path; 00502 gint i; 00503 00504 g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), NULL); 00505 g_return_val_if_fail (iter != NULL, NULL); 00506 g_return_val_if_fail (iter->user_data != NULL, NULL); 00507 g_return_val_if_fail (iter->stamp == model->stamp, NULL); 00508 00509 ENTER("model %p, iter %s", model, iter_to_string(iter)); 00510 00511 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 00512 if (priv->root == NULL) 00513 { 00514 LEAVE("failed (1)"); 00515 return NULL; 00516 } 00517 00518 account = (Account *) iter->user_data; 00519 parent = (Account *) iter->user_data2; 00520 00521 path = gtk_tree_path_new (); 00522 while (parent) 00523 { 00524 i = gnc_account_child_index(parent, account); 00525 if (i == -1) 00526 { 00527 gtk_tree_path_free (path); 00528 LEAVE("failed (3)"); 00529 return NULL; 00530 } 00531 gtk_tree_path_prepend_index (path, i); 00532 account = parent; 00533 parent = gnc_account_get_parent(account); 00534 }; 00535 00536 /* Add the root node. */ 00537 gtk_tree_path_prepend_index (path, 0); 00538 00539 { 00540 gchar *path_string = gtk_tree_path_to_string(path); 00541 LEAVE("path (4) %s", path_string); 00542 g_free(path_string); 00543 } 00544 return path; 00545 } 00546 00547 static void 00548 gnc_tree_model_account_set_color(GncTreeModelAccount *model, 00549 gboolean negative, 00550 GValue *value) 00551 { 00552 GncTreeModelAccountPrivate *priv; 00553 00554 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 00555 if (negative) 00556 g_value_set_static_string (value, priv->negative_color); 00557 else 00558 g_value_set_static_string (value, "black"); 00559 } 00560 00561 static gchar * 00562 gnc_tree_model_account_compute_period_balance(GncTreeModelAccount *model, 00563 Account *acct, 00564 gboolean recurse, 00565 gboolean *negative) 00566 { 00567 GncTreeModelAccountPrivate *priv; 00568 time_t t1, t2; 00569 gnc_numeric b3; 00570 00571 if ( negative ) 00572 *negative = FALSE; 00573 00574 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 00575 if (acct == priv->root) 00576 return g_strdup(""); 00577 00578 t1 = gnc_accounting_period_fiscal_start(); 00579 t2 = gnc_accounting_period_fiscal_end(); 00580 00581 if (t1 > t2) 00582 return g_strdup(""); 00583 00584 b3 = xaccAccountGetBalanceChangeForPeriod(acct, t1, t2, recurse); 00585 if (gnc_reverse_balance (acct)) 00586 b3 = gnc_numeric_neg (b3); 00587 00588 if (negative) 00589 *negative = gnc_numeric_negative_p(b3); 00590 00591 return g_strdup(xaccPrintAmount(b3, gnc_account_print_info(acct, TRUE))); 00592 } 00593 00594 static void 00595 gnc_tree_model_account_get_value (GtkTreeModel *tree_model, 00596 GtkTreeIter *iter, 00597 int column, 00598 GValue *value) 00599 { 00600 GncTreeModelAccount *model = GNC_TREE_MODEL_ACCOUNT (tree_model); 00601 GncTreeModelAccountPrivate *priv; 00602 Account *account; 00603 gboolean negative; /* used to set "deficit style" also known as red numbers */ 00604 gchar *string; 00605 time_t last_date; 00606 00607 g_return_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model)); 00608 g_return_if_fail (iter != NULL); 00609 g_return_if_fail (iter->user_data != NULL); 00610 g_return_if_fail (iter->stamp == model->stamp); 00611 00612 ENTER("model %p, iter %s, col %d", tree_model, 00613 iter_to_string(iter), column); 00614 00615 account = (Account *) iter->user_data; 00616 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 00617 00618 switch (column) 00619 { 00620 case GNC_TREE_MODEL_ACCOUNT_COL_NAME: 00621 g_value_init (value, G_TYPE_STRING); 00622 if (account == priv->root) 00623 g_value_set_string (value, _("New top level account")); 00624 else 00625 g_value_set_string (value, xaccAccountGetName (account)); 00626 break; 00627 case GNC_TREE_MODEL_ACCOUNT_COL_TYPE: 00628 g_value_init (value, G_TYPE_STRING); 00629 g_value_set_string (value, 00630 xaccAccountGetTypeStr (xaccAccountGetType (account))); 00631 break; 00632 case GNC_TREE_MODEL_ACCOUNT_COL_CODE: 00633 g_value_init (value, G_TYPE_STRING); 00634 g_value_set_string (value, xaccAccountGetCode (account)); 00635 break; 00636 case GNC_TREE_MODEL_ACCOUNT_COL_COMMODITY: 00637 g_value_init (value, G_TYPE_STRING); 00638 g_value_set_string (value, 00639 gnc_commodity_get_fullname(xaccAccountGetCommodity (account))); 00640 break; 00641 case GNC_TREE_MODEL_ACCOUNT_COL_DESCRIPTION: 00642 g_value_init (value, G_TYPE_STRING); 00643 g_value_set_string (value, xaccAccountGetDescription (account)); 00644 break; 00645 00646 case GNC_TREE_MODEL_ACCOUNT_COL_PRESENT: 00647 g_value_init (value, G_TYPE_STRING); 00648 string = gnc_ui_account_get_print_balance(xaccAccountGetPresentBalanceInCurrency, 00649 account, TRUE, &negative); 00650 g_value_take_string (value, string); 00651 break; 00652 case GNC_TREE_MODEL_ACCOUNT_COL_PRESENT_REPORT: 00653 g_value_init (value, G_TYPE_STRING); 00654 string = gnc_ui_account_get_print_report_balance(xaccAccountGetPresentBalanceInCurrency, 00655 account, TRUE, &negative); 00656 g_value_take_string (value, string); 00657 break; 00658 case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_PRESENT: 00659 g_value_init (value, G_TYPE_STRING); 00660 string = gnc_ui_account_get_print_balance(xaccAccountGetPresentBalanceInCurrency, 00661 account, TRUE, &negative); 00662 gnc_tree_model_account_set_color(model, negative, value); 00663 g_free(string); 00664 break; 00665 00666 case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE: 00667 g_value_init (value, G_TYPE_STRING); 00668 string = gnc_ui_account_get_print_balance(xaccAccountGetBalanceInCurrency, 00669 account, TRUE, &negative); 00670 g_value_take_string (value, string); 00671 break; 00672 case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_REPORT: 00673 g_value_init (value, G_TYPE_STRING); 00674 string = gnc_ui_account_get_print_report_balance(xaccAccountGetBalanceInCurrency, 00675 account, TRUE, &negative); 00676 g_value_take_string (value, string); 00677 break; 00678 case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE: 00679 g_value_init (value, G_TYPE_STRING); 00680 string = gnc_ui_account_get_print_balance(xaccAccountGetBalanceInCurrency, 00681 account, TRUE, &negative); 00682 gnc_tree_model_account_set_color(model, negative, value); 00683 g_free(string); 00684 break; 00685 case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_PERIOD: 00686 g_value_init (value, G_TYPE_STRING); 00687 string = gnc_tree_model_account_compute_period_balance(model, account, FALSE, &negative); 00688 g_value_take_string (value, string); 00689 break; 00690 case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE_PERIOD: 00691 g_value_init (value, G_TYPE_STRING); 00692 string = gnc_tree_model_account_compute_period_balance(model, account, FALSE, &negative); 00693 gnc_tree_model_account_set_color(model, negative, value); 00694 g_free (string); 00695 break; 00696 00697 case GNC_TREE_MODEL_ACCOUNT_COL_CLEARED: 00698 g_value_init (value, G_TYPE_STRING); 00699 string = gnc_ui_account_get_print_balance(xaccAccountGetClearedBalanceInCurrency, 00700 account, TRUE, &negative); 00701 g_value_take_string (value, string); 00702 break; 00703 case GNC_TREE_MODEL_ACCOUNT_COL_CLEARED_REPORT: 00704 g_value_init (value, G_TYPE_STRING); 00705 string = gnc_ui_account_get_print_report_balance(xaccAccountGetClearedBalanceInCurrency, 00706 account, TRUE, &negative); 00707 g_value_take_string (value, string); 00708 break; 00709 case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_CLEARED: 00710 g_value_init (value, G_TYPE_STRING); 00711 string = gnc_ui_account_get_print_balance(xaccAccountGetClearedBalanceInCurrency, 00712 account, TRUE, &negative); 00713 gnc_tree_model_account_set_color(model, negative, value); 00714 g_free(string); 00715 break; 00716 00717 case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED: 00718 g_value_init (value, G_TYPE_STRING); 00719 string = gnc_ui_account_get_print_balance(xaccAccountGetReconciledBalanceInCurrency, 00720 account, TRUE, &negative); 00721 g_value_take_string (value, string); 00722 break; 00723 case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED_REPORT: 00724 g_value_init (value, G_TYPE_STRING); 00725 string = gnc_ui_account_get_print_report_balance(xaccAccountGetReconciledBalanceInCurrency, 00726 account, TRUE, &negative); 00727 g_value_take_string (value, string); 00728 break; 00729 case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED_DATE: 00730 g_value_init (value, G_TYPE_STRING); 00731 if (xaccAccountGetReconcileLastDate(account, &last_date)) 00732 { 00733 g_value_take_string(value, qof_print_date(last_date)); 00734 } 00735 break; 00736 00737 case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_RECONCILED: 00738 g_value_init (value, G_TYPE_STRING); 00739 string = gnc_ui_account_get_print_balance(xaccAccountGetReconciledBalanceInCurrency, 00740 account, TRUE, &negative); 00741 gnc_tree_model_account_set_color(model, negative, value); 00742 g_free (string); 00743 break; 00744 00745 case GNC_TREE_MODEL_ACCOUNT_COL_FUTURE_MIN: 00746 g_value_init (value, G_TYPE_STRING); 00747 string = gnc_ui_account_get_print_balance(xaccAccountGetProjectedMinimumBalanceInCurrency, 00748 account, TRUE, &negative); 00749 g_value_take_string (value, string); 00750 break; 00751 case GNC_TREE_MODEL_ACCOUNT_COL_FUTURE_MIN_REPORT: 00752 g_value_init (value, G_TYPE_STRING); 00753 string = gnc_ui_account_get_print_report_balance(xaccAccountGetProjectedMinimumBalanceInCurrency, 00754 account, TRUE, &negative); 00755 g_value_take_string (value, string); 00756 break; 00757 case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_FUTURE_MIN: 00758 g_value_init (value, G_TYPE_STRING); 00759 string = gnc_ui_account_get_print_balance(xaccAccountGetProjectedMinimumBalanceInCurrency, 00760 account, TRUE, &negative); 00761 gnc_tree_model_account_set_color(model, negative, value); 00762 g_free (string); 00763 break; 00764 00765 case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL: 00766 g_value_init (value, G_TYPE_STRING); 00767 string = gnc_ui_account_get_print_balance(xaccAccountGetBalanceInCurrency, 00768 account, TRUE, &negative); 00769 g_value_take_string (value, string); 00770 break; 00771 case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL_REPORT: 00772 g_value_init (value, G_TYPE_STRING); 00773 string = gnc_ui_account_get_print_report_balance(xaccAccountGetBalanceInCurrency, 00774 account, TRUE, &negative); 00775 g_value_take_string (value, string); 00776 break; 00777 case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL: 00778 g_value_init (value, G_TYPE_STRING); 00779 string = gnc_ui_account_get_print_balance(xaccAccountGetBalanceInCurrency, 00780 account, TRUE, &negative); 00781 gnc_tree_model_account_set_color(model, negative, value); 00782 g_free (string); 00783 break; 00784 case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL_PERIOD: 00785 g_value_init (value, G_TYPE_STRING); 00786 string = gnc_tree_model_account_compute_period_balance(model, account, TRUE, &negative); 00787 g_value_take_string (value, string); 00788 break; 00789 case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL_PERIOD: 00790 g_value_init (value, G_TYPE_STRING); 00791 string = gnc_tree_model_account_compute_period_balance(model, account, TRUE, &negative); 00792 gnc_tree_model_account_set_color(model, negative, value); 00793 g_free (string); 00794 break; 00795 00796 case GNC_TREE_MODEL_ACCOUNT_COL_NOTES: 00797 g_value_init (value, G_TYPE_STRING); 00798 g_value_set_string (value, xaccAccountGetNotes (account)); 00799 break; 00800 00801 case GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO: 00802 g_value_init (value, G_TYPE_STRING); 00803 g_value_take_string (value, gnc_ui_account_get_tax_info_string (account)); 00804 break; 00805 00806 case GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO_SUB_ACCT: 00807 g_value_init (value, G_TYPE_STRING); 00808 g_value_take_string (value, gnc_ui_account_get_tax_info_sub_acct_string (account)); 00809 break; 00810 00811 case GNC_TREE_MODEL_ACCOUNT_COL_LASTNUM: 00812 g_value_init (value, G_TYPE_STRING); 00813 g_value_set_string (value, xaccAccountGetLastNum (account)); 00814 break; 00815 00816 case GNC_TREE_MODEL_ACCOUNT_COL_PLACEHOLDER: 00817 g_value_init (value, G_TYPE_BOOLEAN); 00818 g_value_set_boolean (value, xaccAccountGetPlaceholder (account)); 00819 break; 00820 00821 default: 00822 g_assert_not_reached (); 00823 } 00824 LEAVE(" "); 00825 } 00826 00827 static gboolean 00828 gnc_tree_model_account_iter_next (GtkTreeModel *tree_model, 00829 GtkTreeIter *iter) 00830 { 00831 GncTreeModelAccount *model = GNC_TREE_MODEL_ACCOUNT (tree_model); 00832 GncTreeModelAccountPrivate *priv; 00833 Account *account, *parent; 00834 gint i; 00835 00836 g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), FALSE); 00837 g_return_val_if_fail (iter != NULL, FALSE); 00838 g_return_val_if_fail (iter->user_data != NULL, FALSE); 00839 g_return_val_if_fail (iter->stamp == model->stamp, FALSE); 00840 00841 ENTER("model %p, iter %s", tree_model, iter_to_string(iter)); 00842 00843 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 00844 00845 parent = (Account *) iter->user_data2; 00846 if (parent == NULL) 00847 { 00848 /* This is the root. There is no next. */ 00849 LEAVE("at root"); 00850 return FALSE; 00851 } 00852 00853 /* Get the *next* sibling account. */ 00854 i = GPOINTER_TO_INT (iter->user_data3); 00855 account = gnc_account_nth_child (parent, i + 1); 00856 if (account == NULL) 00857 { 00858 iter->stamp = 0; 00859 LEAVE("failed (3)"); 00860 return FALSE; 00861 } 00862 00863 iter->user_data = account; 00864 iter->user_data2 = parent; 00865 iter->user_data3 = GINT_TO_POINTER (i + 1); 00866 00867 LEAVE("iter %s", iter_to_string(iter)); 00868 return TRUE; 00869 } 00870 00871 static gboolean 00872 gnc_tree_model_account_iter_children (GtkTreeModel *tree_model, 00873 GtkTreeIter *iter, 00874 GtkTreeIter *parent_iter) 00875 { 00876 GncTreeModelAccountPrivate *priv; 00877 GncTreeModelAccount *model; 00878 Account *account, *parent; 00879 00880 g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE); 00881 ENTER("model %p, iter %p (to be filed in), parent %s", 00882 tree_model, iter, (parent_iter ? iter_to_string(parent_iter) : "(null)")); 00883 00884 model = GNC_TREE_MODEL_ACCOUNT (tree_model); 00885 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 00886 00887 if (priv->root == NULL) 00888 { 00889 iter->stamp = 0; 00890 LEAVE("failed (no root)"); 00891 return FALSE; 00892 } 00893 00894 /* Special case when no parent supplied. */ 00895 if (!parent_iter) 00896 { 00897 iter->user_data = priv->root; 00898 iter->user_data2 = NULL; 00899 iter->user_data3 = GINT_TO_POINTER (0); 00900 iter->stamp = model->stamp; 00901 LEAVE("iter (2) %s", iter_to_string(iter)); 00902 return TRUE; 00903 } 00904 00905 gnc_leave_return_val_if_fail (parent_iter != NULL, FALSE); 00906 gnc_leave_return_val_if_fail (parent_iter->user_data != NULL, FALSE); 00907 gnc_leave_return_val_if_fail (parent_iter->stamp == model->stamp, FALSE); 00908 00909 parent = (Account *)parent_iter->user_data; 00910 account = gnc_account_nth_child (parent, 0); 00911 00912 if (account == NULL) 00913 { 00914 iter->stamp = 0; 00915 LEAVE("failed (child account is null)"); 00916 return FALSE; 00917 } 00918 00919 iter->user_data = account; 00920 iter->user_data2 = parent; 00921 iter->user_data3 = GINT_TO_POINTER (0); 00922 iter->stamp = model->stamp; 00923 LEAVE("iter (3) %s", iter_to_string(iter)); 00924 return TRUE; 00925 } 00926 00927 static gboolean 00928 gnc_tree_model_account_iter_has_child (GtkTreeModel *tree_model, 00929 GtkTreeIter *iter) 00930 { 00931 GncTreeModelAccount *model; 00932 GncTreeModelAccountPrivate *priv; 00933 Account *account; 00934 00935 g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE); 00936 00937 ENTER("model %p, iter %s", tree_model, iter_to_string(iter)); 00938 00939 model = GNC_TREE_MODEL_ACCOUNT (tree_model); 00940 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 00941 00942 gnc_leave_return_val_if_fail (iter != NULL, FALSE); 00943 gnc_leave_return_val_if_fail (iter->user_data != NULL, FALSE); 00944 gnc_leave_return_val_if_fail (iter->stamp == model->stamp, FALSE); 00945 00946 account = (Account *) iter->user_data; 00947 if (gnc_account_n_children(account) > 0) 00948 { 00949 LEAVE("yes"); 00950 return TRUE; 00951 } 00952 00953 LEAVE("no"); 00954 return FALSE; 00955 } 00956 00957 static int 00958 gnc_tree_model_account_iter_n_children (GtkTreeModel *tree_model, 00959 GtkTreeIter *iter) 00960 { 00961 GncTreeModelAccount *model; 00962 GncTreeModelAccountPrivate *priv; 00963 gint num; 00964 00965 g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE); 00966 ENTER("model %p, iter %s", tree_model, iter_to_string(iter)); 00967 00968 model = GNC_TREE_MODEL_ACCOUNT (tree_model); 00969 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 00970 00971 if (iter == NULL) 00972 { 00973 /* How many children does the invisible root node 00974 * have. One! Its the real root account node. */ 00975 LEAVE("count is 1"); 00976 return 1; 00977 } 00978 00979 gnc_leave_return_val_if_fail (iter != NULL, FALSE); 00980 gnc_leave_return_val_if_fail (iter->user_data != NULL, FALSE); 00981 gnc_leave_return_val_if_fail (iter->stamp == model->stamp, FALSE); 00982 00983 num = gnc_account_n_children(iter->user_data); 00984 LEAVE("count is %d", num); 00985 return num; 00986 } 00987 00988 static gboolean 00989 gnc_tree_model_account_iter_nth_child (GtkTreeModel *tree_model, 00990 GtkTreeIter *iter, 00991 GtkTreeIter *parent_iter, 00992 int n) 00993 { 00994 GncTreeModelAccount *model; 00995 GncTreeModelAccountPrivate *priv; 00996 Account *account, *parent; 00997 00998 if (parent_iter) 00999 { 01000 gchar *parent_string; 01001 parent_string = g_strdup(iter_to_string(parent_iter)); 01002 ENTER("model %p, iter %s, parent_iter %s, n %d", 01003 tree_model, iter_to_string(iter), 01004 parent_string, n); 01005 g_free(parent_string); 01006 } 01007 else 01008 { 01009 ENTER("model %p, iter %s, parent_iter (null), n %d", 01010 tree_model, iter_to_string(iter), n); 01011 } 01012 gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE); 01013 01014 model = GNC_TREE_MODEL_ACCOUNT (tree_model); 01015 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 01016 01017 /* Special case when no parent supplied. */ 01018 if (!parent_iter) 01019 { 01020 if (n != 0) 01021 { 01022 LEAVE("bad root index"); 01023 return FALSE; 01024 } 01025 01026 iter->user_data = priv->root; 01027 iter->user_data2 = NULL; 01028 iter->user_data3 = GINT_TO_POINTER (0); 01029 iter->stamp = model->stamp; 01030 LEAVE("root %s", iter_to_string(iter)); 01031 return TRUE; 01032 } 01033 01034 gnc_leave_return_val_if_fail (parent_iter->user_data != NULL, FALSE); 01035 gnc_leave_return_val_if_fail (parent_iter->stamp == model->stamp, FALSE); 01036 01037 parent = (Account *)parent_iter->user_data; 01038 account = gnc_account_nth_child(parent, n); 01039 if (account == NULL) 01040 { 01041 iter->stamp = 0; 01042 LEAVE("failed (2)"); 01043 return FALSE; 01044 } 01045 01046 iter->user_data = account; 01047 iter->user_data2 = parent; 01048 iter->user_data3 = GINT_TO_POINTER (n); 01049 iter->stamp = model->stamp; 01050 LEAVE("iter (2) %s", iter_to_string(iter)); 01051 return TRUE; 01052 } 01053 01054 static gboolean 01055 gnc_tree_model_account_iter_parent (GtkTreeModel *tree_model, 01056 GtkTreeIter *iter, 01057 GtkTreeIter *child) 01058 { 01059 GncTreeModelAccount *model; 01060 GncTreeModelAccountPrivate *priv; 01061 Account *account, *parent; 01062 gint i; 01063 01064 if (child) 01065 { 01066 gchar *child_string; 01067 01068 child_string = g_strdup(iter_to_string(child)); 01069 ENTER("model %p, iter %s, child %s", 01070 tree_model, iter_to_string(iter), 01071 child_string); 01072 g_free(child_string); 01073 } 01074 else 01075 { 01076 ENTER("model %p, iter %s, child (null)", 01077 tree_model, iter_to_string(iter)); 01078 } 01079 gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE); 01080 01081 model = GNC_TREE_MODEL_ACCOUNT (tree_model); 01082 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 01083 01084 gnc_leave_return_val_if_fail (child != NULL, FALSE); 01085 gnc_leave_return_val_if_fail (child->user_data != NULL, FALSE); 01086 gnc_leave_return_val_if_fail (child->stamp == model->stamp, FALSE); 01087 01088 account = (Account *) child->user_data; 01089 account = gnc_account_get_parent(account); 01090 if (account == NULL) 01091 { 01092 /* Can't go up from the root node */ 01093 iter->stamp = 0; 01094 LEAVE("failed (1)"); 01095 return FALSE; 01096 } 01097 01098 parent = gnc_account_get_parent(account); 01099 if (parent == NULL) 01100 { 01101 /* Now at the root. */ 01102 i = 0; 01103 } 01104 else 01105 { 01106 i = gnc_account_child_index(parent, account); 01107 } 01108 iter->user_data = account; 01109 iter->user_data2 = parent; 01110 iter->user_data3 = GINT_TO_POINTER (i); 01111 iter->stamp = model->stamp; 01112 LEAVE("iter (2) %s", iter_to_string(iter)); 01113 return TRUE; 01114 } 01115 01116 01117 /************************************************************/ 01118 /* Account Tree View Filter Functions */ 01119 /************************************************************/ 01120 01121 /* 01122 * Convert a model/iter pair to a gnucash account. This routine should 01123 * only be called from an account tree view filter function. 01124 */ 01125 Account * 01126 gnc_tree_model_account_get_account (GncTreeModelAccount *model, 01127 GtkTreeIter *iter) 01128 { 01129 g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), NULL); 01130 g_return_val_if_fail (iter != NULL, NULL); 01131 g_return_val_if_fail (iter->user_data != NULL, NULL); 01132 g_return_val_if_fail (iter->stamp == model->stamp, NULL); 01133 01134 return (Account *) iter->user_data; 01135 } 01136 01137 /* 01138 * Convert a model/account pair into a gtk_tree_model_iter. This 01139 * routine should only be called from the file 01140 * gnc-tree-view-account.c. 01141 */ 01142 gboolean 01143 gnc_tree_model_account_get_iter_from_account (GncTreeModelAccount *model, 01144 Account *account, 01145 GtkTreeIter *iter) 01146 { 01147 GncTreeModelAccountPrivate *priv; 01148 Account *parent; 01149 gint i; 01150 01151 ENTER("model %p, account %p, iter %p", model, account, iter); 01152 gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), FALSE); 01153 gnc_leave_return_val_if_fail ((account != NULL), FALSE); 01154 gnc_leave_return_val_if_fail ((iter != NULL), FALSE); 01155 01156 iter->user_data = account; 01157 iter->stamp = model->stamp; 01158 01159 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 01160 if (account == priv->root) 01161 { 01162 iter->user_data2 = NULL; 01163 iter->user_data3 = GINT_TO_POINTER (0); 01164 LEAVE("Matched root"); 01165 return TRUE; 01166 } 01167 01168 if (priv->root != gnc_account_get_root (account)) 01169 { 01170 LEAVE("Root doesn't match"); 01171 return FALSE; 01172 } 01173 01174 parent = gnc_account_get_parent(account); 01175 i = gnc_account_child_index(parent, account); 01176 iter->user_data2 = parent; 01177 iter->user_data3 = GINT_TO_POINTER (i); 01178 LEAVE("iter %s", iter_to_string(iter)); 01179 return (i != -1); 01180 } 01181 01182 /* 01183 * Convert a model/account pair into a gtk_tree_model_path. This 01184 * routine should only be called from the file 01185 * gnc-tree-view-account.c. 01186 */ 01187 GtkTreePath * 01188 gnc_tree_model_account_get_path_from_account (GncTreeModelAccount *model, 01189 Account *account) 01190 { 01191 GtkTreeIter tree_iter; 01192 GtkTreePath *tree_path; 01193 01194 ENTER("model %p, account %p", model, account); 01195 gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), NULL); 01196 gnc_leave_return_val_if_fail (account != NULL, NULL); 01197 01198 if (!gnc_tree_model_account_get_iter_from_account (model, account, 01199 &tree_iter)) 01200 { 01201 LEAVE("no iter"); 01202 return NULL; 01203 } 01204 01205 tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL(model), &tree_iter); 01206 if (tree_path) 01207 { 01208 gchar *path_string = gtk_tree_path_to_string(tree_path); 01209 LEAVE("path (2) %s", path_string); 01210 g_free(path_string); 01211 } 01212 else 01213 { 01214 LEAVE("no path"); 01215 } 01216 return tree_path; 01217 } 01218 01219 /************************************************************/ 01220 /* Account Tree Model - Engine Event Handling Functions */ 01221 /************************************************************/ 01222 01223 static void 01224 increment_stamp(GncTreeModelAccount *model) 01225 { 01226 do model->stamp++; 01227 while (!model->stamp); 01228 } 01229 01230 static void 01231 propagate_change(GtkTreeModel *model, GtkTreePath *path, gint toggle_if_num) 01232 { 01233 GtkTreeIter iter; 01234 01235 /* Already at the invisible root node? */ 01236 if (!gtk_tree_path_up(path)) 01237 return; 01238 01239 /* Did we just move up to the invisible root node? */ 01240 if (gtk_tree_path_get_depth(path) == 0) 01241 return; 01242 01243 /* Handle the immediate parent */ 01244 if (gtk_tree_model_get_iter(model, &iter, path)) 01245 { 01246 gtk_tree_model_row_changed(model, path, &iter); 01247 if (gtk_tree_model_iter_n_children(model, &iter) == toggle_if_num) 01248 gtk_tree_model_row_has_child_toggled(model, path, &iter); 01249 } 01250 01251 /* All other ancestors */ 01252 while (gtk_tree_path_up(path) && gtk_tree_path_get_depth(path) > 0 && 01253 gtk_tree_model_get_iter(model, &iter, path)) 01254 { 01255 gtk_tree_model_row_changed(model, path, &iter); 01256 } 01257 } 01258 01287 static void 01288 gnc_tree_model_account_event_handler (QofInstance *entity, 01289 QofEventId event_type, 01290 GncTreeModelAccount *model, 01291 GncEventData *ed) 01292 { 01293 GncTreeModelAccountPrivate *priv; 01294 const gchar *parent_name; 01295 GtkTreePath *path = NULL; 01296 GtkTreeIter iter; 01297 Account *account, *parent; 01298 01299 g_return_if_fail(model); /* Required */ 01300 if (!GNC_IS_ACCOUNT(entity)) 01301 return; 01302 01303 ENTER("entity %p of type %d, model %p, event_data %p", 01304 entity, event_type, model, ed); 01305 priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model); 01306 01307 account = GNC_ACCOUNT(entity); 01308 if (gnc_account_get_book(account) != priv->book) 01309 { 01310 LEAVE("not in this book"); 01311 return; 01312 } 01313 if (gnc_account_get_root(account) != priv->root) 01314 { 01315 LEAVE("not in this model"); 01316 return; 01317 } 01318 /* What to do, that to do. */ 01319 switch (event_type) 01320 { 01321 case QOF_EVENT_ADD: 01322 /* Tell the filters/views where the new account was added. */ 01323 DEBUG("add account %p (%s)", account, xaccAccountGetName(account)); 01324 path = gnc_tree_model_account_get_path_from_account(model, account); 01325 if (!path) 01326 { 01327 DEBUG("can't generate path"); 01328 break; 01329 } 01330 increment_stamp(model); 01331 if (!gnc_tree_model_account_get_iter(GTK_TREE_MODEL(model), &iter, path)) 01332 { 01333 DEBUG("can't generate iter"); 01334 break; 01335 } 01336 gtk_tree_model_row_inserted (GTK_TREE_MODEL(model), path, &iter); 01337 propagate_change(GTK_TREE_MODEL(model), path, 1); 01338 break; 01339 01340 case QOF_EVENT_REMOVE: 01341 if (!ed) /* Required for a remove. */ 01342 break; 01343 parent = ed->node ? GNC_ACCOUNT(ed->node) : priv->root; 01344 parent_name = ed->node ? xaccAccountGetName(parent) : "Root"; 01345 DEBUG("remove child %d of account %p (%s)", ed->idx, parent, parent_name); 01346 path = gnc_tree_model_account_get_path_from_account(model, parent); 01347 if (!path) 01348 { 01349 DEBUG("can't generate path"); 01350 break; 01351 } 01352 increment_stamp(model); 01353 gtk_tree_path_append_index (path, ed->idx); 01354 gtk_tree_model_row_deleted (GTK_TREE_MODEL(model), path); 01355 propagate_change(GTK_TREE_MODEL(model), path, 0); 01356 break; 01357 01358 case QOF_EVENT_MODIFY: 01359 DEBUG("modify account %p (%s)", account, xaccAccountGetName(account)); 01360 path = gnc_tree_model_account_get_path_from_account(model, account); 01361 if (!path) 01362 { 01363 DEBUG("can't generate path"); 01364 break; 01365 } 01366 if (!gnc_tree_model_account_get_iter(GTK_TREE_MODEL(model), &iter, path)) 01367 { 01368 DEBUG("can't generate iter"); 01369 break; 01370 } 01371 gtk_tree_model_row_changed(GTK_TREE_MODEL(model), path, &iter); 01372 propagate_change(GTK_TREE_MODEL(model), path, -1); 01373 break; 01374 01375 default: 01376 LEAVE("unknown event type"); 01377 return; 01378 } 01379 01380 if (path) 01381 gtk_tree_path_free(path); 01382 LEAVE(" "); 01383 return; 01384 }
1.7.4