Source/SVEditUtils.c

/*
    File:       SVEditUtils.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/19/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                10/12/95    CW                      Simplified FeatureIsImplemented routine.
                                                            Added init of gHasDragManager flag in CheckEnvironment.
                
 
*/
 
#include <DriverServices.h>
#include <Events.h>
#include <Traps.h>
#include <Dialogs.h>
#include <Fonts.h>
#include <Packages.h>
#include <ToolUtils.h>
#include <AppleEvents.h>
#include <CodeFragments.h>
#include "SVEditUtils.h"
#include <TextUtils.h>
 
/**-----------------------------------------------------------------------
        Name:           LesserOf
        Purpose:        Returns the Lesser of two longints.
    -----------------------------------------------------------------------**/
#pragma segment Utils
        
pascal long LesserOf(long A, long B)
 {
   if (A<B)
       return(A);
     else
       return(B);
 }   /*LesserOf*/
            
/**-----------------------------------------------------------------------
        Name:           GreaterOf
        Purpose:        Returns the Greater of two longints.
    -----------------------------------------------------------------------**/
    
#pragma segment Utils
        
pascal long GreaterOf(long A, long B)
 {
   if (A>B)
       return(A);
     else
       return(B);
 }  /*GreaterOf*/
            
/**-----------------------------------------------------------------------
        Name:           ShowError
        Purpose:        Reports an error to the user as both string and number.
    -----------------------------------------------------------------------**/
#pragma segment Utils
        
pascal void ShowError(Str255  theError,
                                          long    theErrorCode)
{
   short     alertResult;
   Str255    theString;
     OSErr     myErr;
     
     myErr = AEInteractWithUser(kAEDefaultTimeout, nil,nil);
     
     if (myErr == noErr)
       {
             SetCursor(&qd.arrow);
             NumToString(theErrorCode, theString);
             ParamText(theError, theString, (unsigned char *)"", (unsigned char *)"");
             alertResult = Alert(300, nil);
         }
} /* ShowError */
 
/**-----------------------------------------------------------------------
        Name:           Ours
        Purpose:        Checks the frontmost window belongs to the app.
    -----------------------------------------------------------------------**/
#pragma segment Utils       
    
pascal Boolean Ours(WindowPtr aWindow)
 {
        if (aWindow)
            if (((WindowPeek)aWindow)->windowKind == zoomDocProc)
                return(true);
        return(false);
} /* Ours */
 
/**-----------------------------------------------------------------------
        Name:           SetShortMenus
        Purpose:        Cuts the menus down to a minimum - Apple File Edit.
                                Greys out the unavailable options - used when no docs open
    -----------------------------------------------------------------------**/
#pragma segment Utils       
 
pascal void SetShortMenus()
{ 
    DeleteMenu(mfontID);
    DeleteMenu(sizeID);
    DeleteMenu(styleID);
 
    DisableItem(myMenus[fileM], fmClose);
    DisableItem(myMenus[fileM], fmSave);
    DisableItem(myMenus[fileM], fmSaveAs);
    DisableItem(myMenus[fileM], fmRevert);
    DisableItem(myMenus[fileM], fmPageSetUp);
    DisableItem(myMenus[fileM], fmNoGXPrint);
 
    /* now the unnecessary items on the edit menu */
                
    DisableItem(myMenus[editM], undoCommand);
    DisableItem(myMenus[editM], cutCommand);
    DisableItem(myMenus[editM], copyCommand);
    DisableItem(myMenus[editM], clearCommand);
    DisableItem(myMenus[editM], pasteCommand);
    DisableItem(myMenus[editM], selectAllCommand);
 
    DrawMenuBar();
}  /* SetShortMenus */
 
/**-----------------------------------------------------------------------
        Name:           SetLongMenus
        Purpose:        Reinstates the full menu bar - called when first document
                    opened.
    -----------------------------------------------------------------------**/
#pragma segment Utils       
 
pascal void SetLongMenus()
  {
        InsertMenu(myMenus[fontM], 0);
        InsertMenu(myMenus[sizeM], 0);
        InsertMenu(myMenus[styleM], 0);
 
        EnableItem(myMenus[fileM], fmClose);
        EnableItem(myMenus[fileM], fmSave);
        EnableItem(myMenus[fileM], fmSaveAs);
        EnableItem(myMenus[fileM], fmRevert);
        EnableItem(myMenus[fileM], fmPageSetUp);
 
        EnableItem(myMenus[fileM], fmNoGXPrint );
 
        /* now the necessary items on the edit menu -
            many other items fixed on each pass thru the main event
            loop or before the window pulled down
        */
        
        EnableItem(myMenus[editM], selectAllCommand);
 
        DrawMenuBar();
    }  /* SetLongMenus */
 
