📄 edit.cpp
字号:
if( ((mode & (TM_RICHTEXT | TM_PLAINTEXT)) ==
(TM_RICHTEXT | TM_PLAINTEXT)) ||
((mode & (TM_SINGLELEVELUNDO | TM_MULTILEVELUNDO)) ==
(TM_SINGLELEVELUNDO | TM_MULTILEVELUNDO) ) ||
((mode & (TM_SINGLECODEPAGE | TM_MULTICODEPAGE)) ==
(TM_SINGLECODEPAGE | TM_MULTICODEPAGE)) )
{
lres = E_INVALIDARG;
}
else if( (mode & TM_PLAINTEXT) && IsRich())
{
lres = OnRichEditChange(FALSE);
}
else if( (mode & TM_RICHTEXT) && !IsRich())
{
lres = OnRichEditChange(TRUE);
}
if( lres == 0 )
{
if( (mode & TM_SINGLELEVELUNDO) )
{
if( !_pundo )
{
CreateUndoMgr(1, US_UNDO);
}
if( _pundo )
{
// we can 'Enable' single level mode as many times
// as we want, so no need to check for it before hand.
lres = ((CUndoStack *)_pundo)->EnableSingleLevelMode();
}
else
{
lres = E_OUTOFMEMORY;
}
}
else if( (mode & TM_MULTILEVELUNDO) )
{
// if there's no undo stack, no need to do anything,
// we're already in multi-level mode
if( _pundo && ((CUndoStack *)_pundo)->GetSingleLevelMode())
{
((CUndoStack *)_pundo)->DisableSingleLevelMode();
}
}
if( (mode & TM_SINGLECODEPAGE) )
{
_fSingleCodePage = TRUE;
}
else if( (mode & TM_MULTICODEPAGE) )
{
_fSingleCodePage = FALSE;
}
}
// We don't want this marked modified after this operation to make us
// work better in dialog boxes.
_fModified = FALSE;
return lres;
}
////////////////////////// Notification Manager //////////////////////////////
/*
* CTxtEdit::GetNotifyMgr()
*
* @mfunc
* returns a pointer to the notification manager (creating it if necessary)
*
* @rdesc
* Ptr to notification manager
*/
CNotifyMgr *CTxtEdit::GetNotifyMgr()
{
TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "CTxtEdit::GetNotifyMgr");
return &_nm;
}
////////////////////////// Object Manager ///////////////////////////////////
/*
* CTxtEdit::GetObjectMgr()
*
* @mfunc
* returns a pointer to the object manager (creating if necessary )
*
* @rdesc
* pointer to the object manager
*/
CObjectMgr *CTxtEdit::GetObjectMgr()
{
TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "CTxtEdit::GetObjectMgr");
if( !_pobjmgr )
{
_pobjmgr = new CObjectMgr();
}
return _pobjmgr;
}
////////////////////////////// Properties - Selection ////////////////////////////////
LONG CTxtEdit::GetSelMin() const
{
TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "CTxtEdit::GetSelMin");
return _psel ? _psel->GetCpMin() : 0;
}
LONG CTxtEdit::GetSelMost() const
{
TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "CTxtEdit::GetSelMost");
return _psel ? _psel->GetCpMost() : 0;
}
////////////////////////////// Properties - Text //////////////////////////////////////
LONG CTxtEdit::GetTextRange(LONG cpFirst, LONG cch, TCHAR *pch)
{
TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "CTxtEdit::GetTextRange");
#ifdef DEBUG
const LONG cchAsk = cch;
#endif
CTxtPtr tp(this, cpFirst);
LONG length = (LONG)GetAdjustedTextLength();
if(--cch < 0 || cpFirst > length)
return 0;
cch = min(cch, length - cpFirst);
if(cch > 0)
{
cch = tp.GetText(cch, pch);
Assert(cch >= 0);
}
pch[cch] = TEXT('\0');
#ifdef DEBUG
if(cch != cchAsk - 1)
Tracef(TRCSEVINFO, "CmdGetText(): only got %ld out of %ld", cch, cchAsk - 1);
#endif
return cch;
}
/*
* CTxtEdit::GetTextEx
*
* @mfunc grabs text according to various params
*
* @rdesc the number of bytes written
*/
LONG CTxtEdit::GetTextEx(
GETTEXTEX *pgt, //@parm info on what to get
TCHAR *pch) //@parm where to put the text
{
CTxtPtr tp(this, 0);
CTempWcharBuf twcb;
TCHAR *pchUse = pch;
LONG cch, cb;
LONG cchGet = GetAdjustedTextLength();
// allocate a big buffer; make sure that we have
// enough room for lots of CRLFs if necessary
if( (pgt->flags & GT_USECRLF) )
{
cchGet *= 2;
}
if( pgt->codepage != 1200 )
{
// if UNICODE, copy straight to clients buffer;
// else, copy to temp buffer and translate cases first
pchUse = twcb.GetBuf(cchGet + 1);
}
else
{
// be sure to leave room for the NULL terminator.
cchGet = min(((pgt->cb/2) -1), (DWORD)cchGet);
}
// now grab the text.
if( (pgt->flags & GT_USECRLF) )
{
cch = tp.GetPlainText(cchGet, pchUse, tomForward, FALSE);
}
else
{
cch = tp.GetText(cchGet, pchUse);
}
pchUse[cch] = L'\0';
// if we're just doing UNICODE, return the number of chars written.
if( pgt->codepage == 1200 )
{
return cch;
}
// oops, gotta translate to ANSI.
cb = WideCharToMultiByte(pgt->codepage, 0, pchUse, cch + 1, (char *)pch,
pgt->cb, pgt->lpDefaultChar, pgt->lpUsedDefChar);
// don't count the NULL terminator for compatibility with WM_GETTEXT.
return (cb) ? cb - 1 : 0;
}
/*
* CTxtEdit::GetTextLengthEx
*
* @mfunc calculates the length of the text in various ways.
*
* @rdesc varies by the input parameter
*/
LONG CTxtEdit::GetTextLengthEx(
GETTEXTLENGTHEX *pgtl) //@parm info describing how to calculate the
// length
{
LONG cchUnicode = GetAdjustedTextLength();
GETTEXTEX gt;
// make sure the flags are definied appropriately.
if( ((pgtl->flags & GTL_CLOSE) && (pgtl->flags & GTL_PRECISE)) ||
((pgtl->flags & GTL_NUMCHARS) && (pgtl->flags & GTL_NUMBYTES)) )
{
TRACEWARNSZ("Invalid flags for EM_GETTEXTLENGTHEX");
return E_INVALIDARG;
}
if( (pgtl->flags & GTL_USECRLF) )
{
CTxtPtr tp(this, 0);
DWORD numEOP = 0;
while( tp.FindEOP(tomForward) )
{
numEOP++;
}
// take of the default EOD, if it exists. Note
// that in plain text, we may _think_ that there is
// an EOP at the end when there really isn't.
if( IsRich() || (numEOP && !tp.IsAfterEOP()))
{
Assert(numEOP);
numEOP--;
}
cchUnicode += numEOP;
}
// if we're just looking for the number of characters, we've got it.
if( (pgtl->flags & GTL_NUMCHARS) || !pgtl->flags )
{
return cchUnicode;
}
// hmm, they're looking for number of bytes, but don't care about
// precision, just multiply by two. If neither PRECISE or CLOSE is
// specified, default to CLOSE.
// Note if we're UNICODE and asking for number of bytes, we also
// just multiply by 2.
if( (pgtl->flags & GTL_CLOSE) || !(pgtl->flags & GTL_PRECISE) ||
pgtl->codepage == 1200 )
{
return cchUnicode *2;
}
// in order to get a precise answer, we're going to need to convert.
gt.cb = 0;
gt.flags = (pgtl->flags & GT_USECRLF);
gt.codepage = pgtl->codepage;
gt.lpDefaultChar = NULL;
gt.lpUsedDefChar = NULL;
return GetTextEx(>, NULL);
}
////////////////////////////// Properties - Formats //////////////////////////////////
const CCharFormat* CTxtEdit::GetCharFormat(LONG iCF)
{
TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "CTxtEdit::GetCharFormat");
const CCharFormat * pCF;
ICharFormatCache * pICache;
if(iCF < 0)
iCF = _iCF;
Assert(iCF >= 0);
if (FAILED(GetCharFormatCache(&pICache)) ||
FAILED(pICache->Deref(iCF, &pCF)))
{
AssertSz(FALSE, "CTxtEdit::GetCharFormat: couldn't deref iCF");
pCF = NULL;
}
return pCF;
}
const CParaFormat* CTxtEdit::GetParaFormat(LONG iPF)
{
TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "CTxtEdit::GetParaFormat");
IParaFormatCache * pICache;
const CParaFormat * pPF;
if(iPF < 0)
iPF = _iPF;
Assert(iPF >= 0);
if (FAILED(GetParaFormatCache(&pICache)) ||
FAILED(pICache->Deref(iPF, &pPF)))
{
AssertSz(FALSE, "CTxtEdit::GetParaFormat: couldn't deref iPF");
pPF = NULL;
}
return pPF;
}
/*
* CTxtEdit::HandleStyle (pCFTarget, pCF)
*
* @mfunc
* If pCF specifies a style choice, initialize pCFTarget with the
* appropriate style, apply pCF, and return NOERROR. Else return
* S_FALSE or an error
*
* @rdesc
* HRESULT = (pCF specifies a style choice) ? NOERROR : S_FALSE or error code
*/
HRESULT CTxtEdit::HandleStyle(
CCharFormat *pCFTarget, //@parm Target CF to receive CF style content
const CCharFormat *pCF) //@parm Source CF that may specify a style
{
if(pCF->fSetStyle())
{
// FUTURE: generalize to use client style if specified
pCFTarget->Set(GetCharFormat(-1));
pCFTarget->cbSize = sizeof(CHARFORMAT2);
pCFTarget->ApplyDefaultStyle(pCF->sStyle);
return pCFTarget->Apply(pCF, fInOurHost());
}
return S_FALSE;
}
/*
* CTxtEdit::HandleStyle (pPFTarget, pPF)
*
* @mfunc
* If pPF specifies a style choice, initialize pPFTarget with the
* appropriate style, apply pPF, and return NOERROR. Else return
* S_FALSE or an error
*
* @rdesc
* HRESULT = (pPF specifies a style choice) ? NOERROR : S_FALSE or error code
*/
HRESULT CTxtEdit::HandleStyle(
CParaFormat *pPFTarget, //@parm Target PF to receive PF style content
const CParaFormat *pPF) //@parm Source PF that may specify a style
{
if(pPF->fSetStyle())
{
// FUTURE: generalize to use client style if specified
pPFTarget->Set(GetParaFormat(-1));
pPFTarget->cbSize = sizeof(PARAFORMAT2);
pPFTarget->ApplyDefaultStyle(pPF->sStyle);
return pPFTarget->Apply(pPF);
}
return S_FALSE;
}
//////////////////////////// Mouse Commands /////////////////////////////////
HRESULT CTxtEdit::OnTxLButtonDblClk(
INT x,
INT y,
#ifdef PWD_JUPITER // GuyBark 81387: Allow undo of expand/collapse operation
DWORD dwFlags, IUndoBuilder *publdr)
#else
DWORD dwFlags)
#endif // PWD_JUPITER
{
TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "CTxtEdit::OnTxLButtonDblClk");
BOOL fEnterParaSelMode = FALSE;
HITTEST Hit;
CTxtSelection * psel = GetSel();
const POINT pt = {x, y};
AssertSz(psel, "CTxtEdit::OnLeftDblClick() - No selection object !");
_dwTickDblClick = GetTickCount();
_ptDblClick.x = x;
_ptDblClick.y = y;
TxUpdateWindow(); // Repaint window to show any exposed portions
if(!_fFocus)
{
TxSetFocus(); // Create and display caret
return S_OK;
}
// Find out what the cursor is pointing at
_pdp->CpFromPoint(pt, NULL, NULL, NULL, FALSE, &Hit);
if(Hit == HT_Nothing)
return S_OK;
if(Hit == HT_OutlineSymbol)
{
CTxtRange rg(*psel);
#ifdef PWD_JUPITER // GuyBark 81387: Allow undo of expand/collapse operation
rg.ExpandOutline(0, FALSE, publdr);
#else
rg.ExpandOutline(0, FALSE);
#endif // PWD_JUPITER
return S_OK;
}
if(Hit == HT_SelectionBar || Hit == HT_LeftOfText)
fEnterParaSelMode = TRUE;
_fWantDrag = FALSE; // just to be safe
// if we are over a link, let the client have a chance to process
// the message
if(Hit == HT_Link && HandleLinkNotification(WM_LBUTTONDBLCLK, (WPARAM)dwFlags,
MAKELPARAM(x, y)) )
{
return S_OK;
}
if(dwFlags & MK_CONTROL)
return S_OK;
// Mark mouse down
_fMouseDown = TRUE;
if( _pobjmgr )
{
if( _pobjmgr->HandleDoubleClick(this, pt, dwFlags) == TRUE )
{
// the object subsystem handled everything
_fMouseDown = FALSE;
return S_OK;
}
}
// Now update the selection
if(fEnterParaSelMode)
psel->SelectUnit(pt, tomParagraph);
else
psel->SelectWord(pt);
return S_OK;
}
HRESULT CTxtEdit::OnTxLButtonDown(
INT x,
INT y,
DWORD dwFlags)
{
TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "CTxtEdit::OnTxLButtonDown");
BOOL fEnterLineSelMode = FALSE;
BOOL fShift = dwFlags & MK_SHIFT;
HITTEST Hit;
const POINT pt = {x, y};
COleObject *pobj;
BOOL fMustThaw = FALSE;
const BOOL fTripleClick = GetTickCount() < _dwTickDblClick + sysparam.GetDCT() &&
abs(x - _ptDblClick.x) <= sysparam.GetCxDoubleClk() &&
abs(y - _ptDblClick.y) <= sysparam.GetCyDoubleClk();
// Terminate composition for Korea
if(IsIMEComposition())
if(_ime->IsKoreanMode())
_ime->TerminateIMEComposition(*this, CIme::TERMINATE_NORMAL );
// If click isn't inside view, just activate, don't select
if(!_fFocus) // Sets focus if not already
{
// We may be removing an existing selection, so freeze
// the display to avoid flicker
_pdp->Freeze();
fMustThaw = TRUE;
TxSetFocus(); // creates and displays caret
}
// Grab selection object
CTxtSelection * const psel = GetSel();
AssertSz(psel,"CTxtEdit::OnLeftUp() - No selection object !");
// Find out what the cursor is pointing at
_pdp->CpFromPoint(pt, NULL, NULL, NULL, FALSE, &Hit);
if(Hit == HT_SelectionBar || Hit == HT_LeftOfText)
{
// shift click in sel bar treated as normal click
if(!fShift)
{
// control selbar click and triple selbar click
// are select all
if((dwFlags & MK_CONTROL) || fTripleClick)
{
psel->SelectAll();
goto cancel_modes;
}
fEnterLineSelMode = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -