⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 text.cpp

📁 Windows CE 6.0 Word Application 源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
	TCHAR const *pch, 			//@parm replacement text
	IUndoBuilder *publdr,		//@parm if non-NULL, where to put an 
								// anti-event for this action
	IAntiEvent *paeCF,			//@parm char format AE
	IAntiEvent *paePF )			//@parm paragraph formatting AE
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTxtPtr::ReplaceRange");

	_TEST_INVARIANT_

	DWORD cchAdded = 0;
	DWORD cchInBlock;
	DWORD cchNewInBlock;

	CTxtBlk *ptb;

	if(cchOld < 0)
		cchOld = GetTextLength() - _cp;

	if( publdr )
	{
		HandleReplaceRangeUndo( cchOld, cchNew, publdr, paeCF, paePF);
	}

	// blocks involving replacement

	while(cchOld > 0 && cchNew > 0) 
	{	
		ptb = GetRun(0);

		// cchOld should never be nonzero if the text run is empty
		AssertSz(ptb,
			"CTxtPtr::Replace() - Pointer to text block is NULL !");

		ptb->MoveGap(_ich);
		cchInBlock = min((DWORD)cchOld, ptb->_cch - _ich);
		if(cchInBlock > 0)
		{
			cchOld			-= cchInBlock;
			ptb->_cch		-= cchInBlock;
			((CTxtArray *)_prgRun)->_cchText	-= cchInBlock;
		}
		cchNewInBlock = CchOfCb(ptb->_cbBlock) - ptb->_cch;

		// if there's room for a gap, leave one
		if(cchNewInBlock > cchGapInitial)
			cchNewInBlock -= cchGapInitial;

		if(cchNewInBlock > cchNew)
			cchNewInBlock = cchNew;

		if(cchNewInBlock > 0)
		{
			CopyMemory(ptb->_pch + _ich, pch, CbOfCch(cchNewInBlock));
			cchNew			-= cchNewInBlock;
			_cp				+= cchNewInBlock;
			_ich			+= cchNewInBlock;
			pch				+= cchNewInBlock;
			cchAdded		+= cchNewInBlock;
			ptb->_cch		+= cchNewInBlock;
			ptb->_ibGap		+= CbOfCch(cchNewInBlock);
			((CTxtArray *)_prgRun)->_cchText	+= cchNewInBlock;
		}
	   	if(_iRun >= Count() - 1 || !cchOld )
		   	break;

		// go to next block
		_iRun++;
   		_ich = 0;
	}

	if(cchNew > 0)
		cchAdded += InsertRange(cchNew, pch);
	else if(cchOld > 0)
		DeleteRange(cchOld);
	
	return cchAdded;
}

/*
 *	CTxtPtr::HandleReplaceRangeUndo (cchOld, cchNew, pch, publdr)
 *
 *	@mfunc
 *		worker function for ReplaceRange.  Figures out what will happen in
 *		the replace range call and creates the appropriate anti-events
 *
 *	@devnote
 *		We first check to see if our replace range data can be merged into
 *		an existing anti-event.  If it can, then we just return.
 *		Otherwise, we copy the deleted characters into an allocated buffer
 *		and then create a ReplaceRange anti-event.
 *
 *		In order to handle ordering problems between formatting and text
 *		anti-events (that is, text needs to exist before formatting can
 *		be applied), we have any formatting anti-events passed to us first.
 */
