1 /********************************************************************\
2 * qofbook.c -- dataset access (set of books of entities) *
3 * *
4 * This program is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU General Public License as *
6 * published by the Free Software Foundation; either version 2 of *
7 * the License, or (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License*
15 * along with this program; if not, contact: *
16 * *
17 * Free Software Foundation Voice: +1-617-542-5942 *
18 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
19 * Boston, MA 02110-1301, USA gnu@gnu.org *
20 \********************************************************************/
21
22 /*
23 * FILE:
24 * qofbook.c
25 *
26 * FUNCTION:
27 * Encapsulate all the information about a QOF dataset.
28 *
29 * HISTORY:
30 * Created by Linas Vepstas December 1998
31 * Copyright (c) 1998-2001,2003 Linas Vepstas <linas@linas.org>
32 * Copyright (c) 2000 Dave Peticolas
33 * Copyright (c) 2006 Neil Williams <linux@codehelp.co.uk>
34 */
35
36 #include "config.h"
37 #include <stdlib.h>
38 #include <string.h>
39 #include <glib.h>
40 #include "qof.h"
41 #include "qofevent-p.h"
42 #include "qofbackend-p.h"
43 #include "qofbook-p.h"
44 #include "qofid-p.h"
45 #include "qofobject-p.h"
46
47 static QofLogModule log_module = QOF_MOD_ENGINE;
48
49 static void
coll_destroy(gpointer col)50 coll_destroy (gpointer col)
51 {
52 qof_collection_destroy ((QofCollection *) col);
53 }
54
55 static void
qof_book_init(QofBook * book)56 qof_book_init (QofBook * book)
57 {
58 if (!book)
59 return;
60
61 book->hash_of_collections =
62 g_hash_table_new_full (g_str_hash, g_str_equal,
63 (GDestroyNotify) qof_util_string_cache_remove, coll_destroy);
64 qof_instance_init (&book->inst, QOF_ID_BOOK, book);
65 book->data_tables = g_hash_table_new (g_str_hash, g_str_equal);
66 book->data_table_finalizers =
67 g_hash_table_new (g_str_hash, g_str_equal);
68 book->book_open = 'y';
69 book->version = 0;
70 book->idata = 0;
71 book->undo_data = g_new0 (QofUndo, 1);
72 }
73
74 QofBook *
qof_book_new(void)75 qof_book_new (void)
76 {
77 QofBook *book;
78
79 ENTER (" ");
80 book = g_new0 (QofBook, 1);
81 qof_book_init (book);
82 qof_object_book_begin (book);
83 qof_event_gen (&book->inst.entity, QOF_EVENT_CREATE, NULL);
84 LEAVE ("book=%p", book);
85 return book;
86 }
87
88 static void
book_final(gpointer key,gpointer value,gpointer booq)89 book_final (gpointer key, gpointer value, gpointer booq)
90 {
91 QofBookFinalCB cb = value;
92 QofBook *book = booq;
93
94 gpointer user_data = g_hash_table_lookup (book->data_tables, key);
95 (*cb) (book, key, user_data);
96 }
97
98 void
qof_book_destroy(QofBook * book)99 qof_book_destroy (QofBook * book)
100 {
101 if (!book)
102 return;
103 ENTER ("book=%p", book);
104 book->shutting_down = TRUE;
105 qof_event_force (&book->inst.entity, QOF_EVENT_DESTROY, NULL);
106 /* Call the list of finalizers, let them do their thing.
107 * Do this before tearing into the rest of the book.
108 */
109 g_hash_table_foreach (book->data_table_finalizers, book_final, book);
110 qof_object_book_end (book);
111 g_hash_table_destroy (book->data_table_finalizers);
112 book->data_table_finalizers = NULL;
113 g_hash_table_destroy (book->data_tables);
114 book->data_tables = NULL;
115 qof_instance_release (&book->inst);
116 g_hash_table_destroy (book->hash_of_collections);
117 book->hash_of_collections = NULL;
118 g_free (book);
119 LEAVE ("book=%p", book);
120 }
121
122 /* call is_equal callbacks on QofObject ? */
123
124 gboolean
qof_book_equal(QofBook * book_1,QofBook * book_2)125 qof_book_equal (QofBook * book_1, QofBook * book_2)
126 {
127 if (book_1 == book_2)
128 return TRUE;
129 if (!book_1 || !book_2)
130 return FALSE;
131 return TRUE;
132 }
133
134 gboolean
qof_book_not_saved(QofBook * book)135 qof_book_not_saved (QofBook * book)
136 {
137 if (!book)
138 return FALSE;
139
140 return (book->inst.dirty || qof_object_is_dirty (book));
141 }
142
143 void
qof_book_mark_saved(QofBook * book)144 qof_book_mark_saved (QofBook * book)
145 {
146 if (!book)
147 return;
148
149 book->inst.dirty = FALSE;
150 qof_object_mark_clean (book);
151 }
152
153 QofBackend *
qof_book_get_backend(QofBook * book)154 qof_book_get_backend (QofBook * book)
155 {
156 if (!book)
157 return NULL;
158 return book->backend;
159 }
160
161 gboolean
qof_book_shutting_down(QofBook * book)162 qof_book_shutting_down (QofBook * book)
163 {
164 if (!book)
165 return FALSE;
166 return book->shutting_down;
167 }
168
169 void
qof_book_set_backend(QofBook * book,QofBackend * be)170 qof_book_set_backend (QofBook * book, QofBackend * be)
171 {
172 if (!book)
173 return;
174 ENTER ("book=%p be=%p", book, be);
175 book->backend = be;
176 LEAVE (" ");
177 }
178
179 void
qof_book_kvp_changed(QofBook * book)180 qof_book_kvp_changed (QofBook * book)
181 {
182 if (!book)
183 return;
184 book->inst.dirty = TRUE;
185 }
186
187 /* Store arbitrary pointers in the QofBook for data storage extensibility */
188 /* XXX if data is NULL, we should remove the key from the hash table!
189 */
190 void
qof_book_set_data(QofBook * book,const gchar * key,gpointer data)191 qof_book_set_data (QofBook * book, const gchar * key, gpointer data)
192 {
193 if (!book || !key)
194 return;
195 g_hash_table_insert (book->data_tables, (gpointer) key, data);
196 }
197
198 void
qof_book_set_data_fin(QofBook * book,const gchar * key,gpointer data,QofBookFinalCB cb)199 qof_book_set_data_fin (QofBook * book, const gchar * key,
200 gpointer data, QofBookFinalCB cb)
201 {
202 if (!book || !key)
203 return;
204 g_hash_table_insert (book->data_tables, (gpointer) key, data);
205
206 if (!cb)
207 return;
208 g_hash_table_insert (book->data_table_finalizers, (gpointer) key, cb);
209 }
210
211 gpointer
qof_book_get_data(QofBook * book,const gchar * key)212 qof_book_get_data (QofBook * book, const gchar * key)
213 {
214 if (!book || !key)
215 return NULL;
216 return g_hash_table_lookup (book->data_tables, (gpointer) key);
217 }
218
219 QofCollection *
qof_book_get_collection(QofBook * book,QofIdType entity_type)220 qof_book_get_collection (QofBook * book, QofIdType entity_type)
221 {
222 QofCollection *col;
223
224 if (!book || !entity_type)
225 return NULL;
226 col = g_hash_table_lookup (book->hash_of_collections, entity_type);
227 if (!col)
228 {
229 col = qof_collection_new (entity_type);
230 g_hash_table_insert (book->hash_of_collections,
231 qof_util_string_cache_insert ((gpointer) entity_type), col);
232 }
233 return col;
234 }
235
236 struct _iterate
237 {
238 QofCollectionForeachCB fn;
239 gpointer data;
240 };
241
242 static void
foreach_cb(gpointer key,gpointer item,gpointer arg)243 foreach_cb (gpointer key __attribute__ ((unused)), gpointer item, gpointer arg)
244 {
245 struct _iterate *qiter = arg;
246 QofCollection *col = item;
247
248 qiter->fn (col, qiter->data);
249 }
250
251 void
qof_book_foreach_collection(QofBook * book,QofCollectionForeachCB cb,gpointer user_data)252 qof_book_foreach_collection (QofBook * book,
253 QofCollectionForeachCB cb, gpointer user_data)
254 {
255 struct _iterate qiter;
256
257 g_return_if_fail (book);
258 g_return_if_fail (cb);
259 qiter.fn = cb;
260 qiter.data = user_data;
261 g_hash_table_foreach (book->hash_of_collections, foreach_cb, &qiter);
262 }
263
264 void
qof_book_mark_closed(QofBook * book)265 qof_book_mark_closed (QofBook * book)
266 {
267 if (!book)
268 {
269 return;
270 }
271 book->book_open = 'n';
272 }
273
274 gchar
qof_book_get_open_marker(QofBook * book)275 qof_book_get_open_marker (QofBook * book)
276 {
277 if (!book)
278 {
279 return 'n';
280 }
281 return book->book_open;
282 }
283
284 gint32
qof_book_get_version(QofBook * book)285 qof_book_get_version (QofBook * book)
286 {
287 if (!book)
288 {
289 return -1;
290 }
291 return book->version;
292 }
293
294 guint32
qof_book_get_idata(QofBook * book)295 qof_book_get_idata (QofBook * book)
296 {
297 if (!book)
298 {
299 return 0;
300 }
301 return book->idata;
302 }
303
304 void
qof_book_set_version(QofBook * book,gint32 version)305 qof_book_set_version (QofBook * book, gint32 version)
306 {
307 if (!book && version < 0)
308 {
309 return;
310 }
311 book->version = version;
312 }
313
314 void
qof_book_set_idata(QofBook * book,guint32 idata)315 qof_book_set_idata (QofBook * book, guint32 idata)
316 {
317 if (!book && idata == 0)
318 {
319 return;
320 }
321 book->idata = idata;
322 }
323
324 gint64
qof_book_get_counter(QofBook * book,const gchar * counter_name)325 qof_book_get_counter (QofBook * book, const gchar * counter_name)
326 {
327 QofBackend *be;
328 KvpFrame *kvp;
329 KvpValue *value;
330 gint64 counter;
331
332 if (!book)
333 {
334 PWARN ("No book!!!");
335 return -1;
336 }
337 if (!counter_name || *counter_name == '\0')
338 {
339 PWARN ("Invalid counter name.");
340 return -1;
341 }
342 /* If we've got a backend with a counter method, call it */
343 be = book->backend;
344 if (be && be->counter)
345 return ((be->counter) (be, counter_name));
346 /* If not, then use the KVP in the book */
347 kvp = qof_book_get_slots (book);
348 if (!kvp)
349 {
350 PWARN ("Book has no KVP_Frame");
351 return -1;
352 }
353 value = kvp_frame_get_slot_path (kvp, "counters", counter_name, NULL);
354 if (value)
355 {
356 /* found it */
357 counter = kvp_value_get_gint64 (value);
358 }
359 else
360 {
361 /* New counter */
362 counter = 0;
363 }
364 /* Counter is now valid; increment it */
365 counter++;
366 /* Save off the new counter */
367 value = kvp_value_new_gint64 (counter);
368 kvp_frame_set_slot_path (kvp, value, "counters", counter_name, NULL);
369 kvp_value_delete (value);
370 /* and return the value */
371 return counter;
372 }
373
374 /* QofObject function implementation and registration */
375 gboolean
qof_book_register(void)376 qof_book_register (void)
377 {
378 static QofParam params[] = {
379 {QOF_PARAM_GUID, QOF_TYPE_GUID,
380 (QofAccessFunc) qof_entity_get_guid,
381 NULL, NULL},
382 {QOF_PARAM_KVP, QOF_TYPE_KVP,
383 (QofAccessFunc) qof_instance_get_slots,
384 NULL, NULL},
385 {NULL, NULL, NULL, NULL, NULL},
386 };
387
388 qof_class_register (QOF_ID_BOOK, NULL, params);
389
390 return TRUE;
391 }
392
393 /* ========================== END OF FILE =============================== */
394