You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

561 lines
12 KiB
C++

// XTPHyperLink.cpp : implementation of the CXTPHyperLink class.
//
// This file is a part of the XTREME CONTROLS MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Common/Resource.h"
#include "../Resource.h"
#include "Common/XTPResourceManager.h"
#include "Common/XTPColorManager.h"
#include "Common/XTPDrawHelpers.h"
#include "XTPHyperLink.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CXTPHyperLink
/////////////////////////////////////////////////////////////////////////////
#ifndef IDC_HAND
#define IDC_HAND MAKEINTRESOURCE(32649)
#endif
CXTPHyperLink::CXTPHyperLink()
{
// try to load the system hand cursor.
m_hcurHand = AfxGetApp()->LoadStandardCursor(IDC_HAND);
// if not found, use the toolkit version
if (m_hcurHand == NULL)
m_hcurHand = XTPResourceManager()->LoadCursor(XTP_IDC_HAND);
m_clrBack = COLORREF_NULL;
m_clrLink = RGB(0x00, 0x00, 0xFF); // blue
m_clrHover = RGB(0xFF, 0x00, 0x00); // red
m_clrVisited = RGB(0x80, 0x00, 0x80); // dark purple
m_bUnderline = true;
m_bMouseOver = false;
m_bVisited = false;
m_bPreSubclassInit = true;
m_bShellExec = true;
m_bTipEnabled = true;
}
CXTPHyperLink::~CXTPHyperLink()
{
}
IMPLEMENT_DYNAMIC(CXTPHyperLink, CStatic)
BEGIN_MESSAGE_MAP(CXTPHyperLink, CStatic)
//{{AFX_MSG_MAP(CXTPHyperLink)
ON_WM_SETCURSOR()
ON_WM_CREATE()
ON_WM_CTLCOLOR_REFLECT()
ON_WM_MOUSEMOVE()
ON_WM_TIMER()
ON_WM_ERASEBKGND()
ON_WM_PAINT()
ON_WM_WINDOWPOSCHANGED()
//}}AFX_MSG_MAP
ON_WM_NCHITTEST_EX()
ON_CONTROL_REFLECT_EX(STN_CLICKED, OnClicked)
ON_WM_SETFOCUS()
ON_WM_KILLFOCUS()
ON_WM_KEYDOWN()
ON_WM_GETDLGCODE()
END_MESSAGE_MAP()
BOOL CXTPHyperLink::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
// if the hand cursor is not NULL and the mouse is over text,
// set the hand cursor.
if (m_hcurHand && IsLinkHot())
{
::SetCursor(m_hcurHand);
return TRUE;
}
return CStatic::OnSetCursor(pWnd, nHitTest, message);
}
LRESULT CXTPHyperLink::OnNcHitTest(CPoint /*point*/)
{
return (LRESULT)HTCLIENT;
}
BOOL CXTPHyperLink::CreateFont(CFont& font, BOOL bUnderline)
{
// use the control's font.
if (::IsWindow(m_hWnd))
{
CFont* pFont = GetFont();
if (pFont->GetSafeHandle())
{
LOGFONT lf = {0};
pFont->GetLogFont(&lf);
lf.lfUnderline = (BYTE)bUnderline;
font.DeleteObject();
return (font.CreateFontIndirect(&lf));
}
}
// use system font.
LOGFONT lf;
CXTPDrawHelpers::GetIconLogFont(&lf);
lf.lfUnderline = (BYTE)bUnderline;
font.DeleteObject();
return (font.CreateFontIndirect(&lf));
}
bool CXTPHyperLink::InitFont()
{
if (!CreateFont(m_font, m_bUnderline))
return false;
if (::IsWindow(m_hWnd))
{
SetFont(&m_font);
RedrawWindow();
return true;
}
return false;
}
void CXTPHyperLink::SetURL(LPCTSTR lpszLink)
{
m_strLink = lpszLink;
if (m_strTipText.IsEmpty())
{
m_strTipText = m_strLink;
}
if (!m_strTipText.IsEmpty())
{
if (!::IsWindow(m_toolTip.m_hWnd))
{
m_toolTip.Create(this);
m_toolTip.AddTool(this, m_strTipText);
m_toolTip.Activate(m_bTipEnabled);
}
else
{
m_toolTip.UpdateTipText(m_strLink, this);
}
}
}
bool CXTPHyperLink::Init()
{
if (::IsWindow(m_hWnd))
{
// only use the window text if this is a text link and
// the URL has not already been initialized first.
if (IsTextControl())
{
if (m_strLink.IsEmpty())
{
GetWindowText(m_strLink);
}
SetURL(m_strLink);
}
ModifyStyle(NULL, SS_NOTIFY);
return InitFont();
}
return false;
}
void CXTPHyperLink::PreSubclassWindow()
{
CStatic::PreSubclassWindow();
if (m_bPreSubclassInit)
{
// Initialize the control.
Init();
}
}
int CXTPHyperLink::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CStatic::OnCreate(lpCreateStruct) == -1)
return -1;
// Initialize the control.
Init();
return 0;
}
BOOL CXTPHyperLink::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CStatic::PreCreateWindow(cs))
return FALSE;
// When creating controls dynamically Init() must
// be called from OnCreate() and not from
// PreSubclassWindow().
m_bPreSubclassInit = false;
return TRUE;
}
void CXTPHyperLink::ReportError(int iErrorNo)
{
CString strMessage;
switch (iErrorNo)
{
case 0: XTPResourceManager()->LoadString(&strMessage, XTP_IDS_SE_0); break;
case SE_ERR_FNF: XTPResourceManager()->LoadString(&strMessage, XTP_IDS_SE_ERR_FNF); break;
case SE_ERR_PNF: XTPResourceManager()->LoadString(&strMessage, XTP_IDS_SE_ERR_PNF); break;
case SE_ERR_ACCESSDENIED: XTPResourceManager()->LoadString(&strMessage, XTP_IDS_SE_ERR_ACCESSDENIED); break;
case SE_ERR_OOM: XTPResourceManager()->LoadString(&strMessage, XTP_IDS_SE_ERR_OOM); break;
case ERROR_BAD_FORMAT: XTPResourceManager()->LoadString(&strMessage, XTP_IDS_SE_ERR_BAD_FORMAT); break;
case SE_ERR_SHARE: XTPResourceManager()->LoadString(&strMessage, XTP_IDS_SE_ERR_SHARE); break;
case SE_ERR_ASSOCINCOMPLETE: XTPResourceManager()->LoadString(&strMessage, XTP_IDS_SE_ERR_ASSOCINCOMPLETE); break;
case SE_ERR_DDETIMEOUT: XTPResourceManager()->LoadString(&strMessage, XTP_IDS_SE_ERR_DDETIMEOUT); break;
case SE_ERR_DDEFAIL: XTPResourceManager()->LoadString(&strMessage, XTP_IDS_SE_ERR_DDEFAIL); break;
case SE_ERR_DDEBUSY: XTPResourceManager()->LoadString(&strMessage, XTP_IDS_SE_ERR_DDEBUSY); break;
case SE_ERR_NOASSOC: XTPResourceManager()->LoadString(&strMessage, XTP_IDS_SE_ERR_NOASSOC); break;
case SE_ERR_DLLNOTFOUND: XTPResourceManager()->LoadString(&strMessage, XTP_IDS_SE_ERR_DLLNOTFOUND); break;
default:
{
CString str;
XTPResourceManager()->LoadString(&str, XTP_IDS_SE_ERR_UNKOWN);
strMessage.Format(str, iErrorNo);
}
}
::MessageBeep(MB_ICONEXCLAMATION);
AfxMessageBox(strMessage, MB_ICONEXCLAMATION | MB_OK);
}
bool CXTPHyperLink::GotoURL(LPCTSTR lpszLink/*=NULL*/, int nShowCmd/*=SW_SHOW*/, LPCTSTR lpszParams/*=NULL*/, LPCTSTR lpszDir/*=NULL*/)
{
if (!lpszLink)
lpszLink = m_strLink;
// open the URL
int iRetVal = (int)(INT_PTR)::ShellExecute(NULL, _T("open"),
lpszLink, lpszParams, lpszDir, nShowCmd);
// alert user if there was an error.
if (iRetVal <= HINSTANCE_ERROR)
ReportError(iRetVal);
return (iRetVal > HINSTANCE_ERROR);
}
HBRUSH CXTPHyperLink::CtlColor(CDC* pDC, UINT nCtlColor)
{
UNUSED_ALWAYS(nCtlColor);
ASSERT(nCtlColor == CTLCOLOR_STATIC);
if (IsTextControl())
{
HBRUSH hbr = (HBRUSH)::GetStockObject(HOLLOW_BRUSH);
if (m_clrBack == COLORREF_NULL)
{
hbr = (HBRUSH)::DefWindowProc(::GetParent(m_hWnd), WM_CTLCOLORSTATIC, (WPARAM)pDC->GetSafeHdc(), (LPARAM)m_hWnd);
}
// draw the current state color.
if (m_bMouseOver || ::GetFocus() == m_hWnd)
{
pDC->SetTextColor(m_clrHover);
}
else if (m_bVisited)
{
pDC->SetTextColor(m_clrVisited);
}
else
{
pDC->SetTextColor(m_clrLink);
}
pDC->SetBkMode(TRANSPARENT);
return hbr;
}
return NULL;
}
void CXTPHyperLink::OnMouseMove(UINT nFlags, CPoint point)
{
if (IsTextControl() && IsLinkHot())
{
SetTimer(1, 10, NULL);
}
CStatic::OnMouseMove(nFlags, point);
}
void CXTPHyperLink::OnTimer(UINT_PTR nIDEvent)
{
if (IsTextControl())
{
bool bMouseOver = IsLinkHot();
if (bMouseOver != m_bMouseOver)
{
m_bMouseOver = bMouseOver;
RedrawWindow();
}
if (!m_bMouseOver)
{
KillTimer(1);
}
}
CStatic::OnTimer(nIDEvent);
}
BOOL CXTPHyperLink::PreTranslateMessage(MSG* pMsg)
{
if (::IsWindow(m_toolTip.m_hWnd) && m_bTipEnabled)
{
m_toolTip.RelayEvent(pMsg);
}
return CStatic::PreTranslateMessage(pMsg);
}
BOOL CXTPHyperLink::OnEraseBkgnd(CDC* pDC)
{
if (m_clrBack == COLORREF_NULL)
return CStatic::OnEraseBkgnd(pDC);
return TRUE;
}
void CXTPHyperLink::OnPaint()
{
// if the WS_EX_TRANSPARENT style is set, we have to use
// default paint routines otherwise our background will still
// be painted.
if (((::GetWindowLong(m_hWnd, GWL_EXSTYLE)
& WS_EX_TRANSPARENT) != 0) || (m_clrBack == COLORREF_NULL))
{
Default();
}
else
{
CPaintDC dc(this);
// Get the client rect, and paint to a memory device context. This will
// help reduce screen flicker. Pass the memory device context to the
// default window procedure do default painting.
CXTPClientRect r(this);
CXTPBufferDC memDC(dc);
memDC.FillSolidRect(r, GetBackColor());
CStatic::DefWindowProc(WM_PAINT, (WPARAM)memDC.m_hDC, 0);
}
}
void CXTPHyperLink::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos)
{
CStatic::OnWindowPosChanged(lpwndpos);
// if we are resized, redraw hyperlink.
RedrawWindow();
}
BOOL CXTPHyperLink::OnClicked()
{
if (IsLinkHot())
{
if (m_bShellExec)
{
m_bVisited = GotoURL(m_strLink, SW_SHOW);
}
else
{
m_bVisited = true;
}
}
// make sure tooltip is removed.
if (::IsWindow(m_toolTip.m_hWnd) && m_bTipEnabled)
m_toolTip.SendMessage(TTM_POP);
return (!IsTextControl()); // continue routing
}
bool CXTPHyperLink::IsLinkHot()
{
// if this isn't a text control, just return true
if (!IsTextControl())
return true;
// get the text for the hyperlink control.
CString strText;
GetWindowText(strText);
// get the size of the text.
CWindowDC dc(NULL);
CFont* pFont = dc.SelectObject(GetFont());
CSize size = dc.GetTextExtent(strText);
dc.SelectObject(pFont);
// get the total size of the hyperlink
CRect r;
GetWindowRect(&r);
// construct the actual size of the text.
CRect rHot = r;
switch (GetStyle() & (SS_LEFT | SS_CENTER | SS_RIGHT))
{
case SS_LEFT:
{
rHot.right = rHot.left + size.cx;
}
break;
case SS_CENTER:
{
int cx = (r.Width() - size.cx) / 2;
rHot.right -= cx;
rHot.left += cx;
}
break;
case SS_RIGHT:
{
rHot.left = rHot.right - size.cx;
}
break;
}
// get the cursor location, if it is over the
// text, return true, this means the hyperlink
// should appear hot.
CPoint pt;
::GetCursorPos(&pt);
if (rHot.PtInRect(pt))
{
return true;
}
return false;
}
void CXTPHyperLink::EnableToolTips(bool bEnable/*= true*/)
{
m_bTipEnabled = bEnable;
// if the tooltip control is already created, activate or
// deactivate it.
if (::IsWindow(m_toolTip.m_hWnd))
{
m_toolTip.Activate(bEnable);
}
}
void CXTPHyperLink::SetTipText(LPCTSTR lpszTipText)
{
m_strTipText = lpszTipText;
// if the tooltip control is already created, update the
// tip text.
if (::IsWindow(m_toolTip.m_hWnd))
{
m_toolTip.UpdateTipText(m_strTipText, this);
}
}
void CXTPHyperLink::OnSetFocus(CWnd* pOldWnd)
{
CWnd::OnSetFocus(pOldWnd);
Invalidate(FALSE);
}
void CXTPHyperLink::OnKillFocus(CWnd* pOldWnd)
{
CWnd::OnKillFocus(pOldWnd);
Invalidate(FALSE);
}
void CXTPHyperLink::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
if (nChar == VK_SPACE || nChar == VK_RETURN)
{
if (m_bShellExec)
{
m_bVisited = GotoURL(m_strLink, SW_SHOW);
}
else
{
m_bVisited = true;
}
}
}
UINT CXTPHyperLink::OnGetDlgCode()
{
const MSG& msg = AfxGetThreadState()->m_lastSentMsg;
if (!msg.lParam)
return DLGC_UNDEFPUSHBUTTON;
LPMSG lpMsg = (LPMSG)msg.lParam;
if (lpMsg->message == WM_CHAR)
{
if (lpMsg->wParam == VK_RETURN)
return DLGC_WANTCHARS;
}
if (lpMsg->message == WM_KEYDOWN)
{
UINT nChar = (UINT)lpMsg->wParam;
if ((nChar == VK_RETURN || nChar == VK_SPACE))
return DLGC_WANTALLKEYS;
}
return DLGC_UNDEFPUSHBUTTON;
}