Click here to Skip to main content
15,893,668 members
Articles / Web Development / HTML

Catch All Bugs with BugTrap!

Rate me:
Please Sign up or sign in to vote.
4.34/5 (84 votes)
31 Jan 2009MIT5 min read 1.9M   9.1K   293  
A tool that can catch unhandled errors and exceptions, and deliver error reports to remote support servers
/*
 * This is a part of the BugTrap package.
 * Copyright (c) 2005-2007 IntelleSoft.
 * All rights reserved.
 *
 * Description: Hyper-link control class.
 * Author: Maksim Pyatkovskiy.
 *
 * This source code is only intended as a supplement to the
 * BugTrap package reference and related electronic documentation
 * provided with the product. See these sources for detailed
 * information regarding the BugTrap package.
 */

#include "StdAfx.h"
#include "HyperLink.h"
#include "BugTrapUtils.h"
#include "Globals.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

const COLORREF CHyperLink::m_rgbBlueColor = RGB(0x00, 0x00, 0xDD);
const COLORREF CHyperLink::m_rgbRedColor = RGB(0xDD, 0x00, 0x00);

CHyperLink::CHyperLink(void)
{
	m_rgbCurrentColor = m_rgbBlueColor;
	*m_szLinkURL = _T('\0');
	m_hwnd = NULL;
	m_pfnOldHyperLinkWndProc = NULL;
	m_nPrevDefButtonID = -1;
}

/**
 * @param pszLinkURL - new link URL.
 */
void CHyperLink::SetLinkURL(PCTSTR pszLinkURL)
{
	if (pszLinkURL)
		_tcscpy_s(m_szLinkURL, countof(m_szLinkURL), pszLinkURL);
	else
		*m_szLinkURL = _T('\0');
}

/**
 * @param point - point coordinates.
 * @return true if point appears in boundaries of hyper-link text.
 */
BOOL CHyperLink::HitTest(const POINT& point) const
{
	RECT rect;
	GetHyperLinkRect(rect);
	return PtInRect(&rect, point);
}

/**
 * @param x - point x-coordinate.
 * @param y - point y-coordinate.
 * @return true if point appears in boundaries of hyper-link text.
 */
BOOL CHyperLink::HitTest(int x, int y) const
{
	POINT point;
	point.x = x;
	point.y = y;
	return HitTest(point);
}

/**
 * @param hdc - drawing context.
 */
void CHyperLink::DrawHyperLink(HDC hdc) const
{
	TCHAR szLinkText[MAX_PATH];
	GetWindowText(m_hwnd, szLinkText, countof(szLinkText));
	SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
	_ASSERTE(g_pResManager != NULL);
	HFONT hOldFont = g_pResManager->m_hUnderlinedFont ? SelectFont(hdc, g_pResManager->m_hUnderlinedFont) : NULL;
	HWND hwndParent = GetParent(m_hwnd);
	HBRUSH hBrush = hwndParent ? FORWARD_WM_CTLCOLORSTATIC(hwndParent, hdc, m_hwnd, SendMessage) : NULL;
	if (! hBrush)
		hBrush = g_pResManager->m_hbrButtonFaceBrush;
	if (hBrush)
	{
		RECT rcClient;
		GetClientRect(m_hwnd, &rcClient);
		FillRect(hdc, &rcClient, hBrush);
	}
	SetTextColor(hdc, m_rgbCurrentColor);
	TextOut(hdc, 1, 1, szLinkText, _tcslen(szLinkText));
	SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
	if (hOldFont)
		SelectFont(hdc, hOldFont);
	if (GetFocus() == m_hwnd)
	{
		RECT rect;
		GetHyperLinkRect(rect);
		DrawFocusRect(hdc, &rect);
	}
}

void CHyperLink::DoAction(void) const
{
	if (*m_szLinkURL)
	{
		_ASSERTE(g_pResManager != NULL);
		if (g_pResManager->m_hAppStartingCursor)
			SetCursor(g_pResManager->m_hAppStartingCursor);
		ShellExecute(NULL, _T("open"), m_szLinkURL, NULL, NULL, SW_SHOWDEFAULT);
	}
	else
	{
		HWND hwndParent = GetParent(m_hwnd);
		if (hwndParent)
		{
			int nCtrlID = GetDlgCtrlID(m_hwnd);
			FORWARD_WM_COMMAND(hwndParent, nCtrlID, m_hwnd, BN_CLICKED, PostMessage);
		}
	}
}

/**
 * @param hwnd - window handle.
 * @param uMsg - message identifier.
 * @param wParam - first message parameter.
 * @param lParam - second message parameter.
 */
LRESULT CALLBACK CHyperLink::HyperLinkWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	int x, y, nCtrlID;
	POINT point;
	HCURSOR hCursor;
	COLORREF rgbNewColor;
	PAINTSTRUCT ps;
	HWND hwndParent, hwndCtrl;
	LRESULT lResult;
	DWORD dwResult;
	HDC hdc;

	CHyperLink* _this  = (CHyperLink*)GetWindowLongPtr(hwnd, GWL_USERDATA);
	_ASSERTE(_this != NULL);
	switch(uMsg)
	{
	case WM_NCHITTEST:
		return HTCLIENT;
	case WM_SETCURSOR:
		_ASSERTE(g_pResManager != NULL);
		hCursor = g_pResManager->m_hArrowCursor;
		if (g_pResManager->m_hHandCursor)
		{
			dwResult = GetMessagePos();
			point.x = GET_X_LPARAM(dwResult);
			point.y = GET_Y_LPARAM(dwResult);
			ScreenToClient(hwnd, &point);
			if (_this->HitTest(point))
				hCursor = g_pResManager->m_hHandCursor;
		}
		if (hCursor)
		{
			SetCursor(hCursor);
			return TRUE;
		}
		return FALSE;
	case WM_LBUTTONDOWN:
		if (GetCapture() != hwnd)
		{
			x = GET_X_LPARAM(lParam);
			y = GET_Y_LPARAM(lParam);
			if (_this->HitTest(x, y))
			{
				_this->m_rgbCurrentColor = m_rgbRedColor;
				SetCapture(hwnd);
				if (GetFocus() == hwnd)
					InvalidateRect(hwnd, NULL, FALSE);
				else
					SetFocus(hwnd);
			}
		}
		return 0;
	case WM_MOUSEMOVE:
		if (GetCapture() == hwnd)
		{
			x = GET_X_LPARAM(lParam);
			y = GET_Y_LPARAM(lParam);
			rgbNewColor = _this->HitTest(x, y) ? m_rgbRedColor : m_rgbBlueColor;
			if (_this->m_rgbCurrentColor != rgbNewColor)
			{
				_this->m_rgbCurrentColor = rgbNewColor;
				InvalidateRect(hwnd, NULL, FALSE);
			}
		}
		return 0;
	case WM_LBUTTONUP:
		if (GetCapture() == hwnd)
		{
			ReleaseCapture();
			x = GET_X_LPARAM(lParam);
			y = GET_Y_LPARAM(lParam);
			if (_this->HitTest(x, y))
				_this->DoAction();
		}
		return 0;
	case WM_SETFOCUS:
		hwndParent = GetParent(hwnd);
		if (hwndParent)
		{
			nCtrlID = GetDlgCtrlID(hwnd);
			if (_this->m_nPrevDefButtonID < 0)
			{
				lResult = SendMessage(hwndParent, DM_GETDEFID, 0, 0);
				_this->m_nPrevDefButtonID = HIWORD(lResult) == DC_HASDEFID && LOWORD(lResult) != nCtrlID ? LOWORD(lResult) : -1;
			}
			SendMessage(hwndParent, DM_SETDEFID, nCtrlID, 0);
			if (_this->m_nPrevDefButtonID > 0)
			{
				// Sending a DM_SETDEFID message to change the default button will not always
				// remove the default state border from the first push button. In these cases,
				// the application should send a BM_SETSTYLE message to change the first push
				// button border style.
				hwndCtrl = GetDlgItem(hwndParent, _this->m_nPrevDefButtonID);
				if (SendMessage(hwndCtrl, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON)
					SendMessage(hwndCtrl, BM_SETSTYLE, BS_PUSHBUTTON, TRUE);
			}
		}
		InvalidateRect(hwnd, NULL, FALSE);
		return 0;
	case WM_KILLFOCUS:
		hwndParent = GetParent(hwnd);
		if (hwndParent && wParam && IsChild(hwndParent, (HWND)wParam))
		{
			if (! (SendMessage((HWND)wParam, WM_GETDLGCODE, 0, 0) & (DLGC_DEFPUSHBUTTON | DLGC_UNDEFPUSHBUTTON)))
			{
				if (_this->m_nPrevDefButtonID > 0)
				{
					nCtrlID = _this->m_nPrevDefButtonID;
					_this->m_nPrevDefButtonID = -1;
				}
				else
					nCtrlID = IDOK;
				hwndCtrl = GetDlgItem(hwndParent, nCtrlID);
				if (hwndCtrl && IsWindowEnabled(hwndCtrl))
					SendMessage(hwndParent, DM_SETDEFID, nCtrlID, 0);
			}
			else
			{
				_this->m_nPrevDefButtonID = -1;
				nCtrlID = GetDlgCtrlID((HWND)wParam);
				SendMessage(hwndParent, DM_SETDEFID, nCtrlID, 0);
			}
		}
		InvalidateRect(hwnd, NULL, FALSE);
		return 0;
	case WM_CAPTURECHANGED:
		_this->m_rgbCurrentColor = m_rgbBlueColor;
		InvalidateRect(hwnd, NULL, FALSE);
		return 0;
	case WM_ERASEBKGND:
		return TRUE;
	case WM_PAINT:
		hdc = (HDC)wParam;
		if (! hdc)
		{
			hdc = BeginPaint(hwnd, &ps);
			if (hdc)
			{
				_this->DrawHyperLink(hdc);
				EndPaint(hwnd, &ps);
			}
		}
		else
			_this->DrawHyperLink(hdc);
		return 0;
	case WM_PRINTCLIENT:
		hdc = (HDC)wParam;
		_this->DrawHyperLink(hdc);
		return 0;
	case WM_KEYDOWN:
		switch (wParam)
		{
		case VK_RETURN:
			_this->DoAction();
			break;
		case VK_TAB:
			hwndParent = GetParent(hwnd);
			if (hwndParent)
			{
				BOOL bPrevCtrl = GetKeyState(VK_SHIFT) < 0;
				FORWARD_WM_NEXTDLGCTL(hwndParent, bPrevCtrl, FALSE, PostMessage);
			}
			break;
		case VK_LEFT:
		case VK_UP:
			hwndParent = GetParent(hwnd);
			if (hwndParent)
				FORWARD_WM_NEXTDLGCTL(hwndParent, TRUE, FALSE, PostMessage);
			break;
		case VK_RIGHT:
		case VK_DOWN:
			hwndParent = GetParent(hwnd);
			if (hwndParent)
				FORWARD_WM_NEXTDLGCTL(hwndParent, FALSE, FALSE, PostMessage);
			break;
		case VK_ESCAPE:
			hwndParent = GetParent(hwnd);
			if (hwndParent)
			{
				HWND hwndCtl = GetDlgItem(hwndParent, IDCANCEL);
				if (! hwndCtl || IsWindowEnabled(hwndCtl))
					FORWARD_WM_COMMAND(hwndParent, IDCANCEL, hwndCtl, BN_CLICKED, PostMessage);
			}
			break;
		}
		return 0;
	case WM_GETDLGCODE:
		return ((GetFocus() == hwnd ? DLGC_DEFPUSHBUTTON : DLGC_UNDEFPUSHBUTTON) | DLGC_WANTALLKEYS);
	case BM_SETSTYLE:
		return 0;
	default:
		return DefWindowProc(hwnd, uMsg, wParam, lParam);
	}
}

