rtfcontentcontrol.cpp

来自「管理项目进度工具的原代码」· C++ 代码 · 共 605 行 · 第 1/2 页

CPP
605
字号
// RTFContentControl.cpp : implementation file
//

#include "stdafx.h"
#include "RTFContentCtrl.h"
#include "RTFContentControl.h"

#include "..\shared\itasklist.h"
#include "..\shared\enfiledialog.h"
#include "..\shared\autoflag.h"
#include "..\todolist\tdcmsg.h"
#include "..\shared\richedithelper.h"
#include "..\todolist\tdlschemadef.h"
#include "..\shared\misc.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CRTFContentControl

CRTFContentControl::CRTFContentControl() : m_bAllowNotify(TRUE), m_reSpellCheck(m_rtf)
{
	// add custom protocol to comments field for linking to task IDs
	GetRichEditCtrl().AddProtocol(TDL_PROTOCOL, TRUE);
}

CRTFContentControl::~CRTFContentControl()
{
}


BEGIN_MESSAGE_MAP(CRTFContentControl, CRulerRichEditCtrl)
	//{{AFX_MSG_MAP(CRTFContentControl)
	ON_WM_CONTEXTMENU()
	ON_WM_CREATE()
	ON_WM_DESTROY()
	//}}AFX_MSG_MAP
	ON_EN_CHANGE(RTF_CONTROL, OnChangeText)
	ON_MESSAGE(WM_SETFONT, OnSetFont)
	ON_WM_STYLECHANGING()
	ON_REGISTERED_MESSAGE(WM_UREN_CUSTOMURL, OnCustomUrl)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CRTFContentControl message handlers

void CRTFContentControl::OnChangeText() 
{
	if (m_bAllowNotify && !GetRichEditCtrl().IsIMEComposing())
		GetParent()->SendMessage(WM_TDCN_COMMENTSCHANGE);
}

LRESULT CRTFContentControl::OnSetFont(WPARAM wp, LPARAM lp)
{
	// richedit2.0 sends a EN_CHANGE notification if it contains
	// text when it receives a font change.
	// to us though this is a bogus change so we prevent a notification
	// being sent
	CAutoFlag af(m_bAllowNotify, FALSE);

	return CRulerRichEditCtrl::OnSetFont(wp, lp);
}

// ICustomControl implementation
int CRTFContentControl::GetContent(unsigned char* pContent) const
{
	return GetContent(this, pContent);
}

// hack to get round GetRTF not being const
int CRTFContentControl::GetContent(const CRTFContentControl* pCtrl, unsigned char* pContent)
{
	int nLen = 0;
	
	if (pContent)
	{
		CString sContent;
		
		// cast away constness
		sContent = ((CRTFContentControl*)pCtrl)->GetRTF();
		nLen = sContent.GetLength();
		
		if (pContent)
			CopyMemory(pContent, (LPCTSTR)sContent, nLen);
	}
	else
		nLen = ((CRTFContentControl*)pCtrl)->GetRTFLength();
	
	return nLen;
}

bool CRTFContentControl::SetContent(unsigned char* pContent, int nLength)
{
	LPCTSTR RTFTAG = "{\\rtf";
	const int LENTAG = strlen(RTFTAG);

	// content must begin with rtf tag or be empty
	if (nLength && (nLength < LENTAG || strncmp((const char*)pContent, RTFTAG, LENTAG)))
		return false;

	CAutoFlag af(m_bAllowNotify, FALSE);
	CString sContent((LPCSTR)pContent, nLength);

	SetRTF(sContent);
	CRichEditHelper::ClearUndo(GetRichEditCtrl());

	GetRichEditCtrl().ParseAndFormatText(TRUE);
	
	return true; 
}

int CRTFContentControl::GetTextContent(char* szContent, int nLength) const
{
	if (!szContent)
		return GetWindowTextLength();

	// else
	if (nLength == -1)
		nLength = lstrlen(szContent);
	
	GetWindowText(szContent, nLength);
	return nLength;
}

bool CRTFContentControl::SetTextContent(const char* szContent)
{
	CAutoFlag af(m_bAllowNotify, TRUE);
	SendMessage(WM_SETTEXT, 0, (LPARAM)szContent);
	return true; 
}

HWND CRTFContentControl::GetHwnd() const
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	
	return GetSafeHwnd();
}

const char* CRTFContentControl::GetTypeID() const
{
	static CString sID;

	Misc::GuidToString(RTF_TYPEID, sID);

	return sID;
}

void CRTFContentControl::SetReadOnly(bool bReadOnly)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	CRulerRichEditCtrl::SetReadOnly((BOOL)bReadOnly);
}

void CRTFContentControl::Release()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	DestroyWindow();
	delete this;
}

void CRTFContentControl::EnableMenuItem(CMenu* pMenu, UINT nCmdID, BOOL bEnable)
{
	pMenu->EnableMenuItem(nCmdID, MF_BYCOMMAND | (bEnable ? MF_ENABLED : MF_GRAYED));
}

void CRTFContentControl::CheckMenuItem(CMenu* pMenu, UINT nCmdID, BOOL bCheck)
{
	pMenu->CheckMenuItem(nCmdID, MF_BYCOMMAND | (bCheck ? MF_CHECKED  : MF_UNCHECKED));
}

