cdesktopenv/cde/programs/dtappbuilder/src/libABobj/obj.c

783 lines
15 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/*
* $XConsortium: obj.c /main/4 1996/10/02 16:11:56 drk $
*
* @(#)obj.c 3.46 11 Feb 1994 cde_app_builder/src/libABobj
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special restrictions in a
* confidential disclosure agreement between HP, IBM, Sun, USL, SCO and
* Univel. Do not distribute this document outside HP, IBM, Sun, USL, SCO,
* or Univel without Sun's specific written approval. This document and all
* copies and derivative works thereof must be returned or destroyed at Sun's
* request.
*
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
*
*/
/*
* ABObj.c - manipulations of one gobj structure
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#if !defined(CSRG_BASED)
#include <values.h>
#endif
#include <stdlib.h>
#include <sys/param.h>
#include <string.h>
#include "objP.h" /* include first! */
#include <ab_private/trav.h>
#include <ab_private/util.h>
#include "obj_names_listP.h"
#include "obj_notifyP.h"
static int
objP_or_tree_update_clients_with_data(
ABObj obj,
BOOL update_subtree,
int update_code,
void *update_data,
UpdateDataFreeFunc free_func
);
/*
* Gets the item for this object with index which_item
*/
ABObj
obj_get_item(ABObj obj, int which_item)
{
AB_TRAVERSAL trav;
ABObj item = NULL;
int item_num = -1; /* must be -1 */
for (trav_open(&trav, obj, AB_TRAV_ITEMS_FOR_OBJ);
(item = trav_next(&trav)) != NULL;)
{
++item_num;
if (item_num == which_item)
{
break;
}
}
trav_close(&trav);
return item;
}
/*
* Return the Help Item for a given menubar
*/
ABObj
obj_get_menubar_help_item(
ABObj obj
)
{
AB_TRAVERSAL trav;
ABObj help_item = NULL;
ABObj item;
if (!obj_is_menubar(obj))
return NULL;
for (trav_open(&trav, obj, AB_TRAV_ITEMS_FOR_OBJ);
(item = trav_next(&trav)) != NULL;)
{
if (obj_is_help_item(item) == TRUE)
{
help_item = item;
break;
}
}
trav_close(&trav);
return help_item;
}
/*
* Returns the number of this object, as a child of it's parent.
*/
int
obj_get_child_num(ABObj obj)
{
int child_num = -1;
ABObj child;
if (obj->parent == NULL)
{
goto epilogue;
}
for (child = obj->parent->first_child;
child != NULL; child = child->next_sibling)
{
++child_num;
if (obj == child)
{
break;
}
}
epilogue:
return child_num;
}
ABObj
obj_get_container_child(ABObj obj)
{
ABObj child;
for (child = obj->first_child; child != NULL;
child = child->next_sibling)
{
if (obj_is_container(child))
{
break;
}
}
return child;
}
/*
* Returns the item number of this object, with reference to it's parent
*/
int
obj_get_item_num(ABObj obj)
{
int item_num = -1;
ABObj item;
for (item = obj->parent->first_child;
item != NULL; item = item->next_sibling)
{
if (!obj_is_item(item))
{
continue;
}
++item_num;
if (item == obj)
{
break;
}
}
return item_num;
}
ABObj
obj_get_menu(ABObj obj)
{
ABObj child = NULL;
for (child = obj->first_child; child != NULL; child = child->next_sibling)
{
if (obj_is_menu(child))
{
break;
}
}
return child;
}
ABObj
obj_get_pane_child(ABObj obj)
{
ABObj child;
for (child = obj->first_child; child != NULL;
child = child->next_sibling)
{
if (obj_is_pane(child))
{
break;
}
}
return child;
}
BOOL
obj_has_menu(ABObj obj)
{
if (!util_strempty(obj_get_menu_name(obj)))
return TRUE;
else
return FALSE;
}
/*
* Moves the children only if *all* the children can be moved.
*/
int
obj_move_children(ABObj to, ABObj from)
{
int iReturn = 0;
int iRC = 0;/* return code */
ABObj child = NULL;
/*
* Get permission for all children
*/
for (child = from->first_child;
child != NULL; child = child->next_sibling)
{
if ((iRC = objP_notify_send_allow_reparent(child, to)) < 0)
{
iReturn = iRC;
goto epilogue;
}
}
while ((child = from->first_child) != NULL)
{
/*
* Don't send reparent to NULL
*/
objP_notify_push_mode();
objP_notify_clear_mode(OBJEV_MODE_SEND_NOTIFY_EVS);
obj_unparent(child);
obj_append_child(to, child);
objP_notify_pop_mode();
objP_notify_send_reparent(child, from);
}
epilogue:
return iReturn;
}
/*
* maxlen < 1 means no max.
*/
int
obj_ensure_unique_name(ABObj obj, ABObj root, int maxlen)
{
BOOL unique = FALSE;
BOOL error = FALSE;
BOOL name_changed = FALSE;
char mod_name[256];
char obj_name[2048];
int oldlen;
int modlen;
int newlen;
AB_TRAVERSAL trav;
ABObj other_obj = NULL;
int modifier = 0;
unsigned trav_type;
if (obj->name == NULL)
{
return -1;
}
if (maxlen < 1)
{
maxlen = 2048;
}
strncpy(obj_name, istr_string(obj->name), maxlen);
obj_name[2047] = 0;
modifier = 0;
unique = FALSE;
if (obj_is_module(obj))
{
trav_type = AB_TRAV_MODULES;
}
else
{
trav_type = AB_TRAV_UI;
}
while ((!unique) && (!error))
{
unique = TRUE;
for (trav_open(&trav, root, trav_type);
(other_obj = trav_next(&trav)) != NULL;)
{
if ((other_obj != obj)
&& (other_obj->name != NULL)
&& (strncmp(istr_string(other_obj->name), obj_name, maxlen)
== 0))
{
unique = FALSE;
name_changed = TRUE;
sprintf(mod_name, "%d", ++modifier);
if ((strlen(mod_name) + 1) > (unsigned) maxlen)
{
error = TRUE;
break;
}
oldlen = istr_len(obj->name);
modlen = strlen(mod_name);
newlen = oldlen + modlen;
if (newlen > maxlen)
{
newlen = maxlen;
oldlen = newlen - modlen;
}
strncpy(obj_name, istr_string(obj->name),
oldlen);
obj_name[oldlen] = 0;
strcat(obj_name, mod_name);
}
}
trav_close(&trav);
}
if (name_changed && (!error))
{
/* printf("CHANGED %s -> %s\n", obj->name, obj_name); */
/*
* REMIND: CHANGE ALL BY-NAME REFS TO THIS OBJECT!
*/
obj_set_name(obj, obj_name);
}
return error ? -1 : 0;
}
/*
* Munges name, as necessary to get uniqueness
*/
int
obj_set_unique_name_istr(ABObj obj, ISTRING name)
{
int rc = 0; /* return code */
ISTRING newName = obj_alloc_unique_name_istr(obj, name, -1);
rc = obj_set_name_istr(obj, newName);
istr_destroy(newName);
return rc;
}
int
obj_set_unique_name(ABObj obj, STRING strName)
{
int return_value = 0;
ISTRING name = istr_create(strName);
return_value = obj_set_unique_name_istr(obj, name);
istr_destroy(name);
return return_value;
}
STRING
obj_alloc_unique_name(
ABObj obj,
STRING name,
int maxNameLen
)
{
ABObj parent = obj->parent;
if ( (parent == NULL)
|| (obj_find_by_name(parent, name) == obj) )
{
return strdup(name);
}
return obj_alloc_unique_name_for_child(parent, name, maxNameLen);
}
ISTRING
obj_alloc_unique_name_istr(
ABObj obj,
ISTRING name,
int maxNameLen
)
{
ABObj parent = obj->parent;
if ( (parent == NULL)
|| (obj_find_by_name(parent, istr_string(name)) == obj) )
{
return istr_dup(name);
}
return obj_alloc_unique_name_istr_for_child(parent, name, maxNameLen);
}
STRING
obj_get_unique_name(
ABObj obj,
STRING name,
int maxNameLen,
STRING nameOutBuf
)
{
ABObj parent = obj->parent;
if ( (parent == NULL)
|| (obj_find_by_name(parent, name) == obj) )
{
return name;
}
return obj_get_unique_name_for_child(parent, name, maxNameLen-1, nameOutBuf);
}
/*
* maxlen < 1 means no max.
*/
STRING
obj_alloc_unique_name_for_child(
ABObj obj,
STRING name,
int maxlen
)
{
char nameBuf[8192];
STRING unique_name = NULL;
*nameBuf = 0;
if (maxlen < 0)
{
maxlen = 8192;
}
maxlen = util_min(8192,maxlen); /* don't overrun buf */
/*
* Alloc space and copy-in the unique name
*/
unique_name = strdup(
obj_get_unique_name_for_child(obj, name, maxlen-1, nameBuf));
return unique_name;
}
ISTRING
obj_alloc_unique_name_istr_for_child(
ABObj obj,
ISTRING name,
int maxlen
)
{
char nameBuf[8192];
ISTRING unique_name = NULL;
*nameBuf = 0;
if (maxlen < 0)
{
maxlen = 8192;
}
maxlen = util_min(8192,maxlen);
unique_name = istr_create(
obj_get_unique_name_for_child(obj, istr_string(name), maxlen-1, nameBuf));
return unique_name;
}
STRING
obj_get_unique_name_for_child(
ABObj obj,
STRING name,
int maxlen,
STRING nameOutBuf
)
{
STRING returnName = NULL;
int nameOutBufSize = maxlen+1;
StringList namesList = NULL;
BOOL done = FALSE;
BOOL unique = FALSE;
int nameLen = 0;
int i = 0;
int objNumberStart = 0;
int objNumber = 0;
namesList = objP_get_names_scope_for_children(obj);
if (namesList == NULL)
{
returnName = name;
goto epilogue;
}
unique = !strlist_str_exists(namesList, name);
if (unique)
{
returnName = name;
goto epilogue;
}
/*
* Determine trailing number
*/
util_strncpy(nameOutBuf, name, nameOutBufSize);
nameLen = strlen(nameOutBuf);
for (i = nameLen-1; i >= 0; --i)
{
if (!isdigit(nameOutBuf[i]))
{
break;
}
}
objNumberStart = i + 1;
objNumber = atoi(&(nameOutBuf[objNumberStart]));
/*
* Search for a unique name by incrementing trailing #
*/
unique = FALSE;
done = FALSE;
while (!done)
{
if (++objNumber == 1)
{
/* skip 1 - name w/no # is implied 1 */
objNumber = 2;
}
sprintf(&(nameOutBuf[objNumberStart]), "%d", objNumber);
unique = !strlist_str_exists(namesList, nameOutBuf);
done = unique;
}
if (unique)
{
returnName = nameOutBuf;
}
epilogue:
return returnName;
}
/*
* Don't run this on a project!!! It's a severe dog, and can take many
* seconds to complete.
*
* Run it on each module (root = an module) instead.
*/
int
obj_tree_ensure_unique_names(ABObj root, int maxnamelen)
{
AB_TRAVERSAL trav;
ABObj obj;
for (trav_open(&trav, root, AB_TRAV_UI);
(obj = trav_next(&trav)) != NULL;)
{
obj_ensure_unique_name(obj, root, maxnamelen);
}
trav_close(&trav);
return 0;
}
/*
* Calls obj_tree_ensure_unique_names on each module in the given tree.
*/
int
obj_tree_ensure_unique_names_in_modules(ABObj root, int maxnamelen)
{
AB_TRAVERSAL trav;
ABObj module;
for (trav_open(&trav, root, AB_TRAV_MODULES);
(module = trav_next(&trav)) != NULL;)
{
obj_tree_ensure_unique_names(module, maxnamelen);
}
trav_close(&trav);
return 0;
}
/*
* Gives an object a name by munging it's parent's name with it's own label.
* Used for item children, which aren't given names directly.
*
* actual_parent overrides the parent of the object. If actual_parent is NULL,
* the "normal" parent of the object is used.
*/
int
obj_set_name_from_label(ABObj obj, STRING parent_name_in)
{
STRING parent_name = NULL;
STRING item_label = NULL;
STRING new_name = NULL;
parent_name =
(parent_name_in == NULL ?
(obj->parent == NULL ?
NULL
:
istr_string(obj->parent->name)
)
:
parent_name
);
if (parent_name == NULL)
{
return -1;
}
if (istr_len(obj->label) > 0)
{
item_label = istr_string(obj->label);
}
else
{
item_label = "item";
}
obj_set_unique_name(obj,
ab_ident_from_name_and_label(parent_name, item_label));
return 0;
}
int
obj_set_name_from_parent(ABObj obj, STRING suffix)
{
STRING parent_name;
STRING new_name = NULL;
parent_name = (obj->parent == NULL ?
NULL
:
istr_string(obj->parent->name)
);
if (parent_name == NULL)
{
return -1;
}
obj_set_unique_name(obj,
ab_ident_from_name_and_label(parent_name,
suffix));
return 0;
}
/*
* Gets a name for an object. Object may be NULL, or have a NULL name
*
* Copies name into passed-in buffer name, guarantees 0 termination. returns
* parameter string
*/
STRING
obj_get_safe_name(ABObj obj, STRING name, int name_size)
{
if (name_size < 1)
{
return name;
}
if (obj == NULL)
{
strncpy(name, "(nil ABObj)", name_size);
}
else if (obj_get_name(obj) == NULL)
{
char buf[256];
sprintf(buf, "(ABObj:0x%08lx)", (unsigned long) obj);
strncpy(name, buf, name_size);
}
else
{
strncpy(name, obj_get_name(obj), name_size);
}
name[name_size - 1] = 0;
return name;
}
/*************************************************************************
** **
** UPDATE_CLIENTS METHODS **
** **
*************************************************************************/
int
obj_update_clients(ABObj obj)
{
return objP_notify_send_update(obj, FALSE);
}
int
obj_tree_update_clients(ABObj tree)
{
return objP_notify_send_update(tree, TRUE);
}
int
obj_update_clients_with_data(
ABObj obj,
int update_code,
void *update_data,
UpdateDataFreeFunc free_func)
{
return objP_or_tree_update_clients_with_data(
obj, FALSE, update_code, update_data, free_func);
}
int
obj_tree_update_clients_with_data(ABObj obj,
int update_code,
void *update_data,
UpdateDataFreeFunc free_func)
{
return objP_or_tree_update_clients_with_data(
obj, TRUE, update_code, update_data, free_func);
}
static int
objP_or_tree_update_clients_with_data(
ABObj obj,
BOOL update_subtree,
int update_code,
void *update_data,
UpdateDataFreeFunc free_func
)
{
int iReturn = 0;
/*
* event notification will only free the data if the notify events are
* batched. It's pretty smart about it, so we're going to go to batch
* mode and let it handle it.
*/
objP_notify_push_mode();
objP_notify_set_mode(OBJEV_MODE_BATCH_NOTIFY_EVS);
iReturn = objP_notify_send_update_with_data(
obj, update_subtree, update_code, update_data, free_func);
objP_notify_pop_mode();
return iReturn;
}