Click here to Skip to main content
15,895,142 members
Articles / Desktop Programming / WTL

Form Designer

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

#include "stdafx.h"
#include "DDForms.h"
#include "Script.h"

/////////////////////////////////////////////////////////////////////////////
// CScriptEditorLock

CScriptEditorLock::CScriptEditorLock(const CComPtr<IUnknown> &p) : m_p(p)
{
	// lock the editor
	if(m_p!=NULL)
	{
		if(!SUCCEEDED(m_p->LockExternal(TRUE)))
		{
			throw std::exception();
		}
	}
}

CScriptEditorLock::~CScriptEditorLock()
{
	// unlock the editor
	if(m_p!=NULL)
	{
		if(!SUCCEEDED(m_p->LockExternal(FALSE)))
		{
			ATLASSERT(FALSE);	// no recovery possible
		}
	}
}

/////////////////////////////////////////////////////////////////////////////
// CScript

std::wstring CScript::CreateEventHandlerName(
	const std::wstring &Source,const std::wstring &Event) const
{
	// create the event handler name
	return Source + L"_" + Event;
}

std::wstring CScript::CreateEventHandlerStartLocatorName(
	const std::wstring &Source,const std::wstring &Event) const
{
	// create the event handler start locator name
	std::wstringstream strm;
	strm << L"'@@DDF_EVENT_HANDLER_BEGIN";
	strm << L"(";
	strm << Source;
	strm << L",";
	strm << Event;
	strm << L")";
	return strm.str();
}

std::wstring CScript::CreateEventHandlerFinishLocatorName(
	const std::wstring &Source,const std::wstring &Event) const
{
	// create the event handler finish locator name
	std::wstringstream strm;
	strm << L"'@@DDF_EVENT_HANDLER_END";
	strm << L"(";
	strm << Source;
	strm << L",";
	strm << Event;
	strm << L")";
	return strm.str();
}

std::list<std::wstring> CScript::CreateEventHandlerBlock(
	const std::wstring &Source,const std::wstring &Event,
	const std::wstring &Parameters,const std::wstring &Body) const
{
	// create the event handler block
	std::list<std::wstring> EventHandlerBlock;
	// blank line
	EventHandlerBlock.push_back(L"");
	// start locator
	EventHandlerBlock.push_back(
		CreateEventHandlerStartLocatorName(Source,Event));
	// begin subroutine
	std::wstringstream strm;
	strm << L"Sub ";
	strm << CreateEventHandlerName(Source,Event);
	strm << L" ( ";
	strm << Parameters;
	strm << L" ) ";
	EventHandlerBlock.push_back(strm.str());
	// body
	SplitTokenisedString(Body,L"\r\n",EventHandlerBlock);
	// end subroutine
	EventHandlerBlock.push_back(L"End Sub");
	// finish locator
	EventHandlerBlock.push_back(
		CreateEventHandlerFinishLocatorName(Source,Event));
	// blank line
	EventHandlerBlock.push_back(L"");
	return EventHandlerBlock;
}

STDMETHODIMP CScript::AddEventHandler(BSTR Source, BSTR Event, BSTR Parameters)
{
IMP_BEGIN
	// prevent external updates to the editor
	CScriptEditorLock Lock(m_spEditor);

	// get the script buffer interface
	if(m_spEditor==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<IScriptBuffer> spBuffer(m_spEditor);
	if(spBuffer==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// check the event handler does not already exist
	BOOL Found=FALSE;
	DWORD Line=0;
	if(!SUCCEEDED(spBuffer->FindText(0,CreateEventHandlerStartLocatorName(
		BSTR2W(Source),BSTR2W(Event)).c_str(),&Found,&Line)))
	{
		throw CHResult(E_FAIL);
	}
	if(Found)
	{
		throw CHResult(E_FAIL);
	}
	// get the number of lines in the editor
	DWORD LineCount=0;
	if(!SUCCEEDED(spBuffer->GetLineCount(&LineCount)))
	{
		throw CHResult(E_FAIL);
	}
	// add the event handler
	std::list<std::wstring> EventHandlerBlock=
		CreateEventHandlerBlock(BSTR2W(Source),BSTR2W(Event),
			BSTR2W(Parameters),L"\t'Todo : Add the event handler here!");
	if(!SUCCEEDED(spBuffer->InsertLines(LineCount,EventHandlerBlock.size(),
		ComClientStringArrayToServer(EventHandlerBlock).get())))
	{
		throw CHResult(E_FAIL);
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CScript::IsEventHandled(BSTR Source, BSTR Event, VARIANT_BOOL *pRet)
{
IMP_BEGIN
	// prevent external updates to the editor
	CScriptEditorLock Lock(m_spEditor);

	// check parameters
	if(pRet==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// get the script buffer interface
	if(m_spEditor==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<IScriptBuffer> spBuffer(m_spEditor);
	if(spBuffer==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// determine if the event handler exists
	BOOL Found=FALSE;
	DWORD Line=0;
	if(!SUCCEEDED(spBuffer->FindText(0,CreateEventHandlerStartLocatorName(
		BSTR2W(Source),BSTR2W(Event)).c_str(),&Found,&Line)))
	{
		throw CHResult(E_FAIL);
	}
	*pRet=B2VB(Found);
IMP_END
	return RetVal;
}

STDMETHODIMP CScript::EditEventHandler(BSTR Source, BSTR Event)
{
IMP_BEGIN
	// prevent external updates to the editor
	CScriptEditorLock Lock(m_spEditor);

	// get the script buffer interface
	if(m_spEditor==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<IScriptBuffer> spBuffer(m_spEditor);
	if(spBuffer==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// find the event handler
	BOOL Found=FALSE;
	DWORD Line=0;
	if(!SUCCEEDED(spBuffer->FindText(0,CreateEventHandlerStartLocatorName(
		BSTR2W(Source),BSTR2W(Event)).c_str(),&Found,&Line)))
	{
		throw CHResult(E_FAIL);
	}
	if(Found==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// get the script navigation interface
	CComQIPtr<IScriptNavigation> spNavigation(spBuffer);
	if(spNavigation==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// go to the event handler line
	if(!SUCCEEDED(spNavigation->GoToLine(Line)))
	{
		throw CHResult(E_FAIL);
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CScript::EditLine(long Line)
{
IMP_BEGIN
	// prevent external updates to the editor
	CScriptEditorLock Lock(m_spEditor);

	// get the script navigation interface
	if(m_spEditor==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<IScriptNavigation> spNavigation(m_spEditor);
	if(spNavigation==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// go to the line
	// todo : check the line is valid
	if(!SUCCEEDED(spNavigation->GoToLine(Line)))
	{
		throw CHResult(E_FAIL);
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CScript::Reset()
{
IMP_BEGIN
	// prevent external updates to the editor
	CScriptEditorLock Lock(m_spEditor);

	// get the script buffer interface
	if(m_spEditor==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<IScriptBuffer> spBuffer(m_spEditor);
	if(spBuffer==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// get the number of lines in the editor
	DWORD LineCount=0;
	if(!SUCCEEDED(spBuffer->GetLineCount(&LineCount)))
	{
		throw CHResult(E_FAIL);
	}
	// delete all lines
	if(!SUCCEEDED(spBuffer->DeleteLines(0,LineCount)))
	{
		throw CHResult(E_FAIL);
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CScript::LoadFromStream(IUnknown *pUnknown,long StreamVersion)
{
IMP_BEGIN
	// prevent external updates to the editor
	CScriptEditorLock Lock(m_spEditor);

	// check parameters
	if(pUnknown==NULL)
	{
		throw CHResult(E_POINTER);
	}
	CComQIPtr<IStream> spStream(pUnknown);
	if(spStream==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// get the script buffer interface
	if(m_spEditor==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<IScriptBuffer> spBuffer(m_spEditor);
	if(spBuffer==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// reset the script
	if(!SUCCEEDED(Reset()))
	{
		throw CHResult(E_FAIL);
	}
	// read in the script header
	CStreamScriptHeader ScriptHeader;
	ScriptHeader.ReadFromStream(spStream.p,StreamVersion);
	// read in the lines
	std::vector<std::wstring> Lines;
	for(long l=0; l<(long)ScriptHeader.m_LineCount; l++)
	{
		std::wstring Line;		// next line
		ReadFromStream(spStream.p,Line);
		Lines.push_back(Line);	// update the container
	}
	// transfer the lines to the editor
	if(!SUCCEEDED(spBuffer->InsertLines(
		0,ScriptHeader.m_LineCount,ComClientStringArrayToServer(Lines).get())))
	{
		throw CHResult(E_FAIL);
	}
	// remove the trailing blank line
	if(!SUCCEEDED(spBuffer->DeleteLines(ScriptHeader.m_LineCount,1)))
	{
		throw CHResult(E_FAIL);
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CScript::SaveToStream(IUnknown *pUnknown)
{
IMP_BEGIN
	// prevent external updates to the editor
	CScriptEditorLock Lock(m_spEditor);

	// check parameters
	if(pUnknown==NULL)
	{
		throw CHResult(E_POINTER);
	}
	CComQIPtr<IStream> spStream(pUnknown);
	if(spStream==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// get the script buffer interface
	if(m_spEditor==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<IScriptBuffer> spBuffer(m_spEditor);
	if(spBuffer==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// get the number of lines in the editor
	DWORD LineCount=0;
	if(!SUCCEEDED(spBuffer->GetLineCount(&LineCount)))
	{
		throw CHResult(E_FAIL);
	}
	// transfer the lines from the editor
	LPCOLESTR *pLines=NULL;
	if(!SUCCEEDED(spBuffer->GetLines(0,LineCount,(LPOLESTR**)&pLines)))
	{
		throw CHResult(E_FAIL);
	}
	std::vector<std::wstring> Lines;	// local storage
	ComClientStringArrayFromServer(LineCount,pLines,Lines);
	// create the script header
	CStreamScriptHeader ScriptHeader;
	ScriptHeader.m_LineCount=LineCount;
	// write out the script header
	ScriptHeader.WriteToStream(spStream.p);
	// write out the lines
	for(long l=0; l<(long)ScriptHeader.m_LineCount; l++)
	{
		WriteToStream(spStream.p,Lines.at(l));
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CScript::get_Text(BSTR *pVal)
{
IMP_BEGIN
	// prevent external updates to the editor
	CScriptEditorLock Lock(m_spEditor);

	// check parameters
	if(pVal==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// get the script buffer interface
	if(m_spEditor==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<IScriptBuffer> spBuffer(m_spEditor);
	if(spBuffer==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// get the number of lines in the editor
	DWORD LineCount=0;
	if(!SUCCEEDED(spBuffer->GetLineCount(&LineCount)))
	{
		throw CHResult(E_FAIL);
	}
	// transfer the lines from the editor
	LPCOLESTR *pLines=NULL;
	if(!SUCCEEDED(spBuffer->GetLines(0,LineCount,(LPOLESTR**)&pLines)))
	{
		throw CHResult(E_FAIL);
	}
	std::vector<std::wstring> Lines;	// local storage
	ComClientStringArrayFromServer(LineCount,pLines,Lines);
	// create the text
	std::wstring Text;
	for(long l=0; l<(long)LineCount; l++)
	{
		Text+=Lines.at(l);
		if(l < (long)(LineCount-1))		// if more lines follow
		{
			Text+=L"\r\n";
		}
	}
	// return the text
	*pVal=CComBSTR(Text.c_str()).Detach();
IMP_END
	return RetVal;
}

STDMETHODIMP CScript::put_Text(BSTR newVal)
{
IMP_BEGIN
	// prevent external updates to the editor
	CScriptEditorLock Lock(m_spEditor);

	// get the script buffer interface
	if(m_spEditor==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<IScriptBuffer> spBuffer(m_spEditor);
	if(spBuffer==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// reset the script
	if(!SUCCEEDED(Reset()))
	{
		throw CHResult(E_FAIL);
	}
	// split the text into seperate lines
	std::vector<std::wstring> Lines;
	SplitTokenisedString(BSTR2W(newVal),L"\r\n",Lines);
	// transfer the lines to the editor
	if(!SUCCEEDED(spBuffer->InsertLines(
		0,Lines.size(),ComClientStringArrayToServer(Lines).get())))
	{
		throw CHResult(E_FAIL);
	}
	// remove the trailing blank line
	if(!SUCCEEDED(spBuffer->DeleteLines(Lines.size(),1)))
	{
		throw CHResult(E_FAIL);
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CScript::get_Editor(IUnknown **ppUnknown)
{
IMP_BEGIN
	// check parameters
	if(ppUnknown==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// get the script editor
	*ppUnknown=m_spEditor;
	if(*ppUnknown!=NULL)	// add ref it
	{
		(void)(*ppUnknown)->AddRef();
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CScript::put_Editor(IUnknown *pUnknown)
{
IMP_BEGIN
	// set the script editor
	m_spEditor=pUnknown;
IMP_END
	return RetVal;
}

STDMETHODIMP CScript::AddEventHandlerEx(
	BSTR Source,BSTR Event,BSTR Parameters,BSTR Body)
{
IMP_BEGIN
	// prevent external updates to the editor
	CScriptEditorLock Lock(m_spEditor);

	// get the script buffer interface
	if(m_spEditor==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<IScriptBuffer> spBuffer(m_spEditor);
	if(spBuffer==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// check the event handler does not already exist
	BOOL Found=FALSE;
	DWORD Line=0;
	if(!SUCCEEDED(spBuffer->FindText(0,CreateEventHandlerStartLocatorName(
		BSTR2W(Source),BSTR2W(Event)).c_str(),&Found,&Line)))
	{
		throw CHResult(E_FAIL);
	}
	if(Found)
	{
		throw CHResult(E_FAIL);
	}
	// get the number of lines in the editor
	DWORD LineCount=0;
	if(!SUCCEEDED(spBuffer->GetLineCount(&LineCount)))
	{
		throw CHResult(E_FAIL);
	}
	// add the event handler
	std::list<std::wstring> EventHandlerBlock=
		CreateEventHandlerBlock(BSTR2W(Source),BSTR2W(Event),
			BSTR2W(Parameters),BSTR2W(Body));
	if(!SUCCEEDED(spBuffer->InsertLines(LineCount,EventHandlerBlock.size(),
		ComClientStringArrayToServer(EventHandlerBlock).get())))
	{
		throw CHResult(E_FAIL);
	}
IMP_END
	return RetVal;
}

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