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 / svritem.cpp < prev    next >
C/C++ Source or Header  |  1998-03-05  |  21KB  |  870 lines

  1. // svrnode.cpp : implementation of the CServerNode 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.  
  14. #include "stdafx.h"
  15. #include <afxpriv.h>    // for CSharedFile
  16. #include <malloc.h>     // for _alloca
  17.  
  18. #include "$$root$$.h"
  19. #include "svritem.h"
  20. #include "svrdoc.h"
  21. #include "svrview.h"
  22.  
  23. #ifdef _DEBUG
  24. #undef THIS_FILE
  25. static char BASED_CODE THIS_FILE[] = __FILE__;
  26. #endif
  27.  
  28. /////////////////////////////////////////////////////////////////////////////
  29. // Local dialogs used for implementation
  30.  
  31. class CChangeNameDlg : public CDialog
  32. {
  33. // Construction
  34. public:
  35.     CChangeNameDlg(CWnd* pParent = NULL);
  36.  
  37. // Dialog Data
  38.     //{{AFX_DATA(CChangeNameDlg)
  39.     enum { IDD = IDD_CHANGE_NAME };
  40.     int     m_shape;
  41.     CString m_strDescription;
  42.     CString m_strLinkKey;
  43.     CEdit   m_editDescription;
  44.     CButton m_btnOK;
  45.     //}}AFX_DATA
  46.  
  47. // Implementation
  48. protected:
  49.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
  50.     virtual BOOL OnInitDialog();
  51.     // Generated message map functions
  52.     //{{AFX_MSG(CChangeNameDlg)
  53.     afx_msg void OnChange();
  54.     //}}AFX_MSG
  55.     DECLARE_MESSAGE_MAP()
  56. };
  57.  
  58. class CAddNodeDlg : public CDialog
  59. {
  60. // Construction
  61. public:
  62.     CAddNodeDlg(CWnd* pParent = NULL);  // standard constructor
  63.  
  64. // Dialog Data
  65.     //{{AFX_DATA(CAddNodeDlg)
  66.     enum { IDD = IDD_ADD_NODE };
  67.     CString m_strDescription;
  68.     CString m_strLinkKey;
  69.     int     m_shape;
  70.     CEdit   m_editDescription;
  71.     CButton m_btnOK;
  72.     //}}AFX_DATA
  73.  
  74. // Implementation
  75. protected:
  76.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
  77.     virtual BOOL OnInitDialog();
  78.  
  79.     // Generated message map functions
  80.     //{{AFX_MSG(CAddNodeDlg)
  81.     afx_msg void OnChange();
  82.     //}}AFX_MSG
  83.     DECLARE_MESSAGE_MAP()
  84. };
  85.  
  86. /////////////////////////////////////////////////////////////////////////////
  87. // CServerNode
  88.  
  89. IMPLEMENT_SERIAL(CServerNode, CObject, 0);
  90.  
  91. CServerNode::CServerNode(CServerDoc* pServerDoc)
  92. {
  93.     m_shape = shapeRect;
  94.     m_bHideChildren = FALSE;
  95.     m_pDocument = pServerDoc;
  96.  
  97.     m_pServerItem = NULL;   // will get connected if need be
  98. }
  99.  
  100. // Special "new" operator for root node
  101. CServerNode* CServerNode::CreateRootNode(CServerDoc* pDoc)
  102. {
  103.     CServerNode* pRoot = NULL;
  104.     TRY
  105.     {
  106.         pRoot = new CServerNode(pDoc);
  107.         pRoot->InitRootNode();
  108.     }
  109.     CATCH(CException, e)
  110.     {
  111.         delete pRoot;
  112.         pRoot = NULL;
  113.     }
  114.     END_CATCH
  115.  
  116.     return pRoot;
  117. }
  118.  
  119. // Special constructor for root node
  120. void CServerNode::InitRootNode()
  121. {
  122.     DeleteChildNodes(); // initalized root node has no children
  123.  
  124.     m_strDescription = "Root node";
  125.     m_strLinkKey = "%ROOT%";    // link name for root
  126.     UpdateItemName();
  127. }
  128.  
  129. BOOL CServerNode::FindAndDelete(CServerNode* pNode)
  130. {
  131.     POSITION pos = m_listChild.GetHeadPosition();
  132.     while (pos != NULL)
  133.     {
  134.         POSITION posPrev = pos;
  135.         CServerNode *pChild = (CServerNode*)m_listChild.GetNext(pos);
  136.         if (pChild == pNode)
  137.         {
  138.             m_listChild.RemoveAt(posPrev);
  139.             delete pNode;
  140.             return TRUE;
  141.         }
  142.         if (pChild->FindAndDelete(pNode) == TRUE)
  143.             return TRUE;
  144.     }
  145.     return FALSE;
  146. }
  147.  
  148. CServerNode* CServerNode::FindNode(LPCTSTR pszItemName)
  149. {
  150.     // return this node if it matches!
  151.     if (GetItemName() == pszItemName)
  152.         return this;
  153.  
  154.     POSITION pos = m_listChild.GetHeadPosition();
  155.     while (pos != NULL)
  156.     {
  157.         CServerNode* pChild = (CServerNode*)m_listChild.GetNext(pos);
  158.         if (pChild->GetItemName() == pszItemName)
  159.             return pChild;
  160.  
  161.         // recurse down the tree
  162.         pChild = pChild->FindNode(pszItemName);
  163.         if (pChild != NULL)
  164.             return pChild;
  165.     }
  166.     return NULL;
  167. }
  168.  
  169. void CServerNode::DeleteChildNodes()
  170. {
  171.     // delete child nodes
  172.     POSITION pos = m_listChild.GetHeadPosition();
  173.     while (pos != NULL)
  174.         delete m_listChild.GetNext(pos);
  175.     m_listChild.RemoveAll();
  176. }
  177.  
  178. CServerNode::~CServerNode()
  179. {
  180.     // if we are the root of a document, clear it
  181.     if (GetDocument()->m_pRoot == this)
  182.         GetDocument()->m_pRoot = NULL;
  183.  
  184.     // if we are attached to a server item, detach from it
  185.     if (m_pServerItem != NULL)
  186.         m_pServerItem->m_pServerNode = NULL;
  187.  
  188.     // delete all of the child nodes of this node
  189.     DeleteChildNodes();
  190. }
  191.  
  192. BOOL CServerNode::IsChild(const CServerNode* pPotentialChild) const
  193. {
  194.     if (pPotentialChild == this)
  195.         return TRUE;
  196.     POSITION pos = m_listChild.GetHeadPosition();
  197.     while (pos != NULL)
  198.     {
  199.         CServerNode* pNode = (CServerNode*)m_listChild.GetNext(pos);
  200.         if (pNode->IsChild(pPotentialChild))
  201.             return TRUE;
  202.     }
  203.     return FALSE;
  204. }
  205.  
  206. /////////////////////////////////////////////////////////////////////////////
  207. // CServerNode bounding rect helpers
  208.  
  209. #define CX_INSET    4
  210. #define CY_INSET    2
  211.  
  212. // calc node size for arbitrary dc and return
  213. //  (result is in logical units for the given DC)
  214. void CServerNode::CalcNodeSize(CDC* pDC, CSize& sizeNode)
  215. {
  216.     ASSERT(pDC != NULL);
  217.     sizeNode = pDC->GetTextExtent(m_strDescription,
  218.         m_strDescription.GetLength());
  219.     sizeNode += CSize(CX_INSET * 2, CY_INSET * 2);
  220. }
  221.  
  222. // calculate bounding rect using pointer to member for each node
  223. void CServerNode::CalcBounding(CDC* pDC, CPoint& ptStart, CSize& sizeMax)
  224. {
  225.     ASSERT(sizeMax.cx >= 0 && sizeMax.cy >= 0);
  226.     ASSERT(ptStart.x >= 0 && ptStart.y >= 0);
  227.  
  228.     CSize sizeNode;
  229.     CalcNodeSize(pDC, sizeNode);
  230.  
  231.     ptStart.y += sizeNode.cy + CY_SEPARATOR;
  232.     if (ptStart.y > sizeMax.cy)
  233.         sizeMax.cy = ptStart.y;
  234.  
  235.     if (ptStart.x + sizeNode.cx > sizeMax.cx)
  236.         sizeMax.cx = ptStart.x + sizeNode.cx;
  237.     ptStart.x += CX_INDENT;
  238.     // add in the kids
  239.     if (!m_bHideChildren)
  240.     {
  241.         POSITION pos = m_listChild.GetHeadPosition();
  242.         while (pos != NULL)
  243.         {
  244.             CServerNode* pNode = (CServerNode*)m_listChild.GetNext(pos);
  245.             pNode->CalcBounding(pDC, ptStart, sizeMax);
  246.         }
  247.     }
  248.     ptStart.x -= CX_INDENT;
  249. }
  250.  
  251. $$IF(WANTS_TEXTVIEW)
  252. /////////////////////////////////////////////////////////////////////////////
  253. // CSTextView drawing helpers
  254.  
  255. BOOL CServerNode::GetNodeText(CString *strBuf, int TAB)
  256. {
  257.     *strBuf+= m_strDescription ;
  258.     //Insert a return
  259.     *strBuf+= "\r\n" ;
  260.     return TRUE;
  261. }
  262.  
  263. int CServerNode::GetTreeText(CString * strBuf, int TAB)
  264. {
  265.     ASSERT(strBuf != NULL);
  266.  
  267.     // Indent if we need to.
  268.     for(int i = 0; i< TAB; i++)
  269.         *strBuf+= "\t" ;
  270.  
  271.     GetNodeText(strBuf, TAB);
  272.     if (m_listChild.GetCount() == 0 || m_bHideChildren)
  273.         return TAB;     // nothing more to draw
  274.  
  275.     // draw the kids
  276.     POSITION pos = m_listChild.GetHeadPosition();
  277.     while (pos != NULL)
  278.     {
  279.         CServerNode *pChild = (CServerNode*)m_listChild.GetNext(pos);
  280.         // draw the child node
  281.         pChild->GetTreeText(strBuf, TAB +1);
  282.     }
  283.     return TAB;
  284. }
  285.  
  286. $$ENDIF
  287. /////////////////////////////////////////////////////////////////////////////
  288. // CServerNode drawing helpers
  289.  
  290. BOOL CServerNode::Draw(CDC* pDC, CPoint pt, BOOL bSelected, CSize sizeNode)
  291. {
  292.     CRect rect(pt, sizeNode);
  293.     if (!pDC->RectVisible(&rect))
  294.         return TRUE;
  295.  
  296.     // draw a the bounding shape
  297.     BOOL bOK = TRUE;
  298.  
  299.     CPen* pOldPen = NULL;
  300.     CPen penHilite;
  301.     int nPenStyle = (m_bHideChildren) ? PS_DASH : PS_SOLID;
  302.     COLORREF crPen = (bSelected) ? RGB(255,0,0) : RGB(0,0,0);
  303.     if (penHilite.CreatePen(nPenStyle, 0, crPen))
  304.         pOldPen = pDC->SelectObject(&penHilite);
  305.  
  306.     switch (m_shape)
  307.     {
  308.     case shapeRect:
  309.         bOK = pDC->Rectangle(rect);
  310.         break;
  311.     case shapeRound:
  312.         bOK = pDC->RoundRect(rect, CPoint(7, 7));
  313.         break;
  314.     case shapeOval: // really just a rounder rounded rect
  315.         bOK = pDC->RoundRect(rect, CPoint(14, 14));
  316.         break;
  317.     default:
  318.         TRACE1("Error: unknown shape %d\n", m_shape);
  319.         bOK = FALSE;
  320.         break;
  321.     }
  322.     if (pOldPen != NULL)
  323.         pDC->SelectObject(pOldPen);
  324.  
  325.     if (!bOK)
  326.         return FALSE;
  327.  
  328.     // inset a bit
  329.     rect.InflateRect(-CX_INSET, -CY_INSET);
  330.  
  331.     if (!pDC->ExtTextOut(rect.left, rect.top, ETO_OPAQUE, rect,
  332.       m_strDescription, m_strDescription.GetLength(), NULL))
  333.         return FALSE;
  334.  
  335.     // all OK
  336.     return TRUE;
  337. }
  338.  
  339. int CServerNode::DrawTree(CDC* pDC, CPoint ptStart, CServerNode* pNodeSel)
  340. {
  341.     ASSERT(pDC != NULL);
  342.     ASSERT(ptStart.x >= 0 && ptStart.y >= 0);
  343.  
  344.     // root node starts here
  345.     int cyDrawn = 0;
  346.     CSize sizeNode;
  347.     CalcNodeSize(pDC, sizeNode);
  348.     Draw(pDC, ptStart, this == pNodeSel, sizeNode);
  349.     cyDrawn += sizeNode.cy + CY_SEPARATOR;
  350.  
  351.     if (m_listChild.GetCount() == 0 || m_bHideChildren)
  352.         return cyDrawn;     // nothing more to draw
  353.  
  354.     // indent for the kids
  355.     CPoint ptKid(ptStart.x + CX_INDENT, ptStart.y + cyDrawn);
  356.  
  357.     // draw the kids
  358.     int yMid = 0;
  359.     POSITION pos = m_listChild.GetHeadPosition();
  360.     while (pos != NULL)
  361.     {
  362.         CServerNode *pChild = (CServerNode*)m_listChild.GetNext(pos);
  363.  
  364.         // add the little line
  365.         yMid = ptKid.y + (sizeNode.cy)/2;
  366.         pDC->MoveTo(ptStart.x + CX_BACKDENT, yMid);
  367.         pDC->LineTo(ptKid.x, yMid);
  368.  
  369.         // draw the child node
  370.         int cyKid = pChild->DrawTree(pDC, ptKid, pNodeSel);
  371.         if (cyKid == -1)
  372.             return -1;      // error
  373.  
  374.         cyDrawn += cyKid;
  375.         ptKid.y += cyKid;
  376.     }
  377.     ASSERT(ptKid.y == ptStart.y + cyDrawn);
  378.  
  379.     // draw the connecting line (down to last yMid)
  380.     ASSERT(yMid != 0);
  381.     int xLine = ptStart.x + CX_BACKDENT;
  382.     pDC->MoveTo(xLine, ptStart.y + sizeNode.cy);
  383.     pDC->LineTo(xLine, yMid);
  384.     return cyDrawn;
  385. }
  386.  
  387. // Serializes to file or to embedded OLE stream
  388. void CServerNode::Serialize(CArchive& ar)
  389. {
  390.     CObject::Serialize(ar);
  391.     if (ar.IsStoring())
  392.     {
  393.         ar << (WORD)m_shape;
  394.  
  395.         ASSERT(m_strLinkKey.IsEmpty() || m_strDescription != m_strLinkKey);
  396.         if (m_pServerItem != NULL)
  397.             ar << m_pServerItem->GetItemName();
  398.         else
  399.             ar << m_strLinkKey;
  400.         ar << m_strDescription;
  401.         ar << (WORD)m_bHideChildren;
  402.     }
  403.     else
  404.     {
  405.         // get back-pointer to document
  406.         m_pDocument = (CServerDoc*)ar.m_pDocument;
  407.  
  408.         WORD wTemp;
  409.         ar >> wTemp; m_shape = (EShape)wTemp;
  410.         if (m_shape >= shapeMax)
  411.             m_shape = shapeRect;
  412.         ar >> m_strLinkKey >> m_strDescription;
  413.         UpdateItemName();
  414.         ar >> wTemp;
  415.         m_bHideChildren = (BOOL)wTemp;
  416.     }
  417.     m_listChild.Serialize(ar);
  418. }
  419.  
  420. /////////////////////////////////////////////////////////////////////////////
  421. // CServerNode support for CF_TEXT format
  422.  
  423. void CServerNode::SaveAsText(CArchive& ar, int nLevel)
  424. {
  425.     ASSERT(ar.IsStoring());
  426.  
  427.     // indent node text
  428.     char szTabs[MAX_LEVEL];
  429.     int nTabs = min(nLevel, MAX_LEVEL);
  430.     memset(szTabs, '\t', nTabs);
  431.     ar.Write(szTabs, nTabs);
  432.  
  433.     // write node text itself
  434. #ifdef _UNICODE
  435.     int nLen = m_strDescription.GetLength();
  436.     char* psz = (char*)_alloca(nLen+1);
  437.     wcstombs(psz, m_strDescription, nLen+1);
  438.     ar.Write(psz, nLen);
  439. #else
  440.     ar.Write(m_strDescription, m_strDescription.GetLength()*sizeof(TCHAR));
  441. #endif
  442.  
  443.     // terminate line with CRLF
  444.     static char BASED_CODE szCRLF[] = "\r\n";
  445.     ar.Write(szCRLF, sizeof(szCRLF)-1);
  446.  
  447.     // write kids
  448.     POSITION pos = m_listChild.GetHeadPosition();
  449.     while (pos != NULL)
  450.     {
  451.         CServerNode* pNode = (CServerNode*)m_listChild.GetNext(pos);
  452.         pNode->SaveAsText(ar, nLevel+1);
  453.     }
  454. }
  455.  
  456. void CServerNode::UpdateItemName()
  457. {
  458.     // empty link key if same as description (it is redundant)
  459.     if (m_strLinkKey == m_strDescription)
  460.         m_strLinkKey.Empty();
  461.  
  462.     // update link name in item if attached
  463.     if (m_pServerItem != NULL)
  464.     {
  465.         CString* pstr;
  466.         if (m_strLinkKey.IsEmpty())
  467.             pstr = &m_strDescription;
  468.         else
  469.             pstr = &m_strLinkKey;
  470.         m_pServerItem->SetItemName(*pstr);
  471.  
  472.         // empty link key since it is redundant with the server item
  473.         m_strLinkKey.Empty();
  474.     }
  475. }
  476.  
  477. const CString& CServerNode::GetItemName()
  478. {
  479.     // use item name in server item if connected
  480.     if (m_pServerItem != NULL)
  481.         return m_pServerItem->GetItemName();
  482.  
  483.     // use description or link key depending on state of link key
  484.     else if (m_strLinkKey.IsEmpty())
  485.         return m_strDescription;
  486.     else
  487.         return m_strLinkKey;
  488. }
  489.  
  490. BOOL CServerNode::PromptChangeNode()
  491. {
  492.     CChangeNameDlg dlg;
  493.     dlg.m_strDescription = m_strDescription;
  494.     dlg.m_strLinkKey = GetItemName();
  495.     if (dlg.m_strLinkKey == dlg.m_strDescription)
  496.         dlg.m_strLinkKey.Empty(); // leave empty for tracking link name
  497.     dlg.m_shape = m_shape;
  498.  
  499.     if (dlg.DoModal() == IDOK)
  500.     {
  501.         m_strDescription = dlg.m_strDescription;
  502.         m_strLinkKey = dlg.m_strLinkKey;
  503.         UpdateItemName();   // syncronize names as appropriate
  504.         m_shape = (EShape)dlg.m_shape;
  505.         return TRUE;
  506.     }
  507.     return FALSE;
  508. }
  509.  
  510. ////////////////////////////////////////////////////////////////
  511. // Creating child nodes
  512.  
  513. // Special constructor for child node
  514. CServerNode* CServerNode::CreateChildNode(LPCTSTR lpszDescription)
  515. {
  516.     CServerNode* pNew = NULL;
  517.     TRY
  518.     {
  519.         pNew = new CServerNode(GetDocument());
  520.         pNew->m_strDescription = lpszDescription;
  521.             // both item name and description start out the same
  522.  
  523.         // add as the last child
  524.         m_listChild.AddTail(pNew);
  525.     }
  526.     CATCH (CException, e)
  527.     {
  528.         delete pNew;
  529.         pNew = NULL;
  530.     }
  531.     END_CATCH
  532.  
  533.     return pNew;
  534. }
  535.  
  536. CServerNode* CServerNode::PromptNewChildNode()
  537. {
  538.     CAddNodeDlg dlg;
  539.     dlg.m_shape = (EShape)shapeRect;
  540.     if (dlg.DoModal() != IDOK)
  541.         return NULL;
  542.  
  543.     CServerNode* pNew = CreateChildNode(dlg.m_strDescription);
  544.     if (pNew == NULL)
  545.         AfxThrowMemoryException();
  546.     pNew->m_shape = (EShape)dlg.m_shape;
  547.     pNew->m_strLinkKey = dlg.m_strLinkKey;
  548.     pNew->UpdateItemName();
  549.  
  550.     return pNew;
  551. }
  552.  
  553. CServerNode* CServerNode::GetNext(CServerNode* pNode, BOOL bInit)
  554. {
  555.     static BOOL bFound;
  556.     if (bInit)
  557.         bFound = FALSE;
  558.  
  559.     if (pNode == this)
  560.         bFound = TRUE;
  561.     if (!m_bHideChildren)
  562.     {
  563.         POSITION pos = m_listChild.GetHeadPosition();
  564.         while (pos != NULL)
  565.         {
  566.             CServerNode* pChild = (CServerNode*)m_listChild.GetNext(pos);
  567.             if (bFound)
  568.                 return pChild;
  569.             pChild = pChild->GetNext(pNode, FALSE);
  570.             if (pChild != NULL)
  571.                 return pChild;
  572.         }
  573.     }
  574.     // if reached top and last level return original
  575.     if (bInit)
  576.         return pNode;
  577.     else
  578.         return NULL;
  579. }
  580.  
  581. CServerNode* CServerNode::GetPrev(CServerNode* pNode,BOOL bInit)
  582. {
  583.     static CServerNode* pPrev;
  584.     if (bInit)
  585.         pPrev = this;
  586.  
  587.     if (pNode == this)
  588.         return pPrev;
  589.  
  590.     pPrev = this;
  591.  
  592.     if (!m_bHideChildren)
  593.     {
  594.         POSITION pos = m_listChild.GetHeadPosition();
  595.         while (pos != NULL)
  596.         {
  597.             CServerNode* pCur = (CServerNode*)m_listChild.GetNext(pos);
  598.             CServerNode* pChild = pCur->GetPrev(pNode, FALSE);
  599.             if (pChild != NULL)
  600.                 return pChild;
  601.         }
  602.     }
  603.     if (bInit)
  604.         return pPrev;
  605.     else
  606.         return NULL;
  607. }
  608.  
  609. /////////////////////////////////////////////////////////////////////////////
  610. // CChangeNameDlg dialog
  611.  
  612. CChangeNameDlg::CChangeNameDlg(CWnd* pParent)
  613.     : CDialog(CChangeNameDlg::IDD, pParent)
  614. {
  615.     //{{AFX_DATA_INIT(CChangeNameDlg)
  616.     //}}AFX_DATA_INIT
  617. }
  618.  
  619. BOOL CChangeNameDlg::OnInitDialog()
  620. {
  621.     CDialog::OnInitDialog();
  622.     OnChange(); // after DDX
  623.     return TRUE;
  624. }
  625.  
  626. void CChangeNameDlg::DoDataExchange(CDataExchange* pDX)
  627. {
  628.     CDialog::DoDataExchange(pDX);
  629.     //{{AFX_DATA_MAP(CChangeNameDlg)
  630.     DDX_CBIndex(pDX, IDC_COMBO1, m_shape);
  631.     DDX_Text(pDX, IDC_EDIT1, m_strDescription);
  632.     DDX_Text(pDX, IDC_EDIT2, m_strLinkKey);
  633.     DDX_Control(pDX, IDC_EDIT1, m_editDescription);
  634.     DDX_Control(pDX, IDOK, m_btnOK);
  635.     //}}AFX_DATA_MAP
  636. }
  637.  
  638. BEGIN_MESSAGE_MAP(CChangeNameDlg, CDialog)
  639.     //{{AFX_MSG_MAP(CChangeNameDlg)
  640.     ON_EN_CHANGE(IDC_EDIT1, OnChange)
  641.     //}}AFX_MSG_MAP
  642. END_MESSAGE_MAP()
  643.  
  644.  
  645. void CChangeNameDlg::OnChange()
  646. {
  647.     if (m_btnOK.m_hWnd)
  648.         m_btnOK.EnableWindow(m_editDescription.GetWindowTextLength() > 0);
  649. }
  650.  
  651. /////////////////////////////////////////////////////////////////////////////
  652. // CAddNodeDlg dialog
  653.  
  654. CAddNodeDlg::CAddNodeDlg(CWnd* pParent /*=NULL*/)
  655.     : CDialog(CAddNodeDlg::IDD, pParent)
  656. {
  657.     //{{AFX_DATA_INIT(CAddNodeDlg)
  658.     //}}AFX_DATA_INIT
  659. }
  660.  
  661. BOOL CAddNodeDlg::OnInitDialog()
  662. {
  663.     CDialog::OnInitDialog();
  664.     OnChange(); // after DDX
  665.     return TRUE;
  666. }
  667.  
  668. void CAddNodeDlg::DoDataExchange(CDataExchange* pDX)
  669. {
  670.     CDialog::DoDataExchange(pDX);
  671.     //{{AFX_DATA_MAP(CAddNodeDlg)
  672.     DDX_Text(pDX, IDC_EDIT1, m_strDescription);
  673.     DDX_Text(pDX, IDC_EDIT2, m_strLinkKey);
  674.     DDX_CBIndex(pDX, IDC_COMBO1, m_shape);
  675.     DDX_Control(pDX, IDC_EDIT1, m_editDescription);
  676.     DDX_Control(pDX, IDOK, m_btnOK);
  677.     //}}AFX_DATA_MAP
  678. }
  679.  
  680.  
  681. BEGIN_MESSAGE_MAP(CAddNodeDlg, CDialog)
  682.     //{{AFX_MSG_MAP(CAddNodeDlg)
  683.     ON_EN_CHANGE(IDC_EDIT1, OnChange)
  684.     //}}AFX_MSG_MAP
  685. END_MESSAGE_MAP()
  686.  
  687. void CAddNodeDlg::OnChange()
  688. {
  689.     if (m_btnOK.m_hWnd)
  690.         m_btnOK.EnableWindow(m_editDescription.GetWindowTextLength() > 0);
  691. }
  692.  
  693. //////////////////////////////////////////////////////////////////////////////
  694. // CServerItem construction
  695.  
  696. CServerItem::CServerItem(CServerDoc* pServerDoc, CServerNode* pServerNode)
  697.     : COleServerItem(pServerDoc, TRUE)
  698. {
  699.     // need to attach this server item to the node in the document
  700.     ASSERT_VALID(pServerNode);
  701.     m_pServerNode = pServerNode;
  702.     pServerNode->m_pServerItem = this;
  703.     pServerNode->UpdateItemName();
  704.  
  705.     // support CF_TEXT format
  706.     GetDataSource()->DelayRenderFileData(CF_TEXT);
  707. }
  708.  
  709. CServerItem::~CServerItem()
  710. {
  711.     if (m_pServerNode != NULL)
  712.     {
  713.         m_pServerNode->m_pServerItem = NULL;
  714.         m_pServerNode->m_strLinkKey = GetItemName();
  715.         m_pServerNode->UpdateItemName();
  716.     }
  717. }
  718.  
  719. //////////////////////////////////////////////////////////////////////////////
  720. // CServerItem verb handling
  721.  
  722. void CServerItem::OnOpen()
  723. {
  724.     if (IsLinkedItem() && m_pServerNode != NULL)
  725.     {
  726.         // for linked items, try to select this node in the document
  727.         CServerDoc* pDoc = GetDocument();
  728.         ASSERT(pDoc != NULL);
  729.         POSITION pos = pDoc->GetFirstViewPosition();
  730.         ASSERT(pos != NULL);
  731.         CServerView* pView = (CServerView*)pDoc->GetNextView(pos);
  732.         ASSERT(pView->IsKindOf(RUNTIME_CLASS(CServerView)));
  733.  
  734.         pView->SetSelection(m_pServerNode);
  735.         pView->ScrollToItem(m_pServerNode, TRUE);
  736.     }
  737.     COleServerItem::OnOpen();
  738. }
  739.  
  740. /////////////////////////////////////////////////////////////////////////////
  741. // CServerItem drawing
  742.  
  743. BOOL CServerItem::OnGetExtent(DVASPECT dwDrawAspect, CSize& rSize)
  744. {
  745.     if (dwDrawAspect != DVASPECT_CONTENT)
  746.         return COleServerItem::OnGetExtent(dwDrawAspect, rSize);
  747.  
  748.     // determine extent based on screen dc
  749.     rSize = CSize(0, 0);
  750.     if (m_pServerNode != NULL)
  751.     {
  752.         CClientDC dc(NULL);
  753.         dc.SetMapMode(MM_ANISOTROPIC);
  754.         CServerDoc* pDoc = GetDocument();
  755.         ASSERT_VALID(pDoc);
  756.         CPoint ptStart(CX_MARGIN, CY_MARGIN);
  757.         pDoc->CalcBounding(&dc, m_pServerNode, ptStart, rSize);
  758.         rSize.cx += CX_MARGIN;
  759.         dc.LPtoHIMETRIC(&rSize); // convert pixels to HIMETRIC
  760.     }
  761.     return TRUE;
  762. }
  763.  
  764. BOOL CServerItem::OnDraw(CDC* pDC, CSize& rSize)
  765. {
  766.     if (m_pServerNode != NULL)
  767.     {
  768.         // determine extent of this item in the document
  769.         CServerDoc* pDoc = GetDocument();
  770.         ASSERT_VALID(pDoc);
  771.         rSize = CSize(0, 0);
  772.         CPoint ptStart(CX_MARGIN, CY_MARGIN);
  773.         pDoc->CalcBounding(pDC, m_pServerNode, ptStart, rSize);
  774.         rSize.cx += CX_MARGIN;
  775.  
  776.         // prepare to draw and remember the extent in himetric units
  777.         pDC->SetWindowOrg(0, 0);
  778.         pDC->SetWindowExt(rSize);
  779.         pDC->SetViewportExt(rSize);  // Note: only affects the m_hAttribDC
  780.  
  781.         pDC->LPtoHIMETRIC(&rSize);   // convert pixels to HIMETRIC
  782.  
  783.         // CServerDoc::DrawTree selects and releases font automatically
  784.         pDoc->DrawTree(pDC, ptStart, NULL, m_pServerNode);
  785.     }
  786.     return TRUE;
  787. }
  788.  
  789. /////////////////////////////////////////////////////////////////////////////
  790. // CServerItem clipboard handling
  791.  
  792. void CServerItem::Serialize(CArchive& ar)
  793. {
  794.     // serialize font info from document (so it looks like a document)
  795.     CServerDoc* pDoc = GetDocument();
  796.     ASSERT_VALID(pDoc);
  797.     pDoc->SerializeFontInfo(ar);
  798.  
  799.     // serialize node info
  800.     ASSERT_VALID(m_pServerNode);
  801.     m_pServerNode->Serialize(ar);
  802. }
  803.  
  804. BOOL CServerItem::OnRenderFileData(LPFORMATETC lpFormatEtc, CFile* pFile)
  805. {
  806.     ASSERT(lpFormatEtc != NULL);
  807.     if (lpFormatEtc->cfFormat != CF_TEXT)
  808.         return COleServerItem::OnRenderFileData(lpFormatEtc, pFile);
  809.  
  810.     BOOL bResult = FALSE;
  811.     if (m_pServerNode != NULL)
  812.     {
  813.         TRY
  814.         {
  815.             // save as text
  816.             CArchive ar(pFile, CArchive::store);
  817.             m_pServerNode->SaveAsText(ar, 0);
  818.             ar << (BYTE)'\0';   // terminate with NUL character
  819.             bResult = TRUE;
  820.         }
  821.         END_TRY
  822.     }
  823.     return bResult;
  824. }
  825.  
  826. // OnGetClipboardData is used by CopyToClipboard and DoDragDrop
  827. COleDataSource* CServerItem::OnGetClipboardData(BOOL bIncludeLink,
  828.     LPPOINT pptOffset, LPSIZE pSize)
  829. {
  830.     ASSERT_VALID(this);
  831.  
  832.     if (m_pServerNode == NULL)
  833.         return NULL;
  834.  
  835.     COleDataSource* pDataSource = new COleDataSource;
  836.     TRY
  837.     {
  838.         GetNativeClipboardData(pDataSource);
  839.         GetClipboardData(pDataSource, bIncludeLink, pptOffset, pSize);
  840.     }
  841.     CATCH_ALL(e)
  842.     {
  843.         delete pDataSource;
  844.         THROW_LAST();
  845.     }
  846.     END_CATCH_ALL
  847.  
  848.     ASSERT_VALID(pDataSource);
  849.     return pDataSource;
  850. }
  851.  
  852. void CServerItem::GetNativeClipboardData(COleDataSource *pDataSource)
  853. {
  854.     ASSERT_VALID(this);
  855.     ASSERT(CServerDoc::m_cfPrivate != NULL);
  856.  
  857.     // Create a shared file and associate a CArchive with it
  858.     CSharedFile file;
  859.     CArchive ar(&file,CArchive::store);
  860.  
  861.     // Serialize selected objects to the archive
  862.     m_pServerNode->Serialize(ar);
  863.     ar.Close();
  864.  
  865.     // put on local format instead of or in addation to
  866.     pDataSource->CacheGlobalData(CServerDoc::m_cfPrivate,file.Detach());
  867. }
  868.  
  869. /////////////////////////////////////////////////////////////////////////////
  870.