28 #include "dialog-utils.h" 31 #include "gnc-component-manager.h" 32 #include "gnc-query-view.h" 33 #include "search-param.h" 36 static QofLogModule log_module = GNC_MOD_GUI;
51 const QofParam *get_guid;
55 G_DEFINE_TYPE_WITH_PRIVATE(GNCQueryView, gnc_query_view, GTK_TYPE_TREE_VIEW)
57 #define GNC_QUERY_VIEW_GET_PRIVATE(o) \ 58 ((GNCQueryViewPrivate*)gnc_query_view_get_instance_private((GNCQueryView*)o)) 61 static guint query_view_signals[LAST_SIGNAL] = {0};
64 static void gnc_query_view_init_view (GNCQueryView *qview);
65 static void gnc_query_view_select_row_cb (GtkTreeSelection *selection,
67 static void gnc_query_view_toggled_cb (GtkCellRendererToggle *cell_renderer,
68 gchar *path, gpointer user_data);
69 static void gnc_query_view_double_click_cb (GtkTreeView *tree_view,
71 GtkTreeViewColumn *column,
74 static void gnc_query_view_destroy (GtkWidget *widget);
75 static void gnc_query_view_fill (GNCQueryView *qview);
76 static void gnc_query_view_set_query_sort (GNCQueryView *qview,
89 gnc_query_view_construct (GNCQueryView *qview, GList *param_list,
Query *query)
91 GNCQueryViewPrivate *priv;
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));
100 qview->column_params = param_list;
103 priv = GNC_QUERY_VIEW_GET_PRIVATE(qview);
108 gnc_query_view_init_view (qview);
111 gnc_query_view_set_query_sort (qview, TRUE);
115 gnc_query_view_new (GList *param_list,
Query *query)
118 GtkListStore *liststore;
124 g_return_val_if_fail (param_list, NULL);
125 g_return_val_if_fail (query, NULL);
128 columns = g_list_length (param_list) + 1;
129 qview = GNC_QUERY_VIEW(g_object_new (gnc_query_view_get_type (), NULL));
131 array_size =
sizeof(GType) * columns;
132 types = g_slice_alloc (array_size);
134 types[0] = G_TYPE_POINTER;
137 for (i = 0, node = param_list; node; node = node->next, i++)
139 GNCSearchParamSimple *param = node->data;
142 g_assert (GNC_IS_SEARCH_PARAM_SIMPLE(param));
144 type = gnc_search_param_get_param_type ((GNCSearchParam *) param);
146 if (g_strcmp0 (type, QOF_TYPE_BOOLEAN) == 0)
147 types[i+1] = G_TYPE_BOOLEAN;
149 types[i+1] = G_TYPE_STRING;
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);
158 g_slice_free1 (array_size, types);
160 gnc_query_view_construct (qview, param_list, query);
162 return GTK_WIDGET(qview);
165 void gnc_query_view_reset_query (GNCQueryView *qview,
Query *query)
167 g_return_if_fail (qview);
168 g_return_if_fail (query);
169 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
174 gnc_query_view_set_query_sort (qview, TRUE);
178 gnc_query_view_refresh_handler (GHashTable *changes, gpointer user_data)
180 GNCQueryView *qview = (GNCQueryView *)user_data;
181 g_return_if_fail (qview);
182 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
184 gnc_query_view_set_query_sort (qview, TRUE);
188 gnc_query_view_init (GNCQueryView *qview)
190 GNCQueryViewPrivate *priv;
193 gtk_widget_set_name (GTK_WIDGET(qview),
"gnc-id-query-view-view");
197 qview->num_columns = 0;
198 qview->column_params = NULL;
200 qview->use_scroll_to_selection = FALSE;
202 qview->sort_column = 0;
203 qview->increasing = FALSE;
205 qview->numeric_abs = FALSE;
206 qview->numeric_inv_sort = FALSE;
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,
215 sort_iter_compare_func (GtkTreeModel *model,
233 gnc_query_sort_order (GNCQueryView *qview, gint column, GtkSortType order)
235 GtkTreeSortable *sortable;
238 g_return_if_fail (qview != NULL);
239 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
241 sortable = GTK_TREE_SORTABLE(gtk_tree_view_get_model (GTK_TREE_VIEW(qview)));
243 if((column > qview->num_columns) || (column == 0) )
248 gtk_tree_sortable_set_sort_column_id (sortable, sortcol, order);
252 gnc_query_sort_cb (GtkTreeSortable *sortable, gpointer user_data)
254 GNCQueryView *qview = GNC_QUERY_VIEW(user_data);
257 gboolean new_column = FALSE;
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);
263 gtk_tree_sortable_get_sort_column_id (sortable, &sortcol, &type);
267 sortcol = sortcol - 1;
269 if(type == GTK_SORT_ASCENDING)
270 qview->increasing = TRUE;
272 qview->increasing = FALSE;
275 new_column = (qview->sort_column != sortcol);
278 qview->sort_column = sortcol;
280 gnc_query_view_set_query_sort (qview, new_column);
284 gnc_query_view_init_view (GNCQueryView *qview)
286 GtkTreeView *view = GTK_TREE_VIEW(qview);
287 GtkTreeSortable *sortable;
288 GtkTreeSelection *selection;
289 GtkTreeViewColumn *col;
290 GtkCellRenderer *renderer;
294 sortable = GTK_TREE_SORTABLE(gtk_tree_view_get_model (GTK_TREE_VIEW(view)));
297 qview->num_columns = g_list_length (qview->column_params);
300 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW(view), gnc_tree_view_get_grid_lines_pref ());
302 for (i = 0, node = qview->column_params; node; node = node->next, i++)
306 GNCSearchParamSimple *param = node->data;
308 g_assert (GNC_IS_SEARCH_PARAM_SIMPLE(param));
310 col = gtk_tree_view_column_new ();
313 gtk_tree_view_column_set_title (col, gnc_search_param_get_title (GNC_SEARCH_PARAM (param)));
316 gtk_tree_view_append_column (view, col);
319 if (gnc_search_param_get_justify (GNC_SEARCH_PARAM (param)) == GTK_JUSTIFY_CENTER)
321 else if (gnc_search_param_get_justify (GNC_SEARCH_PARAM (param)) == GTK_JUSTIFY_RIGHT)
325 if (gtk_widget_get_direction (GTK_WIDGET(view)) != GTK_TEXT_DIR_RTL)
330 gtk_tree_view_column_set_alignment (col, algn);
333 if (gnc_search_param_get_non_resizeable (GNC_SEARCH_PARAM (param)))
335 gtk_tree_view_column_set_resizable (col, FALSE);
336 gtk_tree_view_column_set_expand (col, FALSE);
339 gtk_tree_view_column_set_resizable (col, TRUE);
342 if (gnc_search_param_get_passive (GNC_SEARCH_PARAM (param)))
343 gtk_tree_view_column_set_clickable (col, FALSE);
346 gtk_tree_view_column_set_clickable (col, TRUE);
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);
354 type = gnc_search_param_get_param_type (((GNCSearchParam *) param));
356 if (g_strcmp0 (type, QOF_TYPE_BOOLEAN) == 0)
358 renderer = gtk_cell_renderer_toggle_new ();
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);
370 renderer = gtk_cell_renderer_text_new ();
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));
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);
384 g_signal_connect (sortable,
"sort-column-changed",
385 G_CALLBACK(gnc_query_sort_cb),
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),
393 g_signal_connect (view,
"row-activated",
394 G_CALLBACK(gnc_query_view_double_click_cb),
399 gnc_query_view_class_init (GNCQueryViewClass *klass)
401 GtkWidgetClass *widget_class = (GtkWidgetClass*) klass;
403 query_view_signals[COLUMN_TOGGLED] =
404 g_signal_new(
"column_toggled",
405 G_TYPE_FROM_CLASS(widget_class),
407 G_STRUCT_OFFSET(GNCQueryViewClass, column_toggled),
409 g_cclosure_marshal_VOID__POINTER,
414 query_view_signals[ROW_SELECTED] =
415 g_signal_new(
"row_selected",
416 G_TYPE_FROM_CLASS(widget_class),
418 G_STRUCT_OFFSET(GNCQueryViewClass, row_selected),
420 g_cclosure_marshal_VOID__POINTER,
425 query_view_signals[DOUBLE_CLICK_ENTRY] =
426 g_signal_new(
"double_click_entry",
427 G_TYPE_FROM_CLASS(widget_class),
429 G_STRUCT_OFFSET(GNCQueryViewClass, double_click_entry),
431 g_cclosure_marshal_VOID__POINTER,
436 widget_class->destroy = gnc_query_view_destroy;
438 klass->column_toggled = NULL;
439 klass->row_selected = NULL;
440 klass->double_click_entry = NULL;
444 gnc_query_view_select_row_cb (GtkTreeSelection *selection, gpointer user_data)
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);
449 g_signal_emit (qview, query_view_signals[ROW_SELECTED], 0,
450 GINT_TO_POINTER(number_of_rows));
454 gnc_query_view_double_click_cb (GtkTreeView *view,
456 GtkTreeViewColumn *column,
459 GNCQueryView *qview = GNC_QUERY_VIEW(view);
462 gpointer entry = NULL;
464 model = gtk_tree_view_get_model (GTK_TREE_VIEW(view));
466 if (gtk_tree_model_get_iter (model, &iter, path))
467 gtk_tree_model_get (model, &iter, 0, &entry, -1);
469 g_signal_emit (qview, query_view_signals[DOUBLE_CLICK_ENTRY], 0, entry);
473 gnc_query_view_toggled_cb (GtkCellRendererToggle *cell_renderer,
477 GNCQueryView *qview = GNC_QUERY_VIEW(user_data);
480 GtkTreePath *treepath;
482 gpointer entry = NULL;
486 model = gtk_tree_view_get_model (GTK_TREE_VIEW(qview));
488 column = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(cell_renderer),
"column"));
490 toggled = gtk_cell_renderer_toggle_get_active (cell_renderer);
492 treepath = gtk_tree_path_new_from_string (path);
494 if (gtk_tree_model_get_iter (model, &iter, treepath))
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;
502 g_signal_emit (qview, query_view_signals[COLUMN_TOGGLED], 0, GINT_TO_POINTER(0));
504 g_signal_emit (qview, query_view_signals[COLUMN_TOGGLED], 0, GINT_TO_POINTER(1));
506 gtk_tree_path_free (treepath);
510 gnc_query_view_destroy (GtkWidget *widget)
512 GNCQueryView *qview = GNC_QUERY_VIEW(widget);
513 GNCQueryViewPrivate *priv;
515 priv = GNC_QUERY_VIEW_GET_PRIVATE(qview);
516 if (priv->component_id > 0)
518 gnc_unregister_gui_component (priv->component_id);
519 priv->component_id = 0;
529 GTK_WIDGET_CLASS(gnc_query_view_parent_class)->destroy (widget);
533 gnc_query_view_get_num_entries (GNCQueryView *qview)
537 g_return_val_if_fail (qview != NULL, 0);
538 g_return_val_if_fail (GNC_IS_QUERY_VIEW(qview), 0);
540 model = gtk_tree_view_get_model (GTK_TREE_VIEW(qview));
541 return gtk_tree_model_iter_n_children (model, NULL);
545 gnc_query_view_get_selected_entry (GNCQueryView *qview)
547 gpointer entry = NULL;
548 GList *entries = NULL;
549 gint num_entries = 0;
551 g_return_val_if_fail (qview != NULL, NULL);
552 g_return_val_if_fail (GNC_IS_QUERY_VIEW(qview), NULL);
554 entries = gnc_query_view_get_selected_entry_list (qview);
556 entry = entries->data;
558 num_entries = g_list_length (entries);
560 PWARN (
"Expected only one selected entry but found %i. " 561 "Discarding all but the first one.", num_entries);
563 g_list_free (entries);
574 accumulate_entries (GtkTreeModel *model, GtkTreePath *path,
575 GtkTreeIter *iter, gpointer data)
578 gpointer entry = NULL;
579 GList *entries = acc_entries->entries;
581 gtk_tree_model_get (model, iter, 0, &entry, -1);
582 entries = g_list_prepend (entries, entry);
583 acc_entries->entries = entries;
587 gnc_query_view_get_selected_entry_list (GNCQueryView *qview)
589 GtkTreeSelection *selection;
592 g_return_val_if_fail (qview != NULL, NULL);
593 g_return_val_if_fail (GNC_IS_QUERY_VIEW(qview), NULL);
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,
599 acc_entries.entries = g_list_reverse (acc_entries.entries);
600 return acc_entries.entries;
604 gnc_query_use_scroll_to_selection (GNCQueryView *qview, gboolean scroll)
606 g_return_if_fail (qview != NULL);
607 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
609 qview->use_scroll_to_selection = scroll;
613 scroll_to_selection (GNCQueryView *qview, gboolean override_scroll)
615 GtkTreeSelection *selection;
616 GList *path_list, *node;
618 if (!qview->use_scroll_to_selection && !override_scroll)
621 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(qview));
624 path_list = gtk_tree_selection_get_selected_rows (selection, NULL);
625 node = g_list_last (path_list);
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);
633 g_list_free_full (path_list, (GDestroyNotify) gtk_tree_path_free);
637 gnc_query_scroll_to_selection (GNCQueryView *qview)
639 g_return_if_fail (qview != NULL);
640 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
642 scroll_to_selection (qview, FALSE);
646 gnc_query_force_scroll_to_selection (GNCQueryView *qview)
648 g_return_if_fail (qview != NULL);
649 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
651 scroll_to_selection (qview, TRUE);
655 gnc_query_view_refresh_selected (GNCQueryView *qview, GList *old_entry)
659 GtkTreeSelection *selection;
663 g_return_if_fail (qview != NULL);
664 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
666 model = gtk_tree_view_get_model (GTK_TREE_VIEW(qview));
667 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(qview));
669 if (g_list_length (old_entry) > 0)
672 for (node = old_entry; node; node = node->next)
676 valid = gtk_tree_model_get_iter_first (model, &iter);
681 gtk_tree_model_get (model, &iter, 0, &pointer, -1);
683 if (pointer == node->data)
685 gtk_tree_selection_select_iter (selection, &iter);
688 valid = gtk_tree_model_iter_next (model, &iter);
691 gnc_query_scroll_to_selection (qview);
703 gnc_query_view_refresh (GNCQueryView *qview)
706 GList *selected_entries;
708 g_return_if_fail (qview != NULL);
709 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
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));
715 gnc_query_view_fill (qview);
716 gnc_query_view_refresh_selected (qview, selected_entries);
717 g_list_free (selected_entries);
730 gnc_query_view_set_query_sort (GNCQueryView *qview, gboolean new_column)
732 gboolean sort_order = qview->increasing;
734 GNCSearchParamSimple *param;
737 node = g_list_nth (qview->column_params, qview->sort_column);
740 g_assert (GNC_IS_SEARCH_PARAM_SIMPLE(param));
743 if (gnc_search_param_has_param_fcn (param))
745 gnc_query_view_refresh (qview);
752 if (qview->numeric_inv_sort)
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;
765 p1 = gnc_search_param_get_param_path (param);
775 gnc_query_view_refresh (qview);
788 gnc_query_set_expand_column (GNCQueryView *qview, gint column)
790 g_return_if_fail (qview != NULL);
791 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
793 GtkTreeView *view = GTK_TREE_VIEW(qview);
795 gint num_columns = gtk_tree_view_get_n_columns (view);
797 if (column >= 0 && column < num_columns)
799 GtkTreeViewColumn *tree_column = gtk_tree_view_get_column (view, column);
800 gtk_tree_view_column_set_expand (tree_column, TRUE);
812 gnc_query_view_fill (GNCQueryView *qview)
814 GNCQueryViewPrivate *priv;
817 GList *entries, *item;
822 priv = GNC_QUERY_VIEW_GET_PRIVATE(qview);
823 gnc_gui_component_clear_watches (priv->component_id);
827 model = gtk_tree_view_get_model (GTK_TREE_VIEW(qview));
829 for (item = entries; item; item = item->next)
836 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
838 gtk_list_store_set (GTK_LIST_STORE(model), &iter, 0, item->data, -1);
840 for (i = 0, node = qview->column_params; node; node = node->next)
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;
849 g_assert (GNC_IS_SEARCH_PARAM_SIMPLE(param));
850 converters = gnc_search_param_get_converters (param);
853 if (g_strcmp0 (type, QOF_TYPE_BOOLEAN) == 0)
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);
862 for (; converters; converters = converters->next)
864 qp = converters->data;
865 if (converters->next)
866 res = (qp->param_getfcn)(res, qp);
870 if (qp && (g_strcmp0 (type, QOF_TYPE_DEBCRED) == 0 ||
871 g_strcmp0 (type, QOF_TYPE_NUMERIC) == 0))
874 gnc_numeric (*nfcn)(gpointer, QofParam *) =
875 (gnc_numeric(*)(gpointer, QofParam *))(qp->param_getfcn);
876 gnc_numeric value = nfcn (res, qp);
878 if (qview->numeric_abs)
880 gtk_list_store_set (GTK_LIST_STORE(model), &iter, i + 1,
886 gtk_list_store_set (GTK_LIST_STORE(model), &iter, i + 1, qofstring , -1);
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);
907 gnc_query_view_unselect_all (GNCQueryView *qview)
909 GtkTreeSelection *selection;
911 g_return_if_fail (qview != NULL);
912 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
914 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(qview));
915 gtk_tree_selection_unselect_all (selection);
918 gboolean gnc_query_view_item_in_view (GNCQueryView *qview, gpointer item)
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);
929 model = gtk_tree_view_get_model (GTK_TREE_VIEW(qview));
930 valid = gtk_tree_model_get_iter_first (model, &iter);
935 gtk_tree_model_get (model, &iter, 0, &pointer, -1);
940 valid = gtk_tree_model_iter_next (model, &iter);
946 gnc_query_view_set_numerics (GNCQueryView *qview, gboolean abs, gboolean inv_sort)
948 g_return_if_fail (qview);
949 g_return_if_fail (GNC_IS_QUERY_VIEW(qview));
951 qview->numeric_abs = abs;
952 qview->numeric_inv_sort = inv_sort;
utility functions for the GnuCash UI
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.
const char * xaccPrintAmount(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
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.
#define PWARN(format, args...)
Log a warning.
const QofParam * qof_class_get_parameter(QofIdTypeConst obj_name, const char *parameter)
Return the registered Parameter Definition for the requested parameter.
void qof_query_destroy(QofQuery *query)
Frees the resources associate with a Query object.
char * qof_query_core_to_string(QofType type, gpointer object, QofParam *getter)
Return a printable string for a core data object.
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...
GList * qof_query_run(QofQuery *query)
Perform the query, return the results.
QofIdType qof_query_get_search_for(const QofQuery *q)
Return the type of data we're querying for.
#define QUERY_DEFAULT_SORT
Default sort object type.
The type used to store guids in C.