1270 lines
31 KiB
C++
1270 lines
31 KiB
C++
// mainview.cpp : implementation of the CMainView class
|
|
//
|
|
// This is a part of the Microsoft Foundation Classes C++ library.
|
|
// Copyright (C) 1992-1998 Microsoft Corporation
|
|
// All rights reserved.
|
|
//
|
|
// This source code is only intended as a supplement to the
|
|
// Microsoft Foundation Classes Reference and related
|
|
// electronic documentation provided with the library.
|
|
// See these sources for detailed information regarding the
|
|
// Microsoft Foundation Classes product.
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "oclient.h"
|
|
|
|
#include "maindoc.h"
|
|
#include "mainview.h"
|
|
#include "rectitem.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CMainView
|
|
|
|
CBrush NEAR CMainView::m_brHatch;
|
|
CLIPFORMAT CMainView::m_cfObjectDescriptor=NULL;
|
|
|
|
IMPLEMENT_DYNCREATE(CMainView, CScrollView)
|
|
|
|
BEGIN_MESSAGE_MAP(CMainView, CScrollView)
|
|
//{{AFX_MSG_MAP(CMainView)
|
|
ON_COMMAND(ID_EDIT_PASTE, OnPaste)
|
|
ON_COMMAND(ID_EDIT_PASTE_LINK, OnPasteLink)
|
|
ON_COMMAND(ID_OLE_INSERT_NEW, OnInsertObject)
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR, OnUpdateEditMenu)
|
|
ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
|
|
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
|
|
ON_COMMAND(ID_EDIT_CUT, OnEditCut)
|
|
ON_WM_LBUTTONDBLCLK()
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_SETCURSOR()
|
|
ON_WM_RBUTTONDOWN()
|
|
ON_WM_CHAR()
|
|
ON_WM_SETFOCUS()
|
|
ON_WM_CREATE()
|
|
ON_WM_SIZE()
|
|
ON_COMMAND(ID_OBJECT_DISPLAYCONTENT, OnObjectDisplayContent)
|
|
ON_UPDATE_COMMAND_UI(ID_OBJECT_DISPLAYCONTENT, OnUpdateObjectDisplayContent)
|
|
ON_COMMAND(ID_OBJECT_DISPLAYASICON, OnObjectDisplayAsIcon)
|
|
ON_UPDATE_COMMAND_UI(ID_OBJECT_DISPLAYASICON, OnUpdateObjectDisplayAsIcon)
|
|
ON_COMMAND(ID_EDIT_PASTE_SPECIAL, OnPasteSpecial)
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_CLONE, OnUpdateEditClone)
|
|
ON_COMMAND(ID_EDIT_CLONE, OnEditClone)
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE_SPECIAL, OnUpdateEditPaste)
|
|
ON_COMMAND(ID_OBJECT_RESETSIZE, OnObjectResetsize)
|
|
ON_COMMAND(ID_CANCEL_INPLACE, OnCancelInplace)
|
|
ON_WM_DESTROY()
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditMenu)
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditMenu)
|
|
ON_UPDATE_COMMAND_UI(ID_OBJECT_RESETSIZE, OnUpdateEditMenu)
|
|
ON_COMMAND(ID_OLE_CHANGE_SOURCE, OnOleChangeSource)
|
|
ON_UPDATE_COMMAND_UI(ID_OLE_CHANGE_SOURCE, OnUpdateOleChangeSource)
|
|
ON_COMMAND(ID_OLE_EDIT_PROPERTIES, OnOleEditProperties)
|
|
ON_UPDATE_COMMAND_UI(ID_OLE_EDIT_PROPERTIES, OnUpdateOleEditProperties)
|
|
//}}AFX_MSG_MAP
|
|
// Standard printing commands
|
|
ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint)
|
|
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview)
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CMainView construction/destruction
|
|
|
|
CMainView::CMainView()
|
|
{
|
|
if (m_brHatch.m_hObject == NULL)
|
|
m_brHatch.CreateHatchBrush(HS_DIAGCROSS, RGB(0,0,0));
|
|
if (m_cfObjectDescriptor == NULL)
|
|
m_cfObjectDescriptor =
|
|
(CLIPFORMAT)::RegisterClipboardFormat(_T("Object Descriptor"));
|
|
|
|
m_pSelection = NULL;
|
|
m_prevDropEffect = DROPEFFECT_NONE;
|
|
m_bInDrag = FALSE;
|
|
}
|
|
|
|
CMainView::~CMainView()
|
|
{
|
|
}
|
|
|
|
void CMainView::OnInitialUpdate()
|
|
{
|
|
CScrollView::OnInitialUpdate();
|
|
|
|
// We can't pass MM_ANISOTROPIC to SetScrollSizes so we have to convert to MM_TEXT
|
|
CSize size = GetDocument()->GetDocumentSize();
|
|
CClientDC dc(NULL);
|
|
size.cx = MulDiv(size.cx, dc.GetDeviceCaps(LOGPIXELSX), 100);
|
|
size.cy = MulDiv(size.cy, dc.GetDeviceCaps(LOGPIXELSY), 100);
|
|
SetScrollSizes(MM_TEXT, size);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CMainView drawing
|
|
|
|
void CMainView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
|
|
{
|
|
CScrollView::OnPrepareDC(pDC, pInfo);
|
|
// set up a reasonable default context
|
|
pDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
|
|
pDC->SetBkColor(::GetSysColor(COLOR_WINDOW));
|
|
|
|
// LOENGLISH units are based on physical inches
|
|
// We want logical inches so we have to do it differently
|
|
pDC->SetMapMode(MM_ANISOTROPIC);
|
|
pDC->SetViewportExt(
|
|
pDC->GetDeviceCaps(LOGPIXELSX), pDC->GetDeviceCaps(LOGPIXELSY));
|
|
pDC->SetWindowExt(100,-100);
|
|
}
|
|
|
|
void CMainView::SetupTracker(CRectTracker* pTracker, CRectItem* pItem,
|
|
CRect* pTrueRect)
|
|
{
|
|
ASSERT(pTracker != NULL);
|
|
ASSERT(pItem != NULL);
|
|
|
|
pTracker->m_rect = pItem->GetRect();
|
|
DocToClient(pTracker->m_rect);
|
|
|
|
// set minimum size for our OLE items
|
|
pTracker->m_sizeMin.cx = 8;
|
|
pTracker->m_sizeMin.cy = 8;
|
|
|
|
pTracker->m_nStyle = 0;
|
|
|
|
// setup resize handles if item is selected
|
|
if (pItem == m_pSelection)
|
|
pTracker->m_nStyle |= CRectTracker::resizeInside;
|
|
|
|
// put correct border depending on item type
|
|
if (pItem->GetType() == OT_LINK)
|
|
pTracker->m_nStyle |= CRectTracker::dottedLine;
|
|
else
|
|
pTracker->m_nStyle |= CRectTracker::solidLine;
|
|
|
|
// put hatching over the item if it is currently open
|
|
if (pItem->GetItemState() == COleClientItem::openState ||
|
|
pItem->GetItemState() == COleClientItem::activeUIState)
|
|
{
|
|
pTracker->m_nStyle |= CRectTracker::hatchInside;
|
|
}
|
|
|
|
if (pTrueRect != NULL)
|
|
pTracker->GetTrueRect(pTrueRect);
|
|
}
|
|
|
|
void CMainView::OnDraw(CDC* pDC)
|
|
{
|
|
CMainDoc* pDoc = GetDocument();
|
|
|
|
ASSERT_VALID(pDC);
|
|
|
|
if (!pDC->IsPrinting())
|
|
{
|
|
m_brHatch.UnrealizeObject();
|
|
CPoint point(0, 0);
|
|
pDC->LPtoDP(&point);
|
|
pDC->SetBrushOrg(point.x % 8, point.y % 8);
|
|
|
|
CRect rcClip;
|
|
GetClientRect(&rcClip);
|
|
ClientToDoc(rcClip);
|
|
CSize docSize = pDoc->GetDocumentSize();
|
|
if (rcClip.right > docSize.cx)
|
|
{
|
|
CRect rcFill(rcClip);
|
|
rcFill.left = max(rcFill.left,docSize.cx);
|
|
pDC->FillRect(rcFill,&m_brHatch);
|
|
}
|
|
if (rcClip.bottom < -docSize.cy)
|
|
{
|
|
CRect rcFill(rcClip);
|
|
rcFill.top = min(rcFill.top, -docSize.cy);
|
|
pDC->FillRect(rcFill,&m_brHatch);
|
|
}
|
|
}
|
|
|
|
// Draw all the CRectItems
|
|
POSITION pos = pDoc->GetStartPosition();
|
|
while (pos != NULL)
|
|
{
|
|
CRectItem* pItem = DYNAMIC_DOWNCAST(CRectItem, pDoc->GetNextItem(pos));
|
|
if (pItem != NULL)
|
|
{
|
|
pItem->Draw(pDC, pItem->GetRect());
|
|
|
|
if (!pDC->IsPrinting())
|
|
{
|
|
// draw the tracker
|
|
CRectTracker tracker;
|
|
CRect rectTrue;
|
|
SetupTracker(&tracker, pItem, &rectTrue);
|
|
ClientToDoc(rectTrue);
|
|
if (pDC->RectVisible(&rectTrue))
|
|
tracker.Draw(pDC);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// pHint is the deleted item or NULL if deselect/delete all
|
|
void CMainView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
|
|
{
|
|
if (pHint == NULL && lHint == 0)
|
|
{
|
|
// some sort of clear all
|
|
m_pSelection = NULL;
|
|
}
|
|
|
|
if (pHint != NULL && pHint->IsKindOf(RUNTIME_CLASS(CRectItem)))
|
|
{
|
|
// just invalidate the one item
|
|
InvalidateItem((CRectItem*)pHint);
|
|
|
|
// clear selection if pointing to deleted item
|
|
if (lHint == 1 && pHint == m_pSelection)
|
|
{
|
|
// specific case of pHint being deleted
|
|
m_pSelection = NULL;
|
|
}
|
|
}
|
|
else if (lHint != 0)
|
|
{
|
|
// invalidate arbitrary rectangle
|
|
InvalidateRect((CRect*)lHint);
|
|
}
|
|
else
|
|
{
|
|
// complete update
|
|
CScrollView::OnUpdate(pSender, lHint, pHint);
|
|
}
|
|
}
|
|
|
|
void CMainView::InvalidateItem(CRectItem* pItem)
|
|
{
|
|
if (m_nMapMode != 0)
|
|
{
|
|
CRectTracker tracker;
|
|
CRect rect;
|
|
SetupTracker(&tracker, pItem, &rect);
|
|
InvalidateRect(&rect);
|
|
}
|
|
}
|
|
|
|
BOOL CMainView::OnScrollBy(CSize sizeScroll, BOOL bDoScroll)
|
|
{
|
|
// remove drag/drop feedback before scrolling
|
|
if (bDoScroll && m_prevDropEffect != DROPEFFECT_NONE)
|
|
{
|
|
CClientDC dc(this);
|
|
dc.DrawFocusRect(CRect(m_dragPoint, m_dragSize));
|
|
// erase previous focus rect
|
|
m_prevDropEffect = DROPEFFECT_NONE;
|
|
}
|
|
|
|
// do the scroll
|
|
if (!CScrollView::OnScrollBy(sizeScroll, bDoScroll))
|
|
return FALSE;
|
|
|
|
// update the position of any in-place active item
|
|
if (bDoScroll)
|
|
{
|
|
UpdateActiveItem();
|
|
UpdateWindow();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CMainView printing
|
|
|
|
BOOL CMainView::OnPreparePrinting(CPrintInfo* pInfo)
|
|
{
|
|
// default preparation
|
|
return DoPreparePrinting(pInfo);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Selection support
|
|
|
|
BOOL CMainView::IsSelected(const CObject* pDocItem) const
|
|
{
|
|
return (pDocItem == m_pSelection);
|
|
}
|
|
|
|
void CMainView::SetSelection(CRectItem* pNewSel, BOOL bSafeSelect)
|
|
{
|
|
if (pNewSel != NULL && pNewSel == m_pSelection)
|
|
return;
|
|
|
|
// deactivate any in-place active item on this view!
|
|
COleClientItem* pActiveItem = GetDocument()->GetInPlaceActiveItem(this);
|
|
if (pActiveItem != NULL && pNewSel != pActiveItem)
|
|
{
|
|
if (bSafeSelect)
|
|
return;
|
|
// if we found one, deactivate it
|
|
pActiveItem->Close();
|
|
ASSERT(GetDocument()->GetInPlaceActiveItem(this) == NULL);
|
|
}
|
|
if (m_pSelection != NULL) // invalidate the old item
|
|
InvalidateItem(m_pSelection);
|
|
if ((m_pSelection = pNewSel) != NULL) // invalidate the new item
|
|
InvalidateItem(m_pSelection);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CMainView diagnostics
|
|
|
|
#ifdef _DEBUG
|
|
void CMainView::AssertValid() const
|
|
{
|
|
CScrollView::AssertValid();
|
|
}
|
|
|
|
void CMainView::Dump(CDumpContext& dc) const
|
|
{
|
|
CScrollView::Dump(dc);
|
|
}
|
|
|
|
#endif //_DEBUG
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Main 'Edit' menu commands
|
|
|
|
void CMainView::OnUpdateEditMenu(CCmdUI* pCmdUI)
|
|
{
|
|
// most Edit menu commands are enabled only if we have a selection
|
|
// and there are no in-place activations for this view
|
|
pCmdUI->Enable(m_pSelection != NULL &&
|
|
GetDocument()->GetInPlaceActiveItem(this) == NULL);
|
|
}
|
|
|
|
void CMainView::OnEditCut()
|
|
{
|
|
ASSERT(m_pSelection != NULL);
|
|
TRY
|
|
{
|
|
m_pSelection->CopyToClipboard(TRUE);
|
|
OnEditClear();
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
AfxMessageBox(IDP_CLIPBOARD_CUT_FAILED);
|
|
}
|
|
END_CATCH_ALL
|
|
}
|
|
|
|
void CMainView::OnEditCopy()
|
|
{
|
|
ASSERT(m_pSelection != NULL);
|
|
TRY
|
|
{
|
|
m_pSelection->CopyToClipboard(TRUE);
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
AfxMessageBox(IDP_CLIPBOARD_COPY_FAILED);
|
|
}
|
|
END_CATCH_ALL
|
|
}
|
|
|
|
void CMainView::OnEditClear()
|
|
{
|
|
if (m_pSelection != NULL)
|
|
GetDocument()->DeleteItem(m_pSelection);
|
|
}
|
|
|
|
void CMainView::OnPaste()
|
|
{
|
|
if (DoPasteItem(FALSE, NULL, NULL) == NULL)
|
|
AfxMessageBox(IDP_GET_FROM_CLIPBOARD_FAILED);
|
|
}
|
|
|
|
void CMainView::OnPasteLink()
|
|
{
|
|
if (DoPasteItem(TRUE, NULL, NULL) == NULL)
|
|
AfxMessageBox(IDP_GET_FROM_CLIPBOARD_FAILED);
|
|
}
|
|
|
|
void CMainView::DoPasteNative(
|
|
COleDataObject* pDataObject, CPoint* pPoint, CRectItem* pItem)
|
|
{
|
|
// get file refering to clipboard data
|
|
CFile* pFile = pDataObject->GetFileData(CMainDoc::m_cfPrivate);
|
|
if (pFile == NULL)
|
|
{
|
|
// if the file failed to open, throw an exception
|
|
// to force cleanup in DoPasteItem. the exact
|
|
// type of exception thrown here is unimportant...
|
|
|
|
AfxThrowFileException(CFileException::generic);
|
|
}
|
|
|
|
CArchive ar(pFile, CArchive::load);
|
|
TRY
|
|
{
|
|
// connect the file to an archive and read the data
|
|
ar.m_pDocument = GetDocument(); // for COleClientItem serialize
|
|
pItem->Serialize(ar);
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
ar.Close();
|
|
delete pFile;
|
|
THROW_LAST();
|
|
}
|
|
END_CATCH_ALL
|
|
|
|
ar.Close();
|
|
delete pFile;
|
|
|
|
// adjust position to that specified by point
|
|
if (pPoint != NULL)
|
|
pItem->m_ptPos = *pPoint;
|
|
}
|
|
|
|
void CMainView::DoPasteStandard(BOOL bLink, COleDataObject* pDataObject,
|
|
CPoint* pPoint, CRectItem* pItem, CLIPFORMAT cfFormat)
|
|
{
|
|
if (bLink) // paste link
|
|
{
|
|
if (!pItem->CreateLinkFromData(pDataObject))
|
|
AfxThrowMemoryException(); // any exception will do
|
|
}
|
|
// paste embedded
|
|
else if (!pItem->CreateFromData(pDataObject) &&
|
|
!pItem->CreateStaticFromData(pDataObject, OLERENDER_DRAW, cfFormat))
|
|
{
|
|
AfxThrowMemoryException(); // any exception will do
|
|
}
|
|
|
|
// copy the current iconic representation
|
|
FORMATETC fmtetc;
|
|
fmtetc.cfFormat = CF_METAFILEPICT;
|
|
fmtetc.dwAspect = DVASPECT_ICON;
|
|
fmtetc.ptd = NULL;
|
|
fmtetc.tymed = TYMED_MFPICT;
|
|
fmtetc.lindex = 1;
|
|
HGLOBAL hObj = pDataObject->GetGlobalData(CF_METAFILEPICT, &fmtetc);
|
|
if (hObj != NULL)
|
|
{
|
|
pItem->SetIconicMetafile(hObj);
|
|
// the following code is an easy way to free a metafile pict
|
|
STGMEDIUM stgMed;
|
|
memset(&stgMed, 0, sizeof(stgMed));
|
|
stgMed.tymed = TYMED_MFPICT;
|
|
stgMed.hGlobal = hObj;
|
|
ReleaseStgMedium(&stgMed);
|
|
}
|
|
|
|
// set the current drawing aspect
|
|
hObj = pDataObject->GetGlobalData(m_cfObjectDescriptor);
|
|
if (hObj != NULL)
|
|
{
|
|
ASSERT(hObj != NULL);
|
|
// got CF_OBJECTDESCRIPTOR ok. Lock it down and extract size.
|
|
LPOBJECTDESCRIPTOR pObjDesc = (LPOBJECTDESCRIPTOR)GlobalLock(hObj);
|
|
ASSERT(pObjDesc != NULL);
|
|
pItem->SetDrawAspect((DVASPECT)pObjDesc->dwDrawAspect);
|
|
GlobalUnlock(hObj);
|
|
GlobalFree(hObj);
|
|
}
|
|
|
|
// set top-left based on point of drop
|
|
if (pPoint != NULL)
|
|
pItem->m_ptPos = *pPoint;
|
|
|
|
// get size from drag/drop operation
|
|
CSize size;
|
|
if (GetObjectInfo(pDataObject, &size, NULL) && size.cx != 0 && size.cy != 0)
|
|
{
|
|
// use size obtained from object instead of default
|
|
size.cx = MulDiv(size.cx, 10, 254);
|
|
size.cy = -MulDiv(size.cy, 10, 254);
|
|
pItem->SetSize(size);
|
|
CSize sizeExtent;
|
|
pItem->GetCachedExtent(&sizeExtent);
|
|
pItem->SetBaseSize(sizeExtent);
|
|
}
|
|
else
|
|
{
|
|
// no extent from CF_OBJECTDESCRIPTOR, use extent from object
|
|
pItem->UpdateExtent();
|
|
}
|
|
}
|
|
|
|
|
|
// Helper for paste/pastelink
|
|
//
|
|
// bLink pDataObject pPoint cfFormat
|
|
// EditPaste FALSE NULL(clipboard) NULL(default) 0
|
|
// Drag/Drop TRUE/FALSE X X 0
|
|
// PasteLink TRUE NULL(clipboard) NULL(default) 0
|
|
// PasteSpecial TRUE/FALSE X NULL(default) X
|
|
CRectItem* CMainView::DoPasteItem(BOOL bLink, COleDataObject* pDataObject,
|
|
CPoint* pPoint, CLIPFORMAT cfFormat)
|
|
{
|
|
BeginWaitCursor();
|
|
|
|
CRectItem* pItem = GetDocument()->CreateItem();
|
|
ASSERT_VALID(pItem);
|
|
BOOL bAllowAdjust = (pPoint == NULL) ? TRUE : FALSE;
|
|
|
|
// use clipboard data if not doing drag/drop
|
|
COleDataObject clipboardData;
|
|
if (pDataObject == NULL)
|
|
{
|
|
clipboardData.AttachClipboard();
|
|
pDataObject = &clipboardData;
|
|
}
|
|
|
|
TRY
|
|
{
|
|
if (cfFormat == CMainDoc::m_cfPrivate)
|
|
{
|
|
// if format specified (i.e. PasteSpecial) then use that one
|
|
DoPasteNative(pDataObject, pPoint, pItem);
|
|
}
|
|
else if (!bLink && cfFormat == 0 &&
|
|
pDataObject->IsDataAvailable(CMainDoc::m_cfPrivate))
|
|
{
|
|
// if we're not pasting a link, cfFormat was unspecified,
|
|
// and private format is available use it
|
|
DoPasteNative(pDataObject, pPoint, pItem);
|
|
}
|
|
// otherwise perform a standard paste
|
|
else if (bAllowAdjust)
|
|
{
|
|
CPoint ptDef(10, -10);
|
|
DoPasteStandard(bLink, pDataObject, &ptDef, pItem, cfFormat);
|
|
}
|
|
else
|
|
{
|
|
DoPasteStandard(bLink, pDataObject, pPoint, pItem, cfFormat);
|
|
}
|
|
|
|
if (bAllowAdjust)
|
|
{
|
|
// allow document to adjust position of item so that it doesn't
|
|
// lay directly over an item of the same size
|
|
// this only occurs if the drop point is not specified
|
|
GetDocument()->AdjustItemPosition(pItem);
|
|
}
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
// general cleanup
|
|
TRACE0("failed to embed/link an OLE object\n");
|
|
pItem->Delete();
|
|
pItem = NULL;
|
|
}
|
|
END_CATCH_ALL
|
|
|
|
// set the selection with bSafeSelect = TRUE
|
|
SetSelection(pItem, TRUE);
|
|
|
|
// update the document and views
|
|
GetDocument()->SetModifiedFlag();
|
|
GetDocument()->UpdateAllViews(NULL, 0, pItem); // including this view
|
|
|
|
EndWaitCursor();
|
|
|
|
return pItem;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Insert New Object and Activate Object
|
|
|
|
void CMainView::OnInsertObject()
|
|
{
|
|
COleInsertDialog dlg;
|
|
if (dlg.DoModal() != IDOK)
|
|
return;
|
|
|
|
BeginWaitCursor();
|
|
|
|
CRectItem* pItem = NULL;
|
|
TRY
|
|
{
|
|
// create item from dialog results
|
|
pItem = GetDocument()->CreateItem();
|
|
if (!dlg.CreateItem(pItem))
|
|
AfxThrowMemoryException(); // any exception will do
|
|
|
|
// try to get initial presentation data
|
|
pItem->UpdateLink();
|
|
pItem->UpdateExtent();
|
|
|
|
// if insert new object -- initially show the object
|
|
if (dlg.GetSelectionType() == COleInsertDialog::createNewItem)
|
|
pItem->DoVerb(OLEIVERB_SHOW, this);
|
|
|
|
SetSelection(pItem);
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
// cleanup item, if allocated
|
|
if (pItem != NULL)
|
|
GetDocument()->DeleteItem(pItem);
|
|
|
|
AfxMessageBox(IDP_FAILED_TO_CREATE);
|
|
}
|
|
END_CATCH_ALL
|
|
|
|
EndWaitCursor();
|
|
}
|
|
|
|
void CMainView::OnLButtonDblClk(UINT, CPoint)
|
|
{
|
|
// Double click will activate the main verb
|
|
if (m_pSelection != NULL)
|
|
{
|
|
BeginWaitCursor();
|
|
LONG iVerb = OLEIVERB_PRIMARY;
|
|
if (GetKeyState(VK_CONTROL) < 0)
|
|
iVerb = OLEIVERB_OPEN;
|
|
m_pSelection->DoVerb(iVerb, this);
|
|
EndWaitCursor();
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Hit detection, moving and resizing items
|
|
|
|
CRectItem* CMainView::GetHitItem(CPoint point)
|
|
{
|
|
CMainDoc* pDoc = GetDocument();
|
|
CRectItem* pItemHit = NULL;
|
|
|
|
// Find the item hit by the mouse
|
|
POSITION pos = pDoc->GetStartPosition();
|
|
while (pos != NULL)
|
|
{
|
|
CRectItem* pItem = DYNAMIC_DOWNCAST(CRectItem, pDoc->GetNextItem(pos));
|
|
if (pItem != NULL)
|
|
{
|
|
CRectTracker tracker;
|
|
SetupTracker(&tracker, pItem);
|
|
if (tracker.HitTest(point) >= 0)
|
|
{
|
|
pItemHit = pItem;
|
|
// items later in the list are drawn on top - so keep looking
|
|
}
|
|
}
|
|
}
|
|
return pItemHit;
|
|
}
|
|
|
|
void CMainView::DocToClient(CRect& rect)
|
|
{
|
|
CClientDC dc(this);
|
|
OnPrepareDC(&dc);
|
|
dc.LPtoDP(&rect); // convert logical rect to device rect
|
|
rect.NormalizeRect();
|
|
}
|
|
|
|
void CMainView::ClientToDoc(CRect& rect)
|
|
{
|
|
CClientDC dc(this);
|
|
OnPrepareDC(&dc);
|
|
dc.DPtoLP(&rect); // convert device rect to logical rect
|
|
}
|
|
|
|
void CMainView::DocToClient(CSize& size)
|
|
{
|
|
CClientDC dc(this);
|
|
OnPrepareDC(&dc);
|
|
dc.LPtoDP(&size); // convert logical size to device size
|
|
size.cx = abs(size.cx);
|
|
size.cy = abs(size.cy);
|
|
}
|
|
|
|
void CMainView::ClientToDoc(CSize& size)
|
|
{
|
|
CClientDC dc(this);
|
|
OnPrepareDC(&dc);
|
|
dc.DPtoLP(&size); // convert device rect to logical rect
|
|
size.cx = abs(size.cx);
|
|
size.cy = abs(size.cy);
|
|
}
|
|
|
|
void CMainView::DocToClient(CPoint& point)
|
|
{
|
|
CClientDC dc(this);
|
|
OnPrepareDC(&dc);
|
|
dc.LPtoDP(&point); // convert logical point to device point
|
|
}
|
|
|
|
void CMainView::ClientToDoc(CPoint& point)
|
|
{
|
|
CClientDC dc(this);
|
|
OnPrepareDC(&dc);
|
|
dc.DPtoLP(&point); // convert device point to logical point
|
|
}
|
|
|
|
void CMainView::OnLButtonDown(UINT /*nFlags*/, CPoint point)
|
|
{
|
|
CRectItem* pItemHit = GetHitItem(point);
|
|
SetSelection(pItemHit);
|
|
if (pItemHit == NULL)
|
|
return;
|
|
|
|
CRect rectLimit;
|
|
GetClientRect(rectLimit);
|
|
|
|
CRectTracker tracker;
|
|
SetupTracker(&tracker, pItemHit);
|
|
|
|
UpdateWindow(); // update before entering the tracker
|
|
if (tracker.HitTest(point) == CRectTracker::hitMiddle) // moving, not sizing
|
|
{
|
|
// determine mouse position offset from the item itself
|
|
CRect rect = pItemHit->GetRect();
|
|
DocToClient(rect);
|
|
CPoint ptOffset(point.x - rect.left, point.y - rect.top);
|
|
|
|
// determine sensitivity rectangle (determines when drag starts)
|
|
CRect rectDrag(rect.left, rect.top, rect.left+1, rect.top+1);
|
|
|
|
// execute the drag/drop operation
|
|
m_bInDrag = TRUE;
|
|
ClientToScreen(&rect); // must be in screen co-ordinates
|
|
ClientToScreen(&rectDrag);
|
|
DROPEFFECT dropEffect = pItemHit->DoDragDrop(rect, ptOffset,
|
|
TRUE, DROPEFFECT_COPY|DROPEFFECT_MOVE, &rectDrag);
|
|
if (m_bInDrag == FALSE) // move in same window
|
|
return;
|
|
m_bInDrag = FALSE;
|
|
|
|
if (dropEffect == DROPEFFECT_MOVE)
|
|
{
|
|
// the item was moved (essentially a copy w/delete)
|
|
pItemHit->Invalidate();
|
|
if (m_pSelection == pItemHit)
|
|
m_pSelection = NULL;
|
|
GetDocument()->DeleteItem(pItemHit);
|
|
}
|
|
}
|
|
else if (tracker.Track(this, point))
|
|
{
|
|
ClientToDoc(tracker.m_rect);
|
|
pItemHit->Move(tracker.m_rect);
|
|
GetDocument()->SetModifiedFlag();
|
|
}
|
|
}
|
|
|
|
BOOL CMainView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
|
|
{
|
|
if (pWnd == this && m_pSelection != NULL)
|
|
{
|
|
// give the tracker for the selection a chance
|
|
CRectTracker tracker;
|
|
SetupTracker(&tracker, m_pSelection);
|
|
if (tracker.SetCursor(this, nHitTest))
|
|
return TRUE;
|
|
}
|
|
return CScrollView::OnSetCursor(pWnd, nHitTest, message);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Right mouse for popup context sensitive menu
|
|
|
|
void CMainView::OnRButtonDown(UINT, CPoint point)
|
|
{
|
|
// make sure window is active
|
|
GetParentFrame()->ActivateFrame();
|
|
|
|
SetSelection(GetHitItem(point)); // reselect item if appropriate
|
|
UpdateWindow();
|
|
|
|
if (m_pSelection != NULL)
|
|
{
|
|
CMenu bar;
|
|
if (bar.LoadMenu(ID_OBJECT_POPUP_MENU))
|
|
{
|
|
CMenu& popup = *bar.GetSubMenu(0);
|
|
ASSERT(popup.m_hMenu != NULL);
|
|
|
|
ClientToScreen(&point);
|
|
popup.TrackPopupMenu(TPM_RIGHTBUTTON,
|
|
point.x, point.y,
|
|
AfxGetMainWnd()); // route commands through main window
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMainView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
MessageBeep(0); // to test for proper focus transfer
|
|
|
|
CScrollView::OnChar(nChar, nRepCnt, nFlags);
|
|
}
|
|
|
|
void CMainView::OnSetFocus(CWnd* pOldWnd)
|
|
{
|
|
COleClientItem* pActiveItem = GetDocument()->GetInPlaceActiveItem(this);
|
|
if (pActiveItem != NULL &&
|
|
pActiveItem->GetItemState() == COleClientItem::activeUIState)
|
|
{
|
|
// need to set focus to this item if it is in the same view
|
|
CWnd* pWnd = pActiveItem->GetInPlaceWindow();
|
|
if (pWnd != NULL)
|
|
{
|
|
pWnd->SetFocus();
|
|
return;
|
|
}
|
|
}
|
|
|
|
CScrollView::OnSetFocus(pOldWnd);
|
|
}
|
|
|
|
void CMainView::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
CScrollView::OnSize(nType, cx, cy);
|
|
|
|
UpdateActiveItem();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// support for drag/drop
|
|
|
|
int CMainView::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
|
{
|
|
if (CScrollView::OnCreate(lpCreateStruct) == -1)
|
|
return -1;
|
|
|
|
// register drop target
|
|
m_dropTarget.Register(this);
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL CMainView::OnDrop(COleDataObject* pDataObject,
|
|
DROPEFFECT dropEffect, CPoint point)
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
// clean up focus rect
|
|
OnDragLeave();
|
|
|
|
// offset point as appropriate for dragging
|
|
GetObjectInfo(pDataObject, &m_dragSize, &m_dragOffset);
|
|
CClientDC dc(NULL);
|
|
dc.HIMETRICtoDP(&m_dragSize);
|
|
dc.HIMETRICtoDP(&m_dragOffset);
|
|
point -= m_dragOffset;
|
|
|
|
// if move within the view
|
|
ClientToDoc(point);
|
|
if ((dropEffect & DROPEFFECT_MOVE) && m_bInDrag)
|
|
{
|
|
ASSERT(m_pSelection != NULL);
|
|
m_bInDrag = FALSE; // signal drag code that a move happened
|
|
// set top-left based on point of drop
|
|
CRect rect = m_pSelection->GetRect();
|
|
if (rect.TopLeft() != point) // if moved
|
|
{
|
|
m_pSelection->Move(CRect(point,rect.Size()));
|
|
GetDocument()->SetModifiedFlag();
|
|
}
|
|
}
|
|
// check and paste link
|
|
else if ((dropEffect & DROPEFFECT_LINK) && DoPasteItem(TRUE, pDataObject, &point))
|
|
return TRUE;
|
|
|
|
// paste embedding/static
|
|
else if (DoPasteItem(FALSE, pDataObject, &point))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CMainView::GetObjectInfo(COleDataObject* pDataObject,
|
|
CSize* pSize, CSize* pOffset)
|
|
{
|
|
ASSERT(pSize != NULL);
|
|
|
|
// get object descriptor data
|
|
HGLOBAL hObjDesc = pDataObject->GetGlobalData(m_cfObjectDescriptor);
|
|
if (hObjDesc == NULL)
|
|
{
|
|
if (pOffset != NULL)
|
|
*pOffset = CSize(0, 0); // fill in defaults instead
|
|
*pSize = CSize(0, 0);
|
|
return FALSE;
|
|
}
|
|
ASSERT(hObjDesc != NULL);
|
|
|
|
// otherwise, got CF_OBJECTDESCRIPTOR ok. Lock it down and extract size.
|
|
LPOBJECTDESCRIPTOR pObjDesc = (LPOBJECTDESCRIPTOR)GlobalLock(hObjDesc);
|
|
ASSERT(pObjDesc != NULL);
|
|
pSize->cx = (int)pObjDesc->sizel.cx;
|
|
pSize->cy = (int)pObjDesc->sizel.cy;
|
|
if (pOffset != NULL)
|
|
{
|
|
pOffset->cx = (int)pObjDesc->pointl.x;
|
|
pOffset->cy = (int)pObjDesc->pointl.y;
|
|
}
|
|
GlobalUnlock(hObjDesc);
|
|
GlobalFree(hObjDesc);
|
|
|
|
// successfully retrieved pSize & pOffset info
|
|
return TRUE;
|
|
}
|
|
|
|
DROPEFFECT CMainView::OnDragEnter(COleDataObject* pDataObject,
|
|
DWORD grfKeyState, CPoint point)
|
|
{
|
|
ASSERT(m_prevDropEffect == DROPEFFECT_NONE);
|
|
|
|
GetObjectInfo(pDataObject, &m_dragSize, &m_dragOffset);
|
|
CClientDC dc(NULL);
|
|
dc.HIMETRICtoDP(&m_dragSize);
|
|
dc.HIMETRICtoDP(&m_dragOffset);
|
|
|
|
return OnDragOver(pDataObject, grfKeyState, point);
|
|
}
|
|
|
|
DROPEFFECT CMainView::OnDragOver(COleDataObject*,
|
|
DWORD grfKeyState, CPoint point)
|
|
{
|
|
point -= m_dragOffset; // adjust target rect by original cursor offset
|
|
|
|
// check for point outside logical area -- i.e. in hatched region
|
|
// GetTotalSize() returns the size passed to SetScrollSizes
|
|
CRect rectScroll(CPoint(0, 0), GetTotalSize());
|
|
|
|
CRect rectItem(point,m_dragSize);
|
|
if (rectItem.IsRectEmpty())
|
|
{
|
|
// some apps might have a null size in the object descriptor...
|
|
rectItem.InflateRect(1,1);
|
|
}
|
|
rectItem.OffsetRect(GetDeviceScrollPosition());
|
|
|
|
DROPEFFECT de = DROPEFFECT_NONE;
|
|
CRect rectTemp;
|
|
if (rectTemp.IntersectRect(rectScroll, rectItem))
|
|
{
|
|
// check for force link
|
|
if ((grfKeyState & (MK_CONTROL|MK_SHIFT)) == (MK_CONTROL|MK_SHIFT))
|
|
de = DROPEFFECT_LINK;
|
|
// check for force copy
|
|
else if ((grfKeyState & MK_CONTROL) == MK_CONTROL)
|
|
de = DROPEFFECT_COPY;
|
|
// check for force move
|
|
else if ((grfKeyState & MK_ALT) == MK_ALT)
|
|
de = DROPEFFECT_MOVE;
|
|
// default -- recommended action is move
|
|
else
|
|
de = DROPEFFECT_MOVE;
|
|
}
|
|
|
|
if (point == m_dragPoint)
|
|
return de;
|
|
|
|
// otherwise, cursor has moved -- need to update the drag feedback
|
|
CClientDC dc(this);
|
|
if (m_prevDropEffect != DROPEFFECT_NONE)
|
|
{
|
|
// erase previous focus rect
|
|
dc.DrawFocusRect(CRect(m_dragPoint, m_dragSize));
|
|
}
|
|
m_prevDropEffect = de;
|
|
if (m_prevDropEffect != DROPEFFECT_NONE)
|
|
{
|
|
m_dragPoint = point;
|
|
dc.DrawFocusRect(CRect(point, m_dragSize));
|
|
}
|
|
return de;
|
|
}
|
|
|
|
void CMainView::OnDragLeave()
|
|
{
|
|
CClientDC dc(this);
|
|
if (m_prevDropEffect != DROPEFFECT_NONE)
|
|
{
|
|
dc.DrawFocusRect(CRect(m_dragPoint,m_dragSize)); // erase previous focus rect
|
|
m_prevDropEffect = DROPEFFECT_NONE;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Commands for switching display aspects
|
|
|
|
void CMainView::OnObjectDisplayContent()
|
|
{
|
|
if (m_pSelection == NULL)
|
|
return;
|
|
ASSERT_VALID(m_pSelection);
|
|
m_pSelection->Invalidate();
|
|
m_pSelection->SetDrawAspect(DVASPECT_CONTENT);
|
|
m_pSelection->UpdateExtent();
|
|
m_pSelection->Invalidate();
|
|
}
|
|
|
|
void CMainView::OnUpdateObjectDisplayContent(CCmdUI* pCmdUI)
|
|
{
|
|
if (m_pSelection == NULL)
|
|
{
|
|
pCmdUI->Enable(FALSE);
|
|
return;
|
|
}
|
|
ASSERT_VALID(m_pSelection);
|
|
pCmdUI->SetCheck(m_pSelection->GetDrawAspect() == DVASPECT_CONTENT);
|
|
pCmdUI->Enable(TRUE);
|
|
}
|
|
|
|
void CMainView::OnObjectDisplayAsIcon()
|
|
{
|
|
if (m_pSelection == NULL)
|
|
return;
|
|
ASSERT_VALID(m_pSelection);
|
|
m_pSelection->Invalidate();
|
|
m_pSelection->SetDrawAspect(DVASPECT_ICON);
|
|
m_pSelection->UpdateExtent();
|
|
m_pSelection->Invalidate();
|
|
}
|
|
|
|
void CMainView::OnUpdateObjectDisplayAsIcon(CCmdUI* pCmdUI)
|
|
{
|
|
if (m_pSelection == NULL)
|
|
{
|
|
pCmdUI->Enable(FALSE);
|
|
return;
|
|
}
|
|
ASSERT_VALID(m_pSelection);
|
|
pCmdUI->SetCheck(m_pSelection->GetDrawAspect() == DVASPECT_ICON);
|
|
pCmdUI->Enable(TRUE);
|
|
}
|
|
|
|
void CMainView::UpdateActiveItem()
|
|
{
|
|
// when there is an active item visible, sizing the window may cause
|
|
// more/less of the in-place object to become visible.
|
|
// (ie. the clipping rectangle changes with the size of the window)
|
|
// a container supporting scrolling would also have to do this
|
|
// when scrolling the contents of the window.
|
|
|
|
COleClientItem* pActiveItem = GetDocument()->GetInPlaceActiveItem(this);
|
|
if (pActiveItem != NULL &&
|
|
pActiveItem->GetItemState() == COleClientItem::activeUIState &&
|
|
pActiveItem->GetActiveView() == this)
|
|
{
|
|
// this will update the item rectangles by calling
|
|
// OnGetPosRect & OnGetClipRect.
|
|
pActiveItem->SetItemRects();
|
|
}
|
|
}
|
|
|
|
void CMainView::OnUpdateEditClone(CCmdUI* pCmdUI)
|
|
{
|
|
pCmdUI->Enable(m_pSelection != NULL);
|
|
}
|
|
|
|
void CMainView::OnEditClone()
|
|
{
|
|
if (m_pSelection == NULL)
|
|
return;
|
|
|
|
BeginWaitCursor();
|
|
|
|
CRectItem* pItem = NULL;
|
|
TRY
|
|
{
|
|
// create item from dialog results
|
|
pItem = GetDocument()->CreateItem();
|
|
if (!pItem->CreateCloneFrom(m_pSelection))
|
|
AfxThrowMemoryException(); // any exception will do
|
|
|
|
// offset it so we can see the clone easier
|
|
CRect rect(20, 20, 0, 0);
|
|
ClientToDoc(rect);
|
|
pItem->m_ptPos.x += rect.left;
|
|
pItem->m_ptPos.y += rect.top;
|
|
ASSERT_VALID(pItem);
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
// cleanup item, if allocated
|
|
if (pItem != NULL)
|
|
GetDocument()->DeleteItem(pItem);
|
|
|
|
AfxMessageBox(IDP_FAILED_TO_CREATE);
|
|
}
|
|
END_CATCH_ALL
|
|
|
|
EndWaitCursor();
|
|
}
|
|
|
|
void CMainView::OnPasteSpecial()
|
|
{
|
|
COlePasteSpecialDialog dlg;
|
|
dlg.AddFormat(CMainDoc::m_cfPrivate, TYMED_HGLOBAL,
|
|
IDS_PRIVATE_CF_DESCR, FALSE, FALSE);
|
|
dlg.AddStandardFormats();
|
|
if (dlg.DoModal() != IDOK)
|
|
return;
|
|
|
|
CRectItem* pItem = NULL;
|
|
TRY
|
|
{
|
|
// Get the clipboard format of the selected
|
|
CLIPFORMAT cf = dlg.m_ps.arrPasteEntries[dlg.m_ps.nSelectedIndex].fmtetc.cfFormat;
|
|
if (cf == CMainDoc::m_cfPrivate)
|
|
{
|
|
BOOL bLink = dlg.GetSelectionType() ==
|
|
COlePasteSpecialDialog::pasteLink;
|
|
COleDataObject dataObject;
|
|
dataObject.Attach(dlg.m_ps.lpSrcDataObj, FALSE);
|
|
pItem = DoPasteItem(bLink, &dataObject, NULL, cf);
|
|
|
|
// try to get initial presentation data
|
|
pItem->UpdateLink();
|
|
}
|
|
else
|
|
{
|
|
pItem = GetDocument()->CreateItem();
|
|
if (!dlg.CreateItem(pItem))
|
|
{
|
|
TRACE0("Warning: paste special failed to create item.\n");
|
|
AfxThrowMemoryException();
|
|
}
|
|
|
|
// try to get initial presentation data
|
|
pItem->UpdateLink();
|
|
|
|
// try to get initial extent
|
|
pItem->UpdateExtent();
|
|
|
|
// allow document to offset item to avoid direct superimposition
|
|
GetDocument()->AdjustItemPosition(pItem);
|
|
|
|
// set the selection with bSafeSelect = TRUE
|
|
SetSelection(pItem, TRUE);
|
|
GetDocument()->SetModifiedFlag();
|
|
GetDocument()->UpdateAllViews(NULL, 0, pItem);
|
|
}
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
// cleanup item, if allocated
|
|
if (pItem != NULL)
|
|
GetDocument()->DeleteItem(pItem);
|
|
AfxMessageBox(IDP_FAILED_TO_CREATE);
|
|
return;
|
|
}
|
|
END_CATCH_ALL
|
|
}
|
|
|
|
void CMainView::OnUpdateEditPaste(CCmdUI* pCmdUI)
|
|
{
|
|
// determine if private or standard OLE formats are on the clipboard
|
|
COleDataObject dataObj;
|
|
BOOL bEnable = dataObj.AttachClipboard() &&
|
|
(dataObj.IsDataAvailable(CMainDoc::m_cfPrivate) ||
|
|
COleClientItem::CanCreateFromData(&dataObj));
|
|
|
|
// enable command based on availability
|
|
pCmdUI->Enable(bEnable);
|
|
}
|
|
|
|
void CMainView::OnObjectResetsize()
|
|
{
|
|
ASSERT(m_pSelection != NULL);
|
|
m_pSelection->ResetSize();
|
|
}
|
|
|
|
void CMainView::OnCancelInplace()
|
|
{
|
|
// deactivate the inplace active item on this frame/view
|
|
COleClientItem* pActiveItem = GetDocument()->GetInPlaceActiveItem(this);
|
|
if (pActiveItem != NULL)
|
|
pActiveItem->Deactivate();
|
|
ASSERT(GetDocument()->GetInPlaceActiveItem(this) == NULL);
|
|
}
|
|
|
|
void CMainView::OnDestroy()
|
|
{
|
|
CScrollView::OnDestroy();
|
|
|
|
// deactivate the inplace active item on this view
|
|
COleClientItem* pActiveItem = GetDocument()->GetInPlaceActiveItem(this);
|
|
if (pActiveItem != NULL && pActiveItem->GetActiveView() == this)
|
|
{
|
|
pActiveItem->Deactivate();
|
|
ASSERT(GetDocument()->GetInPlaceActiveItem(this) == NULL);
|
|
}
|
|
}
|
|
|
|
void CMainView::OnUpdateOleEditProperties(CCmdUI* pCmdUI)
|
|
{
|
|
pCmdUI->Enable(m_pSelection != NULL);
|
|
}
|
|
|
|
// edit properties dialog specific to OCLIENT
|
|
class COlePropertiesEx : public COlePropertiesDialog
|
|
{
|
|
public:
|
|
COlePropertiesEx(COleClientItem* pItem,
|
|
UINT nScaleMin = 10, UINT nScaleMax = 500, CWnd* pParentWnd = NULL)
|
|
: COlePropertiesDialog(pItem, nScaleMin, nScaleMax, pParentWnd)
|
|
{ }
|
|
|
|
virtual BOOL OnApplyScale(
|
|
COleClientItem* pItem, int nCurrentScale, BOOL bRelativeToOrig);
|
|
};
|
|
|
|
BOOL COlePropertiesEx::OnApplyScale(
|
|
COleClientItem* pItem, int nCurrentScale, BOOL bRelativeToOrig)
|
|
{
|
|
if (nCurrentScale != -1)
|
|
{
|
|
ASSERT_VALID(pItem);
|
|
CRectItem* pRectItem = (CRectItem*)pItem;
|
|
ASSERT_KINDOF(CRectItem, pRectItem);
|
|
|
|
// reset to original size if necessary
|
|
if (bRelativeToOrig)
|
|
pRectItem->ResetSize();
|
|
|
|
// update extent to reflect scaling factor
|
|
pRectItem->Invalidate();
|
|
CSize size = pRectItem->GetSize();
|
|
size.cx = MulDiv(size.cx, nCurrentScale, 100);
|
|
size.cy = MulDiv(size.cy, nCurrentScale, 100);
|
|
pRectItem->SetSize(size);
|
|
pRectItem->Invalidate();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void CMainView::OnOleEditProperties()
|
|
{
|
|
ASSERT(m_pSelection != NULL);
|
|
|
|
COlePropertiesEx dlg(m_pSelection);
|
|
dlg.DoModal();
|
|
}
|
|
|
|
void CMainView::OnUpdateOleChangeSource(CCmdUI* pCmdUI)
|
|
{
|
|
pCmdUI->Enable(m_pSelection != NULL && m_pSelection->GetType() == OT_LINK);
|
|
}
|
|
|
|
void CMainView::OnOleChangeSource()
|
|
{
|
|
ASSERT(m_pSelection != NULL && m_pSelection->GetType() == OT_LINK);
|
|
|
|
COleChangeSourceDialog dlg(m_pSelection);
|
|
dlg.DoModal();
|
|
}
|