MacTech Network:   MacForge.net  |  Computer Memory  |  Register Domains  |  Printer Supplies  |  Cables  |  iPod Deals  |  Mac Deals  |  Mac Book Shelf


  MacTech Magazine

The journal of Macintosh technology

 
 
MacRentals

Magazine In Print
  About MacTech  
  Home Page  
  Subscribe  
  Archives DVD  
  Submit News  
  Submit a Tip!  
  Get a copy of MacTech RISK FREE  
Google
Entire Web
mactech.com
Mac Community
More...
MacTech Central
  by Category  
  by Company  
  by Product  
MacTech News
  MacTech News  
  Previous News  
  MacTech RSS  
Article Archives
  Show Indices  
  by Volume  
  by Author  
  Source Code FTP  
Inside MacTech
  Writer's Kit  
  Editorial Staff  
  Editorial Calendar  
  Back Issues  
  Advertising  
Contact Us
  Customer Service  
  MacTech Store  
  Legal/Disclaimers  
  Webmaster Feedback  

Demonstration Program Files

Goto Contents

// *******************************************************************************************
// Files.h                                                                  CARBON EVENT MODEL
// *******************************************************************************************
//
// This program demonstrates:
//
// o  File operations associated with:
//
//    o  The user invoking the Open., Close, Save, Save As., Revert, and Quit commands of a
//      typical application.
//
//    o  Handling of the required Apple events Open Application, Re-open Application, Open
//      Documents, Print Documents, and Quit Application.
//
// o  File synchronisation.
//
// o  The creation, display, and handling of Open, Save Location, Choose a Folder, Save
//    Changes, Discard Changes, and Review Unsaved dialogs and alerts using the new model
//    introduced with Navigation Services 3.0.
//
// To keep the code not specifically related to files and file-handling to a minimum, an item
// is included in the Demonstration menu which allows the user to simulate "touching" a window
// (that is, modifying the contents of the associated document).  Choosing the first menu item
// in this menu sets the window-touched flag in the window's document structure to true and
// draws the text "WINDOW TOUCHED" in the window in a large font size, this latter so that the
// user can keep track of which windows have been "touched".
//
// This program is also, in part, an extension of the demonstration program Windows2 in that
// it also demonstrates certain file-related Window Manager features introduced with the Mac
// OS 8.5 Window Manager.  These features are:
//
// o  Window proxy icons.
//
// o  Window path pop-up menus.
//
// Those sections of the source code relating to these features are identified with ///// at
// the right of each line.
//
// The program utilises the following resources:
//
// o  A 'plst' resource containing an information property list which provides information
//    to the Mac OS X Finder.
//
// o  An 'MBAR' resource, and 'MENU' and 'xmnu' resources for Apple, File, Edit and 
//    Demonstration menus (preload, non-purgeable).  
//
// o  A 'STR ' resource containing the "missing application name" string, which is copied to
//    all document files created by the program.
//
// o  'STR#' resources (purgeable) containing error strings, the application's name (for
//    certain Navigation Services functions), and a message  string for the Choose a Folder
//    dialog.
//      
// o  An 'open' resource (purgeable) containing the file type list for the Open dialog.
//
// o  A 'kind' resource (purgeable) describing file types, which is used by Navigation 
//    Services to  build the native file types section of the Show pop-up menu in the Open
//    dialog.
//
// o  Two 'pnot' resources (purgeable) which, together with an associated 'PICT' resource 
//    (purgeable) and a 'TEXT' resource created by the program, provide the previews for
//    the PICT and, on Mac OS 8/9, TEXT files.
//
// o  The 'BNDL' resource (non-purgeable), 'FREF' resources (non-purgeable), signature
//    resource (non-purgeable), and icon family resources (purgeable), required to support the
//    built application on Mac OS 8/9.
//
// o  A 'SIZE' resource with the acceptSuspendResumeEvents, canBackground, 
//    doesActivateOnFGSwitch, and isHighLevelEventAware flags set.
//
// *******************************************************************************************

// .................................................................................. includes

#include <Carbon.h>

// ................................................................................... defines

#define rMenubar                  128
#define mAppleApplication         128
#define  Apple_About              'abou'
#define mFile                     129
#define  File_New                 'new '
#define  File_Open                'open'
#define  File_Close               'clos'
#define  File_Save                'save'
#define  File_SaveAs              'sava'
#define  File_Revert              'reve'
#define  File_Quit                'quit'
#define  iQuit                    12
#define mDemonstration            131
#define  Demo_TouchWindow         'touc'
#define  Demo_ChooseAFolderDialog 'choo'
#define rErrorStrings             128  
#define  eInstallHandler          1000
#define  eMaxWindows              1001
#define  eCantFindFinderProcess   1002                                                   /////
#define rMiscStrings              129
#define  sApplicationName         1
#define  sChooseAFolder           2
#define rOpenResource             128
#define kMaxWindows               10
#define kFileCreator              'Kjbb'
#define kFileTypeTEXT             'TEXT'
#define kFileTypePICT             'PICT'
#define kOpen                     0
#define kPrint                    1
#define MIN(a,b)                  ((a) < (b) ? (a) : (b))

// .................................................................................. typedefs

typedef struct
{
  TEHandle     editStrucHdl;
  PicHandle    pictureHdl;
  SInt16       fileRefNum;
  FSSpec       fileFSSpec;
  AliasHandle  aliasHdl;
  Boolean      windowTouched;
  NavDialogRef modalToWindowNavDialogRef;
  NavEventUPP  askSaveDiscardEventFunctionUPP;
  Boolean      isAskSaveChangesDialog;
}  docStructure, *docStructurePointer, **docStructureHandle;

// ....................................................................... function prototypes

void      main                         (void);
void      eventLoop                    (void);
void      doPreliminaries              (void);
void      doInstallAEHandlers          (void);
OSStatus  appEventHandler              (EventHandlerCallRef,EventRef,void *);
OSStatus  windowEventHandler           (EventHandlerCallRef,EventRef,void *);
void      doIdle                       (void);
void      doDrawContent                (WindowRef);
void      doMenuChoice                 (MenuCommand);
void      doAdjustMenus                (void);
void      doErrorAlert                 (SInt16);
void      doCopyPString                (Str255,Str255);
void      doConcatPStrings             (Str255,Str255);
void      doTouchWindow                (void);
OSErr     openAppEventHandler          (AppleEvent *,AppleEvent *,SInt32);
OSErr     reopenAppEventHandler        (AppleEvent *,AppleEvent *,SInt32);
OSErr     openAndPrintDocsEventHandler (AppleEvent *,AppleEvent *,SInt32);
OSErr     quitAppEventHandler          (AppleEvent *,AppleEvent *,SInt32);
OSErr     doHasGotRequiredParams       (AppleEvent *);
SInt16    doReviewChangesAlert         (SInt16);

OSErr     doNewCommand                 (void);
OSErr     doOpenCommand                (void);
OSErr     doCloseCommand               (NavAskSaveChangesAction);
OSErr     doSaveCommand                (void);
OSErr     doSaveAsCommand              (void);
OSErr     doRevertCommand              (void);

OSErr     doNewDocWindow               (Boolean,OSType,WindowRef *);
EventHandlerUPP  doGetHandlerUPP       (void);
OSErr     doCloseDocWindow             (WindowRef);
OSErr     doOpenFile                   (FSSpec,OSType);
OSErr     doReadTextFile               (WindowRef);
OSErr     doReadPictFile               (WindowRef);
OSErr     doCreateAskSaveChangesDialog (WindowRef,docStructureHandle,NavAskSaveChangesAction);
OSErr     doSaveUsingFSSpec            (WindowRef,NavReplyRecord *);
OSErr     doSaveUsingFSRef             (WindowRef,NavReplyRecord *);
OSErr     doWriteFile                  (WindowRef);
OSErr     doWriteTextData              (WindowRef,SInt16);
OSErr     doWritePictData              (WindowRef,SInt16);

void  getFilePutFileEventFunction   (NavEventCallbackMessage,NavCBRecPtr,NavCallBackUserData);
void  askSaveDiscardEventFunction   (NavEventCallbackMessage,NavCBRecPtr,NavCallBackUserData);

OSErr     doCopyResources              (WindowRef);
OSErr     doCopyAResource              (ResType,SInt16,SInt16,SInt16);

void      doSynchroniseFiles           (void);
OSErr     doChooseAFolderDialog        (void);

// *******************************************************************************************
// Files.c
// *******************************************************************************************

// .................................................................................. includes

#include "Files.h"

// .......................................................................... global variables

Boolean     gRunningOnX = false;
SInt16      gAppResFileRefNum;
NavEventUPP gGetFilePutFileEventFunctionUPP ;
Boolean     gQuittingApplication = false;

extern SInt16 gCurrentNumberOfWindows;
extern Rect   gDestRect,gViewRect;

// ************************************************************************************** main

void  main(void)
{
  MenuBarHandle menubarHdl;
  SInt32        response;
  MenuRef       menuRef;
  EventTypeSpec applicationEvents[] = { { kEventClassApplication, kEventAppActivated    },
                                        { kEventClassCommand,     kEventProcessCommand  },
                                        { kEventClassMenu,        kEventMenuEnableItems } };
  EventLoopTimerRef timerRef;

  // ........................................................................ do preliminaries

  doPreliminaries();

  // .................................. save application's resource file file reference number

  gAppResFileRefNum = CurResFile();

  // ............................................................... set up menu bar and menus
  
  menubarHdl = GetNewMBar(rMenubar);
  if(menubarHdl == NULL)
    doErrorAlert(MemError());
  SetMenuBar(menubarHdl);
  DrawMenuBar();

  Gestalt(gestaltMenuMgrAttr,&response);
  if(response & gestaltMenuMgrAquaLayoutMask)
  {
    menuRef = GetMenuRef(mFile);
    if(menuRef != NULL)
    {
      DeleteMenuItem(menuRef,iQuit);
      DeleteMenuItem(menuRef,iQuit - 1);
    }

    gRunningOnX = true;
  }
  else
  {
    menuRef = GetMenuRef(mFile);
    if(menuRef != NULL)
      SetMenuItemCommandID(menuRef,iQuit,kHICommandQuit);
  }

  // ................................................... install required Apple event handlers

  doInstallAEHandlers();

  // ....................................................... install application event handler
  
  InstallApplicationEventHandler(NewEventHandlerUPP((EventHandlerProcPtr) appEventHandler),
                                 GetEventTypeCount(applicationEvents),applicationEvents,
                                 0,NULL);

  // .............................................. install a timer (for file synchronisation)

  InstallEventLoopTimer(GetCurrentEventLoop(),0,TicksToEventTime(15),
                        NewEventLoopTimerUPP((EventLoopTimerProcPtr) doIdle),NULL,
                        &timerRef);

  // ..... get universal procedure pointer to main Navigation Services services event function

  gGetFilePutFileEventFunctionUPP  = 
                                NewNavEventUPP((NavEventProcPtr) getFilePutFileEventFunction);

  // .............................................................. run application event loop

  RunApplicationEventLoop();
}

