www.pudn.com > RichTextEx.rar > HyperText.h


#ifndef MAQ_HYPERTEXT_H 
#define MAQ_HYPERTEXT_H 
 
#if _MSC_VER > 1000 
#pragma once 
#endif 
 
#include  
#include  
 
namespace HyperText 
{ 
#define HTC_WORDWRAP			1	// word wrap text 
#define HTC_AUTO_SCROLL_BARS	2	// auto hide scroll bars 
#define HTC_UNDERLINE_LINKS		4	// underline links 
#define HTC_UNDERLINE_HOVER		8	// underline hover links 
#define HTC_ENABLE_TOOLTIPS		16	// enable hyperlink tool tips 
// -------------------------------------------------------------- 
// CHyperLink	 
class CHyperLink 
{ 
	int m_iBegin; 
	int m_iEnd; 
	CString m_sTitle; 
 
	enum LinkType 
	{ 
		lt_Shell = 0, /* http:// mailto:*/ 
		lt_Message = 1 /* WM_COMMAND */ 
	} m_Type; 
 
	// used for lt_Shell 
	CString m_sCommand; 
	CString m_sDirectory; 
 
	// used for lt_Message 
	HWND m_hWnd;  
	UINT m_uMsg; 
	WPARAM m_wParam; 
	LPARAM m_lParam; 
 
public: 
 
	CHyperLink(int iBegin, int iEnd, const CString& sTitle, const CString& sCommand, const CString& sDirectory) 
	{ 
		m_Type = lt_Shell; 
		m_iBegin = iBegin; 
		m_iEnd = iEnd; 
		m_sTitle = sTitle; 
		m_sCommand = sCommand; 
		m_sDirectory = sDirectory; 
	} 
 
	CHyperLink(int iBegin, int iEnd, const CString& sTitle, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
	{ 
		m_Type = lt_Message; 
		m_iBegin = iBegin; 
		m_iEnd = iEnd; 
		m_sTitle = sTitle; 
		m_hWnd = hWnd; 
		m_uMsg = uMsg; 
		m_wParam = wParam; 
		m_lParam = lParam; 
	} 
 
	CHyperLink(const CHyperLink& Src) 
	{ 
		m_Type = Src.m_Type; 
		m_iBegin = Src.m_iBegin; 
		m_iEnd = Src.m_iEnd; 
		m_sTitle = Src.m_sTitle; 
		m_sCommand = Src.m_sCommand; 
		m_sDirectory = Src.m_sDirectory; 
		m_hWnd = Src.m_hWnd; 
		m_uMsg = Src.m_uMsg; 
		m_wParam = Src.m_wParam; 
		m_lParam = Src.m_lParam; 
	} 
 
	void Execute() 
	{ 
		switch(m_Type) 
		{ 
		case lt_Shell: 
			ShellExecute(NULL, NULL, m_sCommand, NULL, m_sDirectory, SW_SHOWDEFAULT); 
			break; 
 
		case lt_Message: 
			PostMessage(m_hWnd, m_uMsg, m_wParam, m_lParam); 
			break; 
		} 
	} 
 
	inline bool operator < (const CHyperLink& Arg) 
	{ 
		return m_iEnd < Arg.m_iEnd; 
	} 
 
	inline int Begin() 
	{ 
		return m_iBegin; 
	} 
 
	inline int End() 
	{ 
		return m_iEnd; 
	} 
 
	inline int Len() 
	{ 
		return m_iEnd - m_iBegin + 1; 
	} 
 
	inline CString Title() 
	{ 
		return m_sTitle; 
	} 
 
	friend class CPreparedHyperText; 
}; 
class CPreparedHyperText 
{ 
protected: 
	CString m_sText; 
	std::list m_Links; 
 
	inline void RemoveLastSign(CString& sLink) 
	{ 
		int len = sLink.GetLength(); 
		if(len > 0) 
		{ 
			TCHAR c = sLink[len-1]; 
			switch(c) 
			{ 
				case _T('.'): 
				case _T(','): 
				case _T(';'): 
				case _T('\"'): 
				case _T('\''): 
				case _T('('): 
				case _T(')'): 
				case _T('['): 
				case _T(']'): 
				case _T('{'): 
				case _T('}'): 
				sLink.Delete(len -1, 1); 
				break; 
			} 
		} 
	} 
 
