Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtappbuilder / src / libABobj / obj.c
1
2 /*
3  * $XConsortium: obj.c /main/4 1996/10/02 16:11:56 drk $
4  * 
5  * @(#)obj.c    3.46 11 Feb 1994        cde_app_builder/src/libABobj
6  * 
7  * RESTRICTED CONFIDENTIAL INFORMATION:
8  * 
9  * The information in this document is subject to special restrictions in a
10  * confidential disclosure agreement between HP, IBM, Sun, USL, SCO and
11  * Univel.  Do not distribute this document outside HP, IBM, Sun, USL, SCO,
12  * or Univel without Sun's specific written approval.  This document and all
13  * copies and derivative works thereof must be returned or destroyed at Sun's
14  * request.
15  * 
16  * Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
17  * 
18  */
19
20
21 /*
22  * ABObj.c - manipulations of one gobj structure
23  */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <values.h>
29 #include <stdlib.h>
30 #include <sys/param.h>
31 #include <string.h>
32 #include "objP.h"               /* include first! */
33 #include <ab_private/trav.h>
34 #include <ab_private/util.h>
35 #include "obj_names_listP.h"
36 #include "obj_notifyP.h"
37
38 static int 
39 objP_or_tree_update_clients_with_data(
40                                       ABObj obj,
41                                       BOOL update_subtree,
42                                       int update_code,
43                                       void *update_data,
44                                       UpdateDataFreeFunc free_func
45 );
46
47 /*
48  * Gets the item for this object with index which_item
49  */
50 ABObj
51 obj_get_item(ABObj obj, int which_item)
52 {
53     AB_TRAVERSAL        trav;
54     ABObj               item = NULL;
55     int                 item_num = -1;  /* must be -1 */
56
57     for (trav_open(&trav, obj, AB_TRAV_ITEMS_FOR_OBJ);
58          (item = trav_next(&trav)) != NULL;)
59     {
60         ++item_num;
61         if (item_num == which_item)
62         {
63             break;
64         }
65     }
66     trav_close(&trav);
67     return item;
68 }
69
70 /*
71  * Return the Help Item for a given menubar
72  */
73 ABObj
74 obj_get_menubar_help_item(
75                           ABObj obj
76 )
77 {
78     AB_TRAVERSAL        trav;
79     ABObj               help_item = NULL;
80     ABObj               item;
81
82     if (!obj_is_menubar(obj))
83         return NULL;
84
85     for (trav_open(&trav, obj, AB_TRAV_ITEMS_FOR_OBJ);
86          (item = trav_next(&trav)) != NULL;)
87     {
88         if (obj_is_help_item(item) == TRUE)
89         {
90             help_item = item;
91             break;
92         }
93     }
94     trav_close(&trav);
95     return help_item;
96
97 }
98
99 /*
100  * Returns the number of this object, as a child of it's parent.
101  */
102 int
103 obj_get_child_num(ABObj obj)
104 {
105     int                 child_num = -1;
106     ABObj               child;
107
108     if (obj->parent == NULL)
109     {
110         goto epilogue;
111     }
112
113     for (child = obj->parent->first_child;
114          child != NULL; child = child->next_sibling)
115     {
116         ++child_num;
117         if (obj == child)
118         {
119             break;
120         }
121     }
122
123 epilogue:
124     return child_num;
125 }
126
127
128 ABObj
129 obj_get_container_child(ABObj obj)
130 {
131     ABObj               child;
132     for (child = obj->first_child; child != NULL;
133          child = child->next_sibling)
134     {
135         if (obj_is_container(child))
136         {
137             break;
138         }
139     }
140     return child;
141 }
142
143
144 /*
145  * Returns the item number of this object, with reference to it's parent
146  */
147 int
148 obj_get_item_num(ABObj obj)
149 {
150     int                 item_num = -1;
151     ABObj               item;
152     for (item = obj->parent->first_child;
153          item != NULL; item = item->next_sibling)
154     {
155         if (!obj_is_item(item))
156         {
157             continue;
158         }
159         ++item_num;
160         if (item == obj)
161         {
162             break;
163         }
164     }
165     return item_num;
166 }
167
168
169 ABObj
170 obj_get_menu(ABObj obj)
171 {
172     ABObj               child = NULL;
173     for (child = obj->first_child; child != NULL; child = child->next_sibling)
174     {
175         if (obj_is_menu(child))
176         {
177             break;
178         }
179     }
180     return child;
181 }
182
183
184 ABObj
185 obj_get_pane_child(ABObj obj)
186 {
187     ABObj               child;
188     for (child = obj->first_child; child != NULL;
189          child = child->next_sibling)
190     {
191         if (obj_is_pane(child))
192         {
193             break;
194         }
195     }
196     return child;
197 }
198
199
200 BOOL
201 obj_has_menu(ABObj obj)
202 {
203     if (!util_strempty(obj_get_menu_name(obj)))
204         return TRUE;
205     else
206         return FALSE;
207
208 }
209
210 /*
211  * Moves the children only if *all* the children can be moved.
212  */
213 int
214 obj_move_children(ABObj to, ABObj from)
215 {
216     int                 iReturn = 0;
217     int                 iRC = 0;/* return code */
218     ABObj               child = NULL;
219
220     /*
221      * Get permission for all children
222      */
223     for (child = from->first_child;
224          child != NULL; child = child->next_sibling)
225     {
226         if ((iRC = objP_notify_send_allow_reparent(child, to)) < 0)
227         {
228             iReturn = iRC;
229             goto epilogue;
230         }
231     }
232
233     while ((child = from->first_child) != NULL)
234     {
235
236         /*
237          * Don't send reparent to NULL
238          */
239
240         objP_notify_push_mode();
241         objP_notify_clear_mode(OBJEV_MODE_SEND_NOTIFY_EVS);
242         obj_unparent(child);
243         obj_append_child(to, child);
244         objP_notify_pop_mode();
245
246         objP_notify_send_reparent(child, from);
247     }
248
249 epilogue:
250     return iReturn;
251 }
252
253 /*
254  * maxlen < 1 means no max.
255  */
256 int
257 obj_ensure_unique_name(ABObj obj, ABObj root, int maxlen)
258 {
259     BOOL                unique = FALSE;
260     BOOL                error = FALSE;
261     BOOL                name_changed = FALSE;
262     char                mod_name[256];
263     char                obj_name[2048];
264     int                 oldlen;
265     int                 modlen;
266     int                 newlen;
267     AB_TRAVERSAL        trav;
268     ABObj               other_obj = NULL;
269     int                 modifier = 0;
270     unsigned            trav_type;
271
272     if (obj->name == NULL)
273     {
274         return -1;
275     }
276     if (maxlen < 1)
277     {
278         maxlen = 2048;
279     }
280     strncpy(obj_name, istr_string(obj->name), maxlen);
281     obj_name[2047] = 0;
282     modifier = 0;
283     unique = FALSE;
284     if (obj_is_module(obj))
285     {
286         trav_type = AB_TRAV_MODULES;
287     }
288     else
289     {
290         trav_type = AB_TRAV_UI;
291     }
292     while ((!unique) && (!error))
293     {
294         unique = TRUE;
295         for (trav_open(&trav, root, trav_type);
296              (other_obj = trav_next(&trav)) != NULL;)
297         {
298             if ((other_obj != obj)
299                 && (other_obj->name != NULL)
300                 && (strncmp(istr_string(other_obj->name), obj_name, maxlen)
301                     == 0))
302             {
303                 unique = FALSE;
304                 name_changed = TRUE;
305                 sprintf(mod_name, "%d", ++modifier);
306                 if ((strlen(mod_name) + 1) > (unsigned) maxlen)
307                 {
308                     error = TRUE;
309                     break;
310                 }
311                 oldlen = istr_len(obj->name);
312                 modlen = strlen(mod_name);
313                 newlen = oldlen + modlen;
314                 if (newlen > maxlen)
315                 {
316                     newlen = maxlen;
317                     oldlen = newlen - modlen;
318                 }
319                 strncpy(obj_name, istr_string(obj->name),
320                         oldlen);
321                 obj_name[oldlen] = 0;
322                 strcat(obj_name, mod_name);
323             }
324         }
325         trav_close(&trav);
326     }
327     if (name_changed && (!error))
328     {
329         /* printf("CHANGED %s -> %s\n", obj->name, obj_name); */
330
331         /*
332          * REMIND: CHANGE ALL BY-NAME REFS TO THIS OBJECT!
333          */
334         obj_set_name(obj, obj_name);
335     }
336
337     return error ? -1 : 0;
338 }
339
340
341 /*
342  * Munges name, as necessary to get uniqueness
343  */
344 int
345 obj_set_unique_name_istr(ABObj obj, ISTRING name)
346 {
347     int         rc = 0;         /* return code */
348     ISTRING     newName = obj_alloc_unique_name_istr(obj, name, -1);
349     rc = obj_set_name_istr(obj, newName);
350     istr_destroy(newName);
351     return rc;
352 }
353
354
355 int
356 obj_set_unique_name(ABObj obj, STRING strName)
357 {
358     int         return_value = 0;
359     ISTRING     name = istr_create(strName);
360
361     return_value = obj_set_unique_name_istr(obj, name);
362
363     istr_destroy(name);
364     return return_value;
365 }
366
367
368 STRING          
369 obj_alloc_unique_name(
370                         ABObj   obj, 
371                         STRING  name, 
372                         int     maxNameLen
373 )
374 {
375     ABObj       parent = obj->parent;
376     if (   (parent == NULL)
377         || (obj_find_by_name(parent, name) == obj) )
378     {
379         return strdup(name);
380     }
381     return obj_alloc_unique_name_for_child(parent, name, maxNameLen);
382 }
383
384
385 ISTRING         
386 obj_alloc_unique_name_istr(
387                         ABObj   obj, 
388                         ISTRING name, 
389                         int     maxNameLen
390 )
391 {
392     ABObj       parent = obj->parent;
393     if (   (parent == NULL)
394         || (obj_find_by_name(parent, istr_string(name)) == obj) )
395     {
396         return istr_dup(name);
397     }
398     return obj_alloc_unique_name_istr_for_child(parent, name, maxNameLen);
399 }
400
401
402 STRING          
403 obj_get_unique_name(
404                         ABObj   obj, 
405                         STRING  name, 
406                         int     maxNameLen,
407                         STRING  nameOutBuf
408 )
409 {
410     ABObj       parent = obj->parent;
411     if (   (parent == NULL)
412         || (obj_find_by_name(parent, name) == obj) )
413     {
414         return name;
415     }
416     return obj_get_unique_name_for_child(parent, name, maxNameLen-1, nameOutBuf);
417 }
418
419
420 /*
421  * maxlen < 1 means no max.
422  */
423 STRING
424 obj_alloc_unique_name_for_child(
425                       ABObj     obj,
426                       STRING    name,
427                       int       maxlen
428 )
429 {
430     char        nameBuf[8192];
431     STRING      unique_name = NULL;
432     *nameBuf = 0;
433
434     if (maxlen < 0)
435     {
436         maxlen = 8192;
437     }
438 #if defined (USL) || defined(__uxp__)
439         /*
440          * The USL specific changes were added ifdef due to time constraints
441          * They should be removed in the next release
442          */
443     maxlen = util_min(8191,maxlen);     /* don't overrun buf */
444 #else
445     maxlen = util_min(8192,maxlen);     /* don't overrun buf */
446 #endif
447
448     /*
449      * Alloc space and copy-in the unique name
450      */
451     unique_name = strdup(
452                 obj_get_unique_name_for_child(obj, name, maxlen-1, nameBuf));
453      
454     return unique_name;
455 }
456
457
458 ISTRING
459 obj_alloc_unique_name_istr_for_child(
460                       ABObj     obj,
461                       ISTRING   name,
462                       int       maxlen
463 )
464 {
465     char        nameBuf[8192];
466     ISTRING     unique_name = NULL;
467     *nameBuf = 0;
468
469     if (maxlen < 0)
470     {
471         maxlen = 8192;
472     }
473 #if defined (USL) || defined(__uxp__)
474     maxlen = util_min(8191,maxlen);
475 #else
476     maxlen = util_min(8192,maxlen);
477 #endif
478     unique_name = istr_create(
479         obj_get_unique_name_for_child(obj, istr_string(name), maxlen-1, nameBuf));
480
481     return unique_name;
482 }
483
484
485 STRING
486 obj_get_unique_name_for_child(
487     ABObj       obj,
488     STRING      name,
489     int         maxlen,
490     STRING      nameOutBuf
491 )
492 {
493     STRING      returnName = NULL;
494     int         nameOutBufSize = maxlen+1;      
495     StringList  namesList = NULL;
496     BOOL        done = FALSE;
497     BOOL        unique = FALSE;
498     int         nameLen = 0;
499     int         i = 0;
500     int         objNumberStart = 0;
501     int         objNumber = 0;
502
503     namesList = objP_get_names_scope_for_children(obj);
504     if (namesList == NULL)
505     {
506         returnName = name;
507         goto epilogue;
508     }
509
510     unique = !strlist_str_exists(namesList, name);
511     if (unique)
512     {
513         returnName = name;
514         goto epilogue;
515     }
516
517     /*
518      * Determine trailing number
519      */
520     util_strncpy(nameOutBuf, name, nameOutBufSize);
521     nameLen = strlen(nameOutBuf);
522     for (i = nameLen-1; i >= 0; --i)
523     {
524         if (!isdigit(nameOutBuf[i]))
525         {
526             break;
527         }
528     }
529     objNumberStart = i + 1;
530     objNumber = atoi(&(nameOutBuf[objNumberStart]));
531
532     /*
533      * Search for a unique name by incrementing trailing #
534      */
535     unique = FALSE;
536     done = FALSE;
537     while (!done)
538     {
539         if (++objNumber == 1)
540         {
541             /* skip 1 - name w/no # is implied 1 */
542             objNumber = 2;
543         }
544         sprintf(&(nameOutBuf[objNumberStart]), "%d", objNumber);
545         unique = !strlist_str_exists(namesList, nameOutBuf);
546         done = unique;
547     }
548     if (unique)
549     {
550         returnName = nameOutBuf;
551     }
552
553 epilogue:
554     return returnName;
555 }
556
557
558 /*
559  * Don't run this on a project!!! It's a severe dog, and can take many
560  * seconds to complete.
561  * 
562  * Run it on each module (root = an module) instead.
563  */
564 int
565 obj_tree_ensure_unique_names(ABObj root, int maxnamelen)
566 {
567     AB_TRAVERSAL        trav;
568     ABObj               obj;
569
570     for (trav_open(&trav, root, AB_TRAV_UI);
571          (obj = trav_next(&trav)) != NULL;)
572     {
573         obj_ensure_unique_name(obj, root, maxnamelen);
574     }
575     trav_close(&trav);
576     return 0;
577 }
578
579
580 /*
581  * Calls obj_tree_ensure_unique_names on each module in the given tree.
582  */
583 int
584 obj_tree_ensure_unique_names_in_modules(ABObj root, int maxnamelen)
585 {
586     AB_TRAVERSAL        trav;
587     ABObj               module;
588
589     for (trav_open(&trav, root, AB_TRAV_MODULES);
590          (module = trav_next(&trav)) != NULL;)
591     {
592         obj_tree_ensure_unique_names(module, maxnamelen);
593     }
594     trav_close(&trav);
595     return 0;
596 }
597
598 /*
599  * Gives an object a name by munging it's parent's name with it's own label.
600  * Used for item children, which aren't given names directly.
601  * 
602  * actual_parent overrides the parent of the object.  If actual_parent is NULL,
603  * the "normal" parent of the object is used.
604  */
605 int
606 obj_set_name_from_label(ABObj obj, STRING parent_name_in)
607 {
608     STRING              parent_name = NULL;
609     STRING              item_label = NULL;
610     STRING              new_name = NULL;
611
612     parent_name =
613         (parent_name_in == NULL ?
614          (obj->parent == NULL ?
615           NULL
616           :
617           istr_string(obj->parent->name)
618           )
619          :
620          parent_name
621         );
622     if (parent_name == NULL)
623     {
624         return -1;
625     }
626
627     if (istr_len(obj->label) > 0)
628     {
629         item_label = istr_string(obj->label);
630     }
631     else
632     {
633         item_label = "item";
634     }
635
636     obj_set_unique_name(obj,
637                  ab_ident_from_name_and_label(parent_name, item_label));
638
639     return 0;
640 }
641
642 int
643 obj_set_name_from_parent(ABObj obj, STRING suffix)
644 {
645     STRING              parent_name;
646     STRING              new_name = NULL;
647
648     parent_name = (obj->parent == NULL ?
649                    NULL
650                    :
651                    istr_string(obj->parent->name)
652         );
653
654     if (parent_name == NULL)
655     {
656         return -1;
657     }
658
659     obj_set_unique_name(obj,
660                  ab_ident_from_name_and_label(parent_name,
661                                               suffix));
662
663     return 0;
664
665 }
666
667 /*
668  * Gets a name for an object. Object may be NULL, or have a NULL name
669  * 
670  * Copies name into passed-in buffer name, guarantees 0 termination. returns
671  * parameter string
672  */
673 STRING
674 obj_get_safe_name(ABObj obj, STRING name, int name_size)
675 {
676     if (name_size < 1)
677     {
678         return name;
679     }
680
681     if (obj == NULL)
682     {
683         strncpy(name, "(nil ABObj)", name_size);
684     }
685     else if (obj_get_name(obj) == NULL)
686     {
687         char                buf[256];
688         sprintf(buf, "(ABObj:0x%08lx)", obj);
689         strncpy(name, buf, name_size);
690     }
691     else
692     {
693         strncpy(name, obj_get_name(obj), name_size);
694     }
695
696     name[name_size - 1] = 0;
697
698     return name;
699 }
700
701 /*************************************************************************
702 **                                                                      **
703 **              UPDATE_CLIENTS METHODS                                  **
704 **                                                                      **
705 *************************************************************************/
706
707 int
708 obj_update_clients(ABObj obj)
709 {
710     return objP_notify_send_update(obj, FALSE);
711 }
712
713
714 int
715 obj_tree_update_clients(ABObj tree)
716
717 {
718     return objP_notify_send_update(tree, TRUE);
719 }
720
721
722 int
723 obj_update_clients_with_data(
724                              ABObj obj,
725                              int update_code,
726                              void *update_data,
727                              UpdateDataFreeFunc free_func)
728 {
729     return objP_or_tree_update_clients_with_data(
730                            obj, FALSE, update_code, update_data, free_func);
731 }
732
733
734 int
735 obj_tree_update_clients_with_data(ABObj obj,
736                                   int update_code,
737                                   void *update_data,
738                                   UpdateDataFreeFunc free_func)
739 {
740     return objP_or_tree_update_clients_with_data(
741                             obj, TRUE, update_code, update_data, free_func);
742 }
743
744
745 static int
746 objP_or_tree_update_clients_with_data(
747                                       ABObj obj,
748                                       BOOL update_subtree,
749                                       int update_code,
750                                       void *update_data,
751                                       UpdateDataFreeFunc free_func
752 )
753 {
754     int                 iReturn = 0;
755
756     /*
757      * event notification will only free the data if the notify events are
758      * batched.  It's pretty smart about it, so we're going to go to batch
759      * mode and let it handle it.
760      */
761     objP_notify_push_mode();
762     objP_notify_set_mode(OBJEV_MODE_BATCH_NOTIFY_EVS);
763
764     iReturn = objP_notify_send_update_with_data(
765                   obj, update_subtree, update_code, update_data, free_func);
766
767     objP_notify_pop_mode();
768     return iReturn;
769 }