mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
* src/gnome-utils/gnc-query-list.[ch]: an abstracted Query list
widget to display the results of a Query. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@8307 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
661bd34cc4
commit
0a883ac5e0
@ -1,3 +1,8 @@
|
||||
2003-05-12 Derek Atkins <derek@ihtfp.com>
|
||||
|
||||
* src/gnome-utils/gnc-query-list.[ch]: an abstracted Query list
|
||||
widget to display the results of a Query.
|
||||
|
||||
2003-05-11 David Hampton <hampton@employees.org>
|
||||
|
||||
* src/gnome/dialog-commodities.c:
|
||||
|
773
src/gnome-utils/gnc-query-list.c
Normal file
773
src/gnome-utils/gnc-query-list.c
Normal file
@ -0,0 +1,773 @@
|
||||
/********************************************************************\
|
||||
* gnc-query-list.c -- A query display list. *
|
||||
* Copyright (C) 2003 Derek Atkins <derek@ihtfp.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gnome.h>
|
||||
|
||||
#include "dialog-utils.h"
|
||||
#include "gnc-ui-util.h"
|
||||
#include "gnc-engine-util.h"
|
||||
#include "messages.h"
|
||||
#include "gnc-query-list.h"
|
||||
#include "search-param.h"
|
||||
|
||||
/* Signal codes */
|
||||
enum
|
||||
{
|
||||
LINE_TOGGLED,
|
||||
DOUBLE_CLICK_ENTRY,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
|
||||
/* Impossible to get at runtime. Assume this is a reasonable number */
|
||||
#define ARROW_SIZE 14
|
||||
#define VSCROLLBAR_SLOP 40
|
||||
|
||||
|
||||
/** Static Globals ****************************************************/
|
||||
static GtkCListClass *parent_class = NULL;
|
||||
static guint query_list_signals[LAST_SIGNAL] = {0};
|
||||
|
||||
|
||||
/** Static function declarations **************************************/
|
||||
static void gnc_query_list_init(GNCQueryList *list);
|
||||
static void gnc_query_list_init_clist (GNCQueryList *list);
|
||||
static void gnc_query_list_class_init(GNCQueryListClass *klass);
|
||||
static void gnc_query_list_select_row(GtkCList *clist, gint row,
|
||||
gint column, GdkEvent *event);
|
||||
static void gnc_query_list_unselect_row(GtkCList *clist, gint row,
|
||||
gint column, GdkEvent *event);
|
||||
static void gnc_query_list_destroy(GtkObject *object);
|
||||
static void gnc_query_list_fill(GNCQueryList *list);
|
||||
static void gnc_query_list_click_column_cb(GtkWidget *w, gint column,
|
||||
gpointer data);
|
||||
static void gnc_query_list_size_allocate_cb(GtkWidget *w,
|
||||
GtkAllocation *allocation,
|
||||
gpointer data);
|
||||
|
||||
static void gnc_query_list_set_query_sort (GNCQueryList *list, gboolean new_column);
|
||||
|
||||
GtkType
|
||||
gnc_query_list_get_type (void)
|
||||
{
|
||||
static GtkType gnc_query_list_type = 0;
|
||||
|
||||
if (!gnc_query_list_type)
|
||||
{
|
||||
static const GtkTypeInfo gnc_query_list_info =
|
||||
{
|
||||
"GNCQueryList",
|
||||
sizeof (GNCQueryList),
|
||||
sizeof (GNCQueryListClass),
|
||||
(GtkClassInitFunc) gnc_query_list_class_init,
|
||||
(GtkObjectInitFunc) gnc_query_list_init,
|
||||
/* reserved_1 */ NULL,
|
||||
/* reserved_2 */ NULL,
|
||||
(GtkClassInitFunc) NULL
|
||||
};
|
||||
|
||||
gnc_query_list_type = gtk_type_unique(GTK_TYPE_CLIST,
|
||||
&gnc_query_list_info);
|
||||
}
|
||||
|
||||
return gnc_query_list_type;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************\
|
||||
* gnc_query_list_new *
|
||||
* creates the query list *
|
||||
* *
|
||||
* Args: param_list - the list of params *
|
||||
* query - the query to use to find entries *
|
||||
* Returns: the query list widget, or NULL if there was a problem. *
|
||||
\********************************************************************/
|
||||
GtkWidget *
|
||||
gnc_query_list_new(GList *param_list, Query *query)
|
||||
{
|
||||
GNCQueryList *list;
|
||||
|
||||
g_return_val_if_fail(param_list, NULL);
|
||||
g_return_val_if_fail(query, NULL);
|
||||
|
||||
list = GNC_QUERY_LIST(gtk_type_new(gnc_query_list_get_type()));
|
||||
|
||||
/* more configuration */
|
||||
list->query = gncQueryCopy(query);
|
||||
list->column_params = param_list;
|
||||
|
||||
/* Initialize the CList */
|
||||
gnc_query_list_init_clist(list);
|
||||
|
||||
return GTK_WIDGET(list);
|
||||
}
|
||||
|
||||
void gnc_query_list_reset_query (GNCQueryList *list, Query *query)
|
||||
{
|
||||
g_return_if_fail(list);
|
||||
g_return_if_fail(query);
|
||||
g_return_if_fail (IS_GNC_QUERY_LIST(list));
|
||||
|
||||
gncQueryDestroy(list->query);
|
||||
list->query = gncQueryCopy(query);
|
||||
gnc_query_list_set_query_sort(list, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
update_booleans (GNCQueryList *list, gint row)
|
||||
{
|
||||
GtkCList *clist = GTK_CLIST(list);
|
||||
gpointer entry;
|
||||
GList *node;
|
||||
gint i;
|
||||
gboolean result;
|
||||
|
||||
entry = gtk_clist_get_row_data (clist, row);
|
||||
for (i = 0, node = list->column_params; node; node = node->next, i++)
|
||||
{
|
||||
GNCSearchParam *param = node->data;
|
||||
const char *type = gnc_search_param_get_param_type (param);
|
||||
|
||||
/* if this is a boolean, ignore it now -- we'll use a checkmark later */
|
||||
if (safe_strcmp (type, QUERYCORE_BOOLEAN))
|
||||
continue;
|
||||
|
||||
result = (gboolean)(gnc_search_param_compute_value(param, entry));
|
||||
gnc_clist_set_check (clist, row, i, result);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_query_list_column_title (GNCQueryList *list, gint column, const gchar *title)
|
||||
{
|
||||
GtkWidget *hbox, *label, *arrow;
|
||||
|
||||
hbox = gtk_hbox_new(FALSE, 2);
|
||||
gtk_widget_show(hbox);
|
||||
gtk_clist_set_column_widget(GTK_CLIST(list), column, hbox);
|
||||
|
||||
label = gtk_label_new(title);
|
||||
gtk_widget_show(label);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
|
||||
|
||||
arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_ETCHED_IN);
|
||||
list->title_arrows[column] = arrow;
|
||||
if (column == 0)
|
||||
gtk_widget_show(arrow);
|
||||
gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_query_list_init (GNCQueryList *list)
|
||||
{
|
||||
list->query = NULL;
|
||||
list->no_toggle = FALSE;
|
||||
|
||||
list->num_columns = 0;
|
||||
list->column_params = NULL;
|
||||
|
||||
list->sort_column = 0;
|
||||
list->increasing = TRUE;
|
||||
list->title_arrows = NULL;
|
||||
|
||||
list->prev_allocation = -1;
|
||||
list->title_widths = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gnc_query_list_init_clist (GNCQueryList *list)
|
||||
{
|
||||
GtkCList *clist = GTK_CLIST (list);
|
||||
GtkStyle *style;
|
||||
GList *node;
|
||||
gchar **titles;
|
||||
gint i;
|
||||
|
||||
/* compute the number of columns and fill in the rest of the list */
|
||||
list->num_columns = g_list_length(list->column_params);
|
||||
list->title_arrows = g_new0(GtkWidget*, list->num_columns);
|
||||
list->title_widths = g_new0(gint, list->num_columns);
|
||||
|
||||
/* build an array of titles */
|
||||
titles = g_new0(gchar*, list->num_columns);
|
||||
for (i = 0, node = list->column_params; node; node = node->next, i++) {
|
||||
GNCSearchParam *param = node->data;
|
||||
titles[i] = (gchar *)param->title;
|
||||
}
|
||||
|
||||
/* construct the clist */
|
||||
gtk_clist_construct (clist, list->num_columns, titles);
|
||||
gtk_clist_set_shadow_type (clist, GTK_SHADOW_IN);
|
||||
|
||||
/* build all the column titles */
|
||||
for (i = 0; i < list->num_columns; i++)
|
||||
gnc_query_list_column_title(list, i, titles[i]);
|
||||
|
||||
/* set the column justification */
|
||||
for (i = 0, node = list->column_params; node; node = node->next, i++) {
|
||||
GNCSearchParam *param = node->data;
|
||||
gtk_clist_set_column_justification (clist, i, param->justify);
|
||||
|
||||
if (param->passive)
|
||||
gtk_clist_column_title_passive (clist, i);
|
||||
|
||||
if (param->non_resizeable)
|
||||
gtk_clist_set_column_resizeable (clist, i, FALSE);
|
||||
}
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (clist), "click_column",
|
||||
GTK_SIGNAL_FUNC(gnc_query_list_click_column_cb),
|
||||
NULL);
|
||||
gtk_signal_connect (GTK_OBJECT (clist), "size_allocate",
|
||||
GTK_SIGNAL_FUNC(gnc_query_list_size_allocate_cb),
|
||||
NULL);
|
||||
|
||||
style = gtk_widget_get_style (GTK_WIDGET(list));
|
||||
|
||||
{
|
||||
GdkFont *font = NULL;
|
||||
gint width;
|
||||
|
||||
font = style->font;
|
||||
if (font != NULL)
|
||||
{
|
||||
for (i = 0, node = list->column_params; node; node = node->next, i++)
|
||||
{
|
||||
GNCSearchParam *param = node->data;
|
||||
width = gdk_string_width (font, titles[i]) + 5;
|
||||
if (!param->passive)
|
||||
width += ARROW_SIZE;
|
||||
gtk_clist_set_column_min_width (clist, i, width);
|
||||
list->title_widths[i] = width;
|
||||
}
|
||||
}
|
||||
}
|
||||
g_free(titles);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_query_list_class_init (GNCQueryListClass *klass)
|
||||
{
|
||||
GtkObjectClass *object_class;
|
||||
GtkWidgetClass *widget_class;
|
||||
GtkContainerClass *container_class;
|
||||
GtkCListClass *clist_class;
|
||||
|
||||
object_class = (GtkObjectClass*) klass;
|
||||
widget_class = (GtkWidgetClass*) klass;
|
||||
container_class = (GtkContainerClass*) klass;
|
||||
clist_class = (GtkCListClass*) klass;
|
||||
|
||||
parent_class = gtk_type_class(GTK_TYPE_CLIST);
|
||||
|
||||
query_list_signals[LINE_TOGGLED] =
|
||||
gtk_signal_new("line_toggled",
|
||||
GTK_RUN_FIRST,
|
||||
object_class->type,
|
||||
GTK_SIGNAL_OFFSET(GNCQueryListClass,
|
||||
line_toggled),
|
||||
gtk_marshal_NONE__POINTER,
|
||||
GTK_TYPE_NONE, 1,
|
||||
GTK_TYPE_POINTER);
|
||||
|
||||
query_list_signals[DOUBLE_CLICK_ENTRY] =
|
||||
gtk_signal_new("double_click_entry",
|
||||
GTK_RUN_FIRST,
|
||||
object_class->type,
|
||||
GTK_SIGNAL_OFFSET(GNCQueryListClass,
|
||||
double_click_entry),
|
||||
gtk_marshal_NONE__POINTER,
|
||||
GTK_TYPE_NONE, 1,
|
||||
GTK_TYPE_POINTER);
|
||||
|
||||
gtk_object_class_add_signals(object_class,
|
||||
query_list_signals,
|
||||
LAST_SIGNAL);
|
||||
|
||||
object_class->destroy = gnc_query_list_destroy;
|
||||
|
||||
clist_class->select_row = gnc_query_list_select_row;
|
||||
clist_class->unselect_row = gnc_query_list_unselect_row;
|
||||
|
||||
klass->line_toggled = NULL;
|
||||
klass->double_click_entry = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_query_list_toggle (GNCQueryList *list)
|
||||
{
|
||||
gpointer entry;
|
||||
gint row;
|
||||
|
||||
g_return_if_fail (IS_GNC_QUERY_LIST(list));
|
||||
|
||||
if (list->no_toggle)
|
||||
return;
|
||||
|
||||
row = list->current_row;
|
||||
entry = gtk_clist_get_row_data (GTK_CLIST(list), row);
|
||||
list->current_entry = entry;
|
||||
|
||||
gtk_signal_emit (GTK_OBJECT (list), query_list_signals[LINE_TOGGLED], entry);
|
||||
|
||||
update_booleans (list, row);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_query_list_select_row (GtkCList *clist, gint row, gint column,
|
||||
GdkEvent *event)
|
||||
{
|
||||
GNCQueryList *list = GNC_QUERY_LIST(clist);
|
||||
|
||||
list->current_row = row;
|
||||
|
||||
gnc_query_list_toggle (list);
|
||||
if (event == NULL) {
|
||||
/* User pressed the space key */
|
||||
parent_class->scroll_vertical(clist, GTK_SCROLL_STEP_FORWARD, 0.0);
|
||||
}
|
||||
|
||||
/* This will trigger an unselect event for the currently selected row */
|
||||
parent_class->select_row (clist, row, column, event);
|
||||
|
||||
if (event && (event->type == GDK_2BUTTON_PRESS))
|
||||
{
|
||||
gpointer entry;
|
||||
|
||||
entry = gtk_clist_get_row_data (clist, row);
|
||||
|
||||
gtk_signal_emit(GTK_OBJECT(list),
|
||||
query_list_signals[DOUBLE_CLICK_ENTRY], entry);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_query_list_unselect_row (GtkCList *clist, gint row, gint column,
|
||||
GdkEvent *event)
|
||||
{
|
||||
GNCQueryList *list = GNC_QUERY_LIST(clist);
|
||||
|
||||
if (row == list->current_row)
|
||||
{
|
||||
gnc_query_list_toggle (list);
|
||||
if (event == NULL) {
|
||||
/* User pressed the space key */
|
||||
parent_class->scroll_vertical(clist, GTK_SCROLL_STEP_FORWARD, 0.0);
|
||||
}
|
||||
/* XXX
|
||||
if (!list->always_unselect)
|
||||
return;
|
||||
*/
|
||||
}
|
||||
|
||||
parent_class->unselect_row (clist, row, column, event);
|
||||
|
||||
if (event && (event->type == GDK_2BUTTON_PRESS))
|
||||
{
|
||||
gpointer entry;
|
||||
|
||||
entry = gtk_clist_get_row_data (clist, row);
|
||||
|
||||
gtk_signal_emit (GTK_OBJECT(list),
|
||||
query_list_signals[DOUBLE_CLICK_ENTRY], entry);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_query_list_destroy (GtkObject *object)
|
||||
{
|
||||
GNCQueryList *list = GNC_QUERY_LIST(object);
|
||||
|
||||
if (list->query)
|
||||
{
|
||||
xaccFreeQuery(list->query);
|
||||
list->query = NULL;
|
||||
}
|
||||
if (list->column_params)
|
||||
{
|
||||
/* XXX: free the params list??? */
|
||||
}
|
||||
if (list->title_arrows)
|
||||
{
|
||||
g_free(list->title_arrows);
|
||||
list->title_arrows = NULL;
|
||||
}
|
||||
if (list->title_widths)
|
||||
{
|
||||
g_free(list->title_widths);
|
||||
list->title_widths = NULL;
|
||||
}
|
||||
|
||||
if (GTK_OBJECT_CLASS(parent_class)->destroy)
|
||||
GTK_OBJECT_CLASS(parent_class)->destroy (object);
|
||||
}
|
||||
|
||||
gint
|
||||
gnc_query_list_get_needed_height (GNCQueryList *list, gint num_rows)
|
||||
{
|
||||
GtkCList *clist;
|
||||
gint list_height;
|
||||
gint title_height;
|
||||
|
||||
g_return_val_if_fail (list != NULL, 0);
|
||||
g_return_val_if_fail (IS_GNC_QUERY_LIST(list), 0);
|
||||
|
||||
if (!GTK_WIDGET_REALIZED (list))
|
||||
return 0;
|
||||
|
||||
clist = GTK_CLIST (list);
|
||||
|
||||
/* sync with gtkclist.c */
|
||||
title_height = (clist->column_title_area.height +
|
||||
(GTK_WIDGET(list)->style->klass->ythickness +
|
||||
GTK_CONTAINER(list)->border_width) * 2);
|
||||
list_height = (clist->row_height * num_rows) + (num_rows + 1);
|
||||
|
||||
return title_height + list_height;
|
||||
}
|
||||
|
||||
gint
|
||||
gnc_query_list_get_num_entries (GNCQueryList *list)
|
||||
{
|
||||
g_return_val_if_fail (list != NULL, 0);
|
||||
g_return_val_if_fail (IS_GNC_QUERY_LIST(list), 0);
|
||||
|
||||
return list->num_entries;
|
||||
}
|
||||
|
||||
gpointer
|
||||
gnc_query_list_get_current_entry (GNCQueryList *list)
|
||||
{
|
||||
g_return_val_if_fail (list != NULL, NULL);
|
||||
g_return_val_if_fail (IS_GNC_QUERY_LIST(list), NULL);
|
||||
|
||||
return list->current_entry;
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
* gnc_query_list_recompute_widths *
|
||||
* Given a new widget width, recompute the widths of each column. *
|
||||
* Give any excess allocation to the description field. This also *
|
||||
* handles the case of allocating column widths when the list is *
|
||||
* first filled with data. *
|
||||
* *
|
||||
* Args: list - a GncQueryList widget *
|
||||
* allocated - the allocated width for this list *
|
||||
* Returns: nothing *
|
||||
\********************************************************************/
|
||||
static void
|
||||
gnc_query_list_recompute_widths (GNCQueryList *list, gint allocated)
|
||||
{
|
||||
GtkCList *clist = GTK_CLIST(list);
|
||||
gint total_width, desc_width = 0, excess, i;
|
||||
|
||||
/* Prevent loops when allocation is bigger than total widths */
|
||||
if (allocated == list->prev_allocation)
|
||||
return;
|
||||
|
||||
/* Enforce column minimum widths */
|
||||
total_width = 0;
|
||||
for (i = 0; i < list->num_columns; i++)
|
||||
{
|
||||
gint width;
|
||||
|
||||
width = gtk_clist_optimal_column_width(clist, i);
|
||||
if (width < list->title_widths[i])
|
||||
width = list->title_widths[i];
|
||||
total_width += width;
|
||||
gtk_clist_set_column_width (clist, i, width);
|
||||
if (i == 2)
|
||||
desc_width = width;
|
||||
}
|
||||
|
||||
/* Did the list use its full allocation?
|
||||
*
|
||||
* Add/subtract any underage/overage to/from the description column
|
||||
*/
|
||||
if (allocated <= 1)
|
||||
allocated = list->prev_allocation;
|
||||
list->prev_allocation = allocated;
|
||||
excess = allocated - total_width - VSCROLLBAR_SLOP;
|
||||
|
||||
/* XXX: Choose a generic column to resize */
|
||||
gtk_clist_set_column_width (clist, 2, desc_width + excess);
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
* gnc_query_list_size_allocate_cb *
|
||||
* The allocated size has changed. Need to recompute the *
|
||||
* column widths *
|
||||
* *
|
||||
* Args: w - a GncQueryList widget *
|
||||
* allocation - a widget allocation desctiption *
|
||||
* data - unused *
|
||||
* Returns: nothing *
|
||||
\********************************************************************/
|
||||
static void
|
||||
gnc_query_list_size_allocate_cb (GtkWidget *w,
|
||||
GtkAllocation *allocation,
|
||||
gpointer data)
|
||||
{
|
||||
GNCQueryList *list = GNC_QUERY_LIST(w);
|
||||
|
||||
g_return_if_fail (list != NULL);
|
||||
gnc_query_list_recompute_widths(list, allocation->width);
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
* gnc_query_list_refresh *
|
||||
* refreshes the list *
|
||||
* *
|
||||
* Args: list - list to refresh *
|
||||
* Returns: nothing *
|
||||
\********************************************************************/
|
||||
void
|
||||
gnc_query_list_refresh (GNCQueryList *list)
|
||||
{
|
||||
GtkCList *clist = GTK_CLIST(list);
|
||||
GtkAdjustment *adjustment;
|
||||
gfloat save_value = 0.0;
|
||||
gpointer *old_focus_entry;
|
||||
gpointer *old_entry;
|
||||
gint old_focus_row;
|
||||
gint new_row;
|
||||
|
||||
g_return_if_fail (list != NULL);
|
||||
g_return_if_fail (IS_GNC_QUERY_LIST(list));
|
||||
|
||||
adjustment = gtk_clist_get_vadjustment (GTK_CLIST(list));
|
||||
if (adjustment != NULL)
|
||||
save_value = adjustment->value;
|
||||
|
||||
old_focus_row = clist->focus_row;
|
||||
old_focus_entry = gtk_clist_get_row_data (clist, old_focus_row);
|
||||
|
||||
gtk_clist_freeze (clist);
|
||||
gtk_clist_clear (clist);
|
||||
|
||||
old_entry = list->current_entry;
|
||||
list->num_entries = 0;
|
||||
list->current_row = -1;
|
||||
list->current_entry = NULL;
|
||||
|
||||
gnc_query_list_fill (list);
|
||||
|
||||
gnc_query_list_recompute_widths (list, -1);
|
||||
|
||||
if (adjustment)
|
||||
{
|
||||
save_value = CLAMP (save_value, adjustment->lower, adjustment->upper);
|
||||
gtk_adjustment_set_value (adjustment, save_value);
|
||||
}
|
||||
|
||||
if (old_entry)
|
||||
{
|
||||
new_row = gtk_clist_find_row_from_data (clist, old_entry);
|
||||
if (new_row >= 0)
|
||||
{
|
||||
list->no_toggle = TRUE;
|
||||
gtk_clist_select_row (clist, new_row, 0);
|
||||
list->no_toggle = FALSE;
|
||||
list->current_entry = old_entry;
|
||||
}
|
||||
}
|
||||
|
||||
if (old_focus_entry)
|
||||
{
|
||||
new_row = gtk_clist_find_row_from_data (clist, old_focus_entry);
|
||||
|
||||
if (new_row < 0)
|
||||
new_row = old_focus_row;
|
||||
|
||||
if (new_row >= 0)
|
||||
clist->focus_row = new_row;
|
||||
}
|
||||
|
||||
gtk_clist_thaw (clist);
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
* gnc_query_list_set_query_sort *
|
||||
* sets the sorting order of entries in the list *
|
||||
* *
|
||||
* Args: list - list to change the sort order for *
|
||||
* new_column - is this a new column (so should we set the *
|
||||
* query sort order or just set the 'increasing' *
|
||||
* Returns: nothing *
|
||||
\********************************************************************/
|
||||
static void
|
||||
gnc_query_list_set_query_sort (GNCQueryList *list, gboolean new_column)
|
||||
{
|
||||
gboolean sort_order = list->increasing;
|
||||
GList *node;
|
||||
GNCSearchParam *param;
|
||||
|
||||
/* Find the column parameter definition */
|
||||
node = g_list_nth(list->column_params, list->sort_column);
|
||||
param = node->data;
|
||||
|
||||
/* XXX: Maybe invert the sort order?
|
||||
if ((list->list_type == RECLIST_CREDIT) && (key == BY_AMOUNT))
|
||||
sort_order = !sort_order;
|
||||
*/
|
||||
|
||||
/* Set the sort order for the engine, if the key changed */
|
||||
if (new_column)
|
||||
{
|
||||
GSList *p1, *p2;
|
||||
|
||||
p1 = gnc_search_param_get_param_path(param);
|
||||
p2 = g_slist_prepend(NULL, QUERY_DEFAULT_SORT);
|
||||
gncQuerySetSortOrder (list->query, p1, p2, NULL);
|
||||
}
|
||||
|
||||
xaccQuerySetSortIncreasing (list->query,
|
||||
sort_order,
|
||||
sort_order,
|
||||
sort_order);
|
||||
|
||||
/*
|
||||
* Recompute the list. Is this really necessary? Why not just sort
|
||||
* the rows already in the clist? Answer: it would be an n-squared
|
||||
* algorithm to get the clist to match the resulting list.
|
||||
*/
|
||||
gnc_query_list_refresh(list);
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
* gnc_query_list_set_sort_column *
|
||||
* sets the sorting order of entries in the list *
|
||||
* *
|
||||
* Args: list - list to change the sort order for *
|
||||
* column - the column to sort on *
|
||||
* Returns: nothing *
|
||||
\********************************************************************/
|
||||
static void
|
||||
gnc_query_list_set_sort_column (GNCQueryList *list, gint sort_column)
|
||||
{
|
||||
gint column;
|
||||
gboolean new_column = FALSE;
|
||||
|
||||
g_return_if_fail (list != NULL);
|
||||
g_return_if_fail (IS_GNC_QUERY_LIST(list));
|
||||
g_return_if_fail (list->query != NULL);
|
||||
|
||||
/* Clear all arrows */
|
||||
for (column = 0; column < list->num_columns; column++)
|
||||
{
|
||||
if (list->title_arrows[column])
|
||||
gtk_widget_hide(list->title_arrows[column]);
|
||||
}
|
||||
|
||||
/* Is this a new column or a re-click on the existing column? */
|
||||
column = sort_column;
|
||||
new_column = (list->sort_column != sort_column);
|
||||
|
||||
list->increasing = new_column ? TRUE : !list->increasing;
|
||||
list->sort_column = sort_column;
|
||||
|
||||
/* Set the appropriate arrow */
|
||||
gtk_arrow_set(GTK_ARROW(list->title_arrows[column]),
|
||||
list->increasing ? GTK_ARROW_DOWN : GTK_ARROW_UP,
|
||||
GTK_SHADOW_ETCHED_IN);
|
||||
gtk_widget_show(list->title_arrows[column]);
|
||||
|
||||
gnc_query_list_set_query_sort (list, new_column);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_query_list_click_column_cb(GtkWidget *w, gint column, gpointer data)
|
||||
{
|
||||
GNCQueryList *list = GNC_QUERY_LIST(w);
|
||||
gnc_query_list_set_sort_column(list, column);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_query_list_fill(GNCQueryList *list)
|
||||
{
|
||||
gchar *strings[list->num_columns + 1];
|
||||
GList *entries, *item;
|
||||
gint i;
|
||||
|
||||
/* Reverse the list now because 'append()' takes too long */
|
||||
entries = gncQueryRun(list->query);
|
||||
entries = g_list_reverse(entries);
|
||||
|
||||
for (item = entries; item; item = item->next)
|
||||
{
|
||||
GList *node;
|
||||
gint row;
|
||||
|
||||
for (i = 0, node = list->column_params; node; node = node->next)
|
||||
{
|
||||
GNCSearchParam *param = node->data;
|
||||
GSList *converters = gnc_search_param_get_converters (param);
|
||||
const char *type = gnc_search_param_get_param_type (param);
|
||||
gpointer res = item->data;
|
||||
QueryAccess fcn = NULL;
|
||||
|
||||
/* if this is a boolean, ignore it now -- we'll use a checkmark later */
|
||||
if (!safe_strcmp (type, QUERYCORE_BOOLEAN)) {
|
||||
strings[i++] = g_strdup("");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Do all the object conversions */
|
||||
for (; converters; converters = converters->next) {
|
||||
fcn = converters->data;
|
||||
|
||||
if (converters->next)
|
||||
res = fcn (res);
|
||||
}
|
||||
|
||||
/* Now convert this to a text value for the row */
|
||||
if (!safe_strcmp(type, QUERYCORE_DEBCRED) ||
|
||||
!safe_strcmp(type, QUERYCORE_NUMERIC))
|
||||
{
|
||||
gnc_numeric (*nfcn)(gpointer) = (gnc_numeric(*)(gpointer))fcn;
|
||||
gnc_numeric value = nfcn(res);
|
||||
strings[i++] = g_strdup(xaccPrintAmount(value,gnc_default_print_info(FALSE)));
|
||||
} else
|
||||
strings[i++] = gncQueryCoreToString (type, res, fcn);
|
||||
}
|
||||
|
||||
row = gtk_clist_prepend (GTK_CLIST(list), (gchar **) strings);
|
||||
gtk_clist_set_row_data (GTK_CLIST(list), row, item->data);
|
||||
|
||||
/* Free up our strings */
|
||||
for (i = 0; i < list->num_columns; i++) {
|
||||
if (strings[i])
|
||||
g_free (strings[i]);
|
||||
}
|
||||
|
||||
/* Now update any checkmarks */
|
||||
update_booleans (list, row);
|
||||
|
||||
list->num_entries++;
|
||||
}
|
||||
|
||||
/* Reverse the list again for the query code */
|
||||
g_list_reverse(entries);
|
||||
}
|
102
src/gnome-utils/gnc-query-list.h
Normal file
102
src/gnome-utils/gnc-query-list.h
Normal file
@ -0,0 +1,102 @@
|
||||
/********************************************************************\
|
||||
* gnc-query-list.h -- GnuCash GNOME query display list widget *
|
||||
* Copyright (C) 2003 Derek Atkins <derek@ihtfp.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef GNC_QUERY_LIST_H
|
||||
#define GNC_QUERY_LIST_H
|
||||
|
||||
#include <gtk/gtkclist.h>
|
||||
|
||||
#include "Query.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define GTK_TYPE_GNC_QUERY_LIST (gnc_query_list_get_type ())
|
||||
#define GNC_QUERY_LIST(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_GNC_QUERY_LIST, GNCQueryList))
|
||||
#define GNC_QUERY_LIST_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_GNC_QUERY_LIST, GNCQueryListClass))
|
||||
#define IS_GNC_QUERY_LIST(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_GNC_QUERY_LIST))
|
||||
#define IS_GNC_QUERY_LIST_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_GNC_QUERY_LIST))
|
||||
|
||||
typedef struct _GNCQueryList GNCQueryList;
|
||||
typedef struct _GNCQueryListClass GNCQueryListClass;
|
||||
|
||||
struct _GNCQueryList
|
||||
{
|
||||
GtkCList clist;
|
||||
|
||||
/* Query information */
|
||||
Query *query;
|
||||
gboolean no_toggle;
|
||||
gint current_row;
|
||||
gint num_entries;
|
||||
gpointer current_entry;
|
||||
|
||||
/* Column information */
|
||||
gint num_columns;
|
||||
GList *column_params;
|
||||
|
||||
/* Sorting info */
|
||||
gint sort_column;
|
||||
gboolean increasing;
|
||||
GtkWidget **title_arrows;
|
||||
|
||||
/* Column resizing */
|
||||
gint prev_allocation;
|
||||
gint *title_widths;
|
||||
};
|
||||
|
||||
struct _GNCQueryListClass
|
||||
{
|
||||
GtkCListClass parent_class;
|
||||
|
||||
void (*line_toggled) (GNCQueryList *list, gpointer entry);
|
||||
void (*double_click_entry) (GNCQueryList *list, gpointer entry);
|
||||
};
|
||||
|
||||
/***********************************************************
|
||||
* public functions *
|
||||
***********************************************************/
|
||||
|
||||
GtkType gnc_query_list_get_type (void);
|
||||
|
||||
/* The param_list remains owned by the caller but is used by the
|
||||
* query-list; do not destroy it until you destroy this query-list.
|
||||
* The query will be copied by the query-list so the caller may do
|
||||
* whatever they want.
|
||||
*/
|
||||
GtkWidget * gnc_query_list_new (GList *param_list, Query *query);
|
||||
void gnc_query_list_reset_query (GNCQueryList *list, Query *query);
|
||||
|
||||
gint gnc_query_list_get_needed_height(GNCQueryList *list, gint num_rows);
|
||||
|
||||
gint gnc_query_list_get_num_entries(GNCQueryList *list);
|
||||
|
||||
gpointer gnc_query_list_get_current_entry(GNCQueryList *list);
|
||||
|
||||
void gnc_query_list_refresh (GNCQueryList *list);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* GNC_QUERY_LIST_H */
|
Loading…
Reference in New Issue
Block a user