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

📄 range.cpp

📁 Windows CE 6.0 Word Application 源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*
 *	@doc INTERNAL
 *
 *	@module	range.cpp - Implement the CTxtRange Class |
 *	
 *		This module implements the internal CTxtRange methods.  See range2.c
 *		for the ITextRange methods
 *
 *	Authors: <nl>
 *		Original RichEdit code: David R. Fulmer <nl>
 *		Christian Fortini <nl>
 *		Murray Sargent <nl>
 *
 *	Revisions: <nl>
 *		AlexGo: update to runptr text ptr; floating ranges, multilevel undo
 *
 */

#include "_common.h"
#include "_range.h"
#include "_edit.h"
#include "_text.h"
#include "_rtext.h"
#include "_m_undo.h"
#include "_antievt.h"
#include "_disp.h"

ASSERTDATA

TCHAR	szEmbedding[] = {WCH_EMBEDDING, 0};

// ===========================  Invariant stuff  ======================================================

#define DEBUG_CLASSNAME CTxtRange
#include "_invar.h"

#ifdef DEBUG
BOOL
CTxtRange::Invariant( void ) const
{
	LONG cpMin, cpMost;
	LONG diff = GetRange(cpMin, cpMost);

	Assert ( cpMin >= 0 );
	Assert ( cpMin <= cpMost );
	Assert ( cpMost <= GetTextLength() );
	Assert ( cpMin != cpMost || cpMost <= (LONG)GetAdjustedTextLength());

	static LONG	numTests = 0;
	numTests++;				// how many times we've been called.

	// make sure the selections are in range.

	return CRchTxtPtr::Invariant();
}
#endif


CTxtRange::CTxtRange(CTxtEdit *ped, LONG cp, LONG cch) :
	CRchTxtPtr(ped, cp),
	_cch(0),
	_iFormat(0),
	_cRefs(0)
{
	TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::CTxtRange");

	LONG cchText = GetAdjustedTextLength();
	LONG cpOther = cp - cch;			// Calculate cpOther with entry cp

	_dwFlags = FALSE;					// This range isn't a selection
	_iFormat = -1;						// Set up the default format, which
										//  doesn't get AddRefFormat'd
	ValidateCp(cpOther);				// Validate requested other end
	cp = GetCp();						// Validated cp
	if(cp == cpOther && cp > cchText)	// IP cannot follow undeletable
		cp = cpOther = SetCp(cchText);	//  EOP at end of story

	_cch = cp - cpOther;				// Store valid length
	Update_iFormat(-1);					// Choose _iFormat

	CNotifyMgr *pnm = ped->GetNotifyMgr();

    if( pnm )
        pnm->Add( (ITxNotify *)this );
}

CTxtRange::CTxtRange(const CTxtRange &rg) :
	CRchTxtPtr((CRchTxtPtr)rg),
    _cch(0),
	_iFormat(0),
	_cRefs(0)
	
{
	TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::CTxtRange");

	_cch = rg._cch;
	_dwFlags = FALSE;				// This range isn't a selection
	_iFormat = -1;					// Set up the default format, which
									//  doesn't get AddRefFormat'd
	Set_iCF(rg._iFormat);

	CNotifyMgr *pnm = GetPed()->GetNotifyMgr();

    if( pnm )
        pnm->Add( (ITxNotify *)this );
}

CTxtRange::~CTxtRange()
{
	TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::~CTxtRange");

	if(!IsZombie())
	{
		CNotifyMgr *pnm = GetPed()->GetNotifyMgr();

		if( pnm )
			pnm->Remove( (ITxNotify *)this );
	}

	ReleaseFormats(_iFormat, -1);
}

CRchTxtPtr& CTxtRange::operator =(const CRchTxtPtr &rtp)
{
	TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::operator =");

	_TEST_INVARIANT_ON(rtp)

	LONG cpSave = GetCp();			// Save entry _cp for CheckChange()

	CRchTxtPtr::operator =(rtp); 
	CheckChange(cpSave);
	return *this;
}

CTxtRange& CTxtRange::operator =(const CTxtRange &rg)
{
	TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::operator =");

	_TEST_INVARIANT_ON( rg );

	LONG cchSave = _cch;			// Save entry _cp, _cch for change check
	LONG cpSave  = GetCp();

	CRchTxtPtr::operator =(rg);
	_cch = rg._cch;					// Can't use CheckChange(), since don't
									//  use _fExtend
	Update_iFormat(-1); 
	_TEST_INVARIANT_

	if( _fSel && (cpSave != GetCp() || cchSave != _cch) )
		GetPed()->GetCallMgr()->SetSelectionChanged();

	return *this;
}

/*
 *	CTxtRange::OnPreReplaceRange (cp, cchDel, cchNew, cpFormatMin,
 *									cpFormatMax)
 *
 *	@mfunc
 *		called when the backing store changes
 *
 *	@devnote
 *		1) if this range is before the changes, do nothing
 *
 *		2) if the changes are before this range, simply
 *		add the delta change to GetCp()
 *
 *		3) if the changes overlap one end of the range, collapse
 *		that end to the edge of the modifications
 *
 *		4) if the changes are completely internal to the range,
 *		adjust _cch and/or GetCp() to reflect the new size.  Note
 *		that two overlapping insertion points will be viewed as
 *		a 'completely internal' change.
 *
 *		5) if the changes overlap *both* ends of the range, collapse
 *		the range to cp
 *
 *		Note that there is an ambiguous cp case; namely the changes
 *		occur *exactly* at a boundary.  In this case, the type of
 *		range matters.  If a range is normal, then the changes
 *		are assumed to fall within the range.  If the range is
 *		is protected (either in reality or via DragDrop), then
 *		the changes are assumed to be *outside* of the range.
 */
void CTxtRange::OnPreReplaceRange (
	DWORD cp,					//@parm cp at start of change
	DWORD cchDel,				//@parm Count of chars deleted
	DWORD cchNew,				//@parm Count of chars inserted
	DWORD cpFormatMin,			//@parm the min cp of a format change
	DWORD cpFormatMax)			//@parm the max cp of a format change
{
	TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::OnPreReplaceRange");

	if (CONVERT_TO_PLAIN == cp)
	{
		// We need to dump our formatting because it is gone.
		_rpCF.SetToNull();
		_rpPF.SetToNull();

		if( _fSel )
		{
			GetPed()->_fUpdateSelection = TRUE;	
		}

		Update_iFormat(-1);
		return;
	}
}

/*
 *	CTxtRange::OnPostReplaceRange (cp, cchDel, cchNew, cpFormatMin,
 *									cpFormatMax)
 *
 *	@mfunc
 *		called when the backing store changes
 *
 *	@devnote
 *		1) if this range is before the changes, do nothing
 *
 *		2) if the changes are before this range, simply
 *		add the delta change to GetCp()
 *
 *		3) if the changes overlap one end of the range, collapse
 *		that end to the edge of the modifications
 *
 *		4) if the changes are completely internal to the range,
 *		adjust _cch and/or GetCp() to reflect the new size.  Note
 *		that two overlapping insertion points will be viewed as
 *		a 'completely internal' change.
 *
 *		5) if the changes overlap *both* ends of the range, collapse
 *		the range to cp
 *
 *		Note that there is an ambiguous cp case; namely the changes
 *		occur *exactly* at a boundary.  In this case, the type of
 *		range matters.  If a range is normal, then the changes
 *		are assumed to fall within the range.  If the range is
 *		is protected (either in reality or via DragDrop), then
 *		the changes are assumed to be *outside* of the range.
 */
void CTxtRange::OnPostReplaceRange (
	DWORD cp,					//@parm cp at start of change
	DWORD cchDel,				//@parm Count of chars deleted
	DWORD cchNew,				//@parm Count of chars inserted
	DWORD cpFormatMin,			//@parm the min cp of a format change
	DWORD cpFormatMax)			//@parm the max cp of a format change
{
	TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::OnPostReplaceRange");

	// NB!! We can't do invariant testing here, because we could
	// be severely out of date!

	DWORD cchtemp;
	DWORD cpMin, cpMost;
	LONG cchAdjTextLen;
	LONG delta = cchNew - cchDel;

	Assert (CONVERT_TO_PLAIN != cp);
	GetRange((LONG&)cpMin, (LONG&)cpMost);
	
	// This range is before the changes. Note: an insertion pt at cp
	// shouldn't be changed
	if( cp >= cpMost )
	{
		// double check to see if we need to fix up our format
		// run pointers.  If so, all we need to do is rebind
		// our inherited rich text pointer

		if( cpFormatMin <=  cpMost || cpFormatMin == INFINITE)
		{
			InitRunPtrs(GetCp());
		}
		else
		{
		 	// It's possible that the format runs changed anyway,
			// e.g., they became allocated, deallocated, or otherwise
			// changed.  Normally, BindToCp takes care of this
			// situation, but we don't want to pay that cost all
			// the time.
			//
			// Note that starting up the rich text subsystem will 
			// generate a notification with cpFormatMin == INFINITE
			//
			// So here, call CheckFormatRuns.  This makes sure that
			// the runs are in sync with what CTxtStory has
			// (doing an InitRunPtrs() _only_ if absolutely necessary).
			CheckFormatRuns();
		}
		return;
	}


	// Anywhere in the following that we want to increment the current cp by a
	// delta, we are counting on the following invariant.
	Assert(GetCp() >= 0);

	// changes are entirely before this range.  Specifically,
	// that's determined by looking at the incoming cp *plus* the number
	// of characters deleted
	if( (cp + cchDel) < cpMin  ||
		(_fDragProtection == TRUE && (cp + cchDel) <= cpMin ))
	{
		cchtemp = _cch;
		BindToCp(GetCp() + delta);
		_cch = cchtemp;
	}	
	// the changes are internal to the range or start within the
	// range and go beyond.
	else if( cp >= cpMin && cp <= cpMost )
	{
		// nobody should be modifying a drag-protected range.  Unfortunately,
		// Ren re-enters us with a SetText call during drag drop, so we need
		// to handle this case 'gracefully'.
		if( _fDragProtection )
		{
			TRACEWARNSZ("REENTERED during a DRAG DROP!! Trying to recover!");
		}

		if( cp + cchDel <= cpMost )
		{
			// changes are purely internal, so
			// be sure to preserve the active end.  Basically, if
			// GetCp() *is* cpMin, then we only need to update _cch.
			// Otherwise, GetCp() needs to be moved as well
			if( _cch >= 0 )
			{
				Assert(GetCp() == (LONG)cpMost);
				cchtemp = _cch;
				BindToCp(GetCp() + delta);
				_cch = cchtemp + delta;
			}
			else
			{
				BindToCp(GetCp());
				_cch -= delta;
			}

			// Special case: the range is left with only the final EOP
			// selected. This means all the characters in the range were
			// deleted so we want to move the range back to an insertion
			// point at the end of the text.
			cchAdjTextLen = GetPed()->GetAdjustedTextLength();

			if (GetCpMin() >= cchAdjTextLen)
			{
				// Reduce the range to an insertion point
				_cch = 0;

				_fExtend = FALSE;

				// Set the cp to the end of the document.
				SetCp(cchAdjTextLen);
			}
		}
		else
		{
			// Changes extended beyond cpMost.  In this case,
			// we want to truncate cpMost to the *beginning* of 
			// the changes (i.e. cp)

			if( _cch > 0 )
			{
				BindToCp(cp);
				_cch = cp - cpMin;
			}
			else
			{
				BindToCp(cpMin);
				_cch = cpMin - cp;
			}
		}
	}
	else if( (cp + cchDel) >= cpMost )
	{
		// nobody should be modifying a drag-protected range.  Unfortunately,
		// Ren re-enters us with a SetText call during drag drop, so we need
		// to handle this case 'gracefully'.
		if( _fDragProtection )
		{
			TRACEWARNSZ("REENTERED during a DRAG DROP!! Trying to recover!");
		}

		// entire range was deleted, so collapse to an insertion point at cp
		BindToCp(cp);
		_cch = 0;
	}
	else
	{
		// nobody should be modifying a drag-protected range.  Unfortunately,
		// Ren re-enters us with a SetText call during drag drop, so we need
		// to handle this case 'gracefully'.
		if( _fDragProtection )
		{
			TRACEWARNSZ("REENTERED during a DRAG DROP!! Trying to recover!");
		}

		// the change crossed over just cpMin.  In this case move cpMin
		// forward to the unchanged part
		LONG cchdiff = (cp + cchDel) - cpMin;

		Assert( (cp + cchDel) < cpMost );
		Assert( (cp + cchDel) >= cpMin );
		Assert( cp < cpMin );

		cchtemp = _cch;
		if( _cch > 0 )
		{
			BindToCp(GetCp() + delta);
			_cch = cchtemp - cchdiff;
		}
		else
		{
			BindToCp(cp + cchNew);
			_cch = cchtemp + cchdiff;
		}
	}

	if( _fSel )
	{
		GetPed()->_fUpdateSelection = TRUE;		
		GetPed()->GetCallMgr()->SetSelectionChanged();
	}

	Update_iFormat(-1);					// Make sure format is up to date

	_TEST_INVARIANT_
}	

/*
 *	CTxtRange::Zombie ()
 *
 *	@mfunc
 *		Turn this range into a zombie (_cp = _cch = 0, NULL ped, ptrs to
 *		backing store arrays.  CTxtRange methods like GetRange(),
 *		GetCpMost(), GetCpMin(), and GetTextLength() all work in zombie mode,
 *		returning zero values.
 */
void CTxtRange::Zombie()
{
	CRchTxtPtr::Zombie();
	_cch = 0;
}

/*
 *	CTxtRange::CheckChange(cpSave, cchSave)
 *
 *	@mfunc
 *		Set _cch according to _fExtend and set selection-changed flag if
 *		this range is a CTxtSelection and the new _cp or _cch differ from
 *		cp and cch, respectively.
 *
 *	@devnote
 *		We can count on GetCp() and cpSave both being <= GetTextLength(),
 *		but we can't leave GetCp() equal to GetTextLength() unless _cch ends
 *		up > 0.

⌨️ 快捷键说明

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