Important: The information in this document is obsolete and should not be used for new development.
Recipes--PowerTalk Mailers
The recipes and sample code in this section describe how to add MacApp's PowerTalk support to your application and how to define a document class that supports PowerTalk mailers.Recipe--Adding PowerTalk Support to Your Application
To add MacApp's PowerTalk support to your application, you perform these steps:
The sample code in this recipe is from the DemoText application.
- Build your application to include MacApp's PowerTalk support.
- Include the Mail menu in your application.
- Initialize MacApp's mailer support by calling
InitUMailerfrom your application'smainroutine.- Define an application class that is a subclass of
TMailingApplication.- Decide whether to define a new file type for your letter files.
- IMPORTANT
- This recipe describes how to include MacApp's PowerTalk support in your application. To use that support, you also must follow the steps in "Recipe--Adding Mailer Support to a Document Class," beginning on page 628.
![]()
Build Your Application to Include MacApp's PowerTalk Support
Not all applications need electronic mail, so MacApp's PowerTalk support is conditionally compiled--that is, the mailer code isn't included unless you specifically ask for it. For example, if you build your application with MPW and the MABuild tool (described in Appendix A), you include MacApp's PowerTalk support with a build line similar to the following:
MABuild YourAppName [-options] -PowerTalkBuilding with the-PowerTalkoption sets theqPowerTalkcompiler flag toTRUE. You can use the following line to specifically build your application without PowerTalk support:
MABuild YourAppName [-options] -noPowerTalkInclude the Mail Menu in Your Application
MacApp'sDefaults.rfile defines a'CMNU'resource for the Mail menu used to perform mail operations. The Mail menu contains the commands Add Mailer/Remove Mailer, Send, Reply, Forward, and Open Next Letter.You can add the Mail menu from MacApp's
Defaults.rfile to your application's resource definition file by cutting and pasting the text or by adding the following lines to your resource file:
#if qPowerTalk include "Defaults.rsrc" 'CMNU' (mMail); #endifCode between the#ifand#endifcompiler directives will not be part of your application unlessqPowerTalkis defined asTRUEwhen the code is compiled (which is the case when you build with the -PowerTalk option). The constantmMailis defined in the fileMacAppTypes.r. You can include that file into your resource definition file with the following lines:
#ifndef __MacAppTypes__ #include "MacAppTypes.r" #endifYou also add the Mail menu to your application's menu-bar resource, as shown in this code fragment from the resource definition file of the DemoText application:
resource 'MBAR' (kMBarDisplayed, #if qNames "kHierDisplayedMBar", #endif nonpurgeable) { { mApple; mFile; mEdit; mText; mFormat #if qPowerTalk ;mMail #endif } };If you don't have room in your application's menu bar for the Mail menu, you can add it as a hierarchical menu in your File menu.Initialize MacApp's Mailer Support
Your application initializes MacApp's mailer support by callingInitUMailerfrom itsmainroutine. You should callInitUMailerafter callingInitUMacApp, with code similar to the following:
#if qPowerTalk if (HasAOCEToolBox()) InitUMailer(); #endifThe line
if (HasAOCEToolBox())determines whether the PowerTalk system software is available on the current machine. Use this test to isolate code that should not be performed unless PowerTalk support is available.
- IMPORTANT
- You should be careful to isolate code that deals with mailers, using either conditional compilation (the
qPowerTalkflag) or conditional testing (HasAOCEToolBox). Otherwise, your application may try to call MacApp code or reference a MacApp compile time variable that was not included in the current build. This can cause the program to crash.![]()
Define an Application Subclass of TMailingApplication
The TMailingApplication class contains application-level support for working with PowerTalk mailers, both in its own methods and in methods and fields inherited from the mixin classMMailing. To take advantage of this support, your application class must be a subclass of TMailingApplication. The DemoText application begins its application class definition as follows:
class TDemoTextApplication : public TMailingApplicationDecide Whether to Define a New Type for Letter Files
MacApp defines a default file type for the letters your application creates:
const DescType typeLetterDesc = 'lttr'; const DescType kStandardLetterFileType = typeLetterDesc;TheMMailingclass fieldfMainLetterFileTypestores the principal file type your application uses for letters. The field is set tokStandardLetterTypein the constructor forTMailingApplication. By default, a letter file has the same Finder icon as the document it is added to, because MacApp does not supply special icons or bundle information for the letter file type.You can specify a different file type for your application's letters by passing it to the
IMailingApplicationmethod. You can specify new icons for your letters by adding icon and bundle information to your application's resource definition file. See the "Finder Interface" chapter of Inside Macintosh: Macintosh Toolbox Essentials for more information about application icons and bundle information.Recipe--Adding Mailer Support to a Document Class
MacApp's PowerTalk mailer support helps you add mailers to your documents, turning them into electronic mail. To add mailer support to your document class, you perform the following steps:
The sample code in this recipe is from the DemoText application.
- Decide which mail formats your document will support.
- Define a subclass of
TMailableDocumentfor your mailer document.- In the constructor method for your mailable document class, set the
fSendFormatsfield to match the formats you support.- Override document methods to get and set the mailer's data for the formats you support. You may need to override the following methods:
AddNativeMailContentAddSnapshotMailContentAddStandardMailContentImageDocumentForMailerReadNativeMailContentReadSnapshotMailContentReadStandardMailContent
- If necessary, override the
MMailable::SetReplyContentsmethod to set up a reply mailer.- If necessary, override the
MMailable::MakeRoomForMailermethod.- If necessary, override the
TLetter::OpenLettermethod.
- IMPORTANT
- This recipe describes how to add PowerTalk support to a document class. To implement this recipe, you must also perform the steps in "Recipe--Adding PowerTalk Support to Your Application," beginning on page 624.
![]()
Decide Which Mail Formats to Support
When you use a mailer to send a document as a letter, you can send the document in a native format (that is, any of the internal document formats supported by your application), in snapshot format (an image or "snapshot" of the document), in a special format called standard interchange format, or in any combination of these formats simultaneously. Standard interchange format is a set of data formats that consists of plain text, styled text, sound (AIFF), images ('PICT'), and QuickTime movies ('MooV').The DemoText application sends letters containing both native and standard interchange format.
Define a Subclass of TMailableDocument for Your Mailer Document
Your application adds to MacApp's PowerTalk support primarily by overriding methods of theMMailableclass. SinceMMailableis mixed in with theTMailableDocumentclass, you normally override methods ofMMailableby defining a document class that descends fromTMailableDocument. The DemoText application begins its document class definition as follows:
class TTEDocument : public TMailableDocumentSet the Document's fSendFormats Field
In the constructor method for your mailable document class, you set thefSendFormatsfield to match the formats you support. The value for this field is computed by adding the constants for each of the three standard mail formats supported by your application. For example, the following line from the constructor method of theMMailableclass indicates that the default setting is to support all three standard formats:
fSendFormats = kSMPNativeMask + kSMPImageMask + kSMPStandardInterchangeMask;In its constructor method, theTTEDocumentclass changes the setting for fSendFormats with the following lines:
#if qPowerTalk fSendFormats = kSMPNativeMask + kSMPStandardInterchangeMask; #endifIn the DemoText application, theTTEDocumentclass supports native and standard interchange formats only.Override Methods to Get and Set Mailer Data
Your document class may need to override certain methods, as described in the following sections, to get and set mailer data for the formats it supports.AddNativeMailContent, ReadNativeMailContent
If your document class suppliesDoReadandDoWritemethods to read and write its data, MacApp handles native format automatically. If your document class doesn't supplyDoReadandDoWritemethods, or if you need to modify MacApp's default behavior, your document class can override theAddNativeMailContentandReadNativeMailContentmethods.In the DemoText application, the
TTEDocumentclass overrides theReadNativeMailContentmethod:
Boolean TTEDocument::ReadNativeMailContent() { Boolean readContent = TMailableDocument::ReadNativeMailContent(); // fStyles and fElements are native to DemoText (see // TTEDocument::DoRead) so they can be used as a valid check // for native content. if (fDocText && fStyles && fElements) { this->ShowReverted(); readContent = TRUE; } return readContent; }This method calls TMailableDocument::ReadNativeMailContent to read the native format content, then callsShowRevertedso that the TTEDocument class can set up its text display.AddSnapshotMailContent, ImageDocumentForMailer, ReadSnapshotMailContent
To support the snapshot format, your document class overrides theImageDocumentForLetterandReadSnapshotMailContentmethods. TheAddSnapshotMailContentmethod callsImageDocumentForLetter, so you don't normally need to overrideAddSnapshotMailContentitself.Your version of the
ImageDocumentForLettermethod provides a suitable image of your document. Your version ofReadSnapshotMailContentextracts the document image. The DemoText application does not support snapshot format, but you can find an example of an image-drawing routine in the "Standard Mail Package" chapter of Inside Macintosh: AOCE Application Interfaces.AddStandardMailContent, ReadStandardMailContent
To support the standard mail format, your document class overrides theAddStandardMailContentandReadStandardMailContentmethods.In the DemoText application, the
TTEDocumentclass overrides theAddStandardMailContentmethod to add styled text content:
void TTEDocument::AddStandardMailContent(Boolean& okToSend) { WindowRef theWindow = fTEView->GetGrafPort(); Boolean appendFlag = FALSE; Handle theText = fTEView->ExtractText(); SignedByte wasTextState = LockHandleHigh(theText); Ptr buffer = *theText; unsigned long bufferSize = GetHandleSize(theText); StScrpHandle theStyles = (StScrpHandle)NewHandle(10); fTEView->GivePasteData((Handle)theStyles, 'styl'); SignedByte wasStyleState = LockHandleHigh((Handle)theStyles); Boolean startNewScript = TRUE; short scriptID = smRoman; FailOSErr(SMPAddContent(theWindow, kMailStyledTextSegmentType, appendFlag,buffer, bufferSize, *theStyles, startNewScript, scriptID)); HSetState(theText, wasTextState); HSetState((Handle)theStyles, wasStyleState); DisposeIfHandle((Handle)theStyles); okToSend = TRUE; }This method extracts text from the document'sfTEViewfield, calls a method of the view (GivePasteData) to extract the style information, then calls the Standard Mail Package routine SMPAddContent to add the styled text content.The
TTEDocumentclass overrides theReadStandardMailContentmethod to perform the opposite operation--to extract styled text content from the mailer and install it in the document's own view. TheReadStandardMailContentmethod is implemented as follows:
Boolean TTEDocument::ReadStandardMailContent() { Boolean readContent = FALSE; const unsigned long kBufferSize = 10000; MailSegmentMasksegmentTypeMask = kMailStyledTextSegmentMask; Handle buffer = NewHandle(kBufferSize); FailNIL(buffer); const short kNumStyles = 200; const long kStyleBufferSize = (sizeof(ScrpSTElement) * kNumStyles) + 4; StScrpHandle theStyles = (StScrpHandle)NewHandleClear(kStyleBufferSize); FailNIL(theStyles); Boolean endOfContent = FALSE; OSErr err = noErr; Boolean allContentExtracted = TRUE; while ((err == noErr) && !endOfContent) { // Skip past empty text segments. ScriptCode script = 0; unsigned longdataSize = 0; long segmentLength = 0; long segmentID = 0; Boolean endOfScript = FALSE; Boolean endOfSegment = FALSE; MailSegmentTypesegmentType; endOfContent = FALSE; unsigned long bufferSize = kBufferSize; SetHandleSize(buffer, bufferSize); SetHandleSize((Handle)theStyles, kStyleBufferSize); (**theStyles).scrpNStyles = kNumStyles; SignedByte wasStylesState = LockHandle((Handle)theStyles); SignedByte wasBufferState = LockHandle(buffer); err = SMPReadContent(fLetter->GetMailerWindowRef(), segmentTypeMask, *buffer, bufferSize, &dataSize, *theStyles, &script, &segmentType, &endOfScript, &endOfSegment, &endOfContent, &segmentLength, &segmentID); if(allContentExtracted && (dataSize > 0) && !endOfContent) allContentExtracted = FALSE; if ((err == noErr) && (dataSize > 0)) { HSetState(buffer, wasBufferState); HSetState((Handle)theStyles, wasStylesState); SetHandleSize(buffer, dataSize); unsigned long textSize = dataSize; dataSize = (sizeof(ScrpSTElement) * (**theStyles).scrpNStyles) + 4; SetHandleSize((Handle)theStyles, dataSize); TEStyleInsert(*buffer, textSize, (StScrpHandle)theStyles, fTEView->fHTE); fTEView->SynchView(FALSE); readContent = TRUE; } } DisposeIfHandle(buffer); DisposeIfHandle((Handle)theStyles); if(!allContentExtracted) { MacAppAlert(kContentNotExtracted, NULL); } return readContent; } // TTEDocument::ReadStandardMailContentThis method repeatedly calls SMPReadContent (a Standard Mail Package routine) to extract text and style data, and TEStyleInsert (a Toolbox routine) to insert the data into the document'sfTEViewfield. If ReadStandardMailContent cannot extract all the content (text style, PICT, or any other format), it displays an alert box. The constant kContentNotExtracted identifies'ALRT'and'DITL'resources defined in the fileTTEDocument.r. The MacApp routine MacAppAlert displays a dialog box with the text "This letter includes Standard Mail Format DemoText cannot display."If Necessary, Override SetReplyContents
When a user chooses the Reply command from the Mail menu, an application typically creates a reply mailer document addressed to the sender of the original letter, with the same or a similar subject and recipient list. The reply letter may also contain the text from the original letter, perhaps separated by a dashed line or other border.MacApp uses its standard (if somewhat complex) Apple event mechanism to respond to the Reply command. The
DoMailMenuCommandmethod of theTLetterclass handles the Reply menu command by calling the letter'sDoReplymethod.DoReplycreates and sends a Create Element (cAECreateElement) event. The event is dispatched to the application object and handled by theMScriptableObject::DoScriptCommandmethod, which callsDoAECreateElement. In theTMailingApplicationclass,DoAECreateElementcreates a document object and calls the document'sDoAECreateReplymethod. That method in turn calls the letter'sDoAECreateReplymethod.The
TLetter::DoAECreateReplymethod takes care of certain overhead, including setting up the mailer view, then calls the document'sSetReplyContentsmethod, at last reaching the subject of this section.In the
MMailableclass, which is mixed intoTMailableDocument, theSetReplyContentsmethod does nothing. To set up the reply letter in your desired format, you overrideSetReplyContentsin your mailable document class. TheTTEDocumentclass overridesSetReplyContentsto set up a reply containing a dashed line followed by the text from the original letter, using the following code:
void TTEDocument::SetReplyContents(TDocument* replyToDoc) { // Extract text from original document and copy into this document. DisposeIfHandle(fDocText); fDocText = ((TTEDocument*)replyToDoc)->fDocText; FailOSErr(HandToHand(&fDocText)); // Do the same for all style information. DisposeIfHandle((Handle)fElements); fElements = ((TTEDocument*)replyToDoc)->fElements; if (fElements != NULL) FailOSErr(HandToHand((Handle*)&fElements)); DisposeIfHandle((Handle)fStyles); fStyles = ((TTEDocument*)replyToDoc)->fStyles; if (fStyles != NULL) FailOSErr(HandToHand((Handle*)&fStyles)); // Call ShowReverted to adjust display. ShowReverted(); // Insert a dashed-line spacer above the styled text. if (fTEView->Focus()) { (*fTEView->fHTE)->selStart = 0; (*fTEView->fHTE)->selEnd = 0; CStr255 replySpacer; GetIndString(replySpacer, kPromptsRsrcID, kReplySpacer); TextStyle newStyle; newStyle.tsFace = 0; TESetStyle(doFace,&newStyle,FALSE,fTEView->fHTE); TEInsert((Ptr)&replySpacer.fStr[1], replySpacer.Length(), fTEView->fHTE); (*fTEView->fHTE)->selStart = 0; (*fTEView->fHTE)->selEnd = 0; fTEView->SynchView(FALSE); } }This code copies the text and style information from the original letter to the reply letter, then inserts a dashed line above the text as a spacer. The insertion point is placed above the space to allow the user to enter a reply to the original letter.If Necessary, Override MMailable::MakeRoomForMailer
When you add a mailer to a document, MacApp attempts to create and position a mailer view automatically. It calls the document'sMakeRoomForMailermethod to make room for the new mailer view.The
MakeRoomForMailermethod is defined in theTLetterandMMailableclasses (MMailableis mixed in with theTMailableDocumentclass). InTLetter,MakeRoomForMailercalls theMakeRoomForMailermethod of its document. InMMailable,MakeRoomForMaileradjusts the document's window to make room for a mailer view.MakeRoomForMaileroperates on the assumption that the main content view, containing all other views, is a scroller with ID'SCLR'.If you have a simple document view in which one scroller view serves as the superview, set the view ID of the scroller to
'SCLR'. The default version ofMakeRoomForMailerwill then resize the mailer view appropriately as the document view changes size. TheTTEDocumentclass creates a view that matches this format, but if your document view hierarchy contains views that are outside the scroller view, you must overrideMakeRoomForMailerto adjust for your hierarchy.If Necessary, Override TLetter::OpenLetter
When a user opens an existing document with a mailer, theTMailingApplication::OpenOldmethod calls the application object'sDoMakeDocumentmethod to create a document.OpenOldcalls various methods of the document to read data and create views, then calls the document'sOpenLettermethod.The document's
OpenLettermethod is defined in theMMailablemixin class. It calls theOpenLettermethod of itsfLetterfield. TheTLetter::OpenLettermethod contains this code:
Boolean readContent; readContent = fMailDoc->ReadNativeMailContent(); if (!readContent) readContent = fMailDoc->ReadSnapshotMailContent(); if (!readContent) fMailDoc->ReadStandardMailContent();This code first tries to read content in native mail format. If it is unsuccessful, it tries to read snapshot format. If it is still unsuccessful, it finally tries to read standard mail format. If your application needs to change this ordering, you can override theOpenLettermethod in either your mailable document class or in a subclass ofTLetter(or ofTFileBasedLetter).