Source code of Windows XP (NT5)
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.

477 lines
10 KiB

  1. // This is a part of the Active Template Library.
  2. // Copyright (C) Microsoft Corporation, 1996 - 1999
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Active Template Library Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Active Template Library product.
  10. // Original file obtained from Nenad Stefanovic (ATL Team) as
  11. // part of WTL (Windows Template Library)
  12. // Kept just all the property page and property sheet classes
  13. #ifndef __ATLDLGS_H__
  14. #define __ATLDLGS_H__
  15. #ifndef __cplusplus
  16. #error ATL requires C++ compilation (use a .cpp suffix)
  17. #endif
  18. #ifndef __ATLWIN_H__
  19. #error atldlgs.h requires atlwin.h to be included first
  20. #endif
  21. #include <commdlg.h>
  22. #include <commctrl.h>
  23. // copied from the new ATLWIN.H file to work with standard ATL 2.1
  24. #define DECLARE_EMPTY_MSG_MAP() \
  25. public: \
  26. BOOL ProcessWindowMessage(HWND, UINT, WPARAM, LPARAM, LRESULT&, DWORD) \
  27. { \
  28. return FALSE; \
  29. }
  30. namespace ATL
  31. {
  32. /////////////////////////////////////////////////////////////////////////////
  33. // Forward declarations
  34. template <class T> class CPropertySheetImpl;
  35. class CPropertySheet;
  36. template <class T> class CPropertyPageImpl;
  37. /////////////////////////////////////////////////////////////////////////////
  38. // CPropertySheetImpl - implements a property sheet
  39. template <class T>
  40. class ATL_NO_VTABLE CPropertySheetImpl : public CWindowImplBase
  41. {
  42. public:
  43. PROPSHEETHEADER m_psh;
  44. // Construction/Destruction
  45. CPropertySheetImpl(LPCTSTR lpszTitle = NULL, UINT uStartPage = 0)
  46. {
  47. memset(&m_psh, 0, sizeof(PROPSHEETHEADER));
  48. m_psh.dwSize = sizeof(PROPSHEETHEADER);
  49. m_psh.dwFlags = PSH_USECALLBACK;
  50. m_psh.phpage = NULL;
  51. m_psh.nPages = 0;
  52. m_psh.pszCaption = lpszTitle;
  53. m_psh.nStartPage = uStartPage;
  54. m_psh.hwndParent = NULL; // will be set in DoModal/Create
  55. m_psh.hInstance = _Module.GetResourceInstance();
  56. m_psh.pfnCallback = T::PropSheetCallback;
  57. }
  58. ~CPropertySheetImpl()
  59. {
  60. if(m_psh.phpage != NULL)
  61. delete[] m_psh.phpage;
  62. }
  63. static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM)
  64. {
  65. if(uMsg == PSCB_INITIALIZED)
  66. {
  67. _ASSERTE(hWnd != NULL);
  68. CWindowImplBase* pT = (CWindowImplBase*)_Module.ExtractCreateWndData();
  69. pT->SubclassWindow(hWnd);
  70. }
  71. return 0;
  72. }
  73. HWND Create(HWND hWndParent = NULL)
  74. {
  75. _ASSERTE(m_hWnd == NULL);
  76. m_psh.dwFlags |= PSH_MODELESS;
  77. m_psh.hwndParent = hWndParent;
  78. _Module.AddCreateWndData(&m_thunk.cd, (CWindowImplBase*)this);
  79. HWND hWnd = (HWND)::PropertySheet(&m_psh);
  80. _ASSERTE(m_hWnd == hWnd);
  81. return hWnd;
  82. }
  83. int DoModal(HWND hWndParent = ::GetActiveWindow())
  84. {
  85. _ASSERTE(m_hWnd == NULL);
  86. m_psh.dwFlags &= ~PSH_MODELESS;
  87. m_psh.hwndParent = hWndParent;
  88. _Module.AddCreateWndData(&m_thunk.cd, (CWindowImplBase*)this);
  89. int nRet = ::PropertySheet(&m_psh);
  90. m_hWnd = NULL;
  91. return nRet;
  92. }
  93. // Attributes
  94. UINT GetPageCount() const
  95. {
  96. if(m_hWnd == NULL)
  97. return m_psh.nPages;
  98. HWND hWndTabCtrl = GetTabControl();
  99. _ASSERTE(hWndTabCtrl != NULL);
  100. return (UINT)::SendMessage(hWndTabCtrl, TCM_GETITEMCOUNT, 0, 0L);
  101. }
  102. HWND GetActivePage() const
  103. {
  104. _ASSERTE(::IsWindow(m_hWnd));
  105. return (HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0L);
  106. }
  107. UINT GetActiveIndex() const
  108. {
  109. if(m_hWnd == NULL)
  110. return m_psh.nStartPage;
  111. HWND hWndTabCtrl = GetTabControl();
  112. _ASSERTE(hWndTabCtrl != NULL);
  113. return (UINT)::SendMessage(hWndTabCtrl, TCM_GETCURSEL, 0, 0L);
  114. }
  115. HPROPSHEETPAGE GetPage(UINT uPageIndex)
  116. {
  117. _ASSERTE(uPageIndex < m_psh.nPages);
  118. return m_psh.phpage[uPageIndex];
  119. }
  120. UINT GetPageIndex(HPROPSHEETPAGE hPage)
  121. {
  122. for(UINT i = 0; i < m_psh.nPages; i++)
  123. {
  124. if(m_psh.phpage[i] == hPage)
  125. return i;
  126. }
  127. return (UINT)-1; // hPage not found
  128. }
  129. BOOL SetActivePage(UINT uPageIndex)
  130. {
  131. if(m_hWnd == NULL)
  132. {
  133. m_psh.nStartPage = uPageIndex;
  134. return TRUE;
  135. }
  136. return (BOOL)SendMessage(PSM_SETCURSEL, uPageIndex);
  137. }
  138. BOOL SetActivePage(HPROPSHEETPAGE hPage)
  139. {
  140. _ASSERTE(hPage != NULL);
  141. UINT uPageIndex = GetPageIndex(hPage);
  142. if(uPageIndex == (UINT)-1)
  143. return FALSE;
  144. return SetActivePage(uPageIndex);
  145. }
  146. void SetTitle(LPCTSTR lpszText, UINT nStyle = 0)
  147. {
  148. _ASSERTE((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid
  149. _ASSERTE(lpszText == NULL);
  150. if(m_hWnd == NULL)
  151. {
  152. // set internal state
  153. m_psh.pszCaption = lpszText;
  154. m_psh.dwFlags &= ~PSH_PROPTITLE;
  155. m_psh.dwFlags |= nStyle;
  156. }
  157. else
  158. {
  159. // set external state
  160. SendMessage(PSM_SETTITLE, nStyle, (LPARAM)lpszText);
  161. }
  162. }
  163. HWND GetTabControl() const
  164. {
  165. _ASSERTE(::IsWindow(m_hWnd));
  166. return (HWND)::SendMessage(m_hWnd, PSM_GETTABCONTROL, 0, 0L);
  167. }
  168. void SetWizardMode()
  169. {
  170. m_psh.dwFlags |= PSH_WIZARD;
  171. }
  172. void SetFinishText(LPCTSTR lpszText)
  173. {
  174. _ASSERTE(::IsWindow(m_hWnd));
  175. ::SendMessage(m_hWnd, PSM_SETFINISHTEXT, 0, (LPARAM)lpszText);
  176. }
  177. void SetWizardButtons(DWORD dwFlags)
  178. {
  179. _ASSERTE(::IsWindow(m_hWnd));
  180. ::SendMessage(m_hWnd, PSM_SETWIZBUTTONS, 0, dwFlags);
  181. }
  182. // Operations
  183. BOOL AddPage(HPROPSHEETPAGE hPage)
  184. {
  185. _ASSERTE(hPage != NULL);
  186. // add page to internal list
  187. HPROPSHEETPAGE* php = (HPROPSHEETPAGE*)realloc(m_psh.phpage, (m_psh.nPages + 1) * sizeof(HPROPSHEETPAGE));
  188. if(php == NULL)
  189. return FALSE;
  190. m_psh.phpage = php;
  191. m_psh.phpage[m_psh.nPages] = hPage;
  192. m_psh.nPages++;
  193. if(m_hWnd != NULL)
  194. ::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage);
  195. return TRUE;
  196. }
  197. BOOL AddPage(LPCPROPSHEETPAGE pPage)
  198. {
  199. _ASSERTE(pPage != NULL);
  200. HPROPSHEETPAGE hPSP = ::CreatePropertySheetPage(pPage);
  201. if(hPSP == NULL)
  202. return FALSE;
  203. AddPage(hPSP);
  204. return TRUE;
  205. }
  206. BOOL RemovePage(HPROPSHEETPAGE hPage)
  207. {
  208. _ASSERTE(hPage != NULL);
  209. int nPage = GetPageIndex(hPage);
  210. if(nPage == -1)
  211. return FALSE;
  212. return RemovePage(nPage);
  213. }
  214. BOOL RemovePage(UINT uPageIndex)
  215. {
  216. // remove the page externally
  217. if(m_hWnd != NULL)
  218. SendMessage(PSM_REMOVEPAGE, uPageIndex);
  219. // remove the page from internal list
  220. if(uPageIndex >= m_psh.nPages)
  221. return FALSE;
  222. if(!DestroyPropertySheetPage(m_psh.phpage[uPageIndex]))
  223. return FALSE;
  224. for(UINT i = uPageIndex; i < m_psh.nPages - 1; i++)
  225. m_psh.phpage[i] = m_psh.phpage[i+1];
  226. m_psh.phpage = (HPROPSHEETPAGE*)realloc(m_psh.phpage, (m_psh.nPages - 1) * sizeof(HPROPSHEETPAGE));
  227. m_psh.nPages--;
  228. return TRUE;
  229. }
  230. BOOL PressButton(int nButton)
  231. {
  232. _ASSERTE(::IsWindow(m_hWnd));
  233. return (BOOL)::SendMessage(m_hWnd, PSM_PRESSBUTTON, nButton, 0L);
  234. }
  235. };
  236. class CPropertySheet : public CPropertySheetImpl<CPropertySheet>
  237. {
  238. public:
  239. CPropertySheet(LPCTSTR lpszTitle = NULL, UINT uStartPage = 0)
  240. : CPropertySheetImpl<CPropertySheet>(lpszTitle, uStartPage)
  241. { }
  242. DECLARE_EMPTY_MSG_MAP()
  243. };
  244. /////////////////////////////////////////////////////////////////////////////
  245. // CPropertyPageImpl - implements a property page
  246. template <class T>
  247. class ATL_NO_VTABLE CPropertyPageImpl : public CDialogImplBase
  248. {
  249. public:
  250. PROPSHEETPAGE m_psp;
  251. operator PROPSHEETPAGE*() { return &m_psp; }
  252. // Construction
  253. CPropertyPageImpl(LPCTSTR lpszTitle = NULL)
  254. {
  255. // initialize PROPSHEETPAGE struct
  256. memset(&m_psp, 0, sizeof(PROPSHEETPAGE));
  257. m_psp.dwSize = sizeof(PROPSHEETPAGE);
  258. m_psp.dwFlags = PSP_USECALLBACK;
  259. m_psp.hInstance = _Module.GetResourceInstance();
  260. m_psp.pszTemplate = MAKEINTRESOURCE(T::IDD);
  261. m_psp.pfnDlgProc = (DLGPROC)T::StartDialogProc;
  262. m_psp.pfnCallback = T::PropPageCallback;
  263. m_psp.lParam = (LPARAM)this;
  264. if(lpszTitle != NULL)
  265. {
  266. m_psp.pszTitle = lpszTitle;
  267. m_psp.dwFlags |= PSP_USETITLE;
  268. }
  269. }
  270. static UINT CALLBACK PropPageCallback(HWND hWnd, UINT uMsg, LPPROPSHEETPAGE ppsp)
  271. {
  272. if(uMsg == PSPCB_CREATE)
  273. {
  274. _ASSERTE(hWnd == NULL);
  275. CDialogImplBase* pPage = (CDialogImplBase*)ppsp->lParam;
  276. _Module.AddCreateWndData(&pPage->m_thunk.cd, pPage);
  277. }
  278. return 1;
  279. }
  280. HPROPSHEETPAGE Create()
  281. {
  282. return ::CreatePropertySheetPage(&m_psp);
  283. }
  284. BOOL EndDialog(int)
  285. {
  286. // do nothing here, calling ::EndDialog will close the whole sheet
  287. _ASSERTE(FALSE);
  288. return FALSE;
  289. }
  290. // Operations
  291. void CancelToClose()
  292. {
  293. _ASSERTE(::IsWindow(m_hWnd));
  294. _ASSERTE(GetParent() != NULL);
  295. ::SendMessage(GetParent(), PSM_CANCELTOCLOSE, 0, 0L);
  296. }
  297. void SetModified(BOOL bChanged = TRUE)
  298. {
  299. _ASSERTE(::IsWindow(m_hWnd));
  300. _ASSERTE(GetParent() != NULL);
  301. if(bChanged)
  302. ::SendMessage(GetParent(), PSM_CHANGED, (WPARAM)m_hWnd, 0L);
  303. else
  304. ::SendMessage(GetParent(), PSM_UNCHANGED, (WPARAM)m_hWnd, 0L);
  305. }
  306. LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam)
  307. {
  308. _ASSERTE(::IsWindow(m_hWnd));
  309. _ASSERTE(GetParent() != NULL);
  310. return ::SendMessage(GetParent(), PSM_QUERYSIBLINGS, wParam, lParam);
  311. }
  312. BEGIN_MSG_MAP(CPropertyPageImpl< T >)
  313. MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
  314. END_MSG_MAP()
  315. // Message handler
  316. LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  317. {
  318. _ASSERTE(::IsWindow(m_hWnd));
  319. NMHDR* pNMHDR = (NMHDR*)lParam;
  320. // don't handle messages not from the page/sheet itself
  321. if(pNMHDR->hwndFrom != m_hWnd && pNMHDR->hwndFrom != ::GetParent(m_hWnd))
  322. {
  323. bHandled = FALSE;
  324. return 1;
  325. }
  326. T* pT = static_cast<T*>(this);
  327. LRESULT lResult = 0;
  328. // handle default
  329. switch(pNMHDR->code)
  330. {
  331. case PSN_SETACTIVE:
  332. //? other values
  333. lResult = pT->OnSetActive() ? 0 : -1;
  334. break;
  335. case PSN_KILLACTIVE:
  336. lResult = !pT->OnKillActive();
  337. break;
  338. case PSN_APPLY:
  339. lResult = pT->OnApply() ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE;
  340. break;
  341. case PSN_RESET:
  342. pT->OnReset();
  343. break;
  344. case PSN_QUERYCANCEL:
  345. lResult = !pT->OnQueryCancel();
  346. break;
  347. case PSN_WIZNEXT:
  348. //? other values
  349. lResult = pT->OnWizardNext();
  350. break;
  351. case PSN_WIZBACK:
  352. lResult = pT->OnWizardBack();
  353. break;
  354. case PSN_WIZFINISH:
  355. lResult = !pT->OnWizardFinish();
  356. break;
  357. case PSN_HELP:
  358. /**/ lResult = pT->OnHelp();
  359. break;
  360. default:
  361. bHandled = FALSE; // not handled
  362. }
  363. return lResult;
  364. }
  365. // Overridables
  366. BOOL OnSetActive()
  367. {
  368. return TRUE;
  369. }
  370. BOOL OnKillActive()
  371. {
  372. return TRUE;
  373. }
  374. BOOL OnApply()
  375. {
  376. return TRUE;
  377. }
  378. void OnReset()
  379. {
  380. }
  381. BOOL OnQueryCancel()
  382. {
  383. return TRUE; // ok to cancel
  384. }
  385. LRESULT OnWizardBack()
  386. {
  387. return 0; // default go to previous page
  388. }
  389. LRESULT OnWizardNext()
  390. {
  391. return 0; // default go to next page
  392. }
  393. BOOL OnWizardFinish()
  394. {
  395. return TRUE;
  396. }
  397. BOOL OnHelp()
  398. {
  399. return TRUE;
  400. }
  401. };
  402. }; //namespace ATL
  403. #endif // __ATLDLGS_H__