home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 18.ddi / MFC / SAMPLES / HIERSVR / SVRVIEW.CP_ / SVRVIEW.CP
Encoding:
Text File  |  1993-02-08  |  10.9 KB  |  420 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 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.  
  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.  
  23. #ifdef _DEBUG
  24. #undef THIS_FILE
  25. static char BASED_CODE THIS_FILE[] = __FILE__;
  26. #endif
  27.  
  28. /////////////////////////////////////////////////////////////////////////////
  29. // CServerView
  30.  
  31. IMPLEMENT_DYNCREATE(CServerView, CScrollView)
  32.  
  33. BEGIN_MESSAGE_MAP(CServerView, CScrollView)
  34.     //{{AFX_MSG_MAP(CServerView)
  35.     ON_COMMAND(ID_CHANGE_NAME, OnChangeName)
  36.     ON_COMMAND(ID_ADD_NODE, OnAddNode)
  37.     ON_UPDATE_COMMAND_UI(ID_CHANGE_NAME, OnUpdateHasSel)
  38.     ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
  39.     ON_WM_LBUTTONDOWN()
  40.     ON_WM_RBUTTONDOWN()
  41.     ON_UPDATE_COMMAND_UI(ID_ADD_NODE, OnUpdateHasSel)
  42.     ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateHasSel)
  43.     ON_UPDATE_COMMAND_UI(ID_IMPORT_TEXT, OnUpdateHasSel)
  44.     ON_COMMAND(ID_IMPORT_TEXT, OnImportText)
  45.     //}}AFX_MSG_MAP
  46. END_MESSAGE_MAP()
  47.  
  48. /////////////////////////////////////////////////////////////////////////////
  49. // CServerView construction/destruction
  50.  
  51. CServerView::CServerView()
  52. {
  53.     m_pSelectedNode = NULL;
  54.     m_ptStart = CPoint(8, 4);       // upper left position
  55. }
  56.  
  57. CServerView::~CServerView()
  58. {
  59. }
  60.  
  61.  
  62. /////////////////////////////////////////////////////////////////////////////
  63. // CServerView drawing
  64.  
  65.  
  66. #define CX_INDENT   12
  67. #define CX_BACKDENT 5
  68. #define CY_SEPARATOR 4
  69.  
  70.  
  71. static int DrawTree(CDC* pDC, CPoint ptStart, CServerItem* pRoot,
  72.     CServerItem* pItemSel)
  73. {
  74.     ASSERT(pDC != NULL);
  75.     ASSERT(pRoot != NULL);
  76.     ASSERT(ptStart.x >= 0 && ptStart.y >= 0);
  77.  
  78.     // root node starts here
  79.     int cyDrawn = 0;
  80.     pRoot->DoDraw(pDC, ptStart, pRoot == pItemSel);
  81.     cyDrawn += pRoot->m_sizeNode.cy + CY_SEPARATOR;
  82.  
  83.     if (pRoot->m_pFirstChild == NULL)
  84.         return cyDrawn;     // nothing more to draw
  85.  
  86.     // indent for the kids
  87.     CPoint ptKid(ptStart.x + CX_INDENT, ptStart.y + cyDrawn);
  88.  
  89.     // draw the kids
  90.     int yMid = 0;
  91.     for (CServerItem* pChild = pRoot->m_pFirstChild;
  92.       pChild != NULL; pChild = pChild->m_pNextSibling)
  93.     {
  94.         int cyKid;
  95.         if ((cyKid = DrawTree(pDC, ptKid, pChild, pItemSel)) == -1)
  96.             return -1;      // error
  97.  
  98.         yMid = ptKid.y + (pChild->m_sizeNode.cy)/2;
  99.         // add the little line
  100.         pDC->MoveTo(ptStart.x + CX_BACKDENT, yMid);
  101.         pDC->LineTo(ptKid.x, yMid);
  102.         cyDrawn += cyKid;
  103.         ptKid.y += cyKid;
  104.     }
  105.     ASSERT(ptKid.y == ptStart.y + cyDrawn);
  106.  
  107.     // draw the connecting line (down to last yMid)
  108.     ASSERT(yMid != 0);
  109.     int xLine = ptStart.x + CX_BACKDENT;
  110.     pDC->MoveTo(xLine, ptStart.y + pRoot->m_sizeNode.cy);
  111.     pDC->LineTo(xLine, yMid);
  112.     return cyDrawn;
  113. }
  114.  
  115. void CServerView::OnDraw(CDC* pDC)
  116. {
  117.     if (DrawTree(pDC, m_ptStart, GetDocument()->m_pRoot, m_pSelectedNode) == -1)
  118.     {
  119.         TRACE("Error drawing tree!!\n");
  120.         ::MessageBeep(-1);
  121.     }
  122. }
  123.  
  124. /////////////////////////////////////////////////////////////////////////////
  125. // Simple selection
  126.  
  127. // calculate the bounding rect for a given item in the context of this view
  128. static BOOL FindItemRect(CServerItem* pItemFind, LPRECT lpRect,
  129.     CPoint& ptStart, CServerItem* pRoot)
  130. {
  131.     ASSERT(pItemFind != NULL);
  132.     ASSERT(lpRect != NULL);
  133.     ASSERT(ptStart.x >= 0 && ptStart.y >= 0);
  134.     ASSERT(pRoot != NULL);
  135.  
  136.     if (pItemFind == pRoot)
  137.     {
  138.         // item rect does not include separator
  139.         lpRect->right = (lpRect->left = ptStart.x) + pRoot->m_sizeNode.cx;
  140.         lpRect->bottom = (lpRect->top = ptStart.y) + pRoot->m_sizeNode.cy;
  141.         return TRUE;
  142.     }
  143.     ptStart.x += CX_INDENT;     // not essential for calculation
  144.     ptStart.y += pRoot->m_sizeNode.cy + CY_SEPARATOR;
  145.  
  146.     // check the kids
  147.     for (CServerItem* pChild = pRoot->m_pFirstChild;
  148.       pChild != NULL; pChild = pChild->m_pNextSibling)
  149.     {
  150.         if (FindItemRect(pItemFind, lpRect, ptStart, pChild))
  151.             return TRUE;    // found
  152.     }
  153.     ptStart.x -= CX_INDENT;
  154.     return FALSE;
  155. }
  156.  
  157. // calculate the bounding rect for a given item in the context of this view
  158. static CServerItem* HitDetect(CPoint point, CPoint& ptStart, CServerItem* pRoot)
  159. {
  160.     ASSERT(point.x >= 0 && point.y >= 0);
  161.     ASSERT(ptStart.x >= 0 && ptStart.y >= 0);
  162.     ASSERT(pRoot != NULL);
  163.  
  164.     CRect rect(ptStart, pRoot->m_sizeNode);
  165.     if (rect.PtInRect(point))
  166.         return pRoot;
  167.  
  168.     ptStart.x += CX_INDENT;
  169.     ptStart.y += pRoot->m_sizeNode.cy + CY_SEPARATOR;
  170.     if (ptStart.y >= point.y)
  171.         return FALSE;       // no point in looking any lower
  172.  
  173.     // check the kids
  174.     for (CServerItem* pChild = pRoot->m_pFirstChild;
  175.       pChild != NULL; pChild = pChild->m_pNextSibling)
  176.     {
  177.         CServerItem* pItem;
  178.         if ((pItem = HitDetect(point, ptStart, pChild)) != NULL)
  179.             return pItem;   // found
  180.     }
  181.     ptStart.x -= CX_INDENT;
  182.     return NULL;
  183. }
  184.  
  185. static void CalcBounding(CPoint& ptStart, CSize& sizeMax, CServerItem* pRoot)
  186. {
  187.     ASSERT(sizeMax.cx >= 0 && sizeMax.cy >= 0);
  188.     ASSERT(ptStart.x >= 0 && ptStart.y >= 0);
  189.     ASSERT(pRoot != NULL);
  190.  
  191.     ptStart.y += pRoot->m_sizeNode.cy + CY_SEPARATOR;
  192.     if (ptStart.y > sizeMax.cy)
  193.         sizeMax.cy = ptStart.y;
  194.  
  195.     if (ptStart.x + pRoot->m_sizeNode.cx > sizeMax.cx)
  196.         sizeMax.cx = ptStart.x + pRoot->m_sizeNode.cx;
  197.     ptStart.x += CX_INDENT;
  198.     // add in the kids
  199.     for (CServerItem* pChild = pRoot->m_pFirstChild;
  200.       pChild != NULL; pChild = pChild->m_pNextSibling)
  201.     {
  202.         CalcBounding(ptStart, sizeMax, pChild);
  203.     }
  204.     ptStart.x -= CX_INDENT;
  205. }
  206.  
  207.  
  208. CServerItem* CServerView::GetSelection()
  209. {
  210.     return m_pSelectedNode;
  211. }
  212.  
  213. void CServerView::SetSelection(CServerItem* pNewSel)
  214. {
  215.     if (pNewSel == m_pSelectedNode)
  216.         return;     // already set
  217.     if (m_pSelectedNode != NULL)
  218.     {
  219.         // invalidate old selection
  220.         CRect rect;
  221.         CPoint pt = m_ptStart;
  222.         VERIFY(FindItemRect(m_pSelectedNode, &rect, pt,
  223.             GetDocument()->m_pRoot));
  224.         rect -= GetDeviceScrollPosition();
  225.         InvalidateRect(rect);
  226.     }
  227.     if ((m_pSelectedNode = pNewSel) != NULL)
  228.     {
  229.         // invalidate new selection
  230.         CRect rect;
  231.         CPoint pt = m_ptStart;
  232.         VERIFY(FindItemRect(m_pSelectedNode, &rect, pt,
  233.             GetDocument()->m_pRoot));
  234.         rect -= GetDeviceScrollPosition();
  235.         InvalidateRect(rect);
  236.     }
  237. }
  238.  
  239. /////////////////////////////////////////////////////////////////////////////
  240. // CServerView diagnostics
  241.  
  242. #ifdef _DEBUG
  243. void CServerView::AssertValid() const
  244. {
  245.     CScrollView::AssertValid();
  246. }
  247.  
  248. void CServerView::Dump(CDumpContext& dc) const
  249. {
  250.     CScrollView::Dump(dc);
  251. }
  252.  
  253. #endif //_DEBUG
  254.  
  255. /////////////////////////////////////////////////////////////////////////////
  256. // CServerView commands
  257.  
  258. void CServerView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
  259. {
  260.     CScrollView::OnUpdate(pSender, lHint, pHint);
  261.  
  262.     // update our selection
  263.     CServerItem* pRoot = GetDocument()->m_pRoot;
  264.     ASSERT(pRoot != NULL);
  265.     if (m_pSelectedNode == NULL)
  266.     {
  267.         m_pSelectedNode = pRoot;
  268.     }
  269.     else if (!pRoot->IsChild(m_pSelectedNode))
  270.     {
  271.         TRACE("Selected node is deleted - setting to no selection\n");
  272.         m_pSelectedNode = NULL;
  273.     }
  274.  
  275.     // Find the total size of the view
  276.     CPoint pt = m_ptStart;
  277.     CSize sizeTotal(0,0);
  278.     CalcBounding(pt, sizeTotal, pRoot);
  279.     CSize sizeLine(sizeDefault.cx, pRoot->m_sizeNode.cy + CY_SEPARATOR);
  280.     CSize sizePage(sizeDefault.cx, sizeLine.cy * 10);
  281.     SetScrollSizes(MM_TEXT, sizeTotal, sizePage, sizeLine);
  282. }
  283.  
  284.  
  285. void CServerView::OnUpdateHasSel(CCmdUI* pCmdUI)
  286. {
  287.     pCmdUI->Enable(m_pSelectedNode != NULL);
  288. }
  289.  
  290. void CServerView::OnChangeName()
  291. {
  292.     if (m_pSelectedNode != NULL &&
  293.       m_pSelectedNode->PromptChangeNode())
  294.     {
  295.         GetDocument()->SetModifiedFlag();
  296.         GetDocument()->UpdateAllViews(NULL);
  297.  
  298.         if (m_pSelectedNode->IsConnected())
  299.             m_pSelectedNode->NotifyChanged();
  300.                 // notify client immediately - will update automatic links
  301.     }
  302. }
  303.  
  304. void CServerView::OnAddNode()
  305. {
  306.     if (m_pSelectedNode == NULL)
  307.         AfxThrowNotSupportedException();
  308.     CServerItem* pNew;
  309.     if ((pNew = m_pSelectedNode->PromptNewChildNode()) == NULL)
  310.         return;
  311.  
  312.     // wire it in
  313.     GetDocument()->SetModifiedFlag();
  314.     m_pSelectedNode = pNew;
  315.     GetDocument()->UpdateAllViews(NULL);
  316. }
  317.  
  318.  
  319.  
  320.  
  321. void CServerView::OnEditCopy()
  322. {
  323.     if (m_pSelectedNode == NULL)
  324.         AfxThrowNotSupportedException();
  325.     if (!m_pSelectedNode->CopyToClipboard(TRUE, TRUE))
  326.         AfxMessageBox("Copy to clipboard failed");
  327.  
  328. }
  329.  
  330.  
  331. void CServerView::OnLButtonDown(UINT, CPoint point)
  332. {
  333.     // change the selection as appropriate
  334.     CPoint ptLog = m_ptStart;
  335.     SetSelection(HitDetect(point + (CSize)GetDeviceScrollPosition(),
  336.         ptLog, GetDocument()->m_pRoot));
  337. }
  338.  
  339.  
  340.  
  341. void CServerView::OnRButtonDown(UINT nFlags, CPoint point)
  342. {
  343.     OnLButtonDown(nFlags, point);   // select first
  344.  
  345.     int iSub;
  346.     if (m_pSelectedNode == NULL ||
  347.       (iSub = m_pSelectedNode->GetPopupMenuIndex()) == -1)
  348.        return;  // nothing if no selection or no popup
  349.  
  350.     CMenu popups;
  351.     if (!popups.LoadMenu(IDR_POPUPS))
  352.         AfxThrowResourceException();
  353.     CMenu* pMenu = popups.GetSubMenu(iSub);
  354.     ASSERT(pMenu != NULL);
  355.  
  356.     ClientToScreen(&point);
  357.     pMenu->TrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON,
  358.         point.x, point.y, AfxGetApp()->m_pMainWnd);
  359. }
  360.  
  361.  
  362. void CServerView::OnImportText()
  363. {
  364.     if (m_pSelectedNode == NULL)
  365.         AfxThrowNotSupportedException();
  366.  
  367.     CFileDialog dlg(TRUE, "txt", NULL,
  368.         OFN_FILEMUSTEXIST | OFN_HIDEREADONLY,
  369.         "Text Files (*.txt)|*.txt|All Files (*.*)|*.*||");
  370.  
  371.     if (dlg.DoModal() != IDOK)
  372.         return;                 // stay with old data file
  373.  
  374.     CStdioFile file;
  375.     if (!file.Open(dlg.GetPathName(), CFile::modeRead | CFile::typeText))
  376.     {
  377.         AfxMessageBox("Failed to open text file");
  378.         return;
  379.     }
  380.     // read in lines appending items from this node
  381.     char szT[256];
  382.     int nCurLevel = 0;
  383. #define MAX_LEVEL   20
  384.     CServerItem* parents[MAX_LEVEL];
  385.     parents[0] = m_pSelectedNode;   // must have a parent at the current level
  386.     while (file.ReadString(szT, sizeof(szT)) != NULL)
  387.     {
  388.         int cch = strlen(szT);
  389.         if (cch < 1 || szT[cch-1] != '\n')
  390.         {
  391.             AfxMessageBox("Text file contains too long a line - aborting read\n");
  392.             break;      // leaves items loaded so far
  393.         }
  394.         szT[cch-1] = '\0';
  395.         // check the indentation level
  396.         char* pch = szT;
  397.         while (*pch == '\t')
  398.             pch++;
  399.         int nLevel = (pch - szT)+1;
  400.         ASSERT(nLevel >= 1);        // levels are 1 based, 0 is the root
  401.  
  402.         if (*pch == '\0')
  403.             continue;       // skip blank lines
  404.         if (nLevel > nCurLevel + 1 || nLevel >= MAX_LEVEL)
  405.         {
  406.             AfxMessageBox("Text file contains too many tabs = aborting read\n");
  407.             break;      // leaves items loaded so far
  408.         }
  409.  
  410.         parents[nLevel] = parents[nLevel-1]->CreateChildNode(pch);
  411.         nCurLevel = nLevel;
  412.     }
  413.     file.Close();
  414.     if (nCurLevel == 0)
  415.         return;     // nothing added
  416.     GetDocument()->UpdateAllViews(NULL);    // including this one
  417.     GetDocument()->SetModifiedFlag();
  418. }
  419.  
  420.