home *** CD-ROM | disk | FTP | other *** search
/ AppleScript - The Beta Release / AppleScript - The Beta Release.iso / Development Tools / Sample Applications / MenuScripter 1.0d4.1 / MenuScripter Source / MSEditions.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-24  |  41.5 KB  |  1,514 lines  |  [TEXT/MPS ]

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