qofbook.c

00001 /********************************************************************\
00002  * qofbook.c -- dataset access (set of books of entities)           *
00003  *                                                                  *
00004  * This program is free software; you can redistribute it and/or    *
00005  * modify it under the terms of the GNU General Public License as   *
00006  * published by the Free Software Foundation; either version 2 of   *
00007  * the License, or (at your option) any later version.              *
00008  *                                                                  *
00009  * This program is distributed in the hope that it will be useful,  *
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00012  * GNU General Public License for more details.                     *
00013  *                                                                  *
00014  * You should have received a copy of the GNU General Public License*
00015  * along with this program; if not, contact:                        *
00016  *                                                                  *
00017  * Free Software Foundation           Voice:  +1-617-542-5942       *
00018  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00019  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00020 \********************************************************************/
00021 
00022 /*
00023  * FILE:
00024  * qofbook.c
00025  *
00026  * FUNCTION:
00027  * Encapsulate all the information about a QOF dataset.
00028  *
00029  * HISTORY:
00030  * Created by Linas Vepstas December 1998
00031  * Copyright (c) 1998-2001,2003 Linas Vepstas <linas@linas.org>
00032  * Copyright (c) 2000 Dave Peticolas
00033  * Copyright (c) 2007 David Hampton <hampton@employees.org>
00034  */
00035 
00036 #include "config.h"
00037 
00038 #include <stdlib.h>
00039 #include <string.h>
00040 
00041 #include <glib.h>
00042 
00043 #include "qof.h"
00044 #include "qofevent-p.h"
00045 #include "qofbackend-p.h"
00046 #include "qofbook-p.h"
00047 #include "qofid-p.h"
00048 #include "qofobject-p.h"
00049 
00050 static QofLogModule log_module = QOF_MOD_ENGINE;
00051 
00052 QOF_GOBJECT_IMPL(qof_book, QofBook, QOF_TYPE_INSTANCE);
00053 
00054 /* ====================================================================== */
00055 /* constructor / destructor */
00056 
00057 static void coll_destroy(gpointer col)
00058 {
00059   qof_collection_destroy((QofCollection *) col);
00060 }
00061 
00062 static void
00063 qof_book_init (QofBook *book)
00064 {
00065   if (!book) return;
00066 
00067   book->hash_of_collections = g_hash_table_new_full(
00068       g_str_hash, g_str_equal,
00069       (GDestroyNotify)qof_util_string_cache_remove,  /* key_destroy_func   */
00070       coll_destroy);                            /* value_destroy_func */
00071 
00072   qof_instance_init_data (&book->inst, QOF_ID_BOOK, book);
00073 
00074   book->data_tables = g_hash_table_new (g_str_hash, g_str_equal);
00075   book->data_table_finalizers = g_hash_table_new (g_str_hash, g_str_equal);
00076   
00077   book->book_open = 'y';
00078   book->version = 0;
00079 }
00080 
00081 QofBook *
00082 qof_book_new (void)
00083 {
00084   QofBook *book;
00085 
00086   ENTER (" ");
00087   book = g_object_new(QOF_TYPE_BOOK, NULL);
00088   qof_object_book_begin (book);
00089 
00090   qof_event_gen (&book->inst, QOF_EVENT_CREATE, NULL);
00091   LEAVE ("book=%p", book);
00092   return book;
00093 }
00094 
00095 static void
00096 book_final (gpointer key, gpointer value, gpointer booq)
00097 {
00098   QofBookFinalCB cb = value;
00099   QofBook *book = booq;
00100 
00101   gpointer user_data = g_hash_table_lookup (book->data_tables, key);
00102   (*cb) (book, key, user_data);
00103 }
00104 
00105 static void
00106 qof_book_dispose_real (GObject *bookp)
00107 {
00108 }
00109 
00110 static void
00111 qof_book_finalize_real (GObject *bookp)
00112 {
00113 }
00114 
00115 void
00116 qof_book_destroy (QofBook *book) 
00117 {
00118   GHashTable* cols;
00119 
00120   if (!book) return;
00121   ENTER ("book=%p", book);
00122 
00123   book->shutting_down = TRUE;
00124   qof_event_force (&book->inst, QOF_EVENT_DESTROY, NULL);
00125 
00126   /* Call the list of finalizers, let them do their thing. 
00127    * Do this before tearing into the rest of the book.
00128    */
00129   g_hash_table_foreach (book->data_table_finalizers, book_final, book);
00130 
00131   qof_object_book_end (book);
00132 
00133   g_hash_table_destroy (book->data_table_finalizers);
00134   book->data_table_finalizers = NULL;
00135   g_hash_table_destroy (book->data_tables);
00136   book->data_tables = NULL;
00137 
00138   /* qof_instance_release (&book->inst); */
00139 
00140   /* Note: we need to save this hashtable until after we remove ourself
00141    * from it, otherwise we'll crash in our dispose() function when we
00142    * DO remove ourself from the collection but the collection had already
00143    * been destroyed.
00144    */
00145   cols = book->hash_of_collections;
00146   g_object_unref (book);
00147   g_hash_table_destroy (cols);
00148   book->hash_of_collections = NULL;
00149 
00150   LEAVE ("book=%p", book);
00151 }
00152 
00153 /* ====================================================================== */
00154 /* XXX this should probably be calling is_equal callbacks on gncObject */
00155 
00156 gboolean
00157 qof_book_equal (const QofBook *book_1, const QofBook *book_2)
00158 {
00159   if (book_1 == book_2) return TRUE;
00160   if (!book_1 || !book_2) return FALSE;
00161   return FALSE;
00162 }
00163 
00164 /* ====================================================================== */
00165 
00166 gboolean
00167 qof_book_not_saved (const QofBook *book)
00168 {
00169   if (!book) return FALSE;
00170 
00171   return(qof_instance_get_dirty_flag(book) || qof_object_is_dirty(book));
00172 }
00173 
00174 void
00175 qof_book_mark_saved (QofBook *book)
00176 {
00177   gboolean was_dirty;
00178 
00179   if (!book) return;
00180 
00181   was_dirty = qof_instance_get_dirty_flag(book);
00182   qof_instance_set_dirty_flag(book, FALSE);
00183   book->dirty_time = 0;
00184   qof_object_mark_clean (book);
00185   if (was_dirty) {
00186     if (book->dirty_cb)
00187       book->dirty_cb(book, FALSE, book->dirty_data);
00188   }
00189 }
00190 
00191 void qof_book_mark_dirty (QofBook *book)
00192 {
00193   gboolean was_dirty;
00194 
00195   if (!book) return;
00196 
00197   was_dirty = qof_instance_get_dirty_flag(book);
00198   qof_instance_set_dirty_flag(book, TRUE);
00199   if (!was_dirty) {
00200     book->dirty_time = time(NULL);
00201     if (book->dirty_cb)
00202       book->dirty_cb(book, TRUE, book->dirty_data);
00203   }
00204 }
00205 
00206 void
00207 qof_book_print_dirty (const QofBook *book)
00208 {
00209   if (qof_instance_get_dirty_flag(book))
00210     printf("book is dirty.\n");
00211   qof_book_foreach_collection
00212     (book, (QofCollectionForeachCB)qof_collection_print_dirty, NULL);
00213 }
00214 
00215 time_t
00216 qof_book_get_dirty_time (const QofBook *book)
00217 {
00218   return book->dirty_time;
00219 }
00220 
00221 void
00222 qof_book_set_dirty_cb(QofBook *book, QofBookDirtyCB cb, gpointer user_data)
00223 {
00224   if (book->dirty_cb)
00225     g_warning("qof_book_set_dirty_cb: Already existing callback %p, will be overwritten by %p\n",
00226               book->dirty_cb, cb);
00227   book->dirty_data = user_data;
00228   book->dirty_cb = cb;
00229 }
00230 
00231 /* ====================================================================== */
00232 /* getters */
00233 
00234 QofBackend * 
00235 qof_book_get_backend (const QofBook *book)
00236 {
00237    if (!book) return NULL;
00238    return book->backend;
00239 }
00240 
00241 gboolean
00242 qof_book_shutting_down (const QofBook *book)
00243 {
00244   if (!book) return FALSE;
00245   return book->shutting_down;
00246 }
00247 
00248 /* ====================================================================== */
00249 /* setters */
00250 
00251 void
00252 qof_book_set_backend (QofBook *book, QofBackend *be)
00253 {
00254   if (!book) return;
00255   ENTER ("book=%p be=%p", book, be);
00256   book->backend = be;
00257   LEAVE (" ");
00258 }
00259 
00260 void qof_book_kvp_changed (QofBook *book)
00261 {
00262   qof_book_mark_dirty(book);
00263 }
00264 
00265 /* ====================================================================== */
00266 
00267 /* Store arbitrary pointers in the QofBook for data storage extensibility */
00268 /* XXX if data is NULL, we should remove the key from the hash table!
00269  */
00270 void 
00271 qof_book_set_data (QofBook *book, const char *key, gpointer data)
00272 {
00273   if (!book || !key) return;
00274   g_hash_table_insert (book->data_tables, (gpointer)key, data);
00275 }
00276 
00277 void 
00278 qof_book_set_data_fin (QofBook *book, const char *key, gpointer data, QofBookFinalCB cb)
00279 {
00280   if (!book || !key) return;
00281   g_hash_table_insert (book->data_tables, (gpointer)key, data);
00282 
00283   if (!cb) return;
00284   g_hash_table_insert (book->data_table_finalizers, (gpointer)key, cb);
00285 }
00286 
00287 gpointer 
00288 qof_book_get_data (const QofBook *book, const char *key)
00289 {
00290   if (!book || !key) return NULL;
00291   return g_hash_table_lookup (book->data_tables, (gpointer)key);
00292 }
00293 
00294 /* ====================================================================== */
00295 
00296 QofCollection *
00297 qof_book_get_collection (const QofBook *book, QofIdType entity_type)
00298 {
00299   QofCollection *col;
00300 
00301   if (!book || !entity_type) return NULL;
00302 
00303   col = g_hash_table_lookup (book->hash_of_collections, entity_type);
00304   if (!col) {
00305       col = qof_collection_new (entity_type);
00306       g_hash_table_insert(
00307           book->hash_of_collections,
00308           qof_util_string_cache_insert((gpointer) entity_type), col);
00309   }
00310   return col;
00311 }
00312 
00313 struct _iterate {
00314   QofCollectionForeachCB  fn;
00315   gpointer                data;
00316 };
00317 
00318 static void 
00319 foreach_cb (gpointer key, gpointer item, gpointer arg)
00320 {
00321   struct _iterate *iter = arg;
00322   QofCollection *col = item;
00323 
00324   iter->fn (col, iter->data);
00325 }
00326 
00327 void 
00328 qof_book_foreach_collection (const QofBook *book, 
00329                              QofCollectionForeachCB cb, gpointer user_data)
00330 {
00331   struct _iterate iter;
00332 
00333   g_return_if_fail (book);
00334   g_return_if_fail (cb);
00335 
00336   iter.fn = cb;
00337   iter.data = user_data;
00338 
00339   g_hash_table_foreach (book->hash_of_collections, foreach_cb, &iter);
00340 }
00341 
00342 /* ====================================================================== */
00343 
00344 void qof_book_mark_closed (QofBook *book)
00345 {
00346         if(!book) { return; }
00347         book->book_open = 'n';
00348 }
00349 
00350 gchar qof_book_get_open_marker(const QofBook *book)
00351 {
00352         if(!book) { return 'n'; }
00353         return book->book_open;
00354 }
00355 
00356 gint32 qof_book_get_version (const QofBook *book)
00357 {
00358         if(!book) { return -1; }
00359         return book->version;
00360 }
00361 
00362 void qof_book_set_version (QofBook *book, gint32 version)
00363 {
00364         if(!book && version < 0) { return; }
00365         book->version = version;
00366 }
00367 
00368 gint64
00369 qof_book_get_counter (const QofBook *book, const char *counter_name)
00370 {
00371   QofBackend *be;
00372   KvpFrame *kvp;
00373   KvpValue *value;
00374   gint64 counter;
00375 
00376   if (!book) {
00377     PWARN ("No book!!!");
00378     return -1;
00379   }
00380 
00381   if (!counter_name || *counter_name == '\0') {
00382     PWARN ("Invalid counter name.");
00383     return -1;
00384   }
00385 
00386   /* If we've got a backend with a counter method, call it */
00387   be = book->backend;
00388   if (be && be->counter)
00389     return ((be->counter)(be, counter_name));
00390 
00391   /* If not, then use the KVP in the book */
00392   kvp = qof_book_get_slots (book);
00393 
00394   if (!kvp) {
00395     PWARN ("Book has no KVP_Frame");
00396     return -1;
00397   }
00398 
00399   value = kvp_frame_get_slot_path (kvp, "counters", counter_name, NULL);
00400   if (value) {
00401     /* found it */
00402     counter = kvp_value_get_gint64 (value);
00403   } else {
00404     /* New counter */
00405     counter = 0;
00406   }
00407 
00408   /* Counter is now valid; increment it */
00409   counter++;
00410 
00411   /* Save off the new counter */
00412   value = kvp_value_new_gint64 (counter);
00413   kvp_frame_set_slot_path (kvp, value, "counters", counter_name, NULL);
00414   kvp_value_delete (value);
00415 
00416   /* and return the value */
00417   return counter;
00418 }
00419 
00420 /* QofObject function implementation and registration */
00421 gboolean qof_book_register (void)
00422 {
00423   static QofParam params[] = {
00424     { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_entity_get_guid, NULL },
00425     { QOF_PARAM_KVP,  QOF_TYPE_KVP,  (QofAccessFunc)qof_instance_get_slots, NULL },
00426     { NULL },
00427   };
00428 
00429   qof_class_register (QOF_ID_BOOK, NULL, params);
00430 
00431   return TRUE;
00432 }
00433 
00434 /* ========================== END OF FILE =============================== */

Generated on Tue Oct 14 05:04:58 2008 for GnuCash by  doxygen 1.5.2