From f450305ca26298914c4c66ba08009a7ba4770f15 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Mon, 19 Apr 2004 03:35:52 +0000 Subject: [PATCH] QOF to GObject glue code. Not currently built or used by GnuCash; checked in here to keep gnucash in sync with qof files. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@9899 57a11ea4-9604-0410-9ed3-97b8803252fd --- src/engine/qofgobj.c | 309 +++++++++++++++++++++++++++++++++++++++++++ src/engine/qofgobj.h | 82 ++++++++++++ 2 files changed, 391 insertions(+) create mode 100644 src/engine/qofgobj.c create mode 100644 src/engine/qofgobj.h diff --git a/src/engine/qofgobj.c b/src/engine/qofgobj.c new file mode 100644 index 0000000000..cad921a202 --- /dev/null +++ b/src/engine/qofgobj.c @@ -0,0 +1,309 @@ +/********************************************************************\ + * qofgobj.c -- QOF to GLib GObject mapping * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 59 Temple Place - Suite 330 Fax: +1-617-542-2652 * + * Boston, MA 02111-1307, USA gnu@gnu.org * + * * +\********************************************************************/ + +#include +#include +#include + +static short module = MOD_QUERY; + +static gboolean initialized = FALSE; +static GSList *paramList = NULL; +static GSList *classList = NULL; + +/* =================================================================== */ + +#if 0 +static gboolean +clear_table (gpointer key, gpointer value, gpointer user_data) +{ + g_slist_free (value); + return TRUE; +} +#endif + +void +qof_gobject_init(void) +{ + if (initialized) return; + initialized = TRUE; + + // gobjectClassTable = g_hash_table_new (g_str_hash, g_str_equal); + + /* Init the other subsystems that we need */ + qof_object_initialize(); + qof_query_init (); +} + +void +qof_gobject_shutdown (void) +{ + if (!initialized) return; + initialized = FALSE; + + GSList *n; + for (n=paramList; n; n=n->next) g_free(n->data); + g_slist_free (paramList); + + for (n=classList; n; n=n->next) g_free(n->data); + g_slist_free (classList); + +#if 0 + // XXX also need to walk over books, and collection and delete + // the collection get_data instance lists !! + // without this we have a memory leak !! + g_hash_table_foreach_remove (gobjectParamTable, clear_table, NULL); + g_hash_table_destroy (gobjectParamTable); +#endif +} + +/* =================================================================== */ + +#define GOBJECT_TABLE "GobjectTable" + +void +qof_gobject_register_instance (QofBook *book, QofType type, GObject *gob) +{ + if (!book || !type) return; + + QofCollection *coll = qof_book_get_collection (book, type); + + GSList * instance_list = qof_collection_get_data (coll); + instance_list = g_slist_prepend (instance_list, gob); + qof_collection_set_data (coll, instance_list); +} + +/* =================================================================== */ + +static gpointer +qof_gobject_getter (gpointer data, QofParam *getter) +{ + GObject *gob = data; + + GParamSpec *gps = getter->param_userdata; + + /* Note that the return type must actually be of type + * getter->param_type but we just follow the hard-coded + * mapping below ... */ + if (G_IS_PARAM_SPEC_STRING(gps)) + { + GValue gval = {G_TYPE_INVALID}; + g_value_init (&gval, G_TYPE_STRING); + g_object_get_property (gob, getter->param_name, &gval); + + const char * str = g_value_get_string (&gval); + return (gpointer) str; + } + else + if (G_IS_PARAM_SPEC_INT(gps)) + { + GValue gval = {G_TYPE_INVALID}; + g_value_init (&gval, G_TYPE_INT); + g_object_get_property (gob, getter->param_name, &gval); + + int ival = g_value_get_int (&gval); + return (gpointer) ival; + } + else + if (G_IS_PARAM_SPEC_UINT(gps)) + { + GValue gval = {G_TYPE_INVALID}; + g_value_init (&gval, G_TYPE_UINT); + g_object_get_property (gob, getter->param_name, &gval); + + int ival = g_value_get_uint (&gval); + return (gpointer) ival; + } + else + if (G_IS_PARAM_SPEC_BOOLEAN(gps)) + { + GValue gval = {G_TYPE_INVALID}; + g_value_init (&gval, G_TYPE_BOOLEAN); + g_object_get_property (gob, getter->param_name, &gval); + + int ival = g_value_get_boolean (&gval); + return (gpointer) ival; + } + + PWARN ("unhandled parameter type %s for paramter %s", + G_PARAM_SPEC_TYPE_NAME(gps), getter->param_name); + return NULL; +} + +static double +qof_gobject_double_getter (gpointer data, QofParam *getter) +{ + GObject *gob = data; + + GParamSpec *gps = getter->param_userdata; + + /* Note that the return type must actually be of type + * getter->param_type but we just follow the hard-coded + * mapping below ... */ + if (G_IS_PARAM_SPEC_FLOAT(gps)) + { + GValue gval = {G_TYPE_INVALID}; + g_value_init (&gval, G_TYPE_FLOAT); + g_object_get_property (gob, getter->param_name, &gval); + + double fval = g_value_get_float (&gval); + return fval; + } + else + if (G_IS_PARAM_SPEC_DOUBLE(gps)) + { + GValue gval = {G_TYPE_INVALID}; + g_value_init (&gval, G_TYPE_DOUBLE); + g_object_get_property (gob, getter->param_name, &gval); + + double fval = g_value_get_double (&gval); + return fval; + } + + PWARN ("unhandled parameter type %s for paramter %s", + G_PARAM_SPEC_TYPE_NAME(gps), getter->param_name); + return 0.0; +} + +/* =================================================================== */ +/* Loop over every instance of the given type in the collection + * of instances that we have on hand. + */ +static void +qof_gobject_foreach (QofCollection *coll, QofEntityForeachCB cb, gpointer ud) +{ + GSList *n; + n = qof_collection_get_data (coll); + for (; n; n=n->next) + { + cb (n->data, ud); + } +} + +/* =================================================================== */ + +void +qof_gobject_register (QofType e_type, GObjectClass *obclass) +{ + + /* Get the GObject properties, convert to QOF properties */ + GParamSpec **prop_list; + int n_props; + prop_list = g_object_class_list_properties (obclass, &n_props); + + QofParam * qof_param_list = g_new0 (QofParam, n_props); + paramList = g_slist_prepend (paramList, qof_param_list); + + PINFO ("object %s has %d props", e_type, n_props); + int i, j=0; + for (i=0; iname, G_PARAM_SPEC_TYPE_NAME(gparam)); + + qpar->param_name = g_param_spec_get_name (gparam); + qpar->param_getfcn = qof_gobject_getter; + qpar->param_setfcn = NULL; + qpar->param_userdata = gparam; + if ((G_IS_PARAM_SPEC_INT(gparam)) || + (G_IS_PARAM_SPEC_UINT(gparam)) || + (G_IS_PARAM_SPEC_ENUM(gparam)) || + (G_IS_PARAM_SPEC_FLAGS(gparam))) + { + qpar->param_type = QOF_TYPE_INT32; + j++; + } + else + if ((G_IS_PARAM_SPEC_INT64(gparam)) || + (G_IS_PARAM_SPEC_UINT64(gparam))) + { + qpar->param_type = QOF_TYPE_INT64; + j++; + } + else + if (G_IS_PARAM_SPEC_BOOLEAN(gparam)) + { + qpar->param_type = QOF_TYPE_BOOLEAN; + j++; + } + else + if (G_IS_PARAM_SPEC_STRING(gparam)) + { + qpar->param_type = QOF_TYPE_STRING; + j++; + } + else + if ((G_IS_PARAM_SPEC_POINTER(gparam)) || + (G_IS_PARAM_SPEC_OBJECT(gparam))) + { + /* No-op, silently ignore. Someday we should handle this ... */ + } + else + if ((G_IS_PARAM_SPEC_FLOAT(gparam)) || + (G_IS_PARAM_SPEC_DOUBLE(gparam))) + { + qpar->param_getfcn = (QofAccessFunc) qof_gobject_double_getter; + qpar->param_type = QOF_TYPE_DOUBLE; + j++; + } + else + if (G_IS_PARAM_SPEC_CHAR(gparam)) + { + qpar->param_type = QOF_TYPE_CHAR; + j++; + } + else + { + PWARN ("Unknown/unhandled parameter type %s on %s:%s\n", + G_PARAM_SPEC_TYPE_NAME(gparam), e_type, qpar->param_name); + } + } + + /* NULL-terminated list! */ + qof_param_list[j].param_type = NULL; + + qof_class_register (e_type, NULL, qof_param_list); + + /* ------------------------------------------------------ */ + /* Now do the class itself */ + QofObject *class_def = g_new0 (QofObject, 1); + classList = g_slist_prepend (classList, class_def); + + class_def->interface_version = QOF_OBJECT_VERSION; + class_def->e_type = e_type; + /* We could let the user specify a "nick" here, but + * the actual class name seems reasonable, e.g. for debugging. */ + class_def->type_label = G_OBJECT_CLASS_NAME (obclass); + class_def->book_begin = NULL; + class_def->book_end = NULL; + class_def->is_dirty = NULL; + class_def->mark_clean = NULL; + class_def->foreach = qof_gobject_foreach; + class_def->printable = NULL; + + qof_object_register (class_def); +} + +/* ======================= END OF FILE ================================ */ diff --git a/src/engine/qofgobj.h b/src/engine/qofgobj.h new file mode 100644 index 0000000000..51833191bd --- /dev/null +++ b/src/engine/qofgobj.h @@ -0,0 +1,82 @@ +/********************************************************************\ + * qofgobj.h -- QOF to GLib GObject mapping * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 59 Temple Place - Suite 330 Fax: +1-617-542-2652 * + * Boston, MA 02111-1307, USA gnu@gnu.org * + * * +\********************************************************************/ + +#ifndef QOF_GOBJ_H +#define QOF_GOBJ_H + +/** @addtogroup Engine + @{ */ +/** @file qofgobj.h + @brief QOF to GLib GObject mapping + @author Copyright (C) 2004 Linas Vepstas +*/ + +/** The API defined in this file allows a user to register any + * GLib GObject (and any object derived from one, e.g. GTK/Gnome) + * with the QOF system so that it becomes searchable. + * + * XXX Only GObject properties are searchable, data and other + * hanging off the GObject is not. Fix this. + */ + +#include +#include +#include + +/** Initalize and shut down this subsystem. */ +void qof_gobject_init(void); +void qof_gobject_shutdown (void); + +/** Register a GObject class with the QOF subsystem. + * Doing this will make the properties associated with + * this GObject searchable using the QOF subsystem. + * + * The QofType can be any string you desire, although typically + * you might want to set it to G_OBJECT_CLASS_NAME() of the + * object class. Note that this type will become the name of + * the "table" that is searched by SQL queries: + * e.g. in order to be able to say "SELECT * FROM MyStuff;" + * you must first say: + * qof_gobject_register ("MyStuff", gobj_class); + */ +void qof_gobject_register (QofType type, GObjectClass *obclass); + +/** Register an instance of a GObject with the QOF subsystem. + * + * The QofType can be any string you desire, although typically + * you might want to set it to G_OBJECT_CLASS_NAME() of the + * object class. Note that this type will become the name of + * the "table" that is searched by SQL queries: + * e.g. in order to be able to say "SELECT * FROM MyStuff;" + * you must first say: + * qof_gobject_register_instance (book, "MyStuff", obj); + * + * The 'book' argument specifies an anchor point for the collection + * of all of the registered instances. By working with disjoint books, + * you can have multiple disjoint searchable sets of objects. + */ + +void qof_gobject_register_instance (QofBook *book, QofType, GObject *); + +#endif /* QOF_GOBJ_H */ +/** @} */ +