GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-query-view.c
1/********************************************************************\
2 * gnc-query-view.c -- A query display view. *
3 * Copyright (C) 2003 Derek Atkins <derek@ihtfp.com> *
4 * Copyright (C) 2012 Robert Fewell *
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#include <config.h>
25
26#include <gtk/gtk.h>
27
28#include "dialog-utils.h"
29#include "gnc-ui-util.h"
30#include "qof.h"
31#include "gnc-component-manager.h"
32#include "gnc-query-view.h"
33#include "search-param.h"
34
35/* This static indicates the debugging module that this .o belongs to. */
36static QofLogModule log_module = GNC_MOD_GUI;
37
38/* Signal codes */
39enum
40{
41 COLUMN_TOGGLED,
42 ROW_SELECTED,
43 DOUBLE_CLICK_ENTRY,
44 LAST_SIGNAL
45};
46
47typedef struct _GNCQueryViewPrivate GNCQueryViewPrivate;
48
50{
51 const QofParam *get_guid;
52 gint component_id;
53};
54
55G_DEFINE_TYPE_WITH_PRIVATE(GNCQueryView, gnc_query_view, GTK_TYPE_TREE_VIEW)
56
57#define GNC_QUERY_VIEW_GET_PRIVATE(o) \
58 ((GNCQueryViewPrivate*)gnc_query_view_get_instance_private((GNCQueryView*)o))
59
61static guint query_view_signals[LAST_SIGNAL] = {0};
62
64static void gnc_query_view_init_view (GNCQueryView *qview);
65static void gnc_query_view_select_row_cb (GtkTreeSelection *selection,
66 gpointer user_data);
67static void gnc_query_view_toggled_cb (GtkCellRendererToggle *cell_renderer,
68 gchar *path, gpointer user_data);
69static void gnc_query_view_double_click_cb (GtkTreeView *tree_view,
70 GtkTreePath *path,
71 GtkTreeViewColumn *column,
72 gpointer user_data);
73
74static void gnc_query_view_destroy (GtkWidget *widget);
75static void gnc_query_view_fill (GNCQueryView *qview);
76static void gnc_query_view_set_query_sort (GNCQueryView *qview,
77 gboolean new_column);
78
79
80/********************************************************************\
81 * gnc_query_view_new *
82 * creates the query view *
83 * *
84 * Args: param_list - the list of params *
85 * query - the query to use to find entries *
86 * Returns: the query view widget, or NULL if there was a problem. *
87\********************************************************************/
88void
89gnc_query_view_construct (GNCQueryView *qview, GList *param_list, Query *query)
90{
91 GNCQueryViewPrivate *priv;
92
93 g_return_if_fail (qview);
94 g_return_if_fail (param_list);
95 g_return_if_fail (query);
96 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
97
98 /* more configuration */
99 qview->query = qof_query_copy (query);
100 qview->column_params = param_list;
101
102 /* cache the function to get the guid of this query type */
103 priv = GNC_QUERY_VIEW_GET_PRIVATE(qview);
104 priv->get_guid = qof_class_get_parameter (qof_query_get_search_for (query),
105 QOF_PARAM_GUID);
106
107 /* Initialize the Tree View */
108 gnc_query_view_init_view (qview);
109
110 /* Set initial sort order */
111 gnc_query_view_set_query_sort (qview, TRUE);
112}
113
114GtkWidget *
115gnc_query_view_new (GList *param_list, Query *query)
116{
117 GNCQueryView *qview;
118 GtkListStore *liststore;
119 GList *node;
120 gint columns, i;
121 gsize array_size;
122 GType *types;
123
124 g_return_val_if_fail (param_list, NULL);
125 g_return_val_if_fail (query, NULL);
126
127 /* Add 1 to param_list length for extra pointer column */
128 columns = g_list_length (param_list) + 1;
129 qview = GNC_QUERY_VIEW(g_object_new (gnc_query_view_get_type (), NULL));
130
131 array_size = sizeof(GType) * columns;
132 types = g_slice_alloc (array_size);
133
134 types[0] = G_TYPE_POINTER;
135
136 /* Get the types for the list store */
137 for (i = 0, node = param_list; node; node = node->next, i++)
138 {
139 GNCSearchParamSimple *param = node->data;
140 const char *type;
141
142 g_assert (GNC_IS_SEARCH_PARAM_SIMPLE(param));
143
144 type = gnc_search_param_get_param_type ((GNCSearchParam *) param);
145
146 if (g_strcmp0 (type, QOF_TYPE_BOOLEAN) == 0)
147 types[i+1] = G_TYPE_BOOLEAN;
148 else
149 types[i+1] = G_TYPE_STRING;
150 }
151
152 /* Create the list store and add to treeview */
153 liststore = gtk_list_store_newv (columns, types );
154 gtk_tree_view_set_model (GTK_TREE_VIEW(qview), GTK_TREE_MODEL(liststore));
155 g_object_unref (liststore);
156
157 /* Free array */
158 g_slice_free1 (array_size, types);
159
160 gnc_query_view_construct (qview, param_list, query);
161
162 return GTK_WIDGET(qview);
163}
164
165void gnc_query_view_reset_query (GNCQueryView *qview, Query *query)
166{
167 g_return_if_fail (qview);
168 g_return_if_fail (query);
169 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
170
171 qof_query_destroy (qview->query);
172 qview->query = qof_query_copy (query);
173
174 gnc_query_view_set_query_sort (qview, TRUE);
175}
176
177static void
178gnc_query_view_refresh_handler (GHashTable *changes, gpointer user_data)
179{
180 GNCQueryView *qview = (GNCQueryView *)user_data;
181 g_return_if_fail (qview);
182 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
183
184 gnc_query_view_set_query_sort (qview, TRUE);
185}
186
187static void
188gnc_query_view_init (GNCQueryView *qview)
189{
190 GNCQueryViewPrivate *priv;
191
192 // Set the name for this widget so it can be easily manipulated with css
193 gtk_widget_set_name (GTK_WIDGET(qview), "gnc-id-query-view-view");
194
195 qview->query = NULL;
196
197 qview->num_columns = 0;
198 qview->column_params = NULL;
199
200 qview->use_scroll_to_selection = FALSE;
201
202 qview->sort_column = 0;
203 qview->increasing = FALSE;
204
205 qview->numeric_abs = FALSE;
206 qview->numeric_inv_sort = FALSE;
207
208 priv = GNC_QUERY_VIEW_GET_PRIVATE(qview);
209 priv->component_id = gnc_register_gui_component ("gnc-query-view-cm-class",
210 gnc_query_view_refresh_handler,
211 NULL, qview);
212}
213
214static gint
215sort_iter_compare_func (GtkTreeModel *model,
216 GtkTreeIter *a,
217 GtkTreeIter *b,
218 gpointer userdata)
219{
220 /* This is really a dummy sort function, it leaves the list as is. */
221 return 0;
222}
223
224/********************************************************************\
225 * gnc_query_sort_order *
226 * allows the sort order to be specified *
227 * *
228 * Args: qview - the view to sort *
229 * column - the sort column in the tree view, 1 -> *
230 * order - GTK_SORT_ASCENDING or GTK_SORT_DESCENDING *
231\********************************************************************/
232void
233gnc_query_sort_order (GNCQueryView *qview, gint column, GtkSortType order)
234{
235 GtkTreeSortable *sortable;
236 gint sortcol;
237
238 g_return_if_fail (qview != NULL);
239 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
240
241 sortable = GTK_TREE_SORTABLE(gtk_tree_view_get_model (GTK_TREE_VIEW(qview)));
242
243 if((column > qview->num_columns) || (column == 0) )
244 sortcol = 1;
245 else
246 sortcol = column;
247
248 gtk_tree_sortable_set_sort_column_id (sortable, sortcol, order);
249}
250
251static void
252gnc_query_sort_cb (GtkTreeSortable *sortable, gpointer user_data)
253{
254 GNCQueryView *qview = GNC_QUERY_VIEW(user_data);
255 GtkSortType type;
256 gint sortcol;
257 gboolean new_column = FALSE;
258
259 g_return_if_fail (qview != NULL);
260 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
261 g_return_if_fail (qview->query != NULL);
262
263 gtk_tree_sortable_get_sort_column_id (sortable, &sortcol, &type);
264
265 /* We need to subtract 1 for the added pointer column in the liststore
266 which is not displayed to align back to params */
267 sortcol = sortcol - 1;
268
269 if(type == GTK_SORT_ASCENDING)
270 qview->increasing = TRUE;
271 else
272 qview->increasing = FALSE;
273
274 /* Is this a new column or a re-click on the existing column? */
275 new_column = (qview->sort_column != sortcol);
276
277 /* Save the column */
278 qview->sort_column = sortcol;
279
280 gnc_query_view_set_query_sort (qview, new_column);
281}
282
283static void
284gnc_query_view_init_view (GNCQueryView *qview)
285{
286 GtkTreeView *view = GTK_TREE_VIEW(qview);
287 GtkTreeSortable *sortable;
288 GtkTreeSelection *selection;
289 GtkTreeViewColumn *col;
290 GtkCellRenderer *renderer;
291 GList *node;
292 gint i;
293
294 sortable = GTK_TREE_SORTABLE(gtk_tree_view_get_model (GTK_TREE_VIEW(view)));
295
296 /* compute the number of columns and fill in the rest of the view */
297 qview->num_columns = g_list_length (qview->column_params);
298
299 // Set grid lines option to preference
300 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW(view), gnc_tree_view_get_grid_lines_pref ());
301
302 for (i = 0, node = qview->column_params; node; node = node->next, i++)
303 {
304 const char *type;
305 gfloat algn = 0;
306 GNCSearchParamSimple *param = node->data;
307
308 g_assert (GNC_IS_SEARCH_PARAM_SIMPLE(param));
309
310 col = gtk_tree_view_column_new ();
311
312 /* Set the column title */
313 gtk_tree_view_column_set_title (col, gnc_search_param_get_title (GNC_SEARCH_PARAM (param)));
314
315 /* pack tree view column into tree view */
316 gtk_tree_view_append_column (view, col);
317
318 /* Get justification */
319 if (gnc_search_param_get_justify (GNC_SEARCH_PARAM (param)) == GTK_JUSTIFY_CENTER)
320 algn = 0.5;
321 else if (gnc_search_param_get_justify (GNC_SEARCH_PARAM (param)) == GTK_JUSTIFY_RIGHT)
322 {
323 /* GTK_JUSTIFY_RIGHT is only used for monetary values so right align
324 * the column title and data for both ltr and rtl */
325 if (gtk_widget_get_direction (GTK_WIDGET(view)) != GTK_TEXT_DIR_RTL)
326 algn = 1.0;
327 }
328
329 /* Set the column title alignment to that of the column */
330 gtk_tree_view_column_set_alignment (col, algn);
331
332 /* Set column resizable */
333 if (gnc_search_param_get_non_resizeable (GNC_SEARCH_PARAM (param)))
334 {
335 gtk_tree_view_column_set_resizable (col, FALSE);
336 gtk_tree_view_column_set_expand (col, FALSE);
337 }
338 else
339 gtk_tree_view_column_set_resizable (col, TRUE);
340
341 /* Set column clickable */
342 if (gnc_search_param_get_passive (GNC_SEARCH_PARAM (param)))
343 gtk_tree_view_column_set_clickable (col, FALSE);
344 else
345 {
346 gtk_tree_view_column_set_clickable (col, TRUE);
347 /* Add sortable columns */
348 gtk_tree_view_column_set_sort_column_id (col, i+1);
349 gtk_tree_sortable_set_sort_func (sortable, i+1,
350 sort_iter_compare_func,
351 GINT_TO_POINTER(i+1), NULL);
352 }
353
354 type = gnc_search_param_get_param_type (((GNCSearchParam *) param));
355
356 if (g_strcmp0 (type, QOF_TYPE_BOOLEAN) == 0)
357 {
358 renderer = gtk_cell_renderer_toggle_new ();
359
360 /* pack cell renderer toggle into tree view column */
361 gtk_tree_view_column_pack_start (col, renderer, TRUE);
362 gtk_tree_view_column_add_attribute (col, renderer, "active", i+1);
363 g_object_set (renderer, "xalign", algn, NULL);
364 g_object_set_data (G_OBJECT(renderer), "column", GINT_TO_POINTER(i+1));
365 g_signal_connect (renderer, "toggled",
366 G_CALLBACK(gnc_query_view_toggled_cb), view);
367 }
368 else
369 {
370 renderer = gtk_cell_renderer_text_new ();
371
372 /* pack cell renderer text into tree view column */
373 gtk_tree_view_column_pack_start (col, renderer, TRUE);
374 gtk_tree_view_column_add_attribute (col, renderer, "text", i+1);
375 g_object_set (renderer, "xalign", algn, NULL);
376 g_object_set_data (G_OBJECT(renderer), "column", GINT_TO_POINTER(i+1));
377 }
378 }
379
380 /* set initial sort order */
381 gtk_tree_sortable_set_default_sort_func (sortable, NULL, NULL, NULL);
382 gtk_tree_sortable_set_sort_column_id (sortable, 1, GTK_SORT_DESCENDING);
383
384 g_signal_connect (sortable, "sort-column-changed",
385 G_CALLBACK(gnc_query_sort_cb),
386 view);
387
388 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view));
389 g_signal_connect (selection, "changed",
390 G_CALLBACK(gnc_query_view_select_row_cb),
391 NULL);
392
393 g_signal_connect (view, "row-activated",
394 G_CALLBACK(gnc_query_view_double_click_cb),
395 NULL);
396}
397
398static void
399gnc_query_view_class_init (GNCQueryViewClass *klass)
400{
401 GtkWidgetClass *widget_class = (GtkWidgetClass*) klass;
402
403 query_view_signals[COLUMN_TOGGLED] =
404 g_signal_new("column_toggled",
405 G_TYPE_FROM_CLASS(widget_class),
406 G_SIGNAL_RUN_FIRST,
407 G_STRUCT_OFFSET(GNCQueryViewClass, column_toggled),
408 NULL, NULL,
409 g_cclosure_marshal_VOID__POINTER,
410 G_TYPE_NONE,
411 1,
412 G_TYPE_POINTER);
413
414 query_view_signals[ROW_SELECTED] =
415 g_signal_new("row_selected",
416 G_TYPE_FROM_CLASS(widget_class),
417 G_SIGNAL_RUN_FIRST,
418 G_STRUCT_OFFSET(GNCQueryViewClass, row_selected),
419 NULL, NULL,
420 g_cclosure_marshal_VOID__POINTER,
421 G_TYPE_NONE,
422 1,
423 G_TYPE_POINTER);
424
425 query_view_signals[DOUBLE_CLICK_ENTRY] =
426 g_signal_new("double_click_entry",
427 G_TYPE_FROM_CLASS(widget_class),
428 G_SIGNAL_RUN_FIRST,
429 G_STRUCT_OFFSET(GNCQueryViewClass, double_click_entry),
430 NULL, NULL,
431 g_cclosure_marshal_VOID__POINTER,
432 G_TYPE_NONE,
433 1,
434 G_TYPE_POINTER);
435
436 widget_class->destroy = gnc_query_view_destroy;
437
438 klass->column_toggled = NULL;
439 klass->row_selected = NULL;
440 klass->double_click_entry = NULL;
441}
442
443static void
444gnc_query_view_select_row_cb (GtkTreeSelection *selection, gpointer user_data)
445{
446 GNCQueryView *qview = GNC_QUERY_VIEW(gtk_tree_selection_get_tree_view (selection));
447 gint number_of_rows = gtk_tree_selection_count_selected_rows (selection);
448
449 g_signal_emit (qview, query_view_signals[ROW_SELECTED], 0,
450 GINT_TO_POINTER(number_of_rows));
451}
452
453static void
454gnc_query_view_double_click_cb (GtkTreeView *view,
455 GtkTreePath *path,
456 GtkTreeViewColumn *column,
457 gpointer user_data)
458{
459 GNCQueryView *qview = GNC_QUERY_VIEW(view);
460 GtkTreeModel *model;
461 GtkTreeIter iter;
462 gpointer entry = NULL;
463
464 model = gtk_tree_view_get_model (GTK_TREE_VIEW(view));
465
466 if (gtk_tree_model_get_iter (model, &iter, path))
467 gtk_tree_model_get (model, &iter, 0, &entry, -1);
468
469 g_signal_emit (qview, query_view_signals[DOUBLE_CLICK_ENTRY], 0, entry);
470}
471
472static void
473gnc_query_view_toggled_cb (GtkCellRendererToggle *cell_renderer,
474 gchar *path,
475 gpointer user_data)
476{
477 GNCQueryView *qview = GNC_QUERY_VIEW(user_data);
478 GtkTreeModel *model;
479 GtkTreeIter iter;
480 GtkTreePath *treepath;
481 gint *indices;
482 gpointer entry = NULL;
483 gboolean toggled;
484 gint column;
485
486 model = gtk_tree_view_get_model (GTK_TREE_VIEW(qview));
487
488 column = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(cell_renderer), "column"));
489
490 toggled = gtk_cell_renderer_toggle_get_active (cell_renderer);
491
492 treepath = gtk_tree_path_new_from_string (path);
493
494 if (gtk_tree_model_get_iter (model, &iter, treepath))
495 {
496 gtk_tree_model_get (model, &iter, 0, &entry, -1);
497 indices = gtk_tree_path_get_indices (treepath);
498 qview->toggled_row = indices[0];
499 qview->toggled_column = column;
500
501 if(toggled)
502 g_signal_emit (qview, query_view_signals[COLUMN_TOGGLED], 0, GINT_TO_POINTER(0));
503 else
504 g_signal_emit (qview, query_view_signals[COLUMN_TOGGLED], 0, GINT_TO_POINTER(1));
505 }
506 gtk_tree_path_free (treepath);
507}
508
509static void
510gnc_query_view_destroy (GtkWidget *widget)
511{
512 GNCQueryView *qview = GNC_QUERY_VIEW(widget);
513 GNCQueryViewPrivate *priv;
514
515 priv = GNC_QUERY_VIEW_GET_PRIVATE(qview);
516 if (priv->component_id > 0)
517 {
518 gnc_unregister_gui_component (priv->component_id);
519 priv->component_id = 0;
520 }
521
522 /* Remove the query */
523 if (qview->query)
524 {
525 qof_query_destroy (qview->query);
526 qview->query = NULL;
527 }
528
529 GTK_WIDGET_CLASS(gnc_query_view_parent_class)->destroy (widget);
530}
531
532gint
533gnc_query_view_get_num_entries (GNCQueryView *qview)
534{
535 GtkTreeModel *model;
536
537 g_return_val_if_fail (qview != NULL, 0);
538 g_return_val_if_fail (GNC_IS_QUERY_VIEW(qview), 0);
539
540 model = gtk_tree_view_get_model (GTK_TREE_VIEW(qview));
541 return gtk_tree_model_iter_n_children (model, NULL);
542}
543
544gpointer
545gnc_query_view_get_selected_entry (GNCQueryView *qview)
546{
547 gpointer entry = NULL;
548 GList *entries = NULL;
549 gint num_entries = 0;
550
551 g_return_val_if_fail (qview != NULL, NULL);
552 g_return_val_if_fail (GNC_IS_QUERY_VIEW(qview), NULL);
553
554 entries = gnc_query_view_get_selected_entry_list (qview);
555 if (entries)
556 entry = entries->data;
557
558 num_entries = g_list_length (entries);
559 if (num_entries > 1)
560 PWARN ("Expected only one selected entry but found %i. "
561 "Discarding all but the first one.", num_entries);
562
563 g_list_free (entries);
564
565 return entry;
566}
567
568typedef struct
569{
570 GList *entries;
571} acc_data;
572
573static void
574accumulate_entries (GtkTreeModel *model, GtkTreePath *path,
575 GtkTreeIter *iter, gpointer data)
576{
577 acc_data *acc_entries = (acc_data*)data;
578 gpointer entry = NULL;
579 GList *entries = acc_entries->entries;
580
581 gtk_tree_model_get (model, iter, 0, &entry, -1);
582 entries = g_list_prepend (entries, entry);
583 acc_entries->entries = entries;
584}
585
586GList *
587gnc_query_view_get_selected_entry_list (GNCQueryView *qview)
588{
589 GtkTreeSelection *selection;
590 acc_data acc_entries;
591
592 g_return_val_if_fail (qview != NULL, NULL);
593 g_return_val_if_fail (GNC_IS_QUERY_VIEW(qview), NULL);
594
595 acc_entries.entries = NULL;
596 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(qview));
597 gtk_tree_selection_selected_foreach (selection, accumulate_entries,
598 &acc_entries);
599 acc_entries.entries = g_list_reverse (acc_entries.entries);
600 return acc_entries.entries;
601}
602
603void
604gnc_query_use_scroll_to_selection (GNCQueryView *qview, gboolean scroll)
605{
606 g_return_if_fail (qview != NULL);
607 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
608
609 qview->use_scroll_to_selection = scroll;
610}
611
612static void
613scroll_to_selection (GNCQueryView *qview, gboolean override_scroll)
614{
615 GtkTreeSelection *selection;
616 GList *path_list, *node;
617
618 if (!qview->use_scroll_to_selection && !override_scroll)
619 return;
620
621 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(qview));
622
623 /* Ensure last selected item, if any, can be seen */
624 path_list = gtk_tree_selection_get_selected_rows (selection, NULL);
625 node = g_list_last (path_list);
626
627 if (node)
628 {
629 GtkTreePath *tree_path = node->data;
630 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW(qview),
631 tree_path, NULL, FALSE, 0.0, 0.0);
632 }
633 g_list_free_full (path_list, (GDestroyNotify) gtk_tree_path_free);
634}
635
636void
637gnc_query_scroll_to_selection (GNCQueryView *qview)
638{
639 g_return_if_fail (qview != NULL);
640 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
641
642 scroll_to_selection (qview, FALSE);
643}
644
645void
646gnc_query_force_scroll_to_selection (GNCQueryView *qview)
647{
648 g_return_if_fail (qview != NULL);
649 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
650
651 scroll_to_selection (qview, TRUE);
652}
653
654static void
655gnc_query_view_refresh_selected (GNCQueryView *qview, GList *old_entry)
656{
657 GtkTreeModel *model;
658 GtkTreeIter iter;
659 GtkTreeSelection *selection;
660 GList *node;
661 gboolean valid;
662
663 g_return_if_fail (qview != NULL);
664 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
665
666 model = gtk_tree_view_get_model (GTK_TREE_VIEW(qview));
667 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(qview));
668
669 if (g_list_length (old_entry) > 0)
670 {
671 /* Walk the list of old entries */
672 for (node = old_entry; node; node = node->next)
673 {
674 gpointer pointer;
675
676 valid = gtk_tree_model_get_iter_first (model, &iter);
677
678 while (valid)
679 {
680 // Walk through the liststore, reading each row
681 gtk_tree_model_get (model, &iter, 0, &pointer, -1);
682
683 if (pointer == node->data)
684 {
685 gtk_tree_selection_select_iter (selection, &iter);
686 break;
687 }
688 valid = gtk_tree_model_iter_next (model, &iter);
689 }
690 }
691 gnc_query_scroll_to_selection (qview);
692 }
693}
694
695/********************************************************************\
696 * gnc_query_view_refresh *
697 * refreshes the view *
698 * *
699 * Args: qview - view to refresh *
700 * Returns: nothing *
701\********************************************************************/
702void
703gnc_query_view_refresh (GNCQueryView *qview)
704{
705 GtkTreeModel *model;
706 GList *selected_entries;
707
708 g_return_if_fail (qview != NULL);
709 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
710
711 selected_entries = gnc_query_view_get_selected_entry_list (qview);
712 model = gtk_tree_view_get_model (GTK_TREE_VIEW(qview));
713 gtk_list_store_clear (GTK_LIST_STORE(model));
714
715 gnc_query_view_fill (qview);
716 gnc_query_view_refresh_selected (qview, selected_entries);
717 g_list_free (selected_entries);
718}
719
720/********************************************************************\
721 * gnc_query_view_set_query_sort *
722 * sets the sorting order of entries in the view *
723 * *
724 * Args: qview - view to change the sort order for *
725 * new_column - is this a new column (so should we set the *
726 * query sort order or just set the 'increasing' *
727 * Returns: nothing *
728\********************************************************************/
729static void
730gnc_query_view_set_query_sort (GNCQueryView *qview, gboolean new_column)
731{
732 gboolean sort_order = qview->increasing;
733 GList *node;
734 GNCSearchParamSimple *param;
735
736 /* Find the column parameter definition */
737 node = g_list_nth (qview->column_params, qview->sort_column);
738 param = node->data;
739
740 g_assert (GNC_IS_SEARCH_PARAM_SIMPLE(param));
741
742 /* If param values are based on a param function, sorting is not possible */
743 if (gnc_search_param_has_param_fcn (param))
744 {
745 gnc_query_view_refresh (qview);
746 return;
747 }
748
749 /* If we're asked to invert numerics, and if this is a numeric or
750 * debred column, then invert the sort order.
751 */
752 if (qview->numeric_inv_sort)
753 {
754 const char *type = gnc_search_param_get_param_type ((GNCSearchParam *) param);
755 if (!g_strcmp0(type, QOF_TYPE_NUMERIC) ||
756 !g_strcmp0(type, QOF_TYPE_DEBCRED))
757 sort_order = !sort_order;
758 }
759
760 /* Set the sort order for the engine, if the key changed */
761 if (new_column)
762 {
763 GSList *p1, *p2;
764
765 p1 = gnc_search_param_get_param_path (param);
766 p2 = g_slist_prepend (NULL, QUERY_DEFAULT_SORT);
767 qof_query_set_sort_order (qview->query, p1, p2, NULL);
768 }
769
770 qof_query_set_sort_increasing (qview->query,
771 sort_order,
772 sort_order,
773 sort_order);
774
775 gnc_query_view_refresh (qview);
776}
777
778/********************************************************************\
779 * gnc_query_set_expand_column *
780 * sets the column that expands to take up free space starting *
781 * from 0 *
782 * *
783 * Args: qview - view to change the sort order for *
784 * column - the tree view column to set to expand *
785 * Returns: nothing *
786\********************************************************************/
787void
788gnc_query_set_expand_column (GNCQueryView *qview, gint column)
789{
790 g_return_if_fail (qview != NULL);
791 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
792
793 GtkTreeView *view = GTK_TREE_VIEW(qview);
794
795 gint num_columns = gtk_tree_view_get_n_columns (view);
796
797 if (column >= 0 && column < num_columns)
798 {
799 GtkTreeViewColumn *tree_column = gtk_tree_view_get_column (view, column);
800 gtk_tree_view_column_set_expand (tree_column, TRUE);
801 }
802}
803
804/********************************************************************\
805 * gnc_query_view_fill *
806 * Add all items to the list store *
807 * *
808 * Args: qview - view to add item to *
809 * Returns: nothing *
810\********************************************************************/
811static void
812gnc_query_view_fill (GNCQueryView *qview)
813{
814 GNCQueryViewPrivate *priv;
815 GtkTreeModel *model;
816 GtkTreeIter iter;
817 GList *entries, *item;
818 const GncGUID *guid;
819 gint i;
820
821 /* Clear all watches */
822 priv = GNC_QUERY_VIEW_GET_PRIVATE(qview);
823 gnc_gui_component_clear_watches (priv->component_id);
824
825 entries = qof_query_run (qview->query);
826
827 model = gtk_tree_view_get_model (GTK_TREE_VIEW(qview));
828
829 for (item = entries; item; item = item->next)
830 {
831 GList *node;
832 const QofParam *gup;
833 QofParam *qp = NULL;
834
835 /* Add a row to the list store */
836 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
837 /* Add a pointer to the data in the first column of the list store */
838 gtk_list_store_set (GTK_LIST_STORE(model), &iter, 0, item->data, -1);
839
840 for (i = 0, node = qview->column_params; node; node = node->next)
841 {
842 gboolean result;
843 GNCSearchParamSimple *param = node->data;
844 GSList *converters = NULL;
845 const char *type = gnc_search_param_get_param_type ((GNCSearchParam *) param);
846 gpointer res = item->data;
847 gchar *qofstring;
848
849 g_assert (GNC_IS_SEARCH_PARAM_SIMPLE(param));
850 converters = gnc_search_param_get_converters (param);
851
852 /* Test for boolean type */
853 if (g_strcmp0 (type, QOF_TYPE_BOOLEAN) == 0)
854 {
855 result = (gboolean) GPOINTER_TO_INT(gnc_search_param_compute_value (param, res));
856 gtk_list_store_set (GTK_LIST_STORE(model), &iter, i + 1, result, -1);
857 i++;
858 continue;
859 }
860
861 /* Do all the object conversions */
862 for (; converters; converters = converters->next)
863 {
864 qp = converters->data;
865 if (converters->next)
866 res = (qp->param_getfcn)(res, qp);
867 }
868
869 /* Now convert this to a text value for the row */
870 if (qp && (g_strcmp0 (type, QOF_TYPE_DEBCRED) == 0 ||
871 g_strcmp0 (type, QOF_TYPE_NUMERIC) == 0))
872 {
873
874 gnc_numeric (*nfcn)(gpointer, QofParam *) =
875 (gnc_numeric(*)(gpointer, QofParam *))(qp->param_getfcn);
876 gnc_numeric value = nfcn (res, qp);
877
878 if (qview->numeric_abs)
879 value = gnc_numeric_abs (value);
880 gtk_list_store_set (GTK_LIST_STORE(model), &iter, i + 1,
881 xaccPrintAmount (value, gnc_default_print_info (FALSE)), -1);
882 }
883 else
884 {
885 qofstring = qof_query_core_to_string (type, res, qp);
886 gtk_list_store_set (GTK_LIST_STORE(model), &iter, i + 1, qofstring , -1);
887 g_free (qofstring);
888 }
889 i++;
890 }
891 /* and set a watcher on this item */
892 gup = priv->get_guid;
893 guid = (const GncGUID*)((gup->param_getfcn)(item->data, gup));
894 gnc_gui_component_watch_entity (priv->component_id, guid,
895 QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
896 }
897}
898
899/********************************************************************\
900 * gnc_query_view_unselect_all *
901 * unselect all items in the view *
902 * *
903 * Args: qview - view to unselect all *
904 * Returns: nothing *
905\********************************************************************/
906void
907gnc_query_view_unselect_all (GNCQueryView *qview)
908{
909 GtkTreeSelection *selection;
910
911 g_return_if_fail (qview != NULL);
912 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
913
914 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(qview));
915 gtk_tree_selection_unselect_all (selection);
916}
917
918gboolean gnc_query_view_item_in_view (GNCQueryView *qview, gpointer item)
919{
920 GtkTreeModel *model;
921 GtkTreeIter iter;
922 gboolean valid;
923 gpointer pointer;
924
925 g_return_val_if_fail (qview, FALSE);
926 g_return_val_if_fail (item, FALSE);
927 g_return_val_if_fail (GNC_IS_QUERY_VIEW(qview), FALSE);
928
929 model = gtk_tree_view_get_model (GTK_TREE_VIEW(qview));
930 valid = gtk_tree_model_get_iter_first (model, &iter);
931
932 while (valid)
933 {
934 // Walk through the list, reading each row
935 gtk_tree_model_get (model, &iter, 0, &pointer, -1);
936
937 if (pointer == item)
938 return TRUE;
939
940 valid = gtk_tree_model_iter_next (model, &iter);
941 }
942 return FALSE;
943}
944
945void
946gnc_query_view_set_numerics (GNCQueryView *qview, gboolean abs, gboolean inv_sort)
947{
948 g_return_if_fail (qview);
949 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
950
951 qview->numeric_abs = abs;
952 qview->numeric_inv_sort = inv_sort;
953}
utility functions for the GnuCash UI
const QofParam * qof_class_get_parameter(QofIdTypeConst obj_name, const char *parameter)
Return the registered Parameter Definition for the requested parameter.
Definition qofclass.cpp:136
const char * xaccPrintAmount(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
gnc_numeric gnc_numeric_abs(gnc_numeric a)
Returns a newly created gnc_numeric that is the absolute value of the given gnc_numeric value.
#define QUERY_DEFAULT_SORT
Default sort object type.
Definition qofquery.h:105
QofQuery * qof_query_copy(QofQuery *q)
Make a copy of the indicated query.
void qof_query_set_sort_increasing(QofQuery *q, gboolean prim_inc, gboolean sec_inc, gboolean tert_inc)
When a query is run, the results are sorted before being returned.
void qof_query_set_sort_order(QofQuery *q, QofQueryParamList *params1, QofQueryParamList *params2, QofQueryParamList *params3)
When a query is run, the results are sorted before being returned.
char * qof_query_core_to_string(QofType type, gpointer object, QofParam *getter)
Return a printable string for a core data object.
void qof_query_destroy(QofQuery *query)
Frees the resources associate with a Query object.
QofIdType qof_query_get_search_for(const QofQuery *q)
Return the type of data we're querying for.
GList * qof_query_run(QofQuery *query)
Perform the query, return the results.
The type used to store guids in C.
Definition guid.h:75
A Query.
Definition qofquery.cpp:75