📄 range.cpp
字号:
if(!(cchNew | _cch)) // Nothing to add or delete,
return 0; // so we're done
if( publdr && selaemode != SELRR_IGNORE )
{
Assert(selaemode == SELRR_REMEMBERRANGE);
HandleSelectionAEInfo(GetPed(), publdr, GetCp(), _cch,
GetCpMin() + cchNew, 0, SELAE_MERGE);
}
if(_cch > 0)
FlipRange();
// If we are replacing a non-degenerate selection, then the Word95
// UI specifies that we should use the rightmost formatting at cpMin.
if( _cch < 0 && _rpCF.IsValid() && !_fDualFontMode && !_fUseiFormat )
{
_rpCF.AdjustForward();
iFormat = _rpCF.GetFormat();
// This is a bit icky, but the idea is to stabilize the
// reference count on iFormat. When we get it above, it's
// not addref'ed, so if we happen to delete the text in the
// range and the range is the only one with that format,
// then the format will go away.
if(FAILED(GetCharFormatCache(&pcf)))
{
AssertSz(0, "couldn't get format cache yet we have formatting");
return 0;
}
pcf->AddRefFormat(iFormat);
fReleaseFormat = TRUE;
}
_fUseiFormat = FALSE;
LONG cchForReplace = -_cch;
_cch = 0;
lRet = CRchTxtPtr::ReplaceRange(cchForReplace, cchNew, pch, publdr,
iFormat);
Update_iFormat(fReleaseFormat ? iFormat : -1);
if(fReleaseFormat)
{
Assert(pcf);
pcf->ReleaseFormat(iFormat);
}
return lRet;
}
/*
* CTxtRange::GetCharFormat(pCF, flags)
*
* @mfunc
* Set *pCF = CCharFormat for this range. If cbSize = sizeof(CHARFORMAT)
* only transfer CHARFORMAT data.
*
* @devnote
* NINCH means No Input No CHange (a Microsoft Word term). Here used for
* properties that change during the range of cch characters. NINCHed
* properties in a Word-Font dialog have grayed boxes. They are indicated
* by zero values in their respective dwMask bit positions. Note that
* a blank at the end of the range does not participate in the NINCH
* test, i.e., it can have a different CCharFormat without zeroing the
* corresponding dwMask bits. This is done to be compatible with Word
* (see also CTxtSelection::SetCharFormat when _fWordSelMode is TRUE).
*/
void CTxtRange::GetCharFormat (
CCharFormat *pCF, // @parm CCharFormat to fill with results
DWORD flags) const // @parm flags
{
TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::GetCharFormat");
_TEST_INVARIANT_
CTxtEdit * const ped = GetPed();
if(!_cch || !_rpCF.IsValid()) // IP or invalid CF
{ // run ptr: use CF at
ped->GetCharFormat(_iFormat)->Get(pCF); // this text ptr
return;
}
LONG cpMin, cpMost; // Nondegenerate range:
LONG cch = GetRange(cpMin, cpMost); // need to scan
LONG cchChunk; // cch in CF run
LONG iDirection; // Direction of scan
CFormatRunPtr rp(_rpCF); // Nondegenerate range
/*
* The code below reads character formatting the way Word does it,
* that is, by not including the formatting of the last character in the
* selection if that character is a blank.
*
* See also the corresponding code in CTxtSelection::SetCharFormat().
*/
if(cch > 1 && _fSel && (flags & SCF_USEUIRULES))// If more than one char,
{ // don't include trailing
CTxtPtr tp(ped, cpMost - 1); // blank in NINCH test
if(tp.GetChar() == ' ')
{ // Have trailing blank:
cch--; // one less char to check
if(_cch > 0) // Will scan backward, so
rp.AdvanceCp(-1); // backup before blank
}
}
if(_cch < 0) // Setup direction and
{ // initial cchChunk
iDirection = 1; // Scan forward
rp.AdjustForward();
cchChunk = rp.GetCchLeft(); // Chunk size for _rpCF
}
else
{
iDirection = -1; // Scan backward
rp.AdjustBackward(); // If at BOR, go to
cchChunk = rp.GetIch(); // previous EOR
}
ped->GetCharFormat(rp.GetFormat())->Get(pCF); // Initialize *pCF to
// starting format
AssertSz(pCF->dwMask == (pCF->cbSize == sizeof(CHARFORMAT)
? CFM_ALL : CFM_ALL2),
"CTxtRange::GetCharFormat: dwMask not initialized");
while(cchChunk < cch) // NINCH properties that
{ // change over the range
cch -= cchChunk; // given by cch
if(!rp.ChgRun(iDirection)) // No more runs
return; // (cch too big)
cchChunk = rp.GetRun(0)->_cch;
const CCharFormat *pCFTemp = ped->GetCharFormat(rp.GetFormat());
if (pCFTemp)
{
pCFTemp->Delta(pCF); // NINCH properties that
}
else
{
AssertSz(pCFTemp, "ped->GetCharFormat failed");
}
// changed, i.e., reset
} // corresponding bits
}
/*
* CTxtRange::SetCharFormat(pCF, flags, publdr)
*
* @mfunc
* apply CCharFormat *pCF to this range. If range is an insertion point,
* and fApplyToWord is TRUE, then apply CCharFormat to word surrounding
* this insertion point
*
* @rdesc
* HRESULT = (successfully set whole range) ? NOERROR : S_FALSE
*
* @devnote
* SetParaFormat() is similar, but simpler, since it doesn't have to
* special case insertion-point ranges or worry about bullet character
* formatting, which is given by EOP formatting.
*/
HRESULT CTxtRange::SetCharFormat (
const CCharFormat *pCF, // @parm CCharFormat to fill with results
DWORD flags, // @parm APPLYTOWORD or IGNORESELAE
IUndoBuilder *publdr) // @parm the undo builder to use.
{
TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::SetCharFormat");
LONG cch = -_cch; // Defaults for _cch <= 0
LONG cchBack = 0; // cch to back up for formatting
LONG cchFormat; // cch for formatting
CCharFormat CF; // Temporary CF
LONG cp = 0; // Used for DEBUG only
LONG cpMin, cpMost;
LONG cpStart = 0;
LONG cpWordMin, cpWordMost;
LONG delta;
BOOL fApplyToWord = (flags & APPLYTOWORD);
BOOL fApplyToEOP = FALSE;
BOOL fProtected = FALSE;
HRESULT hr = NOERROR;
LONG icf;
CTxtEdit * const ped = GetPed(); // defined and not style
ICharFormatCache * pf;
_TEST_INVARIANT_
AssertSz(IsValidCharFormat((CHARFORMAT *)pCF),
"RTR::SetCharFormat(): invalid CCharFormat");
if (!Check_rpCF() ||
FAILED(GetCharFormatCache(&pf)))
{
return NOERROR;
}
if(_cch > 0) // Active end at range end
{
cchBack = -_cch; // Setup to back up _rpCF to
cch = _cch; // start of format area
}
else if (_cch < 0)
{
_rpCF.AdjustForward();
}
else if(!cch && fApplyToWord )
{
FindWord(&cpWordMin, &cpWordMost, FW_EXACT);
// If nearest word is within this range, calculate cchback and cch
// so that we can apply the given format to the word
if( cpWordMin < GetCp() && GetCp() < cpWordMost )
{
// RichEdit 1.0 made 1 final check: ensure word's format
// is constant w.r.t. the format passed in
CTxtRange rg(*this);
rg.Set(cpWordMin, cpWordMin - cpWordMost);
fProtected = rg.WriteAccessDenied();
if(!fProtected)
{
rg.GetCharFormat(&CF);
if( (CF.dwMask & pCF->dwMask) == pCF->dwMask )
{
cchBack = cpWordMin - GetCp();
cch = cpWordMost - cpWordMin;
}
}
}
else if(_rpTX.IsAtEOP() && !GetPF()->wNumbering)
{
CTxtPtr tp(_rpTX);
cch = tp.AdvanceCpCRLF();
_rpCF.AdjustForward(); // Go onto format EOP
fApplyToEOP = TRUE;
}
}
cchFormat = cch;
BOOL fFullyDefined = FALSE; // Default input CF not fully
BOOL fInOurHost = ped->fInOurHost(); // defined
if (ped->HandleStyle(&CF, pCF) == NOERROR &&
pf->Cache(&CF, &icf) == NOERROR)
{
fFullyDefined = TRUE;
}
if(!cch) // Set degenerate-range (IP)
{ // CF
if(!fFullyDefined) // If pCF doesn't specify
{ // full CF, fill in undefined
ped->GetCharFormat(_iFormat) // Copy current CF at IP to CF
->Get(&CF);
hr = CF.Apply(pCF, fInOurHost); // Apply *pCF
if(hr != NOERROR) // Cache result if new
return hr;
hr = pf->Cache(&CF, &icf); // In any case, get icf
if(hr != NOERROR)
return hr;
}
pf->ReleaseFormat(_iFormat); // AddRefFormat() it)
_iFormat = icf;
if(fProtected) // Signal to beep if UI
hr = S_FALSE;
}
else // Set nondegenerate-range CF
{ // Get start of affected area
CNotifyMgr *pnm = ped->GetNotifyMgr(); // Get the notification mgr
if(pnm)
{
cpStart = GetCp() + cchBack; // Bulletting may move
// affected area back if
if(GetPF()->wNumbering) // formatting hits EOP that
{ // affects bullet at BOP
FindParagraph(&cpMin, &cpMost);
if(cpMost <= GetCpMost())
cpStart = cpMin;
}
pnm->NotifyPreReplaceRange(this, // Notify interested parties of
INFINITE, 0, 0, cpStart, // the impending update
cpStart + cchFormat);
}
_rpCF.AdvanceCp(cchBack); // Back up to formatting start
CFormatRunPtr rp(_rpCF); // Clone _rpCF to walk range
if( publdr )
{
IAntiEvent *pae = gAEDispenser.CreateReplaceFormattingAE(
ped, rp, cch, pf, CharFormat);
if( pae )
publdr->AddAntiEvent(pae);
}
while(cch > 0 && rp.IsValid())
{
if(!fFullyDefined) // If input CF not fully def'd
{ // fill in remaining members
ped->GetCharFormat(rp.GetFormat()) // Copy rp CF to temp CF
->Get(&CF);
hr = CF.Apply(pCF, fInOurHost); // Apply *pCF
if(hr != NOERROR)
return hr;
hr = pf->Cache(&CF, &icf); // Cache result if new, In any
if(hr != NOERROR) // cause, use format index icf
break;
}
delta = rp.SetFormat(icf, cch, pf); // Set format for this run
if( delta == -1 )
{
ped->GetCallMgr()->SetOutOfMemory();
break;
}
cch -= delta;
}
_rpCF.AdjustBackward(); // Expand scope for merging
rp.AdjustForward(); // runs
rp.MergeRuns(_rpCF._iRun, pf); // Merge adjacent runs that
// have the same format
if(cchBack) // Move _rpCF back to where it
_rpCF.AdvanceCp(-cchBack); // was
else // Active end at range start:
_rpCF.AdjustForward(); // don't leave at EOR
if (pnm)
{
pnm->NotifyPostReplaceRange(this, // Notify interested parties
INFINITE, 0, 0, cpStart, // of the change.
cpStart + cchFormat - cch);
}
if( publdr && !(flags & IGNORESELAE))
{
HandleSelectionAEInfo(ped, publdr, GetCp(), _cch, GetCp(), _cch,
SELAE_FORCEREPLACE);
}
if(!_cch) // In case IP with ApplyToWord
{
if(fApplyToEOP) // Formatting EOP only
{
_rpCF.AdjustForward(); // Get EOP format
Set_iCF(_rpCF.GetFormat()); // Use it for IP
}
else
Update_iFormat(-1);
}
ped->GetCallMgr()->SetChangeEvent(CN_GENERIC);
}
if(_fSel)
ped->GetCallMgr()->SetSelectionChanged();
AssertSz(GetCp() == (cp = _rpCF.GetCp()),
"RTR::SetCharFormat(): incorrect format-run ptr");
return (hr == NOERROR && cch) ? S_FALSE : hr;
}
/*
* CTxtRange::GetParaFormat(pPF)
*
* @mfunc
* return CParaFormat for this text range. If no PF runs are allocated,
* then return default CParaFormat
*
* @devnote
* This is very similar to GetCharFormat, but it's not obvious how to
* reduce the code size further w/o introducing virtual methods on
* CCharFormat and CParaFormat, which inherit from structs. We don't
* want a vtable, since it would increase the storage of format classes
*/
void CTxtRange::GetParaFormat (
CParaFormat *pPF) const // @parm ptr to user-supplied CParaFormat to
{ // be filled with possibly NINCH'd values
TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::GetParaFormat");
CTxtEdit * const ped = GetPed();
_TEST_INVARIANT_
pPF->dwMask = pPF->cbSize == sizeof(PARAFORMAT2)// Default presence of
? PFM_ALL2 : PFM_ALL; // all properties
CFormatRunPtr rp(_rpPF);
LONG cch = -_cch;
if(cch < 0) // At end of range:
{ // go to start of range
rp.AdvanceCp(cch);
cch = -cch; // Count with cch > 0
}
ped->GetParaFormat(rp.GetFormat())->Get(pPF); // Initialize *pPF to
// starting paraformat
if(!cch || !rp.IsValid()) // No cch or invalid PF
return; // run ptr: use PF at
// this text ptr
LONG cchChunk = rp.GetCchLeft(); // Chunk size for rp
while(cchChunk < cch) // NINCH properties that
{ // change over the range
cch -= cchChunk; // given by cch
if(!rp.NextRun()) // Go to next run // No more runs
break; // (cch too big)
cchChunk = rp.GetCchLeft();
ped->GetParaFormat(rp.GetFormat()) // NINCH properties that
->Delta(pPF); // changed, i.e., reset
} // corresponding bits
}
/*
* CTxtRange::SetParaFormat(pPF, publdr)
*
* @mfunc
* apply CParaFormat *pPF to this range.
*
* @rdesc
* if successfully set whole range, return NOERROR, otherwise
* return error code or S_FALSE.
*/
HRESULT CTxtRange::SetParaFormat (
const CParaFormat* pPF, // @parm CParaFormat to apply to this range
IUndoBuilder *publdr) // @parm the undo context for this operation
{
TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::SetParaFormat");
LONG cch; // length of text to format
LONG cchBack; // cch to back up for formatting
LONG cp = 0; // Used for DEBUG only
LONG cpMin, cpMost; // limits of text to format
LONG delta;
HRESULT hr = NOERROR;
LONG ipf; // index to a CParaFormat
CTxtEdit * const ped = GetPed();
CParaFormat PF; // Temporary CParaFormat
IParaFormatCache * pf; // ptr to format caches for Cache,
// AddRefFormat, ReleaseFormat
AssertSz(IsValidParaFormat((PARAFORMAT *)pPF),
"RTR::SetParaFormat(): invalid CParaFormat");
_TEST_INVARIANT_
if(!Check_rpPF())
return E_FAIL;
if(FAILED(hr = GetParaFormatCache(&pf)))
return hr;
FindParagraph(&cpMin, &cpMost); // Get limits of text to
cch = cpMost - cpMin; // format, namely closest
CNotifyMgr *pnm = ped->GetNotifyMgr();
if (pnm)
{
pnm->NotifyPreReplaceRange(this, // Notify interested parties of
INFINITE, 0, 0, cpMin, cpMost); // the impending update
}
cchBack = cpMin - GetCp();
_rpPF.AdvanceCp(cchBack); // Back up to formatting start
CFormatRunPtr rp(_rpPF); // Clone _rpPF to walk range
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -