Object dependency view improved
authorVictor Kirhenshtein <victor@netxms.org>
Fri, 8 Dec 2006 13:12:27 +0000 (13:12 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Fri, 8 Dec 2006 13:12:27 +0000 (13:12 +0000)
ChangeLog
include/netxms_maps.h
src/console/win32/MapView.cpp
src/console/win32/ObjectDepView.cpp
src/console/win32/ObjectView.cpp
src/libnxmap/graph.cpp
src/libnxmap/libnxmap.dsp
src/libnxmap/libnxmap.h
src/libnxmap/radial.cpp
src/libnxmap/submap.cpp
src/libnxmap/vertex.cpp

index 471b65f..52535e4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,8 @@
 
 - IPSO agent improved
 - UPS subagent: added support for MICRODOWELL UPS devices
+- Windows console:
+       - Object browser improved
 
 
 *
index 6ec7f27..c9bedc3 100644 (file)
@@ -62,8 +62,9 @@
 // Submap layout methods
 //
 
-#define SUBMAP_LAYOUT_DUMB          0
-#define SUBMAP_LAYOUT_RADIAL        1
+#define SUBMAP_LAYOUT_DUMB                0
+#define SUBMAP_LAYOUT_RADIAL              1
+#define SUBMAP_LAYOUT_REINGOLD_TILFORD    2
 
 
 //
@@ -155,10 +156,16 @@ class LIBNXMAP_EXPORTABLE nxVertex
 {
 protected:
    DWORD m_dwId;
-   DWORD m_dwNumLinks;
-   nxVertex **m_ppLinkList;
+   DWORD m_dwNumChilds;
+   nxVertex **m_ppChildList;
+   DWORD m_dwNumParents;
+   nxVertex **m_ppParentList;
    int m_posX;
    int m_posY;
+   BOOL m_isProcessed;  // Processed flag for various recursive operations
+
+   void LinkParent(nxVertex *pVtx);
+   void UnlinkParent(nxVertex *pVtx);
 
 public:
    nxVertex(DWORD dwId);
@@ -167,11 +174,18 @@ public:
    DWORD GetId(void) { return m_dwId; }
    int GetPosX(void) { return m_posX; }
    int GetPosY(void) { return m_posY; }
-   DWORD GetNumLinks(void) { return m_dwNumLinks; }
-   nxVertex *GetLink(DWORD dwIndex) { return (dwIndex < m_dwNumLinks) ? m_ppLinkList[dwIndex] : NULL; }
-
-   void Link(nxVertex *pVtx);
+   DWORD GetNumChilds(void) { return m_dwNumChilds; }
+   nxVertex *GetChild(DWORD dwIndex) { return (dwIndex < m_dwNumChilds) ? m_ppChildList[dwIndex] : NULL; }
+   DWORD GetNumParents(void) { return m_dwNumParents; }
+   nxVertex *GetParent(DWORD dwIndex) { return (dwIndex < m_dwNumParents) ? m_ppParentList[dwIndex] : NULL; }
+   BOOL IsParentOf(nxVertex *pVertex);
+   BOOL IsProcessed(void) { return m_isProcessed; }
+
+   void LinkChild(nxVertex *pVtx);
+   void UnlinkChild(nxVertex *pVtx);
    void SetPosition(int x, int y) { m_posX = x; m_posY = y; }
+   void SetAsProcessed(void) { m_isProcessed = TRUE; }
+   void SetAsUnprocessed(void) { m_isProcessed = FALSE; }
 };
 
 
@@ -184,6 +198,10 @@ class LIBNXMAP_EXPORTABLE nxGraph
 protected:
    DWORD m_dwVertexCount;
    nxVertex **m_ppVertexList;
+   nxVertex *m_pRoot;
+
+   void SetAsUnprocessed(void);
+   void NormalizeVertexLinks(nxVertex *pRoot);
 
 public:
    nxGraph();
@@ -193,9 +211,11 @@ public:
    DWORD GetVertexCount(void) { return m_dwVertexCount; }
    nxVertex *FindVertex(DWORD dwId);
    DWORD GetVertexIndex(nxVertex *pVertex);
-   nxVertex *GetRootVertex(void) { return m_dwVertexCount > 0 ? m_ppVertexList[0] : NULL; }
+   nxVertex *GetRootVertex(void) { return (m_pRoot != NULL) ? m_pRoot : (m_dwVertexCount > 0 ? m_ppVertexList[0] : NULL); }
    nxVertex *GetVertexByIndex(DWORD dwIndex) { return dwIndex < m_dwVertexCount ? m_ppVertexList[dwIndex] : NULL; }
 
+   void SetRootVertex(DWORD dwId);
+   void NormalizeLinks(void);
    void NormalizeVertexPositions(void);
 };
 
