Sources/MSAESelect.c

// MSAESelect.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.
 
#include "MSAESelect.h"
 
#include <Windows.h>
 
#include "MSAEUtils.h"
#include "MSWindow.h"       // for DPtrFromWindowPtr()
 
#include "MSAETextUtils.h"
#include "MSAEWindowUtils.h"
#include "MSMain.h"
 
// -----------------------------------------------------------------------
//  Name:       DoSelect
//  Purpose:    Handles the 'Select' Apple Event, extracting the direct
//              object (which is the text range to set the selection to) 
//              'Select' is equivalent to 'set the selection to...'
// -----------------------------------------------------------------------
     
pascal OSErr    DoSelect(const AppleEvent *theAppleEvent, AppleEvent *reply, long refcon)
{
#ifdef __MWERKS__
    #pragma unused (refcon)
#endif
 
    AEDesc      directObj = {typeNull, NULL},
                result = {typeNull, NULL};
    OSErr       err;
 
    err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeWildCard, &directObj);
    
            // There was a direct parameter
    if (directObj.descriptorType != typeNull)
        err = SelectDesc(&directObj, &result);
    else    // There was no direct parameter
    {
        err = PutPStringToDescriptor(&result, "\pYou have not specified an object to select");
        if (noErr != err) goto done;
        err = errAENoSuchObject;
    }
 
    err = AddResultToReply(&result, reply, err);
 
done:   
    (void)AEDisposeDesc(&directObj);
    (void)AEDisposeDesc(&result);
        
    return(err);
} // DoSelect
 
 
OSErr   SelectWindowToken(WindowToken* theToken)
{
    OSErr           err = noErr;
    
    if (! theToken->tokenWindow)
        return errAENoSuchObject;
        
    SelectWindow( theToken->tokenWindow );
    if ( IsVisible( theToken->tokenWindow ) )
    {
        DoActivate( GetNthWindow( 2 ), false );
        DoActivate( theToken->tokenWindow, true );
    }
 
                                    
    return(err);
}
 
OSErr   SelectWindowDesc(AEDesc* windowDesc)
{
    AEDesc          aDesc = { typeNull, NULL };
    WindowToken     aToken;
    Size            actualSize;
    OSErr           err;
 
    err = AECoerceDesc( windowDesc, typeMyWndw, &aDesc );
    if ( noErr != err ) goto done;
        
    GetRawDataFromDescriptor( &aDesc, (Ptr)&aToken, sizeof( aToken ), &actualSize );
 
    err = SelectWindowToken( &aToken );
 
done:
    (void)AEDisposeDesc( &aDesc );
    
    return(err);
}
 
 
OSErr   SelectTextToken(TextToken* theToken)
{
    DPtr            docPtr;
    OSErr           err = noErr;
    
    docPtr = DPtrFromWindowPtr(theToken->tokenWindow);
    
    if (! theToken->tokenWindow || ! docPtr)
        return errAEWrongDataType;
    
    TESetSelect(theToken->tokenOffset - 1,
                    theToken->tokenOffset + theToken->tokenLength - 1,
                                    docPtr->theText);
                                    
    return(err);
}
 
OSErr   SelectTextDesc(AEDesc* textDesc)
{
    TextToken       aTextToken;
    Size            actualSize;
    OSErr           err;
 
    if (typeMyText != textDesc->descriptorType)
        return(errAETypeError);
        
    GetRawDataFromDescriptor(textDesc, (Ptr)&aTextToken, sizeof(aTextToken), &actualSize);
 
    err = SelectTextToken(&aTextToken);
    
    return(err);
}
 
 
OSErr   SelectMenuItemToken( MenuItemToken* theToken )
{
    OSErr           err = noErr;
        
    DoMenuItem( theToken->tokenMenuToken.tokenID, theToken->tokenItem );
                                    
    return err;
}
 
