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