Source/SVAEGetData.c

/*
    File:       SVAEGetData.c
 
    Contains:   
 
    Written by: Original version by Jon Lansdell and Nigel Humphreys.
                3.1 updates by Greg Sutton.
 
    Copyright:  Copyright © 1995-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
 
    Change History (most recent first):
                7/20/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
 
#include "SVAEGetData.h"
 
#include "SVEditWindow.h"
#include "SVEditGlobals.h"
#include "SVEditAEUtils.h"
#include "SVAppleEvents.h"
 
#include "SVAETextUtils.h"
#include "SVAEWindowUtils.h"
#include "SVAEAccessors.h"
#include "SVAERecording.h"
#include "SVToken.h"
 
 
#include <AEPackObject.h>
#include <Resources.h>
#include <Script.h>
 
 
 
extern short        gRefNum;
 
// -----------------------------------------------------------------------
//      Name:           DoGetData
//      Purpose:        Handles the GetData AppleEvent.
// -----------------------------------------------------------------------
 
pascal OSErr     DoGetData(const AppleEvent *theAppleEvent,
                                AppleEvent  *reply,
                                long        handlerRefCon)
{ 
#pragma unused (handlerRefCon)
 
    AEDesc      directObj = {typeNull, NULL},
                result = {typeNull, NULL};
    Size        actualSize;
    DescType    returnedType;
    DescType    reqType;
    OSErr       reqTypeErr,
                err;
    
        // extract the direct object, which is the object
        // whose data is to be returned
    err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeWildCard, &directObj);
    if (noErr != err) goto done;
        
        // now the get the type of data wanted - optional
    reqTypeErr = AEGetParamPtr(theAppleEvent, keyAERequestedType, typeType,
                                &returnedType, (Ptr)&reqType, sizeof(reqType), &actualSize);
        
    err = GotRequiredParams(theAppleEvent);
    if (noErr != err) goto done;
    
        // get the data
    err = HandleGetData(&directObj, &result);
        
    err = AddResultToReply(&result, reply, err);
 
done:               
    if (directObj.dataHandle)
          AEDisposeDesc(&directObj);
    if (result.dataHandle)
          AEDisposeDesc(&result);
        
    return(err);
}   // DoGetData
 
 
// -----------------------------------------------------------------------
//  Name:       HandleGetData
//  Purpose:    Coerces theObj into a token which we understand and
//              extracts the data requested in the token and puts it
//              into dataDesc.
// -----------------------------------------------------------------------
 
OSErr   HandleGetData(AEDesc *theObj, AEDesc *dataDesc)
{
    TextToken       theTextToken;
    Size            tokenSize;
    AEDesc          objTokenDesc = {typeNull, NULL},
                    itemDesc = {typeNull, NULL},
                    resultDesc = {typeNull, NULL};
    long            index;
    DescType        returnedType;
    OSErr           err;
 
            //  Coerce theObj into a token which we can use - 
            //      this may involve converting a list of tokens to a list of property tokens
    if (typeObjectSpecifier == theObj->descriptorType)
        err = AEResolve(theObj, kAEIDoMinimum, &objTokenDesc);
    else    // Otherwise, just copy it
        err = AEDuplicateDesc(theObj, &objTokenDesc);
    
    if (noErr != err) goto done;
    
    switch (objTokenDesc.descriptorType)
    {
        case typeMyApplProp:
            err = GetApplicationProperty(&objTokenDesc, dataDesc);
            break;
            
        case typeMyTextProp:
            err = GetTextProperty(&objTokenDesc, dataDesc);
            break;
            
        case typeMyWindowProp:
            err = DoGetWindowProperty(&objTokenDesc, dataDesc);
            break;
            
        case typeMyText:
            GetRawDataFromDescriptor(&objTokenDesc, (Ptr)&theTextToken,
                                        sizeof(theTextToken), &tokenSize);
            
            err = GetTextTextProperty(&theTextToken, dataDesc);
            break;
            
        case typeAEList:
            err = AECountItems(&objTokenDesc, &index);
            if (noErr != err) goto done;
    
            for (; index > 0; index--)
            {
                err = AEGetNthDesc(&objTokenDesc, index, typeWildCard, &returnedType, &itemDesc);
    
                if (noErr == err)       // Call this function recursively if necessary
                    err = HandleGetData(&itemDesc, &resultDesc);
                
                if (noErr == err)       // Overwrite item in list with descriptor item
                    err = AEPutDesc(&objTokenDesc, index, &resultDesc);
                                                        // objTokenDesc is just a copy anyway.
                if (itemDesc.dataHandle)
                    AEDisposeDesc(&itemDesc);
                if (resultDesc.dataHandle)
                    AEDisposeDesc(&resultDesc);
            }
            
            err = AEDuplicateDesc(&objTokenDesc, dataDesc);     // Copy list into result
            break;
            
        default:    
            err = errAEWrongDataType;
    }
 
done:
    if (objTokenDesc.dataHandle)
        AEDisposeDesc(&objTokenDesc);
    
    return(err);
} // HandleGetData
 
 
// Get the actual data for a text token - rather than just offset and length
// used internally.
 
OSErr   GetTextTextProperty(TextToken* theToken, AEDesc *dataDesc)
{
    TEHandle    aTEH;
    short       anOffset,
                aLength;
    OSErr       err;
    
    aTEH = TEHandleFromTextToken(theToken);
    anOffset = theToken->tokenOffset;
    aLength = theToken->tokenLength;
    
    err = BuildStyledTextDesc(aTEH, anOffset, aLength, dataDesc);
 
    return(err);
}
 
// -----------------------------------------------------------------------
//  Name:       GetTextProperty
//  Purpose:    Fills dataDesc with the requested text property.
// -----------------------------------------------------------------------
     
OSErr GetTextProperty(const AEDesc *theTokenDesc, AEDesc *dataDesc)
{
    DPtr          theDocument;
    TEHandle      theHTE;
    Str255        fontName;
    TextStyle     theTextStyle;
    short         lineHeight;
    short         fontAscent;
    TextPropToken theTextPropToken;
    Size          tokenSize;
    AEDesc        tempDesc;
    OSErr         err;
    
    err = AECoerceDesc(theTokenDesc, typeMyTextProp, &tempDesc);
    if (noErr != err) goto done;
    
    GetRawDataFromDescriptor(&tempDesc, (Ptr)&theTextPropToken,
                                    sizeof(theTextPropToken), &tokenSize);
 
    // For each property we build a descriptor to be returned as the reply.
            
    theDocument = DPtrFromWindowPtr(theTextPropToken.tokenTextToken.tokenWindow);
    theHTE = theDocument->theText;
    
    TEGetStyle(theTextPropToken.tokenTextToken.tokenOffset - 1, &theTextStyle,
                                                &lineHeight, &fontAscent, theHTE);
    
    switch (theTextPropToken.tokenProperty)
    {
        case pText:
        case pContents:
            err = GetTextTextProperty(&(theTextPropToken.tokenTextToken), dataDesc);
            break;
            
        case pFont: 
            GetFontName(theTextStyle.tsFont, fontName);
            
            err = AECreateDesc(typeChar,  (Ptr)&fontName[1], fontName[0], dataDesc);
            break;
        
        case pTextStyles: 
            err = BuildTextStylesDesc(theTextStyle.tsFace, dataDesc);
            break;
 
        case pPointSize: 
            err = CreateOffsetDescriptor(theTextStyle.tsSize, dataDesc);
            break;
 
        case pScriptTag: 
            err = CreateOffsetDescriptor(smSystemScript, dataDesc);
            break;
        
        case pColor: 
            err = AECreateDesc(typeRGBColor, (Ptr)&theTextStyle.tsColor,
                                        sizeof(theTextStyle.tsColor), dataDesc);
            break;
            
        case pLength:
            tokenSize = theTextPropToken.tokenTextToken.tokenLength;
            err = AECreateDesc(typeInteger, (Ptr)&tokenSize,
                                sizeof(tokenSize), dataDesc);
            break;
            
        case pOffset:
            tokenSize = theTextPropToken.tokenTextToken.tokenOffset;
            err = AECreateDesc(typeInteger, (Ptr)&tokenSize,
                                sizeof(tokenSize), dataDesc);
            break;
            
        default:
            err = errAEEventNotHandled;
    }
 
done:
    if (tempDesc.dataHandle)
        AEDisposeDesc(&tempDesc);
    
    return(err);
} // GetTextProperty
    
// -----------------------------------------------------------------------
//      Name:           GetWindowProperty
//      Purpose:        Fills dataDesc with the requested window property.
// -----------------------------------------------------------------------
typedef Rect **RectHandle;
 
OSErr   DoGetWindowProperty(const AEDesc *theWPTokenObj, AEDesc *dataDesc)
{            
    Str255          theName;
    Boolean         theBoolean;
    Rect            theRect;
    Point           thePoint;
    Rect            winRect;
    Rect            userRect;
    short           theIndex;
    DPtr            docPtr;
    TEHandle        theHTE;
    GrafPtr         savePort;
    WindowPropToken theWindowPropToken;
    AEDesc          tempDesc = {typeNull, NULL};
    Size            tokenSize;
    OSErr           err;
    
    err = AECoerceDesc(theWPTokenObj,typeMyWindowProp, &tempDesc);
    if (noErr != err) goto done;
    
    GetRawDataFromDescriptor(&tempDesc, (Ptr)&theWindowPropToken,
                                sizeof(theWindowPropToken),  &tokenSize);
    
    switch (theWindowPropToken.tokenProperty)
    {
        case pName:
            GetWTitle(theWindowPropToken.tokenWindowToken.tokenWindow, theName);
            err = AECreateDesc(typeChar, (Ptr)&theName[1], theName[0], dataDesc);
            break;
            
        case pText:
        case pContents:
            docPtr = DPtrFromWindowPtr(theWindowPropToken.tokenWindowToken.tokenWindow);
            theHTE = docPtr->theText;
            err = BuildStyledTextDesc(theHTE, 1, (**theHTE).teLength, dataDesc);
            break;
            
        case pBounds:
            GetPort(&savePort);
            SetPort(theWindowPropToken.tokenWindowToken.tokenWindow);
            theRect = (*((WindowPeek)theWindowPropToken.tokenWindowToken.tokenWindow)->strucRgn)->rgnBBox;
            err = AECreateDesc(typeQDRectangle, (Ptr)&theRect, sizeof(theRect), dataDesc);
            SetPort(savePort);
            break;
            
        case pPosition:
            thePoint.v = (*((WindowPeek)theWindowPropToken.tokenWindowToken.tokenWindow)->strucRgn)->rgnBBox.top;
            thePoint.h = (*((WindowPeek)theWindowPropToken.tokenWindowToken.tokenWindow)->strucRgn)->rgnBBox.left;
            err= AECreateDesc(typeQDPoint, (Ptr)&thePoint, sizeof(thePoint), dataDesc);
            break;
            
        case pVisible:
            theBoolean = ((WindowPeek)theWindowPropToken.tokenWindowToken.tokenWindow)->visible;
            err = AECreateDesc(typeBoolean, (Ptr)&theBoolean, sizeof(theBoolean), dataDesc);
            break;
            
        case pIsModal:
        case pIsFloating:
            theBoolean = false;
            err = AECreateDesc(typeBoolean, (Ptr)&theBoolean, sizeof(theBoolean), dataDesc);
            break;
            
        case pIsZoomed:
            if (((WindowPeek)theWindowPropToken.tokenWindowToken.tokenWindow)->spareFlag)
            {
                GetPort(&savePort);
                SetPort(theWindowPropToken.tokenWindowToken.tokenWindow);
                
                userRect = **((RectHandle)((WindowPeek)qd.thePort)->dataHandle);
                winRect  = qd.thePort->portRect;
                LocalToGlobal((Point *)&winRect.top);
                LocalToGlobal((Point *)&winRect.bottom);
                
                theBoolean = ! EqualRect(&userRect, &winRect);
                SetPort(savePort);
            }
            else
                theBoolean = false;
                            
            err = AECreateDesc(typeBoolean, (Ptr)&theBoolean, sizeof(theBoolean), dataDesc);
            break;
            
        case pIsResizable:
        case pHasTitleBar:
        case pHasCloseBox:
        case pIsZoomable:
            theBoolean = true;
            err = AECreateDesc(typeBoolean, (Ptr)&theBoolean, sizeof(theBoolean), dataDesc);
            break;
            
        case pIsModified:
            docPtr = DPtrFromWindowPtr(theWindowPropToken.tokenWindowToken.tokenWindow);
            theBoolean = docPtr->dirty;
            err = AECreateDesc(typeBoolean, (Ptr)&theBoolean, sizeof(theBoolean), dataDesc);
            break;
            
        case pIndex:
            theIndex = 0;
            if (theWindowPropToken.tokenWindowToken.tokenWindow) 
                do
                    theIndex++;
                while (theWindowPropToken.tokenWindowToken.tokenWindow != GetWindowPtrOfNthWindow(theIndex));
                            
            err = AECreateDesc(typeShortInteger, (Ptr)theIndex, sizeof(theIndex), dataDesc);
            break;
            
        case pPageSetup:
                docPtr = DPtrFromWindowPtr(theWindowPropToken.tokenWindowToken.tokenWindow);
                
                HLock((Handle)docPtr->thePrintSetup);
                err = AECreateDesc(typeTPrint, (Ptr)*(docPtr->thePrintSetup),
                                                                sizeof(TPrint), dataDesc);
                HUnlock((Handle)docPtr->thePrintSetup);
 
 
        case pSelection:
            docPtr = DPtrFromWindowPtr(theWindowPropToken.tokenWindowToken.tokenWindow);
            err = MakeSelectedTextObj(theWindowPropToken.tokenWindowToken.tokenWindow,
                                                                docPtr->theText, dataDesc);
            break;
    
        default:
            err = errAEEventNotHandled;
    }
 
done:
    if (tempDesc.dataHandle)
        AEDisposeDesc(&tempDesc);
            
    return(err);
} // GetWindowProperty
    
// -----------------------------------------------------------------------
//      Name:           GetApplicationProperty
//      Purpose:        Fills dataDesc with the requested application property.
// -----------------------------------------------------------------------
     
OSErr   GetApplicationProperty(const AEDesc *theObjToken, AEDesc *result)
{
    Str255              name;
    Boolean             isFront;
    ApplPropToken       theApplPropToken;
    AEDesc              aDesc = {typeNull, NULL},
                        nullDesc = {typeNull, NULL};
    Size                tokenSize;
    DescType            theType;
    ProcessInfoRec      processInfo;
    ProcessSerialNumber currentProcess;
    short               refNum;
    Handle              aHandle;
    OSErr               err;
    
    err = AECoerceDesc(theObjToken, typeMyApplProp, &aDesc);
    if (noErr != err) goto done;
    
    GetRawDataFromDescriptor(&aDesc, (Ptr)&theApplPropToken,
                                        sizeof(theApplPropToken), &tokenSize);
      
    switch (theApplPropToken.tokenApplProperty)
    {
        case pBestType:     // Return the null descriptor representing
        case pDefaultType:  // the application.
            err = AEDuplicateDesc(&nullDesc, result);
            break;
        
        case pClass:
            theType = cApplication;
            err = AECreateDesc(typeType, (Ptr)&theType, sizeof(DescType), result);
            break;
        
        case pName:
            // Clear out the name, and then call the process manager to get
            // the string for the name of our application.
            
            name[0] = 0;
            processInfo.processInfoLength = sizeof(processInfo);
            processInfo.processName = name;
            processInfo.processAppSpec = NULL;
            
            GetCurrentProcess(&currentProcess);
            GetProcessInformation(&currentProcess, &processInfo);
            
            // Create an AEDesc returning the application name string
            // returned by the process manager.
 
            err = AECreateDesc(typeChar, (Ptr)&name[1], name[0], result);
            break;
        
        case pIsFrontProcess:
            isFront = ! gInBackground;
            err = AECreateDesc(typeBoolean, (Ptr)&isFront, sizeof(isFront), result);
            break;
 
        case pVersion:
            refNum = CurResFile();  // save current resource
            UseResFile(gRefNum);    // set this resource to be current
            aHandle = (Handle)Get1Resource((ResType)'vers', 1);
            HLock(aHandle);
            err = AECreateDesc(typeVersion, *aHandle, GetHandleSize(aHandle), result);
            HUnlock(aHandle);
            UseResFile(refNum);     // reset back to resource previously set
            break;
 
        default:   // We don't handle the requested property.
            err = errAEEventNotHandled;
    }
 
done:
    if (aDesc.dataHandle)
        AEDisposeDesc(&aDesc);
            
    return(err);
} // GetApplicationProperty