index 30bc632..c63f8f7 100644 (file)
@@ -537,7 +537,7 @@ void CMapView::DoSubmapLayout()
 
             m_pSubmap->DoLayout(dwObjListSize, pdwObjectList,
                                 dwNumLinks, pLinkList, rect.right, rect.bottom,
-                                SUBMAP_LAYOUT_DUMB);
+                                SUBMAP_LAYOUT_RADIAL);
             safe_free(pdwObjectList);
             safe_free(pLinkList);
          }
index 8790955..64eb294 100644 (file)
@@ -99,7 +99,7 @@ void CObjectDepView::Refresh()
    pSubmap = new nxSubmap((DWORD)0);
    pSubmap->DoLayout(list.GetNumObjects(), list.GetObjects(),
                      list.GetNumLinks(), list.GetLinks(), rect.right, rect.bottom,
-                     SUBMAP_LAYOUT_RADIAL);
+                     SUBMAP_LAYOUT_REINGOLD_TILFORD);
    pMap->AddSubmap(pSubmap);
    m_wndMap.SetMap(pMap);
 }
@@ -119,9 +119,12 @@ void CObjectDepView::AddParentsToMap(NXC_OBJECT *pChild, nxObjList &list)
       pObject = NXCFindObjectById(g_hSession, pChild->pdwParentList[i]);
       if (pObject != NULL)
       {
-         list.AddObject(pChild->pdwParentList[i]);
-         list.LinkObjects(pChild->dwId, pChild->pdwParentList[i]);
-         AddParentsToMap(pObject, list);
+         if (pObject->iClass != OBJECT_TEMPLATE)
+         {
+            list.AddObject(pChild->pdwParentList[i]);
+            list.LinkObjects(pChild->dwId, pChild->pdwParentList[i]);
+            AddParentsToMap(pObject, list);
+         }
       }
    }
 }
index 73598f1..2037fb7 100644 (file)
@@ -157,6 +157,9 @@ void CObjectView::Refresh()
    GetClientRect(&rect);
    rect.bottom = TITLE_BAR_HEIGHT;
    InvalidateRect(&rect, FALSE);
+
+   m_wndOverview.Refresh();
+   m_wndDepView.Refresh();
 }
 
 
@@ -168,6 +171,7 @@ void CObjectView::SetCurrentObject(NXC_OBJECT *pObject)
 {
    int i, nItem, nCurrTabId, nTab;
    LRESULT nTemp;
+   RECT rect;
 
    nCurrTabId = m_pTabWnd[m_wndTabCtrl.GetCurSel()]->GetDlgCtrlID();
    m_pObject = pObject;
@@ -192,7 +196,7 @@ void CObjectView::SetCurrentObject(NXC_OBJECT *pObject)
          case OBJECT_CONTAINER:
          case OBJECT_SERVICEROOT:
             CreateTab(1, _T("Alarms"), 1, &m_wndAlarms);
-            CreateTab(2, _T("Dependencies"), 2, &m_wndDepView);
+            CreateTab(2, _T("Dependants"), 2, &m_wndDepView);
             break;
          default:
             break;
@@ -212,7 +216,9 @@ void CObjectView::SetCurrentObject(NXC_OBJECT *pObject)
    OnTabChange(NULL, &nTemp);
 
    // Refresh object view
-   Refresh();
+   GetClientRect(&rect);
+   rect.bottom = TITLE_BAR_HEIGHT;
+   InvalidateRect(&rect, FALSE);
    for(i = 0; (m_pTabWnd[i] != NULL) && (i < MAX_TABS); i++)
       m_pTabWnd[i]->SendMessage(NXCM_SET_OBJECT, 0, (LPARAM)m_pObject);
 }
index eb6024f..4538c0b 100644 (file)
@@ -34,6 +34,7 @@ nxGraph::nxGraph()
    m_ppVertexList = NULL;
    m_dwVertexCount = 0;
    m_ppVertexList = NULL;
+   m_pRoot = NULL;
 }
 
 
@@ -60,8 +61,10 @@ nxGraph::nxGraph(DWORD dwNumObjects, DWORD *pdwObjectList,
       pVtx1 = FindVertex(pLinkList[i].dwId1);
       pVtx2 = FindVertex(pLinkList[i].dwId2);
       if ((pVtx1 != NULL) && (pVtx2 != NULL))
-         pVtx1->Link(pVtx2);
+         pVtx1->LinkChild(pVtx2);
    }
+
+   m_pRoot = NULL;   // No selected root by default
 }
 
 
@@ -79,6 +82,19 @@ nxGraph::~nxGraph()
 }
 
 
+//
+// Set all vertexes as unprocessed
+//
+
+void nxGraph::SetAsUnprocessed(void)
+{
+   DWORD i;
+
+   for(i = 0; i < m_dwVertexCount; i++)
+      m_ppVertexList[i]->SetAsUnprocessed();
+}
+
+
 //
 // Find vertex by ID
 //
