home *** CD-ROM | disk | FTP | other *** search
- /*
- File: TextFile.c
-
- Contains: Text file support for simple text application.
-
- Version: SimpleText 1.4 or later
-
- ** Copyright 1993-1996 Apple Computer. All rights reserved.
- **
- ** You may incorporate this sample code into your applications without
- ** restriction, though the sample code has been provided "AS IS" and the
- ** responsibility for its operation is 100% yours. However, what you are
- ** not permitted to do is to redistribute the source as "DSC Sample Code"
- ** after having made changes. If you're going to re-distribute the source,
- ** we require that you make it clear in the source that the code was
- ** descended from Apple Sample Code, but that you've made changes.
-
- */
-
- #include "MacIncludes.h"
-
- #include "TextFile.h"
-
- #pragma segment Text
-
-
-
- // --------------------------------------------------------------------------------------------------------------
- // INTERNAL DEFINES
- // --------------------------------------------------------------------------------------------------------------
- #define kOnePageWidth 600 // preferred width of a window
- #define kMargins 4 // margins in window
- #define kPrintMargins 8 // margins in printing window
- #define kGXPrintMargins 10 // margins in printing a GX window
-
- #define kPictureBase 1000 // resource base ID for PICTs in documents
- #define kSoundBase 10000 // resource base ID for 'snd 's in documents
-
- // resources for controling printing
- #define kFormResource 'form'
- #define kFormFeed 0x00000001 // form feed after this line
-
- #define kContentsListID 10000 // resource ID for STR# contents menu
-
- // some memory requirements
- #define kPrefBufferSize 90*1024
- #define kMinBufferSize 5*1024
-
- #define kDeleteKey 8
- #define kForwardDeleteKey 0x75
-
-
- extern pascal void AsmClikLoop();
-
- #define ABS(n) (((n) < 0) ? -(n) : (n))
-
- // --------------------------------------------------------------------------------------------------------------
- // GLOBALS USED ONLY BY THESE ROUTINES
- // --------------------------------------------------------------------------------------------------------------
-
- // These variables are used for speech, notice that on purpose we only
- // support a single channel at a time.
- static SpeechChannel gSpeechChannel = nil;
- static VoiceSpec gCurrentVoice;
- static Ptr gSpeakPtr = nil;
- static Boolean gAddedVoices = false;
- static Str31 gPictMarker1, gPictMarker2;
-
- // --------------------------------------------------------------------------------------------------------------
- // EXTERNAL FUNCTIONS
- // --------------------------------------------------------------------------------------------------------------
-
- extern OSErr TextDragTracking(WindowRef pWindow, void *pData, DragReference theDragRef, short message);
- extern OSErr TextDragReceive(WindowRef pWindow, void *refCon, DragReference theDragRef);
- extern Boolean DragText(WindowRef pWindow, void *pData, EventRecord *pEvent, RgnHandle hilightRgn);
-
- // --------------------------------------------------------------------------------------------------------------
- // INTERNAL ROUTINES
- // --------------------------------------------------------------------------------------------------------------
-
- static void TextAddContentsMenu(WindowDataPtr pData);
- static void TextRemoveContentsMenu(WindowDataPtr pData);
- static OSErr TextGetContentsListItem(WindowDataPtr pData, short itemNum, StringPtr menuStr, StringPtr searchStr, short *totalItems);
- static OSErr TextAdjustContentsMenu(WindowDataPtr pData);
-
- // --------------------------------------------------------------------------------------------------------------
- // UNDO UTILITY FUNCTIONS
- // --------------------------------------------------------------------------------------------------------------
- OSErr SaveCurrentUndoState(WindowDataPtr pData, short newCommandID)
- {
- OSErr anErr = noErr;
- TEHandle hTE = ((TextDataPtr) pData)->hTE;
-
- // this is only a new command if:
- // the command ID is different
- // OR
- // the selection is a range, and not equal to the old one
- if (
- ( ((TextDataPtr) pData)->prevCommandID != newCommandID )
- ||
- (
- ( (**hTE).selStart != (**hTE).selEnd )
- ||
- ( ABS((**hTE).selStart - ((TextDataPtr) pData)->prevSelStart) > 1 )
- )
- )
- {
- Handle tempHandle;
- Size tempSize;
-
- // if we don't have save handles, make em!
- if (!((TextDataPtr) pData)->prevText)
- {
- ((TextDataPtr) pData)->prevText = NewHandle(0);
- anErr = MemError();
- nrequire(anErr, MakeTextSave);
- }
- if (!((TextDataPtr) pData)->prevStyle)
- {
- ((TextDataPtr) pData)->prevStyle = NewHandle(0);
- anErr = MemError();
- nrequire(anErr, MakeStyleSave);
- }
-
- // grow the save handles and block move into them
- tempHandle = (**hTE).hText;
- tempSize = GetHandleSize(tempHandle);
- SetHandleSize( ((TextDataPtr) pData)->prevText, tempSize);
- anErr = MemError();
- nrequire(anErr, GrowTextSave);
- BlockMoveData(*tempHandle, * ((TextDataPtr) pData)->prevText, tempSize );
-
- tempHandle = (Handle) TEGetStyleHandle(hTE);
- tempSize = GetHandleSize(tempHandle);
- SetHandleSize( ((TextDataPtr) pData)->prevStyle, tempSize);
- anErr = MemError();
- nrequire(anErr, GrowTextSave);
- BlockMoveData(*tempHandle, * ((TextDataPtr) pData)->prevStyle, tempSize );
-
- // save length
- ((TextDataPtr) pData)->prevLength = (**hTE).teLength;
- ((TextDataPtr) pData)->beforeSelStart = (**hTE).selStart;
- ((TextDataPtr) pData)->beforeSelEnd = (**hTE).selEnd;
- }
-
- // save start and end of the selection
- ((TextDataPtr) pData)->prevSelStart = (**hTE).selStart;
-
- // if we didn't have any problems, then we can undo this operation
- ((TextDataPtr) pData)->prevCommandID = newCommandID;
- return(noErr);
-
- // EXCEPTION HANDLING
- GrowStyleSave:
- GrowTextSave:
- MakeStyleSave:
- MakeTextSave:
- // can't undo because of an error
- // (at some point might warn the user, but that's probably more annoying)
- ((TextDataPtr) pData)->prevCommandID = cNull;
-
- return(anErr);
-
- } // SaveCurrentUndoState
-
- // --------------------------------------------------------------------------------------------------------------
- static void PerformUndo(WindowDataPtr pData)
- {
- if (((TextDataPtr) pData)->prevCommandID != cNull)
- {
- TEHandle hTE = ((TextDataPtr) pData)->hTE;
- long tempLong;
-
- // undo text
- tempLong = (long) (**hTE).hText;
- (**hTE).hText = ((TextDataPtr) pData)->prevText;
- ((TextDataPtr) pData)->prevText = (Handle)tempLong;
-
- // undo length
- tempLong = (long) (**hTE).teLength;
- (**hTE).teLength = ((TextDataPtr) pData)->prevLength;
- ((TextDataPtr) pData)->prevLength = tempLong;
-
- // undo style
- tempLong = (long) TEGetStyleHandle(hTE);
- if (HandToHand((Handle*) &tempLong) == noErr)
- {
- TESetStyleHandle( (TEStyleHandle) ((TextDataPtr) pData)->prevStyle, hTE );
- ((TextDataPtr) pData)->prevStyle = (Handle)tempLong;
- }
-
- // undo selection
- {
- short start, end;
-
- start = ((TextDataPtr) pData)->beforeSelStart;
- end = ((TextDataPtr) pData)->beforeSelEnd;
- ((TextDataPtr) pData)->prevSelStart = (**hTE).selStart;
- TESetSelect(start, end, hTE);
- }
-
- }
-
- } // PerformUndo
-
-
- // --------------------------------------------------------------------------------------------------------------
- // TEXT EDIT UTILITY FUNCTIONS
- // --------------------------------------------------------------------------------------------------------------
- static long CalculateTextEditHeight(TEHandle hTE)
- {
- long result;
- short length;
-
- result = TEGetHeight(32767, 0, hTE);
- length = (**hTE).teLength;
-
- // Text Edit doesn't return the height of the last character, if that
- // character is a <cr>. So if we see that, we go grab the height of
- // that last character and add it into the total height.
- if ( (length) && ( (*(**hTE).hText)[length-1] == '\n') )
- {
- TextStyle theStyle;
- short theHeight;
- short theAscent;
-
- TEGetStyle(length, &theStyle, &theHeight, &theAscent, hTE);
- result += theHeight;
- }
-
- return result;
-
- } // CalculateTextEditHeight
-
- // --------------------------------------------------------------------------------------------------------------
- void AdjustTE(WindowDataPtr pData, Boolean doScroll)
- {
- TEPtr te;
- short value;
- short prevValue;
-
- te = *((TextDataPtr) pData)->hTE;
- prevValue = GetControlValue(pData->vScroll);
- value = te->viewRect.top - te->destRect.top;
- SetControlValue(pData->vScroll, value);
-
- te = *((TextDataPtr) pData)->hTE;
- if (doScroll)
- {
- short hScroll = te->viewRect.left - te->destRect.left;
- short vScroll = value - prevValue;
- if ((hScroll != 0) || (vScroll != 0))
- TEScroll(hScroll, vScroll, ((TextDataPtr) pData)->hTE);
- }
-
-
- } // AdjustTE
-
- // --------------------------------------------------------------------------------------------------------------
-
- static void RecalcTE(WindowDataPtr pData, Boolean doInval)
- {
- Rect viewRect, destRect;
- short oldOffset;
-
- destRect = (**((TextDataPtr) pData)->hTE).destRect;
- viewRect = (**((TextDataPtr) pData)->hTE).viewRect;
- oldOffset = destRect.top - viewRect.top;
-
- viewRect = pData->contentRect;
-
- InsetRect(&viewRect, kMargins, kMargins);
- destRect = viewRect;
-
- OffsetRect(&destRect, 0, oldOffset);
-
- (**((TextDataPtr) pData)->hTE).viewRect = viewRect;
- (**((TextDataPtr) pData)->hTE).destRect = destRect;
-
- TECalText(((TextDataPtr) pData)->hTE);
-
- if (doInval)
- InvalRect(&qd.thePort->portRect);
-
- } // RecalcTE
-
- // --------------------------------------------------------------------------------------------------------------
-
- pascal TEClickLoopUPP GetOldClickLoop(void)
- {
- return ((TextDataPtr) FrontWindow())->docClick;
-
- } // GetOldClikLoop
-
- pascal void TextClickLoop(void)
- {
- WindowRef window;
- RgnHandle region;
-
- window = FrontWindow();
- region = NewRgn();
- GetClip(region); /* save clip */
- ClipRect(&GetWindowPort(window)->portRect);
- ((TextDataPtr) window)->insideClickLoop = true;
- AdjustScrollBars(window, false, false, nil);
- ((TextDataPtr) window)->insideClickLoop = false;
- SetClip(region); /* restore clip */
- DisposeRgn(region);
-
- } // TextClickLoop
-
- #if GENERATINGPOWERPC
- static pascal Boolean CClikLoop(TEPtr pTE)
- {
- CallTEClickLoopProc(GetOldClickLoop(), pTE);
-
- TextClickLoop();
-
- return(true);
-
- } // CClikLoop
-
- static RoutineDescriptor gMyClickLoopRD = BUILD_ROUTINE_DESCRIPTOR(uppTEClickLoopProcInfo, CClikLoop);
- static TEClickLoopUPP gMyClickLoop = &gMyClickLoopRD;
- #else
- static TEClickLoopUPP gMyClickLoop = NewDrawHookProc(AsmClikLoop);
- #endif
-
- // --------------------------------------------------------------------------------------------------------------
- #if GENERATINGPOWERPC
- pascal void MyDrawHook ( unsigned short offset, unsigned short textLen,
- Ptr textPtr, TEPtr tePtr, TEHandle teHdl )
- #else
- pascal void MyDrawGlue();
-
- pascal void MyDrawHook ( TEHandle teHdl, TEPtr tePtr, Ptr textPtr, short textLen, short offset )
- #endif
- {
- #pragma unused ( teHdl, tePtr)
-
- register short drawLen = 0;
- register Ptr drawPtr;
-
- drawPtr = textPtr + (long)offset;
-
- while ( textLen--)
- {
- if ( *drawPtr == 0xCA &&
- ( *(drawPtr - 1) == 0x0D || *tePtr->hText == textPtr) )
- {
- DrawText( textPtr, offset, drawLen);
- DrawChar( '\040');
- offset += drawLen + 1;
- drawLen = 0;
- }
- else
- {
- ++drawLen;
- }
- ++drawPtr;
- }
-
- DrawText( textPtr, offset, drawLen);
-
- } // MyDrawHook
-
- #if GENERATINGCFM
- static RoutineDescriptor gMyDrawGlueRD = BUILD_ROUTINE_DESCRIPTOR(uppDrawHookProcInfo, MyDrawHook);
- static DrawHookUPP gMyDrawGlue = &gMyDrawGlueRD;
- #else
- static DrawHookUPP gMyDrawGlue = NewDrawHookProc(MyDrawGlue);
- #endif
-
- // --------------------------------------------------------------------------------------------------------------
- static void DisposeOfSpeech(Boolean throwAway)
- {
- if (gSpeechChannel)
- {
- (void) StopSpeech( gSpeechChannel );
- if (throwAway)
- {
- (void) DisposeSpeechChannel( gSpeechChannel );
- gSpeechChannel = nil;
- }
- }
- if (gSpeakPtr)
- {
- DisposePtr(gSpeakPtr);
- gSpeakPtr = nil;
- }
-
- } // DisposeOfSpeech
-
- // --------------------------------------------------------------------------------------------------------------
-
- static Boolean FindNextPicture(Handle textHandle, short *offset, short *delta)
- {
- long result;
-
- // marker at begining of document means a picture there
- if ( (*offset == 0) && ( (*(unsigned char*)(*textHandle + (*offset))) == 0xCA) )
- {
- *delta = 1;
- return true;
- }
-
- if (gPictMarker1[0] != 0)
- {
- result = Munger(textHandle, *offset, &gPictMarker1[1], gPictMarker1[0], nil, 0);
- if (result >= 0)
- {
- *offset = result;
- *delta = gPictMarker1[0];
- return true;
- }
- }
-
- if (gPictMarker2[0] != 0)
- {
- result = Munger(textHandle, *offset, &gPictMarker2[1], gPictMarker2[0], nil, 0);
- if (result >= 0)
- {
- *offset = result;
- *delta = gPictMarker2[0];
- return true;
- }
- }
-
- *delta = 1;
- return false;
-
- } // FindNextPicture
-
- // --------------------------------------------------------------------------------------------------------------
- static Boolean LineHasPageBreak(short lineNum, TEHandle hTE)
- {
- Boolean result = false;
- short offset, delta, lineStartOffset;
- short textLength;
- Handle textHandle;
- short pictIndex = 0;
-
- textHandle = (** hTE).hText;
- lineStartOffset = (**hTE).lineStarts[lineNum];
- textLength = (**hTE).lineStarts[lineNum+1];
-
- offset = 0;
- while (offset < textLength)
- {
- if (FindNextPicture(textHandle, &offset, &delta))
- {
- Handle formHandle;
-
- formHandle = Get1Resource(kFormResource, kFormResource + pictIndex);
- if (formHandle)
- {
- long options = **(long**)formHandle;
-
- ReleaseResource(formHandle);
- if ( (options & kFormFeed) && (offset >= lineStartOffset) && (offset < textLength) )
- {
- result = true;
- break;
- }
- }
- ++pictIndex;
- }
-
- offset += delta;
- }
-
- return(result);
-
- } // LineHasPageBreak
-
- // --------------------------------------------------------------------------------------------------------------
- #define USE_PICT_SPOOL_CACHE 1
-
- enum {kSpoolCacheBlockSize = 1024}; // 1K is arbitrary, perhaps could be tuned
-
- static Handle gSpoolPicture;
- static long gSpoolOffset;
- static Handle gSpoolCacheBlock;
- static long gSpoolCacheOffset;
- static long gSpoolCacheSize;
-
- // --------------------------------------------------------------------------------------------------------------
- /*
- ReadPartialResource is very painful over slow links such as ARA or ISDN. This code implements a simple
- cache that vastly improves the performance of displaying embedded pictures over a slow network link.
- The cache also improves scrolling performance in documents with many embedded pictures, even on local
- volumes.
- */
- static short ReadPartialData(Ptr dataPtr, short byteCount)
- {
- #if USE_PICT_SPOOL_CACHE
-
- if (gSpoolCacheBlock == NULL)
- {
- gSpoolCacheBlock = NewHandle(kSpoolCacheBlockSize);
- if (gSpoolCacheBlock != NULL)
- {
- long cacheBytes = GetResourceSizeOnDisk(gSpoolPicture) - gSpoolOffset;
-
- if (cacheBytes > kSpoolCacheBlockSize)
- cacheBytes = kSpoolCacheBlockSize;
-
- HLock(gSpoolCacheBlock);
- ReadPartialResource(gSpoolPicture, gSpoolOffset, *gSpoolCacheBlock, cacheBytes);
- HUnlock(gSpoolCacheBlock);
-
- gSpoolCacheOffset = gSpoolOffset;
- gSpoolCacheSize = cacheBytes;
- }
- }
-
- // if the requested data is entirely present in the cache block, get it from there…
- if (gSpoolCacheBlock != NULL &&
- gSpoolOffset >= gSpoolCacheOffset && gSpoolOffset + byteCount <= gSpoolCacheOffset + gSpoolCacheSize)
- {
- BlockMoveData(*gSpoolCacheBlock + (gSpoolOffset - gSpoolCacheOffset), dataPtr, byteCount);
- return byteCount;
- }
- // …else read it directly from disk, and force the cache block to be filled with new data
- else
- {
- ReadPartialResource(gSpoolPicture, gSpoolOffset, dataPtr, byteCount);
- if (gSpoolCacheBlock != NULL)
- {
- DisposeHandle(gSpoolCacheBlock);
- gSpoolCacheBlock = NULL;
- }
- return byteCount;
- }
-
- #else
-
- ReadPartialResource(gSpoolPicture, gSpoolOffset, dataPtr, byteCount);
- return byteCount;
-
- #endif
-
- } // ReadPartialData
-
- // --------------------------------------------------------------------------------------------------------------
- static pascal void GetPartialPICTData(Ptr dataPtr,short byteCount)
- {
- while (byteCount > 0)
- {
- short readBytes = ReadPartialData(dataPtr, byteCount);
-
- byteCount -= readBytes;
- dataPtr += readBytes;
-
- gSpoolOffset += readBytes;
- }
-
- } // GetPartialPICTData
-
- #if GENERATINGCFM
- static RoutineDescriptor gGetPartialPICTDataRD = BUILD_ROUTINE_DESCRIPTOR(uppQDGetPicProcInfo, GetPartialPICTData);
- static QDGetPicUPP gGetPartialPICTData = &gGetPartialPICTDataRD;
- #else
- static QDGetPicUPP gGetPartialPICTData = NewQDGetPicProc(GetPartialPICTData);
- #endif
-
- // --------------------------------------------------------------------------------------------------------------
- static void SpoolDrawPicture(Handle spoolPicture, PicHandle pictureHeader, Rect *pRect)
- {
- CQDProcs spoolProcs;
- QDProcs *oldProcs;
-
- gSpoolPicture = spoolPicture;
- gSpoolOffset = sizeof(Picture);
-
- if (gMachineInfo.theEnvirons.hasColorQD)
- SetStdCProcs(&spoolProcs);
- else
- SetStdProcs((QDProcs*) &spoolProcs);
-
- spoolProcs.getPicProc = gGetPartialPICTData;
- oldProcs = qd.thePort->grafProcs;
- qd.thePort->grafProcs = (QDProcs*) &spoolProcs;
- DrawPicture(pictureHeader, pRect);
- qd.thePort->grafProcs = oldProcs;
-
- if (gSpoolCacheBlock != NULL)
- {
- DisposeHandle(gSpoolCacheBlock);
- gSpoolCacheBlock = NULL;
- }
-
- } // SpoolDrawPicture
-
- // --------------------------------------------------------------------------------------------------------------
- static void DrawPictures( WindowDataPtr pData, TEHandle hTE)
- {
- Handle textHandle;
- long textLength;
- short oldResFile;
- short pictIndex;
- short numPicts;
-
- oldResFile = CurResFile();
- UseResFile(pData->resRefNum);
-
- numPicts = Count1Resources('PICT');
- pictIndex = 0;
-
- if (numPicts != 0)
- {
- short offset, delta;
- RgnHandle oldClip;
- Rect theRect;
- Rect viewRect;
-
- viewRect = theRect = (** hTE).viewRect;
- // intersect our viewing area with the actual clip to avoid
- // drawing over the scroll bars
- {
- RgnHandle newClip = NewRgn();
-
- oldClip = NewRgn();
- GetClip(oldClip);
- RectRgn(newClip, &theRect);
- SectRgn(oldClip, newClip, newClip);
- SetClip(newClip);
- }
- textHandle = (** hTE).hText;
- textLength = (** hTE).teLength;
-
- offset = 0;
- while (offset < textLength)
- {
- if (FindNextPicture(textHandle, &offset, &delta))
- {
- Handle pictHandle;
- Point picturePoint = TEGetPoint(offset, hTE);
-
- SetResLoad(false);
- pictHandle = Get1Resource('PICT', kPictureBase + pictIndex);
- SetResLoad(true);
- if (pictHandle)
- {
- PicHandle pictHeader = (PicHandle)NewHandle(sizeof(Picture) + sizeof(long)*8);
-
- if (pictHeader)
- {
- HLock((Handle) pictHeader);
- ReadPartialResource(pictHandle, 0, (Ptr)*pictHeader, GetHandleSize((Handle)pictHeader));
- HUnlock((Handle) pictHeader);
-
- // calculate where to draw the picture, this location is
- // computed by:
- // 1) the frame of the original picture, normalized to 0,0
- // 2) the location of the non-breaking space character
- // 3) centering the picture on the content frame horizontally
- // 4) subtracting off the line-height of the character
-
- GetPICTRectangleAt72dpi(pictHeader, &theRect);
- OffsetRect(&theRect, -theRect.left, -theRect.top);
- OffsetRect(&theRect,
- theRect.left +
- ((viewRect.right - viewRect.left) >> 1) -
- ((theRect.right - theRect.left) >> 1),
- picturePoint.v-theRect.top - pData->vScrollAmount);
-
- // only draw the picture if it will be visible (vastly improves scrolling
- // performance in documents with many embedded pictures)
-
- if (RectInRgn(&theRect, qd.thePort->clipRgn))
- SpoolDrawPicture(pictHandle, pictHeader, &theRect);
- }
- ReleaseResource((Handle) pictHandle);
- }
- ++pictIndex;
-
- offset += delta;
- }
- else
- break;
- }
-
- SetClip(oldClip);
- DisposeRgn(oldClip);
- }
-
- UseResFile(oldResFile);
-
- } // DrawPictures
-
- // --------------------------------------------------------------------------------------------------------------
- static void UpdateFileInfo(FSSpec *pSpec, Boolean documentIsText)
- {
- FInfo theInfo;
-
- FSpGetFInfo(pSpec, &theInfo);
- theInfo.fdCreator = 'ttxt';
-
- // set the stationary bit, if we must
- if (!documentIsText)
- {
- theInfo.fdFlags |= kIsStationary;
- theInfo.fdType = 'sEXT';
- }
- else
- {
- theInfo.fdFlags &= ~kIsStationary;
- theInfo.fdType = 'TEXT';
- }
- FSpSetFInfo(pSpec, &theInfo);
-
- } // UpdateFileInfo
-
- // --------------------------------------------------------------------------------------------------------------
- static OSErr TextSave(WindowDataPtr pData)
- {
- OSErr anErr = noErr;
- long amountToWrite;
-
- // write out the text
- SetFPos(pData->dataRefNum, fsFromStart, 0);
- amountToWrite = (** ((TextDataPtr) pData)->hTE).teLength;
- anErr = FSWrite(pData->dataRefNum, &amountToWrite, * (** ((TextDataPtr) pData)->hTE).hText);
- nrequire(anErr, FailedWrite);
- SetEOF(pData->dataRefNum, amountToWrite);
-
- if (pData->resRefNum == -1)
- {
- FSpCreateResFile(&pData->fileSpec, 'ttxt', pData->originalFileType, 0);
- pData->resRefNum = FSpOpenResFile(&pData->fileSpec, fsRdWrPerm);
- }
- else
- {
- // a save always makes it into file of type 'TEXT', for Save As… we
- // afterwards set it again if the user is saving as stationary.
- UpdateFileInfo(&pData->fileSpec, true);
- }
-
- if (pData->resRefNum != -1)
- {
- short oldResFile = CurResFile();
- Handle resourceHandle;
-
- UseResFile(pData->resRefNum);
-
- // remove any old sounds
- resourceHandle = Get1Resource('snd ', kSoundBase);
- if (resourceHandle)
- {
- RemoveResource(resourceHandle);
- DisposeHandle(resourceHandle);
- }
-
- // save the new sound
- resourceHandle = ((TextDataPtr) pData)->soundHandle;
- if (resourceHandle)
- {
- anErr = HandToHand(&resourceHandle);
- if (anErr == noErr)
- {
- AddResource(resourceHandle, 'snd ', kSoundBase, "\p");
- anErr = ResError();
- }
- nrequire(anErr, AddSoundResourceFailed);
- }
-
- // remove any old styles
- resourceHandle = Get1Resource('styl', 128);
- if (resourceHandle)
- {
- RemoveResource(resourceHandle);
- DisposeHandle(resourceHandle);
- }
-
- // save the new style -- get the scrap handle from the TE record
- // To do this, we must select the text -- BUT doing so through the
- // TextEdit API results in lots of flashing and annoying behavior.
- // So we just change the offsets by hand
- {
- short oldStart, oldEnd;
-
- oldStart = (** ((TextDataPtr) pData)->hTE).selStart;
- oldEnd = (** ((TextDataPtr) pData)->hTE).selEnd;
-
- (** ((TextDataPtr) pData)->hTE).selStart = 0;
- (** ((TextDataPtr) pData)->hTE).selEnd = 32767;
-
- resourceHandle = (Handle) TEGetStyleScrapHandle( ((TextDataPtr) pData)->hTE );
-
- (** ((TextDataPtr) pData)->hTE).selStart = oldStart;
- (** ((TextDataPtr) pData)->hTE).selEnd = oldEnd;
- }
-
- if (resourceHandle)
- {
- AddResource(resourceHandle, 'styl', 128, "\p");
- anErr = ResError();
- nrequire(anErr, AddStyleResourceFailed);
- }
-
- AddSoundResourceFailed:
- AddStyleResourceFailed:
-
- UpdateResFile(pData->resRefNum);
- UseResFile(oldResFile);
- }
-
-
- // FALL THROUGH EXCEPTION HANDLING
- FailedWrite:
-
- // if everything went okay, then clear the changed bit
- if (anErr == noErr)
- {
- pData->changed = false;
- (void) FlushVol("\p", pData->fileSpec.vRefNum);
- }
-
- return anErr;
-
- } // TextSave
-
- // --------------------------------------------------------------------------------------------------------------
-
- static pascal void DrawTextUserItem(DialogPtr dPtr, short theItem)
- /*
- Draw text icon in the location
- */
- {
- short kind;
- Handle itemHandle;
- Rect box;
-
- GetDialogItem(dPtr, theItem, &kind, &itemHandle, &box);
- PlotIconID(&box, ttNone, ttNone, kTextIcon);
-
- } // DrawTextUserItem
-
- #if GENERATINGCFM
- static RoutineDescriptor gDrawTextUserItemRD = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, DrawTextUserItem);
- static UserItemUPP gDrawTextUserItem = &gDrawTextUserItemRD;
- #else
- static UserItemUPP gDrawTextUserItem = NewUserItemProc(DrawTextUserItem);
- #endif
-
- // --------------------------------------------------------------------------------------------------------------
-
- static pascal void DrawStationeryUserItem(DialogPtr dPtr, short theItem)
- /*
- Draw stationery icon in the location
- */
- {
- short kind;
- Handle itemHandle;
- Rect box;
-
- GetDialogItem(dPtr, theItem, &kind, &itemHandle, &box);
- PlotIconID(&box, ttNone, ttNone, kStationeryIcon);
-
- } // DrawStationeryUserItem
-
-
- #if GENERATINGCFM
- static RoutineDescriptor gDrawStationeryUserItemRD = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, DrawStationeryUserItem);
- static UserItemUPP gDrawStationeryUserItem = &gDrawStationeryUserItemRD;
- #else
- static UserItemUPP gDrawStationeryUserItem = NewUserItemProc(DrawStationeryUserItem);
- #endif
-
-
- // --------------------------------------------------------------------------------------------------------------
- // pre and post update procs for inline input
-
- static pascal void TSMPreUpdateProc(TEHandle textH, long refCon)
- {
- #pragma unused (refCon)
-
- ScriptCode keyboardScript;
- short mode;
- TextStyle theStyle;
-
- keyboardScript = GetScriptManagerVariable(smKeyScript);
- mode = doFont;
- if (!
- (
- (TEContinuousStyle(&mode, &theStyle, textH) )&&
- (FontToScript(theStyle.tsFont) == keyboardScript)
- )
- )
- {
- theStyle.tsFont = GetScriptVariable(keyboardScript, smScriptAppFond);
- TESetStyle(doFont, &theStyle, false, textH);
- }
-
- } // TSMPreUpdateProc
-
- #if GENERATINGCFM
- static RoutineDescriptor gTSMPreUpdateProcRD = BUILD_ROUTINE_DESCRIPTOR(uppTSMTEPreUpdateProcInfo, TSMPreUpdateProc);
- static TSMTEPreUpdateUPP gTSMPreUpdateProc = &gTSMPreUpdateProcRD;
- #else
- static TSMTEPreUpdateUPP gTSMPreUpdateProc = NewTSMTEPreUpdateProc(TSMPreUpdateProc);
- #endif
-
- static pascal void TSMPostUpdateProc(
- TEHandle textH,
- long fixLen,
- long inputAreaStart,
- long inputAreaEnd,
- long pinStart,
- long pinEnd,
- long refCon)
- {
- #pragma unused (textH, fixLen, inputAreaStart, inputAreaEnd, pinStart, pinEnd)
-
- AdjustScrollBars((WindowRef)refCon, false, false, nil);
- AdjustTE((WindowDataPtr)refCon, true);
-
- ((WindowDataPtr)refCon)->changed = true;
-
- } // TSMPostUpdateProc
-
- #if GENERATINGCFM
- static RoutineDescriptor gTSMPostUpdateProcRD = BUILD_ROUTINE_DESCRIPTOR(uppTSMTEPostUpdateProcInfo, TSMPostUpdateProc);
- static TSMTEPostUpdateUPP gTSMPostUpdateProc = &gTSMPostUpdateProcRD;
- #else
- static TSMTEPostUpdateUPP gTSMPostUpdateProc = NewTSMTEPostUpdateProc(TSMPostUpdateProc);
- #endif
-
- // --------------------------------------------------------------------------------------------------------------
-
- static pascal short SaveDialogHook(short item, DialogPtr dPtr, Boolean *isText)
- {
- short theType;
- Handle theHandle;
- Rect theRect;
- short returnValue = item;
-
-
- switch (item)
- {
- case sfHookFirstCall:
- if (GetWRefCon(GetDialogWindow(dPtr)) == sfMainDialogRefCon)
- {
- GetDialogItem(dPtr, iTextUserItem, &theType, &theHandle, &theRect);
- theHandle = (Handle) gDrawTextUserItem;
- SetDialogItem(dPtr, iTextUserItem, theType, theHandle, &theRect);
-
- GetDialogItem(dPtr, iStationeryUserItem, &theType, &theHandle, &theRect);
- theHandle = (Handle) gDrawStationeryUserItem;
- SetDialogItem(dPtr, iStationeryUserItem, theType, theHandle, &theRect);
-
- GetDialogItem(dPtr, iTextDocumentItem, &theType, &theHandle, &theRect);
- SetControlValue((ControlHandle) theHandle, 1);
-
- GetDialogItem(dPtr, iStationeryDocumentItem, &theType, &theHandle, &theRect);
- SetControlValue((ControlHandle) theHandle, 0);
- *isText = true;
- }
- break;
-
- case iTextDocumentItem:
- case iTextUserItem:
- GetDialogItem(dPtr, iTextDocumentItem, &theType, &theHandle, &theRect);
- SetControlValue((ControlHandle) theHandle, 1);
-
- GetDialogItem(dPtr, iStationeryDocumentItem, &theType, &theHandle, &theRect);
- SetControlValue((ControlHandle) theHandle, 0);
-
- *isText = true;
- returnValue = sfHookNullEvent;
- break;
-
- case iStationeryDocumentItem:
- case iStationeryUserItem:
- GetDialogItem(dPtr, iTextDocumentItem, &theType, &theHandle, &theRect);
- SetControlValue((ControlHandle) theHandle, 0);
-
- GetDialogItem(dPtr, iStationeryDocumentItem, &theType, &theHandle, &theRect);
- SetControlValue((ControlHandle) theHandle, 1);
-
- *isText = false;
- returnValue = sfHookNullEvent;
- break;
-
- }
-
- return returnValue;
-
- } // SaveDialogHook
-
- #if GENERATINGCFM
- static RoutineDescriptor gSaveDialogHookRD = BUILD_ROUTINE_DESCRIPTOR(uppDlgHookYDProcInfo, SaveDialogHook);
- static DlgHookYDUPP gSaveDialogHook = &gSaveDialogHookRD;
- #else
- static DlgHookYDUPP gSaveDialogHook = NewDlgHookYDProc(SaveDialogHook);
- #endif
-
- // --------------------------------------------------------------------------------------------------------------
-
- // Handle update/activate events behind Standard File
- static pascal Boolean SaveDialogFilter(DialogPtr theDialog, EventRecord *theEvent,
- short *itemHit, void *myDataPtr)
- {
- #pragma unused(myDataPtr)
-
- if (StdFilterProc(theDialog, theEvent, itemHit))
- return true;
-
- // Pass updates through (Activates are tricky...was mucking with Apple menu & thereby
- // drastically changing how the system handles the menu bar during our alert)
- if (theEvent->what == updateEvt /* || theEvent->what == activateEvt */ )
- {
- HandleEvent(theEvent);
- }
-
- return false;
-
- } // SaveDialogFilter
-
-
- #if GENERATINGCFM
- static RoutineDescriptor gSaveDialogFilterRD = BUILD_ROUTINE_DESCRIPTOR(uppModalFilterYDProcInfo, SaveDialogFilter);
- static ModalFilterYDUPP gSaveDialogFilter = &gSaveDialogFilterRD;
- #else
- static ModalFilterYDUPP gSaveDialogFilter = NewModalFilterYDProc(SaveDialogFilter);
- #endif
-
- // --------------------------------------------------------------------------------------------------------------
-
- static OSErr TextSaveAs(WindowRef pWindow, WindowDataPtr pData)
- {
- OSErr anErr = noErr;
- short oldRes, oldData;
- StandardFileReply sfReply;
- Boolean documentIsText;
-
- // save the old references -- if there is an error, we restore them
- oldRes = pData->resRefNum;
- oldData = pData->dataRefNum;
-
- // ask where and how to save this document
- {
- Str255 defaultName;
- Point where = {-1, -1};
-
- // setup for the call
- GetWTitle(pWindow, defaultName);
- SetCursor(&qd.arrow);
-
- // find out where the user wants the file
- CustomPutFile("\p", defaultName, &sfReply,
- kTextSaveAsDialogID, where,
- gSaveDialogHook, gSaveDialogFilter, nil, nil, &documentIsText);
-
- // map the cancel button into a cancelling error
- if (!sfReply.sfGood)
- anErr = eUserCanceled;
- }
-
- // can't replace over other types
- if (sfReply.sfReplacing)
- {
- FInfo theInfo;
-
- FSpGetFInfo(&sfReply.sfFile, &theInfo);
-
- if ( (theInfo.fdType != 'TEXT') && (theInfo.fdType != 'sEXT') )
- anErr = eDocumentWrongKind;
- }
- nrequire(anErr, StandardPutFile);
-
- if (
- (sfReply.sfReplacing) &&
- (oldData != -1) &&
- (pData->fileSpec.vRefNum == sfReply.sfFile.vRefNum) &&
- (pData->fileSpec.parID == sfReply.sfFile.parID) &&
- EqualString(pData->fileSpec.name, sfReply.sfFile.name, false, false)
- )
- {
-
- anErr = TextSave(pData);
-
- if (anErr == noErr)
- UpdateFileInfo(&sfReply.sfFile, documentIsText);
- }
- else
- {
- // create the data file and resource fork
- (void) FSpDelete(&sfReply.sfFile);
- anErr = FSpCreate(&sfReply.sfFile, 'ttxt', documentIsText ? 'TEXT' : 'sEXT', 0);
- FSpCreateResFile(&sfReply.sfFile, 'ttxt', documentIsText ? 'TEXT' : 'sEXT', 0);
- nrequire(anErr, FailedCreate);
-
- // set the stationary bit, if we must
- if (!documentIsText)
- {
- FInfo theInfo;
-
- FSpGetFInfo(&sfReply.sfFile, &theInfo);
- theInfo.fdFlags |= kIsStationary;
- FSpSetFInfo(&sfReply.sfFile, &theInfo);
- }
-
- // open both of forks
- anErr = FSpOpenDF(&sfReply.sfFile, fsRdWrPerm, &pData->dataRefNum);
- if (anErr == noErr)
- {
- pData->resRefNum = FSpOpenResFile(&sfReply.sfFile, fsRdWrPerm);
- anErr = ResError();
- }
- nrequire(anErr, FailedOpen);
-
- // call the standard save function to do the save
- anErr = TextSave(pData);
-
- // FALL THROUGH EXCEPTION HANDLING
- FailedOpen:
- FSpDelete(&sfReply.sfFile);
- FailedCreate:
- StandardPutFile:
-
- // finally, close the old files if everything went okay
- if (anErr == noErr)
- {
- if (oldRes != -1)
- CloseResFile(oldRes);
- if (oldData != -1)
- FSClose(oldData);
- pData->isWritable = true;
- SetWTitle(pWindow, sfReply.sfFile.name);
- }
- else
- {
- pData->resRefNum = oldRes;
- pData->dataRefNum = oldData;
- }
- }
-
- // save new location
- if (anErr == noErr)
- BlockMoveData(&sfReply.sfFile, &pData->fileSpec, sizeof(FSSpec));
-
- // Return eUserCanceled so we can avoid closing/quitting if they cancel the SF dialog
- // // don't propagate this error
- // if (anErr == eUserCanceled)
- // anErr = noErr;
-
- return anErr;
-
- } // TextSaveAs
-
- // --------------------------------------------------------------------------------------------------------------
- static void ApplyFace(short requestedFace, WindowRef pWindow, WindowDataPtr pData, short commandID)
- {
- TextStyle style;
- short oldNumLines = (**(((TextDataPtr) pData)->hTE)).nLines;
-
- SaveCurrentUndoState(pData, commandID);
-
- style.tsFace = requestedFace;
- TESetStyle(doFace + ((requestedFace != normal) ? doToggle : 0), &style, true, ((TextDataPtr) pData)->hTE);
- TECalText(((TextDataPtr) pData)->hTE);
-
- oldNumLines -= (**(((TextDataPtr) pData)->hTE)).nLines;
- AdjustTE(pData, false);
- AdjustScrollBars(pWindow, (oldNumLines > 0), (oldNumLines > 0), nil);
-
- pData->changed = true;
-
- } // ApplyFace
-
- // --------------------------------------------------------------------------------------------------------------
- static OSErr ApplySize(short requestedSize, WindowRef pWindow, WindowDataPtr pData, short commandID)
- {
- OSErr anErr = noErr;
- TextStyle style;
- short oldNumLines = (**(((TextDataPtr) pData)->hTE)).nLines;
-
- SaveCurrentUndoState(pData, commandID);
-
- style.tsSize = requestedSize;
- TESetStyle(doSize, &style, true, ((TextDataPtr) pData)->hTE);
- TECalText(((TextDataPtr) pData)->hTE);
- if (CalculateTextEditHeight(((TextDataPtr) pData)->hTE) > 32767)
- {
- style.tsSize = 0;
- TESetStyle(doSize, &style, true, ((TextDataPtr) pData)->hTE);
- anErr = eDocumentTooLarge;
- }
-
- oldNumLines -= (**(((TextDataPtr) pData)->hTE)).nLines;
- AdjustTE(pData, false);
- AdjustScrollBars(pWindow, (oldNumLines > 0), (oldNumLines > 0), nil);
-
- pData->changed = true;
-
- return anErr;
-
- } // ApplySize
-
- // --------------------------------------------------------------------------------------------------------------
- // OOP INTERFACE ROUTINES
- // --------------------------------------------------------------------------------------------------------------
-
- static OSErr TextUpdateWindow(WindowRef pWindow, WindowDataPtr pData)
- {
- Rect updateArea = pData->contentRect;
-
- // be sure to also erase the area where the horizontal scroll bar
- // is missing.
- updateArea.bottom = GetWindowPort(pWindow)->portRect.bottom;
- EraseRect(&updateArea);
-
- TEUpdate(&pData->contentRect, ((TextDataPtr) pData)->hTE);
-
- DrawPictures(pData, ((TextDataPtr) pData)->hTE);
-
- DrawControls(pWindow);
- DrawGrowIcon(pWindow);
-
- return noErr;
-
- } // TextUpdateWindow
-
- // --------------------------------------------------------------------------------------------------------------
-
- static OSErr TextCloseWindow(WindowRef pWindow, WindowDataPtr pData)
- {
- #pragma unused (pWindow)
-
- // shut down text services
- if (pData->docTSMDoc)
- {
- FixTSMDocument(pData->docTSMDoc);
- DeactivateTSMDocument(pData->docTSMDoc);
- DeleteTSMDocument(pData->docTSMDoc);
- }
-
- DisposeOfSpeech(true);
- DisposeHandle(((TextDataPtr) pData)->soundHandle);
- TEDispose(((TextDataPtr) pData)->hTE);
-
- DisposeHandle(((TextDataPtr) pData)->prevText);
- DisposeHandle(((TextDataPtr) pData)->prevStyle);
-
- TextRemoveContentsMenu(pData);
-
- return noErr;
-
- } // TextCloseWindow
-
- // --------------------------------------------------------------------------------------------------------------
-
- static OSErr TextActivateEvent(WindowRef pWindow, WindowDataPtr pData, Boolean activating)
- {
- #pragma unused (pWindow)
-
- // only modifyable docs can be active
- if (pData->originalFileType == 'TEXT')
- {
- if (activating)
- {
- TEActivate(((TextDataPtr) pData)->hTE);
- if (pData->docTSMDoc != nil)
- ActivateTSMDocument(pData->docTSMDoc);
- }
- else
- {
- TEDeactivate(((TextDataPtr) pData)->hTE);
- if (pData->docTSMDoc != nil)
- DeactivateTSMDocument(pData->docTSMDoc);
- }
- }
-
- // add contents menu, if appropriate
- if (activating)
- {
- TextAddContentsMenu(pData);
- }
- else
- {
- TextRemoveContentsMenu(pData);
- }
-
- return noErr;
-
- } // TextActivateEvent
-
- // --------------------------------------------------------------------------------------------------------------
-
- static Boolean TextFilterEvent(WindowRef pWindow, WindowDataPtr pData, EventRecord *pEvent)
- {
- switch (pEvent->what)
- {
- case nullEvent:
- if (pData->originalFileType == 'TEXT')
- {
- if ( pWindow == FrontWindow() )
- TEIdle(((TextDataPtr) pData)->hTE);
- }
-
- // if we stop speaking, ditch the channel
- if (gSpeechChannel)
- {
- SpeechStatusInfo status; // Status of our speech channel.
-
- if (
- (GetSpeechInfo( gSpeechChannel, soStatus, (void*) &status ) == noErr)
- && (!status.outputBusy )
- )
- DisposeOfSpeech(true);
- }
- break;
- }
-
- return false;
-
- } // TextFilterEvent
-
- // --------------------------------------------------------------------------------------------------------------
-
- static OSErr TextScrollContent(WindowRef pWindow, WindowDataPtr pData, short deltaH, short deltaV)
- {
- GrafPtr port = (GrafPtr) GetWindowPort(pWindow);
- RgnHandle srcRgn, dstRgn;
- Rect viewRect;
-
- // scroll the text area
- TEScroll(deltaH, deltaV, ((TextDataPtr) pData)->hTE);
-
- // calculate the region that is uncovered by the scroll
- srcRgn = NewRgn();
- dstRgn = NewRgn();
- viewRect = (**((TextDataPtr) pData)->hTE).viewRect;
- RectRgn( srcRgn, &viewRect );
- SectRgn( srcRgn, port->visRgn, srcRgn );
- SectRgn( srcRgn, port->clipRgn, srcRgn );
- CopyRgn( srcRgn, dstRgn );
- OffsetRgn( dstRgn, deltaH, deltaV );
- SectRgn( srcRgn, dstRgn, dstRgn );
- DiffRgn( srcRgn, dstRgn, srcRgn );
-
- // clip to this new area
- GetClip(dstRgn);
- SetClip(srcRgn);
- DrawPictures(pData, ((TextDataPtr) pData)->hTE);
- SetClip(dstRgn);
-
- // all done with these calculation regions
- DisposeRgn( srcRgn );
- DisposeRgn( dstRgn );
-
- return eActionAlreadyHandled;
-
- } // TextScrollContent
-
- // --------------------------------------------------------------------------------------------------------------
-
- static OSErr TextKeyEvent(WindowRef pWindow, WindowDataPtr pData, EventRecord *pEvent, Boolean isMotionKey)
- {
- OSErr anErr = noErr;
-
- if (!(pEvent->modifiers & cmdKey))
- {
- char theKey = pEvent->message & charCodeMask;
- char theKeyCode = (pEvent->message >> 8) & charCodeMask;
-
- if ( ((theKey != kDeleteKey) || (theKeyCode != kForwardDeleteKey)) &&
- ((** ((TextDataPtr) pData)->hTE).teLength+1 > kMaxLength) )
- anErr = eDocumentTooLarge;
- else
- {
- long oldHeight = CalculateTextEditHeight(((TextDataPtr) pData)->hTE);
- long end = (**(((TextDataPtr) pData)->hTE)).selEnd;
- long start = (**(((TextDataPtr) pData)->hTE)).selStart;
-
- ObscureCursor();
- SaveCurrentUndoState(pData, cTypingCommand);
- if (theKeyCode != kForwardDeleteKey)
- {
- if (pEvent->modifiers & shiftKey)
- {
- switch (theKeyCode)
- {
- case kUpArrow:
- TEKey(theKey, ((TextDataPtr) pData)->hTE);
- TESetSelect((**(((TextDataPtr) pData)->hTE)).selStart, end, ((TextDataPtr) pData)->hTE);
- break;
-
- case kDownArrow:
- TESetSelect(end, end, ((TextDataPtr) pData)->hTE);
- TEKey(theKey, ((TextDataPtr) pData)->hTE);
- TESetSelect(start, (**(((TextDataPtr) pData)->hTE)).selEnd, ((TextDataPtr) pData)->hTE);
- break;
-
- case kRightArrow:
- {
- Handle textHandle = (**(((TextDataPtr) pData)->hTE)).hText;
- Ptr textBuf;
- char state;
-
- state = HGetState(textHandle);
- HLock(textHandle);
- textBuf = *(**(((TextDataPtr) pData)->hTE)).hText;
- if (CharacterByteType(textBuf, start, smCurrentScript) != smSingleByte)
- ++end;
- HSetState(textHandle, state);
- TESetSelect(start, ++end, ((TextDataPtr) pData)->hTE);
- }
- break;
-
- case kLeftArrow:
- if (start > 0)
- {
- if (start > 1)
- {
- Handle textHandle = (**(((TextDataPtr) pData)->hTE)).hText;
- Ptr textBuf;
- char state;
-
- state = HGetState(textHandle);
- HLock(textHandle);
- textBuf = *(**(((TextDataPtr) pData)->hTE)).hText;
- if (CharacterByteType(textBuf, start-1, smCurrentScript) != smSingleByte)
- --start;
- HSetState(textHandle, state);
- }
- TESetSelect(--start, end, ((TextDataPtr) pData)->hTE);
- }
- break;
-
- default:
- TEKey(theKey, ((TextDataPtr) pData)->hTE);
- }
- }
- else
- TEKey(theKey, ((TextDataPtr) pData)->hTE);
- }
- else
- {
- if (end < (**(((TextDataPtr) pData)->hTE)).teLength)
- {
- if (start == end)
- TEKey(kRightArrowCharCode, ((TextDataPtr) pData)->hTE);
- TEKey(kBackspaceCharCode, ((TextDataPtr) pData)->hTE);
- }
- }
- oldHeight -= CalculateTextEditHeight(((TextDataPtr) pData)->hTE);
-
- ((TextDataPtr) pWindow)->insideClickLoop = true;
- AdjustTE(pData, false);
- AdjustScrollBars(pWindow, (oldHeight > 0), (oldHeight > 0), nil);
- ((TextDataPtr) pWindow)->insideClickLoop = false;
-
- if (!isMotionKey)
- pData->changed = true;
- }
- }
-
- return anErr;
-
- } // TextKeyEvent
-
- // --------------------------------------------------------------------------------------------------------------
-
- static OSErr TextContentClick(WindowRef pWindow, WindowDataPtr pData, EventRecord *pEvent)
- {
- OSErr anErr = noErr;
- Point clickPoint = pEvent->where;
- ControlHandle theControl;
- RgnHandle hilightRgn;
-
- GlobalToLocal(&clickPoint);
- if (FindControl(clickPoint, pWindow, &theControl) == 0)
- {
- if (gMachineInfo.haveDragMgr)
- {
- hilightRgn = NewRgn();
- TEGetHiliteRgn(hilightRgn, ((TextDataPtr) pData)->hTE);
-
- if (PtInRgn(clickPoint, hilightRgn))
- {
- SaveCurrentUndoState(pData, cTypingCommand);
- if (!DragText(pWindow, pData, pEvent, hilightRgn))
- anErr = eActionAlreadyHandled;
- }
- else
- {
- anErr = eActionAlreadyHandled;
- }
-
- DisposeRgn(hilightRgn);
- }
- else
- {
- anErr = eActionAlreadyHandled;
- }
- }
-
- if ( (anErr == eActionAlreadyHandled) && (PtInRect(clickPoint, &pData->contentRect)) )
- {
- TEClick(clickPoint, (pEvent->modifiers & shiftKey) != 0, ((TextDataPtr) pData)->hTE);
- }
-
- return anErr;
-
- } // TextContentClick
-
- // --------------------------------------------------------------------------------------------------------------
-
- static OSErr TextAdjustSize(WindowRef pWindow, WindowDataPtr pData,
- Boolean *didReSize) // input: was window resized, output: t->we resized something
- {
- #pragma unused (pWindow)
-
- if (*didReSize)
- {
- RecalcTE(pData, true);
- AdjustTE(pData, true);
- }
- else
- {
- AdjustTE(pData, false);
- }
-
- return noErr;
-
- } // TextAdjustSize
-
- // --------------------------------------------------------------------------------------------------------------
-
- static short FontToQD(gxFont fontID, Style* styleBits)
- {
- short numFonts = GetHandleSize((Handle) gFontMappingList) / sizeof(FontMappingRecord);
- short i;
- FontMappingPtr pList = *gFontMappingList;
-
- for (i = 0; i < numFonts; ++i)
- {
- if (pList->fontID == fontID)
- {
- if (styleBits)
- *styleBits = pList->qdStyle;
- return(pList->qdFont);
- }
- pList++;
- }
-
- // error case? default.
- if (styleBits)
- *styleBits = normal;
- return(0);
-
- } // FontToQD
-
- // --------------------------------------------------------------------------------------------------------------
-
- static gxFont QDToFont(short qdFont, Style styleBits)
- {
- short numFonts = GetHandleSize((Handle) gFontMappingList) / sizeof(FontMappingRecord);
- short i;
- FontMappingPtr pList;
-
- if (qdFont == systemFont)
- qdFont = GetSysFont();
- if (qdFont == applFont)
- qdFont = GetAppFont();
-
- // try to match both font and style
- pList = *gFontMappingList;
- for (i = 0; i < numFonts; ++i)
- {
- if ((pList->qdFont == qdFont) && (styleBits == pList->qdStyle))
- return(pList->fontID);
- pList++;
- }
-
- // if we can't match font and style, just look for font
- pList = *gFontMappingList;
- for (i = 0; i < numFonts; ++i)
- {
- if (pList->qdFont == qdFont)
- return(pList->fontID);
- pList++;
- }
-
- // error case? default.
- return(nil);
-
- } // QDToFont
-
- // --------------------------------------------------------------------------------------------------------------
-
- static OSErr TextCommand(WindowRef pWindow, WindowDataPtr pData, short commandID, long menuResult)
- {
-
- OSErr anErr = noErr;
-
- SetPort((GrafPtr) GetWindowPort(pWindow));
-
- if ( (pData->docTSMDoc) && (menuResult != 0) )
- FixTSMDocument(pData->docTSMDoc);
-
- switch (commandID)
- {
- case cUndo:
- {
- short oldNumLines = (**(((TextDataPtr) pData)->hTE)).nLines;
-
- PerformUndo(pData);
- oldNumLines -= (**(((TextDataPtr) pData)->hTE)).nLines;
- AdjustTE(pData, false);
- AdjustScrollBars(pWindow, (oldNumLines > 0), (oldNumLines > 0), nil);
- RecalcTE(pData, true);
- pData->changed = true;
- }
- break;
-
- case cCut:
- SaveCurrentUndoState(pData, cCut);
- {
- short oldNumLines = (**(((TextDataPtr) pData)->hTE)).nLines;
-
- TECut(((TextDataPtr) pData)->hTE); // no need for TEToScrap with styled TE record
- oldNumLines -= (**(((TextDataPtr) pData)->hTE)).nLines;
- AdjustTE(pData, false);
- AdjustScrollBars(pWindow, (oldNumLines > 0), (oldNumLines > 0), nil);
- pData->changed = true;
- }
- break;
-
- case cCopy:
- TECopy(((TextDataPtr) pData)->hTE); // no need for TEToScrap with styled TE record
- AdjustTE(pData, false);
- break;
-
- case cClear:
- SaveCurrentUndoState(pData, cClear);
- {
- short oldNumLines = (**(((TextDataPtr) pData)->hTE)).nLines;
-
- TEDelete(((TextDataPtr) pData)->hTE);
- oldNumLines -= (**(((TextDataPtr) pData)->hTE)).nLines;
- AdjustTE(pData, false);
- AdjustScrollBars(pWindow, (oldNumLines > 0), (oldNumLines > 0), nil);
- pData->changed = true;
- }
- break;
-
- case cPaste:
- SaveCurrentUndoState(pData, cPaste);
- {
- short oldNumLines = (**(((TextDataPtr) pData)->hTE)).nLines;
-
- anErr = TEFromScrap();
- if (anErr == noErr)
- {
- // if the current length, plus the paste data, minus the data in the selection
- // would make the document too large, say so
- if (
- ((** ((TextDataPtr) pData)->hTE).teLength +
- TEGetScrapLength() -
- ((** ((TextDataPtr) pData)->hTE).selEnd-(** ((TextDataPtr) pData)->hTE).selStart)
- )
- > kMaxLength)
- {
- anErr = eDocumentTooLarge;
- }
- else
- {
- Handle aHandle = (Handle) TEGetText(((TextDataPtr) pData)->hTE);
- Size oldSize = GetHandleSize(aHandle);
- Size newSize = oldSize + TEGetScrapLength();
- OSErr saveErr;
-
- SetHandleSize(aHandle, newSize);
- saveErr = MemError();
- SetHandleSize(aHandle, oldSize);
- if (saveErr != noErr)
- anErr = eDocumentTooLarge;
- else
- TEStylePaste(((TextDataPtr) pData)->hTE);
- }
-
- UnloadScrap();
- }
- oldNumLines -= (**(((TextDataPtr) pData)->hTE)).nLines;
- AdjustTE(pData, false);
- AdjustScrollBars(pWindow, (oldNumLines > 0), (oldNumLines > 0), nil);
- pData->changed = true;
- }
- break;
-
- case cReplace:
- SaveCurrentUndoState(pData, cReplace);
- {
- short result = ConductFindOrReplaceDialog(kReplaceWindowID);
-
- if (result == cancel)
- break;
-
- if (result == iReplaceAll)
- {
- long newStart, newEnd;
- short oldNumLines = (**(((TextDataPtr) pData)->hTE)).nLines;
-
- TESetSelect(0, 0, ((TextDataPtr) pData)->hTE);
- while (PerformSearch((**((TextDataPtr) pData)->hTE).hText,
- (**((TextDataPtr) pData)->hTE).selStart,
- gFindString, gCaseSensitive, false, false,
- &newStart, &newEnd))
- {
- TESetSelect(newStart, newEnd, ((TextDataPtr) pData)->hTE);
- TEDelete(((TextDataPtr) pData)->hTE);
- TEInsert(&gReplaceString[1], gReplaceString[0], ((TextDataPtr) pData)->hTE);
- TESetSelect(newStart, newStart+gReplaceString[0], ((TextDataPtr) pData)->hTE);
- pData->changed = true;
- }
- oldNumLines -= (**(((TextDataPtr) pData)->hTE)).nLines;
-
- AdjustTE(pData, false);
- AdjustScrollBars(pWindow, (oldNumLines > 0), (oldNumLines > 0), nil);
-
- anErr = eActionAlreadyHandled;
- break;
- }
- }
-
- // fall through from replace
- case cReplaceAgain:
- SaveCurrentUndoState(pData, cReplaceAgain);
- {
- long newStart, newEnd;
- Boolean isBackwards = ((gEvent.modifiers & shiftKey) != 0);
-
- if (PerformSearch((**((TextDataPtr) pData)->hTE).hText,
- isBackwards ? (**((TextDataPtr) pData)->hTE).selEnd : (**((TextDataPtr) pData)->hTE).selStart,
- gFindString, gCaseSensitive, isBackwards, gWrapAround,
- &newStart, &newEnd))
- {
- short oldNumLines = (**(((TextDataPtr) pData)->hTE)).nLines;
-
- TESetSelect(newStart, newEnd, ((TextDataPtr) pData)->hTE);
- TEDelete(((TextDataPtr) pData)->hTE);
- TEInsert(&gReplaceString[1], gReplaceString[0], ((TextDataPtr) pData)->hTE);
- TESetSelect(newStart, newStart+gReplaceString[0], ((TextDataPtr) pData)->hTE);
- oldNumLines -= (**(((TextDataPtr) pData)->hTE)).nLines;
-
- AdjustTE(pData, false);
- AdjustScrollBars(pWindow, (oldNumLines > 0), (oldNumLines > 0), nil);
- pData->changed = true;
- }
- else
- SysBeep(1);
-
- anErr = eActionAlreadyHandled;
- }
- break;
-
- case cFind:
- case cFindSelection:
- if (commandID == cFind)
- {
- if (ConductFindOrReplaceDialog(kFindWindowID) == cancel)
- break;
- }
- else
- {
- gFindString[0] = (**((TextDataPtr) pData)->hTE).selEnd - (**((TextDataPtr) pData)->hTE).selStart;
- BlockMoveData( (*(**((TextDataPtr) pData)->hTE).hText) + (**((TextDataPtr) pData)->hTE).selStart, &gFindString[1], gFindString[0]);
- }
-
- // fall through from find or find selection
- case cFindAgain:
- {
- long newStart, newEnd;
- Boolean isBackwards = ((gEvent.modifiers & shiftKey) != 0);
-
- if (PerformSearch((**((TextDataPtr) pData)->hTE).hText,
- isBackwards ? (**((TextDataPtr) pData)->hTE).selStart : (**((TextDataPtr) pData)->hTE).selEnd,
- gFindString, gCaseSensitive, isBackwards, gWrapAround,
- &newStart, &newEnd))
- {
- TESetSelect(newStart, newEnd, ((TextDataPtr) pData)->hTE);
- AdjustTE(pData, false);
- AdjustScrollBars(pWindow, false, false, nil);
- }
- else
- SysBeep(1);
-
- anErr = eActionAlreadyHandled;
- }
- break;
-
- case cSelectAll:
- TESetSelect(0, (**((TextDataPtr) pData)->hTE).teLength,
- ((TextDataPtr) pData)->hTE);
- AdjustTE(pData, false);
- AdjustScrollBars(pWindow, false, false, nil);
- anErr = eActionAlreadyHandled;
- break;
-
- // save turns into save as if this is a new document or if the original wasn't
- // available for writing
- case cSave:
- if (
- (!pData->isWritable) ||
- ( (pData->dataRefNum == -1) && (pData->resRefNum == -1) )
- )
- anErr = TextSaveAs(pWindow, pData);
- else
- anErr = TextSave(pData);
- break;
-
- case cSaveAs:
- anErr = TextSaveAs(pWindow, pData);
- break;
-
- // SUPPORTED FONTS
- case cSelectFontStyle:
- case cSelectFont:
- SaveCurrentUndoState(pData, cSelectFont);
- {
- Str255 itemName;
- Str255 menuName;
- TextStyle theStyle;
- short oldNumLines = (**(((TextDataPtr) pData)->hTE)).nLines;
- gxFont fontID;
-
- GetMenuItemText( GetMenuHandle( menuResult>>16 ), menuResult & 0xFFFF, itemName );
- if (commandID == cSelectFont)
- {
- if (gMachineInfo.haveGX)
- {
- GXFindFonts(nil, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, itemName[0], &itemName[1], 1,1, &fontID);
- theStyle.tsFont = FontToQD(fontID, nil);
- }
- else
- GetFNum( itemName, &theStyle.tsFont );
-
- TESetStyle( doFont, &theStyle, true, ((TextDataPtr) pData)->hTE );
- }
- else
- {
- BlockMoveData((**GetMenuHandle( menuResult>>16 )).menuData, menuName, sizeof(Str255));
-
- // find the font based upon family and style names
- GXFindFonts(nil, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, menuName[0], &menuName[1], 1,1, &fontID);
- GXFindFonts(fontID, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, itemName[0], &itemName[1], 1,1, &fontID);
-
- // convert the font into a QD font ID and style bits (as appropriate)
- theStyle.tsFont = FontToQD(fontID, &theStyle.tsFace);
- TESetStyle( doFont + doFace, &theStyle, true, ((TextDataPtr) pData)->hTE );
- }
-
- TECalText(((TextDataPtr) pData)->hTE);
- oldNumLines -= (**(((TextDataPtr) pData)->hTE)).nLines;
- AdjustTE(pData, false);
- AdjustScrollBars(pWindow, (oldNumLines > 0), (oldNumLines > 0), nil);
- pData->changed = true;
- }
- break;
-
-
- // SUPPORTED STYLES
- case cPlain:
- ApplyFace(normal, pWindow, pData, cPlain);
- break;
-
- case cBold:
- ApplyFace(bold, pWindow, pData, cBold);
- break;
-
- case cItalic:
- ApplyFace(italic, pWindow, pData, cItalic);
- break;
-
- case cUnderline:
- ApplyFace(underline, pWindow, pData, cUnderline);
- break;
-
- case cOutline:
- ApplyFace(outline, pWindow, pData, cOutline);
- break;
-
- case cShadow:
- ApplyFace(shadow, pWindow, pData, cShadow);
- break;
-
- case cCondensed:
- ApplyFace(condense, pWindow, pData, cCondensed);
- break;
-
- case cExtended:
- ApplyFace(extend, pWindow, pData, cExtended);
- break;
-
-
- // SUPPORTED SIZES
- case cSize9:
- anErr = ApplySize(9, pWindow, pData, cSize9);
- break;
-
- case cSize10:
- anErr = ApplySize(10, pWindow, pData, cSize10);
- break;
-
- case cSize12:
- anErr = ApplySize(12, pWindow, pData, cSize12);
- break;
-
- case cSize14:
- anErr = ApplySize(14, pWindow, pData, cSize14);
- break;
-
- case cSize18:
- anErr = ApplySize(18, pWindow, pData, cSize18);
- break;
-
- case cSize24:
- anErr = ApplySize(24, pWindow, pData, cSize24);
- break;
-
- case cSize36:
- anErr = ApplySize(36, pWindow, pData, cSize36);
- break;
-
-
- // SUPPORTED SOUND COMMANDS
- case cRecord:
- {
- Handle tempHandle;
-
- // allocate our prefered buffer if we can, but if we can't
- // make sure that at least a minimum amount of RAM is around
- // before recording.
- tempHandle = NewHandle(kPrefBufferSize);
- anErr = MemError();
- if (anErr != noErr)
- {
- tempHandle = NewHandle(kMinBufferSize);
- anErr = MemError();
- DisposeHandle(tempHandle);
- tempHandle = nil;
- }
-
- // if the preflight goes okay, do the record
- if (anErr == noErr)
- {
- Point where = {50, 100};
-
- anErr = SndRecord(nil, where, siGoodQuality, (SndListHandle*) &tempHandle);
- if (anErr == noErr)
- {
- DisposeHandle(((TextDataPtr) pData)->soundHandle);
- ((TextDataPtr) pData)->soundHandle = tempHandle;
- pData->changed = true;
- }
- else
- DisposeHandle(tempHandle);
-
- if (anErr == userCanceledErr)
- anErr = noErr;
- }
- }
- break;
-
- case cPlay:
- if (((TextDataPtr) pData)->soundHandle)
- (void) SndPlay(nil, (SndListHandle) ((TextDataPtr) pData)->soundHandle, false);
- break;
-
- case cErase:
- DisposeHandle(((TextDataPtr) pData)->soundHandle);
- ((TextDataPtr) pData)->soundHandle = nil;
- pData->changed = true;
- break;
-
- case cSpeak:
- DisposeOfSpeech(false);
- if (gSpeechChannel == nil)
- anErr = NewSpeechChannel( &gCurrentVoice, &gSpeechChannel );
-
- if ( anErr == noErr )
- {
- short textLength, textStart;
-
- // determine which text to speak
- if ( (**((TextDataPtr) pData)->hTE).selEnd > (**((TextDataPtr) pData)->hTE).selStart ) // If there is a selection.
- {
- textLength = (**((TextDataPtr) pData)->hTE).selEnd - (**((TextDataPtr) pData)->hTE).selStart;
- textStart = (**((TextDataPtr) pData)->hTE).selStart;
- }
- else // No text selected.
- {
- textLength = (**((TextDataPtr) pData)->hTE).teLength;
- textStart = 0;
- }
-
-
- gSpeakPtr = NewPtr(textLength);
- anErr = MemError();
- if (anErr == noErr)
- {
- BlockMoveData( *((**((TextDataPtr) pData)->hTE).hText) + textStart, gSpeakPtr, (Size) textLength );
- anErr = SpeakText( gSpeechChannel, gSpeakPtr, textLength );
- }
- }
- break;
-
- case cStopSpeaking:
- DisposeOfSpeech(true);
- break;
-
- case cSelectVoiceSubMenu:
- {
- VoiceSpec newSpec;
- short i, menuIndex;
- Str255 itemText;
- short theVoiceCount;
- MenuHandle menu = GetMenuHandle(mVoices);
-
- // in order to change voices, we need to ditch the speaking
- DisposeOfSpeech(true);
-
- // get the name of the selected voice
- menuIndex = menuResult & 0xFFFF;
- GetMenuItemText(menu, menuIndex, itemText);
-
- if (CountVoices( &theVoiceCount ) == noErr)
- {
- VoiceDescription description; // Info about a voice.
-
- for (i = 1; i <= theVoiceCount; ++i)
- {
- if ( (GetIndVoice( i, &newSpec ) == noErr) &&
- (GetVoiceDescription( &newSpec, &description, sizeof(description) ) == noErr ) )
- {
- if (IUCompString( itemText, description.name ) == 0)
- break;
- }
- }
- }
-
- gCurrentVoice = newSpec;
- for (i = CountMItems(menu); i >= 1; --i)
- CheckItem(menu, i, (menuIndex == i));
- }
- break;
-
-
- case cSelectContents:
- {
- Str255 searchStr;
- short menuIndex;
- long newStart, newEnd;
-
- menuIndex = menuResult & 0xFFFF;
-
- // get the search string for this menu item
- anErr = TextGetContentsListItem(pData, menuIndex, nil, searchStr, nil);
-
- if (anErr == noErr)
- {
- if (PerformSearch(
- (**((TextDataPtr) pData)->hTE).hText,
- 0, // start at beginning of text
- searchStr,
- false, // not case sensitive
- false, // forwards
- false, // wrap
- &newStart,
- &newEnd))
- {
-
- // <7>
-
- short amount;
- Point newSelectionPt;
-
- // get QuickDraw offset of found text,
- // scroll that amount plus a line height,
- // and add a fifth of the window for aesthetics (and
- // for slop to avoid fraction-of-line problems)
-
- newSelectionPt = TEGetPoint(newEnd, ((TextDataPtr) pData)->hTE);
-
- amount = - newSelectionPt.v + pData->vScrollAmount;
- amount += (pData->contentRect.bottom - pData->contentRect.top) / 5;
-
- SetControlAndClipAmount(pData->vScroll, &amount);
- if (amount != 0)
- {
- DoScrollContent(pWindow, pData, 0, amount);
- }
-
- // move selection to beginning of found text
- // (are the Adjust calls necessary?)
-
- TESetSelect(newStart, newStart, ((TextDataPtr) pData)->hTE);
- AdjustTE(pData, false);
- AdjustScrollBars(pWindow, false, false, nil);
-
- }
- else
- {
- // search failed
- SysBeep(10);
- }
- }
- }
- break;
- }
-
- return anErr;
-
- } // TextCommand
-
- // --------------------------------------------------------------------------------------------------------------
-
- static OSErr TextAdjustMenus(WindowRef pWindow, WindowDataPtr pData)
- {
- #pragma unused (pWindow)
-
- // enable the commands that we support for editable text document
- if (pData->originalFileType == 'TEXT')
- {
- if (((TextDataPtr) pData)->prevCommandID != cNull)
- EnableCommand(cUndo);
-
- if ( (**((TextDataPtr) pData)->hTE).selEnd > (**((TextDataPtr) pData)->hTE).selStart ) // If there is a selection.
- {
- EnableCommand(cCut);
- EnableCommand(cCopy);
- EnableCommand(cClear);
-
- EnableCommand(cFindSelection);
- }
-
- TEFromScrap();
- if (TEGetScrapLength() > 0)
- EnableCommand(cPaste);
-
- EnableCommand(cSaveAs);
- EnableCommand(cSelectAll);
-
- EnableCommand(cFind);
- EnableCommand(cReplace);
- if (gFindString[0] != 0)
- {
- EnableCommand(cFindAgain);
- EnableCommand(cReplaceAgain);
- }
-
- // enable all fonts, select the font current, if that's what's best
- EnableCommand(cSelectFont);
- {
- short mode = doFont;
- Str255 fontName, itemName;
- Str255 styleName;
- TextStyle theStyle;
- Boolean isCont;
- gxFont fontID;
-
- isCont = TEContinuousStyle(&mode, &theStyle, ((TextDataPtr) pData)->hTE);
- if (isCont)
- {
- if (gMachineInfo.haveGX)
- {
- fontID = QDToFont(theStyle.tsFont, theStyle.tsFace);
-
- fontName[0] = GXFindFontName(fontID, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &fontName[1], nil);
- styleName[0] = GXFindFontName(fontID, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &styleName[1], nil);
- }
- else
- {
- GetFontName(theStyle.tsFont, fontName);
- }
- }
-
-
- {
- MenuHandle menu = GetMenuHandle( mFont );
- short count = CountMItems(menu);
- short index;
-
- for (index = 1; index <= count; ++index)
- {
- short mark;
-
- GetItemMark(menu, index, &mark);
- if (isCont)
- {
- GetMenuItemText( menu, index, itemName );
-
- // don't change the checkmark if it's a heirarchichal menu, because
- // the mark actually holds the ID of sub-menu
- if ((mark == noMark) || (mark == checkMark))
- {
- CheckItem(menu, index, EqualString(itemName, fontName, true, true) );
- }
- else
- {
- // if it is a sub menu, we check there too
- MenuHandle subMenu = GetMenuHandle(mark);
- short subCount = CountMItems(subMenu);
- short subIndex;
-
- if (EqualString(itemName, fontName, true, true))
- {
- SetItemStyle(menu, index, underline);
- for (subIndex = 1; subIndex <= subCount; ++subIndex)
- {
- GetMenuItemText(subMenu, subIndex, itemName);
- CheckItem(subMenu, subIndex, EqualString(itemName, styleName, true, true) );
- }
- }
- else
- {
- SetItemStyle(menu, index, normal);
- for (subIndex = 1; subIndex <= subCount; ++subIndex)
- CheckItem(subMenu, subIndex, false );
- }
- }
- }
- else
- {
- if ((mark == noMark) || (mark == checkMark))
- CheckItem(menu, index, false);
- else
- SetItemStyle(menu, index, normal);
- }
- }
- }
- }
-
- // enable the sizes, and outline what's currently valid
- {
- short mode;
- TextStyle theStyle;
- Boolean isCont;
- short whichToCheck;
-
- // find out the continuous run of sizes
- whichToCheck = 0;
- mode = doSize;
- if (TEContinuousStyle(&mode, &theStyle, ((TextDataPtr) pData)->hTE))
- {
- whichToCheck = theStyle.tsSize;
-
- // default font size -> proper size
- if (whichToCheck == 0)
- whichToCheck = GetDefFontSize();
- }
-
- // find out the font runs
- mode = doFont;
- isCont = TEContinuousStyle(&mode, &theStyle, ((TextDataPtr) pData)->hTE);
-
- EnableCommandCheckStyle(cSize9, whichToCheck == 9, (isCont & RealFont(theStyle.tsFont, 9)) ? outline : normal);
- EnableCommandCheckStyle(cSize10, whichToCheck == 10, (isCont & RealFont(theStyle.tsFont, 10)) ? outline : normal);
- EnableCommandCheckStyle(cSize12, whichToCheck == 12, (isCont & RealFont(theStyle.tsFont, 12)) ? outline : normal);
- EnableCommandCheckStyle(cSize14, whichToCheck == 14, (isCont & RealFont(theStyle.tsFont, 14)) ? outline : normal);
- EnableCommandCheckStyle(cSize18, whichToCheck == 18, (isCont & RealFont(theStyle.tsFont, 18)) ? outline : normal);
- EnableCommandCheckStyle(cSize24, whichToCheck == 24, (isCont & RealFont(theStyle.tsFont, 24)) ? outline : normal);
- EnableCommandCheckStyle(cSize36, whichToCheck == 36, (isCont & RealFont(theStyle.tsFont, 36)) ? outline : normal);
- }
-
- {
- short mode = doFace;
- TextStyle theStyle;
- Style legalStyles;
-
- if (!TEContinuousStyle(&mode, &theStyle, ((TextDataPtr) pData)->hTE))
- {
- theStyle.tsFace = normal;
- EnableCommandCheck(cPlain, false);
- }
- else
- EnableCommandCheck(cPlain, theStyle.tsFace == normal);
-
- // <39> use the script manager to determine legal styles for this
- // run of text. If the legal styles are zero (trap unimplemented),
- // then we assume all styles.
- legalStyles = GetScriptVariable(GetScriptManagerVariable(smKeyScript), smScriptValidStyles);
- if (legalStyles == 0)
- legalStyles = 0xFFFF;
-
- if (legalStyles & bold)
- EnableCommandCheck(cBold, theStyle.tsFace & bold);
- if (legalStyles & italic)
- EnableCommandCheck(cItalic, theStyle.tsFace & italic);
- if (legalStyles & underline)
- EnableCommandCheck(cUnderline, theStyle.tsFace & underline);
- if (legalStyles & outline)
- EnableCommandCheck(cOutline, theStyle.tsFace & outline);
- if (legalStyles & shadow)
- EnableCommandCheck(cShadow, theStyle.tsFace & shadow);
- if (legalStyles & condense)
- EnableCommandCheck(cCondensed, theStyle.tsFace & condense);
- if (legalStyles & extend)
- EnableCommandCheck(cExtended, theStyle.tsFace & extend);
- }
-
- }
-
- // enable commands related to speaking the content if we have support for that
- if (gMachineInfo.haveTTS)
- {
- // if we are speaking, we can stop
- if (gSpeechChannel)
- EnableCommand(cStopSpeaking);
-
- // even while speaking, you can re-speak or select a new voice
- EnableCommand(cSpeak);
- EnableCommand(cSelectVoice);
- EnableCommand(cSelectVoiceSubMenu);
-
- if ( (**((TextDataPtr) pData)->hTE).selEnd > (**((TextDataPtr) pData)->hTE).selStart ) // If there is a selection.
- ChangeCommandName(cSpeak, kTextStrings, iSpeakSelection);
- else
- ChangeCommandName(cSpeak, kTextStrings, iSpeakAll);
-
- }
-
- // enable the correct controls to go with sound input/output
- if (((TextDataPtr) pData)->soundHandle)
- EnableCommand(cPlay);
- if (pData->originalFileType == 'TEXT')
- {
- if (((TextDataPtr) pData)->soundHandle)
- EnableCommand(cErase);
- else
- {
- if (gMachineInfo.haveRecording)
- EnableCommand(cRecord);
- }
- }
-
- // enable the contents menu, if any
- (void) TextAdjustContentsMenu(pData);
-
- // enable commands that we support at all times
- if (GetControlMaximum(pData->vScroll) != 0)
- {
- EnableCommand(cNextPage);
- EnableCommand(cPreviousPage);
- }
-
- return noErr;
-
- } // TextAdjustMenus
-
- // --------------------------------------------------------------------------------------------------------------
-
- static OSErr TextGetDocumentRect(WindowRef pWindow, WindowDataPtr pData,
- LongRect * documentRectangle, Boolean forGrow)
- {
- #pragma unused (pWindow)
-
- Rect theRect = pData->contentRect;
- Rect maxRect = (**GetGrayRgn()).rgnBBox;
-
- if ( (!forGrow) && (!(((TextDataPtr) pData)->insideClickLoop) ) )
- RecalcTE(pData, false);
-
- theRect.bottom = CalculateTextEditHeight(((TextDataPtr) pData)->hTE);
- theRect.bottom += kMargins*2;
- theRect.right = maxRect.right;
-
- if (theRect.bottom < pData->contentRect.bottom)
- theRect.bottom = pData->contentRect.bottom;
-
- if (forGrow)
- theRect.bottom = maxRect.bottom-kScrollBarSize;
-
- RectToLongRect(&theRect, documentRectangle);
-
- return noErr;
-
- } // TextGetDocumentRect
-
- // --------------------------------------------------------------------------------------------------------------
-
- static OSErr TextGetBalloon(WindowRef pWindow, WindowDataPtr pData,
- Point *localMouse, short * returnedBalloonIndex, Rect *returnedRectangle)
- {
- #pragma unused (pWindow, pData, localMouse, returnedRectangle)
-
- *returnedBalloonIndex = iHelpTextContent;
-
- return noErr;
-
- } // TextGetBalloon
-
- // --------------------------------------------------------------------------------------------------------------
-
- static long TextCalculateIdleTime(WindowRef pWindow, WindowDataPtr pData)
- {
- #pragma unused (pWindow, pData)
-
- if ( (gMachineInfo.amInBackground) || (! (**(((TextDataPtr) pData)->hTE)).active) )
- return(0x7FFFFFF);
- else
- return(1);
-
- } // TextCalculateIdleTime
-
- // --------------------------------------------------------------------------------------------------------------
-
- static OSErr TextAdjustCursor(WindowRef pWindow, WindowDataPtr pData,
- Point * localMouse, Rect * globalRect)
- {
- #pragma unused (pWindow, globalRect)
-
- OSErr anErr = noErr;
- CursHandle theCross;
- RgnHandle hilightRgn;
-
- if (gMachineInfo.haveDragMgr)
- {
- hilightRgn = NewRgn();
- TEGetHiliteRgn(hilightRgn, ((TextDataPtr) pData)->hTE);
- if (PtInRgn(*localMouse, hilightRgn))
- {
- SetCursor(&qd.arrow);
- DisposeRgn(hilightRgn);
- return eActionAlreadyHandled;
- }
-
- DisposeRgn(hilightRgn);
- }
-
- theCross = GetCursor(iBeamCursor);
- if (theCross)
- {
- char oldState;
-
- oldState = HGetState((Handle) theCross);
- HLock((Handle) theCross);
- SetCursor(*theCross);
- HSetState((Handle) theCross, oldState);
- anErr = eActionAlreadyHandled;
- }
-
- return anErr;
-
- } // TextAdjustCursor
-
- // --------------------------------------------------------------------------------------------------------------
-
- short gNilCaretProc[] = {
- 0x584F, // ADDQ.W #$4, A7
- 0x4E75}; // RTS
-
- // --------------------------------------------------------------------------------------------------------------
-
- static OSErr TextPrintPage(WindowRef pWindow, WindowDataPtr pData,
- Rect * pageRect, long *pageNum)
- {
- #pragma unused (pWindow)
-
- OSErr anErr = noErr;
- short footerHeight;
- TEHandle hTE;
- Rect areaForThisPage;
- short ourPage = 1;
- Boolean documentHasFormControl = Count1Resources(kFormResource) != 0;
-
- // calculate area for the footer (page number)
- {
- FontInfo theInfo;
-
- TextFont(0);
- TextSize(0);
- TextFace(normal);
- GetFontInfo(&theInfo);
- footerHeight = (theInfo.ascent + theInfo.descent + theInfo.leading) << 1;
- }
-
- // duplicate the text edit record, disable the selection before swapping the new port in
- hTE = ((TextDataPtr) pData)->hTE;
- TEDeactivate(hTE);
-
- anErr = HandToHand((Handle*) &hTE);
- nrequire(anErr, DuplicateTE);
-
- // turn off outline hilighting -- because the window is disabled while
- // printing is going on, but we don't want that disabled hilight to draw
- TEFeatureFlag(teFOutlineHilite, teBitClear, ((TextDataPtr) pData)->hTE);
-
- // now HERE'S a real hack! Under certain conditions, Text Edit will draw the
- // cursor, even if you said the edit record is inactive! This happens when
- // the internal state sez that the cursor hasn't been drawn yet. Lucky
- // for us, the caret is drawn through a hook, which we replace with a NOP.
- (**hTE).caretHook = (CaretHookUPP) gNilCaretProc;
-
- // point the rectangles to be the page rect minus the footer
- areaForThisPage = *pageRect;
- areaForThisPage.bottom -= footerHeight;
- if (gMachineInfo.haveGX)
- InsetRect(&areaForThisPage, kGXPrintMargins, kGXPrintMargins);
- else
- InsetRect(&areaForThisPage, kPrintMargins, kPrintMargins);
- (**hTE).viewRect = (**hTE).destRect = areaForThisPage;
-
- // recalculate the line breaks
- TECalText(hTE);
-
- // point it at the printing port.
- (**hTE).inPort = qd.thePort;
-
- // now loop over all pages doing page breaking until we find our current
- // page, which we print, and then return.
- {
- Rect oldPageHeight = (**hTE).viewRect;
- short currentLine = 0;
- long prevPageHeight = 0;
-
- while (ourPage <= *pageNum)
- {
- long currentPageHeight = 0;
-
- // calculate the height including the current page, breaks
- // when one of three things happen:
- // 1) adding another line to this page would go beyond the length of the page
- // 2) a picture needs to be broken to the next page (NOT YET IMPLEMENTED)
- // 3) we run out of lines for the document
- // 4) if the line has a page break (defined as a non breaking space w/o a PICT)
-
- // POTENTIAL BUG CASES:
- // If a single line > the page height. Can that happen? If so, we need to
- // add something to handle it.
- do
- {
- long currentLineHeight;
-
- // zero based count -- but one based calls to TEGetHeight
- currentLineHeight = TEGetHeight(currentLine+1, currentLine+1, hTE);
-
- // if adding this line would just be too much, break out of here
- if ((currentLineHeight + currentPageHeight) > (areaForThisPage.bottom - areaForThisPage.top))
- break;
-
- ++ currentLine;
- currentPageHeight += currentLineHeight;
-
- // if this line had a page break on it, break out of pagination
- if (documentHasFormControl && LineHasPageBreak(currentLine-1, hTE))
- break;
-
- } while (currentLine < (**hTE).nLines);
-
- // if this the page we are trying to print
- if (ourPage == *pageNum)
- {
- Str255 pageString;
- RgnHandle oldRgn = NewRgn();
-
- // move onto the next page via offset by the previous pages -- but
- // clip to the current page height because we wouldn't want to see
- // half of a line from the next page at the bottom of a page.
- OffsetRect(&oldPageHeight, 0, -(prevPageHeight));
- oldPageHeight.bottom = oldPageHeight.top + currentPageHeight;
- (**hTE).destRect = oldPageHeight;
-
- // clip to this area as well
- areaForThisPage.bottom = areaForThisPage.top + currentPageHeight;
- GetClip(oldRgn);
- ClipRect(&areaForThisPage);
-
- // draw the edit record, plus our cool pictures
- TEUpdate(&areaForThisPage, hTE);
- DrawPictures(pData, hTE);
-
- // restore the clip
- SetClip(oldRgn);
- DisposeRgn(oldRgn);
-
- // Draw the page string at the bottom of the page, centered
- pageString[0] = 2;
- pageString[1] = '-';
- NumToString(*pageNum, &pageString[2]);
- pageString[0] += pageString[2];
- pageString[2] = ' ';
- pageString[++pageString[0]] = ' ';
- pageString[++pageString[0]] = '-';
-
- MoveTo(
- pageRect->left +
- ((pageRect->right - pageRect->left) >> 1) -
- (StringWidth(pageString)>>1),
- pageRect->bottom - kPrintMargins);
-
- DrawString(pageString);
-
- // if we have completed all pages
- if (currentLine >= (**hTE).nLines)
- {
- // tell it to stop printing
- *pageNum = -1;
- }
-
- // get out of here!
- break;
- }
-
- // move onto the next page via count
- ++ourPage;
-
- // and the list of pages before now includes this page we just finished
- prevPageHeight += currentPageHeight;
-
- }
-
- }
-
-
- // restore text for visible page if done
- if (*pageNum == -1)
- {
- TEFeatureFlag(teFOutlineHilite, teBitSet, ((TextDataPtr) pData)->hTE);
- TECalText(((TextDataPtr) pData)->hTE);
- if (pData->originalFileType != 'ttro')
- TEActivate(((TextDataPtr) pData)->hTE);
- }
-
- // FALL THROUGH EXCEPTION HANDLING
-
- // Dispose this way to avoid disposing of any owned objects
- DisposeHandle((Handle) hTE);
- DuplicateTE:
-
- return anErr;
-
- } // TextPrintPage
-
- // --------------------------------------------------------------------------------------------------------------
-
- static OSErr TextMakeWindow(WindowRef pWindow, WindowDataPtr pData)
- {
- #pragma unused(pWindow)
-
- OSErr anErr = noErr;
-
- pData->bumpUntitledCount = true;
-
- pData->pScrollContent = (ScrollContentProc) TextScrollContent;
- pData->pAdjustSize = (AdjustSizeProc) TextAdjustSize;
- pData->pGetDocumentRect = (GetDocumentRectProc) TextGetDocumentRect;
- pData->pAdjustMenus = (AdjustMenusProc) TextAdjustMenus;
- pData->pCommand = (CommandProc) TextCommand;
-
- pData->pCloseWindow = (CloseWindowProc) TextCloseWindow;
- pData->pFilterEvent = (FilterEventProc) TextFilterEvent;
- pData->pActivateEvent = (ActivateEventProc) TextActivateEvent;
- pData->pUpdateWindow = (UpdateWindowProc) TextUpdateWindow;
- pData->pPrintPage = (PrintPageProc) TextPrintPage;
-
- // we only support keydowns and editing for modifable docs
- if (pData->originalFileType != 'ttro')
- {
- pData->pKeyEvent = (KeyEventProc) TextKeyEvent;
- pData->pContentClick = (ContentClickProc) TextContentClick;
- pData->pAdjustCursor = (AdjustCursorProc) TextAdjustCursor;
- pData->pGetBalloon = (GetBalloonProc) TextGetBalloon;
- pData->pCalculateIdleTime = (CalculateIdleTimeProc) TextCalculateIdleTime;
-
- // We can always reference our Drag handlers, because they will not be called if we
- // don't have the Drag Manager available. We needn't check here (it would be redundant).
- pData->pDragTracking = (DragTrackingProc) TextDragTracking;
- pData->pDragReceive = (DragReceiveProc) TextDragReceive;
-
- pData->documentAcceptsText = true;
- }
-
- // leave room for the grow area at bottom
- pData->hasGrow = true;
- pData->contentRect.bottom -= kScrollBarSize;
- if ((pData->contentRect.right - pData->contentRect.left) > kOnePageWidth)
- pData->contentRect.right = pData->contentRect.left + kOnePageWidth;
-
- ((TextDataPtr) pData)->hTE = TEStyleNew(&pData->contentRect, &pData->contentRect);
- anErr = MemError();
- nrequire(anErr, TENewFailed);
-
- pData->hScrollAmount = 0;
- pData->vScrollAmount = TEGetHeight(0, 0, ((TextDataPtr) pData)->hTE);
-
- TEAutoView(true, ((TextDataPtr) pData)->hTE);
-
- // Setup our click loop to handle autoscrolling
- ((TextDataPtr) pData)->docClick = (**(((TextDataPtr) pData)->hTE)).clickLoop;
- TESetClickLoop(gMyClickLoop, ((TextDataPtr) pData)->hTE);
-
- // if we have a data fork, read the contents into the record
- if (pData->dataRefNum != -1)
- {
- long dataSize;
-
- GetEOF(pData->dataRefNum, &dataSize);
- if (dataSize > kMaxLength)
- anErr = eDocumentTooLarge;
- else
- {
- Handle tempHandle = NewHandle(dataSize);
- anErr = MemError();
- if (anErr == noErr)
- {
- // read the text in
- SetFPos(pData->dataRefNum, fsFromStart, 0);
- anErr = FSRead(pData->dataRefNum, &dataSize, * tempHandle);
-
- // then insert it.
- if (anErr == noErr)
- {
- HLock(tempHandle);
- TEStyleInsert(*tempHandle, dataSize, nil, ((TextDataPtr) pData)->hTE);
- anErr = MemError();
- }
- DisposeHandle(tempHandle);
- }
-
- }
-
- }
- nrequire(anErr, ReadData);
-
- // if we have a resource fork, read the contents
- if (pData->resRefNum != -1)
- {
- short oldResFile = CurResFile();
- Handle theStyle;
-
- // read the style information
- UseResFile(pData->resRefNum);
- theStyle = Get1Resource('styl', 128);
- if (theStyle)
- {
- HNoPurge(theStyle);
- TEUseStyleScrap(0, 32767, (StScrpHandle) theStyle, true, ((TextDataPtr) pData)->hTE);
- ReleaseResource(theStyle);
- }
-
- // if we have sound, load it in and detach it
- {
- Handle soundHandle = Get1Resource('snd ', kSoundBase);
- if (soundHandle)
- {
- HNoPurge(soundHandle);
- DetachResource(soundHandle);
- ((TextDataPtr) pData)->soundHandle = soundHandle;
- }
- }
-
-
- UseResFile(oldResFile);
- }
-
- // hook out drawing of the non-breaking space for read only documents,
- // for modifiable documents, enable outline hiliting (ie, when TE window
- // isn't in front, show the gray outline)
- if (pData->originalFileType == 'ttro')
- {
- UniversalProcPtr hookRoutine = (UniversalProcPtr)gMyDrawGlue;
-
- TECustomHook(intDrawHook, &hookRoutine, ((TextDataPtr) pData)->hTE);
- }
- else
- {
- TEFeatureFlag(teFOutlineHilite, teBitSet, ((TextDataPtr) pData)->hTE);
- }
-
- // make a TSM document if this is editable
- if (
- (pData->originalFileType != 'ttro') &&
- (gMachineInfo.haveTSMTE)
- )
- {
- OSType supportedInterfaces[1];
-
- supportedInterfaces[0] = kTSMTEInterfaceType;
-
- if (NewTSMDocument(1, supportedInterfaces,
- &pData->docTSMDoc, (long)&pData->docTSMRecHandle) == noErr)
- {
- long response;
-
- (**(pData->docTSMRecHandle)).textH = ((TextDataPtr) pData)->hTE;
- if ((Gestalt(gestaltTSMTEVersion, &response) == noErr) && (response == gestaltTSMTE1))
- (**(pData->docTSMRecHandle)).preUpdateProc = gTSMPreUpdateProc;
- (**(pData->docTSMRecHandle)).postUpdateProc = gTSMPostUpdateProc;
- (**(pData->docTSMRecHandle)).updateFlag = kTSMTEAutoScroll;
- (**(pData->docTSMRecHandle)).refCon = (long)pData;
- }
- }
-
- // now we have added text, so adjust views and such as needed
- TESetSelect(0, 0, ((TextDataPtr) pData)->hTE);
- RecalcTE(pData, true);
- AdjustTE(pData, true);
-
- // ???? Hack to get around a 7.0 TextEdit bug. If you are pasting a multiple
- // line clipboard into TE, *and* the TextEdit record is new, *and* the selection
- // is at the begining of the doc (0,0 as above), *and* you haven't moved the
- // cursor around at all, then TE pastes thinking it's at the end of the line,
- // when it really should be at the begining. Then if you <cr> with the cursor
- // visible, it'll leave a copy behind.
-
- // I'm not happy with this, but I don't know another way around the problem.
- if (pData->originalFileType != 'ttro')
- {
- TEKey(0x1F, ((TextDataPtr) pData)->hTE);
- TEKey(0x1E, ((TextDataPtr) pData)->hTE);
- }
-
- // <39> if this is a new document, convert the "system size", "system font", and
- // "application font" into real font IDs and sizes. This is so that
- // if someone saves this document and opens it with another script
- // system, they don't get all huffy that the font changed on them.
- // It also solves problems with cut and paste to applications too stupid
- // to know that "zero" means system size.
- if (pData->dataRefNum == -1)
- {
- TEHandle hTE = ((TextDataPtr) pData)->hTE;
- short mode = doAll;
- TextStyle theStyle;
-
- TEContinuousStyle(&mode, &theStyle, hTE);
- if (theStyle.tsSize == 0)
- theStyle.tsSize = GetDefFontSize();
- if (theStyle.tsFont == systemFont)
- theStyle.tsFont = GetSysFont();
- if (theStyle.tsFont == applFont)
- theStyle.tsFont = GetAppFont();
-
- mode = doAll;
- TESetStyle(mode, &theStyle, false, hTE);
- }
-
- // if stationary, use untitled and close down the files
- if (pData->originalFileType == 'sEXT')
- {
- pData->originalFileType = 'TEXT';
- pData->openAsNew = true;
- if (pData->resRefNum != -1)
- CloseResFile(pData->resRefNum);
- if (pData->dataRefNum != -1)
- FSClose(pData->dataRefNum);
- pData->resRefNum = pData->dataRefNum = -1;
- }
-
- // initalize undo information
- ((TextDataPtr) pData)->prevCommandID = cNull;
-
- // if we have voices, add them to the menu
- if ( (gMachineInfo.haveTTS) && (!gAddedVoices) )
- {
- short theVoiceCount;
- short i, item;
-
- if (CountVoices( &theVoiceCount ) == noErr)
- {
- VoiceSpec spec; // A voice to add to the menu.
- VoiceDescription description; // Info about a voice.
- MenuHandle voicesMenu = GetMenuHandle(mVoices);
-
- anErr = GetVoiceDescription( nil, &description, sizeof(description) );
- if (anErr == noErr)
- {
- gCurrentVoice = description.voice;
- for (i = 1; i <= theVoiceCount; ++i)
- {
- if ( (GetIndVoice( i, &spec ) == noErr) &&
- (GetVoiceDescription( &spec, &description, sizeof(description) ) == noErr ) )
- {
- short menuCount = CountMItems( voicesMenu );
-
- // first one we are adding == get rid of item already there
- if ( (i == 1) && (menuCount > 0) )
- {
- DeleteMenuItem( voicesMenu, 1 );
- --menuCount;
- }
-
- for ( item = 1; item <= menuCount; ++item )
- {
- Str255 itemText;
-
- GetMenuItemText( voicesMenu, item, itemText );
- /*1st > 2nd*/
- if ( IUCompString( itemText, description.name ) == 1 )
- break; // Found where name goes in list.
- }
-
- InsertMenuItem( voicesMenu, "\p ", item - 1 );
- SetMenuItemText( voicesMenu, item, description.name );
-
- CheckItem(voicesMenu, item,
- ((gCurrentVoice.creator == spec.creator) && (gCurrentVoice.id == spec.id)) );
- }
- }
-
- }
-
- gAddedVoices = true;
- }
-
- } // end of adding voices
-
- return noErr;
-
- // EXCEPTION HANDLING
- ReadData:
- TEDispose(((TextDataPtr) pData)->hTE);
-
- TENewFailed:
-
- return anErr;
-
- } // TextMakeWindow
-
-
- // --------------------------------------------------------------------------------------------------------------
-
- OSErr TextPreflightWindow(PreflightPtr pPreflightData)
- {
- pPreflightData->continueWithOpen = true;
- pPreflightData->wantVScroll = true;
- pPreflightData->doZoom = true;
- pPreflightData->makeProcPtr = TextMakeWindow;
- if (pPreflightData->fileType != 'ttro')
- pPreflightData->openKind = fsRdWrPerm;
-
- pPreflightData->storageSize = sizeof(TextDataRecord);
-
- // get strings that mark the picture
- GetIndString(gPictMarker1, kTextStrings, iPictureMarker1);
- GetIndString(gPictMarker2, kTextStrings, iPictureMarker2);
-
- return noErr;
-
- } // TextPreflightWindow
-
- // --------------------------------------------------------------------------------------------------------------
-
- void TextGetFileTypes(OSType * pFileTypes, OSType * pDocumentTypes, short * numTypes)
- {
- pFileTypes[*numTypes] = 'TEXT';
- pDocumentTypes[*numTypes] = kTextWindow;
- (*numTypes)++;
-
- pFileTypes[*numTypes] = 'ttro';
- pDocumentTypes[*numTypes] = kTextWindow;
- (*numTypes)++;
-
- pFileTypes[*numTypes] = 'sEXT';
- pDocumentTypes[*numTypes] = kTextWindow;
- (*numTypes)++;
-
- } // TextGetFileTypes
-
- // --------------------------------------------------------------------------------------------------------------
-
-
-
- // TextAddContentsMenu checks if there is a contents list and, if there
- // is, creates a new menu handle for the contents list and fills it with
- // the appropriate visible items
-
- void TextAddContentsMenu(WindowDataPtr pData)
- {
- MenuHandle contentsMenu;
- Str255 menuStr;
- short totalItems;
- short index;
- OSErr err;
-
- contentsMenu = GetMenuHandle(mContents);
- require(contentsMenu == nil, ContentsMenuAlreadyInstalled);
-
- // Is there a contents list? If so, get the menu name
- // and the number of items in the list
-
- if (TextGetContentsListItem(pData, 0, menuStr, nil, &totalItems) == noErr)
- {
-
- // create the menu and fill it with all the items
- // listed in the string list resource
-
- contentsMenu = NewMenu(mContents, menuStr);
- require(contentsMenu != nil, CantCreateContentsMenu);
-
- for (index = 1; index < totalItems; index++)
- {
- err = TextGetContentsListItem(pData, index, menuStr, nil, nil);
- require(err == noErr, CantGetItem);
-
- AppendMenu(contentsMenu, menuStr);
- }
-
- // add the menu to the menu bar, and redraw the menu bar
- InsertMenu(contentsMenu, 0);
- DrawMenuBar();
- }
- else
- {
- // no contents, do nothing
- }
-
- return;
-
- // error handling
- CantGetItem:
- CantCreateContentsMenu:
-
- if (contentsMenu) DisposeMenu(contentsMenu);
-
- ContentsMenuAlreadyInstalled:
-
- return;
-
- } // TextAddContentsMenu
-
-
-
-
- // TextRemoveContentsMenu removes the contents menu, if any,
- // and redraws the menu bar
-
- static void TextRemoveContentsMenu(WindowDataPtr pData)
- {
- #pragma unused (pData)
-
- MenuHandle contentsMenu;
-
- contentsMenu = GetMenuHandle(mContents);
- if (contentsMenu)
- {
- DeleteMenu(mContents);
- DisposeMenu(contentsMenu);
- DrawMenuBar();
- }
-
- } // TextRemoveContentsMenu
-
-
-
- // TextGetContentsListItem is a general utility routine for examining the
- // contents menu list, returning the menu and search strings, and returning
- // the total number of entries in the contents list.
- //
- // Pass 0 as itemNum to retrieve the strings for the contents menu title.
- //
- // Pass nil for menuStr, searchStr, or totalItems if you don't want that
- // info returned.
- //
- // Returns eDocumentHasNoContentsEntries if there is no contents string list
- // resource for the specified window
-
- static OSErr TextGetContentsListItem(WindowDataPtr pData, short itemNum,
- StringPtr menuStr, StringPtr searchStr,
- short *totalItems)
- {
-
- OSErr err;
- short oldResFile;
- short menuItemNum;
- short searchItemNum;
- Handle contentsStrListHandle;
-
- // if no original resource file, don't bother
- if (pData->resRefNum == -1)
- {
- return eDocumentHasNoContentsEntries;
- }
-
- err = noErr;
-
- oldResFile = CurResFile();
- UseResFile(pData->resRefNum);
-
- // two entries per item
- //
- // first (itemNum zero) is content menu title
- // (second -- itemNum one, search string for menu title -- is unused)
-
- menuItemNum = itemNum * 2 + 1;
- searchItemNum = menuItemNum + 1;
-
- contentsStrListHandle = Get1Resource('STR#', kContentsListID);
- if (contentsStrListHandle)
- {
- if (totalItems) *totalItems = (*(short *)*contentsStrListHandle) / 2;
-
- if (menuStr) GetIndString(menuStr, kContentsListID, menuItemNum);
- if (searchStr)
- {
- GetIndString(searchStr, kContentsListID, searchItemNum);
-
- if (searchStr[0] == 0)
- {
- // search string was empty, so use the
- // menu string as the search string
-
- GetIndString(searchStr, kContentsListID, menuItemNum);
- }
- }
- }
- else
- {
- err = eDocumentHasNoContentsEntries;
- if (totalItems) *totalItems = 0;
- }
-
- UseResFile(oldResFile);
-
- return err;
- } // TextGetContentsListItem
-
-
- // TextAdjustContentsMenu enables the items in the contents menu
- //
- // This routine is essentially a placeholder in case the contents
- // menu really were to be dynamically enabled.
-
- static OSErr TextAdjustContentsMenu(WindowDataPtr pData)
- {
- #pragma unused (pData)
-
- EnableCommand(cSelectContents);
- return(noErr);
-
- } // TextAdjustContentsMenu
-
-