void CRTFContentControl::OnContextMenu(CWnd* pWnd, CPoint point) 
{
	if (pWnd == &GetRichEditCtrl())
	{
		// prepare a simple edit menu
		CMenu menu;

		if (menu.LoadMenu(IDR_POPUP))
		{
			CMenu* pPopup = menu.GetSubMenu(0);

			if (pPopup)
			{
				CRulerRichEdit& re = GetRichEditCtrl();

				BOOL bCanEdit = re.IsWindowEnabled() && !(re.GetStyle() & ES_READONLY);
				BOOL bHasText = re.GetTextLength();

				EnableMenuItem(pPopup, ID_EDIT_UNDO, bCanEdit && re.CanUndo());
				EnableMenuItem(pPopup, ID_EDIT_REDO, bCanEdit && re.SendMessage(EM_CANREDO));

				CHARRANGE cr;
				re.GetSel(cr);

				BOOL bHasSel = (cr.cpMax - cr.cpMin);

				CharFormat	cf;
				cf.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_COLOR;
				re.GetSelectionCharFormat(cf);
				
				CheckMenuItem(pPopup, BUTTON_BOLD, (cf.dwEffects & CFE_BOLD));
				CheckMenuItem(pPopup, BUTTON_ITALIC, (cf.dwEffects & CFE_ITALIC));
				CheckMenuItem(pPopup, BUTTON_UNDERLINE, (cf.dwEffects & CFE_UNDERLINE));
				CheckMenuItem(pPopup, BUTTON_STRIKETHRU, (cf.dwEffects & CFE_STRIKEOUT));

				CheckMenuItem(pPopup, ID_EDIT_SUPERSCRIPT, (cf.dwEffects & CFE_SUPERSCRIPT));
				CheckMenuItem(pPopup, ID_EDIT_SUBSCRIPT, (cf.dwEffects & CFE_SUBSCRIPT));

				EnableMenuItem(pPopup, BUTTON_BOLD, bCanEdit);
				EnableMenuItem(pPopup, BUTTON_ITALIC, bCanEdit);
				EnableMenuItem(pPopup, BUTTON_UNDERLINE, bCanEdit);
				EnableMenuItem(pPopup, BUTTON_STRIKETHRU, bCanEdit);

				EnableMenuItem(pPopup, ID_EDIT_SUPERSCRIPT, bCanEdit);
				EnableMenuItem(pPopup, ID_EDIT_SUBSCRIPT, bCanEdit);

				EnableMenuItem(pPopup, ID_EDIT_CUT, bCanEdit && bHasSel);
				EnableMenuItem(pPopup, ID_EDIT_COPY, bHasSel);
				EnableMenuItem(pPopup, ID_EDIT_PASTE, bCanEdit && CanPaste());
				EnableMenuItem(pPopup, ID_EDIT_PASTESIMPLE, bCanEdit && CanPaste());
				EnableMenuItem(pPopup, ID_EDIT_DELETE, bCanEdit && bHasSel);
				EnableMenuItem(pPopup, ID_EDIT_SELECT_ALL, bHasText);

				EnableMenuItem(pPopup, ID_EDIT_PASTEASREF, bCanEdit && !IsClipboardEmpty());
				
				int nUrl = re.GetContextUrl();
				EnableMenuItem(pPopup, ID_EDIT_OPENURL, nUrl != -1);

				if (nUrl != -1)
				{
					CString sText, sMenu;
					pPopup->GetMenuString(ID_EDIT_OPENURL, sMenu, MF_BYCOMMAND);
					
					sText.Format("%s: %s", sMenu, re.GetUrl(nUrl, TRUE));
					pPopup->ModifyMenu(ID_EDIT_OPENURL, MF_BYCOMMAND, ID_EDIT_OPENURL, sText);
				}

				EnableMenuItem(pPopup, ID_EDIT_FILEBROWSE, bCanEdit);
				EnableMenuItem(pPopup, ID_EDIT_INSERTDATESTAMP, bCanEdit);
				EnableMenuItem(pPopup, ID_EDIT_SPELLCHECK, bCanEdit && bHasText);

				EnableMenuItem(pPopup, ID_EDIT_FIND, bHasText);
				EnableMenuItem(pPopup, ID_EDIT_FINDREPLACE, bCanEdit && bHasText);

				CheckMenuItem(pPopup, ID_EDIT_SHOWTOOLBAR, IsToolbarVisible());
				CheckMenuItem(pPopup, ID_EDIT_SHOWRULER, IsRulerVisible());
				CheckMenuItem(pPopup, ID_EDIT_WORDWRAP, HasWordWrap());

				// check pos
				if (point.x == -1 && point.y == -1)
				{
					point = GetCaretPos();
					::ClientToScreen(m_rtf, &point);
				}

				UINT nCmdID = ::TrackPopupMenu(*pPopup, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_LEFTBUTTON, 
												point.x, point.y, 0, *this, NULL);

				switch (nCmdID)
				{
				case BUTTON_BOLD:
				case BUTTON_ITALIC:
				case BUTTON_UNDERLINE:
				case BUTTON_STRIKETHRU:
					SendMessage(WM_COMMAND, nCmdID);
					break;

				case ID_EDIT_SUPERSCRIPT:
					DoSuperscript();
					break;

				case ID_EDIT_SUBSCRIPT:
					DoSubscript();
					break;

				case ID_EDIT_UNDO:
					CTextDocument(re).Undo();
					break;

				case ID_EDIT_REDO:
					re.SendMessage(EM_REDO);
					break;

				case ID_EDIT_COPY:
					re.Copy();
					break;

				case ID_EDIT_CUT:
					re.Cut();
					break;

				case ID_EDIT_FIND:
					re.DoEditFind(IDS_FIND_TITLE);
					break;

				case ID_EDIT_FINDREPLACE:
					re.DoEditReplace(IDS_REPLACE_TITLE);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?