- Fixed bugs number 195 and 203
[public/netxms.git] / src / console / win32 / ActionEditor.cpp
1 // ActionEditor.cpp : implementation file
2 //
3
4 #include "stdafx.h"
5 #include "nxcon.h"
6 #include "ActionEditor.h"
7 #include "NewActionDlg.h"
8 #include "EditActionDlg.h"
9
10 #ifdef _DEBUG
11 #define new DEBUG_NEW
12 #undef THIS_FILE
13 static char THIS_FILE[] = __FILE__;
14 #endif
15
16 /////////////////////////////////////////////////////////////////////////////
17 // CActionEditor
18
19 IMPLEMENT_DYNCREATE(CActionEditor, CMDIChildWnd)
20
21 CActionEditor::CActionEditor()
22 {
23 m_iSortMode = theApp.GetProfileInt(_T("ActionEditor"), _T("SortMode"), 0);
24 m_iSortDir = theApp.GetProfileInt(_T("ActionEditor"), _T("SortDir"), 1);
25 }
26
27 CActionEditor::~CActionEditor()
28 {
29 theApp.WriteProfileInt(_T("ActionEditor"), _T("SortMode"), m_iSortMode);
30 theApp.WriteProfileInt(_T("ActionEditor"), _T("SortDir"), m_iSortDir);
31 }
32
33
34 BEGIN_MESSAGE_MAP(CActionEditor, CMDIChildWnd)
35 //{{AFX_MSG_MAP(CActionEditor)
36 ON_WM_CREATE()
37 ON_WM_DESTROY()
38 ON_WM_SETFOCUS()
39 ON_WM_SIZE()
40 ON_WM_CLOSE()
41 ON_COMMAND(ID_VIEW_REFRESH, OnViewRefresh)
42 ON_WM_CONTEXTMENU()
43 ON_UPDATE_COMMAND_UI(ID_ACTION_DELETE, OnUpdateActionDelete)
44 ON_UPDATE_COMMAND_UI(ID_ACTION_PROPERTIES, OnUpdateActionProperties)
45 ON_UPDATE_COMMAND_UI(ID_ACTION_RENAME, OnUpdateActionRename)
46 ON_COMMAND(ID_ACTION_NEW, OnActionNew)
47 ON_COMMAND(ID_ACTION_PROPERTIES, OnActionProperties)
48 ON_COMMAND(ID_ACTION_DELETE, OnActionDelete)
49 //}}AFX_MSG_MAP
50 ON_NOTIFY(NM_DBLCLK, IDC_LIST_VIEW, OnListViewDoubleClick)
51 ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST_VIEW, OnListViewColumnClick)
52 END_MESSAGE_MAP()
53
54 /////////////////////////////////////////////////////////////////////////////
55 // CActionEditor message handlers
56
57 BOOL CActionEditor::PreCreateWindow(CREATESTRUCT& cs)
58 {
59 if (cs.lpszClass == NULL)
60 cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,
61 NULL,
62 GetSysColorBrush(COLOR_WINDOW),
63 AfxGetApp()->LoadIcon(IDI_EXEC));
64 return CMDIChildWnd::PreCreateWindow(cs);
65 }
66
67
68 //
69 // WM_CREATE message handler
70 //
71
72 int CActionEditor::OnCreate(LPCREATESTRUCT lpCreateStruct)
73 {
74 RECT rect;
75
76 if (CMDIChildWnd::OnCreate(lpCreateStruct) == -1)
77 return -1;
78
79 theApp.OnViewCreate(VIEW_ACTION_EDITOR, this);
80
81 // Create list view control
82 GetClientRect(&rect);
83 m_wndListCtrl.Create(WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS, rect, this, IDC_LIST_VIEW);
84 m_wndListCtrl.SetExtendedStyle(LVS_EX_TRACKSELECT | LVS_EX_UNDERLINEHOT |
85 LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
86 m_wndListCtrl.SetHoverTime(0x7FFFFFFF);
87
88 // Create image list
89 m_imageList.Create(16, 16, ILC_COLOR8 | ILC_MASK, 8, 8);
90 m_imageList.Add(AfxGetApp()->LoadIcon(IDI_EXEC));
91 m_imageList.Add(AfxGetApp()->LoadIcon(IDI_REXEC));
92 m_imageList.Add(AfxGetApp()->LoadIcon(IDI_EMAIL));
93 m_imageList.Add(AfxGetApp()->LoadIcon(IDI_SMS));
94 m_iSortImageBase = m_imageList.GetImageCount();
95 m_imageList.Add(theApp.LoadIcon(IDI_SORT_UP));
96 m_imageList.Add(theApp.LoadIcon(IDI_SORT_DOWN));
97 m_wndListCtrl.SetImageList(&m_imageList, LVSIL_SMALL);
98
99 // Setup columns
100 m_wndListCtrl.InsertColumn(0, _T("Name"), LVCFMT_LEFT, 100);
101 m_wndListCtrl.InsertColumn(1, _T("Type"), LVCFMT_LEFT, 70);
102 m_wndListCtrl.InsertColumn(2, _T("Recipient"), LVCFMT_LEFT, 150);
103 m_wndListCtrl.InsertColumn(3, _T("Data"), LVCFMT_LEFT, 350);
104
105 LoadListCtrlColumns(m_wndListCtrl, _T("ActionEditor"), _T("ListCtrl"));
106
107 PostMessage(WM_COMMAND, ID_VIEW_REFRESH, 0);
108
109 return 0;
110 }
111
112
113 //
114 // WM_DESTROY message handler
115 //
116
117 void CActionEditor::OnDestroy()
118 {
119 SaveListCtrlColumns(m_wndListCtrl, _T("ActionEditor"), _T("ListCtrl"));
120 theApp.OnViewDestroy(VIEW_ACTION_EDITOR, this);
121 CMDIChildWnd::OnDestroy();
122 }
123
124
125 //
126 // WM_SETFOCUS message handler
127 //
128
129 void CActionEditor::OnSetFocus(CWnd* pOldWnd)
130 {
131 CMDIChildWnd::OnSetFocus(pOldWnd);
132
133 m_wndListCtrl.SetFocus();
134 }
135
136
137 //
138 // WM_SIZE message handler
139 //
140
141 void CActionEditor::OnSize(UINT nType, int cx, int cy)
142 {
143 CMDIChildWnd::OnSize(nType, cx, cy);
144
145 m_wndListCtrl.SetWindowPos(NULL, 0, 0, cx, cy, SWP_NOZORDER);
146 }
147
148
149 //
150 // WM_CLOSE message handler
151 //
152
153 void CActionEditor::OnClose()
154 {
155 DoRequestArg1(NXCUnlockActionDB, g_hSession, _T("Unlocking action configuration database..."));
156 CMDIChildWnd::OnClose();
157 }
158
159
160 //
161 // Handler for double-clicks in list view
162 //
163
164 void CActionEditor::OnListViewDoubleClick(NMITEMACTIVATE *pInfo, LRESULT *pResult)
165 {
166 PostMessage(WM_COMMAND, ID_ACTION_PROPERTIES, 0);
167 }
168
169
170 //
171 // WM_COMMAND::ID_VIEW_REFRESH message handler
172 //
173
174 void CActionEditor::OnViewRefresh()
175 {
176 DWORD i;
177
178 m_wndListCtrl.DeleteAllItems();
179 LockActions();
180 for(i = 0; i < g_dwNumActions; i++)
181 AddItem(&g_pActionList[i]);
182 SortList();
183 UnlockActions();
184 }
185
186
187 //
188 // WM_CONTEXTMENU message handler
189 //
190
191 void CActionEditor::OnContextMenu(CWnd* pWnd, CPoint point)
192 {
193 CMenu *pMenu;
194
195 pMenu = theApp.GetContextMenu(7);
196 pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this, NULL);
197 }
198
199
200 //
201 // Replace data in existing item
202 //
203
204 void CActionEditor::ReplaceItem(int iItem, NXC_ACTION *pAction)
205 {
206 if (iItem != -1)
207 {
208 m_wndListCtrl.SetItem(iItem, 0, LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM,
209 pAction->szName, pAction->iType, 0, 0, pAction->dwId);
210 m_wndListCtrl.SetItemText(iItem, 1, g_szActionType[pAction->iType]);
211 m_wndListCtrl.SetItemText(iItem, 2, pAction->szRcptAddr);
212 m_wndListCtrl.SetItemText(iItem, 3, pAction->pszData);
213 }
214
215 }
216
217
218 //
219 // Add new item to list
220 //
221
222 int CActionEditor::AddItem(NXC_ACTION *pAction)
223 {
224 int iIndex;
225
226 iIndex = m_wndListCtrl.InsertItem(0x7FFFFFFF, pAction->szName, pAction->iType);
227 if (iIndex != -1)
228 {
229 m_wndListCtrl.SetItemData(iIndex, pAction->dwId);
230 m_wndListCtrl.SetItemText(iIndex, 1, g_szActionType[pAction->iType]);
231 m_wndListCtrl.SetItemText(iIndex, 2, pAction->szRcptAddr);
232 m_wndListCtrl.SetItemText(iIndex, 3, pAction->pszData);
233 }
234 return iIndex;
235 }
236
237
238 //
239 // Update status for menu items
240 //
241
242 void CActionEditor::OnUpdateActionDelete(CCmdUI* pCmdUI)
243 {
244 pCmdUI->Enable(m_wndListCtrl.GetSelectedCount() > 0);
245 }
246
247 void CActionEditor::OnUpdateActionProperties(CCmdUI* pCmdUI)
248 {
249 pCmdUI->Enable(m_wndListCtrl.GetSelectedCount() == 1);
250 }
251
252 void CActionEditor::OnUpdateActionRename(CCmdUI* pCmdUI)
253 {
254 pCmdUI->Enable(m_wndListCtrl.GetSelectedCount() == 1);
255 }
256
257
258 //
259 // WM_COMMAND::ID_ACTION_NEW message handler
260 //
261
262 void CActionEditor::OnActionNew()
263 {
264 CNewActionDlg dlg;
265 DWORD i, dwActionId, dwResult;
266 int iItem;
267
268 if (dlg.DoModal() == IDOK)
269 {
270 dwResult = DoRequestArg3(NXCCreateAction, g_hSession, (void *)((LPCTSTR)dlg.m_strName),
271 &dwActionId, _T("Creating new action..."));
272 if (dwResult == RCC_SUCCESS)
273 {
274 LockActions();
275
276 // Check if we already received an update from server
277 for(i = 0; i < g_dwNumActions; i++)
278 if (g_pActionList[i].dwId == dwActionId)
279 break; // Already have this action in list
280 if (i == g_dwNumActions)
281 {
282 // Action still not in list, add it
283 g_dwNumActions++;
284 g_pActionList = (NXC_ACTION *)realloc(g_pActionList, sizeof(NXC_ACTION) * g_dwNumActions);
285 memset(&g_pActionList[i], 0, sizeof(NXC_ACTION));
286 g_pActionList[i].dwId = dwActionId;
287 g_pActionList[i].iType = ACTION_EXEC;
288 nx_strncpy(g_pActionList[i].szName, dlg.m_strName, MAX_OBJECT_NAME);
289 g_pActionList[i].pszData = _tcsdup(_T(""));
290 }
291
292 iItem = AddItem(&g_pActionList[i]);
293 SelectListViewItem(&m_wndListCtrl, iItem);
294 SortList();
295 PostMessage(WM_COMMAND, ID_ACTION_PROPERTIES, 0);
296
297 UnlockActions();
298 }
299 else
300 {
301 theApp.ErrorBox(dwResult, _T("Error creating action: %s"));
302 }
303 }
304 }
305
306
307 //
308 // WM_COMMAND::ID_ACTION_PROPERTIES message handler
309 //
310
311 void CActionEditor::OnActionProperties()
312 {
313 int iItem;
314
315 if (m_wndListCtrl.GetSelectedCount() == 1)
316 {
317 iItem = m_wndListCtrl.GetSelectionMark();
318 if (iItem != -1)
319 {
320 NXC_ACTION *pAction;
321
322 LockActions();
323
324 pAction = FindActionById(m_wndListCtrl.GetItemData(iItem));
325 if (pAction != NULL)
326 {
327 CEditActionDlg dlg;
328
329 dlg.m_iType = pAction->iType;
330 dlg.m_strData = pAction->pszData;
331 dlg.m_strName = pAction->szName;
332 dlg.m_strRcpt = pAction->szRcptAddr;
333 dlg.m_strSubject = pAction->szEmailSubject;
334 UnlockActions();
335
336 if (dlg.DoModal() == IDOK)
337 {
338 NXC_ACTION action;
339 DWORD dwResult;
340
341 memset(&action, 0, sizeof(NXC_ACTION));
342 action.dwId = m_wndListCtrl.GetItemData(iItem);
343 action.iType = dlg.m_iType;
344 action.pszData = _tcsdup((LPCTSTR)dlg.m_strData);
345 nx_strncpy(action.szEmailSubject, (LPCTSTR)dlg.m_strSubject, MAX_EMAIL_SUBJECT_LEN);
346 nx_strncpy(action.szName, (LPCTSTR)dlg.m_strName, MAX_OBJECT_NAME);
347 nx_strncpy(action.szRcptAddr, (LPCTSTR)dlg.m_strRcpt, MAX_RCPT_ADDR_LEN);
348
349 dwResult = DoRequestArg2(NXCModifyAction, g_hSession, &action,
350 _T("Updating action configuration..."));
351 if (dwResult == RCC_SUCCESS)
352 {
353 ReplaceItem(iItem, &action);
354 LockActions();
355 SortList();
356 UnlockActions();
357 }
358 else
359 {
360 theApp.ErrorBox(dwResult, _T("Error updating action configuration: %s"));
361 }
362 free(action.pszData);
363 }
364 }
365 else
366 {
367 UnlockActions();
368 MessageBox(_T("Internal error: cannot find requested action entry in list"), _T("Internal Error"), MB_OK | MB_ICONSTOP);
369 }
370 }
371 }
372 }
373
374
375 //
376 // Worker function for action deletion
377 //
378
379 static DWORD DeleteActions(DWORD dwNumActions, DWORD *pdwDeleteList, CListCtrl *pList)
380 {
381 DWORD i, dwResult = RCC_SUCCESS;
382 LVFINDINFO lvfi;
383 int iItem;
384
385 lvfi.flags = LVFI_PARAM;
386 for(i = 0; i < dwNumActions; i++)
387 {
388 dwResult = NXCDeleteAction(g_hSession, pdwDeleteList[i]);
389 if (dwResult == RCC_SUCCESS)
390 {
391 lvfi.lParam = pdwDeleteList[i];
392 iItem = pList->FindItem(&lvfi);
393 if (iItem != -1)
394 pList->DeleteItem(iItem);
395 }
396 else
397 {
398 break;
399 }
400 }
401 return dwResult;
402 }
403
404
405 //
406 // WM_COMMAND::ID_ACTION_DELETE message handler
407 //
408
409 void CActionEditor::OnActionDelete()
410 {
411 int iItem;
412 DWORD i, dwNumItems, *pdwDeleteList, dwResult;
413
414 dwNumItems = m_wndListCtrl.GetSelectedCount();
415 if (dwNumItems > 0)
416 {
417 pdwDeleteList = (DWORD *)malloc(sizeof(DWORD) * dwNumItems);
418 iItem = m_wndListCtrl.GetNextItem(-1, LVIS_SELECTED);
419 for(i = 0; (i < dwNumItems) && (iItem != -1); i++)
420 {
421 pdwDeleteList[i] = m_wndListCtrl.GetItemData(iItem);
422 iItem = m_wndListCtrl.GetNextItem(iItem, LVIS_SELECTED);
423 }
424
425 dwResult = DoRequestArg3(DeleteActions, (void *)dwNumItems, pdwDeleteList,
426 &m_wndListCtrl, _T("Deleting action(s)..."));
427 if (dwResult != RCC_SUCCESS)
428 theApp.ErrorBox(dwResult, _T("Error deleting action: %s"));
429 free(pdwDeleteList);
430 }
431 }
432
433
434 //
435 // Action comparision procedure for sorting
436 //
437
438 static int CALLBACK ActionCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
439 {
440 CActionEditor *pWnd = (CActionEditor *)lParamSort;
441 NXC_ACTION *pAction1, *pAction2;
442 int iResult;
443
444 pAction1 = FindActionById(lParam1);
445 pAction2 = FindActionById(lParam2);
446
447 if ((pAction1 == NULL) || (pAction2 == NULL))
448 {
449 theApp.DebugPrintf(_T("WARNING: pAction == NULL in ActionCompareProc() !!!"));
450 return 0;
451 }
452
453 switch(pWnd->GetSortMode())
454 {
455 case 0: // Name
456 iResult = _tcsicmp(pAction1->szName, pAction2->szName);
457 break;
458 case 1: // Type
459 iResult = _tcsicmp(g_szActionType[pAction1->iType], g_szActionType[pAction2->iType]);
460 break;
461 case 2: // Recipient
462 iResult = _tcsicmp(pAction1->szRcptAddr, pAction2->szRcptAddr);
463 break;
464 case 3: // Data
465 iResult = _tcsicmp(pAction1->pszData, pAction2->pszData);
466 break;
467 default:
468 iResult = 0;
469 break;
470 }
471
472 return iResult * pWnd->GetSortDir();
473 }
474
475
476 //
477 // Sort action list
478 //
479
480 void CActionEditor::SortList()
481 {
482 LVCOLUMN lvc;
483
484 m_wndListCtrl.SortItems(ActionCompareProc, (LPARAM)this);
485 lvc.mask = LVCF_IMAGE | LVCF_FMT;
486 lvc.fmt = LVCFMT_LEFT | LVCFMT_IMAGE | LVCFMT_BITMAP_ON_RIGHT;
487 lvc.iImage = (m_iSortDir == 1) ? m_iSortImageBase : m_iSortImageBase + 1;
488 m_wndListCtrl.SetColumn(m_iSortMode, &lvc);
489 }
490
491
492 //
493 // WM_NOTIFY::LVN_COLUMNCLICK message handler
494 //
495
496 void CActionEditor::OnListViewColumnClick(LPNMLISTVIEW pNMHDR, LRESULT *pResult)
497 {
498 LVCOLUMN lvCol;
499
500 // Unmark old sorting column
501 lvCol.mask = LVCF_FMT;
502 lvCol.fmt = LVCFMT_LEFT;
503 m_wndListCtrl.SetColumn(m_iSortMode, &lvCol);
504
505 // Change current sort mode and resort list
506 if (m_iSortMode == pNMHDR->iSubItem)
507 {
508 // Same column, change sort direction
509 m_iSortDir = -m_iSortDir;
510 }
511 else
512 {
513 // Another sorting column
514 m_iSortMode = pNMHDR->iSubItem;
515 }
516
517 LockActions();
518 SortList();
519 UnlockActions();
520
521 *pResult = 0;
522 }