/**-----------------------------------------------------------------------
        Name:           SetStyleMenu
        Purpose:        Sets the style menu checking to reflect the style of the
                    first character of the current selection in the given
                                document.
    -----------------------------------------------------------------------**/
#pragma segment Utils       
        
pascal void SetStyleMenu(DPtr theDoc)
  {
    TextStyle       theTStyle;
        short       contMode;
        short       i;
        
        contMode = doFace;
        
        TEContinuousStyle(&contMode,&theTStyle,theDoc->theText);
        
        if ((contMode & doFace) != 0)
            {
                CheckItem(myMenus[styleM], cPlain,     (theTStyle.tsFace == 0));
                CheckItem(myMenus[styleM], cBold,      (bold      & theTStyle.tsFace));
                CheckItem(myMenus[styleM], cItalic,    (italic    & theTStyle.tsFace));
                CheckItem(myMenus[styleM], cUnderline, (underline & theTStyle.tsFace));
                CheckItem(myMenus[styleM], cOutline,   (outline   & theTStyle.tsFace));
                CheckItem(myMenus[styleM], cShadow,    (shadow    & theTStyle.tsFace));
                CheckItem(myMenus[styleM], cCondense,  (condense  & theTStyle.tsFace));
                CheckItem(myMenus[styleM], cExtend,    (extend    & theTStyle.tsFace));
          }
        else
            for (i=cPlain; i<= cExtend; i++)
                CheckItem(myMenus[styleM], i,     false);
  }
 
/**-----------------------------------------------------------------------
    Name:       SetSizeMenu
    Purpose:    Outline all the items if the current font is an
                outline font. Check the size of the current selection
  -----------------------------------------------------------------------**/
#pragma segment Utils       
 
pascal void SetSizeMenu(DPtr theDoc)
  {
      short             i;
        short               aSize;
        short               max;
    long                theSize;
    Str255      name;
    Boolean     sizeinMenu;
    Boolean     oldState;
    Point       numer;
    TextStyle       theStyle;
        TEHandle    myText;
        short       contMode;
      
    numer.h = 1;
    numer.v = 1;
 
    myText = theDoc->theText;
        
        contMode = doSize+doFont;
        
        TEContinuousStyle(&contMode,&theStyle,theDoc->theText);
        
    sizeinMenu = false;
    max = CountMItems(myMenus[sizeM]);
        for (i = 1; i <= max - 5; i++)
      {
                GetMenuItemText(myMenus[sizeM], i, name);
                StringToNum(name, &theSize);
                aSize = (short)theSize;
 
                if (RealFont(theStyle.tsFont, aSize) && (contMode & doFont) != 0) // there is only one font and this size exists
                    SetItemStyle(myMenus[sizeM], i, outline);
                else
                    SetItemStyle(myMenus[sizeM], i, 0);
 
                if ((aSize == theStyle.tsSize) && (contMode & doSize) != 0)
                    {
                        sizeinMenu = true;
                        CheckItem(myMenus[sizeM], i, true);
                    }
                else
                    CheckItem(myMenus[sizeM], i, false);
            }
        
            /*
                if it's not a size in the menu,and there is only one size in the
              selection range check the other item
            */
            
            if (!sizeinMenu && (contMode & doSize) != 0)
              CheckItem(myMenus[sizeM], max, true);
            else
                CheckItem(myMenus[sizeM], max, false);
 
            /*if this is an outline font, set the rest of the items to outline style*/
            /*RealFont will ensure that the sizes are outlined*/
 
            oldState = GetOutlinePreferred();
            SetOutlinePreferred(true);
            for (i = max-4; i <= max; i++)
                {
                    if (IsOutline(numer, numer) && (contMode & doFont)!= 0)
                        SetItemStyle(myMenus[sizeM], i, outline);
                    else
                        SetItemStyle(myMenus[sizeM], i, 0);
                }
                
            SetOutlinePreferred(oldState);
    }
 
/**-----------------------------------------------------------------------
    Name:       SetFontMenu
    Purpose:    Set the font menu according to the state of
                                current selection of the supplied document.
  -----------------------------------------------------------------------**/
#pragma segment Utils
        
pascal void SetFontMenu(DPtr theDoc)
  {
    MenuHandle      theMHandle;
    short         theNumber;
    short         i;
    short               max;
    Str255        name;
    TextStyle     theStyle;
        short         contMode;
 
        theMHandle = GetMenuHandle(mfontID);
 
        if (gFontMItem)
      CheckItem(theMHandle, gFontMItem, false);
            
        max = CountMItems(theMHandle);
 
        contMode = doFont;
        TEContinuousStyle(&contMode,&theStyle,theDoc->theText);
 
        gFontMItem = 0;
        
    if (contMode & doFont)
            for (i=1; i<=max; i++)
                {
                    GetMenuItemText(theMHandle, i, name);
                    GetFNum(name, &theNumber);
                    if (theNumber == theStyle.tsFont)
                        gFontMItem = i;
                }
 
    if (gFontMItem)
      CheckItem(theMHandle, gFontMItem, true);
            
        SetSizeMenu(theDoc);
        SetStyleMenu(theDoc);
    }
 
/**-----------------------------------------------------------------------
    Name:       GetTempFileName
    Purpose:    Fills newstring with a temporary file name.
  -----------------------------------------------------------------------**/
 
#pragma segment Utils
 
pascal void GetTempFileName(DPtr aDoc,
                            Str255 newString)
 
    {
       Str255        s;
     Str255        fileName;
 
        if (aDoc->everSaved == false)
          PStrCopy(fileName, (unsigned char *)"\pTEXTra");
        else
            PStrCopy(fileName, aDoc->theFileName);
 
    /*generate a unique(ish) temporary filename*/
        
        if (fileName[0] > 21)
          fileName[0] = 21;
                
        NumToString(TickCount(), s);
        
        PStrCat(fileName, s);
        
        PStrCopy(newString,fileName);
    }
 
/**-----------------------------------------------------------------------
    Name:       SetText
    Purpose:    Sets the text of the supplied itemNo in aDialog to 
                                theString and select it.
  -----------------------------------------------------------------------**/
 
#pragma segment Utils
 
pascal void SetText(DialogPtr aDialog,
                    short     itemNo,
                    Str255    theString)
  {
    Handle      itemHandle;
    Rect        box;
    short       kind;
    TEHandle    theTEHandle;
 
        GetDialogItem(aDialog, itemNo, &kind, &itemHandle, &box);
        SetDialogItemText(itemHandle, theString);
        
        theTEHandle = ((DialogPeek)aDialog)->textH;
 
        /*set all the text to be selected*/
        if (theTEHandle)
            TESetSelect(0, 255, theTEHandle);
    }
            
/**-----------------------------------------------------------------------
    Name:       RetrieveText
    Purpose:    Returns the text of anItem in aDialog in aString.
  -----------------------------------------------------------------------**/
 
#pragma segment Utils
 
pascal void RetrieveText(DialogPtr aDialog,
                                               short     anItem,
                                               Str255    aString)
  {
     short      kind;
     Rect       box;
     Handle     itemHandle;
 
         GetDialogItem(aDialog, anItem, &kind, &itemHandle, &box);
         GetDialogItemText(itemHandle, aString);
  }
 
/**-----------------------------------------------------------------------
    Name:       DrawDefaultOutline
    Purpose:    Draws an outline around theItem.
                                Called as a useritem Proc by the dialog manager.
                                To use place a useritem over the default item in the
                                dialog and install the address of this proc as the item
                                handle.
  -----------------------------------------------------------------------**/
 
#pragma segment Utils
 
pascal void DrawDefaultOutline(DialogPtr theDialog, short theItem)
  {
      short       kind;
    Handle      itemHandle;
    Rect        box;
                
    GetDialogItem(theDialog, theItem, &kind, &itemHandle, &box);
    PenSize(3, 3);
    InsetRect(&box, - 4, - 4);
    FrameRoundRect(&box, 16, 16);
    PenNormal();
        
    }  /* DrawDefaultOutline */
            
/**-----------------------------------------------------------------------
    Name:       AdornDefaultButton
    Purpose:    Installs DrawDefaultOutline as the useritem proc
                    for the given item.
  -----------------------------------------------------------------------**/
 
#pragma segment Utils
        
pascal void AdornDefaultButton(DialogPtr theDialog,short theItem)
  {
      short       kind;
    Handle      itemHandle;
    Rect        box;
 
        GetDialogItem(theDialog, theItem, &kind, &itemHandle, &box);
        SetDialogItem(theDialog, theItem, kind, (Handle)gDefaultButtonUPP, &box);
  }
 
    /*-------  Determining of Gestalt is available ---------------*/
    /*The following routines come from the Inside Mac VI recommendations*/
    /*about how to find if a trap is available*/
        /*
            The glue for Gestalt will be in MPW 3.2, so if it is available we will also
            need to check the system version
        */
 
pascal void GetRectOfDialogItem(DialogPtr theDialog, short theItem, Rect *theRect)
    {
      short       kind;
    Handle      itemHandle;
        
        GetDialogItem(theDialog, theItem, &kind, &itemHandle, theRect);
    }
 
