home *** CD-ROM | disk | FTP | other *** search
- /*
- MSEditions.c
-
- Version 1.0d4
-
- Copyright © Apple Computer UK Ltd. 1992
-
- All rights reserved.
-
- Produced by : UK Developer Technical Support
- AppleLink : UK.DTS
-
- The Edition Manager routines from the Menuscripter example.
-
-
- Known incomplete bits-:
- i) Handling the mouse downs for Publishers and Subscribers is not all there-
- future versions will include double clicking to open the section options dialog,
- for example.
- ii) There are problems if an edition is moved from the Finder- there needs to
- be code added to handle orphaned sections.
- iii) We need to issue a warning if a document is disposed of containing
- sections that will be lost.
- */
- /*
- Changes for 1.0d3:
-
- 1-Sep-92 : NH : RecalcChangedSectionBorders and OKToModifySelection added
-
- */
-
- #include <OSUtils.h>
- #include <Resources.h>
- #include <Errors.h>
- #include <AppleEvents.h>
-
- #include "MSEditions.h"
-
- /**-----------------------------------------------------------------------
- Name: GetERefCon
- Purpose: Return the sectHandle (our own type) stored in
- the refcon of the SectionRecord.
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal SectHandle GetERefCon(SectionHandle EMSection)
- {
- SectHandle aSectHandle;
-
- aSectHandle = (SectHandle)(*EMSection)->refCon;
- return(aSectHandle);
- }
-
- /**-----------------------------------------------------------------------
- Name: SetERefCon
- Purpose: Store a handle to our own SectRecord in the refcon
- field of the SectionRecord.
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void SetERefCon(SectionHandle EMSection, SectHandle aSectHandle)
- {
- (*EMSection)->refCon = (long)aSectHandle;
- }
-
- /**-----------------------------------------------------------------------
- Name: AddSection
- Purpose: Add our own section record to the document linked
- list. Set up the first and last section variables.
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void AddSection(SectHandle newSection, DPtr aDocument)
- {
- /*
- add the section to the document
- */
- aDocument->numSections += 1;
-
- /*
- if not NIL, add the new section to the list after the last element
- */
-
- if (aDocument->lastSection)
- (*(aDocument->lastSection))->fNextSection = newSection;
- else
- aDocument->firstSection = newSection;
-
- aDocument->lastSection = newSection;
- (*newSection)->fNextSection = nil;
- }
-
- /**-----------------------------------------------------------------------
- Name: CreateSection
- Purpose: Create a new section record to hold a Publisher or
- Subscriber. Link this to the SectionRecord.
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void CreateSection(SectionHandle EMSection,
- short sectionID,
- short theStart,
- short theEnd,
- DPtr aDocument,
- RgnHandle theBorder)
-
- {
- SectHandle newSection;
-
- /*
- create a section and call AddSection to add it to the list
- */
- newSection = (SectHandle)NewHandle(sizeof(SectRec));
-
- if (newSection)
- {
- (*newSection)->fSectionID = sectionID;
- (*newSection)->fNextSection = nil;
- (*newSection)->fSectHandle = EMSection;
- (*newSection)->fStart = theStart;
- (*newSection)->fEnd = theEnd;
- (*newSection)->fCount = theEnd - theStart;
- (*newSection)->fBorderRgn = theBorder;
- (*newSection)->fDocument = aDocument;
-
- /*
- put a reference to our section record in the section's refCon field
- */
-
- SetERefCon(EMSection, newSection);
- AddSection(newSection, aDocument);
- }
- }
-
- /**-----------------------------------------------------------------------
- Name: DeleteASection
- Purpose: Delete the section from the list.
- Called when 'Cancel Publisher/Subscriber is chosen in
- the 'Section Options' dialog.
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void DeleteASection(SectHandle sectToDelete, DPtr theDoc)
- {
- SectHandle currSect;
- SectHandle prevSect;
-
- currSect = theDoc->firstSection;
- prevSect = nil;
-
- while (currSect)
- {
- if (currSect == sectToDelete)
- {
- /*
- unlink the section from the list
- */
- if (prevSect)
- (*prevSect)->fNextSection = (*currSect)->fNextSection;
-
- if (currSect == theDoc->firstSection)
- theDoc->firstSection = nil;
-
- if (currSect == theDoc->lastSection)
- theDoc->lastSection = nil;
- }
- prevSect = currSect;
- currSect = (*currSect)->fNextSection;
- }
- }
-
- /**-----------------------------------------------------------------------
- Name: ReadASection
- Purpose: Read in a section from disk
- Read in the rAliasType and rsectionType resources and register
- the section with the document.
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void ReadASection(SectHandle aSectHandle)
- {
- SectionHandle aSectionHandle;
- AliasHandle anAlias;
- OSErr err;
- FSSpec myFSSpec;
- Boolean ignore;
-
- /*read in the rAliasType and rSectionType resources*/
-
- aSectionHandle = (SectionHandle)Get1Resource(rSectionType, (*aSectHandle)->fSectionID);
- err = HandToHand((Handle *)&aSectionHandle);
- (*aSectHandle)->fSectHandle = aSectionHandle;
- SetERefCon(aSectionHandle, aSectHandle);
-
- anAlias = (AliasHandle)Get1Resource(rAliasType, (*aSectHandle)->fSectionID);
- err = HandToHand((Handle *)&anAlias);
- (*aSectionHandle)->alias = anAlias;
-
- /*now register the section*/
-
- err = ResolveAlias(nil, (*aSectionHandle)->alias, &myFSSpec, &ignore);
- if (err)
- {
- ShowError("\pResolve Alias", err);
- return;
- }
-
- err = RegisterSection(&myFSSpec, aSectionHandle, &ignore);
-
- if ((err) && (err != notThePublisherWrn) && (err != multiplePublisherWrn))
- {
- ShowError("\pRegisterSection", err);
- return;
- }
- SetSelectionRgn(((*aSectHandle)->fDocument)->theText,
- (*aSectHandle)->fStart,
- (*aSectHandle)->fEnd,
- &(*aSectHandle)->fBorderRgn);
- InvalRgn((*aSectHandle)->fBorderRgn);
- }
-
- /**-----------------------------------------------------------------------
- Name: ReadAllSectionResources
- Purpose: Call the above routine to read in the resources for
- each section in the document.
- -----------------------------------------------------------------------**/
- #pragma segment Editions
-
- pascal void ReadAllSectionResources(DPtr aDoc)
- {
- SectHandle theSection;
-
- /*read in each section resource*/
-
- theSection = aDoc->firstSection;
- while (theSection)
- {
- ReadASection(theSection);
- theSection = (*theSection)->fNextSection;
- }
- }
-
- /**-----------------------------------------------------------------------
- Name: ReadSectionRecords
- Purpose: Read in all the 'sect' resources and form list
- of sections in the document. This is called from the
- main read document routine.
- -----------------------------------------------------------------------**/
- #pragma segment Editions
-
- pascal void ReadSectionRecords(DPtr aDoc)
- {
- short theID;
- SectHandle aSectHandle;
- OSErr err;
- short theCount;
-
- /*read in all the 'sect' resources for our document's sections*/
-
- theCount = aDoc->numSections;
- if (theCount == 0)
- return;
-
- aDoc->numSections = 0;
- for (theID = 1; theID <= theCount; theID++)
- {
- aSectHandle = (SectHandle)Get1Resource('SECT', theID);
- err = HandToHand((Handle *)&aSectHandle);
-
- /*now add it to the list*/
-
- if (aSectHandle)
- AddSection(aSectHandle, aDoc);
-
- /*here we should recalculate the region for the bounds*/
-
- (*aSectHandle)->fBorderRgn = NewRgn();
-
- (*aSectHandle)->fDocument = aDoc;
- }
- }
-
- /**-----------------------------------------------------------------------
- Name: SaveASection
- Purpose: Write out the 'sect', rAliasType and rSectionType resources
- to file. Called when the document is saved.
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void SaveASection(SectHandle aSection, short count)
- {
- SectionHandle EMSection;
- OSErr err;
- Handle tempHandle;
-
- HLock((Handle)aSection);
-
- /*save this section as its component rAliasType and rSectionType resource*/
- /*also save as our own section record as a 'sect' resource*/
-
- EMSection = (*aSection)->fSectHandle;
- tempHandle = (Handle)EMSection;
- err = HandToHand(&tempHandle);
-
- HLock((Handle)EMSection);
- AddResource(tempHandle, rSectionType, (*EMSection)->sectionID, "");
- err = ResError();
- if (err)
- {
- ShowError("\pAddResource- rSectionType", err);
- return;
- }
-
- /*now add the alias resource*/
- tempHandle = (Handle)(*EMSection)->alias;
- err = HandToHand(&tempHandle);
- AddResource(tempHandle, rAliasType, (*EMSection)->sectionID, "");
- if (err)
- {
- ShowError("\pAddResource- rAliasType", err);
- return;
- }
-
- /*now add our own resource- for now all the record, although we only need a few fields*/
- tempHandle = (Handle)aSection;
- err = HandToHand(&tempHandle);
- AddResource(tempHandle, 'SECT', count, "");
- if (err)
- {
- ShowError("\pAddResource- SECT", err);
- return;
- }
-
- HUnlock((Handle)aSection);
- HUnlock((Handle)EMSection);
- }
-
- /**-----------------------------------------------------------------------
- Name: SaveSections
- Purpose: Called to go down to the section list and call SaveASection
- for each one.
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void SaveSections(DPtr aDocument)
- {
- OSErr err;
- SectHandle currSection;
- short count;
-
- /*go down the list and save each of the sections*/
- /*the resource file is already open for writing*/
-
- count = 1;
- err = ResError();
- if (err)
- {
- ShowError("\pHOpenResFile", err);
- return;
- }
-
- /*now go down the list*/
- currSection = aDocument->firstSection;
- while (currSection)
- {
- SaveASection(currSection, count);
- currSection = (*currSection)->fNextSection;
- count ++;
- }
- }
-
- /**-----------------------------------------------------------------------
- Name: AssocAllSections
- Purpose: Associate all the sections in a document with the document.
- Called on a SaveAs.
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void AssocAllSections(DPtr theDoc)
- {
- SectHandle aSection;
- SectionHandle EMSection;
- OSErr err;
-
- /*called by DoSaveAs. Make sure sections are registered with this document*/
- aSection = theDoc->firstSection;
- while (aSection)
- {
- EMSection = (*aSection)->fSectHandle;
- err = AssociateSection(EMSection, &theDoc->theFSSpec);
- aSection = (*aSection)->fNextSection;
- }
- }
-
-
- /**-----------------------------------------------------------------------
- Name: KeyOKinSubscriber
- Purpose: Detects arrow keys.
- -----------------------------------------------------------------------**/
- #define kChLeft 28
- #define kChRight 29
- #define kChUp 30
- #define kChDown 31
-
- #pragma segment Editions
-
- pascal Boolean KeyOKinSubscriber(char whatKey)
-
- {
- return( (whatKey==kChUp) || (whatKey==kChDown) ||
- (whatKey==kChLeft) || (whatKey==kChRight));
-
- } /*KeyOKinSubscriber*/
-
- /**-----------------------------------------------------------------------
- Name: ShiftSection
- Purpose: Moves a section by howMany characters.
- -----------------------------------------------------------------------**/
-
- pascal void ShiftSection(SectHandle whichSection, short howMany)
- {
- (*whichSection)->fStart += howMany;
- (*whichSection)->fEnd += howMany;
- } /* ShiftSection */
-
- /**-----------------------------------------------------------------------
- Name: DoSectionRecalc
- Purpose: Keeps track of the positions of the sections.
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void DoSectionRecalc(DPtr theDoc, short toAdd)
- {
- short theStartPos;
- short theEndPos;
- short oldSectionStart;
- short oldSectionEnd;
- SectHandle aSection;
- Boolean wasChanged;
- GrafPtr oldPort;
-
- /*
- Work thru all sections -
- 1) Those spanning area of modification get modified or zapped
- 2) Those after get shifted back or forwards.
-
- Sorry it is so complicated - there's a lot of possibilities
- */
- theStartPos = (*(theDoc->theText))->selStart;
- theEndPos = (*(theDoc->theText))->selEnd;
-
- aSection = theDoc->firstSection;
- while (aSection)
- {
- wasChanged = true;
-
- oldSectionEnd = (*aSection)->fEnd;
- oldSectionStart = (*aSection)->fStart;
-
- if (theEndPos < (*aSection)->fStart)
- ShiftSection(aSection, toAdd - (theEndPos-theStartPos));
- else
- if (theStartPos == (*aSection)->fStart)
- if (theEndPos == (*aSection)->fStart)
- ShiftSection(aSection, toAdd - (theEndPos-theStartPos));
- else
- if (theEndPos >= (*aSection)->fEnd) /* section becomes pasted text */
- (*aSection)->fEnd = (*aSection)->fStart + toAdd;
- else /* insert pasted text */
- (*aSection)->fEnd = (*aSection)->fEnd + toAdd - (theEndPos-theStartPos);
- else
- if (theStartPos< (*aSection)->fStart)
- (*aSection)->fStart = theStartPos + toAdd; /* move start to end of pasted text */
- else
- if (theStartPos <= (*aSection)->fEnd)
- if (theEndPos >= (*aSection)->fEnd) /* end of section becomes pasted text */
- (*aSection)->fEnd = theStartPos + toAdd ;
- else /* insert pasted text into section */
- (*aSection)->fEnd = (*aSection)->fEnd + toAdd - (theEndPos-theStartPos);
- else
- wasChanged = false;
-
- if (wasChanged)
- {
- (*aSection)->fCount = (*aSection)->fEnd - (*aSection)->fStart;
-
- if (theDoc->showBorders)
- { /* Force an update of the borders - later*/
- GetPort(&oldPort);
- SetPort(theDoc->theWindow);
-
- SetSelectionRgn(theDoc->theText,
- oldSectionStart,
- oldSectionEnd,
- &(*aSection)->fBorderRgn);
- InvalRgn((*aSection)->fBorderRgn);
-
- SetPort(oldPort);
- }
-
- }
-
- (**aSection).fChanged = wasChanged; // Mark for later recalc
-
- aSection = (*aSection)->fNextSection;
- }
- } /* DoSectionRecalc */
-
- pascal void RecalcChangedSectionBorders(DPtr theDocument)
- {
- SectHandle aSection;
- GrafPtr oldPort;
-
- aSection = theDocument->firstSection;
- while (aSection)
- {
- if ((**aSection).fChanged)
- {
- (**aSection).fChanged = false; // clear flag
-
- GetPort(&oldPort);
- SetPort(theDocument->theWindow);
-
- SetSelectionRgn(theDocument->theText,
- (**aSection).fStart,
- (**aSection).fEnd,
- &(*aSection)->fBorderRgn);
-
- InvalRgn((**aSection).fBorderRgn);
-
- SetPort(oldPort);
- }
-
- aSection = (**aSection).fNextSection;
- }
- }
-
- /**-----------------------------------------------------------------------
- Name: OKToModifySelection
- Purpose: Looks to see if the selection includes a subscriber,
- in which case its not ok.
- -----------------------------------------------------------------------**/
-
- pascal Boolean OKToModifySelection(DPtr theDoc)
- {
- SectHandle aSection;
- short selectionStart;
- short selectionEnd;
-
- selectionStart = (**(theDoc->theText)).selStart;
- selectionEnd = (**(theDoc->theText)).selEnd;
-
- aSection = theDoc->firstSection;
- while (aSection)
- {
- if (selectionStart < (**aSection).fEnd &&
- selectionEnd >=(**aSection).fStart)
- if ((**(**aSection).fSectHandle).kind == stSubscriber)
- return(false);
-
- aSection = (**aSection).fNextSection;
- }
-
- return(true);
- }
-
- /**-----------------------------------------------------------------------
- Name: ReadAnEdition
- Purpose: Read the latest version of an edition from disk.
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void ReadAnEdition(SectionHandle mySectHdl)
- {
- SectHandle aSectHandle;
- EditionRefNum theRefNum;
- OSErr err;
- Ptr p;
- Handle theStylHandle;
- Size cutSize;
- Size stylSize;
- OSErr stylErr;
-
- p = nil;
- theStylHandle = nil;
-
- if (!mySectHdl)
- {
- ShowError("\pmySectHdl is NIL", 0);
- return;
- }
-
- aSectHandle = (SectHandle)GetERefCon(mySectHdl);
- if (!aSectHandle)
- {
- ShowError("\paSectHandle is NIL", 0);
- return;
- }
-
- GetDateTime(&(*mySectHdl)->mdDate);
-
- /*read a subscriber in from disk. Usually in response to a sectionread event*/
-
- err = OpenEdition(mySectHdl, &theRefNum);
-
- if (err)
- {
- ShowError("\pOpenEdition in ReadAnEdition", err);
- return;
- }
-
- err = EditionHasFormat(theRefNum, 'TEXT', &cutSize);
- if (err)
- {
- ShowError("\pEditionHasFormat in ReadAnEdition", err);
- return;
- }
-
- stylErr = EditionHasFormat(theRefNum, 'styl', &stylSize);
-
- err = SetEditionFormatMark(theRefNum, 'TEXT', 0);
- if (err)
- {
- ShowError("\pSetEditionFormatMark in ReadAnEdition", err);
- return;
- }
-
- /*set up a buffer for the text we're going to read in*/
- p = NewPtr(cutSize);
- if (!p)
- {
- ShowError("\pInsufficient memory to read edition", MemError());
- return;
- }
-
- err = ReadEdition(theRefNum, 'TEXT', p, &cutSize);
-
- if (err)
- {
- ShowError("\pReadEdition", err);
- return;
- }
-
- if (!stylErr)
- {
- theStylHandle = NewHandle(stylSize);
- stylErr = SetEditionFormatMark(theRefNum, 'styl', 0);
- if (!stylErr)
- if (theStylHandle)
- {
- HLock(theStylHandle);
- stylErr = ReadEdition(theRefNum, 'styl', *theStylHandle, &stylSize);
- HUnlock(theStylHandle);
- }
- }
-
- err = CloseEdition(theRefNum, true);
- if (err)
- {
- ShowError("\pCloseEdition", err);
- return;
- }
-
- /*
- Ensure this section has a region and invalidate the old region
- */
-
- if ((*aSectHandle)->fBorderRgn == nil)
- (*aSectHandle)->fBorderRgn = NewRgn();
-
- SetSelectionRgn(((*aSectHandle)->fDocument)->theText,
- (*aSectHandle)->fStart,
- (*aSectHandle)->fEnd,
- &(*aSectHandle)->fBorderRgn);
-
- InvalRgn((*aSectHandle)->fBorderRgn);
-
- /*now insert the text in the right place by setting the selection range*/
- /*we want this to act like paste, but without putting the contents on the clipboard*/
- /*so we have to delete the current selection range and then insert our new text*/
-
- /*
- Also fixup section info. for other moved sections
- */
-
- TESetSelect((*aSectHandle)->fStart,
- (*aSectHandle)->fEnd,
- ((*aSectHandle)->fDocument)->theText);
-
- DoSectionRecalc((*aSectHandle)->fDocument, cutSize);
-
- TEDelete(((*aSectHandle)->fDocument)->theText);
- TEStylInsert(p, cutSize, (StScrpHandle)theStylHandle, ((*aSectHandle)->fDocument)->theText);
-
- /*
- Now a little fix up - if the section was previously empty the
- DoSectionRecalc will have put the text in before the section.
- It's like that so you can type in before a subscriber in an
- otherwise empty document. So now pull the start of this section
- back to include the text we just added.
- */
-
- (*aSectHandle)->fStart = (*aSectHandle)->fEnd - cutSize;
-
- /*
- Force redraw of this region
- */
-
- SetSelectionRgn(((*aSectHandle)->fDocument)->theText,
- (*aSectHandle)->fStart,
- (*aSectHandle)->fEnd,
- &(*aSectHandle)->fBorderRgn);
-
- InvalRgn((*aSectHandle)->fBorderRgn);
-
- DisposPtr(p);
-
- if (theStylHandle)
- DisposHandle(theStylHandle);
- }
-
- /**-----------------------------------------------------------------------
- Name: WriteAnEdition
- Purpose: Write out the latest version of an Edition.
- Called on a Save and on selecting WriteEdition now from
- the Publisher Options dialog.
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void WriteAnEdition(SectionHandle mySectHdl)
- {
- OSErr err;
- SectHandle aSectHandle;
- EditionRefNum theRefNum;
- Handle aHandle;
- StScrpHandle theStylHandle;
- short oldSelStart;
- short oldSelEnd;
- FSSpecPtr theFSSpecPtr;
- TEHandle myText;
-
- aSectHandle = (SectHandle)GetERefCon(mySectHdl);
- /*alter the modification date for the section*/
- GetDateTime(&(*mySectHdl)->mdDate);
- /*write out the edition. Assume that it is a publisher for now*/
- /*subscribers will be opened for writing with OpenEdition*/
-
- if (((*aSectHandle)->fDocument)->everSaved == false)
- theFSSpecPtr = nil;
- else
- theFSSpecPtr = &((*aSectHandle)->fDocument)->theFSSpec;
-
- err = OpenNewEdition( mySectHdl,
- MenuScripterAppSig,
- theFSSpecPtr,
- &theRefNum);
- if (err)
- {
- ShowError("\pOpenNewEdition", err);
- return;
- }
-
- err = SetEditionFormatMark(theRefNum, 'TEXT', 0);
- if (err)
- {
- ShowError("\pSetEditionFormatMark", err);
- return;
- }
-
- /*now get a handle to the text to be written out*/
- /*use the same start and end positions for now, increasing and decreasing*/
- /*the selection will be implemented later*/
-
- aHandle = GetHandleToText(((*aSectHandle)->fDocument)->theText,
- (*aSectHandle)->fStart,
- (*aSectHandle)->fEnd);
- HLock(aHandle);
-
- /*make sure the count is up to date*/
- (*aSectHandle)->fCount = (*aSectHandle)->fEnd - (*aSectHandle)->fStart;
-
- err = WriteEdition(theRefNum, 'TEXT', *aHandle, (*aSectHandle)->fCount);
- if (err)
- {
- ShowError("\pWriteEdition", err);
- return;
- }
- HUnlock(aHandle);
-
- myText = ((*aSectHandle)->fDocument)->theText;
-
- oldSelStart = (*myText)->selStart;
- oldSelEnd = (*myText)->selEnd;
-
- TESetSelect((*aSectHandle)->fStart,
- (*aSectHandle)->fEnd,
- myText);
-
- theStylHandle = GetStylScrap(myText);
-
- TESetSelect(oldSelStart,oldSelEnd, myText);
-
- if (theStylHandle)
- {
- err = SetEditionFormatMark(theRefNum, 'styl', 0);
- if (err)
- {
- ShowError("\pSetEditionFormatMark for styl", err);
- return;
- }
- HLock((Handle)theStylHandle);
-
- err = WriteEdition(theRefNum,
- 'styl',
- (Ptr)*theStylHandle,
- GetHandleSize((Handle)theStylHandle));
- HUnlock((Handle)theStylHandle);
- }
-
- /*remember to save the section and alias records as resources later*/
-
- /*now close the edition*/
-
- err = CloseEdition(theRefNum, true);
- if (err)
- {
- ShowError("\pCloseEdition", err);
- return;
- }
-
- /*
- Clean Up
- */
-
- DisposHandle(aHandle);
- if (theStylHandle)
- DisposHandle((Handle)theStylHandle);
-
- } /*WriteAnEdition*/
-
- /**-----------------------------------------------------------------------
- Name: WriteAllEditions
- Purpose: Go down the list and call WriteAnEdition
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void WriteAllEditions(DPtr aDocument)
- {
- SectHandle aSection;
- SectionHandle EMSection;
-
- /*called on a Save, to write out all editions*/
- aSection = aDocument->firstSection;
-
- while (aSection)
- {
- EMSection = (*aSection)->fSectHandle;
- if ((*EMSection)->kind == stPublisher)
- WriteAnEdition(EMSection);
- aSection = (*aSection)->fNextSection;
- }
- }
-
- /**-----------------------------------------------------------------------
- Name: DeRegisterAllSections
- Purpose: Called on cancel Publisher/Subscriber and on a close.
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void DeRegisterAllSections(DPtr aDoc)
- {
- SectHandle aSection;
- SectionHandle EMSection;
- OSErr err;
-
- aSection = aDoc->firstSection;
- while (aSection)
- {
- EMSection = (*aSection)->fSectHandle;
- err = UnRegisterSection(EMSection);
- aSection = (*aSection)->fNextSection;
- }
- }
-
- /**-----------------------------------------------------------------------
- Name: GetHandleToText
- Purpose: Get a handle to the current text selection.
- Used to provide a preview on Create Publisher...
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal Handle GetHandleToText(TEHandle aTEHandle, short theStart, short theEnd)
- {
- OSErr err;
- Handle myHandle;
- Ptr p;
-
- HLock((*aTEHandle)->hText);
- p = *((*aTEHandle)->hText);
- p += theStart;
- err = PtrToHand(p, &myHandle, (theEnd - theStart));
- HUnlock((*aTEHandle)->hText);
- return(myHandle);
- } /* GetHandleToText */
-
- /**-----------------------------------------------------------------------
- Name: FindLine
- Purpose: Find the line a character is in.
- Used to find to calculate the region to use for the Publisher/
- Subscriber borders.
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal short FindLine(short thePos,TEHandle theTEHandle)
- {
- short index;
- short theFirstPos;
- short theNextPos;
-
- index = 0;
-
- do {
- theFirstPos = (*theTEHandle)->lineStarts[index];
- theNextPos = (*theTEHandle)->lineStarts[index + 1];
- index++;
- }while (! (((thePos >= theFirstPos) && (thePos < theNextPos)) ||
- (index > (*theTEHandle)->nLines)));
-
- return(index);
- }
-
- /**-----------------------------------------------------------------------
- Name: DrawSelectionRgn
- Purpose: Given a text handle and a start and end position this routine
- will draw a section border around the selected text.
- Must allow for the case when the section has no text in it-
- but we still want to show it as a published section
- -----------------------------------------------------------------------**/
-
- pascal void DrawSelectionRegion(TEHandle theTEHandle,
- short posStart,
- short posEnd)
-
- {
- RgnHandle theSelRgn;
-
- theSelRgn = NewRgn();
-
- SetSelectionRgn(theTEHandle, posStart, posEnd,&theSelRgn);
- FrameRgn(theSelRgn);
-
- DisposeRgn(theSelRgn);
-
- } /* DrawSelectionRegion */
-
- /**-----------------------------------------------------------------------
- Name: SetSelectionRgn
- Purpose: Given a text handle and a start and end position this routine
- will return the region which is necessary to draw a section
- border around the selected text.
- Must allow for the case when the section has no text in it-
- but we still want to show it as a published section
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void SetSelectionRgn(TEHandle theTEHandle,
- short posStart,
- short posEnd,
- RgnHandle *theSelRgn)
-
- {
- Point theStart;
- Point theEnd;
- short startLine;
- short endLine;
- Rect theRect;
- short theLeft;
- short theRight;
- short theBottom;
- short theTop;
- short slineHeight;
- short elineHeight;
- short fontAscent;
- TextStyle theTStyle;
-
- /*first of all find out if the text is on the same line*/
- startLine = FindLine(posStart, theTEHandle);
- endLine = FindLine(posEnd, theTEHandle);
-
- theStart = TEGetPoint(posStart, theTEHandle);
- theEnd = TEGetPoint(posEnd, theTEHandle);
-
- /*
- Get the line height info
- */
- TEGetStyle(posStart, &theTStyle, &slineHeight, &fontAscent, theTEHandle);
- TEGetStyle(posEnd, &theTStyle, &elineHeight, &fontAscent, theTEHandle);
-
- if (startLine == endLine)
- {
- /*use the start and end points to form the rectangle and draw this into the region*/
- theStart.v -= slineHeight;
- Pt2Rect(theStart, theEnd, &theRect);
- InsetRect(&theRect, - 1, - 1);
- RectRgn(*theSelRgn, &theRect);
- }
- else
- {
- theLeft = (*theTEHandle)->destRect.left;
- theRight = (*theTEHandle)->destRect.right;
- theTop = theStart.v - slineHeight;
- theBottom = theEnd.v;
- OpenRgn();
- MoveTo(theStart.h, theStart.v - slineHeight);
- LineTo(theRight, theStart.v - slineHeight);
- LineTo(theRight, theEnd.v - elineHeight);
- LineTo(theEnd.h, theEnd.v - elineHeight);
- LineTo(theEnd.h, theEnd.v);
- LineTo(theLeft, theEnd.v);
- LineTo(theLeft, theStart.v);
- LineTo(theStart.h, theStart.v);
- LineTo(theStart.h, theStart.v - slineHeight);
- CloseRgn(*theSelRgn);
- }
-
- InsetRgn(*theSelRgn, - 2, - 2);
-
- }
-
- /**-----------------------------------------------------------------------
- Name: ShowSectionBorders
- Purpose: Show the borders for all the sections in a document.
- Show a Publisher border in 50% gray, a subscriber in 75% gray
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void ShowSectionBorders(DPtr aDoc)
- {
- SectHandle aSection;
-
- PenNormal();
- PenSize(3, 3);
- PenPat(&qd.gray);
- aSection = aDoc->firstSection;
- while (aSection)
- {
- if ((*aSection)->fBorderRgn)
- {
- SetSelectionRgn(((*aSection)->fDocument)->theText,
- (*aSection)->fStart,
- (*aSection)->fEnd,
- &(*aSection)->fBorderRgn);
-
- if ((*(*aSection)->fSectHandle)->kind == stPublisher)
- PenPat(&qd.gray);
- else
- PenPat(&qd.dkGray);
-
- FrameRgn((*aSection)->fBorderRgn);
- PenNormal();
- }
- aSection = (*aSection)->fNextSection;
- }
- PenNormal();
- }
-
- /**-----------------------------------------------------------------------
- Name: RecalcBorders
- Purpose: Recalculate all the borders for the sections in a document.
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void RecalcBorders(DPtr aDoc, Boolean invalidate)
- {
- SectHandle aSection;
-
- /*go down the section list and recalculate all the borders*/
- aSection = aDoc->firstSection;
- while (aSection)
- {
- if ((*aSection)->fBorderRgn)
- {
- if (invalidate)
- InvalRgn((*aSection)->fBorderRgn);
-
- SetSelectionRgn(((*aSection)->fDocument)->theText,
- (*aSection)->fStart,
- (*aSection)->fEnd,
- &(*aSection)->fBorderRgn);
-
- if (invalidate)
- InvalRgn((*aSection)->fBorderRgn);
- }
- aSection = (*aSection)->fNextSection;
- }
- }
-
- /**-----------------------------------------------------------------------
- Name: GetSection
- Purpose: Given a start and end of a selection- return the section
- handle if it is in a Publisher or Subscriber.
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal SectHandle GetSection(short theStartPos, short theEndPos, DPtr aDoc)
- {
- SectHandle foundSection;
- SectHandle aSection;
-
- /*returns the section handle for the section between theStartPos and theEndPos*/
-
- foundSection = nil;
-
- aSection = aDoc->firstSection;
- while (aSection)
- {
- if ((theStartPos >= (*aSection)->fStart) && (theEndPos <= (*aSection)->fEnd))
- foundSection = aSection;
- aSection = (*aSection)->fNextSection;
- }
-
- return(foundSection);
- }
-
- /**-----------------------------------------------------------------------
- Name: DoTEPasteSectionRecalc
- Purpose: Keeps track of the positions of the sections call before a
- TEPaste or TEStylPaste.
- -----------------------------------------------------------------------**/
-
- pascal void DoTEPasteSectionRecalc(DPtr theDoc)
- {
- short toAdd;
-
- toAdd = TEGetScrapLen();
- DoSectionRecalc(theDoc, toAdd);
- } /* DoTEPasteSectionRecalc */
-
- /**-----------------------------------------------------------------------
- Name: DoTEDeleteSectionRecalc
- Purpose: Keeps track of the positions of the sections call before a
- TEDelete.
- -----------------------------------------------------------------------**/
-
- pascal void DoTEDeleteSectionRecalc(DPtr theDoc)
- {
- DoSectionRecalc(theDoc, 0);
- } /* DoTEDeleteSectionRecalc */
-
- /**-----------------------------------------------------------------------
- Name: DoTECutSectionRecalc
- Purpose: Keeps track of the positions of the sections call before a
- TECut.
- -----------------------------------------------------------------------**/
-
- pascal void DoTECutSectionRecalc(DPtr theDoc)
- {
- DoSectionRecalc(theDoc, 0);
- } /* DoTEDeleteSectionRecalc */
-
- /**-----------------------------------------------------------------------
- Name: DoTEKeySectionRecalc
- Purpose: Keeps track of the positions of the sections call before a
- TECut.
- -----------------------------------------------------------------------**/
-
- pascal void DoTEKeySectionRecalc(DPtr theDoc,char theChar)
- {
- short toAdd;
- short oldStart;
-
- if (!KeyOKinSubscriber(theChar)) /* is it a cursor motion key? - yes = ignore */
- {
- if (theChar==8)
- if ((*(theDoc->theText))->selStart<(*(theDoc->theText))->selEnd)
- toAdd = 0;
- else
- {
- toAdd = -1;
- oldStart = (*(theDoc->theText))->selStart;
-
- (*(theDoc->theText))->selStart = GreaterOf(oldStart-1,0);
- DoSectionRecalc(theDoc, 0);
- (*(theDoc->theText))->selStart = oldStart;
- }
- else
- toAdd = 1;
-
- if (toAdd!=-1)
- DoSectionRecalc(theDoc, toAdd);
- }
- } /* DoTEKeySectionRecalc */
-
- /**-----------------------------------------------------------------------
- Name: GetEditionContainer
- Purpose: Gets the Edition Container to put the edition into.
- The main user interface stuff.
- Puts up the new publisher dialog.
- Should check kAEInteractWithUser etc.
- -----------------------------------------------------------------------**/
-
- #pragma segment Main
-
- pascal OSErr GetEditionContainer(DPtr theDoc, FSSpec *theFSSpec)
- {
- OSErr err;
- NewPublisherReply myReply;
- short theStart;
- short theEnd;
- Handle myHandle;
- TEHandle myText;
-
- err = noErr;
-
- /*get default editionContainer to use, using last volume and folder*/
-
- myReply.container.thePart = kPartsNotUsed;
-
- err = GetLastEditionContainerUsed(&myReply.container);
-
- if (err==fnfErr)
- err = noErr;
-
- myText = theDoc->theText;
-
- theStart = (*myText)->selStart;
- theEnd = (*myText)->selEnd;
-
- if (err==noErr)
- {
- /*
- Create a handle containing the text to be published for previewing -
- need to ask the user where to put the data
- */
- myHandle = GetHandleToText(myText, theStart, theEnd);
-
- myReply.usePart = false;
- myReply.preview = myHandle;
- myReply.previewFormat = 'TEXT';
- myReply.container.theFile.name[0] = 0; /* Want a proper prompted name here */
- HLock(myHandle);
-
- /* Should take suggested name and avoid dialog if no user interaction */
-
- err = AEInteractWithUser(kAEDefaultTimeout, nil, nil);
-
- err = NewPublisherDialog(&myReply);
- HUnlock(myHandle);
- DisposHandle(myHandle);
- }
-
- /*IF user cancelled, THEN exit from this routine*/
-
- if (err==noErr)
- if (myReply.canceled)
- err = userCanceledErr; /* User cancelled marker - replace later */
-
- if (err==noErr)
- if (myReply.replacing)
- err = FSpDelete(&myReply.container.theFile);
-
- if (err == noErr)
- *theFSSpec = myReply.container.theFile;
-
- return(err);
- } /*GetEditionContainer*/
-
-
- /**-----------------------------------------------------------------------
- Name: PublishText
- Purpose: Publishes the current selection of theDoc.
- The main user interface stuff.
- Puts up the new publisher dialog - if theFSSpec=NIL
- Writes the new edition out to disk.
- -----------------------------------------------------------------------**/
-
- #pragma segment Main
-
- pascal OSErr PublishText(DPtr theDoc, FSSpecPtr theFSSpec)
- {
- NewPublisherReply myReply;
- SectionHandle mySectHdl;
- OSErr err;
- long mysectionID;
- FSSpecPtr pubFSSpec;
- short theStart;
- short theEnd;
- RgnHandle theRgnHandle;
-
- mysectionID = theDoc->lastID + 1;
- theDoc->lastID = mysectionID;
-
- /*get default editionContainer to use, using last volume and folder*/
-
- myReply.container.thePart = kPartsNotUsed;
-
- err = GetLastEditionContainerUsed(&myReply.container);
-
- if (err==fnfErr)
- err = noErr;
-
- theStart = (*theDoc->theText)->selStart;
- theEnd = (*theDoc->theText)->selEnd;
-
- /*don't want to publish an empty section*/
-
- if (theEnd - theStart == 0)
- err = userCanceledErr; /* Replace this later */
-
- myReply.container.theFile = *theFSSpec;
-
- /*now publish this section*/
-
- if (err == noErr)
- err = CreateEditionContainerFile(&myReply.container.theFile, MenuScripterAppSig, 0);
-
- /*check IF the file has been saved, IF not set pubCFS to NIL*/
-
- if (theDoc->everSaved == false)
- pubFSSpec = nil;
- else
- pubFSSpec = &theDoc->theFSSpec;
-
- /*get the region to encompass the selection*/
-
- theRgnHandle = NewRgn();
- SetSelectionRgn(theDoc->theText,
- (*theDoc->theText)->selStart,
- (*theDoc->theText)->selEnd,
- &theRgnHandle);
-
- InvalRgn(theRgnHandle);
-
- /*create a publisher section*/
- if (err==noErr)
- {
- err = NewSection(&myReply.container,
- pubFSSpec,
- stPublisher,
- mysectionID,
- pumOnSave,
- &mySectHdl);
-
- /*now add this section to our document list*/
-
- if (err == noErr)
- CreateSection(mySectHdl, mysectionID, theStart, theEnd, theDoc, theRgnHandle);
- }
-
- /*now write out the edition to file*/
-
- if (err==noErr)
- WriteAnEdition(mySectHdl);
-
- return(err);
- } /*PublishText*/
-
- /**-----------------------------------------------------------------------
- Name: DoSubscribe
- Purpose: Subscribe to a published section. Puts up the subscriber
- dialog, creates and adds the new section.
- -----------------------------------------------------------------------**/
-
- #pragma segment Main
-
- pascal void DoSubscribe(DPtr theDoc)
- {
- NewSubscriberReply myReply;
- SectionHandle mySectHdl;
- long mysectionID;
- FSSpecPtr subFSSpec; /*the fsspec for the subscriber file*/
- OSErr err;
- short theStart;
- short theEnd;
-
- mysectionID = theDoc->lastID + 1;
- theDoc->lastID = mysectionID;
- err = noErr;
-
- /*get default editionContainer to use, using last volume and folder*/
- /* myreply.container.thePart := kPartNumberUnknown;*/
- myReply.formatsMask = kTEXTformatMask;
-
- err = GetLastEditionContainerUsed(&myReply.container);
- if (err && (err !=fnfErr))
- {
- ShowError("\pGetLastEditionContainerUsed", err);
- return;
- }
-
- /*put up the subscriber dialog*/
- err = NewSubscriberDialog(&myReply);
- if (err && (err !=fnfErr))
- {
- ShowError("\pNewSubscriberDialog", err);
- return;
- }
-
- if (myReply.canceled)
- return;
-
- /*check IF the file has been saved, IF not set pubCFS to NIL*/
- if (theDoc->everSaved == false)
- subFSSpec = nil;
- else
- subFSSpec = &theDoc->theFSSpec;
-
- /*create a publisher section*/
- err = NewSection(&myReply.container,
- subFSSpec,
- stSubscriber,
- mysectionID,
- sumAutomatic,
- &mySectHdl);
-
- if (err)
- {
- ShowError("\pNewSection", err);
- return;
- }
-
- theStart = (*theDoc->theText)->selStart;
- theEnd = (*theDoc->theText)->selEnd;
-
- /*now add this section to our document list*/
-
- CreateSection(mySectHdl, mysectionID, theStart, theEnd, theDoc, nil);
-
- /*read the subscriber in from disk*/
-
- ReadAnEdition(mySectHdl);
-
- } /*DoSubscribe*/
-
- /**-----------------------------------------------------------------------
- Name: DoSectionOptions
- Purpose: Put up the section option dialogs for a publisher
- or subscriber. Handle all the various options.
- Note that 'Find Publisher' doesn't work yet.
- -----------------------------------------------------------------------**/
-
- #pragma segment Main
-
- pascal void DoSectionOptions(DPtr theDoc)
- {
- OSErr err;
- SectionOptionsReply reply;
- EditionInfoRecord theInfo;
- SectHandle currSection;
-
- currSection = GetSection((*theDoc->theText)->selStart,
- (*theDoc->theText)->selEnd,
- theDoc);
-
- reply.sectionH = (*currSection)->fSectHandle;
- err = SectionOptionsDialog(&reply);
- if (!reply.canceled)
- {
- /*find out IF there is any action needed*/
- if (reply.action == 'read')
- /*read the latest version of a subscriber*/
- ReadAnEdition((*currSection)->fSectHandle);
- else
- if (reply.action == 'writ')
- /*write out the latest version of a publisher to disk*/
- WriteAnEdition((*currSection)->fSectHandle);
- else
- if (reply.action == 'goto') /*goto a published section*/
- {
- err = GetEditionInfo((*currSection)->fSectHandle, &theInfo);
-
- if (err)
- ShowError("\pGetEditionInfo", err);
-
- err = GoToPublisherSection(&theInfo.container);
-
- if (err)
- ShowError("\pGotoPublisherSection", err);
- }
- else
- if (reply.action == 'cncl') /*cancel a publisher or subscriber*/
- {
- /*unRegister the section and delete from our own list*/
- /*should have a free PROCEDURE which frees the structures*/
- /*associated with a section*/
- err = UnRegisterSection((*currSection)->fSectHandle);
- DeleteASection(currSection, theDoc);
-
- /*IF this is the ONLY publisher writing data to this edition*/
- /*we should delete the container file as well*/
- }
- }
- }
-