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