Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Sources/MSFile.c
// MSFile.c |
// |
// Original version by Jon Lansdell and Nigel Humphreys. |
// 4.0 and 3.1 updates by Greg Sutton. |
// ©Apple Computer Inc 1996, all rights reserved. |
/* |
Changes for 4.0 |
28-Feb-96 : GS : Added script to document file. This script is attached to the document |
and gets first go at handling Apple events targetted at the document. |
*/ |
#include <Errors.h> |
#include <Resources.h> |
#include <Desk.h> |
#ifdef THINK_C |
#include "PLStrs.h" |
#else |
#include <PLStringFuncs.h> |
#endif |
#include <AppleEvents.h> |
#include <AERegistry.h> |
#include <StandardFile.h> |
#include "MSFile.h" |
#include "Offscreen.h" |
#include "MSResultWind.h" |
#include "MSAEWindowUtils.h" |
#include "MSScript.h" |
#include "MSAESetData.h" |
#include <LowMem.h> |
// Constants |
const OSType kStyleInfoType = 'TFSF'; |
const OSType kHeaderInfoType = 'TFSS'; |
const OSType kGXPrinterInfoType = 'TFGX'; |
// Name: FileError |
// Purpose: Puts up an error alert. |
#pragma segment File |
void FileError( Str255 s, Str255 f ) |
{ |
short alertResult; |
SetCursor(&qd.arrow); |
ParamText(s, f, (unsigned char *)"", (unsigned char *)""); |
alertResult = Alert( ErrorAlert, NULL ); |
} |
// Name: DoClose |
// Purpose: Closes a window. |
#pragma segment File |
OSErr DoClose( WindowPtr aWindow,Boolean canInteract,DescType dialogAnswer ) |
{ |
DPtr aDocument; |
short alertResult; |
OSErr myErr; |
myErr = noErr; |
aDocument = DPtrFromWindowPtr(aWindow); |
if ( ! aDocument ) |
return noErr; |
// Save if the windows contents have changed and it's not the results window |
if ((aDocument->dirty) && !IsThisResultWind(aWindow)) |
{ |
if (canInteract && (dialogAnswer==kAEAsk)) |
{ |
alertResult = DoFileDialog ( kSaveDontsaveDialog, aWindow ); |
switch ( alertResult ) |
{ |
case kStdOkItemIndex: |
if (aDocument->everSaved == false) |
{ |
myErr = GetFileNameToSaveAs(aDocument); |
if (myErr == noErr) |
myErr = DoSave(aDocument, aDocument->theFSSpec); |
} |
else |
myErr = SaveUsingTemp(aDocument); |
break; |
case kStdCancelItemIndex: |
return(userCanceledErr); |
break; |
case kDontSaveItemIndex: |
aDocument->dirty = false; |
break; |
} |
} |
else |
{ |
if (dialogAnswer==kAEYes) |
if (aDocument->everSaved == false) |
{ |
if (canInteract) |
{ |
myErr = GetFileNameToSaveAs(aDocument); |
if (myErr==noErr) |
myErr = DoSave(aDocument, aDocument->theFSSpec); |
} |
else |
return(errAENoUserInteraction); |
} |
else |
myErr = SaveUsingTemp(aDocument); |
else |
myErr = noErr; // Don't save |
} |
} |
if ( myErr == noErr ) |
CloseMyWindow(aWindow); |
return(myErr); |
} |
// This is called to display the "save before closing" and "revert" dialogs. |
short DoFileDialog( short theDlogID, WindowRef theWindow ) |
{ |
short theItem; |
DialogRef theDialog; |
WindowRef dialogWindow; |
DPtr theDocument; |
Str255 theTitle, theReason; |
theDocument = DPtrFromWindowPtr ( theWindow ); |
theDialog = GetNewDialog ( theDlogID, nil, (WindowRef) -1 ); |
dialogWindow = GetDialogWindow ( theDialog ); |
SetPortWindowPort ( dialogWindow ); |
if ( theDocument->everSaved == false ) |
GetWTitle ( theWindow, theTitle ); // Pick it up as a script may have changed it |
else |
PLstrcpy ( theTitle, theDocument->theFileName ); |
if ( gQuitting ) |
GetIndString ( theReason, kMiscStrings, kQuittingIndex ); |
else |
GetIndString ( theReason, kMiscStrings, kClosingindex ); |
SetCursor ( &qd.arrow ); |
ParamText ( theTitle, theReason, nil, nil ); |
ShowMSWindow ( dialogWindow ); |
SelectWindow ( dialogWindow ); |
SetDialogDefaultItem ( theDialog, kStdOkItemIndex ); |
SetDialogCancelItem ( theDialog, kStdCancelItemIndex ); |
// As long as the only enabled items are the dimissers, |
// there is no need to call ModalDialog within a loop. |
ModalDialog ( nil, &theItem ); |
DisposeDialog ( theDialog ); |
return theItem; |
} |
#pragma segment File |
// DoQuit |
// saveOpt - one of kAEAsk,kAEYes,kAENo |
// if kAEYes or kAEAsk then AEInteactWithUser should have been called |
// before DoQuit. Assumes that it can interact if it needs to. |
void DoQuit( DescType saveOpt ) |
{ |
WindowPtr aWindow; |
WindowPtr nextWindow; |
WindowPeek nextWPeek; |
short theKind; |
OSErr check; |
aWindow = (WindowPtr)LMGetWindowList(); |
gQuitting = true; |
while ( aWindow ) |
{ |
nextWPeek = ((WindowPeek)aWindow)->nextWindow; |
nextWindow = &nextWPeek->port; |
if (Ours(aWindow)) |
{ |
check = DoClose(aWindow, true, saveOpt); |
if ( check != noErr ) |
{ |
gQuitting = false; |
return; |
} |
} |
else |
{ |
theKind = ((WindowPeek)aWindow)->windowKind; |
if (theKind < 0) |
CloseDeskAcc(theKind); |
} |
aWindow = nextWindow; |
} |
} // DoQuit |
OSErr GetFile( FSSpec *theFSSpec ) |
{ |
SFTypeList myTypes; |
StandardFileReply reply; |
myTypes[0] = 'TEXT'; |
StandardGetFile( NULL, 1, myTypes, &reply ); |
if (reply.sfGood) |
{ |
*theFSSpec = reply.sfFile; |
return(noErr); |
} |
else |
return(userCanceledErr); |
} |
#pragma segment File |
OSErr DoCreate( FSSpec theSpec ) |
{ |
OSErr err; |
err = FSpCreate(&theSpec, MenuScripterAppSig, 'TEXT', smSystemScript); |
if (err != noErr) |
ShowError((unsigned char *)"\pDoCreate", err); |
return(err); |
} |
#pragma segment File |
OSErr WriteFile( DPtr theDocument, short refNum, FSSpec theFSSpec ) |
{ |
short resFile; |
long length; |
HHandle theHHandle; |
StScrpHandle theSHandle; |
OSErr err; |
StringHandle theAppName; |
short oldSelStart; |
short oldSelEnd; |
Handle thePHandle; |
Handle myText; |
Handle thePGXHandle; |
tWindowOffscreen* theOffscreen = nil; |
// first write out the text to the data fork |
length = (*(theDocument->theText))->teLength; |
myText = (*(theDocument->theText))->hText; |
HLock( myText ); |
err = FSWrite(refNum, &length, *myText); |
if ( noErr != err ) |
return err; |
HUnlock( myText ); |
// we are writing to a temporary file, so we need to create the resource file |
// before writing out the resources |
// now open the resource file |
HCreateResFile(theFSSpec.vRefNum, theFSSpec.parID, theFSSpec.name); |
err = ResError(); |
if (err) |
{ |
ShowError((unsigned char *)"\pHCreateResFile", err); |
return(err); |
} |
resFile = HOpenResFile( theFSSpec.vRefNum, theFSSpec.parID, theFSSpec.name, fsWrPerm ); |
err = ResError(); |
if (err) |
{ |
ShowError((unsigned char *)"\pHOpenResFile", err); |
return(err); |
} |
// Write out our 'TFSF' resource to file |
// Draw everything into offscreen pixmap. |
theOffscreen = DrawOffscreen ( theDocument->theWindow ); |
if ( theOffscreen ) |
(*theDocument->theText)->inPort = (GrafPtr) theOffscreen->offscreenWorld; |
oldSelStart = (*(theDocument->theText))->selStart; |
oldSelEnd = (*(theDocument->theText))->selEnd; |
TESetSelect( 0, kMaxTELength, theDocument->theText ); |
theSHandle = TEGetStyleScrapHandle(theDocument->theText); |
TESetSelect(oldSelStart,oldSelEnd, theDocument->theText); |
if ( theOffscreen ) |
{ |
// If it wasn't for the caret, we wouldn't need to draw this |
theOffscreen = DrawOnscreen ( theOffscreen ); |
(*theDocument->theText)->inPort = theDocument->theWindow; |
} |
AddResource((Handle)theSHandle, kStyleInfoType, 255, (unsigned char *)"\pStyle Info"); |
err = ResError(); |
if (err) |
{ |
ShowError((unsigned char *)"\pAddResource - Style Info", err); |
return(err); |
} |
// Write out the printer info |
// First the QD info |
if (theDocument->thePrintSetup) |
{ |
thePHandle = (Handle)theDocument->thePrintSetup; |
err = HandToHand(&thePHandle); |
AddResource(thePHandle, 'TFSP', 255, (unsigned char *)"\pPrinter Info"); |
err = ResError(); |
if (err) |
{ |
ShowError((unsigned char *)"\pAddResource- TFSP", err); |
return(err); |
} |
} |
// Next the QD QX info |
if ( ( gGXIsPresent ) && ( theDocument->documentJob ) ) |
{ |
thePGXHandle = NewHandle(0); |
GXFlattenJobToHdl(theDocument->documentJob, thePGXHandle); |
AddResource(thePGXHandle, kGXPrinterInfoType, 255, (unsigned char *)"\pGX Printer Info"); |
err = ResError(); |
if (err) |
{ |
ShowError((unsigned char *)"\pAddResource- TFGX", err); |
return(err); |
} |
} |
theHHandle = (HHandle)NewHandle(sizeof(HeaderRec)); |
HLock((Handle)theHHandle); |
GetFontName(theDocument->theFont, (unsigned char *)&(*theHHandle)->theFont); |
(*theHHandle)->theSize = theDocument->theSize; |
(*theHHandle)->theStyle = theDocument->theStyle; |
(*theHHandle)->lastID = 0; |
HUnlock((Handle)theHHandle); |
AddResource((Handle)theHHandle, kHeaderInfoType, 255, (unsigned char *)"\pHeader Info"); |
err = ResError(); |
if (err) |
{ |
ShowError((unsigned char *)"\pAddResource- Header Info", err); |
return(err); |
} |
// Now put an AppName in for Finder in 7.0 |
theAppName = (StringHandle)NewHandle(gAppRec.theName[0]); |
PLstrcpy( *theAppName, gAppRec.theName ); |
AddResource((Handle)theAppName, 'STR ', -16396, (unsigned char *)"\pFinder App Info"); |
err = ResError(); |
if (err) |
{ |
ShowError((unsigned char *)"\pAppName", err); |
return(err); |
} |
// Each document has a script associated with it |
// this can be changed so store in resource. |
err = StoreDocumentScript( theDocument, resFile ); |
CloseResFile( resFile ); |
return err; |
} // WriteFile |
#pragma segment File |
OSErr ReadFile( DPtr theDocument, short refNum, Str255 fn ) |
{ |
long theSize; |
short resFile; |
OSErr err; |
HHandle aHandle; |
Handle gHandle; |
Handle hGXJobData; |
Boolean gotQDPrintRec; |
gotQDPrintRec = false; |
err = GetEOF(refNum, &theSize); |
if (err) |
return(err); |
// We're only using TE, so check that there is not more than 32K worth of text |
if (theSize > kMaxTELength) |
return(1); |
gHandle = NewHandle(theSize); |
HLock(gHandle); |
err = FSRead(refNum, &theSize, *gHandle); |
if (err) |
{ |
HUnlock(gHandle); |
return(err); |
} |
resFile = HOpenResFile(theDocument->theFSSpec.vRefNum, |
theDocument->theFSSpec.parID, |
fn, |
fsWrPerm); |
if ( resFile == -1 ) |
err = fnfErr; |
if ( err == noErr ) |
{ |
aHandle = NULL; |
if ( Count1Resources( kHeaderInfoType ) ) |
aHandle = (HHandle)Get1Resource( kHeaderInfoType, 255 ); |
// New Format Info |
aHandle = nil; |
if ( Count1Resources( kStyleInfoType ) ) |
aHandle = (HHandle)Get1Resource( kStyleInfoType, 255 ); |
HLock(gHandle); |
TEStylInsert( *gHandle, GetHandleSize(gHandle), |
(StScrpHandle)aHandle, theDocument->theText ); |
HUnlock(gHandle); |
// If there is a print record saved, ditch the old one |
// created by new document and fill this one in |
if (Count1Resources('TFSP')) |
{ |
if (theDocument->thePrintSetup) |
DisposHandle((Handle)theDocument->thePrintSetup); |
theDocument->thePrintSetup = (THPrint)Get1Resource('TFSP', 255); |
err = HandToHand((Handle *)&theDocument->thePrintSetup); |
gotQDPrintRec = true; |
if (! gGXIsPresent) |
PrValidate(theDocument->thePrintSetup); |
} |
if ( gGXIsPresent ) |
if ( Count1Resources( kGXPrinterInfoType ) ) |
{ |
if (theDocument->documentJob) |
{ |
// GXDisposeJob(theDocument->documentJob); |
// theDocument->documentJob = nil; |
} |
hGXJobData = Get1Resource( kGXPrinterInfoType, 255 ); |
if (hGXJobData) |
{ |
GXUnflattenJobFromHdl(theDocument->documentJob, hGXJobData); |
err = GXGetJobError(theDocument->documentJob); |
ReleaseResource(hGXJobData); |
} |
} |
else |
{ |
if (gotQDPrintRec) |
GXConvertPrintRecord(theDocument->documentJob, theDocument->thePrintSetup); |
} |
err = LoadDocumentScript( theDocument, resFile ); |
CloseResFile(resFile); |
err = ResError(); |
if (err) |
{ |
ShowError((unsigned char *)"\pReadFile - CloseResFile", err); |
return(err); |
} |
} |
else |
TESetText( *gHandle, GetHandleSize(gHandle), theDocument->theText ); |
if (gHandle) |
DisposHandle(gHandle); |
if (err==fnfErr) |
err = noErr; |
return(err); |
} // ReadFile |
// Name: GetFileContents |
// Purpose: Opens the document specified by theFSSpec and puts |
// the contents into theDocument. |
#pragma segment File |
OSErr GetFileContents( FSSpec theFSSpec, DPtr theDocument ) |
{ |
OSErr err; |
short theRefNum; |
// this can be called from two places- on an OpenDoc AppleEvent |
// and by the user just selecting Open from the File Menu |
// assume that the CFS is correct when the routine is called |
err = FSpOpenDF( &theFSSpec, fsRdWrPerm, &theRefNum ); |
if (err) |
{ |
ShowError((unsigned char *)"\pFSpOpenDF", err); |
return(err); |
} |
else |
{ |
err = ReadFile(theDocument, theRefNum, theFSSpec.name); |
if (err) |
{ |
ShowError((unsigned char *)"\pReadFile", err); |
return(err); |
} |
err=FSClose(theRefNum); |
if (err) |
{ |
ShowError((unsigned char *)"\pFSClose", err); |
return(err); |
} |
return(noErr); |
} |
} |
#pragma segment File |
OSErr SaveUsingTemp( DPtr theDocument ) |
{ |
Str255 tempName; |
FSSpec tempFSSpec; |
OSErr err; |
// save the file to disk using a temporary file |
// this is the recommended way of doing things |
// first write out the file to disk using a temporary filename |
// if it is sucessfully written, exchange the temporary file with the last one saved |
// then delete the temporary file- so if anything goes wrong, the original version is still there |
// first generate the temporary filename |
GetTempFileName(theDocument, tempName); |
//create this file on disk |
tempFSSpec = theDocument->theFSSpec; |
PLstrcpy( tempFSSpec.name, tempName ); |
err = DoCreate(tempFSSpec); |
// now save the file as normal |
if (err == noErr) |
err = DoSave(theDocument, tempFSSpec); |
if (err == noErr) |
err = FSpExchangeFiles(&tempFSSpec, &theDocument->theFSSpec); |
// we've exchanged the files, now delete the temporary one |
if (err == noErr) |
err = FSpDelete(&tempFSSpec); |
return(err); |
} |
#pragma segment File |
// Fills in the document record with the user chosen destination |
OSErr GetFileNameToSaveAs(DPtr theDocument) |
{ |
StandardFileReply reply; |
OSErr err; |
Str255 suggestName; |
GetWTitle(theDocument->theWindow, suggestName); |
StandardPutFile((unsigned char *)"\pSave Document As:", suggestName, &reply); |
if (reply.sfGood) |
{ |
err = FSpDelete(&reply.sfFile); |
if (!((err==noErr) || (err==fnfErr))) |
return(err); |
else |
err = noErr; |
theDocument->theFSSpec = reply.sfFile; |
PLstrcpy(theDocument->theFileName, reply.sfFile.name); |
} |
else |
err = userCanceledErr; |
return(err); |
} // GetFileNameToSaveAs |
#pragma segment File |
OSErr DoSave( DPtr theDocument, FSSpec theFSSpec ) |
{ |
short refNum; |
OSErr fileErr; |
fileErr = FSpOpenDF(&theFSSpec, fsRdWrPerm, &refNum); |
if (fileErr == fnfErr) |
{ |
fileErr = DoCreate(theFSSpec); |
if (fileErr) |
return(fileErr); |
fileErr = FSpOpenDF(&theFSSpec, fsRdWrPerm, &refNum); |
} |
if (fileErr == noErr) |
{ |
fileErr = WriteFile(theDocument, refNum, theFSSpec); |
if (fileErr==noErr) |
theDocument->dirty = false; |
fileErr = FSClose(refNum); |
} |
else |
FileError((unsigned char *)"\perror opening file ", theFSSpec.name); |
return(fileErr); |
} |
#pragma segment File |
OSErr OpenOld( FSSpec aFSSpec ) |
{ |
DPtr aDocument; |
AEDesc aDesc = { typeNull, NULL }, |
aBoundsDesc = { typeNull, NULL }; |
WindowPropToken aPropToken; |
Str255 aPStr; |
OSErr anErr; |
aDocument = NewDocument( true, (WindowPtr)-1L ); |
SetWTitle( aDocument->theWindow, aFSSpec.name ); |
SetPort( aDocument->theWindow ); |
aDocument->theFSSpec = aFSSpec; |
PLstrcpy( aDocument->theFileName,aFSSpec.name ); |
aDocument->dirty = false; |
aDocument->everSaved = true; |
anErr = GetFileContents( aFSSpec, aDocument ); |
if ( noErr == anErr ) |
{ // Try and get the saved script property |
if ( kOSANullScript != aDocument->theScriptID ) |
{ |
PLstrcpy( aPStr, "\pwindowbounds" ); |
anErr = AECreateDesc( typeChar, (Ptr)&aPStr[1], aPStr[0], &aDesc ); |
if ( noErr != anErr ) goto done; |
anErr = GetScriptProperty( aDocument->theScriptID, &aDesc, &aBoundsDesc ); |
if ( noErr == anErr ) |
{ // Set up a token for the document |
aPropToken.tokenWindowToken.tokenWindow = aDocument->theWindow; |
aPropToken.tokenProperty = pBounds; |
anErr = SetDocumentTokenProperty( &aPropToken, &aBoundsDesc ); |
} |
else |
anErr = noErr; // Script does not have this property |
} |
ResizeWindow( aDocument ); |
SelectWindow( aDocument->theWindow ); |
ShowMSWindow( aDocument->theWindow ); |
} |
else |
FileError( (unsigned char *)"\pError Opening ", aFSSpec.name ); |
done: |
(void)AEDisposeDesc( &aDesc ); |
(void)AEDisposeDesc( &aBoundsDesc ); |
return anErr; |
} // OpenOld |
/* |
#pragma segment File |
OSErr OpenUsingAlias( AliasHandle theAliasH ) |
{ |
OSErr err; |
FSSpec aFSSpec; |
Boolean dummy; |
err = ResolveAlias(nil, theAliasH, &aFSSpec, &dummy); |
if (err == noErr) |
err = OpenOld(aFSSpec); |
return(err); |
} |
*/ |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14