Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: Programmer's Guide to MacApp / Part 2 - Working With MacApp
Chapter 31 - Working With the Edition Manager


Recipes--The Edition Manager

The recipe and sample code in this section demonstrate how to add publish and subscribe support to your application. Classes and methods that supply Edition Manager support are shown in Figure 31-1.

Recipe--Adding Publish and Subscribe Support to Your Application

MacApp handles much of the work of interacting with the Edition Manager, including handling section Apple events and displaying and responding to Edition Manager menu commands. To add publish and subscribe support to your application, you perform these additional steps:

  1. Include MacApp header files for the Edition Manager in your source code.
  2. Include Edition Manager resources in your resource definition file.
  3. Base your document class on TEditionDocument.
  4. Provide a document initialization method. Your method should do the following:

    • Call the IEditionDocument method of its parent class.
    • Create a selection designator for the document and call SetUserSelection to set it.

  5. Specify the data format for your subscriber sections.
  6. Override the DoWriteData method to publish data.
  7. Override the DoReadData method to subscribe to data.
  8. Notify the Edition Manager when the user selection changes.
  9. Override the DoAddBorder method to supply a border adorner.
  10. Add a dependency to trigger publisher updates (optional).

The sample code shown in this recipe is from the Calc application.

Include MacApp Header Files for the Edition Manager

To use MacApp support for the Edition Manager in your source code, you need to include specific MacApp header files. For example, the Calc application includes the following headers in the file UCalc.h:

#ifndef __EDITIONS__
#include <Editions.h>
#endif

#ifndef __UAPPLEEVENTS__
#include "UAppleEvents.h"
#endif

#ifndef __UDESIGNATOR__
#include "UDesignator.h"
#endif

#ifndef __UEDITIONDOCUMENT__
#include "UEditionDocument.h"
#endif

#ifndef __USECTION__
#include "USection.h"
#endif
The first file shown, Editions.h, contains Edition Manager interface definitions. The remaining files contain definitions for MacApp Edition Manager classes and other Edition Manager support.

Include Edition Manager Resources in Your Resource File

To be able to respond to section Apple events from the Event Manager, your application must include MacApp's Edition Manager resources. These resources are in the file Editions.rsrc. To include them in your application, add the following line to your resource definition file:

include "Editions.rsrc" not 'ckid';
The words not 'ckid' ensure that you will not copy the resource that is used for source-code control.

Edition Manager menu commands are normally displayed in the Edit menu, so your application should include an Edit menu 'CMNU' resource that contains these commands. MacApp provides a default Edition Manager Edit menu in the file Defaults.rsrc. You can include this resource in your application by adding the following line to your resource definition file:

include "Defaults.rsrc" 'CMNU' (mEditionMgrEdit);
If you prefer, you can modify your own Edit menu definition to include the Edition Manager items. The easiest way to do this is to cut the text for the items from the Edit menu 'CMNU' resource in MacApp's Defaults.r file and paste them into the Edit menu resource in your resource definition file.

You also need to add the Edition Manager menu to your menu bar, by adding its ID to your 'MBAR' definition. For example, this 'MBAR' definition from the Calc application is defined in the file Calc.r:

resource 'MBAR' (kMBarDisplayed,
#if qNames
"Calc",
#endif
   purgeable) {
   {mApple; mFile; mEditionMgrEdit; mFormat; mCalculation}
};

Base Your Document Class on TEditionDocument

To take advantage of MacApp's Edition Manager support, your document class should descend from the TEditionDocument class. For example, the TCalcDocument class begins its definition as follows:

class TCalcDocument : public TEditionDocument

Provide a Document Initialization Method

The initialization method for your document class has two responsibilities for initializing MacApp's Edition Manager support. First, it should call the initialization method of its parent class, TEditionDocument, with a line like the following (from ICalcDocument):

this->IEditionDocument(itsFile, kCalcScrapType, kSignature);
In this call, the Calc document class passes constants that specify its file, its preferred scrap type (for cutting and pasting), and the application's signature (to identify the application that created the document). The IEditionDocument method calls the InitUSectionManager method, which initializes the MacApp Section Manager unit.

The second responsibility of your initialization method is to create a selection designator and use it to set the document's fUserSelection field. The Calc document does so with the following code, from the ICalcDocument method:

TRegionDesignator*aRgnDesignator;
RgnHandle      aRgnHandle;