	void PrepareText(const CString& sText) 
	{ 
		m_sText = sText; 
		m_Links.clear(); 
		 
		enum { 
			unknown, 
			space, 
			http0,		/* http://		*/ 
				http1, http2, http3, http4, http5, http6, 
			ftp0,		/* ftp://		*/ 
				ftp1, ftp2, ftp3, ftp4, ftp5, 
			ftp,		/* ftp.			*/ 
			www0,		/* www.			*/ 
				www1, www2, www3, 
			mailto0, 	/* mailto:		*/ 
				mailto1, mailto2, mailto3, mailto4, mailto5, mailto6, 
			mail		/* xxx@yyy		*/ 
		} state = space; 
		 
		int WordPos = 0; 
		TCHAR sz[2]; 
		TCHAR& c = sz[0]; 
		sz[1] = 0; 
		int last = m_sText.GetLength() -1; 
		for(int i = 0; i <= last; i++) 
		{ 
			c = m_sText[i]; 
			_tcslwr(sz); 
 
			switch(state) 
			{ 
			case unknown: 
				if(tspace(c)) 
					state = space; 
				else 
				if(c == _T('@') && WordPos != i) 
					state = mail;		 
				break; 
 
			case space: 
				WordPos = i; 
				switch(c) 
				{ 
				case _T('h'): state = http0; break; 
				case _T('f'): state = ftp0; break; 
				case _T('w'): state = www0; break; 
				case _T('m'): state = mailto0; break; 
				default: 
					if(!tspace(c)) 
						state = unknown; 
				} 
				break; 
 
			/*----------------- http -----------------*/ 
			case http0: 
				if(c == _T('t')) 
					state = http1; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case http1: 
				if(c == _T('t')) 
					state = http2; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case http2: 
				if(c == _T('p')) 
					state = http3; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case http3: 
				if(c == _T(':')) 
					state = http4; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case http4: 
				if(c == _T('/')) 
					state = http5; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case http5: 
				if(c == _T('/')) 
					state = http6; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case http6: 
				if(tspace(c) || i == last) 
				{ 
					int len = i == last ? i - WordPos + 1 : i - WordPos; 
					CString s = m_sText.Mid(WordPos, len); 
					RemoveLastSign(s); 
					m_Links.push_back(CHyperLink(WordPos, WordPos + len - 1, s, s, (LPCTSTR)NULL)); 
					state = space; 
				} 
				break; 
 
			/*----------------- ftp -----------------*/ 
			case ftp0: 
				if(c == _T('t')) 
					state = ftp1; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case ftp1: 
				if(c == _T('p')) 
					state = ftp2; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case ftp2: 
				if(c == _T(':')) 
					state = ftp3; 
				else 
				if(c == _T('.')) 
					state = ftp; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case ftp3: 
				if(c == _T('/')) 
					state = ftp4; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case ftp4: 
				if(c == _T('/')) 
					state = ftp5; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case ftp: 
				if(tspace(c) || i == last) 
				{ 
					int len = i == last ? i - WordPos + 1 : i - WordPos; 
					CString s = CString(_T("ftp://")) + m_sText.Mid(WordPos, len); 
					RemoveLastSign(s); 
					m_Links.push_back(CHyperLink(WordPos, WordPos + len - 1, s, s, (LPCTSTR)NULL)); 
					state = space; 
				} 
				break; 
 
			case ftp5: 
				if(tspace(c) || i == last) 
				{ 
					int len = i == last ? i - WordPos + 1 : i - WordPos; 
					CString s = m_sText.Mid(WordPos, len); 
					RemoveLastSign(s); 
					m_Links.push_back(CHyperLink(WordPos, WordPos + len - 1, s, s, (LPCTSTR)NULL)); 
					state = space; 
				} 
				break; 
 
			/*----------------- www -----------------*/ 
			case www0: 
				if(c == _T('w')) 
					state = www1; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case www1: 
				if(c == _T('w')) 
					state = www2; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case www2: 
				if(c == _T('.')) 
					state = www3; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case www3: 
				if(tspace(c) || i == last) 
				{ 
					int len = i == last ? i - WordPos + 1 : i - WordPos; 
					CString s = CString(_T("http://")) + m_sText.Mid(WordPos, len); 
					RemoveLastSign(s); 
					m_Links.push_back(CHyperLink(WordPos, WordPos + len - 1, s, s, (LPCTSTR)NULL)); 
					state = space; 
				} 
				break; 
 
			/*----------------- mailto -----------------*/ 
			case mailto0: 
				if(c == _T('a')) 
					state = mailto1; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case mailto1: 
				if(c == _T('i')) 
					state = mailto2; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case mailto2: 
				if(c == _T('l')) 
					state = mailto3; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case mailto3: 
				if(c == _T('t')) 
					state = mailto4; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case mailto4: 
				if(c == _T('o')) 
					state = mailto5; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case mailto5: 
				if(c == _T(':')) 
					state = mailto6; 
				else 
				if(tspace(c)) 
					state = space; 
				else 
					state = unknown; 
				break; 
 
			case mailto6: 
				if(tspace(c) || i == last) 
				{ 
					int len = i == last ? i - WordPos + 1 : i - WordPos; 
					CString s = m_sText.Mid(WordPos, len); 
					RemoveLastSign(s); 
					m_Links.push_back(CHyperLink(WordPos, WordPos + len - 1, s, s, (LPCTSTR)NULL)); 
					state = space; 
				} 
				break; 
 
			/*----------------- mailto -----------------*/ 
			case mail: 
				if(tspace(c) || i == last) 
				{ 
					int len = i == last ? i - WordPos + 1 : i - WordPos; 
					CString s = CString(_T("mailto:")) + m_sText.Mid(WordPos, len); 
					RemoveLastSign(s); 
					m_Links.push_back(CHyperLink(WordPos, WordPos + len - 1, s, s, (LPCTSTR)NULL)); 
					state = space; 
				} 
				break; 
			} 
		} 
 
		m_Links.sort(); 
	} 
 
