home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / appwiz / hierwiz / template / svrview.cpp < prev    next >
C/C++ Source or Header  |  1998-03-05  |  29KB  |  1,141 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-1995 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 Microsoft
  9. // QuickHelp and/or WinHelp documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include "stdafx.h"
  14. #include "afxdlgs.h"        // for FileOpen
  15. #include "$$root$$.h"
  16.  
  17. #include "svrdoc.h"
  18. #include "svrview.h"
  19. #include "svritem.h"
  20. #include "zoomdlg.h"
  21. $$IF(WANTS_TEXTVIEW)
  22. #include "textview.h"
  23. $$ENDIF
  24.  
  25. #ifdef _DEBUG
  26. #undef THIS_FILE
  27. static char BASED_CODE THIS_FILE[] = __FILE__;
  28. #endif
  29.  
  30. CServerNode* NEAR CServerView::m_pDragNode = NULL;
  31.  
  32. static int ReadString(CArchive& ar, char* pString, int nMaxLen);
  33. static BOOL FindItemRect(CDC* pDC, CServerNode* pItemFind, LPRECT lpRect,
  34.     CPoint& ptStart, CServerNode* pRoot);
  35. static CServerNode* HitDetect(CDC* pDC, CPoint point,
  36.     CPoint& ptStart, CServerNode* pRoot);
  37.  
  38. /////////////////////////////////////////////////////////////////////////////
  39. // support for zooming
  40.  
  41. static int NEAR rgiZoomFactor[] =
  42. {
  43.     25, 50, 75, 100, 125, 150, 175, 200, 250, 300
  44. };
  45.  
  46. /////////////////////////////////////////////////////////////////////////////
  47. // CServerView
  48.  
  49. IMPLEMENT_DYNCREATE(CServerView, CScrollView)
  50.  
  51. BEGIN_MESSAGE_MAP(CServerView, CScrollView)
  52.     //{{AFX_MSG_MAP(CServerView)
  53.     ON_COMMAND(ID_CHANGE_NAME, OnChangeName)
  54.     ON_COMMAND(ID_ADD_NODE, OnAddNode)
  55.     ON_UPDATE_COMMAND_UI(ID_CHANGE_NAME, OnUpdateHasSel)
  56.     ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
  57.     ON_WM_LBUTTONDOWN()
  58.     ON_WM_RBUTTONDOWN()
  59.     ON_COMMAND(ID_IMPORT_TEXT, OnImportText)
  60.     ON_COMMAND(ID_VIEW_ZOOMCUSTOM, OnViewZoomCustom)
  61.     ON_COMMAND(ID_EDIT_CUT, OnEditCut)
  62.     ON_WM_LBUTTONDBLCLK()
  63.     ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
  64.     ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)
  65.     ON_WM_CREATE()
  66.     ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
  67.     ON_COMMAND(ID_TREE_COLLAPSEBRANCH, OnTreeCollapsebranch)
  68.     ON_COMMAND(ID_TREE_EXPANDALL, OnTreeExpandall)
  69.     ON_COMMAND(ID_TREE_EXPANDBRANCH, OnTreeExpandbranch)
  70.     ON_COMMAND(ID_TREE_EXPANDONELEVEL, OnTreeExpandonelevel)
  71.     ON_UPDATE_COMMAND_UI(ID_TREE_COLLAPSEBRANCH, OnUpdateTreeCollapsebranch)
  72.     ON_UPDATE_COMMAND_UI(ID_TREE_EXPANDONELEVEL, OnUpdateTreeExpandonelevel)
  73.     ON_UPDATE_COMMAND_UI(ID_TREE_EXPANDALL, OnUpdateTreeExpandall)
  74.     ON_UPDATE_COMMAND_UI(ID_TREE_EXPANDBRANCH, OnUpdateTreeExpandbranch)
  75.     ON_WM_KEYDOWN()
  76.     ON_UPDATE_COMMAND_UI(ID_ADD_NODE, OnUpdateHasSel)
  77.     ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateHasSel)
  78.     ON_UPDATE_COMMAND_UI(ID_IMPORT_TEXT, OnUpdateHasSel)
  79.     ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateHasSel)
  80.     ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR, OnUpdateHasSel)
  81. $$IF(WANTS_TEXTVIEW)
  82.     ON_COMMAND(ID_VIEW_TEXT_VIEW, OnViewTextView)
  83. $$ENDIF
  84.     ON_WM_SIZE()
  85.     //}}AFX_MSG_MAP
  86.     ON_COMMAND_RANGE(ID_VIEW_ZOOM25, ID_VIEW_ZOOM300, OnZoom)
  87.     ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_ZOOM25, ID_VIEW_ZOOM300, OnUpdateZoom)
  88. END_MESSAGE_MAP()
  89.  
  90. /////////////////////////////////////////////////////////////////////////////
  91. // CServerView construction/destruction
  92.  
  93. CServerView::CServerView()
  94. {
  95.     m_pSelectedNode = NULL;
  96.     m_ptStart = CPoint(CX_MARGIN, CY_MARGIN);   // upper left position
  97.  
  98.     // initialize zoom state (100% from size cache)
  99.     m_zoomNum = CSize(100, 100);
  100.     m_zoomDenom = CSize(100, 100);
  101.     m_prevDropEffect = DROPEFFECT_NONE;
  102. }
  103.  
  104. CServerView::~CServerView()
  105. {
  106. }
  107.  
  108. /////////////////////////////////////////////////////////////////////////////
  109. // Attributes -- public
  110.  
  111. void CServerView::SetSelection(CServerNode* pNewSel, CDC* pDC)
  112. {
  113.     if (pNewSel == m_pSelectedNode)
  114.         return;     // already set
  115.     InvalidateItem(m_pSelectedNode, pDC);
  116.     m_pSelectedNode = pNewSel;
  117.     InvalidateItem(m_pSelectedNode, pDC);
  118. }
  119.  
  120. void CServerView::SetSelection(CServerNode* pNewSel)
  121. {
  122.     CServerDC dc(this);
  123.     SetSelection(pNewSel, &dc);
  124. }
  125.  
  126. /////////////////////////////////////////////////////////////////////////////
  127. // Operations -- public
  128.  
  129. void CServerView::SetScrollInfo()
  130. {
  131.     CServerNode* pRoot = GetDocument()->m_pRoot;
  132.     ASSERT(pRoot != NULL);
  133.  
  134.     //BLOCK: determine new scrolling sizes
  135.     CSize sizeLine;
  136.     CSize sizePage;
  137.     CSize sizeTotal;
  138.     {
  139.         CServerDC dc(this);
  140.  
  141.         pRoot->CalcNodeSize(&dc, sizeLine);
  142.         sizeLine.cx = sizeDefault.cx;
  143.         sizeLine.cy += CY_SEPARATOR;
  144.         sizePage.cx = sizeDefault.cx;
  145.         sizePage.cy = sizeLine.cy * 10;
  146.  
  147.         // set the scroll sizes dependent on the zoom factor
  148.         dc.LPtoDP(&sizePage);
  149.         dc.LPtoDP(&sizeLine);
  150.         sizeTotal = CalcActualViewSize(&dc);
  151.         // subtract out the right and bottom margins
  152.         // these are not interesting and this way we avoid
  153.         // some problems with nonlinear scaling of fonts
  154.         CSize sizeMargin(CX_MARGIN, CY_MARGIN);
  155.         CRect rect(CPoint(0, 0), sizeMargin);
  156.         dc.LPtoDP(rect);
  157.         sizeTotal -= rect.Size();
  158.     }
  159.  
  160.     SetScrollSizes(MM_TEXT, sizeTotal, sizePage, sizeLine);
  161. }
  162.  
  163. BOOL CServerView::SetZoomFactor(CSize zoomNum, CSize zoomDenom)
  164. {
  165.     if (zoomDenom != m_zoomDenom || zoomNum != m_zoomNum)
  166.     {
  167.         // sync to new zoom factor
  168.         m_zoomNum = zoomNum;
  169.         m_zoomDenom = zoomDenom;
  170.  
  171.         // resync to new sizes
  172.         Invalidate();
  173.         return TRUE;
  174.     }
  175.     return FALSE;
  176. }
  177.  
  178. void CServerView::UpdateServerView()
  179. {
  180.     CServerDoc* pDoc = GetDocument();
  181.     pDoc->SetModifiedFlag();
  182.     pDoc->UpdateAllItems(NULL);
  183.     pDoc->UpdateAllViews(NULL);
  184. }
  185.  
  186. CSize CServerView::CalcActualViewSize(CDC *pDC)
  187. {
  188.     return CalcActualItemSize(GetDocument()->m_pRoot, pDC);
  189. }
  190.  
  191. CSize CServerView::CalcActualItemSize(CServerNode* pItem, CDC *pDC)
  192. {
  193.     CSize sizeTotal(0, 0);
  194.     CPoint ptStart = m_ptStart;
  195.     pItem->CalcBounding(pDC, ptStart, sizeTotal);
  196.     sizeTotal.cx += CX_MARGIN;
  197.     // sizeTotal is the extent in logical coords
  198.     // convert from logical to device
  199.     CRect rc(CPoint(0,0),sizeTotal);
  200.     pDC->LPtoDP(rc);
  201.     return rc.Size();
  202. }
  203.  
  204. CSize CServerView::CalcScaledViewSize()
  205. {
  206.     return CalcScaledItemSize(GetDocument()->m_pRoot);
  207. }
  208.  
  209. CSize CServerView::CalcScaledItemSize(CServerNode* pItem)
  210. {
  211.     CServerDC dc(this);
  212.     // set extent to 100%
  213.     dc.SetViewportExt(CSize(1,1));
  214.     dc.SetWindowExt(CSize(1,1));
  215.  
  216.     CSize sizeTotal(0, 0);
  217.     CPoint ptStart = m_ptStart;
  218.     pItem->CalcBounding(&dc, ptStart, sizeTotal);
  219.     sizeTotal.cx += CX_MARGIN;
  220.     // sizeTotal is the native extent in device coords
  221.     sizeTotal.cx = MulDiv(sizeTotal.cx,m_zoomNum.cx,m_zoomDenom.cx);
  222.     sizeTotal.cy = MulDiv(sizeTotal.cy,m_zoomNum.cy,m_zoomDenom.cy);
  223.     return sizeTotal;
  224. }
  225.  
  226. CServerNode* CServerView::DoPasteItem(COleDataObject* pDataObject)
  227. {
  228.     ASSERT(pDataObject != NULL);
  229.     ASSERT_VALID(this);
  230.     ASSERT(m_pSelectedNode != NULL);
  231.  
  232.     BeginWaitCursor();
  233.  
  234.     CServerNode* pItem = new CServerNode(GetDocument());
  235.     ASSERT_VALID(pItem);
  236.  
  237.     TRY
  238.     {
  239.         if (pDataObject->IsDataAvailable(CServerDoc::m_cfPrivate))
  240.             DoPasteNative(pDataObject,pItem);
  241.         else if (pDataObject->IsDataAvailable(CF_TEXT))
  242.             DoPasteText(pDataObject,pItem);
  243.         else
  244.             AfxThrowNotSupportedException();
  245.     }
  246.     CATCH_ALL(e)
  247.     {
  248.         // general cleanup
  249.         TRACE0("failed to embed/link an OLE object\n");
  250.         delete pItem;
  251.         pItem = NULL;
  252.     }
  253.     END_CATCH_ALL
  254.  
  255.     EndWaitCursor();
  256.  
  257.     // update the document and views
  258.     SetSelection(pItem);
  259.     return pItem;
  260. }
  261.  
  262. void CServerView::DoPasteNative(COleDataObject *pDataObject,CServerNode *pItem)
  263. {
  264.     ASSERT(m_pSelectedNode != NULL);
  265.  
  266.     // get file refering to clipboard data
  267.     CFile *pFile = pDataObject->GetFileData(CServerDoc::m_cfPrivate);
  268.     if (pFile == NULL)
  269.         return;
  270.  
  271.     // connect the file to the archive and read the contents
  272.     CArchive ar(pFile, CArchive::load);
  273.     ar.m_pDocument = GetDocument(); // for COleClientItem serialize
  274.     pItem->Serialize(ar);
  275.     ar.Close();
  276.     delete pFile;
  277.  
  278.     // add the item to selected node
  279.     m_pSelectedNode->m_listChild.AddHead(pItem);
  280. }
  281.  
  282. void CServerView::DoPasteText(COleDataObject *pDataObject, CServerNode*)
  283. {
  284.     ASSERT(m_pSelectedNode != NULL);
  285.  
  286.     // get file refering to clipboard data
  287.     CFile *pFile = pDataObject->GetFileData(CF_TEXT);
  288.     if (pFile == NULL)
  289.         return;
  290.  
  291.     // connect the file to the archive and read the contents
  292.     CArchive ar(pFile, CArchive::load);
  293.     DoImportText(ar);
  294.     ar.Close();
  295.     delete pFile;
  296. }
  297.  
  298. void CServerView::DoImportText(CArchive &ar)
  299. {
  300.     // read in lines appending items from this node
  301.     char szNode[256];
  302. #ifdef _UNICODE
  303.     TCHAR szT[256];
  304. #endif
  305.     int nCurLevel = 0;
  306.     CServerNode* parents[MAX_LEVEL];
  307.     parents[0] = m_pSelectedNode;   // must have a parent at the current level
  308.  
  309.     while (ReadString(ar, szNode, sizeof(szNode)) != NULL)
  310.     {
  311.         int cch = strlen(szNode);
  312.         if (cch == 0)
  313.             continue;
  314.         if (szNode[cch-1] != '\n')
  315.         {
  316.             AfxMessageBox(
  317.                 _T("Text file contains too long a line - aborting read\n"));
  318.             break;      // leaves items loaded so far
  319.         }
  320.         szNode[cch-1] = '\0';
  321.         // check the indentation level
  322.         char* pch = szNode;
  323.         while (*pch == '\t')
  324.             pch++;
  325.         int nLevel = (pch - szNode)+1;
  326.         ASSERT(nLevel >= 1);        // levels are 1 based, 0 is the root
  327.  
  328.         if (*pch == '\0')
  329.             continue;       // skip blank lines
  330.         if (nLevel > nCurLevel + 1 || nLevel >= MAX_LEVEL)
  331.         {
  332.             AfxMessageBox(
  333.                 _T("Text file contains too many tabs = aborting read\n"));
  334.             break;      // leaves items loaded so far
  335.         }
  336.  
  337. #ifdef _UNICODE
  338.         _mbstowcsz(szT, pch, sizeof(szT)/sizeof(szT[0]));
  339.         parents[nLevel] = parents[nLevel-1]->CreateChildNode(szT);
  340. #else
  341.         parents[nLevel] = parents[nLevel-1]->CreateChildNode(pch);
  342. #endif
  343.         nCurLevel = nLevel;
  344.     }
  345.     if (nCurLevel == 0)
  346.         return;     // nothing added
  347.  
  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) != NULL)
  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.  
  732.     if (dlg.DoModal() != IDOK)
  733.         return;                 // stay with old data file
  734.  
  735.     OpenTextFile(dlg.GetPathName());
  736.  
  737. }
  738.  
  739. void CServerView::OpenTextFile(CString Name)
  740. {
  741.     CFile file;
  742.     if (!file.Open(Name, CFile::modeRead))
  743.     {
  744.         AfxMessageBox(_T("Failed to open text file"));
  745.         return;
  746.     }
  747.  
  748.     CArchive ar(&file,CArchive::load);
  749.     DoImportText(ar);
  750.     ar.Close();
  751.     file.Close();
  752. }
  753.  
  754. static int ReadString(CArchive& ar, char* pString, int nMaxLen)
  755. {
  756.     int nCount = 0;
  757.     char ch;
  758.     pString[nCount] = (char)0;
  759.     TRY
  760.     {
  761.         do
  762.         {
  763.             ar >> (BYTE&)ch;
  764.  
  765.             // watch out for ^Z (EOF under DOS)
  766.             if (ch == 0x1A)
  767.                 break;
  768.  
  769.             // combine "\r\n" pair into single "\n"
  770.             if (ch == '\n' && nCount != 0 && pString[nCount-1] == '\r')
  771.                 nCount--;
  772.  
  773.             //Remove any extra \r
  774.             if (ch == '\r' && nCount != 0 && pString[nCount-1] == '\r')
  775.                 nCount--;
  776.  
  777.             pString[nCount++] = ch;
  778.  
  779.         } while (nCount < nMaxLen-1 && ch != '\n');
  780.     }
  781.     END_TRY
  782.  
  783.     // insert newline if missing
  784.     if (nCount != 0 && pString[nCount-1] != '\n' && nCount < nMaxLen-1)
  785.         pString[nCount++] = '\n';
  786.     pString[nCount] = (char)0;
  787.  
  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.  
  1119. $$IF(WANTS_TEXTVIEW)
  1120. void CServerView::OnViewTextView()
  1121. {
  1122.     // Show the active document in text view.
  1123.     CServerDoc* pServerDoc = GetDocument();
  1124.     CDocument * pNewDoc ;
  1125.     pNewDoc = ((CServerApp *)AfxGetApp())->pDocTxtTemplate->OpenDocumentFile(NULL);
  1126.  
  1127.    //Detach the view from the newly created doc and attach it to the CServerDoc document
  1128.     POSITION pos = pNewDoc->GetFirstViewPosition() ;
  1129.     CTextView * pTxtvw = ( CTextView *)pNewDoc->GetNextView(pos) ;
  1130.     pNewDoc->RemoveView(pTxtvw) ;
  1131.     pServerDoc->AddView(pTxtvw) ;
  1132.     pTxtvw->RedrawText() ; // Do an initial draw of textview
  1133.  
  1134. }
  1135. void CServerView::CreateTextView()
  1136. {
  1137.     OnViewTextView() ;
  1138. }
  1139.  
  1140. $$ENDIF //WANTS_TEXTVIEW
  1141.