// Create a user selection designator.
aRgnHandle = MakeNewRgn();
aRgnDesignator = new TRegionDesignator;
aRgnDesignator->IRegionDesignator(aRgnHandle, TRUE);
aRgnDesignator->SetDesignationRect(CRect(1, 1, 2, 2));
// Set the document's fUserSelection field.
SetUserSelection(aRgnDesignator);
This code creates a new region and region designator, initializes the region designator, sets the designator to designate the top-left cell in the spreadsheet, and calls SetUserSelection. The TCalcDocument::SetUserSelection method calls Inherited to set the fUserSelection field to the new designator, then performs its own user-selection operations.

Note
In this snippet of sample code, failure handling is left as an exercise for the reader.

Specify the Data Format for Your Subscriber Sections

You can skip this step if your application subscribes only to sections with data in one of the standard formats: 'PICT', 'TEXT', or 'snd '.

If you are not using one of the standard formats, you override two methods in your document class: GetPublishPreference and GetSubscriberFormatsMask. These methods are described next.

GetPublishPreference

The GetPublishPreference method returns the document's preferred section type. For the TEditionDocument class, 'TEXT' is the preferred type. Your version of GetPublishPreference should look something like the following:

FormatType TYourDocument::GetPublishPreference()
{
   return ((long) kYourSectionPreference);
}

GetSubscriberFormatsMask

The GetSubscriberFormatsMask method calls the GetPublishPreference method to help it determine which section format mask to use. In the TEditionDocument class, GetSubscriberFormatsMask is defined as follows:

SignedByte TEditionDocument::GetSubscriberFormatsMask()
{
   // Return a mask corresponding to the edition format type to display
   // within the subscriber dialog box. This mask may consist of as
   // many types as are supported in the application.
   // Construct the mask as follows:
   //  GetSubscriberFormatsMask =[kPICTformatMask] [+]
   //                      [kTextformatMask [+] [ksndFormatMask]
   if (this->GetPublishPreference() == 'TEXT')
      return (kTEXTformatMask);
   else if (this->GetPublishPreference() == 'PICT')
      return (kPICTformatMask);
   else if (this->GetPublishPreference() == 'snd ')
      return (ksndFormatMask);
   else return 0;
}
Your version of GetSubscriberFormatsMask should look something like the following:

SignedByte TYourDocument::GetSubscriberFormatsMask()
{
   if (this->GetPublishPreference() == kYourSectionPreference)
      return (kYourFormatMask);
   else
      return Inherited::GetSubscriberFormatsMask();
}

Override the DoWriteData Method to Publish Data

MacApp calls your document's DoWriteData method as part of processing a Publish command. You override DoWriteData to write your data to an edition container file by writing to the passed stream. The kind of data you write depends on the aScrapType parameter passed to DoWriteData. In the Calc application, the TCalcDocument::DoWriteData method can publish three kinds of data: 'TEXT', 'PICT', or its own kind of spreadsheet data:

void TCalcDocument::DoWriteData(const OSTypeaScrapType,
                        TDesignator*aDesignator,
                        TStream*    aStream) // Override.
{
   SignedByte savedState;
   Handle textHandle;

   if (aScrapType == 'TEXT')
   {
      textHandle = fCellsView->DesignatorAsTEXT(aDesignator);
      savedState = LockHandleHigh(textHandle);
      aStream->WriteBytes((*textHandle), GetHandleSize(textHandle));
      HSetState(textHandle, savedState);
      DisposeHandle(textHandle);
   }
   else if (aScrapType == fScrapType)
      this->DoWritePrivateTypes(aDesignator, aStream);
}
This DoWriteData method calls the TCellsView::DesignatorAsTEXT method to write the data for the selected spreadsheet cells. DesignatorAsTEXT iterates over the selected cells and asks each cell to write its data, delimited by a tab or a carriage return character, to a handle stream. It then returns the handle containing the text. (For more information on the DesignatorAsTEXT method, see "Recipe--Using a Handle Stream to Write Text to a Handle," beginning on page 601.)

Override the DoReadData Method to Subscribe to Data

MacApp calls your document's DoReadData method as part of processing a Subscribe command. You override DoReadData to read your data from an edition container file by reading from the passed stream. The kind of data you read depends on the aScrapType parameter passed to DoReadData. In the Calc application, the TCalcDocument::DoReadData method can read either 'TEXT' data or its own kind of spreadsheet data:

void TCalcDocument::DoReadData(const OSTypeaScrapType,
                        TDesignator*aDesignator,
                        TStream* aStream,
                        long     length) // Override.
{
   if (aScrapType == 'TEXT')
      this->DoReadTEXT(aDesignator, aStream, length);
   else if (aScrapType == fScrapType)
      this->DoReadPrivateTypes(aDesignator, aStream);
}
The DoReadTEXT method reads text data, and the DoReadPrivateTypes method reads Calc's private spreadsheet data.

Notify the Edition Manager When the User Selection Changes

Whenever the user changes the current selection, your application should call the UserSelectionChanged method of the view class that displays your document's data. In the TView class, the UserSelectionChanged method calls the UserSelectionChanged method of the view's document.

If your view class overrides UserSelectionChanged, your version of UserSelectionChanged should call Inherited, as Calc's TCellsView class does:

void TCellsView::UserSelectionChanged(TView* changedView)
{
   if (!fCalcDocument->fShowSectionBorders)
   {
      // Invalidate all adorners if not showing borders.
      CAdornerIterator iter(this);
      
      for (TAdorner* theAdorner = iter.FirstAdorner(); iter.More();
                  theAdorner = iter.NextAdorner())
      {
         if ((theAdorner->fIdentifier == kPublisherAdornerID)
            || (theAdorner->fIdentifier == kSubscriberAdornerID))
         {
            theAdorner->InvalidateAdorner(this);
         }
      }
   }
   // Call Inherited to inform the document of the change.
   Inherited::UserSelectionChanged(changedView);

}  // TCellsView::UserSelectionChanged
The Calc application also overrides the UserSelectionChanged method in the TCalcDocument class:

void TCalcDocument::UserSelectionChanged(TView* changedView) // Override.
{
   TDesignator * userSelection;

   // Let document's selection designator know designation has changed. 
   userSelection = this->GetUserSelection();
   if ((userSelection != NULL) &&userSelection->DescendsFrom(
                        TRegionDesignator::GetClassDescStatic()))
      CopyRgn(fCellsView->fSelections,((TRegionDesignator *)
                        (userSelection))->fDesignation);
   Inherited::UserSelectionChanged(changedView);
}
If the user selection has changed, this method updates the document's user selection designator by copying the view's current selection region.

Override DoAddBorder to Supply a Border Adorner

The DoAddBorder method does nothing in the TEditionDocument class. You override this method in your document class to supply an adorner object to draw the border for your publisher or subscriber. The following is the DoAddBorder method from the Calc document:

void TCalcDocument::DoAddBorder(TSection* aSection)
{
   // Adding a section--give it a section adorner.
   if (fCellsView)
   {
      if (aSection->GetSectionType() == stSubscriber)
         fCellsView->CreateSubscriberAdorner((TSubscriber *)aSection);
      else
         fCellsView->CreatePublisherAdorner((TPublisher *)aSection);

      // Invalidate the borders of publishers/subscribers if we aren't
      // showing all borders.
      if (!fShowSectionBorders)
      {
         CAdornerIterator iter(fCellsView);
   
         for (TAdorner * anAdorner = iter.FirstAdorner(); iter.More();
                     anAdorner = iter.NextAdorner())
            if ((anAdorner->fIdentifier == kPublisherAdornerID) ||
               (anAdorner->fIdentifier == kSubscriberAdornerID))

               anAdorner->InvalidateAdorner(fCellsView);
      }
   }
}
The CreateSubscriberAdorner method creates an adorner to draw a subscriber border, and the CreatePublisherAdorner method creates an adorner to draw a publisher border. Both methods add the adorner to the view's list of adorners.

Add a Dependency to Trigger Publisher Updates

The Calc application uses dependencies to ensure that a publisher is notified whenever a cell within the publisher is changed. This is not a requirement, but it is an approach you may wish to emulate in your application.

To make a publisher a dependent of each cell in the published selection, the TCalcDocument class overrides the TEditionDocument method AddSectionAndBorder with the following implementation:

void TCalcDocument::AddSectionAndBorder(TSection* aSection)
{
   Inherited::AddSectionAndBorder(aSection);

   this->AddPublisherDependency(aSection);
}
This AddSectionAndBorder method first calls Inherited to add the section and its adorner, then calls AddPublisherDependency, also a method of TCalcDocument. The AddPublisherDependency method iterates over the cells in the published section, adding the section as a dependent of each cell.

The TCell::Recalculate method makes the following call whenever a cell changes:

this->Changed(mValueChanged, this);
As a result, the publisher is notified whenever the contents of one of its cells changes.

Appendixes


Previous Book Contents Book Index Next

© Apple Computer, Inc.
25 JUL 1996