OSErr   SelectMenuItemDesc( AEDesc* theDesc )
{
    MenuItemToken   aToken;
    Size            actualSize;
    OSErr           err;
 
    if ( typeMyMenuItem != theDesc->descriptorType )
        return errAETypeError;
        
    GetRawDataFromDescriptor( theDesc, (Ptr)&aToken, sizeof( aToken ), &actualSize );
 
    err = SelectMenuItemToken( &aToken );
    
    return err;
}
 
 
OSErr   SelectDesc( const AEDesc* aDesc, AEDesc* result )
{
    AEDesc      selectDesc = {typeNull, NULL},
                textDesc = {typeNull, NULL};
    OSErr       err;
    
    if ( typeObjectSpecifier == aDesc->descriptorType )
        err = AEResolve( aDesc, kAEIDoMinimum, &selectDesc );
    else if ( typeNull != aDesc->descriptorType )
        err = AEDuplicateDesc( aDesc, &selectDesc );
        
    if (noErr != err) goto done;
    
    switch (selectDesc.descriptorType)
    {
        case typeAEList:
            err = PutPStringToDescriptor(result, "\pThis application cannot select a list of objects");
            if (noErr != err) goto done;
            err = errAETypeError;
            break;
            
        case typeMyWndw:
        case typeMyDocument:
            err = SelectWindowDesc(&selectDesc);
            break;
            
        case typeMyMenuItem:
            err = SelectMenuItemDesc(&selectDesc);
            break;
            
        default:
            err = AECoerceDesc(&selectDesc, typeMyText, &textDesc);
            if (noErr != err) goto done;
            err = SelectTextDesc(&textDesc);
    }
    
done:
    (void)AEDisposeDesc( &selectDesc );
    (void)AEDisposeDesc( &textDesc );
    
    return(err);
}
 
 
// Given a window, this routine will fill out a TextToken with details
// of the window's current selection. The total text length can also be retrieved
// so that the selection can be updated depending on changes.
 
OSErr   GetWindowSelection(WindowPtr aWindow, TextToken* resultToken, short* resultLength)
{
    AEDesc      propertyDesc = {typeNull, NULL},
                dataDesc = {typeNull, NULL},
                textDesc = {typeNull, NULL};
    TEHandle    aTextEditHandle;
    OSErr       err = noErr;
    
    if (! aWindow)
        return(errAENoSuchObject);
    
    aTextEditHandle = TEHandleFromWindow(aWindow);
 
    resultToken->tokenWindow = aWindow;
                                    // TEHandle starts counting characters from 1, not 0
    resultToken->tokenOffset = (*aTextEditHandle)->selStart + 1;
    resultToken->tokenLength = (*aTextEditHandle)->selEnd - (*aTextEditHandle)->selStart;
    
    if (resultLength)
        *resultLength = (*aTextEditHandle)->teLength;
    
    return(err);
}
 
 
// Given the selection that was deleted/changed/?moved? and the original
// selection before the operation. Also the old length of text in the
// TextEdit. This routine sorts out the selection that may change
// due to position of delete/change/?move?. It returns in insertLength
// the length of the inserted data (not just the difference).
 
OSErr   UpdateSelectionToken(TextToken* anInsertToken, TextToken* aSelectionToken,
                                                short oldLength, short* insertLength)
{
    TextToken   updatedToken;
    short       newLength,      // Lots of local variables to make
                deleteLength,   // things clearer.
                insertOffset,
                selectOffset,
                selectLength,
                numPartial;
    OSErr       err;
    
    if (! anInsertToken->tokenWindow || ! aSelectionToken->tokenWindow)
        return(errAENoSuchObject);
        
    updatedToken.tokenWindow = aSelectionToken->tokenWindow;
    
    newLength = (*TEHandleFromWindow(anInsertToken->tokenWindow))->teLength;
    deleteLength = anInsertToken->tokenLength;                      // Characters deleted
    
    insertOffset = anInsertToken->tokenOffset;
    selectOffset = aSelectionToken->tokenOffset;
    selectLength = aSelectionToken->tokenLength;
 
    *insertLength = newLength - oldLength + deleteLength;           // Characters inserted
 
    switch (TokenWithinToken(aSelectionToken, anInsertToken, &numPartial))
    {
        case kTokenBefore:
            updatedToken.tokenOffset = selectOffset + *insertLength - deleteLength;
            updatedToken.tokenLength = selectLength;
            break;
 
        case kTokenAfter:
        case kTokenPartialBefore:
        case kTokenPartialAfter:
            updatedToken.tokenOffset = selectOffset;
            updatedToken.tokenLength = selectLength;
            break;
            
        case kTokenWithin:
            updatedToken.tokenOffset = selectOffset;
            updatedToken.tokenLength = selectLength + *insertLength - deleteLength;
            break;
    }
        
    err = SelectTextToken(&updatedToken);
    
    return(err);
}