comctl32/tests: Add tests for wizard dialog navigation.
[wine] / dlls / comctl32 / tests / propsheet.c
1 /* Unit test suite for property sheet control.
2  *
3  * Copyright 2006 Huw Davies
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include <windows.h>
21 #include <commctrl.h>
22
23 #include "resources.h"
24
25 #include "wine/test.h"
26
27 static HWND parent;
28
29 static LONG active_page = -1;
30
31 static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam)
32 {
33     switch(msg)
34     {
35     case PSCB_INITIALIZED:
36       {
37         char caption[256];
38         GetWindowTextA(hwnd, caption, sizeof(caption));
39         ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
40         return 0;
41       }
42     }
43     return 0;
44 }
45         
46 static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
47                                       LPARAM lparam)
48 {
49     switch(msg)
50     {
51     case WM_INITDIALOG:
52       {
53         HWND sheet = GetParent(hwnd);
54         char caption[256];
55         GetWindowTextA(sheet, caption, sizeof(caption));
56         ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
57         return TRUE;
58       }
59
60     case WM_NOTIFY:
61       {
62         NMHDR *nmhdr = (NMHDR *)lparam;
63         switch(nmhdr->code)
64         {
65         case PSN_APPLY:
66             return TRUE;
67         default:
68             return FALSE;
69         }
70       }
71     default:
72         return FALSE;
73     }
74 }
75
76 static void test_title(void)
77 {
78     HPROPSHEETPAGE hpsp[1];
79     PROPSHEETPAGEA psp;
80     PROPSHEETHEADERA psh;
81     HWND hdlg;
82
83     memset(&psp, 0, sizeof(psp));
84     psp.dwSize = sizeof(psp);
85     psp.dwFlags = 0;
86     psp.hInstance = GetModuleHandleW(NULL);
87     U(psp).pszTemplate = "prop_page1";
88     U2(psp).pszIcon = NULL;
89     psp.pfnDlgProc = page_dlg_proc;
90     psp.lParam = 0;
91
92     hpsp[0] = CreatePropertySheetPageA(&psp);
93
94     memset(&psh, 0, sizeof(psh));
95     psh.dwSize = sizeof(psh);
96     psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
97     psh.pszCaption = "test caption";
98     psh.nPages = 1;
99     psh.hwndParent = GetDesktopWindow();
100     U3(psh).phpage = hpsp;
101     psh.pfnCallback = sheet_callback;
102
103     hdlg = (HWND)PropertySheetA(&psh);
104     DestroyWindow(hdlg);
105 }
106
107 static void test_nopage(void)
108 {
109     HPROPSHEETPAGE hpsp[1];
110     PROPSHEETPAGEA psp;
111     PROPSHEETHEADERA psh;
112     HWND hdlg;
113
114     memset(&psp, 0, sizeof(psp));
115     psp.dwSize = sizeof(psp);
116     psp.dwFlags = 0;
117     psp.hInstance = GetModuleHandleW(NULL);
118     U(psp).pszTemplate = "prop_page1";
119     U2(psp).pszIcon = NULL;
120     psp.pfnDlgProc = page_dlg_proc;
121     psp.lParam = 0;
122
123     hpsp[0] = CreatePropertySheetPageA(&psp);
124
125     memset(&psh, 0, sizeof(psh));
126     psh.dwSize = sizeof(psh);
127     psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
128     psh.pszCaption = "test caption";
129     psh.nPages = 1;
130     psh.hwndParent = GetDesktopWindow();
131     U3(psh).phpage = hpsp;
132     psh.pfnCallback = sheet_callback;
133
134     hdlg = (HWND)PropertySheetA(&psh);
135     ShowWindow(hdlg,SW_NORMAL);
136     SendMessage(hdlg, PSM_REMOVEPAGE, 0, 0);
137     RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW);
138     DestroyWindow(hdlg);
139 }
140
141 static int CALLBACK disableowner_callback(HWND hwnd, UINT msg, LPARAM lparam)
142 {
143     switch(msg)
144     {
145     case PSCB_INITIALIZED:
146       {
147         ok(IsWindowEnabled(parent) == 0, "parent window should be disabled\n");
148         PostQuitMessage(0);
149         return FALSE;
150       }
151     }
152     return FALSE;
153 }
154
155 static void register_parent_wnd_class(void)
156 {
157     WNDCLASSA cls;
158
159     cls.style = 0;
160     cls.lpfnWndProc = DefWindowProcA;
161     cls.cbClsExtra = 0;
162     cls.cbWndExtra = 0;
163     cls.hInstance = GetModuleHandleA(NULL);
164     cls.hIcon = 0;
165     cls.hCursor = LoadCursorA(0, IDC_ARROW);
166     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
167     cls.lpszMenuName = NULL;
168     cls.lpszClassName = "parent class";
169     RegisterClassA(&cls);
170 }
171
172 static void test_disableowner(void)
173 {
174     HPROPSHEETPAGE hpsp[1];
175     PROPSHEETPAGEA psp;
176     PROPSHEETHEADERA psh;
177
178     register_parent_wnd_class();
179     parent = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0);
180
181     memset(&psp, 0, sizeof(psp));
182     psp.dwSize = sizeof(psp);
183     psp.dwFlags = 0;
184     psp.hInstance = GetModuleHandleW(NULL);
185     U(psp).pszTemplate = "prop_page1";
186     U2(psp).pszIcon = NULL;
187     psp.pfnDlgProc = NULL;
188     psp.lParam = 0;
189
190     hpsp[0] = CreatePropertySheetPageA(&psp);
191
192     memset(&psh, 0, sizeof(psh));
193     psh.dwSize = sizeof(psh);
194     psh.dwFlags = PSH_USECALLBACK;
195     psh.pszCaption = "test caption";
196     psh.nPages = 1;
197     psh.hwndParent = parent;
198     U3(psh).phpage = hpsp;
199     psh.pfnCallback = disableowner_callback;
200
201     PropertySheetA(&psh);
202     ok(IsWindowEnabled(parent) != 0, "parent window should be enabled\n");
203     DestroyWindow(parent);
204 }
205
206 static LRESULT CALLBACK nav_page_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
207 {
208     switch(msg){
209     case WM_NOTIFY:
210         {
211             LPNMHDR hdr = (LPNMHDR)lparam;
212             switch(hdr->code){
213             case PSN_SETACTIVE:
214                 active_page = PropSheet_HwndToIndex(hdr->hwndFrom, hwnd);
215                 break;
216             case PSN_KILLACTIVE:
217                 /* prevent navigation away from the fourth page */
218                 if(active_page == 3){
219                     SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE);
220                     return TRUE;
221                 }
222             }
223             break;
224         }
225     }
226     return DefWindowProc(hwnd, msg, wparam, lparam);
227 }
228
229 static void test_wiznavigation(void)
230 {
231     HPROPSHEETPAGE hpsp[4];
232     PROPSHEETPAGEA psp[4];
233     PROPSHEETHEADERA psh;
234     HWND hdlg, control;
235     LONG_PTR controlID;
236     LRESULT defidres;
237     const INT nextID = 12324;
238     const INT backID = 12323;
239
240     /* create the property sheet pages */
241     memset(psp, 0, sizeof(PROPSHEETPAGEA) * 4);
242
243     psp[0].dwSize = sizeof(PROPSHEETPAGEA);
244     psp[0].hInstance = GetModuleHandleW(NULL);
245     U(psp[0]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_INTRO);
246     psp[0].pfnDlgProc = nav_page_proc;
247     hpsp[0] = CreatePropertySheetPageA(&psp[0]);
248
249     psp[1].dwSize = sizeof(PROPSHEETPAGEA);
250     psp[1].hInstance = GetModuleHandleW(NULL);
251     U(psp[1]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_EDIT);
252     psp[1].pfnDlgProc = nav_page_proc;
253     hpsp[1] = CreatePropertySheetPageA(&psp[1]);
254
255     psp[2].dwSize = sizeof(PROPSHEETPAGEA);
256     psp[2].hInstance = GetModuleHandleW(NULL);
257     U(psp[2]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_RADIO);
258     psp[2].pfnDlgProc = nav_page_proc;
259     hpsp[2] = CreatePropertySheetPageA(&psp[2]);
260
261     psp[3].dwSize = sizeof(PROPSHEETPAGEA);
262     psp[3].hInstance = GetModuleHandleW(NULL);
263     U(psp[3]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_EXIT);
264     psp[3].pfnDlgProc = nav_page_proc;
265     hpsp[3] = CreatePropertySheetPageA(&psp[3]);
266
267     /* set up the property sheet dialog */
268     memset(&psh, 0, sizeof(psh));
269     psh.dwSize = sizeof(psh);
270     psh.dwFlags = PSH_MODELESS | PSH_WIZARD;
271     psh.pszCaption = "A Wizard";
272     psh.nPages = 4;
273     psh.hwndParent = GetDesktopWindow();
274     U3(psh).phpage = hpsp;
275     hdlg = (HWND)PropertySheetA(&psh);
276
277     ok(active_page == 0, "Active page should be 0. Is: %d\n", active_page);
278
279     control = GetFocus();
280     controlID = GetWindowLongPtr(control, GWLP_ID);
281     ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
282
283     /* simulate pressing the Next button */
284     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
285     ok(active_page == 1, "Active page should be 1 after pressing Next. Is: %d\n", active_page);
286
287     control = GetFocus();
288     controlID = GetWindowLongPtr(control, GWLP_ID);
289     ok(controlID == IDC_PS_EDIT1, "Focus should be set to the first item on the second page. Expected: %d, Found: %ld\n", IDC_PS_EDIT1, controlID);
290
291     defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
292     ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
293
294     /* set the focus to the second edit box on this page */
295     SetFocus(GetNextDlgTabItem(hdlg, control, FALSE));
296
297     /* press next again */
298     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
299     ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
300
301     control = GetFocus();
302     controlID = GetWindowLongPtr(control, GWLP_ID);
303     ok(controlID == IDC_PS_RADIO1, "Focus should have been set to item on third page. Expected: %d, Found %ld\n", IDC_PS_RADIO1, controlID);
304
305     /* back button */
306     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
307     ok(active_page == 1, "Active page should be 1 after pressing Back. Is: %d\n", active_page);
308
309     control = GetFocus();
310     controlID = GetWindowLongPtr(control, GWLP_ID);
311     ok(controlID == IDC_PS_EDIT1, "Focus should have been set to the first item on second page. Expected: %d, Found %ld\n", IDC_PS_EDIT1, controlID);
312
313     defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
314     ok(defidres == MAKELRESULT(backID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", backID, LOWORD(defidres));
315
316     /* press next twice */
317     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
318     ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
319     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
320     ok(active_page == 3, "Active page should be 3 after pressing Next. Is: %d\n", active_page);
321
322     control = GetFocus();
323     controlID = GetWindowLongPtr(control, GWLP_ID);
324     ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
325
326     /* try to navigate away, but shouldn't be able to */
327     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
328     ok(active_page == 3, "Active page should still be 3 after pressing Back. Is: %d\n", active_page);
329
330     defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
331     ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
332
333     DestroyWindow(hdlg);
334 }
335
336 START_TEST(propsheet)
337 {
338     test_title();
339     test_nopage();
340     test_disableowner();
341     test_wiznavigation();
342 }