Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1193 lines
34 KiB

  1. // rootprop.cpp - Root Property Page Implementation
  2. #include "stdafx.h"
  3. #include "resource.h"
  4. #include "rootprop.h"
  5. #include "compdata.h"
  6. #include "scopenode.h"
  7. #include "wizards.h"
  8. #include "query.h"
  9. #include "cmndlgs.h"
  10. #include "util.h"
  11. #include "namemap.h"
  12. #include <windowsx.h>
  13. #include <algorithm>
  14. int GetDateTimeString(FILETIME* pftime, LPWSTR pszBuf, int cBuf);
  15. void LoadObjectCB(CComboBox& ComboBox, CEditObjList& ObjList);
  16. ///////////////////////////////////////////////////////////////////////////////////////////
  17. // CRootGeneralPage
  18. LRESULT CRootGeneralPage::OnInitDialog(UINT mMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  19. {
  20. CRootNode* pRootNode = m_ObjList.RootNode();
  21. ASSERT(pRootNode != NULL);
  22. if( !pRootNode ) return 0;
  23. Edit_LimitText(GetDlgItem(IDC_COMMENTS),255);
  24. SetDlgItemText( IDC_NAME, pRootNode->GetName() );
  25. tstring strComment;
  26. pRootNode->GetComment(strComment);
  27. SetDlgItemText( IDC_COMMENTS, strComment.c_str() );
  28. FILETIME ftime;
  29. WCHAR szDateTime[32];
  30. pRootNode->GetCreateTime(&ftime);
  31. if( GetDateTimeString(&ftime, szDateTime, lengthof(szDateTime)) )
  32. {
  33. SetDlgItemText( IDC_CREATED, szDateTime );
  34. }
  35. pRootNode->GetModifyTime(&ftime);
  36. if( GetDateTimeString(&ftime, szDateTime, lengthof(szDateTime)) )
  37. {
  38. SetDlgItemText( IDC_MODIFIED, szDateTime );
  39. }
  40. m_bChgComment = FALSE;
  41. return TRUE;
  42. }
  43. LRESULT CRootGeneralPage::OnChange(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
  44. {
  45. SetModified(TRUE);
  46. m_bChgComment = TRUE;
  47. return 0;
  48. }
  49. //------------------------------------------------------------------------------------
  50. // CRootGeneralPage::OnClose
  51. //
  52. // This method is invoked when the edit box receives an Esc char. The method converts
  53. // the WM_CLOSE message into a command to close the property sheet. Otherwise the
  54. // WM_CLOSE message has no effect.
  55. //------------------------------------------------------------------------------------
  56. LRESULT CRootGeneralPage::OnClose( UINT mMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  57. {
  58. // Simulate press of Cancel button
  59. ::PropSheet_PressButton(GetParent(), PSBTN_CANCEL);
  60. return 0;
  61. }
  62. BOOL CRootGeneralPage::OnSetActive()
  63. {
  64. m_ObjList.PageActive(m_hWnd);
  65. return TRUE;
  66. }
  67. BOOL CRootGeneralPage::OnApply()
  68. {
  69. if (m_bChgComment)
  70. {
  71. CRootNode* pRootNode = m_ObjList.RootNode();
  72. ASSERT(pRootNode);
  73. if( !pRootNode ) return FALSE;
  74. int cLen = ::GetWindowTextLength(GetDlgItem(IDC_COMMENTS));
  75. LPWSTR szTemp = new WCHAR[(cLen+1)];
  76. if( !szTemp ) return FALSE;
  77. int cLen1 = ::GetWindowText(GetDlgItem(IDC_COMMENTS), szTemp, cLen+1);
  78. ASSERT(cLen == cLen1);
  79. pRootNode->SetComment(szTemp);
  80. pRootNode->UpdateModifyTime();
  81. m_bChgComment = FALSE;
  82. delete [] szTemp;
  83. }
  84. return m_ObjList.ApplyChanges(m_hWnd);
  85. }
  86. ///////////////////////////////////////////////////////////////////////////////////////////
  87. // CRootMenuPage
  88. CRootMenuPage::~CRootMenuPage()
  89. {
  90. m_ObjectCB.Detach();
  91. m_MenuLV.Detach();
  92. m_ObjList.Release();
  93. }
  94. LRESULT CRootMenuPage::OnInitDialog( UINT mMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  95. {
  96. m_ObjectCB.Attach(GetDlgItem(IDC_OBJECTLIST));
  97. m_MenuLV.Attach(GetDlgItem(IDC_MENULIST));
  98. m_itObjSelect = NULL;
  99. ::ConfigSingleColumnListView(GetDlgItem(IDC_MENULIST));
  100. return TRUE;
  101. }
  102. BOOL CRootMenuPage::OnSetActive()
  103. {
  104. m_ObjList.PageActive(m_hWnd);
  105. LoadObjectCB(m_ObjectCB, m_ObjList);
  106. // if object was previously selected
  107. if (m_itObjSelect != NULL)
  108. {
  109. // find the edit object by name because it may have been moved or deleted
  110. // while another page was active
  111. m_itObjSelect = m_ObjList.FindObject(m_strObjSelect.c_str());
  112. if (m_itObjSelect != NULL && m_itObjSelect->IsDeleted())
  113. m_itObjSelect = NULL;
  114. }
  115. // if object still around, reselect it in the combo box
  116. if (m_itObjSelect != NULL)
  117. {
  118. DisplayNameMap* pNameMap = DisplayNames::GetClassMap();
  119. ASSERT( pNameMap );
  120. if( !pNameMap ) return FALSE;
  121. int iSel = m_ObjectCB.FindStringExact(-1, pNameMap->GetAttributeDisplayName(m_strObjSelect.c_str()));
  122. ASSERT(iSel != CB_ERR);
  123. m_ObjectCB.SetCurSel(iSel);
  124. }
  125. else if (m_ObjectCB.GetCount() > 0)
  126. {
  127. // default to the first object and update the columns
  128. m_ObjectCB.SetCurSel(0);
  129. void* pv = m_ObjectCB.GetItemDataPtr(0);
  130. m_itObjSelect = *(EditObjIter*)&pv;
  131. m_strObjSelect = m_itObjSelect->Name();
  132. DisplayMenus();
  133. }
  134. else
  135. {
  136. DisplayMenus();
  137. }
  138. return TRUE;
  139. }
  140. LRESULT CRootMenuPage::OnObjectSelect( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
  141. {
  142. int iItem = m_ObjectCB.GetCurSel();
  143. // Double-clicking an empty combo box will call this with no selection
  144. if (iItem >= 0)
  145. {
  146. void* pv = m_ObjectCB.GetItemDataPtr(iItem);
  147. m_itObjSelect = *(EditObjIter*)&pv;
  148. m_strObjSelect = m_itObjSelect->Name();
  149. DisplayMenus();
  150. }
  151. return 0;
  152. }
  153. void CRootMenuPage::DisplayMenus()
  154. {
  155. HWND hwndLV = GetDlgItem(IDC_MENULIST);
  156. if( !hwndLV || !::IsWindow(hwndLV) ) return;
  157. ListView_DeleteAllItems(hwndLV);
  158. if (m_itObjSelect != NULL)
  159. {
  160. CClassInfo& classInfo = m_itObjSelect->GetObject();
  161. // make sure menu names have been loaded
  162. IStringTable* pStringTable = m_ObjList.RootNode()->GetCompData()->GetStringTable();
  163. ASSERT(pStringTable != NULL);
  164. classInfo.LoadStrings(pStringTable);
  165. LV_ITEM lvi;
  166. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  167. lvi.iItem = 0;
  168. lvi.iSubItem = 0;
  169. menucmd_vector::iterator itMenu;
  170. for (itMenu = classInfo.Menus().begin(); itMenu != classInfo.Menus().end(); ++itMenu)
  171. {
  172. lvi.pszText = const_cast<LPWSTR>((*itMenu)->Name());
  173. lvi.lParam = (*itMenu)->ID();
  174. int iPos = ListView_InsertItem(hwndLV, &lvi);
  175. ASSERT(iPos >= 0);
  176. lvi.iItem++;
  177. }
  178. // if items are added, select the first
  179. if (ListView_GetItemCount(hwndLV) > 0)
  180. {
  181. ListView_SetItemState(hwndLV, 0, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
  182. }
  183. }
  184. EnableDlgItem( m_hWnd, IDC_ADDMENU, (m_itObjSelect != NULL) );
  185. EnableDlgItem( m_hWnd, IDC_REMOVEMENU, FALSE );
  186. EnableDlgItem( m_hWnd, IDC_EDITMENU, FALSE );
  187. EnableDlgItem( m_hWnd, IDC_MOVEUP, FALSE );
  188. EnableDlgItem( m_hWnd, IDC_MOVEDOWN, FALSE );
  189. }
  190. LRESULT CRootMenuPage::OnAddMenu( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
  191. {
  192. // if object is selected
  193. if (m_itObjSelect == NULL)
  194. return 0;
  195. CAddMenuDlg dlg(m_itObjSelect->GetObject());
  196. if (dlg.DoModal() == IDOK)
  197. {
  198. CClassInfo* pClassInfo = m_itObjSelect->GetModifiedObject();
  199. if( !pClassInfo ) return 0;
  200. CMenuCmd* pMenuNew = dlg.GetMenu();
  201. ASSERT(pMenuNew != NULL);
  202. if( pMenuNew )
  203. {
  204. // Add new menu to list
  205. HWND hwndList = GetDlgItem(IDC_MENULIST);
  206. // Set name to add it to string table and generate the menu ID
  207. IStringTable* pStringTable = m_ObjList.RootNode()->GetCompData()->GetStringTable();
  208. ASSERT( pStringTable );
  209. if( !pStringTable ) return 0;
  210. // Use temp string because string fails an assignement like: strX = strX.c_str()
  211. // (it relases the private buffer first and then assigns the string)
  212. tstring strName = pMenuNew->Name();
  213. pMenuNew->SetName(pStringTable, strName.c_str());
  214. LVITEM lvi;
  215. lvi.mask = LVIF_PARAM | LVIF_TEXT;
  216. lvi.iSubItem = 0;
  217. lvi.iItem = ListView_GetItemCount(hwndList);
  218. lvi.lParam = pMenuNew->ID();
  219. lvi.pszText = const_cast<LPWSTR>(pMenuNew->Name());
  220. ListView_InsertItem(hwndList,&lvi);
  221. // if first item is added, select it
  222. if (ListView_GetItemCount(hwndList) == 1)
  223. {
  224. ListView_SetItemState(hwndList, 0, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
  225. }
  226. // Add to menu vector (note that temp CMenuCmdPtr will delete pMenuNew)
  227. pClassInfo->Menus().push_back(CMenuCmdPtr(pMenuNew));
  228. SetModified(TRUE);
  229. }
  230. }
  231. return 0;
  232. }
  233. LRESULT CRootMenuPage::OnEditMenu( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
  234. {
  235. HWND hwndList = GetDlgItem(IDC_MENULIST);
  236. if( !hwndList || !::IsWindow(hwndList) ) return 0;
  237. int iIndex = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
  238. ASSERT(iIndex != -1);
  239. if( iIndex == -1 ) return 0;
  240. LVITEM lvi;
  241. lvi.mask = LVIF_PARAM;
  242. lvi.iSubItem = 0;
  243. lvi.iItem = iIndex;
  244. ListView_GetItem(hwndList, &lvi);
  245. // Locate selected menu by it's ID (lparam)
  246. CClassInfo& classInfo = m_itObjSelect->GetObject();
  247. menucmd_vector& vMenus = classInfo.Menus();
  248. menucmd_vector::iterator itMenu;
  249. itMenu = std::find(vMenus.begin(), vMenus.end(), lvi.lParam);
  250. ASSERT(itMenu != vMenus.end());
  251. if( itMenu == vMenus.end() ) return 0;
  252. CMenuCmd* pMenu = *itMenu;
  253. if( !pMenu ) return 0;
  254. CAddMenuDlg dlg(m_itObjSelect->GetObject(), pMenu);
  255. if (dlg.DoModal() == IDOK)
  256. {
  257. CMenuCmd* pMenuNew = dlg.GetMenu();
  258. ASSERT( pMenuNew );
  259. if( !pMenuNew ) return 0;
  260. // Set the name again in case it was changed
  261. IStringTable* pStringTable = m_ObjList.RootNode()->GetCompData()->GetStringTable();
  262. ASSERT( pStringTable );
  263. if( !pStringTable ) return 0;
  264. // Use temp string because string fails an assignement like: strX = strX.c_str()
  265. // (it relases the private buffer first and then assigns the string)
  266. tstring strName = pMenuNew->Name();
  267. pMenuNew->SetName(pStringTable, strName.c_str());
  268. // locate object again because the vector may have been reallocated
  269. CClassInfo* pClassInfoNew = m_itObjSelect->GetModifiedObject();
  270. if( !pClassInfoNew ) return 0;
  271. menucmd_vector& vMenusNew = pClassInfoNew->Menus();
  272. // locate with the old ID because it will be different if the name was changed
  273. itMenu = std::find(vMenusNew.begin(), vMenusNew.end(), pMenu->ID());
  274. ASSERT(itMenu != vMenusNew.end());
  275. if( itMenu == vMenusNew.end() ) return 0;
  276. // Replace menu with new one
  277. *itMenu = pMenuNew;
  278. // Update the list
  279. lvi.mask = LVIF_PARAM | LVIF_TEXT;
  280. lvi.lParam = pMenuNew->ID();
  281. lvi.pszText = const_cast<LPWSTR>(pMenuNew->Name());
  282. ListView_SetItem(hwndList,&lvi);
  283. SetModified(TRUE);
  284. }
  285. return 0;
  286. }
  287. LRESULT CRootMenuPage::OnRemoveMenu( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
  288. {
  289. if (m_itObjSelect == NULL)
  290. return 0;
  291. HWND hwndList = GetDlgItem(IDC_MENULIST);
  292. UINT uiMsg = (ListView_GetSelectedCount(hwndList) == 1) ? IDS_MENU_REMOVE_ONE : IDS_MENU_REMOVE;
  293. int iRet = DisplayMessageBox(m_hWnd, IDS_MENU_REMOVE_TITLE, uiMsg, MB_YESNO|MB_ICONWARNING);
  294. if (iRet != IDYES)
  295. return 0;
  296. CClassInfo* pClassInfo = m_itObjSelect->GetModifiedObject();
  297. if( !pClassInfo ) return 0;
  298. menucmd_vector& vMenus = pClassInfo->Menus();
  299. LVITEM lvi;
  300. lvi.mask = LVIF_PARAM;
  301. lvi.iSubItem = 0;
  302. int iIndex = -1;
  303. while ((iIndex = ListView_GetNextItem(hwndList, iIndex, LVNI_SELECTED)) >= 0)
  304. {
  305. lvi.iItem = iIndex;
  306. ListView_GetItem(hwndList, &lvi);
  307. // Locate menu by its ID
  308. menucmd_vector::iterator itMenu = std::find(vMenus.begin(), vMenus.end(), lvi.lParam);
  309. ASSERT(itMenu != vMenus.end());
  310. vMenus.erase(itMenu);
  311. ListView_DeleteItem(hwndList, iIndex);
  312. iIndex--;
  313. }
  314. EnableDlgItem( m_hWnd, IDC_REMOVEMENU, FALSE );
  315. EnableDlgItem( m_hWnd, IDC_EDITMENU, FALSE );
  316. EnableDlgItem( m_hWnd, IDC_MOVEUP, FALSE );
  317. EnableDlgItem( m_hWnd, IDC_MOVEDOWN, FALSE );
  318. SetModified(TRUE);
  319. return 0;
  320. }
  321. LRESULT CRootMenuPage::OnMoveUpDown( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
  322. {
  323. HWND hwndList = GetDlgItem(IDC_MENULIST);
  324. int iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
  325. ASSERT(iItem >= 0);
  326. // Determine new position for selected item
  327. if (wID == IDC_MOVEUP)
  328. iItem--;
  329. else
  330. iItem++;
  331. // Now swap the selected item with the item at its new position
  332. // Do it by moving the unselected item to avoid state change notifications
  333. // because they will cause unwanted butten enables/disables.
  334. LVITEM lvi;
  335. lvi.mask = LVIF_PARAM;
  336. lvi.iSubItem = 0;
  337. lvi.iItem = iItem;
  338. ListView_GetItem(hwndList, &lvi);
  339. // Move the menu item in the menu vector
  340. CClassInfo* pClassInfo = m_itObjSelect->GetModifiedObject();
  341. if( !pClassInfo ) return 0;
  342. menucmd_vector& vMenus = pClassInfo->Menus();
  343. menucmd_vector::iterator itMenu = std::find(vMenus.begin(), vMenus.end(), lvi.lParam);
  344. ASSERT(itMenu != vMenus.end());
  345. menucmd_vector::iterator itMenuOld = itMenu;
  346. if (wID == IDC_MOVEUP)
  347. itMenu++;
  348. else
  349. itMenu--;
  350. // swap the items
  351. std::iter_swap (itMenuOld, itMenu);
  352. //Now delete and reinsert it in the list view
  353. ListView_DeleteItem(hwndList, lvi.iItem);
  354. if (wID == IDC_MOVEUP)
  355. lvi.iItem++;
  356. else
  357. lvi.iItem--;
  358. lvi.mask = LVIF_PARAM | LVIF_TEXT;
  359. lvi.pszText = const_cast<LPWSTR>((*itMenu)->Name());
  360. ListView_InsertItem(hwndList, &lvi);
  361. // Update Up/Down buttons
  362. EnableDlgItem( m_hWnd, IDC_MOVEUP, (iItem > 0) );
  363. EnableDlgItem( m_hWnd, IDC_MOVEDOWN, (iItem < (ListView_GetItemCount(hwndList) - 1)) );
  364. SetModified(TRUE);
  365. return 0;
  366. }
  367. LRESULT CRootMenuPage::OnMenuListChanged(int idCtrl, LPNMHDR pNMHDR, BOOL& bHandled)
  368. {
  369. HWND hwndList = GetDlgItem(IDC_MENULIST);
  370. int nItemSel = ListView_GetSelectedCount(hwndList);
  371. int iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
  372. EnableDlgItem( m_hWnd, IDC_REMOVEMENU, (nItemSel > 0) );
  373. EnableDlgItem( m_hWnd, IDC_EDITMENU, (nItemSel == 1) );
  374. EnableDlgItem( m_hWnd, IDC_MOVEUP, ((nItemSel == 1) && (iItem > 0)) );
  375. EnableDlgItem( m_hWnd, IDC_MOVEDOWN, ((nItemSel == 1) && (iItem < (ListView_GetItemCount(hwndList) - 1))) );
  376. return TRUE;
  377. }
  378. LRESULT CRootMenuPage::OnMenuListDblClk(int idCtrl, LPNMHDR pNMHDR, BOOL& bHandled)
  379. {
  380. if (ListView_GetSelectedCount(GetDlgItem(IDC_MENULIST)))
  381. ::SendMessage(GetDlgItem(IDC_EDITMENU), BM_CLICK, (WPARAM)0, (LPARAM)0);
  382. return 0;
  383. }
  384. BOOL CRootMenuPage::OnApply()
  385. {
  386. return m_ObjList.ApplyChanges(m_hWnd);
  387. }
  388. ///////////////////////////////////////////////////////////////////////////////////////////
  389. // CRootObjectPage
  390. LRESULT CRootObjectPage::OnInitDialog(UINT mMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  391. {
  392. HWND hwndList = GetDlgItem(IDC_OBJECTLIST);
  393. ConfigSingleColumnListView(hwndList);
  394. return TRUE;
  395. }
  396. LRESULT CRootObjectPage::OnAddObject(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
  397. {
  398. HRESULT hr;
  399. do
  400. {
  401. // Pass list of current classes, so wizard won't add one twice
  402. string_vector vstrClasses;
  403. for (EditObjIter itObj = m_ObjList.begin(); itObj != m_ObjList.end(); ++itObj)
  404. {
  405. if (!itObj->IsDeleted())
  406. vstrClasses.push_back(itObj->Name());
  407. }
  408. CAddObjectWizard objWiz;
  409. objWiz.Initialize(&vstrClasses, m_ObjList.RootNode()->GetCompData()->GetStringTable());
  410. // Run the wizard
  411. IPropertySheetProviderPtr spProvider = m_ObjList.RootNode()->GetCompData()->GetConsole();
  412. if( spProvider == NULL ) return E_NOINTERFACE;
  413. hr = objWiz.Run(spProvider, m_hWnd);
  414. if (hr == S_OK)
  415. {
  416. ASSERT(objWiz.GetNewObject() != NULL);
  417. if( !(objWiz.GetNewObject()) ) return E_FAIL;
  418. EditObjIter itObj = m_ObjList.AddObject(objWiz.GetNewObject());
  419. ASSERT(itObj != NULL);
  420. if( itObj == NULL ) return E_FAIL;
  421. LV_ITEM lvi;
  422. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  423. lvi.iItem = 0;
  424. lvi.iSubItem = 0;
  425. lvi.pszText = const_cast<LPWSTR>(DisplayNames::GetClassMap()->GetAttributeDisplayName(itObj->Name()));
  426. lvi.lParam = *(LPARAM*)&itObj; // NEED BETTER CONVERSION
  427. int iPos = ListView_InsertItem(GetDlgItem(IDC_OBJECTLIST), &lvi);
  428. ASSERT(iPos >= 0);
  429. // if first item is added, select it
  430. if (ListView_GetItemCount(GetDlgItem(IDC_OBJECTLIST)) == 1)
  431. {
  432. ListView_SetItemState(GetDlgItem(IDC_OBJECTLIST), 0, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
  433. }
  434. SetModified(TRUE);
  435. }
  436. }
  437. while (FALSE);
  438. return hr;
  439. }
  440. LRESULT CRootObjectPage::OnRemoveObject( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
  441. {
  442. HWND hwndList = GetDlgItem(IDC_OBJECTLIST);
  443. BOOL bFirst = TRUE;
  444. int iIndex = -1;
  445. while ((iIndex = ListView_GetNextItem(hwndList, iIndex, LVNI_SELECTED)) != -1)
  446. {
  447. LVITEM lvi;
  448. lvi.mask = LVIF_PARAM;
  449. lvi.iItem = iIndex;
  450. lvi.iSubItem = 0;
  451. BOOL bStat = ListView_GetItem(hwndList, &lvi);
  452. ASSERT(bStat);
  453. EditObjIter itObj = *(EditObjIter*)&lvi.lParam;
  454. // get confirmation before deleting first object
  455. if (bFirst)
  456. {
  457. bFirst = FALSE;
  458. CString strTitle;
  459. strTitle.LoadString(IDS_DELETEOBJ_TITLE);
  460. CString strMsgFmt;
  461. if (ListView_GetSelectedCount(hwndList) == 1)
  462. strMsgFmt.LoadString(IDS_DELETEOBJ);
  463. else
  464. strMsgFmt.LoadString(IDS_DELETEOBJS);
  465. WCHAR szName[MAX_PATH];
  466. ListView_GetItemText(hwndList, iIndex, 0, szName, sizeof(szName));
  467. CString strMsg;
  468. strMsg.Format(strMsgFmt, szName);
  469. if (::MessageBox(m_hWnd, strMsg, strTitle, MB_YESNO|MB_ICONWARNING) != IDYES)
  470. return 0;
  471. }
  472. m_ObjList.DeleteObject(itObj);
  473. ListView_DeleteItem(hwndList, iIndex);
  474. // backup index because it now points to the next item
  475. iIndex--;
  476. SetModified(TRUE);
  477. }
  478. EnableDlgItem( m_hWnd, IDC_REMOVEOBJECT, FALSE );
  479. return 0;
  480. }
  481. LRESULT CRootObjectPage::OnObjListChanged(int idCtrl, LPNMHDR pNMHDR, BOOL& bHandled)
  482. {
  483. EnableDlgItem( m_hWnd, IDC_REMOVEOBJECT, ListView_GetSelectedCount(GetDlgItem(IDC_OBJECTLIST)) );
  484. return TRUE;
  485. }
  486. BOOL CRootObjectPage::OnSetActive()
  487. {
  488. HWND hwndList = GetDlgItem(IDC_OBJECTLIST);
  489. ListView_DeleteAllItems(hwndList);
  490. LV_ITEM lvi;
  491. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  492. lvi.iItem = 0;
  493. lvi.iSubItem = 0;
  494. DisplayNameMap* pNameMap = DisplayNames::GetClassMap();
  495. ASSERT(pNameMap != NULL);
  496. if (pNameMap == NULL)
  497. return TRUE;
  498. for (EditObjIter itObj = m_ObjList.begin(); itObj != m_ObjList.end(); ++itObj)
  499. {
  500. if (!itObj->IsDeleted())
  501. {
  502. lvi.pszText = const_cast<LPWSTR>(pNameMap->GetAttributeDisplayName(itObj->Name()));
  503. lvi.lParam = *(LPARAM*)&itObj; // NEED BETTER CONVERSION
  504. int iPos = ListView_InsertItem(hwndList, &lvi);
  505. ASSERT(iPos >= 0);
  506. }
  507. }
  508. // if items are added, select the first
  509. if (ListView_GetItemCount(hwndList) > 0)
  510. {
  511. ListView_SetItemState(hwndList, 0, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
  512. }
  513. EnableDlgItem( m_hWnd, IDC_REMOVEOBJECT, FALSE );
  514. m_ObjList.PageActive(m_hWnd);
  515. return TRUE;
  516. }
  517. BOOL CRootObjectPage::OnApply()
  518. {
  519. return m_ObjList.ApplyChanges(m_hWnd);
  520. }
  521. ///////////////////////////////////////////////////////////////////////////////////////////
  522. // CRootViewPage
  523. CRootViewPage::~CRootViewPage()
  524. {
  525. m_ObjectCB.Detach();
  526. m_ColumnLV.Detach();
  527. m_ObjList.Release();
  528. }
  529. LRESULT CRootViewPage::OnInitDialog( UINT mMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  530. {
  531. m_ObjectCB.Attach(GetDlgItem(IDC_OBJECTLIST));
  532. m_ColumnLV.Attach(GetDlgItem(IDC_COLUMNLIST));
  533. m_itObjSelect = NULL;
  534. ::ConfigSingleColumnListView(GetDlgItem(IDC_COLUMNLIST));
  535. return TRUE;
  536. }
  537. LRESULT CRootViewPage::OnObjectSelect( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
  538. {
  539. int iItem = m_ObjectCB.GetCurSel();
  540. // Double-clicking an empty combo box can call this with no selection
  541. if (iItem >= 0)
  542. {
  543. void* pv = m_ObjectCB.GetItemDataPtr(iItem);
  544. m_itObjSelect = *(EditObjIter*)&pv;
  545. m_strObjSelect = m_itObjSelect->Name();
  546. DisplayColumns();
  547. }
  548. return 0;
  549. }
  550. LRESULT CRootViewPage::OnColumnListChanged(int idCtrl, LPNMHDR pNMHDR, BOOL& bHandled)
  551. {
  552. EnableDlgItem( m_hWnd, IDC_REMOVECOLUMN, ListView_GetSelectedCount(GetDlgItem(IDC_COLUMNLIST)) );
  553. return TRUE;
  554. }
  555. void CRootViewPage::DisplayColumns()
  556. {
  557. HWND hwndLV = GetDlgItem(IDC_COLUMNLIST);
  558. ASSERT(::IsWindow(hwndLV));
  559. ListView_DeleteAllItems(hwndLV);
  560. if (m_itObjSelect != NULL)
  561. {
  562. CClassInfo& classInfo = m_itObjSelect->GetObject();
  563. DisplayNameMap* pNameMap = DisplayNames::GetMap(classInfo.Name());
  564. if( !pNameMap ) return;
  565. LV_ITEM lvi;
  566. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  567. lvi.iItem = 0;
  568. lvi.iSubItem = 0;
  569. string_vector::iterator itStr;
  570. for (itStr = classInfo.Columns().begin(); itStr != classInfo.Columns().end(); ++itStr)
  571. {
  572. lvi.pszText = const_cast<LPWSTR>(pNameMap->GetAttributeDisplayName(itStr->c_str()));
  573. lvi.lParam = reinterpret_cast<LPARAM>(itStr->c_str());
  574. int iPos = ListView_InsertItem(hwndLV, &lvi);
  575. ASSERT(iPos >= 0);
  576. }
  577. // if items are added, select the first
  578. if (ListView_GetItemCount(hwndLV) > 0)
  579. {
  580. ListView_SetItemState(hwndLV, 0, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
  581. }
  582. }
  583. EnableDlgItem( m_hWnd, IDC_ADDCOLUMN, (m_itObjSelect != NULL) );
  584. EnableDlgItem( m_hWnd, IDC_REMOVECOLUMN, FALSE );
  585. }
  586. LRESULT CRootViewPage::OnAddColumn( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
  587. {
  588. // if object is selected
  589. if (m_itObjSelect == NULL)
  590. return 0;
  591. CAddColumnDlg dlg(m_itObjSelect->Name());
  592. if (dlg.DoModal() == IDOK)
  593. {
  594. BOOL bModified = FALSE;
  595. CClassInfo* pClassInfo = m_itObjSelect->GetModifiedObject();
  596. if( !pClassInfo ) return 0;
  597. HWND hwndList = GetDlgItem(IDC_COLUMNLIST);
  598. ASSERT(hwndList != NULL);
  599. string_vector::iterator itStr = dlg.GetColumns().begin();
  600. while (itStr != dlg.GetColumns().end())
  601. {
  602. if (std::find(pClassInfo->Columns().begin(), pClassInfo->Columns().end(), *itStr) == pClassInfo->Columns().end())
  603. {
  604. pClassInfo->Columns().push_back(*itStr);
  605. bModified = TRUE;
  606. }
  607. ++itStr;
  608. }
  609. if (bModified)
  610. {
  611. SetModified(TRUE);
  612. DisplayColumns();
  613. }
  614. }
  615. return 0;
  616. }
  617. LRESULT CRootViewPage::OnRemoveColumn( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
  618. {
  619. if (m_itObjSelect == NULL)
  620. return 0;
  621. HWND hwndList = GetDlgItem(IDC_COLUMNLIST);
  622. ASSERT(hwndList != NULL);
  623. UINT uiMsg = (ListView_GetSelectedCount(hwndList) == 1) ? IDS_PROP_REMOVE_ONE : IDS_PROP_REMOVE;
  624. int iRet = DisplayMessageBox(m_hWnd, IDS_PROP_REMOVE_TITLE, uiMsg, MB_YESNO|MB_ICONWARNING);
  625. if (iRet != IDYES)
  626. return 0;
  627. CClassInfo* pClassInfo = m_itObjSelect->GetModifiedObject();
  628. if( !pClassInfo ) return 0;
  629. string_vector vstrTmp = pClassInfo->Columns();
  630. LVITEM lvi;
  631. lvi.mask = LVIF_PARAM;
  632. lvi.iSubItem = 0;
  633. int iIndex = -1;
  634. while ((iIndex = ListView_GetNextItem(hwndList, iIndex, LVNI_SELECTED)) >= 0)
  635. {
  636. lvi.iItem = iIndex;
  637. ListView_GetItem(hwndList, &lvi);
  638. LPCWSTR pszName = reinterpret_cast<LPCWSTR>(lvi.lParam);
  639. string_vector::iterator itStr;
  640. itStr = std::find(vstrTmp.begin(), vstrTmp.end(), pszName);
  641. ASSERT(itStr != vstrTmp.end());
  642. if( itStr != vstrTmp.end() )
  643. {
  644. vstrTmp.erase(itStr);
  645. }
  646. }
  647. pClassInfo->Columns() = vstrTmp;
  648. DisplayColumns();
  649. SetModified(TRUE);
  650. return 0;
  651. }
  652. BOOL CRootViewPage::OnSetActive()
  653. {
  654. m_ObjList.PageActive(m_hWnd);
  655. LoadObjectCB(m_ObjectCB, m_ObjList);
  656. // if object was previously selected
  657. if (m_itObjSelect != NULL)
  658. {
  659. // find the edit object by name because it may have been moved or deleted
  660. // while another page was active
  661. m_itObjSelect = m_ObjList.FindObject(m_strObjSelect.c_str());
  662. if (m_itObjSelect != NULL && m_itObjSelect->IsDeleted())
  663. m_itObjSelect = NULL;
  664. }
  665. // if object still around, reselect it in the combo box
  666. if (m_itObjSelect != NULL)
  667. {
  668. DisplayNameMap* pNameMap = DisplayNames::GetClassMap();
  669. ASSERT(pNameMap != NULL);
  670. int iSel = m_ObjectCB.FindStringExact(-1, pNameMap->GetAttributeDisplayName(m_strObjSelect.c_str()));
  671. ASSERT(iSel != CB_ERR);
  672. m_ObjectCB.SetCurSel(iSel);
  673. }
  674. else if (m_ObjectCB.GetCount() > 0)
  675. {
  676. // default to the first object and update the columns
  677. m_ObjectCB.SetCurSel(0);
  678. void* pv = m_ObjectCB.GetItemDataPtr(0);
  679. m_itObjSelect = *(EditObjIter*)&pv;
  680. m_strObjSelect = m_itObjSelect->Name();
  681. DisplayColumns();
  682. }
  683. else
  684. {
  685. DisplayColumns();
  686. }
  687. return TRUE;
  688. }
  689. BOOL CRootViewPage::OnApply()
  690. {
  691. return m_ObjList.ApplyChanges(m_hWnd);
  692. }
  693. /////////////////////////////////////////////////////////////////////////////////////////////////
  694. // CEditObjList
  695. HRESULT CEditObjList::Initialize(CRootNode* pRootNode, classInfo_vector& vClasses, LONG_PTR lNotifyHandle)
  696. {
  697. ASSERT(pRootNode != NULL);
  698. ASSERT(lNotifyHandle != NULL);
  699. m_spRootNode = pRootNode;
  700. classInfo_vector::iterator itClass = vClasses.begin();
  701. while(itClass != vClasses.end())
  702. {
  703. CEditObject* pObj = new CEditObject();
  704. if( !pObj )
  705. {
  706. break;
  707. }
  708. EditObjIter iter = m_ObjectList.insert(end(), *pObj);
  709. iter->m_strName = itClass->Name();
  710. iter->m_itObjOriginal = itClass;
  711. ++itClass;
  712. }
  713. m_pvClasses = &vClasses;
  714. m_iPageMax = -1;
  715. m_lNotifyHandle = lNotifyHandle;
  716. return S_OK;
  717. }
  718. BOOL CEditObjList::ApplyChanges(HWND hwndPage)
  719. {
  720. ASSERT(::IsWindow(hwndPage));
  721. // Don't apply changes until called from highest activated page
  722. if (PropSheet_HwndToIndex(GetParent(hwndPage), hwndPage) < m_iPageMax)
  723. return TRUE;
  724. // Build a vector of the modified classes
  725. string_vector* pvstrModified = new string_vector;
  726. if( !pvstrModified ) return FALSE;
  727. // Apply changes in reverse order so deletions won't invalidate stored iterators
  728. std::list<CEditObject>::reverse_iterator itObj = m_ObjectList.rbegin();
  729. while (itObj != m_ObjectList.rend())
  730. {
  731. // if object is modified, replace the original
  732. if (itObj->m_itObjOriginal != NULL)
  733. {
  734. if (itObj->m_pObjModified != NULL)
  735. {
  736. *(itObj->m_itObjOriginal) = *(itObj->m_pObjModified);
  737. pvstrModified->push_back(itObj->m_pObjModified->Name());
  738. }
  739. else if (itObj->IsDeleted())
  740. {
  741. m_pvClasses->erase(itObj->m_itObjOriginal);
  742. pvstrModified->push_back(itObj->m_itObjOriginal->Name());
  743. }
  744. }
  745. ++itObj;
  746. }
  747. // Now go through list again to add any new objects
  748. // This must be done separately because it can invalidate all stored iterators
  749. itObj = m_ObjectList.rbegin();
  750. while(itObj != m_ObjectList.rend())
  751. {
  752. if (itObj->m_itObjOriginal == NULL && itObj->m_pObjModified != NULL)
  753. {
  754. m_pvClasses->push_back(*(itObj->m_pObjModified));
  755. pvstrModified->push_back(itObj->m_pObjModified->Name());
  756. }
  757. ++itObj;
  758. }
  759. // clear the edit list and re-initialize it
  760. m_ObjectList.clear();
  761. Initialize(m_spRootNode, *m_pvClasses, m_lNotifyHandle);
  762. // Send change notification to root node, so it can update affected child nodes
  763. // Use MMC method to send from prop page thread to main thread
  764. if (pvstrModified->size() != 0)
  765. {
  766. // create prop change info struct with root node's data interface
  767. // and list of changed classes
  768. PropChangeInfo* pChg = new PropChangeInfo;
  769. if( !pChg )
  770. {
  771. delete pvstrModified;
  772. return FALSE;
  773. }
  774. pChg->pDataObject = static_cast<IDataObject*>(m_spRootNode.p);
  775. pChg->lNotifyParam = (LPARAM)pvstrModified;
  776. MMCPropertyChangeNotify(m_lNotifyHandle, (LPARAM)pChg);
  777. }
  778. else
  779. delete pvstrModified;
  780. return TRUE;
  781. }
  782. void CEditObjList::PageActive(HWND hwndPage)
  783. {
  784. ASSERT(::IsWindow(hwndPage));
  785. // track the highest created page number for ApplyChanges method
  786. int iPage = PropSheet_HwndToIndex(GetParent(hwndPage), hwndPage);
  787. if (iPage > m_iPageMax)
  788. m_iPageMax = iPage;
  789. }
  790. EditObjIter CEditObjList::FindObject(LPCWSTR pszName)
  791. {
  792. if( !pszName ) return NULL;
  793. EditObjIter iter = begin();
  794. while (iter != end())
  795. {
  796. // look for class object with matching name
  797. if (wcscmp(iter->Name(), pszName) == 0)
  798. {
  799. // If the object hasn't been modified (copied) yet, then load any
  800. // string table strings before returning the object
  801. if (iter->m_itObjOriginal != NULL && iter->m_pObjModified == NULL)
  802. {
  803. ASSERT(m_spRootNode != NULL);
  804. if( !m_spRootNode ) return NULL;
  805. IStringTable* pStringTable = m_spRootNode->GetCompData()->GetStringTable();
  806. ASSERT(pStringTable != NULL);
  807. if( !pStringTable ) return NULL;
  808. HRESULT hr = iter->m_itObjOriginal->LoadStrings(pStringTable);
  809. }
  810. return iter;
  811. }
  812. ++iter;
  813. }
  814. return NULL;
  815. }
  816. EditObjIter CEditObjList::AddObject(CClassInfo* pClassInfo)
  817. {
  818. if( !pClassInfo ) return NULL;
  819. EditObjIter iter = begin();
  820. while (iter != end())
  821. {
  822. // Check for exiting edit object (can be there if object was deleted)
  823. if (wcscmp(iter->Name(), pClassInfo->Name()) == 0)
  824. {
  825. ASSERT(iter->m_bDeleted && iter->m_pObjModified == NULL);
  826. iter->m_bDeleted = FALSE;
  827. iter->m_pObjModified = pClassInfo;
  828. return iter;
  829. }
  830. ++iter;
  831. }
  832. // if not found, create new edit object and store new class info as the modified object
  833. CEditObject* pObj = new CEditObject();
  834. if( !pObj ) return iter;
  835. iter = m_ObjectList.insert(end(), *pObj);
  836. iter->m_strName = pClassInfo->Name();
  837. iter->m_pObjModified = pClassInfo;
  838. return iter;
  839. }
  840. void CEditObjList::DeleteObject(EditObjIter itObj)
  841. {
  842. ASSERT(itObj != NULL);
  843. if (itObj->m_itObjOriginal == NULL)
  844. {
  845. m_ObjectList.erase(itObj);
  846. }
  847. else
  848. {
  849. if (itObj->m_pObjModified != NULL)
  850. {
  851. delete itObj->m_pObjModified;
  852. itObj->m_pObjModified = NULL;
  853. }
  854. itObj->m_bDeleted = TRUE;
  855. }
  856. }
  857. /////////////////////////////////////////////////////////////////////////////////////////////////
  858. //
  859. void LoadObjectCB(CComboBox& ComboBox, CEditObjList& ObjList)
  860. {
  861. ComboBox.ResetContent();
  862. DisplayNameMap* pNameMap = DisplayNames::GetClassMap();
  863. ASSERT(pNameMap != NULL);
  864. if (pNameMap == NULL)
  865. return;
  866. for (EditObjIter itObj = ObjList.begin(); itObj != ObjList.end(); ++itObj)
  867. {
  868. if (!itObj->IsDeleted())
  869. {
  870. int iIndex = ComboBox.AddString(pNameMap->GetAttributeDisplayName(itObj->Name()));
  871. ASSERT(iIndex >= 0);
  872. ComboBox.SetItemDataPtr(iIndex, *(LPVOID*)&itObj);
  873. }
  874. }
  875. }
  876. int GetDateTimeString(FILETIME* pftime, LPWSTR pszBuf, int cBuf)
  877. {
  878. if( !pftime || !pszBuf || !cBuf ) return 0;
  879. FILETIME ftimeLocal;
  880. BOOL bStat = FileTimeToLocalFileTime(pftime, &ftimeLocal);
  881. ASSERT(bStat);
  882. SYSTEMTIME systime;
  883. bStat = FileTimeToSystemTime(&ftimeLocal, &systime);
  884. ASSERT(bStat);
  885. // get date string
  886. int cDate = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systime, NULL, pszBuf, cBuf);
  887. if (cDate == 0 || cDate > cBuf - 2)
  888. return 0;
  889. // replace teminating null with ", "
  890. pszBuf[cDate-1] = ',';
  891. pszBuf[cDate] = ' ';
  892. // append time string
  893. int cTime = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &systime, NULL,
  894. pszBuf + (cDate + 1), cBuf - (cDate + 1));
  895. if (cTime == 0)
  896. return 0;
  897. // return total string length excluding terminating null
  898. return (cDate + cTime - 2);
  899. }