urlricheditctrl.cpp
来自「管理项目进度工具的原代码」· C++ 代码 · 共 1,009 行 · 第 1/2 页
CPP
1,009 行
CPoint CUrlRichEditCtrl::GetCaretPos()
{
if (GetFocus() != this)
{
ASSERT (0);
return CPoint(0, 0);
}
CPoint ptCaret = CWnd::GetCaretPos();
ptCaret.y += GetLineHeight() / 2; // half line height
ptCaret.x += 4; // estaimate 1/2 char width
return ptCaret;
}
BOOL CUrlRichEditCtrl::GoToUrl(int nUrl) const
{
if (nUrl < 0 || nUrl >= m_aUrls.GetSize())
return FALSE;
const URLITEM& urli = m_aUrls[nUrl];
if (!urli.bWantNotify)
{
CString sUrl = GetUrl(nUrl, TRUE);
if (FileMisc::Run(*this, sUrl) > 32)
return TRUE;
// else
if (!s_sGotoErrMsg.IsEmpty())
AfxMessageBox(s_sGotoErrMsg, MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// else
SendNotifyCustomUrl(urli.sUrl);
return TRUE;
}
BOOL CUrlRichEditCtrl::GoToUrl(const CString& sUrl) const
{
int nUrl = m_aUrls.GetSize();
while (nUrl--)
{
const URLITEM& urli = m_aUrls[nUrl];
if (urli.sUrl.CompareNoCase(sUrl) == 0)
return GoToUrl(nUrl);
}
// didn't match then it might be a file
if (GetFileAttributes(sUrl) != 0xffffffff)
{
if (FileMisc::Run(*this, sUrl) > 32)
return TRUE;
// else
if (!s_sGotoErrMsg.IsEmpty())
AfxMessageBox(s_sGotoErrMsg, MB_OK | MB_ICONEXCLAMATION);
}
return FALSE;
}
LRESULT CUrlRichEditCtrl::SendNotifyCustomUrl(LPCTSTR szUrl) const
{
return GetParent()->SendMessage(WM_UREN_CUSTOMURL, GetDlgCtrlID(), (LPARAM)szUrl);
}
/////////////////////////////////////////////////////////////////////////////
// CUrlRichEditCtrl
HRESULT CUrlRichEditCtrl::QueryAcceptData(LPDATAOBJECT lpdataobj, CLIPFORMAT* lpcfFormat,
DWORD /*reco*/, BOOL /*fReally*/, HGLOBAL /*hMetaPict*/)
{
BOOL bEnable = !(GetStyle() & ES_READONLY) && IsWindowEnabled();
if (bEnable)
{
*lpcfFormat = GetAcceptableClipFormat(lpdataobj, *lpcfFormat);
return S_OK;
}
// else
return E_FAIL;
}
CLIPFORMAT CUrlRichEditCtrl::GetAcceptableClipFormat(LPDATAOBJECT lpDataOb, CLIPFORMAT format)
{
CLIPFORMAT formats[] =
{
CF_HDROP,
CF_TEXT,
};
const long nNumFmts = sizeof(formats) / sizeof(CLIPFORMAT);
COleDataObject dataobj;
dataobj.Attach(lpDataOb, FALSE);
for (int nFmt = 0; nFmt < nNumFmts; nFmt++)
{
if (format && format == formats[nFmt])
return format;
if (dataobj.IsDataAvailable(formats[nFmt]))
return formats[nFmt];
}
return CF_TEXT;
}
HRESULT CUrlRichEditCtrl::GetDragDropEffect(BOOL fDrag, DWORD grfKeyState, LPDWORD pdwEffect)
{
if (!fDrag) // allowable dest effects
{
BOOL bEnable = !(GetStyle() & ES_READONLY) && IsWindowEnabled();
if (!bEnable)
*pdwEffect = DROPEFFECT_NONE;
else
{
DWORD dwEffect = DROPEFFECT_NONE;
BOOL bFileDrop = ((*pdwEffect & DROPEFFECT_LINK) == DROPEFFECT_LINK);
// we can deduce (I think) that what's being dragged is a file
// by whether pdwEffect include the LINK effect.
// if so save off the current selection pos (for now) because it gets reset
// when the files are dropped
if (bFileDrop)
{
dwEffect = DROPEFFECT_MOVE;
// keep track of cursor
TrackDragCursor();
}
else // it's text
{
if ((grfKeyState & MK_CONTROL) == MK_CONTROL)
dwEffect = DROPEFFECT_COPY;
else // if ((grfKeyState & MK_SHIFT) == MK_SHIFT)
dwEffect = DROPEFFECT_MOVE;
}
if (dwEffect & *pdwEffect) // make sure allowed type
*pdwEffect = dwEffect;
}
}
return S_OK;
}
void CUrlRichEditCtrl::TrackDragCursor()
{
// also track the cursor for the drop position
CPoint ptCursor(::GetMessagePos());
ScreenToClient(&ptCursor);
int nChar = CharFromPoint(ptCursor);
m_crDropSel.cpMin = m_crDropSel.cpMax = nChar;
SetFocus();
SetSel(m_crDropSel);
ShowCaret();
}
HRESULT CUrlRichEditCtrl::GetContextMenu(WORD /*seltype*/, LPOLEOBJECT /*lpoleobj*/,
CHARRANGE* /*lpchrg*/, HMENU* /*lphmenu*/)
{
CPoint point = m_ptContextMenu;
// send on as a simple context menu message
SendMessage(WM_CONTEXTMENU, (WPARAM)GetSafeHwnd(), MAKELPARAM(point.x, point.y));
return E_NOTIMPL;
}
/////////////////////////////////////////////////////////////////////////////
void CUrlRichEditCtrl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CRichEditBaseCtrl::OnChar(nChar, nRepCnt, nFlags);
}
CString CUrlRichEditCtrl::GetUrl(int nURL, BOOL bAsFile) const
{
ASSERT (nURL >= 0 && nURL < m_aUrls.GetSize());
if (nURL >= 0 && nURL < m_aUrls.GetSize())
{
CString sUrl(m_aUrls[nURL].sUrl);
CString sUrlLower(sUrl);
sUrlLower.MakeLower();
if (!bAsFile || sUrlLower.Find(FILEPREFIX) == -1)
return sUrl;
else
{
sUrl = sUrl.Mid(sUrlLower.Find(FILEPREFIX) + lstrlen(FILEPREFIX));
sUrl.Replace("%20", " ");
sUrl.Replace('/', '\\');
}
return sUrl;
}
// else
return "";
}
void CUrlRichEditCtrl::PathReplaceSel(LPCTSTR lpszPath, BOOL bFile)
{
CString sPath(lpszPath);
if (bFile || sPath.Find(":\\") != -1 || sPath.Find("\\\\") != -1)
{
sPath = FILEPREFIX + sPath;
sPath.Replace(" ", "%20");
sPath.Replace('\\', '/');
}
// add space fore and aft depending on selection
CHARRANGE crSel, crSelOrg;
GetSel(crSelOrg); // save this off
GetSel(crSel);
// enlarge to include end items
if (crSel.cpMin > 0)
crSel.cpMin--;
if (crSel.cpMax < GetTextLength() - 1)
crSel.cpMax++;
SetSel(crSel);
CString sSelText = GetSelText();
SetSel(crSelOrg);
// test
if (!sSelText.IsEmpty())
{
if (!isspace(sSelText[0]))
sPath = ' ' + sPath;
if (!isspace(sSelText[sSelText.GetLength() - 1]))
sPath += ' ';
}
ReplaceSel(sPath, TRUE);
ParseAndFormatText();
// set the new selection to be the dropped text
SetSel(crSelOrg.cpMin, crSelOrg.cpMin + sPath.GetLength());
SetFocus();
}
void CUrlRichEditCtrl::OnRButtonUp(UINT nHitTest, CPoint point)
{
m_ptContextMenu = point;
ClientToScreen(&m_ptContextMenu);
CRichEditBaseCtrl::OnRButtonUp(nHitTest, point);
}
void CUrlRichEditCtrl::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (nChar == VK_APPS)
{
m_ptContextMenu = GetCaretPos();
// does this location lie on a url?
m_nContextUrl = FindUrl(m_ptContextMenu);
// convert point to screen coords
ClientToScreen(&m_ptContextMenu);
}
CRichEditBaseCtrl::OnKeyUp(nChar, nRepCnt, nFlags);
}
void CUrlRichEditCtrl::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (nChar == VK_F10 && (::GetKeyState(VK_SHIFT) & 0x8000))
{
m_ptContextMenu = GetCaretPos();
// does this location lie on a url?
m_nContextUrl = FindUrl(m_ptContextMenu);
// convert point to screen coords
ClientToScreen(&m_ptContextMenu);
// eat message else we'll get a WM_KEYUP with VK_APPS
}
CRichEditBaseCtrl::OnSysKeyDown(nChar, nRepCnt, nFlags);
}
void CUrlRichEditCtrl::OnRButtonDown(UINT nFlags, CPoint point)
{
m_nContextUrl = -1;
// move the caret to the pos clicked
int nChar = CharFromPoint(point);
if (nChar >= 0)
{
// don't reset the selection if the character
// falls within the current selection
CHARRANGE crSel;
GetSel(crSel);
if (nChar < crSel.cpMin || nChar > crSel.cpMax)
SetSel(nChar, nChar);
}
CRichEditBaseCtrl::OnRButtonDown(nFlags, point);
}
void CUrlRichEditCtrl::OnShowWindow(BOOL bShow, UINT nStatus)
{
CRichEditBaseCtrl::OnShowWindow(bShow, nStatus);
// TODO: Add your message handler code here
}
int CUrlRichEditCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CRichEditBaseCtrl::OnCreate(lpCreateStruct) == -1)
return -1;
SetEventMask(GetEventMask() | ENM_CHANGE | ENM_DROPFILES | ENM_DRAGDROPDONE | ENM_LINK);
DragAcceptFiles();
// enable multilevel undo
SendMessage(EM_SETTEXTMODE, TM_MULTILEVELUNDO);
m_ncBorder.Initialize(GetSafeHwnd());
return 0;
}
void CUrlRichEditCtrl::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
{
// if we arrived here then it means that noone had derived
// from us and handled OnContextMenu. sow e must forward to
// our parent else we'll end up in a recursive loop
GetParent()->SendMessage(WM_CONTEXTMENU, (WPARAM)GetSafeHwnd(), MAKELPARAM(point.x, point.y));
}
BOOL CUrlRichEditCtrl::OnNotifyLink(NMHDR* pNMHDR, LRESULT* pResult)
{
BOOL bCtrl = (GetKeyState(VK_CONTROL) & 0x8000);
ENLINK* pENL = (ENLINK*)pNMHDR;
switch (pENL->msg)
{
case WM_SETCURSOR:
if (!bCtrl)
{
// because we're overriding the default behaviour we need to
// handle the cursor being over a selected block
CHARRANGE crSel;
GetSel(crSel);
CPoint ptCursor(GetMessagePos());
ScreenToClient(&ptCursor);
LPCTSTR nCursor = IDC_ARROW;
int nChar = CharFromPoint(ptCursor);
if (nChar < crSel.cpMin || nChar > crSel.cpMax)
nCursor = IDC_IBEAM;
SetCursor(AfxGetApp()->LoadStandardCursor(nCursor));
*pResult = TRUE;
return TRUE;
}
break;
case WM_LBUTTONUP:
if (bCtrl)
{
if (GoToUrl(FindUrl(pENL->chrg)))
return TRUE;
}
case WM_RBUTTONUP:
m_nContextUrl = FindUrl(pENL->chrg);
break;
}
return FALSE;
}
int CUrlRichEditCtrl::FindUrl(const CHARRANGE& cr)
{
int nUrl = m_aUrls.GetSize();
while (nUrl--)
{
const URLITEM& urli = m_aUrls[nUrl];
if (urli.cr.cpMax == cr.cpMax && urli.cr.cpMin == cr.cpMin)
return nUrl;
}
// not found
return -1;
}
int CUrlRichEditCtrl::FindUrl(const CPoint& point)
{
int nPos = CharFromPoint(point);
int nUrl = m_aUrls.GetSize();
while (nUrl--)
{
const URLITEM& urli = m_aUrls[nUrl];
if (urli.cr.cpMax >= nPos && urli.cr.cpMin < nPos)
return nUrl;
}
// not found
return -1;
}
int CUrlRichEditCtrl::FindUrlEx(const CPoint& point)
{
int nUrl = m_aUrls.GetSize();
while (nUrl--)
{
const URLITEM& urli = m_aUrls[nUrl];
CRect rUrl(GetCharPos(urli.cr.cpMin), GetCharPos(urli.cr.cpMax));
rUrl.bottom += GetLineHeight();
// if (urli.cr.cpMax >= nPos && urli.cr.cpMin < nPos)
// return nUrl;
if (rUrl.PtInRect(point))
return nUrl;
}
// not found
return -1;
}
BOOL CUrlRichEditCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
return CRichEditHelper::CreateRichEdit20(*this, dwStyle, rect, pParentWnd, nID);
}
void CUrlRichEditCtrl::OnTimer(UINT nIDEvent)
{
// if we've arrived here then it means that the user
// has paused for long enough to reparse the latest changes
if (nIDEvent == TIMER_REPARSE)
{
KillTimer(TIMER_REPARSE);
ParseAndFormatText();
}
CRichEditBaseCtrl::OnTimer(nIDEvent);
}
int CUrlRichEditCtrl::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
{
int nHit = MAKELONG(point.x, point.y);
pTI->hwnd = m_hWnd;
pTI->uId = nHit;
pTI->rect = CRect(CPoint(point.x-1,point.y-1),CSize(2,2));
pTI->uFlags |= TTF_NOTBUTTON | TTF_ALWAYSTIP;
pTI->lpszText = LPSTR_TEXTCALLBACK;
return nHit;
}
void CUrlRichEditCtrl::OnNeedTooltip(UINT /*id*/, NMHDR* pNMHDR, LRESULT* pResult)
{
*pResult = 0;
TOOLTIPTEXT* pTTT = (TOOLTIPTEXT*)pNMHDR;
CPoint point(GetMessagePos());
ScreenToClient(&point);
if (FindUrlEx(point) != -1)
strcpy(pTTT->szText, "Ctrl+Click to open url");
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?