Click here to Skip to main content
15,896,557 members
Articles / Desktop Programming / MFC

Syntax colorizing with Speller engine using TOM and CSAPI

Rate me:
Please Sign up or sign in to vote.
4.89/5 (17 votes)
12 Nov 20044 min read 101.4K   3.1K   46  
Syntax colorizing with Speller engine using TOM and CSAPI.
// DemoEditorView.cpp : implementation of the CDemoEditorView class
//

#include "stdafx.h"
#include "DemoEditor.h"

#include "DemoEditorDoc.h"
#include "DemoEditorView.h"

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

/////////////////////////////////////////////////////////////////////////////
// CDemoEditorView

IMPLEMENT_DYNCREATE(CDemoEditorView, CCtrlView)

BEGIN_MESSAGE_MAP(CDemoEditorView, CCtrlView)
	//{{AFX_MSG_MAP(CDemoEditorView)
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
	ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
	ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)
	ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditCut)
	ON_CONTROL_REFLECT(EN_CHANGE,OnChangeEdit)
	ON_NOTIFY_REFLECT(EN_MSGFILTER, OnMsgfilterEdit)
	ON_WM_RBUTTONDOWN()
	ON_WM_SETCURSOR()
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CCtrlView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CCtrlView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CCtrlView::OnFilePrintPreview)



	ON_COMMAND_RANGE(ID_SUGGEST_START,ID_SUGGEST_END,OnSuggest)
	ON_UPDATE_COMMAND_UI_RANGE(ID_SUGGEST_START,ID_SUGGEST_END,OnSuggestUI)
	ON_COMMAND(ID_ADDTODICTIONNARY, OnAddtodictionnary)
	ON_UPDATE_COMMAND_UI(ID_ADDTODICTIONNARY, OnUpdateAddtodictionnary)
	ON_COMMAND(ID_IGNORALWAYS, OnIgnoralways)
	ON_UPDATE_COMMAND_UI(ID_IGNORALWAYS, OnUpdateIgnoralways)



	ON_COMMAND(ID_EDIT_CUT, OnEditCut)
	ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
	ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
	ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
	ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)


END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDemoEditorView construction/destruction

CDemoEditorView::CDemoEditorView()  : CCtrlView(_T("RICHEDIT"), AFX_WS_DEFAULT_VIEW |	WS_HSCROLL | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL |	ES_MULTILINE | ES_NOHIDESEL | ES_SAVESEL | ES_SELECTIONBAR)
{
		m_bChangeAll = TRUE;
		m_bInContextMenu = FALSE;


}

CDemoEditorView::~CDemoEditorView()
{
}

BOOL CDemoEditorView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CCtrlView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CDemoEditorView drawing

void CDemoEditorView::OnDraw(CDC* pDC)
{
	CDemoEditorDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
}

/////////////////////////////////////////////////////////////////////////////
// CDemoEditorView printing

BOOL CDemoEditorView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CDemoEditorView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CDemoEditorView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// CDemoEditorView diagnostics

#ifdef _DEBUG
void CDemoEditorView::AssertValid() const
{
	CCtrlView::AssertValid();
}

void CDemoEditorView::Dump(CDumpContext& dc) const
{
	CCtrlView::Dump(dc);
}

CDemoEditorDoc* CDemoEditorView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDemoEditorDoc)));
	return (CDemoEditorDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CDemoEditorView message handlers





static DWORD CALLBACK readFunction(DWORD dwCookie,
							 LPBYTE lpBuf,	//the buffer to fill
							 LONG nCount,	//the no. of bytes to read
							 LONG* nRead) // no. of bytes read
{
	CFile* fp = (CFile *)dwCookie;
	*nRead = fp->Read(lpBuf,nCount);
	return 0;
}

static DWORD CALLBACK writeFunction(DWORD dwCookie,
							 LPBYTE lpBuf,	//the buffer to fill
							 LONG nCount,	//the no. of bytes to read
							 LONG* nRead) // no. of bytes read
{
	CFile *pFile = (CFile*)dwCookie;
	try
	{
		pFile->Write(lpBuf, nCount);
	}
	catch(CFileException* pEX)
	{
		pEX;
		*nRead = 0;
		return 1;
	};

	*nRead = nCount;
	return 0;
}


// -------------------------------------------------------------------------------------
/*! 
 *
 * \param sFileName   
 *
 * \return void   
 */
bool CDemoEditorView::writeFile(LPCSTR  sFileName)
{
	CString oldfile(sFileName);
	oldfile += ".Bak";

	::MoveFileEx(sFileName,oldfile,MOVEFILE_REPLACE_EXISTING);

	try
	{
		CFile file(sFileName,CFile::modeCreate | CFile::modeWrite|CFile::typeBinary);
		m_es.dwCookie = (DWORD)&file;
		m_es.pfnCallback = writeFunction;
		GetRichEditCtrl().StreamOut(SF_TEXT,m_es);
		file.Close();
		GetRichEditCtrl().SetModify(FALSE);
	}
	catch(...) 
	{
		return false;
	}
	return true;

}







// -------------------------------------------------------------------------------------
/*! 
 *
 * \param sFileName   
 *
 * \return void   
 */
bool CDemoEditorView::readFile(LPCSTR  sFileName)
{

	try
	{

	//set redraw to false to reduce flicker, and to speed things up
	GetRichEditCtrl().LimitText(0);
	
	CFile file(sFileName,CFile::modeRead|CFile::typeBinary);
	m_es.dwCookie = (DWORD)&file;
	m_es.pfnCallback = readFunction;
	GetRichEditCtrl().StreamIn(SF_TEXT,m_es);
	file.Close();
	GetRichEditCtrl().SetModify(FALSE);
	}
	catch(...) 
	{
		return false;
	}
	return true;




}






// -------------------------------------------------------------------------------------
/*! 
 *
 * \param file   
 *
 * \return void   
 */
BOOL CDemoEditorView::Load(LPCSTR file)
{
	GetRichEditCtrl().SetRedraw(FALSE); // avoid flash screen
	bool ret = readFile(file);
	m_colorizer.ColorizeAll();	// color all the file 
	GetRichEditCtrl().SetRedraw(TRUE);
	GetRichEditCtrl().RedrawWindow();

	return ret;

}


// -------------------------------------------------------------------------------------
/*! 
 *
 * \param file   
 *
 * \return void   
 */
BOOL CDemoEditorView::Save(LPCSTR file)
{
	
	return writeFile(file);
}









//--------------------------------------------------------------------------------------------
//
//
//
//
void CDemoEditorView::OnInitMenuPopup(CMenu* pMenu, UINT nIndex, BOOL bSysMenu)
{



	ASSERT(pMenu != NULL);
	// check the enabled state of various menu items

	CCmdUI state;
	state.m_pMenu = pMenu;
	ASSERT(state.m_pOther == NULL);
	ASSERT(state.m_pParentMenu == NULL);

	// determine if menu is popup in top-level menu and set m_pOther to
	//  it if so (m_pParentMenu == NULL indicates that it is secondary popup)
	HMENU hParentMenu;
	if (AfxGetThreadState()->m_hTrackingMenu == pMenu->m_hMenu)
		state.m_pParentMenu = pMenu;    // parent == child for tracking popup
	else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL)
	{
		CWnd* pParent = GetTopLevelParent();
			// child windows don't have menus -- need to go to the top!
		if (pParent != NULL &&
			(hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL)
		{
			int nIndexMax = ::GetMenuItemCount(hParentMenu);
			for (int nIndex = 0; nIndex < nIndexMax; nIndex++)
			{
				if (::GetSubMenu(hParentMenu, nIndex) == pMenu->m_hMenu)
				{
					// when popup is found, m_pParentMenu is containing menu
					state.m_pParentMenu = CMenu::FromHandle(hParentMenu);
					break;
				}
			}
		}
	}

	state.m_nIndexMax = pMenu->GetMenuItemCount();
	for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
	  state.m_nIndex++)
	{
		state.m_nID = pMenu->GetMenuItemID(state.m_nIndex);
		if (state.m_nID == 0)
			continue; // menu separator or invalid cmd - ignore it

		ASSERT(state.m_pOther == NULL);
		ASSERT(state.m_pMenu != NULL);
		if (state.m_nID == (UINT)-1)
		{
			// possibly a popup menu, route to first item of that popup
			state.m_pSubMenu = pMenu->GetSubMenu(state.m_nIndex);
			if (state.m_pSubMenu == NULL ||
				(state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||
				state.m_nID == (UINT)-1)
			{
				continue;       // first item of popup can't be routed to
			}
			state.DoUpdate(this, FALSE);    // popups are never auto disabled
			OnInitMenuPopup(state.m_pSubMenu,0,0);
		}
		else
		{
			// normal menu item
			// Auto enable/disable if frame window has 'm_bAutoMenuEnable'
			//    set and command is _not_ a system command.
			state.m_pSubMenu = NULL;
			state.DoUpdate(this, 1 && state.m_nID < 0xF000);
		}

		// adjust for menu deletions and additions
		UINT nCount = pMenu->GetMenuItemCount();
		if (nCount < state.m_nIndexMax)
		{
			state.m_nIndex -= (state.m_nIndexMax - nCount);
			while (state.m_nIndex < nCount &&
				pMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)
			{
				state.m_nIndex++;
			}
		}
		state.m_nIndexMax = nCount;
	}
}

// -----------------------------------------------------------------------------------------
//  
//  
//  
//  
//  
//  


void CDemoEditorView::UpdateDynaMenu(CCmdUI* pCmdUI,CStringArray & list,CString & m_strOriginal)
{

	CMenu* pMenu = pCmdUI->m_pMenu;
	if (m_strOriginal.IsEmpty() && pMenu != NULL)	
	{
		pMenu->GetMenuString(pCmdUI->m_nID, m_strOriginal, MF_BYCOMMAND);
	}


	if (list.GetSize() == 0)
	{
		// no MRU files
		if (!m_strOriginal.IsEmpty()) 	pCmdUI->SetText(m_strOriginal);
		pCmdUI->Enable(FALSE);
		return;
	}

	if (pCmdUI->m_pMenu == NULL)
		return;

	for (int iMRU = 0; iMRU < list.GetSize(); iMRU++)
		pCmdUI->m_pMenu->DeleteMenu(pCmdUI->m_nID + iMRU, MF_BYCOMMAND);

	CString strName;
	CString strTemp;
	for (iMRU = 0; iMRU < list.GetSize(); iMRU++)
	{

		if(iMRU >= list.GetSize() ) break;

		strName = list[iMRU];

		// double up any '&' characters so they are not underlined
		LPCTSTR lpszSrc = strName;
		LPTSTR lpszDest = strTemp.GetBuffer(strName.GetLength()*2);
		while (*lpszSrc != 0)
		{
			if (*lpszSrc == '&')
				*lpszDest++ = '&';
			if (_istlead(*lpszSrc))
				*lpszDest++ = *lpszSrc++;
			*lpszDest++ = *lpszSrc++;
		}
		*lpszDest = 0;
		strTemp.ReleaseBuffer();

		int flg = 0;
		if(iMRU && (iMRU%16) == 0 )  flg = MFT_MENUBARBREAK;


		pCmdUI->m_pMenu->InsertMenu(pCmdUI->m_nIndex++,
			MF_STRING | MF_BYPOSITION | flg, pCmdUI->m_nID++,
			strTemp);
	}

	// update end menu count
	pCmdUI->m_nIndex--; // point to last menu added
	pCmdUI->m_nIndexMax = pCmdUI->m_pMenu->GetMenuItemCount();

	pCmdUI->m_bEnableChanged = TRUE;    // all the added items are enabled
}





/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  
//  
//		SPELLER IMPLEMNTATION
//  
//  
//  

void CDemoEditorView::OnSuggest(UINT id )
{

	int idx= id -ID_SUGGEST_START;
	m_colorizer.ReplaceWord(m_ContextRange,m_tSuggestlist[idx]); 
	




}

// -----------------------------------------------------------------------------------------
//  
//  
//  
//  
//  
//  
void CDemoEditorView::OnSuggestUI(CCmdUI* pCmdUI)
{


	pCmdUI->Enable(FALSE);
	if(!m_bSpellEnabled) return;

	m_colorizer.SuggestWords(m_tSuggestlist,m_ContextRange);

	if(!m_tSuggestlist.GetSize() || pCmdUI->m_pSubMenu)
	{
		pCmdUI->Enable(FALSE);
	}
	else
	{
		pCmdUI->Enable(TRUE);

		UpdateDynaMenu(pCmdUI,m_tSuggestlist,m_strOrgSuggest);
	}
	
}







// -------------------------------------------------------------------------------------
/*! 
 *
 *
 * \return void   
 */
void CDemoEditorView::OnAddtodictionnary() 
{
	m_colorizer.AddToDictionnary(m_ContextRange);
}


// -------------------------------------------------------------------------------------
/*! 
 *
 * \param pCmdUI   
 *
 * \return void   
 */
void CDemoEditorView::OnUpdateAddtodictionnary(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(FALSE);
	if(!m_bSpellEnabled) return;
	CString text ;
	text.Format("Add to dictionary  \"%s\"", m_colorizer.GetWord(m_ContextRange));
	pCmdUI->SetText(text);
	pCmdUI->Enable(TRUE);
}


// -------------------------------------------------------------------------------------
/*! 
 *
 *
 * \return void   
 */
void CDemoEditorView::OnIgnoralways() 
{
	m_colorizer.IgnoreAlways(m_ContextRange);
	
}


// -------------------------------------------------------------------------------------
/*! 
 *
 * \param pCmdUI   
 *
 * \return void   
 */
void CDemoEditorView::OnUpdateIgnoralways(CCmdUI* pCmdUI) 
{

	pCmdUI->Enable(FALSE);
	if(!m_bSpellEnabled) return;

	CString text;
	text.Format("Ignore Always \"%s\"", m_colorizer.GetWord(m_ContextRange));
	pCmdUI->SetText(text);
	pCmdUI->Enable(TRUE);
	
}


// -------------------------------------------------------------------------------------
/*!
 *
 * \param nFlags   
 * \param point   
 *
 * \return void   
 */
void CDemoEditorView::OnRButtonDown(UINT nFlags, CPoint point) 
{

	CCtrlView::OnRButtonDown(nFlags, point);
	m_bInContextMenu = TRUE;
	
	GetRichEditCtrl().ClientToScreen(&point);
	m_bSpellEnabled = m_colorizer.GetSpellSelFromPos(point.x,point.y,m_ContextRange);


	CMenu menu;
	menu.LoadMenu(IDR_CTX);
	CMenu *pop = menu.GetSubMenu(0);
	OnInitMenuPopup(pop,0,0);
	pop->TrackPopupMenu(TPM_CENTERALIGN,point.x, point.y,this);
	m_bInContextMenu = FALSE;

}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
//						
//							COLORIZER IMP
//
//
//
//






// -------------------------------------------------------------------------------------
/*! 
 *
 *
 * \return void   
 */
void CDemoEditorView::OnDestroy() 
{
	m_colorizer.Terminate();
	CCtrlView::OnDestroy();
}


// -------------------------------------------------------------------------------------
/*! 
 *
 * \param pCmdUI   
 *
 * \return void   
 */
void CDemoEditorView::OnUpdateEditUndo(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(GetRichEditCtrl().CanUndo());
	
}


// -------------------------------------------------------------------------------------
/*! 
 *
 * \param pCmdUI   
 *
 * \return void   
 */
void CDemoEditorView::OnUpdateEditCopy(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(TRUE);
	
}
// -------------------------------------------------------------------------------------
/*! 
 *
 *
 * \return void   
 */
void CDemoEditorView::OnEditCopy()
{
	GetRichEditCtrl().Copy();

}




// -------------------------------------------------------------------------------------
/*! 
 *
 * \param pCmdUI   
 *
 * \return void   
 */
void CDemoEditorView::OnUpdateEditPaste(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(GetRichEditCtrl().CanPaste());
	
}



// -------------------------------------------------------------------------------------
/*! 
 *
 *
 * \return void   
 */
void CDemoEditorView::OnEditPaste()
{
	GetRichEditCtrl().Paste();
	m_colorizer.ColorizeAll();
}


// -------------------------------------------------------------------------------------
/*! 
 *
 *
 * \return void   
 */
void CDemoEditorView::OnEditCut()
{
	GetRichEditCtrl().Cut();
	m_colorizer.ColorizeAll();
}


// -------------------------------------------------------------------------------------
/*! 
 *
 *
 * \return void   
 */
void CDemoEditorView::OnEditUndo()
{
	GetRichEditCtrl().Undo();
	m_colorizer.ColorizeAll();
}


// -------------------------------------------------------------------------------------
/*! 
 *
 *
 * \return void   
 */
void CDemoEditorView::OnEditClear()
{
	GetRichEditCtrl().Clear();
	m_colorizer.ColorizeAll();

}


// -------------------------------------------------------------------------------------
/*! 
 *
 * \param pCmdUI   
 *
 * \return void   
 */
void CDemoEditorView::OnUpdateEditCut(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(TRUE);
	
	
}

BOOL CDemoEditorView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
	if(m_bInContextMenu)
	{

		SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW ));
		return TRUE;
	}
	else
	{
		return CCtrlView::OnSetCursor(pWnd, nHitTest, message);
	}
}


//
//
//					INIT AND NOTIFICATION
//
//




// -------------------------------------------------------------------------------------
/*! 
 *
 * \param pNMHDR   
 * \param pResult   
 *
 * \return void   
 */
void CDemoEditorView::OnMsgfilterEdit(NMHDR* pNMHDR, LRESULT* pResult) 
{
	MSGFILTER *pMsgFilter = reinterpret_cast<MSGFILTER *>(pNMHDR);
	if(pMsgFilter->msg == WM_CHAR)
	{
		switch(pMsgFilter->wParam)		
		{
			case '*':
			case '/':
				{
					m_bChangeAll = true;
					break;// '*' comment could affect all the file
				}
					
		}
		CHARRANGE cr;
		GetRichEditCtrl().GetSel(cr);
		if(cr.cpMax -cr.cpMin)// when we remove, it could remove '*/' or '/*'
		{
			m_bChangeAll = true;
		}
	}
	if(pMsgFilter->msg == WM_KEYDOWN)
	{
		switch(pMsgFilter->wParam)		
		{
				case VK_BACK:
				case VK_DELETE:
				case VK_RETURN:
					m_bChangeAll = true;
					break;
		}
	}
	if(m_bChangeAll)
	{
		CHARRANGE cr;
		GetRichEditCtrl().GetSel(cr);
		m_nextedComments  = m_colorizer.AnalyseMultiCommentLine(GetRichEditCtrl().LineFromChar(cr.cpMin));
	}
	*pResult = 0;
}





