Sources/MSAESetData.c

// MSAESetData.c
//
// Original version by Jon Lansdell and Nigel Humphreys.
// 4.0 and 3.1 updates by Greg Sutton.
// ©Apple Computer Inc 1996, all rights reserved.
 
/*
        Changes for 4.0
 
        29-Feb-96 : GS : Added abiltiy to set properties from menus and menu items.
        29-Feb-96 : GS : Added script properties to application and document objects.
*/
 
#include "MSAESetData.h"
 
#include "MSWindow.h"
#include "MSGlobals.h"
#include "MSAEUtils.h"
#include "MSAETextUtils.h"
#include "MSAEWindowUtils.h"
#include "MSAEMenuUtils.h"
#include "MSAppleEvents.h"
 
#include "MSAESelect.h"
#include "MSScript.h"
#include "MSAECreate.h"
 
#ifdef THINK_C
    #include "PLStrs.h"
#else
    #include <PLStringFuncs.h>
#endif
#include <string.h>
 
    // Prototypes
void    SendwCalcRgnsToWind( WindowPtr wP );
 
 
// --------------------------------------------------------------------------
//  Name:           DoSetData
//  Purpose:        Handles the SetData Apple Event, extracting the direct
//                  object (which says what to set) and the data (what to set
//                  it to).
// --------------------------------------------------------------------------
     
pascal OSErr    DoSetData(const AppleEvent  *theAppleEvent,
                                AppleEvent  *reply,
                                long        handlerRefCon)
{
#ifdef __MWERKS__
    #pragma unused (reply, handlerRefCon)
#endif
    
    AEDesc  directObj = {typeNull, NULL},
            dataDesc = {typeNull, NULL};
    OSErr   err;
            
        // pick up the direct object, which is the object whose data is to be set
    err = AEGetParamDesc(theAppleEvent,  keyDirectObject,
                                    typeWildCard, &directObj);
    if (noErr != err) goto done;
        
        // now the data to set it to - typeWildCard means get as is
        // e.g. this is the name of the font for text
    err = AEGetParamDesc(theAppleEvent, keyAEData, typeWildCard, &dataDesc);
    if (noErr != err) goto done;
    
        // missing any parameters?
    err = GotRequiredParams(theAppleEvent);
    if (noErr != err) goto done;
    
        // set the data
    err = HandleSetData(&directObj, &dataDesc);
 
done:           
    (void)AEDisposeDesc(&directObj);
    (void)AEDisposeDesc(&dataDesc);
 
    return(err);
}   // DoSetData
 
 
// ---------------------------------------------------------------------------
//      Name:           HandleSetData
//      Purpose:        Resolves the object into a token (could be one of 
//                      many) andthe sets the data of that object to dataDesc.
// ---------------------------------------------------------------------------
     
OSErr HandleSetData(const AEDesc *theObj, AEDesc *dataDesc)
{
    TextToken       theTextToken;
    Size            tokenSize;
    AEDesc          objTokenDesc = {typeNull, NULL},
                    itemDesc = {typeNull, NULL},
                    ignoreResult = {typeNull, NULL};
    long            index;
    DescType        returnedType;
    OSErr           err;
 
        //  Coerce theObj into a token which we can use - 
        //   set the property or data for that token
    if ( typeObjectSpecifier == theObj->descriptorType )
        err = AEResolve( theObj, kAEIDoMinimum, &objTokenDesc );
    else if ( typeNull != theObj->descriptorType )  // Otherwise, just copy it
        err = AEDuplicateDesc( theObj, &objTokenDesc );
 
    if (noErr != err) goto done;
            
    switch (objTokenDesc.descriptorType)
    {
        case typeMyApplProp:
            err = SetApplicationProperty( &objTokenDesc, dataDesc );
            break;
    
        case typeMyWindowProp:
            err = SetWindowProperty(&objTokenDesc, dataDesc);
            break;
        
        case typeMyDocumentProp:
            err = SetDocumentProperty(&objTokenDesc, dataDesc);
            break;
            
        case typeMyMenuProp:
            err = SetMenuProperty( &objTokenDesc, dataDesc );
            break;
            
        case typeMyMenuItemProp:
            err = SetMenuItemProperty( &objTokenDesc, dataDesc );
            break;
        
        case typeMyTextProp:
            err = SetTextProperty(&objTokenDesc, dataDesc);
            break;
            
        case typeMyText:
            GetRawDataFromDescriptor(&objTokenDesc,  (Ptr)&theTextToken,
                                            sizeof(theTextToken), &tokenSize);
            
                        // itemDesc is a null descriptor here
            err = CreateAtTextToken(cText, dataDesc, &theTextToken,
                                                    &itemDesc, &ignoreResult);
            break;
 
        case typeAEList:                // If it's a list then do each item
            err = AECountItems(&objTokenDesc, &index);
            if (noErr != err) goto done;
 
            for (; index > 0; index--)
            {
                err = AEGetNthDesc(&objTokenDesc, index, typeWildCard, &returnedType, &itemDesc);
 
                if (noErr == err)       // Get property by calling this function again
                    err = HandleSetData(&itemDesc, dataDesc);
                
                if (itemDesc.dataHandle)
                    AEDisposeDesc(&itemDesc);
            }
            break;
            
        default:
            err = errAEWrongDataType;
    }
 
done:
    (void)AEDisposeDesc( &objTokenDesc );
    (void)AEDisposeDesc( &itemDesc );
    (void)AEDisposeDesc( &ignoreResult );
 
    return err;
} // HandleSetData
 
 
 
OSErr   SetApplicationProperty( const AEDesc *theTokenDesc, const AEDesc *dataDesc )
{
    AppPropToken    aToken;
    AEDesc          aDesc = {typeNull, NULL};
    Size            tokenSize;
    OSErr           err;
 
    err = AECoerceDesc( theTokenDesc, typeMyApplProp, &aDesc );
    if (noErr != err) goto done;
 
    GetRawDataFromDescriptor( &aDesc, (Ptr)&aToken,
                                    sizeof( aToken ), &tokenSize );
    
    SetApplicationTokenProperty( &aToken, dataDesc );
    
done:
    (void)AEDisposeDesc(&aDesc);
    
    return(err);
} // SetApplicationProperty
 
 
OSErr   SetApplicationTokenProperty( AppPropToken* theToken, const AEDesc *dataDesc )
{
    OSErr           err;
    
    switch ( theToken->tokenProperty )
    {
        case pScript:
            err = SetScriptDesc( dataDesc, &gAppRec.theScriptID );
            break;
    
        default:    
            err = errAEEventNotHandled;
    }
    
    return err;
}
 
 
OSErr   SetWindowSelectionProperty(WindowPtr theWindow, const AEDesc *dataDesc)
{
    AEDesc      textDesc = {typeNull, NULL},
                ignoreResult = {typeNull, NULL};
    TextToken   aTextToken;
    Size        actualSize;
    short       ignore;
    OSErr       err;
        
    // first check to see if we are dealing with a TEXT descriptor or
    // an object specifier. Since AECoerceDesc will end up calling
    // AEResolve, we don't want to call this if the user entered something
    // like 'Set selection of window 1 to "some text"
 
    switch (dataDesc->descriptorType)
    {
        case typeChar:
        case typeIntlText:
        case typeStyledText:
            err = GetWindowSelection(theWindow, &aTextToken, &ignore);
            if (noErr != err) goto done;
 
                        // textDesc is a null descriptor here
            err = CreateAtTextToken(cText, dataDesc, &aTextToken,
                                                    &textDesc, &ignoreResult);
            break;
            
        default:     // we are dealing with an object specifier
            err = AECoerceDesc(dataDesc, typeMyText, &textDesc);
            if (noErr != err) goto done;
            
            GetRawDataFromDescriptor(&textDesc, (Ptr)&aTextToken, sizeof(aTextToken),
                                            &actualSize);
                                            
            SelectTextToken(&aTextToken);
    }
 
done:
    (void)AEDisposeDesc(&textDesc);
 
    return(err);
}
 
 
void    SendwCalcRgnsToWind( WindowPtr wP )
{
// This forces a wCalcRgns message to be sent to the windows proc!! Ughhhhhhh.....
    Handle                  h;
    long                    param = 0;
    SInt8                   hState;
 
    h = (*(WindowPeek)wP).windowDefProc;
    hState = HGetState(h);
    HLock(h);       // paranoia?
 
    CallWindowDefProc((WindowDefProcPtr)*h, documentProc, wP, wCalcRgns, param);
 
    HSetState(h, hState);
}
 
 
OSErr   SetWindowProperty( const AEDesc *theTokenDesc, const AEDesc *dataDesc )
{
    WindowPropToken theWindowPropToken;
    AEDesc          aDesc = {typeNull, NULL};
    Size            tokenSize;
    OSErr           err;
 
    err = AECoerceDesc( theTokenDesc, typeMyWindowProp, &aDesc );
    if (noErr != err) goto done;
 
    GetRawDataFromDescriptor( &aDesc, (Ptr)&theWindowPropToken,
                                    sizeof(theWindowPropToken), &tokenSize );
                                    
    err = SetWindowTokenProperty( &theWindowPropToken, dataDesc );
 
done:
    (void)AEDisposeDesc( &aDesc );
 
    return err;
}
 
 
// ------------------------------------------------------------------------
//  Name:       SetWindowTokenProperty
//  Purpose:    Sets the window property specified in theToken to
//              be that supplied in dataDesc.
// ------------------------------------------------------------------------
 
OSErr   SetWindowTokenProperty( WindowPropToken* theToken, const AEDesc* theData )
{
    Rect        aRect,
                strucRect,
                contRect;
    Boolean     aBoolean;
    Str255      aString;
    long        aLong;
    GrafPtr     aPort;
    WindowPeek  aWindowPeek;
    OSErr       err = noErr;
    
    switch (theToken->tokenProperty)
    {
        case pBounds:
            err = GetRectFromDescriptor( theData, &aRect );
            if ( noErr != err ) goto done;
            
            err = GetWindowBounds( theToken->tokenWindowToken.tokenWindow, &strucRect );
                // Don't set bounds if they're the same as before
            if ( noErr != err || EqualRect( &aRect, &strucRect ) ) goto done;
            
            aWindowPeek = (WindowPeek)theToken->tokenWindowToken.tokenWindow;
 
            aBoolean = IsVisible( theToken->tokenWindowToken.tokenWindow );
 
            if ( ! aBoolean )
                SendwCalcRgnsToWind( theToken->tokenWindowToken.tokenWindow );
            
            strucRect = (*aWindowPeek->strucRgn)->rgnBBox;
            contRect = (*aWindowPeek->contRgn)->rgnBBox;
 
            // the rectangle is for the structure region, and is in global coordinates
            // MoveWindow and SizeWindow apply to the content region, so we have to massage a little
 
            aRect.top    += contRect.top - strucRect.top;
            aRect.left   += contRect.left - strucRect.left;
            aRect.bottom -= strucRect.bottom - contRect.bottom;
            aRect.right  -= strucRect.right - contRect.right;
            
            if ( EmptyRect( &aRect ) ) 
                err = errAECorruptData;
            else
            {
                if ( aBoolean )     // IsVisible
                {
                    MoveWindow( theToken->tokenWindowToken.tokenWindow,
                                         aRect.left,
                                         aRect.top,
                                         false );
                    SizeWindow( theToken->tokenWindowToken.tokenWindow,
                                         aRect.right - aRect.left,
                                         aRect.bottom - aRect.top,
                                         true );
                }
                else
                {           // Move offscreen first
                    MoveWindow( theToken->tokenWindowToken.tokenWindow,
                                         10000,
                                         10000,
                                         false );
 
                            // Encapsulate the resizing in Show then Hide
                    ShowWindow( theToken->tokenWindowToken.tokenWindow );
                    SizeWindow( theToken->tokenWindowToken.tokenWindow,
                                         aRect.right - aRect.left,
                                         aRect.bottom - aRect.top,
                                         true );
                    HideWindow( theToken->tokenWindowToken.tokenWindow );
 
                            // Move it to the proper place
                    MoveWindow( theToken->tokenWindowToken.tokenWindow,
                                         aRect.left,
                                         aRect.top,
                                         false );
                }
 
                GetPort( &aPort );
                SetPort( theToken->tokenWindowToken.tokenWindow );
                ResizeWindow( DPtrFromWindowPtr( theToken->tokenWindowToken.tokenWindow ) );
                SetPort( aPort );
            }
            break;
 
        case pVisible:
            err = GetBooleanFromDescriptor(theData, &aBoolean);
            if (noErr != err) goto done;
 
            if (aBoolean)
                ShowMSWindow(theToken->tokenWindowToken.tokenWindow);
            else
                HideMSWindow(theToken->tokenWindowToken.tokenWindow);
            break;
 
        case pIsZoomed:
            GetPort( &aPort );
            SetPort( theToken->tokenWindowToken.tokenWindow );
            err = GetBooleanFromDescriptor( theData, &aBoolean );
            if ( aBoolean )
                ZoomWindow( qd.thePort, inZoomOut, false );
            else
                ZoomWindow( qd.thePort, inZoomIn, false );
                                                    
            ResizeWindow( DPtrFromWindowPtr( theToken->tokenWindowToken.tokenWindow ) );
            SetPort( aPort );
            break;
 
        case pName:
            err = GetPStringFromDescriptor(theData, aString);
            if (noErr != err) goto done;
            
            SetWTitle(theToken->tokenWindowToken.tokenWindow, aString);
            break;
            
        case pIndex:
            err = GetLongIntFromDescriptor(theData, &aLong);
            if (noErr != err) goto done;
            
            SetWindowIndex( theToken->tokenWindowToken.tokenWindow, aLong );
            break;
 
        case pBestType:
        case pClass:
        case pDefaultType:
        case pHasCloseBox:
        case pIsZoomable:
            err = errAEEventNotHandled;
            break;
            
        default:
            err = errAEEventNotHandled;
    }
 
done:   
    return(err);
}
 
 
OSErr   SetDocumentProperty( const AEDesc *theTokenDesc, const AEDesc *dataDesc )
{
    WindowPropToken theWindowPropToken;
    AEDesc          aDesc = {typeNull, NULL};
    Size            tokenSize;
    OSErr           err;
 
    err = AECoerceDesc( theTokenDesc, typeMyDocumentProp, &aDesc );
    if (noErr != err) goto done;
 
    GetRawDataFromDescriptor( &aDesc, (Ptr)&theWindowPropToken,
                                    sizeof(theWindowPropToken), &tokenSize );
    
    SetDocumentTokenProperty( &theWindowPropToken, dataDesc );
    
done:
    (void)AEDisposeDesc(&aDesc);
    
    return(err);
} // SetDocumentProperty
 
 
OSErr   SetDocumentTokenProperty( WindowPropToken* theToken, const AEDesc *dataDesc )
{
    Str255          aPStr;
    DPtr            theDocument;
    THPrint         theTHPrint;
    TextToken       aTextToken;
    Boolean         aBoolean;
    AEDesc          nullDesc = {typeNull, NULL},
                    aDesc = {typeNull, NULL};
    Handle          hGXJobData;
    OSErr           err = noErr;
    
    theDocument = DPtrFromWindowPtr( theToken->tokenWindowToken.tokenWindow );
    
    switch ( theToken->tokenProperty )
    {
        case pName:
            err = GetPStringFromDescriptor( dataDesc, aPStr );
            if (noErr != err) goto done;
 
            if ( aPStr[0] == 0) 
                err = errAEWrongDataType;
            else
            {
                SetWTitle( theToken->tokenWindowToken.tokenWindow, aPStr );
                PLstrcpy( theDocument->theFileName, aPStr ); // Should we do this???
            }
            break;
 
        case pText:
        case pContents:
                            // Get whole window as place to insert data
            err = TextTokenFromDocumentToken(&(theToken->tokenWindowToken), &aTextToken);
            if (noErr != err) goto done;
 
            err = CreateAtTextToken( cText, dataDesc, &aTextToken,
                                                    &nullDesc, &aDesc );
            break;
 
        case pIsModified:
            err = GetBooleanFromDescriptor( dataDesc, &aBoolean );
            if (noErr != err) goto done;
        
            theDocument->dirty = aBoolean;
            goto done;  // Don't set dirty flag again
            
        case pPageSetup:
            if ( ! gGXIsPresent )
            {
                err = GetTHPrintFromDescriptor(dataDesc, &theTHPrint);
                    
                if (theTHPrint) 
                {
                    if (theDocument->thePrintSetup) 
                        DisposHandle((Handle)theDocument->thePrintSetup);
                        
                    theDocument->thePrintSetup = theTHPrint;
                    
                    ResizePageSetupForDocument(theDocument);
                }
            }
            else
                err = errAEEventNotHandled;                  
            break;
            
        case pGXPageSetup:
            if ( gGXIsPresent )
            {
                err = AECoerceDesc(dataDesc,typeTGXPrint,&aDesc);
    
                hGXJobData = nil;
    
                if (err==noErr) 
                {
                    hGXJobData = NewHandle(GetHandleSize(aDesc.dataHandle));
    
                    BlockMove(*(aDesc.dataHandle),
                                        *hGXJobData,
                                        GetHandleSize(aDesc.dataHandle));
                }
                    
                if (hGXJobData) 
                {
                    GXUnflattenJobFromHdl(theDocument->documentJob, hGXJobData);
                    err = GXGetJobError(theDocument->documentJob);
                    
                    ResizePageSetupForDocument(theDocument);
                }
            }
            else
                err = errAEEventNotHandled;                  
            break;
            
        case pSelection:
            err = SetWindowSelectionProperty(theToken->tokenWindowToken.tokenWindow, dataDesc);
            break;
    
        case pScript:
            err = SetScriptDesc( dataDesc, &theDocument->theScriptID );
            break;
 
        default:    
            err = SetWindowTokenProperty( theToken, dataDesc );
    }
    
    if ( noErr == err && pIsModified != theToken->tokenProperty)
        theDocument->dirty = true;
    
done:
    (void)AEDisposeDesc( &nullDesc );
    (void)AEDisposeDesc( &aDesc );
    
    return(err);
}
 
OSErr   GetTHPrintFromDescriptor(const AEDesc *sourceDesc, THPrint *result)
{
    Size    ptSize;
    AEDesc  resultDesc;
    OSErr   err;
    
    *result = NULL;
    
    err = AECoerceDesc(sourceDesc, typeTPrint, &resultDesc);
    if (noErr != err) goto done;
    
    *result = (THPrint)NewHandle(sizeof(TPrint));
    
    PrOpen();
    PrintDefault(*result);
    
    HLock((Handle)*result);
    GetRawDataFromDescriptor(&resultDesc, (Ptr)**result, sizeof(TPrint), &ptSize);
    HUnlock((Handle)*result);
    
    if ((ptSize<sizeof(TPrint)) || (PrValidate(*result)))
    {
        err = errAECoercionFail;
        DisposHandle((Handle)*result);
        *result = NULL;
    }
    
    PrClose();
 
done:   
    if (resultDesc.dataHandle) 
        AEDisposeDesc(&resultDesc);
        
    return(err);
} // GetTHPrintFromDescriptor
 
 
OSErr   SetMenuProperty( const AEDesc *theTokenDesc, const AEDesc *dataDesc )
{
    MenuPropToken   aToken;
    Size            tokenSize;
    OSErr           err;
 
    if ( typeMyMenuProp != theTokenDesc->descriptorType )
        return errAEWrongDataType;
 
    GetRawDataFromDescriptor( theTokenDesc, (Ptr)&aToken,
                                    sizeof( aToken ), &tokenSize );
                                    
    err = SetMenuTokenProperty( &aToken, dataDesc );
 
    return err;
}
 
OSErr   SetMenuTokenProperty( MenuPropToken* theToken, const AEDesc* theData )
{
    MenuScriptRecPtr    aMenuRecPtr;
    OSErr               err;
    
    switch ( theToken->tokenProperty )
    {
        case pScript:
            aMenuRecPtr = GetMenuScriptRecPtr( theToken->token.tokenID * 32 );
            if ( ! aMenuRecPtr || kOSANullScript == aMenuRecPtr->theScriptID )
            {
                err = errAENoSuchObject;
                goto done;
            }
        
            err = SetScriptDesc( theData, &aMenuRecPtr->theScriptID );
            if ( noErr == err )
                aMenuRecPtr->fChanged = true;
            break;
            
        default:
            err = errAEEventNotHandled;
    }
 
done:   
    return(err);
}
 
 
OSErr   SetMenuItemProperty( const AEDesc *theTokenDesc, const AEDesc *dataDesc )
{
    MenuItemPropToken   aToken;
    Size                tokenSize;
    OSErr               err;
 
    if ( typeMyMenuItemProp != theTokenDesc->descriptorType )
        return errAEWrongDataType;
 
    GetRawDataFromDescriptor( theTokenDesc, (Ptr)&aToken,
                                    sizeof( aToken ), &tokenSize );
                                    
    err = SetMenuItemTokenProperty( &aToken, dataDesc );
 
    return err;
}
 
OSErr   SetMenuItemTokenProperty( MenuItemPropToken* theToken, const AEDesc* theData )
{
    AEDesc              aDesc = { typeNull, NULL };
    MenuScriptRecPtr    aMenuRecPtr;
    Str255              aPStr;
    short               aResID;
    OSErr               err;
 
    aResID = theToken->token.tokenMenuToken.tokenID * 32 + theToken->token.tokenItem;
    aMenuRecPtr = GetMenuScriptRecPtr( aResID );
    
    switch ( theToken->tokenProperty )
    {
        case pName:
            err = GetPStringFromDescriptor( theData, aPStr );
            if ( noErr != err ) goto done;
            
            SetMenuItemName( &theToken->token, aPStr );
            
                // If there is a script associated then try setting the
                // itemName property.
            if ( aMenuRecPtr && kOSANullScript != aMenuRecPtr->theScriptID )
            {
                err = PutPStringToDescriptor( &aDesc, "\pitemname" );
                if ( noErr != err ) goto done;
            
                    // Ignore the error because it may not have the property
                (void)SetScriptProperty( aMenuRecPtr->theScriptID, &aDesc, theData );
            }
            break;
    
        case pScript:
            if ( ! aMenuRecPtr || kOSANullScript == aMenuRecPtr->theScriptID )
            {
                err = errAENoSuchObject;
                goto done;
            }
        
            err = SetScriptDesc( theData, &aMenuRecPtr->theScriptID );
            if ( noErr == err )
            {
                aMenuRecPtr->fChanged = true;
                err = CheckForMenuItemName( aResID, aMenuRecPtr->theScriptID );
            }
            break;
            
        default:
            err = errAEEventNotHandled;
    }
 
done:
    (void)AEDisposeDesc( &aDesc );
    
    return(err);
}
 
OSErr   CheckForMenuItemName( short theResID, OSAID theOSAID )
{
    AEDesc      aDesc = { typeNull, NULL },
                aNameDesc = { typeNull, NULL };
    Str255      aPStr;
    OSErr       anErr;
    
    anErr = PutPStringToDescriptor( &aDesc, "\pitemname" );
    if ( noErr != anErr ) goto done;
 
    anErr = GetScriptProperty( theOSAID, &aDesc, &aNameDesc );
    if ( noErr == anErr )
    {
        anErr = GetPStringFromDescriptor( &aNameDesc, aPStr );
        if ( noErr != anErr ) goto done;
    
        SetMenuItemText( MenuHandleFromMenuID( theResID / 32 ), theResID % 32, aPStr );
    }
    else
        anErr = noErr;  // Just doesn't have the property so no error
 
done:   
    return anErr;
}
 
 
// ----------------------------------------------------------------------
//  Name:       SetTextProperty
//  Purpose:    Sets the text property specfied by theTextPropToken to
//              that in dataDesc.
// ----------------------------------------------------------------------
     
OSErr   SetTextProperty(const AEDesc *tokenDesc, const AEDesc *dataDesc)
{
    DPtr            theDoc;
    Str255          name;
    short           theSize;
    Style           onStyle;
    Style           offStyle;
    TextPropToken   theTextPropToken;
    AEDesc          newDesc = {typeNull, NULL},
                    nullDesc = {typeNull, NULL},
                    ignoreResult = {typeNull, NULL};
    Size            tokenSize;
    OSErr           err;
 
    err = AECoerceDesc(tokenDesc, typeMyTextProp, &newDesc);
    if (noErr != err) goto done;
 
    GetRawDataFromDescriptor(&newDesc, (Ptr)&theTextPropToken,
                                    sizeof(theTextPropToken), &tokenSize);
        
    theDoc = DPtrFromWindowPtr(theTextPropToken.tokenTextToken.tokenWindow);
    theDoc->dirty = true;
    
    switch (theTextPropToken.tokenProperty)
    {
        case pText:
        case pContents:
            err = CreateAtTextToken(cText, dataDesc, &(theTextPropToken.tokenTextToken),
                                                                &nullDesc, &ignoreResult);
            break;
            
        case pFont:
            err = GetPStringFromDescriptor(dataDesc, name);
            if (noErr != err) goto done;
            err = SetFontOfTextToken(&theTextPropToken.tokenTextToken, name);
            break;
            
        case pPointSize:    
            err = GetIntegerFromDescriptor(dataDesc, &theSize);
            if (noErr != err) goto done;
            err = SetSizeOfTextToken(&theTextPropToken.tokenTextToken, theSize);
            break;
            
        case pTextStyles:
            onStyle  = 0;
            offStyle = 0;
            
            err = GetTextStyles(dataDesc, &onStyle, &offStyle);
            if (noErr != err) goto done;
 
            if (onStyle & offStyle != 0)
                err = errAEEventFailed;
            else
                err = SetStyleOfTextToken(&theTextPropToken.tokenTextToken, onStyle, offStyle);
            break;
        
        default:
            err = errAEWrongDataType;
    }
 
done:
    (void)AEDisposeDesc(&newDesc);
            
    return(err);
} // SetTextProperty
 
    
short ItemForNamedFont(Str255 theName)
{
    Str255  itemName;
    short   limit;
 
    limit = CountMItems(myMenus[fontM]);
    while (limit>0)
    {
        GetItem(myMenus[fontM],limit, itemName);
        if (IUEqualString(theName, itemName)==0) 
            return(limit);
        else
            limit--;
    }
    return(0);
} // ItemForNamedFont
 
 
// -----------------------------------------------------------------------
//  Name:       SetFontOfTextToken
//  Purpose:    Sets the font of the text specified by theToken to 
//              the font in name.
// -----------------------------------------------------------------------
     
OSErr   SetFontOfTextToken(TextToken* theToken, Str255 name)
{
    DPtr        docPtr;
    TextToken   oldSelection;
    short       theNumber,
                theItem;
    TextStyle   newStyle;
    Boolean     fCurrentSelection;
    OSErr       err;
 
    docPtr = DPtrFromWindowPtr(theToken->tokenWindow);
    
    if (!docPtr) return(errAENoSuchObject);
        
                // ignore theNumber result
    err = GetWindowSelection(theToken->tokenWindow, &oldSelection, &theNumber);
    if (noErr != err) goto done;
    
    if (memcmp(theToken, &oldSelection, sizeof(TextToken)))
    {
        fCurrentSelection = false;
        err = SelectTextToken(theToken);    // Only set the selection if it's different
        if (noErr != err) goto done;
    }
    else
        fCurrentSelection = true;
            
    GetFNum(name, &theNumber);
    
    theItem = ItemForNamedFont(name); // returns 0 if failed - i.e. SystemFont
    
    if (gFontMItem)
        CheckItem(myMenus[fontM], gFontMItem, false);
    
    gFontMItem = theItem;
    CheckItem(myMenus[fontM], gFontMItem, true);
    
    docPtr->theFont = theNumber;
        
    newStyle.tsFont = theNumber;
    TESetStyle(doFont, &newStyle, true, docPtr->theText); 
    
    AdjustScrollbars(docPtr, false);
    DrawPageExtras(docPtr);
    docPtr->dirty = true;
    
    if (! fCurrentSelection)
        err = SelectTextToken(&oldSelection);
 
done:   
    return(err);
} // SetFontOfTextToken
    
// -----------------------------------------------------------------------
//  Name:           SetSizeOfTextToken
//  Purpose:        Sets the size of the text specified by theToken to 
//                  the size in theSize.
// -----------------------------------------------------------------------
     
OSErr   SetSizeOfTextToken(TextToken* theToken, short theSize)
{
    DPtr        docPtr;
    TextToken   oldSelection;
    TextStyle   newStyle;
    short       ignore;
    Boolean     fCurrentSelection;
    OSErr       err;
 
    docPtr = DPtrFromWindowPtr(theToken->tokenWindow);
    
    if (!docPtr) return(errAENoSuchObject);
        
                // Save the old selection
    err = GetWindowSelection(theToken->tokenWindow, &oldSelection, &ignore);
    if (noErr != err) goto done;
    
    if (memcmp(theToken, &oldSelection, sizeof(TextToken)))
    {
        fCurrentSelection = false;
        err = SelectTextToken(theToken);
        if (noErr != err) goto done;
    }
    else
        fCurrentSelection = true;
                            
    docPtr->theSize = theSize;
    
    newStyle.tsSize = theSize;
    TESetStyle(doSize, &newStyle, true, docPtr->theText); 
    
    AdjustScrollbars(docPtr, false);
    DrawPageExtras(docPtr);
    docPtr->dirty = true;
    
    if (! fCurrentSelection)    // If we reset the selection we may loose the
        err = SelectTextToken(&oldSelection);   // Size or style just set
 
done:   
    return(err);
} // SetSizeOfTextToken
    
// ------------------------------------------------------------------------
//  Name:           SetStyleOfTextToken
//  Purpose:        Sets the style of the text specified by theToken to 
//                  the style in theStyle.
// ------------------------------------------------------------------------
     
OSErr   SetStyleOfTextToken(TextToken* theToken, Style onStyle, Style offStyle)
{
    DPtr        docPtr;
    TextToken   oldSelection;
    TextStyle   newStyle;
    short       mode;
    Boolean     wasContinuous;
    short       ignore;
    Boolean     fCurrentSelection;
    OSErr       err;
 
    docPtr = DPtrFromWindowPtr(theToken->tokenWindow);
    
    if (!docPtr) return(errAENoSuchObject);
        
                // Save the old selection
    err = GetWindowSelection(theToken->tokenWindow, &oldSelection, &ignore);
    if (noErr != err) goto done;
    
    if (memcmp(theToken, &oldSelection, sizeof(TextToken)))
    {
        fCurrentSelection = false;
        err = SelectTextToken(theToken);
        if (noErr != err) goto done;
    }
    else
        fCurrentSelection = true;
                            
    docPtr->theStyle = onStyle;
    
        // Check to see if off styles are on for whole selection
    mode = doFace;
    
    wasContinuous = TEContinuousStyle(&mode, &newStyle, docPtr->theText);
    if ((newStyle.tsFace & offStyle) != offStyle) // not off styles are on for all
    {
            // switch on across board so that toggle off will clear all
        newStyle.tsFace  = offStyle - (newStyle.tsFace & offStyle);
        TESetStyle(doFace+doToggle, &newStyle, false, docPtr->theText); 
    }
        
    newStyle.tsFace  = offStyle;
    TESetStyle(doFace+doToggle, &newStyle,(onStyle==0), docPtr->theText); // toggle all to off
    
    mode = doFace;
    if (onStyle)
    {
        wasContinuous = TEContinuousStyle(&mode, &newStyle, docPtr->theText);
        if ((newStyle.tsFace & onStyle) != onStyle) // are they on for only a few chars
        { 
                // Need to make all chars have these characteristics
            newStyle.tsFace = onStyle - (newStyle.tsFace & onStyle); // take out those continuous
            TESetStyle(doFace+doToggle, &newStyle, true, docPtr->theText);
        }
        else
            TESetStyle(0, &newStyle, true, docPtr->theText); // Just Draw it, no changes
    }
        
    AdjustScrollbars(docPtr, false);
    DrawPageExtras(docPtr);
    docPtr->dirty = true;
    
    if (! fCurrentSelection)
        err = SelectTextToken(&oldSelection);
 
done:   
    return(err);
} // SetStyleOfTextToken
 
    
OSErr   GetTextStyles(const AEDesc *dataDesc, Style *onStyles, Style *offStyles)
{
    OSErr      myErr;
    AEDescList textSDesc = { typeNull, NULL };
    AEDescList onDesc = { typeNull, NULL };
    AEDescList offDesc = { typeNull, NULL };
    Boolean    hadPlain;
    
    *onStyles  = 0;
    *offStyles = 0;
    
    myErr = AECoerceDesc(dataDesc, typeAERecord, &textSDesc);
    
    if (myErr==noErr)
      myErr = AEGetKeyDesc(&textSDesc, keyAEOnStyles, typeAEList, &onDesc);
    
    if (myErr==noErr)
      myErr = AEGetKeyDesc(&textSDesc, keyAEOffStyles, typeAEList, &offDesc);
    
    if (myErr==noErr)
        myErr = MakeStyleFromAEList(&onDesc,  onStyles, &hadPlain);
    
    if (hadPlain)
        *offStyles = bold+italic+underline+outline+shadow+condense+extend;
    else
    {
        if (myErr==noErr)
            myErr = MakeStyleFromAEList(&offDesc, offStyles, &hadPlain);
        
        if (hadPlain)
            myErr = errAEEventFailed;
    }
        
    (void)AEDisposeDesc(&textSDesc);
    (void)AEDisposeDesc(&onDesc);
    (void)AEDisposeDesc(&offDesc);
    
    return(myErr);
} // GetTextStyles
 
// -----------------------------------------------------------------------
//  Name:       AddDescStyleItem
//  Purpose:    Adds the kAEXXXX style to theStyle.
// -----------------------------------------------------------------------
     
void    AddDescStyleItem(DescType theDesc, Style *theStyle)
{
    if (theDesc == kAEBold)
        *theStyle = *theStyle+bold;
    else
    if (theDesc == kAEItalic)
        *theStyle = *theStyle+italic;
    else
    if (theDesc == kAEUnderline)
        *theStyle = *theStyle+underline;
    else
    if (theDesc == kAEOutline)
        *theStyle = *theStyle+outline;
    else
    if (theDesc == kAEShadow)
        *theStyle = *theStyle+shadow;
    else
    if (theDesc == kAECondensed)
        *theStyle = *theStyle+condense;
    else
    if (theDesc == kAEExpanded)
        *theStyle = *theStyle+extend;
    else
    if (theDesc == kAEPlain)
        *theStyle = 0;
} // AddDescStyleItem
    
OSErr   MakeStyleFromAEList(const AEDescList *styleList, Style *theStyle, Boolean *hadPlain)
{
    OSErr     myErr;
    DescType  styleDesc;
    long      itemsInList;
    long      actSize;
    AEKeyword keywd;
    DescType  typeCode;
        
    *hadPlain = false;
    *theStyle = 0;
    
    myErr = AECountItems(styleList, &itemsInList);
    while (itemsInList>0)
        if (myErr==noErr)
        {
            myErr  = AEGetNthPtr(styleList, itemsInList, typeEnumerated, &keywd,
                                &typeCode, (Ptr)&styleDesc, sizeof(styleDesc), &actSize);
            
            AddDescStyleItem(styleDesc, theStyle);
            
            if (styleDesc == kAEPlain) 
            {
                itemsInList = 0;
                *hadPlain = true;
            }
            else
              itemsInList--;
        }
            
    return(myErr);
} // MakeStyleFromAEList