📄 htricheditctrl.cpp
字号:
ReplaceSel(_T(""));
// delete 1st line
int iLine0Len = LineLength(0) + 2; // add NL character
SetSel(0, iLine0Len);
ReplaceSel(_T(""));
// update any possible available selection
iStartChar -= iLine0Len;
if (iStartChar < 0)
iStartChar = 0;
iEndChar -= iLine0Len;
if (iEndChar < 0)
iEndChar = 0;
// add the new line again
nPos = GetWindowTextLength();
AddString(nPos, pszLine, bLink, cr);
if (m_bEnErrSpace && nPos == 0){
// should never happen: if we tried to add the line another time in the 1st line, there
// will be no chance to add the line at all -> avoid endless loop!
break;
}
iSafetyCounter++; // never ever create an endless loop!
}
m_bNoPaint = bOldNoPaint;
if (bIsVisible && !m_bNoPaint){
SetRedraw();
if (m_bRichEdit)
Invalidate();
}
}
}
void CHTRichEditCtrl::Reset(){
m_astrBuff.RemoveAll();
SetRedraw(FALSE);
SetWindowText(_T(""));
SetRedraw();
if (m_bRichEdit)
Invalidate();
}
void CHTRichEditCtrl::OnContextMenu(CWnd* pWnd, CPoint point){
long iSelStart, iSelEnd;
GetSel(iSelStart, iSelEnd);
int iTextLen = GetWindowTextLength();
m_LogMenu.EnableMenuItem(MP_COPYSELECTED, iSelEnd > iSelStart ? MF_ENABLED : MF_GRAYED);
m_LogMenu.EnableMenuItem(MP_REMOVEALL, iTextLen > 0 ? MF_ENABLED : MF_GRAYED);
m_LogMenu.EnableMenuItem(MP_SELECTALL, iTextLen > 0 ? MF_ENABLED : MF_GRAYED);
m_LogMenu.EnableMenuItem(MP_SAVELOG, iTextLen > 0 ? MF_ENABLED : MF_GRAYED);
m_LogMenu.CheckMenuItem(MP_AUTOSCROLL, m_bAutoScroll ? MF_CHECKED : MF_UNCHECKED);
if (point.x == -1 && point.y == -1){
point.x = 16;
point.y = 32;
ClientToScreen(&point);
}
m_LogMenu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
}
BOOL CHTRichEditCtrl::OnCommand(WPARAM wParam, LPARAM lParam){
switch (wParam) {
case MP_COPYSELECTED:
CopySelectedItems();
break;
case MP_SELECTALL:
SelectAllItems();
break;
case MP_REMOVEALL:
Reset();
break;
case MP_SAVELOG:
SaveLog();
break;
case MP_AUTOSCROLL:
m_bAutoScroll = !m_bAutoScroll;
break;
}
return TRUE;
}
bool CHTRichEditCtrl::SaveLog(LPCTSTR pszDefName)
{
bool bResult = false;
CFileDialog dlg(FALSE, _T("log"), pszDefName ? pszDefName : (LPCTSTR)m_strTitle, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("Log Files (*.log)|*.log||"), this, 0);
if (dlg.DoModal() == IDOK)
{
FILE* fp = _tfsopen(dlg.GetPathName(), _T("wb"), _SH_DENYWR);
if (fp)
{
#ifdef _UNICODE
// write Unicode byte-order mark 0xFEFF
fputwc(0xFEFF, fp);
#endif
CString strText;
GetWindowText(strText);
fwrite(strText, sizeof(TCHAR), strText.GetLength(), fp);
if (ferror(fp)){
CString strError;
strError.Format(_T("Failed to write log file \"%s\" - %s"), dlg.GetPathName(), strerror(errno));
AfxMessageBox(strError, MB_ICONERROR);
}
else
bResult = true;
fclose(fp);
}
else{
CString strError;
strError.Format(_T("Failed to create log file \"%s\" - %s"), dlg.GetPathName(), strerror(errno));
AfxMessageBox(strError, MB_ICONERROR);
}
}
return bResult;
}
CString CHTRichEditCtrl::GetLastLogEntry(){
CString strLog;
int iLastLine = GetLineCount() - 2;
if (iLastLine >= 0){
GetLine(iLastLine, strLog.GetBuffer(1024), 1024);
strLog.ReleaseBuffer();
}
return strLog;
}
CString CHTRichEditCtrl::GetAllLogEntries(){
CString strLog;
GetWindowText(strLog);
return strLog;
}
void CHTRichEditCtrl::SelectAllItems()
{
SetSel(0, -1);
}
void CHTRichEditCtrl::CopySelectedItems()
{
Copy();
}
void CHTRichEditCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (nChar == 'A' && (GetKeyState(VK_CONTROL) & 0x8000))
{
//////////////////////////////////////////////////////////////////
// Ctrl+A: Select all items
SelectAllItems();
}
else if (nChar == 'C' && (GetKeyState(VK_CONTROL) & 0x8000))
{
//////////////////////////////////////////////////////////////////
// Ctrl+C: Copy listview items to clipboard
CopySelectedItems();
}
CRichEditCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
}
static const struct
{
LPCTSTR pszScheme;
int iLen;
} _apszSchemes[] =
{
{ _T("ed2k://"), 7 },
{ _T("http://"), 7 },
{ _T("https://"), 8 },
{ _T("ftp://"), 6 },
{ _T("www."), 4 },
{ _T("ftp."), 4 },
{ _T("mailto:"), 7 }
};
void CHTRichEditCtrl::AppendText(const CString& sText, bool bInvalidate)
{
LPCTSTR psz = sText;
LPCTSTR pszStart = psz;
while (*psz != _T('\0'))
{
bool bFoundScheme = false;
for (int i = 0; i < ARRSIZE(_apszSchemes); i++)
{
if (_tcsncmp(psz, _apszSchemes[i].pszScheme, _apszSchemes[i].iLen) == 0)
{
// output everything before the URL
if (psz - pszStart > 0){
CString str(pszStart, psz - pszStart);
AddLine(str, str.GetLength());
}
// search next space or EOL
int iLen = _tcscspn(psz, _T(" \n\r\t"));
if (iLen == 0){
AddLine(psz, -1, true);
psz += _tcslen(psz);
}
else{
CString str(psz, iLen);
AddLine(str, str.GetLength(), true);
psz += iLen;
}
pszStart = psz;
bFoundScheme = true;
break;
}
}
if (!bFoundScheme)
psz = _tcsinc(psz);
}
if (*pszStart != _T('\0'))
AddLine(pszStart, -1);
}
void CHTRichEditCtrl::AppendHyperLink(const CString& sText, const CString& sTitle, const CString& sCommand, const CString& sDirectory, bool bInvalidate)
{
ASSERT( sText.IsEmpty() );
ASSERT( sTitle.IsEmpty() );
ASSERT( sDirectory.IsEmpty() );
AddLine(sCommand, sCommand.GetLength(), true);
}
void CHTRichEditCtrl::AppendColoredText(LPCTSTR pszText, COLORREF cr)
{
AddLine(pszText, -1, false, cr);
}
void CHTRichEditCtrl::AppendKeyWord(const CString& str, COLORREF cr)
{
AppendColoredText(str, cr);
}
BOOL CHTRichEditCtrl::OnEnLink(NMHDR *pNMHDR, LRESULT *pResult)
{
BOOL bMsgHandled = FALSE;
*pResult = 0;
ENLINK* pEnLink = reinterpret_cast<ENLINK *>(pNMHDR);
if (pEnLink && pEnLink->msg == WM_LBUTTONDOWN)
{
CString strUrl;
GetTextRange(pEnLink->chrg.cpMin, pEnLink->chrg.cpMax, strUrl);
// check if that "URL" has a valid URL scheme. if it does not have, pass that notification up to the
// parent window which may interpret that "URL" in some other way.
for (int i = 0; i < ARRSIZE(_apszSchemes); i++){
if (_tcsncmp(strUrl, _apszSchemes[i].pszScheme, _apszSchemes[i].iLen) == 0){
ShellExecute(NULL, NULL, strUrl, NULL, NULL, SW_SHOWDEFAULT);
*pResult = 1;
bMsgHandled = TRUE; // do not route this message to any parent
break;
}
}
}
return bMsgHandled;
}
CString CHTRichEditCtrl::GetText() const
{
CString strText;
GetWindowText(strText);
return strText;
}
void CHTRichEditCtrl::SetFont(CFont* pFont, BOOL bRedraw)
{
LOGFONT lf = {0};
pFont->GetLogFont(&lf);
CHARFORMAT cf = {0};
cf.cbSize = sizeof cf;
cf.dwMask |= CFM_BOLD;
cf.dwEffects |= (lf.lfWeight == FW_BOLD) ? CFE_BOLD : 0;
cf.dwMask |= CFM_ITALIC;
cf.dwEffects |= (lf.lfItalic) ? CFE_ITALIC : 0;
cf.dwMask |= CFM_UNDERLINE;
cf.dwEffects |= (lf.lfUnderline) ? CFE_UNDERLINE : 0;
cf.dwMask |= CFM_STRIKEOUT;
cf.dwEffects |= (lf.lfStrikeOut) ? CFE_STRIKEOUT : 0;
cf.dwMask |= CFM_SIZE;
HDC hDC = ::GetDC(NULL);
int iPointSize = -MulDiv(lf.lfHeight, 72, GetDeviceCaps(hDC, LOGPIXELSY));
cf.yHeight = iPointSize * 20;
::ReleaseDC(NULL, hDC);
cf.dwMask |= CFM_FACE;
cf.bPitchAndFamily = lf.lfPitchAndFamily;
_tcsncpy(cf.szFaceName, lf.lfFaceName, ARRSIZE(cf.szFaceName));
cf.szFaceName[ARRSIZE(cf.szFaceName) - 1] = _T('\0');
// although this should work correctly (according SDK) it may give false results (e.g. the "click here..." text
// which is shown in the server info window may not be entirely used as a hyperlink???)
// cf.dwMask |= CFM_CHARSET;
// cf.bCharSet = lf.lfCharSet;
cf.yOffset = 0;
VERIFY( SetDefaultCharFormat(cf) );
VERIFY( GetSelectionCharFormat(m_cfDefault) );
if (bRedraw){
Invalidate();
UpdateWindow();
}
}
CFont* CHTRichEditCtrl::GetFont() const
{
ASSERT(0);
return NULL;
}
void CHTRichEditCtrl::OnSysColorChange()
{
CRichEditCtrl::OnSysColorChange();
ApplySkin();
}
void CHTRichEditCtrl::ApplySkin()
{
if (!m_strSkinKey.IsEmpty())
{
COLORREF cr;
if (theApp.LoadSkinColor(m_strSkinKey + _T("Bk"), cr))
{
SetBackgroundColor(FALSE, cr);
}
else
{
SetBackgroundColor(TRUE, GetSysColor(COLOR_WINDOW));
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -