24 #include "gnc-component-manager.h"
41 GHashTable * event_masks;
42 GHashTable * entity_events;
49 GNCComponentRefreshHandler refresh_handler;
50 GNCComponentCloseHandler close_handler;
55 char *component_class;
62 static guint suspend_counter = 0;
64 static gint next_component_id = 1;
65 static GList *components = NULL;
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;
85 dump_components (
void)
89 fprintf (stderr,
"Components:\n");
91 for (node = components; node; node = node->next)
95 fprintf (stderr,
" %s:\t%d\n",
96 ci->component_class ? ci->component_class :
"(null)",
100 fprintf (stderr,
"\n");
105 clear_mask_hash_helper (gpointer key, gpointer value, gpointer user_data)
116 clear_mask_hash (GHashTable *hash)
121 g_hash_table_foreach (hash, clear_mask_hash_helper, NULL);
125 destroy_mask_hash_helper (gpointer key, gpointer value, gpointer user_data)
134 destroy_mask_hash (GHashTable *hash)
136 g_hash_table_foreach_remove (hash, destroy_mask_hash_helper, NULL);
137 g_hash_table_destroy (hash);
141 destroy_event_hash_helper (gpointer key, gpointer value, gpointer user_data)
155 clear_event_hash (GHashTable *hash)
160 g_hash_table_foreach_remove (hash, destroy_event_hash_helper, NULL);
164 destroy_event_hash (GHashTable *hash)
166 clear_event_hash (hash);
167 g_hash_table_destroy (hash);
176 clear_mask_hash (cei->event_masks);
177 clear_event_hash (cei->entity_events);
186 if (!cei || !cei->entity_events || !entity)
189 hash = cei->entity_events;
199 if (g_hash_table_lookup_extended (hash, entity, &key, &value))
201 g_hash_table_remove (hash, entity);
210 ei = g_hash_table_lookup (hash, entity);
221 g_hash_table_insert (hash, key, ei);
225 ei->event_mask |= event_mask;
227 ei->event_mask = event_mask;
237 g_return_if_fail (cei);
238 g_return_if_fail (cei->event_masks);
239 g_return_if_fail (entity_type);
241 mask = g_hash_table_lookup (cei->event_masks, entity_type);
246 g_hash_table_insert (cei->event_masks, key, mask);
265 fprintf (stderr,
"event_handler: event %d, entity %p, guid %s\n", event_type,
268 add_event (&changes, guid, event_type, TRUE);
275 add_event_type (&changes, GNC_ID_TRANS, QOF_EVENT_MODIFY, TRUE);
278 add_event_type (&changes, entity->
e_type, event_type, TRUE);
282 if (suspend_counter == 0)
283 gnc_gui_refresh_internal (FALSE);
286 static gint handler_id;
289 gnc_component_manager_init (
void)
291 if (changes.entity_events)
293 PERR (
"component manager already initialized");
297 changes.event_masks = g_hash_table_new (g_str_hash, g_str_equal);
300 changes_backup.event_masks = g_hash_table_new (g_str_hash, g_str_equal);
307 gnc_component_manager_shutdown (
void)
309 if (!changes.entity_events)
311 PERR (
"component manager not initialized");
315 destroy_mask_hash (changes.event_masks);
316 changes.event_masks = NULL;
318 destroy_event_hash (changes.entity_events);
319 changes.entity_events = NULL;
321 destroy_mask_hash (changes_backup.event_masks);
322 changes_backup.event_masks = NULL;
324 destroy_event_hash (changes_backup.entity_events);
325 changes_backup.entity_events = NULL;
331 find_component (gint component_id)
335 for (node = components; node; node = node->next)
339 if (ci->component_id == component_id)
347 find_components_by_data (gpointer user_data)
352 for (node = components; node; node = node->next)
356 if (ci->user_data == user_data)
357 list = g_list_prepend (list, ci);
364 find_components_by_session (gpointer session)
369 for (node = components; node; node = node->next)
373 if (ci->session == session)
374 list = g_list_prepend (list, ci);
381 gnc_register_gui_component_internal (
const char * component_class)
386 g_return_val_if_fail (component_class, NULL);
389 component_id = next_component_id;
395 while (find_component (component_id))
396 if (++component_id == NO_COMPONENT)
399 if (component_id < 0)
400 PERR(
"Amazing! Half way to running out of component_ids.");
405 ci->watch_info.event_masks = g_hash_table_new (g_str_hash, g_str_equal);
408 ci->component_class = g_strdup (component_class);
409 ci->component_id = component_id;
412 components = g_list_prepend (components, ci);
415 next_component_id = component_id + 1;
418 fprintf (stderr,
"Register component %d in class %s\n",
419 component_id, component_class ? component_class :
"(null)");
427 gnc_register_gui_component (
const char *component_class,
428 GNCComponentRefreshHandler refresh_handler,
429 GNCComponentCloseHandler close_handler,
435 if (!component_class)
437 PERR (
"no class specified");
441 ci = gnc_register_gui_component_internal (component_class);
442 g_return_val_if_fail (ci, NO_COMPONENT);
444 ci->refresh_handler = refresh_handler;
445 ci->close_handler = close_handler;
446 ci->user_data = user_data;
448 return ci->component_id;
452 gnc_gui_component_watch_entity (gint component_id,
461 ci = find_component (component_id);
464 PERR (
"component not found");
468 add_event (&ci->watch_info, entity, event_mask, FALSE);
472 gnc_gui_component_watch_entity_type (gint component_id,
478 ci = find_component (component_id);
481 PERR (
"component not found");
485 add_event_type (&ci->watch_info, entity_type, event_mask, FALSE);
489 gnc_gui_get_entity_events (GHashTable *changes,
const GncGUID *entity)
491 if (!changes || !entity)
494 return g_hash_table_lookup (changes, entity);
498 gnc_gui_component_clear_watches (gint component_id)
502 ci = find_component (component_id);
505 PERR (
"component not found");
509 clear_event_info (&ci->watch_info);
513 gnc_unregister_gui_component (gint component_id)
517 ci = find_component (component_id);
520 PERR (
"component %d not found", component_id);
525 fprintf (stderr,
"Unregister component %d in class %s\n",
527 ci->component_class ? ci->component_class :
"(null)");
530 gnc_gui_component_clear_watches (component_id);
532 components = g_list_remove (components, ci);
534 destroy_mask_hash (ci->watch_info.event_masks);
535 ci->watch_info.event_masks = NULL;
537 destroy_event_hash (ci->watch_info.entity_events);
538 ci->watch_info.entity_events = NULL;
540 g_free (ci->component_class);
541 ci->component_class = NULL;
551 gnc_unregister_gui_component_by_data (
const char *component_class,
557 list = find_components_by_data (user_data);
559 for (node = list; node; node = node->next)
563 if (component_class &&
564 g_strcmp0 (component_class, ci->component_class) != 0)
567 gnc_unregister_gui_component (ci->component_id);
574 gnc_suspend_gui_refresh (
void)
578 if (suspend_counter == 0)
580 PERR (
"suspend counter overflow");
585 gnc_resume_gui_refresh (
void)
587 if (suspend_counter == 0)
589 PERR (
"suspend counter underflow");
595 if (suspend_counter == 0)
596 gnc_gui_refresh_internal (FALSE);
600 match_type_helper (gpointer key, gpointer value, gpointer user_data)
607 et_2 = g_hash_table_lookup (cei->event_masks, id_type);
616 match_helper (gpointer key, gpointer value, gpointer user_data)
623 ei_2 = g_hash_table_lookup (cei->entity_events, guid);
627 if (ei_1->event_mask & ei_2->event_mask)
635 GHashTable *smalltable;
642 g_hash_table_foreach (changes->event_masks, match_type_helper, cei);
646 if (g_hash_table_size (cei->entity_events) <=
647 g_hash_table_size (changes->entity_events))
649 smalltable = cei->entity_events;
654 smalltable = changes->entity_events;
658 big_cei->match = FALSE;
660 g_hash_table_foreach (smalltable, match_helper, big_cei);
662 return big_cei->match;
666 gnc_gui_refresh_internal (gboolean force)
671 if (!got_events && !force)
674 gnc_suspend_gui_refresh ();
679 table = changes_backup.event_masks;
680 changes_backup.event_masks = changes.event_masks;
681 changes.event_masks = table;
683 table = changes_backup.entity_events;
684 changes_backup.entity_events = changes.entity_events;
685 changes.entity_events = table;
689 fprintf (stderr,
"%srefresh!\n", force ?
"forced " :
"");
692 list = find_component_ids_by_class (NULL);
694 for (node = list; node; node = node->next)
696 ComponentInfo *ci = find_component (GPOINTER_TO_INT (node->data));
701 if (!ci->refresh_handler)
704 fprintf (stderr,
"no handlers for %s:%d\n", ci->component_class, ci->component_id);
711 if (ci->refresh_handler)
714 fprintf (stderr,
"calling %s:%d C handler\n", ci->component_class, ci->component_id);
716 ci->refresh_handler (NULL, ci->user_data);
719 else if (changes_match (&ci->watch_info, &changes_backup))
721 if (ci->refresh_handler)
724 fprintf (stderr,
"calling %s:%d C handler\n", ci->component_class, ci->component_id);
726 ci->refresh_handler (changes_backup.entity_events, ci->user_data);
732 fprintf (stderr,
"no match for %s:%d\n", ci->component_class, ci->component_id);
737 clear_event_info (&changes_backup);
742 gnc_resume_gui_refresh ();
746 gnc_gui_refresh_all (
void)
748 if (suspend_counter != 0)
750 PERR (
"suspend counter not zero");
754 gnc_gui_refresh_internal (TRUE);
758 gnc_gui_refresh_suspended (
void)
760 return suspend_counter != 0;
764 gnc_close_gui_component (gint component_id)
768 ci = find_component (component_id);
771 PERR (
"component not found");
775 if (!ci->close_handler)
778 if (ci->close_handler)
779 ci->close_handler (ci->user_data);
783 gnc_close_gui_component_by_data (
const char *component_class,
789 list = find_components_by_data (user_data);
791 for (node = list; node; node = node->next)
795 if (component_class &&
796 g_strcmp0 (component_class, ci->component_class) != 0)
799 gnc_close_gui_component (ci->component_id);
806 gnc_gui_component_set_session (gint component_id, gpointer session)
810 ci = find_component (component_id);
813 PERR (
"component not found");
817 ci->session = session;
821 gnc_close_gui_component_by_session (gpointer session)
826 list = find_components_by_session (session);
828 for (node = list; node; node = node->next)
832 gnc_close_gui_component (ci->component_id);
839 gnc_find_gui_components (
const char *component_class,
840 GNCComponentFindHandler find_handler,
846 if (!component_class)
849 for (node = components; node; node = node->next)
853 if (g_strcmp0 (component_class, ci->component_class) != 0)
856 if (find_handler && !find_handler (find_data, ci->user_data))
859 list = g_list_prepend (list, ci->user_data);
866 gnc_find_first_gui_component (
const char *component_class,
867 GNCComponentFindHandler find_handler,
874 fprintf (stderr,
"find: class %s, fn %p, data %p\n", component_class,
875 find_handler, find_data);
877 if (!component_class)
880 list = gnc_find_gui_components (component_class, find_handler, find_data);
884 user_data = list->data;
889 fprintf (stderr,
"found: data %p\n", user_data);
895 find_component_ids_by_class (
const char *component_class)
900 for (node = components; node; node = node->next)
904 if (component_class &&
905 g_strcmp0 (component_class, ci->component_class) != 0)
908 list = g_list_prepend (list, GINT_TO_POINTER (ci->component_id));
915 gnc_forall_gui_components (
const char *component_class,
916 GNCComponentHandler handler,
927 list = find_component_ids_by_class (component_class);
929 for (node = list; node; node = node->next)
931 ComponentInfo *ci = find_component (GPOINTER_TO_INT (node->data));
936 if (handler (ci->component_class, ci->component_id, ci->user_data, iter_data))
utility functions for the GnuCash UI
const gchar * QofIdTypeConst
GHashTable * guid_hash_table_new(void)
gchar * guid_to_string_buff(const GncGUID *guid, gchar *buff)
#define PERR(format, args...)
gint qof_event_register_handler(QofEventHandler handler, gpointer handler_data)
Register a handler for events.
#define QOF_CHECK_TYPE(obj, type)
GncGUID * guid_malloc(void)
#define GUID_ENCODING_LENGTH
void qof_event_unregister_handler(gint handler_id)
Unregister an event handler.
const GncGUID * qof_entity_get_guid(gconstpointer)
#define QOF_EVENT_NONE
Default events for backwards compatibility.
void qof_string_cache_remove(gconstpointer key)
gpointer qof_string_cache_insert(gconstpointer key)
const gchar * QofLogModule