home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / mfc / ole / oclient / mainview.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-27  |  32.5 KB  |  1,270 lines

  1. // mainview.cpp : implementation of the CMainView class
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13.  
  14. #include "stdafx.h"
  15. #include "oclient.h"
  16.  
  17. #include "maindoc.h"
  18. #include "mainview.h"
  19. #include "rectitem.h"
  20.  
  21. #ifdef _DEBUG
  22. #undef THIS_FILE
  23. static char BASED_CODE THIS_FILE[] = __FILE__;
  24. #endif
  25.  
  26. /////////////////////////////////////////////////////////////////////////////
  27. // CMainView
  28.  
  29. CBrush NEAR CMainView::m_brHatch;
  30. CLIPFORMAT CMainView::m_cfObjectDescriptor=NULL;
  31.  
  32. IMPLEMENT_DYNCREATE(CMainView, CScrollView)
  33.  
  34. BEGIN_MESSAGE_MAP(CMainView, CScrollView)
  35.     //{{AFX_MSG_MAP(CMainView)
  36.     ON_COMMAND(ID_EDIT_PASTE, OnPaste)
  37.     ON_COMMAND(ID_EDIT_PASTE_LINK, OnPasteLink)
  38.     ON_COMMAND(ID_OLE_INSERT_NEW, OnInsertObject)
  39.     ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR, OnUpdateEditMenu)
  40.     ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
  41.     ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
  42.     ON_COMMAND(ID_EDIT_CUT, OnEditCut)
  43.     ON_WM_LBUTTONDBLCLK()
  44.     ON_WM_LBUTTONDOWN()
  45.     ON_WM_SETCURSOR()
  46.     ON_WM_RBUTTONDOWN()
  47.     ON_WM_CHAR()
  48.     ON_WM_SETFOCUS()
  49.     ON_WM_CREATE()
  50.     ON_WM_SIZE()
  51.     ON_COMMAND(ID_OBJECT_DISPLAYCONTENT, OnObjectDisplayContent)
  52.     ON_UPDATE_COMMAND_UI(ID_OBJECT_DISPLAYCONTENT, OnUpdateObjectDisplayContent)
  53.     ON_COMMAND(ID_OBJECT_DISPLAYASICON, OnObjectDisplayAsIcon)
  54.     ON_UPDATE_COMMAND_UI(ID_OBJECT_DISPLAYASICON, OnUpdateObjectDisplayAsIcon)
  55.     ON_COMMAND(ID_EDIT_PASTE_SPECIAL, OnPasteSpecial)
  56.     ON_UPDATE_COMMAND_UI(ID_EDIT_CLONE, OnUpdateEditClone)
  57.     ON_COMMAND(ID_EDIT_CLONE, OnEditClone)
  58.     ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE_SPECIAL, OnUpdateEditPaste)
  59.     ON_COMMAND(ID_OBJECT_RESETSIZE, OnObjectResetsize)
  60.     ON_COMMAND(ID_CANCEL_INPLACE, OnCancelInplace)
  61.     ON_WM_DESTROY()
  62.     ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)
  63.     ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditMenu)
  64.     ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditMenu)
  65.     ON_UPDATE_COMMAND_UI(ID_OBJECT_RESETSIZE, OnUpdateEditMenu)
  66.     ON_COMMAND(ID_OLE_CHANGE_SOURCE, OnOleChangeSource)
  67.     ON_UPDATE_COMMAND_UI(ID_OLE_CHANGE_SOURCE, OnUpdateOleChangeSource)
  68.     ON_COMMAND(ID_OLE_EDIT_PROPERTIES, OnOleEditProperties)
  69.     ON_UPDATE_COMMAND_UI(ID_OLE_EDIT_PROPERTIES, OnUpdateOleEditProperties)
  70.     //}}AFX_MSG_MAP
  71.     // Standard printing commands
  72.     ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint)
  73.     ON_COMMAND(ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview)
  74. END_MESSAGE_MAP()
  75.  
  76. /////////////////////////////////////////////////////////////////////////////
  77. // CMainView construction/destruction
  78.  
  79. CMainView::CMainView()
  80. {
  81.     if (m_brHatch.m_hObject == NULL)
  82.         m_brHatch.CreateHatchBrush(HS_DIAGCROSS, RGB(0,0,0));
  83.     if (m_cfObjectDescriptor == NULL)
  84.         m_cfObjectDescriptor =
  85.             (CLIPFORMAT)::RegisterClipboardFormat(_T("Object Descriptor"));
  86.  
  87.     m_pSelection = NULL;
  88.     m_prevDropEffect = DROPEFFECT_NONE;
  89.     m_bInDrag = FALSE;
  90. }
  91.  
  92. CMainView::~CMainView()
  93. {
  94. }
  95.  
  96. void CMainView::OnInitialUpdate()
  97. {
  98.     CScrollView::OnInitialUpdate();
  99.  
  100.     // We can't pass MM_ANISOTROPIC to SetScrollSizes so we have to convert to MM_TEXT
  101.     CSize size = GetDocument()->GetDocumentSize();
  102.     CClientDC dc(NULL);
  103.     size.cx = MulDiv(size.cx, dc.GetDeviceCaps(LOGPIXELSX), 100);
  104.     size.cy = MulDiv(size.cy, dc.GetDeviceCaps(LOGPIXELSY), 100);
  105.     SetScrollSizes(MM_TEXT, size);
  106. }
  107.  
  108. /////////////////////////////////////////////////////////////////////////////
  109. // CMainView drawing
  110.  
  111. void CMainView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
  112. {
  113.     CScrollView::OnPrepareDC(pDC, pInfo);
  114.     // set up a reasonable default context
  115.     pDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
  116.     pDC->SetBkColor(::GetSysColor(COLOR_WINDOW));
  117.  
  118.     // LOENGLISH units are based on physical inches
  119.     // We want logical inches so we have to do it differently
  120.     pDC->SetMapMode(MM_ANISOTROPIC);
  121.     pDC->SetViewportExt(
  122.         pDC->GetDeviceCaps(LOGPIXELSX), pDC->GetDeviceCaps(LOGPIXELSY));
  123.     pDC->SetWindowExt(100,-100);
  124. }
  125.  
  126. void CMainView::SetupTracker(CRectTracker* pTracker, CRectItem* pItem,
  127.     CRect* pTrueRect)
  128. {
  129.     ASSERT(pTracker != NULL);
  130.     ASSERT(pItem != NULL);
  131.  
  132.     pTracker->m_rect = pItem->GetRect();
  133.     DocToClient(pTracker->m_rect);
  134.  
  135.     // set minimum size for our OLE items
  136.     pTracker->m_sizeMin.cx = 8;
  137.     pTracker->m_sizeMin.cy = 8;
  138.  
  139.     pTracker->m_nStyle = 0;
  140.  
  141.     // setup resize handles if item is selected
  142.     if (pItem == m_pSelection)
  143.         pTracker->m_nStyle |= CRectTracker::resizeInside;
  144.  
  145.     // put correct border depending on item type
  146.     if (pItem->GetType() == OT_LINK)
  147.         pTracker->m_nStyle |= CRectTracker::dottedLine;
  148.     else
  149.         pTracker->m_nStyle |= CRectTracker::solidLine;
  150.  
  151.     // put hatching over the item if it is currently open
  152.     if (pItem->GetItemState() == COleClientItem::openState ||
  153.         pItem->GetItemState() == COleClientItem::activeUIState)
  154.     {
  155.         pTracker->m_nStyle |= CRectTracker::hatchInside;
  156.     }
  157.  
  158.     if (pTrueRect != NULL)
  159.         pTracker->GetTrueRect(pTrueRect);
  160. }
  161.  
  162. void CMainView::OnDraw(CDC* pDC)
  163. {
  164.     CMainDoc* pDoc = GetDocument();
  165.  
  166.     ASSERT_VALID(pDC);
  167.  
  168.     if (!pDC->IsPrinting())
  169.     {
  170.         m_brHatch.UnrealizeObject();
  171.         CPoint point(0, 0);
  172.         pDC->LPtoDP(&point);
  173.         pDC->SetBrushOrg(point.x % 8, point.y % 8);
  174.  
  175.         CRect rcClip;
  176.         GetClientRect(&rcClip);
  177.         ClientToDoc(rcClip);
  178.         CSize docSize = pDoc->GetDocumentSize();
  179.         if (rcClip.right > docSize.cx)
  180.         {
  181.             CRect rcFill(rcClip);
  182.             rcFill.left = max(rcFill.left,docSize.cx);
  183.             pDC->FillRect(rcFill,&m_brHatch);
  184.         }
  185.         if (rcClip.bottom < -docSize.cy)
  186.         {
  187.             CRect rcFill(rcClip);
  188.             rcFill.top = min(rcFill.top, -docSize.cy);
  189.             pDC->FillRect(rcFill,&m_brHatch);
  190.         }
  191.     }
  192.  
  193.     // Draw all the CRectItems
  194.     POSITION pos = pDoc->GetStartPosition();
  195.     while (pos != NULL)
  196.     {
  197.         CRectItem* pItem = DYNAMIC_DOWNCAST(CRectItem, pDoc->GetNextItem(pos));
  198.         if (pItem != NULL)
  199.         {
  200.             pItem->Draw(pDC, pItem->GetRect());
  201.  
  202.             if (!pDC->IsPrinting())
  203.             {
  204.                 // draw the tracker
  205.                 CRectTracker tracker;
  206.                 CRect rectTrue;
  207.                 SetupTracker(&tracker, pItem, &rectTrue);
  208.                 ClientToDoc(rectTrue);
  209.                 if (pDC->RectVisible(&rectTrue))
  210.                     tracker.Draw(pDC);
  211.             }
  212.         }
  213.     }
  214. }
  215.  
  216. // pHint is the deleted item or NULL if deselect/delete all
  217. void CMainView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
  218. {
  219.     if (pHint == NULL && lHint == 0)
  220.     {
  221.         // some sort of clear all
  222.         m_pSelection = NULL;
  223.     }
  224.  
  225.     if (pHint != NULL && pHint->IsKindOf(RUNTIME_CLASS(CRectItem)))
  226.     {
  227.         // just invalidate the one item
  228.         InvalidateItem((CRectItem*)pHint);
  229.  
  230.         // clear selection if pointing to deleted item
  231.         if (lHint == 1 && pHint == m_pSelection)
  232.         {
  233.             // specific case of pHint being deleted
  234.             m_pSelection = NULL;
  235.         }
  236.     }
  237.     else if (lHint != 0)
  238.     {
  239.         // invalidate arbitrary rectangle
  240.         InvalidateRect((CRect*)lHint);
  241.     }
  242.     else
  243.     {
  244.         // complete update
  245.         CScrollView::OnUpdate(pSender, lHint, pHint);
  246.     }
  247. }
  248.  
  249. void CMainView::InvalidateItem(CRectItem* pItem)
  250. {
  251.     if (m_nMapMode != 0)
  252.     {
  253.         CRectTracker tracker;
  254.         CRect rect;
  255.         SetupTracker(&tracker, pItem, &rect);
  256.         InvalidateRect(&rect);
  257.     }
  258. }
  259.  
  260. BOOL CMainView::OnScrollBy(CSize sizeScroll, BOOL bDoScroll)
  261. {
  262.     // remove drag/drop feedback before scrolling
  263.     if (bDoScroll && m_prevDropEffect != DROPEFFECT_NONE)
  264.     {
  265.         CClientDC dc(this);
  266.         dc.DrawFocusRect(CRect(m_dragPoint, m_dragSize));
  267.             // erase previous focus rect
  268.         m_prevDropEffect = DROPEFFECT_NONE;
  269.     }
  270.  
  271.     // do the scroll
  272.     if (!CScrollView::OnScrollBy(sizeScroll, bDoScroll))
  273.         return FALSE;
  274.  
  275.     // update the position of any in-place active item
  276.     if (bDoScroll)
  277.     {
  278.         UpdateActiveItem();
  279.         UpdateWindow();
  280.     }
  281.  
  282.     return TRUE;
  283. }
  284.  
  285. /////////////////////////////////////////////////////////////////////////////
  286. // CMainView printing
  287.  
  288. BOOL CMainView::OnPreparePrinting(CPrintInfo* pInfo)
  289. {
  290.     // default preparation
  291.     return DoPreparePrinting(pInfo);
  292. }
  293.  
  294. /////////////////////////////////////////////////////////////////////////////
  295. // Selection support
  296.  
  297. BOOL CMainView::IsSelected(const CObject* pDocItem) const
  298. {
  299.     return (pDocItem == m_pSelection);
  300. }
  301.  
  302. void CMainView::SetSelection(CRectItem* pNewSel, BOOL bSafeSelect)
  303. {
  304.     if (pNewSel != NULL && pNewSel == m_pSelection)
  305.         return;
  306.  
  307.     // deactivate any in-place active item on this view!
  308.     COleClientItem* pActiveItem = GetDocument()->GetInPlaceActiveItem(this);
  309.     if (pActiveItem != NULL && pNewSel != pActiveItem)
  310.     {
  311.         if (bSafeSelect)
  312.             return;
  313.         // if we found one, deactivate it
  314.         pActiveItem->Close();
  315.         ASSERT(GetDocument()->GetInPlaceActiveItem(this) == NULL);
  316.     }
  317.     if (m_pSelection != NULL) // invalidate the old item
  318.         InvalidateItem(m_pSelection);
  319.     if ((m_pSelection = pNewSel) != NULL) // invalidate the new item
  320.         InvalidateItem(m_pSelection);
  321. }
  322.  
  323. /////////////////////////////////////////////////////////////////////////////
  324. // CMainView diagnostics
  325.  
  326. #ifdef _DEBUG
  327. void CMainView::AssertValid() const
  328. {
  329.     CScrollView::AssertValid();
  330. }
  331.  
  332. void CMainView::Dump(CDumpContext& dc) const
  333. {
  334.     CScrollView::Dump(dc);
  335. }
  336.  
  337. #endif //_DEBUG
  338.  
  339. /////////////////////////////////////////////////////////////////////////////
  340. // Main 'Edit' menu commands
  341.  
  342. void CMainView::OnUpdateEditMenu(CCmdUI* pCmdUI)
  343. {
  344.     // most Edit menu commands are enabled only if we have a selection
  345.     //  and there are no in-place activations for this view
  346.     pCmdUI->Enable(m_pSelection != NULL &&
  347.         GetDocument()->GetInPlaceActiveItem(this) == NULL);
  348. }
  349.  
  350. void CMainView::OnEditCut()
  351. {
  352.     ASSERT(m_pSelection != NULL);
  353.     TRY
  354.     {
  355.         m_pSelection->CopyToClipboard(TRUE);
  356.         OnEditClear();
  357.     }
  358.     CATCH_ALL(e)
  359.     {
  360.         AfxMessageBox(IDP_CLIPBOARD_CUT_FAILED);
  361.     }
  362.     END_CATCH_ALL
  363. }
  364.  
  365. void CMainView::OnEditCopy()
  366. {
  367.     ASSERT(m_pSelection != NULL);
  368.     TRY
  369.     {
  370.         m_pSelection->CopyToClipboard(TRUE);
  371.     }
  372.     CATCH_ALL(e)
  373.     {
  374.         AfxMessageBox(IDP_CLIPBOARD_COPY_FAILED);
  375.     }
  376.     END_CATCH_ALL
  377. }
  378.  
  379. void CMainView::OnEditClear()
  380. {
  381.     if (m_pSelection != NULL)
  382.         GetDocument()->DeleteItem(m_pSelection);
  383. }
  384.  
  385. void CMainView::OnPaste()
  386. {
  387.     if (DoPasteItem(FALSE, NULL, NULL) == NULL)
  388.         AfxMessageBox(IDP_GET_FROM_CLIPBOARD_FAILED);
  389. }
  390.  
  391. void CMainView::OnPasteLink()
  392. {
  393.     if (DoPasteItem(TRUE, NULL, NULL) == NULL)
  394.         AfxMessageBox(IDP_GET_FROM_CLIPBOARD_FAILED);
  395. }
  396.  
  397. void CMainView::DoPasteNative(
  398.     COleDataObject* pDataObject, CPoint* pPoint, CRectItem* pItem)
  399. {
  400.     // get file refering to clipboard data
  401.     CFile* pFile = pDataObject->GetFileData(CMainDoc::m_cfPrivate);
  402.     if (pFile == NULL)
  403.         {
  404.         // if the file failed to open, throw an exception
  405.         // to force cleanup in DoPasteItem.  the exact
  406.         // type of exception thrown here is unimportant...
  407.  
  408.         AfxThrowFileException(CFileException::generic);
  409.         }
  410.  
  411.     CArchive ar(pFile, CArchive::load);
  412.     TRY
  413.     {
  414.         // connect the file to an archive and read the data
  415.         ar.m_pDocument = GetDocument(); // for COleClientItem serialize
  416.         pItem->Serialize(ar);
  417.     }
  418.     CATCH_ALL(e)
  419.     {
  420.         ar.Close();
  421.         delete pFile;
  422.         THROW_LAST();
  423.     }
  424.     END_CATCH_ALL
  425.  
  426.     ar.Close();
  427.     delete pFile;
  428.  
  429.     // adjust position to that specified by point
  430.     if (pPoint != NULL)
  431.         pItem->m_ptPos = *pPoint;
  432. }
  433.  
  434. void CMainView::DoPasteStandard(BOOL bLink, COleDataObject* pDataObject,
  435.     CPoint* pPoint, CRectItem* pItem, CLIPFORMAT cfFormat)
  436. {
  437.     if (bLink)      // paste link
  438.     {
  439.         if (!pItem->CreateLinkFromData(pDataObject))
  440.             AfxThrowMemoryException();  // any exception will do
  441.     }
  442.     // paste embedded
  443.     else if (!pItem->CreateFromData(pDataObject) &&
  444.         !pItem->CreateStaticFromData(pDataObject, OLERENDER_DRAW, cfFormat))
  445.     {
  446.         AfxThrowMemoryException();      // any exception will do
  447.     }
  448.  
  449.     // copy the current iconic representation
  450.     FORMATETC fmtetc;
  451.     fmtetc.cfFormat = CF_METAFILEPICT;
  452.     fmtetc.dwAspect = DVASPECT_ICON;
  453.     fmtetc.ptd = NULL;
  454.     fmtetc.tymed = TYMED_MFPICT;
  455.     fmtetc.lindex = 1;
  456.     HGLOBAL hObj = pDataObject->GetGlobalData(CF_METAFILEPICT, &fmtetc);
  457.     if (hObj != NULL)
  458.     {
  459.         pItem->SetIconicMetafile(hObj);
  460.         // the following code is an easy way to free a metafile pict
  461.         STGMEDIUM stgMed;
  462.         memset(&stgMed, 0, sizeof(stgMed));
  463.         stgMed.tymed = TYMED_MFPICT;
  464.         stgMed.hGlobal = hObj;
  465.         ReleaseStgMedium(&stgMed);
  466.     }
  467.  
  468.     // set the current drawing aspect
  469.     hObj = pDataObject->GetGlobalData(m_cfObjectDescriptor);
  470.     if (hObj != NULL)
  471.     {
  472.         ASSERT(hObj != NULL);
  473.         // got CF_OBJECTDESCRIPTOR ok.  Lock it down and extract size.
  474.         LPOBJECTDESCRIPTOR pObjDesc = (LPOBJECTDESCRIPTOR)GlobalLock(hObj);
  475.         ASSERT(pObjDesc != NULL);
  476.         pItem->SetDrawAspect((DVASPECT)pObjDesc->dwDrawAspect);
  477.         GlobalUnlock(hObj);
  478.         GlobalFree(hObj);
  479.     }
  480.  
  481.     // set top-left based on point of drop
  482.     if (pPoint != NULL)
  483.         pItem->m_ptPos = *pPoint;
  484.  
  485.     // get size from drag/drop operation
  486.     CSize size;
  487.     if (GetObjectInfo(pDataObject, &size, NULL) && size.cx != 0 && size.cy != 0)
  488.     {
  489.         // use size obtained from object instead of default
  490.         size.cx = MulDiv(size.cx, 10, 254);
  491.         size.cy = -MulDiv(size.cy, 10, 254);
  492.         pItem->SetSize(size);
  493.         CSize sizeExtent;
  494.         pItem->GetCachedExtent(&sizeExtent);
  495.         pItem->SetBaseSize(sizeExtent);
  496.     }
  497.     else
  498.     {
  499.         // no extent from CF_OBJECTDESCRIPTOR, use extent from object
  500.         pItem->UpdateExtent();
  501.     }
  502. }
  503.  
  504.  
  505. // Helper for paste/pastelink
  506. //
  507. //                  bLink       pDataObject     pPoint              cfFormat
  508. //  EditPaste       FALSE       NULL(clipboard) NULL(default)       0
  509. //  Drag/Drop       TRUE/FALSE  X               X                   0
  510. //  PasteLink       TRUE        NULL(clipboard) NULL(default)       0
  511. //  PasteSpecial    TRUE/FALSE  X               NULL(default)       X
  512. CRectItem* CMainView::DoPasteItem(BOOL bLink, COleDataObject* pDataObject,
  513.     CPoint* pPoint, CLIPFORMAT cfFormat)
  514. {
  515.     BeginWaitCursor();
  516.  
  517.     CRectItem* pItem = GetDocument()->CreateItem();
  518.     ASSERT_VALID(pItem);
  519.     BOOL bAllowAdjust = (pPoint == NULL) ? TRUE : FALSE;
  520.  
  521.     // use clipboard data if not doing drag/drop
  522.     COleDataObject clipboardData;
  523.     if (pDataObject == NULL)
  524.     {
  525.         clipboardData.AttachClipboard();
  526.         pDataObject = &clipboardData;
  527.     }
  528.  
  529.     TRY
  530.     {
  531.         if (cfFormat == CMainDoc::m_cfPrivate)
  532.         {
  533.             // if format specified (i.e. PasteSpecial) then use that one
  534.             DoPasteNative(pDataObject, pPoint, pItem);
  535.         }
  536.         else if (!bLink && cfFormat == 0 &&
  537.             pDataObject->IsDataAvailable(CMainDoc::m_cfPrivate))
  538.         {
  539.             // if we're not pasting a link, cfFormat was unspecified,
  540.             // and private format is available use it
  541.             DoPasteNative(pDataObject, pPoint, pItem);
  542.         }
  543.         // otherwise perform a standard paste
  544.         else if (bAllowAdjust)
  545.         {
  546.             CPoint ptDef(10, -10);
  547.             DoPasteStandard(bLink, pDataObject, &ptDef, pItem, cfFormat);
  548.         }
  549.         else
  550.         {
  551.             DoPasteStandard(bLink, pDataObject, pPoint, pItem, cfFormat);
  552.         }
  553.  
  554.         if (bAllowAdjust)
  555.         {
  556.             // allow document to adjust position of item so that it doesn't
  557.             // lay directly over an item of the same size
  558.             // this only occurs if the drop point is not specified
  559.             GetDocument()->AdjustItemPosition(pItem);
  560.         }
  561.     }
  562.     CATCH_ALL(e)
  563.     {
  564.         // general cleanup
  565.         TRACE0("failed to embed/link an OLE object\n");
  566.         pItem->Delete();
  567.         pItem = NULL;
  568.     }
  569.     END_CATCH_ALL
  570.  
  571.     // set the selection with bSafeSelect = TRUE
  572.     SetSelection(pItem, TRUE);
  573.  
  574.     // update the document and views
  575.     GetDocument()->SetModifiedFlag();
  576.     GetDocument()->UpdateAllViews(NULL, 0, pItem);      // including this view
  577.  
  578.     EndWaitCursor();
  579.  
  580.     return pItem;
  581. }
  582.  
  583. /////////////////////////////////////////////////////////////////////////////
  584. // Insert New Object and Activate Object
  585.  
  586. void CMainView::OnInsertObject()
  587. {
  588.     COleInsertDialog dlg;
  589.     if (dlg.DoModal() != IDOK)
  590.         return;
  591.  
  592.     BeginWaitCursor();
  593.  
  594.     CRectItem* pItem = NULL;
  595.     TRY
  596.     {
  597.         // create item from dialog results
  598.         pItem = GetDocument()->CreateItem();
  599.         if (!dlg.CreateItem(pItem))
  600.             AfxThrowMemoryException();  // any exception will do
  601.  
  602.         // try to get initial presentation data
  603.         pItem->UpdateLink();
  604.         pItem->UpdateExtent();
  605.  
  606.         // if insert new object -- initially show the object
  607.         if (dlg.GetSelectionType() == COleInsertDialog::createNewItem)
  608.             pItem->DoVerb(OLEIVERB_SHOW, this);
  609.  
  610.         SetSelection(pItem);
  611.     }
  612.     CATCH_ALL(e)
  613.     {
  614.         // cleanup item, if allocated
  615.         if (pItem != NULL)
  616.             GetDocument()->DeleteItem(pItem);
  617.  
  618.         AfxMessageBox(IDP_FAILED_TO_CREATE);
  619.     }
  620.     END_CATCH_ALL
  621.  
  622.     EndWaitCursor();
  623. }
  624.  
  625. void CMainView::OnLButtonDblClk(UINT, CPoint)
  626. {
  627.     // Double click will activate the main verb
  628.     if (m_pSelection != NULL)
  629.     {
  630.         BeginWaitCursor();
  631.         LONG iVerb = OLEIVERB_PRIMARY;
  632.         if (GetKeyState(VK_CONTROL) < 0)
  633.             iVerb = OLEIVERB_OPEN;
  634.         m_pSelection->DoVerb(iVerb, this);
  635.         EndWaitCursor();
  636.     }
  637. }
  638.  
  639. /////////////////////////////////////////////////////////////////////////////
  640. // Hit detection, moving and resizing items
  641.  
  642. CRectItem* CMainView::GetHitItem(CPoint point)
  643. {
  644.     CMainDoc* pDoc = GetDocument();
  645.     CRectItem* pItemHit = NULL;
  646.  
  647.     // Find the item hit by the mouse
  648.     POSITION pos = pDoc->GetStartPosition();
  649.     while (pos != NULL)
  650.     {
  651.         CRectItem* pItem = DYNAMIC_DOWNCAST(CRectItem, pDoc->GetNextItem(pos));
  652.         if (pItem != NULL)
  653.         {
  654.             CRectTracker tracker;
  655.             SetupTracker(&tracker, pItem);
  656.             if (tracker.HitTest(point) >= 0)
  657.             {
  658.                 pItemHit = pItem;
  659.                 // items later in the list are drawn on top - so keep looking
  660.             }
  661.         }
  662.     }
  663.     return pItemHit;
  664. }
  665.  
  666. void CMainView::DocToClient(CRect& rect)
  667. {
  668.     CClientDC dc(this);
  669.     OnPrepareDC(&dc);
  670.     dc.LPtoDP(&rect); // convert logical rect to device rect
  671.     rect.NormalizeRect();
  672. }
  673.  
  674. void CMainView::ClientToDoc(CRect& rect)
  675. {
  676.     CClientDC dc(this);
  677.     OnPrepareDC(&dc);
  678.     dc.DPtoLP(&rect); // convert device rect to logical rect
  679. }
  680.  
  681. void CMainView::DocToClient(CSize& size)
  682. {
  683.     CClientDC dc(this);
  684.     OnPrepareDC(&dc);
  685.     dc.LPtoDP(&size); // convert logical size to device size
  686.     size.cx = abs(size.cx);
  687.     size.cy = abs(size.cy);
  688. }
  689.  
  690. void CMainView::ClientToDoc(CSize& size)
  691. {
  692.     CClientDC dc(this);
  693.     OnPrepareDC(&dc);
  694.     dc.DPtoLP(&size); // convert device rect to logical rect
  695.     size.cx = abs(size.cx);
  696.     size.cy = abs(size.cy);
  697. }
  698.  
  699. void CMainView::DocToClient(CPoint& point)
  700. {
  701.     CClientDC dc(this);
  702.     OnPrepareDC(&dc);
  703.     dc.LPtoDP(&point); // convert logical point to device point
  704. }
  705.  
  706. void CMainView::ClientToDoc(CPoint& point)
  707. {
  708.     CClientDC dc(this);
  709.     OnPrepareDC(&dc);
  710.     dc.DPtoLP(&point); // convert device point to logical point
  711. }
  712.  
  713. void CMainView::OnLButtonDown(UINT /*nFlags*/, CPoint point)
  714. {
  715.     CRectItem* pItemHit = GetHitItem(point);
  716.     SetSelection(pItemHit);
  717.     if (pItemHit == NULL)
  718.         return;
  719.  
  720.     CRect rectLimit;
  721.     GetClientRect(rectLimit);
  722.  
  723.     CRectTracker tracker;
  724.     SetupTracker(&tracker, pItemHit);
  725.  
  726.     UpdateWindow(); // update before entering the tracker
  727.     if (tracker.HitTest(point) == CRectTracker::hitMiddle) // moving, not sizing
  728.     {
  729.         // determine mouse position offset from the item itself
  730.         CRect rect = pItemHit->GetRect();
  731.         DocToClient(rect);
  732.         CPoint ptOffset(point.x - rect.left, point.y - rect.top);
  733.  
  734.         // determine sensitivity rectangle (determines when drag starts)
  735.         CRect rectDrag(rect.left, rect.top, rect.left+1, rect.top+1);
  736.  
  737.         // execute the drag/drop operation
  738.         m_bInDrag = TRUE;
  739.         ClientToScreen(&rect);  // must be in screen co-ordinates
  740.         ClientToScreen(&rectDrag);
  741.         DROPEFFECT dropEffect = pItemHit->DoDragDrop(rect, ptOffset,
  742.             TRUE, DROPEFFECT_COPY|DROPEFFECT_MOVE, &rectDrag);
  743.         if (m_bInDrag == FALSE) // move in same window
  744.             return;
  745.         m_bInDrag = FALSE;
  746.  
  747.         if (dropEffect == DROPEFFECT_MOVE)
  748.         {
  749.             // the item was moved (essentially a copy w/delete)
  750.             pItemHit->Invalidate();
  751.             if (m_pSelection == pItemHit)
  752.                 m_pSelection = NULL;
  753.             GetDocument()->DeleteItem(pItemHit);
  754.         }
  755.     }
  756.     else if (tracker.Track(this, point))
  757.     {
  758.         ClientToDoc(tracker.m_rect);
  759.         pItemHit->Move(tracker.m_rect);
  760.         GetDocument()->SetModifiedFlag();
  761.     }
  762. }
  763.  
  764. BOOL CMainView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
  765. {
  766.     if (pWnd == this && m_pSelection != NULL)
  767.     {
  768.         // give the tracker for the selection a chance
  769.         CRectTracker tracker;
  770.         SetupTracker(&tracker, m_pSelection);
  771.         if (tracker.SetCursor(this, nHitTest))
  772.             return TRUE;
  773.     }
  774.     return CScrollView::OnSetCursor(pWnd, nHitTest, message);
  775. }
  776.  
  777. /////////////////////////////////////////////////////////////////////////////
  778. // Right mouse for popup context sensitive menu
  779.  
  780. void CMainView::OnRButtonDown(UINT, CPoint point)
  781. {
  782.     // make sure window is active
  783.     GetParentFrame()->ActivateFrame();
  784.  
  785.     SetSelection(GetHitItem(point));    // reselect item if appropriate
  786.     UpdateWindow();
  787.  
  788.     if (m_pSelection != NULL)
  789.     {
  790.         CMenu bar;
  791.         if (bar.LoadMenu(ID_OBJECT_POPUP_MENU))
  792.         {
  793.             CMenu& popup = *bar.GetSubMenu(0);
  794.             ASSERT(popup.m_hMenu != NULL);
  795.  
  796.             ClientToScreen(&point);
  797.             popup.TrackPopupMenu(TPM_RIGHTBUTTON,
  798.                 point.x, point.y,
  799.                 AfxGetMainWnd()); // route commands through main window
  800.         }
  801.     }
  802. }
  803.  
  804. void CMainView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
  805. {
  806.     MessageBeep(0);     // to test for proper focus transfer
  807.  
  808.     CScrollView::OnChar(nChar, nRepCnt, nFlags);
  809. }
  810.  
  811. void CMainView::OnSetFocus(CWnd* pOldWnd)
  812. {
  813.     COleClientItem* pActiveItem = GetDocument()->GetInPlaceActiveItem(this);
  814.     if (pActiveItem != NULL &&
  815.         pActiveItem->GetItemState() == COleClientItem::activeUIState)
  816.     {
  817.         // need to set focus to this item if it is in the same view
  818.         CWnd* pWnd = pActiveItem->GetInPlaceWindow();
  819.         if (pWnd != NULL)
  820.         {
  821.             pWnd->SetFocus();
  822.             return;
  823.         }
  824.     }
  825.  
  826.     CScrollView::OnSetFocus(pOldWnd);
  827. }
  828.  
  829. void CMainView::OnSize(UINT nType, int cx, int cy)
  830. {
  831.     CScrollView::OnSize(nType, cx, cy);
  832.  
  833.     UpdateActiveItem();
  834. }
  835.  
  836. /////////////////////////////////////////////////////////////////////////////
  837. // support for drag/drop
  838.  
  839. int CMainView::OnCreate(LPCREATESTRUCT lpCreateStruct)
  840. {
  841.     if (CScrollView::OnCreate(lpCreateStruct) == -1)
  842.         return -1;
  843.  
  844.     // register drop target
  845.     m_dropTarget.Register(this);
  846.  
  847.     return 0;
  848. }
  849.  
  850. BOOL CMainView::OnDrop(COleDataObject* pDataObject,
  851.     DROPEFFECT dropEffect, CPoint point)
  852. {
  853.     ASSERT_VALID(this);
  854.  
  855.     // clean up focus rect
  856.     OnDragLeave();
  857.  
  858.     // offset point as appropriate for dragging
  859.     GetObjectInfo(pDataObject, &m_dragSize, &m_dragOffset);
  860.     CClientDC dc(NULL);
  861.     dc.HIMETRICtoDP(&m_dragSize);
  862.     dc.HIMETRICtoDP(&m_dragOffset);
  863.     point -= m_dragOffset;
  864.  
  865.     // if move within the view
  866.     ClientToDoc(point);
  867.     if ((dropEffect & DROPEFFECT_MOVE) && m_bInDrag)
  868.     {
  869.         ASSERT(m_pSelection != NULL);
  870.         m_bInDrag = FALSE; // signal drag code that a move happened
  871.         // set top-left based on point of drop
  872.         CRect rect = m_pSelection->GetRect();
  873.         if (rect.TopLeft() != point) // if moved
  874.         {
  875.             m_pSelection->Move(CRect(point,rect.Size()));
  876.             GetDocument()->SetModifiedFlag();
  877.         }
  878.     }
  879.     // check and paste link
  880.     else if ((dropEffect & DROPEFFECT_LINK) && DoPasteItem(TRUE, pDataObject, &point))
  881.         return TRUE;
  882.  
  883.     // paste embedding/static
  884.     else if (DoPasteItem(FALSE, pDataObject, &point))
  885.         return TRUE;
  886.  
  887.     return FALSE;
  888. }
  889.  
  890. BOOL CMainView::GetObjectInfo(COleDataObject* pDataObject,
  891.     CSize* pSize, CSize* pOffset)
  892. {
  893.     ASSERT(pSize != NULL);
  894.  
  895.     // get object descriptor data
  896.     HGLOBAL hObjDesc = pDataObject->GetGlobalData(m_cfObjectDescriptor);
  897.     if (hObjDesc == NULL)
  898.     {
  899.         if (pOffset != NULL)
  900.             *pOffset = CSize(0, 0); // fill in defaults instead
  901.         *pSize = CSize(0, 0);
  902.         return FALSE;
  903.     }
  904.     ASSERT(hObjDesc != NULL);
  905.  
  906.     // otherwise, got CF_OBJECTDESCRIPTOR ok.  Lock it down and extract size.
  907.     LPOBJECTDESCRIPTOR pObjDesc = (LPOBJECTDESCRIPTOR)GlobalLock(hObjDesc);
  908.     ASSERT(pObjDesc != NULL);
  909.     pSize->cx = (int)pObjDesc->sizel.cx;
  910.     pSize->cy = (int)pObjDesc->sizel.cy;
  911.     if (pOffset != NULL)
  912.     {
  913.         pOffset->cx = (int)pObjDesc->pointl.x;
  914.         pOffset->cy = (int)pObjDesc->pointl.y;
  915.     }
  916.     GlobalUnlock(hObjDesc);
  917.     GlobalFree(hObjDesc);
  918.  
  919.     // successfully retrieved pSize & pOffset info
  920.     return TRUE;
  921. }
  922.  
  923. DROPEFFECT CMainView::OnDragEnter(COleDataObject* pDataObject,
  924.     DWORD grfKeyState, CPoint point)
  925. {
  926.     ASSERT(m_prevDropEffect == DROPEFFECT_NONE);
  927.  
  928.     GetObjectInfo(pDataObject, &m_dragSize, &m_dragOffset);
  929.     CClientDC dc(NULL);
  930.     dc.HIMETRICtoDP(&m_dragSize);
  931.     dc.HIMETRICtoDP(&m_dragOffset);
  932.  
  933.     return OnDragOver(pDataObject, grfKeyState, point);
  934. }
  935.  
  936. DROPEFFECT CMainView::OnDragOver(COleDataObject*,
  937.     DWORD grfKeyState, CPoint point)
  938. {
  939.     point -= m_dragOffset;  // adjust target rect by original cursor offset
  940.  
  941.     // check for point outside logical area -- i.e. in hatched region
  942.     // GetTotalSize() returns the size passed to SetScrollSizes
  943.     CRect rectScroll(CPoint(0, 0), GetTotalSize());
  944.  
  945.     CRect rectItem(point,m_dragSize);
  946.     if (rectItem.IsRectEmpty())
  947.     {
  948.         // some apps might have a null size in the object descriptor...
  949.         rectItem.InflateRect(1,1);
  950.     }
  951.     rectItem.OffsetRect(GetDeviceScrollPosition());
  952.  
  953.     DROPEFFECT de = DROPEFFECT_NONE;
  954.     CRect rectTemp;
  955.     if (rectTemp.IntersectRect(rectScroll, rectItem))
  956.     {
  957.         // check for force link
  958.         if ((grfKeyState & (MK_CONTROL|MK_SHIFT)) == (MK_CONTROL|MK_SHIFT))
  959.             de = DROPEFFECT_LINK;
  960.         // check for force copy
  961.         else if ((grfKeyState & MK_CONTROL) == MK_CONTROL)
  962.             de = DROPEFFECT_COPY;
  963.         // check for force move
  964.         else if ((grfKeyState & MK_ALT) == MK_ALT)
  965.             de = DROPEFFECT_MOVE;
  966.         // default -- recommended action is move
  967.         else
  968.             de = DROPEFFECT_MOVE;
  969.     }
  970.  
  971.     if (point == m_dragPoint)
  972.         return de;
  973.  
  974.     // otherwise, cursor has moved -- need to update the drag feedback
  975.     CClientDC dc(this);
  976.     if (m_prevDropEffect != DROPEFFECT_NONE)
  977.     {
  978.         // erase previous focus rect
  979.         dc.DrawFocusRect(CRect(m_dragPoint, m_dragSize));
  980.     }
  981.     m_prevDropEffect = de;
  982.     if (m_prevDropEffect != DROPEFFECT_NONE)
  983.     {
  984.         m_dragPoint = point;
  985.         dc.DrawFocusRect(CRect(point, m_dragSize));
  986.     }
  987.     return de;
  988. }
  989.  
  990. void CMainView::OnDragLeave()
  991. {
  992.     CClientDC dc(this);
  993.     if (m_prevDropEffect != DROPEFFECT_NONE)
  994.     {
  995.         dc.DrawFocusRect(CRect(m_dragPoint,m_dragSize)); // erase previous focus rect
  996.         m_prevDropEffect = DROPEFFECT_NONE;
  997.     }
  998. }
  999.  
  1000. /////////////////////////////////////////////////////////////////////////////
  1001. // Commands for switching display aspects
  1002.  
  1003. void CMainView::OnObjectDisplayContent()
  1004. {
  1005.     if (m_pSelection == NULL)
  1006.         return;
  1007.     ASSERT_VALID(m_pSelection);
  1008.     m_pSelection->Invalidate();
  1009.     m_pSelection->SetDrawAspect(DVASPECT_CONTENT);
  1010.     m_pSelection->UpdateExtent();
  1011.     m_pSelection->Invalidate();
  1012. }
  1013.  
  1014. void CMainView::OnUpdateObjectDisplayContent(CCmdUI* pCmdUI)
  1015. {
  1016.     if (m_pSelection == NULL)
  1017.     {
  1018.         pCmdUI->Enable(FALSE);
  1019.         return;
  1020.     }
  1021.     ASSERT_VALID(m_pSelection);
  1022.     pCmdUI->SetCheck(m_pSelection->GetDrawAspect() == DVASPECT_CONTENT);
  1023.     pCmdUI->Enable(TRUE);
  1024. }
  1025.  
  1026. void CMainView::OnObjectDisplayAsIcon()
  1027. {
  1028.     if (m_pSelection == NULL)
  1029.         return;
  1030.     ASSERT_VALID(m_pSelection);
  1031.     m_pSelection->Invalidate();
  1032.     m_pSelection->SetDrawAspect(DVASPECT_ICON);
  1033.     m_pSelection->UpdateExtent();
  1034.     m_pSelection->Invalidate();
  1035. }
  1036.  
  1037. void CMainView::OnUpdateObjectDisplayAsIcon(CCmdUI* pCmdUI)
  1038. {
  1039.     if (m_pSelection == NULL)
  1040.     {
  1041.         pCmdUI->Enable(FALSE);
  1042.         return;
  1043.     }
  1044.     ASSERT_VALID(m_pSelection);
  1045.     pCmdUI->SetCheck(m_pSelection->GetDrawAspect() == DVASPECT_ICON);
  1046.     pCmdUI->Enable(TRUE);
  1047. }
  1048.  
  1049. void CMainView::UpdateActiveItem()
  1050. {
  1051.     // when there is an active item visible, sizing the window may cause
  1052.     //  more/less of the in-place object to become visible.
  1053.     //  (ie. the clipping rectangle changes with the size of the window)
  1054.     // a container supporting scrolling would also have to do this
  1055.     //  when scrolling the contents of the window.
  1056.  
  1057.     COleClientItem* pActiveItem = GetDocument()->GetInPlaceActiveItem(this);
  1058.     if (pActiveItem != NULL &&
  1059.         pActiveItem->GetItemState() == COleClientItem::activeUIState &&
  1060.         pActiveItem->GetActiveView() == this)
  1061.     {
  1062.         // this will update the item rectangles by calling
  1063.         //  OnGetPosRect & OnGetClipRect.
  1064.         pActiveItem->SetItemRects();
  1065.     }
  1066. }
  1067.  
  1068. void CMainView::OnUpdateEditClone(CCmdUI* pCmdUI)
  1069. {
  1070.     pCmdUI->Enable(m_pSelection != NULL);
  1071. }
  1072.  
  1073. void CMainView::OnEditClone()
  1074. {
  1075.     if (m_pSelection == NULL)
  1076.         return;
  1077.  
  1078.     BeginWaitCursor();
  1079.  
  1080.     CRectItem* pItem = NULL;
  1081.     TRY
  1082.     {
  1083.         // create item from dialog results
  1084.         pItem = GetDocument()->CreateItem();
  1085.         if (!pItem->CreateCloneFrom(m_pSelection))
  1086.             AfxThrowMemoryException();  // any exception will do
  1087.  
  1088.         // offset it so we can see the clone easier
  1089.         CRect rect(20, 20, 0, 0);
  1090.         ClientToDoc(rect);
  1091.         pItem->m_ptPos.x += rect.left;
  1092.         pItem->m_ptPos.y += rect.top;
  1093.         ASSERT_VALID(pItem);
  1094.     }
  1095.     CATCH_ALL(e)
  1096.     {
  1097.         // cleanup item, if allocated
  1098.         if (pItem != NULL)
  1099.             GetDocument()->DeleteItem(pItem);
  1100.  
  1101.         AfxMessageBox(IDP_FAILED_TO_CREATE);
  1102.     }
  1103.     END_CATCH_ALL
  1104.  
  1105.     EndWaitCursor();
  1106. }
  1107.  
  1108. void CMainView::OnPasteSpecial()
  1109. {
  1110.     COlePasteSpecialDialog dlg;
  1111.     dlg.AddFormat(CMainDoc::m_cfPrivate, TYMED_HGLOBAL,
  1112.         IDS_PRIVATE_CF_DESCR, FALSE, FALSE);
  1113.     dlg.AddStandardFormats();
  1114.     if (dlg.DoModal() != IDOK)
  1115.         return;
  1116.  
  1117.     CRectItem* pItem = NULL;
  1118.     TRY
  1119.     {
  1120.         // Get the clipboard format of the selected
  1121.         CLIPFORMAT cf = dlg.m_ps.arrPasteEntries[dlg.m_ps.nSelectedIndex].fmtetc.cfFormat;
  1122.         if (cf == CMainDoc::m_cfPrivate)
  1123.         {
  1124.             BOOL bLink = dlg.GetSelectionType() ==
  1125.                 COlePasteSpecialDialog::pasteLink;
  1126.             COleDataObject dataObject;
  1127.             dataObject.Attach(dlg.m_ps.lpSrcDataObj, FALSE);
  1128.             pItem = DoPasteItem(bLink, &dataObject, NULL, cf);
  1129.  
  1130.             // try to get initial presentation data
  1131.             pItem->UpdateLink();
  1132.         }
  1133.         else
  1134.         {
  1135.             pItem = GetDocument()->CreateItem();
  1136.             if (!dlg.CreateItem(pItem))
  1137.             {
  1138.                 TRACE0("Warning: paste special failed to create item.\n");
  1139.                 AfxThrowMemoryException();
  1140.             }
  1141.  
  1142.             // try to get initial presentation data
  1143.             pItem->UpdateLink();
  1144.  
  1145.             // try to get initial extent
  1146.             pItem->UpdateExtent();
  1147.  
  1148.             // allow document to offset item to avoid direct superimposition
  1149.             GetDocument()->AdjustItemPosition(pItem);
  1150.  
  1151.             // set the selection with bSafeSelect = TRUE
  1152.             SetSelection(pItem, TRUE);
  1153.             GetDocument()->SetModifiedFlag();
  1154.             GetDocument()->UpdateAllViews(NULL, 0, pItem);
  1155.         }
  1156.     }
  1157.     CATCH_ALL(e)
  1158.     {
  1159.         // cleanup item, if allocated
  1160.         if (pItem != NULL)
  1161.             GetDocument()->DeleteItem(pItem);
  1162.         AfxMessageBox(IDP_FAILED_TO_CREATE);
  1163.         return;
  1164.     }
  1165.     END_CATCH_ALL
  1166. }
  1167.  
  1168. void CMainView::OnUpdateEditPaste(CCmdUI* pCmdUI)
  1169. {
  1170.     // determine if private or standard OLE formats are on the clipboard
  1171.     COleDataObject dataObj;
  1172.     BOOL bEnable = dataObj.AttachClipboard() &&
  1173.         (dataObj.IsDataAvailable(CMainDoc::m_cfPrivate) ||
  1174.          COleClientItem::CanCreateFromData(&dataObj));
  1175.  
  1176.     // enable command based on availability
  1177.     pCmdUI->Enable(bEnable);
  1178. }
  1179.  
  1180. void CMainView::OnObjectResetsize()
  1181. {
  1182.     ASSERT(m_pSelection != NULL);
  1183.     m_pSelection->ResetSize();
  1184. }
  1185.  
  1186. void CMainView::OnCancelInplace()
  1187. {
  1188.     // deactivate the inplace active item on this frame/view
  1189.     COleClientItem* pActiveItem = GetDocument()->GetInPlaceActiveItem(this);
  1190.     if (pActiveItem != NULL)
  1191.         pActiveItem->Deactivate();
  1192.     ASSERT(GetDocument()->GetInPlaceActiveItem(this) == NULL);
  1193. }
  1194.  
  1195. void CMainView::OnDestroy()
  1196. {
  1197.     CScrollView::OnDestroy();
  1198.  
  1199.     // deactivate the inplace active item on this view
  1200.     COleClientItem* pActiveItem = GetDocument()->GetInPlaceActiveItem(this);
  1201.     if (pActiveItem != NULL && pActiveItem->GetActiveView() == this)
  1202.     {
  1203.         pActiveItem->Deactivate();
  1204.         ASSERT(GetDocument()->GetInPlaceActiveItem(this) == NULL);
  1205.     }
  1206. }
  1207.  
  1208. void CMainView::OnUpdateOleEditProperties(CCmdUI* pCmdUI)
  1209. {
  1210.     pCmdUI->Enable(m_pSelection != NULL);
  1211. }
  1212.  
  1213. // edit properties dialog specific to OCLIENT
  1214. class COlePropertiesEx : public COlePropertiesDialog
  1215. {
  1216. public:
  1217.     COlePropertiesEx(COleClientItem* pItem,
  1218.         UINT nScaleMin = 10, UINT nScaleMax = 500, CWnd* pParentWnd = NULL)
  1219.         : COlePropertiesDialog(pItem, nScaleMin, nScaleMax, pParentWnd)
  1220.         { }
  1221.  
  1222.     virtual BOOL OnApplyScale(
  1223.         COleClientItem* pItem, int nCurrentScale, BOOL bRelativeToOrig);
  1224. };
  1225.  
  1226. BOOL COlePropertiesEx::OnApplyScale(
  1227.     COleClientItem* pItem, int nCurrentScale, BOOL bRelativeToOrig)
  1228. {
  1229.     if (nCurrentScale != -1)
  1230.     {
  1231.         ASSERT_VALID(pItem);
  1232.         CRectItem* pRectItem = (CRectItem*)pItem;
  1233.         ASSERT_KINDOF(CRectItem, pRectItem);
  1234.  
  1235.         // reset to original size if necessary
  1236.         if (bRelativeToOrig)
  1237.             pRectItem->ResetSize();
  1238.  
  1239.         // update extent to reflect scaling factor
  1240.         pRectItem->Invalidate();
  1241.         CSize size = pRectItem->GetSize();
  1242.         size.cx = MulDiv(size.cx, nCurrentScale, 100);
  1243.         size.cy = MulDiv(size.cy, nCurrentScale, 100);
  1244.         pRectItem->SetSize(size);
  1245.         pRectItem->Invalidate();
  1246.     }
  1247.     return TRUE;
  1248. }
  1249.  
  1250. void CMainView::OnOleEditProperties()
  1251. {
  1252.     ASSERT(m_pSelection != NULL);
  1253.  
  1254.     COlePropertiesEx dlg(m_pSelection);
  1255.     dlg.DoModal();
  1256. }
  1257.  
  1258. void CMainView::OnUpdateOleChangeSource(CCmdUI* pCmdUI)
  1259. {
  1260.     pCmdUI->Enable(m_pSelection != NULL && m_pSelection->GetType() == OT_LINK);
  1261. }
  1262.  
  1263. void CMainView::OnOleChangeSource()
  1264. {
  1265.     ASSERT(m_pSelection != NULL && m_pSelection->GetType() == OT_LINK);
  1266.  
  1267.     COleChangeSourceDialog dlg(m_pSelection);
  1268.     dlg.DoModal();
  1269. }
  1270.