|
GnuCash 2.4.99
|
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 =================== */
1.7.4