// -------------------------------------------------------------------------------------
/*! 
 *
 *
 * \return void   
 */
void CDemoEditorView::OnChangeEdit() 
{
	CHARRANGE cr;
	GetRichEditCtrl().GetSel(cr);
	int line = GetRichEditCtrl().LineFromChar(cr.cpMin);
	int nextedComment = m_colorizer.ColorizeLine(line,false);
	if(m_bChangeAll && m_nextedComments != nextedComment)
	{
		m_colorizer.ColorizeAll();
		TRACE(" Multi-Comments Changed %d \n",line);
	}
	GetRichEditCtrl().SendMessage(EM_SCROLLCARET,0,0);
	m_bChangeAll = false;
}








// -------------------------------------------------------------------------------------
/*! 
 *
 * \param lpCreateStruct   
 *
 * \return int   
 */
int CDemoEditorView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CCtrlView::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	// init to reicieve changes
	long mask = GetRichEditCtrl().GetEventMask();
	GetRichEditCtrl().SetEventMask(mask | ENM_KEYEVENTS | ENM_CHANGE);


	GetRichEditCtrl().SetOptions(ECOOP_OR   ,ECO_AUTOHSCROLL   );

	
	m_colorizer.Initialize(&GetRichEditCtrl());
	
	return 0;
}

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


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

Comments and Discussions