// 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;
}