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.
TESample.cp
/*------------------------------------------------------------------------------------------ |
Program: CPlusTESample 2.0 |
File: TESample.cp |
Uses: TEDocument.h |
TESample.h |
by Andrew Shebanow |
of Apple Macintosh Developer Technical Support |
Copyright © 1989-1990 Apple Computer, Inc. |
All rights reserved. |
------------------------------------------------------------------------------------------*/ |
#ifndef __TYPES__ |
#include <Types.h> |
#endif |
#ifndef __QUICKDRAW__ |
#include <QuickDraw.h> |
#endif |
#ifndef __FONTS__ |
#include <Fonts.h> |
#endif |
#ifndef __EVENTS__ |
#include <Events.h> |
#endif |
#ifndef __CONTROLS__ |
#include <Controls.h> |
#endif |
#ifndef __WINDOWS__ |
#include <Windows.h> |
#endif |
#ifndef __MENUS__ |
#include <Menus.h> |
#endif |
#ifndef __TEXTEDIT__ |
#include <TextEdit.h> |
#endif |
#ifndef __DIALOGS__ |
#include <Dialogs.h> |
#endif |
#ifndef __MENUS__ |
#include <Menus.h> |
#endif |
#ifndef __DEVICES__ |
#include <Devices.h> |
#endif |
#ifndef __SCRAP__ |
#include <Scrap.h> |
#endif |
#ifndef __TOOLUTILS__ |
#include <ToolUtils.h> |
#endif |
#ifndef __MEMORY__ |
#include <Memory.h> |
#endif |
#ifndef __SEGLOAD__ |
#include <SegLoad.h> |
#endif |
#ifndef __FILES__ |
#include <Files.h> |
#endif |
#ifndef __OSUTILS__ |
#include <OSUtils.h> |
#endif |
#ifndef __TRAPS__ |
#include <Traps.h> |
#endif |
#ifndef __PACKAGES__ |
#include <Packages.h> |
#endif |
#ifndef __ERRORS__ |
#include <Errors.h> |
#endif |
// our class definitions |
#include "TEDocument.h" |
#include "TESample.h" |
// ExtremeNeg and ExtremePos are used to set up wide open rectangles and regions. |
const short kExtremeNeg = -32768; |
const short kExtremePos = 32767 - 1; // required to address an old region bug |
// kMaxOpenDocuments is used to determine whether a new document can be opened |
// or created. We keep track of the number of open documents, and disable the |
// menu items that create a new document when the maximum is reached. If the |
// number of documents falls below the maximum, the items are enabled again. |
const short kMaxOpenDocuments = 4; |
const OSType kCreatorType = 'MOOT'; |
// Define max and min macros for efficiency. |
#define max(a,b) ((a) > (b) ? (a) : (b)) |
#define min(a,b) ((a) < (b) ? (a) : (b)) |
// Our application object, initialized in main(). We make it |
// global so our functions which don't belong to any class |
// can find the active document. |
TESample* gTheApplication; |
// main is the entrypoint to the program |
int main() |
{ |
// Create our application object. This MUST be the FIRST thing |
// done in main(), since it initializes the Toolbox for us. |
gTheApplication = new TESample; |
if (gTheApplication == nil) // if we couldn't allocate object (impossible!?) |
ExitToShell(); // go back to Finder |
gTheApplication->ProcessArgs(); |
// Start our main event loop running. This won't return until user quits |
gTheApplication->EventLoop(); |
// We always return a value, like good little ANSI worshippers, |
// so that the compiler won't complain |
return 0; |
} |
// the constructor for our class, called automatically when we create |
// an instance of this class. In this particular case, we only want |
// one instance since the constructor does all the menu setups and |
// creates our (untitled) document. |
// Note that we call our base TApplication constructor, passing it |
// our creator signature constant. |
TESample::TESample() : TApplication(kCreatorType) |
{ |
Handle menuBar; |
// read menus into menu bar |
menuBar = GetNewMBar(rMenuBar); |
// install menus |
SetMenuBar(menuBar); |
DisposeHandle(menuBar); |
// add DA names to Apple menu |
AppendResMenu(GetMenuHandle(mApple), 'DRVR'); |
DrawMenuBar(); |
// create empty mouse region |
fMouseRgn = NewRgn(); |
// make sure we have a valid cursor region |
AdjustCursor(); |
} |
// Tell TApplication class how much heap we need |
long TESample::HeapNeeded() |
{ |
return (kMinSize * 1024); |
} |
// Calculate a sleep value for WaitNextEvent. This takes into account the things |
// that DoIdle does with idle time. |
unsigned long TESample::SleepVal() |
{ |
unsigned long sleep; |
sleep = kMaxSleepTime; // default value for sleep |
// if we aren't in background, let document tell us how long to sleep |
if ((!fInBackground) && (fCurDoc != nil)) |
sleep = min(sleep,fCurDoc->CalcIdle()); |
return sleep; |
} |
// This is called whenever we get a null event et al. |
// It takes care of necessary periodic actions. For this program, |
// it calls TEIdle. |
void TESample::DoIdle() |
{ |
TEDocument* fTECurDoc = (TEDocument*) fCurDoc; |
if (fTECurDoc != nil) |
fTECurDoc->DoIdle(); |
} // DoIdle |
// Change the cursor's shape, depending on its position. This also calculates a |
// region that includes the cursor for WaitNextEvent. |
void TESample::AdjustCursor() |
{ |
TEDocument* fTECurDoc = (TEDocument*) fCurDoc; |
// notice that we don't change cursor if front window isn't ours |
if ( (!fInBackground) && (fTECurDoc != nil) ) |
{ |
RgnHandle arrowRgn; |
RgnHandle iBeamRgn; |
Point mouse; |
// get mouse location and convert to global coordinates |
GetMouse(&mouse); |
LocalToGlobal(&mouse); |
// calculate regions for different cursor shapes |
arrowRgn = NewRgn(); |
iBeamRgn = NewRgn(); |
// start arrowRgn wide open |
SetRectRgn(arrowRgn, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos); |
// calculate iBeamRgn |
fTECurDoc->GetVisTERgn(iBeamRgn); |
// subtract iBeamRgn from arrowRgn |
DiffRgn(arrowRgn, iBeamRgn, arrowRgn); |
// change the cursor and the region parameter |
if (PtInRgn(mouse, iBeamRgn)) |
{ |
SetCursor(*GetCursor(iBeamCursor)); |
CopyRgn(iBeamRgn, fMouseRgn); |
} |
else |
{ |
SetCursor(&qd.arrow); |
CopyRgn(arrowRgn, fMouseRgn); |
} |
// get rid of regions we don't need anymore |
DisposeRgn(arrowRgn); |
DisposeRgn(iBeamRgn); |
} |
} // AdjustCursor |
// Enable and disable menus based on the current state. The |
// user can only select enabled menu items. We set up all the |
// menu items before calling MenuSelect or MenuKey, since |
// these are the only times that a menu item can be selected. |
// Note that MenuSelect is also the only time the user will |
// see menu items. This approach to deciding what enable/ |
// disable state a menu item has the advantage of |
// concentrating all the decision-making in one routine, as |
// opposed to being spread throughout the application. Other |
// application designs may take a different approach that may |
// or may not be as valid. |
void TESample::AdjustMenus() |
{ |
WindowPtr frontmost; |
MenuHandle fileMenu, editMenu; |
long offset; |
Boolean undo; |
Boolean cutCopyClear; |
Boolean paste; |
Boolean save, saveAs; |
Boolean selectAll; |
TEDocument* fTECurDoc = (TEDocument*) fCurDoc; |
frontmost = FrontWindow(); |
fileMenu = GetMenuHandle(mFile); |
if (fDocList->NumDocs() < kMaxOpenDocuments) |
{ |
// New & Open are enabled when we can open more documents |
EnableItem(fileMenu, iNew); |
EnableItem(fileMenu, iOpen); |
} |
else |
{ |
DisableItem(fileMenu, iNew); |
DisableItem(fileMenu, iOpen); |
} |
if (frontmost != (WindowPtr) nil) // Close is enabled when there is a window to close |
EnableItem(fileMenu, iClose); |
else DisableItem(fileMenu, iClose); |
editMenu = GetMenuHandle(mEdit); |
undo = false; |
cutCopyClear = false; |
paste = false; |
save = saveAs = false; |
selectAll = false; |
if (frontmost != nil) |
{ |
selectAll = true; |
if (fCurDoc == nil) |
{ |
undo = true; // all editing is enabled for DA windows |
cutCopyClear = true; |
paste = true; |
} |
else |
{ |
// Cut, Copy, and Clear is enabled for app. windows with selections |
if ( fTECurDoc->HaveSelection() ) |
cutCopyClear = true; |
// If we have any TEXT in the scrap, enable paste |
if ( GetScrap(nil, 'TEXT', &offset) ) |
paste = true; |
// enable save if we are dirty |
save = fCurDoc->CanSave(); |
saveAs = fCurDoc->CanSaveAs(); |
} |
} |
if (save) |
EnableItem(fileMenu, iSave); |
else DisableItem(fileMenu, iSave); |
if (saveAs) |
EnableItem(fileMenu, iSaveAs); |
else DisableItem(fileMenu, iSaveAs); |
if (undo) |
EnableItem(editMenu, iUndo); |
else DisableItem(editMenu, iUndo); |
if ( cutCopyClear ) |
{ |
EnableItem(editMenu, iCut); |
EnableItem(editMenu, iCopy); |
EnableItem(editMenu, iClear); |
} |
else |
{ |
DisableItem(editMenu, iCut); |
DisableItem(editMenu, iCopy); |
DisableItem(editMenu, iClear); |
} |
if (paste) |
EnableItem(editMenu, iPaste); |
else DisableItem(editMenu, iPaste); |
if (selectAll) |
EnableItem(editMenu, iSelectAll); |
else DisableItem(editMenu, iSelectAll); |
} // AdjustMenus |
// This is called when an item is chosen from the menu bar (after calling |
// MenuSelect or MenuKey). It does the right thing for each command. |
void TESample::DoMenuCommand(short menuID, short menuItem) |
{ |
short itemHit; |
Str255 daName; |
short daRefNum; |
WindowPtr window; |
TEDocument* fTECurDoc = (TEDocument*) fCurDoc; |
window = FrontWindow(); |
switch ( menuID ) |
{ |
case mApple: |
switch ( menuItem ) |
{ |
case iAbout: // bring up alert for About |
itemHit = Alert(rAboutAlert, nil); |
break; |
default: // all non-About items in this menu are DAs et al |
GetMenuItemText(GetMenuHandle(mApple), menuItem, daName); |
daRefNum = OpenDeskAcc(daName); |
break; |
} |
break; |
case mFile: |
switch ( menuItem ) |
{ |
case iNew: |
DoNew(); |
break; |
case iOpen: |
DoOpen(); |
break; |
case iClose: |
if (fTECurDoc != nil) |
{ |
// only close the document if the user doesn't cancel |
if (fTECurDoc->DoClose(true, yesResult, false) != cancelResult) |
{ |
fDocList->RemoveDoc(fTECurDoc); |
delete fTECurDoc; |
} |
} |
else CloseDeskAcc(((WindowPeek) fWhichWindow)->windowKind); |
// make sure our current document/window references are valid |
fWhichWindow = FrontWindow(); |
if (fWhichWindow != nil) |
{ |
fCurDoc = fDocList->FindDoc(fWhichWindow); |
SetPort(fWhichWindow); |
} |
else fCurDoc = nil; |
break; |
case iSave: |
if (fTECurDoc != nil) |
fTECurDoc->DoSave(); |
break; |
case iSaveAs: |
if (fTECurDoc != nil) |
fTECurDoc->DoSaveAs(); |
break; |
case iQuit: |
DoQuit(true, yesResult); |
break; |
} |
break; |
case mEdit: // call SystemEdit for DA editing & MultiFinder |
if (!SystemEdit(menuItem-1)) |
{ |
switch (menuItem) |
{ |
case iCut: |
fTECurDoc->DoCut(); |
break; |
case iCopy: |
fTECurDoc->DoCopy(); |
break; |
case iPaste: |
fTECurDoc->DoPaste(); |
break; |
case iClear: |
fTECurDoc->DoClear(); |
break; |
case iSelectAll: |
fTECurDoc->DoSelectAll(); |
break; |
} |
} |
break; |
} |
HiliteMenu(0); // unhighlight what MenuSelect (or MenuKey) hilited |
} // DoMenuCommand |
// Create a new document and window. |
void TESample::DoNew() |
{ |
TEDocument* tDoc; |
tDoc = new TEDocument(rDocWindow); |
FailNIL(tDoc); |
TRY |
{ |
tDoc->OpenNewDoc(); |
fDocList->AddDoc(tDoc); |
} |
RECOVER |
{ |
delete tDoc; |
} |
ENDTRY |
} // DoNew |
void TESample::OpenADoc(short vRefNum, long dirID, StringPtr fName, OSType fType) |
{ |
if (fType != kTEFileType) |
Failure(eBadFileType,kTEDocErrStrings); |
TEDocument* tDoc = new TEDocument(rDocWindow); |
FailNIL(tDoc); |
TRY |
{ |
CanonicalFileSpec fileSpec; |
fileSpec.vRefNum = vRefNum; |
fileSpec.dirID = dirID; |
CopyPString(fileSpec.fileName, fName); |
tDoc->OpenOldDoc(fileSpec,false); |
fDocList->AddDoc(tDoc); |
} |
RECOVER |
{ |
delete tDoc; |
} |
ENDTRY |
} |
void TESample::DoOpen() |
{ |
Point where; |
Str255 prompt; |
SFTypeList typeList; |
SFReply reply; |
short vRefNum; |
long dirID; |
SetPt(&where,100,100); |
prompt[0] = '\0'; |
typeList[0] = kTEFileType; |
SFGetFile(where,prompt,(FileFilterProcPtr) nil, |
1,typeList,(DlgHookProcPtr) nil,&reply); |
if (reply.good == false) |
return; |
WDToDirID(reply.vRefNum,vRefNum,dirID); |
OpenADoc(vRefNum,dirID,reply.fName, kTEFileType); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14