GnuCash  5.6-150-g038405b370+
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
gnc-component-manager.c
1 /********************************************************************\
2  * gnc-component-manager.h - GUI component manager interface *
3  * Copyright (C) 2000 Dave Peticolas <dave@krondo.com> *
4  * *
5  * This program is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU General Public License as *
7  * published by the Free Software Foundation; either version 2 of *
8  * the License, or (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License*
16  * along with this program; if not, write to the Free Software *
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
18 \********************************************************************/
19 
20 #include <config.h>
21 
22 #include <stdio.h>
23 
24 #include "gnc-component-manager.h"
25 #include "qof.h"
26 #include "gnc-ui-util.h"
27 
28 
31 #define CM_DEBUG 0
32 
33 typedef struct
34 {
35  QofIdType entity_type;
36  QofEventId event_mask;
38 
39 typedef struct
40 {
41  GHashTable * event_masks;
42  GHashTable * entity_events;
43 
44  gboolean match;
46 
47 typedef struct
48 {
49  GNCComponentRefreshHandler refresh_handler;
50  GNCComponentCloseHandler close_handler;
51  gpointer user_data;
52 
53  ComponentEventInfo watch_info;
54 
55  char *component_class;
56  gint component_id;
57  gpointer session;
59 
60 
62 static guint suspend_counter = 0;
63 /* Some code foolishly uses 0 instead of NO_COMPONENT, so we start with 1. */
64 static gint next_component_id = 1;
65 static GList *components = NULL;
66 
67 static ComponentEventInfo changes = { NULL, NULL, FALSE };
68 static ComponentEventInfo changes_backup = { NULL, NULL, FALSE };
69 
70 
71 /* This static indicates the debugging module that this .o belongs to. */
72 static QofLogModule log_module = GNC_MOD_GUI;
73 
74 
76 static void gnc_gui_refresh_internal (gboolean force);
77 static GList * find_component_ids_by_class (const char *component_class);
78 static gboolean got_events = FALSE;
79 
80 
83 #if CM_DEBUG
84 static void
85 dump_components (void)
86 {
87  GList *node;
88 
89  fprintf (stderr, "Components:\n");
90 
91  for (node = components; node; node = node->next)
92  {
93  ComponentInfo *ci = node->data;
94 
95  fprintf (stderr, " %s:\t%d\n",
96  ci->component_class ? ci->component_class : "(null)",
97  ci->component_id);
98  }
99 
100  fprintf (stderr, "\n");
101 }
102 #endif
103 
104 static void
105 clear_mask_hash_helper (gpointer key, gpointer value, gpointer user_data)
106 {
107  QofEventId * et = value;
108 
109  *et = 0;
110 }
111 
112 /* clear a hash table of the form string --> QofEventId,
113  * where the values are g_malloced and the keys are in the engine
114  * string cache. */
115 static void
116 clear_mask_hash (GHashTable *hash)
117 {
118  if (hash == NULL)
119  return;
120 
121  g_hash_table_foreach (hash, clear_mask_hash_helper, NULL);
122 }
123 
124 static gboolean
125 destroy_mask_hash_helper (gpointer key, gpointer value, gpointer user_data)
126 {
128  g_free (value);
129 
130  return TRUE;
131 }
132 
133 static void
134 destroy_mask_hash (GHashTable *hash)
135 {
136  g_hash_table_foreach_remove (hash, destroy_mask_hash_helper, NULL);
137  g_hash_table_destroy (hash);
138 }
139 
140 static gboolean
141 destroy_event_hash_helper (gpointer key, gpointer value, gpointer user_data)
142 {
143  GncGUID *guid = key;
144  EventInfo *ei = value;
145 
146  guid_free (guid);
147  g_free (ei);
148 
149  return TRUE;
150 }
151 
152 /* clear a hash table of the form GncGUID --> EventInfo, where
153  * both keys and values are g_malloced */
154 static void
155 clear_event_hash (GHashTable *hash)
156 {
157  if (hash == NULL)
158  return;
159 
160  g_hash_table_foreach_remove (hash, destroy_event_hash_helper, NULL);
161 }
162 
163 static void
164 destroy_event_hash (GHashTable *hash)
165 {
166  clear_event_hash (hash);
167  g_hash_table_destroy (hash);
168 }
169 
170 static void
171 clear_event_info (ComponentEventInfo *cei)
172 {
173  if (!cei)
174  return;
175 
176  clear_mask_hash (cei->event_masks);
177  clear_event_hash (cei->entity_events);
178 }
179 
180 static void
181 add_event (ComponentEventInfo *cei, const GncGUID *entity,
182  QofEventId event_mask, gboolean or_in)
183 {
184  GHashTable *hash;
185 
186  if (!cei || !cei->entity_events || !entity)
187  return;
188 
189  hash = cei->entity_events;
190 
191  if (event_mask == 0)
192  {
193  gpointer key;
194  gpointer value;
195 
196  if (or_in)
197  return;
198 
199  if (g_hash_table_lookup_extended (hash, entity, &key, &value))
200  {
201  g_hash_table_remove (hash, entity);
202  guid_free (key);
203  g_free (value);
204  }
205  }
206  else
207  {
208  EventInfo *ei;
209 
210  ei = g_hash_table_lookup (hash, entity);
211  if (ei == NULL)
212  {
213  GncGUID *key;
214 
215  key = guid_malloc ();
216  *key = *entity;
217 
218  ei = g_new (EventInfo, 1);
219  ei->event_mask = 0;
220 
221  g_hash_table_insert (hash, key, ei);
222  }
223 
224  if (or_in)
225  ei->event_mask |= event_mask;
226  else
227  ei->event_mask = event_mask;
228  }
229 }
230 
231 static void
232 add_event_type (ComponentEventInfo *cei, QofIdTypeConst entity_type,
233  QofEventId event_mask, gboolean or_in)
234 {
235  QofEventId *mask;
236 
237  g_return_if_fail (cei);
238  g_return_if_fail (cei->event_masks);
239  g_return_if_fail (entity_type);
240 
241  mask = g_hash_table_lookup (cei->event_masks, entity_type);
242  if (!mask)
243  {
244  const char * key = qof_string_cache_insert ((gpointer) entity_type);
245  mask = g_new0 (QofEventId, 1);
246  g_hash_table_insert (cei->event_masks, (gpointer)key, mask);
247  }
248 
249  if (or_in)
250  *mask |= event_mask;
251  else
252  *mask = event_mask;
253 }
254 
255 static void
256 gnc_cm_event_handler (QofInstance *entity,
257  QofEventId event_type,
258  gpointer user_data,
259  gpointer event_data)
260 {
261  const GncGUID *guid = qof_entity_get_guid(entity);
262 #if CM_DEBUG
263  gchar guidstr[GUID_ENCODING_LENGTH+1];
264  guid_to_string_buff (guid, guidstr);
265  fprintf (stderr, "event_handler: event %d, entity %p, guid %s\n", event_type,
266  entity, guidstr);
267 #endif
268  add_event (&changes, guid, event_type, TRUE);
269 
270  if (QOF_CHECK_TYPE(entity, GNC_ID_SPLIT))
271  {
272  /* split events are never generated by the engine, but might
273  * be generated by a backend (viz. the postgres backend.)
274  * Handle them like a transaction modify event. */
275  add_event_type (&changes, GNC_ID_TRANS, QOF_EVENT_MODIFY, TRUE);
276  }
277  else
278  add_event_type (&changes, entity->e_type, event_type, TRUE);
279 
280  got_events = TRUE;
281 
282  if (suspend_counter == 0)
283  gnc_gui_refresh_internal (FALSE);
284 }
285 
286 static gint handler_id;
287 
288 void
289 gnc_component_manager_init (void)
290 {
291  if (changes.entity_events)
292  {
293  PERR ("component manager already initialized");
294  return;
295  }
296 
297  changes.event_masks = g_hash_table_new (g_str_hash, g_str_equal);
298  changes.entity_events = guid_hash_table_new ();
299 
300  changes_backup.event_masks = g_hash_table_new (g_str_hash, g_str_equal);
301  changes_backup.entity_events = guid_hash_table_new ();
302 
303  handler_id = qof_event_register_handler (gnc_cm_event_handler, NULL);
304 }
305 
306 void
307 gnc_component_manager_shutdown (void)
308 {
309  if (!changes.entity_events)
310  {
311  PERR ("component manager not initialized");
312  return;
313  }
314 
315  destroy_mask_hash (changes.event_masks);
316  changes.event_masks = NULL;
317 
318  destroy_event_hash (changes.entity_events);
319  changes.entity_events = NULL;
320 
321  destroy_mask_hash (changes_backup.event_masks);
322  changes_backup.event_masks = NULL;
323 
324  destroy_event_hash (changes_backup.entity_events);
325  changes_backup.entity_events = NULL;
326 
327  qof_event_unregister_handler (handler_id);
328 }
329 
330 static ComponentInfo *
331 find_component (gint component_id)
332 {
333  GList *node;
334 
335  for (node = components; node; node = node->next)
336  {
337  ComponentInfo *ci = node->data;
338 
339  if (ci->component_id == component_id)
340  return ci;
341  }
342 
343  return NULL;
344 }
345 
346 static GList *
347 find_components_by_data (gpointer user_data)
348 {
349  GList *list = NULL;
350  GList *node;
351 
352  for (node = components; node; node = node->next)
353  {
354  ComponentInfo *ci = node->data;
355 
356  if (ci->user_data == user_data)
357  list = g_list_prepend (list, ci);
358  }
359 
360  return list;
361 }
362 
363 static GList *
364 find_components_by_session (gpointer session)
365 {
366  GList *list = NULL;
367  GList *node;
368 
369  for (node = components; node; node = node->next)
370  {
371  ComponentInfo *ci = node->data;
372 
373  if (ci->session == session)
374  list = g_list_prepend (list, ci);
375  }
376 
377  return list;
378 }
379 
380 static ComponentInfo *
381 gnc_register_gui_component_internal (const char * component_class)
382 {
383  ComponentInfo *ci;
384  gint component_id;
385 
386  g_return_val_if_fail (component_class, NULL);
387 
388  /* look for a free handler id */
389  component_id = next_component_id;
390 
391  /* design warning: if we ever get 2^32-1 components,
392  this loop is infinite. Instead of fixing it, we'll just
393  complain when (if) we get half way there (probably never).
394  */
395  while (find_component (component_id))
396  if (++component_id == NO_COMPONENT)
397  component_id++;
398 
399  if (component_id < 0)
400  PERR("Amazing! Half way to running out of component_ids.");
401 
402  /* found one, add the handler */
403  ci = g_new0 (ComponentInfo, 1);
404 
405  ci->watch_info.event_masks = g_hash_table_new (g_str_hash, g_str_equal);
406  ci->watch_info.entity_events = guid_hash_table_new ();
407 
408  ci->component_class = g_strdup (component_class);
409  ci->component_id = component_id;
410  ci->session = NULL;
411 
412  components = g_list_prepend (components, ci);
413 
414  /* update id for next registration */
415  next_component_id = component_id + 1;
416 
417 #if CM_DEBUG
418  fprintf (stderr, "Register component %d in class %s\n",
419  component_id, component_class ? component_class : "(null)");
420  dump_components ();
421 #endif
422 
423  return ci;
424 }
425 
426 gint
427 gnc_register_gui_component (const char *component_class,
428  GNCComponentRefreshHandler refresh_handler,
429  GNCComponentCloseHandler close_handler,
430  gpointer user_data)
431 {
432  ComponentInfo *ci;
433 
434  /* sanity check */
435  if (!component_class)
436  {
437  PERR ("no class specified");
438  return NO_COMPONENT;
439  }
440 
441  ci = gnc_register_gui_component_internal (component_class);
442  g_return_val_if_fail (ci, NO_COMPONENT);
443 
444  ci->refresh_handler = refresh_handler;
445  ci->close_handler = close_handler;
446  ci->user_data = user_data;
447 
448  return ci->component_id;
449 }
450 
451 void
452 gnc_gui_component_watch_entity (gint component_id,
453  const GncGUID *entity,
454  QofEventId event_mask)
455 {
456  ComponentInfo *ci;
457 
458  if (entity == NULL)
459  return;
460 
461  ci = find_component (component_id);
462  if (!ci)
463  {
464  PERR ("component not found");
465  return;
466  }
467 
468  add_event (&ci->watch_info, entity, event_mask, FALSE);
469 }
470 
471 void
472 gnc_gui_component_watch_entity_type (gint component_id,
473  QofIdTypeConst entity_type,
474  QofEventId event_mask)
475 {
476  ComponentInfo *ci;
477 
478  ci = find_component (component_id);
479  if (!ci)
480  {
481  PERR ("component not found");
482  return;
483  }
484 
485  add_event_type (&ci->watch_info, entity_type, event_mask, FALSE);
486 }
487 
488 const EventInfo *
489 gnc_gui_get_entity_events (GHashTable *changes, const GncGUID *entity)
490 {
491  if (!changes || !entity)
492  return QOF_EVENT_NONE;
493 
494  return g_hash_table_lookup (changes, entity);
495 }
496 
497 void
498 gnc_gui_component_clear_watches (gint component_id)
499 {
500  ComponentInfo *ci;
501 
502  ci = find_component (component_id);
503  if (!ci)
504  {
505  PERR ("component not found");
506  return;
507  }
508 
509  clear_event_info (&ci->watch_info);
510 }
511 
512 void
513 gnc_unregister_gui_component (gint component_id)
514 {
515  ComponentInfo *ci;
516 
517  ci = find_component (component_id);
518  if (!ci)
519  {
520  PERR ("component %d not found", component_id);
521  return;
522  }
523 
524 #if CM_DEBUG
525  fprintf (stderr, "Unregister component %d in class %s\n",
526  ci->component_id,
527  ci->component_class ? ci->component_class : "(null)");
528 #endif
529 
530  gnc_gui_component_clear_watches (component_id);
531 
532  components = g_list_remove (components, ci);
533 
534  destroy_mask_hash (ci->watch_info.event_masks);
535  ci->watch_info.event_masks = NULL;
536 
537  destroy_event_hash (ci->watch_info.entity_events);
538  ci->watch_info.entity_events = NULL;
539 
540  g_free (ci->component_class);
541  ci->component_class = NULL;
542 
543  g_free (ci);
544 
545 #if CM_DEBUG
546  dump_components ();
547 #endif
548 }
549 
550 void
551 gnc_unregister_gui_component_by_data (const char *component_class,
552  gpointer user_data)
553 {
554  GList *list;
555  GList *node;
556 
557  list = find_components_by_data (user_data);
558 
559  for (node = list; node; node = node->next)
560  {
561  ComponentInfo *ci = node->data;
562 
563  if (component_class &&
564  g_strcmp0 (component_class, ci->component_class) != 0)
565  continue;
566 
567  gnc_unregister_gui_component (ci->component_id);
568  }
569 
570  g_list_free (list);
571 }
572 
573 void
574 gnc_suspend_gui_refresh (void)
575 {
576  suspend_counter++;
577 
578  if (suspend_counter == 0)
579  {
580  PERR ("suspend counter overflow");
581  }
582 }
583 
584 void
585 gnc_resume_gui_refresh (void)
586 {
587  if (suspend_counter == 0)
588  {
589  PERR ("suspend counter underflow");
590  return;
591  }
592 
593  suspend_counter--;
594 
595  if (suspend_counter == 0)
596  gnc_gui_refresh_internal (FALSE);
597 }
598 
599 static void
600 match_type_helper (gpointer key, gpointer value, gpointer user_data)
601 {
602  ComponentEventInfo *cei = user_data;
603  QofIdType id_type = key;
604  QofEventId * et = value;
605  QofEventId * et_2;
606 
607  et_2 = g_hash_table_lookup (cei->event_masks, id_type);
608  if (!et_2)
609  return;
610 
611  if (*et & *et_2)
612  cei->match = TRUE;
613 }
614 
615 static void
616 match_helper (gpointer key, gpointer value, gpointer user_data)
617 {
618  GncGUID *guid = key;
619  EventInfo *ei_1 = value;
620  EventInfo *ei_2;
621  ComponentEventInfo *cei = user_data;
622 
623  ei_2 = g_hash_table_lookup (cei->entity_events, guid);
624  if (!ei_2)
625  return;
626 
627  if (ei_1->event_mask & ei_2->event_mask)
628  cei->match = TRUE;
629 }
630 
631 static gboolean
632 changes_match (ComponentEventInfo *cei, ComponentEventInfo *changes)
633 {
634  ComponentEventInfo *big_cei;
635  GHashTable *smalltable;
636 
637  if (cei == NULL)
638  return FALSE;
639 
640  /* check types first, for efficiency */
641  cei->match = FALSE;
642  g_hash_table_foreach (changes->event_masks, match_type_helper, cei);
643  if (cei->match)
644  return TRUE;
645 
646  if (g_hash_table_size (cei->entity_events) <=
647  g_hash_table_size (changes->entity_events))
648  {
649  smalltable = cei->entity_events;
650  big_cei = changes;
651  }
652  else
653  {
654  smalltable = changes->entity_events;
655  big_cei = cei;
656  }
657 
658  big_cei->match = FALSE;
659 
660  g_hash_table_foreach (smalltable, match_helper, big_cei);
661 
662  return big_cei->match;
663 }
664 
665 static void
666 gnc_gui_refresh_internal (gboolean force)
667 {
668  GList *list;
669  GList *node;
670 
671  if (!got_events && !force)
672  return;
673 
674  gnc_suspend_gui_refresh ();
675 
676  {
677  GHashTable *table;
678 
679  table = changes_backup.event_masks;
680  changes_backup.event_masks = changes.event_masks;
681  changes.event_masks = table;
682 
683  table = changes_backup.entity_events;
684  changes_backup.entity_events = changes.entity_events;
685  changes.entity_events = table;
686  }
687 
688 #if CM_DEBUG
689  fprintf (stderr, "%srefresh!\n", force ? "forced " : "");
690 #endif
691 
692  list = find_component_ids_by_class (NULL);
693  // reverse the list so class GncPluginPageRegister is before register-single
694  list = g_list_reverse (list);
695 
696  for (node = list; node; node = node->next)
697  {
698  ComponentInfo *ci = find_component (GPOINTER_TO_INT (node->data));
699 
700  if (!ci)
701  continue;
702 
703  if (!ci->refresh_handler)
704  {
705 #if CM_DEBUG
706  fprintf (stderr, "no handlers for %s:%d\n", ci->component_class, ci->component_id);
707 #endif
708  continue;
709  }
710 
711  if (force)
712  {
713  if (ci->refresh_handler)
714  {
715 #if CM_DEBUG
716  fprintf (stderr, "calling %s:%d C handler\n", ci->component_class, ci->component_id);
717 #endif
718  ci->refresh_handler (NULL, ci->user_data);
719  }
720  }
721  else if (changes_match (&ci->watch_info, &changes_backup))
722  {
723  if (ci->refresh_handler)
724  {
725 #if CM_DEBUG
726  fprintf (stderr, "calling %s:%d C handler\n", ci->component_class, ci->component_id);
727 #endif
728  ci->refresh_handler (changes_backup.entity_events, ci->user_data);
729  }
730  }
731  else
732  {
733 #if CM_DEBUG
734  fprintf (stderr, "no match for %s:%d\n", ci->component_class, ci->component_id);
735 #endif
736  }
737  }
738 
739  clear_event_info (&changes_backup);
740  got_events = FALSE;
741 
742  g_list_free (list);
743 
744  gnc_resume_gui_refresh ();
745 }
746 
747 void
748 gnc_gui_refresh_all (void)
749 {
750  if (suspend_counter != 0)
751  {
752  PERR ("suspend counter not zero");
753  return;
754  }
755 
756  gnc_gui_refresh_internal (TRUE);
757 }
758 
759 gboolean
760 gnc_gui_refresh_suspended (void)
761 {
762  return suspend_counter != 0;
763 }
764 
765 void
766 gnc_close_gui_component (gint component_id)
767 {
768  ComponentInfo *ci;
769 
770  ci = find_component (component_id);
771  if (!ci)
772  {
773  PERR ("component not found");
774  return;
775  }
776 
777  if (!ci->close_handler)
778  return;
779 
780  if (ci->close_handler)
781  ci->close_handler (ci->user_data);
782 }
783 
784 void
785 gnc_close_gui_component_by_data (const char *component_class,
786  gpointer user_data)
787 {
788  GList *list;
789  GList *node;
790 
791  list = find_components_by_data (user_data);
792 
793  for (node = list; node; node = node->next)
794  {
795  ComponentInfo *ci = node->data;
796 
797  if (component_class &&
798  g_strcmp0 (component_class, ci->component_class) != 0)
799  continue;
800 
801  gnc_close_gui_component (ci->component_id);
802  }
803 
804  g_list_free (list);
805 }
806 
807 void
808 gnc_gui_component_set_session (gint component_id, gpointer session)
809 {
810  ComponentInfo *ci;
811 
812  ci = find_component (component_id);
813  if (!ci)
814  {
815  PERR ("component not found");
816  return;
817  }
818 
819  ci->session = session;
820 }
821 
822 void
823 gnc_close_gui_component_by_session (gpointer session)
824 {
825  GList *list;
826  GList *node;
827 
828  list = find_components_by_session (session);
829 
830  // reverse the list so class like dialog-options close before window-report
831  list = g_list_reverse (list);
832 
833  for (node = list; node; node = node->next)
834  {
835  ComponentInfo *ci = node->data;
836 
837  gnc_close_gui_component (ci->component_id);
838  }
839 
840  g_list_free (list);
841 }
842 
843 GList *
844 gnc_find_gui_components (const char *component_class,
845  GNCComponentFindHandler find_handler,
846  gpointer find_data)
847 {
848  GList *list = NULL;
849  GList *node;
850 
851  if (!component_class)
852  return NULL;
853 
854  for (node = components; node; node = node->next)
855  {
856  ComponentInfo *ci = node->data;
857 
858  if (g_strcmp0 (component_class, ci->component_class) != 0)
859  continue;
860 
861  if (find_handler && !find_handler (find_data, ci->user_data))
862  continue;
863 
864  list = g_list_prepend (list, ci->user_data);
865  }
866 
867  return list;
868 }
869 
870 gpointer
871 gnc_find_first_gui_component (const char *component_class,
872  GNCComponentFindHandler find_handler,
873  gpointer find_data)
874 {
875  GList *list;
876  gpointer user_data;
877 
878 #if CM_DEBUG
879  fprintf (stderr, "find: class %s, fn %p, data %p\n", component_class,
880  find_handler, find_data);
881 #endif
882  if (!component_class)
883  return NULL;
884 
885  list = gnc_find_gui_components (component_class, find_handler, find_data);
886  if (!list)
887  return NULL;
888 
889  user_data = list->data;
890 
891  g_list_free (list);
892 
893 #if CM_DEBUG
894  fprintf (stderr, "found: data %p\n", user_data);
895 #endif
896  return user_data;
897 }
898 
899 static GList *
900 find_component_ids_by_class (const char *component_class)
901 {
902  GList *list = NULL;
903  GList *node;
904 
905  for (node = components; node; node = node->next)
906  {
907  ComponentInfo *ci = node->data;
908 
909  if (component_class &&
910  g_strcmp0 (component_class, ci->component_class) != 0)
911  continue;
912 
913  list = g_list_prepend (list, GINT_TO_POINTER (ci->component_id));
914  }
915 
916  return list;
917 }
918 
919 gint
920 gnc_forall_gui_components (const char *component_class,
921  GNCComponentHandler handler,
922  gpointer iter_data)
923 {
924  GList *list;
925  GList *node;
926  gint count = 0;
927 
928  if (!handler)
929  return(0);
930 
931  /* so components can be destroyed during the forall */
932  list = find_component_ids_by_class (component_class);
933 
934  for (node = list; node; node = node->next)
935  {
936  ComponentInfo *ci = find_component (GPOINTER_TO_INT (node->data));
937 
938  if (!ci)
939  continue;
940 
941  if (handler (ci->component_class, ci->component_id, ci->user_data, iter_data))
942  count++;
943  }
944 
945  g_list_free (list);
946  return(count);
947 }
utility functions for the GnuCash UI
const gchar * QofIdTypeConst
QofIdTypeConst declaration.
Definition: qofid.h:82
GHashTable * guid_hash_table_new(void)
Returns a GHashTable with <GUID*> as key and a <gpointer> as value and no destructor functions for ke...
Definition: guid.cpp:254
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition: guid.cpp:173
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
const char * qof_string_cache_insert(const char *key)
You can use this function with g_hash_table_insert(), for the key (or value), as long as you use the ...
gint qof_event_register_handler(QofEventHandler handler, gpointer user_data)
Register a handler for events.
Definition: qofevent.cpp:73
const gchar * QofIdType
QofIdType declaration.
Definition: qofid.h:80
#define QOF_CHECK_TYPE(obj, type)
return TRUE if object is of the given type
Definition: qofid.h:102
gint QofEventId
Define the type of events allowed.
Definition: qofevent.h:45
GncGUID * guid_malloc(void)
Allocate memory for a GUID.
Definition: guid.cpp:104
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition: guid.h:84
void qof_event_unregister_handler(gint handler_id)
Unregister an event handler.
Definition: qofevent.cpp:103
const GncGUID * qof_entity_get_guid(gconstpointer ent)
#define QOF_EVENT_NONE
Default events for backwards compatibility.
Definition: qofevent.h:72
The type used to store guids in C.
Definition: guid.h:75
void qof_string_cache_remove(const char *key)
You can use this function as a destroy notifier for a GHashTable that uses common strings as keys (or...