Click here to Skip to main content
15,886,860 members
Articles / Desktop Programming / WTL

Form Designer

26 Jul 2021CPOL24 min read 351.2K   82.5K   230  
Component for adding scriptable forms capabilities to an application.
// SimpleScriptEditor.cpp : Implementation of CSimpleScriptEditor
//
// Author : David Shepherd
//			Copyright (c) 2002, DaeDoe-Software
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "DDForms.h"
#include "SimpleScriptEditor.h"

// default font name
// the most common font is used here as the initial font creation
// must always succeed otherwise object creation fails
#define DEFAULT_FONT_NAME	L"MS Sans Serif"
// default font size
#define DEFAULT_FONT_SIZE	8
// default tab stops
#define DEFAULT_TAB_STOPS	4

namespace AxSimpleScriptEditor {

/////////////////////////////////////////////////////////////////////////////
// CSimpleScriptEditor

CSimpleScriptEditor::CSimpleScriptEditor() :
	m_ContainedEdit(_T("Edit"),this,1)
{
	// initialise everything
	m_bWindowOnly=TRUE;
	m_hAccel=NULL;
	m_LockCount=0;
	m_Modified=FALSE;
	m_BorderVisible=VARIANT_TRUE;
	m_BackColor=MAKE_OLE_COLOR(COLOR_WINDOW);
	m_ForeColor=MAKE_OLE_COLOR(COLOR_WINDOWTEXT);
	m_BackBrush=NULL;
}

CSimpleScriptEditor::~CSimpleScriptEditor()
{
	// clean up
	if(m_BackBrush!=NULL)
	{
		(void)DeleteObject(m_BackBrush);
		m_BackBrush=NULL;
	}
}

void CSimpleScriptEditor::SetModified(BOOL Modified)
{
	// set the modified flag and fire the modified state changed event
	if(m_Modified!=Modified)
	{
		m_Modified=Modified;
		(void)Fire_ModifiedStateChanged(B2VB(m_Modified));
	}
}

void CSimpleScriptEditor::CreateBackgroundBrush(OLE_COLOR BackColor)
{
	// create the edit control background brush
	COLORREF RGBBackColor=RGB(0,0,0);
	if(!SUCCEEDED(OleTranslateColor(BackColor,NULL,&RGBBackColor)))
	{
		throw std::exception();
	}
	HBRUSH BackBrush=CreateSolidBrush(RGBBackColor);
	if(BackBrush==NULL)
	{
		throw std::exception();
	}
	if(m_BackBrush!=NULL)
	{
		(void)DeleteObject(m_BackBrush);
	}
	m_BackBrush=BackBrush;
}

void CSimpleScriptEditor::SetFont(const CComPtr<IFontDisp> &pFontDisp)
{
	// check parameters
	if(pFontDisp==NULL)
	{
		throw std::exception();
	}
	// set the edit control font
	HFONT hOldFont=m_Edit.GetFont();	// NULL for default
	if(m_Edit.IsWindow()==FALSE)
	{
		throw std::exception();
	}
	CComQIPtr<IFont> spFont(pFontDisp);
	if(spFont==NULL)
	{
		throw std::exception();
	}
	HFONT hFont=0;
	if(!SUCCEEDED(spFont->get_hFont(&hFont)))
	{
		throw std::exception();
	}
	m_Edit.SetFont(hFont);
	// set the edit control tab stops
	int TabStops=DEFAULT_TAB_STOPS*4;	// dialog units
	if(m_Edit.SetTabStops(1,&TabStops)==FALSE)
	{
		m_Edit.SetFont(hOldFont);		// restore the old font
		throw std::exception();
	}
}

DWORD CSimpleScriptEditor::GetLongestLineLength()
{
	// determine the length of the longest line in the edit control
	if(m_Edit.IsWindow()==FALSE)
	{
		throw std::exception();
	}
	DWORD Length=0;
	for(long l=0; l<m_Edit.GetLineCount(); l++)
	{
		Length=max(Length,(DWORD)m_Edit.LineLength(m_Edit.LineIndex(l)));
	}
	return Length;
}

HRESULT CSimpleScriptEditor::FinalConstruct()
{
IMP_BEGIN
	// call the base class
	HRESULT hr=CComObjectRootBase::FinalConstruct();
	if(!SUCCEEDED(hr))
	{
		throw CHResult(hr);
	}
	// create the background brush
	CreateBackgroundBrush(m_BackColor);

	// some containers require us to have a valid IFontDisp available at
	// all times in order to modify the font

	// create the default font
	FONTDESC FontDesc;
	CY cy={ DEFAULT_FONT_SIZE*10000, 0 };
	FontDesc.cbSizeofstruct=sizeof(FONTDESC);
	FontDesc.lpstrName=DEFAULT_FONT_NAME;
	FontDesc.cySize=cy;
	FontDesc.sWeight=FW_NORMAL;
	FontDesc.sCharset=DEFAULT_CHARSET;
	FontDesc.fItalic=FALSE;
	FontDesc.fUnderline=FALSE;
	FontDesc.fStrikethrough=FALSE;
	if(!SUCCEEDED(OleCreateFontIndirect(
		&FontDesc,IID_IFontDisp,(void**)&m_spFontDisp)))
	{
		throw CHResult(E_FAIL);
	}
	if(m_spFontDisp==NULL)
	{
		throw CHResult(E_FAIL);
	}
IMP_END
	return RetVal;
}

HRESULT CSimpleScriptEditor::OnDraw(ATL_DRAWINFO &di)
{
	// ATL wizard generated
IMP_BEGIN
	// some containers will only provide a window for us to draw on using
	// this function - ie the control is not created

	if(IsWindow()==FALSE)	// skip if we are created
	{
		// draw rectangle
		CRect Rect=*(RECT*)di.prcBounds;
		Rectangle(di.hdcDraw,Rect.left,Rect.top,Rect.right,Rect.bottom);
		// show text
		LPCTSTR pszText=_T("SimpleScriptEditor");
		SetTextAlign(di.hdcDraw,TA_CENTER|TA_BASELINE);
		TextOut(di.hdcDraw,
			(Rect.left+Rect.right)/2,(Rect.top+Rect.bottom)/2,
				pszText,lstrlen(pszText));
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::put_BorderVisible(VARIANT_BOOL newVal)
{
IMP_BEGIN
	// refresh the edit control
	if(m_Edit.IsWindow())
	{
		if(newVal)	// show border
		{
			(void)m_Edit.ModifyStyleEx(0,WS_EX_CLIENTEDGE);
		}
		else	// hide border
		{
			(void)m_Edit.ModifyStyleEx(WS_EX_CLIENTEDGE,0);
		}
		(void)m_Edit.SetWindowPos(NULL,0,0,0,0,
			SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED);
	}
	// set the border visible flag
	m_BorderVisible=newVal;
	PROPERTY_CHANGED(DISPID_BORDERVISIBLE);
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::get_BorderVisible(VARIANT_BOOL *pVal)
{
IMP_BEGIN
	// check parameters
	if(pVal==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// get the border visible flag
	*pVal=m_BorderVisible;
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::put_BackColor(OLE_COLOR newVal)
{
IMP_BEGIN
	// create the background brush
	CreateBackgroundBrush(newVal);
	// refresh the edit control
	if(m_Edit.IsWindow())
	{
		(void)m_Edit.Invalidate();
	}
	// set the background color
	m_BackColor=newVal;
	PROPERTY_CHANGED(DISPID_BACKCOLOR);
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::get_BackColor(OLE_COLOR *pVal)
{
IMP_BEGIN
	// check parameters
	if(pVal==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// get the background color
	*pVal=m_BackColor;
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::put_ForeColor(OLE_COLOR newVal)
{
IMP_BEGIN
	// refresh the edit control
	if(m_Edit.IsWindow())
	{
		(void)m_Edit.Invalidate();
	}
	// set the foreground color
	m_ForeColor=newVal;
	PROPERTY_CHANGED(DISPID_FORECOLOR);
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::get_ForeColor(OLE_COLOR *pVal)
{
IMP_BEGIN
	// check parameters
	if(pVal==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// get the foreground color
	*pVal=m_ForeColor;
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::putref_Font(IFontDisp *pFontDisp)
{
IMP_BEGIN
	// check parameters
	if(pFontDisp==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// set the edit control font
	if(m_Edit.IsWindow())
	{
		SetFont(pFontDisp);
	}
	m_spFontDisp=pFontDisp;
	PROPERTY_CHANGED(DISPID_FONT);
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::put_Font(IFontDisp *pFontDisp)
{
IMP_BEGIN
	// check parameters
	if(pFontDisp==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// take a clone of the font
	CComQIPtr<IFont> spFont(pFontDisp);
	if(spFont==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComPtr<IFont> spFontClone;
	if(!SUCCEEDED(spFont->Clone(&spFontClone)))
	{
		throw CHResult(E_FAIL);
	}
	if(spFontClone==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<IFontDisp> spFontCloneDisp(spFontClone);
	if(spFontCloneDisp==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// set the edit control font
	if(m_Edit.IsWindow())
	{
		SetFont(spFontCloneDisp.p);
	}
	m_spFontDisp=spFontCloneDisp;
	PROPERTY_CHANGED(DISPID_FONT);
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::get_Font(IFontDisp **ppFontDisp)
{
IMP_BEGIN
	// check parameters
	if(ppFontDisp==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// get the edit control font
	*ppFontDisp=m_spFontDisp;
	if(*ppFontDisp!=NULL)	// add ref it
	{
		(void)(*ppFontDisp)->AddRef();
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::InitNew()
{
IMP_BEGIN
	// call the base class
	HRESULT hr=IPersistStreamInitImpl<CSimpleScriptEditor>::InitNew();
	if(!SUCCEEDED(hr))
	{
		throw CHResult(hr);
	}
	// todo : populate this when required
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::OnAmbientPropertyChange(DISPID dispid)
{
IMP_BEGIN
	// call the base class
	HRESULT hr=IOleControlImpl<CSimpleScriptEditor>::OnAmbientPropertyChange(dispid);
	ATLASSERT(hr==S_OK);	// S_OK is the only valid return value
	// disable the edit control in design mode
	// since the user mode ambient property may not be supported by
	// the container we assume run mode if this fails
	if((dispid==DISPID_AMBIENT_USERMODE or dispid==DISPID_UNKNOWN) and
		// the edit control may not have been created by the container if it
		// prefers to create a window only for us to draw on in design mode
		m_Edit.IsWindow())
	{
		BOOL RunMode=TRUE;
		(void)GetAmbientUserMode(RunMode);
		if(RunMode==FALSE)
		{
			(void)m_Edit.EnableWindow(FALSE);
		}
		else
		{
			(void)m_Edit.EnableWindow(TRUE);
		}
	}
IMP_END
	return S_OK;	// must always return S_OK
}

STDMETHODIMP CSimpleScriptEditor::SetObjectRects(LPCRECT prcPos, LPCRECT prcClip)
{
	// ATL wizard generated
IMP_BEGIN
	// call the base class
	IOleInPlaceObjectWindowlessImpl<CSimpleScriptEditor>::SetObjectRects(prcPos,prcClip);
	// size the edit control to fill the full client area
	long cx=prcPos->right-prcPos->left;
	long cy=prcPos->bottom-prcPos->top;
	::SetWindowPos(m_Edit,NULL,0,0,cx,cy,SWP_NOZORDER|SWP_NOACTIVATE);
IMP_END
	return RetVal;
}

BOOL CSimpleScriptEditor::PreTranslateAccelerator(LPMSG pMsg, HRESULT& hRet)
{
	// this will be set TRUE if the key press was handled
	BOOL Handled=FALSE;
	// if the edit control has focus
	if(GetFocus()==m_Edit and
		// and this is a key down message
		pMsg->message==WM_KEYDOWN)
	{
		// get shift key modifiers
		BOOL Ctrl  = (GetKeyState(VK_CONTROL) & 0x80000000) ? TRUE : FALSE;
		BOOL Shift = (GetKeyState(VK_SHIFT  ) & 0x80000000) ? TRUE : FALSE;
		BOOL Alt   = (GetKeyState(VK_MENU   ) & 0x80000000) ? TRUE : FALSE;

		// tab key
		if(pMsg->wParam==VK_TAB)
		{
			m_Edit.ReplaceSel(_T("\t"),TRUE);
			Handled=TRUE;
		}
		// arrow key
		if(	pMsg->wParam==VK_LEFT  or
			pMsg->wParam==VK_RIGHT or
			pMsg->wParam==VK_UP	   or
			pMsg->wParam==VK_DOWN  or
			// other navigation
			pMsg->wParam==VK_HOME  or
			pMsg->wParam==VK_END   or
			pMsg->wParam==VK_PRIOR or
			pMsg->wParam==VK_NEXT  or
			// del
			pMsg->wParam==VK_DELETE)
		{
			(void)m_Edit.SendMessage(pMsg->message,pMsg->wParam,pMsg->lParam);
			Handled=TRUE;
		}
		// cut / copy / paste / undo
		if(Handled==FALSE)
		{
			if(::TranslateAccelerator(*this,m_hAccel,pMsg)!=0)
			{
				Handled=TRUE;
			}
		}
	}
	// if the key press was handled
	if(Handled)
	{
		// signal success
		hRet=S_OK;
	}
	return Handled;
}

LRESULT CSimpleScriptEditor::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	// ATL wizard generated

	// call the base class
	LRESULT lRes=CComControl<CSimpleScriptEditor>::OnSetFocus(uMsg,wParam,lParam,bHandled);
	// give focus to the edit control
	if(m_bInPlaceActive)
	{
		DoVerbUIActivate(&m_rcPos,NULL);
		if(!IsChild(::GetFocus()))
		{
			m_Edit.SetFocus();
		}
	}
	return lRes;
}

LRESULT CSimpleScriptEditor::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	// modify the style
	(void)ModifyStyleEx(0,WS_EX_CONTROLPARENT);
	// create the edit control
	CRect ClientRect(0,0,0,0);
	if(m_ContainedEdit.Create(*this,ClientRect,_T(""),
		// standard window styles
		WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|
		// edit control styles
		ES_AUTOHSCROLL|ES_AUTOVSCROLL|ES_MULTILINE|ES_WANTRETURN,
		// extended styles
		(m_BorderVisible) ? WS_EX_CLIENTEDGE : 0,
		// id
		IDC_EDIT)==NULL)
	{
		return -1;
	}
	// wrap the edit control
	m_Edit.m_hWnd=NULL;	// allow reuse
	m_Edit.Attach(m_ContainedEdit);
	// set the edit control font
	try { SetFont(m_spFontDisp); }
	catch(std::exception &)
	{
		return -1;
	}
	// disable the edit control in design mode
	// since the user mode ambient property may not be supported by
	// the container we assume run mode if this fails
	BOOL RunMode=TRUE;
	(void)GetAmbientUserMode(RunMode);
	if(RunMode==FALSE)
	{
		(void)m_Edit.EnableWindow(FALSE);
	}
	// load the edit control accelerators
	m_hAccel=LoadAccelerators(_Module.GetResourceInstance(),
		MAKEINTRESOURCE(IDA_SIMPLESCRIPTEDITOR));
	if(m_hAccel==NULL)
	{
		return -1;
	}
	return 0;
}

LRESULT CSimpleScriptEditor::OnCtlColorEdit(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	// the edit control should be our only child
	ATLASSERT((HWND)lParam==m_Edit);
	// assume the worst
	bHandled=FALSE;
	if(m_BackBrush==NULL)	// todo : remove this redundant check
	{
		return NULL;
	}
	// convert OLE colors to RGB
	COLORREF RGBBackColor=RGB(0,0,0);
	if(!SUCCEEDED(OleTranslateColor(m_BackColor,NULL,&RGBBackColor)))
	{
		return NULL;
	}
	COLORREF RGBForeColor=RGB(0,0,0);
	if(!SUCCEEDED(OleTranslateColor(m_ForeColor,NULL,&RGBForeColor)))
	{
		return NULL;
	}
	// modify the dc
	HDC hdc=(HDC)wParam;
	if(SetTextColor(hdc,RGBForeColor)==CLR_INVALID)
	{
		return NULL;
	}
	if(SetBkColor(hdc,RGBBackColor)==CLR_INVALID)
	{
		return NULL;
	}
	// we handled this
	bHandled=TRUE;
	// return the background brush
	return (LRESULT)m_BackBrush;
}

LRESULT CSimpleScriptEditor::OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	// to prevent flicker do not erase the background
	return TRUE;
}

LRESULT CSimpleScriptEditor::OnEditChanged(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
	// set the modified flag
	SetModified(TRUE);
	return 0;
}

LRESULT CSimpleScriptEditor::OnCut(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
	// delegate to ISimpleScriptEditor
	(void)Cut();
	return 0;
}

LRESULT CSimpleScriptEditor::OnCopy(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
	// delegate to ISimpleScriptEditor
	(void)Copy();
	return 0;
}

LRESULT CSimpleScriptEditor::OnPaste(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
	// delegate to ISimpleScriptEditor
	(void)Paste();
	return 0;
}

LRESULT CSimpleScriptEditor::OnUndo(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
	// delegate to ISimpleScriptEditor
	(void)Undo();
	return 0;
}

STDMETHODIMP CSimpleScriptEditor::About()
{
IMP_BEGIN
	// show the about box
	CSimpleDialog<IDD_ABOUT_SIMPLESCRIPTEDITOR> AboutDlg;
	(void)AboutDlg.DoModal();
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::Cut()
{
IMP_BEGIN
	// check the edit control exists
	if(m_Edit.IsWindow()==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// cut
	(void)m_Edit.SendMessage(WM_CUT,0,0);
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::Copy()
{
IMP_BEGIN
	// check the edit control exists
	if(m_Edit.IsWindow()==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// copy
	(void)m_Edit.SendMessage(WM_COPY,0,0);
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::Paste()
{
IMP_BEGIN
	// check the edit control exists
	if(m_Edit.IsWindow()==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// paste
	(void)m_Edit.SendMessage(WM_PASTE,0,0);
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::Undo()
{
IMP_BEGIN
	// check the edit control exists
	if(m_Edit.IsWindow()==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// undo
	(void)m_Edit.SendMessage(WM_UNDO,0,0);
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::RefreshModifiedState()
{
IMP_BEGIN
	// fire the modified state changed event
	(void)Fire_ModifiedStateChanged(B2VB(m_Modified));
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::get_Modified(VARIANT_BOOL *pVal)
{
IMP_BEGIN
	// check parameters
	if(pVal==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// return the modified flag
	*pVal=B2VB(m_Modified);
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::put_Modified(VARIANT_BOOL newVal)
{
IMP_BEGIN
	// set the modified flag
	SetModified(VB2B(newVal));
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::LockExternal(BOOL Lock)
{
IMP_BEGIN
	// check the edit control exists
	if(m_Edit.IsWindow()==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// update the lock count
	Lock ? m_LockCount++ : m_LockCount--;
	// update the edit control state
	if(m_LockCount > 0)
	{
		// reduce flicker
		m_Edit.SetRedraw(FALSE);
		// read only
		if(m_Edit.SetReadOnly(TRUE)==FALSE)
		{
			throw CHResult(E_FAIL);
		}
	}
	else
	{
		// read writable
		if(m_Edit.SetReadOnly(FALSE)==FALSE)
		{
			throw CHResult(E_FAIL);
		}
		// prevent flicker
		m_Edit.SetRedraw(TRUE);
		(void)m_Edit.InvalidateRect(NULL,FALSE);
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::GetLineCount(DWORD *pCount)
{
IMP_BEGIN
	// check the edit control exists
	if(m_Edit.IsWindow()==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// check parameters
	if(pCount==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// return the number of lines in the edit control
	*pCount=m_Edit.GetLineCount();
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::FindText(
	DWORD Start, LPCOLESTR pText, BOOL *pFound, DWORD *pLine)
{
	USES_CONVERSION;
IMP_BEGIN
	// check the edit control exists
	if(m_Edit.IsWindow()==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// check parameters
	if(Start >= (DWORD)m_Edit.GetLineCount())
	{
		throw CHResult(E_INVALIDARG);
	}
	if(pText==NULL)
	{
		throw CHResult(E_POINTER);
	}
	if(wcslen(pText)==0)
	{
		throw CHResult(E_INVALIDARG);
	}
	if(pFound==NULL)
	{
		throw CHResult(E_POINTER);
	}
	if(pLine==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// create a buffer large enough to hold any line of text
	// due to the way edit controls work this buffer must be at
	// least 2 bytes wide since the actual buffer size is placed
	// in the first WORD when calling EM_GETLINE
	DWORD LongestLineLength=GetLongestLineLength();
	auto_array_ptr<TCHAR> Buf(new TCHAR [max(2,LongestLineLength+1)]);
	// look for the text in each line
	*pFound=FALSE;
	for(long l=Start; l<m_Edit.GetLineCount(); l++)
	{
		// get the next line
		DWORD Count=m_Edit.GetLine(l,Buf.get(),LongestLineLength);
		Buf.get()[Count]=_T('\0');
		// look for an exact substring match
		std::wstring str(T2CW(Buf.get()));
		if(str.find(pText)!=std::wstring::npos)
		{
			*pLine=l;
			*pFound=TRUE;
			break;	// finished
		}
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::InsertLines(
	DWORD Start, DWORD Count, LPCOLESTR *pLines)
{
	USES_CONVERSION;
IMP_BEGIN
	// check the edit control exists
	if(m_Edit.IsWindow()==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// check parameters
	if(Start > (DWORD)m_Edit.GetLineCount())
	{
		throw CHResult(E_INVALIDARG);
	}
	if(pLines==NULL)
	{
		throw CHResult(E_POINTER);
	}
	if(Count==0)	// special case
	{
		throw CHResult(S_OK);
	}
	// create CRLF tokenised lines
	std::list<std::wstring> Lines;
	ComServerStringArrayFromClient(Count,pLines,Lines);
	std::wstring TokenisedLines;
	if(Start==m_Edit.GetLineCount())
	{
		TokenisedLines=L"\r\n";	// required to create a new line
	}
	std::list<std::wstring>::const_iterator iter=Lines.begin();
	while(iter!=Lines.end())
	{
		TokenisedLines+=iter->c_str();
		iter++;
		if(iter!=Lines.end())	// if more lines follow
		{
			TokenisedLines+=L"\r\n";
		}
	}
	// begin following lines on a new line
	if(Start!=m_Edit.GetLineCount())
	{
		TokenisedLines+=L"\r\n";
	}
	// get the insertion point
	DWORD StartChar=0;
	if(Start==m_Edit.GetLineCount())
	{
		StartChar=m_Edit.LineIndex(Start-1);
		StartChar+=m_Edit.LineLength(StartChar);	// end of last line
	}
	else
	{
		StartChar=m_Edit.LineIndex(Start);
	}
	// move to the insertion point
	m_Edit.SetSel(StartChar,StartChar,TRUE);
	// insert the line
	m_Edit.ReplaceSel(W2CT(TokenisedLines.c_str()));
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::GetLines(
	DWORD Start, DWORD Count, LPOLESTR **ppLines)
{
	USES_CONVERSION;
IMP_BEGIN
	// check the edit control exists
	if(m_Edit.IsWindow()==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// check parameters
	if(Start >= (DWORD)m_Edit.GetLineCount())
	{
		throw CHResult(E_INVALIDARG);
	}
	if(Start+Count > (DWORD)m_Edit.GetLineCount())
	{
		throw CHResult(E_INVALIDARG);
	}
	if(ppLines==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// create a buffer large enough to hold any line of text
	// due to the way edit controls work this buffer must be at
	// least 2 bytes wide since the actual buffer size is placed
	// in the first WORD when calling EM_GETLINE
	DWORD LongestLineLength=GetLongestLineLength();
	auto_array_ptr<TCHAR> Buf(new TCHAR [max(2,LongestLineLength+1)]);
	// get the required lines
	std::list<std::wstring> Lines;
	for(long l=Start; l<(long)(Start+Count); l++)
	{
		// get the next line
		DWORD Count=m_Edit.GetLine(l,Buf.get(),LongestLineLength);
		Buf.get()[Count]=_T('\0');
		// add it to the array
		Lines.push_back(T2CW(Buf.get()));
	}
	*ppLines=const_cast<LPOLESTR*>(ComServerStringArrayToClient(Lines));
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::DeleteLines(DWORD Start, DWORD Count)
{
IMP_BEGIN
	// check the edit control exists
	if(m_Edit.IsWindow()==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// check parameters
	if(Start >= (DWORD)m_Edit.GetLineCount())
	{
		throw CHResult(E_INVALIDARG);
	}
	if(Start+Count > (DWORD)m_Edit.GetLineCount())
	{
		throw CHResult(E_INVALIDARG);
	}
	if(Count==0)	// special case
	{
		throw CHResult(S_OK);
	}
	// get the last line to delete
	DWORD End=Start+Count-1;
	// deletion start point
	DWORD StartChar=0;
	// deletion end point
	DWORD EndChar=0;

	// case (a)
	// there are no preceding or following lines
	if(Start==0 and End==m_Edit.GetLineCount()-1)
	{
		// deletion start point
		StartChar=m_Edit.LineIndex(Start);
		// deletion end point
		EndChar=m_Edit.LineIndex(End);
		EndChar+=m_Edit.LineLength(EndChar);
	}
	// case (b)
	// there are no preceding lines
	else if(Start==0)
	{
		// deletion start point
		StartChar=m_Edit.LineIndex(Start);
		// deletion end point
		EndChar=m_Edit.LineIndex(End+1);
	}
	// case (c)
	// there are no following lines
	else if(End==m_Edit.GetLineCount()-1)
	{
		// deletion start point
		StartChar=m_Edit.LineIndex(Start-1);
		StartChar+=m_Edit.LineLength(StartChar);
		// deletion end point
		EndChar=m_Edit.LineIndex(End);
		EndChar+=m_Edit.LineLength(EndChar);
	}

	// select the lines to delete
	m_Edit.SetSel(StartChar,EndChar,TRUE);
	// delete the lines
	m_Edit.ReplaceSel(_T(""));
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::ModifyLines(
	DWORD Start, DWORD End, DWORD Count, LPCOLESTR *pLines)
{
IMP_BEGIN
	// todo : add this when required
	throw CHResult(E_NOTIMPL);
	// todo : ensure the modified flag is correct
IMP_END
	return RetVal;
}

STDMETHODIMP CSimpleScriptEditor::GoToLine(DWORD Line)
{
IMP_BEGIN
	// check the edit control exists
	if(m_Edit.IsWindow()==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// check parameters
	if(Line >= (DWORD)m_Edit.GetLineCount())
	{
		throw CHResult(E_INVALIDARG);
	}
	// move the cursor to the requested line
	if(m_LockCount > 0)
	{
		m_Edit.SetRedraw(TRUE);
	}
	long StartChar=m_Edit.LineIndex(Line);
	m_Edit.SetSel(StartChar,StartChar);
	if(m_LockCount > 0)
	{
		m_Edit.SetRedraw(FALSE);
	}
	// indirectly give focus to the edit control
	(void)SetFocus();
IMP_END
	return RetVal;
}

} // namespace AxSimpleScriptEditor

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 Code Project Open License (CPOL)


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

Comments and Discussions