NameAttribute.c

/*
 * Quickdraw 3D sample code
 *
 * This file shows how to implement a simple custom attribute as a plug-in.
 *
 * Nick Thompson, nickt@apple.com, November 1996
 *
 * Please send technical questions that you may have about this code
 * to devsupport@apple.com
 *
 * Based on attributelib.  For more information about the basic principles
 * of this, check the article in develop, plugins in the form of shared 
 * libraries were just a twinkle in kent's eye then.  The main difference 
 * is in the way these puppies get registered, and in the name sapce.
 *
 * This sample code has minimal error checking. More should be added if this
 * code is used in a production quality product.
 *
 * Revision History:
 *      8/12/97 RDD     Changed register and unregister functions and fixed
 *                      CopyReplace method.
 */
 
#include "QD3D.h"
#include "QD3DExtension.h"
#include "QD3DGeometry.h"
#include "QD3DIO.h"
#include "QD3DSet.h"
#include "QD3DString.h"
#include "QD3DView.h"
 
#include <Errors.h>
 
#include <string.h>
#include "NameAttribute.h"
 
 
/******************************************************************************
 **     
 **     Globals
 **     
 *****************************************************************************/
 
static TQ3XObjectClass          pNameAttributeClass = NULL;
 
static unsigned long            pSharedLibrary = 0;
static const    short           pMajorVersion = 1 ;
static const    short           pMinorVersion = 5 ;
 
/******************************************************************************
 **     
 **     Function prototypes for functions local to this file
 **     
 *****************************************************************************/ 
 
static TQ3Status        NameAttribute_Traverse(
                            TQ3Object               unused,
                            TQ3StringObject         *stringObject,
                            TQ3ViewObject           view) ;
 
static TQ3Status        NameAttribute_ReadData(
                            TQ3SetObject            attributeSet,
                            TQ3FileObject           file) ;
 
static TQ3Status        NameAttribute_CopyAdd(
                            TQ3StringObject         *src,
                            TQ3StringObject         *dst) ;
 
static TQ3Status        NameAttribute_CopyReplace(
                            TQ3StringObject         *src,
                            TQ3StringObject         *dst) ;
 
static TQ3Status        NameAttribute_Delete(
                            TQ3StringObject         *stringObject) ;
    
static TQ3XFunctionPointer NameAttribute_MetaHandler(
                            TQ3XMethodType          methodType) ;
 
 
 
/*===========================================================================*\
 *
 *  Routine:    NameAttribute_SetName()
 *
 *  Comments:   Utility function to add a name on an shape object, geometry 
 *              object, or attribute set.
 *
\*===========================================================================*/
 
TQ3Status   NameAttribute_SetName(
    TQ3Object object, 
    char    *name)
{
    TQ3StringObject         string = NULL;
    TQ3AttributeSet         set = NULL;
    TQ3Status               status = kQ3Success;
    TQ3ElementType          myElementType ;
    
    /* 
     * NOTE: You cannot just use the type as it was registered,
     * so you have two options: the first is to save a reference 
     * to the element type that we got back from the register function
     * the second is to use the global class to get the type.  Since
     * we already need to keep the class global, that's what I decided
     * to do here. (This code is not optimal)
     */
     Q3XObjectClass_GetType( pNameAttributeClass, &myElementType) ;
    
    if( Q3Object_IsType(object, kQ3SharedTypeShape) == kQ3True ) {
        
        string = Q3CString_New(name);
        
        if( string == NULL) {
            status = kQ3Failure;
            goto cleanExit;
        }
            
        if( Q3Object_IsType(object, kQ3ShapeTypeGeometry) == kQ3True ) {
            
            Q3Geometry_GetAttributeSet(object, &set);
            
            if( set == NULL ) {
                set = Q3AttributeSet_New();
                if( set == NULL ) {
                    status = kQ3Failure;
                    goto cleanExit;
                }
                Q3Geometry_SetAttributeSet(object, set);
            }
        } else {
            Q3Shape_GetSet(object, &set);
            
            if( set == NULL ) {
                set = Q3Set_New();
                if( set == NULL ) {
                    status = kQ3Failure;
                    goto cleanExit;
                }
                Q3Shape_SetSet(object, set);
            }
        }   
            
        if( Q3Set_Add(set, myElementType, &string) == kQ3Failure ) {
            status = kQ3Failure;
            goto cleanExit;
        }
    } else if( Q3Object_IsType(object, kQ3SharedTypeSet) == kQ3True ) {
        string = Q3CString_New(name);
        
        if( string == NULL) {
            status = kQ3Failure;
            goto cleanExit;
        }
        
        if( Q3AttributeSet_Add(object, myElementType, &string) == kQ3Failure ) {
            status = kQ3Failure;
            goto cleanExit;
        }
    } else 
        status = kQ3Failure;
        
cleanExit:
    if( string )
        Q3Object_Dispose(string);
    if( set )
        Q3Object_Dispose(set);
    return status;
}
 