void CTxtPtr::HandleReplaceRangeUndo( 
	DWORD			cchOld, //@parm Count of characters to delete
	DWORD			cchNew, //@parm Count of new characters to add
	IUndoBuilder *	publdr,	//@parm Undo builder to receive anti-event
	IAntiEvent *	paeCF,	//@parm char formatting AE
	IAntiEvent *	paePF )	//@parm paragraph formatting AE
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTxtPtr::HandleReplaceRangeUndo");

	_TEST_INVARIANT_

	IAntiEvent *pae = publdr->GetTopAntiEvent();
	TCHAR *		pch = NULL;

	if( pae )
	{
		SimpleReplaceRange	sr;
		sr.cpMin = _cp;
		sr.cpMax = _cp + cchNew;
		sr.cchDel = cchOld;
	
#ifdef PWD_JUPITER // GuyBark Jupiter 18411: Don't attempt to merge events during an undo
		if( !(publdr->_bNoAttemptToMerge) && pae->MergeData(MD_SIMPLE_REPLACERANGE, &sr) == NOERROR )
#else
		if( pae->MergeData(MD_SIMPLE_REPLACERANGE, &sr) == NOERROR )
#endif // PWD_JUPITER
		{
			// if the data was merged successfully, then we do
			// not need these anti-events
			if( paeCF )
			{
				DestroyAEList(paeCF);
			}
			if( paePF )
			{
				DestroyAEList(paePF);
			}

			// we've done everything we need to.  
			return;
		}
	}

	// allocate a buffer and grab the soon-to-be deleted
	// text (if necessary)

	if( cchOld > 0 )
	{
		pch = new TCHAR[cchOld];
		if( pch )
		{
			GetText(cchOld, pch);
		}
		else
		{
			cchOld = 0;
		}
	}

	// the new range will exist from our current position plus
	// cchNew (because everything in cchOld gets deleted)

	pae = gAEDispenser.CreateReplaceRangeAE(_ped, _cp, _cp + cchNew, 
			cchOld, pch, paeCF, paePF);

	if( !pae )
	{
		delete [] pch;
	}

	if( pae )
	{
		publdr->AddAntiEvent(pae);
	}
}

/*
 *	CTxtPtr::InsertRange(cch, pch)
 *	
 *	@mfunc
 *		Insert a range of characters at this text pointer			
 *	
 *	@rdesc
 *		Count of characters successfully inserted
 *	
 *	@comm Side Effects: <nl>
 *		moves this text pointer to end of inserted text <nl>
 *		moves the text block array <nl>
 */
DWORD CTxtPtr::InsertRange (
	DWORD cch, 				//@parm length of text to insert
	TCHAR const *pch)		//@parm text to insert
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTxtPtr::InsertRange");

	_TEST_INVARIANT_

	DWORD cchSave = cch;
	DWORD cchInBlock;
	DWORD cchFirst;
	DWORD cchLast = 0;
	DWORD ctbNew;
	CTxtBlk *ptb;
	
	// Ensure text array is allocated
	if(!Count())
	{
		LONG	cbSize = -1;

		// If we don't have any blocks, allocate first block to be big enuf
		// for the inserted text *only* if it's smaller than the normal block
		// size. This allows us to be used efficiently as a display engine
		// for small amounts of text.

		if( cch < CchOfCb(cbBlockInitial) )
			cbSize = CbOfCch(cch);

		if( !((CTxtArray *)_prgRun)->AddBlock(0, cbSize) )
		{
			_ped->GetCallMgr()->SetOutOfMemory();
			goto done;
		}
	}

	ptb = GetRun(0);
	cchInBlock = CchOfCb(ptb->_cbBlock) - ptb->_cch;
	AssertSz(ptb->_cbBlock <= cbBlockMost, "block too big");

	// try and resize without splitting...
	if(cch > cchInBlock &&
		cch <= cchInBlock + CchOfCb(cbBlockMost - ptb->_cbBlock))
	{
		if( !ptb->ResizeBlock(min(cbBlockMost,
				CbOfCch(ptb->_cch + cch + cchGapInitial))) )
		{
			_ped->GetCallMgr()->SetOutOfMemory();
			goto done;
		}
		cchInBlock = CchOfCb(ptb->_cbBlock) - ptb->_cch;
	}
	if(cch <= cchInBlock)
	{
		// all fits into block without any hassle

		ptb->MoveGap(_ich);
		CopyMemory(ptb->_pch + _ich, pch, CbOfCch(cch));
		_cp				+= cch;					// *this points at end of
		_ich			+= cch;					//  insertion
		ptb->_cch		+= cch;
		((CTxtArray *)_prgRun)->_cchText	+= cch;
		ptb->_ibGap		+= CbOfCch(cch);

		return cch;
	}

	// won't all fit in this block

	// figure out best division into blocks
	TxDivideInsertion(cch, _ich, ptb->_cch - _ich,&cchFirst, &cchLast);

	// Subtract cchLast up front so return value isn't negative
	// if SplitBlock() fails
	cch -= cchLast;	// don't include last block in count for middle blocks

	// split block containing insertion point

	// ***** moves _prgtb ***** //
	if(!((CTxtArray *)_prgRun)->SplitBlock(_iRun, _ich, cchFirst, cchLast,
		_ped->IsStreaming()))
	{
		_ped->GetCallMgr()->SetOutOfMemory();
		goto done;
	}
	ptb = GetRun(0);			// recompute ptb after (*_prgRun) moves

	// copy into first block (first half of split)
	if(cchFirst > 0)
	{
		AssertSz(ptb->_ibGap == CbOfCch(_ich), "split first gap in wrong place");
		AssertSz(cchFirst <= CchOfCb(ptb->_cbBlock) - ptb->_cch, "split first not big enough");

		CopyMemory(ptb->_pch + _ich, pch, CbOfCch(cchFirst));
		cch				-= cchFirst;
		pch				+= cchFirst;
		_ich			+= cchFirst;
		ptb->_cch		+= cchFirst;
		((CTxtArray *)_prgRun)->_cchText	+= cchFirst;
		ptb->_ibGap		+= CbOfCch(cchFirst);
	}

	// copy into middle blocks
	// FUTURE: (jonmat) I increased the size for how large a split block
	// could be and this seems to increase the performance, we should test
	// the block size difference on a retail build, however. 5/15/1995
	ctbNew = cch / cchBlkInsertmGapI /* cchBlkInitmGapI */;
	if(ctbNew <= 0 && cch > 0)
		ctbNew = 1;
	for(; ctbNew > 0; ctbNew--)
	{
		cchInBlock = cch / ctbNew;
		AssertSz(cchInBlock > 0, "nothing to put into block");

		// ***** moves _prgtb ***** //
		if(!((CTxtArray *)_prgRun)->AddBlock(++_iRun, 
			CbOfCch(cchInBlock + cchGapInitial)))
		{
			_ped->GetCallMgr()->SetOutOfMemory();
			BindToCp(_cp);	//force a rebind;
			goto done;
		}
		// NOTE: next line intentionally advances ptb to next CTxtBlk

		ptb = GetRun(0);
		AssertSz(ptb->_ibGap == 0, "New block not added correctly");

		CopyMemory(ptb->_pch, pch, CbOfCch(cchInBlock));
		cch				-= cchInBlock;
		pch				+= cchInBlock;
		_ich			= cchInBlock;
		ptb->_cch		= cchInBlock;
		((CTxtArray *)_prgRun)->_cchText	+= cchInBlock;
		ptb->_ibGap		= CbOfCch(cchInBlock);
	}
	AssertSz(cch == 0, "Didn't use up all text");

	// copy into last block (second half of split)
	if(cchLast > 0)
	{
		AssertSz(_iRun < Count()-1, "no last block");
		ptb = Elem(++_iRun);
		AssertSz(ptb->_ibGap == 0,	"split last gap in wrong place");
		AssertSz(cchLast <= CchOfCb(ptb->_cbBlock) - ptb->_cch,
									"split last not big enuf");

		CopyMemory(ptb->_pch, pch, CbOfCch(cchLast));
		// don't subtract cchLast from cch; it's already been done
		_ich			= cchLast;
		ptb->_cch		+= cchLast;
		((CTxtArray *)_prgRun)->_cchText	+= cchLast;
		ptb->_ibGap		= CbOfCch(cchLast);
		cchLast = 0;						// Inserted all requested chars
	}

