Sources/MSResultWind.c

// MSResultWind.c
//
// Written by Don Swatman and Greg Sutton
// ©Apple Computer Inc 1996, all rights reserved.
    
#include "MSResultWind.h"
 
#ifdef THINK_C
    #include "PLStrs.h"
#else
    #include <PLStringFuncs.h>
#endif
#include <ASRegistry.h>
 
#include "MSWindow.h"
#include "MSAETextUtils.h"
#include "MSAEWindowUtils.h"
#include "MSAEDelete.h"
#include "MSAESetData.h"
#include "MSAECreate.h"
#include "MSAESelect.h"
#include "MSMain.h"
 
 
    // Prototypes
OSErr           AddPStrToResults( StringPtr theStringPtr );
OSErr           AddDescToResults( AEDesc* theDesc );
static OSErr    EndOfDocumentTextToken( WindowPtr theWindow, TextToken* theToken );
OSAError        TextDescUsingOSADisplay( AEDesc* theDesc, AEDesc* theResult );
OSErr           SelectErrorRange( AEDesc* theRangeDesc, DPtr theDoc );
 
 
    // Globals
extern ComponentInstance    gScriptingComponent;
 
WindowPtr                   gPResultWind = NULL;
 
 
OSErr   OpenResultWind( void )
{       
    DPtr        myDoc;
 
    if ( ! gPResultWind )
    {
        myDoc = NewDocument(false, (WindowPtr)-1L );
        myDoc->windowType = kResultsWind;
        SetWTitle(myDoc->theWindow, "\presults" );
        
        gPResultWind = myDoc->theWindow;
    }
    else
    {
        ShowMSWindow( gPResultWind );
        SelectWindow( gPResultWind );
    }
 
    return noErr;
}
 
Boolean IsThereAResultWind( void )
{
    WindowPtr   aWindow = GetResultsWindPtr( );
 
    if ( aWindow && ((WindowPeek)aWindow)->visible )
        return ( true );
    else
        return ( false );
}
 
Boolean IsThisResultWind( WindowPtr theWind )
{
    return ( theWind == GetResultsWindPtr( ) );
}
 
void CloseResultWind( WindowPtr theWind )
{
    if ( IsThisResultWind( theWind ) )
        HideMSWindow( theWind );
}
 
WindowPtr GetResultsWindPtr( void )
{
    if ( ! gPResultWind )   // Just hasn't been accessed yet - usually always around
    {                       //  just hidden.
        OpenResultWind( );
        CloseResultWind( gPResultWind );    // Just hides it
    }
 
    return gPResultWind;
}
 
DPtr GetResultsDoc( void )
{
    return DPtrFromWindowPtr( GetResultsWindPtr( ) );
}
 
 
OSErr   DisplayDescResult( WindowPtr theWindow, AEDesc* theTextDesc, DPtr theDoc, OSErr theErr )
{
    WindowPropToken aToken;
    OSErr           err;
    
    if ( errOSAScriptError == theErr )
        return (OSErr)DisplayOSAScriptError( theDoc );
           
    if ( ! theWindow )
        return noErr;
 
    aToken.tokenWindowToken.tokenWindow = theWindow;
 
            // If the descriptor is NULL then clear the window
    if ( typeNull == theTextDesc->descriptorType )
    {
        err = TextDescFromDocumentToken( &aToken.tokenWindowToken, theTextDesc );
        
        if ( noErr == err )
            err = DeleteDesc( theTextDesc );
        
        (void)AEDisposeDesc( theTextDesc );
    }
    else    // Set the text to that provided
    {
        aToken.tokenProperty = pText;       // All of the text in document
        
        err = SetDocumentTokenProperty( &aToken, theTextDesc );
    }
    
    return err;
}
 
OSErr   DisplayOSAIDResult( WindowPtr theWindow, OSAID theOSAID, DPtr theDoc, OSErr theErr )
{
    AEDesc      textDesc = { typeNull, NULL };
    OSErr       err;
    
    if ( errOSAScriptError == theErr )
        return (OSErr)DisplayOSAScriptError( theDoc );
 
    err = OSADisplay( gScriptingComponent, theOSAID, typeStyledText,
                                                kOSAModeNull, &textDesc );
    if ( noErr != err ) goto done;
    
    err = DisplayDescResult( theWindow, &textDesc, theDoc, theErr );
                                                
done:
    (void)AEDisposeDesc( &textDesc );
    
    return err;
}
 
 
OSAError    DisplayOSAScriptError( DPtr theDoc )
{
    AEDesc      applicationDesc = { typeNull, NULL },
                messageDesc = { typeNull, NULL },
                numberDesc = { typeNull, NULL },
                typeDesc = { typeNull, NULL },
                objectDesc = { typeNull, NULL },
                partialDesc = { typeNull, NULL },
                rangeDesc = { typeNull, NULL },
                aDesc = { typeNull, NULL };
    Str255      aPStr;
    OSAError    anErr;
 
    (void)OSAScriptError( gScriptingComponent, kOSAErrorApp, typeChar, &applicationDesc );
    (void)OSAScriptError( gScriptingComponent, kOSAErrorMessage, typeChar, &messageDesc );
    (void)OSAScriptError( gScriptingComponent, kOSAErrorNumber, typeShortInteger, &numberDesc );
    (void)OSAScriptError( gScriptingComponent, kOSAErrorExpectedType, typeWildCard, &typeDesc );
    (void)OSAScriptError( gScriptingComponent, kOSAErrorOffendingObject, typeWildCard, &objectDesc );
    (void)OSAScriptError( gScriptingComponent, kOSAErrorPartialResult, typeWildCard, &partialDesc );
    (void)OSAScriptError( gScriptingComponent, kOSAErrorRange, typeOSAErrorRange, &rangeDesc );
 
        // Select the range before bringing results document forward
    anErr = SelectErrorRange( &rangeDesc, theDoc );
    
        // This calls a script that is executed through OSA so we need
        //  to get all the script errors before calling.
    if ( ! IsVisible( GetResultsWindPtr( ) ) )
        DoMenuItem( mscriptID, cResultWindow ); // Go through script on menu item
    else
        SelectWindow( GetResultsWindPtr( ) );
    
    PLstrcpy( aPStr, "\pError" );
    anErr = AECreateDesc( typeChar, (Ptr)&aPStr[1], aPStr[0], &aDesc );
    if ( noErr != anErr ) goto done;
        // Just blat it straight into the results document
        //  deleting anything that's there.
    anErr = DisplayDescResult( GetResultsWindPtr( ), &aDesc, NULL, noErr );
    if ( noErr != anErr ) goto done;
    
        // Add the application name
    if ( typeNull != applicationDesc.descriptorType )
    {
        anErr = AddPStrToResults( "\p in application " );
        if ( noErr != anErr ) goto done;
        anErr = AddDescToResults( &applicationDesc );
        if ( noErr != anErr ) goto done;
    }
    
    if ( typeNull != messageDesc.descriptorType )
    {
        anErr = AddPStrToResults( "\p\r\rMessage :  " );
        if ( noErr != anErr ) goto done;
        anErr = AddDescToResults( &messageDesc );
        if ( noErr != anErr ) goto done;
    }
    
    if ( typeNull != numberDesc.descriptorType )
    {
        anErr = AddPStrToResults( "\p\r\rNumber :  " );
        if ( noErr != anErr ) goto done;
        anErr = AddDescToResults( &numberDesc );
        if ( noErr != anErr ) goto done;
    }
    
    if ( typeNull != typeDesc.descriptorType )
    {
        anErr = AddPStrToResults( "\p\r\rType :  " );
        if ( noErr != anErr ) goto done;
        anErr = AddDescToResults( &typeDesc );  // Try and use OSADisplay() to get terminology
        if ( noErr != anErr ) goto done;        //  for the type.
    }
    
    if ( typeNull != objectDesc.descriptorType )
    {
        anErr = AddPStrToResults( "\p\r\rOffending Object :  " );
        if ( noErr != anErr ) goto done;
        anErr = AddDescToResults( &objectDesc );
        if ( noErr != anErr ) goto done;
    }
    
    if ( typeNull != partialDesc.descriptorType )
    {
        anErr = AddPStrToResults( "\p\r\rPartial Result :  " );
        if ( noErr != anErr ) goto done;
        anErr = AddDescToResults( &partialDesc );
        if ( noErr != anErr ) goto done;
    }
    
done:
    (void)AEDisposeDesc( &applicationDesc );
    (void)AEDisposeDesc( &messageDesc );
    (void)AEDisposeDesc( &numberDesc );
    (void)AEDisposeDesc( &typeDesc );
    (void)AEDisposeDesc( &objectDesc );
    (void)AEDisposeDesc( &partialDesc );
    (void)AEDisposeDesc( &rangeDesc );
    (void)AEDisposeDesc( &aDesc );
 
    return anErr;
}
 
OSErr   SelectErrorRange( AEDesc* theRangeDesc, DPtr theDoc )
{
    AEDesc      aRecordDesc = { typeNull, NULL };
    DescType    aType;
    short       errorStart,
                errorEnd;
    Size        actSize;
    TextToken   aTextToken;
    OSErr       anErr;
 
    if ( ! theDoc )
        return noErr;
    
    anErr = AECoerceDesc( theRangeDesc, typeAERecord, &aRecordDesc );
    if ( noErr != anErr ) goto done;
 
    anErr = AEGetKeyPtr( &aRecordDesc, keyOSASourceStart, typeShortInteger,
                        &aType, (Ptr)&errorStart, sizeof( errorStart ), &actSize );
    if ( noErr != anErr ) goto done;
                                            
    anErr = AEGetKeyPtr( &aRecordDesc, keyOSASourceEnd, typeShortInteger,
                            &aType, (Ptr)&errorEnd, sizeof( errorEnd ), &actSize );
    if ( noErr != anErr ) goto done;
 
    aTextToken.tokenWindow = theDoc->theWindow; 
    aTextToken.tokenOffset = errorStart + 1;
    aTextToken.tokenLength = errorEnd - errorStart;
    
    anErr = SelectTextToken( &aTextToken );
 
 
done:
    (void)AEDisposeDesc( &aRecordDesc );
    
    return anErr;
}
 
