GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-tree-view-price.c
1/********************************************************************\
2 * gnc-tree-view-price.c -- GtkTreeView implementation to display *
3 * prices in a GtkTreeView. *
4 * Copyright (C) 2003,2005 David Hampton <hampton@employees.org> *
5 * *
6 * This program is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU General Public License as *
8 * published by the Free Software Foundation; either version 2 of *
9 * the License, or (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License*
17 * along with this program; if not, contact: *
18 * *
19 * Free Software Foundation Voice: +1-617-542-5942 *
20 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 * Boston, MA 02110-1301, USA gnu@gnu.org *
22 * *
23\********************************************************************/
24
25#include <config.h>
26
27#include <gtk/gtk.h>
28#include <glib/gi18n.h>
29#include <string.h>
30
31#include "gnc-tree-view.h"
33#include "gnc-tree-view-price.h"
34
35#include "gnc-pricedb.h"
36#include "gnc-component-manager.h"
37#include "gnc-engine.h"
38#include "gnc-glib-utils.h"
39#include "gnc-gnome-utils.h"
40#include "gnc-icons.h"
41#include "gnc-ui-util.h"
42
43
46/* This static indicates the debugging module that this .o belongs to. */
47static QofLogModule log_module = GNC_MOD_GUI;
48
50static void gnc_tree_view_price_finalize (GObject *object);
51static void gnc_tree_view_price_destroy (GtkWidget *widget);
52
54{
55 GncTreeView gnc_tree_view;
56 int stamp;
57};
58
59
60/************************************************************/
61/* g_object required functions */
62/************************************************************/
63
64G_DEFINE_TYPE(GncTreeViewPrice, gnc_tree_view_price, GNC_TYPE_TREE_VIEW)
65
66static void
67gnc_tree_view_price_class_init (GncTreeViewPriceClass *klass)
68{
69 GObjectClass *o_class;
70 GtkWidgetClass *widget_class;
71
72 o_class = G_OBJECT_CLASS (klass);
73 widget_class = GTK_WIDGET_CLASS (klass);
74
75 /* GObject signals */
76 o_class->finalize = gnc_tree_view_price_finalize;
77
78 /* GtkWidget signals */
79 widget_class->destroy = gnc_tree_view_price_destroy;
80}
81
82static void
83gnc_tree_view_price_init (GncTreeViewPrice *view)
84{
85}
86
87static void
88gnc_tree_view_price_finalize (GObject *object)
89{
90 ENTER("view %p", object);
91 gnc_leave_return_if_fail (object != NULL);
92 gnc_leave_return_if_fail (GNC_IS_TREE_VIEW_PRICE (object));
93
94 G_OBJECT_CLASS (gnc_tree_view_price_parent_class)->finalize (object);
95 LEAVE(" ");
96}
97
98static void
99gnc_tree_view_price_destroy (GtkWidget *widget)
100{
101 ENTER("view %p", widget);
102 gnc_leave_return_if_fail (widget != NULL);
103 gnc_leave_return_if_fail (GNC_IS_TREE_VIEW_PRICE (widget));
104
105 GTK_WIDGET_CLASS (gnc_tree_view_price_parent_class)->destroy (widget);
106 LEAVE(" ");
107}
108
109
110/************************************************************/
111/* sort functions */
112/************************************************************/
113
114static gboolean
115get_prices (GtkTreeModel *f_model,
116 GtkTreeIter *f_iter_a,
117 GtkTreeIter *f_iter_b,
118 GNCPrice **price_a,
119 GNCPrice **price_b)
120{
121 GncTreeModelPrice *model;
122 GtkTreeModel *tree_model;
123 GtkTreeIter iter_a, iter_b;
124
125 tree_model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
126 model = GNC_TREE_MODEL_PRICE(tree_model);
127
128 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(f_model),
129 &iter_a,
130 f_iter_a);
131
132 /* The iters must point to prices for this to be meaningful */
133 if (!gnc_tree_model_price_iter_is_price (model, &iter_a))
134 return FALSE;
135
136 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(f_model),
137 &iter_b,
138 f_iter_b);
139
140 *price_a = gnc_tree_model_price_get_price (model, &iter_a);
141 *price_b = gnc_tree_model_price_get_price (model, &iter_b);
142 return TRUE;
143}
144
145static gint
146sort_ns_or_cm (GtkTreeModel *f_model,
147 GtkTreeIter *f_iter_a,
148 GtkTreeIter *f_iter_b)
149{
150 GncTreeModelPrice *model;
151 GtkTreeModel *tree_model;
152 GtkTreeIter iter_a, iter_b;
153 gnc_commodity_namespace *ns_a, *ns_b;
154 gnc_commodity *comm_a, *comm_b;
155
156 tree_model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
157 model = GNC_TREE_MODEL_PRICE(tree_model);
158
159 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(f_model),
160 &iter_a,
161 f_iter_a);
162 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(f_model),
163 &iter_b,
164 f_iter_b);
165
166 if (gnc_tree_model_price_iter_is_namespace (model, &iter_a))
167 {
168 ns_a = gnc_tree_model_price_get_namespace (model, &iter_a);
169 ns_b = gnc_tree_model_price_get_namespace (model, &iter_b);
172 }
173
174 comm_a = gnc_tree_model_price_get_commodity (model, &iter_a);
175 comm_b = gnc_tree_model_price_get_commodity (model, &iter_b);
178}
179
180static gint
181default_sort (GNCPrice *price_a, GNCPrice *price_b)
182{
183 gnc_commodity *curr_a, *curr_b;
184 time64 time_a, time_b;
185 gint result;
186
187 /* Primary sort (i.e. commodity name) handled by the tree structure. */
188
189 /* secondary sort: currency */
190 curr_a = gnc_price_get_currency (price_a);
191 curr_b = gnc_price_get_currency (price_b);
192
195 if (result != 0) return result;
196
199 if (result != 0) return result;
200
201 /* tertiary sort: time */
202 time_a = gnc_price_get_time64 (price_a);
203 time_b = gnc_price_get_time64 (price_b);
204 result = time_a < time_b ? -1 : time_a > time_b ? 1 : 0;
205 if (result)
206 /* Reverse the result to present the most recent quote first. */
207 return -result;
208
209 /* last sort: value */
210 return gnc_numeric_compare (gnc_price_get_value (price_a),
211 gnc_price_get_value (price_b));
212}
213
214static gint
215sort_by_name (GtkTreeModel *f_model,
216 GtkTreeIter *f_iter_a,
217 GtkTreeIter *f_iter_b,
218 gpointer user_data)
219{
220 GNCPrice *price_a, *price_b;
221
222 if (!get_prices (f_model, f_iter_a, f_iter_b, &price_a, &price_b))
223 return sort_ns_or_cm (f_model, f_iter_a, f_iter_b);
224
225 return default_sort (price_a, price_b);
226}
227
228static gint
229sort_by_date (GtkTreeModel *f_model,
230 GtkTreeIter *f_iter_a,
231 GtkTreeIter *f_iter_b,
232 gpointer user_data)
233{
234 GNCPrice *price_a, *price_b;
235 time64 time_a, time_b;
236 gboolean result;
237
238 if (!get_prices (f_model, f_iter_a, f_iter_b, &price_a, &price_b))
239 return sort_ns_or_cm (f_model, f_iter_a, f_iter_b);
240
241 /* sort by time first */
242 time_a = gnc_price_get_time64 (price_a);
243 time_b = gnc_price_get_time64 (price_b);
244 result = time_a < time_b ? -1 : time_a > time_b ? 1 : 0;
245 if (result)
246 /* Reverse the result to present the most recent quote first. */
247 return -result;
248
249 return default_sort (price_a, price_b);
250}
251
252static gint
253sort_by_source (GtkTreeModel *f_model,
254 GtkTreeIter *f_iter_a,
255 GtkTreeIter *f_iter_b,
256 gpointer user_data)
257{
258 GNCPrice *price_a, *price_b;
259 gint result;
260
261 if (!get_prices (f_model, f_iter_a, f_iter_b, &price_a, &price_b))
262 return sort_ns_or_cm (f_model, f_iter_a, f_iter_b);
263
264 /* sort by source first */
265 result = gnc_price_get_source (price_a) < gnc_price_get_source (price_b);
266 if (result != 0)
267 return result;
268
269 return default_sort (price_a, price_b);
270}
271
272static gint
273sort_by_type (GtkTreeModel *f_model,
274 GtkTreeIter *f_iter_a,
275 GtkTreeIter *f_iter_b,
276 gpointer user_data)
277{
278 GNCPrice *price_a, *price_b;
279 gint result;
280
281 if (!get_prices (f_model, f_iter_a, f_iter_b, &price_a, &price_b))
282 return sort_ns_or_cm (f_model, f_iter_a, f_iter_b);
283
284 /* sort by source first */
285 result = safe_utf8_collate (gnc_price_get_typestr (price_a),
286 gnc_price_get_typestr (price_b));
287 if (result != 0)
288 return result;
289
290 return default_sort (price_a, price_b);
291}
292
293static gint
294sort_by_value (GtkTreeModel *f_model,
295 GtkTreeIter *f_iter_a,
296 GtkTreeIter *f_iter_b,
297 gpointer user_data)
298{
299 gnc_commodity *comm_a, *comm_b;
300 GNCPrice *price_a, *price_b;
301 gboolean result;
302 gint value;
303
304 if (!get_prices (f_model, f_iter_a, f_iter_b, &price_a, &price_b))
305 return sort_ns_or_cm (f_model, f_iter_a, f_iter_b);
306
307 /*
308 * Sorted by commodity because of the tree structure. Now sort by
309 * currency so we're only comparing numbers in the same currency
310 * denomination.
311 */
312 comm_a = gnc_price_get_currency (price_a);
313 comm_b = gnc_price_get_currency (price_b);
314 if (comm_a && comm_b)
315 {
318 if (value != 0)
319 return value;
322 if (value != 0)
323 return value;
324 }
325
326 /*
327 * Now do the actual price comparison now we're sure that its an
328 * apples to apples comparison.
329 */
330 result = gnc_numeric_compare (gnc_price_get_value (price_a),
331 gnc_price_get_value (price_b));
332 if (result)
333 return result;
334
335 return default_sort (price_a, price_b);
336}
337
338
339/************************************************************/
340/* New View Creation */
341/************************************************************/
342
343/*
344 * Create a new price tree view with (optional) top level root node.
345 * This view will be based on a model that is common to all view of
346 * the same set of books, but will have its own private filter on that
347 * model.
348 */
349GtkTreeView *
351 const gchar *first_property_name,
352 ...)
353{
354 GncTreeView *view;
355 GtkTreeModel *model, *f_model, *s_model;
356 GtkTreeViewColumn *col;
357 GNCPriceDB *price_db;
358 va_list var_args;
359 const gchar *sample_text;
360 gchar *sample_text2;
361
362 ENTER(" ");
363 /* Create/get a pointer to the existing model for this set of books. */
364 price_db = gnc_pricedb_get_db(book);
365 model = gnc_tree_model_price_new (book, price_db);
366
367 /* Set up the view private filter on the common model. */
368 f_model = gtk_tree_model_filter_new (model, NULL);
369 g_object_unref(G_OBJECT(model));
370 s_model = gtk_tree_model_sort_new_with_model (f_model);
371 g_object_unref(G_OBJECT(f_model));
372
373 /* Create our view */
374 view = g_object_new (GNC_TYPE_TREE_VIEW_PRICE,
375 "name", "gnc-id-price-tree", NULL);
376 gtk_tree_view_set_model (GTK_TREE_VIEW (view), s_model);
377 g_object_unref(G_OBJECT(s_model));
378
379 DEBUG("model ref count is %d", G_OBJECT(model)->ref_count);
380 DEBUG("f_model ref count is %d", G_OBJECT(f_model)->ref_count);
381 DEBUG("s_model ref count is %d", G_OBJECT(s_model)->ref_count);
382
384 sample_text2 = g_strdup_printf("%s%s", sample_text, sample_text);
386 view, _("Security"), "security", NULL, sample_text2,
387 GNC_TREE_MODEL_PRICE_COL_COMMODITY,
388 GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
389 sort_by_name);
390 g_free(sample_text2);
392 view, _("Currency"), "currency", NULL, sample_text,
393 GNC_TREE_MODEL_PRICE_COL_CURRENCY,
394 GNC_TREE_MODEL_PRICE_COL_VISIBILITY,
395 sort_by_name);
396 g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
398 view, _("Date"), "date", NULL, "2005-05-20",
399 GNC_TREE_MODEL_PRICE_COL_DATE,
400 GNC_TREE_MODEL_PRICE_COL_VISIBILITY,
401 sort_by_date);
402 g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
404 view, _("Source"), "source", NULL, "Finance::Quote",
405 GNC_TREE_MODEL_PRICE_COL_SOURCE,
406 GNC_TREE_MODEL_PRICE_COL_VISIBILITY,
407 sort_by_source);
408 g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
410 view, _("Type"), "type", NULL, "last",
411 GNC_TREE_MODEL_PRICE_COL_TYPE,
412 GNC_TREE_MODEL_PRICE_COL_VISIBILITY,
413 sort_by_type);
414 g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
416 view, _("Price"), "price", "100.00000",
417 GNC_TREE_MODEL_PRICE_COL_VALUE,
418 GNC_TREE_VIEW_COLUMN_COLOR_NONE,
419 GNC_TREE_MODEL_PRICE_COL_VISIBILITY,
420 sort_by_value);
421 g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
422
424
425 /* Set properties */
426 va_start (var_args, first_property_name);
427 g_object_set_valist (G_OBJECT(view), first_property_name, var_args);
428 va_end (var_args);
429
430 /* Sort on the commodity column by default. This allows for a consistent
431 * sort if commodities are removed and re-added from the model. */
432 if (!gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(s_model),
433 NULL, NULL))
434 {
435 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(s_model),
436 GNC_TREE_MODEL_PRICE_COL_COMMODITY,
437 GTK_SORT_ASCENDING);
438 }
439
440 gtk_widget_show(GTK_WIDGET(view));
441 LEAVE(" %p", view);
442 return GTK_TREE_VIEW(view);
443}
444
445/************************************************************/
446/* Auxiliary Functions */
447/************************************************************/
448
449#define debug_path(fn, path) { \
450 gchar *path_string = gtk_tree_path_to_string(path); \
451 fn("tree path %s", path_string); \
452 g_free(path_string); \
453 }
454
455#if 0 /* Not Used */
456static gboolean
457gnc_tree_view_price_get_iter_from_price (GncTreeViewPrice *view,
458 GNCPrice *price,
459 GtkTreeIter *s_iter)
460{
461 GtkTreeModel *model, *f_model, *s_model;
462 GtkTreeIter iter, f_iter;
463
464 g_return_val_if_fail(GNC_IS_TREE_VIEW_PRICE(view), FALSE);
465 g_return_val_if_fail(price != NULL, FALSE);
466 g_return_val_if_fail(s_iter != NULL, FALSE);
467
468 ENTER("view %p, price %p", view, price);
469
470 /* Reach down to the real model and get an iter for this price */
471 s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
472 f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
473 model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
474 if (!gnc_tree_model_price_get_iter_from_price (GNC_TREE_MODEL_PRICE(model), price, &iter))
475 {
476 LEAVE("model_get_iter_from_price failed");
477 return FALSE;
478 }
479
480 /* convert back to a sort iter */
481 gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER(f_model),
482 &f_iter, &iter);
483 gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT(s_model),
484 s_iter, &f_iter);
485 LEAVE(" ");
486 return TRUE;
487}
488#endif /* Not Used */
489
490/************************************************************/
491/* Price Tree View Filter Functions */
492/************************************************************/
493
494/************************************************************/
495/* Price Tree View Visibility Filter */
496/************************************************************/
497
498typedef struct
499{
501 gnc_tree_view_price_cm_filter_func user_cm_fn;
502 gnc_tree_view_price_pc_filter_func user_pc_fn;
503 gpointer user_data;
504 GDestroyNotify user_destroy;
506
507static void
508gnc_tree_view_price_filter_destroy (gpointer data)
509{
510 filter_user_data *fd = data;
511
512 if (fd->user_destroy)
513 fd->user_destroy(fd->user_data);
514 g_free(fd);
515}
516
517static gboolean
518gnc_tree_view_price_filter_helper (GtkTreeModel *model,
519 GtkTreeIter *iter,
520 gpointer data)
521{
522 gnc_commodity_namespace *name_space;
523 gnc_commodity *commodity;
524 GNCPrice *price;
525 filter_user_data *fd = data;
526
527 g_return_val_if_fail (GNC_IS_TREE_MODEL_PRICE (model), FALSE);
528 g_return_val_if_fail (iter != NULL, FALSE);
529
530 if (gnc_tree_model_price_iter_is_namespace (GNC_TREE_MODEL_PRICE(model), iter))
531 {
532 if (fd->user_ns_fn)
533 {
534 name_space = gnc_tree_model_price_get_namespace (GNC_TREE_MODEL_PRICE(model), iter);
535 return fd->user_ns_fn(name_space, fd->user_data);
536 }
537 return TRUE;
538 }
539
540 if (gnc_tree_model_price_iter_is_commodity (GNC_TREE_MODEL_PRICE(model), iter))
541 {
542 if (fd->user_cm_fn)
543 {
544 commodity = gnc_tree_model_price_get_commodity (GNC_TREE_MODEL_PRICE(model), iter);
545 return fd->user_cm_fn(commodity, fd->user_data);
546 }
547 return TRUE;
548 }
549
550 if (gnc_tree_model_price_iter_is_price (GNC_TREE_MODEL_PRICE(model), iter))
551 {
552 if (fd->user_pc_fn)
553 {
554 price = gnc_tree_model_price_get_price (GNC_TREE_MODEL_PRICE(model), iter);
555 return fd->user_pc_fn(price, fd->user_data);
556 }
557 return TRUE;
558 }
559
560 return FALSE;
561}
562
563/*
564 * Set an GtkTreeModel visible filter on this price. This filter will be
565 * called for each price that the tree is about to show, and the
566 * price will be passed to the callback function.
567 */
568void
569gnc_tree_view_price_set_filter (GncTreeViewPrice *view,
571 gnc_tree_view_price_cm_filter_func cm_func,
572 gnc_tree_view_price_pc_filter_func pc_func,
573 gpointer data,
574 GDestroyNotify destroy)
575{
576 GtkTreeModel *f_model, *s_model;
577 filter_user_data *fd = data;
578
579 ENTER("view %p, ns func %p, cm func %p, pc func %p, data %p, destroy %p",
580 view, ns_func, cm_func, pc_func, data, destroy);
581
582 g_return_if_fail(GNC_IS_TREE_VIEW_PRICE(view));
583 g_return_if_fail((ns_func != NULL) || (cm_func != NULL));
584
585 fd = g_malloc(sizeof(filter_user_data));
586 fd->user_ns_fn = ns_func;
587 fd->user_cm_fn = cm_func;
588 fd->user_pc_fn = pc_func;
589 fd->user_data = data;
590 fd->user_destroy = destroy;
591
592 s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
593 f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
594
595 /* disconnect model from view */
596 g_object_ref (G_OBJECT(s_model));
597 gtk_tree_view_set_model (GTK_TREE_VIEW(view), NULL);
598
599 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (f_model),
600 gnc_tree_view_price_filter_helper,
601 fd,
602 gnc_tree_view_price_filter_destroy);
603
604 /* Whack any existing levels. The top two levels have been created
605 * before this routine can be called. Unfortunately, if the just
606 * applied filter filters out all the nodes in the tree, the gtk
607 * code throws a critical error. This occurs when there are no
608 * prices in the price database. Once the very first price has been
609 * added this error message goes away. */
610 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (f_model));
611
612 /* connect model to view */
613 gtk_tree_view_set_model (GTK_TREE_VIEW(view), s_model);
614 g_object_unref (G_OBJECT(s_model));
615
616 LEAVE(" ");
617}
618
619/************************************************************/
620/* Price Tree View Get/Set Functions */
621/************************************************************/
622
623/*
624 * Retrieve the selected price from an price tree view. The
625 * price tree must be in single selection mode.
626 */
627GNCPrice *
629{
630 GtkTreeSelection *selection;
631 GtkTreeModel *model, *f_model, *s_model;
632 GtkTreeIter iter, f_iter, s_iter;
633 GNCPrice *price;
634
635 ENTER("view %p", view);
636 g_return_val_if_fail (GNC_IS_TREE_VIEW_PRICE (view), NULL);
637
638 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view));
639 if (!gtk_tree_selection_get_selected (selection, &s_model, &s_iter))
640 {
641 LEAVE("no price, get_selected failed");
642 return FALSE;
643 }
644
645 gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model),
646 &f_iter, &s_iter);
647
648 f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
649 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (f_model),
650 &iter, &f_iter);
651
652 model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
653 price = gnc_tree_model_price_get_price (GNC_TREE_MODEL_PRICE(model),
654 &iter);
655 LEAVE("price %p", price);
656 return price;
657}
658
659/*
660 * Selects a single price in the price tree view. The price
661 * tree must be in single selection mode.
662 */
663void
665 GNCPrice *price)
666{
667 GtkTreeModel *model, *f_model, *s_model;
668 GtkTreePath *path, *f_path, *s_path, *parent_path;
669 GtkTreeSelection *selection;
670
671 ENTER("view %p, price %p", view, price);
672
673 /* Clear any existing selection. */
674 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
675 gtk_tree_selection_unselect_all (selection);
676
677 if (price == NULL)
678 return;
679
680 s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
681 f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
682 model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (f_model));
683
684 path = gnc_tree_model_price_get_path_from_price (GNC_TREE_MODEL_PRICE(model), price);
685 if (path == NULL)
686 {
687 LEAVE("get_path_from_price failed");
688 return;
689 }
690 debug_path(DEBUG, path);
691
692 f_path = gtk_tree_model_filter_convert_child_path_to_path (GTK_TREE_MODEL_FILTER (f_model),
693 path);
694 gtk_tree_path_free(path);
695 if (f_path == NULL)
696 {
697 LEAVE("no filter path");
698 return;
699 }
700 debug_path(DEBUG, f_path);
701
702 s_path = gtk_tree_model_sort_convert_child_path_to_path (GTK_TREE_MODEL_SORT (s_model),
703 f_path);
704 gtk_tree_path_free(f_path);
705 if (s_path == NULL)
706 {
707 LEAVE("no sort path");
708 return;
709 }
710
711 /* gtk_tree_view requires that a row be visible before it can be selected */
712 parent_path = gtk_tree_path_copy (s_path);
713 if (gtk_tree_path_up (parent_path))
714 {
715 /* This function is misnamed. It expands the actual item
716 * specified, not the path to the item specified. I.E. It expands
717 * one level too many, thus the get of the parent. */
718 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(view), parent_path);
719 }
720 gtk_tree_path_free(parent_path);
721
722 gtk_tree_selection_select_path (selection, s_path);
723 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW(view), s_path, NULL, FALSE, 0.0, 0.0);
724 debug_path(LEAVE, s_path);
725 gtk_tree_path_free(s_path);
726}
727
728/*
729 * This helper function is called once for each row in the tree view
730 * that is currently selected. Its task is to add the corresponding
731 * price to the end of a glist.
732 */
733static void
734get_selected_prices_helper (GtkTreeModel *s_model,
735 GtkTreePath *s_path,
736 GtkTreeIter *s_iter,
737 gpointer data)
738{
739 GList **return_list = data;
740 GtkTreeModel *model, *f_model;
741 GtkTreeIter iter, f_iter;
742 GNCPrice *price;
743
744 gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model),
745 &f_iter, s_iter);
746
747 f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
748 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (f_model),
749 &iter, &f_iter);
750
751 model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
752 price = gnc_tree_model_price_get_price (GNC_TREE_MODEL_PRICE(model),
753 &iter);
754 if (price)
755 *return_list = g_list_prepend (*return_list, price);
756}
757
758/*
759 * Given a price tree view, return a list of the selected prices. The
760 * price tree must be in multiple selection mode.
761 *
762 * Note: It is the responsibility of the caller to free the returned
763 * list.
764 */
765GList *
767{
768 GtkTreeSelection *selection;
769 GList *return_list = NULL;
770
771 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view));
772 gtk_tree_selection_selected_foreach(selection, get_selected_prices_helper, &return_list);
773 return g_list_reverse (return_list);
774}
775
776static void
777get_selected_commodity_helper (GtkTreeModel *s_model,
778 GtkTreePath *s_path,
779 GtkTreeIter *s_iter,
780 gpointer data)
781{
782 GList **return_list = data;
783 GtkTreeModel *model, *f_model;
784 GtkTreeIter iter, f_iter;
785 gnc_commodity *commodity;
786
787 gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model),
788 &f_iter, s_iter);
789
790 f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
791 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (f_model),
792 &iter, &f_iter);
793
794 model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
795 commodity = gnc_tree_model_price_get_commodity (GNC_TREE_MODEL_PRICE(model), &iter);
796
797 if (commodity)
798 *return_list = g_list_prepend (*return_list, commodity);
799}
800
801/*
802 * Given a price tree view, return a list of the selected rows that have
803 * commodities but are not prices, the parent rows for prices. The
804 * price tree must be in multiple selection mode.
805 *
806 * Note: It is the responsibility of the caller to free the returned
807 * list.
808 */
809GList *
811{
812 GtkTreeSelection *selection;
813 GList *return_list = NULL;
814
815 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view));
816 gtk_tree_selection_selected_foreach (selection, get_selected_commodity_helper, &return_list);
817 return g_list_reverse (return_list);
818}
All type declarations for the whole Gnucash engine.
GLib helper routines.
Gnome specific utility functions.
a simple price database for gnucash
GtkTreeModel implementation for gnucash price database.
GtkTreeView implementation for gnucash price tree.
common utilities for manipulating a GtkTreeView within gnucash
utility functions for the GnuCash UI
const char * gnc_commodity_get_namespace(const gnc_commodity *cm)
Retrieve the namespace for the specified commodity.
const char * gnc_commodity_get_printname(const gnc_commodity *cm)
Retrieve the 'print' name for the specified commodity.
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
const char * gnc_commodity_namespace_get_gui_name(const gnc_commodity_namespace *ns)
Return the textual name of a namespace data structure in a form suitable to present to the user.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
void gnc_tree_view_configure_columns(GncTreeView *view)
Make all the correct columns visible, respecting their default visibility setting,...
GtkTreeViewColumn * gnc_tree_view_add_text_column(GncTreeView *view, const gchar *column_title, const gchar *pref_name, const gchar *icon_name, const gchar *sizing_text, gint model_data_column, gint model_visibility_column, GtkTreeIterCompareFunc column_sort_fn)
This function adds a new text column to a GncTreeView base view.
GtkTreeViewColumn * gnc_tree_view_add_numeric_column(GncTreeView *view, const gchar *column_title, const gchar *pref_name, const gchar *sizing_text, gint model_data_column, gint model_color_column, gint model_visibility_column, GtkTreeIterCompareFunc column_sort_fn)
This function adds a new numeric column to a GncTreeView base view.
gboolean(* gnc_tree_view_price_ns_filter_func)(gnc_commodity_namespace *, gpointer data)
This function attaches a filter function to the given price tree.
GNCPrice * gnc_tree_view_price_get_selected_price(GncTreeViewPrice *view)
This function returns the price associated with the selected item in the price tree view.
void gnc_tree_view_price_set_selected_price(GncTreeViewPrice *view, GNCPrice *price)
This function selects an price in the price tree view.
gnc_commodity_namespace * gnc_tree_model_price_get_namespace(GncTreeModelPrice *model, GtkTreeIter *iter)
Convert a model/iter pair to a gnucash commodity namespace.
GtkTreePath * gnc_tree_model_price_get_path_from_price(GncTreeModelPrice *model, GNCPrice *price)
Convert a price pointer into a GtkTreePath.
GtkTreeModel * gnc_tree_model_price_new(QofBook *book, GNCPriceDB *price_db)
Create a new GtkTreeModel for manipulating gnucash commodity prices.
gboolean gnc_tree_model_price_iter_is_commodity(GncTreeModelPrice *model, GtkTreeIter *iter)
Determine whether or not the specified GtkTreeIter points to a commodity.
gboolean gnc_tree_model_price_iter_is_price(GncTreeModelPrice *model, GtkTreeIter *iter)
Determine whether or not the specified GtkTreeIter points to a price.
GtkTreeView * gnc_tree_view_price_new(QofBook *book, const gchar *first_property_name,...)
Create a new price tree view.
GList * gnc_tree_view_price_get_selected_commodities(GncTreeViewPrice *view)
This function returns a list of commodities associated with the selected rows that are not prices but...
gnc_commodity * gnc_tree_model_price_get_commodity(GncTreeModelPrice *model, GtkTreeIter *iter)
Convert a model/iter pair to a gnucash commodity.
GNCPrice * gnc_tree_model_price_get_price(GncTreeModelPrice *model, GtkTreeIter *iter)
Convert a model/iter pair to a gnucash price.
gboolean gnc_tree_model_price_iter_is_namespace(GncTreeModelPrice *model, GtkTreeIter *iter)
Determine whether or not the specified GtkTreeIter points to a "commodity namespace".
GList * gnc_tree_view_price_get_selected_prices(GncTreeViewPrice *view)
This function returns a list of the prices associated with the selected items in the price tree view.
gboolean gnc_tree_model_price_get_iter_from_price(GncTreeModelPrice *model, GNCPrice *price, GtkTreeIter *iter)
Convert a price pointer into a GtkTreeIter.
gnc_commodity * gnc_default_currency(void)
Return the default currency set by the user.
int safe_utf8_collate(const char *da, const char *db)
Collate two UTF-8 strings.
#define gnc_leave_return_if_fail(test)
Replacement for g_return_if_fail, but calls LEAVE if the test fails.
Definition qoflog.h:300
#define DEBUG(format, args...)
Print a debugging message.
Definition qoflog.h:264
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b
GNCPriceDB * gnc_pricedb_get_db(QofBook *book)
Return the pricedb associated with the book.
QofBook reference.
Definition qofbook-p.hpp:47