Branch data Line data Source code
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 : :
29 : : /** Declarations ****************************************************/
30 : :
31 : : #define CM_DEBUG 0
32 : :
33 : : typedef struct
34 : : {
35 : : QofIdType entity_type;
36 : : QofEventId event_mask;
37 : : } EntityTypeEventInfo;
38 : :
39 : : typedef struct
40 : : {
41 : : GHashTable * event_masks;
42 : : GHashTable * entity_events;
43 : :
44 : : gboolean match;
45 : : } ComponentEventInfo;
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;
58 : : } ComponentInfo;
59 : :
60 : :
61 : : /** Static Variables ************************************************/
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 : :
75 : : /** Prototypes ******************************************************/
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 : :
81 : : /** Implementations *************************************************/
82 : :
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 : 0 : clear_mask_hash_helper (gpointer key, gpointer value, gpointer user_data)
106 : : {
107 : 0 : QofEventId * et = value;
108 : :
109 : 0 : *et = 0;
110 : 0 : }
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 : 0 : clear_mask_hash (GHashTable *hash)
117 : : {
118 : 0 : if (hash == NULL)
119 : 0 : return;
120 : :
121 : 0 : g_hash_table_foreach (hash, clear_mask_hash_helper, NULL);
122 : : }
123 : :
124 : : static gboolean
125 : 0 : destroy_mask_hash_helper (gpointer key, gpointer value, gpointer user_data)
126 : : {
127 : 0 : qof_string_cache_remove (key);
128 : 0 : g_free (value);
129 : :
130 : 0 : return TRUE;
131 : : }
132 : :
133 : : static void
134 : 0 : destroy_mask_hash (GHashTable *hash)
135 : : {
136 : 0 : g_hash_table_foreach_remove (hash, destroy_mask_hash_helper, NULL);
137 : 0 : g_hash_table_destroy (hash);
138 : 0 : }
139 : :
140 : : static gboolean
141 : 0 : destroy_event_hash_helper (gpointer key, gpointer value, gpointer user_data)
142 : : {
143 : 0 : GncGUID *guid = key;
144 : 0 : EventInfo *ei = value;
145 : :
146 : 0 : guid_free (guid);
147 : 0 : g_free (ei);
148 : :
149 : 0 : 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 : 0 : clear_event_hash (GHashTable *hash)
156 : : {
157 : 0 : if (hash == NULL)
158 : 0 : return;
159 : :
160 : 0 : g_hash_table_foreach_remove (hash, destroy_event_hash_helper, NULL);
161 : : }
162 : :
163 : : static void
164 : 0 : destroy_event_hash (GHashTable *hash)
165 : : {
166 : 0 : clear_event_hash (hash);
167 : 0 : g_hash_table_destroy (hash);
168 : 0 : }
169 : :
170 : : static void
171 : 0 : clear_event_info (ComponentEventInfo *cei)
172 : : {
173 : 0 : if (!cei)
174 : 0 : return;
175 : :
176 : 0 : clear_mask_hash (cei->event_masks);
177 : 0 : clear_event_hash (cei->entity_events);
178 : : }
179 : :
180 : : static void
181 : 0 : add_event (ComponentEventInfo *cei, const GncGUID *entity,
182 : : QofEventId event_mask, gboolean or_in)
183 : : {
184 : : GHashTable *hash;
185 : :
186 : 0 : if (!cei || !cei->entity_events || !entity)
187 : 0 : return;
188 : :
189 : 0 : hash = cei->entity_events;
190 : :
191 : 0 : if (event_mask == 0)
192 : : {
193 : : gpointer key;
194 : : gpointer value;
195 : :
196 : 0 : if (or_in)
197 : 0 : return;
198 : :
199 : 0 : if (g_hash_table_lookup_extended (hash, entity, &key, &value))
200 : : {
201 : 0 : g_hash_table_remove (hash, entity);
202 : 0 : guid_free (key);
203 : 0 : g_free (value);
204 : : }
205 : : }
206 : : else
207 : : {
208 : : EventInfo *ei;
209 : :
210 : 0 : ei = g_hash_table_lookup (hash, entity);
211 : 0 : if (ei == NULL)
212 : : {
213 : : GncGUID *key;
214 : :
215 : 0 : key = guid_malloc ();
216 : 0 : *key = *entity;
217 : :
218 : 0 : ei = g_new (EventInfo, 1);
219 : 0 : ei->event_mask = 0;
220 : :
221 : 0 : g_hash_table_insert (hash, key, ei);
222 : : }
223 : :
224 : 0 : if (or_in)
225 : 0 : ei->event_mask |= event_mask;
226 : : else
227 : 0 : ei->event_mask = event_mask;
228 : : }
229 : : }
230 : :
231 : : static void
232 : 0 : add_event_type (ComponentEventInfo *cei, QofIdTypeConst entity_type,
233 : : QofEventId event_mask, gboolean or_in)
234 : : {
235 : : QofEventId *mask;
236 : :
237 : 0 : g_return_if_fail (cei);
238 : 0 : g_return_if_fail (cei->event_masks);
239 : 0 : g_return_if_fail (entity_type);
240 : :
241 : 0 : mask = g_hash_table_lookup (cei->event_masks, entity_type);
242 : 0 : if (!mask)
243 : : {
244 : 0 : const char * key = qof_string_cache_insert ((gpointer) entity_type);
245 : 0 : mask = g_new0 (QofEventId, 1);
246 : 0 : g_hash_table_insert (cei->event_masks, (gpointer)key, mask);
247 : : }
248 : :
249 : 0 : if (or_in)
250 : 0 : *mask |= event_mask;
251 : : else
252 : 0 : *mask = event_mask;
253 : : }
254 : :
255 : : static void
256 : 0 : gnc_cm_event_handler (QofInstance *entity,
257 : : QofEventId event_type,
258 : : gpointer user_data,
259 : : gpointer event_data)
260 : : {
261 : 0 : 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 : 0 : add_event (&changes, guid, event_type, TRUE);
269 : :
270 : 0 : 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 : 0 : add_event_type (&changes, GNC_ID_TRANS, QOF_EVENT_MODIFY, TRUE);
276 : : }
277 : : else
278 : 0 : add_event_type (&changes, entity->e_type, event_type, TRUE);
279 : :
280 : 0 : got_events = TRUE;
281 : :
282 : 0 : if (suspend_counter == 0)
283 : 0 : gnc_gui_refresh_internal (FALSE);
284 : 0 : }
285 : :
286 : : static gint handler_id;
287 : :
288 : : void
289 : 0 : gnc_component_manager_init (void)
290 : : {
291 : 0 : if (changes.entity_events)
292 : : {
293 : 0 : PERR ("component manager already initialized");
294 : 0 : return;
295 : : }
296 : :
297 : 0 : changes.event_masks = g_hash_table_new (g_str_hash, g_str_equal);
298 : 0 : changes.entity_events = guid_hash_table_new ();
299 : :
300 : 0 : changes_backup.event_masks = g_hash_table_new (g_str_hash, g_str_equal);
301 : 0 : changes_backup.entity_events = guid_hash_table_new ();
302 : :
303 : 0 : handler_id = qof_event_register_handler (gnc_cm_event_handler, NULL);
304 : : }
305 : :
306 : : void
307 : 0 : gnc_component_manager_shutdown (void)
308 : : {
309 : 0 : if (!changes.entity_events)
310 : : {
311 : 0 : PERR ("component manager not initialized");
312 : 0 : return;
313 : : }
314 : :
315 : 0 : destroy_mask_hash (changes.event_masks);
316 : 0 : changes.event_masks = NULL;
317 : :
318 : 0 : destroy_event_hash (changes.entity_events);
319 : 0 : changes.entity_events = NULL;
320 : :
321 : 0 : destroy_mask_hash (changes_backup.event_masks);
322 : 0 : changes_backup.event_masks = NULL;
323 : :
324 : 0 : destroy_event_hash (changes_backup.entity_events);
325 : 0 : changes_backup.entity_events = NULL;
326 : :
327 : 0 : qof_event_unregister_handler (handler_id);
328 : : }
329 : :
330 : : static ComponentInfo *
331 : 0 : find_component (gint component_id)
332 : : {
333 : : GList *node;
334 : :
335 : 0 : for (node = components; node; node = node->next)
336 : : {
337 : 0 : ComponentInfo *ci = node->data;
338 : :
339 : 0 : if (ci->component_id == component_id)
340 : 0 : return ci;
341 : : }
342 : :
343 : 0 : return NULL;
344 : : }
345 : :
346 : : static GList *
347 : 0 : find_components_by_data (gpointer user_data)
348 : : {
349 : 0 : GList *list = NULL;
350 : : GList *node;
351 : :
352 : 0 : for (node = components; node; node = node->next)
353 : : {
354 : 0 : ComponentInfo *ci = node->data;
355 : :
356 : 0 : if (ci->user_data == user_data)
357 : 0 : list = g_list_prepend (list, ci);
358 : : }
359 : :
360 : 0 : return list;
361 : : }
362 : :
363 : : static GList *
364 : 0 : find_components_by_session (gpointer session)
365 : : {
366 : 0 : GList *list = NULL;
367 : : GList *node;
368 : :
369 : 0 : for (node = components; node; node = node->next)
370 : : {
371 : 0 : ComponentInfo *ci = node->data;
372 : :
373 : 0 : if (ci->session == session)
374 : 0 : list = g_list_prepend (list, ci);
375 : : }
376 : :
377 : 0 : return list;
378 : : }
379 : :
380 : : static ComponentInfo *
381 : 0 : gnc_register_gui_component_internal (const char * component_class)
382 : : {
383 : : ComponentInfo *ci;
384 : : gint component_id;
385 : :
386 : 0 : g_return_val_if_fail (component_class, NULL);
387 : :
388 : : /* look for a free handler id */
389 : 0 : 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 : 0 : while (find_component (component_id))
396 : 0 : if (++component_id == NO_COMPONENT)
397 : 0 : component_id++;
398 : :
399 : 0 : if (component_id < 0)
400 : 0 : PERR("Amazing! Half way to running out of component_ids.");
401 : :
402 : : /* found one, add the handler */
403 : 0 : ci = g_new0 (ComponentInfo, 1);
404 : :
405 : 0 : ci->watch_info.event_masks = g_hash_table_new (g_str_hash, g_str_equal);
406 : 0 : ci->watch_info.entity_events = guid_hash_table_new ();
407 : :
408 : 0 : ci->component_class = g_strdup (component_class);
409 : 0 : ci->component_id = component_id;
410 : 0 : ci->session = NULL;
411 : :
412 : 0 : components = g_list_prepend (components, ci);
413 : :
414 : : /* update id for next registration */
415 : 0 : 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 : 0 : return ci;
424 : : }
425 : :
426 : : gint
427 : 0 : 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 : 0 : if (!component_class)
436 : : {
437 : 0 : PERR ("no class specified");
438 : 0 : return NO_COMPONENT;
439 : : }
440 : :
441 : 0 : ci = gnc_register_gui_component_internal (component_class);
442 : 0 : g_return_val_if_fail (ci, NO_COMPONENT);
443 : :
444 : 0 : ci->refresh_handler = refresh_handler;
445 : 0 : ci->close_handler = close_handler;
446 : 0 : ci->user_data = user_data;
447 : :
448 : 0 : return ci->component_id;
449 : : }
450 : :
451 : : void
452 : 0 : gnc_gui_component_watch_entity (gint component_id,
453 : : const GncGUID *entity,
454 : : QofEventId event_mask)
455 : : {
456 : : ComponentInfo *ci;
457 : :
458 : 0 : if (entity == NULL)
459 : 0 : return;
460 : :
461 : 0 : ci = find_component (component_id);
462 : 0 : if (!ci)
463 : : {
464 : 0 : PERR ("component not found");
465 : 0 : return;
466 : : }
467 : :
468 : 0 : add_event (&ci->watch_info, entity, event_mask, FALSE);
469 : : }
470 : :
471 : : void
472 : 0 : gnc_gui_component_watch_entity_type (gint component_id,
473 : : QofIdTypeConst entity_type,
474 : : QofEventId event_mask)
475 : : {
476 : : ComponentInfo *ci;
477 : :
478 : 0 : ci = find_component (component_id);
479 : 0 : if (!ci)
480 : : {
481 : 0 : PERR ("component not found");
482 : 0 : return;
483 : : }
484 : :
485 : 0 : add_event_type (&ci->watch_info, entity_type, event_mask, FALSE);
486 : : }
487 : :
488 : : const EventInfo *
489 : 0 : gnc_gui_get_entity_events (GHashTable *changes, const GncGUID *entity)
490 : : {
491 : 0 : if (!changes || !entity)
492 : 0 : return QOF_EVENT_NONE;
493 : :
494 : 0 : return g_hash_table_lookup (changes, entity);
495 : : }
496 : :
497 : : void
498 : 0 : gnc_gui_component_clear_watches (gint component_id)
499 : : {
500 : : ComponentInfo *ci;
501 : :
502 : 0 : ci = find_component (component_id);
503 : 0 : if (!ci)
504 : : {
505 : 0 : PERR ("component not found");
506 : 0 : return;
507 : : }
508 : :
509 : 0 : clear_event_info (&ci->watch_info);
510 : : }
511 : :
512 : : void
513 : 0 : gnc_unregister_gui_component (gint component_id)
514 : : {
515 : : ComponentInfo *ci;
516 : :
517 : 0 : ci = find_component (component_id);
518 : 0 : if (!ci)
519 : : {
520 : 0 : PERR ("component %d not found", component_id);
521 : 0 : 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 : 0 : gnc_gui_component_clear_watches (component_id);
531 : :
532 : 0 : components = g_list_remove (components, ci);
533 : :
534 : 0 : destroy_mask_hash (ci->watch_info.event_masks);
535 : 0 : ci->watch_info.event_masks = NULL;
536 : :
537 : 0 : destroy_event_hash (ci->watch_info.entity_events);
538 : 0 : ci->watch_info.entity_events = NULL;
539 : :
540 : 0 : g_free (ci->component_class);
541 : 0 : ci->component_class = NULL;
542 : :
543 : 0 : g_free (ci);
544 : :
545 : : #if CM_DEBUG
546 : : dump_components ();
547 : : #endif
548 : : }
549 : :
550 : : void
551 : 0 : gnc_unregister_gui_component_by_data (const char *component_class,
552 : : gpointer user_data)
553 : : {
554 : : GList *list;
555 : : GList *node;
556 : :
557 : 0 : list = find_components_by_data (user_data);
558 : :
559 : 0 : for (node = list; node; node = node->next)
560 : : {
561 : 0 : ComponentInfo *ci = node->data;
562 : :
563 : 0 : if (component_class &&
564 : 0 : g_strcmp0 (component_class, ci->component_class) != 0)
565 : 0 : continue;
566 : :
567 : 0 : gnc_unregister_gui_component (ci->component_id);
568 : : }
569 : :
570 : 0 : g_list_free (list);
571 : 0 : }
572 : :
573 : : void
574 : 0 : gnc_suspend_gui_refresh (void)
575 : : {
576 : 0 : suspend_counter++;
577 : :
578 : 0 : if (suspend_counter == 0)
579 : : {
580 : 0 : PERR ("suspend counter overflow");
581 : : }
582 : 0 : }
583 : :
584 : : void
585 : 0 : gnc_resume_gui_refresh (void)
586 : : {
587 : 0 : if (suspend_counter == 0)
588 : : {
589 : 0 : PERR ("suspend counter underflow");
590 : 0 : return;
591 : : }
592 : :
593 : 0 : suspend_counter--;
594 : :
595 : 0 : if (suspend_counter == 0)
596 : 0 : gnc_gui_refresh_internal (FALSE);
597 : : }
598 : :
599 : : static void
600 : 0 : match_type_helper (gpointer key, gpointer value, gpointer user_data)
601 : : {
602 : 0 : ComponentEventInfo *cei = user_data;
603 : 0 : QofIdType id_type = key;
604 : 0 : QofEventId * et = value;
605 : : QofEventId * et_2;
606 : :
607 : 0 : et_2 = g_hash_table_lookup (cei->event_masks, id_type);
608 : 0 : if (!et_2)
609 : 0 : return;
610 : :
611 : 0 : if (*et & *et_2)
612 : 0 : cei->match = TRUE;
613 : : }
614 : :
615 : : static void
616 : 0 : match_helper (gpointer key, gpointer value, gpointer user_data)
617 : : {
618 : 0 : GncGUID *guid = key;
619 : 0 : EventInfo *ei_1 = value;
620 : : EventInfo *ei_2;
621 : 0 : ComponentEventInfo *cei = user_data;
622 : :
623 : 0 : ei_2 = g_hash_table_lookup (cei->entity_events, guid);
624 : 0 : if (!ei_2)
625 : 0 : return;
626 : :
627 : 0 : if (ei_1->event_mask & ei_2->event_mask)
628 : 0 : cei->match = TRUE;
629 : : }
630 : :
631 : : static gboolean
632 : 0 : changes_match (ComponentEventInfo *cei, ComponentEventInfo *changes)
633 : : {
634 : : ComponentEventInfo *big_cei;
635 : : GHashTable *smalltable;
636 : :
637 : 0 : if (cei == NULL)
638 : 0 : return FALSE;
639 : :
640 : : /* check types first, for efficiency */
641 : 0 : cei->match = FALSE;
642 : 0 : g_hash_table_foreach (changes->event_masks, match_type_helper, cei);
643 : 0 : if (cei->match)
644 : 0 : return TRUE;
645 : :
646 : 0 : if (g_hash_table_size (cei->entity_events) <=
647 : 0 : g_hash_table_size (changes->entity_events))
648 : : {
649 : 0 : smalltable = cei->entity_events;
650 : 0 : big_cei = changes;
651 : : }
652 : : else
653 : : {
654 : 0 : smalltable = changes->entity_events;
655 : 0 : big_cei = cei;
656 : : }
657 : :
658 : 0 : big_cei->match = FALSE;
659 : :
660 : 0 : g_hash_table_foreach (smalltable, match_helper, big_cei);
661 : :
662 : 0 : return big_cei->match;
663 : : }
664 : :
665 : : static void
666 : 0 : gnc_gui_refresh_internal (gboolean force)
667 : : {
668 : : GList *list;
669 : : GList *node;
670 : :
671 : 0 : if (!got_events && !force)
672 : 0 : return;
673 : :
674 : 0 : gnc_suspend_gui_refresh ();
675 : :
676 : : {
677 : : GHashTable *table;
678 : :
679 : 0 : table = changes_backup.event_masks;
680 : 0 : changes_backup.event_masks = changes.event_masks;
681 : 0 : changes.event_masks = table;
682 : :
683 : 0 : table = changes_backup.entity_events;
684 : 0 : changes_backup.entity_events = changes.entity_events;
685 : 0 : changes.entity_events = table;
686 : : }
687 : :
688 : : #if CM_DEBUG
689 : : fprintf (stderr, "%srefresh!\n", force ? "forced " : "");
690 : : #endif
691 : :
692 : 0 : list = find_component_ids_by_class (NULL);
693 : : // reverse the list so class GncPluginPageRegister is before register-single
694 : 0 : list = g_list_reverse (list);
695 : :
696 : 0 : for (node = list; node; node = node->next)
697 : : {
698 : 0 : ComponentInfo *ci = find_component (GPOINTER_TO_INT (node->data));
699 : :
700 : 0 : if (!ci)
701 : 0 : continue;
702 : :
703 : 0 : 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 : 0 : continue;
709 : : }
710 : :
711 : 0 : if (force)
712 : : {
713 : 0 : 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 : 0 : ci->refresh_handler (NULL, ci->user_data);
719 : : }
720 : : }
721 : 0 : else if (changes_match (&ci->watch_info, &changes_backup))
722 : : {
723 : 0 : 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 : 0 : 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 : 0 : clear_event_info (&changes_backup);
740 : 0 : got_events = FALSE;
741 : :
742 : 0 : g_list_free (list);
743 : :
744 : 0 : gnc_resume_gui_refresh ();
745 : : }
746 : :
747 : : void
748 : 0 : gnc_gui_refresh_all (void)
749 : : {
750 : 0 : if (suspend_counter != 0)
751 : : {
752 : 0 : PERR ("suspend counter not zero");
753 : 0 : return;
754 : : }
755 : :
756 : 0 : gnc_gui_refresh_internal (TRUE);
757 : : }
758 : :
759 : : gboolean
760 : 0 : gnc_gui_refresh_suspended (void)
761 : : {
762 : 0 : return suspend_counter != 0;
763 : : }
764 : :
765 : : void
766 : 0 : gnc_close_gui_component (gint component_id)
767 : : {
768 : : ComponentInfo *ci;
769 : :
770 : 0 : ci = find_component (component_id);
771 : 0 : if (!ci)
772 : : {
773 : 0 : PERR ("component not found");
774 : 0 : return;
775 : : }
776 : :
777 : 0 : if (!ci->close_handler)
778 : 0 : return;
779 : :
780 : 0 : if (ci->close_handler)
781 : 0 : ci->close_handler (ci->user_data);
782 : : }
783 : :
784 : : void
785 : 0 : gnc_close_gui_component_by_data (const char *component_class,
786 : : gpointer user_data)
787 : : {
788 : : GList *list;
789 : : GList *node;
790 : :
791 : 0 : list = find_components_by_data (user_data);
792 : :
793 : 0 : for (node = list; node; node = node->next)
794 : : {
795 : 0 : ComponentInfo *ci = node->data;
796 : :
797 : 0 : if (component_class &&
798 : 0 : g_strcmp0 (component_class, ci->component_class) != 0)
799 : 0 : continue;
800 : :
801 : 0 : gnc_close_gui_component (ci->component_id);
802 : : }
803 : :
804 : 0 : g_list_free (list);
805 : 0 : }
806 : :
807 : : void
808 : 0 : gnc_gui_component_set_session (gint component_id, gpointer session)
809 : : {
810 : : ComponentInfo *ci;
811 : :
812 : 0 : ci = find_component (component_id);
813 : 0 : if (!ci)
814 : : {
815 : 0 : PERR ("component not found");
816 : 0 : return;
817 : : }
818 : :
819 : 0 : ci->session = session;
820 : : }
821 : :
822 : : void
823 : 0 : gnc_close_gui_component_by_session (gpointer session)
824 : : {
825 : : GList *list;
826 : : GList *node;
827 : :
828 : 0 : list = find_components_by_session (session);
829 : :
830 : : // reverse the list so class like dialog-options close before window-report
831 : 0 : list = g_list_reverse (list);
832 : :
833 : 0 : for (node = list; node; node = node->next)
834 : : {
835 : 0 : ComponentInfo *ci = node->data;
836 : :
837 : 0 : gnc_close_gui_component (ci->component_id);
838 : : }
839 : :
840 : 0 : g_list_free (list);
841 : 0 : }
842 : :
843 : : GList *
844 : 0 : gnc_find_gui_components (const char *component_class,
845 : : GNCComponentFindHandler find_handler,
846 : : gpointer find_data)
847 : : {
848 : 0 : GList *list = NULL;
849 : : GList *node;
850 : :
851 : 0 : if (!component_class)
852 : 0 : return NULL;
853 : :
854 : 0 : for (node = components; node; node = node->next)
855 : : {
856 : 0 : ComponentInfo *ci = node->data;
857 : :
858 : 0 : if (g_strcmp0 (component_class, ci->component_class) != 0)
859 : 0 : continue;
860 : :
861 : 0 : if (find_handler && !find_handler (find_data, ci->user_data))
862 : 0 : continue;
863 : :
864 : 0 : list = g_list_prepend (list, ci->user_data);
865 : : }
866 : :
867 : 0 : return list;
868 : : }
869 : :
870 : : gpointer
871 : 0 : 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 : 0 : if (!component_class)
883 : 0 : return NULL;
884 : :
885 : 0 : list = gnc_find_gui_components (component_class, find_handler, find_data);
886 : 0 : if (!list)
887 : 0 : return NULL;
888 : :
889 : 0 : user_data = list->data;
890 : :
891 : 0 : g_list_free (list);
892 : :
893 : : #if CM_DEBUG
894 : : fprintf (stderr, "found: data %p\n", user_data);
895 : : #endif
896 : 0 : return user_data;
897 : : }
898 : :
899 : : static GList *
900 : 0 : find_component_ids_by_class (const char *component_class)
901 : : {
902 : 0 : GList *list = NULL;
903 : : GList *node;
904 : :
905 : 0 : for (node = components; node; node = node->next)
906 : : {
907 : 0 : ComponentInfo *ci = node->data;
908 : :
909 : 0 : if (component_class &&
910 : 0 : g_strcmp0 (component_class, ci->component_class) != 0)
911 : 0 : continue;
912 : :
913 : 0 : list = g_list_prepend (list, GINT_TO_POINTER (ci->component_id));
914 : : }
915 : :
916 : 0 : return list;
917 : : }
918 : :
919 : : gint
920 : 0 : gnc_forall_gui_components (const char *component_class,
921 : : GNCComponentHandler handler,
922 : : gpointer iter_data)
923 : : {
924 : : GList *list;
925 : : GList *node;
926 : 0 : gint count = 0;
927 : :
928 : 0 : if (!handler)
929 : 0 : return(0);
930 : :
931 : : /* so components can be destroyed during the forall */
932 : 0 : list = find_component_ids_by_class (component_class);
933 : :
934 : 0 : for (node = list; node; node = node->next)
935 : : {
936 : 0 : ComponentInfo *ci = find_component (GPOINTER_TO_INT (node->data));
937 : :
938 : 0 : if (!ci)
939 : 0 : continue;
940 : :
941 : 0 : if (handler (ci->component_class, ci->component_id, ci->user_data, iter_data))
942 : 0 : count++;
943 : : }
944 : :
945 : 0 : g_list_free (list);
946 : 0 : return(count);
947 : : }
|