OSErr   AddPStrToResults( StringPtr theStringPtr )
{
    AEDesc  aTextDesc = { typeNull, NULL };
    OSErr   anErr;
    
    anErr = AECreateDesc( typeChar, (Ptr)&theStringPtr[1], theStringPtr[0], &aTextDesc );
    if ( noErr != anErr ) goto done;
    
    anErr = AddDescToResults( &aTextDesc );
    
done:
    (void)AEDisposeDesc( &aTextDesc );
 
    return anErr;
}
 
OSErr   AddDescToResults( AEDesc* theDesc )
{
    AEDesc      aTextDesc = { typeNull, NULL },
                aNullDesc = {typeNull, NULL},
                aResultDesc = { typeNull, NULL };
    TextToken   aTextToken;
    long        aCount,
                anIndex;
    DescType    anAEKeyword;
    OSErr       anErr;
 
    
    switch ( theDesc->descriptorType )
    {
        case typeNull:
        case typeScript:
            return noErr;
    
        case typeChar:
        case typeStyledText:
        case typeIntlText:
            anErr = AEDuplicateDesc( theDesc, &aTextDesc );
            break;
            
        case typeObjectSpecifier:
        case cEventIdentifier:
            anErr = TextDescUsingOSADisplay( theDesc, &aTextDesc );
            break;
            
        case typeAEList:
            anErr = AddPStrToResults( "\p{ " ); // Brackets to signify a list
            if ( noErr != anErr ) goto done;
        
            anErr = AECountItems( theDesc, &aCount );
            if ( noErr != anErr ) goto done;
            
            for ( anIndex = 1; anIndex <= aCount; anIndex++ )
            {
                anErr = AEGetNthDesc( theDesc, anIndex, typeWildCard, &anAEKeyword, &aTextDesc );
                if ( noErr != anErr ) goto done;
                    // Call recursively - may even be another list
                anErr = AddDescToResults( &aTextDesc );
                if ( noErr != anErr ) goto done;
                
                (void)AEDisposeDesc( &aTextDesc );
            }
 
            anErr = AddPStrToResults( "\p }" );
            goto done;  // We have been through the list so no further descriptor to add
            
        case typeType:
        case typeEnumeration:
            anErr = AECoerceDesc( theDesc, typeChar, &aTextDesc );
 
            if ( noErr != anErr ) goto done;        // Add the OSType first
            anErr = AddPStrToResults( "\p'" );
            if ( noErr != anErr ) goto done;
            anErr = AddDescToResults( &aTextDesc );
            if ( noErr != anErr ) goto done;
            anErr = AddPStrToResults( "\p'" );
            if ( noErr != anErr ) goto done;
            (void)AEDisposeDesc( &aTextDesc );      // We're using it again
 
            anErr = TextDescUsingOSADisplay( theDesc, &aTextDesc );
            if ( noErr == anErr )
                anErr = AddPStrToResults( "\p - " );    // Go on to display the terminology
            else
            {                                       // Couldn't get terminology
                anErr = noErr;                      //  so make do with OSType.
                goto done;
            }
            break;
            
        default:    // Apple Event Manager can coerce numbers and stuff
            anErr = AECoerceDesc( theDesc, typeChar, &aTextDesc );
    }
    
    if ( noErr != anErr ) goto done;
    
    anErr = EndOfDocumentTextToken( GetResultsWindPtr( ), &aTextToken );
    if ( noErr != anErr ) goto done;
    
        // Add text to end of results window
    anErr = CreateAtTextToken( cText, &aTextDesc, &aTextToken, &aNullDesc, &aResultDesc );
    
done:
    (void)AEDisposeDesc( &aTextDesc );
    (void)AEDisposeDesc( &aResultDesc );
 
    return anErr;
}
 
static OSErr    EndOfDocumentTextToken( WindowPtr theWindow, TextToken* theToken )
{
    DPtr    aDoc = DPtrFromWindowPtr( theWindow );
    
    if ( ! aDoc )
        return errAEWrongDataType;
        
    theToken->tokenWindow = theWindow;
    theToken->tokenOffset = (**aDoc->theText).teLength + 1;
    theToken->tokenLength = 0;
    
    return noErr;
}
 
 
// Routine that takes a type descriptor and returns the text that is 
// used to describe the type in a script.
// e.g. atypeType descriptor for 'docu' will return a text descriptor containing "document"
 
OSAError    TextDescUsingOSADisplay( AEDesc* theDesc, AEDesc* theResult )
{
    OSAID       aScriptID = kOSANullScript;
    OSAError    anErr;
 
                        // Convert from a descriptor to a script ID
    anErr = OSACoerceFromDesc( gScriptingComponent, theDesc, kOSAModeNull, &aScriptID );
    if (noErr != anErr) goto done;
                                                   // typeStyledText
    anErr = OSADisplay( gScriptingComponent, aScriptID, typeChar, kOSAModeNull, theResult );
 
done:                   // Clean up memory
    (void)OSADispose( gScriptingComponent, aScriptID );
 
    return anErr;
}