// FormEditor.cpp : Implementation of CFormEditor
//
// Author : David Shepherd
// Copyright (c) 2002, DaeDoe-Software
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "DDForms.h"
#include "FormEditor.h"
#include "FormEditorItemCollection.h"
#include "FormEditorItemDetails.h"
#include "FormPropertiesAccessor.h"
#include "InsertItemDlg.h"
#include "Script.h"
#import <msscript.ocx> raw_interfaces_only
#import "..\DDPropPageAll\DDPropPageAll.tlb"
// minimum form dimensions
#define MIN_FORM_WIDTH 50
#define MIN_FORM_HEIGHT 50
// maximum form dimensions
#define MAX_FORM_WIDTH 2500
#define MAX_FORM_HEIGHT 2500
// minimum item dimensions
#define MIN_ITEM_WIDTH 10
#define MIN_ITEM_HEIGHT 10
// default item dimensions
#define DEFAULT_ITEM_WIDTH 50
#define DEFAULT_ITEM_HEIGHT 50
// minimum grid dimensions
#define MIN_GRID_WIDTH 1
#define MIN_GRID_HEIGHT 1
// number of horizontal and vertical pixels to scroll per line
#define HSCROLL_LINE_SIZE 10
#define VSCROLL_LINE_SIZE 10
// drag rect size (the width and height are the same)
#define DRAG_RECT_SIZE 2
// custom clipboard format name
#define CLIPBOARD_FORMAT_NAME _T("{A20C77E1-2C45-11d6-B6A6-F2FFFB705547}")
// default form name
#define DEFAULT_FORM_NAME L"Form"
// default item base name
#define DEFAULT_ITEM_BASE_NAME L"Object"
// storage stream name
#define STREAM_NAME L"DaeDoeForm"
// timer id
#define TIMER_ID 1
// timer elapse time (in milliseconds)
#define TIMER_ELAPSE 250
// dictates whether unlocking is allowed
#define CAN_UNLOCK TRUE
// default locked mode
#define DEFAULT_LOCKED_MODE TRUE
// maximum number of items which can be hosted in locked mode
#define MAX_LOCKED_MODE_ITEMS 6
// unlock key
#define UNLOCK_KEY 0x49ACC539,0x07ABFA45,0x7629FEDE,0xEDA76CB0
namespace AxFormEditor {
/////////////////////////////////////////////////////////////////////////////
// CExtendedPropPageData
CExtendedPropPageData::CExtendedPropPageData()
{
// initialise everything
}
CExtendedPropPageData::~CExtendedPropPageData()
{
// clean up
}
/////////////////////////////////////////////////////////////////////////////
// CItemInfo
CItemInfo::CItemInfo()
{
// initialise everything
m_LastDragRect=CRect(0,0,0,0);
}
CItemInfo::CItemInfo(const CItemInfo &ItemInfo)
{
ATLASSERT(FALSE); // not allowed
}
CItemInfo::~CItemInfo()
{
// clean up
if(m_HostWindow.IsWindow()) // host window
{
ATLASSERT(FALSE);
(void)m_HostWindow.DestroyWindow();
}
if(m_DragFrame.IsWindow()) // drag frame
{
ATLASSERT(FALSE);
(void)m_DragFrame.DestroyWindow();
}
if(m_TabNumber.IsWindow()) // tab number
{
ATLASSERT(FALSE);
(void)m_TabNumber.DestroyWindow();
}
}
const CItemInfo &CItemInfo::operator=(const CItemInfo &ItemInfo)
{
ATLASSERT(FALSE); // not allowed
return *this;
}
CItemInfo *CItemInfo::CreateObject()
{
// create a new object
return new CItemInfo;
}
void CItemInfo::DeleteObject(const CItemInfo *pItemInfo)
{
// delete an existing object
ATLASSERT(pItemInfo!=NULL);
delete pItemInfo;
}
/////////////////////////////////////////////////////////////////////////////
// CItemInfo predicates
bool IsItemTabNumberLess(
const CItemInfo *p1,const CItemInfo *p2)
{
// check the item info pointers
ATLASSERT(p1!=NULL and p2!=NULL);
// get the tab number for item 1
long TabNumber1=p1->m_TabNumber.GetTabNumber();
// get the tab number for item 2
long TabNumber2=p2->m_TabNumber.GetTabNumber();
// compare the tab numbers
return (TabNumber1 < TabNumber2) ? true : false;
}
bool IsItemHorzontalPositionLess(
const CItemInfo *p1,const CItemInfo *p2)
{
// check the item info pointers
ATLASSERT(p1!=NULL and p2!=NULL);
// get the item rect for item 1
CRect ItemRect1(0,0,0,0);
(void)p1->m_HostWindow.GetWindowRect(ItemRect1);
// get the item rect for item 2
CRect ItemRect2(0,0,0,0);
(void)p2->m_HostWindow.GetWindowRect(ItemRect2);
// compare the horizontal positions
return (ItemRect1.left < ItemRect2.left) ? true : false;
}
bool IsItemVerticalPositionLess(
const CItemInfo *p1,const CItemInfo *p2)
{
// check the item info pointers
ATLASSERT(p1!=NULL and p2!=NULL);
// get the item rect for item 1
CRect ItemRect1(0,0,0,0);
(void)p1->m_HostWindow.GetWindowRect(ItemRect1);
// get the item rect for item 2
CRect ItemRect2(0,0,0,0);
(void)p2->m_HostWindow.GetWindowRect(ItemRect2);
// compare the vertical positions
return (ItemRect1.top < ItemRect2.top) ? true : false;
}
bool IsItemIDispatchEqual(
CItemInfo *p1,const IDispatch *p2)
{
// check the item info pointer
ATLASSERT(p1!=NULL);
// check the IDispatch pointer
ATLASSERT(p2!=NULL);
// get the items IDispatch interface
CComPtr<IDispatch> spDispatch;
(void)p1->m_HostWindow.QueryControl(&spDispatch);
// compare the interfaces
return (spDispatch==p2) ? true : false;
}
/////////////////////////////////////////////////////////////////////////////
// CEventInfo
CEventInfo::CEventInfo()
{
// initialise everything
}
CEventInfo::~CEventInfo()
{
// clean up
}
/////////////////////////////////////////////////////////////////////////////
// CFormEditorState
CFormEditorState::CFormEditorState()
{
// initialise everything
m_Busy=FALSE;
m_Modified=FALSE;
m_CanPaste=FALSE;
m_CanUndo=FALSE;
m_CanRedo=FALSE;
m_ItemCount=0;
m_SelectedItemCount=0;
}
CFormEditorState::~CFormEditorState()
{
// clean up
}
BOOL CFormEditorState::operator==(const CFormEditorState &Obj) const
{
// test for equality
if( m_Busy==Obj.m_Busy and
m_Modified==Obj.m_Modified and
m_CanPaste==Obj.m_CanPaste and
m_CanUndo==Obj.m_CanUndo and
m_CanRedo==Obj.m_CanRedo and
m_ItemCount==Obj.m_ItemCount and
m_SelectedItemCount==Obj.m_SelectedItemCount)
{
return TRUE; // equal
}
return FALSE; // not equal
}
BOOL CFormEditorState::operator!=(const CFormEditorState &Obj) const
{
// test for unequality
return (*this==Obj) ? FALSE : TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CFormEditor
CFormEditor::CFormEditor()
{
// initialise everything
m_bWindowOnly=TRUE;
// form
m_FormName=DEFAULT_FORM_NAME;
m_LastFormDragRect=CRect(0,0,0,0);
// selection box
m_SelectionBoxActive=FALSE;
m_SelectionBoxAnchorPos=CPoint(0,0);
m_LastSelectionBoxDragRect=CRect(0,0,0,0);
// clipboard
m_ClipboardFormatId=0;
// tab ordering
m_TabOrderingModeActive=FALSE;
m_NextTabNumber=1;
// state
m_Busy=FALSE;
m_Modified=FALSE;
m_CanPaste=FALSE;
// locked mode
m_LockedModeActive=DEFAULT_LOCKED_MODE;
// properties
m_BorderVisible=VARIANT_TRUE;
m_BackColor=MAKE_OLE_COLOR(COLOR_WINDOW);
m_Form.GetDimensions(m_DefaultFormWidth,m_DefaultFormHeight);
m_Form.GetColors(m_DefaultFormBackColor,m_DefaultFormForeColor);
}
CFormEditor::~CFormEditor()
{
// clean up
}
BOOL CFormEditor::InRunMode()
{
// determine if run mode is active
// 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);
return VB2B(RunMode);
}
BOOL CFormEditor::InDesignMode()
{
// determine if design mode is active
return (InRunMode()) ? FALSE : TRUE;
}
void CFormEditor::SetFormDimensions(long Width,long Height)
{
// set the form dimensions
m_Form.SetDimensions(Width,Height);
PROPERTY_CHANGED(DISPID_UNKNOWN); // multiple properties
}
void CFormEditor::SetFormColors(OLE_COLOR BackColor,OLE_COLOR ForeColor)
{
// set the form colors
m_Form.SetColors(BackColor,ForeColor);
// update the ambient properties for all host windows
for(CItemInfoPtrList::const_iterator iter=
m_ItemInfoPtrList.begin(); iter!=m_ItemInfoPtrList.end(); iter++)
{
// get the host window IAxWinAmbientDispatch interface
CComPtr<IAxWinAmbientDispatch> spAxWinAmbientDispatch;
if(!SUCCEEDED((*iter)->m_HostWindow.QueryHost(&spAxWinAmbientDispatch)))
{
throw std::exception();
}
// background color
if(!SUCCEEDED(spAxWinAmbientDispatch->put_BackColor(BackColor)))
{
throw std::exception();
}
// foreground color
if(!SUCCEEDED(spAxWinAmbientDispatch->put_ForeColor(ForeColor)))
{
throw std::exception();
}
}
PROPERTY_CHANGED(DISPID_UNKNOWN); // multiple properties
}
CItemInfo *CFormEditor::HitTest(const CPoint &Pos)
{
// start from the top item and work down to the bottom
for(CItemInfoPtrList::reverse_iterator iter=
m_ItemInfoPtrList.rbegin(); iter!=m_ItemInfoPtrList.rend(); iter++)
{
// see if the item is at the passed position
if(GetItemRect(**iter).PtInRect(Pos))
{
return *iter;
}
}
return NULL; // not found
}
void CFormEditor::SelectForm()
{
// there should be no items selected
ATLASSERT(GetSelectedItemCount()==0);
// if the form is not already selected
if(IsFormSelected()==FALSE)
{
// select the form
DWORD EnabledDragHandles=
CDragFrame::DragHandleRight |
CDragFrame::DragHandleBottomRight |
CDragFrame::DragHandleBottom;
(void)m_FormDragFrame.Create(
*this,m_Form,this,EnabledDragHandles,FALSE,TRUE);
}
}
void CFormEditor::UnselectForm()
{
// if the form is currently selected
if(IsFormSelected())
{
// unselect the form
(void)m_FormDragFrame.DestroyWindow();
}
}
BOOL CFormEditor::IsFormSelected()
{
// determine if the form is selected
return m_FormDragFrame.IsWindow() ? TRUE : FALSE;
}
void CFormEditor::SelectItem(CItemInfo &ItemInfo)
{
// the form should not be selected
ATLASSERT(IsFormSelected()==FALSE);
// if the item is not already selected
if(IsItemSelected(ItemInfo)==FALSE)
{
// if there are other items selected
long SelectedItemCount=GetSelectedItemCount();
if(SelectedItemCount==1) // only need to do this once
{
// disable all drag frame handles for the selected item
GetSelectedItems().front()->m_DragFrame.
EnableDragHandles(CDragFrame::DragHandleNone);
}
// select the item
DWORD EnabledDragHandles=(SelectedItemCount==0) ?
CDragFrame::DragHandleAll : CDragFrame::DragHandleNone;
(void)ItemInfo.m_DragFrame.Create(
*this,ItemInfo.m_HostWindow,this,EnabledDragHandles);
}
}
void CFormEditor::SelectAllItemsInRect(const CRect &Rect)
{
// select all items contained in the passed rectangle
for(CItemInfoPtrList::const_iterator iter=
m_ItemInfoPtrList.begin(); iter!=m_ItemInfoPtrList.end(); iter++)
{
// get the item rect
CRect ItemRect=GetItemRect(**iter);
// select the item if fully contained in the passed rectangle
CRect IntersectRect(0,0,0,0);
(void)IntersectRect.IntersectRect(Rect,ItemRect);
if(IntersectRect==ItemRect)
{
SelectItem(**iter);
}
}
}
void CFormEditor::SelectItems(const CItemInfoPtrList &ItemInfoPtrList)
{
// select the passed items
for(CItemInfoPtrList::const_iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
SelectItem(**iter);
}
}
void CFormEditor::SelectAllItems()
{
// select all items
SelectItems(m_ItemInfoPtrList);
}
void CFormEditor::UnselectItem(CItemInfo &ItemInfo)
{
// if the item is currently selected
if(IsItemSelected(ItemInfo))
{
// unselect the item
(void)ItemInfo.m_DragFrame.DestroyWindow();
}
// if there is only one item left selected
if(GetSelectedItemCount()==1)
{
// enable all drag frame handles for the selected item
GetSelectedItems().front()->m_DragFrame.
EnableDragHandles(CDragFrame::DragHandleAll);
}
}
void CFormEditor::UnselectItems(const CItemInfoPtrList &ItemInfoPtrList)
{
// unselect the passed items
for(CItemInfoPtrList::const_iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
UnselectItem(**iter);
}
}
void CFormEditor::UnselectAllItems()
{
// unselect all items
UnselectItems(m_ItemInfoPtrList);
}
BOOL CFormEditor::IsItemSelected(CItemInfo &ItemInfo)
{
// determine if the item is selected
return ItemInfo.m_DragFrame.IsWindow() ? TRUE : FALSE;
}
CItemInfoPtrList CFormEditor::GetSelectedItems()
{
// return a list of selected items
CItemInfoPtrList ItemInfoPtrList;
for(CItemInfoPtrList::const_iterator iter=
m_ItemInfoPtrList.begin(); iter!=m_ItemInfoPtrList.end(); iter++)
{
if(IsItemSelected(**iter)) // if the item is selected
{
// update the list
ItemInfoPtrList.push_back(*iter);
}
}
return ItemInfoPtrList;
}
DWORD CFormEditor::GetSelectedItemCount()
{
// return the number of selected items
DWORD Count=0;
for(CItemInfoPtrList::const_iterator iter=
m_ItemInfoPtrList.begin(); iter!=m_ItemInfoPtrList.end(); iter++)
{
if(IsItemSelected(**iter)) // if the item is selected
{
// update the count
Count++;
}
}
return Count;
}
void CFormEditor::HideAllDragFrames()
{
// hide all drag frames
if(IsFormSelected())
{
// form drag frame
(void)m_FormDragFrame.ShowWindow(SW_HIDE);
}
// item drag frames
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
for(CItemInfoPtrList::const_iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// hide the drag frame
(void)ItemInfo.m_DragFrame.ShowWindow(SW_HIDE);
}
}
void CFormEditor::RestoreAndRepositionAllDragFrames()
{
// restore and reposition all drag frames
if(IsFormSelected())
{
// form drag frame
m_FormDragFrame.AutoPositionAndSize();
(void)m_FormDragFrame.ShowWindow(SW_SHOW);
}
// item drag frames
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
for(CItemInfoPtrList::const_iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// restore and reposition the drag frame
ItemInfo.m_DragFrame.AutoPositionAndSize();
(void)ItemInfo.m_DragFrame.ShowWindow(SW_SHOW);
}
}
void CFormEditor::HideAllTabNumbers()
{
// hide all tab numbers
for(CItemInfoPtrList::const_iterator iter=
m_ItemInfoPtrList.begin(); iter!=m_ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// hide the tab number
(void)ItemInfo.m_TabNumber.ShowWindow(SW_HIDE);
}
}
void CFormEditor::RestoreAndRepositionAllTabNumbers()
{
// restore and reposition all tab numbers
for(CItemInfoPtrList::const_iterator iter=
m_ItemInfoPtrList.begin(); iter!=m_ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// restore and reposition the tab number
ItemInfo.m_TabNumber.AutoPosition();
(void)ItemInfo.m_TabNumber.ShowWindow(SW_SHOW);
}
}
void CFormEditor::HideAllDragFramesAndTabNumbers()
{
// hide all drag frames and tab numbers
HideAllDragFrames();
HideAllTabNumbers();
}
void CFormEditor::RestoreAndRepositionAllDragFramesAndTabNumbers()
{
// restore and reposition all drag frames and tab numbers
RestoreAndRepositionAllDragFrames();
RestoreAndRepositionAllTabNumbers();
}
CRect CFormEditor::GetItemRect(CItemInfo &ItemInfo)
{
// get the item rect reletive to the screen
CRect ItemRect(0,0,0,0);
(void)ItemInfo.m_HostWindow.GetWindowRect(ItemRect);
// convert to form coordinates
(void)m_Form.ScreenToClient(ItemRect);
return ItemRect;
}
CRect CFormEditor::GetBoundingRectForItems(
const CItemInfoPtrList &ItemInfoPtrList)
{
// return the rectangle which encapsulates the passed items
CRect BoundingRect(0,0,0,0);
for(CItemInfoPtrList::const_iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
// get the item rect
CRect ItemRect=GetItemRect(**iter);
// initialise the bounding rectangle on the first pass
if(iter==ItemInfoPtrList.begin())
{
BoundingRect=ItemRect;
}
// update the bounding rectangle
(void)BoundingRect.UnionRect(BoundingRect,ItemRect);
}
return BoundingRect;
}
CRect CFormEditor::ForceRectIntoRect(
const CRect &Destination,const CRect &Source)
{
CRect NewRect=Source;
// check the width is not too large
if(NewRect.Width() > Destination.Width())
{
NewRect.right=NewRect.left+Destination.Width();
}
// check the height is not too large
if(NewRect.Height() > Destination.Height())
{
NewRect.bottom=NewRect.top+Destination.Height();
}
// check the horizontal positioning
if(NewRect.left < 0)
{
NewRect.OffsetRect(-NewRect.left,0);
}
if(NewRect.right > Destination.right)
{
NewRect.OffsetRect(Destination.right-NewRect.right,0);
}
// check the vertical positioning
if(NewRect.top < 0)
{
NewRect.OffsetRect(0,-NewRect.top);
}
if(NewRect.bottom > Destination.bottom)
{
NewRect.OffsetRect(0,Destination.bottom-NewRect.bottom);
}
return NewRect;
}
CRect CFormEditor::GetBoundingRectForSelectedItems()
{
// return the rectangle which encapsulates all selected items
return GetBoundingRectForItems(GetSelectedItems());
}
CRect CFormEditor::GetBoundingRectForAllItems()
{
// return the rectangle which encapsulates all items
return GetBoundingRectForItems(m_ItemInfoPtrList);
}
CPoint CFormEditor::ClientPosToFormPos(const CPoint &Pos)
{
// convert client position coordinates to form coordinates
CPoint NewPos=Pos;
(void)ClientToScreen(&NewPos);
(void)m_Form.ScreenToClient(&NewPos);
return NewPos;
}
CRect CFormEditor::ClientRectToFormRect(const CRect &Rect)
{
// convert client rectangle coordinates to form coordinates
CRect NewRect=Rect;
(void)ClientToScreen(NewRect);
(void)m_Form.ScreenToClient(NewRect);
return NewRect;
}
CPoint CFormEditor::SnapPosToGrid(const CPoint &Pos)
{
// get grid settings
long Width=1;
long Height=1;
// if the grid is not visible ignore the settings
if(m_Form.IsGridVisible())
{
m_Form.GetGrid(Width,Height);
}
// snap the passed position to the gird
CPoint NewPos=Pos;
NewPos.x=Width*(NewPos.x/Width);
NewPos.y=Height*(NewPos.y/Height);
return NewPos;
}
CRect CFormEditor::SnapRectToGrid(const CRect &Rect)
{
// determine the snap offset
CPoint Pos=Rect.TopLeft();
CPoint NewPos=SnapPosToGrid(Pos);
CPoint Offset=(NewPos-Pos);
// snap the passed rectangle to the grid
CRect NewRect=Rect;
NewRect.OffsetRect(Offset);
return NewRect;
}
CItemInfo &CFormEditor::InsertItem(const CLSID &ClassId,const CRect &Rect)
{
// insert an item given the class id
return CreateItem(L"",L"",Rect,ClassId,CComPtr<IStream>());
}
CItemInfo &CFormEditor::InsertItem(const std::wstring &ProgId,const CRect &Rect)
{
// insert an item give the prog id
CLSID ClassId=CLSID_NULL;
if(!SUCCEEDED(CLSIDFromProgID(ProgId.c_str(),&ClassId)))
{
throw std::exception();
}
return InsertItem(ClassId,Rect);
}
void CFormEditor::DeleteItem(CItemInfo &ItemInfo)
{
// ensure the item is not selected
UnselectItem(ItemInfo);
// remove item info from the list
CItemInfoPtrList::iterator iter=std::find(
m_ItemInfoPtrList.begin(),m_ItemInfoPtrList.end(),&ItemInfo);
ATLASSERT(iter!=m_ItemInfoPtrList.end()); // should always exist
m_ItemInfoPtrList.erase(iter); // remove item info
// clean up item info
(void)ItemInfo.m_HostWindow.DestroyWindow();
ATLASSERT(ItemInfo.m_DragFrame.IsWindow()==FALSE);
ATLASSERT(ItemInfo.m_TabNumber.IsWindow()==FALSE);
// delete item info
CItemInfo::DeleteObject(&ItemInfo);
}
void CFormEditor::DeleteSelectedItems()
{
// delete all selected items
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
CItemInfoPtrList::const_iterator iter=ItemInfoPtrList.begin();
while(iter!=ItemInfoPtrList.end())
{
// we need to be careful here since the iterator
// will become invalid for the deleted item
CItemInfoPtrList::const_iterator iter_del=iter++;
DeleteItem(**iter_del);
}
}
void CFormEditor::DeleteAllItems()
{
// delete all items
CItemInfoPtrList::const_iterator iter=m_ItemInfoPtrList.begin();
while(iter!=m_ItemInfoPtrList.end())
{
// we need to be careful here since the iterator
// will become invalid for the deleted item
CItemInfoPtrList::const_iterator iter_del=iter++;
DeleteItem(**iter_del);
}
}
void CFormEditor::GetItemPosition(
CItemInfo &ItemInfo,CRect &Rect,long &TabNumber)
{
// get the item rect
Rect=GetItemRect(ItemInfo);
// find item info in the list
CItemInfoPtrList::const_iterator iter=std::find(
m_ItemInfoPtrList.begin(),m_ItemInfoPtrList.end(),&ItemInfo);
ATLASSERT(iter!=m_ItemInfoPtrList.end()); // should always exist
// the item tab number is the same as the item index but 1 based
TabNumber=std::distance(
(CItemInfoPtrList::const_iterator)m_ItemInfoPtrList.begin(),iter)+1;
}
void CFormEditor::SetItemPosition(
CItemInfo &ItemInfo,const CRect &Rect,long TabNumber)
{
// the item should fit within the form
#ifdef _DEBUG
CRect FormRect(0,0,0,0);
(void)m_Form.GetClientRect(FormRect);
ATLASSERT(Rect.left >= 0);
ATLASSERT(Rect.top >= 0);
ATLASSERT(Rect.right <= FormRect.right);
ATLASSERT(Rect.bottom <= FormRect.bottom);
#endif
// the tab number should be valid
ATLASSERT(TabNumber >= 1 and TabNumber <= (long)m_ItemInfoPtrList.size());
// remove item info from the list
CItemInfoPtrList::iterator iter_delete=std::find(
m_ItemInfoPtrList.begin(),m_ItemInfoPtrList.end(),&ItemInfo);
ATLASSERT(iter_delete!=m_ItemInfoPtrList.end()); // should always exist
m_ItemInfoPtrList.erase(iter_delete); // remove item info
CAutoItemInfoPtr ItemInfoPtr(&ItemInfo);
// insert item info back into the list at the correct position
CItemInfoPtrList::iterator iter_insert=m_ItemInfoPtrList.begin();
std::advance(iter_insert,TabNumber-1);
m_ItemInfoPtrList.insert(iter_insert,&ItemInfo);
(void)ItemInfoPtr.Release();
// determine the window to insert the item after
HWND InsertAfter=m_ItemRootWindow;
if(TabNumber < (long)m_ItemInfoPtrList.size())
{
// advance to the next item
CItemInfoPtrList::const_iterator iter_next=m_ItemInfoPtrList.begin();
std::advance(iter_next,TabNumber);
// get the item host window
InsertAfter=(**iter_next).m_HostWindow;
}
// set the item position
(void)ItemInfo.m_HostWindow.SetWindowPos(
InsertAfter,Rect,SWP_NOACTIVATE|SWP_NOCOPYBITS);
}
void CFormEditor::CutSelectedItemsToClipboard()
{
// copy selected items to the clipboard
CopySelectedItemsToClipboard();
// delete selected items
DeleteSelectedItems();
}
void CFormEditor::CopySelectedItemsToClipboard()
{
// create the memory stream
CAutoGlobalMemory GlobalMem(
GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_DDESHARE,0));
if(GlobalMem==NULL)
{
throw std::exception();
}
CComPtr<IStream> spStream;
if(!SUCCEEDED(CreateStreamOnHGlobal(GlobalMem,FALSE,&spStream)))
{
throw std::exception();
}
// save selected items to the memory stream
InternalSave(spStream,StreamTypeClipboard);
// open the clipboard
CAutoClipboard Clipboard(*this);
// empty the clipboard and become the new owner
if(EmptyClipboard()==FALSE)
{
throw std::exception();
}
// set the clipboard data
if(SetClipboardData(
m_ClipboardFormatId,GlobalMem.Release())==NULL)
{
throw std::exception();
}
}
CItemInfoPtrList CFormEditor::PasteItemsFromClipboard()
{
// open the clipboard
CAutoClipboard Clipboard(*this);
// get the clipboard data
HGLOBAL hGlobal=::GetClipboardData(m_ClipboardFormatId);
if(hGlobal==NULL)
{
throw std::exception();
}
// create the memory stream
CComPtr<IStream> spStream;
if(!SUCCEEDED(CreateStreamOnHGlobal(hGlobal,FALSE,&spStream)))
{
throw std::exception();
}
// create items from the memory stream
return InternalLoad(spStream,StreamTypeClipboard);
}
void CFormEditor::UpdateUndoStorage(BOOL PreserveRedoStorage/*=FALSE*/)
{
// save the current form into the undo storage
InternalSave(
m_UndoStorage.CreateNewElement(),StreamTypeUndoRedo);
// clear the redo storage
if(PreserveRedoStorage==FALSE)
{
m_RedoStorage.RemoveAllElements();
}
}
void CFormEditor::UpdateRedoStorage()
{
// save the current form into the redo storage
InternalSave(
m_RedoStorage.CreateNewElement(),StreamTypeUndoRedo);
}
void CFormEditor::UndoLastChange()
{
// update the redo storage
UpdateRedoStorage();
// load the form from the undo storage
(void)InternalLoad(
m_UndoStorage.GetStreamOnLastElement(),StreamTypeUndoRedo);
// remove
m_UndoStorage.RemoveLastElement();
}
void CFormEditor::RedoLastUndo()
{
// update the undo storage
UpdateUndoStorage(TRUE);
// load the form from the redo storage
(void)InternalLoad(
m_RedoStorage.GetStreamOnLastElement(),StreamTypeUndoRedo);
// remove
m_RedoStorage.RemoveLastElement();
}
void CFormEditor::ClearUndoStorage()
{
// clear all undo storage elements
m_UndoStorage.RemoveAllElements();
}
void CFormEditor::ClearRedoStorage()
{
// clear all redo storage elements
m_RedoStorage.RemoveAllElements();
}
void CFormEditor::ClearUndoAndRedoStorage()
{
// clear the undo and redo storage
ClearUndoStorage();
ClearRedoStorage();
}
void CFormEditor::BeginSetTabOrder()
{
// the editor should not already be in tab ordering mode
ATLASSERT(m_TabOrderingModeActive==FALSE);
// there should be nothing selected
ATLASSERT(IsFormSelected()==FALSE);
ATLASSERT(GetSelectedItemCount()==0);
// get the editor state
CFormEditorState State=GetState();
// create all item tab numbers
DWORD TabNumber=1;
for(CItemInfoPtrList::const_iterator iter=m_ItemInfoPtrList.begin();
iter!=m_ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// create the tab number
(void)ItemInfo.m_TabNumber.Create(
*this,ItemInfo.m_HostWindow,m_ItemInfoPtrList.size());
// set the tab number
ItemInfo.m_TabNumber.SetTabNumber(TabNumber++);
}
// switch the editor into tab ordering mode
m_TabOrderingModeActive=TRUE;
m_NextTabNumber=1;
// set the busy flag
SetBusy(TRUE);
FireStateChangedEvent(State); // state changed
}
void CFormEditor::EndSetTabOrder()
{
// the editor should be in tab ordering mode
ATLASSERT(m_TabOrderingModeActive);
// get the editor state
CFormEditorState State=GetState();
// update the undo storage
UpdateUndoStorage();
// destroy all item tab numbers
for(CItemInfoPtrList::const_iterator iter=m_ItemInfoPtrList.begin();
iter!=m_ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// destroy the tab number
(void)ItemInfo.m_TabNumber.DestroyWindow();
}
// sort the item info list by tab order
SortListUsingPredicate(m_ItemInfoPtrList,IsItemTabNumberLess);
// update the zorder of all items based on the tab order
HWND InsertAfter=m_ItemRootWindow;
for(CItemInfoPtrList::reverse_iterator iter=m_ItemInfoPtrList.rbegin();
iter!=m_ItemInfoPtrList.rend(); iter++)
{
CItemInfo &ItemInfo=**iter;
// update the zorder
(void)ItemInfo.m_HostWindow.SetWindowPos(
InsertAfter,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOCOPYBITS);
// insert the next item after this one
InsertAfter=ItemInfo.m_HostWindow;
}
// switch the editor back from tab ordering mode
m_TabOrderingModeActive=FALSE;
// set the modified flag
SetModified(TRUE);
// reset the busy flag
SetBusy(FALSE);
FireStateChangedEvent(State); // state changed
}
void CFormEditor::UpdateItemTabOrder(CItemInfo &ItemInfo)
{
// the editor should be in tab ordering mode
ATLASSERT(m_TabOrderingModeActive);
// check the next tab number is valid
ATLASSERT(m_NextTabNumber <= m_ItemInfoPtrList.size());
// get the old item tab number
DWORD OldTabNumber=ItemInfo.m_TabNumber.GetTabNumber();
for(CItemInfoPtrList::const_iterator iter=m_ItemInfoPtrList.begin();
iter!=m_ItemInfoPtrList.end(); iter++)
{
// if the tab number is being decreased
if(m_NextTabNumber < OldTabNumber)
{
// increment relevant tab numbers
// for(long l=m_NextTabNumber; l<OldTabNumber; l++)
CItemInfo &ItemInfo=**iter;
// update the tab number
long TabNumber=ItemInfo.m_TabNumber.GetTabNumber();
if(TabNumber >= (long)m_NextTabNumber and TabNumber < (long)OldTabNumber)
{
ItemInfo.m_TabNumber.SetTabNumber(TabNumber+1);
}
}
// if the tab number is being increased
else if(m_NextTabNumber > OldTabNumber)
{
// decrement relevant tab numbers
// for(long l=OldTabNumber+1; l<=m_NextTabNumber; l++)
CItemInfo &ItemInfo=**iter;
// update the tab number
long TabNumber=ItemInfo.m_TabNumber.GetTabNumber();
if(TabNumber > (long)OldTabNumber and TabNumber <= (long)m_NextTabNumber)
{
ItemInfo.m_TabNumber.SetTabNumber(TabNumber-1);
}
}
}
// update the item tab number
ItemInfo.m_TabNumber.SetTabNumber(m_NextTabNumber);
// update the next tab number
if(m_NextTabNumber < m_ItemInfoPtrList.size())
{
m_NextTabNumber++;
}
}
void CFormEditor::SetBusy(BOOL Busy)
{
// set the busy flag
ATLASSERT(m_Busy!=Busy);
m_Busy=Busy;
// do not allow deactivation when the editor is busy
CComQIPtr<IOleControlSite> spOleControlSite(m_spClientSite);
if(spOleControlSite!=NULL)
{
// not all containers will support this method
(void)spOleControlSite->LockInPlaceActive(m_Busy);
}
}
void CFormEditor::SetModified(BOOL Modified)
{
// set the modified flag
m_Modified=Modified;
}
CFormEditorState CFormEditor::GetState()
{
// create the state
CFormEditorState State;
State.m_Busy=m_Busy;
State.m_Modified=m_Modified;
State.m_CanPaste=m_CanPaste;
State.m_CanUndo=
(m_UndoStorage.GetElementCount() > 0) ? TRUE : FALSE;
State.m_CanRedo=
(m_RedoStorage.GetElementCount() > 0) ? TRUE : FALSE;
State.m_ItemCount=m_ItemInfoPtrList.size();
State.m_SelectedItemCount=GetSelectedItemCount();
return State;
}
void CFormEditor::FireStateChangedEvent(
const CFormEditorState &OldState,BOOL Force/*=FALSE*/)
{
if(m_nFreezeEvents==0)
{
// get the current state
CFormEditorState State=GetState();
// fire the state changed event
if(State!=OldState or Force)
{
(void)Fire_StateChanged(
B2VB(State.m_Busy),
B2VB(State.m_Modified),
B2VB(State.m_CanPaste),
B2VB(State.m_CanUndo),
B2VB(State.m_CanRedo),
State.m_ItemCount,
State.m_SelectedItemCount);
}
}
}
BOOL CFormEditor::IsNameValid(const std::wstring &Name)
{
// determine if the passed name is valid
BOOL IsValid=TRUE;
// the name should not be empty
if(Name.empty())
{
IsValid=FALSE;
}
// the name should not contain any invalid characters
if(std::find_if(Name.begin(),Name.end(),
boost::compose_f_gx_hx(
std::logical_and<bool>(),
std::not1(std::ptr_fun(iswalnum)),
std::not1(std::bind2nd(std::equal_to<WCHAR>(),L'_'))))!=Name.end())
{
IsValid=FALSE;
}
// the name should not begin with a number
if(Name.length() and iswdigit(*Name.begin()))
{
IsValid=FALSE;
}
return IsValid;
}
BOOL CFormEditor::IsNameUnique(
const std::wstring &Name,const CWindow &Ignore/*=NULL*/)
{
// determine if the name is unique
BOOL IsUnique=TRUE;
// if the form should not be ignored
if(m_Form!=Ignore)
{
// do a caseless comparison on the form name
if(!_wcsicmp(m_FormName.c_str(),Name.c_str()))
{
IsUnique=FALSE;
}
}
// check all item names
for(CItemInfoPtrList::const_iterator
ItemInfoPtrIter=m_ItemInfoPtrList.begin();
ItemInfoPtrIter!=m_ItemInfoPtrList.end() and IsUnique;
ItemInfoPtrIter++)
{
CItemInfo &ItemInfo=**ItemInfoPtrIter;
// if the current item should not be ignored
if(ItemInfo.m_HostWindow!=Ignore)
{
// do a caseless comparison on the item name
if(!_wcsicmp(ItemInfo.m_Name.c_str(),Name.c_str()))
{
IsUnique=FALSE;
}
}
}
// check all exposed object names
for(CObjectNameToIDispatchMap::const_iterator
ExposedObjectIter=m_ExposedObjects.begin();
ExposedObjectIter!=m_ExposedObjects.end() and IsUnique;
ExposedObjectIter++)
{
// do a caseless comparison on the exposed object name
if(!_wcsicmp(ExposedObjectIter->first.c_str(),Name.c_str()))
{
IsUnique=FALSE;
}
}
return IsUnique;
}
std::wstring CFormEditor::CreateUniqueItemName(const std::wstring &BaseName)
{
// the base name should be valid
ATLASSERT(IsNameValid(BaseName));
// create the unique item name
for(long l=1;/*forever*/;l++)
{
// create an item name (using base name + number)
std::wstringstream strm;
strm << BaseName;
strm << l;
// use the name if unique
std::wstring Name=strm.str().c_str();
if(IsNameUnique(Name))
{
return Name;
}
}
// should never get to here
ATLASSERT(FALSE);
return L"";
}
std::wstring CFormEditor::CreateUniqueItemName(
const CComPtr<IOleObject> &spOleObject)
{
// get the base name
CAutoCoTaskMem<WCHAR> CoBaseName;
if(!SUCCEEDED(spOleObject->
GetUserType(USERCLASSTYPE_SHORT,&CoBaseName)))
{
throw std::exception();
}
// remove invalid characters
std::wstring BaseName=CoBaseName;
BaseName.erase(
std::remove_if(BaseName.begin(),BaseName.end(),
boost::compose_f_gx_hx(
std::logical_and<bool>(),
std::not1(std::ptr_fun(iswalnum)),
std::not1(std::bind2nd(std::equal_to<WCHAR>(),L'_')))),
BaseName.end());
// if the base name is invalid
if(IsNameValid(BaseName)==FALSE)
{
// use the default base name
BaseName=DEFAULT_ITEM_BASE_NAME;
}
// create the unique name
return CreateUniqueItemName(BaseName);
}
void CFormEditor::InitialiseForm(
const std::wstring &Name,const CSize &Size,
OLE_COLOR BackColor,OLE_COLOR ForeColor)
{
// the form name should be valid
ATLASSERT(IsNameValid(Name));
// the form name should be unique
ATLASSERT(IsNameUnique(Name,m_Form));
// the form should not be selected
ATLASSERT(IsFormSelected()==FALSE);
// the form should be empty
ATLASSERT(m_ItemInfoPtrList.size()==0);
// set the form name
m_FormName=Name;
// set the form dimensions
SetFormDimensions(Size.cx,Size.cy);
// set the form colors
SetFormColors(BackColor,ForeColor);
}
void CFormEditor::InitialiseFormFromStream(
const CComPtr<IStream> &spStream,DWORD StreamVersion)
{
// read the form block from the passed stream
CStreamFormBlock FormBlock;
FormBlock.ReadFromStream(spStream,StreamVersion);
// initialise the form
InitialiseForm(FormBlock.m_Name,FormBlock.m_Size,
FormBlock.m_BackColor,FormBlock.m_ForeColor);
}
void CFormEditor::SaveFormToStream(const CComPtr<IStream> &spStream)
{
// get the form rect
CRect FormRect(0,0,0,0);
(void)m_Form.GetClientRect(FormRect);
// get the form colors
OLE_COLOR BackColor=RGB(0,0,0);
OLE_COLOR ForeColor=RGB(0,0,0);
m_Form.GetColors(BackColor,ForeColor);
// create the form block
CStreamFormBlock FormBlock;
FormBlock.m_Name=m_FormName;
FormBlock.m_Size=FormRect.BottomRight();
FormBlock.m_BackColor=BackColor;
FormBlock.m_ForeColor=ForeColor;
// write the form block to the passed stream
FormBlock.WriteToStream(spStream);
}
CItemInfo &CFormEditor::CreateItem(
const std::wstring &Name,const std::wstring &Tag,
const CRect &Rect,const CLSID &ClassId,
const CComPtr<IStream> &spStream)
{
// the item name should be valid if present
ATLASSERT(Name.empty() or IsNameValid(Name));
// the item name should be unique if present
ATLASSERT(Name.empty() or IsNameUnique(Name));
// the item should fit within the form
#ifdef _DEBUG
CRect FormRect(0,0,0,0);
(void)m_Form.GetClientRect(FormRect);
ATLASSERT(Rect.left >= 0);
ATLASSERT(Rect.top >= 0);
ATLASSERT(Rect.right <= FormRect.right);
ATLASSERT(Rect.bottom <= FormRect.bottom);
#endif
// if the editor is in locked mode
if(m_LockedModeActive)
{
// limit the number of items which can be hosted
if(m_ItemInfoPtrList.size() >= MAX_LOCKED_MODE_ITEMS)
{
throw std::exception();
}
}
// create item info
CAutoItemInfoPtr pItemInfo(CItemInfo::CreateObject());
// set the name
pItemInfo->m_Name=Name;
// set the tag
pItemInfo->m_Tag=Tag;
// create the host window
if(pItemInfo->m_HostWindow.Create(m_Form,CRect(0,0,0,0),_T(""),
WS_CHILD|WS_DISABLED|WS_CLIPCHILDREN|WS_CLIPSIBLINGS)==NULL)
{
throw std::exception();
}
// get the host window IAxWinAmbientDispatch interface
CComPtr<IAxWinAmbientDispatch> spAxWinAmbientDispatch;
if(!SUCCEEDED(pItemInfo->m_HostWindow.QueryHost(&spAxWinAmbientDispatch)))
{
throw std::exception();
}
// set the host window ambient properties
OLE_COLOR BackColor=RGB(0,0,0);
OLE_COLOR ForeColor=RGB(0,0,0);
m_Form.GetColors(BackColor,ForeColor);
// background color
if(!SUCCEEDED(spAxWinAmbientDispatch->put_BackColor(BackColor)))
{
throw std::exception();
}
// foreground color
if(!SUCCEEDED(spAxWinAmbientDispatch->put_ForeColor(ForeColor)))
{
throw std::exception();
}
// windowless activation
if(!SUCCEEDED(spAxWinAmbientDispatch->
put_AllowWindowlessActivation(VARIANT_FALSE)))
{
throw std::exception();
}
// user mode
if(!SUCCEEDED(spAxWinAmbientDispatch->put_UserMode(VARIANT_FALSE)))
{
throw std::exception();
}
// get the host window IAxWinHostWindow interface
CComPtr<IAxWinHostWindow> spAxWinHostWindow;
if(!SUCCEEDED(pItemInfo->m_HostWindow.QueryHost(&spAxWinHostWindow)))
{
throw std::exception();
}
// get the item class id as text
WCHAR ClassIdText[64]=L"";
if(StringFromGUID2(ClassId,
ClassIdText,NUM_ELEMENTS(ClassIdText,WCHAR))==0)
{
throw std::exception();
}
// create the item
if(!SUCCEEDED(spAxWinHostWindow->
CreateControl(ClassIdText,pItemInfo->m_HostWindow,spStream)))
{
throw std::exception();
}
// set the host window size and position
// this is required to correctly size some items and also set the zorder
if(pItemInfo->m_HostWindow.SetWindowPos(
m_ItemRootWindow,Rect,SWP_FRAMECHANGED)==FALSE)
{
throw std::exception();
}
// if the item name is empty
if(pItemInfo->m_Name.empty())
{
// create a unique item name
CComPtr<IOleObject> spOleObject;
if(!SUCCEEDED(pItemInfo->
m_HostWindow.QueryControl(&spOleObject)))
{
throw std::exception();
}
pItemInfo->m_Name=CreateUniqueItemName(spOleObject);
}
// set the drag frame colors
m_FormDragFrame.GetColors(BackColor,ForeColor);
pItemInfo->m_DragFrame.SetColors(BackColor,ForeColor);
// set the tab number colors
m_FormTabNumber.GetColors(BackColor,ForeColor);
pItemInfo->m_TabNumber.SetColors(BackColor,ForeColor);
// add item info to the list
m_ItemInfoPtrList.push_back(pItemInfo);
// make the host window visible
(void)pItemInfo->m_HostWindow.ShowWindow(SW_SHOW);
return *pItemInfo.Release();
}
CItemInfoPtrList CFormEditor::CreateItemsFromStream(
const CComPtr<IStream> &spStream,DWORD StreamVersion,
BOOL IsPasting)
{
// read the item list header from the passed stream
CStreamItemListHeader ItemListHeader;
ItemListHeader.ReadFromStream(spStream,StreamVersion);
// item info for the new items
CItemInfoPtrList ItemInfoPtrList;
// for each item
for(long l=0; l<(long)ItemListHeader.m_Count; l++)
{
// read the item block from the passed stream
CStreamItemBlock ItemBlock;
ItemBlock.ReadFromStream(spStream,StreamVersion);
// we need to do some additional tasks if pasting
if(IsPasting)
{
// force a unique item name
ItemBlock.m_Name=L"";
// remove the tag
ItemBlock.m_Tag=L"";
// the top left item being inserted will be placed at
// the top left corner of the form so all other items
// will be reletive to this one
CRect ItemRect=ItemBlock.m_Rect;
ItemRect.OffsetRect(
-ItemListHeader.m_BoundingRect.left,
-ItemListHeader.m_BoundingRect.top);
// get the form rect
CRect FormRect(0,0,0,0);
(void)m_Form.GetClientRect(FormRect);
// ensure the item fits within the form
ItemBlock.m_Rect=ForceRectIntoRect(FormRect,ItemRect);
}
// for early stream versions the item data will be read directly from
// the passed stream, for later stream versions the item data will first
// be copied to a temporary data stream and then read from there
CComPtr<IStream> spDataStream=spStream;
if(ItemBlock.m_HasPersistantData and StreamVersion > 2)
{
// create the data stream
spDataStream=NULL;
if(!SUCCEEDED(CreateStreamOnHGlobal(NULL,TRUE,&spDataStream)))
{
throw std::exception();
}
// initialise the size
ULARGE_INTEGER Size;
Size.QuadPart=0;
if(!SUCCEEDED(spDataStream->SetSize(Size)))
{
throw std::exception();
}
// read the item persistant data header from the passed stream
CStreamItemPersistantDataHeader ItemPersistantDataHeader;
ItemPersistantDataHeader.ReadFromStream(spStream,StreamVersion);
// copy the item data to the data stream
if(!SUCCEEDED(spStream->CopyTo(
spDataStream,ItemPersistantDataHeader.m_Length,NULL,NULL)))
{
throw std::exception();
}
// seek back to the start of the data stream
LARGE_INTEGER Offset;
Offset.QuadPart=0;
if(!SUCCEEDED(spDataStream->Seek(Offset,STREAM_SEEK_SET,NULL)))
{
throw std::exception();
}
}
// create the item
CItemInfo &ItemInfo=CreateItem(ItemBlock.m_Name,ItemBlock.m_Tag,
ItemBlock.m_Rect,ItemBlock.m_ClassId,
ItemBlock.m_HasPersistantData ? spDataStream : NULL);
// add item info to the list
ItemInfoPtrList.push_back(&ItemInfo);
}
return ItemInfoPtrList;
}
void CFormEditor::SaveItemsToStream(const CComPtr<IStream> &spStream,
const CItemInfoPtrList &ItemInfoPtrList)
{
// create the item list header
CStreamItemListHeader ItemListHeader;
ItemListHeader.m_Count=ItemInfoPtrList.size();
ItemListHeader.m_BoundingRect=GetBoundingRectForItems(ItemInfoPtrList);
// write the item list header to the passed stream
ItemListHeader.WriteToStream(spStream);
// for each item
for(CItemInfoPtrList::const_iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// get the item class id
CComPtr<IOleObject> spOleObject;
if(!SUCCEEDED(ItemInfo.m_HostWindow.QueryControl(&spOleObject)))
{
throw std::exception();
}
CLSID ClassId=CLSID_NULL;
if(!SUCCEEDED(spOleObject->GetUserClassID(&ClassId)))
{
throw std::exception();
}
// create the item block
CStreamItemBlock ItemBlock;
ItemBlock.m_Name=ItemInfo.m_Name;
ItemBlock.m_Tag=ItemInfo.m_Tag;
ItemBlock.m_Rect=GetItemRect(ItemInfo);
ItemBlock.m_ClassId=ClassId;
// determine if the item supports stream persistance
CComPtr<IPersistStream> spPersistStream;
if(!SUCCEEDED(ItemInfo.m_HostWindow.QueryControl(&spPersistStream)))
{
// fall back to IPersistStreamInit
(void)ItemInfo.m_HostWindow.QueryControl(
IID_IPersistStreamInit,(void**)&spPersistStream);
}
ItemBlock.m_HasPersistantData=(spPersistStream!=NULL) ? TRUE : FALSE;
// save the item block position
LARGE_INTEGER Offset;
Offset.QuadPart=0;
ULARGE_INTEGER Position;
Position.QuadPart=0;
if(!SUCCEEDED(spStream->Seek(Offset,STREAM_SEEK_CUR,&Position)))
{
throw std::exception();
}
// write the item block to the passed stream
ItemBlock.WriteToStream(spStream);
// write the item data to the passed stream
if(ItemBlock.m_HasPersistantData)
{
// create the data stream
CComPtr<IStream> spDataStream;
if(!SUCCEEDED(CreateStreamOnHGlobal(NULL,TRUE,&spDataStream)))
{
throw std::exception();
}
// initialise the size
ULARGE_INTEGER Size;
Size.QuadPart=0;
if(!SUCCEEDED(spDataStream->SetSize(Size)))
{
throw std::exception();
}
// write the item data to the data stream
if(SUCCEEDED(spPersistStream->Save(spDataStream,TRUE)))
{
// get the data stream size
STATSTG StatStg;
if(!SUCCEEDED(spDataStream->Stat(&StatStg,STATFLAG_NONAME)))
{
throw std::exception();
}
// create the item persistant data header
CStreamItemPersistantDataHeader ItemPersistantDataHeader;
ItemPersistantDataHeader.m_Length=StatStg.cbSize;
// write the item persistant data header to the passed stream
ItemPersistantDataHeader.WriteToStream(spStream);
// seek back to the start of the data stream
LARGE_INTEGER Offset;
Offset.QuadPart=0;
if(!SUCCEEDED(spDataStream->Seek(Offset,STREAM_SEEK_SET,NULL)))
{
throw std::exception();
}
// copy the item data to the passed stream
if(!SUCCEEDED(
spDataStream->CopyTo(spStream,StatStg.cbSize,NULL,NULL)))
{
throw std::exception();
}
}
else // failed to write the item data to the data stream
{
// seek back to the item block position
Offset.QuadPart=Position.QuadPart;
if(!SUCCEEDED(spStream->Seek(Offset,STREAM_SEEK_SET,NULL)))
{
throw std::exception();
}
// indicate the item does not support stream persistance
ItemBlock.m_HasPersistantData=FALSE;
ItemBlock.WriteToStream(spStream);
}
}
}
}
void CFormEditor::ResetScript()
{
// reset the script
if(!SUCCEEDED(m_spScript->Reset()))
{
throw std::exception();
}
}
void CFormEditor::LoadScriptFromStream(
const CComPtr<IStream> &spStream,DWORD StreamVersion)
{
// load the script from the passed stream
if(!SUCCEEDED(m_spScript->LoadFromStream(spStream,StreamVersion)))
{
throw std::exception();
}
}
void CFormEditor::SaveScriptToStream(const CComPtr<IStream> &spStream)
{
// save the script to the passed stream
if(!SUCCEEDED(m_spScript->SaveToStream(spStream)))
{
throw std::exception();
}
}
CItemInfoPtrList CFormEditor::InternalLoad(
const CComPtr<IStream> &spStream,StreamType Type)
{
// perform pre processing based on the stream type
if(Type==StreamTypeFull)
{
// delete all items
DeleteAllItems();
// clear the undo and redo storage
ClearUndoAndRedoStorage();
// reset the scrollbars
(void)SetScrollPos(SB_HORZ,0);
(void)SetScrollPos(SB_VERT,0);
// reset the form position
(void)m_Form.SetWindowPos(NULL,
m_FormDragFrame.GetFrameSize(),m_FormDragFrame.GetFrameSize(),
0,0,SWP_NOZORDER|SWP_NOSIZE|SWP_NOCOPYBITS/*prevent flicker*/);
// reset the script
ResetScript();
}
else if(Type==StreamTypeClipboard)
{
}
else if(Type==StreamTypeUndoRedo)
{
// delete all items
DeleteAllItems();
}
// read in the header
CStreamHeader StreamHeader;
StreamHeader.ReadFromStream(spStream);
// the stream version must be recognisable
if(StreamHeader.m_Version > CStreamHeader().m_Version)
{
throw std::exception();
}
// read in the form
if(Type==StreamTypeFull or Type==StreamTypeUndoRedo)
{
InitialiseFormFromStream(spStream,StreamHeader.m_Version);
}
// read in the item list
BOOL IsPasting=(Type==StreamTypeClipboard) ? TRUE : FALSE;
CItemInfoPtrList ItemInfoPtrList=
CreateItemsFromStream(spStream,StreamHeader.m_Version,IsPasting);
// read in the script
if(Type==StreamTypeFull)
{
LoadScriptFromStream(spStream,StreamHeader.m_Version);
}
// read in the footer
CStreamFooter StreamFooter;
StreamFooter.ReadFromStream(spStream);
return ItemInfoPtrList;
}
void CFormEditor::InternalSave(
const CComPtr<IStream> &spStream,StreamType Type)
{
// write out the header
CStreamHeader StreamHeader;
StreamHeader.WriteToStream(spStream);
// write out the form
if(Type==StreamTypeFull or Type==StreamTypeUndoRedo)
{
SaveFormToStream(spStream);
}
// write out the item list
if(Type==StreamTypeClipboard)
{
// selected items
SaveItemsToStream(spStream,GetSelectedItems());
}
else
{
// all items
SaveItemsToStream(spStream,m_ItemInfoPtrList);
}
// write out the script
if(Type==StreamTypeFull)
{
SaveScriptToStream(spStream);
}
// write out the footer
CStreamFooter StreamFooter;
StreamFooter.WriteToStream(spStream);
}
BOOL CFormEditor::InternalValidateScript()
{
// validate the script
BOOL IsValid=TRUE;
// create the script control
CComPtr<MSScriptControl::IScriptControl> spScriptControl;
if(!SUCCEEDED(spScriptControl.CoCreateInstance(
__uuidof(MSScriptControl::ScriptControl))))
{
throw std::exception();
}
// set the language
if(!SUCCEEDED(spScriptControl->put_Language(CComBSTR(L"VBScript"))))
{
throw std::exception();
}
// get the script text
CComBSTR Text;
if(!SUCCEEDED(m_spScript->get_Text(&Text)))
{
throw std::exception();
}
// load the script text into the script control
if(!SUCCEEDED(spScriptControl->AddCode(Text)))
{
IsValid=FALSE;
// get error information
CComPtr<MSScriptControl::IScriptError> spError;
if(!SUCCEEDED(spScriptControl->get_Error(&spError)))
{
throw std::exception();
}
// source
CComBSTR Source;
if(!SUCCEEDED(spError->get_Source(&Source)))
{
throw std::exception();
}
// line
long Line=0;
if(!SUCCEEDED(spError->get_Line(&Line)))
{
throw std::exception();
}
// number
long Number=0;
if(!SUCCEEDED(spError->get_Number(&Number)))
{
throw std::exception();
}
// description
CComBSTR Description;
if(!SUCCEEDED(spError->get_Description(&Description)))
{
throw std::exception();
}
// edit the error in the script
if(!SUCCEEDED(m_spScript->EditLine(Line-1)))
{
throw std::exception();
}
// fire the script error event
(void)Fire_EditScriptError(Source,Number,Description);
}
return IsValid;
}
void CFormEditor::MoveSelectedItems(MoveType Type)
{
// get the form rect
CRect FormRect(0,0,0,0);
(void)m_Form.GetClientRect(FormRect);
// get the selected items bounding rectangle
CRect BoundingRect=GetBoundingRectForSelectedItems();
// offset the bounding rectangle
switch(Type)
{
case MoveTypeLeft: // left
BoundingRect.OffsetRect(-1,0);
break;
case MoveTypeRight: // right
BoundingRect.OffsetRect(1,0);
break;
case MoveTypeUp: // up
BoundingRect.OffsetRect(0,-1);
break;
case MoveTypeDown: // down
BoundingRect.OffsetRect(0,1);
break;
default: // unknown
ATLASSERT(FALSE);
break;
}
// ensure the bounding rectangle stays within the form
BoundingRect=ForceRectIntoRect(FormRect,BoundingRect);
// determine the final valid offset
CSize FinalOffset=BoundingRect.TopLeft()-
GetBoundingRectForSelectedItems().TopLeft();
// move all selected items
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
for(CItemInfoPtrList::const_iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// get the item rect
CRect ItemRect=GetItemRect(ItemInfo);
// offset the item rect
ItemRect.OffsetRect(FinalOffset);
// move the item
(void)ItemInfo.m_HostWindow.
SetWindowPos(NULL,ItemRect,SWP_NOZORDER|SWP_NOSIZE);
}
}
void CFormEditor::AlignSelectedItems(AlignType Type)
{
// get the selected items bounding rectangle
CRect BoundingRect=GetBoundingRectForSelectedItems();
// align all selected items
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
for(CItemInfoPtrList::const_iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// get the item rect
CRect ItemRect=GetItemRect(ItemInfo);
// offset the item rect
switch(Type)
{
case AlignTypeLeft: // left
ItemRect.OffsetRect(
BoundingRect.left-ItemRect.left,0);
break;
case AlignTypeRight: // right
ItemRect.OffsetRect(
BoundingRect.right-ItemRect.right,0);
break;
case AlignTypeTop: // top
ItemRect.OffsetRect(
0,BoundingRect.top-ItemRect.top);
break;
case AlignTypeBottom: // bottom
ItemRect.OffsetRect(
0,BoundingRect.bottom-ItemRect.bottom);
break;
default: // unknown
ATLASSERT(FALSE);
break;
}
// align the item
(void)ItemInfo.m_HostWindow.
SetWindowPos(NULL,ItemRect,SWP_NOZORDER|SWP_NOSIZE);
}
}
void CFormEditor::AlignSelectedItemsToForm(FormAlignType Type)
{
// get the form rect
CRect FormRect(0,0,0,0);
(void)m_Form.GetClientRect(FormRect);
// get the selected items bounding rectangle
CRect BoundingRect=GetBoundingRectForSelectedItems();
// get the bounding rectangle aligned position
CPoint AlignedPos=CPoint(
(FormRect.Width()-BoundingRect.Width())/2,
(FormRect.Height()-BoundingRect.Height())/2);
// determine the bounding rectangle offset
CSize Offset(0,0);
if(Type==FormAlignTypeHCenter or Type==FormAlignTypeBoth)
{
// horizontal center
Offset.cx=AlignedPos.x-BoundingRect.left;
}
if(Type==FormAlignTypeVCenter or Type==FormAlignTypeBoth)
{
// vertical center
Offset.cy=AlignedPos.y-BoundingRect.top;
}
// align all selected items
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
for(CItemInfoPtrList::const_iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// get the item rect
CRect ItemRect=GetItemRect(ItemInfo);
// offset the item rect
ItemRect.OffsetRect(Offset);
// align the item
(void)ItemInfo.m_HostWindow.
SetWindowPos(NULL,ItemRect,SWP_NOZORDER|SWP_NOSIZE);
}
}
void CFormEditor::SizeSelectedItemsToLargest(SizeType Type)
{
// get the form rect
CRect FormRect(0,0,0,0);
(void)m_Form.GetClientRect(FormRect);
// the width of the largest selected item
long LargestWidth=0;
// the height of the largest selected item
long LargestHeight=0;
// the width and height of the overall largest selected item
CSize LargestOverall(0,0);
// scan selected items for the largest dimensions
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
for(CItemInfoPtrList::const_iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// get the item rect
CRect ItemRect=GetItemRect(ItemInfo);
// update the largest width
LargestWidth=max(LargestWidth,ItemRect.Width());
// update the largest height
LargestHeight=max(LargestHeight,ItemRect.Height());
// update the overall largest
if(ItemRect.Width()*ItemRect.Height() >
LargestOverall.cx*LargestOverall.cy)
{
LargestOverall= // new overall largest
CSize(ItemRect.Width(),ItemRect.Height());
}
}
// size all selected items
for(iter=ItemInfoPtrList.begin();
iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// get the item rect
CRect ItemRect=GetItemRect(ItemInfo);
// size the item rect
switch(Type)
{
case SizeTypeWidth: // width
ItemRect.right=ItemRect.left+LargestWidth;
break;
case SizeTypeHeight: // height
ItemRect.bottom=ItemRect.top+LargestHeight;
break;
case SizeTypeBoth: // width and height
ItemRect.right=ItemRect.left+LargestOverall.cx;
ItemRect.bottom=ItemRect.top+LargestOverall.cy;
break;
default: // unknown
ATLASSERT(FALSE);
}
// ensure the item stays within the form
ItemRect=ForceRectIntoRect(FormRect,ItemRect);
// size the item
(void)ItemInfo.m_HostWindow.SetWindowPos(
NULL,ItemRect,SWP_NOZORDER/* may have to move */);
}
}
void CFormEditor::SizeSelectedItemsToSmallest(SizeType Type)
{
// get the form rect
CRect FormRect(0,0,0,0);
(void)m_Form.GetClientRect(FormRect);
// the width of the smallest selected item
long SmallestWidth=FormRect.Width();
// the height of the smallest selected item
long SmallestHeight=FormRect.Height();
// the width and height of the overall smallest selected item
CSize SmallestOverall(SmallestWidth,SmallestHeight);
// scan selected items for the smallest dimensions
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
for(CItemInfoPtrList::const_iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// get the item rect
CRect ItemRect=GetItemRect(ItemInfo);
// update the smallest width
SmallestWidth=min(SmallestWidth,ItemRect.Width());
// update the smallest height
SmallestHeight=min(SmallestHeight,ItemRect.Height());
// update the overall smallest
if(ItemRect.Width()*ItemRect.Height() <
SmallestOverall.cx*SmallestOverall.cy)
{
SmallestOverall= // new overall smallest
CSize(ItemRect.Width(),ItemRect.Height());
}
}
// size all selected items
for(iter=ItemInfoPtrList.begin();
iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// get the item rect
CRect ItemRect=GetItemRect(ItemInfo);
// size the item rect
switch(Type)
{
case SizeTypeWidth: // width
ItemRect.right=ItemRect.left+SmallestWidth;
break;
case SizeTypeHeight: // height
ItemRect.bottom=ItemRect.top+SmallestHeight;
break;
case SizeTypeBoth: // width and height
ItemRect.right=ItemRect.left+SmallestOverall.cx;
ItemRect.bottom=ItemRect.top+SmallestOverall.cy;
break;
default: // unknown
ATLASSERT(FALSE);
}
// ensure the item stays within the form
ItemRect=ForceRectIntoRect(FormRect,ItemRect);
// size the item
(void)ItemInfo.m_HostWindow.SetWindowPos(
NULL,ItemRect,SWP_NOZORDER/* may have to move */);
}
}
void CFormEditor::SpaceSelectedItemsHorizontally()
{
// there should be at least two items selected
ATLASSERT(GetSelectedItemCount() >= 2);
// get the form rect
CRect FormRect(0,0,0,0);
(void)m_Form.GetClientRect(FormRect);
// get a list of selected items
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
// copy the list to a temporary vector
CItemInfoPtrVector ItemInfoPtrVector;
std::copy(ItemInfoPtrList.begin(),ItemInfoPtrList.end(),
std::back_insert_iterator<CItemInfoPtrVector>(ItemInfoPtrVector));
// sort the vector by horizontal item position
std::sort(ItemInfoPtrVector.begin(),ItemInfoPtrVector.end(),
IsItemHorzontalPositionLess);
// get the left most item rect
CRect LeftMostItemRect=
GetItemRect(*ItemInfoPtrVector[0]);
// get the right most item rect
CRect RightMostItemRect=
GetItemRect(*ItemInfoPtrVector[ItemInfoPtrVector.size()-1]);
// space all selected items
for(long l=1; l<=(long)(ItemInfoPtrVector.size()-2); l++)
{
CItemInfo &ItemInfo=*ItemInfoPtrVector[l];
// determine the required item horizontal position
float FreeWidth=(float)(RightMostItemRect.left-LeftMostItemRect.left);
float Spacing=FreeWidth/(ItemInfoPtrVector.size()-1);
float Position=LeftMostItemRect.left+(l*Spacing);
// get the item rect
CRect ItemRect=GetItemRect(ItemInfo);
// offset the item rect
ItemRect.OffsetRect((int)Position-ItemRect.left,0);
// ensure the item stays within the form
ItemRect=ForceRectIntoRect(FormRect,ItemRect);
// space the item
(void)ItemInfo.m_HostWindow.SetWindowPos(
NULL,ItemRect,SWP_NOZORDER|SWP_NOSIZE);
}
}
void CFormEditor::SpaceSelectedItemsVertically()
{
// there should be at least two items selected
ATLASSERT(GetSelectedItemCount() >= 2);
// get the form rect
CRect FormRect(0,0,0,0);
(void)m_Form.GetClientRect(FormRect);
// get a list of selected items
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
// copy the list to a temporary vector
CItemInfoPtrVector ItemInfoPtrVector;
std::copy(ItemInfoPtrList.begin(),ItemInfoPtrList.end(),
std::back_insert_iterator<CItemInfoPtrVector>(ItemInfoPtrVector));
// sort the vector by vertical item position
std::sort(ItemInfoPtrVector.begin(),ItemInfoPtrVector.end(),
IsItemVerticalPositionLess);
// get the top most item rect
CRect TopMostItemRect=
GetItemRect(*ItemInfoPtrVector[0]);
// get the bottom most item rect
CRect BottomMostItemRect=
GetItemRect(*ItemInfoPtrVector[ItemInfoPtrVector.size()-1]);
// space all selected items
for(long l=1; l<=(long)(ItemInfoPtrVector.size()-2); l++)
{
CItemInfo &ItemInfo=*ItemInfoPtrVector[l];
// determine the required item vertical position
float FreeHeight=(float)(BottomMostItemRect.top-TopMostItemRect.top);
float Spacing=FreeHeight/(ItemInfoPtrVector.size()-1);
float Position=TopMostItemRect.top+(l*Spacing);
// get the item rect
CRect ItemRect=GetItemRect(ItemInfo);
// offset the item rect
ItemRect.OffsetRect(0,(int)Position-ItemRect.top);
// ensure the item stays within the form
ItemRect=ForceRectIntoRect(FormRect,ItemRect);
// space the item
(void)ItemInfo.m_HostWindow.SetWindowPos(
NULL,ItemRect,SWP_NOZORDER|SWP_NOSIZE);
}
}
BOOL CFormEditor::DoesItemRequirePropertyPages(CItemInfo &ItemInfo)
{
// get the items IUnknown interface
CComPtr<IUnknown> spUnknown;
if(!SUCCEEDED(ItemInfo.m_HostWindow.QueryControl(&spUnknown)))
{
throw std::exception();
}
// get the items ISpecifyPropertyPages interface
CComQIPtr<ISpecifyPropertyPages> spSpecifyPropertyPages(spUnknown);
if(spSpecifyPropertyPages==NULL)
{
return FALSE; // no property pages
}
// get a list of property pages required by the item
CAUUID Pages={0,NULL};
if(!SUCCEEDED(spSpecifyPropertyPages->GetPages(&Pages)))
{
throw std::exception();
}
CAutoCoTaskMem<GUID> CoPages(Pages.pElems);
if(Pages.cElems==0)
{
return FALSE; // no property pages
}
return TRUE; // the item requires one or more property pages
}
void CFormEditor::ShowFormProperties()
{
// create the form properties accessor
CComPtr<IFormPropertiesAccessor> spFormPropertiesAccessor;
if(!SUCCEEDED(
CFormPropertiesAccessor::CreateInstance(&spFormPropertiesAccessor)))
{
throw std::exception();
}
// set the form editor
CComQIPtr<IFormEditor> spFormEditor(GetUnknown());
if(spFormEditor==NULL)
{
throw std::exception();
}
if(!SUCCEEDED(spFormPropertiesAccessor->put_FormEditor(spFormEditor)))
{
throw std::exception();
}
// create the property page array
const DWORD NumPages=2;
CAutoCoTaskMem<GUID> CoPages((GUID*)CoTaskMemAlloc(NumPages*sizeof(GUID)));
if(CoPages==NULL)
{
throw std::exception();
}
CAUUID Pages={ NumPages,CoPages };
Pages.pElems[0]=CLSID_StockColorPage;
Pages.pElems[1]=__uuidof(DDPROPPAGEALLLib::PropPageAll);
// get the form properties accessor IUnknown interface
CComPtr<IUnknown> spUnknown=spFormPropertiesAccessor;
// show the form property frame
if(!SUCCEEDED(OleCreatePropertyFrame(*this,0,0,L"Form",1,&spUnknown.p,
Pages.cElems,Pages.pElems,LOCALE_USER_DEFAULT,0,NULL)))
{
throw std::exception();
}
}
void CFormEditor::ShowSelectedItemProperties()
{
// get item info for the selected item
ATLASSERT(GetSelectedItemCount()==1);
CItemInfo &ItemInfo=*GetSelectedItems().front();
// initialise an empty array of property page class ids
CAUUID Pages={ 0,(GUID*)CoTaskMemAlloc(0) };
if(Pages.pElems==NULL)
{
throw std::exception();
}
CAutoCoTaskMem<GUID> CoPages(Pages.pElems);
// get the items IUnknown interface
CComPtr<IUnknown> spUnknown;
if(!SUCCEEDED(ItemInfo.m_HostWindow.QueryControl(&spUnknown)))
{
throw std::exception();
}
// get the items IOleObject interface
CComQIPtr<IOleObject> spOleObject(spUnknown);
if(spOleObject==NULL)
{
throw std::exception();
}
// get the item name
CAutoCoTaskMem<WCHAR> Name;
if(!SUCCEEDED(spOleObject->GetUserType(USERCLASSTYPE_SHORT,&Name)))
{
throw std::exception();
}
// get a list of property pages required by the item
if(DoesItemRequirePropertyPages(ItemInfo))
{
// get the items ISpecifyPropertyPages interface
CComQIPtr<ISpecifyPropertyPages> spSpecifyPropertyPages(spUnknown);
if(spSpecifyPropertyPages==NULL)
{
throw std::exception();
}
// get a list of property pages required by the item
if(!SUCCEEDED(spSpecifyPropertyPages->GetPages(&Pages)))
{
throw std::exception();
}
CoPages=CAutoCoTaskMem<GUID>(Pages.pElems);
}
// make room for the extended property pages
Pages.cElems+=2;
Pages.pElems=(GUID*)CoTaskMemRealloc(
CoPages.Release(),(Pages.cElems)*sizeof(GUID));
if(Pages.pElems==NULL)
{
// todo : this will leak CoTaskMem from the above release
throw std::exception();
}
CoPages=CAutoCoTaskMem<GUID>(Pages.pElems);
// add the extended property pages
Pages.pElems[Pages.cElems-2]=__uuidof(DDPROPPAGEALLLib::PropPageAll);
Pages.pElems[Pages.cElems-1]=CLSID_PropPageExtended;
// show the item property frame
if(!SUCCEEDED(OleCreatePropertyFrame(*this,0,0,Name,1,&spUnknown.p,
Pages.cElems,Pages.pElems,LOCALE_USER_DEFAULT,0,NULL)))
{
throw std::exception();
}
}
void CFormEditor::AddExposedObject(
const std::wstring &Name,const CComPtr<IDispatch> &spDispatch)
{
// the object name should be valid
ATLASSERT(IsNameValid(Name));
// the object name should be unique
ATLASSERT(IsNameUnique(Name));
// add the object to the exposed objects map
m_ExposedObjects[Name]=spDispatch;
}
BOOL CFormEditor::IsEventHandled(
const std::wstring &Source,const std::wstring &Event)
{
// determine if the event is handled by the script
VARIANT_BOOL Handled=VARIANT_FALSE;
if(!SUCCEEDED(m_spScript->IsEventHandled(
CComBSTR(Source.c_str()),CComBSTR(Event.c_str()),&Handled)))
{
throw std::exception();
}
return VB2B(Handled);
}
void CFormEditor::AddEventHandler(const CEventInfo &EventInfo)
{
// add the event handler to the script
if(!SUCCEEDED(m_spScript->AddEventHandler(
CComBSTR(EventInfo.m_SourceName.c_str()),
CComBSTR(EventInfo.m_EventName.c_str()),
CComBSTR(EventInfo.m_ParameterNames.c_str()))))
{
throw std::exception();
}
}
void CFormEditor::EditEventHandler(
const std::wstring &Source,const std::wstring &Event)
{
// edit the event handler in the script
if(!SUCCEEDED(m_spScript->EditEventHandler(
CComBSTR(Source.c_str()),CComBSTR(Event.c_str()))))
{
throw std::exception();
}
}
CMenuHandle CFormEditor::CreateEventMenu(
const std::wstring &SourceName,
const CComPtr<IDispatch> &spDispatch,
CAvailableMenuItemIdSet &AvailableMenuItemIdSet,
CMenuItemIdToEventInfoMap &MenuItemIdToEventInfoMap)
{
// type info for the event interface
CComPtr<ITypeInfo> spTypeInfo;
try
{
// get type info for the coclass
spTypeInfo=GetImplementingCoClassTypeInfo(spDispatch);
// get type info for the event interface
spTypeInfo=GetDefaultSourceInterfaceTypeInfo(spTypeInfo);
}
catch(std::exception &)
{
// return an empty menu since GetImplementingCoClassTypeInfo() and
// GetDefaultSourceInterfaceTypeInfo() may fail for valid reasons
return CreateEmptyPopupMenu(IDS_EMPTY);
}
// create the event menu
return CreateEventMenu(SourceName,spTypeInfo,
AvailableMenuItemIdSet,MenuItemIdToEventInfoMap);
}
CMenuHandle CFormEditor::CreateEventMenu(
const std::wstring &SourceName,
const CComPtr<ITypeInfo> &spTypeInfo,
CAvailableMenuItemIdSet &AvailableMenuItemIdSet,
CMenuItemIdToEventInfoMap &MenuItemIdToEventInfoMap)
{
USES_CONVERSION;
// create the event menu
CMenu Menu;
if(Menu.CreatePopupMenu()==FALSE)
{
throw std::exception();
}
// get the number of events on the interface
CAutoTypeAttrPtr pTypeAttr(spTypeInfo);
long EventCount=pTypeAttr->cFuncs;
// add all events to the event menu
for(long l=0; l<EventCount; l++)
{
// get the event name
std::wstring EventName=GetFunctionName(l,spTypeInfo);
// determine if the event is handled by the script
BOOL Handled=IsEventHandled(SourceName,EventName);
// get the next available menu item id
if(AvailableMenuItemIdSet.size()==0)
{
throw std::exception();
}
DWORD Id=*AvailableMenuItemIdSet.begin();
// update the set
AvailableMenuItemIdSet.erase(Id);
// insert the new menu item
if(Menu.AppendMenu(MF_STRING|Handled ? MF_CHECKED : MF_UNCHECKED,
Id,W2CT(EventName.c_str()))==FALSE)
{
throw std::exception();
}
// create event info
CEventInfo EventInfo;
EventInfo.m_SourceName=SourceName;
EventInfo.m_EventName=EventName;
EventInfo.m_ParameterNames=
GetCommaSeperatedFunctionParameterNames(l,spTypeInfo);
// update the menu item id to event info map
MenuItemIdToEventInfoMap[Id]=EventInfo;
}
// return the event menu
return Menu.GetMenuItemCount() ? Menu.Detach() :
// or an empty menu if the event menu is empty
CreateEmptyPopupMenu(IDS_EMPTY);
}
CMenuHandle CFormEditor::CreateFormEventMenu(
CAvailableMenuItemIdSet &AvailableMenuItemIdSet,
CMenuItemIdToEventInfoMap &MenuItemIdToEventInfoMap)
{
// load in the type library
CComPtr<ITypeLib> spTypeLib;
if(!SUCCEEDED(LoadRegTypeLib(LIBID_DDFORMSLib,
TlbVerMaj,TlbVerMin,LOCALE_USER_DEFAULT,&spTypeLib)))
{
throw std::exception();
}
// get type info for the form viewer script events interface
CComPtr<ITypeInfo> spTypeInfo;
if(!SUCCEEDED(spTypeLib->GetTypeInfoOfGuid(
DIID__IViewableFormEvents,&spTypeInfo)))
{
throw std::exception();
}
// create the form event menu
return CreateEventMenu(m_FormName,spTypeInfo,
AvailableMenuItemIdSet,MenuItemIdToEventInfoMap);
}
CMenuHandle CFormEditor::CreateItemEventMenu(
CItemInfo &ItemInfo,
CAvailableMenuItemIdSet &AvailableMenuItemIdSet,
CMenuItemIdToEventInfoMap &MenuItemIdToEventInfoMap)
{
// get the items IDispatch interface
CComPtr<IDispatch> spDispatch;
if(!SUCCEEDED(ItemInfo.m_HostWindow.QueryControl(&spDispatch)))
{
throw std::exception();
}
// create the item event menu
return CreateEventMenu(ItemInfo.m_Name,spDispatch,
AvailableMenuItemIdSet,MenuItemIdToEventInfoMap);
}
CMenuHandle CFormEditor::CreateExposedObjectEventMenu(
const std::wstring &Name,
CAvailableMenuItemIdSet &AvailableMenuItemIdSet,
CMenuItemIdToEventInfoMap &MenuItemIdToEventInfoMap)
{
// create the exposed object event menu
return CreateEventMenu(Name,m_ExposedObjects[Name],
AvailableMenuItemIdSet,MenuItemIdToEventInfoMap);
}
CMenuHandle CFormEditor::CreateExposedObjectsMenu(
CAvailableMenuItemIdSet &AvailableMenuItemIdSet,
CMenuItemIdToEventInfoMap &MenuItemIdToEventInfoMap)
{
USES_CONVERSION;
// create the exposed objects menu
CMenu Menu;
if(Menu.CreatePopupMenu()==FALSE)
{
throw std::exception();
}
// add all exposed objects to the exposed objects menu
for(CObjectNameToIDispatchMap::const_iterator iter=m_ExposedObjects.begin();
iter!=m_ExposedObjects.end(); iter++)
{
// get the exposed object name
std::wstring Name=iter->first;
// get the next available menu item id
if(AvailableMenuItemIdSet.size()==0)
{
throw std::exception();
}
DWORD Id=*AvailableMenuItemIdSet.begin();
// update the set
AvailableMenuItemIdSet.erase(Id);
// insert the new menu item
if(Menu.AppendMenu(MF_STRING,Id,W2CT(Name.c_str()))==FALSE)
{
throw std::exception();
}
// insert the event menu
SetPopupMenu((HMENU)Menu,Id,
CreateExposedObjectEventMenu(Name,
AvailableMenuItemIdSet,MenuItemIdToEventInfoMap));
}
// return the exposed objects menu
return Menu.Detach();
}
void CFormEditor::DFNS_BeginMove()
{
// get the editor state
CFormEditorState State=GetState();
// hide all drag frames
HideAllDragFrames();
(void)UpdateWindow();
// modify the form window style to allow us to draw over everything
(void)m_Form.UpdateWindow();
(void)m_Form.ModifyStyle(WS_CLIPCHILDREN,0);
// initialise the drag rects
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
for(CItemInfoPtrList::const_iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// initialise the drag rect
ItemInfo.m_LastDragRect=CRect(0,0,0,0);
}
// set the busy flag
SetBusy(TRUE);
FireStateChangedEvent(State); // state changed
}
void CFormEditor::DFNS_Move(long cx,long cy)
{
// if the alt key is down the grid settings are ignored
BOOL IgnoreGrid=
(GetKeyState(VK_MENU) & 0x80000000) ? TRUE : FALSE;
// get the form rect
CRect FormRect(0,0,0,0);
(void)m_Form.GetClientRect(FormRect);
// get the selected items bounding rectangle
CRect BoundingRect=GetBoundingRectForSelectedItems();
// offset the bounding rectangle
BoundingRect.OffsetRect(cx,cy);
// snap the bounding rectangle to the grid
if(IgnoreGrid==FALSE)
{
BoundingRect=SnapRectToGrid(BoundingRect);
}
// ensure the bounding rectangle stays within the form
BoundingRect=ForceRectIntoRect(FormRect,BoundingRect);
// determine the final valid offset
CSize FinalOffset=BoundingRect.TopLeft()-
GetBoundingRectForSelectedItems().TopLeft();
// update the drag rects
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
for(CItemInfoPtrList::const_iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// get the new drag rect
CRect DragRect=GetItemRect(ItemInfo);
DragRect.OffsetRect(FinalOffset);
// update the drag rect
CSize Size(DRAG_RECT_SIZE,DRAG_RECT_SIZE);
DrawDragRect(CClientDC(m_Form),
DragRect,Size,ItemInfo.m_LastDragRect,Size);
// save the new drag rect
ItemInfo.m_LastDragRect=DragRect;
}
}
void CFormEditor::DFNS_EndMove()
{
// get the editor state
CFormEditorState State=GetState();
// update the undo storage
UpdateUndoStorage();
// clean up the drag rects
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
for(CItemInfoPtrList::const_iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// remove the drag rect from the form
CSize Size(DRAG_RECT_SIZE,DRAG_RECT_SIZE);
DrawDragRect(CClientDC(m_Form),
CRect(0,0,0,0),Size,ItemInfo.m_LastDragRect,Size);
}
// move the items
for(iter=ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// if the drag rect is empty the user has not moved the item
if(ItemInfo.m_LastDragRect!=CRect(0,0,0,0))
{
// move the item
(void)ItemInfo.m_HostWindow.SetWindowPos(
NULL,ItemInfo.m_LastDragRect,SWP_NOZORDER|SWP_NOSIZE);
}
}
// resore the form window style
(void)m_Form.ModifyStyle(0,WS_CLIPCHILDREN);
// restore and reposition all drag frames
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
// reset the busy flag
SetBusy(FALSE);
FireStateChangedEvent(State); // state changed
}
void CFormEditor::DFNS_BeginSize()
{
// if the form is selected
if(IsFormSelected())
{
// simulate the notification
DFNS_BeginSizeForm();
return;
}
// get the editor state
CFormEditorState State=GetState();
// get item info for the selected item
ATLASSERT(GetSelectedItemCount()==1);
CItemInfo &ItemInfo=*GetSelectedItems().front();
// hide all drag frames
HideAllDragFrames();
(void)UpdateWindow();
// modify the form window style to allow us to draw over everything
(void)m_Form.UpdateWindow();
(void)m_Form.ModifyStyle(WS_CLIPCHILDREN,0);
// initialise the drag rect
ItemInfo.m_LastDragRect=CRect(0,0,0,0);
// set the busy flag
SetBusy(TRUE);
FireStateChangedEvent(State); // state changed
}
void CFormEditor::DFNS_Size(CDragFrame::DragHandle Handle,long cx,long cy)
{
// if the form is selected
if(IsFormSelected())
{
// simulate the notification
DFNS_SizeForm(Handle,cx,cy);
return;
}
// get item info for the selected item
ATLASSERT(GetSelectedItemCount()==1);
CItemInfo &ItemInfo=*GetSelectedItems().front();
// if the alt key is down the grid settings are ignored
BOOL IgnoreGrid=
(GetKeyState(VK_MENU) & 0x80000000) ? TRUE : FALSE;
// get the form rect
CRect FormRect(0,0,0,0);
(void)m_Form.GetClientRect(FormRect);
// get the item rect
CRect ItemRect=GetItemRect(ItemInfo);
// left edge size
if( Handle==CDragFrame::DragHandleBottomLeft or
Handle==CDragFrame::DragHandleLeft or
Handle==CDragFrame::DragHandleTopLeft)
{
// get the top left corner
CPoint TopLeft=ItemRect.TopLeft();
// apply the horizontal offset
TopLeft.x+=cx;
if(IgnoreGrid==FALSE) // snap the top left corner to the grid
{
TopLeft=SnapPosToGrid(TopLeft);
}
ItemRect.left=TopLeft.x;
// ensure the item width is not too small
if(ItemRect.Width() < MIN_ITEM_WIDTH)
{
ItemRect.left=ItemRect.right-MIN_ITEM_WIDTH;
}
// ensure the item stays within the form
(void)ItemRect.IntersectRect(FormRect,ItemRect);
}
// top edge size
if( Handle==CDragFrame::DragHandleTopLeft or
Handle==CDragFrame::DragHandleTop or
Handle==CDragFrame::DragHandleTopRight)
{
// get the top left corner
CPoint TopLeft=ItemRect.TopLeft();
// apply the vertical offset
TopLeft.y+=cy;
if(IgnoreGrid==FALSE) // snap the top left corner to the grid
{
TopLeft=SnapPosToGrid(TopLeft);
}
ItemRect.top=TopLeft.y;
// ensure the item height is not too small
if(ItemRect.Height() < MIN_ITEM_HEIGHT)
{
ItemRect.top=ItemRect.bottom-MIN_ITEM_HEIGHT;
}
// ensure the item stays within the form
(void)ItemRect.IntersectRect(FormRect,ItemRect);
}
// right edge size
if( Handle==CDragFrame::DragHandleTopRight or
Handle==CDragFrame::DragHandleRight or
Handle==CDragFrame::DragHandleBottomRight)
{
// get the bottom right corner
CPoint BottomRight=ItemRect.BottomRight();
// apply the horizontal offset
BottomRight.x+=cx;
if(IgnoreGrid==FALSE) // snap the bottom right corner to the grid
{
BottomRight=SnapPosToGrid(BottomRight);
}
ItemRect.right=BottomRight.x;
// ensure the item width is not too small
if(ItemRect.Width() < MIN_ITEM_WIDTH)
{
ItemRect.right=ItemRect.left+MIN_ITEM_WIDTH;
}
// ensure the item stays within the form
(void)ItemRect.IntersectRect(FormRect,ItemRect);
}
// bottom edge size
if( Handle==CDragFrame::DragHandleBottomRight or
Handle==CDragFrame::DragHandleBottom or
Handle==CDragFrame::DragHandleBottomLeft)
{
// get the bottom right corner
CPoint BottomRight=ItemRect.BottomRight();
// apply the vertical offset
BottomRight.y+=cy;
if(IgnoreGrid==FALSE) // snap the bottom right corner to the grid
{
BottomRight=SnapPosToGrid(BottomRight);
}
ItemRect.bottom=BottomRight.y;
// ensure the item height is not too small
if(ItemRect.Height() < MIN_ITEM_HEIGHT)
{
ItemRect.bottom=ItemRect.top+MIN_ITEM_HEIGHT;
}
// ensure the item stays within the form
(void)ItemRect.IntersectRect(FormRect,ItemRect);
}
// get the new drag rect
CRect DragRect=ItemRect;
// update the drag rect
CSize Size(DRAG_RECT_SIZE,DRAG_RECT_SIZE);
DrawDragRect(CClientDC(m_Form),
DragRect,Size,ItemInfo.m_LastDragRect,Size);
// save the new drag rect
ItemInfo.m_LastDragRect=DragRect;
}
void CFormEditor::DFNS_EndSize()
{
// if the form is selected
if(IsFormSelected())
{
// simulate the notification
DFNS_EndSizeForm();
return;
}
// get the editor state
CFormEditorState State=GetState();
// get item info for the selected item
ATLASSERT(GetSelectedItemCount()==1);
CItemInfo &ItemInfo=*GetSelectedItems().front();
// update the undo storage
UpdateUndoStorage();
// remove the drag rect from the form
CSize Size(DRAG_RECT_SIZE,DRAG_RECT_SIZE);
DrawDragRect(CClientDC(m_Form),
CRect(0,0,0,0),Size,ItemInfo.m_LastDragRect,Size);
// if the drag rect is empty the user has not sized the item
if(ItemInfo.m_LastDragRect!=CRect(0,0,0,0))
{
// size the item
(void)ItemInfo.m_HostWindow.SetWindowPos(
NULL,ItemInfo.m_LastDragRect,SWP_NOZORDER);
}
// resore the form window style
(void)m_Form.ModifyStyle(0,WS_CLIPCHILDREN);
// restore and reposition all drag frames
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
// reset the busy flag
SetBusy(FALSE);
FireStateChangedEvent(State); // state changed
}
void CFormEditor::DFNS_ContextMenu()
{
// show the context menu
// note that PostMessage() must be used here rather than SendMessage()
// since the drag frame which this notification originated from could
// be destroyed by the context menu handler
(void)PostMessage(WM_CONTEXTMENU_INDIRECT);
}
void CFormEditor::DFNS_BeginSizeForm()
{
// get the editor state
CFormEditorState State=GetState();
// hide all drag frames
HideAllDragFrames();
(void)UpdateWindow();
// modify the window style to allow us to draw over everything
(void)UpdateWindow();
(void)ModifyStyle(WS_CLIPCHILDREN,0);
// initialise the drag rect
m_LastFormDragRect=CRect(0,0,0,0);
// set the busy flag
SetBusy(TRUE);
FireStateChangedEvent(State); // state changed
}
void CFormEditor::DFNS_SizeForm(CDragFrame::DragHandle Handle,long cx,long cy)
{
// check the drag handle is valid
ATLASSERT(
Handle==CDragFrame::DragHandleRight or
Handle==CDragFrame::DragHandleBottomRight or
Handle==CDragFrame::DragHandleBottom);
// if the alt key is down the grid settings are ignored
BOOL IgnoreGrid=
(GetKeyState(VK_MENU) & 0x80000000) ? TRUE : FALSE;
// get the form rect
CRect FormRect(0,0,0,0);
(void)m_Form.GetClientRect(FormRect);
// get the minimum form dimensions
long MinWidth=max(
MIN_FORM_WIDTH,GetBoundingRectForAllItems().right);
long MinHeight=max(
MIN_FORM_HEIGHT,GetBoundingRectForAllItems().bottom);
// get the bottom right corner
CPoint BottomRight=FormRect.BottomRight();
// apply the horizontal offset
if( Handle==CDragFrame::DragHandleRight or
Handle==CDragFrame::DragHandleBottomRight)
{
BottomRight+=CPoint(cx,0);
}
// apply the vertical offset
if( Handle==CDragFrame::DragHandleBottomRight or
Handle==CDragFrame::DragHandleBottom)
{
BottomRight+=CPoint(0,cy);
}
// snap the bottom right corner to the grid
if(IgnoreGrid==FALSE)
{
BottomRight=SnapPosToGrid(BottomRight);
}
// update the form rect
FormRect.right=BottomRight.x;
FormRect.bottom=BottomRight.y;
// ensure the width is in range
FormRect.right=min(FormRect.right,MAX_FORM_WIDTH);
FormRect.right=max(FormRect.right,MinWidth);
// ensure the height is in range
FormRect.bottom=min(FormRect.bottom,MAX_FORM_HEIGHT);
FormRect.bottom=max(FormRect.bottom,MinHeight);
// get the new drag rect
CRect DragRect=FormRect;
DragRect.OffsetRect( // offset due to the drag frame
m_FormDragFrame.GetFrameSize(),m_FormDragFrame.GetFrameSize());
DragRect.OffsetRect( // offset due to the scroll position
-GetScrollPos(SB_HORZ),-GetScrollPos(SB_VERT));
// update the drag rect
CSize Size(DRAG_RECT_SIZE,DRAG_RECT_SIZE);
DrawDragRect(CClientDC(*this),
DragRect,Size,m_LastFormDragRect,Size);
// save the new drag rect
m_LastFormDragRect=DragRect;
}
void CFormEditor::DFNS_EndSizeForm()
{
// get the editor state
CFormEditorState State=GetState();
// update the undo storage
UpdateUndoStorage();
// remove the drag rect
CSize Size(DRAG_RECT_SIZE,DRAG_RECT_SIZE);
DrawDragRect(CClientDC(*this),
CRect(0,0,0,0),Size,m_LastFormDragRect,Size);
// if the drag rect is empty the user has not sized the form
if(m_LastFormDragRect!=CRect(0,0,0,0))
{
// size the form
SetFormDimensions(
m_LastFormDragRect.Width(),m_LastFormDragRect.Height());
}
// resore the window style
(void)ModifyStyle(0,WS_CLIPCHILDREN);
// restore and reposition all drag frames
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
// reset the busy flag
SetBusy(FALSE);
FireStateChangedEvent(State); // state changed
}
HRESULT CFormEditor::OnDraw(ATL_DRAWINFO &di)
{
// ATL wizard generated
IMP_BEGIN
// dc wrapper
CDCHandle dc(di.hdcDraw);
// bounding rectangle
CRect Rect=*(RECT*)di.prcBounds;
// 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
(void)dc.Rectangle(Rect);
// show text
LPCTSTR pszText=_T("FormEditor");
(void)dc.SetTextAlign(TA_CENTER|TA_BASELINE);
(void)dc.TextOut(
(Rect.left+Rect.right)/2,(Rect.top+Rect.bottom)/2,
pszText,lstrlen(pszText));
}
else
{
// fill in the background
COLORREF RGBBackColor=RGB(0,0,0);
if(!SUCCEEDED(OleTranslateColor(m_BackColor,NULL,&RGBBackColor)))
{
throw std::exception();
}
dc.FillSolidRect(Rect,RGBBackColor);
// update all drag frames
if(IsFormSelected())
{
// form drag frame
(void)m_FormDragFrame.Invalidate(FALSE);
}
// item drag frames
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
for(CItemInfoPtrList::const_iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// update the drag frame
(void)ItemInfo.m_DragFrame.Invalidate(FALSE);
}
}
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::OnAmbientPropertyChange(DISPID dispid)
{
IMP_BEGIN
// call the base class
HRESULT hr=IOleControlImpl<CFormEditor>::OnAmbientPropertyChange(dispid);
ATLASSERT(hr==S_OK); // S_OK is the only valid return value
// if the user mode ambient property has changed
if((dispid==DISPID_AMBIENT_USERMODE or dispid==DISPID_UNKNOWN) and
// the editor may not have been created by the container if it
// prefers to create a window only for us to draw on in design mode
IsWindow())
{
// the editor should not be busy
ATLASSERT(m_Busy==FALSE);
// hide the form tab number in run mode
(void)m_FormTabNumber.ShowWindow(InRunMode() ? SW_HIDE : SW_SHOW);
// disable the editor in design mode
(void)EnableWindow(InDesignMode() ? FALSE : TRUE);
}
IMP_END
return S_OK; // must always return S_OK
}
LRESULT CFormEditor::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// set the window style
if(m_BorderVisible==VARIANT_FALSE)
{
(void)ModifyStyleEx(WS_EX_CLIENTEDGE,0);
}
// set the scrollbar ranges
long DragFrameSize=m_FormDragFrame.GetFrameSize();
if(SetScrollRange(
SB_HORZ,0,MAX_FORM_WIDTH+(2*DragFrameSize),FALSE)==FALSE)
{
throw std::exception();
}
if(SetScrollRange(
SB_VERT,0,MAX_FORM_HEIGHT+(2*DragFrameSize),FALSE)==FALSE)
{
throw std::exception();
}
// set the timer
if(SetTimer(TIMER_ID,TIMER_ELAPSE)==0)
{
throw std::exception();
}
// enable control containment
if(AtlAxWinInit()==FALSE)
{
throw std::exception();
}
// create the script
if(m_spScript==NULL)
{
if(!SUCCEEDED(CScript::CreateInstance(&m_spScript)))
{
throw std::exception();
}
}
// the form dimensions and colors should be saved as the default
m_Form.GetDimensions(m_DefaultFormWidth,m_DefaultFormHeight);
m_Form.GetColors(m_DefaultFormBackColor,m_DefaultFormForeColor);
// create the form
CRect FormRect(0,0,m_DefaultFormWidth,m_DefaultFormHeight);
FormRect.OffsetRect(DragFrameSize,DragFrameSize);
if(m_Form.Create(*this,FormRect,_T("EditableForm"),
WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|WS_DISABLED,WS_EX_CONTROLPARENT)==NULL)
{
throw std::exception();
}
// create the form tab number
if(m_FormTabNumber.Create(m_Form,m_Form,0)==FALSE)
{
throw std::exception();
}
m_FormTabNumber.SetTabNumber(0);
// create the item root window
m_ItemRootWindow.m_hWnd=NULL; // allow the wrapper to be reused
if(m_ItemRootWindow.Create(_T("STATIC"),
m_Form,CRect(0,0,0,0),_T("ItemRootWindow"),WS_CHILD|WS_DISABLED,0)==NULL)
{
throw std::exception();
}
// register the custom clipboard format
m_ClipboardFormatId=RegisterClipboardFormat(CLIPBOARD_FORMAT_NAME);
if(m_ClipboardFormatId==0)
{
throw std::exception();
}
// create the undo storage
if(m_UndoStorage.IsCreated()==FALSE)
{
m_UndoStorage.Create();
}
// create the redo storage
if(m_RedoStorage.IsCreated()==FALSE)
{
m_RedoStorage.Create();
}
// select the form
SelectForm();
// hide the form tab number in run mode
if(InRunMode())
{
(void)m_FormTabNumber.ShowWindow(SW_HIDE);
}
// disable the editor in design mode
if(InDesignMode())
{
(void)EnableWindow(FALSE);
}
// initial state
FireStateChangedEvent(CFormEditorState(),TRUE);
CATCH_ALL
return Caught ? -1 : 0; // fail creation if an exception was thrown
}
LRESULT CFormEditor::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// the editor should not be busy
ATLASSERT(m_Busy==FALSE);
// kill the timer
(void)KillTimer(TIMER_ID);
// clean up on deactivation
// this is required since the editor state and all properties
// must still be valid if queried in the deactive state
DeleteAllItems();
// make the next activation like a first time activation
if(m_UndoStorage.IsCreated())
{
ClearUndoStorage();
}
if(m_RedoStorage.IsCreated())
{
ClearRedoStorage();
}
SetModified(FALSE);
// deactivated state
FireStateChangedEvent(CFormEditorState(),TRUE);
CATCH_ALL
return 0;
}
LRESULT CFormEditor::OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// to prevent flicker do not erase the background
return TRUE;
}
LRESULT CFormEditor::OnHScroll(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// get our client rect
CRect ClientRect(0,0,0,0);
(void)GetClientRect(ClientRect);
// get the minimum and maximum scroll positions
int MinPos=0;
int MaxPos=0;
(void)GetScrollRange(SB_HORZ,&MinPos,&MaxPos);
// get the new scroll position
long ScrollPos=GetScrollPos(SB_HORZ);
switch(LOWORD(wParam))
{
case SB_ENDSCROLL:
// ignored until later
break;
case SB_LEFT:
ScrollPos=MinPos;
break;
case SB_RIGHT:
ScrollPos=MaxPos;
break;
case SB_LINELEFT:
ScrollPos-=HSCROLL_LINE_SIZE;
break;
case SB_LINERIGHT:
ScrollPos+=HSCROLL_LINE_SIZE;
break;
case SB_PAGELEFT:
ScrollPos-=ClientRect.Width();
break;
case SB_PAGERIGHT:
ScrollPos+=ClientRect.Width();
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
ScrollPos=HIWORD(wParam);
break;
default:
ATLASSERT(FALSE); // unexpected
break;
}
if(LOWORD(wParam)!=SB_ENDSCROLL)
{
// hide all drag frames
HideAllDragFrames();
// hide all tab numbers
if(m_TabOrderingModeActive)
{
HideAllTabNumbers();
}
// check the new scroll position is in range
ScrollPos=min(ScrollPos,MaxPos);
ScrollPos=max(ScrollPos,MinPos);
// update the scrollbar
(void)SetScrollPos(SB_HORZ,ScrollPos);
// scroll the form horizontally
CRect FormRect(0,0,0,0);
(void)m_Form.GetWindowRect(FormRect); // window rect
(void)ScreenToClient(FormRect); // reletive to our client
(void)m_Form.SetWindowPos(NULL,
(-ScrollPos)+m_FormDragFrame.GetFrameSize(),FormRect.top,
0,0,SWP_NOZORDER|SWP_NOSIZE);
}
else
{
// restore and reposition all drag frames
RestoreAndRepositionAllDragFrames();
// restore and reposition all tab numbers
if(m_TabOrderingModeActive)
{
RestoreAndRepositionAllTabNumbers();
}
}
CATCH_ALL
return 0;
}
LRESULT CFormEditor::OnVScroll(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// get our client rect
CRect ClientRect(0,0,0,0);
(void)GetClientRect(ClientRect);
// get the minimum and maximum scroll positions
int MinPos=0;
int MaxPos=0;
(void)GetScrollRange(SB_VERT,&MinPos,&MaxPos);
// get the new scroll position
long ScrollPos=GetScrollPos(SB_VERT);
switch(LOWORD(wParam))
{
case SB_ENDSCROLL:
// ignored until later
break;
case SB_TOP:
ScrollPos=MinPos;
break;
case SB_BOTTOM:
ScrollPos=MaxPos;
break;
case SB_LINEUP:
ScrollPos-=VSCROLL_LINE_SIZE;
break;
case SB_LINEDOWN:
ScrollPos+=VSCROLL_LINE_SIZE;
break;
case SB_PAGEUP:
ScrollPos-=ClientRect.Height();
break;
case SB_PAGEDOWN:
ScrollPos+=ClientRect.Height();
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
ScrollPos=HIWORD(wParam);
break;
default:
ATLASSERT(FALSE); // unexpected
break;
}
if(LOWORD(wParam)!=SB_ENDSCROLL)
{
// hide all drag frames
HideAllDragFrames();
// hide all tab numbers
if(m_TabOrderingModeActive)
{
HideAllTabNumbers();
}
// check the new scroll position is in range
ScrollPos=min(ScrollPos,MaxPos);
ScrollPos=max(ScrollPos,MinPos);
// update the scrollbar
(void)SetScrollPos(SB_VERT,ScrollPos);
// scroll the form vertically
CRect FormRect(0,0,0,0);
(void)m_Form.GetWindowRect(FormRect); // window rect
(void)ScreenToClient(FormRect); // reletive to our client
(void)m_Form.SetWindowPos(NULL,
FormRect.left,(-ScrollPos)+m_FormDragFrame.GetFrameSize(),
0,0,SWP_NOZORDER|SWP_NOSIZE);
}
else
{
// restore and reposition all drag frames
RestoreAndRepositionAllDragFrames();
// restore and reposition all tab numbers
if(m_TabOrderingModeActive)
{
RestoreAndRepositionAllTabNumbers();
}
}
CATCH_ALL
return 0;
}
LRESULT CFormEditor::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// apply special processing if the editor is in tab ordering mode
if(m_TabOrderingModeActive)
{
// see which item was clicked
CItemInfo *pItemInfo=HitTest(ClientPosToFormPos(
CPoint(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam))));
if(pItemInfo!=NULL)
{
// update the item tab order
UpdateItemTabOrder(*pItemInfo);
}
else
{
// switch the editor back from tab ordering mode
EndSetTabOrder();
SelectForm();
}
return 0;
}
// get the editor state
CFormEditorState State=GetState();
// unselect the form
UnselectForm();
// if the ctrl key is not down unselect all items
if(!(wParam & MK_CONTROL))
{
UnselectAllItems();
}
// see which item was clicked
CItemInfo *pItemInfo=HitTest(ClientPosToFormPos(
CPoint(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam))));
if(pItemInfo!=NULL)
{
// select the item
SelectItem(*pItemInfo);
// activate the item drag frame to allow immediate actions
pItemInfo->m_DragFrame.ExternalActivate();
}
else
{
// initialise the selection box settings
ATLASSERT(m_SelectionBoxActive==FALSE);
m_SelectionBoxActive=TRUE;
m_SelectionBoxAnchorPos=
CPoint(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));
m_LastSelectionBoxDragRect=CRect(0,0,0,0);
// capture the cursor
(void)SetCapture();
// modify the window style to allow us to draw over everything
(void)UpdateWindow();
(void)ModifyStyle(WS_CLIPCHILDREN,0);
// set the busy flag
SetBusy(TRUE);
}
FireStateChangedEvent(State); // state may have changed
CATCH_ALL
return 0;
}
LRESULT CFormEditor::OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// get the editor state
CFormEditorState State=GetState();
if(m_SelectionBoxActive)
{
// remove the selection box drag rect
CSize Size(DRAG_RECT_SIZE,DRAG_RECT_SIZE);
DrawDragRect(CClientDC(*this),
m_LastSelectionBoxDragRect,Size,CRect(0,0,0,0),Size);
// select all items contained within the selection box
SelectAllItemsInRect(
ClientRectToFormRect(m_LastSelectionBoxDragRect));
// if no items were selected select the form
if(GetSelectedItemCount()==0)
{
SelectForm();
}
// clean up the selection box settings
m_SelectionBoxActive=FALSE;
// release the cursor
// we need to be careful here since ReleaseCapture() calls
// OnCaptureChanged() which in turn calls us back just incase
// the capture was taken from under our feet
if(GetCapture()==*this)
{
(void)ReleaseCapture();
}
// restore the window style
(void)ModifyStyle(0,WS_CLIPCHILDREN);
// reset the busy flag
SetBusy(FALSE);
}
FireStateChangedEvent(State); // state may have changed
CATCH_ALL
return 0;
}
LRESULT CFormEditor::OnRButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// do nothing if the editor is busy
if(m_Busy)
{
return 0;
}
// get the editor state
CFormEditorState State=GetState();
// see which item was clicked
CItemInfo *pItemInfo=HitTest(ClientPosToFormPos(
CPoint(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam))));
if(pItemInfo!=NULL)
{
// unselect the form
UnselectForm();
// unselect all items
UnselectAllItems();
// select the item
SelectItem(*pItemInfo);
}
else
{
// unselect all items
UnselectAllItems();
// select the form
SelectForm();
}
FireStateChangedEvent(State); // state may have changed
CATCH_ALL
return 0;
}
LRESULT CFormEditor::OnRButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// show the context menu
(void)PostMessage(WM_CONTEXTMENU_INDIRECT);
CATCH_ALL
return 0;
}
LRESULT CFormEditor::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
if(m_SelectionBoxActive)
{
// get the new selection box drag rect
CRect DragRect(m_SelectionBoxAnchorPos,
CPoint(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)));
DragRect.NormalizeRect();
// update the selection box drag rect
CSize Size(DRAG_RECT_SIZE,DRAG_RECT_SIZE);
DrawDragRect(CClientDC(*this),
DragRect,Size,m_LastSelectionBoxDragRect,Size);
// save the new selection box drag rect
m_LastSelectionBoxDragRect=DragRect;
}
CATCH_ALL
return 0;
}
LRESULT CFormEditor::OnCaptureChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// simulate a left button up message
BOOL Dummy=FALSE;
(void)OnLButtonUP(WM_LBUTTONUP,0,0,Dummy);
CATCH_ALL
return 0;
}
LRESULT CFormEditor::OnContextMenuIndirect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// show the context menu
(void)SendMessage(WM_CONTEXTMENU,0,-1);
CATCH_ALL
return 0;
}
LRESULT CFormEditor::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// do nothing if the editor is busy
if(m_Busy)
{
return 0;
}
// get the editor state
CFormEditorState State=GetState();
// load in the context menu
CMenu ParentMenu;
if(ParentMenu.LoadMenu(IDR_CTXMENU_FORMEDITOR)==FALSE)
{
throw std::exception();
}
CMenuHandle hMenu=ParentMenu.GetSubMenu(0);
if(hMenu==NULL)
{
throw std::exception();
}
// enable menu items which require a selection
if(GetSelectedItemCount()==0)
{
// cut
(void)hMenu.EnableMenuItem(
ID_CUT,MF_BYCOMMAND|MF_GRAYED);
// copy
(void)hMenu.EnableMenuItem(
ID_COPY,MF_BYCOMMAND|MF_GRAYED);
// delete
(void)hMenu.EnableMenuItem(
ID_DELETE,MF_BYCOMMAND|MF_GRAYED);
}
// enable menu items which require a single selection
if(GetSelectedItemCount() > 1)
{
// events
(void)hMenu.EnableMenuItem(
ID_EVENTS,MF_BYCOMMAND|MF_GRAYED);
// properties
(void)hMenu.EnableMenuItem(
ID_PROPERTIES,MF_BYCOMMAND|MF_GRAYED);
}
// enable menu items which require a selection
if(GetSelectedItemCount()==0 or
// but not everything should be selected
GetSelectedItemCount()==m_ItemInfoPtrList.size())
{
// send to back
(void)hMenu.EnableMenuItem(
ID_SENDTOBACK,MF_BYCOMMAND|MF_GRAYED);
// bring to front
(void)hMenu.EnableMenuItem(
ID_BRINGTOFRONT,MF_BYCOMMAND|MF_GRAYED);
}
// enable menu items which require the clipboard format to be available
if(m_CanPaste==FALSE)
{
// paste
(void)hMenu.EnableMenuItem(
ID_PASTE,MF_BYCOMMAND|MF_GRAYED);
}
// enable menu items which require exposed objects
if(m_ExposedObjects.size()==0)
{
// exposed objects
(void)hMenu.EnableMenuItem(
ID_EXPOSED_OBJECTS,MF_BYCOMMAND|MF_GRAYED);
}
// create the available menu item id set
CAvailableMenuItemIdSet AvailableMenuItemIdSet;
for(long l=1; l<=1024; l++)
{
AvailableMenuItemIdSet.insert(l);
}
// remove used menu item ids
AvailableMenuItemIdSet.erase(ID_CUT);
AvailableMenuItemIdSet.erase(ID_COPY);
AvailableMenuItemIdSet.erase(ID_PASTE);
AvailableMenuItemIdSet.erase(ID_DELETE);
AvailableMenuItemIdSet.erase(ID_SENDTOBACK);
AvailableMenuItemIdSet.erase(ID_BRINGTOFRONT);
AvailableMenuItemIdSet.erase(ID_EVENTS);
AvailableMenuItemIdSet.erase(ID_EXPOSED_OBJECTS);
AvailableMenuItemIdSet.erase(ID_INSERT_ACTIVEX);
AvailableMenuItemIdSet.erase(ID_PROPERTIES);
// create the menu item id to event info map
CMenuItemIdToEventInfoMap MenuItemIdToEventInfoMap;
// if the form is selected
if(IsFormSelected())
{
// create the form event menu
CMenu Menu=CreateFormEventMenu(
AvailableMenuItemIdSet,MenuItemIdToEventInfoMap);
SetPopupMenu(hMenu,ID_EVENTS,(HMENU)Menu);
(void)Menu.Detach(); // detach on success
}
// if there is a single item selected
else if(GetSelectedItemCount()==1)
{
// get item info for the selected item
CItemInfo &ItemInfo=*GetSelectedItems().front();
// create the item event menu
CMenu Menu=CreateItemEventMenu(ItemInfo,
AvailableMenuItemIdSet,MenuItemIdToEventInfoMap);
SetPopupMenu(hMenu,ID_EVENTS,(HMENU)Menu);
(void)Menu.Detach(); // detach on success
}
// if there are exposed objects
if(m_ExposedObjects.size())
{
// create the exposed objects menu
CMenu Menu=CreateExposedObjectsMenu(
AvailableMenuItemIdSet,MenuItemIdToEventInfoMap);
SetPopupMenu(hMenu,ID_EXPOSED_OBJECTS,(HMENU)Menu);
(void)Menu.Detach(); // detach on success
}
// get the cursor position
CPoint CursorPos(0,0);
(void)GetCursorPos(&CursorPos);
// show the menu
long Command=hMenu.TrackPopupMenu(
TPM_NONOTIFY|TPM_RETURNCMD|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,
CursorPos.x,CursorPos.y,*this);
// process the command
switch(Command)
{
// cut
case ID_CUT:
(void)Cut(); // delegate to IFormEditor
break;
// copy
case ID_COPY:
(void)Copy(); // delegate to IFormEditor
break;
// paste
case ID_PASTE:
(void)Paste(); // delegate to IFormEditor
break;
// delete
case ID_DELETE:
(void)Delete(); // delegate to IFormEditor
break;
// send to back
case ID_SENDTOBACK:
(void)SendToBack(); // delegate to IFormEditor
break;
// bring to front
case ID_BRINGTOFRONT:
(void)BringToFront(); // delegate to IFormEditor
break;
// properties
case ID_PROPERTIES:
(void)Properties(); // delegate to IFormEditor
break;
// unknown
default:
break;
}
// if the command is a request to add or edit an event handler
if(MenuItemIdToEventInfoMap.
find(Command)!=MenuItemIdToEventInfoMap.end())
{
// get event info
CEventInfo EventInfo=MenuItemIdToEventInfoMap[Command];
// determine if the event is handled by the script
BOOL Handled=IsEventHandled(
EventInfo.m_SourceName,EventInfo.m_EventName);
// add the event handler
if(Handled==FALSE)
{
AddEventHandler(EventInfo);
}
// edit the event handler
EditEventHandler(
EventInfo.m_SourceName,EventInfo.m_EventName);
// fire the relevant event
if(Handled)
{
(void)Fire_EditExistingEventHandler();
}
else
{
(void)Fire_EditNewEventHandler();
}
}
// if the command is a request to insert an item
if(Command==ID_INSERT_ACTIVEX)
{
// show the insert item dialog
CInsertItemDlg Dlg;
if(Dlg.DoModal()==IDOK)
{
// delegate to IFormEditor
CComPtr<IDispatch> spDispatch;
(void)Insert(CComBSTR(Dlg.m_ProgId.c_str()),&spDispatch);
}
}
FireStateChangedEvent(State); // state may have changed
CATCH_ALL
return 0;
}
LRESULT CFormEditor::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// get the editor state
CFormEditorState State=GetState();
// determine if the clipboard format is available
m_CanPaste=IsClipboardFormatAvailable(m_ClipboardFormatId);
FireStateChangedEvent(State); // state may have changed
CATCH_ALL
return 0;
}
LRESULT CFormEditor::OnGetExtendedPropPageData(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// get item info for the selected item
ATLASSERT(GetSelectedItemCount()==1);
CItemInfo &ItemInfo=*GetSelectedItems().front();
// check parameters
if(lParam==NULL)
{
throw std::exception();
}
// return the extended property page data
CExtendedPropPageData *pData=(CExtendedPropPageData *)lParam;
pData->m_Name=ItemInfo.m_Name;
CATCH_ALL
return Caught ? FALSE : TRUE; // return TRUE on success
}
LRESULT CFormEditor::OnSetExtendedPropPageData(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// get item info for the selected item
ATLASSERT(GetSelectedItemCount()==1);
CItemInfo &ItemInfo=*GetSelectedItems().front();
// check parameters
if(lParam==NULL)
{
throw std::exception();
}
// set the extended property page data
CExtendedPropPageData *pData=(CExtendedPropPageData *)lParam;
// the name must be valid
if(IsNameValid(pData->m_Name)==FALSE)
{
throw std::exception();
}
// the name must be unique
if(IsNameUnique(pData->m_Name,ItemInfo.m_HostWindow)==FALSE)
{
throw std::exception();
}
// set the name
ItemInfo.m_Name=pData->m_Name;
CATCH_ALL
return Caught ? FALSE : TRUE; // return TRUE on success
}
// begin standard method implementation block
#define METHOD_BEGIN \
if(IsWindow()==FALSE) \
{ \
throw CHResult(E_FAIL); \
} \
if(m_Busy) \
{ \
throw CHResult(E_FAIL); \
} \
CFormEditorState State=GetState(); \
// end standard method implementation block
#define METHOD_END \
FireStateChangedEvent(State);
// begin standard property put implementation block
#define PROPPUT_BEGIN \
if(m_Busy) \
{ \
throw CHResult(E_FAIL); \
} \
CFormEditorState State=GetState();
// end standard property put implementation block
#define PROPPUT_END \
FireStateChangedEvent(State);
// begin standard property get implementation block
#define PROPGET_BEGIN \
if(m_Busy) \
{ \
throw CHResult(E_FAIL); \
} \
CFormEditorState State=GetState();
// end standard property get implementation block
#define PROPGET_END \
FireStateChangedEvent(State);
// unselects everything
#define UNSELECT_EVERYTHING \
UnselectForm(); \
UnselectAllItems();
// selects an item ensuring nothing else is selected
#define SELECT_SINGLE_ITEM(ii) \
UNSELECT_EVERYTHING; \
SelectItem(ii);
// selects the form ensuring nothing else is selected
#define SELECT_FORM \
UnselectAllItems(); \
SelectForm();
// ensures something is selected (with a preference on items)
#define SELECT_SOMETHING \
if(GetSelectedItemCount()==0) \
{ \
if(m_ItemInfoPtrList.size()!=0) \
{ \
SELECT_SINGLE_ITEM(*m_ItemInfoPtrList.back()); \
} \
else \
{ \
SELECT_FORM; \
} \
}
STDMETHODIMP CFormEditor::About()
{
// this is allowed not matter what state the editor is in
IMP_BEGIN
// show the about box
CSimpleDialog<IDD_ABOUT_FORMEDITOR> AboutDlg;
(void)AboutDlg.DoModal();
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SelectAll()
{
IMP_BEGIN
METHOD_BEGIN
// select all items
if(m_ItemInfoPtrList.size()!=0)
{
UnselectForm();
SelectAllItems();
}
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SelectNone()
{
IMP_BEGIN
METHOD_BEGIN
// unselect all items
if(GetSelectedItemCount()!=0)
{
UnselectAllItems();
SelectForm();
}
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::New()
{
IMP_BEGIN
METHOD_BEGIN
// delegate to NewEx()
return NewEx(
m_DefaultFormWidth,m_DefaultFormHeight,
m_DefaultFormBackColor,m_DefaultFormForeColor);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::NewEx(
long Width,long Height,OLE_COLOR BackColor,OLE_COLOR ForeColor)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
if(Width < MIN_FORM_WIDTH or Width > MAX_FORM_WIDTH)
{
throw CHResult(E_INVALIDARG);
}
if(Height < MIN_FORM_HEIGHT or Height > MAX_FORM_HEIGHT)
{
throw CHResult(E_INVALIDARG);
}
UNSELECT_EVERYTHING;
// delete all items
DeleteAllItems();
// clear the undo and redo storage
ClearUndoAndRedoStorage();
// reset the scrollbars
(void)SetScrollPos(SB_HORZ,0);
(void)SetScrollPos(SB_VERT,0);
// reset the form position
(void)m_Form.SetWindowPos(NULL,
m_FormDragFrame.GetFrameSize(),m_FormDragFrame.GetFrameSize(),
0,0,SWP_NOZORDER|SWP_NOSIZE|SWP_NOCOPYBITS/*prevent flicker*/);
// reset the script
ResetScript();
// initialise a new form
InitialiseForm(
DEFAULT_FORM_NAME,CSize(Width,Height),BackColor,ForeColor);
SELECT_FORM;
// reset the modified flag
SetModified(FALSE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::ShowInsertDialog(BSTR *pProgID)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
if(pProgID==NULL)
{
throw CHResult(E_POINTER);
}
// initialise the return value to an empty string
*pProgID=NULL;
// show the insert item dialog
CInsertItemDlg Dlg;
if(Dlg.DoModal()==IDOK)
{
*pProgID=CComBSTR(Dlg.m_ProgId.c_str()).Detach();
}
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::Insert(BSTR ProgID,IDispatch **ppDispatch)
{
IMP_BEGIN
METHOD_BEGIN
// delegate to InsertEx
return InsertEx(ProgID,0,0,DEFAULT_ITEM_WIDTH,DEFAULT_ITEM_HEIGHT,ppDispatch);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::InsertEx(
BSTR ProgID,long Left,long Top,long Width,long Height,IDispatch **ppDispatch)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
if(Width < MIN_ITEM_WIDTH)
{
throw CHResult(E_INVALIDARG);
}
if(Height < MIN_ITEM_HEIGHT)
{
throw CHResult(E_INVALIDARG);
}
if(ppDispatch==NULL)
{
throw CHResult(E_POINTER);
}
// get the form rect
CRect FormRect(0,0,0,0);
(void)m_Form.GetClientRect(FormRect);
// get the item rect
CRect ItemRect(Left,Top,Left+Width,Top+Height);
// check the item fits within the form
CRect IntersectRect(0,0,0,0);
(void)IntersectRect.IntersectRect(FormRect,ItemRect);
if(IntersectRect!=ItemRect)
{
throw CHResult(E_INVALIDARG);
}
// update the undo storage
UpdateUndoStorage();
// insert the new item
CItemInfo &ItemInfo=InsertItem(BSTR2W(ProgID),ItemRect);
// get the new items IDispatch interface
CComPtr<IDispatch> spDispatch;
if(!SUCCEEDED(ItemInfo.m_HostWindow.QueryControl(&spDispatch)))
{
throw CHResult(E_FAIL);
}
*ppDispatch=spDispatch.Detach();
// select the new item
SELECT_SINGLE_ITEM(ItemInfo);
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::Delete()
{
IMP_BEGIN
METHOD_BEGIN
// check there are items selected
if(GetSelectedItemCount()==0)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// delete selected items
DeleteSelectedItems();
SELECT_SOMETHING;
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::Cut()
{
IMP_BEGIN
METHOD_BEGIN
// check there are items selected
if(GetSelectedItemCount()==0)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// cut selected items to the clipboard
CutSelectedItemsToClipboard();
SELECT_SOMETHING;
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::Copy()
{
IMP_BEGIN
METHOD_BEGIN
// check there are items selected
if(GetSelectedItemCount()==0)
{
throw CHResult(E_FAIL);
}
// copy selected items to the clipboard
CopySelectedItemsToClipboard();
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::Paste()
{
IMP_BEGIN
METHOD_BEGIN
// check the clipboard format is available
if(m_CanPaste==FALSE)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// paste items from the clipboard
UNSELECT_EVERYTHING;
SelectItems(PasteItemsFromClipboard());
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::Undo()
{
IMP_BEGIN
METHOD_BEGIN
// check there is something to undo
if(m_UndoStorage.GetElementCount()==0)
{
throw CHResult(E_FAIL);
}
// undo
UNSELECT_EVERYTHING;
UndoLastChange();
SELECT_FORM;
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::Redo()
{
IMP_BEGIN
METHOD_BEGIN
// check there is something to redo
if(m_RedoStorage.GetElementCount()==0)
{
throw CHResult(E_FAIL);
}
// redo
UNSELECT_EVERYTHING;
RedoLastUndo();
SELECT_FORM;
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SetTabOrder()
{
IMP_BEGIN
METHOD_BEGIN
// check there are items to set the tab order of
if(m_ItemInfoPtrList.size()==0)
{
throw CHResult(E_FAIL);
}
// switch the editor into tab ordering mode
UNSELECT_EVERYTHING;
BeginSetTabOrder();
// the modified flag and undo storage are updated internally
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::RefreshState()
{
IMP_BEGIN
METHOD_BEGIN
// refresh the state
FireStateChangedEvent(GetState(),TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::LoadFromFile(BSTR FileName)
{
IMP_BEGIN
METHOD_BEGIN
// open the storage
CComPtr<IStorage> spStorage;
if(!SUCCEEDED(StgOpenStorage(BSTR2W(FileName),NULL,
STGM_DIRECT|STGM_READ|STGM_SHARE_EXCLUSIVE,
NULL,0,&spStorage)))
{
throw CHResult(E_FAIL);
}
// open the stream
CComPtr<IStream> spStream;
if(!SUCCEEDED(spStorage->OpenStream(STREAM_NAME,NULL,
STGM_DIRECT|STGM_READ|STGM_SHARE_EXCLUSIVE,
0,&spStream)))
{
throw CHResult(E_FAIL);
}
// load the form
UNSELECT_EVERYTHING;
(void)InternalLoad(spStream,StreamTypeFull);
SELECT_FORM;
// reset the modified flag
SetModified(FALSE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SaveToFile(BSTR FileName)
{
IMP_BEGIN
METHOD_BEGIN
// create the storage
CComPtr<IStorage> spStorage;
if(!SUCCEEDED(StgCreateDocfile(BSTR2W(FileName),
STGM_DIRECT|STGM_WRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE,
0,&spStorage)))
{
throw CHResult(E_FAIL);
}
// create the stream
CComPtr<IStream> spStream;
if(!SUCCEEDED(spStorage->CreateStream(STREAM_NAME,
STGM_DIRECT|STGM_WRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE,
0,0,&spStream)))
{
throw CHResult(E_FAIL);
}
// save the form
InternalSave(spStream,StreamTypeFull);
// reset the modified flag
SetModified(FALSE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::ValidateScript(VARIANT_BOOL *pRet)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
if(pRet==NULL)
{
throw CHResult(E_POINTER);
}
// validate the script
*pRet=B2VB(InternalValidateScript());
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::MoveLeft()
{
IMP_BEGIN
METHOD_BEGIN
// check there are items selected
if(GetSelectedItemCount()==0)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// move selected items left
HideAllDragFrames();
MoveSelectedItems(MoveTypeLeft);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::MoveRight()
{
IMP_BEGIN
METHOD_BEGIN
// check there are items selected
if(GetSelectedItemCount()==0)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// move selected items right
HideAllDragFrames();
MoveSelectedItems(MoveTypeRight);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::MoveUp()
{
IMP_BEGIN
METHOD_BEGIN
// check there are items selected
if(GetSelectedItemCount()==0)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// move selected items up
HideAllDragFrames();
MoveSelectedItems(MoveTypeUp);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::MoveDown()
{
IMP_BEGIN
METHOD_BEGIN
// check there are items selected
if(GetSelectedItemCount()==0)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// move selected items down
HideAllDragFrames();
MoveSelectedItems(MoveTypeDown);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::AlignLeft()
{
IMP_BEGIN
METHOD_BEGIN
// check there are enough items selected
if(GetSelectedItemCount() < 2)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// align selected items to the left most
HideAllDragFrames();
AlignSelectedItems(AlignTypeLeft);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::AlignRight()
{
IMP_BEGIN
METHOD_BEGIN
// check there are enough items selected
if(GetSelectedItemCount() < 2)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// align selected items to the right most
HideAllDragFrames();
AlignSelectedItems(AlignTypeRight);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::AlignTop()
{
IMP_BEGIN
METHOD_BEGIN
// check there are enough items selected
if(GetSelectedItemCount() < 2)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// align selected items to the top most
HideAllDragFrames();
AlignSelectedItems(AlignTypeTop);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::AlignBottom()
{
IMP_BEGIN
METHOD_BEGIN
// check there are enough items selected
if(GetSelectedItemCount() < 2)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// align selected items to the bottom most
HideAllDragFrames();
AlignSelectedItems(AlignTypeBottom);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::FormAlignHCenter()
{
IMP_BEGIN
METHOD_BEGIN
// check there are items selected
if(GetSelectedItemCount()==0)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// align selected items to the form horizontal center
HideAllDragFrames();
AlignSelectedItemsToForm(FormAlignTypeHCenter);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::FormAlignVCenter()
{
IMP_BEGIN
METHOD_BEGIN
// check there are items selected
if(GetSelectedItemCount()==0)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// align selected items to the form vertical center
HideAllDragFrames();
AlignSelectedItemsToForm(FormAlignTypeVCenter);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::FormAlignBoth()
{
IMP_BEGIN
METHOD_BEGIN
// check there are items selected
if(GetSelectedItemCount()==0)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// align selected items to the form horizontal and vertical center
HideAllDragFrames();
AlignSelectedItemsToForm(FormAlignTypeBoth);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SizeWidthToLargest()
{
IMP_BEGIN
METHOD_BEGIN
// check there are enough items selected
if(GetSelectedItemCount() < 2)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// size selected items to the largest width
HideAllDragFrames();
SizeSelectedItemsToLargest(SizeTypeWidth);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SizeHeightToLargest()
{
IMP_BEGIN
METHOD_BEGIN
// check there are enough items selected
if(GetSelectedItemCount() < 2)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// size selected items to the largest height
HideAllDragFrames();
SizeSelectedItemsToLargest(SizeTypeHeight);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SizeToLargest()
{
IMP_BEGIN
METHOD_BEGIN
// check there are enough items selected
if(GetSelectedItemCount() < 2)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// size selected items to the largest overall
HideAllDragFrames();
SizeSelectedItemsToLargest(SizeTypeBoth);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SizeWidthToSmallest()
{
IMP_BEGIN
METHOD_BEGIN
// check there are enough items selected
if(GetSelectedItemCount() < 2)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// size selected items to the smallest width
HideAllDragFrames();
SizeSelectedItemsToSmallest(SizeTypeWidth);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SizeHeightToSmallest()
{
IMP_BEGIN
METHOD_BEGIN
// check there are enough items selected
if(GetSelectedItemCount() < 2)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// size selected items to the smallest height
HideAllDragFrames();
SizeSelectedItemsToSmallest(SizeTypeHeight);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SizeToSmallest()
{
IMP_BEGIN
METHOD_BEGIN
// check there are enough items selected
if(GetSelectedItemCount() < 2)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// size selected items to the smallest overall
HideAllDragFrames();
SizeSelectedItemsToSmallest(SizeTypeBoth);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SpaceHorizontally()
{
IMP_BEGIN
METHOD_BEGIN
// check there are enough items selected
if(GetSelectedItemCount() < 3)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// space selected items horizontally
HideAllDragFrames();
SpaceSelectedItemsHorizontally();
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SpaceVertically()
{
IMP_BEGIN
METHOD_BEGIN
// check there are enough items selected
if(GetSelectedItemCount() < 3)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// space selected items vertically
HideAllDragFrames();
SpaceSelectedItemsVertically();
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::Properties()
{
IMP_BEGIN
METHOD_BEGIN
// check there is a valid selection
if(IsFormSelected()==FALSE and GetSelectedItemCount()!=1)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// if the form is selected
if(IsFormSelected())
{
// show property pages for the form
ShowFormProperties();
}
// if there is a single item selected
else if(GetSelectedItemCount()==1)
{
// show property pages for the selected item
ShowSelectedItemProperties();
}
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::Expose(BSTR Name, IDispatch *pDispatch)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
std::wstring ObjectName=BSTR2W(Name);
if(IsNameValid(ObjectName)==FALSE)
{
// the name should be valid
throw CHResult(E_INVALIDARG);
}
if(IsNameUnique(ObjectName)==FALSE)
{
// the name should be unique
throw CHResult(E_INVALIDARG);
}
if(pDispatch==NULL)
{
throw CHResult(E_POINTER);
}
// expose the object
AddExposedObject(ObjectName,pDispatch);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::DDUnlock(
long Data1_High, long Data1_Low, long Data2_High, long Data2_Low)
{
IMP_BEGIN
METHOD_BEGIN
// check if the editor can be unlocked
if(CAN_UNLOCK==FALSE)
{
throw CHResult(E_FAIL);
}
// create data1
unsigned long Data1[2]={ Data1_High,Data1_Low };
// create data2
unsigned long Data2[2]={ Data2_High,Data2_Low };
// decipher data2
unsigned long Data3[2]={ 0,0 };
unsigned long UnlockKey[4]={ UNLOCK_KEY };
decipher(Data2,Data3,UnlockKey);
// data1 should match data3
if(memcmp(Data1,Data3,sizeof(Data1)))
{
throw CHResult(E_FAIL);
}
// unlock
m_LockedModeActive=FALSE;
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::get_Script(IScript2 **ppScript2)
{
IMP_BEGIN
PROPGET_BEGIN
// check parameters
if(ppScript2==NULL)
{
throw CHResult(E_POINTER);
}
// get the script
CComQIPtr<IScript2> spScript2(m_spScript);
if(spScript2==NULL)
{
throw CHResult(E_FAIL);
}
*ppScript2=spScript2.Detach();
PROPGET_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::get_BorderVisible(VARIANT_BOOL *pVal)
{
IMP_BEGIN
PROPGET_BEGIN
// check parameters
if(pVal==NULL)
{
throw CHResult(E_POINTER);
}
// get the border visible flag
*pVal=m_BorderVisible;
PROPGET_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::put_BorderVisible(VARIANT_BOOL newVal)
{
IMP_BEGIN
PROPPUT_BEGIN
if(IsWindow()) // refresh
{
if(newVal)
{
// show the border
(void)ModifyStyleEx(0,WS_EX_CLIENTEDGE);
}
else
{
// hide the border
(void)ModifyStyleEx(WS_EX_CLIENTEDGE,0);
}
(void)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);
PROPPUT_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::get_BackColor(OLE_COLOR *pVal)
{
IMP_BEGIN
PROPGET_BEGIN
// check parameters
if(pVal==NULL)
{
throw CHResult(E_POINTER);
}
// get the background color
*pVal=m_BackColor;
PROPGET_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::put_BackColor(OLE_COLOR newVal)
{
IMP_BEGIN
PROPPUT_BEGIN
if(IsWindow()) // refresh
{
(void)Invalidate();
}
// set the background color
m_BackColor=newVal;
PROPERTY_CHANGED(DISPID_BACKCOLOR);
PROPPUT_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::get_FormWidth(long *pVal)
{
IMP_BEGIN
PROPGET_BEGIN
// check parameters
if(pVal==NULL)
{
throw CHResult(E_POINTER);
}
// get the form width
long Width=0,Height=0;
m_Form.GetDimensions(Width,Height);
*pVal=Width;
PROPGET_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::put_FormWidth(long newVal)
{
IMP_BEGIN
PROPPUT_BEGIN
// check parameters
if(newVal < MIN_FORM_WIDTH or newVal > MAX_FORM_WIDTH)
{
throw CHResult(E_INVALIDARG);
}
// get the current form dimensions
long Width=0,Height=0;
m_Form.GetDimensions(Width,Height);
if(IsWindow())
{
// check the width is not too small
if(newVal < GetBoundingRectForAllItems().right)
{
throw CHResult(E_INVALIDARG);
}
// update the undo storage
UpdateUndoStorage();
// set the form width
UNSELECT_EVERYTHING;
SetFormDimensions(newVal,Height);
SELECT_FORM;
// set the modified flag
SetModified(TRUE);
}
else
{
// set the form width
SetFormDimensions(newVal,Height);
}
PROPPUT_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::get_FormHeight(long *pVal)
{
IMP_BEGIN
PROPGET_BEGIN
// check parameters
if(pVal==NULL)
{
throw CHResult(E_POINTER);
}
// get the form height
long Width=0,Height=0;
m_Form.GetDimensions(Width,Height);
*pVal=Height;
PROPGET_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::put_FormHeight(long newVal)
{
IMP_BEGIN
PROPPUT_BEGIN
// check parameters
if(newVal < MIN_FORM_HEIGHT or newVal > MAX_FORM_HEIGHT)
{
throw CHResult(E_INVALIDARG);
}
// get the current form dimensions
long Width=0,Height=0;
m_Form.GetDimensions(Width,Height);
if(IsWindow())
{
// check the height is not too small
if(newVal < GetBoundingRectForAllItems().bottom)
{
throw CHResult(E_INVALIDARG);
}
// update the undo storage
UpdateUndoStorage();
// set the form height
UNSELECT_EVERYTHING;
SetFormDimensions(Width,newVal);
SELECT_FORM;
// set the modified flag
SetModified(TRUE);
}
else
{
// set the form height
SetFormDimensions(Width,newVal);
}
PROPPUT_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::get_FormBackColor(OLE_COLOR *pVal)
{
IMP_BEGIN
PROPGET_BEGIN
// check parameters
if(pVal==NULL)
{
throw CHResult(E_POINTER);
}
// get the form background color
OLE_COLOR BackColor=RGB(0,0,0),ForeColor=RGB(0,0,0);
m_Form.GetColors(BackColor,ForeColor);
*pVal=BackColor;
PROPGET_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::put_FormBackColor(OLE_COLOR newVal)
{
IMP_BEGIN
PROPPUT_BEGIN
// get the current form colors
OLE_COLOR BackColor=RGB(0,0,0),ForeColor=RGB(0,0,0);
m_Form.GetColors(BackColor,ForeColor);
if(IsWindow())
{
// update the undo storage
UpdateUndoStorage();
// set the form background color
SetFormColors(newVal,ForeColor);
// set the modified flag
SetModified(TRUE);
}
else
{
// set the form background color
SetFormColors(newVal,ForeColor);
}
PROPPUT_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::get_FormForeColor(OLE_COLOR *pVal)
{
IMP_BEGIN
PROPGET_BEGIN
// check parameters
if(pVal==NULL)
{
throw CHResult(E_POINTER);
}
// get the form foreground color
OLE_COLOR BackColor=RGB(0,0,0),ForeColor=RGB(0,0,0);
m_Form.GetColors(BackColor,ForeColor);
*pVal=ForeColor;
PROPGET_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::put_FormForeColor(OLE_COLOR newVal)
{
IMP_BEGIN
PROPPUT_BEGIN
// get the current form colors
OLE_COLOR BackColor=RGB(0,0,0),ForeColor=RGB(0,0,0);
m_Form.GetColors(BackColor,ForeColor);
if(IsWindow())
{
// update the undo storage
UpdateUndoStorage();
// set the form foreground color
SetFormColors(BackColor,newVal);
// set the modified flag
SetModified(TRUE);
}
else
{
// set the form foreground color
SetFormColors(BackColor,newVal);
}
PROPPUT_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::get_GridWidth(long *pVal)
{
IMP_BEGIN
PROPGET_BEGIN
// check parameters
if(pVal==NULL)
{
throw CHResult(E_POINTER);
}
// get the grid width
long Width=0,Height=0;
m_Form.GetGrid(Width,Height);
*pVal=Width;
PROPGET_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::put_GridWidth(long newVal)
{
IMP_BEGIN
PROPPUT_BEGIN
// check parameters
if(newVal < MIN_GRID_WIDTH)
{
throw CHResult(E_INVALIDARG);
}
// set the grid width
long Width=0,Height=0;
m_Form.GetGrid(Width,Height);
m_Form.SetGrid(newVal,Height);
PROPERTY_CHANGED(DISPID_GRIDWIDTH);
PROPPUT_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::get_GridHeight(long *pVal)
{
IMP_BEGIN
PROPGET_BEGIN
// check parameters
if(pVal==NULL)
{
throw CHResult(E_POINTER);
}
// get the grid height
long Width=0,Height=0;
m_Form.GetGrid(Width,Height);
*pVal=Height;
PROPGET_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::put_GridHeight(long newVal)
{
IMP_BEGIN
PROPPUT_BEGIN
// check parameters
if(newVal < MIN_GRID_HEIGHT)
{
throw CHResult(E_INVALIDARG);
}
// set the grid height
long Width=0,Height=0;
m_Form.GetGrid(Width,Height);
m_Form.SetGrid(Width,newVal);
PROPERTY_CHANGED(DISPID_GRIDHEIGHT);
PROPPUT_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::get_GridVisible(VARIANT_BOOL *pVal)
{
IMP_BEGIN
PROPGET_BEGIN
// check parameters
if(pVal==NULL)
{
throw CHResult(E_POINTER);
}
// get the grid visibility
*pVal=B2VB(m_Form.IsGridVisible());
PROPGET_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::put_GridVisible(VARIANT_BOOL newVal)
{
IMP_BEGIN
PROPPUT_BEGIN
// set the grid visibility
m_Form.ShowGrid(VB2B(newVal));
PROPERTY_CHANGED(DISPID_GRIDVISIBLE);
PROPPUT_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::get_DragFrameBackColor(OLE_COLOR *pVal)
{
IMP_BEGIN
PROPGET_BEGIN
// check parameters
if(pVal==NULL)
{
throw CHResult(E_POINTER);
}
// get the drag frame background color
OLE_COLOR BackColor=RGB(0,0,0),ForeColor=RGB(0,0,0);
m_FormDragFrame.GetColors(BackColor,ForeColor);
*pVal=BackColor;
PROPGET_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::put_DragFrameBackColor(OLE_COLOR newVal)
{
IMP_BEGIN
PROPPUT_BEGIN
// set the drag frame background color
OLE_COLOR BackColor=RGB(0,0,0),ForeColor=RGB(0,0,0);
m_FormDragFrame.GetColors(BackColor,ForeColor);
m_FormDragFrame.SetColors(newVal,ForeColor);
// update all item drag frames
for(CItemInfoPtrList::const_iterator iter=
m_ItemInfoPtrList.begin(); iter!=m_ItemInfoPtrList.end(); iter++)
{
(*iter)->m_DragFrame.SetColors(newVal,ForeColor);
}
PROPERTY_CHANGED(DISPID_DRAGFRAMEBACKCOLOR);
PROPPUT_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::get_DragFrameForeColor(OLE_COLOR *pVal)
{
IMP_BEGIN
PROPGET_BEGIN
// check parameters
if(pVal==NULL)
{
throw CHResult(E_POINTER);
}
// get the drag frame foreground color
OLE_COLOR BackColor=RGB(0,0,0),ForeColor=RGB(0,0,0);
m_FormDragFrame.GetColors(BackColor,ForeColor);
*pVal=ForeColor;
PROPGET_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::put_DragFrameForeColor(OLE_COLOR newVal)
{
IMP_BEGIN
PROPPUT_BEGIN
// set the drag frame foreground color
OLE_COLOR BackColor=RGB(0,0,0),ForeColor=RGB(0,0,0);
m_FormDragFrame.GetColors(BackColor,ForeColor);
m_FormDragFrame.SetColors(BackColor,newVal);
// update all item drag frames
for(CItemInfoPtrList::const_iterator iter=
m_ItemInfoPtrList.begin(); iter!=m_ItemInfoPtrList.end(); iter++)
{
(*iter)->m_DragFrame.SetColors(BackColor,newVal);
}
PROPERTY_CHANGED(DISPID_DRAGFRAMEFORECOLOR);
PROPPUT_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::get_TabNumberBackColor(OLE_COLOR *pVal)
{
IMP_BEGIN
PROPGET_BEGIN
// check parameters
if(pVal==NULL)
{
throw CHResult(E_POINTER);
}
// get the tab number background color
OLE_COLOR BackColor=RGB(0,0,0),ForeColor=RGB(0,0,0);
m_FormTabNumber.GetColors(BackColor,ForeColor);
*pVal=BackColor;
PROPGET_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::put_TabNumberBackColor(OLE_COLOR newVal)
{
IMP_BEGIN
PROPPUT_BEGIN
// set the tab number background color
OLE_COLOR BackColor=RGB(0,0,0),ForeColor=RGB(0,0,0);
m_FormTabNumber.GetColors(BackColor,ForeColor);
m_FormTabNumber.SetColors(newVal,ForeColor);
// update all item tab numbers
for(CItemInfoPtrList::const_iterator iter=
m_ItemInfoPtrList.begin(); iter!=m_ItemInfoPtrList.end(); iter++)
{
(*iter)->m_TabNumber.SetColors(newVal,ForeColor);
}
PROPERTY_CHANGED(DISPID_TABNUMBERBACKCOLOR);
PROPPUT_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::get_TabNumberForeColor(OLE_COLOR *pVal)
{
IMP_BEGIN
PROPGET_BEGIN
// check parameters
if(pVal==NULL)
{
throw CHResult(E_POINTER);
}
// get the tab number foreground color
OLE_COLOR BackColor=RGB(0,0,0),ForeColor=RGB(0,0,0);
m_FormTabNumber.GetColors(BackColor,ForeColor);
*pVal=ForeColor;
PROPGET_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::put_TabNumberForeColor(OLE_COLOR newVal)
{
IMP_BEGIN
PROPPUT_BEGIN
// set the tab number foreground color
OLE_COLOR BackColor=RGB(0,0,0),ForeColor=RGB(0,0,0);
m_FormTabNumber.GetColors(BackColor,ForeColor);
m_FormTabNumber.SetColors(BackColor,newVal);
// update all item tab numbers
for(CItemInfoPtrList::const_iterator iter=
m_ItemInfoPtrList.begin(); iter!=m_ItemInfoPtrList.end(); iter++)
{
(*iter)->m_DragFrame.SetColors(BackColor,newVal);
}
PROPERTY_CHANGED(DISPID_TABNUMBERFORECOLOR);
PROPPUT_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SendToBack()
{
IMP_BEGIN
METHOD_BEGIN
// check there are items selected
if(GetSelectedItemCount()==0)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// get a list of selected items
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
// send selected items to the back
for(CItemInfoPtrList::reverse_iterator iter=
ItemInfoPtrList.rbegin(); iter!=ItemInfoPtrList.rend(); iter++)
{
CItemInfo &ItemInfo=**iter;
// get the item position
CRect ItemRect(0,0,0,0);
long TabNumber=0;
GetItemPosition(ItemInfo,ItemRect,TabNumber);
// update the tab number
TabNumber=1;
// set the item position
HideAllDragFrames();
SetItemPosition(ItemInfo,ItemRect,TabNumber);
RestoreAndRepositionAllDragFrames();
}
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::BringToFront()
{
IMP_BEGIN
METHOD_BEGIN
// check there are items selected
if(GetSelectedItemCount()==0)
{
throw CHResult(E_FAIL);
}
// update the undo storage
UpdateUndoStorage();
// get a list of selected items
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
// bring selected items to the front
for(CItemInfoPtrList::iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// get the item position
CRect ItemRect(0,0,0,0);
long TabNumber=0;
GetItemPosition(ItemInfo,ItemRect,TabNumber);
// update the tab number
TabNumber=m_ItemInfoPtrList.size();
// set the item position
HideAllDragFrames();
SetItemPosition(ItemInfo,ItemRect,TabNumber);
RestoreAndRepositionAllDragFrames();
}
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::GetItemDetails(
IDispatch *pDispatch, IFormEditorItemDetails **ppFormEditorItemDetails)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
if(pDispatch==NULL)
{
throw CHResult(E_POINTER);
}
if(ppFormEditorItemDetails==NULL)
{
throw CHResult(E_POINTER);
}
// check the item exists
if(std::find_if(m_ItemInfoPtrList.begin(),m_ItemInfoPtrList.end(),
std::bind2nd(std::ptr_fun(IsItemIDispatchEqual),pDispatch))==
m_ItemInfoPtrList.end())
{
throw CHResult(E_INVALIDARG);
}
// create the item details
CComObject<CFormEditorItemDetails> *pItemDetails=NULL;
if(!SUCCEEDED(
CComObject<CFormEditorItemDetails>::CreateInstance(&pItemDetails)))
{
throw CHResult(E_FAIL);
}
CComPtr<IUnknown> spUnknown(pItemDetails->GetUnknown());
// set the item
pItemDetails->m_spItem=pDispatch;
// set the form editor
CComQIPtr<IFormEditor2> spFormEditor2(GetUnknown());
if(spFormEditor2==NULL)
{
throw CHResult(E_FAIL);
}
pItemDetails->m_spFormEditor2=spFormEditor2;
// get the item details
CComQIPtr<IFormEditorItemDetails> spFormEditorItemDetails(spUnknown);
if(spFormEditorItemDetails==NULL)
{
throw CHResult(E_FAIL);
}
*ppFormEditorItemDetails=spFormEditorItemDetails.Detach();
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::GetItemClassId(IDispatch *pDispatch,BSTR *pClassId)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
if(pDispatch==NULL)
{
throw CHResult(E_POINTER);
}
if(pClassId==NULL)
{
throw CHResult(E_POINTER);
}
// check the item exists
CItemInfoPtrList::const_iterator iter=
std::find_if(m_ItemInfoPtrList.begin(),m_ItemInfoPtrList.end(),
std::bind2nd(std::ptr_fun(IsItemIDispatchEqual),pDispatch));
if(iter==m_ItemInfoPtrList.end())
{
throw CHResult(E_INVALIDARG);
}
CItemInfo &ItemInfo=**iter;
// get the item class id
CComPtr<IOleObject> spOleObject;
if(!SUCCEEDED(ItemInfo.m_HostWindow.QueryControl(&spOleObject)))
{
throw CHResult(E_FAIL);
}
CLSID ClassId=CLSID_NULL;
if(!SUCCEEDED(spOleObject->GetUserClassID(&ClassId)))
{
throw CHResult(E_FAIL);
}
// convert to text
WCHAR ClassIdText[64]=L"";
if(StringFromGUID2(ClassId,
ClassIdText,NUM_ELEMENTS(ClassIdText,WCHAR))==0)
{
throw CHResult(E_FAIL);
}
// get the item class id
*pClassId=CComBSTR(ClassIdText).Detach();
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::GetItemName(IDispatch *pDispatch,BSTR *pName)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
if(pDispatch==NULL)
{
throw CHResult(E_POINTER);
}
if(pName==NULL)
{
throw CHResult(E_POINTER);
}
// check the item exists
CItemInfoPtrList::const_iterator iter=
std::find_if(m_ItemInfoPtrList.begin(),m_ItemInfoPtrList.end(),
std::bind2nd(std::ptr_fun(IsItemIDispatchEqual),pDispatch));
if(iter==m_ItemInfoPtrList.end())
{
throw CHResult(E_INVALIDARG);
}
CItemInfo &ItemInfo=**iter;
// get the item name
*pName=CComBSTR(ItemInfo.m_Name.c_str()).Detach();
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SetItemName(IDispatch *pDispatch,BSTR Name)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
if(pDispatch==NULL)
{
throw CHResult(E_POINTER);
}
// check the item exists
CItemInfoPtrList::const_iterator iter=
std::find_if(m_ItemInfoPtrList.begin(),m_ItemInfoPtrList.end(),
std::bind2nd(std::ptr_fun(IsItemIDispatchEqual),pDispatch));
if(iter==m_ItemInfoPtrList.end())
{
throw CHResult(E_INVALIDARG);
}
CItemInfo &ItemInfo=**iter;
// the name should not contain any embedded NULL characters
std::wstring ItemName=BSTR2W(Name);
if(ItemName.length()!=SysStringLen(Name))
{
throw CHResult(E_INVALIDARG);
}
// the name should be valid
if(IsNameValid(ItemName)==FALSE)
{
throw CHResult(E_INVALIDARG);
}
// the name should be unique
if(IsNameUnique(ItemName,ItemInfo.m_HostWindow)==FALSE)
{
throw CHResult(E_INVALIDARG);
}
// update the undo storage
UpdateUndoStorage();
// set the item name
ItemInfo.m_Name=ItemName;
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::GetItemTag(IDispatch *pDispatch,BSTR *pTag)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
if(pDispatch==NULL)
{
throw CHResult(E_POINTER);
}
if(pTag==NULL)
{
throw CHResult(E_POINTER);
}
// check the item exists
CItemInfoPtrList::const_iterator iter=
std::find_if(m_ItemInfoPtrList.begin(),m_ItemInfoPtrList.end(),
std::bind2nd(std::ptr_fun(IsItemIDispatchEqual),pDispatch));
if(iter==m_ItemInfoPtrList.end())
{
throw CHResult(E_INVALIDARG);
}
CItemInfo &ItemInfo=**iter;
// get the item tag
*pTag=CComBSTR(ItemInfo.m_Tag.c_str()).Detach();
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SetItemTag(IDispatch *pDispatch,BSTR Tag)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
if(pDispatch==NULL)
{
throw CHResult(E_POINTER);
}
// check the item exists
CItemInfoPtrList::const_iterator iter=
std::find_if(m_ItemInfoPtrList.begin(),m_ItemInfoPtrList.end(),
std::bind2nd(std::ptr_fun(IsItemIDispatchEqual),pDispatch));
if(iter==m_ItemInfoPtrList.end())
{
throw CHResult(E_INVALIDARG);
}
CItemInfo &ItemInfo=**iter;
// the tag should not contain any embedded NULL characters
std::wstring ItemTag=BSTR2W(Tag);
if(ItemTag.length()!=SysStringLen(Tag))
{
throw CHResult(E_INVALIDARG);
}
// update the undo storage
UpdateUndoStorage();
// set the item tag
ItemInfo.m_Tag=ItemTag;
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::GetItemPosition(IDispatch *pDispatch,
long *pLeft,long *pTop,long *pWidth,long *pHeight,long *pTabNumber)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
if(pDispatch==NULL)
{
throw CHResult(E_POINTER);
}
if(pLeft==NULL)
{
throw CHResult(E_POINTER);
}
if(pTop==NULL)
{
throw CHResult(E_POINTER);
}
if(pWidth==NULL)
{
throw CHResult(E_POINTER);
}
if(pHeight==NULL)
{
throw CHResult(E_POINTER);
}
if(pTabNumber==NULL)
{
throw CHResult(E_POINTER);
}
// check the item exists
CItemInfoPtrList::const_iterator iter=
std::find_if(m_ItemInfoPtrList.begin(),m_ItemInfoPtrList.end(),
std::bind2nd(std::ptr_fun(IsItemIDispatchEqual),pDispatch));
if(iter==m_ItemInfoPtrList.end())
{
throw CHResult(E_INVALIDARG);
}
CItemInfo &ItemInfo=**iter;
// get the item position
CRect ItemRect(0,0,0,0);
GetItemPosition(ItemInfo,ItemRect,*pTabNumber);
*pLeft=ItemRect.left;
*pTop=ItemRect.top;
*pWidth=ItemRect.Width();
*pHeight=ItemRect.Height();
// the tab number will be set on return from GetItemPosition()
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SetItemPosition(IDispatch *pDispatch,
long Left,long Top,long Width,long Height,long TabNumber)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
if(pDispatch==NULL)
{
throw CHResult(E_POINTER);
}
if(Width < MIN_ITEM_WIDTH)
{
throw CHResult(E_INVALIDARG);
}
if(Height < MIN_ITEM_HEIGHT)
{
throw CHResult(E_INVALIDARG);
}
// get the form rect
CRect FormRect(0,0,0,0);
(void)m_Form.GetClientRect(FormRect);
// get the item rect
CRect ItemRect(Left,Top,Left+Width,Top+Height);
// check the item fits within the form
CRect IntersectRect(0,0,0,0);
(void)IntersectRect.IntersectRect(FormRect,ItemRect);
if(IntersectRect!=ItemRect)
{
throw CHResult(E_INVALIDARG);
}
if(TabNumber < 1 or TabNumber > (long)m_ItemInfoPtrList.size())
{
throw CHResult(E_INVALIDARG);
}
// check the item exists
CItemInfoPtrList::const_iterator iter=
std::find_if(m_ItemInfoPtrList.begin(),m_ItemInfoPtrList.end(),
std::bind2nd(std::ptr_fun(IsItemIDispatchEqual),pDispatch));
if(iter==m_ItemInfoPtrList.end())
{
throw CHResult(E_INVALIDARG);
}
CItemInfo &ItemInfo=**iter;
// update the undo storage
UpdateUndoStorage();
// set the item position
HideAllDragFrames();
SetItemPosition(ItemInfo,ItemRect,TabNumber);
RestoreAndRepositionAllDragFrames();
// set the modified flag
SetModified(TRUE);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::IsItemSelected(
IDispatch *pDispatch,VARIANT_BOOL *pIsSelected)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
if(pDispatch==NULL)
{
throw CHResult(E_POINTER);
}
if(pIsSelected==NULL)
{
throw CHResult(E_POINTER);
}
// check the item exists
CItemInfoPtrList::const_iterator iter=
std::find_if(m_ItemInfoPtrList.begin(),m_ItemInfoPtrList.end(),
std::bind2nd(std::ptr_fun(IsItemIDispatchEqual),pDispatch));
if(iter==m_ItemInfoPtrList.end())
{
throw CHResult(E_INVALIDARG);
}
CItemInfo &ItemInfo=**iter;
// determine if the item is selected
*pIsSelected=B2VB(IsItemSelected(ItemInfo));
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::SelectItem(
IDispatch *pDispatch,VARIANT_BOOL KeepCurrentSelection)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
if(pDispatch==NULL)
{
throw CHResult(E_POINTER);
}
// check the item exists
CItemInfoPtrList::const_iterator iter=
std::find_if(m_ItemInfoPtrList.begin(),m_ItemInfoPtrList.end(),
std::bind2nd(std::ptr_fun(IsItemIDispatchEqual),pDispatch));
if(iter==m_ItemInfoPtrList.end())
{
throw CHResult(E_INVALIDARG);
}
CItemInfo &ItemInfo=**iter;
// unselect the form
UnselectForm();
// if the current selection should not be maintained unselect all items
if(KeepCurrentSelection==VARIANT_FALSE)
{
UnselectAllItems();
}
// select the item
SelectItem(ItemInfo);
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::UnselectItem(IDispatch *pDispatch)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
if(pDispatch==NULL)
{
throw CHResult(E_POINTER);
}
// check the item exists
CItemInfoPtrList::const_iterator iter=
std::find_if(m_ItemInfoPtrList.begin(),m_ItemInfoPtrList.end(),
std::bind2nd(std::ptr_fun(IsItemIDispatchEqual),pDispatch));
if(iter==m_ItemInfoPtrList.end())
{
throw CHResult(E_INVALIDARG);
}
CItemInfo &ItemInfo=**iter;
// unselect the item
UnselectItem(ItemInfo);
// if no other items are selected select the form
if(GetSelectedItemCount()==0)
{
SelectForm();
}
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::IsItemDeleted(
IDispatch *pDispatch,VARIANT_BOOL *pIsDeleted)
{
IMP_BEGIN
METHOD_BEGIN
// check parameters
if(pDispatch==NULL)
{
throw CHResult(E_POINTER);
}
if(pIsDeleted==NULL)
{
throw CHResult(E_POINTER);
}
// check the item exists
CItemInfoPtrList::const_iterator iter=
std::find_if(m_ItemInfoPtrList.begin(),m_ItemInfoPtrList.end(),
std::bind2nd(std::ptr_fun(IsItemIDispatchEqual),pDispatch));
// determine if the item is deleted
if(iter==m_ItemInfoPtrList.end())
{
*pIsDeleted=VARIANT_TRUE; // deleted
}
else
{
*pIsDeleted=VARIANT_FALSE; // not deleted
}
METHOD_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::get_Items(
IFormEditorItemCollection **ppFormEditorItemCollection)
{
IMP_BEGIN
PROPGET_BEGIN
// check parameters
if(ppFormEditorItemCollection==NULL)
{
throw CHResult(E_POINTER);
}
// create the item collection
CComObject<CFormEditorItemCollection> *pItems=NULL;
if(!SUCCEEDED(
CComObject<CFormEditorItemCollection>::CreateInstance(&pItems)))
{
throw CHResult(E_FAIL);
}
CComPtr<IUnknown> spUnknown(pItems->GetUnknown());
// add all items to the item collection
for(CItemInfoPtrList::const_iterator iter=
m_ItemInfoPtrList.begin(); iter!=m_ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// get the items IDispatch interface
CComPtr<IDispatch> spDispatch;
if(!SUCCEEDED(ItemInfo.m_HostWindow.QueryControl(&spDispatch)))
{
throw CHResult(E_FAIL);
}
// update the item collection
pItems->m_coll.push_back(spDispatch);
}
// get the item collection
CComQIPtr<IFormEditorItemCollection> spFormEditorItemCollection(spUnknown);
if(spFormEditorItemCollection==NULL)
{
throw CHResult(E_FAIL);
}
*ppFormEditorItemCollection=spFormEditorItemCollection.Detach();
PROPGET_END
IMP_END
return RetVal;
}
STDMETHODIMP CFormEditor::get_SelectedItems(
IFormEditorItemCollection **ppFormEditorItemCollection)
{
IMP_BEGIN
PROPGET_BEGIN
// check parameters
if(ppFormEditorItemCollection==NULL)
{
throw CHResult(E_POINTER);
}
// create the item collection
CComObject<CFormEditorItemCollection> *pItems=NULL;
if(!SUCCEEDED(
CComObject<CFormEditorItemCollection>::CreateInstance(&pItems)))
{
throw CHResult(E_FAIL);
}
CComPtr<IUnknown> spUnknown(pItems->GetUnknown());
// add all selected items to the item collection
CItemInfoPtrList ItemInfoPtrList=GetSelectedItems();
for(CItemInfoPtrList::const_iterator iter=
ItemInfoPtrList.begin(); iter!=ItemInfoPtrList.end(); iter++)
{
CItemInfo &ItemInfo=**iter;
// get the items IDispatch interface
CComPtr<IDispatch> spDispatch;
if(!SUCCEEDED(ItemInfo.m_HostWindow.QueryControl(&spDispatch)))
{
throw CHResult(E_FAIL);
}
// update the item collection
pItems->m_coll.push_back(spDispatch);
}
// get the item collection
CComQIPtr<IFormEditorItemCollection> spFormEditorItemCollection(spUnknown);
if(spFormEditorItemCollection==NULL)
{
throw CHResult(E_FAIL);
}
*ppFormEditorItemCollection=spFormEditorItemCollection.Detach();
PROPGET_END
IMP_END
return RetVal;
}
} // namespace AxFormEditor