	bool tspace(TCHAR c) 
	{ 
		return _istspace(c) || c < _T(' ') || c == _T(';') || c == _T(',') || c == _T('!'); 
	} 
 
public: 
 
	CPreparedHyperText() 
	{ 
	} 
 
	CPreparedHyperText(const CString& sText) 
	{ 
		PrepareText(sText); 
	} 
 
	CPreparedHyperText(const CPreparedHyperText& src) 
	{ 
		m_sText = src.m_sText; 
		m_Links.assign(src.m_Links.begin(), src.m_Links.end()); 
	} 
 
	void Clear() 
	{ 
		m_sText.Empty(); 
		m_Links.erase(m_Links.begin(), m_Links.end()); 
	} 
 
	void SetText(const CString& sText) 
	{ 
		Clear(); 
		PrepareText(sText); 
	} 
 
	void AppendText(const CString& sText) 
	{ 
		int len = m_sText.GetLength(); 
		CPreparedHyperText ht(sText); 
		m_sText+=sText; 
		for(std::list::iterator it = ht.m_Links.begin(); it != ht.m_Links.end(); it++) 
		{ 
			CHyperLink hl = *it; 
			hl.m_iBegin += len; 
			hl.m_iEnd += len; 
			m_Links.push_back(hl); 
		} 
	} 
 
	void AppendHyperLink(const long lBegin, const long lEnd, const CString& sText, const CString& sTitle, const CString& sCommand, const CString& sDirectory) 
	{ 
		ASSERT(sText.GetLength()>0); 
		ASSERT(sCommand.GetLength()>0); 
 
		int len = m_sText.GetLength(); 
		m_sText+=sText; 
		m_Links.push_back(CHyperLink(lBegin, lEnd, sTitle, sCommand, sDirectory)); 
	} 
 
	void AppendHyperLink(const CString& sText, const CString& sTitle, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
	{ 
		ASSERT(sText.GetLength()>0); 
 
		int len = m_sText.GetLength(); 
		m_sText+=sText; 
		m_Links.push_back(CHyperLink(len, len + sText.GetLength() - 1, sTitle, hWnd, uMsg, wParam, lParam)); 
	} 
 
	inline CString& GetText() 
	{ 
		return m_sText; 
	} 
 
	inline std::list& GetLinks() 
	{ 
		return m_Links; 
	} 
	//friend class CHyperTextCtrl; 
}; 
class CHyperTextCtrl 
{ 
protected: 
	class CLinePartInfo 
	{ 
	public: 
		int m_iBegin; 
		int m_iEnd; 
		CHyperLink* m_pHyperLink; 
 
