Milán Major

netscape-revival

1 branch
Code

lib/mac/VText/V_PowerPlant_Mods/LTextSelection.cp

//	===========================================================================
//	LTextSelection.cp				©1994 Metrowerks Inc. All rights reserved.
//	===========================================================================

#ifdef PowerPlant_PCH
#include PowerPlant_PCH
#endif

#include	"LTextSelection.h"
#include	<LListIterator.h>
#include	<LSelectableItem.h>
#include	<LTextElemAEOM.h>
#include	<LTextModel.h>
#include	<LTextEngine.h>
#include	<UAppleEventsMgr.h>
#include	<LStream.h>
#include	<UDrawingState.h>
#include	<URegions.h>
#include	<LStyleSet.h>
#include	<LCommander.h>

#ifndef		__ERRORS__
#include	<Errors.h>
#endif

#ifndef		__AEREGISTRY__
#include	<AERegistry.h>
#endif

//	Shouldn't be defined for any user code -- just for internal debugging of
//	LTextEngine and derivatives.
//	#define	DEBUG_POINTINRANGE

/*-
LTextSelection::LTextSelection(
	LTextEngine		*inTextEngine
)
{
	mTextModel = NULL;
	mTextEngine = NULL;
	mTyping = NULL;

	SetTextEngine(inTextEngine);

	mPendingStyle = NULL;
	mLastCurrentStyle = NULL;
}
*/

LTextSelection::LTextSelection()
{
	mTextModel = NULL;
	mTextEngine = NULL;
	mTyping = NULL;

	mPendingStyle = NULL;
	mLastCurrentStyle = NULL;
}

LTextSelection::~LTextSelection(void)
{
	SetTextModel(NULL);
	SetTextEngine(NULL);
	
	SetPendingStyle(NULL);
	ReplaceSharable(mLastCurrentStyle, (LStyleSet *)NULL, this);
}

#ifndef	PP_No_ObjectStreaming

void	LTextSelection::WriteObject(LStream &inStream) const
{	
	inherited::WriteObject(inStream);
	
	inStream << mTextEngine;
	inStream << mTextModel;
}

void	LTextSelection::ReadObject(LStream &inStream)
{
	inherited::ReadObject(inStream);
	
	SetTextEngine(ReadStreamable<LTextEngine *>()(inStream));
	SetTextModel(ReadStreamable<LTextModel *>()(inStream));
}

#endif

LTextModel	*	LTextSelection::GetTextModel(void)
{
	return mTextModel;
}

void	LTextSelection::SetTextModel(LTextModel *inTextModel)
{
	//	ReplaceSharable(mTextModel, inTextModel, this);
	//
	//	NOT!
	//		The above would mean both the model and selection share each
	//		other so neither would ever go away.
	//
	//		It is safe to assume that mTextModel will never be left
	//		dangling because the model and selection will both be claimed
	//		by at least one other object.

	mTextModel = inTextModel;
}

LTextEngine *	LTextSelection::GetTextEngine(void)
{
	return mTextEngine;
}

void	LTextSelection::SetTextEngine(LTextEngine *inTextEngine)
{
	//	ReplaceSharable(mTextEngine, inTextEngine, this);
	//
	//	This is unnecessary.  Whatever owns the selection can dispose of it
	//	before the engine
	
	mTextEngine = inTextEngine;
}

TextRangeT	LTextSelection::GetSelectionRange(void) const
{
	TextRangeT	range = LTextEngine::sTextUndefined;
	
	if (ListCount() == 1) {
		LSelectableItem *item = ((LTextSelection *)this)->ListNthItem(1);
//		if (member(item, LTextElemAEOM))
			range = ((LTextElemAEOM *)item)->GetRange();
	}
	
	return range;
}

void	LTextSelection::SetSelectionRange(const TextRangeT &inRange)
{
	if (mTextModel) {
		LTextElemAEOM	*elem = mTextModel->MakeNewElem(inRange, cChar);
		StSharer		lock(elem);	//	in case of failure be sure and blow way elem
		
		SelectSimple(elem);
	}
}

void	LTextSelection::SelectDiscontinuous(LSelectableItem *inItem)
{
//	It isn't a good idea to allow discontinuous selection in text until
//	you could properly undo multi-item moves.  That means an "ordered" move
//	and that hasn't been implemented -- yet.
//
//	So defeat text discontinuous selections with...
SelectSimple(inItem);
}

void	LTextSelection::SetTypingAction(LAETypingAction *inAction)
{
	mTyping = inAction;
}

LAETypingAction *	LTextSelection::GetTypingAction(void)
{
	return mTyping;
}

LStyleSet *	LTextSelection::GetCurrentStyle(void)
{
	LStyleSet	*rval = mPendingStyle;
	TextRangeT	range = LTextEngine::sTextAll;

	if (!rval && ListCount()) {
		LSelectableItem	*item = ListNthItem(1);
		LTextElemAEOM	*elem =	dynamic_cast<LTextElemAEOM *>(item);
		ThrowIfNULL_(elem);
		range = elem->GetRange();
	}
	
	if (!rval && mTextEngine)
		rval = mTextEngine->GetStyleSet(range);
	
	if (rval != mLastCurrentStyle) {
		LCommander::SetUpdateCommandStatus(true);
		ReplaceSharable(mLastCurrentStyle, rval, this);
	}

	return rval;
}

LStyleSet *	LTextSelection::GetPendingStyle(void)
{
	return mPendingStyle;
}

void	LTextSelection::SetPendingStyle(LStyleSet *inStyle)
{
	if (inStyle != mPendingStyle) {
		ReplaceSharable(mPendingStyle, inStyle, this);

		LCommander::SetUpdateCommandStatus(true);
	}
}

void	LTextSelection::SelectionAboutToChange(void)
{
	SetPendingStyle(NULL);
	
	inherited::SelectionAboutToChange();
}

void	LTextSelection::MakeRegion(Point inOrigin, RgnHandle *ioRgn) const
{
	ThrowIfNULL_(ioRgn);
	ThrowIfNULL_(*ioRgn);
		
	URegions::MakeEmpty(*ioRgn);

	StRegion		rgn;
	LListIterator	iter(((LTextSelection *)this)->mItems, iterate_FromStart);
	LSelectableItem	*p;
	LTextElemAEOM	*elem;
			
	while (iter.Next(&p)) {
		ThrowIfNULL_(p);
		elem = (LTextElemAEOM *)p;
//		Assert_(member(elem, LTextElemAEOM));
		mTextEngine->GetRangeRgn(elem->GetRange(), &rgn.mRgn);
		UnionRgn(rgn, *ioRgn, *ioRgn);
		ThrowIfOSErr_(QDError());
	}

	//	Set "origin" of region
	Point	offset;
	offset.h = -inOrigin.h;
	offset.v = -inOrigin.v;
	URegions::Translate(*ioRgn, offset);
}

Boolean		LTextSelection::PointInRepresentation(Point inWhere) const
/*
	It is irritating to have to implement this method this way rather than using
	the inherited LTextEngine::PointInRange.  Unfortunately, there is no way to
	tell exactly what the selection region contains when gluing to other
	engines.  This method will work.
*/
{
#ifdef	DEBUG_POINTINRANGE
	return LSelection::PointInRepresentation(inWhere);
#else
	Boolean rval;
	
	if (!IsSubstantive())
		return false;
	
	StRegion	rgn;
	Point		origin;
	MakeRegion(inWhere, &rgn.mRgn);
	origin.h = origin.v = 0;
	rval = PtInRgn(origin, rgn);
	return rval;
#endif
}

void	LTextSelection::GetPresentHiliteRgn(Boolean inAsActive, RgnHandle ioRegion) const
{
	Point			origin = {0, 0};	
		
	if (IsSubstantive()) {
		MakeRegion(origin, &ioRegion);
		if (!inAsActive)
				URegions::MakeRegionOutline(ioRegion, &ioRegion);
	} else {
		if (inAsActive) {
			//	blinking caret is black and doesn't fit hilited XOR model
			//	(and happily everthing still turns out okay)
			URegions::MakeEmpty(ioRegion);
		} else {
			MakeRegion(origin, &ioRegion);
		}
	}
}

void	LTextSelection::AddFlavorTypesTo(LDataTube *inTube) const
{
	inherited::AddFlavorTypesTo(inTube);
	
	if (IsSubstantive() && (ListCount() == 1)) {
		//	if single item, add flavors to root of tube
		ListNthItem(1)->AddFlavorTypesTo(inTube);
	}
}

Boolean	LTextSelection::SendFlavorTo(FlavorType inFlavor, LDataTube *inTube) const
{
	Boolean	rval = inherited::SendFlavorTo(inFlavor, inTube);
	
	if (!rval && (ListCount() == 1)) {
		rval = ListNthItem(1)->SendFlavorTo(inFlavor, inTube);
	}
	
	return rval;
}

#include	<LAEAction.h>

LAction *	LTextSelection::MakePasteAction(void)
/*
	For text, the selection point should be moved to the end
	of the new text.
*/
{
	LAEAction	*action;

	action = (LAEAction *)LSelection::MakePasteAction();
//	Assert_(member(action, LAEAction));
	action->SetSelection(this, kAEAfter);  //	note selection modifier.

	return action;
}

void	LTextSelection::UndoAddOldData(LAEAction *inAction)
{
	inherited::UndoAddOldData(inAction);
	
	//	To make updating smooth
	inAction->SetRecalcAccumulator(mTextEngine);
}