@@ -139,3 +155,59 @@ void nxGraph::NormalizeVertexPositions(void)
                                         m_ppVertexList[i]->GetPosY() + dy);
    }
 }
+
+
+//
+// Set root vertex
+//
+
+void nxGraph::SetRootVertex(DWORD dwId)
+{
+   DWORD i;
+
+   for(i = 0; i < m_dwVertexCount; i++)
+      if (m_ppVertexList[i]->GetId() == dwId)
+      {
+         m_pRoot = m_ppVertexList[i];
+         return;
+      }
+   m_pRoot = NULL;
+}
+
+
+//
+// Normalize links for given vertex
+//
+
+void nxGraph::NormalizeVertexLinks(nxVertex *pRoot)
+{
+   DWORD i;
+
+   for(i = 0; i < m_dwVertexCount; i++)
+   {
+      if (!m_ppVertexList[i]->IsProcessed() && m_ppVertexList[i]->IsParentOf(pRoot))
+      {
+         m_ppVertexList[i]->UnlinkChild(pRoot);
+         pRoot->LinkChild(m_ppVertexList[i]);
+      }
+      m_ppVertexList[i]->SetAsProcessed();
+   }
+
+   for(i = 0; i < pRoot->GetNumChilds(); i++)
+      NormalizeVertexLinks(pRoot->GetChild(i));
+}
+
+
+//
+// Normalize links - make all links to go from root when possible
+//
+
+void nxGraph::NormalizeLinks(void)
+{
+   if (m_pRoot != NULL)
+   {
+      SetAsUnprocessed();
+      m_pRoot->SetAsProcessed();
+      NormalizeVertexLinks(m_pRoot);
+   }
+}
index 890a901..684149e 100644 (file)
@@ -188,6 +188,10 @@ SOURCE=.\radial.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\rt.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\submap.cpp
 # End Source File
 # Begin Source File
index bc79d3e..6c630eb 100644 (file)
@@ -74,4 +74,33 @@ public:
    virtual void Execute(void);
 };
 
+
+//
+// Reingold Tilford layout engine
+//
+
+class nxleReingoldTilford : public nxleGeneric
+{
+protected:
+   double *m_xPreliminary;
+   double *m_xModifier;
+   double *m_xParentModifier;
+   int *m_passCount;
+   nxVertex **m_leftBrother;
+   DWORD *m_layer;
+   nxVertex **m_contour;
+   double m_spacing;
+
+   void Initialize(nxVertex *root, DWORD layer);
+   double TrueX(nxVertex *root);
+   void FirstPass(nxVertex *root);
+   void SecondPass(nxVertex *root, double modifier);
+
+public:
+   nxleReingoldTilford(nxGraph *pGraph);
+   virtual ~nxleReingoldTilford();
+
+   virtual void Execute(void);
+};
+
 #endif   /* _libnxmap_h_ */
index af965b2..8451d98 100644 (file)
@@ -73,16 +73,16 @@ double nxleRadial::SetWidth(nxVertex *root)
        double width;
    DWORD i;
 
-   if (root->GetNumLinks() == 0)
+   if (root->GetNumChilds() == 0)
    {
       width = MAP_OBJECT_SIZE_X;
    }
    else
    {
       width = 0.0;
-      for(i = 0; i < root->GetNumLinks(); i++)
+      for(i = 0; i < root->GetNumChilds(); i++)
       {
-         width += SetWidth(root->GetLink(i)) + MAP_OBJECT_INTERVAL_X;
+         width += SetWidth(root->GetChild(i)) + MAP_OBJECT_INTERVAL_X;
       }
    }
        m_width[m_graph->GetVertexIndex(root)] = width;
