comctl32: listview: Create the LISTVIEW_INFO in WM_NCCREATE.
[wine] / dlls / comctl32 / tests / listview.c
1 /*
2  * ListView tests
3  *
4  * Copyright 2006 Mike McCormack for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdio.h>
22 #include <windows.h>
23 #include <commctrl.h>
24
25 #include "wine/test.h"
26
27 static void test_images(void)
28 {
29     HWND hwnd, hwndparent = 0;
30     DWORD r;
31     LVITEM item;
32     HIMAGELIST himl;
33     HBITMAP hbmp;
34     RECT r1, r2;
35     static CHAR hello[] = "hello";
36
37     himl = ImageList_Create(40, 40, 0, 4, 4);
38     ok(himl != NULL, "failed to create imagelist\n");
39
40     hbmp = CreateBitmap(40, 40, 1, 1, NULL);
41     ok(hbmp != NULL, "failed to create bitmap\n");
42
43     r = ImageList_Add(himl, hbmp, 0);
44     ok(r == 0, "should be zero\n");
45
46     hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED, 
47                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
48     ok(hwnd != NULL, "failed to create listview window\n");
49
50     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, 0x940);
51     ok(r == 0, "should return zero\n");
52
53     r = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
54     ok(r == 0, "should return zero\n");
55
56     r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
57     /* returns dimensions */
58
59     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
60     ok(r == 0, "should be zero items\n");
61
62     item.mask = LVIF_IMAGE | LVIF_TEXT;
63     item.iItem = 0;
64     item.iSubItem = 1;
65     item.iImage = 0;
66     item.pszText = 0;
67     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
68     ok(r == -1, "should fail\n");
69
70     item.iSubItem = 0;
71     item.pszText = hello;
72     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
73     ok(r == 0, "should not fail\n");
74
75     memset(&r1, 0, sizeof r1);
76     r1.left = LVIR_ICON;
77     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
78
79     r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
80     ok(r == TRUE, "should not fail\n");
81
82     item.iSubItem = 0;
83     item.pszText = hello;
84     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
85     ok(r == 0, "should not fail\n");
86
87     memset(&r2, 0, sizeof r2);
88     r2.left = LVIR_ICON;
89     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
90
91     ok(!memcmp(&r1, &r2, sizeof r1), "rectangle should be the same\n");
92
93     DestroyWindow(hwnd);
94 }
95
96 static void test_checkboxes(void)
97 {
98     HWND hwnd, hwndparent = 0;
99     LVITEMA item;
100     DWORD r;
101     static CHAR text[]  = "Text",
102                 text2[] = "Text2",
103                 text3[] = "Text3";
104
105     hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT, 
106                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
107     ok(hwnd != NULL, "failed to create listview window\n");
108
109     /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
110     item.mask = LVIF_TEXT | LVIF_STATE;
111     item.stateMask = 0xffff;
112     item.state = 0xfccc;
113     item.iItem = 0;
114     item.iSubItem = 0;
115     item.pszText = text;
116     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
117     ok(r == 0, "ret %d\n", r);
118
119     item.iItem = 0;
120     item.mask = LVIF_STATE;
121     item.stateMask = 0xffff;
122     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
123     ok(item.state == 0xfccc, "state %x\n", item.state);
124
125     /* Don't set LVIF_STATE */
126     item.mask = LVIF_TEXT;
127     item.stateMask = 0xffff;
128     item.state = 0xfccc;
129     item.iItem = 1;
130     item.iSubItem = 0;
131     item.pszText = text;
132     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
133     ok(r == 1, "ret %d\n", r);
134
135     item.iItem = 1;
136     item.mask = LVIF_STATE;
137     item.stateMask = 0xffff;
138     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
139     ok(item.state == 0, "state %x\n", item.state);
140
141     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
142     ok(r == 0, "should return zero\n");
143
144     /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
145     item.iItem = 0;
146     item.mask = LVIF_STATE;
147     item.stateMask = 0xffff;
148     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
149     ok(item.state == 0x1ccc, "state %x\n", item.state);
150
151     /* Now add an item without specifying a state and check that its state goes to 0x1000 */
152     item.iItem = 2;
153     item.mask = LVIF_TEXT;
154     item.state = 0;
155     item.pszText = text2;
156     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
157     ok(r == 2, "ret %d\n", r);
158
159     item.iItem = 2;
160     item.mask = LVIF_STATE;
161     item.stateMask = 0xffff;
162     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
163     ok(item.state == 0x1000, "state %x\n", item.state);
164
165     /* Add a further item this time specifying a state and still its state goes to 0x1000 */
166     item.iItem = 3;
167     item.mask = LVIF_TEXT | LVIF_STATE;
168     item.stateMask = 0xffff;
169     item.state = 0x2aaa;
170     item.pszText = text3;
171     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
172     ok(r == 3, "ret %d\n", r);
173
174     item.iItem = 3;
175     item.mask = LVIF_STATE;
176     item.stateMask = 0xffff;
177     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
178     ok(item.state == 0x1aaa, "state %x\n", item.state);
179
180     /* Set an item's state to checked */
181     item.iItem = 3;
182     item.mask = LVIF_STATE;
183     item.stateMask = 0xf000;
184     item.state = 0x2000;
185     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
186
187     item.iItem = 3;
188     item.mask = LVIF_STATE;
189     item.stateMask = 0xffff;
190     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
191     ok(item.state == 0x2aaa, "state %x\n", item.state);
192
193     /* Check that only the bits we asked for are returned,
194      * and that all the others are set to zero
195      */
196     item.iItem = 3;
197     item.mask = LVIF_STATE;
198     item.stateMask = 0xf000;
199     item.state = 0xffff;
200     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
201     ok(item.state == 0x2000, "state %x\n", item.state);
202
203     /* Set the style again and check that doesn't change an item's state */
204     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
205     ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
206
207     item.iItem = 3;
208     item.mask = LVIF_STATE;
209     item.stateMask = 0xffff;
210     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
211     ok(item.state == 0x2aaa, "state %x\n", item.state);
212
213     /* Unsetting the checkbox extended style doesn't change an item's state */
214     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
215     ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
216
217     item.iItem = 3;
218     item.mask = LVIF_STATE;
219     item.stateMask = 0xffff;
220     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
221     ok(item.state == 0x2aaa, "state %x\n", item.state);
222
223     /* Now setting the style again will change an item's state */
224     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
225     ok(r == 0, "ret %x\n", r);
226
227     item.iItem = 3;
228     item.mask = LVIF_STATE;
229     item.stateMask = 0xffff;
230     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
231     ok(item.state == 0x1aaa, "state %x\n", item.state);
232
233     DestroyWindow(hwnd);
234 }
235
236 static void test_items(void)
237 {
238     const LPARAM lparamTest = 0x42;
239     HWND hwnd, hwndparent = 0;
240     LVITEMA item;
241     LVCOLUMNA column;
242     DWORD r;
243     static CHAR text[]  = "Text";
244
245     hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
246                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
247     ok(hwnd != NULL, "failed to create listview window\n");
248
249     /*
250      * Test setting/getting item params
251      */
252
253     /* Set up two columns */
254     column.mask = LVCF_SUBITEM;
255     column.iSubItem = 0;
256     r = SendMessage(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
257     ok(r == 0, "ret %d\n", r);
258     column.iSubItem = 1;
259     r = SendMessage(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&column);
260     ok(r == 1, "ret %d\n", r);
261
262     /* Insert an item with just a param */
263     memset (&item, 0xaa, sizeof (item));
264     item.mask = LVIF_PARAM;
265     item.iItem = 0;
266     item.iSubItem = 0;
267     item.lParam = lparamTest;
268     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
269     ok(r == 0, "ret %d\n", r);
270
271     /* Test getting of the param */
272     memset (&item, 0xaa, sizeof (item));
273     item.mask = LVIF_PARAM;
274     item.iItem = 0;
275     item.iSubItem = 0;
276     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
277     ok(r != 0, "ret %d\n", r);
278     ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
279
280     /* Set up a subitem */
281     memset (&item, 0xaa, sizeof (item));
282     item.mask = LVIF_TEXT;
283     item.iItem = 0;
284     item.iSubItem = 1;
285     item.pszText = text;
286     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
287     ok(r != 0, "ret %d\n", r);
288
289     /* Query param from subitem: returns main item param */
290     memset (&item, 0xaa, sizeof (item));
291     item.mask = LVIF_PARAM;
292     item.iItem = 0;
293     item.iSubItem = 1;
294     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
295     ok(r != 0, "ret %d\n", r);
296     ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
297
298     /* Set up param on first subitem: no effect */
299     memset (&item, 0xaa, sizeof (item));
300     item.mask = LVIF_PARAM;
301     item.iItem = 0;
302     item.iSubItem = 1;
303     item.lParam = lparamTest+1;
304     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
305     ok(r == 0, "ret %d\n", r);
306
307     /* Query param from subitem again: should still return main item param */
308     memset (&item, 0xaa, sizeof (item));
309     item.mask = LVIF_PARAM;
310     item.iItem = 0;
311     item.iSubItem = 1;
312     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
313     ok(r != 0, "ret %d\n", r);
314     ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
315
316     /**** Some tests of state highlighting ****/
317     memset (&item, 0xaa, sizeof (item));
318     item.mask = LVIF_STATE;
319     item.iItem = 0;
320     item.iSubItem = 0;
321     item.state = LVIS_SELECTED;
322     item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
323     r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
324     ok(r != 0, "ret %d\n", r);
325     item.iSubItem = 1;
326     item.state = LVIS_DROPHILITED;
327     r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
328     ok(r != 0, "ret %d\n", r);
329
330     memset (&item, 0xaa, sizeof (item));
331     item.mask = LVIF_STATE;
332     item.iItem = 0;
333     item.iSubItem = 0;
334     item.stateMask = -1;
335     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
336     ok(r != 0, "ret %d\n", r);
337     ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
338     item.iSubItem = 1;
339     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
340     ok(r != 0, "ret %d\n", r);
341     todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
342
343     DestroyWindow(hwnd);
344 }
345
346 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
347 static WNDPROC listviewWndProc;
348 static HIMAGELIST test_create_imagelist;
349
350 static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
351 {
352     if (uMsg == WM_CREATE)
353         SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
354     return CallWindowProc(listviewWndProc, hwnd, uMsg, wParam, lParam);
355 }
356
357 static void test_create()
358 {
359     HWND hList;
360     WNDCLASSEX cls;
361     cls.cbSize = sizeof(WNDCLASSEX);
362     ok(GetClassInfoEx(GetModuleHandle(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
363     listviewWndProc = cls.lpfnWndProc;
364     cls.lpfnWndProc = create_test_wndproc;
365     cls.lpszClassName = "MyListView32";
366     ok(RegisterClassEx(&cls), "RegisterClassEx failed\n");
367
368     test_create_imagelist = ImageList_Create(16, 16, 0, 5, 10);
369     hList = CreateWindow("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0);
370     ok((HIMAGELIST)SendMessage(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
371     DestroyWindow(hList);
372 }
373
374 START_TEST(listview)
375 {
376     INITCOMMONCONTROLSEX icc;
377
378     icc.dwICC = 0;
379     icc.dwSize = sizeof icc;
380     InitCommonControlsEx(&icc);
381
382     test_images();
383     test_checkboxes();
384     test_items();
385     test_create();
386 }