home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 15 / BBS in a box XV-2.iso / Files II / Prog / M / MacPerl 4.13 source.sit / Perl Source ƒ / MacPerl / MPEditions.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-04  |  37.3 KB  |  1,372 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    MacPerl            -    Real Perl Application
  3. File        :    MPEditions.c    -
  4. Author    :    Matthias Neeracher
  5.  
  6. A lot of this code is borrowed from 7Edit written by
  7. Apple Developer Support UK
  8.  
  9. Language    :    MPW C
  10.  
  11. $Log: MPEditions.c,v $
  12. Revision 1.2  1994/05/04  02:50:54  neeri
  13. Fix segment names.
  14.  
  15. Revision 1.1  1994/02/27  23:00:31  neeri
  16. Initial revision
  17.  
  18. Revision 0.3  1993/09/18  00:00:00  neeri
  19. Runtime
  20.  
  21. Revision 0.2  1993/05/30  00:00:00  neeri
  22. Support Console Windows
  23.  
  24. Revision 0.1  1993/05/29  00:00:00  neeri
  25. Compiles correctly
  26.  
  27. *********************************************************************/
  28.  
  29. #include <OSUtils.h>
  30. #include <Resources.h>
  31. #include <Errors.h>
  32. #include <AppleEvents.h>
  33.  
  34. #include "MPEditions.h"
  35.  
  36. #ifndef RUNTIME
  37.  
  38. /**-----------------------------------------------------------------------
  39.         Name:         GetERefCon
  40.         Purpose:        Return the sectHandle (our own type) stored in
  41.                         the refcon of the SectionRecord.
  42.     -----------------------------------------------------------------------**/
  43.  
  44. #pragma segment Editions
  45.  
  46. pascal SectHandle GetERefCon(SectionHandle EMSection)
  47. {
  48.     SectHandle aSectHandle;
  49.  
  50.     aSectHandle = (SectHandle)(*EMSection)->refCon;
  51.     return(aSectHandle);
  52. }
  53.  
  54. /**-----------------------------------------------------------------------
  55. Name:         SetERefCon
  56. Purpose:        Store a handle to our own SectRecord in the refcon
  57.                 field of the SectionRecord.
  58. -----------------------------------------------------------------------**/
  59.  
  60. #pragma segment Editions
  61.  
  62. pascal void SetERefCon(SectionHandle EMSection, SectHandle aSectHandle)
  63. {
  64.     (*EMSection)->refCon = (long)aSectHandle;
  65. }
  66.  
  67. /**-----------------------------------------------------------------------
  68.         Name:         AddSection
  69.         Purpose:        Add our own section record to the document linked
  70.                         list.  Set up the first and last section variables.
  71.     -----------------------------------------------------------------------**/
  72.  
  73. #pragma segment Editions
  74.  
  75. pascal void AddSection(SectHandle newSection, DPtr aDocument)
  76. {
  77.     if (aDocument->kind != kDocumentWindow)
  78.         return;
  79.         
  80.     /*
  81.         add the section to the document
  82.     */
  83.     aDocument->u.reg.numSections += 1;
  84.  
  85.     /*
  86.         if not NIL, add the new section to the list after the last element
  87.     */
  88.  
  89.     if (aDocument->u.reg.lastSection)
  90.         (*(aDocument->u.reg.lastSection))->fNextSection = newSection;
  91.     else
  92.         aDocument->u.reg.firstSection = newSection;
  93.  
  94.     aDocument->u.reg.lastSection = newSection;
  95.     (*newSection)->fNextSection  = nil;
  96. }
  97.  
  98. /**-----------------------------------------------------------------------
  99.         Name:         CreateSection
  100.         Purpose:        Create a new section record to hold a Publisher or
  101.                         Subscriber. Link this to the SectionRecord.
  102.     -----------------------------------------------------------------------**/
  103.  
  104. #pragma segment Editions
  105.  
  106. pascal void CreateSection(SectionHandle   EMSection,
  107.                                   short           sectionID,
  108.                                   short           theStart,
  109.                                   short           theEnd,
  110.                                   DPtr            aDocument,
  111.                                   RgnHandle       theBorder)
  112.  
  113. {
  114.     SectHandle    newSection;
  115.  
  116.     if (aDocument->kind != kDocumentWindow)
  117.         return;
  118.         
  119.     /*
  120.         create a section and call AddSection to add it to the list
  121.     */
  122.     newSection = (SectHandle)NewHandle(sizeof(SectRec));
  123.  
  124.     if (newSection) {
  125.         (*newSection)->fSectionID   = sectionID;
  126.         (*newSection)->fNextSection = nil;
  127.         (*newSection)->fSectHandle  = EMSection;
  128.         (*newSection)->fStart       = theStart;
  129.         (*newSection)->fEnd         = theEnd;
  130.         (*newSection)->fCount       = theEnd - theStart;
  131.         (*newSection)->fBorderRgn   = theBorder;
  132.         (*newSection)->fDocument    = aDocument;
  133.  
  134.         /*
  135.             put a reference to our section record in the section's refCon field
  136.         */
  137.  
  138.         SetERefCon(EMSection, newSection);
  139.         AddSection(newSection, aDocument);
  140.     }
  141. }
  142.  
  143.  /**-----------------------------------------------------------------------
  144.         Name:         DeleteASection
  145.         Purpose:        Delete the section from the list.
  146.                         Called when 'Cancel Publisher/Subscriber is chosen in
  147.                         the 'Section Options' dialog.
  148.     -----------------------------------------------------------------------**/
  149.  
  150.     #pragma segment Editions
  151.  
  152. pascal void DeleteASection(SectHandle sectToDelete, DPtr theDoc)
  153. {
  154.     SectHandle    currSect;
  155.     SectHandle    prevSect;
  156.  
  157.     if (theDoc->kind != kDocumentWindow)
  158.         return;
  159.  
  160.     currSect = theDoc->u.reg.firstSection;
  161.     prevSect = nil;
  162.  
  163.     while (currSect) {
  164.         if (currSect == sectToDelete) {
  165.             /*
  166.                 unlink the section from the list
  167.             */
  168.             if (prevSect)
  169.                 (*prevSect)->fNextSection = (*currSect)->fNextSection;
  170.  
  171.             if (currSect == theDoc->u.reg.firstSection)
  172.                 theDoc->u.reg.firstSection = nil;
  173.  
  174.             if (currSect == theDoc->u.reg.lastSection)
  175.                 theDoc->u.reg.lastSection = nil;
  176.         }
  177.         prevSect = currSect;
  178.         currSect = (*currSect)->fNextSection;
  179.     }
  180. }
  181.  
  182. /**-----------------------------------------------------------------------
  183.         Name:         ReadASection
  184.         Purpose:        Read in a section from disk
  185.                         Read in the rAliasType and rsectionType resources and register
  186.                         the section with the document.
  187.     -----------------------------------------------------------------------**/
  188.  
  189. #pragma segment Editions
  190.  
  191. pascal void ReadASection(SectHandle aSectHandle)
  192. {
  193.     SectionHandle     aSectionHandle;
  194.     AliasHandle         anAlias;
  195.     OSErr               err;
  196.     FSSpec            myFSSpec;
  197.     Boolean            ignore;
  198.  
  199.     /*read in the rAliasType and rSectionType resources*/
  200.  
  201.     aSectionHandle = (SectionHandle)Get1Resource(rSectionType, (*aSectHandle)->fSectionID);
  202.     err            = HandToHand((Handle *)&aSectionHandle);
  203.     (*aSectHandle)->fSectHandle = aSectionHandle;
  204.     SetERefCon(aSectionHandle, aSectHandle);
  205.  
  206.     anAlias = (AliasHandle)Get1Resource(rAliasType, (*aSectHandle)->fSectionID);
  207.     err     = HandToHand((Handle *)&anAlias);
  208.     (*aSectionHandle)->alias = anAlias;
  209.  
  210.     /*now register the section*/
  211.  
  212.     err = ResolveAlias(nil, (*aSectionHandle)->alias, &myFSSpec, &ignore);
  213.     if (err) {
  214.         ShowError("\pResolve Alias", err);
  215.         return;
  216.     }
  217.  
  218.     err = RegisterSection(&myFSSpec, aSectionHandle, &ignore);
  219.  
  220.     if ((err) && (err != notThePublisherWrn) && (err != multiplePublisherWrn)) {
  221.         ShowError("\pRegisterSection", err);
  222.         return;
  223.     }
  224.     SetSelectionRgn(((*aSectHandle)->fDocument)->theText,
  225.                          (*aSectHandle)->fStart,
  226.                                     (*aSectHandle)->fEnd,
  227.                                     &(*aSectHandle)->fBorderRgn);
  228.     InvalRgn((*aSectHandle)->fBorderRgn);
  229. }
  230.  
  231. /**-----------------------------------------------------------------------
  232. Name:         ReadAllSectionResources
  233. Purpose:        Call the above routine to read in the resources for
  234.                 each section in the document.
  235. -----------------------------------------------------------------------**/
  236. #pragma segment Editions
  237.  
  238. pascal void ReadAllSectionResources(DPtr aDoc)
  239. {
  240.     SectHandle  theSection;
  241.  
  242.     if (aDoc->kind != kDocumentWindow)
  243.         return;
  244.         
  245.     /*read in each section resource*/
  246.  
  247.     theSection = aDoc->u.reg.firstSection;
  248.     while (theSection) {
  249.         ReadASection(theSection);
  250.         theSection = (*theSection)->fNextSection;
  251.     }
  252. }
  253.  
  254. /**-----------------------------------------------------------------------
  255. Name:         ReadSectionRecords
  256. Purpose:        Read in all the 'sect' resources and form list
  257.                 of sections in the document.    This is called from the
  258.                 main read document routine.
  259. -----------------------------------------------------------------------**/
  260. #pragma segment Editions
  261.  
  262. pascal void ReadSectionRecords(DPtr aDoc)
  263. {
  264.     short         theID;
  265.     SectHandle    aSectHandle;
  266.     OSErr         err;
  267.     short         theCount;
  268.  
  269.     /*read in all the 'sect' resources for our document's sections*/
  270.  
  271.     if (aDoc->kind != kDocumentWindow)
  272.         return;
  273.         
  274.     theCount = aDoc->u.reg.numSections;
  275.     if (theCount == 0)
  276.         return;
  277.  
  278.     aDoc->u.reg.numSections = 0;
  279.     for (theID = 1; theID <= theCount; theID++) {
  280.         aSectHandle = (SectHandle)Get1Resource('SECT', theID);
  281.         err = HandToHand((Handle *)&aSectHandle);
  282.  
  283.         /*now add it to the list*/
  284.  
  285.         if (aSectHandle)
  286.             AddSection(aSectHandle, aDoc);
  287.  
  288.         /*here we should recalculate the region for the bounds*/
  289.  
  290.         (*aSectHandle)->fBorderRgn = NewRgn();
  291.  
  292.         (*aSectHandle)->fDocument  = aDoc;
  293.     }
  294. }
  295.  
  296. /**-----------------------------------------------------------------------
  297.         Name:             SaveASection
  298.         Purpose:        Write out the 'sect', rAliasType and rSectionType resources
  299.                                 to file.    Called when the document is saved.
  300.     -----------------------------------------------------------------------**/
  301.  
  302. #pragma segment Editions
  303.  
  304. pascal void SaveASection(SectHandle aSection, short count)
  305. {
  306.     SectionHandle  EMSection;
  307.     OSErr          err;
  308.     Handle         tempHandle;
  309.  
  310.     HLock((Handle)aSection);
  311.  
  312.     /*save this section as its component rAliasType and rSectionType resource*/
  313.     /*also save as our own section record as a 'sect' resource*/
  314.  
  315.     EMSection  = (*aSection)->fSectHandle;
  316.     tempHandle = (Handle)EMSection;
  317.     err        = HandToHand(&tempHandle);
  318.  
  319.     HLock((Handle)EMSection);
  320.     AddResource(tempHandle, rSectionType, (*EMSection)->sectionID, "");
  321.     err = ResError();
  322.     if (err) {
  323.         ShowError("\pAddResource- rSectionType", err);
  324.         return;
  325.     }
  326.  
  327.     /*now add the alias resource*/
  328.     tempHandle = (Handle)(*EMSection)->alias;
  329.     err = HandToHand(&tempHandle);
  330.     AddResource(tempHandle, rAliasType, (*EMSection)->sectionID, "");
  331.     if (err) {
  332.         ShowError("\pAddResource- rAliasType", err);
  333.         return;
  334.     }
  335.  
  336.     /*now add our own resource- for now all the record, although we only need a few fields*/
  337.     tempHandle = (Handle)aSection;
  338.     err  = HandToHand(&tempHandle);
  339.     AddResource(tempHandle, 'SECT', count, "");
  340.     if (err) {
  341.         ShowError("\pAddResource- SECT", err);
  342.         return;
  343.     }
  344.  
  345.     HUnlock((Handle)aSection);
  346.     HUnlock((Handle)EMSection);
  347. }
  348.  
  349.  /**-----------------------------------------------------------------------
  350.         Name:         SaveSections
  351.         Purpose:        Called to go down to the section list and call SaveASection
  352.                         for each one.
  353.     -----------------------------------------------------------------------**/
  354.  
  355. #pragma segment Editions
  356.  
  357. pascal void SaveSections(DPtr aDocument)
  358. {
  359.     OSErr          err;
  360.     SectHandle     currSection;
  361.     short          count;
  362.  
  363.     if (aDocument->kind != kDocumentWindow)
  364.         return;
  365.  
  366.     /*go down the list and save each of the sections*/
  367.     /*the resource file is already open for writing*/
  368.  
  369.     count = 1;
  370.     err = ResError();
  371.     if (err) {
  372.         ShowError("\pHOpenResFile", err);
  373.         return;
  374.     }
  375.  
  376.     /*now go down the list*/
  377.     currSection = aDocument->u.reg.firstSection;
  378.     while (currSection) {
  379.         SaveASection(currSection, count);
  380.         currSection = (*currSection)->fNextSection;
  381.         count ++;
  382.     }
  383. }
  384.  
  385. /**-----------------------------------------------------------------------
  386.     Name:         AssocAllSections
  387.     Purpose:        Associate all the sections in a document with the document.
  388.                     Called on a SaveAs.
  389. -----------------------------------------------------------------------**/
  390.  
  391. #pragma segment Editions
  392.  
  393. pascal void AssocAllSections(DPtr theDoc)
  394. {
  395.     SectHandle    aSection;
  396.     SectionHandle EMSection;
  397.     OSErr         err;
  398.  
  399.     if (theDoc->kind != kDocumentWindow)
  400.         return;
  401.  
  402.     /*called by DoSaveAs.    Make sure sections are registered with this document*/
  403.     aSection = theDoc->u.reg.firstSection;
  404.     while (aSection) {
  405.         EMSection = (*aSection)->fSectHandle;
  406.         err = AssociateSection(EMSection, &theDoc->theFSSpec);
  407.         aSection  = (*aSection)->fNextSection;
  408.     }
  409. }
  410. #endif
  411.  
  412. /**-----------------------------------------------------------------------
  413.         Name:         KeyOKinSubscriber
  414.         Purpose:        Detects arrow keys.
  415.  -----------------------------------------------------------------------**/
  416. #define kChLeft    28
  417. #define kChRight    29
  418. #define kChUp        30
  419. #define kChDown    31
  420.  
  421. #pragma segment Editions
  422.  
  423. pascal Boolean KeyOKinSubscriber(char whatKey)
  424. {
  425.     return( (whatKey==kChUp) || (whatKey==kChDown) || (whatKey==kChLeft) || (whatKey==kChRight));
  426. } /*KeyOKinSubscriber*/
  427.  
  428. #ifndef RUNTIME
  429.  
  430. /**-----------------------------------------------------------------------
  431.         Name:         ShiftSection
  432.         Purpose:        Moves a section by howMany characters.
  433.  -----------------------------------------------------------------------**/
  434.  
  435. pascal void ShiftSection(SectHandle whichSection, short howMany)
  436. {
  437.     (*whichSection)->fStart += howMany;
  438.     (*whichSection)->fEnd   += howMany;
  439. }  /* ShiftSection */
  440.  
  441. /**-----------------------------------------------------------------------
  442. Name:         DoSectionRecalc
  443. Purpose:        Keeps track of the positions of the sections.
  444. -----------------------------------------------------------------------**/
  445.  
  446. #pragma segment Editions
  447.  
  448. pascal void DoSectionRecalc(DPtr theDoc, short toAdd)
  449. {
  450.     short        theStartPos;
  451.     short        theEndPos;
  452.     short        oldSectionStart;
  453.     short        oldSectionEnd;
  454.     SectHandle   aSection;
  455.     Boolean      wasChanged;
  456.     GrafPtr      oldPort;
  457.  
  458.     if (theDoc->kind != kDocumentWindow)
  459.         return;
  460.  
  461.     /*
  462.         Work thru all sections -
  463.         1) Those spanning area of modification get modified or zapped
  464.         2) Those after get shifted back or forwards.
  465.  
  466.         Sorry it is so complicated - there's a lot of possibilities
  467.     */
  468.     theStartPos = (*(theDoc->theText))->selStart;
  469.     theEndPos   = (*(theDoc->theText))->selEnd;
  470.  
  471.     aSection = theDoc->u.reg.firstSection;
  472.     while (aSection) {
  473.         wasChanged = true;
  474.  
  475.         oldSectionEnd   = (*aSection)->fEnd;
  476.         oldSectionStart = (*aSection)->fStart;
  477.  
  478.         if (theEndPos < (*aSection)->fStart)
  479.             ShiftSection(aSection, toAdd - (theEndPos-theStartPos));
  480.         else if (theStartPos == (*aSection)->fStart)
  481.             if (theEndPos == (*aSection)->fStart)
  482.                 ShiftSection(aSection, toAdd - (theEndPos-theStartPos));
  483.             else if (theEndPos >= (*aSection)->fEnd) /* section becomes pasted text */
  484.                 (*aSection)->fEnd = (*aSection)->fStart + toAdd;
  485.             else                                                                    /* insert pasted text */
  486.                 (*aSection)->fEnd = (*aSection)->fEnd + toAdd - (theEndPos-theStartPos);
  487.         else if (theStartPos< (*aSection)->fStart)
  488.             (*aSection)->fStart = theStartPos + toAdd; /* move start to end of pasted text */
  489.         else if (theStartPos <= (*aSection)->fEnd)
  490.             if (theEndPos >= (*aSection)->fEnd) /* end of section becomes pasted text */
  491.                 (*aSection)->fEnd = theStartPos + toAdd ;
  492.             else                                                                    /* insert pasted text into section */
  493.                 (*aSection)->fEnd = (*aSection)->fEnd + toAdd - (theEndPos-theStartPos);
  494.         else
  495.             wasChanged = false;
  496.  
  497.         if (wasChanged) {
  498.             (*aSection)->fCount = (*aSection)->fEnd - (*aSection)->fStart;
  499.  
  500.             if (theDoc->u.reg.showBorders) { /* Force an update of the borders - later*/
  501.                 GetPort(&oldPort);
  502.                 SetPort(theDoc->theWindow);
  503.  
  504.                 SetSelectionRgn(theDoc->theText,
  505.                                      oldSectionStart,
  506.                                      oldSectionEnd,
  507.                                      &(*aSection)->fBorderRgn);
  508.                 InvalRgn((*aSection)->fBorderRgn);
  509.  
  510.                 SetPort(oldPort);
  511.             }
  512.         }
  513.  
  514.         aSection = (*aSection)->fNextSection;
  515.     }
  516. }  /* DoSectionRecalc */
  517.  
  518. /**-----------------------------------------------------------------------
  519. Name:         ReadAnEdition
  520. Purpose:        Read the latest version of an edition from disk.
  521. -----------------------------------------------------------------------**/
  522.  
  523. #pragma segment Editions
  524.  
  525. pascal void ReadAnEdition(SectionHandle mySectHdl)
  526. {
  527.     SectHandle    aSectHandle;
  528.     EditionRefNum theRefNum;
  529.     OSErr         err;
  530.     Ptr           p;
  531.     Size          cutSize;
  532.  
  533.     p = nil;
  534.  
  535.     if (!mySectHdl) {
  536.         ShowError("\pmySectHdl is NIL", 0);
  537.         return;
  538.     }
  539.  
  540.     aSectHandle = (SectHandle)GetERefCon(mySectHdl);
  541.     if (!aSectHandle) {
  542.         ShowError("\paSectHandle is NIL", 0);
  543.         return;
  544.     }
  545.  
  546.     GetDateTime(&(*mySectHdl)->mdDate);
  547.  
  548.     /*read a subscriber in from disk.    Usually in response to a sectionread event*/
  549.  
  550.     if (err = OpenEdition(mySectHdl, &theRefNum)) {
  551.         ShowError("\pOpenEdition in ReadAnEdition", err);
  552.         return;
  553.     }
  554.  
  555.     if (err = EditionHasFormat(theRefNum, 'TEXT', &cutSize)) {
  556.         ShowError("\pEditionHasFormat in ReadAnEdition", err);
  557.         return;
  558.     }
  559.  
  560.     if (err = SetEditionFormatMark(theRefNum, 'TEXT', 0)) {
  561.         ShowError("\pSetEditionFormatMark in ReadAnEdition", err);
  562.         return;
  563.     }
  564.  
  565.     /*set up a buffer for the text we're going to read in*/
  566.     p = NewPtr(cutSize);
  567.     if (!p) {
  568.         ShowError("\pInsufficient memory to read edition", MemError());
  569.         return;
  570.     }
  571.  
  572.     if (err = ReadEdition(theRefNum, 'TEXT', p, &cutSize)) {
  573.         ShowError("\pReadEdition", err);
  574.         return;
  575.     }
  576.  
  577.     if (err = CloseEdition(theRefNum, true)) {
  578.         ShowError("\pCloseEdition", err);
  579.         return;
  580.     }
  581.  
  582.     /*
  583.         Ensure this section has a region and invalidate the old region
  584.     */
  585.  
  586.     if ((*aSectHandle)->fBorderRgn == nil)
  587.         (*aSectHandle)->fBorderRgn = NewRgn();
  588.  
  589.     SetSelectionRgn(((*aSectHandle)->fDocument)->theText,
  590.                          (*aSectHandle)->fStart,
  591.                          (*aSectHandle)->fEnd,
  592.                          &(*aSectHandle)->fBorderRgn);
  593.  
  594.     InvalRgn((*aSectHandle)->fBorderRgn);
  595.  
  596.     /*now insert the text in the right place by setting the selection range*/
  597.     /*we want this to act like paste, but without putting the contents on the clipboard*/
  598.     /*so we have to delete the current selection range and then insert our new text*/
  599.  
  600.     /*
  601.         Also fixup section info. for other moved sections
  602.     */
  603.  
  604.     TESetSelect((*aSectHandle)->fStart, (*aSectHandle)->fEnd, ((*aSectHandle)->fDocument)->theText);
  605.     DoSectionRecalc((*aSectHandle)->fDocument, cutSize);
  606.  
  607.     TEDelete(((*aSectHandle)->fDocument)->theText);
  608.     TEInsert(p, cutSize, ((*aSectHandle)->fDocument)->theText);
  609.  
  610.     /*
  611.         Now a little fix up - if the section was previously empty the
  612.         DoSectionRecalc will have put the text in before the section.
  613.         It's like that so you can type in before a subscriber in an
  614.         otherwise empty document. So now pull the start of this section
  615.         back to include the text we just added.
  616.     */
  617.  
  618.     (*aSectHandle)->fStart = (*aSectHandle)->fEnd - cutSize;
  619.  
  620.     /*
  621.         Force redraw of this region
  622.     */
  623.  
  624.     SetSelectionRgn(((*aSectHandle)->fDocument)->theText, 
  625.                          (*aSectHandle)->fStart,
  626.                          (*aSectHandle)->fEnd,
  627.                          &(*aSectHandle)->fBorderRgn);
  628.  
  629.     InvalRgn((*aSectHandle)->fBorderRgn);
  630.  
  631.     DisposPtr(p);
  632. }
  633.  
  634. /**-----------------------------------------------------------------------
  635. Name:         WriteAnEdition
  636. Purpose:        Write out the latest version of an Edition.
  637.                 Called on a Save and on selecting WriteEdition now from
  638.                 the Publisher Options dialog.
  639. -----------------------------------------------------------------------**/
  640.  
  641. #pragma segment Editions
  642.  
  643. pascal void WriteAnEdition(SectionHandle mySectHdl)
  644. {
  645.     OSErr           err;
  646.     SectHandle      aSectHandle;
  647.     EditionRefNum   theRefNum;
  648.     Handle          aHandle;
  649.     FSSpecPtr       theFSSpecPtr;
  650.  
  651.     aSectHandle = (SectHandle)GetERefCon(mySectHdl);
  652.     /*alter the modification date for the section*/
  653.     GetDateTime(&(*mySectHdl)->mdDate);
  654.     /*write out the edition.  Assume that it is a publisher for now*/
  655.     /*subscribers will be opened for writing with OpenEdition*/
  656.  
  657.     if (((*aSectHandle)->fDocument)->u.reg.everSaved == false)
  658.         theFSSpecPtr = nil;
  659.     else
  660.         theFSSpecPtr = &((*aSectHandle)->fDocument)->theFSSpec;
  661.  
  662.     if (err = OpenNewEdition(mySectHdl, MPAppSig, theFSSpecPtr, &theRefNum)) {
  663.         ShowError("\pOpenNewEdition", err);
  664.         return;
  665.     }
  666.  
  667.     if (err = SetEditionFormatMark(theRefNum, 'TEXT', 0)) {
  668.         ShowError("\pSetEditionFormatMark", err);
  669.         return;
  670.     }
  671.  
  672.     /*now get a handle to the text to be written out*/
  673.     /*use the same start and end positions for now, increasing and decreasing*/
  674.     /*the selection will be implemented later*/
  675.  
  676.     aHandle = GetHandleToText(((*aSectHandle)->fDocument)->theText,
  677.                                       (*aSectHandle)->fStart,
  678.                                       (*aSectHandle)->fEnd);
  679.     HLock(aHandle);
  680.  
  681.     /*make sure the count is up to date*/
  682.     (*aSectHandle)->fCount = (*aSectHandle)->fEnd - (*aSectHandle)->fStart;
  683.  
  684.     if (err = WriteEdition(theRefNum, 'TEXT', *aHandle, (*aSectHandle)->fCount)) {
  685.         ShowError("\pWriteEdition", err);
  686.         return;
  687.     }
  688.     HUnlock(aHandle);
  689.  
  690.     /*remember to save the section and alias records as resources later*/
  691.  
  692.     /*now close the edition*/
  693.  
  694.     if (err = CloseEdition(theRefNum, true)) {
  695.         ShowError("\pCloseEdition", err);
  696.         return;
  697.     }
  698.  
  699.     /*
  700.         Clean Up
  701.     */
  702.  
  703.     DisposHandle(aHandle);
  704. }     /*WriteAnEdition*/
  705.  
  706. /**-----------------------------------------------------------------------
  707.     Name:         WriteAllEditions
  708.     Purpose:        Go down the list and call WriteAnEdition
  709. -----------------------------------------------------------------------**/
  710.  
  711. #pragma segment Editions
  712.  
  713. pascal void WriteAllEditions(DPtr aDocument)
  714. {
  715.     SectHandle      aSection;
  716.     SectionHandle   EMSection;
  717.  
  718.     if (aDocument->kind != kDocumentWindow)
  719.         return;
  720.         
  721.     /*called on a Save, to write out all editions*/
  722.     aSection = aDocument->u.reg.firstSection;
  723.  
  724.     while (aSection) {
  725.         EMSection = (*aSection)->fSectHandle;
  726.         if ((*EMSection)->kind == stPublisher)
  727.             WriteAnEdition(EMSection);
  728.         aSection = (*aSection)->fNextSection;
  729.     }
  730. }
  731.  
  732. /**-----------------------------------------------------------------------
  733. Name:         DeRegisterAllSections
  734. Purpose:        Called on cancel Publisher/Subscriber and on a close.
  735. -----------------------------------------------------------------------**/
  736.  
  737. #pragma segment Editions
  738.  
  739. pascal void DeRegisterAllSections(DPtr aDoc)
  740.   {
  741.         SectHandle      aSection;
  742.         SectionHandle   EMSection;
  743.         OSErr           err;
  744.  
  745.         aSection = aDoc->u.reg.firstSection;
  746.         while (aSection)
  747.             {
  748.                 EMSection = (*aSection)->fSectHandle;
  749.                 err = UnRegisterSection(EMSection);
  750.                 aSection = (*aSection)->fNextSection;
  751.             }
  752.     }
  753.  
  754. /**-----------------------------------------------------------------------
  755. Name:         GetHandleToText
  756. Purpose:        Get a handle to the current text selection.
  757.                 Used to provide a preview on Create Publisher...
  758. -----------------------------------------------------------------------**/
  759.  
  760. #pragma segment Editions
  761.  
  762. pascal Handle GetHandleToText(TEHandle aTEHandle, short theStart, short theEnd)
  763. {
  764.     OSErr     err;
  765.     Handle    myHandle;
  766.     Ptr       p;
  767.  
  768.     HLock((*aTEHandle)->hText);
  769.     p  = *((*aTEHandle)->hText);
  770.     p  += theStart;
  771.     err = PtrToHand(p, &myHandle, (theEnd - theStart));
  772.     HUnlock((*aTEHandle)->hText);
  773.     return(myHandle);
  774. } /* GetHandleToText */
  775.  
  776. /**-----------------------------------------------------------------------
  777.         Name:         FindLine
  778.         Purpose:        Find the line a character is in.
  779.                         Used to find to calculate the region to use for the Publisher/
  780.                         Subscriber borders.
  781.     -----------------------------------------------------------------------**/
  782.  
  783. #pragma segment Editions
  784.  
  785. pascal short FindLine(short thePos,TEHandle theTEHandle)
  786. {
  787.     short    index;
  788.     short    theFirstPos;
  789.     short    theNextPos;
  790.  
  791.     index = 0;
  792.  
  793.     do {
  794.         theFirstPos = (*theTEHandle)->lineStarts[index];
  795.         theNextPos  = (*theTEHandle)->lineStarts[index + 1];
  796.         index++;
  797.     } while (! (((thePos >= theFirstPos) && (thePos < theNextPos)) ||
  798.                     (index > (*theTEHandle)->nLines)));
  799.  
  800.     return(index);
  801. }
  802.  
  803. /**-----------------------------------------------------------------------
  804.         Name:         DrawSelectionRgn
  805.         Purpose:        Given a text handle and a start and end position this routine
  806.                         will draw a section border around the selected text.
  807.                         Must allow for the case when the section has no text in it-
  808.                         but we still want to show it as a published section
  809.  -----------------------------------------------------------------------**/
  810.  
  811. pascal void DrawSelectionRegion(TEHandle theTEHandle, short posStart, short posEnd)
  812. {
  813.     RgnHandle  theSelRgn;
  814.     
  815.     theSelRgn = NewRgn();
  816.     
  817.     SetSelectionRgn(theTEHandle, posStart, posEnd,&theSelRgn);
  818.     FrameRgn(theSelRgn);
  819.     
  820.     DisposeRgn(theSelRgn);
  821. } /* DrawSelectionRegion */
  822.  
  823. /**-----------------------------------------------------------------------
  824.         Name:         SetSelectionRgn
  825.         Purpose:        Given a text handle and a start and end position this routine
  826.                         will return the region which is necessary to draw a section
  827.                         border around the selected text.
  828.                         Must allow for the case when the section has no text in it-
  829.                         but we still want to show it as a published section
  830.  -----------------------------------------------------------------------**/
  831.  
  832. #pragma segment Editions
  833.  
  834. pascal void SetSelectionRgn(TEHandle theTEHandle, short posStart, short posEnd, RgnHandle *theSelRgn)
  835. {
  836.     Point           theStart;
  837.     Point           theEnd;
  838.     short           startLine;
  839.     short           endLine;
  840.     Rect            theRect;
  841.     short           theLeft;
  842.     short           theRight;
  843.     short           theBottom;
  844.     short           theTop;
  845.     short           slineHeight;
  846.     short           elineHeight;
  847.     short           fontAscent;
  848.     TextStyle       theTStyle;
  849.  
  850.     /*first of all find out if the text is on the same line*/
  851.     startLine = FindLine(posStart, theTEHandle);
  852.     endLine   = FindLine(posEnd, theTEHandle);
  853.  
  854.     theStart = TEGetPoint(posStart, theTEHandle);
  855.     theEnd   = TEGetPoint(posEnd, theTEHandle);
  856.  
  857. /*
  858. Get the line height info
  859. */
  860.     TEGetStyle(posStart, &theTStyle, &slineHeight, &fontAscent, theTEHandle);
  861.     TEGetStyle(posEnd,   &theTStyle, &elineHeight, &fontAscent, theTEHandle);
  862.  
  863.     if (startLine == endLine) {
  864.         /*use the start and end points to form the rectangle and draw this into the region*/
  865.         theStart.v -= slineHeight;
  866.         Pt2Rect(theStart, theEnd, &theRect);
  867.         InsetRect(&theRect, - 1, - 1);
  868.         RectRgn(*theSelRgn, &theRect);
  869.     } else {
  870.         theLeft  = (*theTEHandle)->destRect.left;
  871.         theRight = (*theTEHandle)->destRect.right;
  872.         theTop   = theStart.v - slineHeight;
  873.         theBottom  = theEnd.v;
  874.         OpenRgn();
  875.         MoveTo(theStart.h, theStart.v - slineHeight);
  876.         LineTo(theRight, theStart.v - slineHeight);
  877.         LineTo(theRight, theEnd.v - elineHeight);
  878.         LineTo(theEnd.h, theEnd.v - elineHeight);
  879.         LineTo(theEnd.h, theEnd.v);
  880.         LineTo(theLeft, theEnd.v);
  881.         LineTo(theLeft, theStart.v);
  882.         LineTo(theStart.h, theStart.v);
  883.         LineTo(theStart.h, theStart.v - slineHeight);
  884.         CloseRgn(*theSelRgn);
  885.     }
  886.  
  887.     InsetRgn(*theSelRgn, - 2, - 2);
  888. }
  889.  
  890. /**-----------------------------------------------------------------------
  891.         Name:         ShowSectionBorders
  892.         Purpose:        Show the borders for all the sections in a document.
  893.                         Show a Publisher border in 50% gray, a subscriber in 75% gray
  894.  -----------------------------------------------------------------------**/
  895.  
  896. #pragma segment Editions
  897.  
  898. pascal void ShowSectionBorders(DPtr aDoc)
  899. {
  900.     SectHandle aSection;
  901.  
  902.     if (aDoc->kind != kDocumentWindow)
  903.         return;
  904.         
  905.     PenNormal();
  906.     PenSize(3, 3);
  907.     PenPat(&qd.gray);
  908.     aSection = aDoc->u.reg.firstSection;
  909.     while (aSection) {
  910.         if ((*aSection)->fBorderRgn) {
  911.             SetSelectionRgn(((*aSection)->fDocument)->theText,
  912.                                  (*aSection)->fStart,
  913.                                  (*aSection)->fEnd,
  914.                                  &(*aSection)->fBorderRgn);
  915.  
  916.             if ((*(*aSection)->fSectHandle)->kind == stPublisher)
  917.                 PenPat(&qd.gray);
  918.             else
  919.                 PenPat(&qd.dkGray);
  920.  
  921.             FrameRgn((*aSection)->fBorderRgn);
  922.             PenNormal();
  923.         }
  924.         aSection = (*aSection)->fNextSection;
  925.     }
  926.     PenNormal();
  927. }
  928.  
  929. /**-----------------------------------------------------------------------
  930.         Name:         RecalcBorders
  931.         Purpose:        Recalculate all the borders for the sections in a document.
  932.  -----------------------------------------------------------------------**/
  933.  
  934. #pragma segment Editions
  935.  
  936. pascal void RecalcBorders(DPtr aDoc, Boolean invalidate)
  937. {
  938.     SectHandle  aSection;
  939.  
  940.     if (aDoc->kind != kDocumentWindow)
  941.         return;
  942.         
  943.     /*go down the section list and recalculate all the borders*/
  944.     aSection = aDoc->u.reg.firstSection;
  945.     while (aSection) {
  946.         if ((*aSection)->fBorderRgn) {
  947.             if (invalidate)
  948.                 InvalRgn((*aSection)->fBorderRgn);
  949.  
  950.             SetSelectionRgn(((*aSection)->fDocument)->theText,
  951.                                  (*aSection)->fStart,
  952.                                  (*aSection)->fEnd,
  953.                                  &(*aSection)->fBorderRgn);
  954.  
  955.             if (invalidate)
  956.                 InvalRgn((*aSection)->fBorderRgn);
  957.         }
  958.         aSection = (*aSection)->fNextSection;
  959.     }
  960. }
  961.  
  962. /**-----------------------------------------------------------------------
  963.         Name:         GetSection
  964.         Purpose:        Given a start and end of a selection- return the section
  965.                         handle if it is in a Publisher or Subscriber.
  966.  -----------------------------------------------------------------------**/
  967.  
  968. #pragma segment Editions
  969.  
  970. pascal SectHandle GetSection(short theStartPos, short theEndPos, DPtr aDoc)
  971. {
  972.     SectHandle   foundSection;
  973.     SectHandle   aSection;
  974.  
  975.     /*returns the section handle for the section between theStartPos and theEndPos*/
  976.  
  977.     if (aDoc->kind != kDocumentWindow)
  978.         return nil;
  979.         
  980.     foundSection = nil;
  981.  
  982.     aSection = aDoc->u.reg.firstSection;
  983.     while (aSection) {
  984.         if ((theStartPos >= (*aSection)->fStart) && (theEndPos <= (*aSection)->fEnd))
  985.             foundSection = aSection;
  986.         aSection = (*aSection)->fNextSection;
  987.     }
  988.  
  989.     return foundSection;
  990. }
  991.  
  992. /**-----------------------------------------------------------------------
  993.         Name:         DoTEPasteSectionRecalc
  994.         Purpose:        Keeps track of the positions of the sections call before a
  995.                     TEPaste or TEStylPaste.
  996.  -----------------------------------------------------------------------**/
  997.  
  998. pascal void DoTEPasteSectionRecalc(DPtr theDoc)
  999. {
  1000.     short toAdd;
  1001.  
  1002.     if (theDoc->kind != kDocumentWindow)
  1003.         return;
  1004.         
  1005.     toAdd = TEGetScrapLen();
  1006.     DoSectionRecalc(theDoc, toAdd);
  1007. }  /* DoTEPasteSectionRecalc */
  1008.  
  1009. /**-----------------------------------------------------------------------
  1010.         Name:         DoTEDeleteSectionRecalc
  1011.         Purpose:        Keeps track of the positions of the sections call before a
  1012.                     TEDelete.
  1013.  -----------------------------------------------------------------------**/
  1014.  
  1015. pascal void DoTEDeleteSectionRecalc(DPtr theDoc)
  1016. {
  1017.     if (theDoc->kind != kDocumentWindow)
  1018.         return;
  1019.         
  1020.     DoSectionRecalc(theDoc, 0);
  1021. }  /* DoTEDeleteSectionRecalc */
  1022.  
  1023. /**-----------------------------------------------------------------------
  1024.         Name:         DoTECutSectionRecalc
  1025.         Purpose:        Keeps track of the positions of the sections call before a
  1026.                     TECut.
  1027.  -----------------------------------------------------------------------**/
  1028.  
  1029. pascal void DoTECutSectionRecalc(DPtr theDoc)
  1030. {
  1031.     if (theDoc->kind != kDocumentWindow)
  1032.         return;
  1033.         
  1034.     DoSectionRecalc(theDoc, 0);
  1035. }  /* DoTEDeleteSectionRecalc */
  1036.  
  1037. /**-----------------------------------------------------------------------
  1038.         Name:         DoTEKeySectionRecalc
  1039.         Purpose:        Keeps track of the positions of the sections call before a
  1040.                     TECut.
  1041.  -----------------------------------------------------------------------**/
  1042.  
  1043. pascal void DoTEKeySectionRecalc(DPtr theDoc,char theChar)
  1044. {
  1045.     short     toAdd;
  1046.     short     oldStart;
  1047.  
  1048.     if (theDoc->kind != kDocumentWindow)
  1049.         return;
  1050.         
  1051.     if (!KeyOKinSubscriber(theChar)) /* is it a cursor motion key? - yes = ignore */ {
  1052.         if (theChar==8)
  1053.             if ((*(theDoc->theText))->selStart<(*(theDoc->theText))->selEnd)
  1054.                 toAdd = 0;
  1055.             else {
  1056.                 toAdd = -1;
  1057.                 oldStart = (*(theDoc->theText))->selStart;
  1058.  
  1059.                 (*(theDoc->theText))->selStart = GreaterOf(oldStart-1,0);
  1060.                 DoSectionRecalc(theDoc, 0);
  1061.                 (*(theDoc->theText))->selStart = oldStart;
  1062.             }
  1063.         else
  1064.             toAdd = 1;
  1065.  
  1066.         if (toAdd!=-1)
  1067.             DoSectionRecalc(theDoc, toAdd);
  1068.     }
  1069. }  /* DoTEKeySectionRecalc */
  1070.  
  1071. /**-----------------------------------------------------------------------
  1072.         Name:         GetEditionContainer
  1073.         Purpose:        Gets the Edition Container to put the edition into.
  1074.                         The main user interface stuff.
  1075.                         Puts up the new publisher dialog.
  1076.                         Should check kAEInteractWithUser etc.
  1077.  -----------------------------------------------------------------------**/
  1078.  
  1079. #pragma segment Main
  1080.  
  1081. pascal OSErr GetEditionContainer(DPtr theDoc, FSSpec *theFSSpec)
  1082. {
  1083.     OSErr             err;
  1084.     NewPublisherReply myReply;
  1085.     short             theStart;
  1086.     short             theEnd;
  1087.     Handle            myHandle;
  1088.     TEHandle          myText;
  1089.  
  1090.     if (theDoc->kind != kDocumentWindow)
  1091.         return noErr;
  1092.         
  1093.     err = noErr;
  1094.  
  1095.     /*get default editionContainer to use, using last volume and folder*/
  1096.  
  1097.     myReply.container.thePart = kPartsNotUsed;
  1098.  
  1099.     err = GetLastEditionContainerUsed(&myReply.container);
  1100.  
  1101.     if (err==fnfErr)
  1102.         err = noErr;
  1103.  
  1104.     myText = theDoc->theText;
  1105.  
  1106.     theStart = (*myText)->selStart;
  1107.     theEnd   = (*myText)->selEnd;
  1108.  
  1109.     if (err==noErr) {
  1110.         /*
  1111.             Create a handle containing the text to be published for previewing -
  1112.             need to ask the user where to put the data
  1113.         */
  1114.         myHandle = GetHandleToText(myText, theStart, theEnd);
  1115.  
  1116.         myReply.usePart       = false;
  1117.         myReply.preview       = myHandle;
  1118.         myReply.previewFormat = 'TEXT';
  1119.         myReply.container.theFile.name[0] = 0; /* Want a proper prompted name here */
  1120.         HLock(myHandle);
  1121.  
  1122.         /* Should take suggested name and avoid dialog if no user interaction */
  1123.  
  1124.         err = AEInteractWithUser(kAEDefaultTimeout, nil, nil);
  1125.  
  1126.         err = NewPublisherDialog(&myReply);
  1127.         HUnlock(myHandle);
  1128.         DisposHandle(myHandle);
  1129.     }
  1130.  
  1131.     /*IF user cancelled, THEN exit from this routine*/
  1132.  
  1133.     if (err==noErr)
  1134.         if (myReply.canceled)
  1135.             err = userCanceledErr; /* User cancelled marker - replace later */
  1136.  
  1137.     if (err==noErr)
  1138.         if (myReply.replacing)
  1139.             err = FSpDelete(&myReply.container.theFile);
  1140.  
  1141.     if (err == noErr)
  1142.         *theFSSpec = myReply.container.theFile;
  1143.  
  1144.     return(err);
  1145. } /*GetEditionContainer*/
  1146.  
  1147.  
  1148. /**-----------------------------------------------------------------------
  1149.         Name:             PublishText
  1150.         Purpose:        Publishes the current selection of theDoc.
  1151.                                 The main user interface stuff.
  1152.                                 Puts up the new publisher dialog - if theFSSpec=NIL
  1153.                                 Writes the new edition out to disk.
  1154.  -----------------------------------------------------------------------**/
  1155.  
  1156. #pragma segment Main
  1157.  
  1158. pascal OSErr PublishText(DPtr theDoc, FSSpecPtr theFSSpec)
  1159. {
  1160.     NewPublisherReply myReply;
  1161.     SectionHandle        mySectHdl;
  1162.     OSErr                 err;
  1163.     long               mysectionID;
  1164.     FSSpecPtr             pubFSSpec;
  1165.     short                 theStart;
  1166.     short                 theEnd;
  1167.     RgnHandle             theRgnHandle;
  1168.  
  1169.     if (theDoc->kind != kDocumentWindow)
  1170.         return noErr;
  1171.         
  1172.     mysectionID            = theDoc->u.reg.lastID + 1;
  1173.     theDoc->u.reg.lastID = mysectionID;
  1174.  
  1175.     /*get default editionContainer to use, using last volume and folder*/
  1176.  
  1177.     myReply.container.thePart = kPartsNotUsed;
  1178.  
  1179.     err = GetLastEditionContainerUsed(&myReply.container);
  1180.  
  1181.     if (err==fnfErr)
  1182.         err = noErr;
  1183.  
  1184.     theStart = (*theDoc->theText)->selStart;
  1185.     theEnd   = (*theDoc->theText)->selEnd;
  1186.  
  1187.     /*don't want to publish an empty section*/
  1188.  
  1189.     if (theEnd - theStart == 0)
  1190.         err = userCanceledErr;
  1191.  
  1192.     myReply.container.theFile = *theFSSpec;
  1193.  
  1194.     /*now publish this section*/
  1195.  
  1196.     if (err == noErr)
  1197.         err = CreateEditionContainerFile(&myReply.container.theFile, MPAppSig, 0);
  1198.  
  1199.     /*check IF the file has been saved, IF not set pubCFS to NIL*/
  1200.  
  1201.     if (theDoc->u.reg.everSaved == false)
  1202.         pubFSSpec = nil;
  1203.     else
  1204.         pubFSSpec = &theDoc->theFSSpec;
  1205.  
  1206.     /*get the region to encompass the selection*/
  1207.  
  1208.     theRgnHandle = NewRgn();
  1209.     SetSelectionRgn(theDoc->theText,
  1210.                          (*theDoc->theText)->selStart,
  1211.                                     (*theDoc->theText)->selEnd,
  1212.                                     &theRgnHandle);
  1213.  
  1214.     InvalRgn(theRgnHandle);
  1215.  
  1216.     /*create a publisher section*/
  1217.     if (err==noErr) {
  1218.         err = NewSection(&myReply.container,
  1219.                               pubFSSpec,
  1220.                               stPublisher,
  1221.                               mysectionID,
  1222.                               pumOnSave,
  1223.                               &mySectHdl);
  1224.  
  1225.         /*now add this section to our document list*/
  1226.  
  1227.         if (err == noErr)
  1228.             CreateSection(mySectHdl, mysectionID, theStart, theEnd, theDoc, theRgnHandle);
  1229.     }
  1230.  
  1231.     /*now write out the edition to file*/
  1232.  
  1233.     if (err==noErr)
  1234.         WriteAnEdition(mySectHdl);
  1235.  
  1236.     return(err);
  1237. } /*PublishText*/
  1238.  
  1239. /**-----------------------------------------------------------------------
  1240.         Name:         DoSubscribe
  1241.         Purpose:        Subscribe to a published section. Puts up the subscriber
  1242.                         dialog, creates and adds the new section.
  1243.  -----------------------------------------------------------------------**/
  1244.  
  1245. #pragma segment Main
  1246.  
  1247. pascal void DoSubscribe(DPtr theDoc)
  1248. {
  1249.     NewSubscriberReply myReply;
  1250.     SectionHandle      mySectHdl;
  1251.     long               mysectionID;
  1252.     FSSpecPtr          subFSSpec; /*the fsspec for the subscriber file*/
  1253.     OSErr              err;
  1254.     short              theStart;
  1255.     short              theEnd;
  1256.  
  1257.     if (theDoc->kind != kDocumentWindow)
  1258.         return;
  1259.         
  1260.     mysectionID = theDoc->u.reg.lastID + 1;
  1261.     theDoc->u.reg.lastID = mysectionID;
  1262.     err = noErr;
  1263.  
  1264.     /*get default editionContainer to use, using last volume and folder*/
  1265.     /*  myreply.container.thePart := kPartNumberUnknown;*/
  1266.     myReply.formatsMask = kTEXTformatMask;
  1267.  
  1268.     err = GetLastEditionContainerUsed(&myReply.container);
  1269.     if (err && (err !=fnfErr)) {
  1270.         ShowError("\pGetLastEditionContainerUsed", err);
  1271.         return;
  1272.     }
  1273.  
  1274.     /*put up the subscriber dialog*/
  1275.     err = NewSubscriberDialog(&myReply);
  1276.     if (err && (err !=fnfErr)) {
  1277.         ShowError("\pNewSubscriberDialog", err);
  1278.         return;
  1279.     }
  1280.  
  1281.     if (myReply.canceled)
  1282.         return;
  1283.  
  1284.     /*check IF the file has been saved, IF not set pubCFS to NIL*/
  1285.     if (theDoc->u.reg.everSaved == false)
  1286.         subFSSpec = nil;
  1287.     else
  1288.         subFSSpec = &theDoc->theFSSpec;
  1289.  
  1290.     /*create a publisher section*/
  1291.     err = NewSection(&myReply.container,
  1292.                           subFSSpec,
  1293.                           stSubscriber,
  1294.                           mysectionID,
  1295.                           sumAutomatic,
  1296.                           &mySectHdl);
  1297.  
  1298.     if (err) {
  1299.         ShowError("\pNewSection", err);
  1300.         return;
  1301.     }
  1302.  
  1303.     theStart = (*theDoc->theText)->selStart;
  1304.     theEnd   = (*theDoc->theText)->selEnd;
  1305.  
  1306.     /*now add this section to our document list*/
  1307.  
  1308.     CreateSection(mySectHdl, mysectionID, theStart, theEnd, theDoc, nil);
  1309.  
  1310.     /*read the subscriber in from disk*/
  1311.  
  1312.     ReadAnEdition(mySectHdl);
  1313.  
  1314. }  /*DoSubscribe*/
  1315.  
  1316. /**-----------------------------------------------------------------------
  1317.         Name:         DoSectionOptions
  1318.         Purpose:        Put up the section option dialogs for a publisher
  1319.                         or subscriber.    Handle all the various options.
  1320.                         Note that 'Find Publisher' doesn't work yet.
  1321.  -----------------------------------------------------------------------**/
  1322.  
  1323. #pragma segment Main
  1324.  
  1325. pascal void DoSectionOptions(DPtr theDoc)
  1326. {
  1327.     OSErr               err;
  1328.     SectionOptionsReply reply;
  1329.     EditionInfoRecord   theInfo;
  1330.     SectHandle          currSection;
  1331.  
  1332.     if (theDoc->kind != kDocumentWindow)
  1333.         return;
  1334.         
  1335.     currSection = GetSection((*theDoc->theText)->selStart,
  1336.                                                      (*theDoc->theText)->selEnd,
  1337.                                                      theDoc);
  1338.  
  1339.     reply.sectionH = (*currSection)->fSectHandle;
  1340.     err = SectionOptionsDialog(&reply);
  1341.     if (!reply.canceled) {
  1342.         /*find out IF there is any action needed*/
  1343.         if (reply.action == 'read')
  1344.         /*read the latest version of a subscriber*/
  1345.             ReadAnEdition((*currSection)->fSectHandle);
  1346.         else if (reply.action == 'writ')
  1347.         /*write out the latest version of a publisher to disk*/
  1348.             WriteAnEdition((*currSection)->fSectHandle);
  1349.         else if (reply.action == 'goto') /*goto a published section*/ {
  1350.             err = GetEditionInfo((*currSection)->fSectHandle, &theInfo);
  1351.  
  1352.             if (err)
  1353.                 ShowError("\pGetEditionInfo", err);
  1354.  
  1355.             err = GoToPublisherSection(&theInfo.container);
  1356.  
  1357.             if (err)
  1358.                 ShowError("\pGotoPublisherSection", err);
  1359.         } else if (reply.action == 'cncl') /*cancel a publisher or subscriber*/ {
  1360.             /*unRegister the section and delete from our own list*/
  1361.             /*should have a free PROCEDURE which frees the structures*/
  1362.             /*associated with a section*/
  1363.             err = UnRegisterSection((*currSection)->fSectHandle);
  1364.             DeleteASection(currSection, theDoc);
  1365.  
  1366.             /*IF this is the ONLY publisher writing data to this edition*/
  1367.             /*we should delete the container file as well*/
  1368.         }
  1369.     }
  1370. }
  1371.  
  1372. #endif