📄 range.cpp
字号:
if( publdr )
{
IAntiEvent *pae = gAEDispenser.CreateReplaceFormattingAE(ped,
rp, cch, pf, ParaFormat);
if( pae )
publdr->AddAntiEvent(pae);
}
BOOL fFullyDefined = FALSE; // Default input PF not fully
// defined
if (ped->HandleStyle(&PF, pPF) == NOERROR &&
pf->Cache(&PF, &ipf) == NOERROR)
{
fFullyDefined = TRUE;
}
do
{
if (!fFullyDefined) // If pPF doesn't specify
{ // full PF, fill in undefined
ped->GetParaFormat(rp.GetFormat()) // Copy rp PF to temp PF
->Get(&PF);
hr = PF.Apply(pPF); // Apply *pPF
if(hr != NOERROR) // (Probably E_INVALIDARG)
return hr; // Cache result if new; in any
hr = pf->Cache(&PF, &ipf); // case, get format index ipf
if(hr != NOERROR) // Can't necessarily return
break; // error, since may need
} // fixups below
delta = rp.SetFormat(ipf, cch, pf); // Set format for this run
if( delta == -1 )
{
ped->GetCallMgr()->SetOutOfMemory();
break;
}
cch -= delta;
} while (cch > 0) ;
_rpPF.AdjustBackward(); // If at BOR, go to prev EOR
rp.MergeRuns(_rpPF._iRun, pf); // Merge any adjacent runs
// that have the same format
if(cchBack) // Move _rpPF back to where it
_rpPF.AdvanceCp(-cchBack); // was
else // Active end at range start:
_rpPF.AdjustForward(); // don't leave at EOR
if (pnm)
{
pnm->NotifyPostReplaceRange(this, // Notify interested parties of
INFINITE, 0, 0, cpMin, cpMost); // the update
}
if( publdr )
{
// Paraformatting works a bit differently, it just remembers the
// current selection. Cast selection to range to avoid including
// _select.h; we only need range methods.
CTxtRange *psel = (CTxtRange *)GetPed()->GetSel();
if( psel )
{
HandleSelectionAEInfo(ped, publdr, psel->GetCp(),
psel->GetCch(), psel->GetCp(), psel->GetCch(),
SELAE_FORCEREPLACE);
}
}
ped->GetCallMgr()->SetChangeEvent(CN_GENERIC);
AssertSz(GetCp() == (cp = _rpPF.GetCp()),
"RTR::SetParaFormat(): incorrect format-run ptr");
return (hr == NOERROR && cch) ? S_FALSE : hr;
}
/*
* CTxtRange::SetParaStyle(pPF, publdr)
*
* @mfunc
* apply CParaFormat *pPF using the style pPF->sStyle to this range.
*
* @rdesc
* if successfully set whole range, return NOERROR, otherwise
* return error code or S_FALSE.
*
* @comm
* If pPF->dwMask & PFM_STYLE is nonzero, this range is expanded to
* complete paragraphs. If it's zero, this call just passes control
* to CTxtRange::SetParaStyle().
*/
HRESULT CTxtRange::SetParaStyle (
const CParaFormat* pPF, // @parm CParaFormat to apply to this range
IUndoBuilder *publdr) // @parm Undo context for this operation
{
LONG cchSave = _cch; // Save range cp and cch in case
LONG cpSave = GetCp(); // para expand needed
HRESULT hr;
if(publdr)
publdr->StopGroupTyping();
if(pPF->fSetStyle())
{
CCharFormat CF; // Need to apply associated CF
CF.dwMask = CFM_STYLE;
LONG cpMin, cpMost;
Expander(tomParagraph, TRUE, NULL, &cpMin, &cpMost);
CF.sStyle = pPF->sStyle;
hr = SetCharFormat(&CF, 0, publdr);
if(hr != NOERROR)
return hr;
}
hr = SetParaFormat(pPF, publdr);
Set(cpSave, cchSave); // Restore this range in case expanded
return hr;
}
/*
* CTxtRange::Update_iFormat(iFmtDefault)
*
* @mfunc
* update _iFormat to CCharFormat at current active end
*
* @devnote
* _iFormat is only used when the range is degenerate
*
* The Word 95 UI specifies that the *previous* format should
* be used if we're in at an ambiguous cp (i.e. where a formatting
* change occurs) _unless_ the previous character is an EOP
* marker _or_ if the previous character is protected.
*/
void CTxtRange::Update_iFormat (
LONG iFmtDefault) //@parm Format index to use if _rpCF isn't valid
{
DWORD dwEffects;
LONG ifmt, ifmtForward;
const CCharFormat *pCF, *pCFForward;
TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::Update_iFormat");
if(_cch || _fDontUpdateFmt) // _iFormat is only used
return; // for degenerate ranges
if(_rpCF.IsValid() && iFmtDefault == -1)
{
// Get forward info before possibly adjusting backward
_rpCF.AdjustForward();
ifmt = ifmtForward = _rpCF.GetFormat();
pCF = pCFForward = GetPed()->GetCharFormat(ifmtForward);
if (NULL == pCF)
{
Assert(pCF);
return;
}
dwEffects = pCF->dwEffects;
if( !_rpTX.IsAfterEOP() )
{
_rpCF.AdjustBackward(); // Adjust backward
ifmt = _rpCF.GetFormat();
pCF = GetPed()->GetCharFormat(ifmt);
dwEffects = pCF->dwEffects;
}
if (!_rpTX.GetCp() && (pCF->bInternalEffects & CFEI_RUNISDBCS))
{
// If at beginning of document, and text is protected, just use
// default format.
ifmt = iFmtDefault;
}
else if((dwEffects & (CFE_PROTECTED | CFE_LINK | CFE_HIDDEN)) ||
(pCF->bInternalEffects & CFEI_RUNISDBCS))
{
// If range is protected or a hyperlink, pick forward format
_rpCF.AdjustForward();
ifmt = _rpCF.GetFormat();
}
else if (pCF->bCharSet != pCFForward->bCharSet)
{
// If charsets don't match, and currently in IME composition mode,
// and forward format matches keyboard, prefer forward format.
if (GetPed()->IsIMEComposition() && W32->FormatMatchesKeyboard(pCFForward))
{
_rpCF.AdjustForward();
ifmt = ifmtForward;
}
}
iFmtDefault = ifmt;
}
// Don't allow _iFormat to include CFE_LINK or CFE_HIDDEN attributes
// unless they're the default
if( iFmtDefault != -1 )
{
pCF = GetPed()->GetCharFormat(iFmtDefault);
if(pCF->dwEffects & (CFE_LINK | CFE_HIDDEN))
{
CCharFormat CF = *pCF;
CF.cbSize = sizeof(CHARFORMAT2);
CF.dwEffects &= ~(CFE_LINK | CFE_HIDDEN);
CF.dwMask = CFM_ALL2;
if(pCF->dwEffects & CFE_LINK)
{
// Copy default's color and underline effect
pCF = GetPed()->GetCharFormat(-1);
CF.crTextColor = pCF->crTextColor;
CF.dwEffects &= ~(CFE_UNDERLINE | CFE_AUTOCOLOR);
CF.dwEffects |= pCF->dwEffects & (CFE_UNDERLINE | CFE_AUTOCOLOR);
}
// This range must be an insertion point!
Assert(_cch == 0);
SetCharFormat(&CF, FALSE, NULL);
return;
}
}
Set_iCF(iFmtDefault);
}
/*
* CTxtRange::Get_iCF()
*
* @mfunc
* Get this range's _iFormat (AddRef'ing, of course)
*
* @devnote
* Get_iCF() is used by the RTF reader
*/
LONG CTxtRange::Get_iCF ()
{
TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::Get_iCF");
ICharFormatCache * pcf;
if(FAILED(GetCharFormatCache(&pcf)))
return -1;
pcf->AddRefFormat(_iFormat);
return _iFormat;
}
/*
* CTxtRange::Set_iCF(iFormat)
*
* @mfunc
* Set range's _iFormat to iFormat
*
* @devnote
* Set_iCF() is used by the RTF reader and by Update_iFormat()
*/
void CTxtRange::Set_iCF (
LONG iFormat) //@parm Index of char format to use
{
TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::Set_iCF");
if(iFormat != _iFormat)
{
ICharFormatCache * pCF;
if(FAILED(GetCharFormatCache(&pCF)))
return;
pCF->AddRefFormat(iFormat);
pCF->ReleaseFormat(_iFormat); // Note: _iFormat = -1 doesn't
_iFormat = iFormat; // get AddRef'd or Release'd
}
AssertSz(GetCF(), "CTxtRange::Set_iCF: illegal format");
}
/*
* CTxtRange::Get_iPF()
*
* @mfunc
* Get paragraph format at active end
*
* @devnote
* Get_iPF() is used by the RTF reader on encountering a start group
*/
LONG CTxtRange::Get_iPF ()
{
TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::Get_iPF");
LONG iPF = _rpPF.GetFormat();
IParaFormatCache * pPF;
if(FAILED(GetParaFormatCache(&pPF)))
return -1;
pPF->AddRefFormat(iPF);
return iPF;
}
/*
* CTxtRange::IsProtected(iDirection)
*
* @mfunc
* Return TRUE if any part of this range is protected (HACK: or
* if any part of the range contains DBCS text stored in our Unicode
* backing store). If degenerate,
* use CCharFormat from run specified by iDirection, that is, use run
* valid up to, at, or starting at this GetCp() for iDirection less, =,
* or greater than 0, respectively.
*
* @rdesc
* TRUE iff any part of this range is protected (HACK: or if any part
* of the range contains DBCS text stored in our Unicode backing store).
*/
BOOL CTxtRange::IsProtected (
LONG iDirection) // @parm Controls which run to check if range is IP
{
TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::IsProtected");
CCharFormat cf;
LONG iFormat = -1; // Default default CF
_TEST_INVARIANT_
if(_rpCF.IsValid()) // Active rich-text runs
{
if(_cch) // Range is nondegenerate
{
cf.dwMask = CFM_PROTECTED; // of range is protected
GetCharFormat(&cf);
if(cf.bInternalEffects & CFEI_RUNISDBCS)
return PROTECTED_YES;
if(!(cf.dwMask & CFM_PROTECTED) ||
(cf.dwEffects & CFE_PROTECTED))
{
return PROTECTED_ASK;
}
return PROTECTED_NO;
}
iFormat = _iFormat; // Degenerate range: default
if(iDirection != 0) // this range's iFormat
{ // Specific run direction
CFormatRunPtr rpCF(_rpCF);
if(iDirection < 0) // If at run ambiguous pos,
rpCF.AdjustBackward(); // use previous run
else
rpCF.AdjustForward();
iFormat = rpCF.GetFormat(); // Get run format
}
}
const CCharFormat *pCF = GetPed()->GetCharFormat(iFormat);
if (NULL == pCF)
{
Assert(pCF);
return FALSE;
}
if(pCF->bInternalEffects & CFEI_RUNISDBCS)
return PROTECTED_YES;
if(pCF->dwEffects & CFE_PROTECTED)
return PROTECTED_ASK;
return PROTECTED_NO;
}
/*
* CTxtRange::AdjustEndEOP (NewChars)
*
* @mfunc
* If this range is a selection and ends with an EOP and consists of
* more than just this EOP and fAdd is TRUE, or this EOP is the final
* EOP (at the story end), or this selection doesn't begin at the start
* of a paragraph, then move cpMost just before the end EOP. This
* function is used by UI methods that delete the selected text, such
* as PutChar(), Delete(), cut/paste, drag/drop.
*
* @rdesc
* TRUE iff range end has been adjusted
*
* @devnote
* This method leaves the active end at the selection cpMin. It is a
* CTxtRange method to handle the selection when it mascarades as a
* range for Cut/Paste.
*/
BOOL CTxtRange::AdjustEndEOP (
EOPADJUST NewChars) //@parm NEWCHARS if chars will be added
{
TRACEBEGIN(TRCSUBSYSSEL, TRCSCOPEINTERN, "CTxtRange::AdjustEndEOP");
LONG cpMin, cpMost;
LONG cch = GetRange(cpMin, cpMost);
LONG cchSave = _cch;
BOOL fRet = FALSE;
if(cch && cch < GetTextLength())
{
LONG cchEOP = GetPed()->Get10Mode() ? 2 : 1;
CTxtPtr tp(_rpTX);
if(_cch > 0) // Ensure active end is cpMin
FlipRange(); // (ReplaceRange() needs to
else // do this anyhow)
tp.AdvanceCp(-_cch); // Ensure tp is at cpMost
if(tp.IsAfterEOP() && // Don't delete EOP at sel
(NewChars == NEWCHARS || // end if there're chars to
(cpMin && !_rpTX.IsAfterEOP() && // add, or cpMin isn't at
cch > cchEOP))) // BOP and more than EOP
{ // is selected
_cch -= tp.BackupCpCRLF(); // Shorten range before EOP
// Note: the -= _adds_ to a
Update_iFormat(-1); // negative _cch to make
fRet = TRUE; // it less negative
}
if((_cch ^ cchSave) < 0 && _fSel) // Keep active end the same
FlipRange(); // selection undo
}
return fRet;
}
/*
* CTxtRange::CheckTextLength(cch)
*
* @mfunc
* Check to see if can add cch characters. If not, notify parent
*
* @rdesc
* TRUE if OK to add cch chars
*/
BOOL CTxtRange::CheckTextLength (
LONG cch)
{
TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::CheckTextLength");
_TEST_INVARIANT_
if((DWORD)(CalcTextLenNotInRange() + cch)
> GetPed()->TxGetMaxLength())
{
GetPed()->GetCallMgr()->SetMaxText();
return FALSE;
}
return TRUE;
}
/*
* CTxtRange::FindObject(pcpMin, pcpMost)
*
* @mfunc
* Set *pcpMin = closest embedded object cpMin <lt>= range cpMin
* Set *pcpMost = closest embedded object cpMost <gt>= range cpMost
*
* @rdesc
* TRUE iff object found
*
* @comm
* An embedded object cpMin points at the first character of an embedded
* object. For RichEdit, this is the WCH_EMBEDDING character. An
* embedded object cpMost follows the last character of an embedded
* object. For RichEdit, this immediately follows the WCH_EMBEDDING
* character.
*/
BOOL CTxtRange::FindObject(
LONG *pcpMin, //@parm Out parm to receive object's cpMin; NULL OK
LONG *pcpMost) const//@parm Out parm to receive object's cpMost; NULL OK
{
TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::FindObject");
if(!GetObjectCount()) // No objects: can't move, so
return FALSE; // return FALSE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -