mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
* gncObject -- object registration in the engine; hook into the books
* QueryNew interface revision-1 check-in * update all the business objects to register with the new query system git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@6680 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
beaab8a9f2
commit
ff880b0efd
17
ChangeLog
17
ChangeLog
@ -1,3 +1,20 @@
|
||||
2002-02-03 Derek Atkins <warlord@MIT.EDU>
|
||||
|
||||
* src/engine/gncObject.c: core object registration.
|
||||
|
||||
* src/engine/gnc-book.c: call into the object registration whenver
|
||||
a book is created or destroyed.
|
||||
|
||||
* src/engine/gnc-engine.c: initialize the object registration and
|
||||
QueryNew subsystems.
|
||||
|
||||
* first revision of the "QueryNew" interface. Note that the
|
||||
interface is not complete -- in fact, the API will be changing
|
||||
this afternoon, but I wanted a baseline (working) system checked
|
||||
into the repository. Right now only the business code is using
|
||||
the new query -- the old query still exists, so you should see no
|
||||
functional difference in anything except the business code.
|
||||
|
||||
2002-01-29 Dave Peticolas <dave@krondo.com>
|
||||
|
||||
* src/report/standard-reports/account-piecharts.scm: bump up default
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "gnc-module-api.h"
|
||||
#include "gw-business-core.h"
|
||||
|
||||
#include "gncBusinessP.h"
|
||||
#include "gncCustomerP.h"
|
||||
#include "gncEmployeeP.h"
|
||||
#include "gncEntryP.h"
|
||||
@ -52,9 +51,6 @@ gnc_module_init(int refcount)
|
||||
|
||||
if(refcount == 0)
|
||||
{
|
||||
/* initialize the business engine on the first load */
|
||||
gncBusinessInitialize (0, NULL);
|
||||
|
||||
/* initialize known types */
|
||||
gncCustomerRegister ();
|
||||
gncEmployeeRegister ();
|
||||
|
@ -1,130 +1,38 @@
|
||||
/*
|
||||
* gncBusiness.c -- the Core Business Object Registry
|
||||
* Copyright (C) 2001 Derek Atkins
|
||||
* gncBusiness.c -- Business helper functions
|
||||
* Copyright (C) 2002 Derek Atkins
|
||||
* Author: Derek Atkins <warlord@MIT.EDU>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "messages.h"
|
||||
|
||||
#include "gncBusiness.h"
|
||||
#include "gncBusinessP.h"
|
||||
|
||||
static gboolean business_is_initialized = FALSE;
|
||||
static GList *business_modules = NULL;
|
||||
struct _iterate {
|
||||
foreachObjectCB cb;
|
||||
gpointer user_data;
|
||||
};
|
||||
|
||||
void gncBusinessCreateBook (GNCBook *book)
|
||||
static void get_list (gpointer key, gpointer item, gpointer arg)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
if (!book) return;
|
||||
for (l = business_modules; l; l = l->next) {
|
||||
GncBusinessObject *obj = l->data;
|
||||
if (obj->create)
|
||||
obj->create (book);
|
||||
}
|
||||
struct _iterate *iter = arg;
|
||||
iter->cb (item, iter->user_data);
|
||||
}
|
||||
|
||||
void gncBusinessDestroyBook (GNCBook *book)
|
||||
void gncBusinessForeach (GNCBook *book, GNCIdType mod_name,
|
||||
foreachObjectCB cb, gpointer user_data)
|
||||
{
|
||||
GList *l;
|
||||
GHashTable *ht;
|
||||
struct _iterate iter;
|
||||
|
||||
if (!book) return;
|
||||
for (l = business_modules; l; l = l->next) {
|
||||
GncBusinessObject *obj = l->data;
|
||||
if (obj->destroy)
|
||||
obj->destroy (book);
|
||||
}
|
||||
}
|
||||
|
||||
GList *
|
||||
gncBusinessGetList (GNCBook *book, const char *type_name,
|
||||
gboolean show_all)
|
||||
{
|
||||
const GncBusinessObject *obj;
|
||||
|
||||
if (!book || !type_name) return NULL;
|
||||
|
||||
obj = gncBusinessLookup (type_name);
|
||||
if (!obj) return NULL;
|
||||
|
||||
if (obj->get_list)
|
||||
return ((*(obj->get_list))(book, show_all));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *
|
||||
gncBusinessPrintable (const char *type_name, gpointer obj)
|
||||
{
|
||||
const GncBusinessObject *b_obj;
|
||||
|
||||
if (!type_name || !obj) return NULL;
|
||||
|
||||
b_obj = gncBusinessLookup (type_name);
|
||||
if (!b_obj) return NULL;
|
||||
|
||||
if (b_obj->printable)
|
||||
return ((*(b_obj->printable))(obj));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char * gncBusinessGetTypeLabel (const char *type_name)
|
||||
{
|
||||
const GncBusinessObject *obj;
|
||||
|
||||
if (!type_name) return NULL;
|
||||
|
||||
obj = gncBusinessLookup (type_name);
|
||||
if (!obj) return NULL;
|
||||
|
||||
return _(obj->type_label);
|
||||
}
|
||||
|
||||
/* INITIALIZATION and PRIVATE FUNCTIONS */
|
||||
|
||||
void
|
||||
gncBusinessInitialize (int argc, char **argv)
|
||||
{
|
||||
if (business_is_initialized) return;
|
||||
business_is_initialized = TRUE;
|
||||
}
|
||||
|
||||
/* Register new types of business objects.
|
||||
* Return TRUE if successful,
|
||||
* return FALSE if it fails, invalid arguments, or if the object
|
||||
* already exists
|
||||
*/
|
||||
gboolean gncBusinessRegister (const GncBusinessObject *object)
|
||||
{
|
||||
if (!object) return FALSE;
|
||||
if (object->version != GNC_BUSINESS_VERSION) return FALSE;
|
||||
if (!business_is_initialized) return FALSE;
|
||||
|
||||
if (g_list_index (business_modules, (gpointer)object) == -1)
|
||||
business_modules = g_list_append (business_modules, (gpointer)object);
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const GncBusinessObject * gncBusinessLookup (const char *name)
|
||||
{
|
||||
GList *iter;
|
||||
const GncBusinessObject *obj;
|
||||
|
||||
if (!name) return NULL;
|
||||
|
||||
for (iter = business_modules; iter; iter = iter->next) {
|
||||
obj = iter->data;
|
||||
if (!strcmp (obj->name, name))
|
||||
return obj;
|
||||
}
|
||||
return NULL;
|
||||
if (!book || !cb) return;
|
||||
|
||||
iter.cb = cb;
|
||||
iter.user_data = user_data;
|
||||
|
||||
ht = gnc_book_get_data (book, mod_name);
|
||||
if (ht)
|
||||
g_hash_table_foreach (ht, get_list, &iter);
|
||||
}
|
||||
|
@ -1,53 +1,16 @@
|
||||
/*
|
||||
* gncBusiness.h -- the Core Business Interface
|
||||
* Copyright (C) 2001 Derek Atkins
|
||||
* gncBusiness.h -- Business Helper Functions
|
||||
* Copyright (C) 2002 Derek Atkins
|
||||
* Author: Derek Atkins <warlord@MIT.EDU>
|
||||
*/
|
||||
|
||||
#ifndef GNC_BUSINESS_H_
|
||||
#define GNC_BUSINESS_H_
|
||||
|
||||
#include "gnc-book.h"
|
||||
|
||||
/* Defines the version of the core business object registration
|
||||
* interface. Only business modules compiled against this version
|
||||
* of the interface will load properly
|
||||
*/
|
||||
#define GNC_BUSINESS_VERSION 1
|
||||
|
||||
typedef struct _gncBusinessObject GncBusinessObject;
|
||||
|
||||
/* This is the Business Object descriptor */
|
||||
struct _gncBusinessObject {
|
||||
gint version;
|
||||
const char * name;
|
||||
const char * type_label;
|
||||
void (*create)(GNCBook *);
|
||||
void (*destroy)(GNCBook *);
|
||||
GList * (*get_list)(GNCBook *, gboolean show_all);
|
||||
const char * (*printable)(gpointer obj);
|
||||
};
|
||||
|
||||
void gncBusinessCreateBook (GNCBook *book);
|
||||
|
||||
void gncBusinessDestroyBook (GNCBook *book);
|
||||
|
||||
GList * gncBusinessGetList (GNCBook *book, const char *type_name,
|
||||
gboolean show_all);
|
||||
|
||||
const char * gncBusinessPrintable (const char *type_name, gpointer obj);
|
||||
|
||||
|
||||
/* REGISTRATION AND REG-LOOKUP FUNCTIONS */
|
||||
|
||||
/* Register new types of business objects */
|
||||
gboolean gncBusinessRegister (const GncBusinessObject *object);
|
||||
|
||||
/* Get the printable label for a type */
|
||||
const char * gncBusinessGetTypeLabel (const char *type_name);
|
||||
|
||||
/* Lookup a business object */
|
||||
const GncBusinessObject * gncBusinessLookup (const char *name);
|
||||
#include "gncObject.h"
|
||||
#include "GNCId.h"
|
||||
|
||||
void gncBusinessForeach (GNCBook *book, GNCIdType mod_name,
|
||||
foreachObjectCB cb, gpointer user_data);
|
||||
|
||||
#endif /* GNC_BUSINESS_H_ */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* gncCustomer.c -- the Core Customer Interface
|
||||
* Copyright (C) 2001 Derek Atkins
|
||||
* Copyright (C) 2001,2002 Derek Atkins
|
||||
* Author: Derek Atkins <warlord@MIT.EDU>
|
||||
*/
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
#include "gnc-book-p.h"
|
||||
#include "GNCIdP.h"
|
||||
#include "gnc-numeric.h"
|
||||
#include "gncObject.h"
|
||||
#include "QueryObject.h"
|
||||
|
||||
#include "gncBusiness.h"
|
||||
#include "gncCustomer.h"
|
||||
@ -315,10 +317,13 @@ gboolean gncCustomerIsDirty (GncCustomer *cust)
|
||||
|
||||
/* Other functions */
|
||||
|
||||
static gint gncCustomerSortFunc (gconstpointer a, gconstpointer b) {
|
||||
GncCustomer *ca = (GncCustomer *) a;
|
||||
GncCustomer *cb = (GncCustomer *) b;
|
||||
return(strcmp(ca->name, cb->name));
|
||||
int gncCustomerCompare (GncCustomer *a, GncCustomer *b)
|
||||
{
|
||||
if (!a && !b) return 0;
|
||||
if (!a && b) return 1;
|
||||
if (a && !b) return -1;
|
||||
|
||||
return(strcmp(a->name, b->name));
|
||||
}
|
||||
|
||||
/* Package-Private functions */
|
||||
@ -343,36 +348,11 @@ static void remObj (GncCustomer *cust)
|
||||
g_hash_table_remove (ht, &cust->guid);
|
||||
}
|
||||
|
||||
struct _iterate {
|
||||
GList *list;
|
||||
gboolean show_all;
|
||||
};
|
||||
|
||||
static void get_list (gpointer key, gpointer item, gpointer arg)
|
||||
static void _gncCustomerForeach (GNCBook *book, foreachObjectCB cb,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct _iterate *iter = arg;
|
||||
GncCustomer *cust = item;
|
||||
|
||||
if (iter->show_all || gncCustomerGetActive (cust)) {
|
||||
iter->list = g_list_insert_sorted (iter->list, cust, gncCustomerSortFunc);
|
||||
}
|
||||
}
|
||||
|
||||
static GList * _gncCustomerGetList (GNCBook *book, gboolean show_all)
|
||||
{
|
||||
GHashTable *ht;
|
||||
struct _iterate iter;
|
||||
|
||||
if (!book) return NULL;
|
||||
|
||||
iter.list = NULL;
|
||||
iter.show_all = show_all;
|
||||
|
||||
ht = gnc_book_get_data (book, _GNC_MOD_NAME);
|
||||
if (ht)
|
||||
g_hash_table_foreach (ht, get_list, &iter);
|
||||
|
||||
return iter.list;
|
||||
if (!book || !cb) return;
|
||||
gncBusinessForeach (book, _GNC_MOD_NAME, cb, user_data);
|
||||
}
|
||||
|
||||
static const char * _gncCustomerPrintable (gpointer item)
|
||||
@ -407,19 +387,33 @@ static void _gncCustomerDestroy (GNCBook *book)
|
||||
g_hash_table_destroy (ht);
|
||||
}
|
||||
|
||||
static GncBusinessObject gncCustomerDesc = {
|
||||
GNC_BUSINESS_VERSION,
|
||||
static GncObject_t gncCustomerDesc = {
|
||||
GNC_OBJECT_VERSION,
|
||||
_GNC_MOD_NAME,
|
||||
"Customer",
|
||||
_gncCustomerCreate,
|
||||
_gncCustomerDestroy,
|
||||
_gncCustomerGetList,
|
||||
_gncCustomerForeach,
|
||||
_gncCustomerPrintable
|
||||
};
|
||||
|
||||
gboolean gncCustomerRegister (void)
|
||||
{
|
||||
return gncBusinessRegister (&gncCustomerDesc);
|
||||
static QueryObjectDef params[] = {
|
||||
{ CUSTOMER_GUID, QUERYCORE_GUID, (QueryAccess)gncCustomerGetGUID },
|
||||
{ CUSTOMER_ID, QUERYCORE_STRING, (QueryAccess)gncCustomerGetID },
|
||||
{ CUSTOMER_NAME, QUERYCORE_STRING, (QueryAccess)gncCustomerGetName },
|
||||
{ NULL },
|
||||
};
|
||||
static const QueryConvertDef converters[] = {
|
||||
{ GNC_ID_BOOK, (QueryConvert)gncCustomerGetBook },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
gncQueryObjectRegister (_GNC_MOD_NAME, (QuerySort)gncCustomerCompare,
|
||||
params, converters);
|
||||
|
||||
return gncObjectRegister (&gncCustomerDesc);
|
||||
}
|
||||
|
||||
static gint lastCustomer = 27;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* gncCustomer.h -- the Core Customer Interface
|
||||
* Copyright (C) 2001 Derek Atkins
|
||||
* Copyright (C) 2001,2002 Derek Atkins
|
||||
* Author: Derek Atkins <warlord@MIT.EDU>
|
||||
*/
|
||||
|
||||
@ -58,5 +58,10 @@ GList * gncCustomerGetJoblist (GncCustomer *customer, gboolean show_all);
|
||||
GncCustomer * gncCustomerLookup (GNCBook *book, const GUID *guid);
|
||||
|
||||
gboolean gncCustomerIsDirty (GncCustomer *customer);
|
||||
int gncCustomerCompare (GncCustomer *a, GncCustomer *b);
|
||||
|
||||
#define CUSTOMER_GUID "guid"
|
||||
#define CUSTOMER_ID "id"
|
||||
#define CUSTOMER_NAME "name"
|
||||
|
||||
#endif /* GNC_CUSTOMER_H_ */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* gncEmployee.c -- the Core Employee Interface
|
||||
* Copyright (C) 2001 Derek Atkins
|
||||
* Copyright (C) 2001,2002 Derek Atkins
|
||||
* Author: Derek Atkins <warlord@MIT.EDU>
|
||||
*/
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
#include "gnc-engine-util.h"
|
||||
#include "gnc-book-p.h"
|
||||
#include "GNCIdP.h"
|
||||
#include "gncObject.h"
|
||||
#include "QueryObject.h"
|
||||
|
||||
#include "gncBusiness.h"
|
||||
#include "gncEmployee.h"
|
||||
@ -243,10 +245,13 @@ void gncEmployeeCommitEdit (GncEmployee *employee)
|
||||
|
||||
/* Other functions */
|
||||
|
||||
static gint gncEmployeeSortFunc (gconstpointer a, gconstpointer b) {
|
||||
GncEmployee *ea = (GncEmployee *) a;
|
||||
GncEmployee *eb = (GncEmployee *) b;
|
||||
return(strcmp(ea->username, eb->username));
|
||||
int gncEmployeeCompare (GncEmployee *a, GncEmployee *b)
|
||||
{
|
||||
if (!a && !b) return 0;
|
||||
if (!a && b) return 1;
|
||||
if (a && !b) return -1;
|
||||
|
||||
return(strcmp(a->username, b->username));
|
||||
}
|
||||
|
||||
/* Package-Private functions */
|
||||
@ -272,36 +277,11 @@ static void remObj (GncEmployee *employee)
|
||||
g_hash_table_remove (ht, &employee->guid);
|
||||
}
|
||||
|
||||
struct _iterate {
|
||||
GList *list;
|
||||
gboolean show_all;
|
||||
};
|
||||
|
||||
static void get_list (gpointer key, gpointer item, gpointer arg)
|
||||
static void _gncEmployeeForeach (GNCBook *book, foreachObjectCB cb,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct _iterate *iter = arg;
|
||||
GncEmployee *employee = item;
|
||||
|
||||
if (iter->show_all || gncEmployeeGetActive (employee)) {
|
||||
iter->list = g_list_insert_sorted (iter->list, employee, gncEmployeeSortFunc);
|
||||
}
|
||||
}
|
||||
|
||||
static GList * _gncEmployeeGetList (GNCBook *book, gboolean show_all)
|
||||
{
|
||||
GHashTable *ht;
|
||||
struct _iterate iter;
|
||||
|
||||
if (!book) return NULL;
|
||||
|
||||
iter.list = NULL;
|
||||
iter.show_all = show_all;
|
||||
|
||||
ht = gnc_book_get_data (book, _GNC_MOD_NAME);
|
||||
if (ht)
|
||||
g_hash_table_foreach (ht, get_list, &iter);
|
||||
|
||||
return iter.list;
|
||||
if (!book || !cb) return;
|
||||
gncBusinessForeach (book, _GNC_MOD_NAME, cb, user_data);
|
||||
}
|
||||
|
||||
static const char * _gncEmployeePrintable (gpointer item)
|
||||
@ -336,19 +316,33 @@ static void _gncEmployeeDestroy (GNCBook *book)
|
||||
g_hash_table_destroy (ht);
|
||||
}
|
||||
|
||||
static GncBusinessObject gncEmployeeDesc = {
|
||||
GNC_BUSINESS_VERSION,
|
||||
static GncObject_t gncEmployeeDesc = {
|
||||
GNC_OBJECT_VERSION,
|
||||
_GNC_MOD_NAME,
|
||||
"Employee",
|
||||
_gncEmployeeCreate,
|
||||
_gncEmployeeDestroy,
|
||||
_gncEmployeeGetList,
|
||||
_gncEmployeeForeach,
|
||||
_gncEmployeePrintable
|
||||
};
|
||||
|
||||
gboolean gncEmployeeRegister (void)
|
||||
{
|
||||
return gncBusinessRegister (&gncEmployeeDesc);
|
||||
static QueryObjectDef params[] = {
|
||||
{ EMPLOYEE_GUID, QUERYCORE_GUID, (QueryAccess)gncEmployeeGetGUID },
|
||||
{ EMPLOYEE_ID, QUERYCORE_STRING, (QueryAccess)gncEmployeeGetID },
|
||||
{ EMPLOYEE_USERNAME, QUERYCORE_STRING, (QueryAccess)gncEmployeeGetUsername },
|
||||
{ NULL },
|
||||
};
|
||||
static const QueryConvertDef converters[] = {
|
||||
{ GNC_ID_BOOK, (QueryConvert)gncEmployeeGetBook },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
gncQueryObjectRegister (_GNC_MOD_NAME, (QuerySort)gncEmployeeCompare,
|
||||
params, converters);
|
||||
|
||||
return gncObjectRegister (&gncEmployeeDesc);
|
||||
}
|
||||
|
||||
static gint lastEmployee = 2;
|
||||
|
@ -46,5 +46,10 @@ GncEmployee * gncEmployeeLookup (GNCBook *book, const GUID *guid);
|
||||
gboolean gncEmployeeIsDirty (GncEmployee *employee);
|
||||
|
||||
void gncEmployeeCommitEdit (GncEmployee *employee);
|
||||
int gncEmployeeCompare (GncEmployee *a, GncEmployee *b);
|
||||
|
||||
#define EMPLOYEE_GUID "guid"
|
||||
#define EMPLOYEE_ID "id"
|
||||
#define EMPLOYEE_USERNAME "username"
|
||||
|
||||
#endif /* GNC_EMPLOYEE_H_ */
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "gnc-engine-util.h"
|
||||
#include "gnc-book-p.h"
|
||||
#include "GNCIdP.h"
|
||||
#include "QueryObject.h"
|
||||
|
||||
#include "gncBusiness.h"
|
||||
#include "gncEntry.h"
|
||||
@ -400,6 +401,26 @@ void gncEntryCommitEdit (GncEntry *entry)
|
||||
/* XXX */
|
||||
}
|
||||
|
||||
int gncEntryCompare (GncEntry *a, GncEntry *b)
|
||||
{
|
||||
int compare;
|
||||
|
||||
if (a == b) return 0;
|
||||
if (!a && b) return -1;
|
||||
if (a && !b) return 1;
|
||||
|
||||
compare = timespec_cmp (&(a->date), &(b->date));
|
||||
if (!compare) return compare;
|
||||
|
||||
compare = safe_strcmp (a->desc, b->desc);
|
||||
if (!compare) return compare;
|
||||
|
||||
compare = safe_strcmp (a->action, b->action);
|
||||
if (!compare) return compare;
|
||||
|
||||
return guid_compare (&(a->guid), &(b->guid));
|
||||
}
|
||||
|
||||
/* Package-Private functions */
|
||||
|
||||
static void addObj (GncEntry *entry)
|
||||
@ -444,17 +465,43 @@ static void _gncEntryDestroy (GNCBook *book)
|
||||
g_hash_table_destroy (ht);
|
||||
}
|
||||
|
||||
static GncBusinessObject gncEntryDesc = {
|
||||
GNC_BUSINESS_VERSION,
|
||||
static void _gncEntryForeach (GNCBook *book, foreachObjectCB cb,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (!book || !cb) return;
|
||||
gncBusinessForeach (book, _GNC_MOD_NAME, cb, user_data);
|
||||
}
|
||||
|
||||
static GncObject_t gncEntryDesc = {
|
||||
GNC_OBJECT_VERSION,
|
||||
_GNC_MOD_NAME,
|
||||
"Order/Invoice Entry",
|
||||
_gncEntryCreate,
|
||||
_gncEntryDestroy,
|
||||
NULL, /* get list */
|
||||
_gncEntryForeach,
|
||||
NULL /* printable */
|
||||
};
|
||||
|
||||
gboolean gncEntryRegister (void)
|
||||
{
|
||||
return gncBusinessRegister (&gncEntryDesc);
|
||||
static QueryObjectDef params[] = {
|
||||
{ ENTRY_GUID, QUERYCORE_GUID, (QueryAccess)gncEntryGetGUID },
|
||||
{ ENTRY_DATE, QUERYCORE_DATE, (QueryAccess)gncEntryGetDate },
|
||||
{ ENTRY_DESC, QUERYCORE_STRING, (QueryAccess)gncEntryGetDescription },
|
||||
{ ENTRY_ACTION, QUERYCORE_STRING, (QueryAccess)gncEntryGetAction },
|
||||
{ ENTRY_QTY, QUERYCORE_NUMERIC, (QueryAccess)gncEntryGetQuantity },
|
||||
{ ENTRY_PRICE, QUERYCORE_NUMERIC, (QueryAccess)gncEntryGetPrice },
|
||||
{ NULL },
|
||||
};
|
||||
static const QueryConvertDef converters[] = {
|
||||
{ GNC_ID_BOOK, (QueryConvert)gncEntryGetBook },
|
||||
{ GNC_INVOICE_MODULE_NAME, (QueryConvert)gncEntryGetInvoice },
|
||||
{ GNC_ORDER_MODULE_NAME, (QueryConvert)gncEntryGetOrder },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
gncQueryObjectRegister (_GNC_MOD_NAME, (QuerySort)gncEntryCompare,
|
||||
params, converters);
|
||||
|
||||
return gncObjectRegister (&gncEntryDesc);
|
||||
}
|
||||
|
@ -84,5 +84,13 @@ GncInvoice * gncEntryGetInvoice (GncEntry *entry);
|
||||
GncEntry * gncEntryLookup (GNCBook *book, const GUID *guid);
|
||||
|
||||
void gncEntryCommitEdit (GncEntry *entry);
|
||||
int gncEntryCompare (GncEntry *a, GncEntry *b);
|
||||
|
||||
#define ENTRY_GUID "guid"
|
||||
#define ENTRY_DATE "date"
|
||||
#define ENTRY_DESC "desc"
|
||||
#define ENTRY_ACTION "action"
|
||||
#define ENTRY_QTY "qty"
|
||||
#define ENTRY_PRICE "price"
|
||||
|
||||
#endif /* GNC_ENTRY_H_ */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* gncInvoice.c -- the Core Business Invoice
|
||||
* Copyright (C) 2001 Derek Atkins
|
||||
* Copyright (C) 2001,2002 Derek Atkins
|
||||
* Author: Derek Atkins <warlord@MIT.EDU>
|
||||
*/
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
#include "gnc-engine-util.h"
|
||||
#include "gnc-book-p.h"
|
||||
#include "GNCIdP.h"
|
||||
#include "QueryObject.h"
|
||||
|
||||
#include "gncBusiness.h"
|
||||
#include "gncEntry.h"
|
||||
@ -45,7 +46,7 @@ struct _gncInvoice {
|
||||
gboolean dirty;
|
||||
};
|
||||
|
||||
#define _GNC_MOD_NAME GNC_ENTRY_MODULE_NAME
|
||||
#define _GNC_MOD_NAME GNC_INVOICE_MODULE_NAME
|
||||
|
||||
#define GNC_INVOICE_ID "gncInvoice"
|
||||
#define GNC_INVOICE_GUID "invoice-guid"
|
||||
@ -488,6 +489,26 @@ void gncInvoiceCommitEdit (GncInvoice *invoice)
|
||||
if (!invoice) return;
|
||||
}
|
||||
|
||||
int gncInvoiceCompare (GncInvoice *a, GncInvoice *b)
|
||||
{
|
||||
int compare;
|
||||
|
||||
if (a == b) return 0;
|
||||
if (!a && b) return -1;
|
||||
if (a && !b) return 1;
|
||||
|
||||
compare = safe_strcmp (a->id, b->id);
|
||||
if (!compare) return compare;
|
||||
|
||||
compare = timespec_cmp (&(a->date_opened), &(b->date_opened));
|
||||
if (!compare) return compare;
|
||||
|
||||
compare = timespec_cmp (&(a->date_closed), &(b->date_closed));
|
||||
if (!compare) return compare;
|
||||
|
||||
return guid_compare (&(a->guid), &(b->guid));
|
||||
}
|
||||
|
||||
/* Package-Private functions */
|
||||
|
||||
static void addObj (GncInvoice *invoice)
|
||||
@ -532,19 +553,40 @@ static void _gncInvoiceDestroy (GNCBook *book)
|
||||
g_hash_table_destroy (ht);
|
||||
}
|
||||
|
||||
static GncBusinessObject gncInvoiceDesc = {
|
||||
GNC_BUSINESS_VERSION,
|
||||
static void _gncInvoiceForeach (GNCBook *book, foreachObjectCB cb,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (!book || !cb) return;
|
||||
gncBusinessForeach (book, _GNC_MOD_NAME, cb, user_data);
|
||||
}
|
||||
|
||||
static GncObject_t gncInvoiceDesc = {
|
||||
GNC_OBJECT_VERSION,
|
||||
_GNC_MOD_NAME,
|
||||
"Purchase/Sales Invoice",
|
||||
_gncInvoiceCreate,
|
||||
_gncInvoiceDestroy,
|
||||
NULL, /* get list */
|
||||
_gncInvoiceForeach,
|
||||
NULL /* printable */
|
||||
};
|
||||
|
||||
gboolean gncInvoiceRegister (void)
|
||||
{
|
||||
return gncBusinessRegister (&gncInvoiceDesc);
|
||||
static QueryObjectDef params[] = {
|
||||
{ INVOICE_GUID, QUERYCORE_GUID, (QueryAccess)gncInvoiceGetGUID },
|
||||
{ NULL },
|
||||
};
|
||||
static const QueryConvertDef converters[] = {
|
||||
{ GNC_ID_BOOK, (QueryConvert)gncInvoiceGetBook },
|
||||
{ GNC_ID_ACCOUNT, (QueryConvert)gncInvoiceGetPostedAcc },
|
||||
{ GNC_ID_TRANS, (QueryConvert)gncInvoiceGetPostedTxn },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
gncQueryObjectRegister (_GNC_MOD_NAME, (QuerySort)gncInvoiceCompare,
|
||||
params, converters);
|
||||
|
||||
return gncObjectRegister (&gncInvoiceDesc);
|
||||
}
|
||||
|
||||
static gint lastId = 187; /* XXX */
|
||||
|
@ -69,5 +69,8 @@ GncInvoice * gncInvoiceLookup (GNCBook *book, const GUID *guid);
|
||||
gboolean gncInvoiceIsDirty (GncInvoice *invoice);
|
||||
void gncInvoiceBeginEdit (GncInvoice *invoice);
|
||||
void gncInvoiceCommitEdit (GncInvoice *invoice);
|
||||
int gncInvoiceCompare (GncInvoice *a, GncInvoice *b);
|
||||
|
||||
#define INVOICE_GUID "guid"
|
||||
|
||||
#endif /* GNC_INVOICE_H_ */
|
||||
|
@ -266,16 +266,6 @@ static void remObj (GncJob *job)
|
||||
g_hash_table_remove (ht, &job->guid);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static GList * _gncJobGetList (GNCBook *obj, gboolean show_all)
|
||||
{
|
||||
if (!obj) return NULL;
|
||||
|
||||
/* XXX */
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char * _gncJobPrintable (gpointer item)
|
||||
{
|
||||
GncJob *c;
|
||||
@ -308,19 +298,26 @@ static void _gncJobDestroy (GNCBook *book)
|
||||
g_hash_table_destroy (ht);
|
||||
}
|
||||
|
||||
static GncBusinessObject gncJobDesc = {
|
||||
GNC_BUSINESS_VERSION,
|
||||
GNC_JOB_MODULE_NAME,
|
||||
static void _gncJobForeach (GNCBook *book, foreachObjectCB cb,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (!book || !cb) return;
|
||||
gncBusinessForeach (book, _GNC_MOD_NAME, cb, user_data);
|
||||
}
|
||||
|
||||
static GncObject_t gncJobDesc = {
|
||||
GNC_OBJECT_VERSION,
|
||||
_GNC_MOD_NAME,
|
||||
"Job",
|
||||
_gncJobCreate,
|
||||
_gncJobDestroy,
|
||||
NULL, /* get_list */
|
||||
_gncJobForeach,
|
||||
_gncJobPrintable
|
||||
};
|
||||
|
||||
gboolean gncJobRegister (void)
|
||||
{
|
||||
return gncBusinessRegister (&gncJobDesc);
|
||||
return gncObjectRegister (&gncJobDesc);
|
||||
}
|
||||
|
||||
static gint lastJob = 57;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* gncOrder.c -- the Core Business Order
|
||||
* Copyright (C) 2001 Derek Atkins
|
||||
* Copyright (C) 2001,2002 Derek Atkins
|
||||
* Author: Derek Atkins <warlord@MIT.EDU>
|
||||
*/
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
#include "gnc-engine-util.h"
|
||||
#include "gnc-book-p.h"
|
||||
#include "GNCIdP.h"
|
||||
#include "QueryObject.h"
|
||||
|
||||
#include "gncBusiness.h"
|
||||
#include "gncEntry.h"
|
||||
@ -256,6 +257,26 @@ void gncOrderCommitEdit (GncOrder *order)
|
||||
if (!order) return;
|
||||
}
|
||||
|
||||
int gncOrderCompare (GncOrder *a, GncOrder *b)
|
||||
{
|
||||
int compare;
|
||||
|
||||
if (a == b) return 0;
|
||||
if (!a && b) return -1;
|
||||
if (a && !b) return 1;
|
||||
|
||||
compare = safe_strcmp (a->id, b->id);
|
||||
if (!compare) return compare;
|
||||
|
||||
compare = timespec_cmp (&(a->opened), &(b->opened));
|
||||
if (!compare) return compare;
|
||||
|
||||
compare = timespec_cmp (&(a->closed), &(b->closed));
|
||||
if (!compare) return compare;
|
||||
|
||||
return guid_compare (&(a->guid), &(b->guid));
|
||||
}
|
||||
|
||||
/* Package-Private functions */
|
||||
|
||||
static void addObj (GncOrder *order)
|
||||
@ -300,19 +321,38 @@ static void _gncOrderDestroy (GNCBook *book)
|
||||
g_hash_table_destroy (ht);
|
||||
}
|
||||
|
||||
static GncBusinessObject gncOrderDesc = {
|
||||
GNC_BUSINESS_VERSION,
|
||||
static void _gncOrderForeach (GNCBook *book, foreachObjectCB cb,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (!book || !cb) return;
|
||||
gncBusinessForeach (book, _GNC_MOD_NAME, cb, user_data);
|
||||
}
|
||||
|
||||
static GncObject_t gncOrderDesc = {
|
||||
GNC_OBJECT_VERSION,
|
||||
_GNC_MOD_NAME,
|
||||
"Purchase/Sales Order",
|
||||
_gncOrderCreate,
|
||||
_gncOrderDestroy,
|
||||
NULL, /* get list */
|
||||
_gncOrderForeach,
|
||||
NULL /* printable */
|
||||
};
|
||||
|
||||
gboolean gncOrderRegister (void)
|
||||
{
|
||||
return gncBusinessRegister (&gncOrderDesc);
|
||||
static QueryObjectDef params[] = {
|
||||
{ ORDER_GUID, QUERYCORE_GUID, (QueryAccess)gncOrderGetGUID },
|
||||
{ NULL },
|
||||
};
|
||||
static const QueryConvertDef converters[] = {
|
||||
{ GNC_ID_BOOK, (QueryConvert)gncOrderGetBook },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
gncQueryObjectRegister (_GNC_MOD_NAME, (QuerySort)gncOrderCompare,
|
||||
params, converters);
|
||||
|
||||
return gncObjectRegister (&gncOrderDesc);
|
||||
}
|
||||
|
||||
static gint lastId = 471; /* XXX */
|
||||
|
@ -51,5 +51,8 @@ GncOrder * gncOrderLookup (GNCBook *book, const GUID *guid);
|
||||
gboolean gncOrderIsDirty (GncOrder *order);
|
||||
void gncOrderBeginEdit (GncOrder *order);
|
||||
void gncOrderCommitEdit (GncOrder *order);
|
||||
int gncOrderCompare (GncOrder *a, GncOrder *b);
|
||||
|
||||
#define ORDER_GUID "guid"
|
||||
|
||||
#endif /* GNC_ORDER_H_ */
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "gnc-engine-util.h"
|
||||
#include "gnc-book-p.h"
|
||||
#include "GNCIdP.h"
|
||||
#include "QueryObject.h"
|
||||
|
||||
#include "gncBusiness.h"
|
||||
#include "gncVendor.h"
|
||||
@ -242,10 +243,13 @@ void gncVendorCommitEdit (GncVendor *vendor)
|
||||
|
||||
/* Other functions */
|
||||
|
||||
static gint gncVendorSortFunc (gconstpointer a, gconstpointer b) {
|
||||
GncVendor *va = (GncVendor *) a;
|
||||
GncVendor *vb = (GncVendor *) b;
|
||||
return(strcmp(va->name, vb->name));
|
||||
int gncVendorCompare (GncVendor *a, GncVendor *b)
|
||||
{
|
||||
if (!a && !b) return 0;
|
||||
if (!a && b) return 1;
|
||||
if (a && !b) return -1;
|
||||
|
||||
return(strcmp(a->name, b->name));
|
||||
}
|
||||
|
||||
GList * gncVendorGetJoblist (GncVendor *vendor, gboolean show_all)
|
||||
@ -300,36 +304,11 @@ static void remObj (GncVendor *vendor)
|
||||
g_hash_table_remove (ht, &vendor->guid);
|
||||
}
|
||||
|
||||
struct _iterate {
|
||||
GList *list;
|
||||
gboolean show_all;
|
||||
};
|
||||
|
||||
static void get_list (gpointer key, gpointer item, gpointer arg)
|
||||
static void _gncVendorForeach (GNCBook *book, foreachObjectCB cb,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct _iterate *iter = arg;
|
||||
GncVendor *vendor = item;
|
||||
|
||||
if (iter->show_all || gncVendorGetActive (vendor)) {
|
||||
iter->list = g_list_insert_sorted (iter->list, vendor, gncVendorSortFunc);
|
||||
}
|
||||
}
|
||||
|
||||
static GList * _gncVendorGetList (GNCBook *book, gboolean show_all)
|
||||
{
|
||||
GHashTable *ht;
|
||||
struct _iterate iter;
|
||||
|
||||
if (!book) return NULL;
|
||||
|
||||
iter.list = NULL;
|
||||
iter.show_all = show_all;
|
||||
|
||||
ht = gnc_book_get_data (book, _GNC_MOD_NAME);
|
||||
if (ht)
|
||||
g_hash_table_foreach (ht, get_list, &iter);
|
||||
|
||||
return iter.list;
|
||||
if (!book || !cb) return;
|
||||
gncBusinessForeach (book, _GNC_MOD_NAME, cb, user_data);
|
||||
}
|
||||
|
||||
static const char * _gncVendorPrintable (gpointer item)
|
||||
@ -364,19 +343,33 @@ static void _gncVendorDestroy (GNCBook *book)
|
||||
g_hash_table_destroy (ht);
|
||||
}
|
||||
|
||||
static GncBusinessObject gncVendorDesc = {
|
||||
GNC_BUSINESS_VERSION,
|
||||
static GncObject_t gncVendorDesc = {
|
||||
GNC_OBJECT_VERSION,
|
||||
_GNC_MOD_NAME,
|
||||
"Vendor",
|
||||
_gncVendorCreate,
|
||||
_gncVendorDestroy,
|
||||
_gncVendorGetList,
|
||||
_gncVendorForeach,
|
||||
_gncVendorPrintable
|
||||
};
|
||||
|
||||
gboolean gncVendorRegister (void)
|
||||
{
|
||||
return gncBusinessRegister (&gncVendorDesc);
|
||||
static QueryObjectDef params[] = {
|
||||
{ VENDOR_GUID, QUERYCORE_GUID, (QueryAccess)gncVendorGetGUID },
|
||||
{ VENDOR_ID, QUERYCORE_STRING, (QueryAccess)gncVendorGetID },
|
||||
{ VENDOR_NAME, QUERYCORE_STRING, (QueryAccess)gncVendorGetName },
|
||||
{ NULL },
|
||||
};
|
||||
static const QueryConvertDef converters[] = {
|
||||
{ GNC_ID_BOOK, (QueryConvert)gncVendorGetBook },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
gncQueryObjectRegister (_GNC_MOD_NAME, (QuerySort)gncVendorCompare,
|
||||
params, converters);
|
||||
|
||||
return gncObjectRegister (&gncVendorDesc);
|
||||
}
|
||||
|
||||
static gint lastVendor = 17;
|
||||
|
@ -50,5 +50,10 @@ GList * gncVendorGetJoblist (GncVendor *vendor, gboolean show_all);
|
||||
|
||||
GncVendor * gncVendorLookup (GNCBook *book, const GUID *guid);
|
||||
gboolean gncVendorIsDirty (GncVendor *vendor);
|
||||
int gncVendorCompare (GncVendor *a, GncVendor *b);
|
||||
|
||||
#define VENDOR_GUID "guid"
|
||||
#define VENDOR_ID "id"
|
||||
#define VENDOR_NAME "name"
|
||||
|
||||
#endif /* GNC_VENDOR_H_ */
|
||||
|
@ -26,7 +26,6 @@
|
||||
ws
|
||||
(lambda (wrapset client-wrapset)
|
||||
(list
|
||||
"#include <gncBusiness.h>\n"
|
||||
"#include <gncAddress.h>\n"
|
||||
"#include <gncCustomer.h>\n"
|
||||
"#include <gncEmployee.h>\n"
|
||||
@ -57,18 +56,6 @@
|
||||
(gw:wrap-as-wct ws '<gnc:GncOwner*> "GncOwner*" "const GncOwner*")
|
||||
(gw:wrap-as-wct ws '<gnc:GncVendor*> "GncVendor*" "const GncVendor*")
|
||||
|
||||
;;
|
||||
;; gncBusiness.h
|
||||
;;
|
||||
|
||||
(gw:wrap-function
|
||||
ws
|
||||
'gnc:business-create-book
|
||||
'<gw:void>
|
||||
"gncBusinessCreateBook"
|
||||
'((<gnc:Book*> book))
|
||||
"Create the Business data tables in the book")
|
||||
|
||||
;; gncAddress.h
|
||||
|
||||
;; gncCustomer.h
|
||||
|
@ -19,7 +19,6 @@ test_address (void)
|
||||
{
|
||||
GncAddress *address;
|
||||
GNCBook *book = gnc_book_new ();
|
||||
gncBusinessCreateBook (book);
|
||||
|
||||
/* Test creation/destruction */
|
||||
{
|
||||
|
@ -12,6 +12,7 @@
|
||||
#define TEST_MODULE_NAME "business-test"
|
||||
#define TEST_MODULE_DESC "Test Business"
|
||||
|
||||
#if 0
|
||||
static GList * get_list (GNCBook *, gboolean show_all);
|
||||
static const char * printable (gpointer obj);
|
||||
static void test_printable (const char *name, gpointer obj);
|
||||
@ -102,10 +103,11 @@ main_helper (int argc, char **argv)
|
||||
print_test_results();
|
||||
exit(get_rv());
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gh_enter (argc, argv, main_helper);
|
||||
// gh_enter (argc, argv, main_helper);
|
||||
return 0;
|
||||
}
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include "guid.h"
|
||||
#include "gnc-module.h"
|
||||
#include "gnc-engine-util.h"
|
||||
#include "gncObject.h"
|
||||
|
||||
#include "gncBusiness.h"
|
||||
#include "gncCustomer.h"
|
||||
#include "gncCustomerP.h"
|
||||
#include "test-stuff.h"
|
||||
@ -39,7 +39,6 @@ test_customer (void)
|
||||
GncCustomer *customer;
|
||||
|
||||
book = gnc_book_new ();
|
||||
gncBusinessCreateBook (book);
|
||||
|
||||
/* Test creation/destruction */
|
||||
{
|
||||
@ -77,6 +76,7 @@ test_customer (void)
|
||||
gncCustomerSetGUID (customer, &guid);
|
||||
do_test (guid_equal (&guid, gncCustomerGetGUID (customer)), "guid compare");
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
GList *list;
|
||||
|
||||
@ -90,12 +90,13 @@ test_customer (void)
|
||||
do_test (g_list_length (list) == 1, "correct length: active");
|
||||
g_list_free (list);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
const char *str = get_random_string();
|
||||
const char *res;
|
||||
|
||||
gncCustomerSetName (customer, str);
|
||||
res = gncBusinessPrintable (GNC_CUSTOMER_MODULE_NAME, customer);
|
||||
res = gncObjectPrintable (GNC_CUSTOMER_MODULE_NAME, customer);
|
||||
do_test (res != NULL, "Printable NULL?");
|
||||
do_test (safe_strcmp (str, res) == 0, "Printable equals");
|
||||
}
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include "guid.h"
|
||||
#include "gnc-module.h"
|
||||
#include "gnc-engine-util.h"
|
||||
#include "gncObject.h"
|
||||
|
||||
#include "gncBusiness.h"
|
||||
#include "gncEmployee.h"
|
||||
#include "gncEmployeeP.h"
|
||||
#include "test-stuff.h"
|
||||
@ -41,7 +41,6 @@ test_employee (void)
|
||||
GncEmployee *employee;
|
||||
|
||||
book = gnc_book_new ();
|
||||
gncBusinessCreateBook (book);
|
||||
|
||||
/* Test creation/destruction */
|
||||
{
|
||||
@ -76,6 +75,7 @@ test_employee (void)
|
||||
gncEmployeeSetGUID (employee, &guid);
|
||||
do_test (guid_equal (&guid, gncEmployeeGetGUID (employee)), "guid compare");
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
GList *list;
|
||||
|
||||
@ -89,12 +89,13 @@ test_employee (void)
|
||||
do_test (g_list_length (list) == 1, "correct length: active");
|
||||
g_list_free (list);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
const char *str = get_random_string();
|
||||
const char *res;
|
||||
|
||||
gncEmployeeSetUsername (employee, str);
|
||||
res = gncBusinessPrintable (GNC_EMPLOYEE_MODULE_NAME, employee);
|
||||
res = gncObjectPrintable (GNC_EMPLOYEE_MODULE_NAME, employee);
|
||||
do_test (res != NULL, "Printable NULL?");
|
||||
do_test (safe_strcmp (str, res) == 0, "Printable equals");
|
||||
}
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include "guid.h"
|
||||
#include "gnc-module.h"
|
||||
#include "gnc-engine-util.h"
|
||||
#include "gncObject.h"
|
||||
|
||||
#include "gncBusiness.h"
|
||||
#include "gncJob.h"
|
||||
#include "gncJobP.h"
|
||||
#include "test-stuff.h"
|
||||
@ -43,7 +43,6 @@ test_job (void)
|
||||
GncJob *job;
|
||||
|
||||
book = gnc_book_new ();
|
||||
gncBusinessCreateBook (book);
|
||||
|
||||
/* Test creation/destruction */
|
||||
{
|
||||
@ -92,7 +91,7 @@ test_job (void)
|
||||
const char *res;
|
||||
|
||||
gncJobSetName (job, str);
|
||||
res = gncBusinessPrintable (GNC_JOB_MODULE_NAME, job);
|
||||
res = gncObjectPrintable (GNC_JOB_MODULE_NAME, job);
|
||||
do_test (res != NULL, "Printable NULL?");
|
||||
do_test (safe_strcmp (str, res) == 0, "Printable equals");
|
||||
}
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include "guid.h"
|
||||
#include "gnc-module.h"
|
||||
#include "gnc-engine-util.h"
|
||||
#include "gncObject.h"
|
||||
|
||||
#include "gncBusiness.h"
|
||||
#include "gncVendor.h"
|
||||
#include "gncVendorP.h"
|
||||
#include "test-stuff.h"
|
||||
@ -41,7 +41,6 @@ test_vendor (void)
|
||||
GncVendor *vendor;
|
||||
|
||||
book = gnc_book_new ();
|
||||
gncBusinessCreateBook (book);
|
||||
|
||||
/* Test creation/destruction */
|
||||
{
|
||||
@ -75,6 +74,7 @@ test_vendor (void)
|
||||
gncVendorSetGUID (vendor, &guid);
|
||||
do_test (guid_equal (&guid, gncVendorGetGUID (vendor)), "guid compare");
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
GList *list;
|
||||
|
||||
@ -88,12 +88,13 @@ test_vendor (void)
|
||||
do_test (g_list_length (list) == 1, "correct length: active");
|
||||
g_list_free (list);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
const char *str = get_random_string();
|
||||
const char *res;
|
||||
|
||||
gncVendorSetName (vendor, str);
|
||||
res = gncBusinessPrintable (GNC_VENDOR_MODULE_NAME, vendor);
|
||||
res = gncObjectPrintable (GNC_VENDOR_MODULE_NAME, vendor);
|
||||
do_test (res != NULL, "Printable NULL?");
|
||||
do_test (safe_strcmp (str, res) == 0, "Printable equals");
|
||||
}
|
||||
|
@ -12,8 +12,9 @@
|
||||
#include "dialog-utils.h"
|
||||
#include "gnc-ui.h"
|
||||
#include "gnc-gui-query.h"
|
||||
#include "gncObject.h"
|
||||
#include "QueryNew.h"
|
||||
|
||||
#include "gncBusiness.h"
|
||||
#include "business-chooser.h"
|
||||
|
||||
struct business_chooser_window {
|
||||
@ -22,8 +23,8 @@ struct business_chooser_window {
|
||||
GtkWidget * choice_entry;
|
||||
GtkWidget * showall_check;
|
||||
|
||||
GNCBook * book;
|
||||
const GncBusinessObject * obj_type;
|
||||
GNCIdTypeConst obj_type;
|
||||
QueryNew * query;
|
||||
gnc_business_chooser_new_cb new_cb;
|
||||
gnc_business_chooser_edit_cb edit_cb;
|
||||
gpointer cb_arg;
|
||||
@ -57,11 +58,12 @@ update_selection_picker (struct business_chooser_window *w)
|
||||
selected = w->selected;
|
||||
|
||||
/* Get the list of objects */
|
||||
obj_list = (*(w->obj_type->get_list))(w->book, show_all);
|
||||
/* XXX: use show_all in the query */
|
||||
obj_list = gncQueryRun (w->query, w->obj_type);
|
||||
|
||||
/* Build a list of strings (objs is pre-sorted, so keep the order!) */
|
||||
for (iterator = obj_list; iterator; iterator = iterator->next) {
|
||||
const gchar *label = (*(w->obj_type->printable))(iterator->data);
|
||||
const gchar *label = gncObjectPrintable (w->obj_type, iterator->data);
|
||||
|
||||
li = gtk_list_item_new_with_label (label);
|
||||
gtk_object_set_data (GTK_OBJECT (li), "list-item-pointer", iterator->data);
|
||||
@ -81,9 +83,7 @@ update_selection_picker (struct business_chooser_window *w)
|
||||
/* And set the current-selected item */
|
||||
gtk_entry_set_text (GTK_ENTRY (w->choice_entry),
|
||||
((w->selected) ?
|
||||
(*(w->obj_type->printable))(w->selected) : ""));
|
||||
|
||||
g_list_free (obj_list);
|
||||
gncObjectPrintable (w->obj_type, w->selected) : ""));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -190,7 +190,7 @@ gnc_ui_business_chooser_new (GtkWidget * parent,
|
||||
/* Set the label */
|
||||
choice_name_label = glade_xml_get_widget (xml, "choice_name_label");
|
||||
gtk_label_set_text (GTK_LABEL (choice_name_label),
|
||||
gncBusinessGetTypeLabel (type_name));
|
||||
gncObjectGetTypeLabel (type_name));
|
||||
|
||||
if(parent) {
|
||||
gnome_dialog_set_parent(GNOME_DIALOG(win->dialog), GTK_WINDOW(parent));
|
||||
@ -225,11 +225,13 @@ gnc_ui_business_chooser_new (GtkWidget * parent,
|
||||
GTK_SIGNAL_FUNC(business_chooser_close), win);
|
||||
|
||||
/* Save the callbacks */
|
||||
win->book = book;
|
||||
win->obj_type = gncBusinessLookup (type_name);
|
||||
win->obj_type = type_name;
|
||||
win->new_cb = new_cb;
|
||||
win->edit_cb = edit_cb;
|
||||
win->cb_arg = cbarg;
|
||||
win->query = gncQueryCreate ();
|
||||
|
||||
gncQuerySetBook (win->query, book);
|
||||
|
||||
/* Setup the menu */
|
||||
win->selected = orig_sel;
|
||||
@ -242,6 +244,7 @@ gnc_ui_business_chooser_new (GtkWidget * parent,
|
||||
|
||||
/* And exit */
|
||||
retval = win->selected;
|
||||
gncQueryDestroy (win->query);
|
||||
g_free(win);
|
||||
|
||||
return retval;
|
||||
|
@ -7,16 +7,6 @@
|
||||
|
||||
(define (add-business-extensions)
|
||||
|
||||
(define gnc:extensions-temp-book #f)
|
||||
|
||||
(define (gnc:extensions-get-book)
|
||||
(if gnc:extensions-temp-book
|
||||
gnc:extensions-temp-book
|
||||
(begin
|
||||
(set! gnc:extensions-temp-book (gnc:get-current-book))
|
||||
(gnc:business-create-book gnc:extensions-temp-book)
|
||||
gnc:extensions-temp-book)))
|
||||
|
||||
(define gnc:extensions-last-order #f)
|
||||
(define gnc:extensions-last-invoice #f)
|
||||
(define gnc:extensions-owner #f)
|
||||
@ -26,14 +16,14 @@
|
||||
(N_ "Test New Job Dialog")
|
||||
(list "Extensions" "")
|
||||
(lambda ()
|
||||
(gnc:job-new #f (gnc:extensions-get-book) #f))))
|
||||
(gnc:job-new #f (gnc:get-current-book) #f))))
|
||||
|
||||
(define select-job-item
|
||||
(gnc:make-menu-item (N_ "Test Job Selection Dialog")
|
||||
(N_ "Test Job Selection Dialog")
|
||||
(list "Extensions" "")
|
||||
(lambda ()
|
||||
(gnc:job-select #f (gnc:extensions-get-book)
|
||||
(gnc:job-select #f (gnc:get-current-book)
|
||||
#f #f))))
|
||||
|
||||
(define new-vendor-item
|
||||
@ -41,7 +31,7 @@
|
||||
(N_ "Test New Vendor Dialog")
|
||||
(list "Extensions" "")
|
||||
(lambda ()
|
||||
(gnc:vendor-new #f (gnc:extensions-get-book)))))
|
||||
(gnc:vendor-new #f (gnc:get-current-book)))))
|
||||
|
||||
|
||||
(define select-vendor-item
|
||||
@ -49,7 +39,7 @@
|
||||
(N_ "Test Vendor Selection Dialog")
|
||||
(list "Extensions" "")
|
||||
(lambda ()
|
||||
(gnc:vendor-select (gnc:extensions-get-book)
|
||||
(gnc:vendor-select (gnc:get-current-book)
|
||||
#f #f))))
|
||||
|
||||
(define new-employee-item
|
||||
@ -57,7 +47,7 @@
|
||||
(N_ "Test New Employee Dialog")
|
||||
(list "Extensions" "")
|
||||
(lambda ()
|
||||
(gnc:employee-new #f (gnc:extensions-get-book)))))
|
||||
(gnc:employee-new #f (gnc:get-current-book)))))
|
||||
|
||||
|
||||
(define select-employee-item
|
||||
@ -65,7 +55,7 @@
|
||||
(N_ "Test Employee Selection Dialog")
|
||||
(list "Extensions" "")
|
||||
(lambda ()
|
||||
(gnc:employee-select (gnc:extensions-get-book)
|
||||
(gnc:employee-select (gnc:get-current-book)
|
||||
#f #f))))
|
||||
|
||||
(define new-order-item
|
||||
@ -75,7 +65,7 @@
|
||||
(lambda ()
|
||||
(set! gnc:extensions-last-order
|
||||
(gnc:order-new #f gnc:extensions-owner
|
||||
(gnc:extensions-get-book))))))
|
||||
(gnc:get-current-book))))))
|
||||
|
||||
(define edit-order-item
|
||||
(gnc:make-menu-item (N_ "Test Edit/View Order Dialog")
|
||||
@ -91,7 +81,7 @@
|
||||
(lambda ()
|
||||
(set! gnc:extensions-last-invoice
|
||||
(gnc:invoice-new #f gnc:extensions-owner
|
||||
(gnc:extensions-get-book))))))
|
||||
(gnc:get-current-book))))))
|
||||
|
||||
(define edit-invoice-item
|
||||
(gnc:make-menu-item (N_ "Test Edit/View Invoice Dialog")
|
||||
|
@ -9,12 +9,12 @@
|
||||
|
||||
#include <gnome.h>
|
||||
|
||||
#include "gncBusiness.h"
|
||||
#include "gncCustomer.h"
|
||||
#include "gncJob.h"
|
||||
#include "gncVendor.h"
|
||||
#include "gncOwner.h"
|
||||
|
||||
#include "gncObject.h"
|
||||
#include "business-utils.h"
|
||||
#include "dialog-customer.h"
|
||||
#include "dialog-job.h"
|
||||
@ -26,7 +26,7 @@ static GtkWidget * gnc_owner_new (GtkWidget *label, GtkWidget *hbox,
|
||||
{
|
||||
GtkWidget *edit;
|
||||
GNCGeneralSelectNewSelectCB do_select = NULL;
|
||||
const GncBusinessObject *bus_obj;
|
||||
const GncObject_t *bus_obj;
|
||||
const char *type_name = NULL;
|
||||
|
||||
switch (owner->type) {
|
||||
@ -63,7 +63,7 @@ static GtkWidget * gnc_owner_new (GtkWidget *label, GtkWidget *hbox,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bus_obj = gncBusinessLookup (type_name);
|
||||
bus_obj = gncObjectLookup (type_name);
|
||||
if (!bus_obj) {
|
||||
g_warning ("Cannot find business object for name and printable()\n");
|
||||
return NULL;
|
||||
@ -76,7 +76,7 @@ static GtkWidget * gnc_owner_new (GtkWidget *label, GtkWidget *hbox,
|
||||
gnc_general_select_set_selected (GNC_GENERAL_SELECT (edit),
|
||||
owner->owner.undefined);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), edit, TRUE, TRUE, 0);
|
||||
gtk_label_set_text (GTK_LABEL (label), gncBusinessGetTypeLabel (type_name));
|
||||
gtk_label_set_text (GTK_LABEL (label), gncObjectGetTypeLabel (type_name));
|
||||
|
||||
return edit;
|
||||
}
|
||||
|
@ -12,8 +12,9 @@
|
||||
#include "dialog-utils.h"
|
||||
#include "gnc-ui.h"
|
||||
#include "gnc-gui-query.h"
|
||||
#include "gncObject.h"
|
||||
#include "QueryNew.h"
|
||||
|
||||
#include "gncBusiness.h"
|
||||
#include "gncJob.h"
|
||||
#include "dialog-job-select.h"
|
||||
#include "dialog-job.h"
|
||||
@ -31,7 +32,8 @@ struct select_job_window {
|
||||
GncJob * job;
|
||||
GncOwner owner;
|
||||
|
||||
const GncBusinessObject *job_type, *owner_type;
|
||||
QueryNew * query;
|
||||
GNCIdTypeConst owner_type;
|
||||
};
|
||||
|
||||
|
||||
@ -68,7 +70,8 @@ update_job_select_picker (struct select_job_window *w)
|
||||
|
||||
/* Build a list of strings (objs is pre-sorted, so keep the order!) */
|
||||
for (iterator = objs; iterator; iterator = iterator->next) {
|
||||
const gchar *label = (*(w->job_type->printable))(iterator->data);
|
||||
const gchar *label = gncObjectPrintable (GNC_JOB_MODULE_NAME,
|
||||
iterator->data);
|
||||
|
||||
li = gtk_list_item_new_with_label (label);
|
||||
gtk_object_set_data (GTK_OBJECT (li), "item-list-pointer", iterator->data);
|
||||
@ -93,7 +96,7 @@ update_job_select_picker (struct select_job_window *w)
|
||||
{
|
||||
const char * label;
|
||||
if (w->job)
|
||||
label = (*(w->job_type->printable))(w->job);
|
||||
label = gncObjectPrintable (GNC_JOB_MODULE_NAME, w->job);
|
||||
else
|
||||
label = "";
|
||||
|
||||
@ -119,11 +122,12 @@ update_customer_select_picker (struct select_job_window *w)
|
||||
gncOwnerCopy (&(w->owner), &saved_owner);
|
||||
|
||||
/* Get the list of objects */
|
||||
custs = (*(w->owner_type->get_list))(w->book, show_all);
|
||||
/* XXX: use show_all in the query */
|
||||
custs = gncQueryRun (w->query, w->owner_type);
|
||||
|
||||
/* Build a list of strings (objs is pre-sorted, so keep the order!) */
|
||||
for (iterator = custs; iterator; iterator = iterator->next) {
|
||||
const gchar *label = (*(w->owner_type->printable))(iterator->data);
|
||||
const gchar *label = gncObjectPrintable (w->owner_type, iterator->data);
|
||||
|
||||
li = gtk_list_item_new_with_label (label);
|
||||
gtk_object_set_data (GTK_OBJECT (li), "item-list-pointer", iterator->data);
|
||||
@ -152,14 +156,12 @@ update_customer_select_picker (struct select_job_window *w)
|
||||
const char * label;
|
||||
|
||||
if (w->owner.owner.undefined)
|
||||
label = (*(w->owner_type->printable))(w->owner.owner.undefined);
|
||||
label = gncObjectPrintable (w->owner_type, w->owner.owner.undefined);
|
||||
else
|
||||
label = "";
|
||||
|
||||
gtk_entry_set_text (GTK_ENTRY (w->customer_entry), label);
|
||||
}
|
||||
|
||||
g_list_free (custs);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -297,15 +299,16 @@ gnc_ui_select_job_new (GtkWidget * parent, GNCBook *book,
|
||||
g_warning ("Cannot handle this owner type");
|
||||
return NULL;
|
||||
}
|
||||
win->owner_type = gncBusinessLookup (type_name);
|
||||
win->job_type = gncBusinessLookup (GNC_JOB_MODULE_NAME);
|
||||
win->owner_type = type_name;
|
||||
win->query = gncQueryCreate ();
|
||||
gncQuerySetBook (win->query, book);
|
||||
|
||||
xml = gnc_glade_xml_new ("job.glade",
|
||||
"Job Selector Dialog");
|
||||
|
||||
owner_label = glade_xml_get_widget (xml, "owner_label");
|
||||
gtk_label_set_text (GTK_LABEL (owner_label),
|
||||
gncBusinessGetTypeLabel (type_name));
|
||||
gncObjectGetTypeLabel (type_name));
|
||||
|
||||
/* Grab the widgets */
|
||||
|
||||
@ -369,6 +372,7 @@ gnc_ui_select_job_new (GtkWidget * parent, GNCBook *book,
|
||||
|
||||
/* exit */
|
||||
retval = win->job;
|
||||
gncQueryDestroy (win->query);
|
||||
g_free(win);
|
||||
|
||||
return retval;
|
||||
|
@ -241,6 +241,7 @@ void gnc_entry_ledger_destroy (GncEntryLedger *ledger)
|
||||
gnc_entry_ledger_clear_blank_entry (ledger);
|
||||
gnc_entry_ledger_display_fini (ledger);
|
||||
gnc_table_destroy (ledger->table);
|
||||
gncQueryDestroy (ledger->query);
|
||||
g_free (ledger);
|
||||
}
|
||||
|
||||
@ -255,14 +256,46 @@ void gnc_entry_ledger_set_default_order (GncEntryLedger *ledger,
|
||||
{
|
||||
if (!ledger) return;
|
||||
ledger->order = order;
|
||||
|
||||
if (!ledger->query && order) {
|
||||
ledger->query = gncQueryCreate ();
|
||||
gncQuerySetBook (ledger->query, gncOrderGetBook (order));
|
||||
gncQueryAddGUIDMatch (ledger->query, QUERY_AND,
|
||||
GNC_ORDER_MODULE_NAME, ORDER_GUID,
|
||||
gncOrderGetGUID (order));
|
||||
}
|
||||
gnc_entry_ledger_display_refresh (ledger);
|
||||
}
|
||||
|
||||
void gnc_entry_ledger_set_default_invoice (GncEntryLedger *ledger,
|
||||
GncInvoice *invoice)
|
||||
GncInvoice *invoice)
|
||||
{
|
||||
if (!ledger) return;
|
||||
ledger->invoice = invoice;
|
||||
|
||||
if (!ledger->query && invoice) {
|
||||
ledger->query = gncQueryCreate ();
|
||||
gncQuerySetBook (ledger->query, gncInvoiceGetBook (invoice));
|
||||
|
||||
/* Match:
|
||||
* Entry's Invoice == this invoice ||
|
||||
* ( Entry's Invoice == NULL &&
|
||||
* Entry's Order's real-parent == Invoice's parent )
|
||||
*
|
||||
* Note that the "second" term is only for Editable invoices, and
|
||||
* only when we've already got an 'owner'.
|
||||
*/
|
||||
gncQueryAddGUIDMatch (ledger->query, QUERY_AND,
|
||||
GNC_INVOICE_MODULE_NAME, INVOICE_GUID,
|
||||
gncInvoiceGetGUID (invoice));
|
||||
|
||||
/* Note that this is a bogus search -- it will find all entries that
|
||||
* exist (including "blank" entries)
|
||||
*/
|
||||
gncQueryAddGUIDMatch (ledger->query, QUERY_OR,
|
||||
GNC_INVOICE_MODULE_NAME, INVOICE_GUID, NULL);
|
||||
|
||||
}
|
||||
gnc_entry_ledger_display_refresh (ledger);
|
||||
}
|
||||
|
||||
|
@ -23,13 +23,10 @@
|
||||
static GList *
|
||||
gnc_entry_ledger_get_entries (GncEntryLedger *ledger)
|
||||
{
|
||||
if (ledger->order)
|
||||
return (gncOrderGetEntries (ledger->order));
|
||||
if (ledger->query)
|
||||
return gncQueryRun (ledger->query, GNC_ENTRY_MODULE_NAME);
|
||||
|
||||
if (ledger->invoice)
|
||||
return (gncInvoiceGetEntries (ledger->invoice));
|
||||
|
||||
// g_warning ("no invoice; no order. Who am I?");
|
||||
// g_warning ("No query to run?");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "guid.h"
|
||||
#include "gnc-book.h"
|
||||
#include "table-allgui.h"
|
||||
#include "QueryNew.h"
|
||||
#include "gncEntryLedger.h"
|
||||
|
||||
struct GncEntryLedger_s {
|
||||
@ -28,6 +29,8 @@ struct GncEntryLedger_s {
|
||||
Table * table;
|
||||
GncOrder * order;
|
||||
GncInvoice * invoice;
|
||||
QueryNew * query;
|
||||
|
||||
GncEntryLedgerType type;
|
||||
};
|
||||
|
||||
|
@ -13,6 +13,9 @@ libgncmod_engine_la_SOURCES = \
|
||||
Group.c \
|
||||
Period.c \
|
||||
Query.c \
|
||||
QueryNew.c \
|
||||
QueryCore.c \
|
||||
QueryObject.c \
|
||||
SchedXaction.c \
|
||||
SX-ttinfo.c \
|
||||
Scrub.c \
|
||||
@ -30,6 +33,7 @@ libgncmod_engine_la_SOURCES = \
|
||||
gnc-session.c \
|
||||
gncmod-engine.c \
|
||||
guid.c \
|
||||
gncObject.c \
|
||||
kvp_frame.c \
|
||||
kvp-util.c \
|
||||
md5.c \
|
||||
@ -47,6 +51,9 @@ gncinclude_HEADERS = \
|
||||
SchedXaction.h \
|
||||
SX-ttinfo.h \
|
||||
Query.h \
|
||||
QueryNew.h \
|
||||
QueryObject.h \
|
||||
QueryCore.h \
|
||||
Scrub.h \
|
||||
TransLog.h \
|
||||
Transaction.h \
|
||||
@ -63,6 +70,7 @@ gncinclude_HEADERS = \
|
||||
gnc-pricedb.h \
|
||||
gnc-session.h \
|
||||
guid.h \
|
||||
gncObject.h \
|
||||
kvp_frame.h \
|
||||
kvp-scm.h \
|
||||
messages.h
|
||||
@ -74,6 +82,9 @@ noinst_HEADERS = \
|
||||
GNCIdP.h \
|
||||
GroupP.h \
|
||||
QueryP.h \
|
||||
QueryNewP.h \
|
||||
QueryObjectP.h \
|
||||
QueryCoreP.h \
|
||||
SchedXactionP.h \
|
||||
SX-ttinfo.h \
|
||||
TransactionP.h \
|
||||
@ -81,6 +92,7 @@ noinst_HEADERS = \
|
||||
gnc-event-p.h \
|
||||
gnc-pricedb-p.h \
|
||||
gnc-session-p.h \
|
||||
gncObjectP.h \
|
||||
kvp-util-p.h \
|
||||
md5.h
|
||||
|
||||
|
917
src/engine/QueryCore.c
Normal file
917
src/engine/QueryCore.c
Normal file
@ -0,0 +1,917 @@
|
||||
/*
|
||||
* QueryCore.c -- provide core Query data types
|
||||
* Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <regex.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gnc-engine-util.h"
|
||||
#include "QueryCoreP.h"
|
||||
#include "QueryNew.h"
|
||||
|
||||
static short module = MOD_QUERY;
|
||||
|
||||
/* Core Type Predicate definitions */
|
||||
typedef struct {
|
||||
QueryPredDataDef pd;
|
||||
string_match_t options;
|
||||
gboolean is_regex;
|
||||
char * matchstring;
|
||||
regex_t compiled;
|
||||
} query_string_def, *query_string_t;
|
||||
typedef const char * (*query_string_getter) (gpointer);
|
||||
static const char * query_string_type = QUERYCORE_STRING;
|
||||
|
||||
typedef struct {
|
||||
QueryPredDataDef pd;
|
||||
date_match_t options;
|
||||
Timespec date;
|
||||
} query_date_def, *query_date_t;
|
||||
typedef Timespec (*query_date_getter) (gpointer);
|
||||
static const char * query_date_type = QUERYCORE_DATE;
|
||||
|
||||
typedef struct {
|
||||
QueryPredDataDef pd;
|
||||
numeric_match_t options;
|
||||
gnc_numeric amount;
|
||||
} query_numeric_def, *query_numeric_t;
|
||||
typedef gnc_numeric (*query_numeric_getter) (gpointer);
|
||||
static const char * query_numeric_type = QUERYCORE_NUMERIC;
|
||||
|
||||
typedef struct {
|
||||
QueryPredDataDef pd;
|
||||
guid_match_t options;
|
||||
GList * guids;
|
||||
} query_guid_def, *query_guid_t;
|
||||
typedef const GUID * (*query_guid_getter) (gpointer);
|
||||
static const char * query_guid_type = QUERYCORE_GUID;
|
||||
|
||||
typedef struct {
|
||||
QueryPredDataDef pd;
|
||||
gint64 val;
|
||||
} query_int64_def, *query_int64_t;
|
||||
typedef gint64 (*query_int64_getter) (gpointer);
|
||||
static const char * query_int64_type = QUERYCORE_INT64;
|
||||
|
||||
typedef struct {
|
||||
QueryPredDataDef pd;
|
||||
double val;
|
||||
} query_double_def, *query_double_t;
|
||||
typedef double (*query_double_getter) (gpointer);
|
||||
static const char * query_double_type = QUERYCORE_DOUBLE;
|
||||
|
||||
typedef struct {
|
||||
QueryPredDataDef pd;
|
||||
gboolean val;
|
||||
} query_boolean_def, *query_boolean_t;
|
||||
typedef gboolean (*query_boolean_getter) (gpointer);
|
||||
static const char * query_boolean_type = QUERYCORE_BOOLEAN;
|
||||
|
||||
typedef struct {
|
||||
QueryPredDataDef pd;
|
||||
char_match_t options;
|
||||
char * char_list;
|
||||
} query_char_def, *query_char_t;
|
||||
typedef char (*query_char_getter) (gpointer);
|
||||
static const char * query_char_type = QUERYCORE_CHAR;
|
||||
|
||||
typedef struct {
|
||||
QueryPredDataDef pd;
|
||||
GSList * path;
|
||||
kvp_value * value;
|
||||
} query_kvp_def, *query_kvp_t;
|
||||
typedef kvp_frame * (*query_kvp_getter) (gpointer);
|
||||
static const char * query_kvp_type = QUERYCORE_KVP;
|
||||
|
||||
static gboolean initialized = FALSE;
|
||||
static GHashTable *predTable = NULL;
|
||||
static GHashTable *cmpTable = NULL;
|
||||
static GHashTable *copyTable = NULL;
|
||||
static GHashTable *freeTable = NULL;
|
||||
|
||||
#define COMPARE_ERROR -3
|
||||
#define PREDICATE_ERROR -2
|
||||
#define VERIFY_PDATA(str) { \
|
||||
g_return_if_fail (pd != NULL); \
|
||||
g_return_if_fail (pd->type_name == str || \
|
||||
!safe_strcmp (str, pd->type_name)); \
|
||||
}
|
||||
#define VERIFY_PDATA_R(str) { \
|
||||
g_return_val_if_fail (pd != NULL, NULL); \
|
||||
g_return_val_if_fail (pd->type_name == str || \
|
||||
!safe_strcmp (str, pd->type_name), \
|
||||
NULL); \
|
||||
}
|
||||
#define VERIFY_PREDICATE(str) { \
|
||||
g_return_val_if_fail (get_fcn != NULL, PREDICATE_ERROR); \
|
||||
g_return_val_if_fail (pd != NULL, PREDICATE_ERROR); \
|
||||
g_return_val_if_fail (pd->type_name == str || \
|
||||
!safe_strcmp (str, pd->type_name), \
|
||||
PREDICATE_ERROR); \
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
/* TYPE-HANDLING FUNCTIONS */
|
||||
|
||||
/* QUERYCORE_STRING */
|
||||
|
||||
static int string_match_predicate (gpointer object, QueryAccess get_fcn,
|
||||
query_compare_t how, QueryPredData_t pd)
|
||||
{
|
||||
query_string_t pdata = (query_string_t) pd;
|
||||
const char *s;
|
||||
|
||||
VERIFY_PREDICATE (query_string_type);
|
||||
|
||||
s = ((query_string_getter)get_fcn) (object);
|
||||
|
||||
if (pdata->is_regex) {
|
||||
regmatch_t match;
|
||||
if (!regexec (&pdata->compiled, s, 1, &match, 0))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pdata->options == STRING_MATCH_CASEINSENSITIVE) {
|
||||
if (strcasestr (s, pdata->matchstring)) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strstr (s, pdata->matchstring)) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int string_compare_func (gpointer a, gpointer b, gint options,
|
||||
QueryAccess get_fcn)
|
||||
{
|
||||
const char *s1, *s2;
|
||||
g_return_val_if_fail (a && b && get_fcn, COMPARE_ERROR);
|
||||
|
||||
s1 = ((query_string_getter)get_fcn) (a);
|
||||
s2 = ((query_string_getter)get_fcn) (b);
|
||||
|
||||
if (options == STRING_MATCH_CASEINSENSITIVE)
|
||||
return safe_strcasecmp (s1, s2);
|
||||
|
||||
return safe_strcmp (s1, s2);
|
||||
}
|
||||
|
||||
static void string_free_pdata (QueryPredData_t pd)
|
||||
{
|
||||
query_string_t pdata = (query_string_t) pd;
|
||||
|
||||
VERIFY_PDATA (query_string_type);
|
||||
|
||||
if (pdata->is_regex)
|
||||
regfree (&pdata->compiled);
|
||||
else
|
||||
g_free (pdata->matchstring);
|
||||
|
||||
g_free (pdata);
|
||||
}
|
||||
|
||||
static QueryPredData_t string_copy_predicate (QueryPredData_t pd)
|
||||
{
|
||||
query_string_t pdata = (query_string_t) pd;
|
||||
|
||||
VERIFY_PDATA_R (query_string_type);
|
||||
|
||||
return gncQueryStringPredicate (pdata->matchstring, pdata->options,
|
||||
pdata->is_regex);
|
||||
}
|
||||
|
||||
QueryPredData_t gncQueryStringPredicate (char *str, string_match_t options,
|
||||
gboolean is_regex)
|
||||
{
|
||||
query_string_t pdata;
|
||||
|
||||
g_return_val_if_fail (str, NULL);
|
||||
g_return_val_if_fail (*str != '\0', NULL);
|
||||
|
||||
pdata = g_new0 (query_string_def, 1);
|
||||
pdata->pd.type_name = query_string_type;
|
||||
pdata->options = options;
|
||||
pdata->matchstring = g_strdup (str);
|
||||
|
||||
if (is_regex) {
|
||||
int flags = REG_EXTENDED;
|
||||
if (options == STRING_MATCH_CASEINSENSITIVE)
|
||||
flags |= REG_ICASE;
|
||||
|
||||
regcomp(&pdata->compiled, str, flags);
|
||||
pdata->is_regex = TRUE;
|
||||
}
|
||||
|
||||
return ((QueryPredData_t)pdata);
|
||||
}
|
||||
|
||||
/* QUERYCORE_DATE */
|
||||
|
||||
static int date_compare (Timespec ta, Timespec tb, date_match_t options)
|
||||
{
|
||||
if (options == DATE_MATCH_ROUNDED) {
|
||||
ta = timespecCanonicalDayTime (ta);
|
||||
tb = timespecCanonicalDayTime (tb);
|
||||
}
|
||||
|
||||
if (ta.tv_sec < tb.tv_sec)
|
||||
return -1;
|
||||
if (ta.tv_sec > tb.tv_sec)
|
||||
return 1;
|
||||
|
||||
if (ta.tv_nsec < tb.tv_nsec)
|
||||
return -1;
|
||||
if (ta.tv_nsec > tb.tv_nsec)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int date_match_predicate (gpointer object, QueryAccess get_fcn,
|
||||
query_compare_t how, QueryPredData_t pd)
|
||||
{
|
||||
query_date_t pdata = (query_date_t)pd;
|
||||
Timespec objtime;
|
||||
int compare;
|
||||
|
||||
VERIFY_PREDICATE (query_date_type);
|
||||
|
||||
objtime = ((query_date_getter)get_fcn) (object);
|
||||
compare = date_compare (objtime, pdata->date, pdata->options);
|
||||
|
||||
switch (how) {
|
||||
case COMPARE_LT:
|
||||
return (compare < 0);
|
||||
case COMPARE_LTE:
|
||||
return (compare <= 0);
|
||||
case COMPARE_EQUAL:
|
||||
return (compare == 0);
|
||||
case COMPARE_GT:
|
||||
return (compare > 0);
|
||||
case COMPARE_GTE:
|
||||
return (compare >= 0);
|
||||
default:
|
||||
PWARN ("bad match type: %d", how);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int date_compare_func (gpointer a, gpointer b, gint options,
|
||||
QueryAccess get_fcn)
|
||||
{
|
||||
Timespec ta, tb;
|
||||
|
||||
g_return_val_if_fail (a && b && get_fcn, COMPARE_ERROR);
|
||||
|
||||
ta = ((query_date_getter)get_fcn) (a);
|
||||
tb = ((query_date_getter)get_fcn) (b);
|
||||
|
||||
return date_compare (ta, tb, options);
|
||||
}
|
||||
|
||||
static void date_free_pdata (QueryPredData_t pd)
|
||||
{
|
||||
query_date_t pdata = (query_date_t)pd;
|
||||
|
||||
VERIFY_PDATA (query_date_type);
|
||||
|
||||
g_free (pdata);
|
||||
}
|
||||
|
||||
static QueryPredData_t date_copy_predicate (QueryPredData_t pd)
|
||||
{
|
||||
query_date_t pdata = (query_date_t)pd;
|
||||
|
||||
VERIFY_PDATA_R (query_date_type);
|
||||
|
||||
return gncQueryDatePredicate (pdata->options, pdata->date);
|
||||
}
|
||||
|
||||
QueryPredData_t gncQueryDatePredicate (date_match_t options, Timespec date)
|
||||
{
|
||||
query_date_t pdata;
|
||||
|
||||
pdata = g_new0 (query_date_def, 1);
|
||||
pdata->pd.type_name = query_date_type;
|
||||
pdata->options = options;
|
||||
pdata->date = date;
|
||||
return ((QueryPredData_t)pdata);
|
||||
}
|
||||
|
||||
/* QUERYCORE_NUMERIC */
|
||||
|
||||
static int numeric_match_predicate (gpointer object, QueryAccess get_fcn,
|
||||
query_compare_t how, QueryPredData_t pd)
|
||||
{
|
||||
query_numeric_t pdata = (query_numeric_t)pd;
|
||||
gnc_numeric obj_val;
|
||||
int compare;
|
||||
|
||||
VERIFY_PREDICATE (query_numeric_type);
|
||||
|
||||
obj_val = ((query_numeric_getter)get_fcn) (object);
|
||||
|
||||
switch (pdata->options) {
|
||||
case NUMERIC_MATCH_NEG_ONLY:
|
||||
if (!gnc_numeric_negative_p (obj_val)) return 0;
|
||||
break;
|
||||
case NUMERIC_MATCH_POS_ONLY:
|
||||
if (!gnc_numeric_positive_p (obj_val)) return 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (how == COMPARE_EQUAL) {
|
||||
gnc_numeric cmp_val = gnc_numeric_create (1, 10000);
|
||||
compare =
|
||||
(gnc_numeric_compare (gnc_numeric_sub (gnc_numeric_abs (obj_val),
|
||||
gnc_numeric_abs (pdata->amount),
|
||||
100000, GNC_RND_ROUND),
|
||||
cmp_val) < 0);
|
||||
} else
|
||||
compare = gnc_numeric_compare (gnc_numeric_abs (obj_val), pdata->amount);
|
||||
|
||||
switch (how) {
|
||||
case COMPARE_LT:
|
||||
return (compare < 0);
|
||||
case COMPARE_LTE:
|
||||
return (compare <= 0);
|
||||
case COMPARE_EQUAL:
|
||||
return compare;
|
||||
case COMPARE_GT:
|
||||
return (compare > 0);
|
||||
case COMPARE_GTE:
|
||||
return (compare >= 0);
|
||||
default:
|
||||
PWARN ("bad match type: %d", how);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int numeric_compare_func (gpointer a, gpointer b, gint options,
|
||||
QueryAccess get_fcn)
|
||||
{
|
||||
gnc_numeric va, vb;
|
||||
|
||||
g_return_val_if_fail (a && b && get_fcn, COMPARE_ERROR);
|
||||
|
||||
va = ((query_numeric_getter)get_fcn) (a);
|
||||
vb = ((query_numeric_getter)get_fcn) (b);
|
||||
|
||||
return gnc_numeric_compare (va, vb);
|
||||
}
|
||||
|
||||
static void numeric_free_pdata (QueryPredData_t pd)
|
||||
{
|
||||
query_numeric_t pdata = (query_numeric_t)pd;
|
||||
VERIFY_PDATA (query_numeric_type);
|
||||
g_free (pdata);
|
||||
}
|
||||
|
||||
static QueryPredData_t numeric_copy_predicate (QueryPredData_t pd)
|
||||
{
|
||||
query_numeric_t pdata = (query_numeric_t)pd;
|
||||
VERIFY_PDATA_R (query_numeric_type);
|
||||
return gncQueryNumericPredicate (pdata->options, pdata->amount);
|
||||
}
|
||||
|
||||
QueryPredData_t gncQueryNumericPredicate (numeric_match_t options,
|
||||
gnc_numeric value)
|
||||
{
|
||||
query_numeric_t pdata;
|
||||
pdata = g_new0 (query_numeric_def, 1);
|
||||
pdata->pd.type_name = query_numeric_type;
|
||||
pdata->options = options;
|
||||
pdata->amount = value;
|
||||
return ((QueryPredData_t)pdata);
|
||||
}
|
||||
|
||||
/* QUERYCORE_GUID */
|
||||
|
||||
static int guid_match_predicate (gpointer object, QueryAccess get_fcn,
|
||||
query_compare_t how, QueryPredData_t pd)
|
||||
{
|
||||
query_guid_t pdata = (query_guid_t)pd;
|
||||
GList *node;
|
||||
const GUID *guid;
|
||||
|
||||
VERIFY_PREDICATE (query_guid_type);
|
||||
|
||||
/* See if the guid is in the list */
|
||||
guid = ((query_guid_getter)get_fcn) (object);
|
||||
for (node = pdata->guids; node; node = node->next) {
|
||||
if (guid_equal (node->data, guid))
|
||||
break;
|
||||
}
|
||||
|
||||
switch (pdata->options) {
|
||||
case GUID_MATCH_ANY:
|
||||
return (node != NULL);
|
||||
break;
|
||||
case GUID_MATCH_NONE:
|
||||
return (node == NULL);
|
||||
break;
|
||||
case GUID_MATCH_NULL:
|
||||
return (guid == NULL);
|
||||
break;
|
||||
default:
|
||||
PWARN ("bad match type");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void guid_free_pdata (QueryPredData_t pd)
|
||||
{
|
||||
query_guid_t pdata = (query_guid_t)pd;
|
||||
VERIFY_PDATA (query_guid_type);
|
||||
g_list_free (pdata->guids);
|
||||
g_free (pdata);
|
||||
}
|
||||
|
||||
static QueryPredData_t guid_copy_predicate (QueryPredData_t pd)
|
||||
{
|
||||
query_guid_t pdata = (query_guid_t)pd;
|
||||
VERIFY_PDATA_R (query_guid_type);
|
||||
return gncQueryGUIDPredicate (pdata->options, pdata->guids);
|
||||
}
|
||||
|
||||
QueryPredData_t gncQueryGUIDPredicate (guid_match_t options, GList *guids)
|
||||
{
|
||||
query_guid_t pdata;
|
||||
|
||||
pdata = g_new0 (query_guid_def, 1);
|
||||
pdata->pd.type_name = query_guid_type;
|
||||
pdata->options = options;
|
||||
pdata->guids = g_list_copy (guids);
|
||||
return ((QueryPredData_t)pdata);
|
||||
}
|
||||
|
||||
/* QUERYCORE_INT64 */
|
||||
|
||||
static int int64_match_predicate (gpointer object, QueryAccess get_fcn,
|
||||
query_compare_t how, QueryPredData_t pd)
|
||||
{
|
||||
gint64 val;
|
||||
query_int64_t pdata = (query_int64_t)pd;
|
||||
|
||||
VERIFY_PREDICATE (query_int64_type);
|
||||
|
||||
val = ((query_int64_getter)get_fcn) (object);
|
||||
|
||||
switch (how) {
|
||||
case COMPARE_LT:
|
||||
return (val < pdata->val);
|
||||
case COMPARE_LTE:
|
||||
return (val <= pdata->val);
|
||||
case COMPARE_EQUAL:
|
||||
return (val == pdata->val);
|
||||
case COMPARE_GT:
|
||||
return (val > pdata->val);
|
||||
case COMPARE_GTE:
|
||||
return (val >= pdata->val);
|
||||
default:
|
||||
PWARN ("bad match type: %d", how);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int int64_compare_func (gpointer a, gpointer b, gint options,
|
||||
QueryAccess get_fcn)
|
||||
{
|
||||
gint64 v1, v2;
|
||||
g_return_val_if_fail (a && b && get_fcn, COMPARE_ERROR);
|
||||
|
||||
v1 = ((query_int64_getter)get_fcn)(a);
|
||||
v2 = ((query_int64_getter)get_fcn)(b);
|
||||
|
||||
if (v1 < v2) return -1;
|
||||
if (v1 > v2) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void int64_free_pdata (QueryPredData_t pd)
|
||||
{
|
||||
query_int64_t pdata = (query_int64_t)pd;
|
||||
VERIFY_PDATA (query_int64_type);
|
||||
g_free (pdata);
|
||||
}
|
||||
|
||||
static QueryPredData_t int64_copy_predicate (QueryPredData_t pd)
|
||||
{
|
||||
query_int64_t pdata = (query_int64_t)pd;
|
||||
VERIFY_PDATA_R (query_int64_type);
|
||||
return gncQueryInt64Predicate (pdata->val);
|
||||
}
|
||||
|
||||
QueryPredData_t gncQueryInt64Predicate (gint64 val)
|
||||
{
|
||||
query_int64_t pdata = g_new0 (query_int64_def, 1);
|
||||
pdata->pd.type_name = query_int64_type;
|
||||
pdata->val = val;
|
||||
return ((QueryPredData_t)pdata);
|
||||
}
|
||||
|
||||
/* QUERYCORE_DOUBLE */
|
||||
|
||||
static int double_match_predicate (gpointer object, QueryAccess get_fcn,
|
||||
query_compare_t how, QueryPredData_t pd)
|
||||
{
|
||||
double val;
|
||||
query_double_t pdata = (query_double_t)pd;
|
||||
|
||||
VERIFY_PREDICATE (query_double_type);
|
||||
|
||||
val = ((query_double_getter)get_fcn) (object);
|
||||
|
||||
switch (how) {
|
||||
case COMPARE_LT:
|
||||
return (val < pdata->val);
|
||||
case COMPARE_LTE:
|
||||
return (val <= pdata->val);
|
||||
case COMPARE_EQUAL:
|
||||
return (val == pdata->val);
|
||||
case COMPARE_GT:
|
||||
return (val > pdata->val);
|
||||
case COMPARE_GTE:
|
||||
return (val >= pdata->val);
|
||||
default:
|
||||
PWARN ("bad match type: %d", how);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int double_compare_func (gpointer a, gpointer b, gint options,
|
||||
QueryAccess get_fcn)
|
||||
{
|
||||
double v1, v2;
|
||||
g_return_val_if_fail (a && b && get_fcn, COMPARE_ERROR);
|
||||
|
||||
v1 = ((query_double_getter)get_fcn) (a);
|
||||
v2 = ((query_double_getter)get_fcn) (b);
|
||||
|
||||
if (v1 < v2) return -1;
|
||||
if (v1 > v2) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void double_free_pdata (QueryPredData_t pd)
|
||||
{
|
||||
query_double_t pdata = (query_double_t)pd;
|
||||
VERIFY_PDATA (query_double_type);
|
||||
g_free (pdata);
|
||||
}
|
||||
|
||||
static QueryPredData_t double_copy_predicate (QueryPredData_t pd)
|
||||
{
|
||||
query_double_t pdata = (query_double_t)pd;
|
||||
VERIFY_PDATA_R (query_double_type);
|
||||
return gncQueryDoublePredicate (pdata->val);
|
||||
}
|
||||
|
||||
QueryPredData_t gncQueryDoublePredicate (double val)
|
||||
{
|
||||
query_double_t pdata = g_new0 (query_double_def, 1);
|
||||
pdata->pd.type_name = query_double_type;
|
||||
pdata->val = val;
|
||||
return ((QueryPredData_t)pdata);
|
||||
}
|
||||
|
||||
|
||||
/* QUERYCORE_BOOLEAN */
|
||||
|
||||
static int boolean_match_predicate (gpointer object, QueryAccess get_fcn,
|
||||
query_compare_t how, QueryPredData_t pd)
|
||||
{
|
||||
gboolean val;
|
||||
query_boolean_t pdata = (query_boolean_t)pd;
|
||||
|
||||
VERIFY_PREDICATE (query_boolean_type);
|
||||
|
||||
val = ((query_boolean_getter)get_fcn) (object);
|
||||
|
||||
return (val == pdata->val);
|
||||
}
|
||||
|
||||
static int boolean_compare_func (gpointer a, gpointer b, gint options,
|
||||
QueryAccess get_fcn)
|
||||
{
|
||||
gboolean va, vb;
|
||||
g_return_val_if_fail (a && b && get_fcn, COMPARE_ERROR);
|
||||
va = ((query_boolean_getter)get_fcn) (a);
|
||||
vb = ((query_boolean_getter)get_fcn) (b);
|
||||
if (!va && vb) return -1;
|
||||
if (va && !vb) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void boolean_free_pdata (QueryPredData_t pd)
|
||||
{
|
||||
query_boolean_t pdata = (query_boolean_t)pd;
|
||||
VERIFY_PDATA (query_boolean_type);
|
||||
g_free (pdata);
|
||||
}
|
||||
|
||||
static QueryPredData_t boolean_copy_predicate (QueryPredData_t pd)
|
||||
{
|
||||
query_boolean_t pdata = (query_boolean_t)pd;
|
||||
VERIFY_PDATA_R (query_boolean_type);
|
||||
return gncQueryBooleanPredicate (pdata->val);
|
||||
}
|
||||
|
||||
QueryPredData_t gncQueryBooleanPredicate (gboolean val)
|
||||
{
|
||||
query_boolean_t pdata = g_new0 (query_boolean_def, 1);
|
||||
pdata->pd.type_name = query_boolean_type;
|
||||
pdata->val = val;
|
||||
return ((QueryPredData_t)pdata);
|
||||
}
|
||||
|
||||
/* QUERYCORE_CHAR */
|
||||
|
||||
static int char_match_predicate (gpointer object, QueryAccess get_fcn,
|
||||
query_compare_t how, QueryPredData_t pd)
|
||||
{
|
||||
char c;
|
||||
query_char_t pdata = (query_char_t)pd;
|
||||
|
||||
VERIFY_PREDICATE (query_char_type);
|
||||
|
||||
c = ((query_char_getter)get_fcn) (object);
|
||||
|
||||
switch (pdata->options) {
|
||||
case CHAR_MATCH_ANY:
|
||||
if (strchr (pdata->char_list, c)) return 1;
|
||||
return 0;
|
||||
case CHAR_MATCH_NONE:
|
||||
if (!strchr (pdata->char_list, c)) return 1;
|
||||
return 0;
|
||||
default:
|
||||
PWARN ("bad match type");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int char_compare_func (gpointer a, gpointer b, gint options,
|
||||
QueryAccess get_fcn)
|
||||
{
|
||||
char va, vb;
|
||||
g_return_val_if_fail (a && b && get_fcn, COMPARE_ERROR);
|
||||
va = ((query_char_getter)get_fcn)(a);
|
||||
vb = ((query_char_getter)get_fcn)(b);
|
||||
return (va-vb);
|
||||
}
|
||||
|
||||
static void char_free_pdata (QueryPredData_t pd)
|
||||
{
|
||||
query_char_t pdata = (query_char_t)pd;
|
||||
VERIFY_PDATA (query_char_type);
|
||||
g_free (pdata->char_list);
|
||||
g_free (pdata);
|
||||
}
|
||||
|
||||
static QueryPredData_t char_copy_predicate (QueryPredData_t pd)
|
||||
{
|
||||
query_char_t pdata = (query_char_t)pd;
|
||||
VERIFY_PDATA_R (query_char_type);
|
||||
return gncQueryCharPredicate (pdata->options, pdata->char_list);
|
||||
}
|
||||
|
||||
QueryPredData_t gncQueryCharPredicate (char_match_t options, const char *chars)
|
||||
{
|
||||
query_char_t pdata;
|
||||
g_return_val_if_fail (chars, NULL);
|
||||
pdata = g_new0 (query_char_def, 1);
|
||||
pdata->pd.type_name = query_char_type;
|
||||
pdata->options = options;
|
||||
pdata->char_list = g_strdup (chars);
|
||||
return ((QueryPredData_t)pdata);
|
||||
}
|
||||
|
||||
|
||||
/* QUERYCORE_KVP */
|
||||
|
||||
static int kvp_match_predicate (gpointer object, QueryAccess get_fcn,
|
||||
query_compare_t how, QueryPredData_t pd)
|
||||
{
|
||||
int compare;
|
||||
kvp_frame *kvp;
|
||||
kvp_value *value;
|
||||
query_kvp_t pdata = (query_kvp_t)pd;
|
||||
|
||||
VERIFY_PREDICATE (query_kvp_type);
|
||||
|
||||
kvp = ((query_kvp_getter)get_fcn) (object);
|
||||
if (!kvp)
|
||||
return 0;
|
||||
|
||||
value = kvp_frame_get_slot_path_gslist (kvp, pdata->path);
|
||||
if (!value)
|
||||
return 0;
|
||||
|
||||
if (kvp_value_get_type (value) != kvp_value_get_type (pdata->value))
|
||||
return 0;
|
||||
|
||||
compare = kvp_value_compare (value, pdata->value);
|
||||
|
||||
switch (how)
|
||||
{
|
||||
case COMPARE_LT:
|
||||
return (compare < 0);
|
||||
case COMPARE_LTE:
|
||||
return (compare <= 0);
|
||||
case COMPARE_EQUAL:
|
||||
return (compare == 0);
|
||||
case COMPARE_GTE:
|
||||
return (compare >= 0);
|
||||
case COMPARE_GT:
|
||||
return (compare > 0);
|
||||
default:
|
||||
PWARN ("bad match type: %d", how);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void kvp_free_pdata (QueryPredData_t pd)
|
||||
{
|
||||
query_kvp_t pdata = (query_kvp_t)pd;
|
||||
GSList *node;
|
||||
|
||||
VERIFY_PDATA (query_kvp_type);
|
||||
kvp_value_delete (pdata->value);
|
||||
for (node = pdata->path; node; node = node->next) {
|
||||
g_free (node->data);
|
||||
node->data = NULL;
|
||||
}
|
||||
g_slist_free (pdata->path);
|
||||
g_free (pdata);
|
||||
}
|
||||
|
||||
static QueryPredData_t kvp_copy_predicate (QueryPredData_t pd)
|
||||
{
|
||||
query_kvp_t pdata = (query_kvp_t)pd;
|
||||
VERIFY_PDATA_R (query_kvp_type);
|
||||
return gncQueryKVPPredicate (pdata->path, pdata->value);
|
||||
}
|
||||
|
||||
QueryPredData_t gncQueryKVPPredicate (GSList *path, const kvp_value *value)
|
||||
{
|
||||
query_kvp_t pdata;
|
||||
GSList *node;
|
||||
|
||||
g_return_val_if_fail (path && value, NULL);
|
||||
|
||||
pdata = g_new0 (query_kvp_def, 1);
|
||||
pdata->pd.type_name = query_kvp_type;
|
||||
pdata->value = kvp_value_copy (value);
|
||||
pdata->path = g_slist_copy (path);
|
||||
for (node = pdata->path; node; node = node->next)
|
||||
node->data = g_strdup (node->data);
|
||||
|
||||
return ((QueryPredData_t)pdata);
|
||||
}
|
||||
|
||||
/* initialization */
|
||||
|
||||
static void init_tables (void)
|
||||
{
|
||||
int i;
|
||||
struct {
|
||||
char const *name;
|
||||
QueryPredicate pred;
|
||||
QueryCompare comp;
|
||||
QueryPredicateCopy copy;
|
||||
QueryPredDataFree pd_free;
|
||||
} knownTypes[] = {
|
||||
{ QUERYCORE_STRING, string_match_predicate, string_compare_func,
|
||||
string_copy_predicate, string_free_pdata },
|
||||
{ QUERYCORE_DATE, date_match_predicate, date_compare_func,
|
||||
date_copy_predicate, date_free_pdata },
|
||||
{ QUERYCORE_NUMERIC, numeric_match_predicate, numeric_compare_func,
|
||||
numeric_copy_predicate, numeric_free_pdata },
|
||||
{ QUERYCORE_GUID, guid_match_predicate, NULL,
|
||||
guid_copy_predicate, guid_free_pdata },
|
||||
{ QUERYCORE_INT64, int64_match_predicate, int64_compare_func,
|
||||
int64_copy_predicate, int64_free_pdata },
|
||||
{ QUERYCORE_DOUBLE, double_match_predicate, double_compare_func,
|
||||
double_copy_predicate, double_free_pdata },
|
||||
{ QUERYCORE_BOOLEAN, boolean_match_predicate, boolean_compare_func,
|
||||
boolean_copy_predicate, boolean_free_pdata },
|
||||
{ QUERYCORE_CHAR, char_match_predicate, char_compare_func,
|
||||
char_copy_predicate, char_free_pdata },
|
||||
{ QUERYCORE_KVP, kvp_match_predicate, NULL, kvp_copy_predicate,
|
||||
kvp_free_pdata },
|
||||
};
|
||||
|
||||
/* Register the known data types */
|
||||
for (i = 0; i < (sizeof(knownTypes)/sizeof(*knownTypes)); i++) {
|
||||
gncQueryRegisterCoreObject (knownTypes[i].name,
|
||||
knownTypes[i].pred,
|
||||
knownTypes[i].comp,
|
||||
knownTypes[i].copy,
|
||||
knownTypes[i].pd_free);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
/* PUBLISHED API FUNCTIONS */
|
||||
|
||||
void gncQueryRegisterCoreObject (char const *core_name,
|
||||
QueryPredicate pred,
|
||||
QueryCompare comp,
|
||||
QueryPredicateCopy copy,
|
||||
QueryPredDataFree pd_free)
|
||||
{
|
||||
g_return_if_fail (core_name);
|
||||
g_return_if_fail (*core_name != '\0');
|
||||
|
||||
if (pred)
|
||||
g_hash_table_insert (predTable, (char *)core_name, pred);
|
||||
|
||||
if (comp)
|
||||
g_hash_table_insert (cmpTable, (char *)core_name, comp);
|
||||
|
||||
if (copy)
|
||||
g_hash_table_insert (copyTable, (char *)core_name, copy);
|
||||
|
||||
if (pd_free)
|
||||
g_hash_table_insert (freeTable, (char *)core_name, pd_free);
|
||||
}
|
||||
|
||||
void gncQueryCoreInit (void)
|
||||
{
|
||||
/* Only let us initialize once */
|
||||
if (initialized) return;
|
||||
initialized = TRUE;
|
||||
|
||||
/* Create the tables */
|
||||
predTable = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
cmpTable = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
copyTable = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
freeTable = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
init_tables ();
|
||||
}
|
||||
|
||||
void gncQueryCoreShutdown (void)
|
||||
{
|
||||
if (!initialized) return;
|
||||
initialized = FALSE;
|
||||
|
||||
g_hash_table_destroy (predTable);
|
||||
g_hash_table_destroy (cmpTable);
|
||||
g_hash_table_destroy (copyTable);
|
||||
g_hash_table_destroy (freeTable);
|
||||
}
|
||||
|
||||
QueryPredicate gncQueryCoreGetPredicate (char const *type)
|
||||
{
|
||||
g_return_val_if_fail (type, NULL);
|
||||
return g_hash_table_lookup (predTable, type);
|
||||
}
|
||||
|
||||
QueryCompare gncQueryCoreGetCompare (char const *type)
|
||||
{
|
||||
g_return_val_if_fail (type, NULL);
|
||||
return g_hash_table_lookup (cmpTable, type);
|
||||
}
|
||||
|
||||
QueryPredicateCopy gncQueryCoreGetCopy (char const *type)
|
||||
{
|
||||
g_return_val_if_fail (type, NULL);
|
||||
return g_hash_table_lookup (copyTable, type);
|
||||
}
|
||||
|
||||
QueryPredDataFree gncQueryCoreGetPredFree (char const *type)
|
||||
{
|
||||
g_return_val_if_fail (type, NULL);
|
||||
return g_hash_table_lookup (freeTable, type);
|
||||
}
|
||||
|
||||
void gncQueryCorePredicateFree (QueryPredData_t pdata)
|
||||
{
|
||||
QueryPredDataFree free_fcn;
|
||||
|
||||
g_return_if_fail (pdata);
|
||||
g_return_if_fail (pdata->type_name);
|
||||
|
||||
free_fcn = gncQueryCoreGetPredFree (pdata->type_name);
|
||||
free_fcn (pdata);
|
||||
}
|
||||
|
||||
QueryPredData_t gncQueryCorePredicateCopy (QueryPredData_t pdata)
|
||||
{
|
||||
QueryPredicateCopy copy;
|
||||
|
||||
g_return_val_if_fail (pdata, NULL);
|
||||
g_return_val_if_fail (pdata->type_name, NULL);
|
||||
|
||||
copy = gncQueryCoreGetCopy (pdata->type_name);
|
||||
return (copy (pdata));
|
||||
}
|
89
src/engine/QueryCore.h
Normal file
89
src/engine/QueryCore.h
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* QueryCore.h -- API for providing core Query data types
|
||||
* Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GNC_QUERYCORE_H
|
||||
#define GNC_QUERYCORE_H
|
||||
|
||||
#include "QueryObject.h" /* for QueryAccess */
|
||||
#include "QueryNew.h" /* for QueryPredData_t */
|
||||
#include "gnc-numeric.h"
|
||||
#include "date.h"
|
||||
#include "kvp_frame.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
/* Head of Predicate Data structures. All PData must start like this. */
|
||||
typedef struct query_pred_data {
|
||||
const char * type_name;
|
||||
} QueryPredDataDef;
|
||||
|
||||
/*
|
||||
* An arbitrary Query Predicate. Given the gnucash object and the
|
||||
* particular parameter get-function (obtained from the registry by
|
||||
* the Query internals), compare the object's parameter to the
|
||||
* predicate data
|
||||
*/
|
||||
typedef int (*QueryPredicate) (gpointer object,
|
||||
QueryAccess get_fcn,
|
||||
query_compare_t how,
|
||||
QueryPredData_t pdata);
|
||||
|
||||
/* A callback for how to destroy a query predicate's pdata */
|
||||
typedef void (*QueryPredDataFree) (QueryPredData_t pdata);
|
||||
|
||||
/* A callback to copy a query's predicate data */
|
||||
typedef QueryPredData_t (*QueryPredicateCopy) (QueryPredData_t pdata);
|
||||
|
||||
/* A callback for how to compare two (same-type) objects based on a
|
||||
* common get_fcn (parameter member), using the provided comparrison
|
||||
* options (which are the type-specific options).
|
||||
*/
|
||||
typedef int (*QueryCompare) (gpointer a, gpointer b,
|
||||
gint compare_options,
|
||||
QueryAccess get_fcn);
|
||||
|
||||
|
||||
/* This function registers a new Core Object with the QueryNew
|
||||
* subsystem. It maps the "core_name" object to the given
|
||||
* query_predicate and predicate_data_free functions.
|
||||
*/
|
||||
void gncQueryRegisterCoreObject (char const *type_name,
|
||||
QueryPredicate pred,
|
||||
QueryCompare comp,
|
||||
QueryPredicateCopy copy,
|
||||
QueryPredDataFree pd_free);
|
||||
|
||||
|
||||
/* An example:
|
||||
*
|
||||
* gncQueryRegisterCoreObject (QUERYCORE_STRING, string_match_predicate,
|
||||
* string_compare_fcn, string_free_pdata);
|
||||
*/
|
||||
|
||||
|
||||
/* XXX: Define the core data type predicate_data structures here? */
|
||||
|
||||
/* Copy a predicate */
|
||||
QueryPredData_t gncQueryCorePredicateCopy (QueryPredData_t pdata);
|
||||
|
||||
/* Destroy a type */
|
||||
void gncQueryCorePredicateFree (QueryPredData_t pdata);
|
||||
|
||||
/* Core Data Type Predicates */
|
||||
QueryPredData_t gncQueryStringPredicate (char *str, string_match_t options,
|
||||
gboolean is_regex);
|
||||
QueryPredData_t gncQueryDatePredicate (date_match_t options, Timespec date);
|
||||
QueryPredData_t gncQueryNumericPredicate (numeric_match_t options,
|
||||
gnc_numeric value);
|
||||
QueryPredData_t gncQueryGUIDPredicate (guid_match_t options, GList *guids);
|
||||
QueryPredData_t gncQueryInt64Predicate (gint64 val);
|
||||
QueryPredData_t gncQueryDoublePredicate (double val);
|
||||
QueryPredData_t gncQueryBooleanPredicate (gboolean val);
|
||||
QueryPredData_t gncQueryCharPredicate (char_match_t options,
|
||||
const char *chars);
|
||||
QueryPredData_t gncQueryKVPPredicate (GSList *path, const kvp_value *value);
|
||||
|
||||
#endif /* GNC_QUERYCORE_H */
|
22
src/engine/QueryCoreP.h
Normal file
22
src/engine/QueryCoreP.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* QueryCoreP.h -- Internal API for providing core Query data types
|
||||
* Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GNC_QUERYCOREP_H
|
||||
#define GNC_QUERYCOREP_H
|
||||
|
||||
#include "QueryCore.h"
|
||||
|
||||
/* Initalize the Query Core registry and install the default type handlers */
|
||||
void gncQueryCoreInit(void);
|
||||
void gncQueryCoreShutdown (void);
|
||||
|
||||
/* Lookup functions */
|
||||
QueryPredicate gncQueryCoreGetPredicate (char const *type);
|
||||
QueryCompare gncQueryCoreGetCompare (char const *type);
|
||||
QueryPredicateCopy gncQueryCoreGetCopy (char const *type);
|
||||
QueryPredDataFree gncQueryCoreGetPredFree (char const *type);
|
||||
|
||||
#endif /* GNC_QUERYCOREP_H */
|
836
src/engine/QueryNew.c
Normal file
836
src/engine/QueryNew.c
Normal file
@ -0,0 +1,836 @@
|
||||
/*
|
||||
* QueryNew.c -- API for finding Gnucash objects
|
||||
* Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <regex.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gnc-engine-util.h"
|
||||
#include "gnc-book-p.h"
|
||||
#include "gncObject.h"
|
||||
//#include "BackendP.h"
|
||||
|
||||
#include "QueryObjectP.h"
|
||||
#include "QueryCoreP.h"
|
||||
#include "QueryNew.h"
|
||||
#include "QueryNewP.h"
|
||||
|
||||
static short module = MOD_QUERY;
|
||||
|
||||
typedef struct {
|
||||
GNCIdType obj_name;
|
||||
const char * param_name;
|
||||
QueryPredData_t pdata;
|
||||
query_compare_t how;
|
||||
gboolean invert;
|
||||
|
||||
/* These values are filled in during "compilation" of the query
|
||||
* term, based upon the obj_name, param_name, and searched-for
|
||||
* object type. If conv_fcn is NULL, then we don't know how to
|
||||
* convert types.
|
||||
*/
|
||||
QueryConvert conv_fcn;
|
||||
QueryAccess get_fcn;
|
||||
QueryPredicate pred_fcn;
|
||||
} QueryNewTerm;
|
||||
|
||||
typedef struct {
|
||||
GNCIdType obj_name;
|
||||
const char * param_name;
|
||||
gint options;
|
||||
gboolean increasing;
|
||||
gboolean use_default;
|
||||
|
||||
/* These values are filled in during "compilation" of the query
|
||||
* term, based upon the obj_name, param_name, and searched-for
|
||||
* object type. If conv_fcn is NULL, then we don't know how to
|
||||
* convert types.
|
||||
*/
|
||||
QueryConvert conv_fcn;
|
||||
QueryAccess get_fcn;
|
||||
QueryCompare comp_fcn;
|
||||
} QuerySort_t;
|
||||
|
||||
/* The QUERY structure */
|
||||
struct querynew_s {
|
||||
/* terms is a list of the OR-terms in a sum-of-products
|
||||
* logical expression. */
|
||||
GList * terms;
|
||||
|
||||
/* sorting and chopping is independent of the search filter */
|
||||
|
||||
QuerySort_t primary_sort;
|
||||
QuerySort_t secondary_sort;
|
||||
QuerySort_t tertiary_sort;
|
||||
QuerySort defaultSort;
|
||||
|
||||
/* The maximum number of results to return */
|
||||
int max_results;
|
||||
|
||||
/* list of books that will be participating in the query */
|
||||
GList * books;
|
||||
|
||||
/* cache the results so we don't have to run the whole search
|
||||
* again until it's really necessary */
|
||||
int changed;
|
||||
GNCIdType last_run_type;
|
||||
|
||||
GList * results;
|
||||
};
|
||||
|
||||
typedef struct query_cb {
|
||||
QueryNew * query;
|
||||
GList * list;
|
||||
int count;
|
||||
} query_cb_t;
|
||||
|
||||
/* initial_term will be owned by the new Query */
|
||||
static void query_init (QueryNew *q, QueryNewTerm *initial_term)
|
||||
{
|
||||
GList * or = NULL;
|
||||
GList *and = NULL;
|
||||
|
||||
if (initial_term) {
|
||||
or = g_list_alloc ();
|
||||
and = g_list_alloc ();
|
||||
and->data = initial_term;
|
||||
or->data = and;
|
||||
}
|
||||
|
||||
if(q->terms)
|
||||
gncQueryClear (q);
|
||||
|
||||
g_list_free (q->results);
|
||||
g_list_free (q->books);
|
||||
|
||||
memset (q, 0, sizeof (*q));
|
||||
|
||||
q->terms = or;
|
||||
q->changed = 1;
|
||||
q->max_results = -1;
|
||||
|
||||
q->primary_sort.obj_name = QUERY_DEFAULT_SORT;
|
||||
q->primary_sort.increasing = TRUE;
|
||||
q->secondary_sort.increasing = TRUE;
|
||||
q->tertiary_sort.increasing = TRUE;
|
||||
}
|
||||
|
||||
static void swap_terms (QueryNew *q1, QueryNew *q2)
|
||||
{
|
||||
GList *g;
|
||||
|
||||
if (!q1 || !q2) return;
|
||||
|
||||
g = q1->terms;
|
||||
q1->terms = q2->terms;
|
||||
q2->terms = g;
|
||||
|
||||
q1->changed = 1;
|
||||
q2->changed = 1;
|
||||
}
|
||||
|
||||
static void free_query_term (QueryNewTerm *qt)
|
||||
{
|
||||
if (!qt) return;
|
||||
|
||||
gncQueryCorePredicateFree (qt->pdata);
|
||||
g_free (qt);
|
||||
}
|
||||
|
||||
static QueryNewTerm * copy_query_term (QueryNewTerm *qt)
|
||||
{
|
||||
QueryNewTerm *new_qt;
|
||||
if (!qt) return NULL;
|
||||
|
||||
new_qt = g_new0 (QueryNewTerm, 1);
|
||||
memcpy (new_qt, qt, sizeof(QueryNewTerm));
|
||||
new_qt->pdata = gncQueryCorePredicateCopy (qt->pdata);
|
||||
return new_qt;
|
||||
}
|
||||
|
||||
static GList * copy_and_terms (GList *and_terms)
|
||||
{
|
||||
GList *and = NULL;
|
||||
GList *cur_and;
|
||||
|
||||
for(cur_and = and_terms; cur_and; cur_and = cur_and->next)
|
||||
{
|
||||
and = g_list_prepend(and, copy_query_term (cur_and->data));
|
||||
}
|
||||
|
||||
return g_list_reverse(and);
|
||||
}
|
||||
|
||||
static GList *
|
||||
copy_or_terms(GList * or_terms)
|
||||
{
|
||||
GList * or = NULL;
|
||||
GList * cur_or;
|
||||
|
||||
for(cur_or = or_terms; cur_or; cur_or = cur_or->next)
|
||||
{
|
||||
or = g_list_prepend(or, copy_and_terms(cur_or->data));
|
||||
}
|
||||
|
||||
return g_list_reverse(or);
|
||||
}
|
||||
|
||||
static void free_members (QueryNew *q)
|
||||
{
|
||||
GList * cur_or;
|
||||
|
||||
if (q == NULL) return;
|
||||
|
||||
for(cur_or = q->terms; cur_or; cur_or = cur_or->next)
|
||||
{
|
||||
GList * cur_and;
|
||||
|
||||
for(cur_and = cur_or->data; cur_and; cur_and = cur_and->next)
|
||||
{
|
||||
free_query_term(cur_and->data);
|
||||
cur_and->data = NULL;
|
||||
}
|
||||
|
||||
g_list_free(cur_or->data);
|
||||
cur_or->data = NULL;
|
||||
}
|
||||
|
||||
g_list_free(q->terms);
|
||||
q->terms = NULL;
|
||||
|
||||
g_list_free(q->books);
|
||||
q->books = NULL;
|
||||
|
||||
g_list_free(q->results);
|
||||
q->results = NULL;
|
||||
}
|
||||
|
||||
static int cmp_func (QuerySort_t *sort, QuerySort default_sort,
|
||||
gconstpointer a, gconstpointer b)
|
||||
{
|
||||
gpointer conva, convb;
|
||||
|
||||
g_return_val_if_fail (sort, 0);
|
||||
g_return_val_if_fail (default_sort, 0);
|
||||
|
||||
/* See if this is a default sort */
|
||||
if (sort->use_default) {
|
||||
if (default_sort)
|
||||
return default_sort ((gpointer)a, (gpointer)b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If no converter, consider them equal */
|
||||
if (!sort->conv_fcn) return 0;
|
||||
|
||||
/* no compare function, consider them equal */
|
||||
if (!sort->comp_fcn) return 0;
|
||||
|
||||
/* Do the converstions */
|
||||
conva = sort->conv_fcn ((gpointer)a);
|
||||
convb = sort->conv_fcn ((gpointer)b);
|
||||
|
||||
/* And now return the compare */
|
||||
return sort->comp_fcn (conva, convb, sort->options, sort->get_fcn);
|
||||
}
|
||||
|
||||
static QueryNew * sortQuery = NULL;
|
||||
|
||||
static int sort_func (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
int retval;
|
||||
|
||||
g_return_val_if_fail (sortQuery, 0);
|
||||
|
||||
retval = cmp_func (&(sortQuery->primary_sort), sortQuery->defaultSort, a, b);
|
||||
if (retval == 0) {
|
||||
retval = cmp_func (&(sortQuery->secondary_sort), sortQuery->defaultSort,
|
||||
a, b);
|
||||
if (retval == 0) {
|
||||
retval = cmp_func (&(sortQuery->tertiary_sort), sortQuery->defaultSort,
|
||||
a, b);
|
||||
return sortQuery->tertiary_sort.increasing ? retval : -retval;
|
||||
} else {
|
||||
return sortQuery->secondary_sort.increasing ? retval : -retval;
|
||||
}
|
||||
} else {
|
||||
return sortQuery->primary_sort.increasing ? retval : -retval;
|
||||
}
|
||||
}
|
||||
|
||||
static int check_object (QueryNew *q, gpointer object)
|
||||
{
|
||||
GList * and_ptr;
|
||||
GList * or_ptr;
|
||||
QueryNewTerm * qt;
|
||||
int and_terms_ok=1;
|
||||
gpointer result_obj;
|
||||
|
||||
for(or_ptr = q->terms; or_ptr; or_ptr = or_ptr->next) {
|
||||
and_terms_ok = 1;
|
||||
for(and_ptr = or_ptr->data; and_ptr; and_ptr = and_ptr->next) {
|
||||
qt = (QueryNewTerm *)(and_ptr->data);
|
||||
if (qt->conv_fcn && qt->pred_fcn) {
|
||||
result_obj = ((qt->conv_fcn) (object));
|
||||
if (((qt->pred_fcn)(result_obj, qt->get_fcn,
|
||||
qt->how, qt->pdata)) == qt->invert) {
|
||||
and_terms_ok = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* XXX: Don't know how to do this conversion -- do we care? */
|
||||
}
|
||||
}
|
||||
if(and_terms_ok) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void compile_sort (QuerySort_t *sort, GNCIdType obj)
|
||||
{
|
||||
sort->use_default = FALSE;
|
||||
|
||||
/* An empty obj_name implies "no sort" */
|
||||
if (!sort->obj_name || *(sort->obj_name) == '\0') {
|
||||
sort->conv_fcn = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Obtain the conversion function */
|
||||
sort->conv_fcn = gncQueryObjectGetConverter (obj, sort->obj_name);
|
||||
|
||||
/* No need to continue if there is no conversion function */
|
||||
if (sort->conv_fcn) {
|
||||
const QueryObjectDef *resObj =
|
||||
gncQueryObjectGetParameter (sort->obj_name, sort->param_name);
|
||||
|
||||
if (resObj) {
|
||||
sort->get_fcn = resObj->param_getfcn;
|
||||
sort->comp_fcn = gncQueryCoreGetCompare (resObj->param_type);
|
||||
} else {
|
||||
sort->get_fcn = NULL;
|
||||
sort->comp_fcn = NULL;
|
||||
}
|
||||
|
||||
} else if (!safe_strcmp (sort->obj_name, QUERY_DEFAULT_SORT)) {
|
||||
sort->use_default = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void compile_terms (QueryNew *q)
|
||||
{
|
||||
GList *or_ptr, *and_ptr;
|
||||
|
||||
/* Find the specific functions for this Query. Note that the
|
||||
* Query's last_run_type should now be set to the new type.
|
||||
*/
|
||||
for (or_ptr = q->terms; or_ptr; or_ptr = or_ptr->next) {
|
||||
for (and_ptr = or_ptr->data; and_ptr; and_ptr = and_ptr->next) {
|
||||
QueryNewTerm *qt = and_ptr->data;
|
||||
|
||||
/* Obtain the conversion function */
|
||||
qt->conv_fcn =
|
||||
gncQueryObjectGetConverter (q->last_run_type, qt->obj_name);
|
||||
|
||||
/* No need to continue if there is no conversion function */
|
||||
if (qt->conv_fcn) {
|
||||
const QueryObjectDef *resObj =
|
||||
gncQueryObjectGetParameter (qt->obj_name, qt->param_name);
|
||||
|
||||
if (resObj) {
|
||||
qt->get_fcn = resObj->param_getfcn;
|
||||
qt->pred_fcn = gncQueryCoreGetPredicate (resObj->param_type);
|
||||
} else {
|
||||
qt->get_fcn = NULL;
|
||||
qt->pred_fcn = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the sort functions */
|
||||
compile_sort (&(q->primary_sort), q->last_run_type);
|
||||
compile_sort (&(q->secondary_sort), q->last_run_type);
|
||||
compile_sort (&(q->tertiary_sort), q->last_run_type);
|
||||
|
||||
q->defaultSort = gncQueryObjectDefaultSort (q->last_run_type);
|
||||
}
|
||||
|
||||
static void check_item_cb (gpointer object, gpointer user_data)
|
||||
{
|
||||
query_cb_t *ql = user_data;
|
||||
|
||||
if (!object || !ql) return;
|
||||
|
||||
if (check_object (ql->query, object)) {
|
||||
ql->list = g_list_prepend (ql->list, object);
|
||||
ql->count++;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
/* PUBLISHED API FUNCTIONS */
|
||||
|
||||
void gncQueryNewInit (void)
|
||||
{
|
||||
gncQueryCoreInit ();
|
||||
gncQueryObjectInit ();
|
||||
}
|
||||
|
||||
void gncQueryNewShutdown (void)
|
||||
{
|
||||
gncQueryObjectShutdown ();
|
||||
gncQueryCoreShutdown ();
|
||||
}
|
||||
|
||||
void gncQueryAddTerm (QueryNew *q,
|
||||
GNCIdTypeConst obj_type, const char *param_name,
|
||||
query_compare_t comparitor, QueryPredData_t pred_data,
|
||||
QueryOp op)
|
||||
{
|
||||
QueryNewTerm *qt;
|
||||
QueryNew *qr, *qs;
|
||||
|
||||
if (!q || !obj_type || !param_name || !pred_data) return;
|
||||
|
||||
qt = g_new0 (QueryNewTerm, 1);
|
||||
qt->obj_name = (GNCIdType)obj_type;
|
||||
qt->param_name = param_name;
|
||||
qt->pdata = pred_data;
|
||||
qt->how = comparitor;
|
||||
|
||||
qs = gncQueryCreate ();
|
||||
query_init (qs, qt);
|
||||
|
||||
if (gncQueryHasTerms (q))
|
||||
qr = gncQueryMerge (q, qs, op);
|
||||
else
|
||||
qr = gncQueryMerge (q, qs, QUERY_OR);
|
||||
|
||||
swap_terms (q, qr);
|
||||
gncQueryDestroy (qs);
|
||||
gncQueryDestroy (qr);
|
||||
}
|
||||
|
||||
void gncQueryPurgeTerms (QueryNew *q,
|
||||
GNCIdTypeConst obj_type, const char *param_name)
|
||||
{
|
||||
QueryNewTerm *qt;
|
||||
GList *or, *and;
|
||||
|
||||
if (!q || !obj_type || !param_name) return;
|
||||
|
||||
for (or = q->terms; or; or = or->next) {
|
||||
for (and = or->data; and; and = and->next) {
|
||||
qt = and->data;
|
||||
if (!safe_strcmp (qt->obj_name, obj_type) &&
|
||||
!safe_strcmp (qt->param_name, param_name)) {
|
||||
if (g_list_length (or->data) == 1) {
|
||||
q->terms = g_list_remove_link (q->terms, or);
|
||||
g_list_free_1 (or);
|
||||
or = q->terms;
|
||||
break;
|
||||
} else {
|
||||
or->data = g_list_remove_link (or->data, and);
|
||||
g_list_free_1 (and);
|
||||
and = or->data;
|
||||
if (!and) break;
|
||||
}
|
||||
q->changed = 1;
|
||||
free_query_term (qt);
|
||||
}
|
||||
}
|
||||
if (!or) break;
|
||||
}
|
||||
}
|
||||
|
||||
GList * gncQueryRun (QueryNew *q, GNCIdTypeConst obj_type)
|
||||
{
|
||||
GList *matching_objects = NULL;
|
||||
GList *node;
|
||||
int object_count = 0;
|
||||
|
||||
if (!q || !obj_type) return NULL;
|
||||
|
||||
/* XXX: Prioritize the query terms? */
|
||||
|
||||
/* prepare the Query for processing */
|
||||
if (q->changed || safe_strcmp (q->last_run_type, obj_type)) {
|
||||
q->last_run_type = (GNCIdType)obj_type;
|
||||
compile_terms (q);
|
||||
}
|
||||
|
||||
/* Now run the query over all the objects and save the results */
|
||||
{
|
||||
query_cb_t qcb;
|
||||
|
||||
memset (&qcb, 0, sizeof (qcb));
|
||||
qcb.query = q;
|
||||
|
||||
/* For each book */
|
||||
for (node=q->books; node; node=node->next) {
|
||||
GNCBook *book = node->data;
|
||||
#if 0 /* XXX FIXME! */
|
||||
Backend *be = book->backend;
|
||||
|
||||
/* query the backend */
|
||||
if (be && be->run_query)
|
||||
(be->run_query) (be, q);
|
||||
#endif
|
||||
|
||||
/* and then iterate over all the objects */
|
||||
gncObjectForeach (obj_type, book, check_item_cb, &qcb);
|
||||
}
|
||||
|
||||
matching_objects = qcb.list;
|
||||
object_count = qcb.count;
|
||||
}
|
||||
|
||||
/* There is no absolute need to reverse this list, since it's being
|
||||
* sorted below. However, in the common case, we will be searching
|
||||
* in a confined location where the objects are already in order,
|
||||
* thus reversing will put us in the correct order we want and make
|
||||
* the sorting go much faster.
|
||||
*/
|
||||
matching_objects = g_list_reverse(matching_objects);
|
||||
|
||||
/* now sort the matching objects based on the search criteria
|
||||
* sortQuery is an unforgivable use of static global data... I just
|
||||
* can't figure out how else to do this sanely.
|
||||
*/
|
||||
sortQuery = q;
|
||||
matching_objects = g_list_sort(matching_objects, sort_func);
|
||||
sortQuery = NULL;
|
||||
|
||||
/* crop the list to limit the number of splits */
|
||||
if((object_count > q->max_results) && (q->max_results > -1))
|
||||
{
|
||||
if(q->max_results > 0)
|
||||
{
|
||||
GList *mptr;
|
||||
|
||||
/* mptr is set to the first node of what will be the new list */
|
||||
mptr = g_list_nth(matching_objects, object_count - q->max_results);
|
||||
/* mptr should not be NULL, but let's be safe */
|
||||
if (mptr != NULL)
|
||||
{
|
||||
if (mptr->prev != NULL) mptr->prev->next = NULL;
|
||||
mptr->prev = NULL;
|
||||
}
|
||||
g_list_free(matching_objects);
|
||||
matching_objects = mptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* q->max_results == 0 */
|
||||
g_list_free(matching_objects);
|
||||
matching_objects = NULL;
|
||||
}
|
||||
object_count = q->max_results;
|
||||
}
|
||||
|
||||
q->changed = 0;
|
||||
|
||||
g_list_free(q->results);
|
||||
q->results = matching_objects;
|
||||
|
||||
return matching_objects;
|
||||
}
|
||||
|
||||
void gncQueryClear (QueryNew *query)
|
||||
{
|
||||
QueryNew *q2 = gncQueryCreate ();
|
||||
swap_terms (query, q2);
|
||||
gncQueryDestroy (q2);
|
||||
|
||||
g_list_free (query->books);
|
||||
query->books = NULL;
|
||||
g_list_free (query->results);
|
||||
query->results = NULL;
|
||||
query->changed = 1;
|
||||
}
|
||||
|
||||
QueryNew * gncQueryCreate (void)
|
||||
{
|
||||
QueryNew *qp = g_new0 (QueryNew, 1);
|
||||
query_init (qp, NULL);
|
||||
return qp;
|
||||
}
|
||||
|
||||
int gncQueryHasTerms (QueryNew *q)
|
||||
{
|
||||
if (!q) return 0;
|
||||
return g_list_length (q->terms);
|
||||
}
|
||||
|
||||
int gncQueryNumTerms (QueryNew *q)
|
||||
{
|
||||
GList *o;
|
||||
int n = 0;
|
||||
if (!q) return 0;
|
||||
for (o = q->terms; o; o=o->next)
|
||||
n += g_list_length(o->data);
|
||||
return n;
|
||||
}
|
||||
|
||||
GList * gncQueryGetTerms (QueryNew *q)
|
||||
{
|
||||
if (!q) return NULL;
|
||||
return q->terms;
|
||||
}
|
||||
|
||||
void gncQueryDestroy (QueryNew *q)
|
||||
{
|
||||
if (!q) return;
|
||||
free_members (q);
|
||||
g_free (q);
|
||||
}
|
||||
|
||||
QueryNew * gncQueryCopy (QueryNew *q)
|
||||
{
|
||||
QueryNew *copy;
|
||||
if (!q) return NULL;
|
||||
copy = gncQueryCreate ();
|
||||
free_members (copy);
|
||||
|
||||
memcpy (copy, q, sizeof (QueryNew));
|
||||
|
||||
copy->terms = copy_or_terms (q->terms);
|
||||
copy->books = g_list_copy (q->books);
|
||||
copy->results = g_list_copy (q->results);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* gncQueryInvert
|
||||
* return a newly-allocated Query object which is the
|
||||
* logical inverse of the original.
|
||||
********************************************************************/
|
||||
|
||||
QueryNew * gncQueryInvert (QueryNew *q)
|
||||
{
|
||||
QueryNew * retval;
|
||||
QueryNew * right, * left, * iright, * ileft;
|
||||
QueryNewTerm * qt;
|
||||
GList * aterms;
|
||||
GList * cur;
|
||||
GList * new_oterm;
|
||||
int num_or_terms;
|
||||
|
||||
num_or_terms = g_list_length(q->terms);
|
||||
|
||||
switch(num_or_terms)
|
||||
{
|
||||
case 0:
|
||||
retval = gncQueryCreate();
|
||||
retval->max_results = q->max_results;
|
||||
break;
|
||||
|
||||
/* this is demorgan expansion for a single AND expression. */
|
||||
/* !(abc) = !a + !b + !c */
|
||||
case 1:
|
||||
retval = gncQueryCreate();
|
||||
retval->max_results = q->max_results;
|
||||
|
||||
aterms = g_list_nth_data(q->terms, 0);
|
||||
new_oterm = NULL;
|
||||
for(cur=aterms; cur; cur=cur->next) {
|
||||
qt = copy_query_term(cur->data);
|
||||
qt->invert = !(qt->invert);
|
||||
new_oterm = g_list_append(NULL, qt);
|
||||
retval->terms = g_list_append(retval->terms, new_oterm);
|
||||
}
|
||||
break;
|
||||
|
||||
/* if there are multiple OR-terms, we just recurse by
|
||||
* breaking it down to !(a + b + c) =
|
||||
* !a * !(b + c) = !a * !b * !c. */
|
||||
default:
|
||||
right = gncQueryCreate();
|
||||
right->terms = copy_or_terms(g_list_nth(q->terms, 1));
|
||||
|
||||
left = gncQueryCreate();
|
||||
left->terms = g_list_append(NULL,
|
||||
copy_and_terms(g_list_nth_data(q->terms, 0)));
|
||||
|
||||
iright = gncQueryInvert(right);
|
||||
ileft = gncQueryInvert(left);
|
||||
|
||||
retval = gncQueryMerge(iright, ileft, QUERY_AND);
|
||||
retval->max_results = q->max_results;
|
||||
retval->changed = 1;
|
||||
|
||||
gncQueryDestroy(iright);
|
||||
gncQueryDestroy(ileft);
|
||||
gncQueryDestroy(right);
|
||||
gncQueryDestroy(left);
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* gncQueryMerge
|
||||
* combine 2 Query objects by the logical operation in "op".
|
||||
********************************************************************/
|
||||
|
||||
QueryNew * gncQueryMerge(QueryNew *q1, QueryNew *q2, QueryOp op)
|
||||
{
|
||||
|
||||
QueryNew * retval = NULL;
|
||||
QueryNew * i1, * i2;
|
||||
QueryNew * t1, * t2;
|
||||
GList * i, * j;
|
||||
|
||||
if(!q1 || !q2 ) return NULL;
|
||||
|
||||
switch(op)
|
||||
{
|
||||
case QUERY_OR:
|
||||
retval = gncQueryCreate();
|
||||
retval->terms =
|
||||
g_list_concat(copy_or_terms(q1->terms), copy_or_terms(q2->terms));
|
||||
retval->max_results = q1->max_results;
|
||||
retval->changed = 1;
|
||||
break;
|
||||
|
||||
case QUERY_AND:
|
||||
retval = gncQueryCreate();
|
||||
retval->max_results = q1->max_results;
|
||||
retval->changed = 1;
|
||||
|
||||
for(i=q1->terms; i; i=i->next)
|
||||
{
|
||||
for(j=q2->terms; j; j=j->next)
|
||||
{
|
||||
retval->terms =
|
||||
g_list_append(retval->terms,
|
||||
g_list_concat
|
||||
(copy_and_terms(i->data),
|
||||
copy_and_terms(j->data)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case QUERY_NAND:
|
||||
/* !(a*b) = (!a + !b) */
|
||||
i1 = gncQueryInvert(q1);
|
||||
i2 = gncQueryInvert(q2);
|
||||
retval = gncQueryMerge(i1, i2, QUERY_OR);
|
||||
gncQueryDestroy(i1);
|
||||
gncQueryDestroy(i2);
|
||||
break;
|
||||
|
||||
case QUERY_NOR:
|
||||
/* !(a+b) = (!a*!b) */
|
||||
i1 = gncQueryInvert(q1);
|
||||
i2 = gncQueryInvert(q2);
|
||||
retval = gncQueryMerge(i1, i2, QUERY_AND);
|
||||
gncQueryDestroy(i1);
|
||||
gncQueryDestroy(i2);
|
||||
break;
|
||||
|
||||
case QUERY_XOR:
|
||||
/* a xor b = (a * !b) + (!a * b) */
|
||||
i1 = gncQueryInvert(q1);
|
||||
i2 = gncQueryInvert(q2);
|
||||
t1 = gncQueryMerge(q1, i2, QUERY_AND);
|
||||
t2 = gncQueryMerge(i1, q2, QUERY_AND);
|
||||
retval = gncQueryMerge(t1, t2, QUERY_OR);
|
||||
|
||||
gncQueryDestroy(i1);
|
||||
gncQueryDestroy(i2);
|
||||
gncQueryDestroy(t1);
|
||||
gncQueryDestroy(t2);
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
gncQuerySetSortOrder (QueryNew *q,
|
||||
GNCIdTypeConst prim_type, const char *prim_param,
|
||||
GNCIdTypeConst sec_type, const char *sec_param,
|
||||
GNCIdTypeConst tert_type, const char *tert_param)
|
||||
{
|
||||
if (!q) return;
|
||||
q->primary_sort.obj_name = (GNCIdType)prim_type;
|
||||
q->primary_sort.param_name = prim_param;
|
||||
q->primary_sort.options = 0;
|
||||
q->secondary_sort.obj_name = (GNCIdType)sec_type;
|
||||
q->secondary_sort.param_name = sec_param;
|
||||
q->secondary_sort.options = 0;
|
||||
q->tertiary_sort.obj_name = (GNCIdType)tert_type;
|
||||
q->tertiary_sort.param_name = tert_param;
|
||||
q->tertiary_sort.options = 0;
|
||||
}
|
||||
|
||||
void gncQuerySetSortOptions (QueryNew *q, gint prim_op, gint sec_op,
|
||||
gint tert_op)
|
||||
{
|
||||
if (!q) return;
|
||||
q->primary_sort.options = prim_op;
|
||||
q->secondary_sort.options = sec_op;
|
||||
q->tertiary_sort.options = tert_op;
|
||||
}
|
||||
|
||||
void gncQuerySetSortIncreasing (QueryNew *q, gboolean prim_inc,
|
||||
gboolean sec_inc, gboolean tert_inc)
|
||||
{
|
||||
if (!q) return;
|
||||
q->primary_sort.increasing = prim_inc;
|
||||
q->secondary_sort.increasing = sec_inc;
|
||||
q->tertiary_sort.increasing = tert_inc;
|
||||
}
|
||||
|
||||
void gncQuerySetMaxResults (QueryNew *q, int n)
|
||||
{
|
||||
if (!q) return;
|
||||
q->max_results = n;
|
||||
}
|
||||
|
||||
int gncQueryGetMaxResults (QueryNew *q)
|
||||
{
|
||||
if (!q) return 0;
|
||||
return q->max_results;
|
||||
}
|
||||
|
||||
void gncQueryAddGUIDMatch (QueryNew *q, QueryOp op,
|
||||
GNCIdTypeConst obj_type, const char *param_name,
|
||||
const GUID *guid)
|
||||
{
|
||||
QueryPredData_t pdata;
|
||||
GList *g = NULL;
|
||||
|
||||
if (!q || !obj_type || !param_name) return;
|
||||
|
||||
if (guid)
|
||||
g = g_list_prepend (g, (gpointer)guid);
|
||||
|
||||
pdata = gncQueryGUIDPredicate (guid ? GUID_MATCH_ANY : GUID_MATCH_NULL, g);
|
||||
g_list_free (g);
|
||||
|
||||
gncQueryAddTerm (q, obj_type, param_name, COMPARE_EQUAL, pdata, op);
|
||||
}
|
||||
|
||||
void gncQuerySetBook (QueryNew *q, GNCBook *book)
|
||||
{
|
||||
if (!q || !book) return;
|
||||
|
||||
q->books = g_list_prepend (q->books, book);
|
||||
gncQueryAddGUIDMatch (q, QUERY_AND, GNC_ID_BOOK, BOOK_GUID,
|
||||
gnc_book_get_guid(book));
|
||||
}
|
||||
|
187
src/engine/QueryNew.h
Normal file
187
src/engine/QueryNew.h
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* QueryNew.h -- API for finding Gnucash objects
|
||||
* Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GNC_QUERYNEW_H
|
||||
#define GNC_QUERYNEW_H
|
||||
|
||||
#include "GNCId.h"
|
||||
|
||||
/* A Query */
|
||||
typedef struct querynew_s QueryNew;
|
||||
|
||||
/* Query Term Operators, for combining Query Terms */
|
||||
typedef enum {
|
||||
QUERY_AND=1,
|
||||
QUERY_OR,
|
||||
QUERY_NAND,
|
||||
QUERY_NOR,
|
||||
QUERY_XOR
|
||||
} QueryOp;
|
||||
|
||||
|
||||
/* Standard Query Term comparitors, for how to process a query term.
|
||||
* Note that not all core types implement all comparitors
|
||||
*/
|
||||
typedef enum {
|
||||
COMPARE_LT = 1,
|
||||
COMPARE_LTE,
|
||||
COMPARE_EQUAL,
|
||||
COMPARE_GT,
|
||||
COMPARE_GTE
|
||||
} query_compare_t;
|
||||
|
||||
#define QUERY_DEFAULT_SORT "GnucashQueryDefaultSortObject"
|
||||
|
||||
/* "Known" Object Parameters */
|
||||
#define SPLIT_KVP "kvp"
|
||||
#define SPLIT_GUID "guid"
|
||||
#define SPLIT_DATE_RECONCILED "date-reconciled"
|
||||
#define SPLIT_BALANCE "balance"
|
||||
#define SPLIT_CLEARED_BALANCE "cleared-balance"
|
||||
#define SPLIT_RECONCILED_BALANCE "reconciled-balance"
|
||||
#define SPLIT_MEMO "memo"
|
||||
#define SPLIT_ACTION "action"
|
||||
#define SPLIT_RECONCILE "reconcile-flag"
|
||||
#define SPLIT_AMOUNT "amount"
|
||||
#define SPLIT_SHARE_PRICE "share-price"
|
||||
#define SPLIT_VALUE "value"
|
||||
#define SPLIT_TYPE "type"
|
||||
#define SPLIT_VOIDED_AMOUNT "voided-amount"
|
||||
#define SPLIT_VOIDED_VALUE "voided-value"
|
||||
|
||||
#define TRANS_KVP "kvp"
|
||||
#define TRANS_GUID "guid"
|
||||
#define TRANS_NUM "num"
|
||||
#define TRANS_DESCRIPTON "desc"
|
||||
#define TRANS_DATE_ENTERED "date-entered"
|
||||
#define TRANS_DATE_POSTED "date-posted"
|
||||
#define TRANS_DATE_DUE "date-due"
|
||||
#define TRANS_TYPE "type"
|
||||
#define TRANS_VOID_STATUS "void-p"
|
||||
#define TRANS_VOID_REASON "void-reason"
|
||||
#define TRANS_VOID_TIME "void-time"
|
||||
|
||||
#define ACCOUNT_KVP "kvp"
|
||||
#define ACCOUNT_GUID "guid"
|
||||
#define ACCOUNT_NAME "name"
|
||||
#define ACCOUNT_CODE "code"
|
||||
#define ACCOUNT_DESCRIPTION "desc"
|
||||
#define ACCOUNT_NOTES "notes"
|
||||
#define ACCOUNT_BALANCE "balance"
|
||||
#define ACCOUNT_CLEARED_BALANCE "cleared-balance"
|
||||
#define ACCOUNT_RECONCILED_BALANCE "reconciled-balance"
|
||||
#define ACCOUNT_TAX_RELATED "tax-related-p"
|
||||
|
||||
#define BOOK_KVP "kvp"
|
||||
#define BOOK_GUID "guid"
|
||||
|
||||
/* Type of Query Core Objects (String, Date, Numeric, GUID, etc. */
|
||||
typedef const char * QueryCoreType;
|
||||
|
||||
/*
|
||||
* List of known core query types...
|
||||
* Each core query type defines it's set of optional "comparitor qualifiers".
|
||||
*/
|
||||
#define QUERYCORE_STRING "string"
|
||||
typedef enum {
|
||||
STRING_MATCH_NORMAL = 1,
|
||||
STRING_MATCH_CASEINSENSITIVE
|
||||
} string_match_t;
|
||||
|
||||
#define QUERYCORE_DATE "date"
|
||||
typedef enum {
|
||||
DATE_MATCH_NORMAL = 1,
|
||||
DATE_MATCH_ROUNDED
|
||||
} date_match_t;
|
||||
|
||||
#define QUERYCORE_NUMERIC "numeric"
|
||||
typedef enum {
|
||||
NUMERIC_MATCH_NEG_ONLY = 1,
|
||||
NUMERIC_MATCH_POS_ONLY,
|
||||
NUMERIC_MATCH_ANY
|
||||
} numeric_match_t;
|
||||
|
||||
#define QUERYCORE_GUID "guid"
|
||||
typedef enum {
|
||||
GUID_MATCH_ANY = 1,
|
||||
GUID_MATCH_NONE,
|
||||
GUID_MATCH_NULL
|
||||
} guid_match_t;
|
||||
|
||||
#define QUERYCORE_INT64 "gint64"
|
||||
#define QUERYCORE_DOUBLE "double"
|
||||
#define QUERYCORE_BOOLEAN "boolean"
|
||||
#define QUERYCORE_KVP "kvp"
|
||||
|
||||
/* A CHAR type is for a RECNCell */
|
||||
#define QUERYCORE_CHAR "character"
|
||||
typedef enum {
|
||||
CHAR_MATCH_ANY = 1,
|
||||
CHAR_MATCH_NONE
|
||||
} char_match_t;
|
||||
|
||||
/* Basic API Functions */
|
||||
|
||||
/* This is the general function that adds a new Query Term to a query.
|
||||
* It will find the 'obj_type' object of the search item and compare
|
||||
* the 'param_name' parameter to the predicate data via the comparitor.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* acct_name_pred_data = make_string_pred_data(STRING_MATCH_CASEINSENSITIVE,
|
||||
* account_name);
|
||||
* gncQueryAddTerm (query, GNC_ID_ACCOUNT, QUERY_ACCOUNT_NAME,
|
||||
* COMPARE_EQUAL, acct_name_pred_data, QUERY_AND);
|
||||
*/
|
||||
|
||||
typedef struct query_pred_data *QueryPredData_t;
|
||||
|
||||
void gncQueryAddTerm (QueryNew *query,
|
||||
GNCIdTypeConst obj_type, const char *param_name,
|
||||
query_compare_t comparitor, QueryPredData_t pred_data,
|
||||
QueryOp op);
|
||||
|
||||
void gncQuerySetBook (QueryNew *q, GNCBook *book);
|
||||
void gncQueryAddGUIDMatch (QueryNew *q, QueryOp op,
|
||||
GNCIdTypeConst obj_type, const char *param_name,
|
||||
const GUID *guid);
|
||||
|
||||
/* Run the query:
|
||||
*
|
||||
* ex: gncQueryRun (query, GNC_ID_SPLIT);
|
||||
*/
|
||||
GList * gncQueryRun (QueryNew *query, GNCIdTypeConst obj_type);
|
||||
|
||||
QueryNew * gncQueryCreate (void);
|
||||
void gncQueryDestroy (QueryNew *q);
|
||||
|
||||
void gncQueryClear (QueryNew *query);
|
||||
void gncQueryPurgeTerms (QueryNew *q, GNCIdTypeConst obj_type,
|
||||
const char *param_name);
|
||||
int gncQueryHasTerms (QueryNew *q);
|
||||
int gncQueryNumTerms (QueryNew *q);
|
||||
GList * gncQueryGetTerms (QueryNew *q);
|
||||
|
||||
QueryNew * gncQueryCopy (QueryNew *q);
|
||||
QueryNew * gncQueryInvert(QueryNew *q);
|
||||
QueryNew * gncQueryMerge(QueryNew *q1, QueryNew *q2, QueryOp op);
|
||||
|
||||
void gncQuerySetSortOrder (QueryNew *q,
|
||||
GNCIdTypeConst prim_type, const char *prim_param,
|
||||
GNCIdTypeConst secy_type, const char *sec_param,
|
||||
GNCIdTypeConst tert_type, const char *tert_param);
|
||||
|
||||
void gncQuerySetSortOptions (QueryNew *q, gint prim_op, gint sec_op,
|
||||
gint tert_op);
|
||||
|
||||
void gncQuerySetSortIncreasing (QueryNew *q, gboolean prim_inc,
|
||||
gboolean sec_inc, gboolean tert_inc);
|
||||
|
||||
|
||||
void gncQuerySetMaxResults (QueryNew *q, int n);
|
||||
int gncQueryGetMaxResults (QueryNew *q);
|
||||
|
||||
#endif /* GNC_QUERYNEW_H */
|
13
src/engine/QueryNewP.h
Normal file
13
src/engine/QueryNewP.h
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* QueryNewP.h -- API for finding Gnucash objects
|
||||
* Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>
|
||||
*/
|
||||
|
||||
#ifndef GNC_QUERYNEWP_H
|
||||
#define GNC_QUERYNEWP_H
|
||||
|
||||
/* Initialize/Shutdown */
|
||||
void gncQueryNewInit (void);
|
||||
void gncQueryNewShutdown (void);
|
||||
|
||||
#endif /* GNC_QUERYNEWP_H */
|
317
src/engine/QueryObject.c
Normal file
317
src/engine/QueryObject.c
Normal file
@ -0,0 +1,317 @@
|
||||
/*
|
||||
* QueryObject.c -- provide Gnucash Queriable data objects
|
||||
* Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <regex.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gnc-engine-util.h"
|
||||
#include "QueryObjectP.h"
|
||||
#include "QueryNew.h"
|
||||
|
||||
#include "Account.h"
|
||||
#include "Transaction.h"
|
||||
|
||||
static short module = MOD_QUERY;
|
||||
|
||||
static GHashTable *paramTable = NULL;
|
||||
static GHashTable *convTable = NULL;
|
||||
static GHashTable *sortTable = NULL;
|
||||
static gboolean initialized = FALSE;
|
||||
|
||||
typedef enum {
|
||||
TYPE_PARAM = 1,
|
||||
TYPE_CONV
|
||||
} QueryObjectType;
|
||||
|
||||
/* Stupid function to perform a no-op, to make the interface clean */
|
||||
static gpointer self_convert (gpointer obj)
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
|
||||
static GHashTable * get_object_table (GNCIdType name, QueryObjectType type)
|
||||
{
|
||||
GHashTable *ht = NULL, *obj_ht = NULL;
|
||||
|
||||
g_return_val_if_fail (name, NULL);
|
||||
g_return_val_if_fail (initialized, NULL);
|
||||
|
||||
switch (type) {
|
||||
case TYPE_PARAM:
|
||||
ht = paramTable;
|
||||
break;
|
||||
case TYPE_CONV:
|
||||
ht = convTable;
|
||||
}
|
||||
|
||||
if (!ht) {
|
||||
PWARN ("Aiee -- no hash table");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
obj_ht = g_hash_table_lookup (ht, name);
|
||||
|
||||
/* If it doesn't already exist, create a new table for this object */
|
||||
if (!obj_ht) {
|
||||
obj_ht = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
g_hash_table_insert (ht, (char *)name, obj_ht);
|
||||
}
|
||||
|
||||
return obj_ht;
|
||||
}
|
||||
|
||||
static void insert_method (GNCIdType objname, const char *param,
|
||||
gconstpointer method, QueryObjectType type)
|
||||
{
|
||||
GHashTable *ht;
|
||||
|
||||
g_return_if_fail (objname);
|
||||
g_return_if_fail (param);
|
||||
g_return_if_fail (method);
|
||||
|
||||
ht = get_object_table (objname, type);
|
||||
g_return_if_fail (ht);
|
||||
|
||||
g_hash_table_insert (ht, (char *)param, (gpointer)method);
|
||||
}
|
||||
|
||||
static void init_split (void)
|
||||
{
|
||||
static const QueryObjectDef params[] = {
|
||||
{ SPLIT_KVP, QUERYCORE_KVP, (QueryAccess)xaccSplitGetSlots },
|
||||
{ SPLIT_GUID, QUERYCORE_GUID, (QueryAccess) xaccSplitGetGUID },
|
||||
{ SPLIT_DATE_RECONCILED, QUERYCORE_DATE,
|
||||
(QueryAccess)xaccSplitRetDateReconciledTS },
|
||||
{ SPLIT_BALANCE, QUERYCORE_NUMERIC, (QueryAccess)xaccSplitGetBalance },
|
||||
{ SPLIT_CLEARED_BALANCE, QUERYCORE_NUMERIC,
|
||||
(QueryAccess)xaccSplitGetClearedBalance },
|
||||
{ SPLIT_RECONCILED_BALANCE, QUERYCORE_NUMERIC,
|
||||
(QueryAccess)xaccSplitGetReconciledBalance },
|
||||
{ SPLIT_MEMO, QUERYCORE_STRING, (QueryAccess)xaccSplitGetMemo },
|
||||
{ SPLIT_ACTION, QUERYCORE_STRING, (QueryAccess)xaccSplitGetAction },
|
||||
{ SPLIT_RECONCILE, QUERYCORE_CHAR, (QueryAccess)xaccSplitGetReconcile },
|
||||
{ SPLIT_AMOUNT, QUERYCORE_NUMERIC, (QueryAccess)xaccSplitGetAmount },
|
||||
{ SPLIT_SHARE_PRICE, QUERYCORE_NUMERIC,
|
||||
(QueryAccess)xaccSplitGetSharePrice },
|
||||
{ SPLIT_VALUE, QUERYCORE_NUMERIC, (QueryAccess)xaccSplitGetValue },
|
||||
{ SPLIT_TYPE, QUERYCORE_STRING, (QueryAccess)xaccSplitGetType },
|
||||
{ SPLIT_VOIDED_AMOUNT, QUERYCORE_NUMERIC,
|
||||
(QueryAccess)xaccSplitVoidFormerAmount },
|
||||
{ SPLIT_VOIDED_VALUE, QUERYCORE_NUMERIC,
|
||||
(QueryAccess)xaccSplitVoidFormerValue },
|
||||
{ NULL },
|
||||
};
|
||||
static const QueryConvertDef converters[] = {
|
||||
{ GNC_ID_TRANS, (QueryConvert)xaccSplitGetParent },
|
||||
{ GNC_ID_ACCOUNT, (QueryConvert)xaccSplitGetAccount },
|
||||
{ GNC_ID_BOOK, (QueryConvert)xaccSplitGetBook },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
gncQueryObjectRegister (GNC_ID_SPLIT, (QuerySort)xaccSplitDateOrder,
|
||||
params, converters);
|
||||
}
|
||||
|
||||
static void init_txn (void)
|
||||
{
|
||||
static QueryObjectDef params[] = {
|
||||
{ TRANS_KVP, QUERYCORE_KVP, (QueryAccess)xaccTransGetSlots },
|
||||
{ TRANS_GUID, QUERYCORE_GUID, (QueryAccess)xaccTransGetGUID },
|
||||
{ TRANS_NUM, QUERYCORE_STRING, (QueryAccess)xaccTransGetNum },
|
||||
{ TRANS_DESCRIPTON, QUERYCORE_STRING, (QueryAccess)xaccTransGetDescription },
|
||||
{ TRANS_DATE_ENTERED, QUERYCORE_DATE, (QueryAccess)xaccTransRetDateEnteredTS },
|
||||
{ TRANS_DATE_POSTED, QUERYCORE_DATE, (QueryAccess)xaccTransRetDatePostedTS },
|
||||
{ TRANS_DATE_DUE, QUERYCORE_DATE, (QueryAccess)xaccTransRetDateDueTS },
|
||||
{ TRANS_TYPE, QUERYCORE_CHAR, (QueryAccess)xaccTransGetTxnType },
|
||||
{ TRANS_VOID_STATUS, QUERYCORE_BOOLEAN, (QueryAccess)xaccTransGetVoidStatus },
|
||||
{ TRANS_VOID_REASON, QUERYCORE_STRING, (QueryAccess)xaccTransGetVoidReason },
|
||||
{ TRANS_VOID_TIME, QUERYCORE_DATE, (QueryAccess)xaccTransGetVoidTime },
|
||||
{ NULL },
|
||||
};
|
||||
static const QueryConvertDef converters[] = {
|
||||
{ GNC_ID_BOOK, (QueryConvert)xaccTransGetBook },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
gncQueryObjectRegister (GNC_ID_TRANS, (QuerySort)xaccTransOrder,
|
||||
params, converters);
|
||||
}
|
||||
|
||||
static void init_account (void)
|
||||
{
|
||||
static QueryObjectDef params[] = {
|
||||
{ ACCOUNT_KVP, QUERYCORE_KVP, (QueryAccess)xaccAccountGetSlots },
|
||||
{ ACCOUNT_GUID, QUERYCORE_GUID, (QueryAccess)xaccAccountGetGUID },
|
||||
{ ACCOUNT_NAME, QUERYCORE_STRING, (QueryAccess)xaccAccountGetName },
|
||||
{ ACCOUNT_CODE, QUERYCORE_STRING, (QueryAccess)xaccAccountGetCode },
|
||||
{ ACCOUNT_DESCRIPTION, QUERYCORE_STRING, (QueryAccess)xaccAccountGetDescription },
|
||||
{ ACCOUNT_NOTES, QUERYCORE_STRING, (QueryAccess)xaccAccountGetNotes },
|
||||
{ ACCOUNT_BALANCE, QUERYCORE_NUMERIC, (QueryAccess)xaccAccountGetBalance },
|
||||
{ ACCOUNT_CLEARED_BALANCE, QUERYCORE_NUMERIC, (QueryAccess)xaccAccountGetClearedBalance },
|
||||
{ ACCOUNT_RECONCILED_BALANCE, QUERYCORE_NUMERIC, (QueryAccess)xaccAccountGetReconciledBalance },
|
||||
{ ACCOUNT_TAX_RELATED, QUERYCORE_BOOLEAN, (QueryAccess)xaccAccountGetTaxRelated },
|
||||
{ NULL },
|
||||
};
|
||||
static const QueryConvertDef converters[] = {
|
||||
{ GNC_ID_BOOK, (QueryConvert)xaccAccountGetBook },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
gncQueryObjectRegister (GNC_ID_ACCOUNT, (QuerySort)xaccAccountOrder,
|
||||
params, converters);
|
||||
}
|
||||
|
||||
static void init_book (void)
|
||||
{
|
||||
static QueryObjectDef params[] = {
|
||||
{ BOOK_KVP, QUERYCORE_KVP, (QueryAccess)gnc_book_get_slots },
|
||||
{ BOOK_GUID, QUERYCORE_GUID, (QueryAccess)gnc_book_get_guid },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
gncQueryObjectRegister (GNC_ID_BOOK, NULL, params, NULL);
|
||||
}
|
||||
|
||||
static void init_tables (void)
|
||||
{
|
||||
init_split ();
|
||||
init_txn ();
|
||||
init_account ();
|
||||
init_book ();
|
||||
}
|
||||
|
||||
static gboolean clear_table (gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
g_hash_table_destroy (value);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
/* PUBLISHED API FUNCTIONS */
|
||||
|
||||
void gncQueryObjectRegister (GNCIdType obj_name,
|
||||
QuerySort default_sort_function,
|
||||
const QueryObjectDef *params,
|
||||
const QueryConvertDef *converters)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!obj_name) return;
|
||||
|
||||
if (default_sort_function)
|
||||
g_hash_table_insert (sortTable, (char *)obj_name, default_sort_function);
|
||||
|
||||
if (params) {
|
||||
for (i = 0; params[i].param_name; i++)
|
||||
insert_method (obj_name, params[i].param_name, &(params[i]), TYPE_PARAM);
|
||||
}
|
||||
|
||||
if (converters) {
|
||||
for (i = 0; converters[i].desired_object_name; i++)
|
||||
insert_method (obj_name, converters[i].desired_object_name,
|
||||
&(converters[i]), TYPE_CONV);
|
||||
}
|
||||
}
|
||||
|
||||
void gncQueryObjectInit(void)
|
||||
{
|
||||
if (initialized) return;
|
||||
initialized = TRUE;
|
||||
|
||||
paramTable = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
convTable = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
sortTable = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
init_tables ();
|
||||
}
|
||||
|
||||
void gncQueryObjectShutdown (void)
|
||||
{
|
||||
if (!initialized) return;
|
||||
initialized = FALSE;
|
||||
|
||||
g_hash_table_foreach_remove (paramTable, clear_table, NULL);
|
||||
g_hash_table_destroy (paramTable);
|
||||
|
||||
g_hash_table_foreach_remove (convTable, clear_table, NULL);
|
||||
g_hash_table_destroy (convTable);
|
||||
|
||||
g_hash_table_destroy (sortTable);
|
||||
}
|
||||
|
||||
|
||||
const QueryObjectDef * gncQueryObjectGetParameter (GNCIdType obj_name,
|
||||
const char *parameter)
|
||||
{
|
||||
GHashTable *ht;
|
||||
|
||||
g_return_val_if_fail (obj_name, NULL);
|
||||
g_return_val_if_fail (parameter, NULL);
|
||||
|
||||
ht = get_object_table (obj_name, TYPE_PARAM);
|
||||
g_return_val_if_fail (ht, NULL);
|
||||
|
||||
return (g_hash_table_lookup (ht, parameter));
|
||||
}
|
||||
|
||||
QueryAccess gncQueryObjectGetParamaterGetter (GNCIdType obj_name,
|
||||
const char *parameter)
|
||||
{
|
||||
const QueryObjectDef *obj;
|
||||
|
||||
g_return_val_if_fail (obj_name, NULL);
|
||||
g_return_val_if_fail (parameter, NULL);
|
||||
|
||||
obj = gncQueryObjectGetParameter (obj_name, parameter);
|
||||
if (obj)
|
||||
return obj->param_getfcn;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QueryConvert gncQueryObjectGetConverter (GNCIdType from_obj,
|
||||
GNCIdType to_obj)
|
||||
{
|
||||
GHashTable *ht;
|
||||
QueryConvertDef *conv;
|
||||
|
||||
g_return_val_if_fail (from_obj, NULL);
|
||||
g_return_val_if_fail (to_obj, NULL);
|
||||
|
||||
if (from_obj == to_obj || !safe_strcmp (from_obj, to_obj))
|
||||
return self_convert;
|
||||
|
||||
ht = get_object_table (from_obj, TYPE_CONV);
|
||||
g_return_val_if_fail (ht, NULL);
|
||||
|
||||
conv = g_hash_table_lookup (ht, to_obj);
|
||||
if (conv)
|
||||
return conv->object_getfcn;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QueryCoreType gncQueryObjectParameterType (GNCIdType obj_name,
|
||||
const char *param_name)
|
||||
{
|
||||
const QueryObjectDef *obj;
|
||||
|
||||
if (!obj_name || !param_name) return NULL;
|
||||
|
||||
obj = gncQueryObjectGetParameter (obj_name, param_name);
|
||||
if (!obj) return NULL;
|
||||
|
||||
return (obj->param_type);
|
||||
}
|
||||
|
||||
QuerySort gncQueryObjectDefaultSort (GNCIdType obj_name)
|
||||
{
|
||||
if (!obj_name) return NULL;
|
||||
return g_hash_table_lookup (sortTable, obj_name);
|
||||
}
|
74
src/engine/QueryObject.h
Normal file
74
src/engine/QueryObject.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* QueryObject.h -- API for registering queriable Gnucash objects
|
||||
* Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GNC_QUERYOBJECT_H
|
||||
#define GNC_QUERYOBJECT_H
|
||||
|
||||
#include "QueryNew.h"
|
||||
|
||||
/* Define an arbitrary function pointer for access functions. This is
|
||||
* because C doesn't have templates, so we just cast a lot. Real
|
||||
* functions must be of the form:
|
||||
*
|
||||
* <param_type> function (object_type *obj);
|
||||
*/
|
||||
typedef void (*QueryAccess)(gpointer);
|
||||
|
||||
/* This structure is for each queriable parameter in an object */
|
||||
typedef struct query_object_def {
|
||||
const char * param_name;
|
||||
QueryCoreType param_type;
|
||||
QueryAccess param_getfcn;
|
||||
} QueryObjectDef;
|
||||
|
||||
/* This function-type will convert from one object-type to another */
|
||||
typedef gpointer (*QueryConvert)(gpointer);
|
||||
|
||||
typedef struct query_convert_def {
|
||||
GNCIdType desired_object_name;
|
||||
QueryConvert object_getfcn;
|
||||
} QueryConvertDef;
|
||||
|
||||
/* This function is the default sort function for a particular object type */
|
||||
typedef int (*QuerySort)(gpointer, gpointer);
|
||||
|
||||
/* This function registers a new Gnucash Object with the QueryNew
|
||||
* subsystem. In particular it registers the set of parameters and
|
||||
* converters to query the type-specific data. Both "params" and
|
||||
* "converters" are NULL-terminated arrays of structures. Either
|
||||
* argument may be NULL if there is nothing to be registered.
|
||||
*/
|
||||
void gncQueryObjectRegister (GNCIdType obj_name,
|
||||
QuerySort default_sort_fcn,
|
||||
const QueryObjectDef *params,
|
||||
const QueryConvertDef *converters);
|
||||
|
||||
/* An example:
|
||||
*
|
||||
* #define MY_QUERY_OBJ_MEMO "memo"
|
||||
* #define MY_QUERY_OBJ_VALUE "value"
|
||||
* #define MY_QUERY_OBJ_DATE "date"
|
||||
*
|
||||
* static QueryObjectDef myQueryObjectParams[] = {
|
||||
* { MY_QUERY_OBJ_MEMO, QUERYCORE_STRING, myMemoGetter },
|
||||
* { MY_QUERY_OBJ_VALUE, QUERYCORE_NUMERIC, myValueGetter },
|
||||
* { MY_QUERY_OBJ_DATE, QUERYCORE_DATE, myDateGetter },
|
||||
* NULL };
|
||||
*
|
||||
* static QueryConvertDef myQueryObjectsConvs[] = {
|
||||
* { GNC_ID_ACCOUNT, myAccountGetter },
|
||||
* { GNC_ID_TRANS, myTransactionGetter },
|
||||
* NULL };
|
||||
*
|
||||
* gncQueryObjectRegisterParamters ("myObjectName", &myQueryObjectParams,
|
||||
* &myQueryObjectConvs);
|
||||
*/
|
||||
|
||||
/* Return the core datatype of the specified object's parameter */
|
||||
QueryCoreType gncQueryObjectParameterType (GNCIdType obj_name,
|
||||
const char *param_name);
|
||||
|
||||
#endif /* GNC_QUERYOBJECT_H */
|
26
src/engine/QueryObjectP.h
Normal file
26
src/engine/QueryObjectP.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* QueryObject.h -- Private API for registering queriable Gnucash objects
|
||||
* Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GNC_QUERYOBJECTP_H
|
||||
#define GNC_QUERYOBJECTP_H
|
||||
|
||||
#include "QueryObject.h"
|
||||
|
||||
void gncQueryObjectInit(void);
|
||||
void gncQueryObjectShutdown (void);
|
||||
|
||||
const QueryObjectDef * gncQueryObjectGetParameter (GNCIdType obj_name,
|
||||
const char *parameter);
|
||||
|
||||
QueryAccess gncQueryObjectGetParamaterGetter (GNCIdType obj_name,
|
||||
const char *parameter);
|
||||
|
||||
QueryConvert gncQueryObjectGetConverter (GNCIdType from_obj,
|
||||
GNCIdType to_obj);
|
||||
|
||||
QuerySort gncQueryObjectDefaultSort (GNCIdType obj_name);
|
||||
|
||||
#endif /* GNC_QUERYOBJECTP_H */
|
@ -2600,6 +2600,16 @@ xaccTransGetDateDueTS (Transaction *trans, Timespec *ts)
|
||||
xaccTransGetDatePostedTS (trans, ts);
|
||||
}
|
||||
|
||||
Timespec
|
||||
xaccTransRetDateDueTS (Transaction *trans)
|
||||
{
|
||||
Timespec ts;
|
||||
ts.tv_sec = 0; ts.tv_nsec = 0;
|
||||
if (!trans) return ts;
|
||||
xaccTransGetDateDueTS (trans, &ts);
|
||||
return ts;
|
||||
}
|
||||
|
||||
char
|
||||
xaccTransGetTxnType (Transaction *trans)
|
||||
{
|
||||
@ -2793,6 +2803,13 @@ xaccSplitGetSharePrice (Split * split) {
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
|
||||
GNCBook *
|
||||
xaccSplitGetBook (Split *split)
|
||||
{
|
||||
if (!split) return NULL;
|
||||
return split->book;
|
||||
}
|
||||
|
||||
const char *
|
||||
xaccSplitGetType(const Split *s)
|
||||
{
|
||||
|
@ -227,6 +227,7 @@ Timespec xaccTransRetDateEnteredTS (Transaction *trans);
|
||||
Timespec xaccTransRetDatePostedTS (Transaction *trans);
|
||||
|
||||
/* Dates and txn-type for A/R and A/P "invoice" postings */
|
||||
Timespec xaccTransRetDateDueTS (Transaction *trans);
|
||||
void xaccTransGetDateDueTS (Transaction *trans, Timespec *ts);
|
||||
char xaccTransGetTxnType (Transaction *trans);
|
||||
|
||||
@ -367,6 +368,7 @@ void xaccSplitSetBaseValue (Split *split, gnc_numeric value,
|
||||
* of all transactions that have been marked as reconciled.
|
||||
*/
|
||||
|
||||
GNCBook * xaccSplitGetBook (Split *split);
|
||||
gnc_numeric xaccSplitGetBalance (Split *split);
|
||||
gnc_numeric xaccSplitGetClearedBalance (Split *split);
|
||||
gnc_numeric xaccSplitGetReconciledBalance (Split *split);
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include "gnc-event.h"
|
||||
#include "gnc-event-p.h"
|
||||
#include "gnc-module.h"
|
||||
#include "gncObjectP.h"
|
||||
|
||||
static short module = MOD_IO;
|
||||
|
||||
@ -105,6 +106,7 @@ gnc_book_new (void)
|
||||
ENTER (" ");
|
||||
book = g_new0(GNCBook, 1);
|
||||
gnc_book_init(book);
|
||||
gncObjectBookBegin (book);
|
||||
|
||||
gnc_engine_generate_event (&book->guid, GNC_EVENT_CREATE);
|
||||
LEAVE ("book=%p", book);
|
||||
@ -119,6 +121,8 @@ gnc_book_destroy (GNCBook *book)
|
||||
ENTER ("book=%p", book);
|
||||
gnc_engine_generate_event (&book->guid, GNC_EVENT_DESTROY);
|
||||
|
||||
gncObjectBookEnd (book);
|
||||
|
||||
xaccAccountGroupBeginEdit (book->topgroup);
|
||||
xaccAccountGroupDestroy (book->topgroup);
|
||||
book->topgroup = NULL;
|
||||
|
@ -316,6 +316,13 @@ safe_strcmp (const char * da, const char * db)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
safe_strcasecmp (const char * da, const char * db)
|
||||
{
|
||||
SAFE_STRCASECMP (da, db);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
null_strcmp (const char * da, const char * db)
|
||||
{
|
||||
|
@ -199,9 +199,9 @@ void gnc_set_logfile (FILE *outfile);
|
||||
#define DEQEPS(x,y,eps) (((((x)+(eps))>(y)) ? 1 : 0) && ((((x)-(eps))<(y)) ? 1 : 0))
|
||||
#define DEQ(x,y) DEQEPS(x,y,EPS)
|
||||
|
||||
#define SAFE_STRCMP(da,db) { \
|
||||
#define SAFE_STRCMP_REAL(fcn,da,db) { \
|
||||
if ((da) && (db)) { \
|
||||
int retval = strcmp ((da), (db)); \
|
||||
int retval = fcn ((da), (db)); \
|
||||
/* if strings differ, return */ \
|
||||
if (retval) return retval; \
|
||||
} else \
|
||||
@ -213,6 +213,9 @@ void gnc_set_logfile (FILE *outfile);
|
||||
} \
|
||||
}
|
||||
|
||||
#define SAFE_STRCMP(da,db) SAFE_STRCMP_REAL(strcmp,(da),(db))
|
||||
#define SAFE_STRCASECMP(da,db) SAFE_STRCMP_REAL(strcasecmp,(da),(db))
|
||||
|
||||
/* Define the long long int conversion for scanf */
|
||||
#if HAVE_SCANF_LLD
|
||||
# define GNC_SCANF_LLD "%lld"
|
||||
@ -228,6 +231,7 @@ void gnc_set_logfile (FILE *outfile);
|
||||
* a non-null string is always greater than a null string.
|
||||
*/
|
||||
int safe_strcmp (const char * da, const char * db);
|
||||
int safe_strcasecmp (const char * da, const char * db);
|
||||
|
||||
/* The null_strcmp compares strings a and b the same way that strcmp()
|
||||
* does, except that either may be null. This routine assumes that
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include <glib.h>
|
||||
|
||||
#include "GNCIdP.h"
|
||||
#include "QueryNewP.h"
|
||||
#include "gncObjectP.h"
|
||||
#include "gnc-engine.h"
|
||||
|
||||
static GList * engine_init_hooks = NULL;
|
||||
@ -70,6 +72,8 @@ gnc_engine_init(int argc, char ** argv)
|
||||
gnc_engine_get_string_cache();
|
||||
|
||||
xaccGUIDInit ();
|
||||
gncObjectInitialize ();
|
||||
gncQueryNewInit ();
|
||||
|
||||
/* call any engine hooks */
|
||||
for (cur = engine_init_hooks; cur; cur = cur->next)
|
||||
@ -102,9 +106,12 @@ gnc_engine_get_string_cache(void)
|
||||
void
|
||||
gnc_engine_shutdown (void)
|
||||
{
|
||||
gncQueryNewShutdown ();
|
||||
|
||||
g_cache_destroy (gnc_string_cache);
|
||||
gnc_string_cache = NULL;
|
||||
|
||||
gncObjectShutdown ();
|
||||
xaccGUIDShutdown ();
|
||||
}
|
||||
|
||||
|
153
src/engine/gncObject.c
Normal file
153
src/engine/gncObject.c
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* gncObject.c -- the Core Object Object Registry
|
||||
* Copyright (C) 2001 Derek Atkins
|
||||
* Author: Derek Atkins <warlord@MIT.EDU>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "messages.h"
|
||||
#include "gnc-engine-util.h"
|
||||
|
||||
#include "gncObjectP.h"
|
||||
|
||||
static gboolean object_is_initialized = FALSE;
|
||||
static GList *object_modules = NULL;
|
||||
static GList *book_list = NULL;
|
||||
|
||||
void gncObjectBookBegin (GNCBook *book)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
if (!book) return;
|
||||
for (l = object_modules; l; l = l->next) {
|
||||
GncObject_t *obj = l->data;
|
||||
if (obj->book_begin)
|
||||
obj->book_begin (book);
|
||||
}
|
||||
|
||||
/* Remember this book for later */
|
||||
book_list = g_list_prepend (book_list, book);
|
||||
}
|
||||
|
||||
void gncObjectBookEnd (GNCBook *book)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
if (!book) return;
|
||||
for (l = object_modules; l; l = l->next) {
|
||||
GncObject_t *obj = l->data;
|
||||
if (obj->book_end)
|
||||
obj->book_end (book);
|
||||
}
|
||||
|
||||
/* Remove it from the list */
|
||||
book_list = g_list_remove (book_list, book);
|
||||
}
|
||||
|
||||
void gncObjectForeach (GNCIdTypeConst type_name, GNCBook *book,
|
||||
foreachObjectCB cb, gpointer user_data)
|
||||
{
|
||||
const GncObject_t *obj;
|
||||
|
||||
if (!book || !type_name) return;
|
||||
|
||||
obj = gncObjectLookup (type_name);
|
||||
if (!obj) return;
|
||||
|
||||
if (obj->foreach)
|
||||
return (obj->foreach (book, cb, user_data));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const char *
|
||||
gncObjectPrintable (GNCIdTypeConst type_name, gpointer obj)
|
||||
{
|
||||
const GncObject_t *b_obj;
|
||||
|
||||
if (!type_name || !obj) return NULL;
|
||||
|
||||
b_obj = gncObjectLookup (type_name);
|
||||
if (!b_obj) return NULL;
|
||||
|
||||
if (b_obj->printable)
|
||||
return (b_obj->printable (obj));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char * gncObjectGetTypeLabel (GNCIdTypeConst type_name)
|
||||
{
|
||||
const GncObject_t *obj;
|
||||
|
||||
if (!type_name) return NULL;
|
||||
|
||||
obj = gncObjectLookup (type_name);
|
||||
if (!obj) return NULL;
|
||||
|
||||
return _(obj->type_label);
|
||||
}
|
||||
|
||||
/* INITIALIZATION and PRIVATE FUNCTIONS */
|
||||
|
||||
void gncObjectInitialize (void)
|
||||
{
|
||||
if (object_is_initialized) return;
|
||||
object_is_initialized = TRUE;
|
||||
}
|
||||
|
||||
void gncObjectShutdown (void)
|
||||
{
|
||||
g_return_if_fail (object_is_initialized == TRUE);
|
||||
g_list_free (object_modules);
|
||||
object_modules = NULL;
|
||||
g_list_free (book_list);
|
||||
book_list = NULL;
|
||||
object_is_initialized = FALSE;
|
||||
}
|
||||
|
||||
/* Register new types of object objects.
|
||||
* Return TRUE if successful,
|
||||
* return FALSE if it fails, invalid arguments, or if the object
|
||||
* already exists
|
||||
*/
|
||||
gboolean gncObjectRegister (const GncObject_t *object)
|
||||
{
|
||||
if (!object) return FALSE;
|
||||
if (object->version != GNC_OBJECT_VERSION) return FALSE;
|
||||
if (!object_is_initialized) return FALSE;
|
||||
|
||||
if (g_list_index (object_modules, (gpointer)object) == -1)
|
||||
object_modules = g_list_prepend (object_modules, (gpointer)object);
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
/* Now initialize all the known books */
|
||||
if (object->book_begin && book_list) {
|
||||
GList *node;
|
||||
for (node = book_list; node; node = node->next)
|
||||
object->book_begin (node->data);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const GncObject_t * gncObjectLookup (GNCIdTypeConst name)
|
||||
{
|
||||
GList *iter;
|
||||
const GncObject_t *obj;
|
||||
|
||||
g_return_val_if_fail (object_is_initialized, NULL);
|
||||
|
||||
if (!name) return NULL;
|
||||
|
||||
for (iter = object_modules; iter; iter = iter->next) {
|
||||
obj = iter->data;
|
||||
if (!safe_strcmp (obj->name, name))
|
||||
return obj;
|
||||
}
|
||||
return NULL;
|
||||
}
|
62
src/engine/gncObject.h
Normal file
62
src/engine/gncObject.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* gncObject.h -- the Core Object Registration/Lookup Interface
|
||||
* Copyright (C) 2001,2002 Derek Atkins
|
||||
* Author: Derek Atkins <warlord@MIT.EDU>
|
||||
*/
|
||||
|
||||
#ifndef GNC_OBJECT_H_
|
||||
#define GNC_OBJECT_H_
|
||||
|
||||
#include "gnc-book.h"
|
||||
#include "GNCId.h"
|
||||
|
||||
/* Defines the version of the core object object registration
|
||||
* interface. Only object modules compiled against this version
|
||||
* of the interface will load properly
|
||||
*/
|
||||
#define GNC_OBJECT_VERSION 1
|
||||
|
||||
typedef void (*foreachObjectCB) (gpointer object, gpointer user_data);
|
||||
|
||||
/* This is the Object Object descriptor */
|
||||
typedef struct _gncObjectDef {
|
||||
gint version; /* of the object interface */
|
||||
GNCIdType name; /* the Object's GNC_ID */
|
||||
const char * type_label; /* "Printable" type-label string */
|
||||
|
||||
/* book_begin is called from within the Book routines to create
|
||||
* module-specific hooks in a book whenever a book is created.
|
||||
* book_end is called when the book is being closed, to clean
|
||||
* up (and free memory).
|
||||
*/
|
||||
void (*book_begin)(GNCBook *);
|
||||
void (*book_end)(GNCBook *);
|
||||
|
||||
/* foreach() is used to execute a callback over each object
|
||||
* stored in the particular book
|
||||
*/
|
||||
void (*foreach)(GNCBook *, foreachObjectCB, gpointer);
|
||||
|
||||
/* Given a particular object, return a printable string */
|
||||
const char * (*printable)(gpointer obj);
|
||||
} GncObject_t;
|
||||
|
||||
void gncObjectForeach (GNCIdTypeConst type_name, GNCBook *book,
|
||||
foreachObjectCB cb, gpointer user_data);
|
||||
|
||||
const char * gncObjectPrintable (GNCIdTypeConst type_name, gpointer obj);
|
||||
|
||||
|
||||
/* REGISTRATION AND REG-LOOKUP FUNCTIONS */
|
||||
|
||||
/* Register new types of object objects */
|
||||
gboolean gncObjectRegister (const GncObject_t *object);
|
||||
|
||||
/* Get the printable label for a type */
|
||||
const char * gncObjectGetTypeLabel (GNCIdTypeConst type_name);
|
||||
|
||||
/* Lookup a object definition */
|
||||
const GncObject_t * gncObjectLookup (GNCIdTypeConst type_name);
|
||||
|
||||
|
||||
#endif /* GNC_OBJECT_H_ */
|
21
src/engine/gncObjectP.h
Normal file
21
src/engine/gncObjectP.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* gncObjectP.h -- the Core Object Registration Interface
|
||||
* Copyright (C) 2001, 2002 Derek Atkins
|
||||
* Author: Derek Atkins <warlord@MIT.EDU>
|
||||
*/
|
||||
|
||||
#ifndef GNC_OBJECTP_H_
|
||||
#define GNC_OBJECTP_H_
|
||||
|
||||
#include "gncObject.h"
|
||||
|
||||
/* Initialize the object registration subsystem */
|
||||
void gncObjectInitialize (void);
|
||||
void gncObjectShutdown (void);
|
||||
|
||||
/* To be called from within the book */
|
||||
void gncObjectBookBegin (GNCBook *book);
|
||||
void gncObjectBookEnd (GNCBook *book);
|
||||
|
||||
|
||||
#endif /* GNC_OBJECTP_H_ */
|
@ -23,6 +23,7 @@ TESTS = \
|
||||
test-commodities \
|
||||
test-date \
|
||||
test-group-vs-book \
|
||||
test-object \
|
||||
test-period \
|
||||
test-query \
|
||||
test-resolve-file-path \
|
||||
@ -45,6 +46,7 @@ noinst_PROGRAMS = \
|
||||
test-freq-spec \
|
||||
test-group-vs-book \
|
||||
test-load-engine \
|
||||
test-object \
|
||||
test-period \
|
||||
test-query \
|
||||
test-resolve-file-path \
|
||||
|
132
src/engine/test/test-object.c
Normal file
132
src/engine/test/test-object.c
Normal file
@ -0,0 +1,132 @@
|
||||
#include <glib.h>
|
||||
#include <guile/gh.h>
|
||||
|
||||
#include "guid.h"
|
||||
#include "gnc-module.h"
|
||||
#include "gnc-engine-util.h"
|
||||
#include "messages.h"
|
||||
|
||||
#include "gncObject.h"
|
||||
#include "test-stuff.h"
|
||||
|
||||
#define TEST_MODULE_NAME "object-test"
|
||||
#define TEST_MODULE_DESC "Test Object"
|
||||
|
||||
static void foreach (GNCBook *, foreachObjectCB, gpointer);
|
||||
static const char * printable (gpointer obj);
|
||||
static void test_printable (const char *name, gpointer obj);
|
||||
static void test_foreach (GNCBook *, const char *);
|
||||
|
||||
static GncObject_t bus_obj = {
|
||||
GNC_OBJECT_VERSION,
|
||||
TEST_MODULE_NAME,
|
||||
TEST_MODULE_DESC,
|
||||
NULL, /* create */
|
||||
NULL, /* destroy */
|
||||
foreach,
|
||||
printable,
|
||||
};
|
||||
|
||||
static void test_object (void)
|
||||
{
|
||||
/* Test the global registration and lookup functions */
|
||||
{
|
||||
do_test (!gncObjectRegister (NULL), "register NULL");
|
||||
do_test (gncObjectRegister (&bus_obj), "register test object");
|
||||
do_test (!gncObjectRegister (&bus_obj), "register test object again");
|
||||
do_test (gncObjectLookup (TEST_MODULE_NAME) == &bus_obj,
|
||||
"lookup our installed object");
|
||||
do_test (gncObjectLookup ("snm98sn snml say dyikh9y9ha") == NULL,
|
||||
"lookup non-existant object object");
|
||||
|
||||
do_test (!safe_strcmp (gncObjectGetTypeLabel (TEST_MODULE_NAME),
|
||||
_(TEST_MODULE_DESC)),
|
||||
"test description return");
|
||||
}
|
||||
|
||||
test_foreach ((GNCBook*)1, TEST_MODULE_NAME);
|
||||
test_printable (TEST_MODULE_NAME, (gpointer)1);
|
||||
}
|
||||
|
||||
static void
|
||||
foreach (GNCBook *book, foreachObjectCB cb, gpointer u_d)
|
||||
{
|
||||
int *foo = u_d;
|
||||
|
||||
do_test (book != NULL, "foreach: NULL object");
|
||||
success ("called foreach callback");
|
||||
|
||||
*foo = 1;
|
||||
}
|
||||
|
||||
static void foreachCB (gpointer obj, gpointer u_d)
|
||||
{
|
||||
do_test (FALSE, "FAIL");
|
||||
}
|
||||
|
||||
static const char *
|
||||
printable (gpointer obj)
|
||||
{
|
||||
do_test (obj != NULL, "printable: object is NULL");
|
||||
success ("called printable callback");
|
||||
return ((const char *)obj);
|
||||
}
|
||||
|
||||
static void
|
||||
test_foreach (GNCBook *book, const char *name)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
gncObjectForeach (NULL, NULL, NULL, &res);
|
||||
do_test (res == 0, "object: Foreach: NULL, NULL, NULL");
|
||||
gncObjectForeach (NULL, NULL, foreachCB, &res);
|
||||
do_test (res == 0, "object: Foreach: NULL, NULL, foreachCB");
|
||||
|
||||
gncObjectForeach (NULL, book, NULL, &res);
|
||||
do_test (res == 0, "object: Foreach: NULL, book, NULL");
|
||||
gncObjectForeach (NULL, book, foreachCB, &res);
|
||||
do_test (res == 0, "object: Foreach: NULL, book, foreachCB");
|
||||
|
||||
gncObjectForeach (name, NULL, NULL, &res);
|
||||
do_test (res == 0, "object: Foreach: name, NULL, NULL");
|
||||
gncObjectForeach (name, NULL, foreachCB, &res);
|
||||
do_test (res == 0, "object: Foreach: name, NULL, foreachCB");
|
||||
|
||||
gncObjectForeach (name, book, NULL, &res);
|
||||
do_test (res != 0, "object: Foreach: name, book, NULL");
|
||||
|
||||
res = 0;
|
||||
gncObjectForeach (name, book, foreachCB, &res);
|
||||
do_test (res != 0, "object: Foreach: name, book, foreachCB");
|
||||
}
|
||||
|
||||
static void
|
||||
test_printable (const char *name, gpointer obj)
|
||||
{
|
||||
const char *res;
|
||||
|
||||
do_test (gncObjectPrintable (NULL, NULL) == NULL,
|
||||
"object: Printable: NULL, NULL");
|
||||
do_test (gncObjectPrintable (NULL, obj) == NULL,
|
||||
"object: Printable: NULL, object");
|
||||
do_test (gncObjectPrintable (name, NULL) == NULL,
|
||||
"object: Printable: mod_name, NULL");
|
||||
res = gncObjectPrintable (name, obj);
|
||||
do_test (res != NULL, "object: Printable: mod_name, object");
|
||||
}
|
||||
|
||||
static void
|
||||
main_helper (int argc, char **argv)
|
||||
{
|
||||
gnc_module_load("gnucash/engine", 0);
|
||||
test_object();
|
||||
print_test_results();
|
||||
exit(get_rv());
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gh_enter (argc, argv, main_helper);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user