[BACK]Return to SoNkCatalog.c++ CVS log [TXT][DIR] Up to [Development] / inventor / lib / nodekits / src / nodekits

File: [Development] / inventor / lib / nodekits / src / nodekits / SoNkCatalog.c++ (download)

Revision 1.4, Tue Sep 25 00:45:46 2001 UTC (16 years, 1 month 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.3: +4 -4 lines

Various changes:

  * Fixed Bug 63 and 64.

  * Handled nonstandard sed location.

  * Used for-loop in man page install.

  * Included casts for 64-bit builds.

  * Added placeholder for FreeBSD options.

  * Included unistd.h for getopt() and stdlib.h for malloc().

  * Implemented SoText[23] workaround for glibc-2.2.* iconv().

  * Split long lines in SoHandleBoxDraggerGeom.h and
    SoTransformerDraggerGeom.h in lib/interaction/src/draggers/geom.

  * Added IV_NO_OVERLAYS/OIV_NO_OVERLAYS variables to disable overlay planes.

/*
 *
 *  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.4 $
 |
 |   Classes:
 |      SoNodekitCatalog
 |
 |   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/errors/SoDebugError.h>
#include <Inventor/nodekits/SoNodekitCatalog.h>
#include <Inventor/nodekits/SoNodeKitListPart.h>
#include <Inventor/SoDB.h>
#include <Inventor/nodekits/SoBaseKit.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoSwitch.h>

// Static variables for the nodekit catalog class...

const SbName  *SoNodekitCatalog::emptyName = NULL;
const SoTypeList *SoNodekitCatalog::emptyList = NULL;
SoType  *SoNodekitCatalog::badType   = NULL;

////////////////////////////////////////////////////////////////////////
//
// Class:
//    SoNodekitCatalogEntry
//
////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////
//
// Description:
//    Constructor
//
// Use: internal

SoNodekitCatalogEntry::SoNodekitCatalogEntry( const SbName &theName, 
			      SoType  theType , SoType theDefaultType,
			      SbBool   theNullByDefault,
			const SbName  &theParentName, 
			const SbName  &theRightSiblingName, SbBool theListPart, 
			      SoType  theListContainerType,
			const SoTypeList &theListItemTypes,
			      SbBool thePublicPart )
//
////////////////////////////////////////////////////////////////////////
{
    name                   = theName;
    type                   = theType;
    defaultType            = theDefaultType;
    nullByDefault   	   = theNullByDefault;
    leafPart               = TRUE;    // everything is a leaf 'til given a child
    parentName             = theParentName;
    rightSiblingName       = theRightSiblingName;
    listPart               = theListPart;
    listContainerType      = theListContainerType;
    listItemTypes.copy( theListItemTypes );
    publicPart             = thePublicPart;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    Creates a new copy of this catalog
//
// Use: private

SoNodekitCatalogEntry *
SoNodekitCatalogEntry::clone() const
//
////////////////////////////////////////////////////////////////////////
{
    // make a clone with the current type and defaultType...
    return clone( type, defaultType );
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    Creates a new copy of this catalog, but sets the type to newType
//
// Use: private

SoNodekitCatalogEntry *
SoNodekitCatalogEntry::clone( SoType newType, 
			      SoType newDefaultType ) const
//
////////////////////////////////////////////////////////////////////////
{
    SoNodekitCatalogEntry *theClone;

    theClone = new SoNodekitCatalogEntry( name, newType, newDefaultType,
	 nullByDefault, parentName, rightSiblingName, listPart, 
	 listContainerType, listItemTypes, publicPart );
    theClone->leafPart = leafPart;

    return theClone;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    Creates a new copy of this catalog
//
// Use: public

void
SoNodekitCatalogEntry::addListItemType( SoType typeToAdd )
//
////////////////////////////////////////////////////////////////////////
{
    listItemTypes.append( typeToAdd );
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    Looks for the given part.
//    Checks this part, then recursively checks all entries in the 
//    catalog of this part (it gets its own catalog by looking
//    at the catalog for the 'dummy' for this type, which is accessed
//    through: type.getInstance()->getNodekitCatalog()
//    or, if type is an abstract type, 
//    uses defaultType.getInstance()->getNodekitCatalog()
//
// Use: public

SbBool
SoNodekitCatalogEntry::recursiveSearch( const SbName    &nameToFind, 
					  SoTypeList   *typesChecked ) const
//
////////////////////////////////////////////////////////////////////////
{
    const SoNodekitCatalog *subCat;

    // is this the part of my dreams?
    if ( name == nameToFind )
	return TRUE;

    // make sure the part isn't a list
    if ( listPart == TRUE )
	return FALSE;
    // make sure the part is subclassed off of SoBaseKit
    if ( !type.isDerivedFrom( SoBaseKit::getClassTypeId() ))
	return FALSE;

    // avoid an infinite search loop by seeing if this type has already been
    // checked...
    if ( typesChecked->find( type ) != -1 )
	return FALSE;

    // if it's still ok, then search within the catalog of this part
    // first check each name:
    const SoBaseKit *inst = (const SoBaseKit *) type.createInstance();
    if ( inst == NULL )
	inst = (const SoBaseKit *) defaultType.createInstance();
    if ( inst == NULL ) {
#ifdef DEBUG
	SoDebugError::post("SoNodekitCatalogEntry::recursiveSearch",
	"part type and defaultType are both abstract classes");
	abort();
#endif
    }

    subCat = inst->getNodekitCatalog();
    inst->ref();
    inst->unref();

    int i;
    for( i = 0; i < subCat->getNumEntries(); i++ ) {
	if ( subCat->getName( i ) == nameToFind ) 
		return TRUE;
    }
    // at these point, we've checked all the names in this class, so 
    // we can add it to typesChecked
    typesChecked->append( type );

    // then, recursively check each part
    for( i = 0; i < subCat->getNumEntries(); i++ ) {
	if ( subCat->recursiveSearch( i, nameToFind, typesChecked ) )
		return TRUE;
    }

    return FALSE;  // couldn't find it ANYwhere!
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    Print contents for debugging purposes
//
// Use: internal

void 
SoNodekitCatalogEntry::printCheck() const
//
////////////////////////////////////////////////////////////////////////
{
    fprintf( stdout,"    name = %s, type = %s, defaultType = %s\n",
	    name.getString(), type.getName().getString(), defaultType.getName().getString() );
    fprintf( stdout,"    nullByDefault = %d\n", nullByDefault);
    fprintf( stdout,"    parentName = %s\n", parentName.getString() );
    fprintf( stdout,"    sibling = %s, listPart = %d\n",
	    rightSiblingName.getString(), listPart );
    if ( listPart ) {
	fprintf( stdout, "listItemTypes = " );
	for ( int i = 0; i < listItemTypes.getLength(); i++ ) {
	    fprintf( stdout,"  %d  ", listItemTypes[i].getName().getString() );
	}
	fprintf( stdout, "\n" );
    }
    fprintf( stdout,"    publicPart = %d\n", publicPart );
}

////////////////////////////////////////////////////////////////////////
//
// Class:
//    SoNodekitCatalog
//
////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////
//
// Description:
//    Constructor
//
// Use: internal

SoNodekitCatalog::SoNodekitCatalog()
//
////////////////////////////////////////////////////////////////////////
{
    numEntries = 0;
    entries    = NULL;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    Destructor
//
// Use: internal

SoNodekitCatalog::~SoNodekitCatalog()
//
////////////////////////////////////////////////////////////////////////
{
    // delete all the members of the entries array
    for ( int i = 0; i < numEntries; i++ )
	delete entries[i];

    // delete the entries array itself
    if (entries != NULL)
	delete [] entries;

}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    Prints out contents of the catalog for debuggin purposes
//
// Use: internal

void
SoNodekitCatalog::printCheck() const
//
////////////////////////////////////////////////////////////////////////
{
    fprintf( stdout, "catalog printout: number of entries = %d\n", numEntries );
    for( int i = 0; i < numEntries; i++ ) {
	fprintf( stdout, "#%d\n", i );
	entries[i]->printCheck();
    }
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the partNumber of an entry given its reference name.
//
// Use: internal

int
SoNodekitCatalog::getPartNumber( const SbName &theName ) const
//
////////////////////////////////////////////////////////////////////////
{
    void *castPNum;

    if ( partNameDict.find( (unsigned long) theName.getString(), castPNum ) )
#if (_MIPS_SZPTR == 64 || __ia64)
	return ( (int) ((long) castPNum) );  // System long
#else
	return ( (int) castPNum );
#endif
    else 
	return SO_CATALOG_NAME_NOT_FOUND;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the name of an entry given its partNumber.
//
// Use: internal

const SbName &
SoNodekitCatalog::getName( int thePartNumber ) const
//
////////////////////////////////////////////////////////////////////////
{
    // return the name of the entry, if you can find it.
    if ( thePartNumber >= 0 && thePartNumber < numEntries )
	return entries[thePartNumber]->getName();
    else
	return *emptyName;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the type of an entry.
//
// Use: internal

SoType
SoNodekitCatalog::getType( int thePartNumber ) const
//
////////////////////////////////////////////////////////////////////////
{
    // return the type of the entry, if you can find it.
    if ( thePartNumber >= 0 && thePartNumber < numEntries )
	return entries[thePartNumber]->getType();
    else
	return *badType;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the type of an entry.
//
// Use: internal

SoType
SoNodekitCatalog::getType( const SbName &theName ) const
//
////////////////////////////////////////////////////////////////////////
{
    return( getType( getPartNumber( theName ) ));
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the default type of an entry.
//
// Use: internal

SoType
SoNodekitCatalog::getDefaultType( int thePartNumber ) const
//
////////////////////////////////////////////////////////////////////////
{
    // return the defaultType of the entry, if you can find it.
    if ( thePartNumber >= 0 && thePartNumber < numEntries )
	return entries[thePartNumber]->getDefaultType();
    else
	return *badType;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the defaultType of an entry.
//
// Use: internal

SoType
SoNodekitCatalog::getDefaultType( const SbName &theName ) const
//
////////////////////////////////////////////////////////////////////////
{
    return( getDefaultType( getPartNumber( theName ) ));
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding 'nullByDefault' of an entry.
//
// Use: internal

SbBool
SoNodekitCatalog::isNullByDefault( int thePartNumber ) const
//
////////////////////////////////////////////////////////////////////////
{
    // return the value for this entry, if you can find it.
    if ( thePartNumber >= 0 && thePartNumber < numEntries )
	return entries[thePartNumber]->isNullByDefault();
    else
	return TRUE;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding 'leafPart' of an entry.
//
// Use: internal

SbBool
SoNodekitCatalog::isNullByDefault( const SbName &theName ) const
//
////////////////////////////////////////////////////////////////////////
{
    return( isNullByDefault( getPartNumber( theName ) ));
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding 'leafPart' of an entry.
//
// Use: internal

SbBool
SoNodekitCatalog::isLeaf( int thePartNumber ) const
//
////////////////////////////////////////////////////////////////////////
{
    // return the type of the entry, if you can find it.
    if ( thePartNumber >= 0 && thePartNumber < numEntries )
	return entries[thePartNumber]->isLeaf();
    else
	return TRUE;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding 'leafPart' of an entry.
//
// Use: internal

SbBool
SoNodekitCatalog::isLeaf( const SbName &theName ) const
//
////////////////////////////////////////////////////////////////////////
{
    return( isLeaf( getPartNumber( theName ) ));
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the name of the parent of an entry.
//
// Use: internal

const SbName &
SoNodekitCatalog::getParentName( int thePartNumber ) const
//
////////////////////////////////////////////////////////////////////////
{
    // return the entry, if you can find it.
    if ( thePartNumber >= 0 && thePartNumber < numEntries )
	return entries[thePartNumber]->getParentName();
    else
	return *emptyName;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the name of the parent of an entry.
//
// Use: internal

const SbName &
SoNodekitCatalog::getParentName( const SbName &theName ) const
//
////////////////////////////////////////////////////////////////////////
{
    return( getParentName( getPartNumber( theName ) ));
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the name of the parent of an entry.
//
// Use: internal

int
SoNodekitCatalog::getParentPartNumber( int thePartNumber ) const
//
////////////////////////////////////////////////////////////////////////
{
    const SbName pName = getParentName( thePartNumber );
    return( getPartNumber( pName ) );
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the name of the parent of an entry.
//
// Use: internal

int
SoNodekitCatalog::getParentPartNumber( const SbName &theName ) const
//
////////////////////////////////////////////////////////////////////////
{
    const SbName pName = getParentName( theName );
    return( getPartNumber( pName ) );
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the name of the right sibling of an entry.
//
// Use: internal

const SbName &
SoNodekitCatalog::getRightSiblingName( int thePartNumber ) const
//
////////////////////////////////////////////////////////////////////////
{
    // return the entry, if you can find it.
    if ( thePartNumber >= 0 && thePartNumber < numEntries )
	return entries[thePartNumber]->getRightSiblingName();
    else
	return *emptyName;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the name of the RightSiblingName of an entry.
//
// Use: internal

const SbName &
SoNodekitCatalog::getRightSiblingName( const SbName &theName ) const
//
////////////////////////////////////////////////////////////////////////
{
    return( getRightSiblingName( getPartNumber( theName ) ));
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the name of the rightSibling of an entry.
//
// Use: internal

int
SoNodekitCatalog::getRightSiblingPartNumber( int thePartNumber ) const
//
////////////////////////////////////////////////////////////////////////
{
    const SbName sName = getRightSiblingName( thePartNumber );
    return( getPartNumber( sName ) );
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the name of the rightSibling of an entry.
//
// Use: internal

int
SoNodekitCatalog::getRightSiblingPartNumber( const SbName &theName ) const
//
////////////////////////////////////////////////////////////////////////
{
    const SbName sName = getRightSiblingName( theName );
    return( getPartNumber( sName ) );
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding 'listPart' of an entry.
//
// Use: internal

SbBool
SoNodekitCatalog::isList( int thePartNumber ) const
//
////////////////////////////////////////////////////////////////////////
{
    // return the type of the entry, if you can find it.
    if ( thePartNumber >= 0 && thePartNumber < numEntries )
	return entries[thePartNumber]->isList();
    else
	return FALSE;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding 'listPart' of an entry.
//
// Use: internal

SbBool
SoNodekitCatalog::isList( const SbName &theName ) const
//
////////////////////////////////////////////////////////////////////////
{
    return( isList( getPartNumber( theName ) ));
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the type of the container of a list entry.
//
// Use: internal

SoType
SoNodekitCatalog::getListContainerType( int thePartNumber ) const
//
////////////////////////////////////////////////////////////////////////
{
    // return the defaultType of the entry, if you can find it.
    if ( thePartNumber >= 0 && thePartNumber < numEntries )
	return entries[thePartNumber]->getListContainerType();
    else
	return *badType;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the type of the container of a list entry.
//
// Use: internal

SoType
SoNodekitCatalog::getListContainerType( const SbName &theName ) const
//
////////////////////////////////////////////////////////////////////////
{
    return( getListContainerType( getPartNumber( theName ) ));
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the list item type of an entry.
//
// Use: internal

const SoTypeList &
SoNodekitCatalog::getListItemTypes( int thePartNumber ) const
//
////////////////////////////////////////////////////////////////////////
{
    // return the type of the entry, if you can find it.
    if ( thePartNumber >= 0 && thePartNumber < numEntries )
	return entries[thePartNumber]->getListItemTypes();
    else
	return ( *emptyList );
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding the list item type of an entry.
//
// Use: internal

const SoTypeList &
SoNodekitCatalog::getListItemTypes( const SbName &theName ) const
//
////////////////////////////////////////////////////////////////////////
{
    return( getListItemTypes( getPartNumber( theName ) ));
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding 'publicPart' of an entry.
//
// Use: internal

SbBool
SoNodekitCatalog::isPublic( int thePartNumber ) const
//
////////////////////////////////////////////////////////////////////////
{
    // return whether the part is public, if you can find it.
    if ( thePartNumber >= 0 && thePartNumber < numEntries )
	return entries[thePartNumber]->isPublic();
    else
	return TRUE;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For finding 'publicPart' of an entry.
//
// Use: internal

SbBool
SoNodekitCatalog::isPublic( const SbName &theName ) const
//
////////////////////////////////////////////////////////////////////////
{
    return( isPublic( getPartNumber( theName ) ));
}


////////////////////////////////////////////////////////////////////////
//
// Description:
//    For adding an allowable child-type to an entry.
//    This will only make a difference if the entry has listPart set to TRUE
//
// Use: public

void
SoNodekitCatalog::addListItemType( int thePartNumber,
					SoType typeToAdd )
//
////////////////////////////////////////////////////////////////////////
{
    // add typeToAdd to the entry's listItemTypes, if you can find
    // the entry...
    if ( thePartNumber >= 0 && thePartNumber < numEntries )
	entries[thePartNumber]->addListItemType( typeToAdd );
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For adding an allowable child-type to an entry.
//    This will only make a difference if the entry has listPart set to TRUE
//
// Use: public

void
SoNodekitCatalog::addListItemType( const SbName &theName,
					SoType typeToAdd )
//
////////////////////////////////////////////////////////////////////////
{
    addListItemType( getPartNumber( theName ), typeToAdd );
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//
// For changing the type and defaultType of an entry.
// The new types must be subclasses of the types already existing in the
// entry.
// For example, in SoShapeKit, the part "shape" has type SoShape and
// default type SoSphere.  Any shape node is acceptable, but be default a 
// sphere will be built.
// Well, when creating the SoVertexShapeKit class, a call of:
//    narrowTypes( "shape", SoVertexShape::getClassTypeId(),
//                          SoFaceSet::getClassTypeId())
// might be used.  This would reflect the fact that:
// Only vertext shapes may be put in the "shape"  part, not just any shape.
// And also, by default, a faceSet will be built, not a sphere.
//
// Use: public

void
SoNodekitCatalog::narrowTypes( const SbName &theName,
			SoType newType, SoType newDefaultType )
//
////////////////////////////////////////////////////////////////////////
{
    int thePartNumber = getPartNumber( theName );

    if ( thePartNumber < 0 || thePartNumber >= numEntries )
	return;

    SoNodekitCatalogEntry *theEntry = entries[thePartNumber];

    // Checks that [1] newDefaultType is not an abstract type, and 
    //             [2] newDefaultType is a subclass of newType
    if ( !checkNewTypes( newType, newDefaultType ) )
	return;

    SoType oldType        = theEntry->getType();
    SoType oldDefaultType = theEntry->getDefaultType();

    // Make sure that the new types is derived from the old type.
    // Parts in derived classes must be subclasses of the types they
    // belong to when cast to the parent classes.
    if ( !newType.isDerivedFrom( oldType ) ) {
#ifdef DEBUG
	const char *newName = newType.getName().getString();
	const char *oldName = oldType.getName().getString();
	SoDebugError::post("SoNodekitCatalog::narrowTypes",
		   "The newType %s is not a subclass of the oldType %s. "
		   "Cannot narrow the  type from %s to %s",
			   newName, oldName, oldName, newName);
#endif
  	return;
    }

    // passed all the tests!
    theEntry->setTypes( newType, newDefaultType );
}
////////////////////////////////////////////////////////////////////////
//
// Description:
//
// For changing whether a part is created by default (during the constructor)
// by nodekits that use this catalog.
//
// Use: EXTENDER public

void
SoNodekitCatalog::setNullByDefault( const SbName &theName, 
				    SbBool newNullByDefault )
//
////////////////////////////////////////////////////////////////////////
{
    int thePartNumber = getPartNumber( theName );

    if ( thePartNumber < 0 || thePartNumber >= numEntries )
	return;

    entries[thePartNumber]->setNullByDefault( newNullByDefault );
}



////////////////////////////////////////////////////////////////////////
//
// Description:
//    Creates a new copy of this catalog
//
// Use: public

SoNodekitCatalog *
SoNodekitCatalog::clone( SoType typeOfThis ) const
//
////////////////////////////////////////////////////////////////////////
{
    SoNodekitCatalog      *theClone;

    theClone = new SoNodekitCatalog;
    theClone->numEntries = numEntries;
    if (numEntries == 0)
	theClone->entries = NULL;
    else {
	theClone->entries = new ( SoNodekitCatalogEntry *[numEntries]);
	for (int i = 0; i < numEntries; i++) {
	    if ( i == SO_CATALOG_THIS_PART_NUM )
		theClone->entries[i] = entries[i]->clone( typeOfThis, 
							  typeOfThis );
	    else
		theClone->entries[i] = entries[i]->clone();
	    theClone->partNameDict.enter( (unsigned long) 
					  entries[i]->getName().getString(), 
					  (void *) (unsigned long) i );
	}
    }

    return theClone;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    Used as a check when adding a new entry to a catalog.
//    Checks that the name is not NULL and not empty.
//
// Use: private

SbBool
SoNodekitCatalog::checkName( const SbName &theName )  // proposed name
//
////////////////////////////////////////////////////////////////////////
{
    // CHECK IF IT'S NULL
    if ( theName.getString() == NULL ) {
#ifdef DEBUG
	SoDebugError::post("SoNodekitCatalog::checkName",
			    "given name is NULL" );
#endif
  	return FALSE;
    }

    // CHECK IF IT'S EMPTY
    if ( theName == "" ) {
#ifdef DEBUG
	SoDebugError::post("SoNodekitCatalog::checkName",
			    "given name is the empty string" );
#endif
  	return FALSE;
    }

    return TRUE;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    Used as a check when adding a new entry to a catalog.
//    Checks that the name is OK to use for the new entry.
//
// Use: private

SbBool
SoNodekitCatalog::checkNewName( const SbName &theName )  // proposed name
//
////////////////////////////////////////////////////////////////////////
{
    if ( !checkName( theName ) )
	return FALSE;

    // CHECK IF IT'S UNIQUE FOR THIS CATALOG
    if ( getPartNumber( theName ) == SO_CATALOG_NAME_NOT_FOUND ) {
	return TRUE;
    }
    else {
#ifdef DEBUG
	SoDebugError::post("SoNodekitCatalog::checkNewName",
			    "the name %s is already in this catalog",
			theName.getString() );
#endif
  	return FALSE;
    }
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    Used as a check when adding a new entry to a catalog.
//    Checks that the type is not for an abstract node type.
//
// Use: private

SbBool
SoNodekitCatalog::checkNewTypes( SoType theType,  // proposed type
				 SoType theDefaultType ) // and default
//
////////////////////////////////////////////////////////////////////////
{
    if ( !theDefaultType.canCreateInstance()) {
#ifdef DEBUG
	SoDebugError::post("SoNodekitCatalog::checkNewTypes",
	"the defaultType %s is an abstract class, and cannot be part of a nodekits structure",
				theDefaultType.getName().getString() );
#endif
  	return FALSE;
    }

    if ( !theDefaultType.isDerivedFrom( theType ) ) {
#ifdef DEBUG
	const char *defName = theDefaultType.getName().getString();
	SoDebugError::post("SoNodekitCatalog::checkNewTypes",
			   "the defaultType %s is not a subclass of the type "
			   "%s. It can not be part of a nodekits structure",
			   defName, theType.getName().getString());
#endif
  	return FALSE;
    }
    else
	return TRUE;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    Used as a check when adding a new entry to a catalog.
//    Checks that the name is OK to use the parent for a new entry.
//
// Use: private

SbBool
SoNodekitCatalog::checkAndGetParent( 
	const SbName                &theName,          // the child's name
	const SbName                &theParentName,    // proposed parent name
	SoNodekitCatalogEntry *& parentEntry ) // corresponding entry filled 
					        // in this method
//
////////////////////////////////////////////////////////////////////////
{
    // CHECK FOR "THIS"
    // The string "this" means that a node is to be the nodekit node itself 
    // In this case, return NULL as the parentEntry, and a status of TRUE!
    if ( theName == "this" ) {
	// 'this' has no parent
	parentEntry = NULL;
	return TRUE;
    }
    else {
	// only 'this' can have no parent
	if ( !checkName( theParentName ) )
	    return FALSE;
    }

    // CHECK THAT THE PARENT IS IN THE CATALOG
    int parentPartNumber = getPartNumber( theParentName );
    if ( parentPartNumber == SO_CATALOG_NAME_NOT_FOUND ) {
#ifdef DEBUG
	SoDebugError::post("SoNodekitCatalog::checkAndGetParent",
        "requested parent >> %s << is not in this catalog",
	    			theParentName.getString() );
#endif
	return FALSE;
    }
    parentEntry = entries[ parentPartNumber ];

    // CHECK THE NODE TYPE OF THE PARENT

    // [1] Unless it's "this", it must be a subclass of SoGroup, 
    //     or you can't add children to it.
    if ( parentPartNumber !=  SO_CATALOG_THIS_PART_NUM &&
	 !parentEntry->getType().isDerivedFrom( SoGroup::getClassTypeId() )) {
#ifdef DEBUG
	SoDebugError::post("SoNodekitCatalog::checkAndGetParent",
        "requested parent >> %s << is a node that is not subclassed from SoGroup, so it can\'t have children",
	    			theParentName.getString() );
#endif
	return FALSE;
    }
    // [2] If they didn't call 'initClass', then 'theParentName' will == 'this',
    //     but parentEntry->getType() will not yet be something derived from
    //     SoBaseKit. Check for this.
    if ( parentPartNumber ==  SO_CATALOG_THIS_PART_NUM &&
	 !parentEntry->getType().isDerivedFrom( SoBaseKit::getClassTypeId() )) {
#ifdef DEBUG
	SoDebugError::post( "SoNodekitCatalog::checkAndGetParent",
	 "  It looks like you forgot to call initClass for one of your nodekit classes! Expect a core dump!");
#endif
    }
    // [3] Unless it is 'this', the parent can NOT be subclass of SoBaseKit.
    //     This is because you can only add child nodes to an nodekit through 
    //     its own class's nodekitCatalog
    if ( parentPartNumber !=  SO_CATALOG_THIS_PART_NUM &&
	 parentEntry->getType().isDerivedFrom( SoBaseKit::getClassTypeId()) ) {
#ifdef DEBUG
	SoDebugError::post("SoNodekitCatalog::checkAndGetParent",
        " Requested parent >> %s << is a node that is subclassed from SoBaseKit, so it can\'t children except through its own class\'s nodekitCatalog",
	    			theParentName.getString() );
#endif
	return FALSE;
    }

    // MAKE SURE THAT THE NODE HAS NOT BEEN DESIGNATED AS A LIST
    if ( parentEntry->isList() == TRUE ) {
#ifdef DEBUG
	SoDebugError::post("SoNodekitCatalog::checkAndGetParent",
        " Requested parent >> %s << is a node that has been designated as a list.  \n It can not have explicit children in the catalog although nodes \n can be added to the list for a given instance by using the special list editting \n methods on the nodekit node.",
	    			theParentName.getString() );
#endif
	return FALSE;
    }

    return TRUE;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    Used as a check when adding a new entry to a catalog.
//    Finds the left and right siblings for the new entry.
//    Also, checks that the right sibling exists in the catalog (unless
//    the name is "", in which case the new entry is to be the rightmost child
//
// Use: private

SbBool
SoNodekitCatalog::checkAndGetSiblings( 
	const SbName            &theParentName,       // parent name
	const SbName            &theRightSiblingName, // proposed sibling name
	SoNodekitCatalogEntry *& leftEntry,      // new left (to be filled in)
	SoNodekitCatalogEntry *& rightEntry )    // new right (to be filled )
//
////////////////////////////////////////////////////////////////////////
{
    leftEntry = NULL;
    rightEntry = NULL;

    for ( int i = 0; i < numEntries; i++ ) {
	if ( entries[i]->getParentName() == theParentName ) {
	    // is it the left sibling?
	    if ( entries[i]->getRightSiblingName() == theRightSiblingName )
		 leftEntry = entries[i];
	    // is it the right sibling?
	    else if ( theRightSiblingName == entries[i]->getName() )
	         rightEntry = entries[i];
	}
    }
    if ( ( rightEntry == NULL ) && ( theRightSiblingName != "" ) ) {
#ifdef DEBUG
	SoDebugError::post("SoNodekitCatalog::checkAndGetSiblings",
	"Requested right sibling >> %s << can not be found in the nodekitCatalog",
				theRightSiblingName.getString() );
#endif
	return FALSE;
    }

    return TRUE;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    Used as a check when adding a new entry to a catalog.
//    Called if the new node is to be a list of other nodes.
//    Checks that the given type is OK as a list.
//
// Use: private

SbBool
SoNodekitCatalog::checkCanTypesBeList(   SoType theType,
				         SoType theDefaultType,
					 SoType theListContainerType )
//
////////////////////////////////////////////////////////////////////////
{
    // CHECK IF IT'S A GROUP OR SEPARATOR
    if ( !theType.isDerivedFrom( SoNodeKitListPart::getClassTypeId() ) ) {
#ifdef DEBUG
	SoDebugError::post("SoNodekitCatalog::checkCanTypesBeList",
        "requested node type can not be a list. It is not derived from SoNodeKitListPart");
#endif
	return FALSE;
    }
    if ( !theDefaultType.isDerivedFrom( theType ) ) {
#ifdef DEBUG
	SoDebugError::post("SoNodekitCatalog::checkCanTypesBeList",
        "requested default type is not derived from requested type.");
#endif
	return FALSE;
    }
    if ( !theListContainerType.isDerivedFrom( SoGroup::getClassTypeId() ) ) {
#ifdef DEBUG
	SoDebugError::post("SoNodekitCatalog::checkCanTypesBeList",
        " requested list container node type can not be used. It is not derived from SoGroup");
#endif
	return FALSE;
    }
    return TRUE;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    For adding a new entry into the nodekitCatalog
//
// Use: internal

SbBool
SoNodekitCatalog::addEntry( const SbName &theName, 
			          SoType theType,
			          SoType theDefaultType,
				  SbBool  theNullByDefault,
			    const SbName &theParentName, 
			    const SbName &theRightSiblingName, 
			          SbBool theListPart, 
			          SoType theListContainerType,
			          SoType theListItemType,
			    SbBool thePublicPart )
//
////////////////////////////////////////////////////////////////////////
{
    SoNodekitCatalogEntry *parentEntry, *rightEntry, *leftEntry;
    SoNodekitCatalogEntry *newEntry;
    SoNodekitCatalogEntry **newArray;

    // CHECK IF THE NEW ENTRY IS OK

    if ( !checkNewName( theName ) )
	return FALSE;

    if ( !checkNewTypes( theType, theDefaultType ) ) {
#ifdef DEBUG
	SoDebugError::post("SoNodekitCatalog::addEntry",
		" Error creating catalog entry %s", theName.getString());
#endif
	return FALSE;
    }

    if ( !checkAndGetParent( theName, theParentName, parentEntry ) )
	return FALSE;

    if ( !checkAndGetSiblings( theParentName, theRightSiblingName, 
			       leftEntry, rightEntry ) )
	return FALSE;

    if ( theListPart && !checkCanTypesBeList( theType, theDefaultType, 
					      theListContainerType ) )
	return FALSE;

    if ( numEntries == SO_CATALOG_THIS_PART_NUM  && theName != "this" ) {
#ifdef DEBUG
	SoDebugError::post("SoNodekitCatalog::addEntry",
		" Entry number %d must be named \"this\" ",
		SO_CATALOG_THIS_PART_NUM );
#endif
	return FALSE;
    }

    // IF ALL TESTS WERE PASSED...

    // expand the list by one slot
    newArray = new ( SoNodekitCatalogEntry *[numEntries + 1]);
    if ( entries != NULL ) {
	for (int i = 0; i < numEntries; i++ )
	    newArray[i] = entries[i];
	delete [] entries;
    }
    entries = newArray;
    numEntries++;	

    // make a list containing only the given list item type.
    SoTypeList listItemTypeList(0);
    listItemTypeList.append( theListItemType );

    // create the new entry
    newEntry = new SoNodekitCatalogEntry( theName, theType, theDefaultType,
	    theNullByDefault, theParentName, theRightSiblingName,
	    theListPart,theListContainerType, listItemTypeList, thePublicPart);
    // enter the new entry in the array
    entries[numEntries - 1] = newEntry;

    // add the new name to the quick-reference part name dictionary
    partNameDict.enter( (unsigned long) theName.getString(), 
			(void *) (unsigned long) (numEntries - 1));

    // parent is no longer a leaf node in the nodekit structure
    if ( parentEntry != NULL ) {
        parentEntry->setLeaf( FALSE );
        parentEntry->setPublic( FALSE );
    }

    // stitch up sibling names.
    if ( leftEntry != NULL )
	leftEntry->setRightSiblingName( theName );
    return TRUE;
}

////////////////////////////////////////////////////////////////////////
//
// Description:
//    Looks for part with the given name within the template.
//    Recursively Checks 'partNumber' only.
//
//    See SoNodekitCatalogEntry::recursiveSearch for more info...
//
// Use: public
SbBool
SoNodekitCatalog::recursiveSearch( int partNumber,
				     const SbName    &nameToFind, 
				     SoTypeList   *typesChecked ) const
//
////////////////////////////////////////////////////////////////////////
{
    // just call the recursive search method on the given entry...
    return( entries[partNumber]->recursiveSearch( nameToFind, typesChecked ));
}