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

  1. // svrview.cpp : implementation of the CServerView 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.  
  15. #include "stdafx.h"
  16. #include "afxdlgs.h"        // for FileOpen
  17. #include "hiersvr.h"
  18.  
  19. #include "svrdoc.h"
  20. #include "svrview.h"
  21. #include "svritem.h"
  22. #include "zoomdlg.h"
  23.  
  24. #ifdef _DEBUG
  25. #undef THIS_FILE
  26. static char BASED_CODE THIS_FILE[] = __FILE__;
  27. #endif
  28.  
  29. CServerNode* NEAR CServerView::m_pDragNode = NULL;
  30.  
  31. static int ReadString(CArchive& ar, char* pString, int nMaxLen);
  32. static BOOL FindItemRect(CDC* pDC, CServerNode* pItemFind, LPRECT lpRect,
  33.     CPoint& ptStart, CServerNode* pRoot);
  34. static CServerNode* HitDetect(CDC* pDC, CPoint point,
  35.     CPoint& ptStart, CServerNode* pRoot);
  36.  
  37. /////////////////////////////////////////////////////////////////////////////
  38. // support for zooming
  39.  
  40. static int NEAR rgiZoomFactor[] =
  41. {
  42.     25, 50, 75, 100, 125, 150, 175, 200, 250, 300
  43. };
  44.  
  45. /////////////////////////////////////////////////////////////////////////////
  46. // CServerView
  47.  
  48. IMPLEMENT_DYNCREATE(CServerView, CScrollView)
  49.  
  50. BEGIN_MESSAGE_MAP(CServerView, CScrollView)
  51.     //{{AFX_MSG_MAP(CServerView)
  52.     ON_COMMAND(ID_CHANGE_NAME, OnChangeName)
  53.     ON_COMMAND(ID_ADD_NODE, OnAddNode)
  54.     ON_UPDATE_COMMAND_UI(ID_CHANGE_NAME, OnUpdateHasSel)
  55.     ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
  56.     ON_WM_LBUTTONDOWN()
  57.     ON_WM_RBUTTONDOWN()
  58.     ON_COMMAND(ID_IMPORT_TEXT, OnImportText)
  59.     ON_COMMAND(ID_VIEW_ZOOMCUSTOM, OnViewZoomCustom)
  60.     ON_COMMAND(ID_EDIT_CUT, OnEditCut)
  61.     ON_WM_LBUTTONDBLCLK()
  62.     ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
  63.     ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)
  64.     ON_WM_CREATE()
  65.     ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
  66.     ON_COMMAND(ID_TREE_COLLAPSEBRANCH, OnTreeCollapsebranch)
  67.     ON_COMMAND(ID_TREE_EXPANDALL, OnTreeExpandall)
  68.     ON_COMMAND(ID_TREE_EXPANDBRANCH, OnTreeExpandbranch)
  69.     ON_COMMAND(ID_TREE_EXPANDONELEVEL, OnTreeExpandonelevel)
  70.     ON_UPDATE_COMMAND_UI(ID_TREE_COLLAPSEBRANCH, OnUpdateTreeCollapsebranch)
  71.     ON_UPDATE_COMMAND_UI(ID_TREE_EXPANDONELEVEL, OnUpdateTreeExpandonelevel)
  72.     ON_UPDATE_COMMAND_UI(ID_TREE_EXPANDALL, OnUpdateTreeExpandall)
  73.     ON_UPDATE_COMMAND_UI(ID_TREE_EXPANDBRANCH, OnUpdateTreeExpandbranch)
  74.     ON_WM_KEYDOWN()
  75.     ON_UPDATE_COMMAND_UI(ID_ADD_NODE, OnUpdateHasSel)
  76.     ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateHasSel)
  77.     ON_UPDATE_COMMAND_UI(ID_IMPORT_TEXT, OnUpdateHasSel)
  78.     ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateHasSel)
  79.     ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR, OnUpdateHasSel)
  80.     ON_WM_SIZE()
  81.     //}}AFX_MSG_MAP
  82.     ON_COMMAND_RANGE(ID_VIEW_ZOOM25, ID_VIEW_ZOOM300, OnZoom)
  83.     ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_ZOOM25, ID_VIEW_ZOOM300, OnUpdateZoom)
  84. END_MESSAGE_MAP()
  85.  
  86. /////////////////////////////////////////////////////////////////////////////
  87. // CServerView construction/destruction
  88.  
  89. CServerView::CServerView()
  90. {
  91.     m_pSelectedNode = NULL;
  92.     m_ptStart = CPoint(CX_MARGIN, CY_MARGIN);   // upper left position
  93.  
  94.     // initialize zoom state (100% from size cache)
  95.     m_zoomNum = CSize(100, 100);
  96.     m_zoomDenom = CSize(100, 100);
  97.     m_prevDropEffect = DROPEFFECT_NONE;
  98. }
  99.  
  100. CServerView::~CServerView()
  101. {
  102. }
  103.  
  104. /////////////////////////////////////////////////////////////////////////////
  105. // Attributes -- public
  106.  
  107. void CServerView::SetSelection(CServerNode* pNewSel, CDC* pDC)
  108. {
  109.     if (pNewSel == m_pSelectedNode)
  110.         return;     // already set
  111.     InvalidateItem(m_pSelectedNode, pDC);
  112.     m_pSelectedNode = pNewSel;
  113.     InvalidateItem(m_pSelectedNode, pDC);
  114. }
  115.  
  116. void CServerView::SetSelection(CServerNode* pNewSel)
  117. {
  118.     CServerDC dc(this);
  119.     SetSelection(pNewSel, &dc);
  120. }
  121.  
  122. /////////////////////////////////////////////////////////////////////////////
  123. // Operations -- public
  124.  
  125. void CServerView::SetScrollInfo()
  126. {
  127.     CServerNode* pRoot = GetDocument()->m_pRoot;
  128.     ASSERT(pRoot != NULL);
  129.  
  130.     //BLOCK: determine new scrolling sizes
  131.     CSize sizeLine;
  132.     CSize sizePage;
  133.     CSize sizeTotal;
  134.     {
  135.         CServerDC dc(this);
  136.  
  137.         pRoot->CalcNodeSize(&dc, sizeLine);
  138.         sizeLine.cx = sizeDefault.cx;
  139.         sizeLine.cy += CY_SEPARATOR;
  140.         sizePage.cx = sizeDefault.cx;
  141.         sizePage.cy = sizeLine.cy * 10;
  142.  
  143.         // set the scroll sizes dependent on the zoom factor
  144.         dc.LPtoDP(&sizePage);
  145.         dc.LPtoDP(&sizeLine);
  146.         sizeTotal = CalcActualViewSize(&dc);
  147.         // subtract out the right and bottom margins
  148.         // these are not interesting and this way we avoid
  149.         // some problems with nonlinear scaling of fonts
  150.         CSize sizeMargin(CX_MARGIN, CY_MARGIN);
  151.         CRect rect(CPoint(0, 0), sizeMargin);
  152.         dc.LPtoDP(rect);
  153.         sizeTotal -= rect.Size();
  154.     }
  155.  
  156.     SetScrollSizes(MM_TEXT, sizeTotal, sizePage, sizeLine);
  157. }
  158.  
  159. BOOL CServerView::SetZoomFactor(CSize zoomNum, CSize zoomDenom)
  160. {
  161.     if (zoomDenom != m_zoomDenom || zoomNum != m_zoomNum)
  162.     {
  163.         // sync to new zoom factor
  164.         m_zoomNum = zoomNum;
  165.         m_zoomDenom = zoomDenom;
  166.  
  167.         // resync to new sizes
  168.         Invalidate();
  169.         return TRUE;
  170.     }
  171.     return FALSE;
  172. }
  173.  
  174. void CServerView::UpdateServerView()
  175. {
  176.     CServerDoc* pDoc = GetDocument();
  177.     pDoc->SetModifiedFlag();
  178.     pDoc->UpdateAllItems(NULL);
  179.     pDoc->UpdateAllViews(NULL);
  180. }
  181.  
  182. CSize CServerView::CalcActualViewSize(CDC *pDC)
  183. {
  184.     return CalcActualItemSize(GetDocument()->m_pRoot, pDC);
  185. }
  186.  
  187. CSize CServerView::CalcActualItemSize(CServerNode* pItem, CDC *pDC)
  188. {
  189.     CSize sizeTotal(0, 0);
  190.     CPoint ptStart = m_ptStart;
  191.     pItem->CalcBounding(pDC, ptStart, sizeTotal);
  192.     sizeTotal.cx += CX_MARGIN;
  193.     // sizeTotal is the extent in logical coords
  194.     // convert from logical to device
  195.     CRect rc(CPoint(0,0),sizeTotal);
  196.     pDC->LPtoDP(rc);
  197.     return rc.Size();
  198. }
  199.  
  200. CSize CServerView::CalcScaledViewSize()
  201. {
  202.     return CalcScaledItemSize(GetDocument()->m_pRoot);
  203. }
  204.  
  205. CSize CServerView::CalcScaledItemSize(CServerNode* pItem)
  206. {
  207.     CServerDC dc(this);
  208.     // set extent to 100%
  209.     dc.SetViewportExt(CSize(1,1));
  210.     dc.SetWindowExt(CSize(1,1));
  211.  
  212.     CSize sizeTotal(0, 0);
  213.     CPoint ptStart = m_ptStart;
  214.     pItem->CalcBounding(&dc, ptStart, sizeTotal);
  215.     sizeTotal.cx += CX_MARGIN;
  216.     // sizeTotal is the native extent in device coords
  217.     sizeTotal.cx = MulDiv(sizeTotal.cx,m_zoomNum.cx,m_zoomDenom.cx);
  218.     sizeTotal.cy = MulDiv(sizeTotal.cy,m_zoomNum.cy,m_zoomDenom.cy);
  219.     return sizeTotal;
  220. }
  221.  
  222. BOOL CServerView::DoPasteItem(COleDataObject* pDataObject)
  223. {
  224.     ASSERT(pDataObject != NULL);
  225.     ASSERT_VALID(this);
  226.     ASSERT(m_pSelectedNode != NULL);
  227.  
  228.     BeginWaitCursor();
  229.  
  230.     TRY
  231.     {
  232.         if (pDataObject->IsDataAvailable(CServerDoc::m_cfPrivate))
  233.             DoPasteNative(pDataObject);
  234.         else if (pDataObject->IsDataAvailable(CF_TEXT))
  235.             DoPasteText(pDataObject);
  236.         else
  237.             AfxThrowNotSupportedException();
  238.     }
  239.     CATCH_ALL(e)
  240.     {
  241.         // general cleanup
  242.         TRACE0("failed to embed/link an OLE object\n");
  243.         EndWaitCursor();
  244.         return FALSE;
  245.     }
  246.     END_CATCH_ALL
  247.  
  248.     EndWaitCursor();
  249.     return TRUE;
  250. }
  251.  
  252. void CServerView::DoPasteNative(COleDataObject *pDataObject)
  253. {
  254.     ASSERT(m_pSelectedNode != NULL);
  255.     CServerNode* pItem = new CServerNode(GetDocument());
  256.     ASSERT_VALID(pItem);
  257.  
  258.     // get file refering to clipboard data
  259.     CFile *pFile = pDataObject->GetFileData(CServerDoc::m_cfPrivate);
  260.     if (pFile == NULL)
  261.     {
  262.         delete pItem;
  263.         return;
  264.     }
  265.  
  266.     // connect the file to the archive and read the contents
  267.     CArchive ar(pFile, CArchive::load);
  268.     ar.m_pDocument = GetDocument(); // for COleClientItem serialize
  269.     pItem->Serialize(ar);
  270.     ar.Close();
  271.     delete pFile;
  272.  
  273.     // add the item to selected node
  274.     m_pSelectedNode->m_listChild.AddHead(pItem);
  275.     SetSelection(pItem);
  276. }
  277.  
  278. void CServerView::DoPasteText(COleDataObject *pDataObject)
  279. {
  280.     ASSERT(m_pSelectedNode != NULL);
  281.  
  282.     // get file refering to clipboard data
  283.     CFile *pFile = pDataObject->GetFileData(CF_TEXT);
  284.     if (pFile == NULL)
  285.         return;
  286.  
  287.     // connect the file to the archive and read the contents
  288.     CArchive ar(pFile, CArchive::load);
  289.     DoImportText(ar);
  290.     ar.Close();
  291.     delete pFile;
  292. }
  293.  
  294. void CServerView::DoImportText(CArchive &ar)
  295. {
  296.     // read in lines appending items from this node
  297.     char szNode[256];
  298. #ifdef _UNICODE
  299.     TCHAR szT[256];
  300. #endif
  301.     int nCurLevel = 0;
  302.     CServerNode* parents[MAX_LEVEL];
  303.     parents[0] = m_pSelectedNode;   // must have a parent at the current level
  304.     CServerNode* pNewSel = NULL;
  305.  
  306.     while (ReadString(ar, szNode, sizeof(szNode)) != NULL)
  307.     {
  308.         int cch = strlen(szNode);
  309.         if (cch == 0)
  310.             continue;
  311.         if (szNode[cch-1] != '\n')
  312.         {
  313.             AfxMessageBox(
  314.                 _T("Text file contains too long a line - aborting read\n"));
  315.             break;      // leaves items loaded so far
  316.         }
  317.         szNode[cch-1] = '\0';
  318.         // check the indentation level
  319.         char* pch = szNode;
  320.         while (*pch == '\t')
  321.             pch++;
  322.         int nLevel = (pch - szNode)+1;
  323.         ASSERT(nLevel >= 1);        // levels are 1 based, 0 is the root
  324.  
  325.         if (*pch == '\0')
  326.             continue;       // skip blank lines
  327.         if (nLevel > nCurLevel + 1 || nLevel >= MAX_LEVEL)
  328.         {
  329.             AfxMessageBox(
  330.                 _T("Text file contains too many tabs = aborting read\n"));
  331.             break;      // leaves items loaded so far
  332.         }
  333.  
  334. #ifdef _UNICODE
  335.         _mbstowcsz(szT, pch, sizeof(szT)/sizeof(szT[0]));
  336.         parents[nLevel] = parents[nLevel-1]->CreateChildNode(szT);
  337. #else
  338.         parents[nLevel] = parents[nLevel-1]->CreateChildNode(pch);
  339. #endif
  340.         nCurLevel = nLevel;
  341.         if (pNewSel == NULL)
  342.             pNewSel = parents[nLevel];
  343.     }
  344.     if (nCurLevel == 0)
  345.         return;     // nothing added
  346.  
  347.     SetSelection(pNewSel);
  348.     UpdateServerView();
  349. }
  350.  
  351. void CServerView::ScrollToItem(CServerNode *pItem, BOOL bScrollUp)
  352. {
  353.     CServerDC dc(this);
  354.  
  355.     CRect rect;
  356.     CPoint ptStart = m_ptStart;
  357.     if (FindItemRect(&dc, pItem, &rect, ptStart, GetDocument()->m_pRoot))
  358.     {
  359.         CRect rc;
  360.         dc.LPtoDP(rect);
  361.         if (GetDocument()->IsInPlaceActive())
  362.         {
  363.             CRect rcPos,rcClip;
  364.             GetDocument()->GetItemPosition(&rcPos);
  365.             GetDocument()->GetItemClipRect(&rcClip);
  366.             rc.IntersectRect(&rcPos,&rcClip);
  367.             rc.OffsetRect(-rcPos.left,-rcPos.top);
  368.             if (!rc.PtInRect(rect.TopLeft()) || !rc.PtInRect(rect.BottomRight()))
  369.             {
  370.                 CSize size(0, 0);
  371.                 // scroll inplace site
  372.                 if (bScrollUp)
  373.                     size.cy = rect.top - rc.top;
  374.                 else
  375.                     size.cy = rect.bottom + rcPos.top - rcClip.bottom;
  376.                 GetDocument()->ScrollContainerBy(size);
  377.             }
  378.         }
  379.         else
  380.         {
  381.             GetClientRect(rc);
  382.             if (!rc.PtInRect(rect.TopLeft()) || !rc.PtInRect(rect.BottomRight()))
  383.             {
  384.                 CPoint ptDevScroll = GetDeviceScrollPosition();
  385.                 if (bScrollUp)
  386.                     ScrollToPosition(CPoint(0,rect.top + ptDevScroll.y));
  387.                 else
  388.                     ScrollToPosition(
  389.                         CPoint(0,ptDevScroll.y + rect.bottom - rc.Height()));
  390.             }
  391.         }
  392.     }
  393. }
  394.  
  395. void CServerView::Locate(int nCount, BOOL bScrollUp)
  396. {
  397.     CServerNode* pRoot = GetDocument()->m_pRoot;
  398.     CServerNode* pItem = pRoot;
  399.  
  400.     if (m_pSelectedNode == NULL)
  401.         SetSelection(pRoot);
  402.  
  403.     if (nCount == 0) // goto top or bottom depending on direction
  404.     {
  405.         if (bScrollUp)
  406.             pItem = pRoot;
  407.         else
  408.         {
  409.             while (pItem->HasChildren())
  410.                 pItem = (CServerNode *)(pItem->m_listChild.GetTail());
  411.         }
  412.     }
  413.     else if (bScrollUp)
  414.     {
  415.         pItem = m_pSelectedNode;
  416.         while (nCount--)
  417.             pItem = pRoot->GetPrev(pItem);
  418.     }
  419.     else // going down
  420.     {
  421.         pItem = m_pSelectedNode;
  422.         while (nCount--)
  423.             pItem = pRoot->GetNext(pItem);
  424.     }
  425.     ScrollToItem(pItem, bScrollUp);
  426.     SetSelection(pItem);
  427.     UpdateWindow();
  428. }
  429.  
  430. void CServerView::InvalidateItem(CServerNode *pItem, CDC* pDC)
  431. {
  432.     if (pItem != NULL)
  433.     {
  434.         CRect rect;
  435.         CPoint ptStart = m_ptStart;
  436.         if (FindItemRect(pDC, pItem, &rect, ptStart, GetDocument()->m_pRoot))
  437.         {
  438.             pDC->LPtoDP(rect);
  439.             InvalidateRect(rect, FALSE);
  440.         }
  441.     }
  442. }
  443.  
  444. void CServerView::InvalidateItem(CServerNode* pItem)
  445. {
  446.     CServerDC dc(this);
  447.     InvalidateItem(pItem, &dc);
  448. }
  449.  
  450. void CServerView::ToggleSelectedItem()
  451. {
  452.     if (m_pSelectedNode != NULL && m_pSelectedNode->HasChildren())
  453.     {
  454.         if (m_pSelectedNode->m_bHideChildren)
  455.             OnTreeExpandonelevel();
  456.         else
  457.             OnTreeCollapsebranch();
  458.     }
  459. }
  460.  
  461. /////////////////////////////////////////////////////////////////////////////
  462. // Implementation
  463.  
  464. void CServerView::OnDraw(CDC* pDC)
  465. {
  466.     if (GetDocument()->DrawTree(pDC, m_ptStart, m_pSelectedNode) == -1)
  467.         TRACE0("Error: CServerDoc::DrawTree failed!!\n");
  468. }
  469.  
  470. void CServerView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
  471. {
  472.     CScrollView::OnUpdate(pSender, lHint, pHint);
  473.     CServerDoc* pDoc = GetDocument();
  474.     CServerNode* pRoot = pDoc->m_pRoot;
  475.     ASSERT(pRoot != NULL);
  476.  
  477.     if (m_pSelectedNode == NULL)
  478.         m_pSelectedNode = pRoot;
  479.  
  480.     if (pDoc->IsInPlaceActive())
  481.     {
  482.         ASSERT_VALID(pDoc->m_pRoot);
  483.         CRect rect;
  484.         pDoc->GetItemPosition(rect);
  485.  
  486.         // adjust rect for new size of view
  487.         rect.BottomRight() = rect.TopLeft() + CalcScaledViewSize();
  488.         pDoc->RequestPositionChange(rect);
  489.             // may resize the window before returning
  490.     }
  491.     SetScrollInfo();
  492. }
  493.  
  494. void CServerView::OnInitialUpdate()
  495. {
  496.     // initialize zoom state (100% from size cache)
  497.     m_zoomNum = CSize(100, 100);
  498.     m_zoomDenom = CSize(100, 100);
  499.  
  500.     // call base class last (will call OnUpdate)
  501.     CScrollView::OnInitialUpdate();
  502. }
  503.  
  504. void CServerView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
  505. {
  506.     CScrollView::OnPrepareDC(pDC, pInfo);
  507.  
  508.     pDC->SetMapMode(MM_ANISOTROPIC);
  509.     pDC->SetViewportExt(m_zoomNum);
  510.     pDC->SetWindowExt(m_zoomDenom);
  511. }
  512.  
  513. void CServerView::SelectAtPoint(CPoint point, CPoint& pointHit)
  514. {
  515.     CServerDC dc(this);
  516.  
  517.     // change the selection as appropriate
  518.     pointHit = m_ptStart;
  519.     CServerNode* pSelection = HitDetect(&dc, point, pointHit,
  520.         GetDocument()->m_pRoot);
  521.  
  522.     // now set the selection to new hit-tested node
  523.     SetSelection(pSelection, &dc);
  524. }
  525.  
  526. void CServerView::DoBranch(CServerNode *pItem, BOOL bHide)
  527. {
  528.     if (pItem->HasChildren())
  529.     {
  530.         pItem->m_bHideChildren = bHide;
  531.         POSITION pos = pItem->m_listChild.GetHeadPosition();
  532.         while (pos != NULL)
  533.             DoBranch((CServerNode *)pItem->m_listChild.GetNext(pos),bHide);
  534.     }
  535. }
  536.  
  537. BOOL CServerView::OnDrop(COleDataObject* pDataObject, DROPEFFECT, CPoint)
  538. {
  539.     ASSERT_VALID(this);
  540.     OnDragLeave();
  541.     if (DoPasteItem(pDataObject))
  542.     {
  543.         UpdateServerView();
  544.         return TRUE;
  545.     }
  546.     else
  547.         return FALSE;
  548. }
  549.  
  550. DROPEFFECT CServerView::OnDragEnter(COleDataObject* pDataObject,
  551.     DWORD grfKeyState, CPoint point)
  552. {
  553.     ASSERT(m_prevDropEffect == DROPEFFECT_NONE);
  554.     return OnDragOver(pDataObject, grfKeyState, point);
  555. }
  556.  
  557. DROPEFFECT CServerView::OnDragOver(COleDataObject* pDataObject,
  558.     DWORD grfKeyState, CPoint point)
  559. {
  560.     DROPEFFECT dropEffect = DROPEFFECT_NONE;
  561.     if (pDataObject->IsDataAvailable(CServerDoc::m_cfPrivate) ||
  562.         pDataObject->IsDataAvailable(CF_TEXT))
  563.     {
  564.         CPoint pointHit;
  565.         SelectAtPoint(point, pointHit);
  566.         UpdateWindow();
  567.         if (m_pSelectedNode != NULL)
  568.         {
  569.             // don't allow a node to drop on itself
  570.             if (m_pDragNode == m_pSelectedNode)
  571.                 dropEffect = DROPEFFECT_NONE;
  572.             // if drop target is a child of drag source
  573.             // then don't drop
  574.             else if (m_pDragNode != NULL && m_pDragNode->IsChild(m_pSelectedNode))
  575.                 dropEffect = DROPEFFECT_NONE;
  576.             // check for force link
  577.             else if ((grfKeyState & (MK_CONTROL|MK_SHIFT)) == (MK_CONTROL|MK_SHIFT))
  578.                 dropEffect = DROPEFFECT_COPY;
  579.             // check for force copy
  580.             else if ((grfKeyState & MK_CONTROL) == MK_CONTROL)
  581.                 dropEffect = DROPEFFECT_COPY;
  582.             // check for force move
  583.             else if ((grfKeyState & MK_ALT) == MK_ALT)
  584.                 dropEffect = DROPEFFECT_MOVE;
  585.             // if m_pDragNode == NULL then not dropping on self
  586.             // so make default effect be copy
  587.             // if dropping on self make default be move
  588.             else
  589.                 dropEffect = (m_pDragNode == NULL) ? DROPEFFECT_COPY :
  590.                     DROPEFFECT_MOVE;
  591.         }
  592.     }
  593.     m_prevDropEffect = dropEffect;
  594.     return dropEffect;
  595. }
  596.  
  597. void CServerView::OnDragLeave()
  598. {
  599.     m_prevDropEffect = DROPEFFECT_NONE;
  600. }
  601.  
  602. /////////////////////////////////////////////////////////////////////////////
  603. // CServerView commands
  604.  
  605. void CServerView::OnUpdateHasSel(CCmdUI* pCmdUI)
  606. {
  607.     pCmdUI->Enable(m_pSelectedNode != NULL);
  608. }
  609.  
  610. void CServerView::OnChangeName()
  611. {
  612.     if (m_pSelectedNode != NULL && m_pSelectedNode->PromptChangeNode())
  613.     {
  614.         GetDocument()->SetModifiedFlag();
  615.         GetDocument()->UpdateAllItems(NULL);
  616.         GetDocument()->UpdateAllViews(NULL);
  617.     }
  618. }
  619.  
  620. void CServerView::OnAddNode()
  621. {
  622.     if (m_pSelectedNode == NULL)
  623.         AfxThrowNotSupportedException();
  624.     CServerNode* pNew;
  625.     if ((pNew = m_pSelectedNode->PromptNewChildNode()) == NULL)
  626.         return;
  627.  
  628.     SetSelection(pNew);
  629.     UpdateServerView();
  630. }
  631.  
  632. void CServerView::OnEditCopy()
  633. {
  634.     ASSERT_VALID(this);
  635.     if (m_pSelectedNode == NULL)
  636.         return;
  637.  
  638.     // get a server item suitable to generate the clipboard data
  639.     CServerItem* pItem = m_pSelectedNode->m_pServerItem;
  640.     if (pItem == NULL)
  641.         pItem = new CServerItem(GetDocument(), m_pSelectedNode);
  642.     ASSERT_VALID(pItem);
  643.  
  644.     pItem->CopyToClipboard(TRUE);
  645. }
  646.  
  647. void CServerView::OnLButtonDown(UINT, CPoint point)
  648. {
  649.     // m_pDragNode != NULL only when drag in progress
  650.     ASSERT(m_pDragNode == NULL);
  651.     CPoint pointHit;
  652.     SelectAtPoint(point, pointHit);
  653.     UpdateWindow();
  654.  
  655.     // maybe start drag drop operation on selection
  656.     if (m_pSelectedNode != NULL)
  657.     {
  658.         // record current selection because a drop back in same view
  659.         // will change the current selection
  660.         m_pDragNode = m_pSelectedNode;
  661.  
  662.         // determine rectangle of object we'll be dragging
  663.         CServerDC dc(this);
  664.         CSize size = CalcActualItemSize(m_pSelectedNode, &dc);
  665.         CRect rect(pointHit, size);
  666.  
  667.         // get a server item suitable to generate the clipboard data
  668.         CServerItem* pItem = m_pSelectedNode->m_pServerItem;
  669.         if (pItem == NULL)
  670.             pItem = new CServerItem(GetDocument(), m_pSelectedNode);
  671.         ASSERT_VALID(pItem);
  672.  
  673.         // rect must be in screen co-ordinates
  674.         dc.LPtoDP(&rect);
  675.         CPoint ptOffset = point - rect.TopLeft();
  676.         ClientToScreen(&rect);
  677.  
  678.         // drag the object
  679.         if (pItem->DoDragDrop(rect, ptOffset, TRUE,
  680.             DROPEFFECT_COPY | DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
  681.         {
  682.             // the object was moved, need to delete/move depending on dest
  683.             CServerDoc* pDoc = GetDocument();
  684.             if (m_pSelectedNode == m_pDragNode)
  685.                 SetSelection(pDoc->m_pRoot->GetPrev(m_pSelectedNode));
  686.             if (m_pDragNode == pDoc->m_pRoot)
  687.                 pDoc->m_pRoot->InitRootNode();
  688.             else
  689.                 pDoc->m_pRoot->FindAndDelete(m_pDragNode);
  690.  
  691.             // if drop was not back in same view clear selected node
  692.             UpdateServerView();
  693.         }
  694.         m_pDragNode = NULL;
  695.     }
  696. }
  697.  
  698. void CServerView::OnRButtonDown(UINT /*nFlags*/, CPoint point)
  699. {
  700.     // make sure window is active
  701.     GetParentFrame()->ActivateFrame();
  702.  
  703.     CPoint pointHit;
  704.     SelectAtPoint(point, pointHit); // select node first
  705.     UpdateWindow();
  706.  
  707.     int iSub;
  708.     if (m_pSelectedNode == NULL ||
  709.       (iSub = m_pSelectedNode->GetPopupMenuIndex()) == -1)
  710.        return;  // nothing if no selection or no popup
  711.  
  712.     CMenu popups;
  713.     if (!popups.LoadMenu(IDR_POPUPS))
  714.         AfxThrowResourceException();
  715.     CMenu* pMenu = popups.GetSubMenu(iSub);
  716.     ASSERT(pMenu != NULL);
  717.  
  718.     ClientToScreen(&point);
  719.     pMenu->TrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON,
  720.         point.x, point.y, AfxGetMainWnd());
  721. }
  722.  
  723. void CServerView::OnImportText()
  724. {
  725.     if (m_pSelectedNode == NULL)
  726.         AfxThrowNotSupportedException();
  727.  
  728.     CFileDialog dlg(TRUE, _T("txt"), NULL,
  729.         OFN_FILEMUSTEXIST | OFN_HIDEREADONLY,
  730.         _T("Text Files (*.txt)|*.txt|All Files (*.*)|*.*||"));
  731.     if (dlg.DoModal() != IDOK)
  732.         return;                 // stay with old data file
  733.  
  734.     CFile file;
  735.     if (!file.Open(dlg.GetPathName(), CFile::modeRead))
  736.     {
  737.         AfxMessageBox(_T("Failed to open text file"));
  738.         return;
  739.     }
  740.  
  741.     CArchive ar(&file,CArchive::load);
  742.     DoImportText(ar);
  743.     ar.Close();
  744.     file.Close();
  745. }
  746.  
  747. static int ReadString(CArchive& ar, char* pString, int nMaxLen)
  748. {
  749.     int nCount = 0;
  750.     char ch;
  751.     pString[nCount] = (char)0;
  752.     TRY
  753.     {
  754.         do
  755.         {
  756.             ar >> (BYTE&)ch;
  757.  
  758.             // watch out for ^Z (EOF under DOS)
  759.             if (ch == 0x1A)
  760.                 break;
  761.  
  762.             // combine "\r\n" pair into single "\n"
  763.             if (ch == '\n' && nCount != 0 && pString[nCount-1] == '\r')
  764.                 nCount--;
  765.  
  766.             pString[nCount++] = ch;
  767.  
  768.         } while (nCount < nMaxLen-1 && ch != '\n');
  769.     }
  770.     END_TRY
  771.  
  772. #ifdef _OLD
  773.     // insert newline if missing
  774.     if (nCount != 0 && pString[nCount-1] != '\n' && nCount < nMaxLen-1)
  775.         pString[nCount++] = '\n';
  776.     pString[nCount] = (char)0;
  777. #else
  778.     // insert newline if missing
  779.     if (nCount != 0 && pString[nCount-1] != '\n' && nCount < nMaxLen-1)
  780.     {
  781.         if (pString[nCount-1] == '\0')
  782.             pString[nCount-1] = '\n';
  783.         else
  784.             pString[nCount++] = '\n';
  785.     }
  786.     pString[nCount] = (char)0;
  787. #endif
  788.     return nCount;
  789. }
  790.  
  791. /////////////////////////////////////////////////////////////////////////////
  792. // Zooming user interface
  793.  
  794. void CServerView::OnZoom(UINT nID)
  795. {
  796.     ASSERT(nID >= ID_VIEW_ZOOM25 && nID <= ID_VIEW_ZOOM300);
  797.  
  798.     CSize zoomDenom;
  799.     CSize zoomNum;
  800.  
  801.     // all of our zoom factors use denominator of 100
  802.     zoomDenom.cx = 100;
  803.     zoomDenom.cy = 100;
  804.  
  805.     // get zoom factor numerator and set it
  806.     ASSERT(nID-ID_VIEW_ZOOM25 < sizeof(rgiZoomFactor)/sizeof(rgiZoomFactor[0]));
  807.     int iZoomFactor = rgiZoomFactor[nID-ID_VIEW_ZOOM25];
  808.     zoomNum.cx = iZoomFactor;
  809.     zoomNum.cy = iZoomFactor;
  810.  
  811.     // change the zoom factor to new zoom factor
  812.     SetZoomFactor(zoomNum, zoomDenom);
  813.     SetScrollInfo();
  814. }
  815.  
  816. void CServerView::OnUpdateZoom(CCmdUI* pCmdUI)
  817. {
  818.     UINT nID = pCmdUI->m_nID;
  819.  
  820.     if (m_zoomDenom.cx == 100 && m_zoomDenom.cy == 100 &&
  821.         nID != ID_VIEW_ZOOMCUSTOM)
  822.     {
  823.         ASSERT(nID-ID_VIEW_ZOOM25 <
  824.             sizeof(rgiZoomFactor)/sizeof(rgiZoomFactor[0]));
  825.         int iZoomFactor = rgiZoomFactor[nID-ID_VIEW_ZOOM25];
  826.  
  827.         if (iZoomFactor == m_zoomNum.cx && iZoomFactor == m_zoomNum.cy)
  828.         {
  829.             pCmdUI->SetCheck(TRUE);
  830.             return;
  831.         }
  832.     }
  833.  
  834.     // default to not checked
  835.     pCmdUI->SetCheck(FALSE);
  836. }
  837.  
  838. void CServerView::OnViewZoomCustom()
  839. {
  840.     // prepare dialog data
  841.     CZoomDlg dlg;
  842.     dlg.m_zoomX = m_zoomNum.cx;
  843.     dlg.m_zoomY = m_zoomNum.cy;
  844.  
  845.     // launch dialog
  846.     if (dlg.DoModal() == IDOK)
  847.     {
  848.         // set new zoom factors
  849.         CSize zoomNum(dlg.m_zoomX, dlg.m_zoomY);
  850.         SetZoomFactor(zoomNum, m_zoomDenom);
  851.         SetScrollInfo();
  852.     }
  853. }
  854.  
  855. /////////////////////////////////////////////////////////////////////////////
  856.  
  857. void CServerView::OnEditCut()
  858. {
  859.     ASSERT(m_pSelectedNode != NULL);
  860.     CServerDoc* pDoc = GetDocument();
  861.     OnEditCopy();
  862.     if (m_pSelectedNode == pDoc->m_pRoot)
  863.         pDoc->m_pRoot->InitRootNode();
  864.     else if (pDoc->m_pRoot->FindAndDelete(m_pSelectedNode))
  865.         m_pSelectedNode = NULL;
  866.     UpdateServerView();
  867. }
  868.  
  869. void CServerView::OnLButtonDblClk(UINT /*nFlags*/, CPoint point)
  870. {
  871.     CPoint pointHit;
  872.     SelectAtPoint(point, pointHit);
  873.     ToggleSelectedItem();
  874. }
  875.  
  876. void CServerView::OnEditPaste()
  877. {
  878.     COleDataObject clipboardData;
  879.     clipboardData.AttachClipboard();
  880.     DoPasteItem(&clipboardData);
  881.     UpdateServerView();
  882. }
  883.  
  884. void CServerView::OnUpdateEditPaste(CCmdUI* pCmdUI)
  885. {
  886.     // determine if private or standard OLE formats are on the clipboard
  887.     COleDataObject dataObj;
  888.     BOOL bEnable = m_pSelectedNode != NULL &&
  889.         dataObj.AttachClipboard() &&
  890.         (dataObj.IsDataAvailable(CServerDoc::m_cfPrivate) ||
  891.          dataObj.IsDataAvailable(CF_TEXT));
  892.     // enable command based on availability
  893.     pCmdUI->Enable(bEnable);
  894. }
  895.  
  896. int CServerView::OnCreate(LPCREATESTRUCT lpCreateStruct)
  897. {
  898.     if (CScrollView::OnCreate(lpCreateStruct) == -1)
  899.         return -1;
  900.  
  901.     // register drop target
  902.     m_dropTarget.Register(this);
  903.  
  904.     // setup scroll state so it is possible to calculate the extent
  905.     SetScrollSizes(MM_TEXT, CSize(0, 0));
  906.  
  907.     return 0;
  908. }
  909.  
  910. void CServerView::OnEditClear()
  911. {
  912.     CServerNode* pRoot = GetDocument()->m_pRoot;
  913.     if (m_pSelectedNode == NULL)
  914.         return;
  915.     if (m_pSelectedNode == pRoot)
  916.         pRoot->InitRootNode();
  917.     else
  918.     {
  919.         CServerNode *pItem = pRoot->GetPrev(m_pSelectedNode);
  920.         if (pRoot->FindAndDelete(m_pSelectedNode))
  921.             m_pSelectedNode = pRoot->GetNext(pItem);
  922.     }
  923.     UpdateServerView();
  924. }
  925.  
  926. void CServerView::OnTreeCollapsebranch()
  927. {
  928.     DoBranch(m_pSelectedNode,TRUE);
  929.     UpdateServerView();
  930. }
  931.  
  932. void CServerView::OnTreeExpandall()
  933. {
  934.     DoBranch(GetDocument()->m_pRoot,FALSE);
  935.     UpdateServerView();
  936. }
  937.  
  938. void CServerView::OnTreeExpandbranch()
  939. {
  940.     DoBranch(m_pSelectedNode,FALSE);
  941.     UpdateServerView();
  942. }
  943.  
  944. void CServerView::OnTreeExpandonelevel()
  945. {
  946.     if (m_pSelectedNode->HasChildren())
  947.     {
  948.         m_pSelectedNode->m_bHideChildren = FALSE;
  949.         UpdateServerView();
  950.     }
  951. }
  952.  
  953. void CServerView::OnUpdateTreeCollapsebranch(CCmdUI* pCmdUI)
  954. {
  955.     pCmdUI->Enable(m_pSelectedNode != NULL && m_pSelectedNode->HasChildren() &&
  956.         !m_pSelectedNode->m_bHideChildren);
  957. }
  958.  
  959. void CServerView::OnUpdateTreeExpandonelevel(CCmdUI* pCmdUI)
  960. {
  961.     pCmdUI->Enable(m_pSelectedNode != NULL && m_pSelectedNode->HasChildren() &&
  962.         m_pSelectedNode->m_bHideChildren);
  963. }
  964.  
  965. void CServerView::OnUpdateTreeExpandall(CCmdUI* pCmdUI)
  966. {
  967.     pCmdUI->Enable(GetDocument()->m_pRoot != NULL &&
  968.         GetDocument()->m_pRoot->HasChildren());
  969. }
  970.  
  971. void CServerView::OnUpdateTreeExpandbranch(CCmdUI* pCmdUI)
  972. {
  973.     pCmdUI->Enable(m_pSelectedNode != NULL && m_pSelectedNode->HasChildren());
  974. }
  975.  
  976. void CServerView::OnKeyDown(UINT nChar, UINT /*nRepCnt*/, UINT /*nFlags*/)
  977. {
  978.     switch (nChar)
  979.     {
  980.         case VK_RETURN:
  981.             ToggleSelectedItem();
  982.             break;
  983.         case VK_UP:
  984.             Locate(1, TRUE);
  985.             break;
  986.         case VK_DOWN:
  987.             Locate(1, FALSE);
  988.             break;
  989.         case VK_HOME:
  990.             Locate(0, TRUE);
  991.             break;
  992.         case VK_END:
  993.             Locate(0, FALSE);
  994.             break;
  995.         case VK_PRIOR:
  996.             Locate(10, TRUE);
  997.             break;
  998.         case VK_NEXT:
  999.             Locate(10, FALSE);
  1000.             break;
  1001.     }
  1002. }
  1003.  
  1004. void CServerView::OnSize(UINT nType, int cx, int cy)
  1005. {
  1006.     // update scroll bar size before handling the size message
  1007.     //  (this avoids multiple updates during in-place activation)
  1008.     SetScrollInfo();
  1009.  
  1010.     CScrollView::OnSize(nType, cx, cy);
  1011. }
  1012.  
  1013. /////////////////////////////////////////////////////////////////////////////
  1014. // CServerDC class -- helper for setting up and cleaning up DC
  1015.  
  1016. CServerDC::CServerDC(CServerView *pView) : CClientDC(pView)
  1017. {
  1018.     pView->OnPrepareDC(this);
  1019.     pOldFont = pView->GetDocument()->SelectDocFont(this, font);
  1020. }
  1021.  
  1022. CServerDC::~CServerDC()
  1023. {
  1024.     if (pOldFont != NULL)
  1025.         SelectObject(pOldFont);
  1026. }
  1027.  
  1028. /////////////////////////////////////////////////////////////////////////////
  1029. // non-member static functions
  1030.  
  1031. // calculate the bounding rect for a given item in the context of this view
  1032. static BOOL FindItemRect(CDC* pDC, CServerNode* pItemFind, LPRECT lpRect,
  1033.     CPoint& ptStart, CServerNode* pRoot)
  1034. {
  1035.     ASSERT(pItemFind != NULL);
  1036.     ASSERT(lpRect != NULL);
  1037.     ASSERT(pRoot != NULL);
  1038.  
  1039.     CSize sizeNode;
  1040.     pRoot->CalcNodeSize(pDC, sizeNode);
  1041.     if (pItemFind == pRoot)
  1042.     {
  1043.         // item rect does not include separator
  1044.         lpRect->right = (lpRect->left = ptStart.x) + sizeNode.cx;
  1045.         lpRect->bottom = (lpRect->top = ptStart.y) + sizeNode.cy;
  1046.         return TRUE;
  1047.     }
  1048.  
  1049.     CPoint pt(CX_INDENT, CY_SEPARATOR);
  1050.     ptStart.x += CX_INDENT; // not essential for calculation
  1051.     ptStart.y += sizeNode.cy + CY_SEPARATOR;
  1052.  
  1053.     // check the kids
  1054.     if (!pRoot->m_bHideChildren)
  1055.     {
  1056.         POSITION pos = pRoot->m_listChild.GetHeadPosition();
  1057.         while (pos != NULL)
  1058.         {
  1059.             CServerNode* pChild = (CServerNode*) (pRoot->m_listChild.GetNext(pos));
  1060.             if (FindItemRect(pDC, pItemFind, lpRect, ptStart, pChild))
  1061.                 return TRUE;    // found
  1062.         }
  1063.     }
  1064.     ptStart.x -= CX_INDENT;
  1065.     return FALSE;
  1066. }
  1067.  
  1068. // calculate the bounding rect for a given item in the context of this view
  1069. static CServerNode* HitDetect(CDC* pDC, CPoint point,
  1070.     CPoint& ptStart, CServerNode* pRoot)
  1071. {
  1072.     ASSERT(pRoot != NULL);
  1073.  
  1074.     CSize sizeNode;
  1075.     pRoot->CalcNodeSize(pDC, sizeNode);
  1076.     CRect rect(ptStart, sizeNode);
  1077.     pDC->LPtoDP(rect);
  1078.     if (rect.PtInRect(point))
  1079.         return pRoot;
  1080.  
  1081.     ptStart.x += CX_INDENT;
  1082.     ptStart.y += sizeNode.cy + CY_SEPARATOR;
  1083.     CPoint pt = ptStart;
  1084.     pDC->LPtoDP(&pt);
  1085.     if (pt.y >= point.y)
  1086.         return FALSE;       // no point in looking any lower
  1087.  
  1088.     // check the kids
  1089.     if (!pRoot->m_bHideChildren)
  1090.     {
  1091.         POSITION pos = pRoot->m_listChild.GetHeadPosition();
  1092.         while (pos != NULL)
  1093.         {
  1094.             CServerNode* pChild = (CServerNode*) (pRoot->m_listChild.GetNext(pos));
  1095.             CServerNode* pItem = HitDetect(pDC, point, ptStart, pChild);
  1096.             if (pItem != NULL)
  1097.                 return pItem;   // found
  1098.         }
  1099.     }
  1100.     ptStart.x -= CX_INDENT;
  1101.     return NULL;
  1102. }
  1103.  
  1104. /////////////////////////////////////////////////////////////////////////////
  1105. // CServerView diagnostics
  1106.  
  1107. #ifdef _DEBUG
  1108. void CServerView::AssertValid() const
  1109. {
  1110.     CScrollView::AssertValid();
  1111. }
  1112.  
  1113. void CServerView::Dump(CDumpContext& dc) const
  1114. {
  1115.     CScrollView::Dump(dc);
  1116. }
  1117. #endif //_DEBUG
  1118.