mainview.cpp
上传用户:biuytresa
上传日期:2007-12-07
资源大小:721k
文件大小:33k
源码类别:

DNA

开发平台:

Visual C++

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