@@ -111,7 +111,7 @@ void nxleRadial::SetPlacement(nxVertex *root, double ro,
        m_angle[index] = fi;
        m_distance[index] = ro;
        
-   if (root->GetNumLinks() > 0)
+   if (root->GetNumChilds() > 0)
    {
       tau = m_bConvexity ? 2.0 * acos(ro / (ro + myDelta)) : 0.0;
                rootFullWidth = m_fullWidth[index];
@@ -126,9 +126,9 @@ void nxleRadial::SetPlacement(nxVertex *root, double ro,
          alpha = alpha1;
       }
 
-      for(i = 0; i < root->GetNumLinks(); i++)
+      for(i = 0; i < root->GetNumChilds(); i++)
       {
-         child = root->GetLink(i);
+         child = root->GetChild(i);
                        childWidth = m_width[m_graph->GetVertexIndex(child)];
                        SetPlacement(child, ro + myDelta, alpha,
                       alpha + s * childWidth, layer + 1);
index 8bc47d7..297ea6f 100644 (file)
@@ -378,11 +378,19 @@ void nxSubmap::DoLayout(DWORD dwNumObjects, DWORD *pdwObjectList,
       nxVertex *vertex;
 
       graph = new nxGraph(dwNumObjects, pdwObjectList, dwNumLinks, pLinkList);
+      if (dwNumObjects > 0)
+      {
+         graph->SetRootVertex(pdwObjectList[0]);
+         graph->NormalizeLinks();
+      }
       switch(nMethod)
       {
          case SUBMAP_LAYOUT_RADIAL:
             engine = new nxleRadial(graph);
             break;
+         case SUBMAP_LAYOUT_REINGOLD_TILFORD:
+            engine = new nxleReingoldTilford(graph);
+            break;
          default: // Unknown method, do nothing
             engine = new nxleGeneric(graph);
             break;
index c010794..bf91eb4 100644 (file)
@@ -33,8 +33,10 @@ nxVertex::nxVertex(DWORD dwId)
    m_dwId = dwId;
    m_posX = 0;
    m_posY = 0;
-   m_dwNumLinks = 0;
-   m_ppLinkList = NULL;
+   m_dwNumChilds = 0;
+   m_ppChildList = NULL;
+   m_dwNumParents = 0;
+   m_ppParentList = NULL;
 }
 
 
@@ -44,25 +46,103 @@ nxVertex::nxVertex(DWORD dwId)
 
 nxVertex::~nxVertex()
 {
-   safe_free(m_ppLinkList);
+   safe_free(m_ppChildList);
+   safe_free(m_ppParentList);
 }
 
 
 //
-// Link another vertex
+// Link another vertex as child
 //
 
-void nxVertex::Link(nxVertex *pVtx)
+void nxVertex::LinkChild(nxVertex *pVtx)
 {
    DWORD i;
 
-   for(i = 0; i < m_dwNumLinks; i++)
-      if (m_ppLinkList[i] == pVtx)
+   for(i = 0; i < m_dwNumChilds; i++)
+      if (m_ppChildList[i] == pVtx)
          break;   // Already linked
-   if (i == m_dwNumLinks)
+   if (i == m_dwNumChilds)
    {
-      m_dwNumLinks++;
-      m_ppLinkList = (nxVertex **)realloc(m_ppLinkList, sizeof(nxVertex *) * m_dwNumLinks);
-      m_ppLinkList[i] = pVtx;
+      m_dwNumChilds++;
+      m_ppChildList = (nxVertex **)realloc(m_ppChildList, sizeof(nxVertex *) * m_dwNumChilds);
+      m_ppChildList[i] = pVtx;
+      pVtx->LinkParent(this);
    }
 }
+
+
+//
+// Unlink child vertex
+//
+
+void nxVertex::UnlinkChild(nxVertex *pVtx)
+{
+   DWORD i;
+
+   for(i = 0; i < m_dwNumChilds; i++)
+      if (m_ppChildList[i] == pVtx)
+      {
+         m_dwNumChilds--;
+         memmove(&m_ppChildList[i], &m_ppChildList[i + 1], (m_dwNumChilds - i) * sizeof(nxVertex *));
+         pVtx->UnlinkParent(this);
+         break;
+      }
+}
+
+
+//
+// Link another vertex as parent
+//
+
+void nxVertex::LinkParent(nxVertex *pVtx)
+{
+   DWORD i;
+
+   for(i = 0; i < m_dwNumParents; i++)
+      if (m_ppParentList[i] == pVtx)
+         break;   // Already linked
+   if (i == m_dwNumParents)
+   {
+      m_dwNumParents++;
+      m_ppParentList = (nxVertex **)realloc(m_ppParentList, sizeof(nxVertex *) * m_dwNumParents);
+      m_ppParentList[i] = pVtx;
+   }
+}
+
+
+//
+// Unlink parent vertex
+//
+
+void nxVertex::UnlinkParent(nxVertex *pVtx)
+{
+   DWORD i;
+
+   for(i = 0; i < m_dwNumParents; i++)
+      if (m_ppParentList[i] == pVtx)
+      {
+         m_dwNumParents--;
+         memmove(&m_ppParentList[i], &m_ppParentList[i + 1], (m_dwNumParents - i) * sizeof(nxVertex *));
+         break;
+      }
+}
+
+
+//
+// Check if link to given vertex exist
+//
+
+BOOL nxVertex::IsParentOf(nxVertex *pVtx)
+{
+   DWORD i;
+   BOOL bRet = FALSE;
+
+   for(i = 0; i < m_dwNumChilds; i++)
+      if (m_ppChildList[i] == pVtx)
+      {
+         bRet = TRUE;
+         break;
+      }
+   return bRet;
+}