/*===========================================================================*\
 *
 *  Routine:    NameAttribute_GetName()
 *
 *  Comments:   Utility function to get a name from a shape object, geometry 
 *              object, or an attribute set.
 *
\*===========================================================================*/
 
TQ3Status   NameAttribute_GetName(
    TQ3Object object, 
    char    *name)
{
    TQ3StringObject         string = NULL;
    TQ3AttributeSet         set = NULL;
    TQ3Status               status = kQ3Success;
    char                    *nameString = NULL ;
    TQ3ElementType          myElementType ;
    
    /* 
     * NOTE: You cannot just use the type as it was registered,
     * so you have two options: the first is to save a reference 
     * to the element type that we got back from the register function
     * the second is to use the global class to get the type.  Since
     * we already need to keep the class global, that's what I decided
     * to do here.  Set up the element type:
     */
     Q3XObjectClass_GetType( pNameAttributeClass, &myElementType) ;
    
    if( Q3Object_IsType(object, kQ3SharedTypeShape) == kQ3True ) {
            
        if( Q3Object_IsType(object, kQ3ShapeTypeGeometry) == kQ3True ) {
            
            Q3Geometry_GetAttributeSet(object, &set);
            
            if( set == NULL ) {
                status = kQ3Failure;
                goto cleanExit;
            }
            
        } 
        else 
        {
            Q3Shape_GetSet(object, &set);
        }
        
        if( Q3Set_Contains ( set, myElementType ) == kQ3True ) {
            status = Q3Set_Get ( set, myElementType, &string ) ;
            if( string == NULL || status == kQ3Failure ) {
                status = kQ3Failure;
                goto cleanExit;
            }
        }
        
    } 
    else if( Q3Object_IsType(object, kQ3SharedTypeSet) == kQ3True ) {
 
        if( Q3AttributeSet_Get(object, myElementType, &string) == kQ3Failure ) {
            status = kQ3Failure;
            goto cleanExit;
        }
        
    } else 
        status = kQ3Failure;
    
    if( status != kQ3Failure && string != NULL )
    {
        /* get the string from the CString object */
        status = Q3CString_GetString ( string, &nameString ) ;
        strcpy( name, nameString ) ;
        status = Q3CString_EmptyData(&nameString);
    }
    else
    {
        *name = NULL ;
    }
        
cleanExit:
    if( string )
        Q3Object_Dispose(string);
 
    if( set )
        Q3Object_Dispose(set);
    return status;
}
 
 
/*===========================================================================*\
 *
 *  Routine:    NameAttributeClassRegister()
 *
 *  Comments:   Registers the Name attribute class.
 *
\*===========================================================================*/
 
TQ3Status   NameAttribute_Register( void )
{
    TQ3ElementType  myElementType = kQ3ObjectTypeInvalid ;  /* discarded */
 
    /* 
     * Register the new name element class.  NOTE: this will change myElementType
     * to be a unique type.  This helps to prevent namespace clashes, but you MUST
     * remember to use what you are passed back when accessing the elements of a set.
     *
     * You can either store the value returned in myElementType or use the global
     * pNameAttributeClass.  In this sample we use the latter approach.  Now that we
     * have a reference to the class around we can use that to get the type for 
     * the calls that need the type using the following API call:
     *
     *   Q3XObjectClass_GetType( pNameAttributeClass, &myElementType) ;
     */
     
    pNameAttributeClass =
        Q3XElementClass_Register(
            &myElementType,
            kElementTypeNameString,
            sizeof(TQ3StringObject),
            NameAttribute_MetaHandler );
    
    if (pNameAttributeClass == NULL)
        return kQ3Failure;
    
    return kQ3Success;
}
 
 
/* Name attribute CFM init and termination routines */
 
OSErr NameAttribute_ConnectionInitializationRoutine(InitBlockPtr initBlock)
{
    TQ3Status               theStatus;
    TQ3XSharedLibraryInfo   sharedLibraryInfo;
    OSErr                   osErr;
 
    /*
     * Register this custom attribute/element with QuickDraw 3D using the
     * callback Q3XSharedLibrary_Register which is passed the register function
     * and the closureID (_not_ the connectionID).
     */
    sharedLibraryInfo.registerFunction = NameAttribute_Register;
    sharedLibraryInfo.sharedLibrary    = (unsigned long)initBlock->connectionID;
    theStatus = Q3XSharedLibrary_Register(&sharedLibraryInfo);
 
    if (theStatus == kQ3Success) {
        pSharedLibrary = (unsigned long)initBlock->connectionID;
        osErr = noErr;
    }
    else {
        osErr = fragMgrInitErr; /* ...or some other meaningfull error */
    }
 
    return osErr;
}
 
 
 
