- Fixed bugs number 195 and 203
authorVictor Kirhenshtein <victor@netxms.org>
Thu, 6 Mar 2008 00:04:21 +0000 (00:04 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Thu, 6 Mar 2008 00:04:21 +0000 (00:04 +0000)
- Console: added sorting to action manager, user manager, and agent configs manager
- Fixed console crash in EPP editor

21 files changed:
ChangeLog
doc/internal/db_format_change.txt
include/netxmsdb.h
include/uuid.h
sql/schema.in
src/console/win32/ActionEditor.cpp
src/console/win32/ActionEditor.h
src/console/win32/AgentConfigMgr.cpp
src/console/win32/AgentConfigMgr.h
src/console/win32/EventPolicyEditor.cpp
src/console/win32/TrapEditor.cpp
src/console/win32/UserEditor.cpp
src/console/win32/UserEditor.h
src/libnetxms/uuid.c
src/server/core/condition.cpp
src/server/core/node.cpp
src/server/core/objects.cpp
src/server/core/template.cpp
src/server/include/nms_objects.h
src/server/tools/nxdbmgr/nxdbmgr.cpp
src/server/tools/nxdbmgr/upgrade.cpp

index 8a0fd2b..ac9a86f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -19,7 +19,7 @@
 - New command line tool for managing alarms - nxalarm
 - Implemented "stop processing" option for event processing policy rule
 - Implemented "move" operation for templates (move between template groups)
-- Fixed issues: #188, #189, #190, #199
+- Fixed issues: #188, #189, #190, #195, #199, #203
 
 
 *
index 07307de..7ed0a43 100644 (file)
@@ -1,4 +1,13 @@
 *************
+* 76 ==> 77 *
+*************
+
+- Table "cond_dci_map" altered:
+       - Added new column sequence_number (type "integer not null")
+       - Primary key changed to "condition_id,sequence_number"
+
+
+*************
 * 75 ==> 76 *
 *************
 
index b216c12..5953e47 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: netxmsdb.h,v 1.78 2008-02-29 21:17:27 victor Exp $ */
+/* $Id: netxmsdb.h,v 1.79 2008-03-06 00:04:17 victor Exp $ */
 /* 
 ** NetXMS - Network Management System
 ** Copyright (C) 2003, 2004, 2005, 2006, 2007 Victor Kirhenshtein
@@ -24,6 +24,6 @@
 #ifndef _netxmsdb_h
 #define _netxmsdb_h
 
-#define DB_FORMAT_VERSION      76
+#define DB_FORMAT_VERSION      77
 
 #endif
index ef81848..87d9171 100644 (file)
@@ -32,8 +32,8 @@ int LIBNETXMS_EXPORTABLE uuid_compare(uuid_t uu1, uuid_t uu2);
 void LIBNETXMS_EXPORTABLE uuid_copy(uuid_t uu1, uuid_t uu2);
 void LIBNETXMS_EXPORTABLE uuid_generate(uuid_t out);
 int LIBNETXMS_EXPORTABLE uuid_is_null(uuid_t uu);
-int LIBNETXMS_EXPORTABLE uuid_parse(char *in, uuid_t uu);
-char LIBNETXMS_EXPORTABLE *uuid_to_string(uuid_t uu, char *out);
+int LIBNETXMS_EXPORTABLE uuid_parse(TCHAR *in, uuid_t uu);
+TCHAR LIBNETXMS_EXPORTABLE *uuid_to_string(uuid_t uu, TCHAR *out);
 
 #ifdef __cplusplus
 }
index 3217126..f07775d 100644 (file)
@@ -356,11 +356,12 @@ CREATE TABLE conditions
 CREATE TABLE cond_dci_map
 (
        condition_id integer not null,
+       sequence_number integer not null,
        dci_id integer not null,
        node_id integer not null,
        dci_func integer not null,
        num_polls integer not null,
-       PRIMARY KEY(condition_id,dci_id)
+       PRIMARY KEY(condition_id,sequence_number)
 ) TABLE_TYPE;
 
 
index 8bd38fa..e6dd13c 100644 (file)
@@ -20,10 +20,14 @@ IMPLEMENT_DYNCREATE(CActionEditor, CMDIChildWnd)
 
 CActionEditor::CActionEditor()
 {
+   m_iSortMode = theApp.GetProfileInt(_T("ActionEditor"), _T("SortMode"), 0);
+   m_iSortDir = theApp.GetProfileInt(_T("ActionEditor"), _T("SortDir"), 1);
 }
 
 CActionEditor::~CActionEditor()
 {
+   theApp.WriteProfileInt(_T("ActionEditor"), _T("SortMode"), m_iSortMode);
+   theApp.WriteProfileInt(_T("ActionEditor"), _T("SortDir"), m_iSortDir);
 }
 
 
@@ -44,6 +48,7 @@ BEGIN_MESSAGE_MAP(CActionEditor, CMDIChildWnd)
        ON_COMMAND(ID_ACTION_DELETE, OnActionDelete)
        //}}AFX_MSG_MAP
    ON_NOTIFY(NM_DBLCLK, IDC_LIST_VIEW, OnListViewDoubleClick)
+       ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST_VIEW, OnListViewColumnClick)
 END_MESSAGE_MAP()
 
 /////////////////////////////////////////////////////////////////////////////
@@ -75,7 +80,7 @@ int CActionEditor::OnCreate(LPCREATESTRUCT lpCreateStruct)
        
    // Create list view control
    GetClientRect(&rect);
-   m_wndListCtrl.Create(WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS, rect, this, IDC_LIST_VIEW);
+   m_wndListCtrl.Create(WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS, rect, this, IDC_LIST_VIEW);
    m_wndListCtrl.SetExtendedStyle(LVS_EX_TRACKSELECT | LVS_EX_UNDERLINEHOT |
                                   LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
    m_wndListCtrl.SetHoverTime(0x7FFFFFFF);
@@ -86,6 +91,9 @@ int CActionEditor::OnCreate(LPCREATESTRUCT lpCreateStruct)
    m_imageList.Add(AfxGetApp()->LoadIcon(IDI_REXEC));
    m_imageList.Add(AfxGetApp()->LoadIcon(IDI_EMAIL));
    m_imageList.Add(AfxGetApp()->LoadIcon(IDI_SMS));
+   m_iSortImageBase = m_imageList.GetImageCount();
+   m_imageList.Add(theApp.LoadIcon(IDI_SORT_UP));
+   m_imageList.Add(theApp.LoadIcon(IDI_SORT_DOWN));
    m_wndListCtrl.SetImageList(&m_imageList, LVSIL_SMALL);
 
    // Setup columns
@@ -94,6 +102,8 @@ int CActionEditor::OnCreate(LPCREATESTRUCT lpCreateStruct)
    m_wndListCtrl.InsertColumn(2, _T("Recipient"), LVCFMT_LEFT, 150);
    m_wndListCtrl.InsertColumn(3, _T("Data"), LVCFMT_LEFT, 350);
 
+       LoadListCtrlColumns(m_wndListCtrl, _T("ActionEditor"), _T("ListCtrl"));
+
    PostMessage(WM_COMMAND, ID_VIEW_REFRESH, 0);
 
        return 0;
@@ -106,6 +116,7 @@ int CActionEditor::OnCreate(LPCREATESTRUCT lpCreateStruct)
 
 void CActionEditor::OnDestroy() 
 {
+       SaveListCtrlColumns(m_wndListCtrl, _T("ActionEditor"), _T("ListCtrl"));
    theApp.OnViewDestroy(VIEW_ACTION_EDITOR, this);
        CMDIChildWnd::OnDestroy();
 }
@@ -168,6 +179,7 @@ void CActionEditor::OnViewRefresh()
    LockActions();
    for(i = 0; i < g_dwNumActions; i++)
       AddItem(&g_pActionList[i]);
+       SortList();
    UnlockActions();
 }
 
@@ -279,6 +291,7 @@ void CActionEditor::OnActionNew()
 
          iItem = AddItem(&g_pActionList[i]);
          SelectListViewItem(&m_wndListCtrl, iItem);
+                       SortList();
          PostMessage(WM_COMMAND, ID_ACTION_PROPERTIES, 0);
 
          UnlockActions();
@@ -338,6 +351,9 @@ void CActionEditor::OnActionProperties()
                if (dwResult == RCC_SUCCESS)
                {
                   ReplaceItem(iItem, &action);
+                                               LockActions();
+                                               SortList();
+                                               UnlockActions();
                }
                else
                {
@@ -413,3 +429,94 @@ void CActionEditor::OnActionDelete()
       free(pdwDeleteList);
    }
 }
+
+
+//
+// Action comparision procedure for sorting
+//
+
+static int CALLBACK ActionCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+   CActionEditor *pWnd = (CActionEditor *)lParamSort;
+   NXC_ACTION *pAction1, *pAction2;
+   int iResult;
+   
+   pAction1 = FindActionById(lParam1);
+   pAction2 = FindActionById(lParam2);
+
+       if ((pAction1 == NULL) || (pAction2 == NULL))
+       {
+               theApp.DebugPrintf(_T("WARNING: pAction == NULL in ActionCompareProc() !!!"));
+               return 0;
+       }
+   
+   switch(pWnd->GetSortMode())
+   {
+      case 0:     // Name
+         iResult = _tcsicmp(pAction1->szName, pAction2->szName);
+         break;
+      case 1:     // Type
+         iResult = _tcsicmp(g_szActionType[pAction1->iType], g_szActionType[pAction2->iType]);
+         break;
+      case 2:     // Recipient
+         iResult = _tcsicmp(pAction1->szRcptAddr, pAction2->szRcptAddr);
+         break;
+      case 3:     // Data
+         iResult = _tcsicmp(pAction1->pszData, pAction2->pszData);
+         break;
+      default:
+         iResult = 0;
+         break;
+   }
+
+   return iResult * pWnd->GetSortDir();
+}
+
+
+//
+// Sort action list
+//
+
+void CActionEditor::SortList()
+{
+   LVCOLUMN lvc;
+
+   m_wndListCtrl.SortItems(ActionCompareProc, (LPARAM)this);
+   lvc.mask = LVCF_IMAGE | LVCF_FMT;
+   lvc.fmt = LVCFMT_LEFT | LVCFMT_IMAGE | LVCFMT_BITMAP_ON_RIGHT;
+   lvc.iImage = (m_iSortDir == 1) ? m_iSortImageBase : m_iSortImageBase + 1;
+   m_wndListCtrl.SetColumn(m_iSortMode, &lvc);
+}
+
+
+//
+// WM_NOTIFY::LVN_COLUMNCLICK message handler
+//
+
+void CActionEditor::OnListViewColumnClick(LPNMLISTVIEW pNMHDR, LRESULT *pResult)
+{
+   LVCOLUMN lvCol;
+
+   // Unmark old sorting column
+   lvCol.mask = LVCF_FMT;
+   lvCol.fmt = LVCFMT_LEFT;
+   m_wndListCtrl.SetColumn(m_iSortMode, &lvCol);
+
+   // Change current sort mode and resort list
+   if (m_iSortMode == pNMHDR->iSubItem)
+   {
+      // Same column, change sort direction
+      m_iSortDir = -m_iSortDir;
+   }
+   else
+   {
+      // Another sorting column
+      m_iSortMode = pNMHDR->iSubItem;
+   }
+
+       LockActions();
+   SortList();
+       UnlockActions();
+   
+   *pResult = 0;
+}
index 9111c88..29cfba4 100644 (file)
@@ -31,6 +31,10 @@ public:
 
 // Implementation
 protected:
+       void SortList();
+       int m_iSortDir;
+       int m_iSortMode;
+       int m_iSortImageBase;
        void ReplaceItem(int iItem, NXC_ACTION *pAction);
        int AddItem(NXC_ACTION *pAction);
        virtual ~CActionEditor();
@@ -52,10 +56,15 @@ protected:
        afx_msg void OnActionDelete();
        //}}AFX_MSG
        afx_msg void OnListViewDoubleClick(NMITEMACTIVATE *pInfo, LRESULT *pResult);
+   afx_msg void OnListViewColumnClick(LPNMLISTVIEW pNMHDR, LRESULT *pResult);
        DECLARE_MESSAGE_MAP()
 private:
        CImageList m_imageList;
        CListCtrl m_wndListCtrl;
+
+public:
+   int GetSortMode(void) { return m_iSortMode; }
+   int GetSortDir(void) { return m_iSortDir; }
 };
 
 /////////////////////////////////////////////////////////////////////////////
index 7355a99..828c65e 100644 (file)
@@ -20,7 +20,7 @@ IMPLEMENT_DYNCREATE(CAgentConfigMgr, CMDIChildWnd)
 CAgentConfigMgr::CAgentConfigMgr()
 {
    m_iSortMode = theApp.GetProfileInt(_T("AgentConfigMgr"), _T("SortMode"), 1);
-   m_iSortDir = theApp.GetProfileInt(_T("AgentConfigMgr"), _T("SortDir"), 0);
+   m_iSortDir = theApp.GetProfileInt(_T("AgentConfigMgr"), _T("SortDir"), 1);
 }
 
 CAgentConfigMgr::~CAgentConfigMgr()
@@ -157,43 +157,6 @@ void CAgentConfigMgr::OnContextMenu(CWnd* pWnd, CPoint point)
 
 
 //
-// WM_COMMAND::ID_VIEW_REFRESH message handler
-//
-
-void CAgentConfigMgr::OnViewRefresh() 
-{
-   DWORD i, dwResult, dwNumCfg;
-   NXC_AGENT_CONFIG_INFO *pList;
-   TCHAR szBuffer[32];
-   int iItem;
-
-   m_wndListCtrl.DeleteAllItems();
-   dwResult = DoRequestArg3(NXCGetAgentConfigList, g_hSession, &dwNumCfg, &pList,
-                            _T("Loading list of agent configurations..."));
-   if (dwResult == RCC_SUCCESS)
-   {
-      for(i = 0; i < dwNumCfg; i++)
-      {
-         _stprintf(szBuffer, _T("%d"), pList[i].dwId);
-         iItem = m_wndListCtrl.InsertItem(0x7FFFFFFF, szBuffer, -1);
-         if (iItem != -1)
-         {
-            m_wndListCtrl.SetItemData(iItem, pList[i].dwId);
-            _stprintf(szBuffer, _T("%d"), pList[i].dwSequence);
-            m_wndListCtrl.SetItemText(iItem, 1, szBuffer);
-            m_wndListCtrl.SetItemText(iItem, 2, pList[i].szName);
-         }
-      }
-      safe_free(pList);
-   }
-   else
-   {
-      theApp.ErrorBox(dwResult, _T("Cannot load list of agent configurations: %s"));
-   }
-}
-
-
-//
 // UI update handlers
 //
 
@@ -209,12 +172,12 @@ void CAgentConfigMgr::OnUpdateConfigDelete(CCmdUI* pCmdUI)
 
 void CAgentConfigMgr::OnUpdateConfigMoveup(CCmdUI* pCmdUI) 
 {
-   pCmdUI->Enable(m_wndListCtrl.GetSelectedCount() == 1);
+   pCmdUI->Enable((m_wndListCtrl.GetSelectedCount() == 1) && (m_iSortMode == 1));
 }
 
 void CAgentConfigMgr::OnUpdateConfigMovedown(CCmdUI* pCmdUI) 
 {
-   pCmdUI->Enable(m_wndListCtrl.GetSelectedCount() == 1);
+   pCmdUI->Enable((m_wndListCtrl.GetSelectedCount() == 1) && (m_iSortMode == 1));
 }
 
 
@@ -374,6 +337,39 @@ void CAgentConfigMgr::OnListViewDblClk(LPNMITEMACTIVATE pNMHDR, LRESULT *pResult
 
 
 //
+// Item comparision procedure for sorting
+//
+
+static int CALLBACK ItemCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+       CAgentConfigMgr *pWnd = (CAgentConfigMgr *)lParamSort;
+       TCHAR item1[256], item2[256];
+   int iResult;
+
+       pWnd->GetItemText(lParam1, pWnd->GetSortMode(), item1);
+       pWnd->GetItemText(lParam2, pWnd->GetSortMode(), item2);
+
+       switch(pWnd->GetSortMode())
+       {
+               case 0: // ID
+         iResult = COMPARE_NUMBERS(_tcstol(item1, NULL, 10), _tcstol(item2, NULL, 10));
+                       break;
+               case 1: // Sequence
+         iResult = COMPARE_NUMBERS(_tcstol(item1, NULL, 10), _tcstol(item2, NULL, 10));
+                       break;
+               case 2: // Name
+         iResult = _tcsicmp(item1, item2);
+                       break;
+      default:
+         iResult = 0;
+         break;
+       }
+
+   return iResult * pWnd->GetSortDir();
+}
+
+
+//
 // WM_NOTIFY::LVN_COLUMNCLICK message handler
 //
 
@@ -390,19 +386,19 @@ void CAgentConfigMgr::OnListViewColumnClick(LPNMLISTVIEW pNMHDR, LRESULT *pResul
    if (m_iSortMode == pNMHDR->iSubItem)
    {
       // Same column, change sort direction
-      m_iSortDir = 1 - m_iSortDir;
+      m_iSortDir = -m_iSortDir;
    }
    else
    {
       // Another sorting column
       m_iSortMode = pNMHDR->iSubItem;
    }
-   //m_wndListCtrl.SortItems(ItemCompareProc, (LPARAM)this);
+   m_wndListCtrl.SortItems(ItemCompareProc, (LPARAM)this);
 
    // Mark new sorting column
    lvCol.mask = LVCF_IMAGE | LVCF_FMT;
    lvCol.fmt = LVCFMT_BITMAP_ON_RIGHT | LVCFMT_IMAGE | LVCFMT_LEFT;
-   lvCol.iImage = m_iSortDir;
+   lvCol.iImage = (m_iSortDir == 1) ? 0 : 1;
    m_wndListCtrl.SetColumn(pNMHDR->iSubItem, &lvCol);
    
    *pResult = 0;
@@ -458,7 +454,7 @@ void CAgentConfigMgr::SwapItems(int nItem1, int nItem2)
       m_wndListCtrl.SetItemText(nItem1, 1, szBuf2);
       if (m_iSortMode == 1)
       {
-         m_wndListCtrl.GetItemText(nItem1, 2, szBuf2, 256);
+         m_wndListCtrl.GetItemText(nItem2, 2, szBuf2, 256);
          m_wndListCtrl.DeleteItem(nItem2);
 
          _stprintf(szBuffer, _T("%d"), dwId2);
@@ -477,3 +473,64 @@ void CAgentConfigMgr::SwapItems(int nItem1, int nItem2)
       theApp.ErrorBox(dwResult, _T("Cannot change sequence number of agent config: %s"));
    }
 }
+
+
+//
+// Get list item text
+//
+
+void CAgentConfigMgr::GetItemText(int item, int col, TCHAR *buffer)
+{
+       int index;
+       LVFINDINFO lvfi;
+
+       lvfi.flags = LVFI_PARAM;
+       lvfi.lParam = item;
+       index = m_wndListCtrl.FindItem(&lvfi);
+       if (index != -1)
+       {
+               m_wndListCtrl.GetItemText(index, col, buffer, 256);
+       }
+       else
+       {
+               *buffer = 0;
+       }
+}
+
+
+//
+// WM_COMMAND::ID_VIEW_REFRESH message handler
+//
+
+void CAgentConfigMgr::OnViewRefresh() 
+{
+   DWORD i, dwResult, dwNumCfg;
+   NXC_AGENT_CONFIG_INFO *pList;
+   TCHAR szBuffer[32];
+   int iItem;
+
+   m_wndListCtrl.DeleteAllItems();
+   dwResult = DoRequestArg3(NXCGetAgentConfigList, g_hSession, &dwNumCfg, &pList,
+                            _T("Loading list of agent configurations..."));
+   if (dwResult == RCC_SUCCESS)
+   {
+      for(i = 0; i < dwNumCfg; i++)
+      {
+         _stprintf(szBuffer, _T("%d"), pList[i].dwId);
+         iItem = m_wndListCtrl.InsertItem(0x7FFFFFFF, szBuffer, -1);
+         if (iItem != -1)
+         {
+            m_wndListCtrl.SetItemData(iItem, pList[i].dwId);
+            _stprintf(szBuffer, _T("%d"), pList[i].dwSequence);
+            m_wndListCtrl.SetItemText(iItem, 1, szBuffer);
+            m_wndListCtrl.SetItemText(iItem, 2, pList[i].szName);
+         }
+      }
+      safe_free(pList);
+          m_wndListCtrl.SortItems(ItemCompareProc, (LPARAM)this);
+   }
+   else
+   {
+      theApp.ErrorBox(dwResult, _T("Cannot load list of agent configurations: %s"));
+   }
+}
index a970ce6..6c67925 100644 (file)
@@ -60,6 +60,11 @@ protected:
    afx_msg void OnListViewDblClk(LPNMITEMACTIVATE pNMHDR, LRESULT *pResult);
    afx_msg void OnListViewColumnClick(LPNMLISTVIEW pNMHDR, LRESULT *pResult);
        DECLARE_MESSAGE_MAP()
+
+public:
+       void GetItemText(int item, int col, TCHAR *buffer);
+   int GetSortMode(void) { return m_iSortMode; }
+   int GetSortDir(void) { return m_iSortDir; }
 };
 
 /////////////////////////////////////////////////////////////////////////////
index 01da998..72c80b2 100644 (file)
@@ -312,6 +312,7 @@ void CEventPolicyEditor::InsertNewRule(int iInsertBefore)
    memset(&m_pEventPolicy->pRuleList[iPos], 0, sizeof(NXC_EPP_RULE));
    m_pEventPolicy->pRuleList[iPos].dwId = (DWORD)iPos;
    m_pEventPolicy->pRuleList[iPos].dwFlags = ANY_SEVERITY;
+       m_pEventPolicy->pRuleList[iPos].pSituationAttrList = new StringMap;
 
    // Insert new row into rule list view
    m_wndRuleList.InsertRow(iPos);
index dc46ff1..9027a55 100644 (file)
@@ -106,6 +106,8 @@ int CTrapEditor::OnCreate(LPCREATESTRUCT lpCreateStruct)
    m_wndListCtrl.InsertColumn(2, _T("Event"), LVCFMT_LEFT, 200);
    m_wndListCtrl.InsertColumn(3, _T("Description"), LVCFMT_LEFT, 250);
 
+       LoadListCtrlColumns(m_wndListCtrl, _T("TrapEditor"), _T("ListCtrl"));
+
    PostMessage(WM_COMMAND, ID_VIEW_REFRESH, 0);
 
        return 0;
@@ -118,6 +120,7 @@ int CTrapEditor::OnCreate(LPCREATESTRUCT lpCreateStruct)
 
 void CTrapEditor::OnDestroy() 
 {
+       SaveListCtrlColumns(m_wndListCtrl, _T("TrapEditor"), _T("ListCtrl"));
    theApp.OnViewDestroy(VIEW_TRAP_EDITOR, this);
        CMDIChildWnd::OnDestroy();
 }
index cb222ce..efc3212 100644 (file)
@@ -19,10 +19,14 @@ IMPLEMENT_DYNCREATE(CUserEditor, CMDIChildWnd)
 CUserEditor::CUserEditor()
 {
    m_dwCurrentUser = INVALID_UID;
+   m_iSortMode = theApp.GetProfileInt(_T("UserEditor"), _T("SortMode"), 0);
+   m_iSortDir = theApp.GetProfileInt(_T("UserEditor"), _T("SortDir"), 1);
 }
 
 CUserEditor::~CUserEditor()
 {
+   theApp.WriteProfileInt(_T("UserEditor"), _T("SortMode"), m_iSortMode);
+   theApp.WriteProfileInt(_T("UserEditor"), _T("SortDir"), m_iSortDir);
 }
 
 
@@ -47,6 +51,7 @@ BEGIN_MESSAGE_MAP(CUserEditor, CMDIChildWnd)
    ON_MESSAGE(NXCM_USERDB_CHANGE, OnUserDBChange)
        ON_NOTIFY(NM_DBLCLK, IDC_LIST_VIEW, OnListViewDblClk)
        ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_VIEW, OnListViewItemChange)
+       ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST_VIEW, OnListViewColumnClick)
 END_MESSAGE_MAP()
 
 /////////////////////////////////////////////////////////////////////////////
@@ -80,6 +85,7 @@ void CUserEditor::OnClose()
 
 void CUserEditor::OnDestroy() 
 {
+       SaveListCtrlColumns(m_wndListCtrl, _T("UserEditor"), _T("ListCtrl"));
    theApp.OnViewDestroy(VIEW_USER_MANAGER, this);
        CMDIChildWnd::OnDestroy();
 }
@@ -92,7 +98,6 @@ void CUserEditor::OnDestroy()
 int CUserEditor::OnCreate(LPCREATESTRUCT lpCreateStruct) 
 {
    RECT rect;
-   CImageList *pImageList;
 
        if (CMDIChildWnd::OnCreate(lpCreateStruct) == -1)
                return -1;
@@ -101,24 +106,31 @@ int CUserEditor::OnCreate(LPCREATESTRUCT lpCreateStruct)
        
    // Create list view control
    GetClientRect(&rect);
-   m_wndListCtrl.Create(WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL, rect, this, IDC_LIST_VIEW);
+   m_wndListCtrl.Create(WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_SHAREIMAGELISTS, rect, this, IDC_LIST_VIEW);
    m_wndListCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
    m_wndListCtrl.SetHoverTime(0x7FFFFFFF);
 
    // Create image list
-   pImageList = new CImageList;
-   pImageList->Create(16, 16, ILC_COLOR8 | ILC_MASK, 8, 8);
-   pImageList->Add(AfxGetApp()->LoadIcon(IDI_USER));
-   pImageList->Add(AfxGetApp()->LoadIcon(IDI_USER_GROUP));
-   pImageList->Add(AfxGetApp()->LoadIcon(IDI_EVERYONE));
-   pImageList->Add(AfxGetApp()->LoadIcon(IDI_OVL_STATUS_CRITICAL));
-   pImageList->SetOverlayImage(3, 1);
-   m_wndListCtrl.SetImageList(pImageList, LVSIL_SMALL);
+   m_imageList.Create(16, 16, ILC_COLOR8 | ILC_MASK, 8, 8);
+   m_imageList.Add(AfxGetApp()->LoadIcon(IDI_USER));
+   m_imageList.Add(AfxGetApp()->LoadIcon(IDI_USER_GROUP));
+   m_imageList.Add(AfxGetApp()->LoadIcon(IDI_EVERYONE));
+   m_imageList.Add(AfxGetApp()->LoadIcon(IDI_OVL_STATUS_CRITICAL));
+   m_iSortImageBase = m_imageList.GetImageCount();
+   m_imageList.Add(theApp.LoadIcon(IDI_SORT_UP));
+   m_imageList.Add(theApp.LoadIcon(IDI_SORT_DOWN));
+   m_imageList.SetOverlayImage(3, 1);
+   m_wndListCtrl.SetImageList(&m_imageList, LVSIL_SMALL);
 
    // Setup columns
-   m_wndListCtrl.InsertColumn(0, _T("Name"), LVCFMT_LEFT, 100);
-   m_wndListCtrl.InsertColumn(1, _T("Full Name"), LVCFMT_LEFT, 170);
-   m_wndListCtrl.InsertColumn(2, _T("Description"), LVCFMT_LEFT, 300);
+   m_wndListCtrl.InsertColumn(0, _T("ID"), LVCFMT_LEFT, 85);
+   m_wndListCtrl.InsertColumn(1, _T("Name"), LVCFMT_LEFT, 100);
+   m_wndListCtrl.InsertColumn(2, _T("Type"), LVCFMT_LEFT, 65);
+   m_wndListCtrl.InsertColumn(3, _T("Full Name"), LVCFMT_LEFT, 170);
+   m_wndListCtrl.InsertColumn(4, _T("Description"), LVCFMT_LEFT, 300);
+   m_wndListCtrl.InsertColumn(5, _T("GUID"), LVCFMT_LEFT, 230);
+
+       LoadListCtrlColumns(m_wndListCtrl, _T("UserEditor"), _T("ListCtrl"));
 
    PostMessage(WM_COMMAND, ID_VIEW_REFRESH, 0);
 
@@ -155,14 +167,19 @@ void CUserEditor::OnSize(UINT nType, int cx, int cy)
 int CUserEditor::AddListItem(NXC_USER *pUser)
 {
    int iItem;
+       TCHAR buffer[256];
 
-   iItem = m_wndListCtrl.InsertItem(0x7FFFFFFF, pUser->szName,
+       _sntprintf(buffer, 256, _T("%08X"), pUser->dwId);
+   iItem = m_wndListCtrl.InsertItem(0x7FFFFFFF, buffer,
                  (pUser->dwId == GROUP_EVERYONE) ? 2 : ((pUser->dwId & GROUP_FLAG) ? 1 : 0));
    if (iItem != -1)
    {
       m_wndListCtrl.SetItemData(iItem, pUser->dwId);
-      m_wndListCtrl.SetItemText(iItem, 1, pUser->szFullName);
-      m_wndListCtrl.SetItemText(iItem, 2, pUser->szDescription);
+      m_wndListCtrl.SetItemText(iItem, 1, pUser->szName);
+      m_wndListCtrl.SetItemText(iItem, 2, (pUser->dwId & GROUP_FLAG) ? _T("Group") : _T("User"));
+      m_wndListCtrl.SetItemText(iItem, 3, pUser->szFullName);
+      m_wndListCtrl.SetItemText(iItem, 4, pUser->szDescription);
+      m_wndListCtrl.SetItemText(iItem, 5, uuid_to_string(pUser->guid, buffer));
       m_wndListCtrl.SetItemState(iItem, INDEXTOOVERLAYMASK(pUser->wFlags & UF_DISABLED ? 1 : 0), LVIS_OVERLAYMASK);
    }
    return iItem;
@@ -186,6 +203,7 @@ void CUserEditor::OnViewRefresh()
       for(i = 0; i < dwNumUsers; i++)
          if (!(pUserList[i].wFlags & UF_DELETED))
             AddListItem(&pUserList[i]);
+               SortList();
    }
 }
 
@@ -261,6 +279,8 @@ void CUserEditor::CreateUserObject(const TCHAR *pszName, BOOL bIsGroup, BOOL bSh
       m_wndListCtrl.SetItemState(iItem, LVIS_SELECTED | LVIS_FOCUSED, 
                                  LVIS_SELECTED | LVIS_FOCUSED);
 
+               SortList();
+
       if (bShowProp)
          PostMessage(WM_COMMAND, ID_USER_PROPERTIES, 0);
    }
@@ -303,10 +323,14 @@ void CUserEditor::OnUserDBChange(int iCode, NXC_USER *pUserInfo)
          }
          else
          {
-            m_wndListCtrl.SetItemText(iItem, 0, pUserInfo->szName);
-            m_wndListCtrl.SetItemText(iItem, 1, pUserInfo->szFullName);
-            m_wndListCtrl.SetItemText(iItem, 2, pUserInfo->szDescription);
-            m_wndListCtrl.SetItemState(iItem, INDEXTOOVERLAYMASK(pUserInfo->wFlags & UF_DISABLED ? 1 : 0), LVIS_OVERLAYMASK);
+                               TCHAR buffer[64];
+
+                               m_wndListCtrl.SetItemText(iItem, 1, pUserInfo->szName);
+                               m_wndListCtrl.SetItemText(iItem, 2, (pUserInfo->dwId & GROUP_FLAG) ? _T("Group") : _T("User"));
+                               m_wndListCtrl.SetItemText(iItem, 3, pUserInfo->szFullName);
+                               m_wndListCtrl.SetItemText(iItem, 4, pUserInfo->szDescription);
+                               m_wndListCtrl.SetItemText(iItem, 5, uuid_to_string(pUserInfo->guid, buffer));
+                               m_wndListCtrl.SetItemState(iItem, INDEXTOOVERLAYMASK(pUserInfo->wFlags & UF_DISABLED ? 1 : 0), LVIS_OVERLAYMASK);
          }
          break;
       case USER_DB_DELETE:
@@ -631,3 +655,98 @@ void CUserEditor::OnUpdateUserSetpassword(CCmdUI* pCmdUI)
 {
    pCmdUI->Enable((m_dwCurrentUser != INVALID_UID) && (!(m_dwCurrentUser & GROUP_FLAG)));
 }
+
+
+//
+// User comparision procedure for sorting
+//
+
+static int CALLBACK UserCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+   CUserEditor *pWnd = (CUserEditor *)lParamSort;
+   NXC_USER *pUser1, *pUser2;
+       TCHAR guid1[64], guid2[64];
+   int iResult;
+   
+   pUser1 = NXCFindUserById(g_hSession, lParam1);
+   pUser2 = NXCFindUserById(g_hSession, lParam2);
+
+       if ((pUser1 == NULL) || (pUser2 == NULL))
+       {
+               theApp.DebugPrintf(_T("WARNING: pUser == NULL in UserCompareProc() !!!"));
+               return 0;
+       }
+   
+   switch(pWnd->GetSortMode())
+   {
+      case 0:     // ID
+         iResult = COMPARE_NUMBERS(pUser1->dwId, pUser2->dwId);
+         break;
+      case 1:     // Name
+         iResult = _tcsicmp(pUser1->szName, pUser2->szName);
+         break;
+      case 2:     // Type
+         iResult = COMPARE_NUMBERS(pUser1->dwId & GROUP_FLAG, pUser2->dwId & GROUP_FLAG);
+         break;
+      case 3:     // Full name
+         iResult = _tcsicmp(pUser1->szFullName, pUser2->szFullName);
+         break;
+      case 4:     // Description
+         iResult = _tcsicmp(pUser1->szDescription, pUser2->szDescription);
+         break;
+      case 5:     // GUID
+         iResult = _tcsicmp(uuid_to_string(pUser1->guid, guid1), uuid_to_string(pUser2->guid, guid2));
+         break;
+      default:
+         iResult = 0;
+         break;
+   }
+
+   return iResult * pWnd->GetSortDir();
+}
+
+
+//
+// Sort user list
+//
+
+void CUserEditor::SortList()
+{
+   LVCOLUMN lvc;
+
+   m_wndListCtrl.SortItems(UserCompareProc, (LPARAM)this);
+   lvc.mask = LVCF_IMAGE | LVCF_FMT;
+   lvc.fmt = LVCFMT_LEFT | LVCFMT_IMAGE | LVCFMT_BITMAP_ON_RIGHT;
+   lvc.iImage = (m_iSortDir == 1) ? m_iSortImageBase : m_iSortImageBase + 1;
+   m_wndListCtrl.SetColumn(m_iSortMode, &lvc);
+}
+
+
+//
+// WM_NOTIFY::LVN_COLUMNCLICK message handler
+//
+
+void CUserEditor::OnListViewColumnClick(LPNMLISTVIEW pNMHDR, LRESULT *pResult)
+{
+   LVCOLUMN lvCol;
+
+   // Unmark old sorting column
+   lvCol.mask = LVCF_FMT;
+   lvCol.fmt = LVCFMT_LEFT;
+   m_wndListCtrl.SetColumn(m_iSortMode, &lvCol);
+
+   // Change current sort mode and resort list
+   if (m_iSortMode == pNMHDR->iSubItem)
+   {
+      // Same column, change sort direction
+      m_iSortDir = -m_iSortDir;
+   }
+   else
+   {
+      // Another sorting column
+      m_iSortMode = pNMHDR->iSubItem;
+   }
+   SortList();
+   
+   *pResult = 0;
+}
index f4014d6..71b040f 100644 (file)
@@ -38,6 +38,11 @@ public:
 
 // Implementation
 protected:
+       void SortList();
+       int m_iSortDir;
+       int m_iSortMode;
+       int m_iSortImageBase;
+       CImageList m_imageList;
        DWORD m_dwCurrentUser;
        CListCtrl m_wndListCtrl;
        virtual ~CUserEditor();
@@ -63,9 +68,14 @@ protected:
    afx_msg void OnUserDBChange(int iCode, NXC_USER *pUserInfo);
    afx_msg void OnListViewDblClk(LPNMITEMACTIVATE pNMHDR, LRESULT *pResult);
    afx_msg void OnListViewItemChange(LPNMLISTVIEW pNMHDR, LRESULT *pResult);
+   afx_msg void OnListViewColumnClick(LPNMLISTVIEW pNMHDR, LRESULT *pResult);
        DECLARE_MESSAGE_MAP()
 private:
        int AddListItem(NXC_USER *pUser);
+
+public:
+   int GetSortMode(void) { return m_iSortMode; }
+   int GetSortDir(void) { return m_iSortDir; }
 };
 
 /////////////////////////////////////////////////////////////////////////////
index 94821c2..7cfa117 100644 (file)
@@ -147,36 +147,36 @@ void uuid_unpack(uuid_t in, struct uuid *uu)
 // Parse UUID
 //
 
-int LIBNETXMS_EXPORTABLE uuid_parse(char *in, uuid_t uu)
+int LIBNETXMS_EXPORTABLE uuid_parse(TCHAR *in, uuid_t uu)
 {
        struct uuid uuid;
        int i;
-       char *cp, buf[3];
+       TCHAR *cp, buf[3];
 
-       if (strlen(in) != 36)
+       if (_tcslen(in) != 36)
                return -1;
        for (i=0, cp = in; i <= 36; i++,cp++) {
                if ((i == 8) || (i == 13) || (i == 18) ||
                    (i == 23))
-                       if (*cp == '-')
+                       if (*cp == _T('-'))
                                continue;
-               if (i== 36)
+               if (i == 36)
                        if (*cp == 0)
                                continue;
-               if (!isxdigit((int) *cp))
+               if (!_istxdigit(*cp))
                        return -1;
        }
-       uuid.time_low = strtoul(in, NULL, 16);
-       uuid.time_mid = (WORD)strtoul(in + 9, NULL, 16);
-       uuid.time_hi_and_version = (WORD)strtoul(in + 14, NULL, 16);
-       uuid.clock_seq = (WORD)strtoul(in + 19, NULL, 16);
+       uuid.time_low = _tcstoul(in, NULL, 16);
+       uuid.time_mid = (WORD)_tcstoul(in + 9, NULL, 16);
+       uuid.time_hi_and_version = (WORD)_tcstoul(in + 14, NULL, 16);
+       uuid.clock_seq = (WORD)_tcstoul(in + 19, NULL, 16);
        cp = in + 24;
        buf[2] = 0;
        for(i = 0; i < 6; i++)
    {
                buf[0] = *cp++;
                buf[1] = *cp++;
-               uuid.node[i] = (BYTE)strtoul(buf, NULL, 16);
+               uuid.node[i] = (BYTE)_tcstoul(buf, NULL, 16);
        }
        
        uuid_pack(&uuid, uu);
@@ -188,13 +188,13 @@ int LIBNETXMS_EXPORTABLE uuid_parse(char *in, uuid_t uu)
 // Convert packed UUID to string
 //
 
-char LIBNETXMS_EXPORTABLE *uuid_to_string(uuid_t uu, char *out)
+TCHAR LIBNETXMS_EXPORTABLE *uuid_to_string(uuid_t uu, TCHAR *out)
 {
        struct uuid uuid;
 
        uuid_unpack(uu, &uuid);
-       sprintf(out,
-               "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+       _sntprintf(out, 64,
+               _T("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"),
                uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
                uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
                uuid.node[0], uuid.node[1], uuid.node[2],
index f21d6fa..d7a44b7 100644 (file)
@@ -130,7 +130,7 @@ BOOL Condition::CreateFromDB(DWORD dwId)
 
    // Load DCI map
    _sntprintf(szQuery, 512, _T("SELECT dci_id,node_id,dci_func,num_polls ")
-                            _T("FROM cond_dci_map WHERE condition_id=%d"), dwId);
+                            _T("FROM cond_dci_map WHERE condition_id=%d ORDER BY sequence_number"), dwId);
    hResult = DBSelect(g_hCoreDB, szQuery);
    if (hResult == NULL)
       return FALSE;     // Query failed
@@ -206,9 +206,9 @@ BOOL Condition::SaveToDB(DB_HANDLE hdb)
    DBQuery(hdb, pszQuery);
    for(i = 0; i < m_dwDCICount; i++)
    {
-      _stprintf(pszQuery, _T("INSERT INTO cond_dci_map (condition_id,dci_id,node_id,")
-                          _T("dci_func,num_polls) VALUES (%d,%d,%d,%d,%d)"),
-                m_dwId, m_pDCIList[i].dwId, m_pDCIList[i].dwNodeId,
+      _stprintf(pszQuery, _T("INSERT INTO cond_dci_map (condition_id,sequence_number,dci_id,node_id,")
+                          _T("dci_func,num_polls) VALUES (%d,%d,%d,%d,%d,%d)"),
+                m_dwId, i, m_pDCIList[i].dwId, m_pDCIList[i].dwNodeId,
                 m_pDCIList[i].nFunction, m_pDCIList[i].nPolls);
       DBQuery(hdb, pszQuery);
    }
index f3561d5..5c7b58f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: node.cpp,v 1.199 2008-02-17 11:07:57 victor Exp $ */
+/* $Id: node.cpp,v 1.200 2008-03-06 00:04:19 victor Exp $ */
 /* 
 ** NetXMS - Network Management System
 ** Copyright (C) 2003, 2004, 2005, 2006, 2007 Victor Kirhenshtein
@@ -2601,6 +2601,7 @@ void Node::PrepareForDeletion(void)
       UnlockData();
       ThreadSleepMs(100);
    }
+       Template::PrepareForDeletion();
 }
 
 
index 89f192e..8135c96 100644 (file)
@@ -133,6 +133,7 @@ static THREAD_RESULT THREAD_CALL ApplyTemplateThread(void *pArg)
 
       if (bSuccess)
       {
+                       pInfo->pTemplate->DecRefCount();
          free(pInfo);
       }
       else
index 43aa9b4..7ed3ebc 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: template.cpp,v 1.40 2008-01-29 21:12:51 victor Exp $ */
+/* $Id: template.cpp,v 1.41 2008-03-06 00:04:19 victor Exp $ */
 /* 
 ** NetXMS - Network Management System
 ** Copyright (C) 2003, 2004, 2005, 2006, 2007 Victor Kirhenshtein
@@ -585,7 +585,7 @@ DCItem *Template::GetItemByIndex(DWORD dwIndex)
 
 void Template::CalculateCompoundStatus(BOOL bForcedRecalc)
 {
-   m_iStatus = STATUS_UNMANAGED;
+   m_iStatus = STATUS_NORMAL;
 }
 
 
@@ -892,3 +892,25 @@ void Template::AssociateItems(void)
                m_ppItems[i]->ChangeBinding(0, this, FALSE);
        UnlockData();
 }
+
+
+//
+// Prepare template for deletion
+//
+
+void Template::PrepareForDeletion(void)
+{
+       if (Type() == OBJECT_TEMPLATE)
+       {
+               DWORD i;
+       
+               LockChildList(FALSE);
+               for(i = 0; i < m_dwChildCount; i++)
+               {
+                       if (m_pChildList[i]->Type() == OBJECT_NODE)
+                               QueueRemoveFromNode(m_pChildList[i]->Id(), TRUE);
+               }
+               UnlockChildList();
+       }
+       NetObj::PrepareForDeletion();
+}
index 969d2e7..d3c2b7e 100644 (file)
@@ -344,6 +344,8 @@ protected:
    BOOL m_bDCIListModified;
    TCHAR m_szCurrDCIOwner[MAX_SESSION_NAME];
 
+   virtual void PrepareForDeletion(void);
+
    void LoadItemsFromDB(void);
    void DestroyItems(void);
        void ValidateDCIList(DCI_CFG *cfg);
index cc37d31..d55b84a 100644 (file)
@@ -164,6 +164,9 @@ BOOL SQLQuery(const TCHAR *pszQuery)
 {
    BOOL bResult;
 
+       if (*pszQuery == 0)
+               return TRUE;
+
    if (g_bTrace)
       ShowQuery(pszQuery);
 
index 427cf1e..0333b1b 100644 (file)
@@ -87,6 +87,68 @@ static BOOL CreateConfigParam(const TCHAR *pszName, const TCHAR *pszValue,
 
 
 //
+// Upgrade from V76 to V77
+//
+
+static BOOL H_UpgradeFromV76(void)
+{
+       DB_RESULT hResult;
+       int i, count, seq;
+       DWORD id, lastId;
+       TCHAR query[1024];
+
+       hResult = SQLSelect(_T("SELECT condition_id,dci_id,node_id,dci_func,num_polls FROM cond_dci_map ORDER BY condition_id"));
+       if (hResult == NULL)
+               if (!g_bIgnoreErrors)
+                       return FALSE;
+
+       if (!SQLQuery(_T("DROP TABLE cond_dci_map")))
+               if (!g_bIgnoreErrors)
+                       goto error;
+
+       if (!CreateTable(_T("CREATE TABLE cond_dci_map (")
+                        _T("condition_id integer not null,")
+                        _T("sequence_number integer not null,")
+                        _T("dci_id integer not null,")
+                        _T("node_id integer not null,")
+                        _T("dci_func integer not null,")
+                        _T("num_polls integer not null,")
+                        _T("PRIMARY KEY(condition_id,sequence_number))")))
+               if (!g_bIgnoreErrors)
+                       goto error;
+
+       count = DBGetNumRows(hResult);
+       for(i = 0, seq = 0, lastId = 0; i < count; i++, seq++)
+       {
+               id = DBGetFieldULong(hResult, i, 0);
+               if (id != lastId)
+               {
+                       seq = 0;
+                       lastId = id;
+               }
+               _sntprintf(query, 1024, _T("INSERT INTO cond_dci_map (condition_id,sequence_number,dci_id,node_id,dci_func,num_polls) VALUES (%d,%d,%d,%d,%d,%d)"),
+                          id, seq, DBGetFieldULong(hResult, i, 1), DBGetFieldULong(hResult, i, 2),
+                                         DBGetFieldULong(hResult, i, 3), DBGetFieldULong(hResult, i, 4));
+               if (!SQLQuery(query))
+                       if (!g_bIgnoreErrors)
+                               goto error;
+       }
+
+       DBFreeResult(hResult);
+
+       if (!SQLQuery(_T("UPDATE config SET var_value='77' WHERE var_name='DBFormatVersion'")))
+      if (!g_bIgnoreErrors)
+         return FALSE;
+
+   return TRUE;
+
+error:
+       DBFreeResult(hResult);
+       return FALSE;
+}
+
+
+//
 // Upgrade from V75 to V76
 //
 
@@ -3359,6 +3421,7 @@ static struct
    { 73, H_UpgradeFromV73 },
    { 74, H_UpgradeFromV74 },
    { 75, H_UpgradeFromV75 },
+   { 76, H_UpgradeFromV76 },
    { 0, NULL }
 };