home *** CD-ROM | disk | FTP | other *** search
- /*********************************************************************
- Project : MacPerl - Real Perl Application
- File : MPEditions.c -
- Author : Matthias Neeracher
-
- A lot of this code is borrowed from 7Edit written by
- Apple Developer Support UK
-
- Language : MPW C
-
- $Log: MPEditions.c,v $
- Revision 1.2 1994/05/04 02:50:54 neeri
- Fix segment names.
-
- Revision 1.1 1994/02/27 23:00:31 neeri
- Initial revision
-
- Revision 0.3 1993/09/18 00:00:00 neeri
- Runtime
-
- Revision 0.2 1993/05/30 00:00:00 neeri
- Support Console Windows
-
- Revision 0.1 1993/05/29 00:00:00 neeri
- Compiles correctly
-
- *********************************************************************/
-
- #include <OSUtils.h>
- #include <Resources.h>
- #include <Errors.h>
- #include <AppleEvents.h>
-
- #include "MPEditions.h"
-
- #ifndef RUNTIME
-
- /**-----------------------------------------------------------------------
- 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)
- {
- if (aDocument->kind != kDocumentWindow)
- return;
-
- /*
- add the section to the document
- */
- aDocument->u.reg.numSections += 1;
-
- /*
- if not NIL, add the new section to the list after the last element
- */
-
- if (aDocument->u.reg.lastSection)
- (*(aDocument->u.reg.lastSection))->fNextSection = newSection;
- else
- aDocument->u.reg.firstSection = newSection;
-
- aDocument->u.reg.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;
-
- if (aDocument->kind != kDocumentWindow)
- return;
-
- /*
- 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;
-
- if (theDoc->kind != kDocumentWindow)
- return;
-
- currSect = theDoc->u.reg.firstSection;
- prevSect = nil;
-
- while (currSect) {
- if (currSect == sectToDelete) {
- /*
- unlink the section from the list
- */
- if (prevSect)
- (*prevSect)->fNextSection = (*currSect)->fNextSection;
-
- if (currSect == theDoc->u.reg.firstSection)
- theDoc->u.reg.firstSection = nil;
-
- if (currSect == theDoc->u.reg.lastSection)
- theDoc->u.reg.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;
-
- if (aDoc->kind != kDocumentWindow)
- return;
-
- /*read in each section resource*/
-
- theSection = aDoc->u.reg.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*/
-
- if (aDoc->kind != kDocumentWindow)
- return;
-
- theCount = aDoc->u.reg.numSections;
- if (theCount == 0)
- return;
-
- aDoc->u.reg.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;
-
- if (aDocument->kind != kDocumentWindow)
- return;
-
- /*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->u.reg.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;
-
- if (theDoc->kind != kDocumentWindow)
- return;
-
- /*called by DoSaveAs. Make sure sections are registered with this document*/
- aSection = theDoc->u.reg.firstSection;
- while (aSection) {
- EMSection = (*aSection)->fSectHandle;
- err = AssociateSection(EMSection, &theDoc->theFSSpec);
- aSection = (*aSection)->fNextSection;
- }
- }
- #endif
-
- /**-----------------------------------------------------------------------
- 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*/
-
- #ifndef RUNTIME
-
- /**-----------------------------------------------------------------------
- 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;
-
- if (theDoc->kind != kDocumentWindow)
- return;
-
- /*
- 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->u.reg.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->u.reg.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 = (*aSection)->fNextSection;
- }
- } /* DoSectionRecalc */
-
- /**-----------------------------------------------------------------------
- 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;
- Size cutSize;
-
- p = 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*/
-
- if (err = OpenEdition(mySectHdl, &theRefNum)) {
- ShowError("\pOpenEdition in ReadAnEdition", err);
- return;
- }
-
- if (err = EditionHasFormat(theRefNum, 'TEXT', &cutSize)) {
- ShowError("\pEditionHasFormat in ReadAnEdition", err);
- return;
- }
-
- if (err = SetEditionFormatMark(theRefNum, 'TEXT', 0)) {
- 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;
- }
-
- if (err = ReadEdition(theRefNum, 'TEXT', p, &cutSize)) {
- ShowError("\pReadEdition", err);
- return;
- }
-
- if (err = CloseEdition(theRefNum, true)) {
- 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);
- TEInsert(p, cutSize, ((*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);
- }
-
- /**-----------------------------------------------------------------------
- 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;
- FSSpecPtr theFSSpecPtr;
-
- 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)->u.reg.everSaved == false)
- theFSSpecPtr = nil;
- else
- theFSSpecPtr = &((*aSectHandle)->fDocument)->theFSSpec;
-
- if (err = OpenNewEdition(mySectHdl, MPAppSig, theFSSpecPtr, &theRefNum)) {
- ShowError("\pOpenNewEdition", err);
- return;
- }
-
- if (err = SetEditionFormatMark(theRefNum, 'TEXT', 0)) {
- 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;
-
- if (err = WriteEdition(theRefNum, 'TEXT', *aHandle, (*aSectHandle)->fCount)) {
- ShowError("\pWriteEdition", err);
- return;
- }
- HUnlock(aHandle);
-
- /*remember to save the section and alias records as resources later*/
-
- /*now close the edition*/
-
- if (err = CloseEdition(theRefNum, true)) {
- ShowError("\pCloseEdition", err);
- return;
- }
-
- /*
- Clean Up
- */
-
- DisposHandle(aHandle);
- } /*WriteAnEdition*/
-
- /**-----------------------------------------------------------------------
- Name: WriteAllEditions
- Purpose: Go down the list and call WriteAnEdition
- -----------------------------------------------------------------------**/
-
- #pragma segment Editions
-
- pascal void WriteAllEditions(DPtr aDocument)
- {
- SectHandle aSection;
- SectionHandle EMSection;
-
- if (aDocument->kind != kDocumentWindow)
- return;
-
- /*called on a Save, to write out all editions*/
- aSection = aDocument->u.reg.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->u.reg.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;
-
- if (aDoc->kind != kDocumentWindow)
- return;
-
- PenNormal();
- PenSize(3, 3);
- PenPat(&qd.gray);
- aSection = aDoc->u.reg.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;
-
- if (aDoc->kind != kDocumentWindow)
- return;
-
- /*go down the section list and recalculate all the borders*/
- aSection = aDoc->u.reg.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*/
-
- if (aDoc->kind != kDocumentWindow)
- return nil;
-
- foundSection = nil;
-
- aSection = aDoc->u.reg.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;
-
- if (theDoc->kind != kDocumentWindow)
- return;
-
- 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)
- {
- if (theDoc->kind != kDocumentWindow)
- return;
-
- DoSectionRecalc(theDoc, 0);
- } /* DoTEDeleteSectionRecalc */
-
- /**-----------------------------------------------------------------------
- Name: DoTECutSectionRecalc
- Purpose: Keeps track of the positions of the sections call before a
- TECut.
- -----------------------------------------------------------------------**/
-
- pascal void DoTECutSectionRecalc(DPtr theDoc)
- {
- if (theDoc->kind != kDocumentWindow)
- return;
-
- 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 (theDoc->kind != kDocumentWindow)
- return;
-
- 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;
-
- if (theDoc->kind != kDocumentWindow)
- return noErr;
-
- 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;
-
- if (theDoc->kind != kDocumentWindow)
- return noErr;
-
- mysectionID = theDoc->u.reg.lastID + 1;
- theDoc->u.reg.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;
-
- myReply.container.theFile = *theFSSpec;
-
- /*now publish this section*/
-
- if (err == noErr)
- err = CreateEditionContainerFile(&myReply.container.theFile, MPAppSig, 0);
-
- /*check IF the file has been saved, IF not set pubCFS to NIL*/
-
- if (theDoc->u.reg.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;
-
- if (theDoc->kind != kDocumentWindow)
- return;
-
- mysectionID = theDoc->u.reg.lastID + 1;
- theDoc->u.reg.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->u.reg.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;
-
- if (theDoc->kind != kDocumentWindow)
- return;
-
- 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*/
- }
- }
- }
-
- #endif