done:
	AssertSz(cch + cchLast >= 0, "we should have inserted some characters");
	AssertSz(cch + cchLast <= cchSave, "don't insert more than was asked for");

	cch = cchSave - cch - cchLast;			// # chars successfully inserted
	_cp += cch;

	AssertSz (GetTextLength() == 
				((CTxtArray *)_prgRun)->GetCch(), 
				"CTxtPtr::InsertRange(): _prgRun->_cchText messed up !");
	return cch;
}


/*
 *	TxDivideInsertion(cch, ichBlock, cchAfter, pcchFirst, pcchLast)
 *	
 *	@func
 *		Find best way to distribute an insertion	
 *	
 *	@rdesc
 *		nothing
 */
LOCAL void TxDivideInsertion(
	DWORD cch, 				//@parm length of text to insert
	DWORD ichBlock, 		//@parm offset within block to insert text
	DWORD cchAfter,			//@parm length of text after insertion in block
	DWORD *pcchFirst, 		//@parm exit: length of text to put in first block
	DWORD *pcchLast)		//@parm exit: length of text to put in last block
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "TxDivideInsertion");

	DWORD cchFirst = max(0, (LONG)(cchBlkCombmGapI - ichBlock));
	DWORD cchLast  = max(0, (LONG)(cchBlkCombmGapI - cchAfter));
	DWORD cchPartial;
	DWORD cchT;

	// Fill first and last blocks to min block size if possible

	cchFirst = min(cch, cchFirst);
	cch		-= cchFirst;
	cchLast = min(cch, cchLast);
	cch		-= cchLast;

	// How much is left over when we divide up the rest?
	cchPartial = cch % cchBlkInsertmGapI;
	if(cchPartial > 0)
	{
		// Fit as much as the leftover as possible in the first and last
		// w/o growing the first and last over cbBlockInitial
		cchT		= max(0, (LONG)(cchBlkInsertmGapI - ichBlock - cchFirst));
		cchT		= min(cchT, cchPartial);
		cchFirst	+= cchT;
		cch			-= cchT;
		cchPartial	-= cchT;
		if(cchPartial > 0)
		{
			cchT	= max(0, (LONG)(cchBlkInsertmGapI - cchAfter - cchLast));
			cchT	= min(cchT, cchPartial);
			cchLast	+= cchT;
		}
	}
	*pcchFirst = cchFirst;
	*pcchLast = cchLast;
}


/*
 *	CTxtPtr::DeleteRange(cch)
 *	
 *	@mfunc
 *		Delete cch characters starting at this text pointer		
 *	
 *	@rdesc
 *		nothing
 *	
 *	@comm Side Effects:	<nl>
 *		moves text block array
 */
void CTxtPtr::DeleteRange(
	DWORD cch)		//@parm length of text to delete
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTxtPtr::DeleteRange");

	_TEST_INVARIANT_

	DWORD		cchInBlock;
	DWORD		ctbDel = 0;					// Default no blocks to delete
	DWORD		itb;
	CTxtBlk *	ptb = GetRun(0);

	AssertSz(ptb,
		"CTxtPtr::DeleteRange: want to delete, but no text blocks");

	if (cch > GetTextLength() - _cp)	// Don't delete beyond end of story
		cch = GetTextLength() - _cp;

	((CTxtArray *)_prgRun)->_cchText -= cch;

	// remove from first block
	ptb->MoveGap(_ich);
	cchInBlock = min(cch, ptb->_cch - _ich);
	cch -= cchInBlock;
	ptb->_cch -= cchInBlock;

#ifdef DEBUG
	((CTxtArray *)_prgRun)->Invariant();
#endif // DEBUG


	for(itb = ptb->_cch ? _iRun + 1 : _iRun;
			cch && cch >= Elem(itb)->_cch; ctbDel++, itb++)
	{
		// More to go: scan for complete blocks to remove
		cch -= Elem(itb)->_cch;
	}

	if(ctbDel)
	{
		// ***** moves (*_prgRun) ***** //
		itb -= ctbDel;
		((CTxtArray *)_prgRun)->RemoveBlocks(itb, ctbDel);
	}


	// remove from last block
	if(cch > 0)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -