QOF  0.8.7
qofid.c
1 /********************************************************************\
2  * qofid.c -- QOF entity identifier implementation *
3  * Copyright (C) 2000 Dave Peticolas <dave@krondo.com> *
4  * Copyright (C) 2003 Linas Vepstas <linas@linas.org> *
5  * *
6  * This program is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU General Public License as *
8  * published by the Free Software Foundation; either version 2 of *
9  * the License, or (at your option) any later version. *
10  * *
11  * This program is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License*
17  * along with this program; if not, contact: *
18  * *
19  * Free Software Foundation Voice: +1-617-542-5942 *
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21  * Boston, MA 02110-1301, USA gnu@gnu.org *
22  * *
23 \********************************************************************/
24 
25 #include "config.h"
26 
27 #include <string.h>
28 #include <glib.h>
29 
30 #include "qof.h"
31 #include "qofid-p.h"
32 
33 static QofLogModule log_module = QOF_MOD_ENGINE;
34 
35 struct QofCollection_s
36 {
37  QofIdType e_type;
38  gboolean is_dirty;
39 
40  GHashTable *hash_of_entities;
41  gpointer data; /* place where object class can hang arbitrary data */
42 };
43 
44 /* =============================================================== */
45 
46 static void qof_collection_remove_entity (QofEntity * ent);
47 
48 void
50 {
51  g_return_if_fail (NULL != tab);
52 
53  /* XXX We passed redundant info to this routine ... but I think that's
54  * OK, it might eliminate programming errors. */
55  if (safe_strcmp (tab->e_type, type))
56  {
57  PERR ("attempt to insert \"%s\" into \"%s\"", type, tab->e_type);
58  return;
59  }
60  ent->e_type = CACHE_INSERT (type);
61 
62  do
63  {
64  guid_new (&ent->guid);
65 
66  if (NULL == qof_collection_lookup_entity (tab, &ent->guid))
67  break;
68 
69  PWARN ("duplicate id created, trying again");
70  }
71  while (1);
72 
73  ent->collection = tab;
74 
76 }
77 
78 void
80 {
81  if (!ent->collection)
82  return;
83  qof_collection_remove_entity (ent);
84  CACHE_REMOVE (ent->e_type);
85  ent->e_type = NULL;
86 }
87 
88 
89 /* This is a restricted function, should be used only during
90  * read from file */
91 void
92 qof_entity_set_guid (QofEntity * ent, const GUID * guid)
93 {
94  QofCollection *col;
95  if (guid_equal (guid, &ent->guid))
96  return;
97 
98  col = ent->collection;
99  qof_collection_remove_entity (ent);
100  ent->guid = *guid;
101  qof_collection_insert_entity (col, ent);
102 }
103 
104 const GUID *
106 {
107  if (!ent)
108  return guid_null ();
109  return &ent->guid;
110 }
111 
112 /* =============================================================== */
113 
114 static gboolean
115 id_compare (gconstpointer key_1, gconstpointer key_2)
116 {
117  return guid_equal (key_1, key_2);
118 }
119 
122 {
123  QofCollection *col;
124  col = g_new0 (QofCollection, 1);
125  col->e_type = CACHE_INSERT (type);
126  col->hash_of_entities = g_hash_table_new (guid_hash_to_guint, id_compare);
127  col->data = NULL;
128  return col;
129 }
130 
131 void
133 {
134  CACHE_REMOVE (col->e_type);
135  g_hash_table_destroy (col->hash_of_entities);
136  col->e_type = NULL;
137  col->hash_of_entities = NULL;
138  col->data = NULL;
139  g_free (col);
140 }
141 
142 /* =============================================================== */
143 /* getters */
144 
145 QofIdType
147 {
148  return col->e_type;
149 }
150 
151 /* =============================================================== */
152 
153 static void
154 qof_collection_remove_entity (QofEntity * ent)
155 {
156  QofCollection *col;
157  if (!ent)
158  return;
159  col = ent->collection;
160  if (!col)
161  return;
162  g_hash_table_remove (col->hash_of_entities, &ent->guid);
163  qof_collection_mark_dirty (col);
164  ent->collection = NULL;
165 }
166 
167 void
169 {
170  if (!col || !ent)
171  return;
172  if (guid_equal (&ent->guid, guid_null ()))
173  return;
174  g_return_if_fail (col->e_type == ent->e_type);
175  qof_collection_remove_entity (ent);
176  g_hash_table_insert (col->hash_of_entities, &ent->guid, ent);
177  qof_collection_mark_dirty (col);
178  ent->collection = col;
179 }
180 
181 gboolean
183 {
184  QofEntity *e;
185 
186  e = NULL;
187  if (!coll || !ent)
188  {
189  return FALSE;
190  }
191  if (guid_equal (&ent->guid, guid_null ()))
192  {
193  return FALSE;
194  }
195  g_return_val_if_fail (coll->e_type == ent->e_type, FALSE);
196  e = qof_collection_lookup_entity (coll, &ent->guid);
197  if (e != NULL)
198  {
199  return FALSE;
200  }
201  g_hash_table_insert (coll->hash_of_entities, &ent->guid, ent);
202  qof_collection_mark_dirty (coll);
203  return TRUE;
204 }
205 
206 static void
207 collection_merge_cb (QofEntity * ent, gpointer data)
208 {
209  QofCollection *target;
210 
211  target = (QofCollection *) data;
212  qof_collection_add_entity (target, ent);
213 }
214 
215 gboolean
217 {
218  if (!target || !merge)
219  {
220  return FALSE;
221  }
222  g_return_val_if_fail (target->e_type == merge->e_type, FALSE);
223  qof_collection_foreach (merge, collection_merge_cb, target);
224  return TRUE;
225 }
226 
227 static void
228 collection_compare_cb (QofEntity * ent, gpointer user_data)
229 {
230  QofCollection *target;
231  QofEntity *e;
232  gint value;
233 
234  e = NULL;
235  target = (QofCollection *) user_data;
236  if (!target || !ent)
237  {
238  return;
239  }
240  value = *(gint *) qof_collection_get_data (target);
241  if (value != 0)
242  {
243  return;
244  }
245  if (guid_equal (&ent->guid, guid_null ()))
246  {
247  value = -1;
248  qof_collection_set_data (target, &value);
249  return;
250  }
251  g_return_if_fail (target->e_type == ent->e_type);
252  e = qof_collection_lookup_entity (target, &ent->guid);
253  if (e == NULL)
254  {
255  value = 1;
256  qof_collection_set_data (target, &value);
257  return;
258  }
259  value = 0;
260  qof_collection_set_data (target, &value);
261 }
262 
263 gint
265 {
266  gint value;
267 
268  value = 0;
269  if (!target && !merge)
270  return 0;
271  if (target == merge)
272  return 0;
273  if (!target && merge)
274  return -1;
275  if (target && !merge)
276  return 1;
277  if (target->e_type != merge->e_type)
278  return -1;
279  qof_collection_set_data (target, &value);
280  qof_collection_foreach (merge, collection_compare_cb, target);
281  value = *(gint *) qof_collection_get_data (target);
282  if (value == 0)
283  {
284  qof_collection_set_data (merge, &value);
285  qof_collection_foreach (target, collection_compare_cb, merge);
286  value = *(gint *) qof_collection_get_data (merge);
287  }
288  return value;
289 }
290 
291 QofEntity *
293 {
294  QofEntity *ent;
295  g_return_val_if_fail (col, NULL);
296  if (guid == NULL)
297  return NULL;
298  ent = g_hash_table_lookup (col->hash_of_entities, guid);
299  return ent;
300 }
301 
304 {
305  QofCollection *coll;
306  QofEntity *ent;
307  GList *list;
308 
309  coll = qof_collection_new (type);
310  for (list = glist; list != NULL; list = list->next)
311  {
312  ent = (QofEntity *) list->data;
313  if (FALSE == qof_collection_add_entity (coll, ent))
314  {
315  return NULL;
316  }
317  }
318  return coll;
319 }
320 
321 guint
323 {
324  guint c;
325 
326  c = g_hash_table_size (col->hash_of_entities);
327  return c;
328 }
329 
330 /* =============================================================== */
331 
332 gboolean
334 {
335  return col ? col->is_dirty : FALSE;
336 }
337 
338 void
340 {
341  if (col)
342  {
343  col->is_dirty = FALSE;
344  }
345 }
346 
347 void
348 qof_collection_mark_dirty (QofCollection * col)
349 {
350  if (col)
351  {
352  col->is_dirty = TRUE;
353  }
354 }
355 
356 /* =============================================================== */
357 
358 gpointer
360 {
361  return col ? col->data : NULL;
362 }
363 
364 void
365 qof_collection_set_data (QofCollection * col, gpointer user_data)
366 {
367  if (col)
368  {
369  col->data = user_data;
370  }
371 }
372 
373 /* =============================================================== */
374 
375 struct _iterate
376 {
377  QofEntityForeachCB fcn;
378  gpointer data;
379 };
380 
381 static void
382 foreach_cb (gpointer key __attribute__ ((unused)), gpointer item,
383  gpointer arg)
384 {
385  struct _iterate *qiter = arg;
386  QofEntity *ent = item;
387 
388  qiter->fcn (ent, qiter->data);
389 }
390 
391 void
393  gpointer user_data)
394 {
395  struct _iterate qiter;
396 
397  g_return_if_fail (col);
398  g_return_if_fail (cb_func);
399 
400  qiter.fcn = cb_func;
401  qiter.data = user_data;
402 
403  g_hash_table_foreach (col->hash_of_entities, foreach_cb, &qiter);
404 }
405 
406 /* =============================================================== */
gboolean qof_collection_add_entity(QofCollection *coll, QofEntity *ent)
Add an entity to a QOF_TYPE_COLLECT.
Definition: qofid.c:182
gboolean guid_equal(const GUID *guid_1, const GUID *guid_2)
Definition: guid.c:620
#define PERR(format, args...)
Definition: qoflog.h:183
gint qof_collection_compare(QofCollection *target, QofCollection *merge)
Compare two secondary collections.
Definition: qofid.c:264
const gchar * QofIdType
Definition: qofid.h:81
const GUID * guid_null(void)
Definition: guid.c:79
gboolean qof_collection_is_dirty(QofCollection *col)
Definition: qofid.c:333
void(* QofEntityForeachCB)(QofEntity *, gpointer user_data)
Definition: qofid.h:187
struct QofCollection_s QofCollection
Definition: qofid.h:138
QofCollection * qof_collection_from_glist(QofIdType type, GList *glist)
Create a secondary collection from a GList.
Definition: qofid.c:303
guint qof_collection_count(QofCollection *col)
Definition: qofid.c:322
QofEntity * qof_collection_lookup_entity(QofCollection *col, const GUID *guid)
Definition: qofid.c:292
void qof_collection_foreach(QofCollection *col, QofEntityForeachCB cb_func, gpointer user_data)
Definition: qofid.c:392
void qof_collection_set_data(QofCollection *col, gpointer user_data)
Definition: qofid.c:365
void qof_entity_release(QofEntity *ent)
Definition: qofid.c:79
void qof_collection_mark_clean(QofCollection *col)
Definition: qofid.c:339
guint guid_hash_to_guint(gconstpointer ptr)
Definition: guid.c:645
QofIdType qof_collection_get_type(QofCollection *col)
Definition: qofid.c:146
Definition: guid.h:53
void guid_new(GUID *guid)
Definition: guid.c:444
gpointer qof_collection_get_data(QofCollection *col)
Definition: qofid.c:359
#define PWARN(format, args...)
Definition: qoflog.h:191
void qof_collection_destroy(QofCollection *col)
Definition: qofid.c:132
const GUID * qof_entity_get_guid(QofEntity *ent)
Definition: qofid.c:105
QofCollection * qof_collection_new(QofIdType type)
Definition: qofid.c:121
gboolean qof_collection_merge(QofCollection *target, QofCollection *merge)
Merge two QOF_TYPE_COLLECT of the same type.
Definition: qofid.c:216
void qof_entity_set_guid(QofEntity *ent, const GUID *guid)
Definition: qofid.c:92
gint safe_strcmp(const gchar *da, const gchar *db)
Definition: qofutil.c:75
void qof_entity_init(QofEntity *ent, QofIdType type, QofCollection *tab)
Definition: qofid.c:49
const gchar * QofLogModule
Definition: qofid.h:85
void qof_collection_insert_entity(QofCollection *col, QofEntity *ent)
Definition: qofid.c:168