// *************************************************************************** doPreliminaries

void  doPreliminaries(void)
{
  MoreMasterPointers(448);
  InitCursor();
}

// *********************************************************************** doInstallAEHandlers

void  doInstallAEHandlers(void)
{
  OSErr osError;

  osError = AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,
                  NewAEEventHandlerUPP((AEEventHandlerProcPtr) openAppEventHandler),
                  0L,false);
  if(osError != noErr)  doErrorAlert(eInstallHandler);

  osError = AEInstallEventHandler(kCoreEventClass,kAEReopenApplication,
                  NewAEEventHandlerUPP((AEEventHandlerProcPtr) reopenAppEventHandler),
                  0L,false);
  if(osError != noErr)  doErrorAlert(eInstallHandler);

  osError = AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,
                  NewAEEventHandlerUPP((AEEventHandlerProcPtr) openAndPrintDocsEventHandler),
                  kOpen,false);
  if(osError != noErr)  doErrorAlert(eInstallHandler);

  osError = AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,
                  NewAEEventHandlerUPP((AEEventHandlerProcPtr) openAndPrintDocsEventHandler),
                  kPrint,false);
  if(osError != noErr)  doErrorAlert(eInstallHandler);

  osError = AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,
                  NewAEEventHandlerUPP((AEEventHandlerProcPtr) quitAppEventHandler),
                  0L,false);
  if(osError != noErr)  doErrorAlert(eInstallHandler);
}

// *************************************************************************** appEventHandler

OSStatus  appEventHandler(EventHandlerCallRef eventHandlerCallRef,EventRef eventRef,
                          void * userData)
{
  OSStatus      result = eventNotHandledErr;
  UInt32        eventClass;
  UInt32        eventKind;
  HICommand     hiCommand;
  MenuID        menuID;
  MenuItemIndex menuItem;

  eventClass = GetEventClass(eventRef);
  eventKind  = GetEventKind(eventRef);

  switch(eventClass)
  {
    case kEventClassApplication:
      if(eventKind == kEventAppActivated)
        SetThemeCursor(kThemeArrowCursor);
      break;

    case kEventClassCommand:
      if(eventKind == kEventProcessCommand)
      {
        GetEventParameter(eventRef,kEventParamDirectObject,typeHICommand,NULL,
                          sizeof(HICommand),NULL,&hiCommand);
        menuID = GetMenuID(hiCommand.menu.menuRef);
        menuItem = hiCommand.menu.menuItemIndex;
        if((hiCommand.commandID != kHICommandQuit) && 
           (menuID >= mAppleApplication && menuID <= mDemonstration))
        {
          doMenuChoice(hiCommand.commandID);
          result = noErr;
        }
      }
      break;

    case kEventClassMenu:
      if(eventKind == kEventMenuEnableItems)
      {
        doAdjustMenus();
        result = noErr;
      }
      break;
  }

  return result;
}

// ************************************************************************ windowEventHandler

OSStatus  windowEventHandler(EventHandlerCallRef eventHandlerCallRef,EventRef eventRef,
                             void* userData)
{
  OSStatus  result = eventNotHandledErr;
  UInt32    eventClass;
  UInt32    eventKind;
  WindowRef windowRef;

  eventClass = GetEventClass(eventRef);
  eventKind  = GetEventKind(eventRef);

  switch(eventClass)
  {
    case kEventClassWindow:
      GetEventParameter(eventRef,kEventParamDirectObject,typeWindowRef,NULL,sizeof(windowRef),
                        NULL,&windowRef);
      switch(eventKind)
      {
        case kEventWindowDrawContent:
          doDrawContent(windowRef);
          result = noErr;
          break;

        case kEventWindowClose:
          if(gQuittingApplication)
            doCloseCommand(kNavSaveChangesQuittingApplication);
          else
            doCloseCommand(kNavSaveChangesClosingDocument);
          result = noErr;
          break;
      }
      break;
  }

  return result;
}

// ************************************************************************************ doIdle

void  doIdle(void)
{
  if(GetWindowKind(FrontWindow()) == kApplicationWindowKind)
    doSynchroniseFiles();
}

// ********************************************************************************** doUpdate

void  doDrawContent(WindowRef windowRef)
{
  docStructureHandle docStrucHdl;
  GrafPtr            oldPort;
  Rect               destRect;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);

  GetPort(&oldPort);
  SetPortWindowPort(windowRef);

  if((*docStrucHdl)->pictureHdl)
  {
    destRect = (*(*docStrucHdl)->pictureHdl)->picFrame;
    OffsetRect(&destRect,170,54);
    HLock((Handle) (*docStrucHdl)->pictureHdl);
    DrawPicture((*docStrucHdl)->pictureHdl,&destRect);
    HUnlock((Handle) (*docStrucHdl)->pictureHdl);
  }
  else if((*docStrucHdl)->editStrucHdl)
  {
    HLock((Handle) (*docStrucHdl)->editStrucHdl);
    TEUpdate(&gDestRect,(*docStrucHdl)->editStrucHdl);
    HUnlock((Handle) (*docStrucHdl)->editStrucHdl);
  }

  if((*docStrucHdl)->windowTouched)
  {
    TextSize(48);
    MoveTo(30,170);
    DrawString("\pWINDOW TOUCHED");
    TextSize(12);
  }

  SetPort(oldPort);
}

// ****************************************************************************** doMenuChoice

void  doMenuChoice(MenuCommand commandID)
{
  OSErr osError = noErr;

  switch(commandID)
  {
    // ................................................................ Apple/Application menu

    case Apple_About:
      SysBeep(10);
      break;

    // ............................................................................. File menu

    case File_New:
      if(osError = doNewCommand())
        doErrorAlert(osError);
      break;

    case File_Open:
      if(osError = doOpenCommand() && osError == opWrErr)
        doErrorAlert(osError);
      break;

    case File_Close:
      if(osError = doCloseCommand(kNavSaveChangesClosingDocument))
        doErrorAlert(osError);
      break;

    case File_Save:
      if(osError = doSaveCommand())
        doErrorAlert(osError);
      break;

    case File_SaveAs:
      if(osError = doSaveAsCommand())
        doErrorAlert(osError);
      break;

    case File_Revert:
      if(osError = doRevertCommand())
        doErrorAlert(osError);
      break;

    // .................................................................... Demonstration menu

    case Demo_TouchWindow:
      doTouchWindow();
      break;
      
    case Demo_ChooseAFolderDialog:
      if(osError = doChooseAFolderDialog())
        doErrorAlert(osError);
      break;
  }
}

// ***************************************************************************** doAdjustMenus

void  doAdjustMenus(void)
{
  OSErr              osError;
  MenuRef            menuRef;
  WindowRef          windowRef;
  docStructureHandle docStrucHdl;

  if(gCurrentNumberOfWindows > 0)
  {
    if(gRunningOnX)
    {
      if((osError = GetSheetWindowParent(FrontWindow(),&windowRef)) == noErr)
      {
        menuRef = GetMenuRef(mFile);
        DisableMenuCommand(menuRef,File_Close);
        DisableMenuCommand(menuRef,File_Save);
        DisableMenuCommand(menuRef,File_SaveAs);
        DisableMenuCommand(menuRef,File_Revert);
        menuRef = GetMenuRef(mDemonstration);
        DisableMenuCommand(menuRef,Demo_TouchWindow);
        return;
      }
      else
        windowRef = FrontWindow();
    }
    else
      windowRef = FrontWindow();

    if(GetWindowKind(windowRef) == kApplicationWindowKind)
    {
      docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);

      menuRef = GetMenuRef(mFile);
      EnableMenuCommand(menuRef,File_Close);
      if((*docStrucHdl)->windowTouched)
      {
        EnableMenuCommand(menuRef,File_Save);
        EnableMenuCommand(menuRef,File_Revert);
      }
      else
      {
        DisableMenuCommand(menuRef,File_Save);
        DisableMenuCommand(menuRef,File_Revert);
      }

      if(((*docStrucHdl)->pictureHdl != NULL) || 
         ((*(*docStrucHdl)->editStrucHdl)->teLength > 0))
        EnableMenuCommand(menuRef,File_SaveAs);
      else
        DisableMenuCommand(menuRef,File_SaveAs);

      menuRef = GetMenuRef(mDemonstration);

      if(((*docStrucHdl)->pictureHdl != NULL) || 
         ((*(*docStrucHdl)->editStrucHdl)->teLength > 0))
      {
        if((*docStrucHdl)->windowTouched == false)
          EnableMenuCommand(menuRef,Demo_TouchWindow);
        else
          DisableMenuCommand(menuRef,Demo_TouchWindow);
      }
      else
        DisableMenuCommand(menuRef,Demo_TouchWindow);
    }
  }
  else
  {
    menuRef = GetMenuRef(mFile);
    DisableMenuCommand(menuRef,File_Close);
    DisableMenuCommand(menuRef,File_Save);
    DisableMenuCommand(menuRef,File_SaveAs);
    DisableMenuCommand(menuRef,File_Revert);
    menuRef = GetMenuRef(mDemonstration);
    DisableMenuCommand(menuRef,Demo_TouchWindow);
  }

  DrawMenuBar();
}

