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
InitUMailer
from your application'smain
routine.- 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-PowerTalk
option sets theqPowerTalk
compiler 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.r
file 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.r
file 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#if
and#endif
compiler directives will not be part of your application unlessqPowerTalk
is defined asTRUE
when the code is compiled (which is the case when you build with the -PowerTalk option). The constantmMail
is 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 callingInitUMailer
from itsmain
routine. You should callInitUMailer
after 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
qPowerTalk
flag) 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;TheMMailing
class fieldfMainLetterFileType
stores the principal file type your application uses for letters. The field is set tokStandardLetterType
in 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
IMailingApplication
method. 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
TMailableDocument
for your mailer document.- In the constructor method for your mailable document class, set the
fSendFormats
field 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:
AddNativeMailContent
AddSnapshotMailContent
AddStandardMailContent
ImageDocumentForMailer
ReadNativeMailContent
ReadSnapshotMailContent
ReadStandardMailContent
- If necessary, override the
MMailable::SetReplyContents
method to set up a reply mailer.- If necessary, override the
MMailable::MakeRoomForMailer
method.- If necessary, override the
TLetter::OpenLetter
method.
- 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 theMMailable
class. SinceMMailable
is mixed in with theTMailableDocument
class, you normally override methods ofMMailable
by 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 thefSendFormats
field 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 theMMailable
class indicates that the default setting is to support all three standard formats:
fSendFormats = kSMPNativeMask + kSMPImageMask + kSMPStandardInterchangeMask;In its constructor method, theTTEDocument
class changes the setting for fSendFormats with the following lines:
#if qPowerTalk fSendFormats = kSMPNativeMask + kSMPStandardInterchangeMask; #endifIn the DemoText application, theTTEDocument
class 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 suppliesDoRead
andDoWrite
methods to read and write its data, MacApp handles native format automatically. If your document class doesn't supplyDoRead
andDoWrite
methods, or if you need to modify MacApp's default behavior, your document class can override theAddNativeMailContent
andReadNativeMailContent
methods.In the DemoText application, the
TTEDocument
class overrides theReadNativeMailContent
method:
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 callsShowReverted
so that the TTEDocument class can set up its text display.AddSnapshotMailContent, ImageDocumentForMailer, ReadSnapshotMailContent
To support the snapshot format, your document class overrides theImageDocumentForLetter
andReadSnapshotMailContent
methods. TheAddSnapshotMailContent
method callsImageDocumentForLetter
, so you don't normally need to overrideAddSnapshotMailContent
itself.Your version of the
ImageDocumentForLetter
method provides a suitable image of your document. Your version ofReadSnapshotMailContent
extracts 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 theAddStandardMailContent
andReadStandardMailContent
methods.In the DemoText application, the
TTEDocument
class overrides theAddStandardMailContent
method 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'sfTEView
field, 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
TTEDocument
class overrides theReadStandardMailContent
method to perform the opposite operation--to extract styled text content from the mailer and install it in the document's own view. TheReadStandardMailContent
method 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'sfTEView
field. 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
DoMailMenuCommand
method of theTLetter
class handles the Reply menu command by calling the letter'sDoReply
method.DoReply
creates and sends a Create Element (cAECreateElement
) event. The event is dispatched to the application object and handled by theMScriptableObject::DoScriptCommand
method, which callsDoAECreateElement
. In theTMailingApplication
class,DoAECreateElement
creates a document object and calls the document'sDoAECreateReply
method. That method in turn calls the letter'sDoAECreateReply
method.The
TLetter::DoAECreateReply
method takes care of certain overhead, including setting up the mailer view, then calls the document'sSetReplyContents
method, at last reaching the subject of this section.In the
MMailable
class, which is mixed intoTMailableDocument
, theSetReplyContents
method does nothing. To set up the reply letter in your desired format, you overrideSetReplyContents
in your mailable document class. TheTTEDocument
class overridesSetReplyContents
to 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'sMakeRoomForMailer
method to make room for the new mailer view.The
MakeRoomForMailer
method is defined in theTLetter
andMMailable
classes (MMailable
is mixed in with theTMailableDocument
class). InTLetter
,MakeRoomForMailer
calls theMakeRoomForMailer
method of its document. InMMailable
,MakeRoomForMailer
adjusts the document's window to make room for a mailer view.MakeRoomForMailer
operates 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 ofMakeRoomForMailer
will then resize the mailer view appropriately as the document view changes size. TheTTEDocument
class creates a view that matches this format, but if your document view hierarchy contains views that are outside the scroller view, you must overrideMakeRoomForMailer
to adjust for your hierarchy.If Necessary, Override TLetter::OpenLetter
When a user opens an existing document with a mailer, theTMailingApplication::OpenOld
method calls the application object'sDoMakeDocument
method to create a document.OpenOld
calls various methods of the document to read data and create views, then calls the document'sOpenLetter
method.The document's
OpenLetter
method is defined in theMMailable
mixin class. It calls theOpenLetter
method of itsfLetter
field. TheTLetter::OpenLetter
method 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 theOpenLetter
method in either your mailable document class or in a subclass ofTLetter
(or ofTFileBasedLetter
).