#pragma segment Utils
 
pascal short NumToolboxTraps(void)
  {
        if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
            return(0x200);
        else
            return(0x400);
    }
 
#pragma segment Utils
 
#define TrapMask  0x0800
 
pascal TrapType GetTrapType(short theTrap)
  {
        if ((theTrap & TrapMask) > 0)
            return(ToolTrap);
        else
            return(OSTrap);
    }
 
#pragma segment Utils
 
pascal Boolean TrapAvailable(short theTrap)
  {
        TrapType  tType;
 
        tType = GetTrapType(theTrap);
        if (tType == ToolTrap)
            {
                theTrap = theTrap & 0x07FF;
                if (theTrap >= NumToolboxTraps())
                    theTrap = _Unimplemented;
            }
        return(NGetTrapAddress(theTrap, tType) != NGetTrapAddress(_Unimplemented,ToolTrap));
    }
 
#pragma segment Utils
 
#define _Gestalt 0xA1AD
 
pascal Boolean GestaltAvailable()
  {
        return(TrapAvailable(_Gestalt));
    }
 
/**------  FeatureIsImplemented    ------------**/
/*This is called to use Gestalt to determine if a feature is implemented.
 This applies to only those referenced by OSType*/
 
#pragma segment Utils
 
 
pascal Boolean FeatureIsImplemented ( OSType theFeature, short theTestBit )
{
    OSErr     err;
    long      result;
 
    err = Gestalt ( theFeature, &result );
    return (err == noErr && (result & (1L << theTestBit)));
    
}
 
 
 
 
#pragma segment Utils
 
pascal Boolean CheckEnvironment()
  {
        /*
         first determine of Gestalt is available- if it isn't exit
         as we only run under 7.0.  It could it present in 6.04 - so we need
         to do some further checks for important features
        */
 
        gGestaltAvailable = GestaltAvailable();
        
        if (!gGestaltAvailable)
            return(false);
 
    /*first check if the Edition Manager is present*/
                
    gEditionManagerImplemented = FeatureIsImplemented(gestaltEditionMgrAttr,
                                                                                                          gestaltEditionMgrPresent);
 
        /*and for good measure- the Alias manager*/
                
        gAliasManagerImplemented  = FeatureIsImplemented(gestaltAliasMgrAttr,
                                                                                                         gestaltAliasMgrPresent);
            
        /*check for the AppleEvents manager - we certainly can't work without it*/
        
        gAppleEventsImplemented   = FeatureIsImplemented(gestaltAppleEventsAttr,
                                                                                                         gestaltAppleEventsPresent);
        
        /*check if recording is implemented*/
        
        gRecordingImplemented   = FeatureIsImplemented(gestaltAppleEventsAttr,1);
            
        /*check for the Outline fonts*/
        
        gOutlineFontsImplemented  = FeatureIsImplemented(gestaltFontMgrAttr,
                                                                                                         gestaltOutlineFonts);
        
    
    // We would also like the Drag Manager
    gHasDragManager = FeatureIsImplemented ( gestaltDragMgrAttr, gestaltDragMgrPresent );
    
    // It isn't enough to use Gestalt because we may not have sucessfully linked
    // to the DragLib shared library. So, we also need to test one of the symbols
    // against kUnresolvedSymbol to make sure we have a valid connection to it.
    
#if GENERATINGCFM
    if ( gHasDragManager )
        gHasDragManager = (InstallTrackingHandler != (void*) kUnresolvedCFragSymbolAddress);
#endif
 
 
        return (gEditionManagerImplemented &&
                        gAliasManagerImplemented   &&
                        gAppleEventsImplemented    &&
                        gOutlineFontsImplemented);
                                
    }  /* CheckEnvironment */
            
    /*
        DoPageSetup returns true if the page setup of the document is altered
    */
    
    pascal Boolean DoPageSetup(DPtr theDoc)
        {
            Boolean result = false;
                if (theDoc)
                        {
                            PrOpen();
                            result =  PrStlDialog(theDoc->thePrintSetup);
                            PrClose();
                        }
                    
                return(result);
        }  /* DoPageSetup */
 
/*
    Name:    CtrlKeyPressed
    Purpose: Returns true if control key pressed during event
*/
pascal Boolean CtrlKeyPressed(const EventRecord *theEvent)
    {
        return((theEvent->modifiers & controlKey) != 0);
    }
    
/*
    Name:    OptionKeyPressed
    Purpose: Returns true if option key pressed during event
*/
pascal Boolean OptionKeyPressed(const EventRecord *theEvent)
    {
        return((theEvent->modifiers & optionKey) != 0);
    }