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.

1025 lines
29 KiB

  1. #include "stdafx.h"
  2. #include "PageIni.h"
  3. #include "MSConfigFind.h"
  4. #ifdef _DEBUG
  5. #define new DEBUG_NEW
  6. #undef THIS_FILE
  7. static char THIS_FILE[] = __FILE__;
  8. #endif
  9. /////////////////////////////////////////////////////////////////////////////
  10. // CPageIni property page
  11. IMPLEMENT_DYNCREATE(CPageIni, CPropertyPage)
  12. CPageIni::CPageIni() : CPropertyPage(CPageIni::IDD)
  13. {
  14. //{{AFX_DATA_INIT(CPageIni)
  15. // NOTE: the ClassWizard will add member initialization here
  16. //}}AFX_DATA_INIT
  17. m_fModified = FALSE;
  18. }
  19. CPageIni::~CPageIni()
  20. {
  21. }
  22. void CPageIni::SetTabInfo(LPCTSTR szFilename)
  23. {
  24. m_strINIFile = szFilename;
  25. }
  26. void CPageIni::DoDataExchange(CDataExchange* pDX)
  27. {
  28. CPropertyPage::DoDataExchange(pDX);
  29. //{{AFX_DATA_MAP(CPageIni)
  30. // NOTE: the ClassWizard will add DDX and DDV calls here
  31. //}}AFX_DATA_MAP
  32. }
  33. BEGIN_MESSAGE_MAP(CPageIni, CPropertyPage)
  34. //{{AFX_MSG_MAP(CPageIni)
  35. ON_BN_CLICKED(IDC_BUTTONINIDISABLE, OnButtonDisable)
  36. ON_BN_CLICKED(IDC_BUTTONINIDISABLEALL, OnButtonDisableAll)
  37. ON_BN_CLICKED(IDC_BUTTONINIENABLE, OnButtonEnable)
  38. ON_BN_CLICKED(IDC_BUTTONINIENABLEALL, OnButtonEnableAll)
  39. ON_BN_CLICKED(IDC_BUTTONINIMOVEDOWN, OnButtonMoveDown)
  40. ON_BN_CLICKED(IDC_BUTTONINIMOVEUP, OnButtonMoveUp)
  41. ON_NOTIFY(TVN_SELCHANGED, IDC_INITREE, OnSelChangedTree)
  42. ON_BN_CLICKED(IDC_BUTTONSEARCH, OnButtonSearch)
  43. ON_NOTIFY(NM_CLICK, IDC_INITREE, OnClickTree)
  44. ON_BN_CLICKED(IDC_BUTTONINIEDIT, OnButtonEdit)
  45. ON_NOTIFY(TVN_ENDLABELEDIT, IDC_INITREE, OnEndLabelEdit)
  46. ON_BN_CLICKED(IDC_BUTTONININEW, OnButtonNew)
  47. ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_INITREE, OnBeginLabelEditIniTree)
  48. ON_NOTIFY(TVN_KEYDOWN, IDC_INITREE, OnKeyDownTree)
  49. //}}AFX_MSG_MAP
  50. END_MESSAGE_MAP()
  51. //-------------------------------------------------------------------------
  52. // Reads the contents of the INI file in to this class's internal
  53. // structures.
  54. //-------------------------------------------------------------------------
  55. BOOL CPageIni::LoadINIFile(CStringArray & lines, int & iLastLine, BOOL fLoadBackupFile)
  56. {
  57. lines.RemoveAll();
  58. // Open the specified INI file.
  59. TCHAR szPath[MAX_PATH];
  60. CString strINIFileLocation;
  61. strINIFileLocation.Format(_T("%%windir%%\\%s"), m_strINIFile);
  62. if (::ExpandEnvironmentStrings(strINIFileLocation, szPath, MAX_PATH) == 0)
  63. return FALSE;
  64. if (fLoadBackupFile)
  65. {
  66. CString strPath = GetBackupName(szPath, _T(".backup"));
  67. // Replacing unsafe string copy: _tcscpy(szPath, strPath);
  68. ::ZeroMemory((PVOID)szPath, sizeof(szPath));
  69. _tcsncpy(szPath, strPath, (sizeof(szPath) / sizeof(TCHAR)) - 1);
  70. }
  71. else
  72. {
  73. // If a backup of this file doesn't exist, we should make one.
  74. BackupFile(szPath, _T(".backup"), FALSE);
  75. }
  76. CStdioFile inifile;
  77. if (inifile.Open(szPath, CFile::modeRead | CFile::typeText))
  78. {
  79. // Estimate how big the string array will need to be (the array
  80. // will grow if we're off). We'll estimate 15 characters/line, average.
  81. // And we'll set the array to grow by 16 if we exceed this.
  82. lines.SetSize(inifile.GetLength() / (15 * sizeof(TCHAR)), 16);
  83. // Read each line and insert it into the array.
  84. CString strLine;
  85. m_iLastLine = -1;
  86. while (inifile.ReadString(strLine))
  87. {
  88. strLine.TrimRight(_T("\r\n"));
  89. CString strCheck(strLine);
  90. strCheck.TrimLeft();
  91. if (!strCheck.IsEmpty())
  92. lines.SetAtGrow(++iLastLine, strLine);
  93. }
  94. inifile.Close();
  95. }
  96. else
  97. return FALSE;
  98. return TRUE;
  99. }
  100. //-------------------------------------------------------------------------
  101. // Writes the contents of the array of lines out to the actual file.
  102. //-------------------------------------------------------------------------
  103. BOOL CPageIni::WriteINIFile(CStringArray & lines, int iLastLine, BOOL fUndoable)
  104. {
  105. // Open the specified INI file.
  106. TCHAR szPath[MAX_PATH];
  107. CString strINIFileLocation;
  108. CString strINIFile(m_strINIFile);
  109. strINIFileLocation.Format(_T("%%windir%%\\%s"), strINIFile);
  110. if (::ExpandEnvironmentStrings(strINIFileLocation, szPath, MAX_PATH) == 0)
  111. return FALSE;
  112. CStdioFile inifile;
  113. if (inifile.Open(szPath, CFile::modeCreate | CFile::modeWrite | CFile::typeText))
  114. {
  115. // We need to traverse the tree structure to get the new contents of
  116. // the file.
  117. HWND hwndTree = m_tree.m_hWnd;
  118. HTREEITEM htiLine = TreeView_GetRoot(hwndTree);
  119. TVITEM tvi;
  120. TCHAR szBuffer[MAX_PATH];
  121. tvi.mask = TVIF_TEXT | TVIF_IMAGE;
  122. tvi.pszText = szBuffer;
  123. while (htiLine)
  124. {
  125. tvi.hItem = htiLine;
  126. tvi.cchTextMax = MAX_PATH;
  127. if (TreeView_GetItem(hwndTree, &tvi))
  128. {
  129. CString strLine(tvi.pszText);
  130. CString strCheck(strLine);
  131. strCheck.TrimLeft();
  132. if (!strCheck.IsEmpty())
  133. {
  134. if (!fUndoable && strLine.Find(DISABLE_STRING) != -1)
  135. strLine.Replace(DISABLE_STRING, _T("; "));
  136. strLine += CString(_T("\n"));
  137. inifile.WriteString(strLine);
  138. }
  139. }
  140. HTREEITEM htiNext = TreeView_GetChild(hwndTree, htiLine);
  141. if (htiNext)
  142. {
  143. htiLine = htiNext;
  144. continue;
  145. }
  146. htiNext = TreeView_GetNextSibling(hwndTree, htiLine);
  147. if (htiNext)
  148. {
  149. htiLine = htiNext;
  150. continue;
  151. }
  152. htiNext = TreeView_GetParent(hwndTree, htiLine);
  153. if (htiNext)
  154. {
  155. htiNext = TreeView_GetNextSibling(hwndTree, htiNext);
  156. if (htiNext)
  157. {
  158. htiLine = htiNext;
  159. continue;
  160. }
  161. }
  162. htiLine = NULL;
  163. }
  164. inifile.Close();
  165. }
  166. else
  167. return FALSE;
  168. return TRUE;
  169. }
  170. //-------------------------------------------------------------------------
  171. // Updates the tree view to show the contents of the internal structures.
  172. //-------------------------------------------------------------------------
  173. void CPageIni::UpdateTreeView()
  174. {
  175. TreeView_DeleteAllItems(m_tree.m_hWnd);
  176. ASSERT(m_iLastLine < m_lines.GetSize());
  177. if (m_iLastLine > m_lines.GetSize())
  178. return;
  179. TVINSERTSTRUCT tvis;
  180. tvis.hParent = TVI_ROOT;
  181. tvis.hInsertAfter = TVI_LAST;
  182. tvis.itemex.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  183. tvis.itemex.iImage = m_checkedID;
  184. tvis.itemex.iSelectedImage = m_checkedID;
  185. // Add each line to the tree view.
  186. int iDisableLen = _tcslen(DISABLE_STRING);
  187. int iDisableLenHdr = _tcslen(DISABLE_STRING_HDR);
  188. for (int i = 0; i <= m_iLastLine; i++)
  189. {
  190. CString strLine = m_lines.GetAt(i);
  191. tvis.itemex.pszText = (LPTSTR)(LPCTSTR)strLine;
  192. if (!strLine.IsEmpty() && (_tcsnccmp((LPCTSTR)strLine, DISABLE_STRING, iDisableLen) == 0))
  193. tvis.itemex.iImage = tvis.itemex.iSelectedImage = m_uncheckedID;
  194. else
  195. tvis.itemex.iImage = tvis.itemex.iSelectedImage = m_checkedID;
  196. BOOL fSectionHeader = FALSE;
  197. if (!strLine.IsEmpty())
  198. {
  199. if (strLine[0] == _T('['))
  200. fSectionHeader = TRUE;
  201. else if (_tcsnccmp((LPCTSTR)strLine, DISABLE_STRING_HDR, iDisableLenHdr) == 0)
  202. fSectionHeader = TRUE;
  203. }
  204. if (fSectionHeader)
  205. {
  206. tvis.hParent = TVI_ROOT;
  207. tvis.hParent = TreeView_InsertItem(m_tree.m_hWnd, &tvis);
  208. }
  209. else
  210. TreeView_InsertItem(m_tree.m_hWnd, &tvis);
  211. }
  212. // Now scan the top level of the tree view. For every node which
  213. // has children, we want to set the image appropriately.
  214. for (HTREEITEM hti = TreeView_GetRoot(m_tree.m_hWnd); hti; hti = TreeView_GetNextSibling(m_tree.m_hWnd, hti))
  215. if (TreeView_GetChild(m_tree.m_hWnd, hti) != NULL)
  216. UpdateLine(hti);
  217. UpdateControls();
  218. }
  219. //-------------------------------------------------------------------------
  220. // Update the image state of the specified line, based on the text in
  221. // the line. If the line is a bracketed section header, this will involve
  222. // scanning the children. Returns the index of the image set for the node.
  223. //-------------------------------------------------------------------------
  224. int CPageIni::UpdateLine(HTREEITEM hti)
  225. {
  226. if (hti == NULL)
  227. return 0;
  228. TVITEM tvi;
  229. tvi.hItem = hti;
  230. int iNewImageIndex = m_checkedID;
  231. HTREEITEM htiChild = TreeView_GetChild(m_tree.m_hWnd, hti);
  232. if (htiChild)
  233. {
  234. BOOL fEnabledChild = FALSE, fDisabledChild = FALSE;
  235. while (htiChild)
  236. {
  237. if (UpdateLine(htiChild) == m_checkedID)
  238. fEnabledChild = TRUE;
  239. else
  240. fDisabledChild = TRUE;
  241. htiChild = TreeView_GetNextSibling(m_tree.m_hWnd, htiChild);
  242. }
  243. if (fDisabledChild)
  244. iNewImageIndex = (fEnabledChild) ? m_fuzzyID : m_uncheckedID;
  245. }
  246. else
  247. {
  248. TCHAR szBuffer[MAX_PATH]; // seems like a reasonably big value
  249. tvi.mask = TVIF_TEXT;
  250. tvi.pszText = szBuffer;
  251. tvi.cchTextMax = MAX_PATH;
  252. if (TreeView_GetItem(m_tree.m_hWnd, &tvi))
  253. iNewImageIndex = (_tcsnccmp(tvi.pszText, DISABLE_STRING, _tcslen(DISABLE_STRING)) == 0) ? m_uncheckedID : m_checkedID;
  254. }
  255. tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  256. if (TreeView_GetItem(m_tree.m_hWnd, &tvi) && tvi.iImage != iNewImageIndex)
  257. {
  258. tvi.iSelectedImage = tvi.iImage = iNewImageIndex;
  259. TreeView_SetItem(m_tree.m_hWnd, &tvi);
  260. }
  261. return iNewImageIndex;
  262. }
  263. //-------------------------------------------------------------------------
  264. // Enable or disable a node in the tree (and its children).
  265. //-------------------------------------------------------------------------
  266. void CPageIni::SetEnable(BOOL fEnable, HTREEITEM htiNode, BOOL fUpdateLine, BOOL fBroadcast)
  267. {
  268. HTREEITEM hti = (htiNode) ? htiNode : TreeView_GetSelection(m_tree.m_hWnd);
  269. if (hti == NULL)
  270. return;
  271. HTREEITEM htiChild = TreeView_GetChild(m_tree.m_hWnd, hti);
  272. if (htiChild)
  273. {
  274. while (htiChild)
  275. {
  276. SetEnable(fEnable, htiChild, FALSE, FALSE);
  277. htiChild = TreeView_GetNextSibling(m_tree.m_hWnd, htiChild);
  278. }
  279. UpdateLine(hti);
  280. }
  281. else
  282. {
  283. int iDisableLen = _tcslen(DISABLE_STRING);
  284. TCHAR szBuffer[MAX_PATH]; // seems like a reasonably big value
  285. TVITEM tvi;
  286. tvi.hItem = hti;
  287. tvi.mask = TVIF_TEXT;
  288. tvi.pszText = &szBuffer[iDisableLen]; // leave some room to add disable string
  289. tvi.cchTextMax = MAX_PATH + iDisableLen;
  290. if (TreeView_GetItem(m_tree.m_hWnd, &tvi))
  291. {
  292. BOOL fAlreadyEnabled = (_tcsnccmp(&szBuffer[iDisableLen], DISABLE_STRING, iDisableLen) != 0);
  293. if (fEnable != fAlreadyEnabled)
  294. {
  295. if (fEnable)
  296. tvi.pszText = &szBuffer[iDisableLen * 2];
  297. else
  298. {
  299. _tcsncpy(szBuffer, DISABLE_STRING, iDisableLen);
  300. tvi.pszText = szBuffer;
  301. }
  302. TreeView_SetItem(m_tree.m_hWnd, &tvi);
  303. if (fUpdateLine)
  304. {
  305. UpdateLine(hti);
  306. if (TreeView_GetParent(m_tree.m_hWnd, hti))
  307. UpdateLine(TreeView_GetParent(m_tree.m_hWnd, hti));
  308. }
  309. }
  310. }
  311. }
  312. if (fBroadcast)
  313. SetModified(TRUE);
  314. }
  315. //-------------------------------------------------------------------------
  316. // Move the specified branch in the tree view to a new location.
  317. //-------------------------------------------------------------------------
  318. void CPageIni::MoveBranch(HWND hwndTree, HTREEITEM htiMove, HTREEITEM htiParent, HTREEITEM htiAfter)
  319. {
  320. HTREEITEM htiNew = CopyBranch(hwndTree, htiMove, htiParent, htiAfter);
  321. if (htiNew != NULL)
  322. {
  323. TreeView_SelectItem(hwndTree, htiNew);
  324. TreeView_DeleteItem(hwndTree, htiMove);
  325. SetModified(TRUE);
  326. }
  327. }
  328. HTREEITEM CPageIni::CopyBranch(HWND hwndTree, HTREEITEM htiFrom, HTREEITEM htiToParent, HTREEITEM htiToAfter)
  329. {
  330. TCHAR szBuffer[MAX_PATH];
  331. TVINSERTSTRUCT tvis;
  332. tvis.item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_STATE;
  333. tvis.item.pszText = szBuffer;
  334. tvis.item.cchTextMax = MAX_PATH;
  335. tvis.item.hItem = htiFrom;
  336. tvis.item.stateMask = TVIS_EXPANDED;
  337. HTREEITEM htiNew = NULL;
  338. if (TreeView_GetItem(hwndTree, &tvis.item))
  339. {
  340. tvis.hParent = htiToParent;
  341. tvis.hInsertAfter = htiToAfter;
  342. htiNew = TreeView_InsertItem(hwndTree, &tvis);
  343. }
  344. HTREEITEM htiPrevious = TVI_FIRST;
  345. if (htiNew)
  346. for (HTREEITEM htiChild = TreeView_GetChild(hwndTree, htiFrom); htiChild; htiChild = TreeView_GetNextSibling(hwndTree, htiChild))
  347. htiPrevious = CopyBranch(hwndTree, htiChild, htiNew, htiPrevious);
  348. return htiNew;
  349. }
  350. //-------------------------------------------------------------------------
  351. // Update the controls to reflect the state of the selection.
  352. //-------------------------------------------------------------------------
  353. void CPageIni::UpdateControls()
  354. {
  355. BOOL fEnable = FALSE;
  356. BOOL fDisable = FALSE;
  357. BOOL fMoveUp = FALSE;
  358. BOOL fMoveDown = FALSE;
  359. HTREEITEM htiSelection = TreeView_GetSelection(m_tree.m_hWnd);
  360. if (htiSelection)
  361. {
  362. fMoveUp = (TreeView_GetPrevSibling(m_tree.m_hWnd, htiSelection) != NULL);
  363. fMoveDown = (TreeView_GetNextSibling(m_tree.m_hWnd, htiSelection) != NULL);
  364. TVITEM tvi;
  365. tvi.hItem = htiSelection;
  366. tvi.mask = TVIF_IMAGE;
  367. if (TreeView_GetItem(m_tree.m_hWnd, &tvi))
  368. {
  369. fEnable = (tvi.iImage != m_checkedID);
  370. fDisable = (tvi.iImage != m_uncheckedID);
  371. }
  372. }
  373. HWND hwndFocus = ::GetFocus();
  374. CPageBase::TabState state = GetCurrentTabState();
  375. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONINIDISABLEALL), (state != DIAGNOSTIC));
  376. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONINIENABLEALL), (state != NORMAL));
  377. if ((state == DIAGNOSTIC) && hwndFocus == GetDlgItemHWND(IDC_BUTTONINIDISABLEALL))
  378. PrevDlgCtrl();
  379. if ((state == NORMAL) && hwndFocus == GetDlgItemHWND(IDC_BUTTONINIENABLEALL))
  380. NextDlgCtrl();
  381. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONINIDISABLE), fDisable);
  382. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONINIENABLE), fEnable);
  383. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONINIMOVEUP), fMoveUp);
  384. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONINIMOVEDOWN), fMoveDown);
  385. if (!fMoveUp && hwndFocus == GetDlgItemHWND(IDC_BUTTONINIMOVEUP))
  386. NextDlgCtrl();
  387. if (!fMoveDown && hwndFocus == GetDlgItemHWND(IDC_BUTTONINIMOVEDOWN))
  388. PrevDlgCtrl();
  389. if (!fEnable && hwndFocus == GetDlgItemHWND(IDC_BUTTONINIENABLE))
  390. NextDlgCtrl();
  391. if (!fDisable && hwndFocus == GetDlgItemHWND(IDC_BUTTONINIDISABLE))
  392. PrevDlgCtrl();
  393. }
  394. //-------------------------------------------------------------------------
  395. // Get the next item in the tree. Since we know this won't be more than
  396. // two levels deep, we don't need to have a loop.
  397. //-------------------------------------------------------------------------
  398. HTREEITEM CPageIni::GetNextItem(HTREEITEM hti)
  399. {
  400. if (hti == NULL)
  401. return NULL;
  402. HTREEITEM htiNext = TreeView_GetChild(m_tree.m_hWnd, hti);
  403. if (htiNext != NULL)
  404. return htiNext;
  405. htiNext = TreeView_GetNextSibling(m_tree.m_hWnd, hti);
  406. if (htiNext != NULL)
  407. return htiNext;
  408. htiNext = TreeView_GetParent(m_tree.m_hWnd, hti);
  409. if (htiNext != NULL)
  410. htiNext = TreeView_GetNextSibling(m_tree.m_hWnd, htiNext);
  411. return htiNext;
  412. }
  413. /////////////////////////////////////////////////////////////////////////////
  414. // CPageIni message handlers
  415. BOOL CPageIni::OnInitDialog()
  416. {
  417. CPropertyPage::OnInitDialog();
  418. // These items are initially disabled.
  419. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONINIDISABLE), FALSE);
  420. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONINIENABLE), FALSE);
  421. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONINIMOVEUP), FALSE);
  422. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONINIMOVEDOWN), FALSE);
  423. m_tree.Attach(GetDlgItemHWND(IDC_INITREE));
  424. VERIFY(m_fImageList = m_imagelist.Create(IDB_IMAGELIST, 0, 3, RGB(255, 0, 255)));
  425. if (m_fImageList)
  426. TreeView_SetImageList(m_tree.m_hWnd, m_imagelist, TVSIL_NORMAL);
  427. // If we are running on an RTL system, then the bitmaps for the check boxes
  428. // will be reversed. The imagemap includes reversed versions of the checked
  429. // and indetermined state, so we should just use the appropriate index.
  430. DWORD dwLayout;
  431. BOOL fRTL = FALSE;
  432. if (::GetProcessDefaultLayout(&dwLayout))
  433. fRTL = ((dwLayout & LAYOUT_RTL) != 0);
  434. m_checkedID = (fRTL) ? IMG_CHECKED_RTL : IMG_CHECKED;
  435. m_fuzzyID = (fRTL) ? IMG_FUZZY_RTL : IMG_FUZZY;
  436. m_uncheckedID = IMG_UNCHECKED;
  437. if (LoadINIFile(m_lines, m_iLastLine))
  438. UpdateTreeView();
  439. else
  440. {
  441. // set controls for no file TBD
  442. }
  443. m_fInitialized = TRUE;
  444. return TRUE; // return TRUE unless you set the focus to a control
  445. }
  446. //-------------------------------------------------------------------------
  447. // When the user clicks on an enable or disable button, we'll modify the
  448. // text in the tree view and update the images.
  449. //-------------------------------------------------------------------------
  450. void CPageIni::OnButtonDisable()
  451. {
  452. SetEnable(FALSE);
  453. UpdateControls();
  454. }
  455. void CPageIni::OnButtonDisableAll()
  456. {
  457. for (HTREEITEM hti = TreeView_GetRoot(m_tree.m_hWnd); hti; hti = TreeView_GetNextSibling(m_tree.m_hWnd, hti))
  458. SetEnable(FALSE, hti, TRUE);
  459. UpdateControls();
  460. }
  461. void CPageIni::OnButtonEnable()
  462. {
  463. SetEnable(TRUE);
  464. UpdateControls();
  465. }
  466. void CPageIni::OnButtonEnableAll()
  467. {
  468. for (HTREEITEM hti = TreeView_GetRoot(m_tree.m_hWnd); hti; hti = TreeView_GetNextSibling(m_tree.m_hWnd, hti))
  469. SetEnable(TRUE, hti, TRUE);
  470. UpdateControls();
  471. }
  472. //-------------------------------------------------------------------------
  473. // Move a branch of the tree up or down.
  474. //-------------------------------------------------------------------------
  475. void CPageIni::OnButtonMoveDown()
  476. {
  477. HTREEITEM htiSelection = TreeView_GetSelection(m_tree.m_hWnd);
  478. if (htiSelection)
  479. {
  480. HTREEITEM htiParent = TreeView_GetParent(m_tree.m_hWnd, htiSelection);
  481. HTREEITEM htiNext = TreeView_GetNextSibling(m_tree.m_hWnd, htiSelection);
  482. if (htiNext == NULL)
  483. return;
  484. if (htiParent == NULL)
  485. htiParent = TVI_ROOT;
  486. MoveBranch(m_tree.m_hWnd, htiSelection, htiParent, htiNext);
  487. }
  488. }
  489. void CPageIni::OnButtonMoveUp()
  490. {
  491. HTREEITEM htiSelection = TreeView_GetSelection(m_tree.m_hWnd);
  492. if (htiSelection)
  493. {
  494. HTREEITEM htiParent = TreeView_GetParent(m_tree.m_hWnd, htiSelection);
  495. HTREEITEM htiPrevious = TreeView_GetPrevSibling(m_tree.m_hWnd, htiSelection);
  496. if (htiPrevious == NULL)
  497. return;
  498. htiPrevious = TreeView_GetPrevSibling(m_tree.m_hWnd, htiPrevious);
  499. if (htiPrevious == NULL)
  500. htiPrevious = TVI_FIRST;
  501. if (htiParent == NULL)
  502. htiParent = TVI_ROOT;
  503. MoveBranch(m_tree.m_hWnd, htiSelection, htiParent, htiPrevious);
  504. }
  505. }
  506. void CPageIni::OnSelChangedTree(NMHDR * pNMHDR, LRESULT * pResult)
  507. {
  508. NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW *)pNMHDR;
  509. UpdateControls();
  510. *pResult = 0;
  511. }
  512. //-------------------------------------------------------------------------
  513. // Search the tree view for a string (present a dialog to the user).
  514. //-------------------------------------------------------------------------
  515. void CPageIni::OnButtonSearch()
  516. {
  517. CMSConfigFind find;
  518. find.m_strSearchFor = m_strLastSearch;
  519. if (find.DoModal() == IDOK && !find.m_strSearchFor.IsEmpty())
  520. {
  521. CString strSearch(find.m_strSearchFor);
  522. m_strLastSearch = strSearch;
  523. strSearch.MakeLower();
  524. HTREEITEM htiSearch;
  525. if (find.m_fSearchFromTop)
  526. htiSearch = TreeView_GetRoot(m_tree.m_hWnd);
  527. else
  528. {
  529. htiSearch = TreeView_GetSelection(m_tree.m_hWnd);
  530. if (htiSearch == NULL)
  531. htiSearch = TreeView_GetRoot(m_tree.m_hWnd);
  532. else
  533. htiSearch = GetNextItem(htiSearch);
  534. }
  535. TVITEM tvi;
  536. TCHAR szBuffer[MAX_PATH];
  537. tvi.mask = TVIF_TEXT | TVIF_IMAGE;
  538. tvi.pszText = szBuffer;
  539. while (htiSearch != NULL)
  540. {
  541. tvi.hItem = htiSearch;
  542. tvi.cchTextMax = MAX_PATH;
  543. if (TreeView_GetItem(m_tree.m_hWnd, &tvi))
  544. {
  545. CString strItem(szBuffer);
  546. strItem.MakeLower();
  547. if (strItem.Find(strSearch) != -1)
  548. {
  549. // We found a hit. Select the node.
  550. TreeView_SelectItem(m_tree.m_hWnd, htiSearch);
  551. break;
  552. }
  553. }
  554. htiSearch = GetNextItem(htiSearch);
  555. }
  556. if (htiSearch == NULL)
  557. Message(IDS_NOFIND);
  558. }
  559. }
  560. //-------------------------------------------------------------------------
  561. // The current tab state can be found by looking through the tree view.
  562. //-------------------------------------------------------------------------
  563. CPageBase::TabState CPageIni::GetCurrentTabState()
  564. {
  565. if (!m_fInitialized)
  566. return GetAppliedTabState();
  567. BOOL fAllEnabled = TRUE, fAllDisabled = TRUE;
  568. HTREEITEM hti = TreeView_GetRoot(m_tree.m_hWnd);
  569. TVITEM tvi;
  570. tvi.mask = TVIF_IMAGE;
  571. while (hti)
  572. {
  573. tvi.hItem = hti;
  574. if (TreeView_GetItem(m_tree.m_hWnd, &tvi))
  575. {
  576. if (m_uncheckedID != tvi.iImage)
  577. fAllDisabled = FALSE;
  578. if (m_checkedID != tvi.iImage)
  579. fAllEnabled = FALSE;
  580. }
  581. hti = TreeView_GetNextSibling(m_tree.m_hWnd, hti);
  582. }
  583. return ((fAllEnabled) ? NORMAL : ((fAllDisabled) ? DIAGNOSTIC : USER));
  584. }
  585. //-------------------------------------------------------------------------
  586. // Apply the changes by saving the INI file.
  587. //
  588. // The base class implementation is called to maintain the
  589. // applied tab state.
  590. //-------------------------------------------------------------------------
  591. BOOL CPageIni::OnApply()
  592. {
  593. if (!m_fModified)
  594. return TRUE;
  595. WriteINIFile(m_lines, m_iLastLine);
  596. CPageBase::SetAppliedState(GetCurrentTabState());
  597. m_fMadeChange = TRUE;
  598. return TRUE;
  599. }
  600. //-------------------------------------------------------------------------
  601. // To commit the changes, write the INI file without the distinguishing
  602. // comments (by calling WriteINIFile with FALSE as the last param).
  603. //
  604. // Then call the base class implementation.
  605. //-------------------------------------------------------------------------
  606. void CPageIni::CommitChanges()
  607. {
  608. WriteINIFile(m_lines, m_iLastLine, FALSE);
  609. LoadINIFile(m_lines, m_iLastLine);
  610. UpdateTreeView();
  611. CPageBase::CommitChanges();
  612. }
  613. //-------------------------------------------------------------------------
  614. // Set the overall state of the tab to normal or diagnostic.
  615. //-------------------------------------------------------------------------
  616. void CPageIni::SetNormal()
  617. {
  618. HWND hwndTree = m_tree.m_hWnd;
  619. HTREEITEM hti = TreeView_GetRoot(hwndTree);
  620. while (hti != NULL)
  621. {
  622. SetEnable(TRUE, hti, TRUE, FALSE);
  623. hti = TreeView_GetNextSibling(hwndTree, hti);
  624. }
  625. SetModified(TRUE);
  626. UpdateControls();
  627. }
  628. void CPageIni::SetDiagnostic()
  629. {
  630. HWND hwndTree = m_tree.m_hWnd;
  631. HTREEITEM hti = TreeView_GetRoot(hwndTree);
  632. while (hti != NULL)
  633. {
  634. SetEnable(FALSE, hti, TRUE, FALSE);
  635. hti = TreeView_GetNextSibling(hwndTree, hti);
  636. }
  637. SetModified(TRUE);
  638. UpdateControls();
  639. }
  640. //-------------------------------------------------------------------------
  641. // We need to look at user clicks on the tree view. If it is on an item,
  642. // and also on the item's image, then we'll need to toggle the image
  643. // state.
  644. //-------------------------------------------------------------------------
  645. void CPageIni::OnClickTree(NMHDR* pNMHDR, LRESULT* pResult)
  646. {
  647. // Determine if this tree click is on a node, and if it is,
  648. // if it is on the image.
  649. TVHITTESTINFO tvhti;
  650. DWORD dwPoint = GetMessagePos();
  651. tvhti.pt.x = ((int)(short)LOWORD(dwPoint));
  652. tvhti.pt.y = ((int)(short)HIWORD(dwPoint));
  653. ::ScreenToClient(m_tree.m_hWnd, &tvhti.pt);
  654. HTREEITEM hti = TreeView_HitTest(m_tree.m_hWnd, &tvhti);
  655. if (hti != NULL && (tvhti.flags & TVHT_ONITEMICON) != 0)
  656. {
  657. // This is a click that we care about. We need to get the
  658. // current state of this node so we know which way to
  659. // toggle the state. We'll make an arbitrary decision
  660. // that the toggle from undetermined is to enabled.
  661. TVITEM tvi;
  662. tvi.hItem = hti;
  663. tvi.mask = TVIF_IMAGE;
  664. if (TreeView_GetItem(m_tree.m_hWnd, &tvi))
  665. {
  666. SetEnable(tvi.iImage != m_checkedID, hti);
  667. UpdateControls();
  668. }
  669. }
  670. }
  671. //-------------------------------------------------------------------------
  672. // We allow the user to edit the lines in the INI file. When the user
  673. // is through editing, we want to make sure we notify the framework
  674. // that a change has been made.
  675. //-------------------------------------------------------------------------
  676. void CPageIni::OnButtonEdit()
  677. {
  678. HTREEITEM hti = TreeView_GetSelection(m_tree.m_hWnd);
  679. if (hti != NULL)
  680. {
  681. ::SetFocus(m_tree.m_hWnd);
  682. TreeView_EditLabel(m_tree.m_hWnd, hti);
  683. }
  684. }
  685. //-------------------------------------------------------------------------
  686. // WndProc for the edit control when editing a label in the tree (handles
  687. // enter/esc better). Lifted from ME source.
  688. //-------------------------------------------------------------------------
  689. WNDPROC pOldEditProc = NULL; // save old wndproc when we subclass edit control
  690. LRESULT TreeViewEditSubclassProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp)
  691. {
  692. switch (wm)
  693. {
  694. case WM_GETDLGCODE:
  695. return DLGC_WANTALLKEYS;
  696. // The Knowledge Base article describing the work-around for this
  697. // this bug indicates the following handling of VK_ESCAPE & VK_RETURN
  698. // is necessary -- however, under Memphis & OSR2 these keys are never
  699. // received (returning DLGC_WANTALLKEYS seems to fix the problem).
  700. // Perhaps it depends on which comctl32.dll is installed...
  701. case WM_CHAR:
  702. if (wp == VK_ESCAPE || wp == VK_RETURN)
  703. {
  704. TreeView_EndEditLabelNow(GetParent(hwnd), wp == VK_ESCAPE);
  705. return 0;
  706. }
  707. break;
  708. }
  709. if (pOldEditProc) // better not be null
  710. return CallWindowProc(pOldEditProc, hwnd, wm, wp, lp);
  711. return 0;
  712. }
  713. //-------------------------------------------------------------------------
  714. // The tree view doesn't handle enter and esc correctly, so when we start
  715. // editing a label, we need to subclass the control.
  716. //-------------------------------------------------------------------------
  717. void CPageIni::OnBeginLabelEditIniTree(NMHDR * pNMHDR, LRESULT * pResult)
  718. {
  719. TV_DISPINFO * pTVDispInfo = (TV_DISPINFO *)pNMHDR;
  720. // Disable Move Up and Down buttons while editing.
  721. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONINIMOVEUP), FALSE);
  722. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONINIMOVEDOWN), FALSE);
  723. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONINIEDIT), FALSE);
  724. // TreeView controls don't properly handle Esc/Enter when editing
  725. // a label. To fix this, it's necessary to subclass the label's edit
  726. // control and process Esc & Enter ourselves. Sigh...
  727. HWND hWndEdit = TreeView_GetEditControl(m_tree.m_hWnd);
  728. if (hWndEdit)
  729. {
  730. pOldEditProc = (WNDPROC)::GetWindowLongPtr(hWndEdit, GWLP_WNDPROC);
  731. ::SetWindowLongPtr(hWndEdit, GWLP_WNDPROC, (ULONG_PTR)(WNDPROC)&TreeViewEditSubclassProc);
  732. }
  733. *pResult = 0;
  734. }
  735. void CPageIni::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
  736. {
  737. TV_DISPINFO * pTVDispInfo = (TV_DISPINFO *)pNMHDR;
  738. // Stop subclassing the edit control.
  739. HWND hWndEdit = TreeView_GetEditControl(m_tree.m_hWnd);
  740. if (hWndEdit && pOldEditProc)
  741. {
  742. ::SetWindowLongPtr(hWndEdit, GWLP_WNDPROC, (ULONG_PTR)(WNDPROC)pOldEditProc);
  743. pOldEditProc = NULL;
  744. }
  745. // If the new text pointer is null, then the edit was cancelled.
  746. // We only care if a new item was being added, in which case
  747. // we should delete it.
  748. if (pTVDispInfo->item.pszText == NULL)
  749. {
  750. TCHAR szBuffer[MAX_PATH];
  751. TVITEM tvi;
  752. tvi.pszText = szBuffer;
  753. tvi.mask = TVIF_TEXT;
  754. tvi.hItem = pTVDispInfo->item.hItem;
  755. tvi.cchTextMax = MAX_PATH;
  756. if (TreeView_GetItem(m_tree.m_hWnd, &tvi) && tvi.pszText && tvi.pszText[0] == _T('\0'))
  757. {
  758. HTREEITEM hPriorItem = TreeView_GetPrevSibling(pTVDispInfo->hdr.hwndFrom, pTVDispInfo->item.hItem);
  759. if (hPriorItem == NULL)
  760. hPriorItem = TreeView_GetParent(pTVDispInfo->hdr.hwndFrom, pTVDispInfo->item.hItem);
  761. TreeView_DeleteItem(m_tree.m_hWnd, pTVDispInfo->item.hItem);
  762. if (hPriorItem)
  763. TreeView_SelectItem(pTVDispInfo->hdr.hwndFrom, hPriorItem);
  764. }
  765. *pResult = 0;
  766. }
  767. else
  768. {
  769. SetModified(TRUE);
  770. *pResult = 1;
  771. }
  772. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONINIEDIT), TRUE);
  773. UpdateControls();
  774. }
  775. //-------------------------------------------------------------------------
  776. // If the user clicks on the new button, then add an empty tree view
  777. // node after the currently selected one. If the selected node has
  778. // children, add the node as the first child under the selected node.
  779. // Then select the node for editing.
  780. //-------------------------------------------------------------------------
  781. void CPageIni::OnButtonNew()
  782. {
  783. HTREEITEM hti = TreeView_GetSelection(m_tree.m_hWnd);
  784. if (hti == NULL)
  785. hti = TreeView_GetRoot(m_tree.m_hWnd);
  786. if (hti == NULL)
  787. return;
  788. TVINSERTSTRUCT tvis;
  789. if (TreeView_GetChild(m_tree.m_hWnd, hti) != NULL)
  790. {
  791. tvis.hParent = hti;
  792. tvis.hInsertAfter = TVI_FIRST;
  793. }
  794. else
  795. {
  796. tvis.hParent = TreeView_GetParent(m_tree.m_hWnd, hti);
  797. tvis.hInsertAfter = hti;
  798. }
  799. TCHAR szBuffer[] = _T("");
  800. tvis.itemex.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  801. tvis.itemex.iImage = m_checkedID;
  802. tvis.itemex.iSelectedImage = m_checkedID;
  803. tvis.itemex.pszText = szBuffer;
  804. HTREEITEM htiNew = TreeView_InsertItem(m_tree.m_hWnd, &tvis);
  805. if (htiNew != NULL)
  806. {
  807. TreeView_SelectItem(m_tree.m_hWnd, htiNew);
  808. TreeView_EditLabel(m_tree.m_hWnd, htiNew);
  809. }
  810. }
  811. //-------------------------------------------------------------------------
  812. // If the user hits the space bar with an item selected in the tree, toggle
  813. // the state of the item.
  814. //-------------------------------------------------------------------------
  815. void CPageIni::OnKeyDownTree(NMHDR* pNMHDR, LRESULT* pResult)
  816. {
  817. TV_KEYDOWN * pTVKeyDown = (TV_KEYDOWN *)pNMHDR;
  818. if (pTVKeyDown->wVKey == VK_SPACE)
  819. {
  820. HTREEITEM hti = TreeView_GetSelection(m_tree.m_hWnd);
  821. if (hti != NULL)
  822. {
  823. TVITEM tvi;
  824. tvi.mask = TVIF_IMAGE;
  825. tvi.hItem = hti;
  826. if (TreeView_GetItem(m_tree.m_hWnd, &tvi))
  827. {
  828. SetEnable(tvi.iImage != m_checkedID, hti);
  829. UpdateControls();
  830. }
  831. }
  832. }
  833. *pResult = 0;
  834. }