gnucash/libgnucash/engine/qofobject.cpp
2023-02-16 09:20:59 +00:00

341 lines
8.3 KiB
C++

/********************************************************************\
* qofobject.c -- the Core Object Registration/Lookup Interface *
* 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 *
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
* Boston, MA 02110-1301, USA gnu@gnu.org *
* *
\********************************************************************/
/*
* qofobject.c -- the Core Object Object Registry
* Copyright (C) 2001 Derek Atkins
* Author: Derek Atkins <warlord@MIT.EDU>
*/
#include <config.h>
#include <glib.h>
#include "qof.h"
#include "qofobject-p.h"
static QofLogModule log_module = QOF_MOD_OBJECT;
static gboolean object_is_initialized = FALSE;
static GList *object_modules = NULL;
static GList *book_list = NULL;
/*
* These getters are used in tests to reach static vars from outside
* They should be removed when no longer needed
*/
extern "C"
{
GList* get_object_modules( void );
GList* get_book_list( void );
}
GList*
get_object_modules( void )
{
return object_modules;
}
GList*
get_book_list( void )
{
return book_list;
}
/*********/
gpointer
qof_object_new_instance (QofIdTypeConst type_name, QofBook *book)
{
const QofObject *obj;
if (!type_name) return NULL;
obj = qof_object_lookup (type_name);
if (!obj) return NULL;
if (obj->create)
return (obj->create (book));
return NULL;
}
void qof_object_book_begin (QofBook *book)
{
GList *l;
if (!book) return;
ENTER (" ");
for (l = object_modules; l; l = l->next)
{
QofObject *obj = static_cast<QofObject*>(l->data);
if (obj->book_begin)
obj->book_begin (book);
}
/* Remember this book for later */
book_list = g_list_prepend (book_list, book);
LEAVE (" ");
}
void qof_object_book_end (QofBook *book)
{
GList *l;
if (!book) return;
ENTER (" ");
for (l = object_modules; l; l = l->next)
{
QofObject *obj = static_cast<QofObject*>(l->data);
if (obj->book_end)
obj->book_end (book);
}
/* Remove it from the list */
book_list = g_list_remove (book_list, book);
LEAVE (" ");
}
gboolean
qof_object_is_dirty (const QofBook *book)
{
GList *l;
if (!book) return FALSE;
for (l = object_modules; l; l = l->next)
{
QofObject *obj = static_cast<QofObject*>(l->data);
if (obj->is_dirty)
{
QofCollection *col;
col = qof_book_get_collection (book, obj->e_type);
if (obj->is_dirty (col)) return TRUE;
}
}
return FALSE;
}
void
qof_object_mark_clean (QofBook *book)
{
GList *l;
if (!book) return;
for (l = object_modules; l; l = l->next)
{
QofObject *obj = static_cast<QofObject*>(l->data);
if (obj->mark_clean)
{
QofCollection *col;
col = qof_book_get_collection (book, obj->e_type);
(obj->mark_clean) (col);
}
}
}
void qof_object_foreach_type (QofForeachTypeCB cb, gpointer user_data)
{
GList *l;
if (!cb) return;
for (l = object_modules; l; l = l->next)
{
QofObject *obj = static_cast<QofObject*>(l->data);
(cb) (obj, user_data);
}
}
gboolean
qof_object_compliance (QofIdTypeConst type_name, gboolean warn)
{
const QofObject *obj;
obj = qof_object_lookup(type_name);
if ((obj->create == NULL) || (obj->foreach == NULL))
{
if (warn)
{
PINFO (" Object type %s is not fully QOF compliant", obj->e_type);
}
return FALSE;
}
return TRUE;
}
void
qof_object_foreach (QofIdTypeConst type_name, QofBook *book,
QofInstanceForeachCB cb, gpointer user_data)
{
QofCollection *col;
const QofObject *obj;
if (!book || !type_name)
{
return;
}
PINFO ("type=%s", type_name);
obj = qof_object_lookup (type_name);
if (!obj)
{
PERR ("No object of type %s", type_name);
return;
}
col = qof_book_get_collection (book, obj->e_type);
if (!obj)
{
return;
}
if (obj->foreach)
{
obj->foreach (col, cb, user_data);
}
return;
}
static void
do_prepend (QofInstance *qof_p, gpointer list_p)
{
GList **list = static_cast<GList**>(list_p);
*list = g_list_prepend(*list, qof_p);
}
void
qof_object_foreach_sorted (QofIdTypeConst type_name, QofBook *book, QofInstanceForeachCB cb, gpointer user_data)
{
GList *list = NULL;
GList *iter;
qof_object_foreach(type_name, book, do_prepend, &list);
list = g_list_sort(list, qof_instance_guid_compare);
for (iter = list; iter; iter = iter->next)
{
cb(static_cast<QofInstance*>(iter->data), user_data);
}
g_list_free(list);
// FIXME: Apparently this is a memory leak, as this g_list_free doesn't
// free all of the allocated memory of g_list_append in do_append(). Why?!?
// Does g_list_sort have special side-effects on the memory of the list?
// Subsequently, I've changed the g_list_append into g_list_prepend, but
// solely for performance reasons. To my surprise, this also makes the
// dubious memory leak go away. But again why?!?
}
const char *
qof_object_printable (QofIdTypeConst type_name, gpointer obj)
{
const QofObject *b_obj;
if (!type_name || !obj) return NULL;
b_obj = qof_object_lookup (type_name);
if (!b_obj) return NULL;
if (b_obj->printable)
return (b_obj->printable (obj));
return NULL;
}
const char * qof_object_get_type_label (QofIdTypeConst type_name)
{
const QofObject *obj;
if (!type_name) return NULL;
obj = qof_object_lookup (type_name);
if (!obj) return NULL;
return (obj->type_label);
}
/* INITIALIZATION and PRIVATE FUNCTIONS */
void qof_object_initialize (void)
{
if (object_is_initialized) return;
object_is_initialized = TRUE;
}
void qof_object_shutdown (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 qof_object_register (const QofObject *object)
{
g_return_val_if_fail (object_is_initialized, FALSE);
if (!object) return FALSE;
g_return_val_if_fail (object->interface_version == QOF_OBJECT_VERSION, 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 (static_cast<QofBook*>(node->data));
}
return TRUE;
}
const QofObject * qof_object_lookup (QofIdTypeConst name)
{
GList *iter;
const QofObject *obj;
g_return_val_if_fail (object_is_initialized, NULL);
if (!name) return NULL;
for (iter = object_modules; iter; iter = iter->next)
{
obj = static_cast<QofObject*>(iter->data);
if (!g_strcmp0 (obj->e_type, name))
return obj;
}
return NULL;
}
/* ========================= END OF FILE =================== */