comctl32: Call TREEVIEW_SendExpanded after expanding.
[wine] / dlls / comctl32 / tests / 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                   ok(SendMessage(pHdr->hwndFrom, TVM_GETITEMRECT, TRUE, (LPARAM)&rect), "Failed to get rect for second visible item.\n");
922                 }
923                 break;
924             }
925         }
926     }
927
928     case WM_DESTROY:
929         PostQuitMessage(0);
930         break;
931     }
932
933     defwndproc_counter++;
934     ret = DefWindowProcA(hWnd, message, wParam, lParam);
935     defwndproc_counter--;
936
937     return ret;
938 }
939
940 static void test_expandinvisible(void)
941 {
942     static CHAR nodeText[][5] = {"0", "1", "2", "3", "4"};
943     TVINSERTSTRUCTA ins;
944     HTREEITEM node[5];
945     RECT dummyRect;
946     BOOL nodeVisible;
947     LRESULT ret;
948     HWND hTree;
949
950     hTree = create_treeview_control();
951
952     /* The test builds the following tree and expands then node 1, while node 0 is collapsed.
953      *
954      * 0
955      * |- 1
956      * |  |- 2
957      * |  |- 3
958      * |- 4
959      *
960      */
961
962     ret = TreeView_DeleteAllItems(hTree);
963     ok(ret == TRUE, "ret\n");
964     ins.hParent = TVI_ROOT;
965     ins.hInsertAfter = TVI_ROOT;
966     U(ins).item.mask = TVIF_TEXT;
967     U(ins).item.pszText = nodeText[0];
968     node[0] = TreeView_InsertItem(hTree, &ins);
969     assert(node[0]);
970
971     ins.hInsertAfter = TVI_LAST;
972     U(ins).item.mask = TVIF_TEXT;
973     ins.hParent = node[0];
974
975     U(ins).item.pszText = nodeText[1];
976     node[1] = TreeView_InsertItem(hTree, &ins);
977     assert(node[1]);
978     U(ins).item.pszText = nodeText[4];
979     node[4] = TreeView_InsertItem(hTree, &ins);
980     assert(node[4]);
981
982     ins.hParent = node[1];
983
984     U(ins).item.pszText = nodeText[2];
985     node[2] = TreeView_InsertItem(hTree, &ins);
986     assert(node[2]);
987     U(ins).item.pszText = nodeText[3];
988     node[3] = TreeView_InsertItem(hTree, &ins);
989     assert(node[3]);
990
991
992     nodeVisible = TreeView_GetItemRect(hTree, node[1], &dummyRect, FALSE);
993     ok(!nodeVisible, "Node 1 should not be visible.\n");
994     nodeVisible = TreeView_GetItemRect(hTree, node[2], &dummyRect, FALSE);
995     ok(!nodeVisible, "Node 2 should not be visible.\n");
996     nodeVisible = TreeView_GetItemRect(hTree, node[3], &dummyRect, FALSE);
997     ok(!nodeVisible, "Node 3 should not be visible.\n");
998     nodeVisible = TreeView_GetItemRect(hTree, node[4], &dummyRect, FALSE);
999     ok(!nodeVisible, "Node 4 should not be visible.\n");
1000
1001     ok(TreeView_Expand(hTree, node[1], TVE_EXPAND), "Expand of node 1 failed.\n");
1002
1003     nodeVisible = TreeView_GetItemRect(hTree, node[1], &dummyRect, FALSE);
1004     ok(!nodeVisible, "Node 1 should not be visible.\n");
1005     nodeVisible = TreeView_GetItemRect(hTree, node[2], &dummyRect, FALSE);
1006     ok(!nodeVisible, "Node 2 should not be visible.\n");
1007     nodeVisible = TreeView_GetItemRect(hTree, node[3], &dummyRect, FALSE);
1008     ok(!nodeVisible, "Node 3 should not be visible.\n");
1009     nodeVisible = TreeView_GetItemRect(hTree, node[4], &dummyRect, FALSE);
1010     ok(!nodeVisible, "Node 4 should not be visible.\n");
1011
1012     DestroyWindow(hTree);
1013 }
1014
1015 static void test_itemedit(void)
1016 {
1017     DWORD r;
1018     HWND edit;
1019     TVITEMA item;
1020     CHAR buff[2];
1021     HWND hTree;
1022
1023     hTree = create_treeview_control();
1024     fill_tree(hTree);
1025
1026     /* try with null item */
1027     edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, 0);
1028     ok(!IsWindow(edit), "Expected valid handle\n");
1029
1030     /* trigger edit */
1031     edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
1032     ok(IsWindow(edit), "Expected valid handle\n");
1033     /* item shouldn't be selected automatically after TVM_EDITLABEL */
1034     r = SendMessage(hTree, TVM_GETITEMSTATE, (WPARAM)hRoot, TVIS_SELECTED);
1035     expect(0, r);
1036     /* try to cancel with wrong edit handle */
1037     r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), 0);
1038     expect(0, r);
1039     ok(IsWindow(edit), "Expected edit control to be valid\n");
1040     r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
1041     expect(0, r);
1042     ok(!IsWindow(edit), "Expected edit control to be destroyed\n");
1043     /* try to cancel without creating edit */
1044     r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), 0);
1045     expect(0, r);
1046
1047     /* try to cancel with wrong (not null) handle */
1048     edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
1049     ok(IsWindow(edit), "Expected valid handle\n");
1050     r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hTree);
1051     expect(0, r);
1052     ok(IsWindow(edit), "Expected edit control to be valid\n");
1053     r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
1054     expect(0, r);
1055
1056     /* remove selection after starting edit */
1057     r = TreeView_SelectItem(hTree, hRoot);
1058     expect(TRUE, r);
1059     edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
1060     ok(IsWindow(edit), "Expected valid handle\n");
1061     r = TreeView_SelectItem(hTree, NULL);
1062     expect(TRUE, r);
1063     /* alter text */
1064     strncpy(buff, "x", sizeof(buff)/sizeof(CHAR));
1065     r = SendMessage(edit, WM_SETTEXT, 0, (LPARAM)buff);
1066     expect(TRUE, r);
1067     r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
1068     expect(0, r);
1069     ok(!IsWindow(edit), "Expected edit control to be destroyed\n");
1070     /* check that text is saved */
1071     item.mask = TVIF_TEXT;
1072     item.hItem = hRoot;
1073     item.pszText = buff;
1074     item.cchTextMax = sizeof(buff)/sizeof(CHAR);
1075     r = SendMessage(hTree, TVM_GETITEM, 0, (LPARAM)&item);
1076     expect(TRUE, r);
1077     ok(!strcmp("x", buff), "Expected item text to change\n");
1078
1079     DestroyWindow(hTree);
1080 }
1081
1082 static void test_treeview_classinfo(void)
1083 {
1084     WNDCLASSA cls;
1085
1086     memset(&cls, 0, sizeof(cls));
1087     GetClassInfo(GetModuleHandleA("comctl32.dll"), WC_TREEVIEWA, &cls);
1088     ok(cls.hbrBackground == NULL, "Expected NULL background brush, got %p\n", cls.hbrBackground);
1089     ok(cls.style == (CS_GLOBALCLASS | CS_DBLCLKS), "Expected got %x\n", cls.style);
1090     expect(0, cls.cbClsExtra);
1091 }
1092
1093 static void test_get_linecolor(void)
1094 {
1095     COLORREF clr;
1096     HWND hTree;
1097
1098     hTree = create_treeview_control();
1099
1100     /* newly created control has default color */
1101     clr = (COLORREF)SendMessage(hTree, TVM_GETLINECOLOR, 0, 0);
1102     if (clr == 0)
1103         win_skip("TVM_GETLINECOLOR is not supported on comctl32 < 5.80\n");
1104     else
1105         expect(CLR_DEFAULT, clr);
1106
1107     DestroyWindow(hTree);
1108 }
1109
1110 static void test_get_insertmarkcolor(void)
1111 {
1112     COLORREF clr;
1113     HWND hTree;
1114
1115     hTree = create_treeview_control();
1116
1117     /* newly created control has default color */
1118     clr = (COLORREF)SendMessage(hTree, TVM_GETINSERTMARKCOLOR, 0, 0);
1119     if (clr == 0)
1120         win_skip("TVM_GETINSERTMARKCOLOR is not supported on comctl32 < 5.80\n");
1121     else
1122         expect(CLR_DEFAULT, clr);
1123
1124     DestroyWindow(hTree);
1125 }
1126
1127 static void test_expandnotify(void)
1128 {
1129     HWND hTree;
1130     BOOL ret;
1131     TVITEMA item;
1132
1133     hTree = create_treeview_control();
1134     fill_tree(hTree);
1135
1136     item.hItem = hRoot;
1137     item.mask = TVIF_STATE;
1138
1139     item.state = TVIS_EXPANDED;
1140     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1141     ok(ret == TRUE, "got %d\n", ret);
1142     ok((item.state & TVIS_EXPANDED) == 0, "expected collapsed\n");
1143
1144     /* preselect root node here */
1145     ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);
1146     ok(ret == TRUE, "got %d\n", ret);
1147
1148     g_get_from_expand = TRUE;
1149     /* expand */
1150     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1151     g_item_expanding.state = 0xdeadbeef;
1152     g_item_expanded.state = 0xdeadbeef;
1153     ret = SendMessageA(hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)hRoot);
1154     ok(ret == TRUE, "got %d\n", ret);
1155     ok(g_item_expanding.state == TVIS_SELECTED, "got state on TVN_ITEMEXPANDING 0x%08x\n",
1156        g_item_expanding.state);
1157     ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1158        g_item_expanded.state);
1159     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_seq, "expand notifications", FALSE);
1160     g_get_from_expand = FALSE;
1161
1162     /* check that it's expanded */
1163     item.state = TVIS_EXPANDED;
1164     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1165     ok(ret == TRUE, "got %d\n", ret);
1166     ok((item.state & TVIS_EXPANDED) == TVIS_EXPANDED, "expected expanded\n");
1167
1168     /* collapse */
1169     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1170     ret = SendMessageA(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot);
1171     ok(ret == TRUE, "got %d\n", ret);
1172     item.state = TVIS_EXPANDED;
1173     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1174     ok(ret == TRUE, "got %d\n", ret);
1175     ok((item.state & TVIS_EXPANDED) == 0, "expected collapsed\n");
1176     /* all next collapse/expand attempts won't produce any notifications,
1177        the only way is to reset with all children removed */
1178     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "collapse after expand notifications", FALSE);
1179
1180     DestroyWindow(hTree);
1181 }
1182
1183 static void test_rect_retrieval_after_expand_with_select(void) {
1184   BOOL ret;
1185   HWND hTree;
1186   hTree = create_treeview_control();
1187   fill_tree(hTree);
1188   g_get_rect_in_expand = TRUE;
1189   ret = TreeView_Select(hTree, hChild, TVGN_CARET);
1190   g_get_rect_in_expand = FALSE;
1191   ok(ret,"TreeView_Select should return true\n");
1192 }
1193
1194 START_TEST(treeview)
1195 {
1196     HMODULE hComctl32;
1197     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
1198     WNDCLASSA wc;
1199     MSG msg;
1200   
1201     hComctl32 = GetModuleHandleA("comctl32.dll");
1202     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
1203     if (pInitCommonControlsEx)
1204     {
1205         INITCOMMONCONTROLSEX iccex;
1206         iccex.dwSize = sizeof(iccex);
1207         iccex.dwICC  = ICC_TREEVIEW_CLASSES;
1208         pInitCommonControlsEx(&iccex);
1209     }
1210     else
1211         InitCommonControls();
1212
1213     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1214   
1215     wc.style = CS_HREDRAW | CS_VREDRAW;
1216     wc.cbClsExtra = 0;
1217     wc.cbWndExtra = 0;
1218     wc.hInstance = GetModuleHandleA(NULL);
1219     wc.hIcon = NULL;
1220     wc.hCursor = LoadCursorA(NULL, IDC_IBEAM);
1221     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
1222     wc.lpszMenuName = NULL;
1223     wc.lpszClassName = "MyTestWnd";
1224     wc.lpfnWndProc = parent_wnd_proc;
1225     RegisterClassA(&wc);
1226
1227     hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW,
1228       CW_USEDEFAULT, CW_USEDEFAULT, 130, 105, NULL, NULL, GetModuleHandleA(NULL), 0);
1229
1230     ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n");
1231     if (!hMainWnd) return;
1232
1233     test_fillroot();
1234     test_select();
1235     test_getitemtext();
1236     test_focus();
1237     test_get_set_bkcolor();
1238     test_get_set_imagelist();
1239     test_get_set_indent();
1240     test_get_set_insertmark();
1241     test_get_set_item();
1242     test_get_set_itemheight();
1243     test_get_set_scrolltime();
1244     test_get_set_textcolor();
1245     test_get_linecolor();
1246     test_get_insertmarkcolor();
1247     test_get_set_tooltips();
1248     test_get_set_unicodeformat();
1249     test_callback();
1250     test_expandinvisible();
1251     test_itemedit();
1252     test_treeview_classinfo();
1253     test_expandnotify();
1254     test_rect_retrieval_after_expand_with_select();
1255
1256     PostMessageA(hMainWnd, WM_CLOSE, 0, 0);
1257     while(GetMessageA(&msg,0,0,0)) {
1258         TranslateMessage(&msg);
1259         DispatchMessageA(&msg);
1260     }
1261 }