Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink...
[reactos.git] / rostests / winetests / comctl32 / treeview.c
1 /* Unit tests for treeview.
2 *
3 * Copyright 2005 Krzysztof Foltman
4 * Copyright 2007 Christopher James Peterson
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 <assert.h>
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "winreg.h"
30 #include "commctrl.h"
31
32 #include "wine/test.h"
33 #include "msg.h"
34
35 const char *TEST_CALLBACK_TEXT = "callback_text";
36
37 #define NUM_MSG_SEQUENCES 2
38 #define TREEVIEW_SEQ_INDEX 0
39 #define PARENT_SEQ_INDEX 1
40
41 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
42
43 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
44
45 static const struct message FillRootSeq[] = {
46 { TVM_INSERTITEM, sent },
47 { TVM_INSERTITEM, sent },
48 { 0 }
49 };
50
51 static const struct message rootnone_select_seq[] = {
52 { TVM_SELECTITEM, sent|wparam, 9 },
53 { TVM_SELECTITEM, sent|wparam, 9 },
54 { TVM_SELECTITEM, sent|wparam, 9 },
55 { TVM_SELECTITEM, sent|wparam, 9 },
56 { TVM_SELECTITEM, sent|wparam, 9 },
57 { TVM_SELECTITEM, sent|wparam, 9 },
58 { 0 }
59 };
60
61 static const struct message rootchild_select_seq[] = {
62 { TVM_SELECTITEM, sent|wparam, 9 },
63 { TVM_SELECTITEM, sent|wparam, 9 },
64 { TVM_SELECTITEM, sent|wparam, 9 },
65 { TVM_SELECTITEM, sent|wparam, 9 },
66 { TVM_SELECTITEM, sent|wparam, 9 },
67 { TVM_SELECTITEM, sent|wparam, 9 },
68 { 0 }
69 };
70
71 static const struct message getitemtext_seq[] = {
72 { TVM_INSERTITEM, sent },
73 { TVM_GETITEM, sent },
74 { TVM_DELETEITEM, sent },
75 { 0 }
76 };
77
78 static const struct message focus_seq[] = {
79 { TVM_INSERTITEM, sent },
80 { TVM_INSERTITEM, sent },
81 { TVM_SELECTITEM, sent|wparam, 9 },
82 /* The following end up out of order in wine */
83 { WM_WINDOWPOSCHANGING, sent|defwinproc },
84 { WM_NCCALCSIZE, sent|wparam|defwinproc, TRUE },
85 { WM_WINDOWPOSCHANGED, sent|defwinproc },
86 { WM_SIZE, sent|defwinproc },
87 { WM_PAINT, sent|defwinproc },
88 { WM_NCPAINT, sent|wparam|defwinproc, 1 },
89 { WM_ERASEBKGND, sent|defwinproc },
90 { TVM_EDITLABEL, sent },
91 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_UPDATE) },
92 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_CHANGE) },
93 { WM_PARENTNOTIFY, sent|wparam|defwinproc, MAKEWPARAM(WM_CREATE, 0) },
94 { WM_KILLFOCUS, sent|defwinproc },
95 { WM_PAINT, sent|defwinproc },
96 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
97 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_SETFOCUS) },
98 { WM_ERASEBKGND, sent|defwinproc|optional },
99 { WM_CTLCOLOREDIT, sent|defwinproc|optional },
100 { WM_CTLCOLOREDIT, sent|defwinproc|optional },
101 { 0 }
102 };
103
104 static const struct message test_get_set_bkcolor_seq[] = {
105 { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
106 { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0 },
107 { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
108 { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0x00ffffff },
109 { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
110 { TVM_SETBKCOLOR, sent|wparam|lparam, 0, -1 },
111 { 0 }
112 };
113
114 static const struct message test_get_set_imagelist_seq[] = {
115 { TVM_SETIMAGELIST, sent|wparam|lparam, 0, 0 },
116 { TVM_GETIMAGELIST, sent|wparam|lparam, 0, 0 },
117 { 0 }
118 };
119
120 static const struct message test_get_set_indent_seq[] = {
121 { TVM_SETINDENT, sent|wparam|lparam, 0, 0 },
122 { TVM_GETINDENT, sent|wparam|lparam, 0, 0 },
123 /* The actual amount to indent is dependent on the system for this message */
124 { TVM_SETINDENT, sent },
125 { TVM_GETINDENT, sent|wparam|lparam, 0, 0 },
126 { 0 }
127 };
128
129 static const struct message test_get_set_insertmarkcolor_seq[] = {
130 { TVM_SETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 },
131 { TVM_GETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 },
132 { 0 }
133 };
134
135 static const struct message test_get_set_item_seq[] = {
136 { TVM_GETITEM, sent },
137 { TVM_SETITEM, sent },
138 { TVM_GETITEM, sent },
139 { TVM_SETITEM, sent },
140 { 0 }
141 };
142
143 static const struct message test_get_set_itemheight_seq[] = {
144 { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
145 { TVM_SETITEMHEIGHT, sent|wparam|lparam, -1, 0 },
146 { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
147 { TVM_SETITEMHEIGHT, sent|lparam, 0xcccccccc, 0 },
148 { TVM_GETITEMHEIGHT, sent|wparam|lparam|optional, 0, 0 },
149 { TVM_SETITEMHEIGHT, sent|wparam|lparam|optional, 9, 0 },
150 { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
151 { 0 }
152 };
153
154 static const struct message test_get_set_scrolltime_seq[] = {
155 { TVM_SETSCROLLTIME, sent|wparam|lparam, 20, 0 },
156 { TVM_GETSCROLLTIME, sent|wparam|lparam, 0, 0 },
157 { 0 }
158 };
159
160 static const struct message test_get_set_textcolor_seq[] = {
161 { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
162 { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
163 { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
164 { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, RGB(255, 255, 255) },
165 { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
166 { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, CLR_NONE },
167 { 0 }
168 };
169
170 static const struct message test_get_set_tooltips_seq[] = {
171 { WM_KILLFOCUS, sent },
172 { WM_IME_SETCONTEXT, sent|optional },
173 { WM_IME_NOTIFY, sent|optional },
174 { TVM_SETTOOLTIPS, sent|wparam|lparam, 0, 0 },
175 { TVM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 },
176 { 0 }
177 };
178
179 static const struct message test_get_set_unicodeformat_seq[] = {
180 { TVM_SETUNICODEFORMAT, sent|wparam|lparam, TRUE, 0 },
181 { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
182 { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
183 { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
184 { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
185 { 0 }
186 };
187
188 static const struct message parent_expand_seq[] = {
189 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDING },
190 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDED },
191 { 0 }
192 };
193
194 static const struct message empty_seq[] = {
195 { 0 }
196 };
197
198 static HWND hMainWnd;
199
200 static HTREEITEM hRoot, hChild;
201
202 static int pos = 0;
203 static char sequence[256];
204
205 static void Clear(void)
206 {
207 pos = 0;
208 sequence[0] = '\0';
209 }
210
211 static void AddItem(char ch)
212 {
213 sequence[pos++] = ch;
214 sequence[pos] = '\0';
215 }
216
217 static void IdentifyItem(HTREEITEM hItem)
218 {
219 if (hItem == hRoot) {
220 AddItem('R');
221 return;
222 }
223 if (hItem == hChild) {
224 AddItem('C');
225 return;
226 }
227 if (hItem == NULL) {
228 AddItem('n');
229 return;
230 }
231 AddItem('?');
232 }
233
234 /* This function hooks in and records all messages to the treeview control */
235 static LRESULT WINAPI TreeviewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
236 {
237 static LONG defwndproc_counter = 0;
238 LRESULT ret;
239 struct message msg;
240 WNDPROC lpOldProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
241
242 msg.message = message;
243 msg.flags = sent|wparam|lparam;
244 if (defwndproc_counter) msg.flags |= defwinproc;
245 msg.wParam = wParam;
246 msg.lParam = lParam;
247 add_message(sequences, TREEVIEW_SEQ_INDEX, &msg);
248
249 defwndproc_counter++;
250 ret = CallWindowProcA(lpOldProc, hwnd, message, wParam, lParam);
251 defwndproc_counter--;
252
253 return ret;
254 }
255
256 static HWND create_treeview_control(void)
257 {
258 WNDPROC pOldWndProc;
259 HWND hTree;
260
261 hTree = CreateWindowExA(WS_EX_CLIENTEDGE, WC_TREEVIEWA, NULL, WS_CHILD|WS_VISIBLE|
262 TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS|TVS_EDITLABELS,
263 0, 0, 120, 100, hMainWnd, (HMENU)100, GetModuleHandleA(0), 0);
264
265 SetFocus(hTree);
266
267 /* Record the old WNDPROC so we can call it after recording the messages */
268 pOldWndProc = (WNDPROC)SetWindowLongPtrA(hTree, GWLP_WNDPROC, (LONG_PTR)TreeviewWndProc);
269 SetWindowLongPtrA(hTree, GWLP_USERDATA, (LONG_PTR)pOldWndProc);
270
271 return hTree;
272 }
273
274 static void fill_tree(HWND hTree)
275 {
276 TVINSERTSTRUCTA ins;
277 static CHAR root[] = "Root",
278 child[] = "Child";
279
280 ins.hParent = TVI_ROOT;
281 ins.hInsertAfter = TVI_ROOT;
282 U(ins).item.mask = TVIF_TEXT;
283 U(ins).item.pszText = root;
284 hRoot = TreeView_InsertItem(hTree, &ins);
285
286 ins.hParent = hRoot;
287 ins.hInsertAfter = TVI_FIRST;
288 U(ins).item.mask = TVIF_TEXT;
289 U(ins).item.pszText = child;
290 hChild = TreeView_InsertItem(hTree, &ins);
291 }
292
293 static void test_fillroot(void)
294 {
295 TVITEM tvi;
296 HWND hTree;
297
298 hTree = create_treeview_control();
299
300 flush_sequences(sequences, NUM_MSG_SEQUENCES);
301
302 fill_tree(hTree);
303
304 Clear();
305 AddItem('A');
306 assert(hRoot);
307 AddItem('B');
308 assert(hChild);
309 AddItem('.');
310 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, FillRootSeq, "FillRoot", FALSE);
311 ok(!strcmp(sequence, "AB."), "Item creation\n");
312
313 /* UMLPad 1.15 depends on this being not -1 (I_IMAGECALLBACK) */
314 tvi.hItem = hRoot;
315 tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
316 SendMessage( hTree, TVM_GETITEM, 0, (LPARAM)&tvi );
317 ok(tvi.iImage == 0, "tvi.iImage=%d\n", tvi.iImage);
318 ok(tvi.iSelectedImage == 0, "tvi.iSelectedImage=%d\n", tvi.iSelectedImage);
319
320 DestroyWindow(hTree);
321 }
322
323 static void test_callback(void)
324 {
325 HTREEITEM hRoot;
326 HTREEITEM hItem1, hItem2;
327 TVINSERTSTRUCTA ins;
328 TVITEM tvi;
329 CHAR test_string[] = "Test_string";
330 CHAR buf[128];
331 LRESULT ret;
332 HWND hTree;
333
334 hTree = create_treeview_control();
335 fill_tree(hTree);
336
337 ret = TreeView_DeleteAllItems(hTree);
338 ok(ret == TRUE, "ret\n");
339 ins.hParent = TVI_ROOT;
340 ins.hInsertAfter = TVI_ROOT;
341 U(ins).item.mask = TVIF_TEXT;
342 U(ins).item.pszText = LPSTR_TEXTCALLBACK;
343 hRoot = TreeView_InsertItem(hTree, &ins);
344 assert(hRoot);
345
346 tvi.hItem = hRoot;
347 tvi.mask = TVIF_TEXT;
348 tvi.pszText = buf;
349 tvi.cchTextMax = sizeof(buf)/sizeof(buf[0]);
350 ret = TreeView_GetItem(hTree, &tvi);
351 ok(ret == 1, "ret\n");
352 ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Callback item text mismatch %s vs %s\n",
353 tvi.pszText, TEST_CALLBACK_TEXT);
354
355 ins.hParent = hRoot;
356 ins.hInsertAfter = TVI_FIRST;
357 U(ins).item.mask = TVIF_TEXT;
358 U(ins).item.pszText = test_string;
359 hItem1 = TreeView_InsertItem(hTree, &ins);
360 assert(hItem1);
361
362 tvi.hItem = hItem1;
363 ret = TreeView_GetItem(hTree, &tvi);
364 ok(ret == TRUE, "ret\n");
365 ok(strcmp(tvi.pszText, test_string) == 0, "Item text mismatch %s vs %s\n",
366 tvi.pszText, test_string);
367
368 /* undocumented: pszText of NULL also means LPSTR_CALLBACK: */
369 tvi.pszText = NULL;
370 ret = TreeView_SetItem(hTree, &tvi);
371 ok(ret == 1, "Expected SetItem return 1, got %ld\n", ret);
372 tvi.pszText = buf;
373 ret = TreeView_GetItem(hTree, &tvi);
374 ok(ret == TRUE, "Expected GetItem return TRUE, got %ld\n", ret);
375 ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
376 tvi.pszText, TEST_CALLBACK_TEXT);
377
378 U(ins).item.pszText = NULL;
379 hItem2 = TreeView_InsertItem(hTree, &ins);
380 assert(hItem2);
381 tvi.hItem = hItem2;
382 memset(buf, 0, sizeof(buf));
383 ret = TreeView_GetItem(hTree, &tvi);
384 ok(ret == TRUE, "Expected GetItem return TRUE, got %ld\n", ret);
385 ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
386 tvi.pszText, TEST_CALLBACK_TEXT);
387
388 DestroyWindow(hTree);
389 }
390
391 static void test_select(void)
392 {
393 BOOL r;
394 HWND hTree;
395
396 hTree = create_treeview_control();
397 fill_tree(hTree);
398
399 /* root-none select tests */
400 flush_sequences(sequences, NUM_MSG_SEQUENCES);
401 r = TreeView_SelectItem(hTree, NULL);
402 expect(TRUE, r);
403 Clear();
404 AddItem('1');
405 r = TreeView_SelectItem(hTree, hRoot);
406 expect(TRUE, r);
407 AddItem('2');
408 r = TreeView_SelectItem(hTree, hRoot);
409 expect(TRUE, r);
410 AddItem('3');
411 r = TreeView_SelectItem(hTree, NULL);
412 expect(TRUE, r);
413 AddItem('4');
414 r = TreeView_SelectItem(hTree, NULL);
415 expect(TRUE, r);
416 AddItem('5');
417 r = TreeView_SelectItem(hTree, hRoot);
418 expect(TRUE, r);
419 AddItem('.');
420 ok(!strcmp(sequence, "1(nR)nR23(Rn)Rn45(nR)nR."), "root-none select test\n");
421 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, rootnone_select_seq,
422 "root-none select seq", FALSE);
423
424 /* root-child select tests */
425 flush_sequences(sequences, NUM_MSG_SEQUENCES);
426 r = TreeView_SelectItem(hTree, NULL);
427 expect(TRUE, r);
428
429 Clear();
430 AddItem('1');
431 r = TreeView_SelectItem(hTree, hRoot);
432 expect(TRUE, r);
433 AddItem('2');
434 r = TreeView_SelectItem(hTree, hRoot);
435 expect(TRUE, r);
436 AddItem('3');
437 r = TreeView_SelectItem(hTree, hChild);
438 expect(TRUE, r);
439 AddItem('4');
440 r = TreeView_SelectItem(hTree, hChild);
441 expect(TRUE, r);
442 AddItem('5');
443 r = TreeView_SelectItem(hTree, hRoot);
444 expect(TRUE, r);
445 AddItem('.');
446 ok(!strcmp(sequence, "1(nR)nR23(RC)RC45(CR)CR."), "root-child select test\n");
447 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, rootchild_select_seq,
448 "root-child select seq", FALSE);
449
450 DestroyWindow(hTree);
451 }
452
453 static void test_getitemtext(void)
454 {
455 TVINSERTSTRUCTA ins;
456 HTREEITEM hChild;
457 TVITEM tvi;
458 HWND hTree;
459
460 CHAR szBuffer[80] = "Blah";
461 int nBufferSize = sizeof(szBuffer)/sizeof(CHAR);
462
463 hTree = create_treeview_control();
464 fill_tree(hTree);
465
466 flush_sequences(sequences, NUM_MSG_SEQUENCES);
467
468 /* add an item without TVIF_TEXT mask and pszText == NULL */
469 ins.hParent = hRoot;
470 ins.hInsertAfter = TVI_ROOT;
471 U(ins).item.mask = 0;
472 U(ins).item.pszText = NULL;
473 U(ins).item.cchTextMax = 0;
474 hChild = TreeView_InsertItem(hTree, &ins);
475 assert(hChild);
476
477 /* retrieve it with TVIF_TEXT mask */
478 tvi.hItem = hChild;
479 tvi.mask = TVIF_TEXT;
480 tvi.cchTextMax = nBufferSize;
481 tvi.pszText = szBuffer;
482
483 SendMessageA( hTree, TVM_GETITEM, 0, (LPARAM)&tvi );
484 ok(!strcmp(szBuffer, ""), "szBuffer=\"%s\", expected \"\"\n", szBuffer);
485 ok(SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild), "DeleteItem failed\n");
486 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, getitemtext_seq, "get item text seq", FALSE);
487
488 DestroyWindow(hTree);
489 }
490
491 static void test_focus(void)
492 {
493 TVINSERTSTRUCTA ins;
494 static CHAR child1[] = "Edit",
495 child2[] = "A really long string";
496 HTREEITEM hChild1, hChild2;
497 HWND hTree;
498 HWND hEdit;
499
500 hTree = create_treeview_control();
501 fill_tree(hTree);
502
503 flush_sequences(sequences, NUM_MSG_SEQUENCES);
504
505 /* This test verifies that when a label is being edited, scrolling
506 * the treeview does not cause the label to lose focus. To test
507 * this, first some additional entries are added to generate
508 * scrollbars.
509 */
510 ins.hParent = hRoot;
511 ins.hInsertAfter = hChild;
512 U(ins).item.mask = TVIF_TEXT;
513 U(ins).item.pszText = child1;
514 hChild1 = TreeView_InsertItem(hTree, &ins);
515 assert(hChild1);
516 ins.hInsertAfter = hChild1;
517 U(ins).item.mask = TVIF_TEXT;
518 U(ins).item.pszText = child2;
519 hChild2 = TreeView_InsertItem(hTree, &ins);
520 assert(hChild2);
521
522 ShowWindow(hMainWnd,SW_SHOW);
523 SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild);
524 hEdit = TreeView_EditLabel(hTree, hChild);
525 ScrollWindowEx(hTree, -10, 0, NULL, NULL, NULL, NULL, SW_SCROLLCHILDREN);
526 ok(GetFocus() == hEdit, "Edit control should have focus\n");
527 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, focus_seq, "focus test", TRUE);
528
529 DestroyWindow(hTree);
530 }
531
532 static void test_get_set_bkcolor(void)
533 {
534 COLORREF crColor = RGB(0,0,0);
535 HWND hTree;
536
537 hTree = create_treeview_control();
538 fill_tree(hTree);
539
540 flush_sequences(sequences, NUM_MSG_SEQUENCES);
541
542 /* If the value is -1, the control is using the system color for the background color. */
543 crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 );
544 ok(crColor == -1, "Default background color reported as 0x%.8x\n", crColor);
545
546 /* Test for black background */
547 SendMessage( hTree, TVM_SETBKCOLOR, 0, RGB(0,0,0) );
548 crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 );
549 ok(crColor == RGB(0,0,0), "Black background color reported as 0x%.8x\n", crColor);
550
551 /* Test for white background */
552 SendMessage( hTree, TVM_SETBKCOLOR, 0, RGB(255,255,255) );
553 crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 );
554 ok(crColor == RGB(255,255,255), "White background color reported as 0x%.8x\n", crColor);
555
556 /* Reset the default background */
557 SendMessage( hTree, TVM_SETBKCOLOR, 0, -1 );
558
559 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_bkcolor_seq,
560 "test get set bkcolor", FALSE);
561
562 DestroyWindow(hTree);
563 }
564
565 static void test_get_set_imagelist(void)
566 {
567 HIMAGELIST hImageList = NULL;
568 HWND hTree;
569
570 hTree = create_treeview_control();
571 fill_tree(hTree);
572
573 flush_sequences(sequences, NUM_MSG_SEQUENCES);
574
575 /* Test a NULL HIMAGELIST */
576 SendMessage( hTree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)hImageList );
577 hImageList = (HIMAGELIST)SendMessage( hTree, TVM_GETIMAGELIST, TVSIL_NORMAL, 0 );
578 ok(hImageList == NULL, "NULL image list, reported as 0x%p, expected 0.\n", hImageList);
579
580 /* TODO: Test an actual image list */
581
582 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_imagelist_seq,
583 "test get imagelist", FALSE);
584
585 DestroyWindow(hTree);
586 }
587
588 static void test_get_set_indent(void)
589 {
590 int ulIndent = -1;
591 int ulMinIndent = -1;
592 int ulMoreThanTwiceMin = -1;
593 HWND hTree;
594
595 hTree = create_treeview_control();
596 fill_tree(hTree);
597
598 flush_sequences(sequences, NUM_MSG_SEQUENCES);
599
600 /* Finding the minimum indent */
601 SendMessage( hTree, TVM_SETINDENT, 0, 0 );
602 ulMinIndent = (int)SendMessage( hTree, TVM_GETINDENT, 0, 0 );
603
604 /* Checking an indent that is more than twice the default indent */
605 ulMoreThanTwiceMin = 2*ulMinIndent+1;
606 SendMessage( hTree, TVM_SETINDENT, ulMoreThanTwiceMin, 0 );
607 ulIndent = (DWORD)SendMessage( hTree, TVM_GETINDENT, 0, 0 );
608 ok(ulIndent == ulMoreThanTwiceMin, "Indent reported as %d, expected %d\n", ulIndent, ulMoreThanTwiceMin);
609
610 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_indent_seq,
611 "test get set indent", FALSE);
612
613 DestroyWindow(hTree);
614 }
615
616 static void test_get_set_insertmark(void)
617 {
618 COLORREF crColor = RGB(0,0,0);
619 HWND hTree;
620
621 hTree = create_treeview_control();
622 fill_tree(hTree);
623
624 flush_sequences(sequences, NUM_MSG_SEQUENCES);
625
626 SendMessage( hTree, TVM_SETINSERTMARKCOLOR, 0, crColor );
627 crColor = (COLORREF)SendMessage( hTree, TVM_GETINSERTMARKCOLOR, 0, 0 );
628 ok(crColor == RGB(0,0,0), "Insert mark color reported as 0x%.8x, expected 0x00000000\n", crColor);
629
630 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_insertmarkcolor_seq,
631 "test get set insertmark color", FALSE);
632
633 DestroyWindow(hTree);
634 }
635
636 static void test_get_set_item(void)
637 {
638 TVITEM tviRoot = {0};
639 int nBufferSize = 80;
640 char szBuffer[80] = {0};
641 HWND hTree;
642
643 hTree = create_treeview_control();
644 fill_tree(hTree);
645
646 flush_sequences(sequences, NUM_MSG_SEQUENCES);
647
648 /* Test the root item */
649 tviRoot.hItem = hRoot;
650 tviRoot.mask = TVIF_TEXT;
651 tviRoot.cchTextMax = nBufferSize;
652 tviRoot.pszText = szBuffer;
653 SendMessage( hTree, TVM_GETITEM, 0, (LPARAM)&tviRoot );
654 ok(!strcmp("Root", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Root\"\n", szBuffer);
655
656 /* Change the root text */
657 strncpy(szBuffer, "Testing123", nBufferSize);
658 SendMessage( hTree, TVM_SETITEM, 0, (LPARAM)&tviRoot );
659 memset(szBuffer, 0, nBufferSize);
660 SendMessage( hTree, TVM_GETITEM, 0, (LPARAM)&tviRoot );
661 ok(!strcmp("Testing123", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Testing123\"\n", szBuffer);
662
663 /* Reset the root text */
664 memset(szBuffer, 0, nBufferSize);
665 strncpy(szBuffer, "Root", nBufferSize);
666 SendMessage( hTree, TVM_SETITEM, 0, (LPARAM)&tviRoot );
667
668 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_item_seq,
669 "test get set item", FALSE);
670
671 DestroyWindow(hTree);
672 }
673
674 static void test_get_set_itemheight(void)
675 {
676 int ulOldHeight = 0;
677 int ulNewHeight = 0;
678 HWND hTree;
679
680 hTree = create_treeview_control();
681 fill_tree(hTree);
682
683 flush_sequences(sequences, NUM_MSG_SEQUENCES);
684
685 /* Assuming default height to begin with */
686 ulOldHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
687
688 /* Explicitly setting and getting the default height */
689 SendMessage( hTree, TVM_SETITEMHEIGHT, -1, 0 );
690 ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
691 ok(ulNewHeight == ulOldHeight, "Default height not set properly, reported %d, expected %d\n", ulNewHeight, ulOldHeight);
692
693 /* Explicitly setting and getting the height of twice the normal */
694 SendMessage( hTree, TVM_SETITEMHEIGHT, 2*ulOldHeight, 0 );
695 ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
696 ok(ulNewHeight == 2*ulOldHeight, "New height not set properly, reported %d, expected %d\n", ulNewHeight, 2*ulOldHeight);
697
698 /* Assuming tree doesn't have TVS_NONEVENHEIGHT set, so a set of 9 will round down to 8 */
699 SendMessage( hTree, TVM_SETITEMHEIGHT, 9, 0 );
700 ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
701 ok(ulNewHeight == 8, "Uneven height not set properly, reported %d, expected %d\n", ulNewHeight, 8);
702
703 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_itemheight_seq,
704 "test get set item height", FALSE);
705
706 DestroyWindow(hTree);
707 }
708
709 static void test_get_set_scrolltime(void)
710 {
711 int ulExpectedTime = 20;
712 int ulTime = 0;
713 HWND hTree;
714
715 hTree = create_treeview_control();
716 fill_tree(hTree);
717
718 flush_sequences(sequences, NUM_MSG_SEQUENCES);
719
720 SendMessage( hTree, TVM_SETSCROLLTIME, ulExpectedTime, 0 );
721 ulTime = (int)SendMessage( hTree, TVM_GETSCROLLTIME, 0, 0 );
722 ok(ulTime == ulExpectedTime, "Scroll time reported as %d, expected %d\n", ulTime, ulExpectedTime);
723
724 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_scrolltime_seq,
725 "test get set scroll time", FALSE);
726
727 DestroyWindow(hTree);
728 }
729
730 static void test_get_set_textcolor(void)
731 {
732 /* If the value is -1, the control is using the system color for the text color. */
733 COLORREF crColor = RGB(0,0,0);
734 HWND hTree;
735
736 hTree = create_treeview_control();
737 fill_tree(hTree);
738
739 flush_sequences(sequences, NUM_MSG_SEQUENCES);
740
741 crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 );
742 ok(crColor == -1, "Default text color reported as 0x%.8x\n", crColor);
743
744 /* Test for black text */
745 SendMessage( hTree, TVM_SETTEXTCOLOR, 0, RGB(0,0,0) );
746 crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 );
747 ok(crColor == RGB(0,0,0), "Black text color reported as 0x%.8x\n", crColor);
748
749 /* Test for white text */
750 SendMessage( hTree, TVM_SETTEXTCOLOR, 0, RGB(255,255,255) );
751 crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 );
752 ok(crColor == RGB(255,255,255), "White text color reported as 0x%.8x\n", crColor);
753
754 /* Reset the default text color */
755 SendMessage( hTree, TVM_SETTEXTCOLOR, 0, CLR_NONE );
756
757 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_textcolor_seq,
758 "test get set text color", FALSE);
759
760 DestroyWindow(hTree);
761 }
762
763 static void test_get_set_tooltips(void)
764 {
765 HWND hwndLastToolTip = NULL;
766 HWND hPopupTreeView;
767 HWND hTree;
768
769 hTree = create_treeview_control();
770 fill_tree(hTree);
771
772 flush_sequences(sequences, NUM_MSG_SEQUENCES);
773
774 /* show even WS_POPUP treeview don't send NM_TOOLTIPSCREATED */
775 hPopupTreeView = CreateWindow(WC_TREEVIEW, NULL, WS_POPUP|WS_VISIBLE, 0, 0, 100, 100, hMainWnd, NULL, NULL, NULL);
776 DestroyWindow(hPopupTreeView);
777
778 /* Testing setting a NULL ToolTip */
779 SendMessage( hTree, TVM_SETTOOLTIPS, 0, 0 );
780 hwndLastToolTip = (HWND)SendMessage( hTree, TVM_GETTOOLTIPS, 0, 0 );
781 ok(hwndLastToolTip == NULL, "NULL tool tip, reported as 0x%p, expected 0.\n", hwndLastToolTip);
782
783 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_tooltips_seq,
784 "test get set tooltips", TRUE);
785
786 /* TODO: Add a test of an actual tooltip */
787 DestroyWindow(hTree);
788 }
789
790 static void test_get_set_unicodeformat(void)
791 {
792 BOOL bPreviousSetting = 0;
793 BOOL bNewSetting = 0;
794 HWND hTree;
795
796 hTree = create_treeview_control();
797 fill_tree(hTree);
798
799 flush_sequences(sequences, NUM_MSG_SEQUENCES);
800
801 /* Set to Unicode */
802 bPreviousSetting = (BOOL)SendMessage( hTree, TVM_SETUNICODEFORMAT, 1, 0 );
803 bNewSetting = (BOOL)SendMessage( hTree, TVM_GETUNICODEFORMAT, 0, 0 );
804 ok(bNewSetting == 1, "Unicode setting did not work.\n");
805
806 /* Set to ANSI */
807 SendMessage( hTree, TVM_SETUNICODEFORMAT, 0, 0 );
808 bNewSetting = (BOOL)SendMessage( hTree, TVM_GETUNICODEFORMAT, 0, 0 );
809 ok(bNewSetting == 0, "ANSI setting did not work.\n");
810
811 /* Revert to original setting */
812 SendMessage( hTree, TVM_SETUNICODEFORMAT, bPreviousSetting, 0 );
813
814 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_unicodeformat_seq,
815 "test get set unicode format", FALSE);
816
817 DestroyWindow(hTree);
818 }
819
820 static TVITEMA g_item_expanding, g_item_expanded;
821 static BOOL g_get_from_expand;
822 static BOOL g_get_rect_in_expand;
823
824 static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
825 {
826 static LONG defwndproc_counter = 0;
827 struct message msg;
828 LRESULT ret;
829 RECT rect;
830 HTREEITEM visibleItem;
831
832 msg.message = message;
833 msg.flags = sent|wparam|lparam;
834 if (defwndproc_counter) msg.flags |= defwinproc;
835 msg.wParam = wParam;
836 msg.lParam = lParam;
837 if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
838
839 /* log system messages, except for painting */
840 if (message < WM_USER &&
841 message != WM_PAINT &&
842 message != WM_ERASEBKGND &&
843 message != WM_NCPAINT &&
844 message != WM_NCHITTEST &&
845 message != WM_GETTEXT &&
846 message != WM_GETICON &&
847 message != WM_DEVICECHANGE)
848 {
849 trace("parent: %p, %04x, %08lx, %08lx\n", hWnd, message, wParam, lParam);
850 add_message(sequences, PARENT_SEQ_INDEX, &msg);
851 }
852
853 switch(message) {
854 case WM_NOTIFY:
855 {
856 NMHDR *pHdr = (NMHDR *)lParam;
857
858 ok(pHdr->code != NM_TOOLTIPSCREATED, "Treeview should not send NM_TOOLTIPSCREATED\n");
859 if (pHdr->idFrom == 100)
860 {
861 NMTREEVIEWA *pTreeView = (LPNMTREEVIEWA) lParam;
862 switch(pHdr->code)
863 {
864 case TVN_SELCHANGINGA:
865 AddItem('(');
866 IdentifyItem(pTreeView->itemOld.hItem);
867 IdentifyItem(pTreeView->itemNew.hItem);
868 break;
869 case TVN_SELCHANGEDA:
870 AddItem(')');
871 IdentifyItem(pTreeView->itemOld.hItem);
872 IdentifyItem(pTreeView->itemNew.hItem);
873 break;
874 case TVN_GETDISPINFOA: {
875 NMTVDISPINFOA *disp = (NMTVDISPINFOA *)lParam;
876 if (disp->item.mask & TVIF_TEXT) {
877 lstrcpyn(disp->item.pszText, TEST_CALLBACK_TEXT, disp->item.cchTextMax);
878 }
879 break;
880 }
881 case TVN_ENDLABELEDIT: return TRUE;
882 case TVN_ITEMEXPANDING:
883 ok(pTreeView->itemNew.mask ==
884 (TVIF_HANDLE | TVIF_SELECTEDIMAGE | TVIF_IMAGE | TVIF_PARAM | TVIF_STATE),
885 "got wrong mask %x\n", pTreeView->itemNew.mask);
886 ok((pTreeView->itemNew.state & TVIS_EXPANDED) == 0,
887 "got wrong state %x\n", pTreeView->itemNew.state);
888 ok(pTreeView->itemOld.mask == 0,
889 "got wrong mask %x\n", pTreeView->itemOld.mask);
890
891 if (g_get_from_expand)
892 {
893 g_item_expanding.mask = TVIF_STATE;
894 g_item_expanding.hItem = hRoot;
895 ret = SendMessageA(pHdr->hwndFrom, TVM_GETITEMA, 0, (LPARAM)&g_item_expanding);
896 ok(ret == TRUE, "got %lu\n", ret);
897 }
898 break;
899 case TVN_ITEMEXPANDED:
900 ok(pTreeView->itemNew.mask & TVIF_STATE, "got wrong mask %x\n", pTreeView->itemNew.mask);
901 ok(pTreeView->itemNew.state & (TVIS_EXPANDED|TVIS_EXPANDEDONCE),
902 "got wrong mask %x\n", pTreeView->itemNew.mask);
903 ok(pTreeView->itemOld.mask == 0,
904 "got wrong mask %x\n", pTreeView->itemOld.mask);
905
906 if (g_get_from_expand)
907 {
908 g_item_expanded.mask = TVIF_STATE;
909 g_item_expanded.hItem = hRoot;
910 ret = SendMessageA(pHdr->hwndFrom, TVM_GETITEMA, 0, (LPARAM)&g_item_expanded);
911 ok(ret == TRUE, "got %lu\n", ret);
912 }
913 if (g_get_rect_in_expand) {
914 visibleItem = TreeView_GetNextItem(pHdr->hwndFrom, NULL, TVGN_FIRSTVISIBLE);
915 ok(pTreeView->itemNew.hItem == visibleItem, "expanded item == first visible item\n");
916 *(HTREEITEM*)&rect = visibleItem;
917 ok(SendMessage(pHdr->hwndFrom, TVM_GETITEMRECT, TRUE, (LPARAM)&rect), "Failed to get rect for first visible item.\n");
918 visibleItem = TreeView_GetNextItem(pHdr->hwndFrom, visibleItem, TVGN_NEXTVISIBLE);
919 *(HTREEITEM*)&rect = visibleItem;
920 ok(visibleItem != NULL, "There must be a visible item after the first visisble item.\n");
921 todo_wine
922 ok(SendMessage(pHdr->hwndFrom, TVM_GETITEMRECT, TRUE, (LPARAM)&rect), "Failed to get rect for second visible item.\n");
923 }
924 break;
925 }
926 }
927 }
928
929 case WM_DESTROY:
930 PostQuitMessage(0);
931 break;
932 }
933
934 defwndproc_counter++;
935 ret = DefWindowProcA(hWnd, message, wParam, lParam);
936 defwndproc_counter--;
937
938 return ret;
939 }
940
941 static void test_expandinvisible(void)
942 {
943 static CHAR nodeText[][5] = {"0", "1", "2", "3", "4"};
944 TVINSERTSTRUCTA ins;
945 HTREEITEM node[5];
946 RECT dummyRect;
947 BOOL nodeVisible;
948 LRESULT ret;
949 HWND hTree;
950
951 hTree = create_treeview_control();
952
953 /* The test builds the following tree and expands then node 1, while node 0 is collapsed.
954 *
955 * 0
956 * |- 1
957 * | |- 2
958 * | |- 3
959 * |- 4
960 *
961 */
962
963 ret = TreeView_DeleteAllItems(hTree);
964 ok(ret == TRUE, "ret\n");
965 ins.hParent = TVI_ROOT;
966 ins.hInsertAfter = TVI_ROOT;
967 U(ins).item.mask = TVIF_TEXT;
968 U(ins).item.pszText = nodeText[0];
969 node[0] = TreeView_InsertItem(hTree, &ins);
970 assert(node[0]);
971
972 ins.hInsertAfter = TVI_LAST;
973 U(ins).item.mask = TVIF_TEXT;
974 ins.hParent = node[0];
975
976 U(ins).item.pszText = nodeText[1];
977 node[1] = TreeView_InsertItem(hTree, &ins);
978 assert(node[1]);
979 U(ins).item.pszText = nodeText[4];
980 node[4] = TreeView_InsertItem(hTree, &ins);
981 assert(node[4]);
982
983 ins.hParent = node[1];
984
985 U(ins).item.pszText = nodeText[2];
986 node[2] = TreeView_InsertItem(hTree, &ins);
987 assert(node[2]);
988 U(ins).item.pszText = nodeText[3];
989 node[3] = TreeView_InsertItem(hTree, &ins);
990 assert(node[3]);
991
992
993 nodeVisible = TreeView_GetItemRect(hTree, node[1], &dummyRect, FALSE);
994 ok(!nodeVisible, "Node 1 should not be visible.\n");
995 nodeVisible = TreeView_GetItemRect(hTree, node[2], &dummyRect, FALSE);
996 ok(!nodeVisible, "Node 2 should not be visible.\n");
997 nodeVisible = TreeView_GetItemRect(hTree, node[3], &dummyRect, FALSE);
998 ok(!nodeVisible, "Node 3 should not be visible.\n");
999 nodeVisible = TreeView_GetItemRect(hTree, node[4], &dummyRect, FALSE);
1000 ok(!nodeVisible, "Node 4 should not be visible.\n");
1001
1002 ok(TreeView_Expand(hTree, node[1], TVE_EXPAND), "Expand of node 1 failed.\n");
1003
1004 nodeVisible = TreeView_GetItemRect(hTree, node[1], &dummyRect, FALSE);
1005 ok(!nodeVisible, "Node 1 should not be visible.\n");
1006 nodeVisible = TreeView_GetItemRect(hTree, node[2], &dummyRect, FALSE);
1007 ok(!nodeVisible, "Node 2 should not be visible.\n");
1008 nodeVisible = TreeView_GetItemRect(hTree, node[3], &dummyRect, FALSE);
1009 ok(!nodeVisible, "Node 3 should not be visible.\n");
1010 nodeVisible = TreeView_GetItemRect(hTree, node[4], &dummyRect, FALSE);
1011 ok(!nodeVisible, "Node 4 should not be visible.\n");
1012
1013 DestroyWindow(hTree);
1014 }
1015
1016 static void test_itemedit(void)
1017 {
1018 DWORD r;
1019 HWND edit;
1020 TVITEMA item;
1021 CHAR buff[2];
1022 HWND hTree;
1023
1024 hTree = create_treeview_control();
1025 fill_tree(hTree);
1026
1027 /* try with null item */
1028 edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, 0);
1029 ok(!IsWindow(edit), "Expected valid handle\n");
1030
1031 /* trigger edit */
1032 edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
1033 ok(IsWindow(edit), "Expected valid handle\n");
1034 /* item shouldn't be selected automatically after TVM_EDITLABEL */
1035 r = SendMessage(hTree, TVM_GETITEMSTATE, (WPARAM)hRoot, TVIS_SELECTED);
1036 expect(0, r);
1037 /* try to cancel with wrong edit handle */
1038 r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), 0);
1039 expect(0, r);
1040 ok(IsWindow(edit), "Expected edit control to be valid\n");
1041 r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
1042 expect(0, r);
1043 ok(!IsWindow(edit), "Expected edit control to be destroyed\n");
1044 /* try to cancel without creating edit */
1045 r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), 0);
1046 expect(0, r);
1047
1048 /* try to cancel with wrong (not null) handle */
1049 edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
1050 ok(IsWindow(edit), "Expected valid handle\n");
1051 r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hTree);
1052 expect(0, r);
1053 ok(IsWindow(edit), "Expected edit control to be valid\n");
1054 r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
1055 expect(0, r);
1056
1057 /* remove selection after starting edit */
1058 r = TreeView_SelectItem(hTree, hRoot);
1059 expect(TRUE, r);
1060 edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
1061 ok(IsWindow(edit), "Expected valid handle\n");
1062 r = TreeView_SelectItem(hTree, NULL);
1063 expect(TRUE, r);
1064 /* alter text */
1065 strncpy(buff, "x", sizeof(buff)/sizeof(CHAR));
1066 r = SendMessage(edit, WM_SETTEXT, 0, (LPARAM)buff);
1067 expect(TRUE, r);
1068 r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
1069 expect(0, r);
1070 ok(!IsWindow(edit), "Expected edit control to be destroyed\n");
1071 /* check that text is saved */
1072 item.mask = TVIF_TEXT;
1073 item.hItem = hRoot;
1074 item.pszText = buff;
1075 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
1076 r = SendMessage(hTree, TVM_GETITEM, 0, (LPARAM)&item);
1077 expect(TRUE, r);
1078 ok(!strcmp("x", buff), "Expected item text to change\n");
1079
1080 DestroyWindow(hTree);
1081 }
1082
1083 static void test_treeview_classinfo(void)
1084 {
1085 WNDCLASSA cls;
1086
1087 memset(&cls, 0, sizeof(cls));
1088 GetClassInfo(GetModuleHandleA("comctl32.dll"), WC_TREEVIEWA, &cls);
1089 ok(cls.hbrBackground == NULL, "Expected NULL background brush, got %p\n", cls.hbrBackground);
1090 ok(cls.style == (CS_GLOBALCLASS | CS_DBLCLKS), "Expected got %x\n", cls.style);
1091 expect(0, cls.cbClsExtra);
1092 }
1093
1094 static void test_get_linecolor(void)
1095 {
1096 COLORREF clr;
1097 HWND hTree;
1098
1099 hTree = create_treeview_control();
1100
1101 /* newly created control has default color */
1102 clr = (COLORREF)SendMessage(hTree, TVM_GETLINECOLOR, 0, 0);
1103 if (clr == 0)
1104 win_skip("TVM_GETLINECOLOR is not supported on comctl32 < 5.80\n");
1105 else
1106 expect(CLR_DEFAULT, clr);
1107
1108 DestroyWindow(hTree);
1109 }
1110
1111 static void test_get_insertmarkcolor(void)
1112 {
1113 COLORREF clr;
1114 HWND hTree;
1115
1116 hTree = create_treeview_control();
1117
1118 /* newly created control has default color */
1119 clr = (COLORREF)SendMessage(hTree, TVM_GETINSERTMARKCOLOR, 0, 0);
1120 if (clr == 0)
1121 win_skip("TVM_GETINSERTMARKCOLOR is not supported on comctl32 < 5.80\n");
1122 else
1123 expect(CLR_DEFAULT, clr);
1124
1125 DestroyWindow(hTree);
1126 }
1127
1128 static void test_expandnotify(void)
1129 {
1130 HWND hTree;
1131 BOOL ret;
1132 TVITEMA item;
1133
1134 hTree = create_treeview_control();
1135 fill_tree(hTree);
1136
1137 item.hItem = hRoot;
1138 item.mask = TVIF_STATE;
1139
1140 item.state = TVIS_EXPANDED;
1141 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1142 ok(ret == TRUE, "got %d\n", ret);
1143 ok((item.state & TVIS_EXPANDED) == 0, "expected collapsed\n");
1144
1145 /* preselect root node here */
1146 ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);
1147 ok(ret == TRUE, "got %d\n", ret);
1148
1149 g_get_from_expand = TRUE;
1150 /* expand */
1151 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1152 g_item_expanding.state = 0xdeadbeef;
1153 g_item_expanded.state = 0xdeadbeef;
1154 ret = SendMessageA(hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)hRoot);
1155 ok(ret == TRUE, "got %d\n", ret);
1156 ok(g_item_expanding.state == TVIS_SELECTED, "got state on TVN_ITEMEXPANDING 0x%08x\n",
1157 g_item_expanding.state);
1158 ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1159 g_item_expanded.state);
1160 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_seq, "expand notifications", FALSE);
1161 g_get_from_expand = FALSE;
1162
1163 /* check that it's expanded */
1164 item.state = TVIS_EXPANDED;
1165 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1166 ok(ret == TRUE, "got %d\n", ret);
1167 ok((item.state & TVIS_EXPANDED) == TVIS_EXPANDED, "expected expanded\n");
1168
1169 /* collapse */
1170 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1171 ret = SendMessageA(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot);
1172 ok(ret == TRUE, "got %d\n", ret);
1173 item.state = TVIS_EXPANDED;
1174 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1175 ok(ret == TRUE, "got %d\n", ret);
1176 ok((item.state & TVIS_EXPANDED) == 0, "expected collapsed\n");
1177 /* all next collapse/expand attempts won't produce any notifications,
1178 the only way is to reset with all children removed */
1179 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "collapse after expand notifications", FALSE);
1180
1181 DestroyWindow(hTree);
1182 }
1183
1184 static void test_rect_retrieval_after_expand_with_select(void) {
1185 BOOL ret;
1186 HWND hTree;
1187 hTree = create_treeview_control();
1188 fill_tree(hTree);
1189 g_get_rect_in_expand = TRUE;
1190 ret = TreeView_Select(hTree, hChild, TVGN_CARET);
1191 g_get_rect_in_expand = FALSE;
1192 ok(ret,"TreeView_Select should return true\n");
1193 }
1194
1195 START_TEST(treeview)
1196 {
1197 HMODULE hComctl32;
1198 BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
1199 WNDCLASSA wc;
1200 MSG msg;
1201
1202 hComctl32 = GetModuleHandleA("comctl32.dll");
1203 pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
1204 if (pInitCommonControlsEx)
1205 {
1206 INITCOMMONCONTROLSEX iccex;
1207 iccex.dwSize = sizeof(iccex);
1208 iccex.dwICC = ICC_TREEVIEW_CLASSES;
1209 pInitCommonControlsEx(&iccex);
1210 }
1211 else
1212 InitCommonControls();
1213
1214 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1215
1216 wc.style = CS_HREDRAW | CS_VREDRAW;
1217 wc.cbClsExtra = 0;
1218 wc.cbWndExtra = 0;
1219 wc.hInstance = GetModuleHandleA(NULL);
1220 wc.hIcon = NULL;
1221 wc.hCursor = LoadCursorA(NULL, IDC_IBEAM);
1222 wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
1223 wc.lpszMenuName = NULL;
1224 wc.lpszClassName = "MyTestWnd";
1225 wc.lpfnWndProc = parent_wnd_proc;
1226 RegisterClassA(&wc);
1227
1228 hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW,
1229 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105, NULL, NULL, GetModuleHandleA(NULL), 0);
1230
1231 ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n");
1232 if (!hMainWnd) return;
1233
1234 test_fillroot();
1235 test_select();
1236 test_getitemtext();
1237 test_focus();
1238 test_get_set_bkcolor();
1239 test_get_set_imagelist();
1240 test_get_set_indent();
1241 test_get_set_insertmark();
1242 test_get_set_item();
1243 test_get_set_itemheight();
1244 test_get_set_scrolltime();
1245 test_get_set_textcolor();
1246 test_get_linecolor();
1247 test_get_insertmarkcolor();
1248 test_get_set_tooltips();
1249 test_get_set_unicodeformat();
1250 test_callback();
1251 test_expandinvisible();
1252 test_itemedit();
1253 test_treeview_classinfo();
1254 test_expandnotify();
1255 test_rect_retrieval_after_expand_with_select();
1256
1257 PostMessageA(hMainWnd, WM_CLOSE, 0, 0);
1258 while(GetMessageA(&msg,0,0,0)) {
1259 TranslateMessage(&msg);
1260 DispatchMessageA(&msg);
1261 }
1262 }