|
GnuCash 2.4.99
|
00001 /* 00002 * gnc-tree-model-commodity.c -- GtkTreeModel implementation to 00003 * display commodities 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 /* 00027 * In this model, valid paths take the form "X" or "X:Y", where: 00028 * X is an index into the namespaces list held by the commodity db 00029 * Y is an index into the commodity list for the namespace 00030 * 00031 * Iterators are populated with the following private data: 00032 * iter->user_data Type NAMESPACE | COMMODITY 00033 * iter->user_data2 A pointer to the namespace/commodity 00034 * iter->user_data3 The index of the namespace/commodity within its parent list 00035 */ 00036 00037 #include "config.h" 00038 00039 #include <gtk/gtk.h> 00040 #include <string.h> 00041 00042 #include "gnc-tree-model-commodity.h" 00043 #include "gnc-component-manager.h" 00044 #include "gnc-engine.h" 00045 #include "gnc-gobject-utils.h" 00046 #include "gnc-ui-util.h" 00047 00048 #define ITER_IS_NAMESPACE GINT_TO_POINTER(1) 00049 #define ITER_IS_COMMODITY GINT_TO_POINTER(2) 00050 00052 static QofLogModule log_module = GNC_MOD_GUI; 00053 00055 static void gnc_tree_model_commodity_class_init (GncTreeModelCommodityClass *klass); 00056 static void gnc_tree_model_commodity_init (GncTreeModelCommodity *model); 00057 static void gnc_tree_model_commodity_finalize (GObject *object); 00058 static void gnc_tree_model_commodity_dispose (GObject *object); 00059 00060 static void gnc_tree_model_commodity_tree_model_init (GtkTreeModelIface *iface); 00061 static GtkTreeModelFlags gnc_tree_model_commodity_get_flags (GtkTreeModel *tree_model); 00062 static int gnc_tree_model_commodity_get_n_columns (GtkTreeModel *tree_model); 00063 static GType gnc_tree_model_commodity_get_column_type (GtkTreeModel *tree_model, 00064 int index); 00065 static gboolean gnc_tree_model_commodity_get_iter (GtkTreeModel *tree_model, 00066 GtkTreeIter *iter, 00067 GtkTreePath *path); 00068 static GtkTreePath *gnc_tree_model_commodity_get_path (GtkTreeModel *tree_model, 00069 GtkTreeIter *iter); 00070 static void gnc_tree_model_commodity_get_value (GtkTreeModel *tree_model, 00071 GtkTreeIter *iter, 00072 int column, 00073 GValue *value); 00074 static gboolean gnc_tree_model_commodity_iter_next (GtkTreeModel *tree_model, 00075 GtkTreeIter *iter); 00076 static gboolean gnc_tree_model_commodity_iter_children (GtkTreeModel *tree_model, 00077 GtkTreeIter *iter, 00078 GtkTreeIter *parent); 00079 static gboolean gnc_tree_model_commodity_iter_has_child (GtkTreeModel *tree_model, 00080 GtkTreeIter *iter); 00081 static int gnc_tree_model_commodity_iter_n_children (GtkTreeModel *tree_model, 00082 GtkTreeIter *iter); 00083 static gboolean gnc_tree_model_commodity_iter_nth_child (GtkTreeModel *tree_model, 00084 GtkTreeIter *iter, 00085 GtkTreeIter *parent, 00086 int n); 00087 static gboolean gnc_tree_model_commodity_iter_parent (GtkTreeModel *tree_model, 00088 GtkTreeIter *iter, 00089 GtkTreeIter *child); 00090 static void gnc_tree_model_commodity_event_handler (QofInstance *entity, 00091 QofEventId event_type, 00092 gpointer user_data, 00093 gpointer event_data); 00094 00096 typedef struct GncTreeModelCommodityPrivate 00097 { 00098 QofBook *book; 00099 gnc_commodity_table *commodity_table; 00100 gint event_handler_id; 00101 } GncTreeModelCommodityPrivate; 00102 00103 #define GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(o) \ 00104 (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_TREE_MODEL_COMMODITY, GncTreeModelCommodityPrivate)) 00105 00107 static GtkObjectClass *parent_class = NULL; 00108 00109 GType 00110 gnc_tree_model_commodity_get_type (void) 00111 { 00112 static GType gnc_tree_model_commodity_type = 0; 00113 00114 if (gnc_tree_model_commodity_type == 0) 00115 { 00116 static const GTypeInfo our_info = 00117 { 00118 sizeof (GncTreeModelCommodityClass), 00119 NULL, 00120 NULL, 00121 (GClassInitFunc) gnc_tree_model_commodity_class_init, 00122 NULL, 00123 NULL, 00124 sizeof (GncTreeModelCommodity), 00125 0, 00126 (GInstanceInitFunc) gnc_tree_model_commodity_init 00127 }; 00128 00129 static const GInterfaceInfo tree_model_info = 00130 { 00131 (GInterfaceInitFunc) gnc_tree_model_commodity_tree_model_init, 00132 NULL, 00133 NULL 00134 }; 00135 00136 gnc_tree_model_commodity_type = g_type_register_static (GNC_TYPE_TREE_MODEL, 00137 GNC_TREE_MODEL_COMMODITY_NAME, 00138 &our_info, 0); 00139 00140 g_type_add_interface_static (gnc_tree_model_commodity_type, 00141 GTK_TYPE_TREE_MODEL, 00142 &tree_model_info); 00143 } 00144 00145 return gnc_tree_model_commodity_type; 00146 } 00147 00148 static void 00149 gnc_tree_model_commodity_class_init (GncTreeModelCommodityClass *klass) 00150 { 00151 GObjectClass *o_class = G_OBJECT_CLASS (klass); 00152 00153 parent_class = g_type_class_peek_parent (klass); 00154 00155 o_class->finalize = gnc_tree_model_commodity_finalize; 00156 o_class->dispose = gnc_tree_model_commodity_dispose; 00157 00158 g_type_class_add_private(klass, sizeof(GncTreeModelCommodityPrivate)); 00159 } 00160 00161 static void 00162 gnc_tree_model_commodity_init (GncTreeModelCommodity *model) 00163 { 00164 while (model->stamp == 0) 00165 { 00166 model->stamp = g_random_int (); 00167 } 00168 } 00169 00170 static void 00171 gnc_tree_model_commodity_finalize (GObject *object) 00172 { 00173 GncTreeModelCommodity *model; 00174 GncTreeModelCommodityPrivate *priv; 00175 00176 g_return_if_fail (object != NULL); 00177 g_return_if_fail (GNC_IS_TREE_MODEL_COMMODITY (object)); 00178 00179 ENTER("model %p", object); 00180 00181 model = GNC_TREE_MODEL_COMMODITY (object); 00182 priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model); 00183 priv->book = NULL; 00184 priv->commodity_table = NULL; 00185 00186 G_OBJECT_CLASS (parent_class)->finalize (object); 00187 LEAVE(" "); 00188 } 00189 00190 static void 00191 gnc_tree_model_commodity_dispose (GObject *object) 00192 { 00193 GncTreeModelCommodity *model; 00194 GncTreeModelCommodityPrivate *priv; 00195 00196 g_return_if_fail (object != NULL); 00197 g_return_if_fail (GNC_IS_TREE_MODEL_COMMODITY (object)); 00198 00199 ENTER("model %p", object); 00200 model = GNC_TREE_MODEL_COMMODITY (object); 00201 priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model); 00202 00203 if (priv->event_handler_id) 00204 { 00205 qof_event_unregister_handler (priv->event_handler_id); 00206 priv->event_handler_id = 0; 00207 } 00208 00209 if (G_OBJECT_CLASS (parent_class)->dispose) 00210 G_OBJECT_CLASS (parent_class)->dispose (object); 00211 LEAVE(" "); 00212 } 00213 00214 GtkTreeModel * 00215 gnc_tree_model_commodity_new (QofBook *book, gnc_commodity_table *ct) 00216 { 00217 GncTreeModelCommodity *model; 00218 GncTreeModelCommodityPrivate *priv; 00219 const GList *item; 00220 00221 ENTER(""); 00222 00223 item = gnc_gobject_tracking_get_list(GNC_TREE_MODEL_COMMODITY_NAME); 00224 for ( ; item; item = g_list_next(item)) 00225 { 00226 model = (GncTreeModelCommodity *)item->data; 00227 priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model); 00228 if (priv->commodity_table == ct) 00229 { 00230 g_object_ref(G_OBJECT(model)); 00231 LEAVE("returning existing model %p", model); 00232 return GTK_TREE_MODEL(model); 00233 } 00234 } 00235 00236 model = g_object_new (GNC_TYPE_TREE_MODEL_COMMODITY, NULL); 00237 priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model); 00238 priv->book = book; 00239 priv->commodity_table = ct; 00240 00241 priv->event_handler_id = 00242 qof_event_register_handler (gnc_tree_model_commodity_event_handler, model); 00243 00244 LEAVE(""); 00245 return GTK_TREE_MODEL (model); 00246 } 00247 00248 gboolean 00249 gnc_tree_model_commodity_iter_is_namespace (GncTreeModelCommodity *model, 00250 GtkTreeIter *iter) 00251 { 00252 g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (model), FALSE); 00253 g_return_val_if_fail (iter != NULL, FALSE); 00254 g_return_val_if_fail (iter->user_data != NULL, FALSE); 00255 g_return_val_if_fail (iter->stamp == model->stamp, FALSE); 00256 00257 return (iter->user_data == ITER_IS_NAMESPACE); 00258 } 00259 00260 gboolean 00261 gnc_tree_model_commodity_iter_is_commodity (GncTreeModelCommodity *model, 00262 GtkTreeIter *iter) 00263 { 00264 g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (model), FALSE); 00265 g_return_val_if_fail (iter != NULL, FALSE); 00266 g_return_val_if_fail (iter->user_data != NULL, FALSE); 00267 g_return_val_if_fail (iter->stamp == model->stamp, FALSE); 00268 00269 return (iter->user_data == ITER_IS_COMMODITY); 00270 } 00271 00272 gnc_commodity_namespace * 00273 gnc_tree_model_commodity_get_namespace (GncTreeModelCommodity *model, 00274 GtkTreeIter *iter) 00275 { 00276 g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (model), NULL); 00277 g_return_val_if_fail (iter != NULL, NULL); 00278 g_return_val_if_fail (iter->user_data != NULL, NULL); 00279 g_return_val_if_fail (iter->stamp == model->stamp, NULL); 00280 00281 if (iter->user_data != ITER_IS_NAMESPACE) 00282 return NULL; 00283 return (gnc_commodity_namespace *)iter->user_data2; 00284 } 00285 00286 gnc_commodity * 00287 gnc_tree_model_commodity_get_commodity (GncTreeModelCommodity *model, 00288 GtkTreeIter *iter) 00289 { 00290 g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (model), NULL); 00291 g_return_val_if_fail (iter != NULL, NULL); 00292 g_return_val_if_fail (iter->user_data != NULL, NULL); 00293 g_return_val_if_fail (iter->stamp == model->stamp, NULL); 00294 00295 if (iter->user_data != ITER_IS_COMMODITY) 00296 return NULL; 00297 return (gnc_commodity *)iter->user_data2; 00298 } 00299 00300 /************************************************************/ 00301 /* Gnc Tree Model Debugging Utility Function */ 00302 /************************************************************/ 00303 00304 #define debug_path(fn, path) { \ 00305 gchar *path_string = gtk_tree_path_to_string(path); \ 00306 fn("tree path %s", path_string? path_string : "NULL"); \ 00307 g_free(path_string); \ 00308 } 00309 00310 #define ITER_STRING_LEN 128 00311 00312 static const gchar * 00313 iter_to_string (GtkTreeIter *iter) 00314 { 00315 gnc_commodity_namespace *namespace; 00316 gnc_commodity *commodity = NULL; 00317 #ifdef G_THREADS_ENABLED 00318 static GStaticPrivate gtmits_buffer_key = G_STATIC_PRIVATE_INIT; 00319 gchar *string; 00320 00321 string = g_static_private_get (>mits_buffer_key); 00322 if (string == NULL) 00323 { 00324 string = g_malloc(ITER_STRING_LEN + 1); 00325 g_static_private_set (>mits_buffer_key, string, g_free); 00326 } 00327 #else 00328 static char string[ITER_STRING_LEN + 1]; 00329 #endif 00330 if (iter) 00331 { 00332 switch (GPOINTER_TO_INT(iter->user_data)) 00333 { 00334 case GPOINTER_TO_INT(ITER_IS_NAMESPACE): 00335 namespace = (gnc_commodity_namespace *) iter->user_data2; 00336 snprintf(string, ITER_STRING_LEN, 00337 "[stamp:%x data:%d (NAMESPACE), %p (%s), %d]", 00338 iter->stamp, GPOINTER_TO_INT(iter->user_data), 00339 iter->user_data2, gnc_commodity_namespace_get_name (namespace), 00340 GPOINTER_TO_INT(iter->user_data3)); 00341 break; 00342 00343 case GPOINTER_TO_INT(ITER_IS_COMMODITY): 00344 commodity = (gnc_commodity *) iter->user_data2; 00345 snprintf(string, ITER_STRING_LEN, 00346 "[stamp:%x data:%d (COMMODITY), %p (%s), %d]", 00347 iter->stamp, GPOINTER_TO_INT(iter->user_data), 00348 iter->user_data2, gnc_commodity_get_mnemonic (commodity), 00349 GPOINTER_TO_INT(iter->user_data3)); 00350 break; 00351 00352 default: 00353 snprintf(string, ITER_STRING_LEN, 00354 "[stamp:%x data:%d (UNKNOWN), %p, %d]", 00355 iter->stamp, 00356 GPOINTER_TO_INT(iter->user_data), 00357 iter->user_data2, 00358 GPOINTER_TO_INT(iter->user_data3)); 00359 break; 00360 } 00361 } 00362 return string; 00363 } 00364 00365 00366 /************************************************************/ 00367 /* Gtk Tree Model Required Interface Functions */ 00368 /************************************************************/ 00369 00370 static void 00371 gnc_tree_model_commodity_tree_model_init (GtkTreeModelIface *iface) 00372 { 00373 iface->get_flags = gnc_tree_model_commodity_get_flags; 00374 iface->get_n_columns = gnc_tree_model_commodity_get_n_columns; 00375 iface->get_column_type = gnc_tree_model_commodity_get_column_type; 00376 iface->get_iter = gnc_tree_model_commodity_get_iter; 00377 iface->get_path = gnc_tree_model_commodity_get_path; 00378 iface->get_value = gnc_tree_model_commodity_get_value; 00379 iface->iter_next = gnc_tree_model_commodity_iter_next; 00380 iface->iter_children = gnc_tree_model_commodity_iter_children; 00381 iface->iter_has_child = gnc_tree_model_commodity_iter_has_child; 00382 iface->iter_n_children = gnc_tree_model_commodity_iter_n_children; 00383 iface->iter_nth_child = gnc_tree_model_commodity_iter_nth_child; 00384 iface->iter_parent = gnc_tree_model_commodity_iter_parent; 00385 } 00386 00387 static GtkTreeModelFlags 00388 gnc_tree_model_commodity_get_flags (GtkTreeModel *tree_model) 00389 { 00390 return 0; 00391 } 00392 00393 static int 00394 gnc_tree_model_commodity_get_n_columns (GtkTreeModel *tree_model) 00395 { 00396 return GNC_TREE_MODEL_COMMODITY_NUM_COLUMNS; 00397 } 00398 00399 static GType 00400 gnc_tree_model_commodity_get_column_type (GtkTreeModel *tree_model, 00401 int index) 00402 { 00403 g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model), G_TYPE_INVALID); 00404 g_return_val_if_fail ((index < GNC_TREE_MODEL_COMMODITY_NUM_COLUMNS) && (index >= 0), G_TYPE_INVALID); 00405 00406 switch (index) 00407 { 00408 case GNC_TREE_MODEL_COMMODITY_COL_MNEMONIC: 00409 case GNC_TREE_MODEL_COMMODITY_COL_NAMESPACE: 00410 case GNC_TREE_MODEL_COMMODITY_COL_FULLNAME: 00411 case GNC_TREE_MODEL_COMMODITY_COL_PRINTNAME: 00412 case GNC_TREE_MODEL_COMMODITY_COL_CUSIP: 00413 case GNC_TREE_MODEL_COMMODITY_COL_UNIQUE_NAME: 00414 case GNC_TREE_MODEL_COMMODITY_COL_QUOTE_SOURCE: 00415 case GNC_TREE_MODEL_COMMODITY_COL_QUOTE_TZ: 00416 return G_TYPE_STRING; 00417 case GNC_TREE_MODEL_COMMODITY_COL_FRACTION: 00418 return G_TYPE_INT; 00419 case GNC_TREE_MODEL_COMMODITY_COL_QUOTE_FLAG: 00420 case GNC_TREE_MODEL_COMMODITY_COL_VISIBILITY: 00421 return G_TYPE_BOOLEAN; 00422 default: 00423 g_assert_not_reached (); 00424 return G_TYPE_INVALID; 00425 } 00426 } 00427 00428 static gboolean 00429 gnc_tree_model_commodity_get_iter (GtkTreeModel *tree_model, 00430 GtkTreeIter *iter, 00431 GtkTreePath *path) 00432 { 00433 GncTreeModelCommodity *model; 00434 GncTreeModelCommodityPrivate *priv; 00435 gnc_commodity_table *ct; 00436 gnc_commodity_namespace *namespace; 00437 gnc_commodity *commodity = NULL; 00438 GList *list; 00439 guint i, depth; 00440 00441 iter->stamp = 0; 00442 g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model), FALSE); 00443 g_return_val_if_fail (iter != NULL, FALSE); 00444 g_return_val_if_fail (path != NULL, FALSE); 00445 00446 depth = gtk_tree_path_get_depth (path); 00447 ENTER("model %p, iter %p, path %p (depth %d)", tree_model, iter, path, depth); 00448 debug_path(DEBUG, path); 00449 00450 /* Check the path depth. */ 00451 if (depth == 0) 00452 { 00453 LEAVE("depth too small"); 00454 return FALSE; 00455 } 00456 if (depth > 2) 00457 { 00458 LEAVE("depth too big"); 00459 return FALSE; 00460 } 00461 00462 /* Make sure the model has a commodity db. */ 00463 model = GNC_TREE_MODEL_COMMODITY (tree_model); 00464 priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model); 00465 ct = priv->commodity_table; 00466 if (ct == NULL) 00467 { 00468 LEAVE("no commodity table"); 00469 return FALSE; 00470 } 00471 00472 /* Verify the first part of the path: the namespace. */ 00473 list = gnc_commodity_table_get_namespaces_list(ct); 00474 i = gtk_tree_path_get_indices (path)[0]; 00475 namespace = g_list_nth_data (list, i); 00476 if (!namespace) 00477 { 00478 LEAVE("invalid path at namespace"); 00479 return FALSE; 00480 } 00481 00482 if (depth == 1) 00483 { 00484 /* Return an iterator for the namespace. */ 00485 iter->stamp = model->stamp; 00486 iter->user_data = ITER_IS_NAMESPACE; 00487 iter->user_data2 = namespace; 00488 iter->user_data3 = GINT_TO_POINTER(i); 00489 LEAVE("iter (ns) %s", iter_to_string(iter)); 00490 return TRUE; 00491 } 00492 00493 /* Verify the second part of the path: the commodity. */ 00494 list = gnc_commodity_namespace_get_commodity_list(namespace); 00495 i = gtk_tree_path_get_indices (path)[1]; 00496 commodity = g_list_nth_data (list, i); 00497 if (!commodity) 00498 { 00499 LEAVE("invalid path at commodity"); 00500 return FALSE; 00501 } 00502 00503 /* Return an iterator for the commodity. */ 00504 iter->stamp = model->stamp; 00505 iter->user_data = ITER_IS_COMMODITY; 00506 iter->user_data2 = commodity; 00507 iter->user_data3 = GINT_TO_POINTER(i); 00508 LEAVE("iter (cm) %s", iter_to_string(iter)); 00509 return TRUE; 00510 } 00511 00512 static GtkTreePath * 00513 gnc_tree_model_commodity_get_path (GtkTreeModel *tree_model, 00514 GtkTreeIter *iter) 00515 { 00516 GncTreeModelCommodity *model; 00517 GncTreeModelCommodityPrivate *priv; 00518 GtkTreePath *path; 00519 gnc_commodity_table *ct; 00520 gnc_commodity_namespace *namespace; 00521 GList *ns_list; 00522 00523 g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model), NULL); 00524 model = GNC_TREE_MODEL_COMMODITY (tree_model); 00525 g_return_val_if_fail (iter != NULL, NULL); 00526 g_return_val_if_fail (iter->user_data != NULL, NULL); 00527 g_return_val_if_fail (iter->user_data2 != NULL, NULL); 00528 g_return_val_if_fail (iter->stamp == model->stamp, NULL); 00529 ENTER("model %p, iter %p (%s)", tree_model, iter, iter_to_string(iter)); 00530 00531 /* Make sure this model has a commodity db. */ 00532 priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model); 00533 ct = priv->commodity_table; 00534 if (ct == NULL) 00535 { 00536 LEAVE("no commodity table"); 00537 return FALSE; 00538 } 00539 00540 if (iter->user_data == ITER_IS_NAMESPACE) 00541 { 00542 /* Create a path to the namespace. This is just the index into 00543 * the namespace list, which we already stored in user_data3. */ 00544 path = gtk_tree_path_new (); 00545 gtk_tree_path_append_index (path, GPOINTER_TO_INT(iter->user_data3)); 00546 debug_path(LEAVE, path); 00547 return path; 00548 } 00549 00550 /* Get the namespaces list. */ 00551 ns_list = gnc_commodity_table_get_namespaces_list(ct); 00552 namespace = gnc_commodity_get_namespace_ds((gnc_commodity*)iter->user_data2); 00553 00554 /* Create a path to the commodity. */ 00555 path = gtk_tree_path_new (); 00556 gtk_tree_path_append_index (path, g_list_index (ns_list, namespace)); 00557 gtk_tree_path_append_index (path, GPOINTER_TO_INT(iter->user_data3)); 00558 debug_path(LEAVE, path); 00559 return path; 00560 } 00561 00562 static void 00563 gnc_tree_model_commodity_get_value (GtkTreeModel *tree_model, 00564 GtkTreeIter *iter, 00565 int column, 00566 GValue *value) 00567 { 00568 GncTreeModelCommodity *model = GNC_TREE_MODEL_COMMODITY (tree_model); 00569 gnc_commodity_namespace *namespace; 00570 gnc_commodity *commodity; 00571 gnc_quote_source *source; 00572 00573 g_return_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model)); 00574 g_return_if_fail (iter != NULL); 00575 g_return_if_fail (iter->user_data != NULL); 00576 g_return_if_fail (iter->user_data2 != NULL); 00577 g_return_if_fail (iter->stamp == model->stamp); 00578 00579 if (iter->user_data == ITER_IS_NAMESPACE) 00580 { 00581 namespace = (gnc_commodity_namespace *)iter->user_data2; 00582 switch (column) 00583 { 00584 case GNC_TREE_MODEL_COMMODITY_COL_NAMESPACE: 00585 g_value_init (value, G_TYPE_STRING); 00586 g_value_set_string (value, gnc_commodity_namespace_get_name (namespace)); 00587 break; 00588 default: 00589 g_value_init (value, G_TYPE_STRING); 00590 g_value_set_string (value, ""); 00591 break; 00592 case GNC_TREE_MODEL_COMMODITY_COL_FRACTION: 00593 g_value_init (value, G_TYPE_INT); 00594 g_value_set_int (value, 0); 00595 break; 00596 case GNC_TREE_MODEL_COMMODITY_COL_QUOTE_FLAG: 00597 g_value_init (value, G_TYPE_BOOLEAN); 00598 g_value_set_boolean (value, FALSE); 00599 break; 00600 case GNC_TREE_MODEL_COMMODITY_COL_VISIBILITY: 00601 g_value_init (value, G_TYPE_BOOLEAN); 00602 g_value_set_boolean (value, FALSE); 00603 break; 00604 } 00605 return; 00606 } 00607 00608 commodity = (gnc_commodity *)iter->user_data2; 00609 switch (column) 00610 { 00611 case GNC_TREE_MODEL_COMMODITY_COL_MNEMONIC: 00612 g_value_init (value, G_TYPE_STRING); 00613 00614 g_value_set_string (value, gnc_commodity_get_mnemonic (commodity)); 00615 break; 00616 case GNC_TREE_MODEL_COMMODITY_COL_NAMESPACE: 00617 g_value_init (value, G_TYPE_STRING); 00618 00619 // g_value_set_string (value, gnc_commodity_get_namespace (commodity)); 00620 g_value_set_string (value, NULL); 00621 break; 00622 case GNC_TREE_MODEL_COMMODITY_COL_FULLNAME: 00623 g_value_init (value, G_TYPE_STRING); 00624 00625 g_value_set_string (value, gnc_commodity_get_fullname (commodity)); 00626 break; 00627 case GNC_TREE_MODEL_COMMODITY_COL_PRINTNAME: 00628 g_value_init (value, G_TYPE_STRING); 00629 00630 g_value_set_string (value, gnc_commodity_get_printname (commodity)); 00631 break; 00632 case GNC_TREE_MODEL_COMMODITY_COL_CUSIP: 00633 g_value_init (value, G_TYPE_STRING); 00634 00635 g_value_set_string (value, gnc_commodity_get_cusip (commodity)); 00636 break; 00637 case GNC_TREE_MODEL_COMMODITY_COL_UNIQUE_NAME: 00638 g_value_init (value, G_TYPE_STRING); 00639 00640 g_value_set_string (value, gnc_commodity_get_unique_name (commodity)); 00641 break; 00642 case GNC_TREE_MODEL_COMMODITY_COL_FRACTION: 00643 g_value_init (value, G_TYPE_INT); 00644 00645 g_value_set_int (value, gnc_commodity_get_fraction (commodity)); 00646 break; 00647 case GNC_TREE_MODEL_COMMODITY_COL_QUOTE_FLAG: 00648 g_value_init (value, G_TYPE_BOOLEAN); 00649 00650 g_value_set_boolean (value, gnc_commodity_get_quote_flag (commodity)); 00651 break; 00652 case GNC_TREE_MODEL_COMMODITY_COL_QUOTE_SOURCE: 00653 g_value_init (value, G_TYPE_STRING); 00654 00655 if (gnc_commodity_get_quote_flag (commodity)) 00656 { 00657 source = gnc_commodity_get_quote_source (commodity); 00658 g_value_set_string (value, gnc_quote_source_get_internal_name(source)); 00659 } 00660 else 00661 { 00662 g_value_set_static_string (value, ""); 00663 } 00664 break; 00665 case GNC_TREE_MODEL_COMMODITY_COL_QUOTE_TZ: 00666 g_value_init (value, G_TYPE_STRING); 00667 00668 if (gnc_commodity_get_quote_flag (commodity)) 00669 { 00670 g_value_set_string (value, gnc_commodity_get_quote_tz (commodity)); 00671 } 00672 else 00673 { 00674 g_value_set_static_string (value, ""); 00675 } 00676 break; 00677 case GNC_TREE_MODEL_COMMODITY_COL_VISIBILITY: 00678 g_value_init (value, G_TYPE_BOOLEAN); 00679 g_value_set_boolean (value, TRUE); 00680 break; 00681 default: 00682 g_assert_not_reached (); 00683 } 00684 } 00685 00686 static gboolean 00687 gnc_tree_model_commodity_iter_next (GtkTreeModel *tree_model, 00688 GtkTreeIter *iter) 00689 { 00690 GncTreeModelCommodity *model; 00691 GncTreeModelCommodityPrivate *priv; 00692 gnc_commodity_table *ct; 00693 gnc_commodity_namespace *namespace; 00694 GList *list; 00695 int n; 00696 00697 g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model), FALSE); 00698 model = GNC_TREE_MODEL_COMMODITY (tree_model); 00699 g_return_val_if_fail (iter != NULL, FALSE); 00700 g_return_val_if_fail (iter->user_data != NULL, FALSE); 00701 g_return_val_if_fail (iter->user_data2 != NULL, FALSE); 00702 g_return_val_if_fail (iter->stamp == model->stamp, FALSE); 00703 00704 ENTER("model %p, iter %p(%s)", tree_model, iter, iter_to_string(iter)); 00705 priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model); 00706 if (iter->user_data == ITER_IS_NAMESPACE) 00707 { 00708 ct = priv->commodity_table; 00709 list = gnc_commodity_table_get_namespaces_list(ct); 00710 } 00711 else if (iter->user_data == ITER_IS_COMMODITY) 00712 { 00713 namespace = gnc_commodity_get_namespace_ds((gnc_commodity *)iter->user_data2); 00714 list = gnc_commodity_namespace_get_commodity_list(namespace); 00715 } 00716 else 00717 { 00718 LEAVE("unknown iter type"); 00719 return FALSE; 00720 } 00721 00722 n = GPOINTER_TO_INT(iter->user_data3) + 1; 00723 iter->user_data2 = g_list_nth_data(list, n); 00724 if (iter->user_data2 == NULL) 00725 { 00726 LEAVE("no next iter"); 00727 return FALSE; 00728 } 00729 iter->user_data3 = GINT_TO_POINTER(n); 00730 LEAVE("iter %p(%s)", iter, iter_to_string(iter)); 00731 return TRUE; 00732 } 00733 00734 00735 static gboolean 00736 gnc_tree_model_commodity_iter_children (GtkTreeModel *tree_model, 00737 GtkTreeIter *iter, 00738 GtkTreeIter *parent) 00739 { 00740 GncTreeModelCommodity *model; 00741 GncTreeModelCommodityPrivate *priv; 00742 gnc_commodity_table *ct; 00743 gnc_commodity_namespace *namespace; 00744 GList *list; 00745 00746 g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model), FALSE); 00747 00748 ENTER("model %p, iter %p, parent %p (%s)", 00749 tree_model, iter, parent, iter_to_string(parent)); 00750 model = GNC_TREE_MODEL_COMMODITY (tree_model); 00751 priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model); 00752 00753 if (parent == NULL) 00754 { 00755 ct = priv->commodity_table; 00756 list = gnc_commodity_table_get_namespaces_list(ct); 00757 if (list == NULL) 00758 { 00759 LEAVE("no namespaces"); 00760 return FALSE; 00761 } 00762 00763 iter->stamp = model->stamp; 00764 iter->user_data = ITER_IS_NAMESPACE; 00765 iter->user_data2 = g_list_nth_data(list, 0); 00766 iter->user_data3 = GINT_TO_POINTER(0); 00767 LEAVE("ns iter %p (%s)", iter, iter_to_string(iter)); 00768 return TRUE; 00769 } 00770 00771 if (parent->user_data == ITER_IS_NAMESPACE) 00772 { 00773 namespace = (gnc_commodity_namespace *)parent->user_data2; 00774 list = gnc_commodity_namespace_get_commodity_list(namespace); 00775 if (list == NULL) 00776 { 00777 LEAVE("no commodities"); 00778 return FALSE; 00779 } 00780 00781 iter->stamp = model->stamp; 00782 iter->user_data = ITER_IS_COMMODITY; 00783 iter->user_data2 = g_list_nth_data(list, 0); 00784 iter->user_data3 = GINT_TO_POINTER(0); 00785 LEAVE("cm iter %p (%s)", iter, iter_to_string(iter)); 00786 return TRUE; 00787 } 00788 00789 LEAVE("FALSE"); 00790 return FALSE; 00791 } 00792 00793 static gboolean 00794 gnc_tree_model_commodity_iter_has_child (GtkTreeModel *tree_model, 00795 GtkTreeIter *iter) 00796 { 00797 gnc_commodity_namespace *namespace; 00798 GList *list; 00799 00800 g_return_val_if_fail (iter != NULL, FALSE); 00801 ENTER("model %p, iter %p (%s)", tree_model, 00802 iter, iter_to_string(iter)); 00803 00804 if (iter->user_data != ITER_IS_NAMESPACE) 00805 { 00806 LEAVE("no children (not ns)"); 00807 return FALSE; 00808 } 00809 00810 namespace = (gnc_commodity_namespace *)iter->user_data2; 00811 list = gnc_commodity_namespace_get_commodity_list(namespace); 00812 LEAVE("%s children", list ? "has" : "no"); 00813 return list != NULL; 00814 } 00815 00816 static int 00817 gnc_tree_model_commodity_iter_n_children (GtkTreeModel *tree_model, 00818 GtkTreeIter *iter) 00819 { 00820 GncTreeModelCommodity *model; 00821 GncTreeModelCommodityPrivate *priv; 00822 gnc_commodity_table *ct; 00823 gnc_commodity_namespace *namespace; 00824 GList *list; 00825 00826 g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model), -1); 00827 00828 ENTER("model %p, iter %p (%s)", tree_model, iter, iter_to_string(iter)); 00829 model = GNC_TREE_MODEL_COMMODITY (tree_model); 00830 priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model); 00831 00832 if (iter == NULL) 00833 { 00834 ct = priv->commodity_table; 00835 list = gnc_commodity_table_get_namespaces_list(ct); 00836 LEAVE("ns list length %d", g_list_length(list)); 00837 return g_list_length (list); 00838 } 00839 00840 if (iter->user_data == ITER_IS_NAMESPACE) 00841 { 00842 namespace = (gnc_commodity_namespace *)iter->user_data2; 00843 list = gnc_commodity_namespace_get_commodity_list(namespace); 00844 LEAVE("cm list length %d", g_list_length(list)); 00845 return g_list_length (list); 00846 } 00847 00848 LEAVE("0"); 00849 return 0; 00850 } 00851 00852 static gboolean 00853 gnc_tree_model_commodity_iter_nth_child (GtkTreeModel *tree_model, 00854 GtkTreeIter *iter, 00855 GtkTreeIter *parent, 00856 int n) 00857 { 00858 GncTreeModelCommodity *model; 00859 GncTreeModelCommodityPrivate *priv; 00860 gnc_commodity_table *ct; 00861 gnc_commodity_namespace *namespace; 00862 GList *list; 00863 00864 g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model), FALSE); 00865 g_return_val_if_fail (iter != NULL, FALSE); 00866 00867 ENTER("model %p, iter %p, parent %p (%s)", 00868 tree_model, iter, parent, iter_to_string(parent)); 00869 model = GNC_TREE_MODEL_COMMODITY (tree_model); 00870 priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model); 00871 00872 if (parent == NULL) 00873 { 00874 ct = priv->commodity_table; 00875 list = gnc_commodity_table_get_namespaces_list(ct); 00876 00877 iter->stamp = model->stamp; 00878 iter->user_data = ITER_IS_NAMESPACE; 00879 iter->user_data2 = g_list_nth_data(list, n); 00880 iter->user_data3 = GINT_TO_POINTER(n); 00881 LEAVE("ns iter %p (%s)", iter, iter_to_string(iter)); 00882 return iter->user_data2 != NULL; 00883 } 00884 00885 if (parent->user_data == ITER_IS_NAMESPACE) 00886 { 00887 namespace = (gnc_commodity_namespace *)parent->user_data2; 00888 list = gnc_commodity_namespace_get_commodity_list(namespace); 00889 00890 iter->stamp = model->stamp; 00891 iter->user_data = ITER_IS_COMMODITY; 00892 iter->user_data2 = g_list_nth_data(list, n); 00893 iter->user_data3 = GINT_TO_POINTER(n); 00894 LEAVE("cm iter %p (%s)", iter, iter_to_string(iter)); 00895 return iter->user_data2 != NULL; 00896 } 00897 00898 iter->stamp = 0; 00899 LEAVE("FALSE"); 00900 return FALSE; 00901 } 00902 00903 static gboolean 00904 gnc_tree_model_commodity_iter_parent (GtkTreeModel *tree_model, 00905 GtkTreeIter *iter, 00906 GtkTreeIter *child) 00907 { 00908 GncTreeModelCommodity *model; 00909 GncTreeModelCommodityPrivate *priv; 00910 gnc_commodity_table *ct; 00911 gnc_commodity_namespace *namespace; 00912 GList *list; 00913 00914 g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model), FALSE); 00915 g_return_val_if_fail (iter != NULL, FALSE); 00916 g_return_val_if_fail (child != NULL, FALSE); 00917 00918 ENTER("model %p, iter %p, child %p (%s)", 00919 tree_model, iter, child, iter_to_string(child)); 00920 model = GNC_TREE_MODEL_COMMODITY (tree_model); 00921 priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model); 00922 00923 if (child->user_data == ITER_IS_NAMESPACE) 00924 { 00925 LEAVE("ns has no parent"); 00926 return FALSE; 00927 } 00928 00929 ct = priv->commodity_table; 00930 list = gnc_commodity_table_get_namespaces_list(ct); 00931 namespace = gnc_commodity_get_namespace_ds((gnc_commodity*)child->user_data2); 00932 00933 iter->stamp = model->stamp; 00934 iter->user_data = ITER_IS_NAMESPACE; 00935 iter->user_data2 = namespace; 00936 iter->user_data3 = GINT_TO_POINTER(g_list_index(list, namespace)); 00937 LEAVE("ns iter %p (%s)", iter, iter_to_string(iter)); 00938 return TRUE; 00939 } 00940 00941 /************************************************************/ 00942 /* Commodity Tree View Functions */ 00943 /************************************************************/ 00944 00945 /* 00946 * Convert a model/commodity pair into a gtk_tree_model_iter. This 00947 * routine should only be called from the file 00948 * gnc-tree-view-commodity.c. 00949 */ 00950 gboolean 00951 gnc_tree_model_commodity_get_iter_from_commodity (GncTreeModelCommodity *model, 00952 gnc_commodity *commodity, 00953 GtkTreeIter *iter) 00954 { 00955 gnc_commodity_namespace *namespace; 00956 GList *list; 00957 gint n; 00958 00959 g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (model), FALSE); 00960 g_return_val_if_fail ((commodity != NULL), FALSE); 00961 g_return_val_if_fail ((iter != NULL), FALSE); 00962 00963 ENTER("model %p, commodity %p, iter %p", model, commodity, iter); 00964 00965 namespace = gnc_commodity_get_namespace_ds(commodity); 00966 if (namespace == NULL) 00967 { 00968 LEAVE("no namespace"); 00969 return FALSE; 00970 } 00971 00972 list = gnc_commodity_namespace_get_commodity_list(namespace); 00973 if (list == NULL) 00974 { 00975 LEAVE("empty list"); 00976 return FALSE; 00977 } 00978 00979 n = g_list_index(list, commodity); 00980 if (n == -1) 00981 { 00982 LEAVE("not in list"); 00983 return FALSE; 00984 } 00985 00986 iter->stamp = model->stamp; 00987 iter->user_data = ITER_IS_COMMODITY; 00988 iter->user_data2 = commodity; 00989 iter->user_data3 = GINT_TO_POINTER(n); 00990 LEAVE("iter %s", iter_to_string(iter)); 00991 return TRUE; 00992 } 00993 00994 /* 00995 * Convert a model/commodity pair into a gtk_tree_model_path. This 00996 * routine should only be called from the file 00997 * gnc-tree-view-commodity.c. 00998 */ 00999 GtkTreePath * 01000 gnc_tree_model_commodity_get_path_from_commodity (GncTreeModelCommodity *model, 01001 gnc_commodity *commodity) 01002 { 01003 GtkTreeIter tree_iter; 01004 GtkTreePath *tree_path; 01005 01006 g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (model), NULL); 01007 g_return_val_if_fail (commodity != NULL, NULL); 01008 ENTER("model %p, commodity %p", model, commodity); 01009 01010 if (!gnc_tree_model_commodity_get_iter_from_commodity (model, commodity, &tree_iter)) 01011 { 01012 LEAVE("no iter"); 01013 return NULL; 01014 } 01015 01016 tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL(model), &tree_iter); 01017 if (tree_path) 01018 { 01019 gchar *path_string = gtk_tree_path_to_string(tree_path); 01020 LEAVE("path (2) %s", path_string); 01021 g_free(path_string); 01022 } 01023 else 01024 { 01025 LEAVE("no path"); 01026 } 01027 return tree_path; 01028 } 01029 01030 /* 01031 * Convert a model/namespace pair into a gtk_tree_model_iter. This 01032 * routine should only be called from the file 01033 * gnc-tree-view-commodity.c. 01034 */ 01035 gboolean 01036 gnc_tree_model_commodity_get_iter_from_namespace (GncTreeModelCommodity *model, 01037 gnc_commodity_namespace *namespace, 01038 GtkTreeIter *iter) 01039 { 01040 GncTreeModelCommodityPrivate *priv; 01041 GList *list; 01042 gint n; 01043 01044 g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (model), FALSE); 01045 g_return_val_if_fail ((namespace != NULL), FALSE); 01046 g_return_val_if_fail ((iter != NULL), FALSE); 01047 01048 ENTER("model %p, namespace %p, iter %p", model, namespace, iter); 01049 01050 priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model); 01051 list = gnc_commodity_table_get_namespaces_list(priv->commodity_table); 01052 if (list == NULL) 01053 { 01054 LEAVE(""); 01055 return FALSE; 01056 } 01057 01058 n = g_list_index(list, namespace); 01059 if (n == -1) 01060 { 01061 LEAVE(""); 01062 return FALSE; 01063 } 01064 01065 iter->stamp = model->stamp; 01066 iter->user_data = ITER_IS_NAMESPACE; 01067 iter->user_data2 = namespace; 01068 iter->user_data3 = GINT_TO_POINTER(n); 01069 LEAVE("iter %s", iter_to_string(iter)); 01070 return TRUE; 01071 } 01072 01073 01074 /************************************************************/ 01075 /* Commodity Tree Model - Engine Event Handling Functions */ 01076 /************************************************************/ 01077 01078 typedef struct _remove_data 01079 { 01080 GncTreeModelCommodity *model; 01081 GtkTreePath *path; 01082 } remove_data; 01083 01084 static GSList *pending_removals = NULL; 01085 01097 static void 01098 gnc_tree_model_commodity_row_add (GncTreeModelCommodity *model, 01099 GtkTreeIter *iter) 01100 { 01101 GtkTreePath *path; 01102 GtkTreeModel *tree_model; 01103 GtkTreeIter tmp_iter; 01104 01105 ENTER("model %p, iter (%p)%s", model, iter, iter_to_string(iter)); 01106 01107 /* We're adding a row, so the lists on which this model is based have 01108 * changed. Since existing iterators (except the one just passed in) 01109 * are all based on old indexes into those lists, we need to invalidate 01110 * them, which we can do by changing the model's stamp. */ 01111 do 01112 { 01113 model->stamp++; 01114 } 01115 while (model->stamp == 0); 01116 iter->stamp = model->stamp; 01117 01118 /* Tag the new row as inserted. */ 01119 tree_model = GTK_TREE_MODEL(model); 01120 path = gnc_tree_model_commodity_get_path(tree_model, iter); 01121 gtk_tree_model_row_inserted(tree_model, path, iter); 01122 01123 /* Inform all ancestors. */ 01124 /* 01125 * Charles Day: I don't think calls to gtk_tree_model_row_changed() should 01126 * be necessary. It is just a workaround for bug #540201. 01127 */ 01128 if (gtk_tree_path_up(path) && 01129 gtk_tree_path_get_depth(path) > 0 && 01130 gtk_tree_model_get_iter(tree_model, &tmp_iter, path)) 01131 { 01132 /* Signal the change to the parent. */ 01133 gtk_tree_model_row_changed(tree_model, path, &tmp_iter); 01134 01135 /* Is this the parent's first child? */ 01136 if (gtk_tree_model_iter_n_children(tree_model, &tmp_iter) == 1) 01137 gtk_tree_model_row_has_child_toggled(tree_model, path, &tmp_iter); 01138 01139 /* Signal any other ancestors. */ 01140 while (gtk_tree_path_up(path) && 01141 gtk_tree_path_get_depth(path) > 0 && 01142 gtk_tree_model_get_iter(tree_model, &tmp_iter, path)) 01143 { 01144 gtk_tree_model_row_changed(tree_model, path, &tmp_iter); 01145 } 01146 } 01147 gtk_tree_path_free(path); 01148 01149 /* If the new row already has children, signal that so the expander 01150 * can be shown. This can happen, for example, if a namespace is 01151 * changed in another place and gets removed and then re-added to 01152 * the commodity db. */ 01153 if (gnc_tree_model_commodity_iter_has_child(tree_model, iter)) 01154 { 01155 path = gnc_tree_model_commodity_get_path(tree_model, iter); 01156 gtk_tree_model_row_has_child_toggled(tree_model, path, iter); 01157 gtk_tree_path_free(path); 01158 } 01159 01160 LEAVE(" "); 01161 } 01162 01174 static void 01175 gnc_tree_model_commodity_row_delete (GncTreeModelCommodity *model, 01176 GtkTreePath *path) 01177 { 01178 GtkTreeModel *tree_model; 01179 GtkTreeIter iter; 01180 01181 g_return_if_fail(GNC_IS_TREE_MODEL_COMMODITY(model)); 01182 g_return_if_fail(path); 01183 01184 debug_path(ENTER, path); 01185 01186 tree_model = GTK_TREE_MODEL(model); 01187 01188 /* We're removing a row, so the lists on which this model is based have 01189 * changed. Since existing iterators are all based on old indexes into 01190 * those lists, we need to invalidate them, which we can do by changing 01191 * the model's stamp. */ 01192 do 01193 { 01194 model->stamp++; 01195 } 01196 while (model->stamp == 0); 01197 01198 /* Signal that the path has been deleted. */ 01199 gtk_tree_model_row_deleted(tree_model, path); 01200 01201 /* Issue any appropriate signals to ancestors. */ 01202 if (gtk_tree_path_up(path) && 01203 gtk_tree_path_get_depth(path) > 0 && 01204 gtk_tree_model_get_iter(tree_model, &iter, path) && 01205 !gtk_tree_model_iter_has_child(tree_model, &iter)) 01206 { 01207 DEBUG("parent toggled, iter %s", iter_to_string(&iter)); 01208 gtk_tree_model_row_has_child_toggled(tree_model, path, &iter); 01209 } 01210 01211 LEAVE(" "); 01212 } 01213 01214 01231 static gboolean 01232 gnc_tree_model_commodity_do_deletions (gpointer unused) 01233 { 01234 ENTER(" "); 01235 01236 /* Go through the list of paths needing removal. */ 01237 while (pending_removals) 01238 { 01239 remove_data *data = pending_removals->data; 01240 pending_removals = g_slist_delete_link(pending_removals, pending_removals); 01241 01242 if (data) 01243 { 01244 debug_path(DEBUG, data->path); 01245 01246 /* Remove the path. */ 01247 gnc_tree_model_commodity_row_delete(data->model, data->path); 01248 01249 gtk_tree_path_free(data->path); 01250 g_free(data); 01251 } 01252 } 01253 01254 LEAVE(" "); 01255 /* Don't call me again. */ 01256 return FALSE; 01257 } 01258 01259 01291 static void 01292 gnc_tree_model_commodity_event_handler (QofInstance *entity, 01293 QofEventId event_type, 01294 gpointer user_data, 01295 gpointer event_data) 01296 { 01297 GncTreeModelCommodity *model; 01298 GtkTreePath *path; 01299 GtkTreeIter iter; 01300 remove_data *data; 01301 const gchar *name; 01302 01303 model = (GncTreeModelCommodity *)user_data; 01304 01305 /* hard failures */ 01306 g_return_if_fail(GNC_IS_TREE_MODEL_COMMODITY(model)); 01307 01308 ENTER("entity %p, event %d, model %p, event data %p", 01309 entity, event_type, user_data, event_data); 01310 01311 /* Do deletions if any are pending. */ 01312 if (pending_removals) 01313 gnc_tree_model_commodity_do_deletions(NULL); 01314 01315 /* get type specific data */ 01316 if (GNC_IS_COMMODITY(entity)) 01317 { 01318 gnc_commodity *commodity; 01319 01320 commodity = GNC_COMMODITY(entity); 01321 name = gnc_commodity_get_mnemonic(commodity); 01322 if (event_type != QOF_EVENT_DESTROY) 01323 { 01324 if (!gnc_tree_model_commodity_get_iter_from_commodity (model, commodity, &iter)) 01325 { 01326 LEAVE("no iter"); 01327 return; 01328 } 01329 } 01330 } 01331 else if (GNC_IS_COMMODITY_NAMESPACE(entity)) 01332 { 01333 gnc_commodity_namespace *namespace; 01334 01335 namespace = GNC_COMMODITY_NAMESPACE(entity); 01336 name = gnc_commodity_namespace_get_name(namespace); 01337 if (event_type != QOF_EVENT_DESTROY) 01338 { 01339 if (!gnc_tree_model_commodity_get_iter_from_namespace (model, namespace, &iter)) 01340 { 01341 LEAVE("no iter"); 01342 return; 01343 } 01344 } 01345 } 01346 else 01347 { 01348 LEAVE(""); 01349 return; 01350 } 01351 01352 switch (event_type) 01353 { 01354 case QOF_EVENT_ADD: 01355 /* Tell the filters/views where the new account was added. */ 01356 DEBUG("add %s", name); 01357 gnc_tree_model_commodity_row_add (model, &iter); 01358 break; 01359 01360 case QOF_EVENT_REMOVE: 01361 /* Record the path of this account for later use in destruction */ 01362 DEBUG("remove %s", name); 01363 path = gtk_tree_model_get_path (GTK_TREE_MODEL(model), &iter); 01364 if (path == NULL) 01365 { 01366 LEAVE("not in model"); 01367 return; 01368 } 01369 01370 data = g_new0 (remove_data, 1); 01371 data->model = model; 01372 data->path = path; 01373 pending_removals = g_slist_append (pending_removals, data); 01374 g_idle_add_full(G_PRIORITY_HIGH_IDLE, 01375 gnc_tree_model_commodity_do_deletions, NULL, NULL); 01376 01377 LEAVE(" "); 01378 return; 01379 01380 case QOF_EVENT_MODIFY: 01381 DEBUG("change %s", name); 01382 path = gtk_tree_model_get_path (GTK_TREE_MODEL(model), &iter); 01383 if (path == NULL) 01384 { 01385 LEAVE("not in model"); 01386 return; 01387 } 01388 gtk_tree_model_row_changed(GTK_TREE_MODEL(model), path, &iter); 01389 gtk_tree_path_free(path); 01390 LEAVE(" "); 01391 return; 01392 01393 default: 01394 LEAVE("ignored event for %s", name); 01395 return; 01396 } 01397 LEAVE(" new stamp %u", model->stamp); 01398 }
1.7.4