void NameAttribute_ConnectionTerminationRoutine (void)
{
    TQ3Status theStatus ;
    
    if( pSharedLibrary != NULL ) {
        theStatus = Q3XSharedLibrary_Unregister(pSharedLibrary);
        pSharedLibrary = NULL;
    }
    
    theStatus = NameAttribute_Unregister() ;
}
 
 
/*
 * Static Functions
 */
 
static TQ3Status NameAttribute_Traverse(
    TQ3Object               unused,
    TQ3StringObject         *stringObject,
    TQ3ViewObject           view)
{
    (void) unused;
    
    if (stringObject == NULL || *stringObject == NULL)
        return kQ3Success;
 
    if (Q3XView_SubmitWriteData(view, 0, NULL, NULL) == kQ3Failure) {
        return kQ3Failure;
    }
 
    if (Q3Object_Submit( *stringObject, view) == kQ3Failure) {
        return kQ3Failure;
    }
 
    return kQ3Success;
}
 
static TQ3Status NameAttribute_ReadData(
    TQ3SetObject            attributeSet,
    TQ3FileObject           file)
{
    TQ3StringObject         stringObject;
    TQ3Status               status;
    
    TQ3ElementType          myElementType ;
    
    /* 
     * NOTE: You cannot just use the type as it was registered,
     * so you have two options: the first is to save a reference 
     * to the element type that we got back from the register function
     * the second is to use the global class to get the type.  Since
     * we already need to keep the class global, that's what I decided
     * to do here.
     */
    Q3XObjectClass_GetType( pNameAttributeClass, &myElementType) ;
 
    stringObject = Q3File_ReadObject(file);
        
    status = Q3Set_Add(attributeSet, myElementType, &stringObject);
    
    Q3Object_Dispose(stringObject);
 
    /*
     *  Note that the string object has a reference count of 1,
     *  which will be taken care of in the dispose
     */
    return status;
}
 
static TQ3Status NameAttribute_CopyAdd(
    TQ3StringObject *src,
    TQ3StringObject *dst)
{
    *dst = Q3Shared_GetReference(*src);
 
    return (*dst != NULL) ? kQ3Success : kQ3Failure;
}
 
static TQ3Status NameAttribute_CopyReplace(
    TQ3StringObject *src,
    TQ3StringObject *dst)
{
    TQ3StringObject tempString;
    
    /*
     *  It is always good form to get a reference first,
     *  in case src and dst point to the same object
     */
    
    tempString = Q3Shared_GetReference(*src);
    if (tempString == NULL) 
        return kQ3Failure;
 
    if( *dst )
        Q3Object_Dispose( *dst );
    
    *dst = tempString;
 
    return kQ3Success;
}
 
static TQ3Status NameAttribute_Delete(
    TQ3StringObject *stringObject)
{
    if (*stringObject != NULL) {
        Q3Object_Dispose(*stringObject);
        *stringObject = NULL;
    }
 
    return kQ3Success;
}
 
TQ3Status NameAttribute_Unregister(
    void)
{
    TQ3Status       returnVal = kQ3Failure ;
    
    if ( pNameAttributeClass != NULL )
    {
        /*
         * QuickDraw 3D unregisters this object together with all
         * other registered objects in the system on Q3Exit.
         */
        pNameAttributeClass = NULL ;
        returnVal = kQ3Success ;
    }   
 
    return returnVal ;
}
 
 
 
/*
 * NameAttribute_MetaHandler
 */
static TQ3XFunctionPointer NameAttribute_MetaHandler(
    TQ3XMethodType      methodType)
{
    switch (methodType)
    {
        case kQ3XMethodTypeObjectClassVersion:
            return (TQ3XFunctionPointer)
                Q3_OBJECT_CLASS_VERSION(pMajorVersion, pMinorVersion);
 
        case kQ3XMethodTypeObjectTraverse:
            return (TQ3XFunctionPointer) NameAttribute_Traverse;
 
        case kQ3XMethodTypeObjectReadData:
            return (TQ3XFunctionPointer) NameAttribute_ReadData;
 
        case kQ3XMethodTypeElementCopyAdd:
        case kQ3XMethodTypeElementCopyGet:
        case kQ3XMethodTypeElementCopyDuplicate:
            return (TQ3XFunctionPointer) NameAttribute_CopyAdd;
 
        case kQ3XMethodTypeElementCopyReplace:
            return (TQ3XFunctionPointer) NameAttribute_CopyReplace;
 
        case kQ3XMethodTypeElementDelete:
            return (TQ3XFunctionPointer) NameAttribute_Delete;
 
        default:
            return (TQ3XFunctionPointer) NULL;
    }
}