File: [Development] / inventor / lib / nodekits / src / nodekits / SoNkParts.c++ (download)
Revision 1.3, Sun Oct 29 15:04:18 2000 UTC (17 years ago) by jlim
Branch: MAIN
CVS Tags: release-2_1_5-9, release-2_1_5-8, release-2_1_5-10, HEAD Changes since 1.2: +1 -2
lines
Eliminated or reduced compiler errors and warnings, as tested with
egcs-2.91.66 (on Red Hat 6.0) and gcc 2.96 (on Red Hat 6.2).
|
/*
*
* Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it 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.
*
* Further, this software is distributed without any warranty that it is
* free of the rightful claim of any third person regarding infringement
* or the like. Any license provided herein, whether implied or
* otherwise, applies only to this software file. Patent licenses, if
* any, provided herein do not apply to combinations of this program with
* other software, or any other product whatsoever.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
* Mountain View, CA 94043, or:
*
* http://www.sgi.com
*
* For further information regarding this notice, see:
*
* http://oss.sgi.com/projects/GenInfo/NoticeExplan/
*
*/
/*
* Copyright (C) 1990,91 Silicon Graphics, Inc.
*
_______________________________________________________________________
______________ S I L I C O N G R A P H I C S I N C . ____________
|
| $Revision: 1.3 $
|
| Classes:
| SoNodekitParts
|
| Author(s) : Paul Isaacs and Thad Beier
|
______________ S I L I C O N G R A P H I C S I N C . ____________
_______________________________________________________________________
*/
#include <Inventor/SoDB.h>
#include <Inventor/errors/SoDebugError.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoSwitch.h>
#include <Inventor/nodekits/SoNodekitParts.h>
#include <Inventor/nodekits/SoNodeKitListPart.h>
#include <Inventor/nodekits/SoBaseKit.h>
#include <Inventor/SoPath.h>
#include <Inventor/fields/SoSFNode.h>
#include <Inventor/nodes/SoGroup.h>
#include <SoDebug.h>
////////////////////////////////////////////////////////////////////////
//
// Class:
// SoNodekitParts
//
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//
// Description:
// Constructor
//
// Use: internal
SoNodekitParts::SoNodekitParts( SoBaseKit *rootOfKit )
//
////////////////////////////////////////////////////////////////////////
{
#ifdef DEBUG
if ( rootOfKit == NULL ) {
SoDebugError::post("SoNodekitParts::SoNodekitParts",
"rootOfKit is NULL. Can not continue construction. Expect a core dump");
return;
}
#endif
rootPointer = rootOfKit;
catalog = rootOfKit->getNodekitCatalog(); // assign the catalog
numEntries = catalog->getNumEntries(); // make a empty node list
fieldList = new ( SoSFNode *[numEntries] );
// Make each field in the fieldList point to the field corresponding
// to the similarly indexed catalog entry.
SbName partName;
SbName fieldName;
for ( int i = 0; i < numEntries; i++ ) {
// Get the name of the part from the catalog
partName = catalog->getName( i );
// Find the field for that part, and set fieldList entry
// to point at it.
if ( i == SO_CATALOG_THIS_PART_NUM ) {
// For the part "this" we do NOT fill in a field. We set it to
// NULL and are careful not to try to look at its contents.
fieldList[i] = NULL;
}
else {
const SoFieldData *fData;
fData = rootOfKit->getFieldData();
for ( int j = 0; j < fData->getNumFields(); j++ ) {
fieldName = fData->getFieldName(j);
if (partName == fieldName) {
SoSFNode *theField =
(SoSFNode *) fData->getField(rootOfKit,j);
fieldList[i] = theField;
// Turn off notification on this field.
// We store the info as a field, but unless we
// turn off notification, everything takes forever.
theField->enableNotify(FALSE);
}
}
}
}
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Destructor
//
// Use: internal
SoNodekitParts::~SoNodekitParts()
//
////////////////////////////////////////////////////////////////////////
{
// delete the nodelist
delete [ /*numEntries*/ ] fieldList;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Creates the node for the part asked for.
// If the part already exists, then just return TRUE without doing anything
// If not, it creates the part and all necessary parts up to the top of
// of the nodekit, and places them properly as children in the graph.
//
// Note:
// this routine will NOT search for the requested part name within the
// catalogs of its child parts.
//
// Use: internal
SbBool
SoNodekitParts::makePart( const int partNum )
//
////////////////////////////////////////////////////////////////////////
{
if ( partNum == SO_CATALOG_THIS_PART_NUM )
return TRUE;
#ifdef DEBUG
if ( !partFoundCheck( partNum ) )
return FALSE;
#endif
// if the part is already in the Node list, just return TRUE
if ( verifyPartExistence( partNum ) )
return TRUE;
// create the node
SoNode *inst = (SoNode *)
catalog->getDefaultType( partNum ).createInstance();
#ifdef DEBUG
if ( inst == NULL ) {
SoDebugError::post("SoNodekitParts::makePart",
"Can't make part %s. It belongs to an abstract class. Bad parts catalog",
catalog->getName(partNum).getString());
return FALSE;
}
#endif
// If it's a list part, set the containerType and childTypes...
if ( catalog->isList( partNum ) ) {
SoNodeKitListPart *lp = (SoNodeKitListPart *) inst;
lp->setContainerType( catalog->getListContainerType( partNum ) );
const SoTypeList childTypes = catalog->getListItemTypes( partNum );
for ( int i = 0; i < childTypes.getLength(); i++ )
lp->addChildType( childTypes[i] );
lp->lockTypes();
}
inst->ref(); // temporarily ref it, until it has a parent
// create its parent part
int parentPartNum = catalog->getParentPartNumber( partNum );
// Turn off notification while building the parent part.
// We'll be notifying when adding the lower part, so let's not
// notify twice.
SbBool wasEn = rootPointer->enableNotify(FALSE);
SbBool madeOk = makePart( parentPartNum );
rootPointer->enableNotify(wasEn);
if ( ! madeOk ) {
#ifdef DEBUG
SoDebugError::post("SoNodekitParts::makePart",
"Can\'t make parent for part named %s",
catalog->getName(partNum).getString() );
#endif
inst->unref(); // undo the temporary ref
return FALSE;
}
// Don't need to check for 'this' part, since we would have returned
// earlier from verifyPartExistence.
fieldList[partNum]->setValue( inst );
// find the next closest right sibling that already exists
int sibPartNum, searchPartNum;
for( sibPartNum = -1,
searchPartNum = catalog->getRightSiblingPartNumber( partNum );
sibPartNum == -1 && searchPartNum != SO_CATALOG_NAME_NOT_FOUND;
searchPartNum = catalog->getRightSiblingPartNumber(searchPartNum )) {
if ( verifyPartExistence( searchPartNum ) )
sibPartNum = searchPartNum;
}
SoBaseKit *parentKit = NULL;
SoGroup *parentGroup = NULL;
if ( parentPartNum == SO_CATALOG_THIS_PART_NUM )
parentKit = rootPointer;
else
parentGroup = (SoGroup *) fieldList[parentPartNum]->getValue();
if (sibPartNum == -1 ) {
// no right sibling is made yet, so just add this as a child to parent
if ( parentKit != NULL )
parentKit->addChild( inst );
else
parentGroup->addChild( inst );
}
else {
// a right sibling exists. Put this node just in front of it.
if ( parentKit != NULL ) {
int sibIndex = parentKit->findChild(fieldList[sibPartNum]->getValue());
parentKit->insertChild( fieldList[partNum]->getValue(), sibIndex );
}
else {
int sibIndex =parentGroup->findChild(fieldList[sibPartNum]->getValue());
parentGroup->insertChild( fieldList[partNum]->getValue(), sibIndex );
}
}
inst->unref(); // undo the temporary ref
return TRUE;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Replaces the node described with the one passed in.
//
// If the part already exists, then the current part is removed from
// its parent and the node list.
//
// Next, the new part is put in the list and made the child of its parent.
//
// Note:
// this routine will NOT search for the requested part name within the
// catalogs of its child parts.
//
// Use: internal
SbBool
SoNodekitParts::replacePart( const int partNum, SoNode *newPartNode )
//
////////////////////////////////////////////////////////////////////////
{
#ifdef DEBUG
if ( partNum == SO_CATALOG_THIS_PART_NUM )
return FALSE;
if ( !partFoundCheck( partNum ) )
return FALSE;
#endif
// make sure the node given is of the proper type
if ( newPartNode != NULL
&& !newPartNode->isOfType( catalog->getType( partNum ) ) ) {
#ifdef DEBUG
SoDebugError::post( "SoNodekitParts::replacePart",
"the given part is not of the correct type");
#endif
return FALSE;
}
// If it's a list part, make sure all the types match okay.
if ( newPartNode != NULL && catalog->isList( partNum ) ) {
const SoTypeList kidTypes = catalog->getListItemTypes( partNum );
SoNodeKitListPart *lp = (SoNodeKitListPart *) newPartNode;
// If types aren't locked, make this part have the right types,
// then lock them.
if ( !lp->isTypeLocked() ) {
lp->setContainerType(catalog->getListContainerType(partNum));
for (int j = 0; j < kidTypes.getLength(); j++)
lp->addChildType( kidTypes[j] );
lp->lockTypes();
}
// Make sure container is of correct type.
if ( lp->getContainerType() != catalog->getListContainerType(partNum)) {
#ifdef DEBUG
SoDebugError::post( "SoNodekitParts::replacePart",
"This new list part has wrong type container");
#endif
return FALSE;
}
SbBool okay = TRUE;
// Make sure child types are all okay.
for ( int i = 0; i < kidTypes.getLength(); i++ )
if ( lp->isTypePermitted( kidTypes[i]) == FALSE )
okay = FALSE;
if ( okay == FALSE ) {
#ifdef DEBUG
SoDebugError::post( "SoNodekitParts::replacePart",
"Allowable child types in given list do not match the specs in the catalog");
#endif
return FALSE;
}
}
int parentPartNum = catalog->getParentPartNumber( partNum );
// So they don't try replacing 'this'
if ( !partFoundCheck( parentPartNum ) )
return FALSE;
// If new node isn't NULL, create its parent part
if ( newPartNode != NULL ) {
// Turn off notification while building the parent part.
// We'll be notifying when adding the lower part, so let's not
// notify twice.
SbBool wasEn = rootPointer->enableNotify(FALSE);
SbBool madeOk = makePart( parentPartNum );
rootPointer->enableNotify(wasEn);
if ( ! madeOk ) {
#ifdef DEBUG
SoDebugError::post( "SoNodekitParts::replacePart",
"can't make parent for part named %s",
catalog->getName(partNum).getString() );
#endif
return FALSE;
}
}
// Now we know there's a parent part, if we need one.
// Set the appropriate parent pointers.
SoBaseKit *parentKit = NULL;
SoGroup *parentGroup = NULL;
if ( parentPartNum == SO_CATALOG_THIS_PART_NUM )
parentKit = rootPointer;
else
parentGroup = (SoGroup *) fieldList[parentPartNum]->getValue();
// If an old part is already in the Node list, then
// get rid of any parts that are its descendants.
// This will not get rid of the old part itself.
SoNode *oldPart = NULL;
if ( verifyPartExistence( partNum ) ) {
// unregister all the descendant parts of this part by setting
// the appropriate SoSFField values in the field list to NULL.
unregisterDescendants( partNum );
oldPart = fieldList[partNum]->getValue();
}
// set the new part as the new field value.
fieldList[partNum]->setValue( newPartNode);
// If the new part is NULL, remove the oldPart from its parent.
// Then, remove parent if it is no longer needed.
if (newPartNode == NULL) {
if ( oldPart != NULL) {
if (parentKit != NULL)
parentKit->removeChild( oldPart );
else if (parentGroup != NULL) {
// If the parent is a switch, make sure this doesn't
// screw it up...
parentGroup->removeChild( oldPart );
if ( parentGroup->isOfType( SoSwitch::getClassTypeId() ) ){
SoSwitch *sw = (SoSwitch *) parentGroup;
int swNum = sw->getNumChildren();
if (sw->whichChild.getValue() >= swNum)
sw->whichChild.setValue( swNum - 1 );
}
}
}
// We just set partNum to NULL and removed from its parent.
// Get rid of the parent, too, if we can...
if ( partIsNonLeafAndMayBeDeleted( parentPartNum ) )
replacePart( parentPartNum, NULL );
return TRUE;
}
// If the new part is not a leaf in the structure, it had better
// not have any children. You've got to set the children after setting
// the internal part.
if ( catalog->isLeaf( partNum ) == FALSE ) {
SoGroup *partAsGroup = (SoGroup *) newPartNode;
if ( partAsGroup->getNumChildren() != 0 ) {
#ifdef DEBUG
SoDebugError::post( "SoNodekitParts::replacePart",
"The given part is a non-leaf in the catalog and contains children. When setting a non-leaf, the node must have 0 children.");
#endif
return FALSE;
}
}
// If there's already a part, then we'll use replace child.
// This way, the new part will be installed in any paths containing oldPart
// Then return.
if (oldPart != NULL) {
if ( parentKit != NULL )
parentKit->replaceChild( oldPart, newPartNode );
else if (parentGroup != NULL)
parentGroup->replaceChild( oldPart, newPartNode );
return TRUE;
}
// There was no old part.
// Find the next closest right sibling that already exists
int sibPartNum, searchPartNum;
for( sibPartNum = -1,
searchPartNum = catalog->getRightSiblingPartNumber( partNum );
sibPartNum == -1 && searchPartNum != SO_CATALOG_NAME_NOT_FOUND;
searchPartNum = catalog->getRightSiblingPartNumber(searchPartNum)){
if ( verifyPartExistence( searchPartNum ) )
sibPartNum = searchPartNum;
}
// If newPartNode is going to be the rightmost child, use addChild...
if (sibPartNum == -1 ) {
if ( parentKit != NULL )
parentKit->addChild( newPartNode );
else if ( parentGroup != NULL )
parentGroup->addChild( newPartNode );
return TRUE;
}
// Otherwise, insert the new part in front of the sibling.
SoNode *sibNode = fieldList[sibPartNum]->getValue();
if ( parentKit != NULL ) {
int sibIndex = parentKit->findChild( sibNode );
parentKit->insertChild( newPartNode, sibIndex );
}
else {
int sibIndex =parentGroup->findChild( sibNode );
parentGroup->insertChild( newPartNode, sibIndex );
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Called when 'partNum' is being set to a new value using replacePart.
//
// Makes sure that all descendant parts of 'partNum' get NULLed out,
// and is called prior to installing the new node value for
// 'partNum'.
//
// This is a dangerous and special purpose routine.
//
// Use: internal
void
SoNodekitParts::unregisterDescendants( const int partNum )
//
////////////////////////////////////////////////////////////////////////
{
// For each part in the catalog...
numEntries = catalog->getNumEntries();
for ( int i = 0; i < numEntries; i++ ) {
// If it's parent is partNum...
if ( catalog->getParentPartNumber(i) == partNum ) {
unregisterDescendants( i );
// Don't need to worry about i being the index of 'this'.
// since 'this' has no parent part number to match.
fieldList[ i ]->setValue( NULL );
}
}
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Gets the part asked for
// Note:
// this routine will NOT search for the requested part name within the
// catalogs of its child parts.
//
// Use: private
SoNode *
SoNodekitParts::getPartFromThisCatalog( const int partNum,
SbBool makeIfNeeded, SbBool leafCheck,
SbBool publicCheck, SbBool &existedBefore )
//
////////////////////////////////////////////////////////////////////////
{
existedBefore = FALSE;
if ( !partFoundCheck( partNum ) )
return FALSE;
if ( partNum == SO_CATALOG_THIS_PART_NUM ||
fieldList[partNum]->getValue() != NULL )
existedBefore = TRUE;
if ( leafCheck ) {
if ( !partIsLeafCheck( partNum ) )
return FALSE;
}
if ( publicCheck ) {
if ( !partIsPublicCheck( partNum ) )
return FALSE;
}
if ( partNum == SO_CATALOG_THIS_PART_NUM )
return rootPointer;
// Return if part already exists...
if ( verifyPartExistence(partNum) )
return ( fieldList[ partNum ]->getValue() );
// Part doesn't exist yet. Either return...
if ( makeIfNeeded == FALSE )
return NULL;
// or make the part
if ( makePart( partNum ) == TRUE )
return ( fieldList[ partNum ]->getValue() ); // it was made O.K.
else
return NULL; // it didn't get made properly
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Gets path to the part asked for
// Note:
// this routine will NOT search for the requested part name within the
// catalogs of its child parts.
//
// Use: private
SoFullPath *
SoNodekitParts::createPathToPartFromThisCatalog( const int partNum,
SbBool makeIfNeeded, SbBool leafCheck,
SbBool publicCheck, SbBool &existedBefore )
//
////////////////////////////////////////////////////////////////////////
{
SoNode *n = getPartFromThisCatalog( partNum, makeIfNeeded,
leafCheck, publicCheck, existedBefore );
return( createPathDownTo( catalog->getName(partNum), n ));
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Sets the part given by nameOfPart
// Note:
// this routine will NOT search for the requested part name within the
// catalogs of its child parts.
//
// Use: private
SbBool
SoNodekitParts::setPartFromThisCatalog( const int partNum,
SoNode *newPartNode, SbBool anyPart )
//
////////////////////////////////////////////////////////////////////////
{
#ifdef DEBUG
if ( partNum == SO_CATALOG_THIS_PART_NUM ) {
SoDebugError::post("SoNodekitParts::setPartFromThisCatalog",
"You can not never set the part \"this\" after construction");
return FALSE;
}
#endif
if ( !partFoundCheck( partNum ) )
return FALSE;
if ( !anyPart ) {
if ( !partIsLeafCheck( partNum ) )
return FALSE;
if ( !partIsPublicCheck( partNum ) )
return FALSE;
}
// otherwise, we need to replace the part that is currently being used
return( replacePart( partNum, newPartNode ) );
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Gets the part asked for
// Assumes that 'nameOfPart' does not need to be parsed into
// names separated by '.'
//
// Use: public
SoNode *
SoNodekitParts::getSingleNamePart( const SbName &nameOfPart,
SbBool makeIfNeeded, SbBool leafCheck, SbBool publicCheck,
SbBool &existedBefore )
//
////////////////////////////////////////////////////////////////////////
{
existedBefore = FALSE;
// IS THERE A BRACKET, WHICH SIGNIFIES INDEXING INTO A LIST?
if ( strrchr( nameOfPart.getString(), '[') != NULL ) {
char *listNameCopy = strdup( nameOfPart.getString());
int arrayIndex;
if ( !parseListItem( listNameCopy, arrayIndex)) {
free ( listNameCopy );
return NULL;
}
// get the list given by 'listNameCopy'
SbBool listExistedBefore;
SoNode *n = getSingleNamePart( listNameCopy, makeIfNeeded, TRUE,
publicCheck, listExistedBefore );
if ( n == NULL ) {
free ( listNameCopy );
return NULL;
}
if ( !n->isOfType( SoNodeKitListPart::getClassTypeId() ) ){
#ifdef DEBUG
SoDebugError::post("SoNodekitParts::getSingleNamePart",
"part specified %s was not a list", listNameCopy );
#endif
if ( listExistedBefore == FALSE ) {
// if we just created the list, we'd better get rid of it...
setSingleNamePart( listNameCopy, NULL, TRUE );
}
free( listNameCopy);
return NULL;
}
SoNodeKitListPart *listGroup = (SoNodeKitListPart *) n;
// If they are asking for the next child in the list,
// try to make it for them. return this new node if successful.
if ((listGroup->getNumChildren() == arrayIndex) && makeIfNeeded ) {
SoNode *newNode = NULL;
SoTypeList itemTypesList = listGroup->getChildTypes();
for ( int i = 0; i < itemTypesList.getLength(); i++ ) {
// Can this child type create an instance?
// (and is it a type of node?)
if ( itemTypesList[i].canCreateInstance() &&
itemTypesList[i].isDerivedFrom( SoNode::getClassTypeId())){
// Create an instance, and add it to the listGroup...
newNode = (SoNode *) itemTypesList[i].createInstance();
listGroup->addChild( newNode );
break;
}
}
if (newNode == NULL ) {
#ifdef DEBUG
if (SoDebug::GetEnv("IV_DEBUG_KIT_PARTS")) {
fprintf(stderr,"\n");
fprintf(stderr,"NODE KIT PARTS DEBUG:\n");
fprintf(stderr," The part %s does not exist\n",
nameOfPart.getString());
fprintf(stderr," and could not be created.The list %s\n",
listNameCopy );
fprintf(stderr," only specifies abstract types\n");
fprintf(stderr," Returning NULL\n");
fprintf(stderr,"\n");
}
#endif
}
free( listNameCopy);
return( newNode );
}
// Return if child doesn't exist yet, and we were not able to
// create one for them.
if ( listGroup->getNumChildren() <= arrayIndex ) {
if ( makeIfNeeded ) {
#ifdef DEBUG
if (SoDebug::GetEnv("IV_DEBUG_KIT_PARTS")) {
fprintf(stderr,"\n");
fprintf(stderr,"NODE KIT PARTS DEBUG:\n");
fprintf(stderr," Could not return the part\n");
fprintf(stderr," %s. The list %s only has\n",
nameOfPart.getString(), listNameCopy );
fprintf(stderr," %d entries. You want entry number %d\n",
listGroup->getNumChildren(),arrayIndex);
fprintf(stderr," Returning NULL\n");
fprintf(stderr,"\n");
}
#endif
}
if ( listExistedBefore == FALSE ) {
// if we just created the list, we'd better get rid of it...
setSingleNamePart( listNameCopy, NULL, TRUE );
}
free( listNameCopy);
return NULL;
}
// return entry number 'arrayIndex'
existedBefore = TRUE;
free( listNameCopy);
return( listGroup->getChild( arrayIndex ) );
}
// NOT A LIST ITEM, IF WE GOT HERE.
// IS THE REQUESTED PART IN THIS CATALOG?
int partNum = catalog->getPartNumber( nameOfPart );
if ( partNum != SO_CATALOG_NAME_NOT_FOUND )
// IF SO, THEN GET IT FROM THIS CATALOG
return ( getPartFromThisCatalog( partNum, makeIfNeeded,leafCheck,
publicCheck, existedBefore ));
else {
// ELSE, SEARCH THE CATALOG RECURSIVELY FOR THE DESIRED PART
// we need to pass a list to the recursive search saying which
// types of nodes we have already checked. This avoids infinite
// loop (does chicken contain egg? does egg contain chicken? etc...)
SoTypeList *typesChecked = new SoTypeList();
typesChecked->append( catalog->getType(SO_CATALOG_THIS_PART_NUM) );
for (int i = 0; i < numEntries; i++ ) {
// does it lie within this 'intermediary' part?
if ( catalog->recursiveSearch(i,nameOfPart,typesChecked) == TRUE) {
delete typesChecked; // don't need this anymore
// if not making parts and 'intermediary' is NULL...
if ( makeIfNeeded == FALSE && !verifyPartExistence( i ) )
return NULL;
SbBool kitExistedBefore = (fieldList[i]->getValue() != NULL);
// create the intermediary part...
// Turn off notification while building the parent part.
// We'll be notifying when adding the lower part, so let's not
// notify twice.
SbBool wasEn = rootPointer->enableNotify(FALSE);
SbBool madeOk = makePart( i );
rootPointer->enableNotify(wasEn);
if ( ! madeOk )
return NULL; // error making the part
// NOTE: it's okay to cast the node into a base kit here,
// since the recursive search would only have worked
// if it was a nodekit
// UGLY, yes, but it works.
#ifdef DEBUG
// supposedly unnecessary type checking:
if ( !fieldList[i]->getValue()->isOfType(
SoBaseKit::getClassTypeId() ) )
return NULL;
#endif
SoBaseKit *intermediary =(SoBaseKit *)fieldList[i]->getValue();
// Now that intermediary is built, get the part from within it
// Call the method on the parts list, not the node.
// It's more efficient and won't do extra virtual things that
// might be added by subclasses of SoBaseKit.
SoNodekitParts *interParts = intermediary->nodekitPartsList;
SbBool answerExistedBefore;
SoNode *answer = interParts->getAnyPart(nameOfPart,makeIfNeeded,
leafCheck, publicCheck, answerExistedBefore );
if (answer == NULL && kitExistedBefore == FALSE ) {
// if we just created the kit, we'd better get rid of it...
replacePart( i, NULL );
}
existedBefore = kitExistedBefore && answerExistedBefore;
return answer;
}
}
delete typesChecked; // don't need this anymore
}
// IF YOU GOT HERE, PARTNAME WAS NOT FOUND IN THE CATALOG OR ANY
// OF THE SUB CATALOGS.
#ifdef DEBUG
if (SoDebug::GetEnv("IV_DEBUG_KIT_PARTS")) {
fprintf(stderr,"\n");
fprintf(stderr,"NODE KIT PARTS DEBUG: The catalog for this class\n");
fprintf(stderr," of nodekit does not have a part named %s, \n",
nameOfPart.getString() );
fprintf(stderr," nor do the catalogs for any of nested nodekits\n");
fprintf(stderr," Returning NULL\n");
fprintf(stderr,"\n");
}
#endif
return NULL;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Gets a path to the part asked for
// Assumes that 'nameOfPart' does not need to be parsed into
// names separated by '.'
//
// Use: public
SoFullPath *
SoNodekitParts::getSingleNamePathToPart(const SbName &nameOfPart,
SbBool makeIfNeeded, SbBool leafCheck,
SbBool publicCheck, SbBool &existedBefore )
//
////////////////////////////////////////////////////////////////////////
{
existedBefore = FALSE;
SoFullPath *answerPath = NULL;
// IS THERE A BRACKET, WHICH SIGNIFIES INDEXING INTO A LIST?
if ( strrchr( nameOfPart.getString(), '[') != NULL ) {
char *listNameCopy = strdup( nameOfPart.getString());
int arrayIndex;
if (!parseListItem( listNameCopy, arrayIndex)){
free(listNameCopy);
return NULL;
}
// get the list given by 'listNameCopy'
SbBool listExistedBefore;
answerPath = getSingleNamePathToPart( listNameCopy, makeIfNeeded,
TRUE, publicCheck, listExistedBefore );
if (answerPath == NULL){
free(listNameCopy);
return NULL;
}
answerPath->ref();
if (!answerPath->getTail()->isOfType(
SoNodeKitListPart::getClassTypeId())) {
#ifdef DEBUG
SoDebugError::post("SoNodekitParts::getSingleNamePathToPart",
"list named %s is not actually a list part\n", listNameCopy );
#endif
answerPath->unref();
if ( listExistedBefore == FALSE ) {
// if we just created the list, we'd better get rid of it...
setSingleNamePart( listNameCopy, NULL, TRUE );
}
free(listNameCopy);
return NULL;
}
SoNodeKitListPart *listGroup
= (SoNodeKitListPart *) answerPath->getTail();
// If they are asking for the next child in the list,
// try to make it for them. return this new node if successful.
if ((listGroup->getNumChildren() == arrayIndex) && makeIfNeeded ) {
SoNode *newNode = NULL;
SoTypeList itemTypesList = listGroup->getChildTypes();
for ( int i = 0; i < itemTypesList.getLength(); i++ ) {
// Can this child type create an instance?
// (and is it a type of node?)
if ( itemTypesList[i].canCreateInstance() &&
itemTypesList[i].isDerivedFrom( SoNode::getClassTypeId())){
// Create an instance, and add it to the listGroup...
newNode = (SoNode *) itemTypesList[i].createInstance();
listGroup->addChild( newNode );
// Now we extend the path to our new node.
// First, append '0' for the container node.
// Second, append the given index within the container node.
answerPath->append( 0 );
answerPath->append( arrayIndex );
answerPath->unrefNoDelete();
break;
}
}
if (newNode == NULL ) {
#ifdef DEBUG
if (SoDebug::GetEnv("IV_DEBUG_KIT_PARTS")) {
fprintf(stderr,"\n");
fprintf(stderr,"NODE KIT PARTS DEBUG:\n");
fprintf(stderr," The part %s does not exist\n",
nameOfPart.getString());
fprintf(stderr," and could not be created.The list %s\n",
listNameCopy );
fprintf(stderr," only specifies abstract types\n");
fprintf(stderr," Returning NULL\n");
fprintf(stderr,"\n");
}
#endif
answerPath->unref();
answerPath = NULL;
}
free( listNameCopy);
return answerPath;
}
// Return if child doesn't exist yet, and we were not able to
// create one for them.
if ( listGroup->getNumChildren() <= arrayIndex ) {
if ( makeIfNeeded ) {
#ifdef DEBUG
if (SoDebug::GetEnv("IV_DEBUG_KIT_PARTS")) {
fprintf(stderr,"\n");
fprintf(stderr,"NODE KIT PARTS DEBUG: Could not return the part\n");
fprintf(stderr," %s. The list %s only has\n",
nameOfPart.getString(), listNameCopy );
fprintf(stderr," %d entries, but you want entry number %d\n",
listGroup->getNumChildren(), arrayIndex);
fprintf(stderr," Returning NULL\n");
fprintf(stderr,"\n");
}
#endif
}
answerPath->unref();
if ( listExistedBefore == FALSE ) {
// if we just created the list, we'd better get rid of it...
setSingleNamePart( listNameCopy, NULL, TRUE );
}
free(listNameCopy);
return NULL;
}
// we have path to list, so append to it:
// First, append '0' for the container node.
// Second, append the given index within the container node.
answerPath->append( 0 );
answerPath->append( arrayIndex );
answerPath->unrefNoDelete();
existedBefore = TRUE;
free(listNameCopy);
return answerPath;
}
// NOT A LIST ITEM, IF WE GOT HERE.
// IS THE REQUESTED PART IN THIS CATALOG?
int partNum = catalog->getPartNumber( nameOfPart );
if ( partNum != SO_CATALOG_NAME_NOT_FOUND )
// IF SO, THEN GET IT FROM THIS CATALOG
return ( createPathToPartFromThisCatalog( partNum, makeIfNeeded,
leafCheck, publicCheck, existedBefore ) );
else {
// ELSE, SEARCH THE CATALOG RECURSIVELY FOR THE DESIRED PART
// we need to pass a list to the recursive search saying which
// types of nodes we have already checked. This avoids infinite
// loop (does chicken contain egg? does egg contain chicken? etc...)
SoTypeList *typesChecked = new SoTypeList();
typesChecked->append( catalog->getType(SO_CATALOG_THIS_PART_NUM) );
for (int i = 0; i < numEntries; i++ ) {
// does it lie within this 'intermediary' part?
if ( catalog->recursiveSearch(i,nameOfPart,typesChecked) == TRUE){
delete typesChecked; // don't need this anymore
// if not making parts and 'intermediary' is NULL...
if ( makeIfNeeded == FALSE && !verifyPartExistence( i ) )
return NULL;
SbBool kitExistedBefore = (fieldList[i]->getValue() != NULL);
// create the intermediary part...
const SbName interName = catalog->getName(i);
// Turn off notification while building the parent part.
// We'll be notifying when adding the lower part, so let's not
// notify twice.
SbBool wasEn = rootPointer->enableNotify(FALSE);
SbBool madeOk = makePart( i );
rootPointer->enableNotify(wasEn);
if ( ! madeOk )
return NULL; // error making the part
// NOTE: it's okay to cast the node into a base kit here,
// since the recursive search would only have worked
// if it was a nodekit
// UGLY, yes, but it works.
#ifdef DEBUG
// supposedly unnecessary type checking:
if ( !fieldList[i]->getValue()->isOfType(
SoBaseKit::getClassTypeId() ) )
return NULL;
#endif
SoBaseKit *intermediary =(SoBaseKit *)fieldList[i]->getValue();
// first, build a path from 'this' to 'intermediary'
SoFullPath *pathA = createPathDownTo( interName, intermediary);
// next, build a path from 'intermediary' to the end...
// Call the method on the parts list, not the node.
// It's more efficient and won't do extra virtual things that
// might be added by subclasses of SoBaseKit.
SoNodekitParts *interParts = intermediary->nodekitPartsList;
SbBool secondExistedBefore;
SoFullPath *pathB =
(SoFullPath *) interParts->createPathToAnyPart(nameOfPart,
makeIfNeeded, leafCheck,
publicCheck, secondExistedBefore );
if (pathA)
pathA->ref();
if (pathB)
pathB->ref();
if ( pathB == NULL && kitExistedBefore == FALSE ) {
// if we just created the kit, we'd better get rid of it...
replacePart( i, NULL );
}
existedBefore = kitExistedBefore && secondExistedBefore;
// tack pathB onto pathA and return it
SoFullPath *totalPath = addPaths( pathA, pathB );
if (pathA)
pathA->unref();
if (pathB)
pathB->unref();
return( totalPath );
}
}
delete typesChecked; // don't need this anymore
}
// IF YOU GOT HERE, PARTNAME WAS NOT FOUND IN THE CATALOG OR ANY
// OF THE SUB CATALOGS.
#ifdef DEBUG
if (SoDebug::GetEnv("IV_DEBUG_KIT_PARTS")) {
fprintf(stderr,"\n");
fprintf(stderr,"NODE KIT PARTS DEBUG: The catalog for this class\n");
fprintf(stderr," of nodekit does not have a part named %s, \n",
nameOfPart.getString() );
fprintf(stderr," nor do the catalogs for any of nested nodekits\n");
fprintf(stderr," Returning NULL\n");
fprintf(stderr,"\n");
}
#endif
return NULL;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Sets the part given
// Assumes that 'nameOfPart' does not need to be parsed into
// names separated by '.'
//
// Use: public
SbBool
SoNodekitParts::setSingleNamePart( const SbName &nameOfPart,SoNode *newPartNode,
SbBool anyPart )
//
////////////////////////////////////////////////////////////////////////
{
// IS THERE A BRACKET, WHICH SIGNIFIES INDEXING INTO A LIST?
if ( strrchr( nameOfPart.getString(), '[') != NULL ) {
char *listNameCopy = strdup( nameOfPart.getString());
int arrayIndex;
if (!parseListItem( listNameCopy, arrayIndex )){
free(listNameCopy);
return FALSE;
}
// get the list given by 'listNameCopy'
// Only need to create it if (newPartNode != NULL)
// This is because, if new part is to be NULL, then the
// list containing it need not exist either.
SbBool needToMake = ( newPartNode != NULL);
SbBool listExistedBefore;
SoNode *n = getSingleNamePart( listNameCopy, needToMake, TRUE,
!anyPart, listExistedBefore );
if ( n == NULL && needToMake == FALSE ) {
free(listNameCopy);
return TRUE;
}
if ( n == NULL && needToMake == TRUE ) {
free(listNameCopy);
return FALSE;
}
if ( !n->isOfType( SoNodeKitListPart::getClassTypeId() ) ){
#ifdef DEBUG
SoDebugError::post("SoNodekitParts::setSingleNamePart",
"part specified %s was not a list", listNameCopy );
#endif
if ( listExistedBefore == FALSE ) {
// if we just created the list, we'd better get rid of it...
setSingleNamePart( listNameCopy, NULL, TRUE );
}
free(listNameCopy);
return FALSE;
}
SoNodeKitListPart *listGroup = (SoNodeKitListPart *) n;
// handle case of setting to NULL
if ( newPartNode == NULL ) {
// remove if you can...
if ( arrayIndex >= 0 && listGroup->getNumChildren() > arrayIndex )
listGroup->removeChild( arrayIndex );
else if ( listExistedBefore == FALSE ) {
// if we just created the list, we'd better get rid of it...
setSingleNamePart( listNameCopy, NULL, TRUE );
}
free(listNameCopy);
return TRUE;
}
// check type...
SoTypeList itemTypesList = listGroup->getChildTypes();
for ( int i = 0; i < itemTypesList.getLength(); i++ ) {
if ( newPartNode->isOfType( itemTypesList[i] ) ) {
// Set the node...
if ( arrayIndex == listGroup->getNumChildren() )
// Create a new final entry, if a new index...
listGroup->insertChild(newPartNode, arrayIndex );
else if ( arrayIndex < listGroup->getNumChildren() )
// Or, replace if it's not a new index...
listGroup->replaceChild(arrayIndex, newPartNode );
#ifdef DEBUG
else if (SoDebug::GetEnv("IV_DEBUG_KIT_PARTS")) {
fprintf(stderr,"\n");
fprintf(stderr,"NODE KIT PARTS DEBUG:\n");
fprintf(stderr," The part %s could not be installed\n",
nameOfPart.getString());
fprintf(stderr," because the index %d is greater \n",
arrayIndex);
fprintf(stderr," than %d, the number of entries in \n",
listGroup->getNumChildren());
fprintf(stderr," the list %s\n",
listNameCopy );
fprintf(stderr," Returning NULL\n");
fprintf(stderr,"\n");
}
#endif
free(listNameCopy);
return TRUE;
}
}
// child was not good for the list...
#ifdef DEBUG
SoDebugError::post("SoNodekitParts::setSingleNamePart",
"Node given is wrong type. Its type is %s, which is inappropriate for list named %s",
newPartNode->getTypeId().getName().getString(), listNameCopy );
#endif
if ( listExistedBefore == FALSE ) {
// if we just created the list, we'd better get rid of it...
setSingleNamePart( listNameCopy, NULL, TRUE );
}
free(listNameCopy);
return FALSE;
}
// NOT A LIST ITEM, IF WE GOT HERE.
// IS THE REQUESTED PART IN THIS CATALOG?
int partNum = catalog->getPartNumber( nameOfPart );
if ( partNum != SO_CATALOG_NAME_NOT_FOUND )
// IF SO, THEN SET IT USING THIS CATALOG
return ( setPartFromThisCatalog( partNum, newPartNode, anyPart ) );
else {
// ELSE, SEARCH THE CATALOG RECURSIVELY FOR THE DESIRED PART
// we need to pass a list to the recursive search saying which
// types of nodes we have already checked. This avoids infinite
// loop (does chicken contain egg? does egg contain chicken? etc...)
SoTypeList *typesChecked = new SoTypeList();
typesChecked->append( catalog->getType(SO_CATALOG_THIS_PART_NUM));
for (int i = 0; i < numEntries; i++ ) {
// does it lie within this 'intermediary' part?
if ( catalog->recursiveSearch(i,nameOfPart,typesChecked) == TRUE){
delete typesChecked; // don't need this anymore
// If the part is not yet made, and the newPartNode is NULL,
// we can just return. The part we seek to set to NULL
// does not exist.
if ( newPartNode == NULL && !verifyPartExistence( i ) )
return TRUE;
SbBool kitExistedBefore = (fieldList[i]->getValue() != NULL);
// create the intermediary part...
// Turn off notification while building the parent part.
// We'll be notifying when adding the lower part, so let's not
// notify twice.
SbBool wasEn = rootPointer->enableNotify(FALSE);
SbBool madeOk = makePart( i );
rootPointer->enableNotify(wasEn);
if ( ! madeOk )
return FALSE; // error making the part
// NOTE: it's okay to cast the node into a base kit here,
// since the recursive search would only have worked
// if it was a nodekit
// UGLY, yes, but it works.
#ifdef DEBUG
// supposedly unnecessary type checking:
if ( !fieldList[i]->getValue()->isOfType(
SoBaseKit::getClassTypeId() ) )
return FALSE;
#endif
SoBaseKit *intermediary =(SoBaseKit *)fieldList[i]->getValue();
// now that intermediary is built, set the part within it
// Now that intermediary is built, set the part within it.
// Call the method on the parts list, not the node.
// It's more efficient and won't do extra virtual things that
// might be added by subclasses of SoBaseKit.
SoNodekitParts *interParts = intermediary->nodekitPartsList;
SbBool didIt = interParts->setAnyPart(nameOfPart, newPartNode,
anyPart );
if (didIt == FALSE && kitExistedBefore == FALSE ) {
// if we just created the kit, we'd better get rid of it...
replacePart( i, NULL );
}
return didIt;
}
}
delete typesChecked; // don't need this anymore
}
// IF YOU GOT HERE, PARTNAME WAS NOT FOUND IN THE CATALOG OR ANY
// OF THE SUB CATALOGS.
#ifdef DEBUG
if (SoDebug::GetEnv("IV_DEBUG_KIT_PARTS")) {
fprintf(stderr,"\n");
fprintf(stderr,"NODE KIT PARTS DEBUG: The catalog for this class\n");
fprintf(stderr," of nodekit does not have a part named %s, \n",
nameOfPart.getString() );
fprintf(stderr," nor do the catalogs for any of nested nodekits\n");
fprintf(stderr," Returning NULL\n");
fprintf(stderr,"\n");
}
#endif
return FALSE;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Gets the part asked for
//
// Use: protected
SoNode *
SoNodekitParts::getAnyPart( const SbName &nameOfPart, SbBool makeIfNeeded,
SbBool leafCheck, SbBool publicCheck )
//
////////////////////////////////////////////////////////////////////////
{
SbBool existedBefore;
return (getAnyPart( nameOfPart, makeIfNeeded, leafCheck, publicCheck,
existedBefore ) );
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Gets the part asked for
//
// Use: protected
SoNode *
SoNodekitParts::getAnyPart( const SbName &nameOfPart, SbBool makeIfNeeded,
SbBool leafCheck, SbBool publicCheck,
SbBool &existedBefore )
//
////////////////////////////////////////////////////////////////////////
{
existedBefore = FALSE;
char *nameCopy, *firstName, *remainderString;
SoNode *firstNode = NULL, *secondNode = NULL;
// JUST A SINGLE NAME...
if ( strrchr( nameOfPart.getString(), '.' ) == NULL )
return getSingleNamePart( nameOfPart, makeIfNeeded, leafCheck,
publicCheck, existedBefore );
// OTHERWISE, A COMPOUND NAME of the form: part1.part2.part3 etc.
// copy the string
nameCopy = strdup( nameOfPart.getString() );
// break string into two parts
firstName = strtok( nameCopy, "."); // everything before the first '.'
remainderString = strtok( NULL, ""); // everything else
// get node for first part
// intermediate names have to be leaves, so arg3 (leafCheck) is TRUE
SbBool firstExistedBefore;
firstNode = getSingleNamePart( firstName, makeIfNeeded, TRUE,
publicCheck, firstExistedBefore );
if ( firstNode == NULL ) {
secondNode = NULL; // can't look any further
}
// get node for second part
// first, check that 'firstNode' is derived from SoBaseKit.
// otherwise, 'getPart' is not a valid method, since it doesn't have
// parts
else if ( !firstNode->isOfType( SoBaseKit::getClassTypeId() ) ) {
#ifdef DEBUG
SoDebugError::post( "SoNodekitParts::getAnyPart",
"you asked for %s but %s is not a nodeKit, so you can not look inside it for %s. returning NULL",
nameOfPart.getString(),firstName, remainderString );
#endif
if ( firstExistedBefore == FALSE ) {
// if we just created the node, we'd better get rid of it...
setSingleNamePart( firstName, NULL, TRUE );
}
secondNode = NULL;
}
else {
// get the second node from within the first...
// Call the method on the parts list, not the node.
// It's more efficient and won't do extra virtual things that
// might be added by subclasses of SoBaseKit.
SoNodekitParts *interParts = ((SoBaseKit *)firstNode)->nodekitPartsList;
SbBool secondExistedBefore;
secondNode = interParts->getAnyPart( remainderString, makeIfNeeded,
leafCheck, publicCheck, secondExistedBefore );
if ( secondNode == NULL && firstExistedBefore == FALSE ) {
// if we just created the list, we'd better get rid of it...
setSingleNamePart( firstName, NULL, TRUE );
}
existedBefore = firstExistedBefore && secondExistedBefore;
}
free ( nameCopy );
return secondNode;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Gets path to the part asked for
//
// Use: public
SoFullPath *
SoNodekitParts::createPathToAnyPart( const SbName &nameOfPart,
SbBool makeIfNeeded, SbBool leafCheck,
SbBool publicCheck )
//
////////////////////////////////////////////////////////////////////////
{
SbBool existedBefore;
return ( createPathToAnyPart( nameOfPart, makeIfNeeded, leafCheck,
publicCheck, existedBefore ) );
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Gets path to the part asked for
//
// Use: public
SoFullPath *
SoNodekitParts::createPathToAnyPart( const SbName &nameOfPart,
SbBool makeIfNeeded, SbBool leafCheck,
SbBool publicCheck, SbBool &existedBefore )
//
////////////////////////////////////////////////////////////////////////
{
existedBefore = FALSE;
char *nameCopy, *firstName, *remainderString;
SoNode *firstNode = NULL;
SoFullPath *firstPath = NULL, *secondPath = NULL, *answer = NULL;
// JUST A SINGLE NAME...
if ( strrchr( nameOfPart.getString(), '.' ) == NULL )
return getSingleNamePathToPart( nameOfPart, makeIfNeeded,
leafCheck, publicCheck, existedBefore );
// OTHERWISE, A COMPOUND NAME of the form: part1.part2.part3 etc.
// copy the string
nameCopy = strdup( nameOfPart.getString() );
// break string into two parts
firstName = strtok( nameCopy, "."); // everything before the first '.'
remainderString = strtok( NULL, ""); // everything else
// get node for first part
// intermediate names have to be leaves, so arg3 (leafCheck) is TRUE
SbBool firstExistedBefore;
firstPath = getSingleNamePathToPart( firstName, makeIfNeeded, TRUE,
publicCheck, firstExistedBefore );
if ( firstPath == NULL ) {
answer = NULL;
}
else {
firstPath->ref();
firstNode = firstPath->getTail();
if ( firstNode == NULL ) {
answer = NULL; // can't look any further
}
// get node for second part
// first, check that 'firstNode' is derived from SoBaseKit.
// otherwise, 'getPart' is not a valid method, since it doesn't have
// parts
else if ( !firstNode->isOfType( SoBaseKit::getClassTypeId() ) ) {
#ifdef DEBUG
SoDebugError::post( "SoNodekitParts::createPathToAnyPart",
"you asked for %s but %s is not a nodeKit, so you can not look inside it for %s. returning NULL",
nameOfPart.getString(), firstName, remainderString );
#endif
if ( firstExistedBefore == FALSE ) {
// if we just created the node, we'd better get rid of it...
setSingleNamePart( firstName, NULL, TRUE );
}
answer = NULL;
}
else {
// next, build a path from the second node to the end...
// Call the method on the parts list, not the node.
// It's more efficient and won't do extra virtual things that
// might be added by subclasses of SoBaseKit.
SoNodekitParts *interParts
= ((SoBaseKit *)firstNode)->nodekitPartsList;
SbBool secondExistedBefore;
secondPath = (SoFullPath *)
interParts->createPathToAnyPart( remainderString, makeIfNeeded,
leafCheck, publicCheck, secondExistedBefore );
if ( secondPath )
secondPath->ref();
answer = addPaths( firstPath, secondPath );
if ( secondPath == NULL && firstExistedBefore == FALSE ) {
// if we just created the list, we'd better get rid of it...
setSingleNamePart( firstName, NULL, TRUE );
}
existedBefore = firstExistedBefore && secondExistedBefore;
}
}
// get rid of paths...
if ( firstPath )
firstPath->unref();
if ( secondPath )
secondPath->unref();
free ( nameCopy );
return answer;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Sets the given part with the node passed in as an argument.
// Returns TRUE if successful, FALSE if not.
//
// Use: private
SbBool
SoNodekitParts::setAnyPart( const SbName &nameOfPart, SoNode *newPartNode,
SbBool anyPart )
//
////////////////////////////////////////////////////////////////////////
{
char *nameCopy, *firstName, *remainderString;
SoNode *firstNode = NULL;
SbBool answer;
// JUST A SINGLE NAME...
if ( strrchr( nameOfPart.getString(), '.' ) == NULL )
return setSingleNamePart( nameOfPart, newPartNode, anyPart );
// OTHERWISE, A COMPOUND NAME of the form: part1.part2.part3 etc.
// copy the string
nameCopy = strdup( nameOfPart.getString() );
// break string into two parts
firstName = strtok( nameCopy, "."); // everything before the first '.'
remainderString = strtok( NULL, ""); // everything else
// Get firstNode:
// [1] Only need to create it if (newPartNode != NULL)
// This is because, if new part is to be NULL, then the
// nodekit containing it need not exist either.
// [2] intermediate names have to be leaves, so arg3 (leafCheck) is TRUE
SbBool needToMake = ( newPartNode != NULL);
SbBool firstExistedBefore;
firstNode = getSingleNamePart( firstName, needToMake,
TRUE, !anyPart, firstExistedBefore );
if ( firstNode == NULL && needToMake == FALSE ) {
answer = TRUE;
}
else if ( firstNode == NULL ) {
#ifdef DEBUG
SoDebugError::post( "SoNodekitParts::setAnyPart",
"cannot set the part %s because the sub-part %s cannot be made",
nameOfPart.getString(),firstName );
#endif
answer = FALSE;
}
// call setAnyPart within firstNode...
// but first, check that 'firstNode' is derived from SoBaseKit.
// otherwise, 'setAnyPart' is not a valid method, since it doesn't have
// parts
else if ( !firstNode->isOfType( SoBaseKit::getClassTypeId() ) ) {
#ifdef DEBUG
SoDebugError::post( "SoNodekitParts::setAnyPart",
"you asked for %s but %s is not a nodeKit, so you can not look inside it for %s. returning NULL",
nameOfPart.getString(), firstName, remainderString );
#endif
if ( firstExistedBefore == FALSE ) {
// if we just created the node, we'd better get rid of it...
setSingleNamePart( firstName, NULL, TRUE );
}
answer = FALSE;
}
else {
// call setAnyPart within firstNode...
// Call the method on the parts list, not the node.
// It's more efficient and won't do extra virtual things that
// might be added by subclasses of SoBaseKit.
SoNodekitParts *interParts
= ((SoBaseKit *)firstNode)->nodekitPartsList;
answer = interParts->setAnyPart(remainderString, newPartNode, anyPart );
if ( answer == FALSE && firstExistedBefore == FALSE ) {
// if we just created the list, we'd better get rid of it...
setSingleNamePart( firstName, NULL, TRUE );
}
}
free ( nameCopy );
return answer;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Builds list from 'this' down to 'theNode'
// Note:
// Assumes that 'nameOfPart' 'partNum', and 'theNode' have already
// been determined to correctly correlate within this partsList
//
// Use: private
SoFullPath *
SoNodekitParts::createPathDownTo( const SbName &nameOfPart, SoNode *theNode )
//
////////////////////////////////////////////////////////////////////////
{
if ( theNode == NULL )
return NULL;
// construct a path from 'this' to the given part.
SoNode *childNode = NULL;
SoGroup *parentNode = NULL;
SoBaseKit *thisNode = NULL;
int childPartNum, parentPartNum, count;
int *backwardsKidIndexArray;
// allocate enough room to hold all the entries...
backwardsKidIndexArray = new int[numEntries];
thisNode = rootPointer;
childPartNum = catalog->getPartNumber( nameOfPart );
childNode = theNode;
// go backwards up the catalog to the top, saving the child index
// at each step of the way.
for ( count = 0; childNode != thisNode; count++ ) {
parentPartNum = catalog->getParentPartNumber( childPartNum );
if ( parentPartNum != SO_CATALOG_THIS_PART_NUM ) {
parentNode = (SoGroup *) fieldList[ parentPartNum ]->getValue();
if ( !parentNode->isOfType( SoGroup::getClassTypeId() ) ) {
#ifdef DEBUG
SoDebugError::post("NodekitParts::createPathDownTo",
"Parent part not derived from a group");
#endif
return NULL;
}
backwardsKidIndexArray[ count ] = parentNode->findChild( childNode);
childPartNum = parentPartNum;
childNode = parentNode;
}
else {
backwardsKidIndexArray[ count ] = thisNode->findChild( childNode );
childNode = thisNode;
}
}
SoFullPath *answer = (SoFullPath *) new SoPath( rootPointer );
answer->ref();
for( int i = count - 1; i >= 0; i-- ) {
answer->append( backwardsKidIndexArray[i] );
}
delete [ /*numEntries*/ ] backwardsKidIndexArray;
answer->unrefNoDelete();
return answer;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Appends pathB after pathA and returns the result.
// Returns NULL if either path is NULL, or if
// pathA->getTail() != pathB->getHead()
//
// Use: private
SoFullPath *
SoNodekitParts::addPaths( const SoFullPath *pathA,
const SoFullPath *pathB ) const
//
////////////////////////////////////////////////////////////////////////
{
if ( pathA == NULL )
return NULL;
if ( pathB == NULL )
return NULL;
if ( pathA->getTail() != pathB->getHead() )
return NULL;
// copy pathA into answer
SoFullPath *answer = (SoFullPath *) pathA->copy();
answer->ref();
// append entries in pathB, but leave out the head, since it already
// matches the tail of pathA
for( int i = 1; i < pathB->getLength(); i++ ) {
answer->append( pathB->getIndex( i ) );
}
answer->unrefNoDelete();
return answer;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// parses the given string into a list name and an index.
// destructive to parseString, so give it a copy.
// Syntax for string is:
// nameOfList[elementNum]
// Returns TRUE if successful, FALSE if not.
//
// Use: private
SbBool
SoNodekitParts::parseListItem( char *parseString, int &index )
//
////////////////////////////////////////////////////////////////////////
{
// First call to strtok writes over "[" with end-of-string character.
strtok( parseString, "["); // look for array bracket
char *indexString = strtok( NULL, "]"); // look for array close bracket
if ( indexString == NULL ) {
#ifdef DEBUG
SoDebugError::post("SoNodekitParts::parseListItem",
"Can\'t parse the name: %s", parseString );
#endif
return FALSE;
}
sscanf( indexString, "%d", &index ); // read index from string
return TRUE;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Determines if partNum is for a non-leaf part that can be deleted.
// This will be TRUE if the part is:
// [a] an actual part.
// [b] not "this"
// [c] not a leaf.
// [d] non-NULL
// [e1] an SoGroup with no children
// OR
// [e2] an SoSeparator with no children and default field values.
//
SbBool
SoNodekitParts::partIsNonLeafAndMayBeDeleted( int partNum )
{
// [a] an actual part.
if ( partNum == SO_CATALOG_NAME_NOT_FOUND )
return FALSE;
// [b] not "this"
if (partNum == SO_CATALOG_THIS_PART_NUM)
return FALSE;
// [c] not a leaf.
if ( catalog->isLeaf( partNum ) == TRUE )
return FALSE;
// [d] non-NULL
SoNode *part = fieldList[partNum]->getValue();
if ( part == NULL )
return FALSE;
// [e1] an SoGroup with no children
if (part->getTypeId() == SoGroup::getClassTypeId() ) {
if ( ((SoGroup *)part)->getNumChildren() == 0 )
return TRUE;
else
return FALSE;
}
// OR
// [e2] an SoSeparator with no children and default field values.
if ( part->getTypeId() == SoSeparator::getClassTypeId()) {
SoSeparator *sep = (SoSeparator *) part;
if ( sep->getNumChildren() != 0 )
return FALSE;
if ( ! sep->renderCaching.isDefault() &&
sep->renderCaching.getValue() != SoSeparator::AUTO )
return FALSE;
if ( ! sep->boundingBoxCaching.isDefault() &&
sep->boundingBoxCaching.getValue() != SoSeparator::AUTO )
return FALSE;
if ( ! sep->renderCulling.isDefault() &&
sep->renderCulling.getValue() != SoSeparator::AUTO )
return FALSE;
if ( ! sep->pickCulling.isDefault() &&
sep->pickCulling.getValue() != SoSeparator::AUTO )
return FALSE;
// Sep has no children and default values, so go ahead and delete.
return TRUE;
}
// If we got here, it's neither a group nor a separator.
return FALSE;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// prints error if partNum is not legal
//
SbBool
SoNodekitParts::partFoundCheck( int partNum )
{
if ( partNum == SO_CATALOG_NAME_NOT_FOUND ) {
#ifdef DEBUG
SoDebugError::post( "SoNodekitParts::partFoundCheck",
"Can\'t find part");
#endif
return FALSE;
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// prints error if partNum is not a leaf
//
SbBool
SoNodekitParts::partIsLeafCheck( int partNum )
{
if ( catalog->isLeaf( partNum ) == FALSE ) {
#ifdef DEBUG
SoDebugError::post( "SoNodekitParts::partIsLeafCheck",
"can't return the part %s because it is not a leaf node in the nodekit\'s structure. Returning NULL instead",
catalog->getName( partNum ).getString() );
#endif
return FALSE;
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// prints error if partNum is not public
//
SbBool
SoNodekitParts::partIsPublicCheck( int partNum )
{
if ( catalog->isPublic( partNum ) == FALSE ) {
#ifdef DEBUG
SoDebugError::post( "SoNodekitParts::partIsPublicCheck",
"can\'t return the part %s because it is not a public node in the nodekit's structure returning NULL instead",
catalog->getName( partNum ).getString() );
#endif
return FALSE;
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// This checks that a part still exists as the child of its parent,
// and so on up to 'this'
// It needs to be called as protection against outside parties deciding to
// delete nodes in the kit.
// If the integrity of the kit is broken, routines which call
// 'checkPartIntegrity' will know to create new parts instead, or
// perhaps return NULL.
//
SbBool
SoNodekitParts::verifyPartExistence( int partNum )
{
if (partNum == SO_CATALOG_THIS_PART_NUM) {
if ( rootPointer )
return TRUE;
else {
#ifdef DEBUG
SoDebugError::post( "SoNodekitParts::verifyPartExistence",
"the part \"this\" is NULL, and should NEVER be. Expect a core dump");
#endif
return FALSE;
}
}
SoNode *part = fieldList[partNum]->getValue();
// is the part there?
if ( part == NULL )
return FALSE;
// is the part the top of the catalog? Then we're OK
if ( partNum == SO_CATALOG_THIS_PART_NUM )
return TRUE;
int parentPartNum = catalog->getParentPartNumber( partNum );
SoNode *parent = NULL;
if (parentPartNum == SO_CATALOG_THIS_PART_NUM)
parent = rootPointer;
else
parent = fieldList[parentPartNum]->getValue();
// parent should exist.
if ( parent == NULL )
return FALSE;
// part should be a valid child of parent
if ( parentPartNum != SO_CATALOG_THIS_PART_NUM &&
((SoGroup *)parent)->findChild( part ) < 0 )
return FALSE;
else if ( parentPartNum == SO_CATALOG_THIS_PART_NUM
&& ((SoBaseKit *)parent)->findChild( part ) < 0 )
return FALSE;
// verify the parent
return( verifyPartExistence( parentPartNum ) );
}