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