// ****************************************************************************** doErrorAlert

void  doErrorAlert(SInt16 errorCode)
{
  Str255 errorString, theString;
  SInt16 itemHit;

  if(errorCode == eInstallHandler)
    GetIndString(errorString,rErrorStrings,1);
  else if(errorCode == eMaxWindows)
    GetIndString(errorString,rErrorStrings,2);
  else if(errorCode == eCantFindFinderProcess)
    GetIndString(errorString,rErrorStrings,3);
  else if(errorCode == opWrErr)
    GetIndString(errorString,rErrorStrings,4);
  else
  {
    GetIndString(errorString,rErrorStrings,5);
    NumToString((SInt32) errorCode,theString);
    doConcatPStrings(errorString,theString);
  }

  if(errorCode != memFullErr)
  {
    StandardAlert(kAlertCautionAlert,errorString,NULL,NULL,&itemHit);
  }
  else
  {
    StandardAlert(kAlertStopAlert,errorString,NULL,NULL,&itemHit);
    ExitToShell();
  }
}

// ***************************************************************************** doCopyPString

void  doCopyPString(Str255 sourceString,Str255 destinationString)
{
  SInt16 stringLength;

  stringLength = sourceString[0];
  BlockMove(sourceString + 1,destinationString + 1,stringLength);
  destinationString[0] = stringLength;
}

// ************************************************************************** doConcatPStrings

void  doConcatPStrings(Str255 targetString,Str255 appendString)
{
  SInt16 appendLength;

  appendLength = MIN(appendString[0],255 - targetString[0]);

  if(appendLength > 0)
  {
    BlockMoveData(appendString+1,targetString+targetString[0]+1,(SInt32) appendLength);
    targetString[0] += appendLength;
  }
}

// ***************************************************************************** doTouchWindow

void  doTouchWindow(void)
{
  WindowRef          windowRef;
  docStructureHandle docStrucHdl;

  windowRef = FrontWindow();
  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);

  SetPortWindowPort(windowRef);

  TextSize(48);
  MoveTo(30,170);
  DrawString("\pWINDOW TOUCHED");
  TextSize(12);

  (*docStrucHdl)->windowTouched = true;

  SetWindowModified(windowRef,true);                                                     /////
}

// *********************************************************************** openAppEventHandler

OSErr  openAppEventHandler(AppleEvent *appEvent,AppleEvent *reply,SInt32 handlerRefCon)
{
  OSErr osError;

  osError = doHasGotRequiredParams(appEvent);
  if(osError == noErr)
    osError = doNewCommand();

  return osError;
}

// ********************************************************************* reopenAppEventHandler

OSErr  reopenAppEventHandler(AppleEvent *appEvent,AppleEvent *reply,
                               SInt32 handlerRefCon)
{
  OSErr osError;

  osError = doHasGotRequiredParams(appEvent);
  if(osError == noErr)
    if(!FrontWindow())
      osError = doNewCommand();

  return osError;
}

// ************************************************************** openAndPrintDocsEventHandler

OSErr  openAndPrintDocsEventHandler(AppleEvent *appEvent,AppleEvent *reply,
                                    SInt32 handlerRefcon)
{
  FSSpec     fileSpec;
  AEDescList docList;
  OSErr      osError, ignoreErr;
  SInt32     index, numberOfItems;
  Size       actualSize;
  AEKeyword  keyWord;
  DescType   returnedType;
  FInfo      fileInfo;

  osError = AEGetParamDesc(appEvent,keyDirectObject,typeAEList,&docList);

  if(osError == noErr)
  {
    osError = doHasGotRequiredParams(appEvent);
    if(osError == noErr)
    {
      osError = AECountItems(&docList,&numberOfItems);
      if(osError == noErr)
      {
        for(index=1;index<=numberOfItems;index++)
        {
          osError = AEGetNthPtr(&docList,index,typeFSS,&keyWord,&returnedType,
                                &fileSpec,sizeof(fileSpec),&actualSize);
          if(osError == noErr)
          {
            osError = FSpGetFInfo(&fileSpec,&fileInfo);
            if(osError == noErr)
            {
              if(osError = doOpenFile(fileSpec,fileInfo.fdType))
                doErrorAlert(osError);

              if(osError == noErr && handlerRefcon == kPrint)
              {
                // Call printing function here
              }
            }
          }
          else
            doErrorAlert(osError);
        }
      }
    }
    else
      doErrorAlert(osError);

    ignoreErr = AEDisposeDesc(&docList);
  }
  else
    doErrorAlert(osError);

  return osError;
}

// *********************************************************************** quitAppEventHandler

OSErr  quitAppEventHandler(AppleEvent *appEvent,AppleEvent *reply,SInt32 handlerRefcon)
{
  OSErr              osError;
  WindowRef          windowRef, previousWindowRef;
  docStructureHandle docStrucHdl;
  SInt16             touchedWindowsCount = 0;
  EventRef           eventRef;
  EventTargetRef     eventTargetRef;
  SInt16             itemHit;

  osError = doHasGotRequiredParams(appEvent);
  if(osError == noErr)
  {
    if(FrontWindow())
    {
      // ...... if any window has a sheet, bring to front, play system alert sound, and return

      windowRef = GetFrontWindowOfClass(kSheetWindowClass,true);
      if(windowRef)
      {
        SelectWindow(windowRef);
        SysBeep(10);
        return noErr;
      }

      // ............................................................... count touched windows

      windowRef = FrontWindow();
      do
      {
        docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
        if((*docStrucHdl)->windowTouched == true)
          touchedWindowsCount++;
        previousWindowRef = windowRef;
      } while(windowRef = GetNextWindowOfClass(previousWindowRef,kDocumentWindowClass,true));

      // ............................................ if no touched windows, simply close down

      if(touchedWindowsCount == 0)
        QuitApplicationEventLoop();

      // .............................. if touched windows are present, and if running on OS X

      if(gRunningOnX)
      {

        // .. if one touched window, cause Save Changes alert on that window, close all others

        if(touchedWindowsCount == 1)
        {
          gQuittingApplication = true;
          CreateEvent(NULL,kEventClassWindow,kEventWindowClose,0,kEventAttributeNone,
                      &eventRef);
          eventTargetRef = GetWindowEventTarget(FrontWindow());
          SendEventToEventTarget(eventRef,eventTargetRef);
        }

      // .. if more than one touched window, create Review Changes alert, handle button clicks

      else if(touchedWindowsCount > 1)
      {
        itemHit = doReviewChangesAlert(touchedWindowsCount);

          if(itemHit == kAlertStdAlertOKButton)
          {
            gQuittingApplication = true;
            CreateEvent(NULL,kEventClassWindow,kEventWindowClose,0,kEventAttributeNone,
                        &eventRef);
            eventTargetRef = GetWindowEventTarget(FrontWindow());
            SendEventToEventTarget(eventRef,eventTargetRef);
          }
          else if(itemHit == kAlertStdAlertCancelButton)
            gQuittingApplication = false;
          else if(itemHit == kAlertStdAlertOtherButton)
            QuitApplicationEventLoop();
        }
      }

      // ............................ if touched windows are present, and if running on OS 8/9

      else
      {
        gQuittingApplication = true;
        CreateEvent(NULL,kEventClassWindow,kEventWindowClose,0,kEventAttributeNone,
                    &eventRef);
        eventTargetRef = GetWindowEventTarget(FrontWindow());
        SendEventToEventTarget(eventRef,eventTargetRef);
      }
    }
    else
      QuitApplicationEventLoop();
  }

  return osError;
}

// ******************************************************************** doHasGotRequiredParams

OSErr  doHasGotRequiredParams(AppleEvent *appEvent)
{
  DescType returnedType;
  Size     actualSize;
  OSErr    osError;

  osError = AEGetAttributePtr(appEvent,keyMissedKeywordAttr,typeWildCard,&returnedType,
                            NULL,0,&actualSize);
  if(osError == errAEDescNotFound)
    osError = noErr;
  else if(osError == noErr)
    osError = errAEParamMissed;

  return osError;
}

// ********************************************************************** doReviewChangesAlert

SInt16  doReviewChangesAlert(SInt16 touchedWindowsCount)
{
  AlertStdCFStringAlertParamRec paramRec;
  Str255      messageText1 = "\pYou have ";
  Str255      messageText2 = "\p Files documents with unsaved changes. ";
  Str255      messageText3 = "\pDo you want to review these changes before quitting?";
  Str255      countString;
  CFStringRef messageText;
  CFStringRef informativeText = 
              CFSTR("If you don't review your documents, all your changes will be lost.");
  DialogRef       dialogRef;
  DialogItemIndex itemHit;

  NumToString(touchedWindowsCount,countString);
  doConcatPStrings(messageText1,countString);  
  doConcatPStrings(messageText1,messageText2);  
  doConcatPStrings(messageText1,messageText3);  
  messageText = CFStringCreateWithPascalString(NULL,messageText1,CFStringGetSystemEncoding());

  GetStandardAlertDefaultParams(¶mRec,kStdCFStringAlertVersionOne);
  paramRec.movable      = true;
  paramRec.defaultText  = CFSTR("Review Changes.");
  paramRec.cancelText    = CFSTR("Cancel");
  paramRec.otherText    = CFSTR("Discard Changes");

  CreateStandardAlert(kAlertStopAlert,messageText,informativeText,¶mRec,&dialogRef);
  RunStandardAlert(dialogRef,NULL,&itemHit);

  if(messageText != NULL)
    CFRelease(messageText);

  return itemHit;
}

// *******************************************************************************************
// NewOpenCloseSave.c  
// *******************************************************************************************

// .................................................................................. includes

#include "Files.h"

// .......................................................................... global variables

NavDialogRef gModalToApplicationNavDialogRef;
SInt16       gCurrentNumberOfWindows = 0;
Rect         gDestRect, gViewRect;
Boolean      gCloseDocWindow = false;

extern NavEventUPP gGetFilePutFileEventFunctionUPP;
extern SInt16      gAppResFileRefNum;
extern Boolean     gQuittingApplication;
extern Boolean     gRunningOnX;

// ****************************************************************************** doNewCommand

OSErr  doNewCommand(void)
{
  WindowRef windowRef;
  OSErr     osError;
  OSType    documentType = kFileTypeTEXT;

  osError = doNewDocWindow(true,documentType,&windowRef);

  if(osError == noErr)
    SetWindowProxyCreatorAndType(windowRef,kFileCreator,documentType,kUserDomain);       /////

  return osError;
}

// ***************************************************************************** doOpenCommand

OSErr  doOpenCommand(void)
{
  OSErr                    osError = noErr;
  NavDialogCreationOptions dialogOptions;
  Str255                   applicationName;
  NavTypeListHandle        fileTypeListHdl = NULL;

  // .................................................... create application-modal Open dialog

  osError = NavGetDefaultDialogCreationOptions(&dialogOptions);
  if(osError == noErr)
  {
    GetIndString(applicationName,rMiscStrings,sApplicationName);
    dialogOptions.clientName = CFStringCreateWithPascalString(NULL,applicationName,
                                                              CFStringGetSystemEncoding());
    dialogOptions.modality = kWindowModalityAppModal;
    fileTypeListHdl = (NavTypeListHandle) GetResource('open',rOpenResource);

    osError = NavCreateGetFileDialog(&dialogOptions,fileTypeListHdl,
                                     gGetFilePutFileEventFunctionUPP,NULL,NULL,NULL,
                                     &gModalToApplicationNavDialogRef);
    if(osError == noErr && gModalToApplicationNavDialogRef != NULL)
    {
      osError = NavDialogRun(gModalToApplicationNavDialogRef);
      if(osError != noErr)
      {
        NavDialogDispose(gModalToApplicationNavDialogRef);
        gModalToApplicationNavDialogRef = NULL;
      }
    }
    
    if(dialogOptions.clientName != NULL)
      CFRelease(dialogOptions.clientName);

    if(fileTypeListHdl != NULL)
      ReleaseResource((Handle) fileTypeListHdl);
  }

  return osError;
}

// **************************************************************************** doCloseCommand

OSErr  doCloseCommand(NavAskSaveChangesAction action)
{
  WindowRef          windowRef;
  SInt16             windowKind;
  docStructureHandle docStrucHdl;
  OSErr              osError = noErr;

  windowRef = FrontWindow();
  windowKind = GetWindowKind(windowRef);

  switch(windowKind)
  {
    case kApplicationWindowKind:
      docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);

      // ............................ if window has unsaved changes, create Save Changes alert

      if((*docStrucHdl)->windowTouched == true)
      {
        if(IsWindowCollapsed(windowRef))
          CollapseWindow(windowRef,false);

        osError = doCreateAskSaveChangesDialog(windowRef,docStrucHdl,action);
      }

      // ................................................... otherwise close file and clean up

      else
        osError = doCloseDocWindow(windowRef);
      break;

    case kDialogWindowKind:
      // Hide or close modeless dialog, as required.
      break;
  }

  return osError;
}

// ***************************************************************************** doSaveCommand

OSErr  doSaveCommand(void)
{
  WindowRef          windowRef;
  docStructureHandle docStrucHdl;
  OSErr              osError = noErr;
  Rect               portRect;

  windowRef = FrontWindow();
  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);

  // ... if the document has a file ref number, write the file, otherwise call doSaveAsCommand

  if((*docStrucHdl)->fileRefNum)
  {
    osError = doWriteFile(windowRef);
    
    SetPortWindowPort(windowRef);
    GetWindowPortBounds(windowRef,&portRect);
    EraseRect(&portRect);
    InvalWindowRect(windowRef,&portRect);
  }
  else
    osError = doSaveAsCommand();

  if(osError == noErr)                                                                   /////
    SetWindowModified(windowRef,false);                                                  /////

  return osError;
}

// *************************************************************************** doSaveAsCommand

OSErr  doSaveAsCommand(void)
{
  OSErr                    osError = noErr;
  NavDialogCreationOptions dialogOptions;
  WindowRef                windowRef;
  Str255                   windowTitle, applicationName;
  docStructureHandle       docStrucHdl;
  OSType                   fileType;

  // ................................................ create window-modal Save Location dialog

  osError = NavGetDefaultDialogCreationOptions(&dialogOptions);
  if(osError == noErr)
  {
    dialogOptions.optionFlags |= kNavNoTypePopup;

    windowRef = FrontWindow();

    GetWTitle(windowRef,windowTitle);
    dialogOptions.saveFileName = CFStringCreateWithPascalString(NULL,windowTitle,
                                                                CFStringGetSystemEncoding());
    GetIndString(applicationName,rMiscStrings,sApplicationName);
    dialogOptions.clientName = CFStringCreateWithPascalString(NULL,applicationName,
                                                              CFStringGetSystemEncoding());
    dialogOptions.parentWindow = windowRef;
    dialogOptions.modality = kWindowModalityWindowModal;
    
    docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
    if((*docStrucHdl)->editStrucHdl != NULL)
      fileType = kFileTypeTEXT;
    else if((*docStrucHdl)->pictureHdl != NULL)
      fileType = kFileTypePICT;

    HLock((Handle) docStrucHdl);

    osError = NavCreatePutFileDialog(&dialogOptions,fileType,kFileCreator,
                                     gGetFilePutFileEventFunctionUPP ,
                                     windowRef,&(*docStrucHdl)->modalToWindowNavDialogRef);
    HUnlock((Handle) docStrucHdl);

    if(osError == noErr && (*docStrucHdl)->modalToWindowNavDialogRef != NULL)
    {
      osError = NavDialogRun((*docStrucHdl)->modalToWindowNavDialogRef);
      if(osError != noErr)
      {
        NavDialogDispose((*docStrucHdl)->modalToWindowNavDialogRef);
        (*docStrucHdl)->modalToWindowNavDialogRef = NULL;
      }
    }

    if(dialogOptions.saveFileName != NULL)
      CFRelease(dialogOptions.saveFileName);
    if(dialogOptions.clientName != NULL)
      CFRelease(dialogOptions.clientName);
  }

  return osError;
}

// *************************************************************************** doRevertCommand

OSErr  doRevertCommand(void)
{
  OSErr                    osError = noErr;
  NavDialogCreationOptions dialogOptions;
  WindowRef                windowRef;
  Str255                   windowTitle;
  docStructureHandle       docStrucHdl;

  // ............................................... create window-modal Discard Changes alert

  osError = NavGetDefaultDialogCreationOptions(&dialogOptions);
  if(osError == noErr)
  {
    windowRef = FrontWindow();

    GetWTitle(windowRef,windowTitle);
    dialogOptions.saveFileName = CFStringCreateWithPascalString(NULL,windowTitle,
                                                                CFStringGetSystemEncoding());
    dialogOptions.parentWindow = windowRef;
    dialogOptions.modality = kWindowModalityWindowModal;

    docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
    if((*docStrucHdl)->askSaveDiscardEventFunctionUPP != NULL)
    {
      DisposeNavEventUPP((*docStrucHdl)->askSaveDiscardEventFunctionUPP);
      (*docStrucHdl)->askSaveDiscardEventFunctionUPP = NULL;
    }
    (*docStrucHdl)->askSaveDiscardEventFunctionUPP = 
                            NewNavEventUPP((NavEventProcPtr) askSaveDiscardEventFunction); 

    HLock((Handle) docStrucHdl);

    osError = NavCreateAskDiscardChangesDialog(&dialogOptions,
                                               (*docStrucHdl)->askSaveDiscardEventFunctionUPP,
                                               windowRef,
                                               &(*docStrucHdl)->modalToWindowNavDialogRef);
    HUnlock((Handle) docStrucHdl);

    if(osError == noErr && (*docStrucHdl)->modalToWindowNavDialogRef != NULL)
    {
      osError = NavDialogRun((*docStrucHdl)->modalToWindowNavDialogRef);
      if(osError != noErr)
      {
        NavDialogDispose((*docStrucHdl)->modalToWindowNavDialogRef);
        (*docStrucHdl)->modalToWindowNavDialogRef = NULL;
      }
    }

    if(dialogOptions.saveFileName != NULL)
      CFRelease(dialogOptions.saveFileName);
  }

  return osError;
}

// **************************************************************************** doNewDocWindow

OSErr  doNewDocWindow(Boolean showWindow,OSType documentType,WindowRef * windowRef)
{
  OSStatus           osError;
  WindowAttributes   attributes = kWindowStandardHandlerAttribute |
                                  kWindowStandardDocumentAttributes;
  Rect               portRect, contentRect = { 0,0,300,500 };
  docStructureHandle docStrucHdl;
  EventTypeSpec      windowEvents[] = { { kEventClassWindow, kEventWindowDrawContent  },
                                        { kEventClassWindow, kEventWindowClose        },
                                        { kEventClassWindow, kEventWindowClickDragRgn },
                                        { kEventClassWindow, kEventWindowPathSelect   } };

  if(gCurrentNumberOfWindows == kMaxWindows)
    return eMaxWindows;

  // ..................... create window, change attributes, reposition, install event handler

  osError = CreateNewWindow(kDocumentWindowClass,attributes,&contentRect,windowRef);
  if(osError != noErr)
    return osError;

  SetWTitle(*windowRef,"\puntitled");
  ChangeWindowAttributes(*windowRef,0,kWindowFullZoomAttribute | kWindowResizableAttribute);
  RepositionWindow(*windowRef,NULL,kWindowCascadeOnMainScreen);
  SetPortWindowPort(*windowRef);
  
  InstallWindowEventHandler(*windowRef,doGetHandlerUPP(),GetEventTypeCount(windowEvents),
                            windowEvents,0,NULL);

  // ..................................................... attach document structure to window

  if(!(docStrucHdl = (docStructureHandle) NewHandle(sizeof(docStructure))))
  {
    DisposeWindow(*windowRef);
    return MemError();
  }

  SetWRefCon(*windowRef,(SInt32) docStrucHdl);

  (*docStrucHdl)->editStrucHdl                   = NULL;
  (*docStrucHdl)->pictureHdl                     = NULL;
  (*docStrucHdl)->fileRefNum                     = 0;
  (*docStrucHdl)->aliasHdl                       = NULL;                                 /////
  (*docStrucHdl)->windowTouched                  = false;
  (*docStrucHdl)->modalToWindowNavDialogRef      = NULL;
  (*docStrucHdl)->askSaveDiscardEventFunctionUPP = NULL;
  (*docStrucHdl)->isAskSaveChangesDialog         = false;

  // ............................................. if text document, create TextEdit structure

  if(documentType == kFileTypeTEXT)
  {
    UseThemeFont(kThemeSmallSystemFont,smSystemScript);

    GetWindowPortBounds(*windowRef,&portRect);
    gDestRect = portRect;
    InsetRect(&gDestRect,6,6);
    gViewRect = gDestRect;

    MoveHHi((Handle) docStrucHdl);
    HLock((Handle) docStrucHdl);

    if(!((*docStrucHdl)->editStrucHdl = TENew(&gDestRect,&gViewRect)))
    {
      DisposeWindow(*windowRef);
      DisposeHandle((Handle) docStrucHdl);
      return MemError();
    }

    HUnlock((Handle) docStrucHdl);
  }

  // ............................................ show window and increment open windows count

  if(showWindow)
    ShowWindow(*windowRef);

  gCurrentNumberOfWindows ++;

  return noErr;
}

// *************************************************************************** doGetHandlerUPP

EventHandlerUPP  doGetHandlerUPP(void)
{
  static EventHandlerUPP windowEventHandlerUPP;

  if(windowEventHandlerUPP == NULL)
    windowEventHandlerUPP = NewEventHandlerUPP((EventHandlerProcPtr) windowEventHandler);

  return windowEventHandlerUPP;
}

// ************************************************************************** doCloseDocWindow

OSErr  doCloseDocWindow(WindowRef windowRef)
{
  docStructureHandle docStrucHdl;
  OSErr              osError = noErr;
  EventRef           eventRef;
  EventTargetRef     eventTargetRef;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);

  // ....................... close file, flush volume, dispose of window and associated memory

  if((*docStrucHdl)->fileRefNum != 0)
  {
    if(!(osError = FSClose((*docStrucHdl)->fileRefNum)))  
    {
      osError = FlushVol(NULL,(*docStrucHdl)->fileFSSpec.vRefNum);
      (*docStrucHdl)->fileRefNum = 0;
    }
  }

  if((*docStrucHdl)->editStrucHdl != NULL)
    TEDispose((*docStrucHdl)->editStrucHdl);
  if((*docStrucHdl)->pictureHdl != NULL)
    KillPicture((*docStrucHdl)->pictureHdl);

  DisposeHandle((Handle) docStrucHdl);
  DisposeWindow(windowRef);

  gCurrentNumberOfWindows --;

  // ................................................................. if quitting application

  if(gQuittingApplication)
  {
    if(FrontWindow() == NULL)
      QuitApplicationEventLoop();
    else
    {
      CreateEvent(NULL,kEventClassWindow,kEventWindowClose,0,kEventAttributeNone,
                  &eventRef);
      eventTargetRef = GetWindowEventTarget(FrontWindow());
      SendEventToEventTarget(eventRef,eventTargetRef);
    }
  }

  return osError;
}

// ******************************************************************************** doOpenFile

OSErr  doOpenFile(FSSpec fileSpec,OSType documentType)
{
  WindowRef          windowRef;
  OSErr              osError = noErr;
  SInt16             fileRefNum;
  docStructureHandle docStrucHdl;

  // ....................................................................... create new window

  if(osError = doNewDocWindow(false,documentType,&windowRef))
    return osError;

  SetWTitle(windowRef,fileSpec.name);  

  // ................................................................... open file's data fork

  if(osError = FSpOpenDF(&fileSpec,fsRdWrPerm,&fileRefNum))
  {
    DisposeWindow(windowRef);
    gCurrentNumberOfWindows --;
    return osError;
  }

  // ................... store file reference number and FSSpec in window's document structure

  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
  (*docStrucHdl)->fileRefNum = fileRefNum;
  (*docStrucHdl)->fileFSSpec = fileSpec;

  // ........................................................................ read in the file

  if(documentType == kFileTypeTEXT)
  {
    if(osError = doReadTextFile(windowRef))
      return osError;
  }
  else if(documentType == kFileTypePICT)
  {
    if(osError = doReadPictFile(windowRef))
      return osError;
  }

  // ............................................. set up window's proxy icon, and show window

  SetWindowProxyFSSpec(windowRef,&fileSpec);                                             /////
  GetWindowProxyAlias(windowRef,&((*docStrucHdl)->aliasHdl));                            /////
  SetWindowModified(windowRef,false);                                                    /////

  ShowWindow(windowRef);

  return noErr;
}

// ************************************************************** doCreateAskSaveChangesDialog

OSErr  doCreateAskSaveChangesDialog(WindowRef windowRef,docStructureHandle docStrucHdl,
                                    NavAskSaveChangesAction action)
{
  OSErr                    osError = noErr;
  NavDialogCreationOptions dialogOptions;
  Str255                   windowTitle, applicationName;

  // ......................................... create window-modal Save Changes Changes dialog
  
  osError = NavGetDefaultDialogCreationOptions(&dialogOptions);
  if(osError == noErr)
  {
    GetWTitle(windowRef,windowTitle);
    dialogOptions.saveFileName = CFStringCreateWithPascalString(NULL,windowTitle,
                                                                CFStringGetSystemEncoding());

    GetIndString(applicationName,rMiscStrings,sApplicationName);
    dialogOptions.clientName = CFStringCreateWithPascalString(NULL,applicationName,
                                                              CFStringGetSystemEncoding());
    dialogOptions.parentWindow = windowRef;
    dialogOptions.modality = kWindowModalityWindowModal;

    if((*docStrucHdl)->askSaveDiscardEventFunctionUPP != NULL)
    {
      DisposeNavEventUPP((*docStrucHdl)->askSaveDiscardEventFunctionUPP);
      (*docStrucHdl)->askSaveDiscardEventFunctionUPP = NULL;
    }
    (*docStrucHdl)->askSaveDiscardEventFunctionUPP = 
                                NewNavEventUPP((NavEventProcPtr) askSaveDiscardEventFunction);

    HLock((Handle) docStrucHdl);

    osError = NavCreateAskSaveChangesDialog(&dialogOptions,action,
                                            (*docStrucHdl)->askSaveDiscardEventFunctionUPP,
                                            windowRef,
                                            &(*docStrucHdl)->modalToWindowNavDialogRef);
    HUnlock((Handle) docStrucHdl);

    if(osError == noErr && (*docStrucHdl)->modalToWindowNavDialogRef != NULL)
    {
      (*docStrucHdl)->isAskSaveChangesDialog = true;

      osError = NavDialogRun((*docStrucHdl)->modalToWindowNavDialogRef);
      if(osError != noErr)
      {
        NavDialogDispose((*docStrucHdl)->modalToWindowNavDialogRef);
        (*docStrucHdl)->modalToWindowNavDialogRef = NULL;
        (*docStrucHdl)->isAskSaveChangesDialog = false;
      }

      if(!gRunningOnX)
      {
        if(gCloseDocWindow)
        {
          osError = doCloseDocWindow(windowRef);
          if(osError != noErr)
            doErrorAlert(osError);
          gCloseDocWindow = false;    
        }
      }
    }

    if(dialogOptions.saveFileName != NULL)
      CFRelease(dialogOptions.saveFileName);
    if(dialogOptions.clientName != NULL)
      CFRelease(dialogOptions.clientName);
  }

  return osError;
}

// ************************************************************************* doSaveUsingFSSpec

OSErr  doSaveUsingFSSpec(WindowRef windowRef,NavReplyRecord *navReplyStruc)
{
  OSErr              osError = noErr;
  AEKeyword          theKeyword;
  DescType           actualType;
  FSSpec             fileSpec;
  Size               actualSize;
  docStructureHandle docStrucHdl;
  OSType             fileType;
  CFStringRef        fileName;
  SInt16             fileRefNum;
  Rect               portRect;

  if((*navReplyStruc).validRecord)
  {
    // ............................................................................ get FSSpec

    if((osError = AEGetNthPtr(&(*navReplyStruc).selection,1,typeFSS,&theKeyword,
                                &actualType,&fileSpec,sizeof(fileSpec),&actualSize)) == noErr)
    {
      docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);

      // ............. get file name, convert to Pascal string, assign to name field of FSSpec

      fileName = NavDialogGetSaveFileName((*docStrucHdl)->modalToWindowNavDialogRef);
      if(fileName != NULL)
        osError = CFStringGetPascalString(fileName,&fileSpec.name[0],sizeof(FSSpec),
                                          CFStringGetSystemEncoding());

      // ........................................... if not replacing, first create a new file

      if(!((*navReplyStruc).replacing))
      {
        if((*docStrucHdl)->editStrucHdl != NULL)
          fileType = kFileTypeTEXT;
        else if((*docStrucHdl)->pictureHdl != NULL)
          fileType = kFileTypePICT;

        osError = FSpCreate(&fileSpec,kFileCreator,fileType,(*navReplyStruc).keyScript);
        if(osError != noErr)
        {
          NavDisposeReply(&(*navReplyStruc));
          return osError;
        }
      }

      // .................... assign FSSpec to fileFSSpec field of window's document structure

      (*docStrucHdl)->fileFSSpec = fileSpec;

      // ..................................... if file currently exists for document, close it

      if((*docStrucHdl)->fileRefNum != 0)
      {
        osError = FSClose((*docStrucHdl)->fileRefNum);
        (*docStrucHdl)->fileRefNum = 0;
      }

      // ................................................ open file's data fork and write file
      
      if(osError == noErr)
        osError = FSpOpenDF(&(*docStrucHdl)->fileFSSpec,fsRdWrPerm,&fileRefNum);

      if(osError == noErr)
      {
        (*docStrucHdl)->fileRefNum = fileRefNum;
        SetWTitle(windowRef,fileSpec.name);

        // . . . . . . . . . . . . . . . . . . . . . proxy icon and file synchronisation stuff

        SetPortWindowPort(windowRef);                                                    /////
        SetWindowProxyFSSpec(windowRef,&fileSpec);                                       /////
        GetWindowProxyAlias(windowRef,&((*docStrucHdl)->aliasHdl));                      /////
        SetWindowModified(windowRef,false);                                              /////

        // . . . . . . . . . . . . . . . . . . . . . . . . . . . .  write file using safe save
        
        osError = doWriteFile(windowRef);

        NavCompleteSave(&(*navReplyStruc),kNavTranslateInPlace);
      }
    }
  }

  SetPortWindowPort(windowRef);
  GetWindowPortBounds(windowRef,&portRect);
  EraseRect(&portRect);
  InvalWindowRect(windowRef,&portRect);

  return osError;
}

// ************************************************************************** doSaveUsingFSRef

OSErr  doSaveUsingFSRef(WindowRef windowRef,NavReplyRecord *navReplyStruc)
{
  OSErr              osError = noErr;
  AEDesc             aeDesc;
  Size               dataSize;
  FSRef              fsRefParent, fsRefDelete;  
  UniCharCount       nameLength;
  UniChar            *nameBuffer;
  FSSpec             fileSpec;
  docStructureHandle docStrucHdl;
  FInfo              fileInfo;
  SInt16             fileRefNum;
  Rect               portRect;

  osError = AECoerceDesc(&(*navReplyStruc).selection,typeFSRef,&aeDesc);
  if(osError == noErr)
  {
    // ............................................................................. get FSRef

    dataSize = AEGetDescDataSize(&aeDesc);
    if(dataSize > 0)
      osError = AEGetDescData(&aeDesc,&fsRefParent,sizeof(FSRef));
    if(osError == noErr)
    {
      // ............................. get file name from saveFileName field of NavReplyRecord

      nameLength = (UniCharCount) CFStringGetLength((*navReplyStruc).saveFileName);
      nameBuffer = (UniChar *) NewPtr(nameLength);
      CFStringGetCharacters((*navReplyStruc).saveFileName,CFRangeMake(0,nameLength),
                            &nameBuffer[0]);
      if(nameBuffer != NULL)
      {
        // ...................................... if replacing, delete the file being replaced

        if((*navReplyStruc).replacing)
        {
          osError = FSMakeFSRefUnicode(&fsRefParent,nameLength,nameBuffer,
                                       kTextEncodingUnicodeDefault,&fsRefDelete);
          {
            if(osError == noErr)
              osError = FSDeleteObject(&fsRefDelete);
            if(osError == fBsyErr)
            {
              DisposePtr((Ptr) nameBuffer);
              return osError;
            }
          }
        }

        // .............. create file with Unicode name (but it can be written with an FSSpec)

        if(osError == noErr)
        {
          osError = FSCreateFileUnicode(&fsRefParent,nameLength,nameBuffer,kFSCatInfoNone,
                                        NULL,NULL,&fileSpec);
          if(osError == noErr)
          {
            docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);

            osError = FSpGetFInfo(&fileSpec,&fileInfo);

            if((*docStrucHdl)->editStrucHdl != NULL)
              fileInfo.fdType = kFileTypeTEXT;
            else if((*docStrucHdl)->pictureHdl != NULL)
              fileInfo.fdType = kFileTypePICT;
            fileInfo.fdCreator = kFileCreator;

            if(osError == noErr)
              osError = FSpSetFInfo(&fileSpec,&fileInfo);

            (*docStrucHdl)->fileFSSpec = fileSpec;

            // .......................................... open file's data fork and write file

            if(osError == noErr)
              osError = FSpOpenDF(&fileSpec,fsRdWrPerm,&fileRefNum);

            if(osError == noErr)
            {
              (*docStrucHdl)->fileRefNum = fileRefNum;
              SetWTitle(windowRef,fileSpec.name);

              // . . . . . . . . . . . . . . . . . . proxy icon and file synchronisation stuff

              SetPortWindowPort(windowRef);                                              /////
              SetWindowProxyFSSpec(windowRef,&fileSpec);                                 /////
              GetWindowProxyAlias(windowRef,&((*docStrucHdl)->aliasHdl));                /////
              SetWindowModified(windowRef,false);                                        /////

              // . . . . . . . . . . . . . . . . . . . . . . . . .  write file using safe save

              osError = doWriteFile(windowRef);

              NavCompleteSave(&(*navReplyStruc),kNavTranslateInPlace);
            }
          }
        }
      }
    
      DisposePtr((Ptr) nameBuffer);
    }

    AEDisposeDesc(&aeDesc);
  }
  
  SetPortWindowPort(windowRef);
  GetWindowPortBounds(windowRef,&portRect);
  EraseRect(&portRect);
  InvalWindowRect(windowRef,&portRect);

  return osError;
}

// ******************************************************************************* doWriteFile

OSErr  doWriteFile(WindowRef windowRef)
{
  docStructureHandle docStrucHdl;
  FSSpec             fileSpecActual, fileSpecTemp;
  UInt32             currentTime;
  Str255             tempFileName;
  SInt16             tempFileVolNum, tempFileRefNum;
  SInt32             tempFileDirID;
  OSErr              osError = noErr;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
  fileSpecActual = (*docStrucHdl)->fileFSSpec;

  GetDateTime(¤tTime);
  NumToString((SInt32) currentTime,tempFileName);
  
  osError = FindFolder(fileSpecActual.vRefNum,kTemporaryFolderType,kCreateFolder,
                        &tempFileVolNum,&tempFileDirID);
  if(osError == noErr)
    osError = FSMakeFSSpec(tempFileVolNum,tempFileDirID,tempFileName,&fileSpecTemp);
  if(osError == noErr || osError == fnfErr)
    osError = FSpCreate(&fileSpecTemp,'trsh','trsh',smSystemScript);
  if(osError == noErr)
    osError = FSpOpenDF(&fileSpecTemp,fsRdWrPerm,&tempFileRefNum);
  if(osError == noErr)
  {
    if((*docStrucHdl)->editStrucHdl)
      osError = doWriteTextData(windowRef,tempFileRefNum);
    else if((*docStrucHdl)->pictureHdl)
      osError = doWritePictData(windowRef,tempFileRefNum);
  }  
  if(osError == noErr)
    osError = FSClose(tempFileRefNum);
  if(osError == noErr)
    osError = FSClose((*docStrucHdl)->fileRefNum);
  if(osError == noErr)
    osError = FSpExchangeFiles(&fileSpecTemp,&fileSpecActual);
  if(osError == noErr)
    osError = FSpDelete(&fileSpecTemp);
  if(osError == noErr)
    osError = FSpOpenDF(&fileSpecActual,fsRdWrPerm,&(*docStrucHdl)->fileRefNum);

  if(osError == noErr)
    osError = doCopyResources(windowRef);

  return osError;
}

// **************************************************************************** doReadTextFile

OSErr  doReadTextFile(WindowRef windowRef)
{
  docStructureHandle docStrucHdl;
  SInt16             fileRefNum;
  TEHandle           textEditHdl;
  SInt32             numberOfBytes;
  Handle             textBuffer;
  OSErr              osError = noErr;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
  fileRefNum = (*docStrucHdl)->fileRefNum;

  textEditHdl = (*docStrucHdl)->editStrucHdl;
  (*textEditHdl)->txSize = 10;
  (*textEditHdl)->lineHeight = 15;

  SetFPos(fileRefNum,fsFromStart,0);
  GetEOF(fileRefNum,&numberOfBytes);

  if(numberOfBytes > 32767)
    numberOfBytes = 32767;

  if(!(textBuffer = NewHandle((Size) numberOfBytes)))
    return MemError();

  osError = FSRead(fileRefNum,&numberOfBytes,*textBuffer);
  if(osError == noErr || osError == eofErr)
  {
    HLockHi(textBuffer);
    TESetText(*textBuffer,numberOfBytes,(*docStrucHdl)->editStrucHdl);
    HUnlock(textBuffer);
    DisposeHandle(textBuffer);
  }
  else
    return osError;

  return noErr;
}

// **************************************************************************** doReadPictFile

OSErr  doReadPictFile(WindowRef windowRef)
{
  docStructureHandle docStrucHdl;
  SInt16             fileRefNum;
  SInt32             numberOfBytes;
  OSErr              osError = noErr;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
  fileRefNum = (*docStrucHdl)->fileRefNum;

  GetEOF(fileRefNum,&numberOfBytes);
  SetFPos(fileRefNum,fsFromStart,512);
  numberOfBytes -= 512;

  if(!((*docStrucHdl)->pictureHdl = (PicHandle) NewHandle(numberOfBytes)))
    return MemError();

  osError = FSRead(fileRefNum,&numberOfBytes,*(*docStrucHdl)->pictureHdl);
  if(osError == noErr || osError == eofErr)
    return(noErr);
  else
    return osError;
}

// *************************************************************************** doWriteTextData

OSErr  doWriteTextData(WindowRef windowRef,SInt16 tempFileRefNum)
{
  docStructureHandle docStrucHdl;
  TEHandle           textEditHdl;
  Handle             editText;
  SInt32             numberOfBytes;
  SInt16             volRefNum;
  OSErr              osError = noErr;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
  textEditHdl = (*docStrucHdl)->editStrucHdl;
  editText = (*textEditHdl)->hText;
  numberOfBytes = (*textEditHdl)->teLength;

  osError = SetFPos(tempFileRefNum,fsFromStart,0);
  if(osError == noErr)
    osError = FSWrite(tempFileRefNum,&numberOfBytes,*editText);
  if(osError == noErr)
    osError = SetEOF(tempFileRefNum,numberOfBytes);
  if(osError == noErr)
    osError = GetVRefNum(tempFileRefNum,&volRefNum);
  if(osError == noErr)
    osError = FlushVol(NULL,volRefNum);

  if(osError == noErr)
    (*docStrucHdl)->windowTouched = false;

  return osError;
}

// *************************************************************************** doWritePictData

OSErr  doWritePictData(WindowRef windowRef,SInt16 tempFileRefNum)
{
  docStructureHandle docStrucHdl;
  PicHandle          pictureHdl;
  SInt32             numberOfBytes, dummyData;
  SInt16             volRefNum;
  OSErr              osError = noErr;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
  pictureHdl = (*docStrucHdl)->pictureHdl;

  numberOfBytes = 512;
  dummyData = 0;

  osError = SetFPos(tempFileRefNum,fsFromStart,0);

  if(osError == noErr)
    osError = FSWrite(tempFileRefNum,&numberOfBytes,&dummyData);

  numberOfBytes = GetHandleSize((Handle) (*docStrucHdl)->pictureHdl);

  if(osError == noErr)
  {
    HLock((Handle) (*docStrucHdl)->pictureHdl);
    osError = FSWrite(tempFileRefNum,&numberOfBytes,*(*docStrucHdl)->pictureHdl);
    HUnlock((Handle) (*docStrucHdl)->pictureHdl);
  }

  if(osError == noErr)
    osError = SetEOF(tempFileRefNum,512 + numberOfBytes);
  if(osError == noErr)
    osError = GetVRefNum(tempFileRefNum,&volRefNum);
  if(osError == noErr)
    osError = FlushVol(NULL,volRefNum);

  if(osError == noErr)
    (*docStrucHdl)->windowTouched = false;

  return osError;
}

// *************************************************************** getFilePutFileEventFunction

void  getFilePutFileEventFunction(NavEventCallbackMessage callBackSelector,
                                  NavCBRecPtr callBackParms,NavCallBackUserData callBackUD)
{
  OSErr              osError = noErr;
  NavReplyRecord     navReplyStruc;
  NavUserAction      navUserAction;
  SInt32             count, index;
  AEKeyword          theKeyword;
  DescType           actualType;
  FSSpec             fileSpec;
  Size               actualSize;
  FInfo              fileInfo;
  OSType             documentType;
  WindowRef          windowRef;
  AEDesc             aeDesc;
  AEKeyword          keyWord;
  DescType           typeCode;
  Rect               theRect;
  Str255             theString, numberString;
  docStructureHandle docStrucHdl;

  switch(callBackSelector)
  {
    case kNavCBUserAction:
      osError = NavDialogGetReply(callBackParms->context,&navReplyStruc);
      if(osError == noErr && navReplyStruc.validRecord)
      {
        navUserAction = NavDialogGetUserAction(callBackParms->context);

        switch(navUserAction)
        {
          // ............................................. click on Open button in Open dialog

          case kNavUserActionOpen:
            if(gModalToApplicationNavDialogRef != NULL)
            {
              osError = AECountItems(&(navReplyStruc.selection),&count);
              if(osError == noErr)
              {
                for(index=1;index<=count;index++)
                {
                  osError = AEGetNthPtr(&(navReplyStruc.selection),index,typeFSS,
                                        &theKeyword,&actualType,&fileSpec,sizeof(fileSpec),
                                        &actualSize);
                  if((osError = FSpGetFInfo(&fileSpec,&fileInfo)) == noErr)
                  {
                    documentType = fileInfo.fdType;
                    osError = doOpenFile(fileSpec,documentType);
                    if(osError != noErr)
                      doErrorAlert(osError);
                  }
                }
              }
            }
            break;

          // .................................... click on Save button in Save Location dialog

          case kNavUserActionSaveAs:
            windowRef = callBackUD;
            osError = AECoerceDesc(&navReplyStruc.selection,typeFSRef,&aeDesc);
            if(osError == noErr)
            {
              osError = doSaveUsingFSRef(windowRef,&navReplyStruc);
              if(osError != noErr)
                doErrorAlert(osError);
              AEDisposeDesc(&aeDesc);
            }
            else
            {
              osError = doSaveUsingFSSpec(windowRef,&navReplyStruc);
              if(osError != noErr)
                doErrorAlert(osError);
            }
            break;

          // ................................ click on Choose button in Choose a Folder dialog

          case kNavUserActionChoose:
            if((osError = AEGetNthPtr(&(navReplyStruc.selection),1,typeFSS,&keyWord,&typeCode,
                                      &fileSpec,sizeof(FSSpec),&actualSize)) == noErr)
            {
              FSMakeFSSpec(fileSpec.vRefNum,fileSpec.parID,fileSpec.name,&fileSpec);
            }
            windowRef = callBackUD;
            SetPortWindowPort(windowRef);
            TextSize(10);
            SetRect(&theRect,0,271,600,300);
            EraseRect(&theRect);
            doCopyPString(fileSpec.name,theString);
            doConcatPStrings(theString, "\p   Volume Reference Number: ");
            NumToString((SInt32) fileSpec.vRefNum,numberString);
            doConcatPStrings(theString,numberString);
            doConcatPStrings(theString, "\p   Parent Directory ID: ");
            NumToString((SInt32) fileSpec.parID,numberString);
            doConcatPStrings(theString,numberString);
            MoveTo(10,290);
            DrawString(theString);
            break;
        }

        osError = NavDisposeReply(&navReplyStruc);
      }
      break;

    case kNavCBTerminate:
      if(gModalToApplicationNavDialogRef != NULL)
      {
        NavDialogDispose(gModalToApplicationNavDialogRef);
        gModalToApplicationNavDialogRef = NULL;
      }
      else
      {
        windowRef = callBackUD;
        docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
        if((*docStrucHdl)->modalToWindowNavDialogRef != NULL)
        {
          NavDialogDispose((*docStrucHdl)->modalToWindowNavDialogRef);
          (*docStrucHdl)->modalToWindowNavDialogRef = NULL;
        }
      }
      break;
  }
}

// *************************************************************** askSaveDiscardEventFunction

void askSaveDiscardEventFunction(NavEventCallbackMessage callBackSelector,
                                 NavCBRecPtr callBackParms,NavCallBackUserData callBackUD)
{
  WindowRef          windowRef;
  docStructureHandle docStrucHdl;
  NavUserAction      navUserAction;
  OSErr              osError = noErr;
  Rect               portRect;

  switch(callBackSelector)
  {
    case kNavCBUserAction:
      windowRef = callBackUD;
      docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);

      if((*docStrucHdl)->modalToWindowNavDialogRef != NULL)
      {
        navUserAction = NavDialogGetUserAction(callBackParms->context);
        switch(navUserAction)
        {
          // ...................................... click on Save button in Save Changes alert

          case kNavUserActionSaveChanges:
            osError = doSaveCommand();
            if(osError != noErr)
              doErrorAlert(osError);

          // ................................ click on Don't Save button in Save Changes alert

          case kNavUserActionDontSaveChanges:
            NavDialogDispose((*docStrucHdl)->modalToWindowNavDialogRef);
            if(gRunningOnX)
            {
              osError = doCloseDocWindow(windowRef);
              if(osError != noErr)
                doErrorAlert(osError);
            }
            else
              gCloseDocWindow = true;
            break;

          // ..................................... click on OK button in Discard Changes alert

          case kNavUserActionDiscardChanges:
            GetWindowPortBounds(windowRef,&portRect);
            SetPortWindowPort(windowRef);
            EraseRect(&portRect);

            if((*docStrucHdl)->editStrucHdl != NULL && (*docStrucHdl)->fileRefNum != 0)
            {
              osError = doReadTextFile(windowRef);
              if(osError != noErr)
                doErrorAlert(osError);
            }
            else if((*docStrucHdl)->pictureHdl != NULL)
            {
              KillPicture((*docStrucHdl)->pictureHdl);
              (*docStrucHdl)->pictureHdl = NULL;

              osError = doReadPictFile(windowRef);
              if(osError != noErr)
                doErrorAlert(osError);
            }

            (*docStrucHdl)->windowTouched = false;
            SetWindowModified(windowRef,false);                                          /////
            InvalWindowRect(windowRef,&portRect);

            NavDialogDispose((*docStrucHdl)->modalToWindowNavDialogRef);
            (*docStrucHdl)->modalToWindowNavDialogRef = NULL;
            break;

          // ................. click on Cancel button in Save Changes or Discard Changes alert

          case kNavUserActionCancel:
            if((*docStrucHdl)->isAskSaveChangesDialog == true)
            {
              gQuittingApplication = false;
              (*docStrucHdl)->isAskSaveChangesDialog = false;
            }
            NavDialogDispose((*docStrucHdl)->modalToWindowNavDialogRef);
            (*docStrucHdl)->modalToWindowNavDialogRef = NULL;
            break;
        }
      }
      break;
  }
}

// *************************************************************************** doCopyResources

OSErr  doCopyResources(WindowRef windowRef)
{
  docStructureHandle docStrucHdl;
  OSType             fileType;
  OSErr              osError = noErr;
  SInt16             fileRefNum;
  Handle             editTextHdl, textResourceHdl;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);

  if((*docStrucHdl)->editStrucHdl)
    fileType = kFileTypeTEXT;
  else if((*docStrucHdl)->pictureHdl)
    fileType = kFileTypePICT;

  FSpCreateResFile(&(*docStrucHdl)->fileFSSpec,kFileCreator,fileType,smSystemScript);

  osError = ResError();
  if(osError == noErr)
    fileRefNum = FSpOpenResFile(&(*docStrucHdl)->fileFSSpec,fsRdWrPerm);

  if(fileRefNum > 0)
  {
    osError = doCopyAResource('STR ',-16396,gAppResFileRefNum,fileRefNum);

    if(fileType == kFileTypePICT)
    {
      doCopyAResource('pnot',128,gAppResFileRefNum,fileRefNum);
      doCopyAResource('PICT',128,gAppResFileRefNum,fileRefNum);
    }

    if(!gRunningOnX && fileType == kFileTypeTEXT)
    {
      doCopyAResource('pnot',129,gAppResFileRefNum,fileRefNum);
      
      editTextHdl = (*(*docStrucHdl)->editStrucHdl)->hText;
      textResourceHdl = NewHandleClear(1024);
      BlockMoveData(*editTextHdl,*textResourceHdl,1024);      
      UseResFile(fileRefNum);
      AddResource(textResourceHdl,'TEXT',129,"\p");
      if(ResError() == noErr)
        UpdateResFile(fileRefNum);
      ReleaseResource(textResourceHdl);
    }
  }
  else
    osError = ResError();

  if(osError == noErr)
    CloseResFile(fileRefNum); 

  osError = ResError();
  return osError;
}

// *************************************************************************** doCopyAResource

OSErr  doCopyAResource(ResType resourceType,SInt16 resourceID,SInt16 sourceFileRefNum,
                      SInt16 destFileRefNum)
{
  Handle  sourceResourceHdl;
  Str255  sourceResourceName;
  ResType ignoredType;
  SInt16  ignoredID;

  UseResFile(sourceFileRefNum);

  sourceResourceHdl = GetResource(resourceType,resourceID);

  if(sourceResourceHdl != NULL)
  {
    GetResInfo(sourceResourceHdl,&ignoredID,&ignoredType,sourceResourceName);
    DetachResource(sourceResourceHdl);
    UseResFile(destFileRefNum);
    AddResource(sourceResourceHdl,resourceType,resourceID,sourceResourceName);
    if(ResError() == noErr)
      UpdateResFile(destFileRefNum);
  }

  ReleaseResource(sourceResourceHdl);

  return ResError();
}

// *******************************************************************************************
// SynchroniseFiles.c
// *******************************************************************************************

// .................................................................................. includes

#include "Files.h"

// .......................................................................... global variables

extern SInt16  gCurrentNumberOfWindows;

// ************************************************************************ doSynchroniseFiles

void  doSynchroniseFiles(void)
{
  WindowRef          windowRef;
  SInt16             trashVRefNum;
  SInt32             trashDirID;
  docStructureHandle docStrucHdl;
  Boolean            aliasChanged;
  AliasHandle        aliasHdl;
  FSSpec             newFSSpec;
  OSErr              osError;

  windowRef = FrontNonFloatingWindow();

  while(windowRef != NULL)
  {
    docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);

    if(docStrucHdl != NULL)
    {
      if((*docStrucHdl)->aliasHdl == NULL)
        break;

      aliasChanged = false;
      aliasHdl = (*docStrucHdl)->aliasHdl;
      ResolveAlias(NULL,aliasHdl,&newFSSpec,&aliasChanged);

      if(aliasChanged)
      {
        (*docStrucHdl)->fileFSSpec = newFSSpec;
        SetWTitle(windowRef,newFSSpec.name);
      }

      osError = FindFolder(kUserDomain,kTrashFolderType,kDontCreateFolder,&trashVRefNum,
                           &trashDirID);

      if(osError == noErr)
      {
        do
        {
          if(newFSSpec.parID == fsRtParID)
            break;

          if((newFSSpec.vRefNum == trashVRefNum) && (newFSSpec.parID == trashDirID))
          {
            FSClose((*docStrucHdl)->fileRefNum);
            if((*docStrucHdl)->editStrucHdl)
              TEDispose((*docStrucHdl)->editStrucHdl);
            if((*docStrucHdl)->pictureHdl)
              KillPicture((*docStrucHdl)->pictureHdl);
            DisposeHandle((Handle) docStrucHdl);
            DisposeWindow(windowRef);
            gCurrentNumberOfWindows --;
            break;
          }
        } while(FSMakeFSSpec(newFSSpec.vRefNum,newFSSpec.parID,"\p",&newFSSpec) == noErr);
      }
    }

    windowRef = GetNextWindow(windowRef);
  }
}

// *******************************************************************************************
// ChooseAFolderDialog.c
// *******************************************************************************************

// .................................................................................. includes

#include "Files.h"

// .......................................................................... global variables

extern NavEventUPP  gGetFilePutFileEventFunctionUPP ;
extern NavDialogRef gModalToApplicationNavDialogRef;

// ********************************************************************* doChooseAFolderDialog

OSErr  doChooseAFolderDialog(void)
{
  OSErr                    osError = noErr;
  NavDialogCreationOptions dialogOptions;
  WindowRef                windowRef, parentWindowRef;
  Str255                   message;

  osError = NavGetDefaultDialogCreationOptions(&dialogOptions);
  if(osError == noErr)
  {
    if((osError = GetSheetWindowParent(FrontWindow(),&parentWindowRef)) == noErr)
      windowRef = parentWindowRef;
    else
      windowRef = FrontWindow();

    GetIndString(message,rMiscStrings,sChooseAFolder);
    dialogOptions.message = CFStringCreateWithPascalString(NULL,message,
                                                           CFStringGetSystemEncoding());
    dialogOptions.modality = kWindowModalityAppModal;

    osError = NavCreateChooseFolderDialog(&dialogOptions,gGetFilePutFileEventFunctionUPP ,
                                          NULL,windowRef,&gModalToApplicationNavDialogRef);

    if(osError == noErr && gModalToApplicationNavDialogRef != NULL)
    {
      osError = NavDialogRun(gModalToApplicationNavDialogRef);
      if(osError != noErr)
      {
        NavDialogDispose(gModalToApplicationNavDialogRef);
        gModalToApplicationNavDialogRef = NULL;
      }
    }
  }

  return osError;
}

// *******************************************************************************************

Demonstration Program Files Comments

When the program is run, the user should:

o Exercise the File menu by opening the supplied TEXT and PICT files, saving those files,
  saving those files under new names, closing files, opening the new files, attempting to open
  files that are already open, attempting to save files to new files with existing names, 
  making open windows "touched" by choosing the first item in the Demonstration menu, reverting
  to the saved versions of files associated with "touched" windows, choosing Quit when one 
  "touched" window is open, choosing Quit when two or more "touched" windows are open, and so
  on.

o Choose, via the Show pop-up menu button, the file types required to be displayed in the Open
  dialog.

o Choose the Choose a Folder item from the Demonstration menu to display the Choose a Folder
  dialog, and choose a folder using the Choose button at the bottom of the dialog.  (The name 
  of the chosen folder will be drawn in the bottom-left corner of the front window.)

o With either the PICT Document or the TEXT Document open:

  o With the document's Finder icon visible, drag the window proxy icon to the desktop or to
    another open folder, noting that the Finder icon moves to the latter.  Then choose Touch
    Window from the Demonstration menu to simulate unsaved changes to the document.  Note that
    the proxy icon changes to the disabled state.  Then save the file, proving the correct 
    operation of the file synchronisation function.  Note that, after the save, the window 
    proxy icon changes back to the enabled state.

  o Command-click the window's title to display the window path pop-up menu, choose a folder 
    from the menu, and note that the Finder is brought to the foreground and the chosen folder 
    opens.

The program may be run from within CodeWarrior to demonstrate responses to the File menu
commands and the Choose a Folder dialog.

The built application, together with the supplied 'TEXT' and 'PICT' files, may be used to
demonstrate the additional aspect of integrating the receipt of required Apple events with the
overall file handling mechanism.  To prove the correct handling of the required Apple events,
the user should:

o Open the application by double-clicking the application icon, noting that a new document
  window is opened after the application is launched and the Open Application event is 
  received.

o Double click on a document icon, or select one or more document icons and either drag those
  icons to the application icon or choose Open from the Finder's File menu, noting that the
  application is launched and the selected files are opened when the Open Documents event is
  received.

o Close all windows and double-click the application icon, noting that the application responds
  to the Re-open Application event by opening a new window.

o With the PICT Document and the TEXT Document open and "touched", and several other windows
  open, choose Restart or Shut Down from the Mac OS 8/9 Finder's Special menu or the Mac OS X
  Apple menu (thus invoking a Quit Application event), noting that, for "touched" windows, the
  Save Changes alert is presented asking the user whether the file should be saved before the
  shutdown process proceeds.  (On Mac OS X, a Review Unsaved alert will be presented at first.)

Note, however, that no printing functions are included.  Thus, selecting one or more document
icons and choosing Print from the Finder's File menu (Mac OS 8/9) will result in the file/s
opening but not printing.

Files.h

defines

Constants are established for a 'STR#' resource containing error strings for three specific
error conditions, a 'STR#' resource containing the application's name and the message string
for the Choose a Folder dialog, and the 'open' resource containing the file types list.  

KFileCreator represents the application's signature and the next two constants represent the
file types that are readable and writeable by the application.

typedefs

Each window created by the program will have an associated document structure.  The
docStructure data type will be used for document structures.

The editStrucHdl field will be assigned a handle to a TextEdit structure ('TEXT' files).  The
pictureHdl field will be assigned a handle to a Picture structure ('PICT' files).  The
fileRefNum and fileFSSpec fields will be assigned the file reference number and the file system
specification structure of the file associated with the window.  When a file is opened, the
aliasHdl field will be assigned a handle to a structure of type AliasRecord, which contains the
alias data for the file.  The windowTouched field will be set to true when a window has been
made "touched".

When modal-to-the-window Navigation Services dialogs (Save Location, Save Changes, and Discard
Changes alerts) are created, the dialog reference will be assigned to the
modalToWindowNavDialogRef field.  When Save Changes and Discard Changes alerts are created, a
universal procedure pointer to the associated event (callback) function will be assigned to the
askSaveDiscardChangesDialog field.  When a Save Changes alert is created, the
isAskSaveChangesDialog field will be set to true to enable the associated event (callback)
function to re-set a "quitting application" flag if the user clicks the Cancel button in a Save
Changes alert (but not if the user clicks the Cancel button in a Discard Changes alert).

Files.c

Global Variables

gAppResFileRefNum will be assigned the file reference number of the application's resource
fork.  gGetFilePutFileEventFunctionUPP will be assigned a universal procedure pointer to the
event (callback) function associated with the Open, Save Location, and Choose a Folder dialogs.
gQuittingApplication is set to true in certain circumstances within quitAppEventHandler and to
false if the Cancel button is clicked in a Save Changes or Review Unsaved alert.

main

The file reference number of the application's resource fork (which is opened automatically at
application launch) is assigned to the global variable gAppResFileRefNum.

After the required Apple event handlers are installed, the program's applicat