/**
 * @param hwnd - hyper-link window handle.
 */
void CHyperLink::Attach(HWND hwnd)
{
	_ASSERTE(hwnd != NULL);
	_ASSERTE(m_hwnd == NULL);
	_ASSERTE(g_pResManager != NULL);
	m_hwnd = hwnd;
	SetWindowLongPtr(hwnd, GWL_USERDATA, (LONG_PTR)this);
	m_pfnOldHyperLinkWndProc = SubclassWindow(hwnd, HyperLinkWndProc);
	InvalidateRect(hwnd, NULL, TRUE);
}

void CHyperLink::Detach(void)
{
	if (m_pfnOldHyperLinkWndProc)
	{
		SubclassWindow(m_hwnd, m_pfnOldHyperLinkWndProc);
		SetWindowLongPtr(m_hwnd, GWL_USERDATA, NULL);
		InvalidateRect(m_hwnd, NULL, TRUE);
		m_pfnOldHyperLinkWndProc = NULL;
		m_hwnd = NULL;
	}
}

/**
 * @param size - hyper-link size.
 */
void CHyperLink::GetHyperLinkSize(SIZE& size) const
{
	HDC hdc = GetDC(m_hwnd);
	_ASSERTE(g_pResManager != NULL);
	HFONT hOldFont = NULL;
	if (g_pResManager->m_hUnderlinedFont)
		hOldFont = SelectFont(hdc, g_pResManager->m_hUnderlinedFont);
	TCHAR szLinkText[MAX_PATH];
	GetWindowText(m_hwnd, szLinkText, countof(szLinkText));
	GetTextExtentPoint32(hdc, szLinkText, _tcslen(szLinkText), &size);
	if (hOldFont)
		SelectFont(hdc, hOldFont);
	ReleaseDC(m_hwnd, hdc);
}

/**
 * @param rect - hyper-link rectangle.
 */
void CHyperLink::GetHyperLinkRect(RECT& rect) const
{
	SIZE size;
	GetHyperLinkSize(size);
	rect.left = rect.top = 0;
	rect.right = size.cx + 3;
	rect.bottom = size.cy + 3;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions