* src/engine/Query{,P}.h: move the location of gncQuerySearchFor()

to allow callers to look it up without requiring the private
	  header.
	* src/business/business-core/gncInvoice.[ch]: define
	  INVOICE_IS_PAID and create gncInvoiceIsPaid() function (the
	  prototype already existed, but it was never implemented).
	* src/business/business-gnome/dialog-invoice.c: add IS_PAID column
	  and the ability to search for paid/not-paid invoices.
	* src/gnome-utils/Makefile.am: build gnc-query-list
	* src/gnome-utils/gnc-query-list.[ch]: finish the GNCQueryList.
	  - allow active-column sorting
	  - watch all the entities in the query and update when an entry changes
	  - use a checkbox to display booleans
	* src/gnome-utils/search-param.[ch]: add extra APIs required to support
	  the initial QueryList implementation
	* src/gnome-search/dialog-search.c: Convert to use the new
	  GNCQueryList to display the search results.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@8308 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Derek Atkins 2003-05-13 02:07:15 +00:00
parent 0a883ac5e0
commit d39367285c
12 changed files with 206 additions and 170 deletions

View File

@ -3,6 +3,24 @@
* src/gnome-utils/gnc-query-list.[ch]: an abstracted Query list
widget to display the results of a Query.
* src/engine/Query{,P}.h: move the location of gncQuerySearchFor()
to allow callers to look it up without requiring the private
header.
* src/business/business-core/gncInvoice.[ch]: define
INVOICE_IS_PAID and create gncInvoiceIsPaid() function (the
prototype already existed, but it was never implemented).
* src/business/business-gnome/dialog-invoice.c: add IS_PAID column
and the ability to search for paid/not-paid invoices.
* src/gnome-utils/Makefile.am: build gnc-query-list
* src/gnome-utils/gnc-query-list.[ch]: finish the GNCQueryList.
- allow active-column sorting
- watch all the entities in the query and update when an entry changes
- use a checkbox to display booleans
* src/gnome-utils/search-param.[ch]: add extra APIs required to support
the initial QueryList implementation
* src/gnome-search/dialog-search.c: Convert to use the new
GNCQueryList to display the search results.
2003-05-11 David Hampton <hampton@employees.org>
* src/gnome/dialog-commodities.c:

View File

@ -507,7 +507,7 @@ const char * gncInvoiceGetType (GncInvoice *invoice)
case GNC_OWNER_VENDOR:
return _("Bill");
case GNC_OWNER_EMPLOYEE:
return _("Expense Voucher");
return _("Expense");
default:
return NULL;
}
@ -1207,6 +1207,13 @@ gboolean gncInvoiceIsPosted (GncInvoice *invoice)
return gncInvoiceDateExists (&(invoice->date_posted));
}
gboolean gncInvoiceIsPaid (GncInvoice *invoice)
{
if (!invoice) return FALSE;
if (!invoice->posted_lot) return FALSE;
return gnc_lot_is_closed(invoice->posted_lot);
}
GUID gncInvoiceRetGUID (GncInvoice *invoice)
{
if (!invoice)
@ -1370,6 +1377,7 @@ gboolean gncInvoiceRegister (void)
{ INVOICE_DUE, QUERYCORE_DATE, (QueryAccess)gncInvoiceGetDateDue },
{ INVOICE_POSTED, QUERYCORE_DATE, (QueryAccess)gncInvoiceGetDatePosted },
{ INVOICE_IS_POSTED, QUERYCORE_BOOLEAN, (QueryAccess)gncInvoiceIsPosted },
{ INVOICE_IS_PAID, QUERYCORE_BOOLEAN, (QueryAccess)gncInvoiceIsPaid },
{ INVOICE_BILLINGID, QUERYCORE_STRING, (QueryAccess)gncInvoiceGetBillingID },
{ INVOICE_NOTES, QUERYCORE_STRING, (QueryAccess)gncInvoiceGetNotes },
{ INVOICE_ACC, GNC_ID_ACCOUNT, (QueryAccess)gncInvoiceGetPostedAcc },

View File

@ -127,6 +127,7 @@ gboolean gncInvoiceIsPaid (GncInvoice *invoice);
#define INVOICE_POSTED "date_posted"
#define INVOICE_DUE "date_due"
#define INVOICE_IS_POSTED "is_posted?"
#define INVOICE_IS_PAID "is_paid?"
#define INVOICE_TERMS "terms"
#define INVOICE_BILLINGID "billing_id"
#define INVOICE_NOTES "notes"

View File

@ -2274,6 +2274,8 @@ gnc_invoice_search (GncInvoice *start, GncOwner *owner, GNCBook *book)
INVOICE_NOTES, NULL);
params = gnc_search_param_prepend (params, _("Billing ID"), NULL, type,
INVOICE_BILLINGID, NULL);
params = gnc_search_param_prepend (params, _("Is Paid?"), NULL, type,
INVOICE_IS_PAID, NULL);
params = gnc_search_param_prepend (params, _("Date Posted"), NULL, type,
INVOICE_POSTED, NULL);
params = gnc_search_param_prepend (params, _("Is Posted?"), NULL, type,
@ -2291,13 +2293,15 @@ gnc_invoice_search (GncInvoice *start, GncOwner *owner, GNCBook *book)
if (columns == NULL) {
columns = gnc_search_param_prepend (columns, _("Billing ID"), NULL, type,
INVOICE_BILLINGID, NULL);
columns = gnc_search_param_prepend (columns, _("Type"), NULL, type,
INVOICE_TYPE, NULL);
columns = gnc_search_param_prepend (columns, _("Paid"), NULL, type,
INVOICE_IS_PAID, NULL);
columns = gnc_search_param_prepend (columns, _("Posted"), NULL, type,
INVOICE_POSTED, NULL);
columns = gnc_search_param_prepend (columns, _("Company"), NULL, type,
INVOICE_OWNER, OWNER_PARENT,
OWNER_NAME, NULL);
columns = gnc_search_param_prepend (columns, _("Type"), NULL, type,
INVOICE_TYPE, NULL);
columns = gnc_search_param_prepend (columns, _("Posted"), NULL, type,
INVOICE_POSTED, NULL);
columns = gnc_search_param_prepend (columns, _("Opened"), NULL, type,
INVOICE_OPENED, NULL);
columns = gnc_search_param_prepend (columns, _("Num"), NULL, type,

View File

@ -135,4 +135,7 @@ gboolean gncQueryEqual (QueryNew *q1, QueryNew *q2);
*/
void gncQueryPrint (QueryNew *query);
/* Return the type of data we're querying for */
GNCIdType gncQueryGetSearchFor (QueryNew *q);
#endif /* GNC_QUERYNEW_H */

View File

@ -17,7 +17,6 @@ void gncQueryNewShutdown (void);
/* Functions to get Query information */
int gncQueryGetMaxResults (QueryNew *q);
GNCIdType gncQueryGetSearchFor (QueryNew *q);
/* Functions to get and look at QueryTerms */

View File

@ -16,6 +16,7 @@
#include "gnc-ui.h"
#include "gnc-gui-query.h"
#include "global-options.h"
#include "gnc-query-list.h"
#include "gncObject.h"
#include "QueryNew.h"
#include "QueryObject.h"
@ -134,136 +135,51 @@ gnc_search_dialog_select_cb (GtkButton *button, GNCSearchWindow *sw)
}
static void
gnc_search_dialog_select_row_cb (GtkCList *clist, gint row, gint column,
GdkEventButton *event, gpointer user_data)
gnc_search_dialog_line_toggled (GNCQueryList *list, gpointer item,
gpointer user_data)
{
GNCSearchWindow *sw = user_data;
sw->selected_item = gtk_clist_get_row_data (clist, row);
if (sw->selected_item == item)
sw->selected_item = NULL;
else
sw->selected_item = item;
}
static void
gnc_search_dialog_double_click_entry (GNCQueryList *list, gpointer item,
gpointer user_data)
{
GNCSearchWindow *sw = user_data;
/* Force the selected item */
sw->selected_item = item;
/* If we double-click an item, then either "select" it, or run it
* through the first button (which should be view/edit
*/
if (event && event->type == GDK_2BUTTON_PRESS) {
if (sw->selected_cb)
/* Select the time */
gnc_search_dialog_select_cb (NULL, sw);
else if (sw->buttons)
/* Call the first button (usually view/edit) */
gnc_search_callback_button_execute (sw->buttons, sw);
/* If we get here, then nothing to do for a double-click */
}
}
static void
gnc_search_dialog_unselect_row_cb (GtkCList *clist, gint row, gint column,
GdkEventButton *event, gpointer user_data)
{
GNCSearchWindow *sw = user_data;
gpointer item = gtk_clist_get_row_data (clist, row);
if (sw->selected_item == item)
sw->selected_item = NULL;
if (sw->selected_cb)
/* Select the time */
gnc_search_dialog_select_cb (NULL, sw);
else if (sw->buttons)
/* Call the first button (usually view/edit) */
gnc_search_callback_button_execute (sw->buttons, sw);
}
static void
gnc_search_dialog_init_result_list (GNCSearchWindow *sw)
{
GList *col;
gint i;
char **titles;
/* How many columns? */
sw->num_cols = g_list_length (sw->display_list);
titles = g_new0 (char*, sw->num_cols);
for (i = 0, col = sw->display_list; col; col = col->next) {
GNCSearchParam *param = col->data;
titles[i] = (char *)param->title;
i++;
}
sw->result_list = gtk_clist_new_with_titles (sw->num_cols, titles);
g_free (titles);
gtk_clist_set_selection_mode (GTK_CLIST (sw->result_list),
GTK_SELECTION_SINGLE);
/* Setup list properties */
gtk_clist_set_shadow_type(GTK_CLIST(sw->result_list), GTK_SHADOW_IN);
gtk_clist_column_titles_passive(GTK_CLIST(sw->result_list));
/* Setup column parameters */
for (i = 0, col = sw->display_list; col; col = col->next) {
GNCSearchParam *param = col->data;
gtk_clist_set_column_justification (GTK_CLIST (sw->result_list), i,
param->justify);
gtk_clist_set_column_auto_resize (GTK_CLIST (sw->result_list), i, TRUE);
i++;
}
sw->result_list = gnc_query_list_new(sw->display_list, sw->q);
/* Setup the list callbacks */
gtk_signal_connect (GTK_OBJECT (sw->result_list), "select-row",
gnc_search_dialog_select_row_cb, sw);
gtk_signal_connect (GTK_OBJECT (sw->result_list), "unselect-row",
gnc_search_dialog_unselect_row_cb, sw);
}
static void
gnc_search_dialog_prepend_item (GNCSearchWindow *sw, gpointer object)
{
const GUID *guid = (const GUID *) ((sw->get_guid)(object));
GList *col;
char ** row_text;
gint row, i;
row_text = g_new0 (char *, sw->num_cols);
/* Iterate over each column, and compute the particular text
* to display for that column.
*/
for (i = 0, col = sw->display_list; col; col = col->next) {
GNCSearchParam *param = col->data;
GSList *converters = gnc_search_param_get_converters (param);
const char *type = gnc_search_param_get_param_type (param);
gpointer res = object;
QueryAccess fcn = NULL;
/* 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 */
row_text[i++] = gncQueryCoreToString (type, res, fcn);
}
row = gtk_clist_prepend (GTK_CLIST (sw->result_list), row_text);
gtk_clist_set_row_data (GTK_CLIST (sw->result_list), row, object);
gtk_clist_set_selectable (GTK_CLIST (sw->result_list), row, TRUE);
/* Free up our strings */
for (i = 0; i < sw->num_cols; i++) {
if (row_text[i])
g_free (row_text[i]);
}
g_free (row_text);
/* Watch this item in case it changes */
gnc_gui_component_watch_entity (sw->component_id, guid,
GNC_EVENT_MODIFY | GNC_EVENT_DESTROY);
gtk_signal_connect (GTK_OBJECT (sw->result_list), "line_toggled",
gnc_search_dialog_line_toggled, sw);
gtk_signal_connect (GTK_OBJECT (sw->result_list), "double_click_entry",
gnc_search_dialog_double_click_entry, sw);
}
static void
gnc_search_dialog_display_results (GNCSearchWindow *sw)
{
GList *list, *node;
GtkAdjustment *vadjustment;
gfloat save_value = 0.0;
gboolean have_list = TRUE;
gint64 count;
gdouble max_count;
/* Check if this is the first time this is called for this window.
@ -273,8 +189,6 @@ gnc_search_dialog_display_results (GNCSearchWindow *sw)
if (sw->result_list == NULL) {
GtkWidget *scroller, *button_box, *button;
have_list = FALSE;
/* Create the list */
gnc_search_dialog_init_result_list (sw);
@ -320,57 +234,12 @@ gnc_search_dialog_display_results (GNCSearchWindow *sw)
gtk_widget_hide_all (sw->select_button);
}
/* Figure out were we were */
vadjustment = gtk_clist_get_vadjustment (GTK_CLIST (sw->result_list));
if (vadjustment)
save_value = vadjustment->value;
/* Clear out all the items, to insert in a moment */
gtk_clist_freeze (GTK_CLIST (sw->result_list));
gtk_clist_clear (GTK_CLIST (sw->result_list));
/* Clear the watches */
gnc_gui_component_clear_watches (sw->component_id);
/* Compute the actual results */
list = g_list_reverse (gncQueryRun (sw->q));
/* Add the list of items to the clist */
for (count = 0, node = list; node; node = node->next, count++) {
gnc_search_dialog_prepend_item (sw, node->data);
}
/* Need to reverse again for internal consistency */
g_list_reverse (list);
/* Return to our saved vadjustment */
if (vadjustment) {
save_value = CLAMP (save_value, vadjustment->lower,
vadjustment->upper - vadjustment->page_size);
gtk_adjustment_set_value (vadjustment, save_value);
}
gtk_clist_thaw (GTK_CLIST (sw->result_list));
/* Figure out what to select */
{
gint row = gtk_clist_find_row_from_data (GTK_CLIST (sw->result_list),
sw->selected_item);
if (row < 0)
row = 0;
gtk_clist_select_row (GTK_CLIST (sw->result_list), row, 0);
/* If this row isn't visible, move it to the center */
if (gtk_clist_row_is_visible (GTK_CLIST (sw->result_list), row) !=
GTK_VISIBILITY_FULL && have_list)
gtk_clist_moveto (GTK_CLIST (sw->result_list), row, 0, 0.5, 0);
}
/* Update the query in the list */
gnc_query_list_reset_query (GNC_QUERY_LIST(sw->result_list), sw->q);
/* set 'new search' if fewer than max_count items is returned. */
max_count = gnc_lookup_number_option ("_+Advanced", "New Search Limit", 0.0);
if (count < max_count)
if (gnc_query_list_get_num_entries(GNC_QUERY_LIST(sw->result_list)) < max_count)
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (sw->new_rb), TRUE);
}

View File

@ -45,6 +45,7 @@ libgncmod_gnome_utils_la_SOURCES = \
gnc-html.c \
gnc-mdi-utils.c \
gnc-menu-extensions.c \
gnc-query-list.c \
gncmod-gnome-utils.c \
gtkselect.c \
print-session.c \
@ -78,6 +79,7 @@ gncinclude_HEADERS = \
gnc-html.h \
gnc-mdi-utils.h \
gnc-menu-extensions.h \
gnc-query-list.h \
gtkselect.h \
print-session.h \
window-help.h

View File

@ -27,6 +27,7 @@
#include "dialog-utils.h"
#include "gnc-ui-util.h"
#include "gnc-engine-util.h"
#include "gnc-component-manager.h"
#include "messages.h"
#include "gnc-query-list.h"
#include "search-param.h"
@ -39,6 +40,10 @@ enum
LAST_SIGNAL
};
struct _GNCQueryListPriv {
QueryAccess get_guid;
gint component_id;
};
/* Impossible to get at runtime. Assume this is a reasonable number */
#define ARROW_SIZE 14
@ -116,7 +121,12 @@ gnc_query_list_new(GList *param_list, Query *query)
/* more configuration */
list->query = gncQueryCopy(query);
list->column_params = param_list;
/* cache the function to get the guid of this query type */
list->priv->get_guid =
gncQueryObjectGetParameterGetter (gncQueryGetSearchFor (query),
QUERY_PARAM_GUID);
/* Initialize the CList */
gnc_query_list_init_clist(list);
@ -178,6 +188,15 @@ gnc_query_list_column_title (GNCQueryList *list, gint column, const gchar *title
gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
}
static void
gnc_query_list_refresh_handler (GHashTable *changes, gpointer user_data)
{
GNCQueryList *list = (GNCQueryList *)user_data;
g_return_if_fail (IS_GNC_QUERY_LIST(list));
gnc_query_list_refresh (list);
}
static void
gnc_query_list_init (GNCQueryList *list)
{
@ -193,8 +212,13 @@ gnc_query_list_init (GNCQueryList *list)
list->prev_allocation = -1;
list->title_widths = NULL;
}
list->priv = g_new0(GNCQueryListPriv, 1);
list->priv->component_id =
gnc_register_gui_component ("gnc-query-list-cm-class",
gnc_query_list_refresh_handler,
NULL, list);
}
static void
gnc_query_list_init_clist (GNCQueryList *list)
@ -400,6 +424,13 @@ gnc_query_list_destroy (GtkObject *object)
{
GNCQueryList *list = GNC_QUERY_LIST(object);
if (list->priv && list->priv->component_id >= 0)
gnc_unregister_gui_component (list->priv->component_id);
if (list->priv)
{
g_free (list->priv);
list->priv = NULL;
}
if (list->query)
{
xaccFreeQuery(list->query);
@ -709,8 +740,12 @@ gnc_query_list_fill(GNCQueryList *list)
{
gchar *strings[list->num_columns + 1];
GList *entries, *item;
const GUID *guid;
gint i;
/* Clear all watches */
gnc_gui_component_clear_watches (list->priv->component_id);
/* Reverse the list now because 'append()' takes too long */
entries = gncQueryRun(list->query);
entries = g_list_reverse(entries);
@ -765,6 +800,11 @@ gnc_query_list_fill(GNCQueryList *list)
/* Now update any checkmarks */
update_booleans (list, row);
/* and set a watcher on this item */
guid = (const GUID*)((list->priv->get_guid)(item->data));
gnc_gui_component_watch_entity (list->priv->component_id, guid,
GNC_EVENT_MODIFY | GNC_EVENT_DESTROY);
list->num_entries++;
}

View File

@ -38,6 +38,7 @@ extern "C" {
#define IS_GNC_QUERY_LIST_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_GNC_QUERY_LIST))
typedef struct _GNCQueryList GNCQueryList;
typedef struct _GNCQueryListPriv GNCQueryListPriv;
typedef struct _GNCQueryListClass GNCQueryListClass;
struct _GNCQueryList
@ -63,6 +64,9 @@ struct _GNCQueryList
/* Column resizing */
gint prev_allocation;
gint *title_widths;
/* Private data */
GNCQueryListPriv *priv;
};
struct _GNCQueryListClass

View File

@ -26,6 +26,9 @@ struct _GNCSearchParamPrivate {
GSList * converters;
GSList * param_path;
GNCIdTypeConst type;
GNCSearchParamFcn lookup_fcn;
gpointer lookup_arg;
};
static GtkObjectClass *parent_class;
@ -215,6 +218,22 @@ gnc_search_param_set_justify (GNCSearchParam *param, GtkJustification justify)
param->justify = justify;
}
void
gnc_search_param_set_passive (GNCSearchParam *param, gboolean value)
{
g_assert (IS_GNCSEARCH_PARAM (param));
param->passive = value;
}
void
gnc_search_param_set_non_resizable (GNCSearchParam *param, gboolean value)
{
g_assert (IS_GNCSEARCH_PARAM (param));
param->non_resizeable = value;
}
gboolean
gnc_search_param_type_match (GNCSearchParam *a, GNCSearchParam *b)
{
@ -304,3 +323,46 @@ gnc_search_param_prepend (GList *list, char const *title,
va_end (ap);
return result;
}
void
gnc_search_param_set_param_fcn (GNCSearchParam *param,
GNCIdTypeConst param_type,
GNCSearchParamFcn fcn,
gpointer arg)
{
g_return_if_fail (param);
g_return_if_fail (param_type && *param_type);
g_return_if_fail (fcn);
g_return_if_fail (IS_GNCSEARCH_PARAM(param));
param->priv->lookup_fcn = fcn;
param->priv->lookup_arg = arg;
gnc_search_param_override_param_type (param, param_type);
}
/* Compute the value of this parameter for this object */
gpointer
gnc_search_param_compute_value (GNCSearchParam *param, gpointer object)
{
g_return_val_if_fail(param, NULL);
g_return_val_if_fail(IS_GNCSEARCH_PARAM(param), NULL);
if (param->priv->lookup_fcn)
{
return ((param->priv->lookup_fcn)(object, param->priv->lookup_arg));
}
else
{
GSList *converters = gnc_search_param_get_converters (param);
QueryAccess fcn = NULL;
gpointer res = object;
/* Do all the object conversions */
for (; converters; converters = converters->next) {
fcn = converters->data;
res = fcn (res);
}
return res;
}
}

View File

@ -21,6 +21,8 @@ struct _GNCSearchParam {
const char * title;
GtkJustification justify;
gboolean passive;
gboolean non_resizeable;
};
struct _GNCSearchParamClass {
@ -38,9 +40,13 @@ guint gnc_search_param_get_type (void);
GNCSearchParam * gnc_search_param_new (void);
GNCSearchParam * gnc_search_param_clone (GNCSearchParam *param);
/* use the param_path for this parameter. This will automatically
* compute the parameter type and the converter functions.
*/
void gnc_search_param_set_param_path (GNCSearchParam *param,
GNCIdTypeConst search_type,
GSList *param_path);
/* List is property of the caller */
GSList * gnc_search_param_get_param_path (GNCSearchParam *param);
GNCIdTypeConst gnc_search_param_get_param_type (GNCSearchParam *param);
@ -48,6 +54,10 @@ void gnc_search_param_set_title (GNCSearchParam *param,
const char *title);
void gnc_search_param_set_justify (GNCSearchParam *param,
GtkJustification justify);
void gnc_search_param_set_passive (GNCSearchParam *param,
gboolean value);
void gnc_search_param_set_non_resizable (GNCSearchParam *param,
gboolean value);
gboolean gnc_search_param_type_match (GNCSearchParam *a,
GNCSearchParam *b);
@ -64,6 +74,7 @@ GSList * gnc_search_param_get_converters (GNCSearchParam *param);
void gnc_search_param_override_param_type (GNCSearchParam *param,
GNCIdTypeConst param_type);
/*************************************************************
* Helper functions ..
*/
@ -81,5 +92,20 @@ GList * gnc_search_param_prepend_with_justify (GList *list, char const *title,
GNCIdTypeConst search_type,
const char *param, ...);
/* set a lookup function for this parameter (in lieu of setting the
* param path) if you want to specify a direct lookup function when
* using the compute_value interface. Note that this wont work with
* sorting or other query interfaces, it's only useful for the
* query-list.
*/
typedef gpointer (*GNCSearchParamFcn)(gpointer object, gpointer arg);
void gnc_search_param_set_param_fcn (GNCSearchParam *param,
GNCIdTypeConst param_type,
GNCSearchParamFcn fcn,
gpointer arg);
/* Compute the value of this parameter for this object */
gpointer gnc_search_param_compute_value (GNCSearchParam *param, gpointer object);
#endif /* _GNCSEARCH_PARAM_H */