GnuCash 2.4.99
qofobject.c
00001 /********************************************************************\
00002  * qofobject.c -- the Core Object Registration/Lookup Interface     *
00003  * This program is free software; you can redistribute it and/or    *
00004  * modify it under the terms of the GNU General Public License as   *
00005  * published by the Free Software Foundation; either version 2 of   *
00006  * the License, or (at your option) any later version.              *
00007  *                                                                  *
00008  * This program is distributed in the hope that it will be useful,  *
00009  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00010  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00011  * GNU General Public License for more details.                     *
00012  *                                                                  *
00013  * You should have received a copy of the GNU General Public License*
00014  * along with this program; if not, contact:                        *
00015  *                                                                  *
00016  * Free Software Foundation           Voice:  +1-617-542-5942       *
00017  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00018  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00019  *                                                                  *
00020 \********************************************************************/
00021 /*
00022  * qofobject.c -- the Core Object Object Registry
00023  * Copyright (C) 2001 Derek Atkins
00024  * Author: Derek Atkins <warlord@MIT.EDU>
00025  */
00026 
00027 #include "config.h"
00028 
00029 #include <glib.h>
00030 
00031 #include "qof.h"
00032 #include "qofobject-p.h"
00033 
00034 static QofLogModule log_module = QOF_MOD_OBJECT;
00035 
00036 static gboolean object_is_initialized = FALSE;
00037 static GList *object_modules = NULL;
00038 static GList *book_list = NULL;
00039 static GHashTable *backend_data = NULL;
00040 
00041 /*
00042  * These getters are used in tests to reach static vars from outside
00043  * They should be removed when no longer needed
00044  */
00045 
00046 gboolean get_object_is_initialized( void );
00047 GList* get_object_modules( void );
00048 GList* get_book_list( void );
00049 GHashTable* get_backend_data( void );
00050 
00051 gboolean
00052 get_object_is_initialized( void )
00053 {
00054     return object_is_initialized;
00055 }
00056 
00057 GList*
00058 get_object_modules( void )
00059 {
00060     return object_modules;
00061 }
00062 
00063 GList*
00064 get_book_list( void )
00065 {
00066     return book_list;
00067 }
00068 
00069 GHashTable*
00070 get_backend_data( void )
00071 {
00072     return backend_data;
00073 }
00074 
00075 /*********/
00076 
00077 gpointer
00078 qof_object_new_instance (QofIdTypeConst type_name, QofBook *book)
00079 {
00080     const QofObject *obj;
00081 
00082     if (!type_name) return NULL;
00083 
00084     obj = qof_object_lookup (type_name);
00085     if (!obj) return NULL;
00086 
00087     if (obj->create)
00088         return (obj->create (book));
00089 
00090     return NULL;
00091 }
00092 
00093 void qof_object_book_begin (QofBook *book)
00094 {
00095     GList *l;
00096 
00097     if (!book) return;
00098     ENTER (" ");
00099     for (l = object_modules; l; l = l->next)
00100     {
00101         QofObject *obj = l->data;
00102         if (obj->book_begin)
00103             obj->book_begin (book);
00104     }
00105 
00106     /* Remember this book for later */
00107     book_list = g_list_prepend (book_list, book);
00108     LEAVE (" ");
00109 }
00110 
00111 void qof_object_book_end (QofBook *book)
00112 {
00113     GList *l;
00114 
00115     if (!book) return;
00116     ENTER (" ");
00117     for (l = object_modules; l; l = l->next)
00118     {
00119         QofObject *obj = l->data;
00120         if (obj->book_end)
00121             obj->book_end (book);
00122     }
00123 
00124     /* Remove it from the list */
00125     book_list = g_list_remove (book_list, book);
00126     LEAVE (" ");
00127 }
00128 
00129 gboolean
00130 qof_object_is_dirty (const QofBook *book)
00131 {
00132     GList *l;
00133 
00134     if (!book) return FALSE;
00135     for (l = object_modules; l; l = l->next)
00136     {
00137         QofObject *obj = l->data;
00138         if (obj->is_dirty)
00139         {
00140             QofCollection *col;
00141             col = qof_book_get_collection (book, obj->e_type);
00142             if (obj->is_dirty (col)) return TRUE;
00143         }
00144     }
00145     return FALSE;
00146 }
00147 
00148 void
00149 qof_object_mark_clean (QofBook *book)
00150 {
00151     GList *l;
00152 
00153     if (!book) return;
00154     for (l = object_modules; l; l = l->next)
00155     {
00156         QofObject *obj = l->data;
00157         if (obj->mark_clean)
00158         {
00159             QofCollection *col;
00160             col = qof_book_get_collection (book, obj->e_type);
00161             (obj->mark_clean) (col);
00162         }
00163     }
00164 }
00165 
00166 void qof_object_foreach_type (QofForeachTypeCB cb, gpointer user_data)
00167 {
00168     GList *l;
00169 
00170     if (!cb) return;
00171 
00172     for (l = object_modules; l; l = l->next)
00173     {
00174         QofObject *obj = l->data;
00175         (cb) (obj, user_data);
00176     }
00177 }
00178 
00179 gboolean
00180 qof_object_compliance (QofIdTypeConst type_name, gboolean warn)
00181 {
00182     const QofObject *obj;
00183 
00184     obj = qof_object_lookup(type_name);
00185     if ((obj->create == NULL) || (obj->foreach == NULL))
00186     {
00187         if (warn)
00188         {
00189             PINFO (" Object type %s is not fully QOF compliant", obj->e_type);
00190         }
00191         return FALSE;
00192     }
00193     return TRUE;
00194 }
00195 
00196 
00197 void
00198 qof_object_foreach (QofIdTypeConst type_name, QofBook *book,
00199                     QofInstanceForeachCB cb, gpointer user_data)
00200 {
00201     QofCollection *col;
00202     const QofObject *obj;
00203 
00204     if (!book || !type_name)
00205     {
00206         return;
00207     }
00208     PINFO ("type=%s", type_name);
00209 
00210     obj = qof_object_lookup (type_name);
00211     if (!obj)
00212     {
00213         PERR ("No object of type %s", type_name);
00214         return;
00215     }
00216     col = qof_book_get_collection (book, obj->e_type);
00217     if (!obj)
00218     {
00219         return;
00220     }
00221     if (obj->foreach)
00222     {
00223         obj->foreach (col, cb, user_data);
00224     }
00225     return;
00226 }
00227 
00228 static void
00229 do_prepend (QofInstance *qof_p, gpointer list_p)
00230 {
00231     GList **list = list_p;
00232     *list = g_list_prepend(*list, qof_p);
00233 }
00234 
00235 void
00236 qof_object_foreach_sorted (QofIdTypeConst type_name, QofBook *book, QofInstanceForeachCB cb, gpointer user_data)
00237 {
00238     GList *list = NULL;
00239     GList *iter;
00240 
00241     qof_object_foreach(type_name, book, do_prepend, &list);
00242 
00243     list = g_list_sort(list, qof_instance_guid_compare);
00244 
00245     for (iter = list; iter; iter = iter->next)
00246     {
00247         cb(iter->data, user_data);
00248     }
00249 
00250     g_list_free(list);
00251 
00252     // FIXME: Apparently this is a memory leak, as this g_list_free doesn't
00253     // free all of the allocated memory of g_list_append in do_append(). Why?!?
00254     // Does g_list_sort have special side-effects on the memory of the list?
00255     // Subsequently, I've changed the g_list_append into g_list_prepend, but
00256     // solely for performance reasons. To my surprise, this also makes the
00257     // dubious memory leak go away. But again why?!?
00258 }
00259 
00260 const char *
00261 qof_object_printable (QofIdTypeConst type_name, gpointer obj)
00262 {
00263     const QofObject *b_obj;
00264 
00265     if (!type_name || !obj) return NULL;
00266 
00267     b_obj = qof_object_lookup (type_name);
00268     if (!b_obj) return NULL;
00269 
00270     if (b_obj->printable)
00271         return (b_obj->printable (obj));
00272 
00273     return NULL;
00274 }
00275 
00276 const char * qof_object_get_type_label (QofIdTypeConst type_name)
00277 {
00278     const QofObject *obj;
00279 
00280     if (!type_name) return NULL;
00281 
00282     obj = qof_object_lookup (type_name);
00283     if (!obj) return NULL;
00284 
00285     return (obj->type_label);
00286 }
00287 
00288 static gboolean clear_table (gpointer key, gpointer value, gpointer user_data)
00289 {
00290     g_hash_table_destroy (value);
00291     return TRUE;
00292 }
00293 
00294 /* INITIALIZATION and PRIVATE FUNCTIONS */
00295 
00296 void qof_object_initialize (void)
00297 {
00298     if (object_is_initialized) return;
00299     backend_data = g_hash_table_new (g_str_hash, g_str_equal);
00300     object_is_initialized = TRUE;
00301 }
00302 
00303 void qof_object_shutdown (void)
00304 {
00305     g_return_if_fail (object_is_initialized == TRUE);
00306 
00307     g_hash_table_foreach_remove (backend_data, clear_table, NULL);
00308     g_hash_table_destroy (backend_data);
00309     backend_data = NULL;
00310 
00311     g_list_free (object_modules);
00312     object_modules = NULL;
00313     g_list_free (book_list);
00314     book_list = NULL;
00315     object_is_initialized = FALSE;
00316 }
00317 
00318 /* Register new types of object objects.
00319  * Return TRUE if successful,
00320  * return FALSE if it fails, invalid arguments, or if the object
00321  * already exists
00322  */
00323 gboolean qof_object_register (const QofObject *object)
00324 {
00325     g_return_val_if_fail (object_is_initialized, FALSE);
00326 
00327     if (!object) return FALSE;
00328     g_return_val_if_fail (object->interface_version == QOF_OBJECT_VERSION, FALSE);
00329 
00330     if (g_list_index (object_modules, (gpointer)object) == -1)
00331         object_modules = g_list_prepend (object_modules, (gpointer)object);
00332     else
00333         return FALSE;
00334 
00335     /* Now initialize all the known books */
00336     if (object->book_begin && book_list)
00337     {
00338         GList *node;
00339         for (node = book_list; node; node = node->next)
00340             object->book_begin (node->data);
00341     }
00342 
00343     return TRUE;
00344 }
00345 
00346 const QofObject * qof_object_lookup (QofIdTypeConst name)
00347 {
00348     GList *iter;
00349     const QofObject *obj;
00350 
00351     g_return_val_if_fail (object_is_initialized, NULL);
00352 
00353     if (!name) return NULL;
00354 
00355     for (iter = object_modules; iter; iter = iter->next)
00356     {
00357         obj = iter->data;
00358         if (!safe_strcmp (obj->e_type, name))
00359             return obj;
00360     }
00361     return NULL;
00362 }
00363 
00364 gboolean qof_object_register_backend (QofIdTypeConst type_name,
00365                                       const char *backend_name,
00366                                       gpointer be_data)
00367 {
00368     GHashTable *ht;
00369     g_return_val_if_fail (object_is_initialized, FALSE);
00370 
00371     if (!type_name || *type_name == '\0' ||
00372             !backend_name || *backend_name == '\0' ||
00373             !be_data)
00374         return FALSE;
00375 
00376     ht = g_hash_table_lookup (backend_data, backend_name);
00377 
00378     /* If it doesn't already exist, create a new table for this backend */
00379     if (!ht)
00380     {
00381         ht = g_hash_table_new (g_str_hash, g_str_equal);
00382         g_hash_table_insert (backend_data, (char *)backend_name, ht);
00383     }
00384 
00385     /* Now insert the data */
00386     g_hash_table_insert (ht, (char *)type_name, be_data);
00387 
00388     return TRUE;
00389 }
00390 
00391 gpointer qof_object_lookup_backend (QofIdTypeConst type_name,
00392                                     const char *backend_name)
00393 {
00394     GHashTable *ht;
00395 
00396     if (!type_name || *type_name == '\0' ||
00397             !backend_name || *backend_name == '\0')
00398         return NULL;
00399 
00400     ht = g_hash_table_lookup (backend_data, (char *)backend_name);
00401     if (!ht)
00402         return NULL;
00403 
00404     return g_hash_table_lookup (ht, (char *)type_name);
00405 }
00406 
00407 struct foreach_data
00408 {
00409     QofForeachBackendTypeCB        cb;
00410     gpointer                 user_data;
00411 };
00412 
00413 static void foreach_backend (gpointer key, gpointer be_item, gpointer arg)
00414 {
00415     char *data_type = key;
00416     struct foreach_data *cb_data = arg;
00417 
00418     g_return_if_fail (key && be_item && arg);
00419 
00420     /* Call the callback for this data type */
00421     (cb_data->cb) (data_type, be_item, cb_data->user_data);
00422 }
00423 
00424 void qof_object_foreach_backend (const char *backend_name,
00425                                  QofForeachBackendTypeCB cb,
00426                                  gpointer user_data)
00427 {
00428     GHashTable *ht;
00429     struct foreach_data cb_data;
00430 
00431     if (!backend_name || *backend_name == '\0' || !cb)
00432         return;
00433 
00434     ht = g_hash_table_lookup (backend_data, (char *)backend_name);
00435     if (!ht)
00436         return;
00437 
00438     cb_data.cb = cb;
00439     cb_data.user_data = user_data;
00440 
00441     g_hash_table_foreach_sorted (ht, foreach_backend, &cb_data, (GCompareFunc)strcmp);
00442 }
00443 
00444 /* ========================= END OF FILE =================== */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines