home *** CD-ROM | disk | FTP | other *** search
- // svrview.cpp : implementation of the CServerView class
- //
- // This is a part of the Microsoft Foundation Classes C++ library.
- // Copyright (C) 1992 Microsoft Corporation
- // All rights reserved.
- //
- // This source code is only intended as a supplement to the
- // Microsoft Foundation Classes Reference and Microsoft
- // QuickHelp and/or WinHelp documentation provided with the library.
- // See these sources for detailed information regarding the
- // Microsoft Foundation Classes product.
-
-
-
- #include "stdafx.h"
- #include "afxdlgs.h" // for FileOpen
- #include "hiersvr.h"
-
- #include "svrdoc.h"
- #include "svrview.h"
- #include "svritem.h"
-
- #ifdef _DEBUG
- #undef THIS_FILE
- static char BASED_CODE THIS_FILE[] = __FILE__;
- #endif
-
- /////////////////////////////////////////////////////////////////////////////
- // CServerView
-
- IMPLEMENT_DYNCREATE(CServerView, CScrollView)
-
- BEGIN_MESSAGE_MAP(CServerView, CScrollView)
- //{{AFX_MSG_MAP(CServerView)
- ON_COMMAND(ID_CHANGE_NAME, OnChangeName)
- ON_COMMAND(ID_ADD_NODE, OnAddNode)
- ON_UPDATE_COMMAND_UI(ID_CHANGE_NAME, OnUpdateHasSel)
- ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
- ON_WM_LBUTTONDOWN()
- ON_WM_RBUTTONDOWN()
- ON_UPDATE_COMMAND_UI(ID_ADD_NODE, OnUpdateHasSel)
- ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateHasSel)
- ON_UPDATE_COMMAND_UI(ID_IMPORT_TEXT, OnUpdateHasSel)
- ON_COMMAND(ID_IMPORT_TEXT, OnImportText)
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
-
- /////////////////////////////////////////////////////////////////////////////
- // CServerView construction/destruction
-
- CServerView::CServerView()
- {
- m_pSelectedNode = NULL;
- m_ptStart = CPoint(8, 4); // upper left position
- }
-
- CServerView::~CServerView()
- {
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- // CServerView drawing
-
-
- #define CX_INDENT 12
- #define CX_BACKDENT 5
- #define CY_SEPARATOR 4
-
-
- static int DrawTree(CDC* pDC, CPoint ptStart, CServerItem* pRoot,
- CServerItem* pItemSel)
- {
- ASSERT(pDC != NULL);
- ASSERT(pRoot != NULL);
- ASSERT(ptStart.x >= 0 && ptStart.y >= 0);
-
- // root node starts here
- int cyDrawn = 0;
- pRoot->DoDraw(pDC, ptStart, pRoot == pItemSel);
- cyDrawn += pRoot->m_sizeNode.cy + CY_SEPARATOR;
-
- if (pRoot->m_pFirstChild == NULL)
- return cyDrawn; // nothing more to draw
-
- // indent for the kids
- CPoint ptKid(ptStart.x + CX_INDENT, ptStart.y + cyDrawn);
-
- // draw the kids
- int yMid = 0;
- for (CServerItem* pChild = pRoot->m_pFirstChild;
- pChild != NULL; pChild = pChild->m_pNextSibling)
- {
- int cyKid;
- if ((cyKid = DrawTree(pDC, ptKid, pChild, pItemSel)) == -1)
- return -1; // error
-
- yMid = ptKid.y + (pChild->m_sizeNode.cy)/2;
- // add the little line
- pDC->MoveTo(ptStart.x + CX_BACKDENT, yMid);
- pDC->LineTo(ptKid.x, yMid);
- cyDrawn += cyKid;
- ptKid.y += cyKid;
- }
- ASSERT(ptKid.y == ptStart.y + cyDrawn);
-
- // draw the connecting line (down to last yMid)
- ASSERT(yMid != 0);
- int xLine = ptStart.x + CX_BACKDENT;
- pDC->MoveTo(xLine, ptStart.y + pRoot->m_sizeNode.cy);
- pDC->LineTo(xLine, yMid);
- return cyDrawn;
- }
-
- void CServerView::OnDraw(CDC* pDC)
- {
- if (DrawTree(pDC, m_ptStart, GetDocument()->m_pRoot, m_pSelectedNode) == -1)
- {
- TRACE("Error drawing tree!!\n");
- ::MessageBeep(-1);
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Simple selection
-
- // calculate the bounding rect for a given item in the context of this view
- static BOOL FindItemRect(CServerItem* pItemFind, LPRECT lpRect,
- CPoint& ptStart, CServerItem* pRoot)
- {
- ASSERT(pItemFind != NULL);
- ASSERT(lpRect != NULL);
- ASSERT(ptStart.x >= 0 && ptStart.y >= 0);
- ASSERT(pRoot != NULL);
-
- if (pItemFind == pRoot)
- {
- // item rect does not include separator
- lpRect->right = (lpRect->left = ptStart.x) + pRoot->m_sizeNode.cx;
- lpRect->bottom = (lpRect->top = ptStart.y) + pRoot->m_sizeNode.cy;
- return TRUE;
- }
- ptStart.x += CX_INDENT; // not essential for calculation
- ptStart.y += pRoot->m_sizeNode.cy + CY_SEPARATOR;
-
- // check the kids
- for (CServerItem* pChild = pRoot->m_pFirstChild;
- pChild != NULL; pChild = pChild->m_pNextSibling)
- {
- if (FindItemRect(pItemFind, lpRect, ptStart, pChild))
- return TRUE; // found
- }
- ptStart.x -= CX_INDENT;
- return FALSE;
- }
-
- // calculate the bounding rect for a given item in the context of this view
- static CServerItem* HitDetect(CPoint point, CPoint& ptStart, CServerItem* pRoot)
- {
- ASSERT(point.x >= 0 && point.y >= 0);
- ASSERT(ptStart.x >= 0 && ptStart.y >= 0);
- ASSERT(pRoot != NULL);
-
- CRect rect(ptStart, pRoot->m_sizeNode);
- if (rect.PtInRect(point))
- return pRoot;
-
- ptStart.x += CX_INDENT;
- ptStart.y += pRoot->m_sizeNode.cy + CY_SEPARATOR;
- if (ptStart.y >= point.y)
- return FALSE; // no point in looking any lower
-
- // check the kids
- for (CServerItem* pChild = pRoot->m_pFirstChild;
- pChild != NULL; pChild = pChild->m_pNextSibling)
- {
- CServerItem* pItem;
- if ((pItem = HitDetect(point, ptStart, pChild)) != NULL)
- return pItem; // found
- }
- ptStart.x -= CX_INDENT;
- return NULL;
- }
-
- static void CalcBounding(CPoint& ptStart, CSize& sizeMax, CServerItem* pRoot)
- {
- ASSERT(sizeMax.cx >= 0 && sizeMax.cy >= 0);
- ASSERT(ptStart.x >= 0 && ptStart.y >= 0);
- ASSERT(pRoot != NULL);
-
- ptStart.y += pRoot->m_sizeNode.cy + CY_SEPARATOR;
- if (ptStart.y > sizeMax.cy)
- sizeMax.cy = ptStart.y;
-
- if (ptStart.x + pRoot->m_sizeNode.cx > sizeMax.cx)
- sizeMax.cx = ptStart.x + pRoot->m_sizeNode.cx;
- ptStart.x += CX_INDENT;
- // add in the kids
- for (CServerItem* pChild = pRoot->m_pFirstChild;
- pChild != NULL; pChild = pChild->m_pNextSibling)
- {
- CalcBounding(ptStart, sizeMax, pChild);
- }
- ptStart.x -= CX_INDENT;
- }
-
-
- CServerItem* CServerView::GetSelection()
- {
- return m_pSelectedNode;
- }
-
- void CServerView::SetSelection(CServerItem* pNewSel)
- {
- if (pNewSel == m_pSelectedNode)
- return; // already set
- if (m_pSelectedNode != NULL)
- {
- // invalidate old selection
- CRect rect;
- CPoint pt = m_ptStart;
- VERIFY(FindItemRect(m_pSelectedNode, &rect, pt,
- GetDocument()->m_pRoot));
- rect -= GetDeviceScrollPosition();
- InvalidateRect(rect);
- }
- if ((m_pSelectedNode = pNewSel) != NULL)
- {
- // invalidate new selection
- CRect rect;
- CPoint pt = m_ptStart;
- VERIFY(FindItemRect(m_pSelectedNode, &rect, pt,
- GetDocument()->m_pRoot));
- rect -= GetDeviceScrollPosition();
- InvalidateRect(rect);
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CServerView diagnostics
-
- #ifdef _DEBUG
- void CServerView::AssertValid() const
- {
- CScrollView::AssertValid();
- }
-
- void CServerView::Dump(CDumpContext& dc) const
- {
- CScrollView::Dump(dc);
- }
-
- #endif //_DEBUG
-
- /////////////////////////////////////////////////////////////////////////////
- // CServerView commands
-
- void CServerView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
- {
- CScrollView::OnUpdate(pSender, lHint, pHint);
-
- // update our selection
- CServerItem* pRoot = GetDocument()->m_pRoot;
- ASSERT(pRoot != NULL);
- if (m_pSelectedNode == NULL)
- {
- m_pSelectedNode = pRoot;
- }
- else if (!pRoot->IsChild(m_pSelectedNode))
- {
- TRACE("Selected node is deleted - setting to no selection\n");
- m_pSelectedNode = NULL;
- }
-
- // Find the total size of the view
- CPoint pt = m_ptStart;
- CSize sizeTotal(0,0);
- CalcBounding(pt, sizeTotal, pRoot);
- CSize sizeLine(sizeDefault.cx, pRoot->m_sizeNode.cy + CY_SEPARATOR);
- CSize sizePage(sizeDefault.cx, sizeLine.cy * 10);
- SetScrollSizes(MM_TEXT, sizeTotal, sizePage, sizeLine);
- }
-
-
- void CServerView::OnUpdateHasSel(CCmdUI* pCmdUI)
- {
- pCmdUI->Enable(m_pSelectedNode != NULL);
- }
-
- void CServerView::OnChangeName()
- {
- if (m_pSelectedNode != NULL &&
- m_pSelectedNode->PromptChangeNode())
- {
- GetDocument()->SetModifiedFlag();
- GetDocument()->UpdateAllViews(NULL);
-
- if (m_pSelectedNode->IsConnected())
- m_pSelectedNode->NotifyChanged();
- // notify client immediately - will update automatic links
- }
- }
-
- void CServerView::OnAddNode()
- {
- if (m_pSelectedNode == NULL)
- AfxThrowNotSupportedException();
- CServerItem* pNew;
- if ((pNew = m_pSelectedNode->PromptNewChildNode()) == NULL)
- return;
-
- // wire it in
- GetDocument()->SetModifiedFlag();
- m_pSelectedNode = pNew;
- GetDocument()->UpdateAllViews(NULL);
- }
-
-
-
-
- void CServerView::OnEditCopy()
- {
- if (m_pSelectedNode == NULL)
- AfxThrowNotSupportedException();
- if (!m_pSelectedNode->CopyToClipboard(TRUE, TRUE))
- AfxMessageBox("Copy to clipboard failed");
-
- }
-
-
- void CServerView::OnLButtonDown(UINT, CPoint point)
- {
- // change the selection as appropriate
- CPoint ptLog = m_ptStart;
- SetSelection(HitDetect(point + (CSize)GetDeviceScrollPosition(),
- ptLog, GetDocument()->m_pRoot));
- }
-
-
-
- void CServerView::OnRButtonDown(UINT nFlags, CPoint point)
- {
- OnLButtonDown(nFlags, point); // select first
-
- int iSub;
- if (m_pSelectedNode == NULL ||
- (iSub = m_pSelectedNode->GetPopupMenuIndex()) == -1)
- return; // nothing if no selection or no popup
-
- CMenu popups;
- if (!popups.LoadMenu(IDR_POPUPS))
- AfxThrowResourceException();
- CMenu* pMenu = popups.GetSubMenu(iSub);
- ASSERT(pMenu != NULL);
-
- ClientToScreen(&point);
- pMenu->TrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON,
- point.x, point.y, AfxGetApp()->m_pMainWnd);
- }
-
-
- void CServerView::OnImportText()
- {
- if (m_pSelectedNode == NULL)
- AfxThrowNotSupportedException();
-
- CFileDialog dlg(TRUE, "txt", NULL,
- OFN_FILEMUSTEXIST | OFN_HIDEREADONLY,
- "Text Files (*.txt)|*.txt|All Files (*.*)|*.*||");
-
- if (dlg.DoModal() != IDOK)
- return; // stay with old data file
-
- CStdioFile file;
- if (!file.Open(dlg.GetPathName(), CFile::modeRead | CFile::typeText))
- {
- AfxMessageBox("Failed to open text file");
- return;
- }
- // read in lines appending items from this node
- char szT[256];
- int nCurLevel = 0;
- #define MAX_LEVEL 20
- CServerItem* parents[MAX_LEVEL];
- parents[0] = m_pSelectedNode; // must have a parent at the current level
- while (file.ReadString(szT, sizeof(szT)) != NULL)
- {
- int cch = strlen(szT);
- if (cch < 1 || szT[cch-1] != '\n')
- {
- AfxMessageBox("Text file contains too long a line - aborting read\n");
- break; // leaves items loaded so far
- }
- szT[cch-1] = '\0';
- // check the indentation level
- char* pch = szT;
- while (*pch == '\t')
- pch++;
- int nLevel = (pch - szT)+1;
- ASSERT(nLevel >= 1); // levels are 1 based, 0 is the root
-
- if (*pch == '\0')
- continue; // skip blank lines
- if (nLevel > nCurLevel + 1 || nLevel >= MAX_LEVEL)
- {
- AfxMessageBox("Text file contains too many tabs = aborting read\n");
- break; // leaves items loaded so far
- }
-
- parents[nLevel] = parents[nLevel-1]->CreateChildNode(pch);
- nCurLevel = nLevel;
- }
- file.Close();
- if (nCurLevel == 0)
- return; // nothing added
- GetDocument()->UpdateAllViews(NULL); // including this one
- GetDocument()->SetModifiedFlag();
- }
-
-