		inline CLinePartInfo(int iBegin, int iEnd, CHyperLink* pHyperLink = NULL) 
		{ 
			m_iBegin = iBegin; 
			m_iEnd = iEnd; 
			m_pHyperLink = pHyperLink; 
		} 
 
		inline CLinePartInfo(const CLinePartInfo& Src) 
		{ 
			m_iBegin = Src.m_iBegin; 
			m_iEnd = Src.m_iEnd; 
			m_pHyperLink = Src.m_pHyperLink; 
		} 
 
		inline int Begin() 
		{ 
			return m_iBegin; 
		} 
 
		inline int End() 
		{ 
			return m_iEnd; 
		} 
 
		inline int Len() 
		{ 
			return m_iEnd - m_iBegin + 1; 
		} 
	}; 
 
	class CLineInfo : public std::vector 
	{ 
	public: 
		int m_iBegin; 
		int m_iEnd; 
 
		inline CLineInfo(int iBegin, int iEnd) 
		{ 
			m_iBegin = iBegin; 
			m_iEnd = iEnd; 
		} 
 
		inline CLineInfo(const CLineInfo& Src) 
		{ 
			m_iBegin = Src.m_iBegin; 
			m_iEnd = Src.m_iEnd; 
			assign(Src.begin(), Src.end()); 
		} 
 
		inline int Begin() 
		{ 
			return m_iBegin; 
		} 
 
		inline int End() 
		{ 
			return m_iEnd; 
		} 
 
		inline int Len() 
		{ 
			return m_iEnd - m_iBegin + 1; 
		} 
	}; 
 
	class CVisPart : public CLinePartInfo 
	{ 
	public: 
		CRect m_rcBounds; 
		int m_iRealBegin; 
		int m_iRealLen; 
		CVisPart* m_pPrev; 
		CVisPart* m_pNext; 
 
		inline CVisPart( 
				const CLinePartInfo& LinePartInfo,  
				const CRect& rcBounds,  
				int iRealBegin,  
				int iRealLen, 
				CVisPart* pPrev, 
				CVisPart* pNext 
			) : CLinePartInfo(LinePartInfo) 
		{ 
			m_rcBounds = rcBounds; 
			m_iRealBegin = iRealBegin; 
			m_iRealLen = iRealLen; 
			m_pPrev = pPrev; 
			m_pNext = pNext; 
		} 
 
		inline CVisPart(const CVisPart& Src) : CLinePartInfo(Src) 
		{ 
			m_rcBounds = Src.m_rcBounds; 
			m_iRealBegin = Src.m_iRealBegin; 
			m_iRealLen = Src.m_iRealLen; 
			m_pPrev = Src.m_pPrev; 
			m_pNext = Src.m_pNext; 
		} 
	}; 
 
	class CVisLine : public std::vector 
	{	}; 
 
 
	CPreparedHyperText m_Text; 
	std::vector m_Lines;	 
	CFont m_Font; 
	COLORREF m_BkColor; 
	COLORREF m_TextColor; 
	COLORREF m_LinkColor; 
	COLORREF m_HoverColor; 
	HCURSOR m_LinkCursor; 
	HCURSOR m_DefaultCursor; 
 
	CToolTipCtrl m_tip; 
 
	//temporary variables 
	int m_iMaxWidth;				// The maximum line width 
	int m_iLineHeight;				// Height of one line 
	int m_iLinesHeight;				// Sum of height of all lines 
	bool m_bDontUpdateSizeInfo;		// Used to prevent recursive call of the UpdateSize() method 
	int m_iVertPos;					// Vertical position in percents 
	int m_iHorzPos;					// Horizontal position in percents 
	CFont m_DefaultFont;			// This font is set by default 
	CFont m_LinksFont;				// Copied from main font to faster draw (link) 
	CFont m_HoverFont;				// Copied from main font to faster draw (hover link) 
	std::vector m_VisLines;	// Currently visible text 
	CVisPart* m_pActivePart;		// Active part of link (hovered) 
	int m_iWheelDelta;				// Mouse wheel scroll delta 
 
}; 
	 
}; 
#endif