1 /* Unit tests for treeview.
3 * Copyright 2005 Krzysztof Foltman
4 * Copyright 2007 Christopher James Peterson
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.
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.
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
32 #include "wine/test.h"
36 static const char *TEST_CALLBACK_TEXT = "callback_text";
38 static TVITEMA g_item_expanding, g_item_expanded;
39 static BOOL g_get_from_expand;
40 static BOOL g_get_rect_in_expand;
41 static BOOL g_disp_A_to_W;
43 #define NUM_MSG_SEQUENCES 2
44 #define TREEVIEW_SEQ_INDEX 0
45 #define PARENT_SEQ_INDEX 1
47 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
49 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
50 static struct msg_sequence *item_sequence[1];
52 static const struct message FillRootSeq[] = {
53 { TVM_INSERTITEM, sent },
54 { TVM_INSERTITEM, sent },
58 static const struct message rootnone_select_seq[] = {
59 { TVM_SELECTITEM, sent|wparam, 9 },
60 { TVM_SELECTITEM, sent|wparam, 9 },
61 { TVM_SELECTITEM, sent|wparam, 9 },
62 { TVM_SELECTITEM, sent|wparam, 9 },
63 { TVM_SELECTITEM, sent|wparam, 9 },
64 { TVM_SELECTITEM, sent|wparam, 9 },
68 static const struct message rootchild_select_seq[] = {
69 { TVM_SELECTITEM, sent|wparam, 9 },
70 { TVM_SELECTITEM, sent|wparam, 9 },
71 { TVM_SELECTITEM, sent|wparam, 9 },
72 { TVM_SELECTITEM, sent|wparam, 9 },
73 { TVM_SELECTITEM, sent|wparam, 9 },
74 { TVM_SELECTITEM, sent|wparam, 9 },
78 static const struct message getitemtext_seq[] = {
79 { TVM_INSERTITEMA, sent },
80 { TVM_GETITEMA, sent },
81 { TVM_DELETEITEM, sent },
85 static const struct message focus_seq[] = {
86 { TVM_INSERTITEM, sent },
87 { TVM_INSERTITEM, sent },
88 { TVM_SELECTITEM, sent|wparam, 9 },
89 /* The following end up out of order in wine */
90 { WM_WINDOWPOSCHANGING, sent|defwinproc },
91 { WM_NCCALCSIZE, sent|wparam|defwinproc, TRUE },
92 { WM_WINDOWPOSCHANGED, sent|defwinproc },
93 { WM_SIZE, sent|defwinproc },
94 { WM_WINDOWPOSCHANGING, sent|defwinproc|optional },
95 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, TRUE },
96 { WM_WINDOWPOSCHANGED, sent|defwinproc|optional },
97 { WM_SIZE, sent|defwinproc|optional },
98 { WM_PAINT, sent|defwinproc },
99 { WM_NCPAINT, sent|wparam|defwinproc, 1 },
100 { WM_ERASEBKGND, sent|defwinproc },
101 { TVM_EDITLABEL, sent },
102 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_UPDATE) },
103 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_CHANGE) },
104 { WM_PARENTNOTIFY, sent|wparam|defwinproc, MAKEWPARAM(WM_CREATE, 0) },
105 { WM_KILLFOCUS, sent|defwinproc },
106 { WM_PAINT, sent|defwinproc },
107 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
108 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_SETFOCUS) },
109 { WM_ERASEBKGND, sent|defwinproc|optional },
110 { WM_CTLCOLOREDIT, sent|defwinproc|optional },
111 { WM_CTLCOLOREDIT, sent|defwinproc|optional },
115 static const struct message test_get_set_bkcolor_seq[] = {
116 { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
117 { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0 },
118 { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
119 { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0x00ffffff },
120 { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
121 { TVM_SETBKCOLOR, sent|wparam|lparam, 0, -1 },
125 static const struct message test_get_set_imagelist_seq[] = {
126 { TVM_SETIMAGELIST, sent|wparam|lparam, 0, 0 },
127 { TVM_GETIMAGELIST, sent|wparam|lparam, 0, 0 },
131 static const struct message test_get_set_indent_seq[] = {
132 { TVM_SETINDENT, sent|wparam|lparam, 0, 0 },
133 { TVM_GETINDENT, sent|wparam|lparam, 0, 0 },
134 /* The actual amount to indent is dependent on the system for this message */
135 { TVM_SETINDENT, sent },
136 { TVM_GETINDENT, sent|wparam|lparam, 0, 0 },
140 static const struct message test_get_set_insertmarkcolor_seq[] = {
141 { TVM_SETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 },
142 { TVM_GETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 },
146 static const struct message test_get_set_item_seq[] = {
147 { TVM_GETITEMA, sent },
148 { TVM_SETITEMA, sent },
149 { TVM_GETITEMA, sent },
150 { TVM_SETITEMA, sent },
154 static const struct message test_get_set_itemheight_seq[] = {
155 { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
156 { TVM_SETITEMHEIGHT, sent|wparam|lparam, -1, 0 },
157 { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
158 { TVM_SETITEMHEIGHT, sent|lparam, 0xcccccccc, 0 },
159 { TVM_GETITEMHEIGHT, sent|wparam|lparam|optional, 0, 0 },
160 { TVM_SETITEMHEIGHT, sent|wparam|lparam|optional, 9, 0 },
161 { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
165 static const struct message test_get_set_scrolltime_seq[] = {
166 { TVM_SETSCROLLTIME, sent|wparam|lparam, 20, 0 },
167 { TVM_GETSCROLLTIME, sent|wparam|lparam, 0, 0 },
171 static const struct message test_get_set_textcolor_seq[] = {
172 { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
173 { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
174 { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
175 { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, RGB(255, 255, 255) },
176 { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
177 { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, CLR_NONE },
181 static const struct message test_get_set_tooltips_seq[] = {
182 { WM_KILLFOCUS, sent },
183 { WM_IME_SETCONTEXT, sent|optional },
184 { WM_IME_NOTIFY, sent|optional },
185 { TVM_SETTOOLTIPS, sent|wparam|lparam, 0, 0 },
186 { TVM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 },
190 static const struct message test_get_set_unicodeformat_seq[] = {
191 { TVM_SETUNICODEFORMAT, sent|wparam|lparam, TRUE, 0 },
192 { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
193 { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
194 { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
195 { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
199 static const struct message parent_expand_seq[] = {
200 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
201 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
205 static const struct message parent_singleexpand_seq[] = {
206 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
207 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
208 { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
209 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
210 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
214 static const struct message empty_seq[] = {
218 static HWND hMainWnd;
220 static HTREEITEM hRoot, hChild;
223 static char sequence[256];
225 static void Clear(void)
231 static void AddItem(char ch)
233 sequence[pos++] = ch;
234 sequence[pos] = '\0';
237 static void IdentifyItem(HTREEITEM hItem)
239 if (hItem == hRoot) {
243 if (hItem == hChild) {
254 /* This function hooks in and records all messages to the treeview control */
255 static LRESULT WINAPI TreeviewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
257 static LONG defwndproc_counter = 0;
260 WNDPROC lpOldProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
262 msg.message = message;
263 msg.flags = sent|wparam|lparam;
264 if (defwndproc_counter) msg.flags |= defwinproc;
267 add_message(sequences, TREEVIEW_SEQ_INDEX, &msg);
269 defwndproc_counter++;
270 ret = CallWindowProcA(lpOldProc, hwnd, message, wParam, lParam);
271 defwndproc_counter--;
276 static HWND create_treeview_control(void)
281 hTree = CreateWindowExA(WS_EX_CLIENTEDGE, WC_TREEVIEWA, NULL, WS_CHILD|WS_VISIBLE|
282 TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS|TVS_EDITLABELS,
283 0, 0, 120, 100, hMainWnd, (HMENU)100, GetModuleHandleA(0), 0);
287 /* Record the old WNDPROC so we can call it after recording the messages */
288 pOldWndProc = (WNDPROC)SetWindowLongPtrA(hTree, GWLP_WNDPROC, (LONG_PTR)TreeviewWndProc);
289 SetWindowLongPtrA(hTree, GWLP_USERDATA, (LONG_PTR)pOldWndProc);
294 static void fill_tree(HWND hTree)
297 static CHAR root[] = "Root",
300 ins.hParent = TVI_ROOT;
301 ins.hInsertAfter = TVI_ROOT;
302 U(ins).item.mask = TVIF_TEXT;
303 U(ins).item.pszText = root;
304 hRoot = TreeView_InsertItem(hTree, &ins);
307 ins.hInsertAfter = TVI_FIRST;
308 U(ins).item.mask = TVIF_TEXT;
309 U(ins).item.pszText = child;
310 hChild = TreeView_InsertItem(hTree, &ins);
313 static void test_fillroot(void)
318 hTree = create_treeview_control();
320 flush_sequences(sequences, NUM_MSG_SEQUENCES);
330 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, FillRootSeq, "FillRoot", FALSE);
331 ok(!strcmp(sequence, "AB."), "Item creation\n");
333 /* UMLPad 1.15 depends on this being not -1 (I_IMAGECALLBACK) */
335 tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
336 SendMessage( hTree, TVM_GETITEMA, 0, (LPARAM)&tvi );
337 ok(tvi.iImage == 0, "tvi.iImage=%d\n", tvi.iImage);
338 ok(tvi.iSelectedImage == 0, "tvi.iSelectedImage=%d\n", tvi.iSelectedImage);
340 DestroyWindow(hTree);
343 static void test_callback(void)
346 HTREEITEM hItem1, hItem2;
349 CHAR test_string[] = "Test_string";
350 static const CHAR test2A[] = "TEST2";
355 hTree = create_treeview_control();
357 ret = TreeView_DeleteAllItems(hTree);
358 ok(ret == TRUE, "ret\n");
359 ins.hParent = TVI_ROOT;
360 ins.hInsertAfter = TVI_ROOT;
361 U(ins).item.mask = TVIF_TEXT;
362 U(ins).item.pszText = LPSTR_TEXTCALLBACK;
363 hRoot = TreeView_InsertItem(hTree, &ins);
367 tvi.mask = TVIF_TEXT;
369 tvi.cchTextMax = sizeof(buf)/sizeof(buf[0]);
370 ret = TreeView_GetItem(hTree, &tvi);
371 ok(ret == 1, "ret\n");
372 ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Callback item text mismatch %s vs %s\n",
373 tvi.pszText, TEST_CALLBACK_TEXT);
376 ins.hInsertAfter = TVI_FIRST;
377 U(ins).item.mask = TVIF_TEXT;
378 U(ins).item.pszText = test_string;
379 hItem1 = TreeView_InsertItem(hTree, &ins);
383 ret = TreeView_GetItem(hTree, &tvi);
384 ok(ret == TRUE, "ret\n");
385 ok(strcmp(tvi.pszText, test_string) == 0, "Item text mismatch %s vs %s\n",
386 tvi.pszText, test_string);
388 /* undocumented: pszText of NULL also means LPSTR_CALLBACK: */
390 ret = TreeView_SetItem(hTree, &tvi);
391 ok(ret == 1, "Expected SetItem return 1, got %ld\n", ret);
393 ret = TreeView_GetItem(hTree, &tvi);
394 ok(ret == TRUE, "Expected GetItem return TRUE, got %ld\n", ret);
395 ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
396 tvi.pszText, TEST_CALLBACK_TEXT);
398 U(ins).item.pszText = NULL;
399 hItem2 = TreeView_InsertItem(hTree, &ins);
402 memset(buf, 0, sizeof(buf));
403 ret = TreeView_GetItem(hTree, &tvi);
404 ok(ret == TRUE, "Expected GetItem return TRUE, got %ld\n", ret);
405 ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
406 tvi.pszText, TEST_CALLBACK_TEXT);
408 /* notification handler changed A->W */
409 g_disp_A_to_W = TRUE;
411 memset(buf, 0, sizeof(buf));
412 ret = TreeView_GetItem(hTree, &tvi);
413 ok(ret == TRUE, "got %ld\n", ret);
414 ok(strcmp(tvi.pszText, test2A) == 0, "got %s, expected %s\n",
415 tvi.pszText, test2A);
416 g_disp_A_to_W = FALSE;
418 DestroyWindow(hTree);
421 static void test_select(void)
426 hTree = create_treeview_control();
429 /* root-none select tests */
430 flush_sequences(sequences, NUM_MSG_SEQUENCES);
431 r = TreeView_SelectItem(hTree, NULL);
435 r = TreeView_SelectItem(hTree, hRoot);
438 r = TreeView_SelectItem(hTree, hRoot);
441 r = TreeView_SelectItem(hTree, NULL);
444 r = TreeView_SelectItem(hTree, NULL);
447 r = TreeView_SelectItem(hTree, hRoot);
450 ok(!strcmp(sequence, "1(nR)nR23(Rn)Rn45(nR)nR."), "root-none select test\n");
451 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, rootnone_select_seq,
452 "root-none select seq", FALSE);
454 /* root-child select tests */
455 flush_sequences(sequences, NUM_MSG_SEQUENCES);
456 r = TreeView_SelectItem(hTree, NULL);
461 r = TreeView_SelectItem(hTree, hRoot);
464 r = TreeView_SelectItem(hTree, hRoot);
467 r = TreeView_SelectItem(hTree, hChild);
470 r = TreeView_SelectItem(hTree, hChild);
473 r = TreeView_SelectItem(hTree, hRoot);
476 ok(!strcmp(sequence, "1(nR)nR23(RC)RC45(CR)CR."), "root-child select test\n");
477 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, rootchild_select_seq,
478 "root-child select seq", FALSE);
480 DestroyWindow(hTree);
483 static void test_getitemtext(void)
490 CHAR szBuffer[80] = "Blah";
491 int nBufferSize = sizeof(szBuffer)/sizeof(CHAR);
493 hTree = create_treeview_control();
496 flush_sequences(sequences, NUM_MSG_SEQUENCES);
498 /* add an item without TVIF_TEXT mask and pszText == NULL */
500 ins.hInsertAfter = TVI_ROOT;
501 U(ins).item.mask = 0;
502 U(ins).item.pszText = NULL;
503 U(ins).item.cchTextMax = 0;
504 hChild = TreeView_InsertItem(hTree, &ins);
507 /* retrieve it with TVIF_TEXT mask */
509 tvi.mask = TVIF_TEXT;
510 tvi.cchTextMax = nBufferSize;
511 tvi.pszText = szBuffer;
513 SendMessageA( hTree, TVM_GETITEMA, 0, (LPARAM)&tvi );
514 ok(!strcmp(szBuffer, ""), "szBuffer=\"%s\", expected \"\"\n", szBuffer);
515 ok(SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild), "DeleteItem failed\n");
516 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, getitemtext_seq, "get item text seq", FALSE);
518 DestroyWindow(hTree);
521 static void test_focus(void)
524 static CHAR child1[] = "Edit",
525 child2[] = "A really long string";
526 HTREEITEM hChild1, hChild2;
530 hTree = create_treeview_control();
533 flush_sequences(sequences, NUM_MSG_SEQUENCES);
535 /* This test verifies that when a label is being edited, scrolling
536 * the treeview does not cause the label to lose focus. To test
537 * this, first some additional entries are added to generate
541 ins.hInsertAfter = hChild;
542 U(ins).item.mask = TVIF_TEXT;
543 U(ins).item.pszText = child1;
544 hChild1 = TreeView_InsertItem(hTree, &ins);
546 ins.hInsertAfter = hChild1;
547 U(ins).item.mask = TVIF_TEXT;
548 U(ins).item.pszText = child2;
549 hChild2 = TreeView_InsertItem(hTree, &ins);
552 ShowWindow(hMainWnd,SW_SHOW);
553 SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild);
554 hEdit = TreeView_EditLabel(hTree, hChild);
555 ScrollWindowEx(hTree, -10, 0, NULL, NULL, NULL, NULL, SW_SCROLLCHILDREN);
556 ok(GetFocus() == hEdit, "Edit control should have focus\n");
557 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, focus_seq, "focus test", TRUE);
559 DestroyWindow(hTree);
562 static void test_get_set_bkcolor(void)
564 COLORREF crColor = RGB(0,0,0);
567 hTree = create_treeview_control();
570 flush_sequences(sequences, NUM_MSG_SEQUENCES);
572 /* If the value is -1, the control is using the system color for the background color. */
573 crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 );
574 ok(crColor == -1, "Default background color reported as 0x%.8x\n", crColor);
576 /* Test for black background */
577 SendMessage( hTree, TVM_SETBKCOLOR, 0, RGB(0,0,0) );
578 crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 );
579 ok(crColor == RGB(0,0,0), "Black background color reported as 0x%.8x\n", crColor);
581 /* Test for white background */
582 SendMessage( hTree, TVM_SETBKCOLOR, 0, RGB(255,255,255) );
583 crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 );
584 ok(crColor == RGB(255,255,255), "White background color reported as 0x%.8x\n", crColor);
586 /* Reset the default background */
587 SendMessage( hTree, TVM_SETBKCOLOR, 0, -1 );
589 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_bkcolor_seq,
590 "test get set bkcolor", FALSE);
592 DestroyWindow(hTree);
595 static void test_get_set_imagelist(void)
597 HIMAGELIST hImageList = NULL;
600 hTree = create_treeview_control();
603 flush_sequences(sequences, NUM_MSG_SEQUENCES);
605 /* Test a NULL HIMAGELIST */
606 SendMessage( hTree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)hImageList );
607 hImageList = (HIMAGELIST)SendMessage( hTree, TVM_GETIMAGELIST, TVSIL_NORMAL, 0 );
608 ok(hImageList == NULL, "NULL image list, reported as 0x%p, expected 0.\n", hImageList);
610 /* TODO: Test an actual image list */
612 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_imagelist_seq,
613 "test get imagelist", FALSE);
615 DestroyWindow(hTree);
618 static void test_get_set_indent(void)
621 int ulMinIndent = -1;
622 int ulMoreThanTwiceMin = -1;
625 hTree = create_treeview_control();
628 flush_sequences(sequences, NUM_MSG_SEQUENCES);
630 /* Finding the minimum indent */
631 SendMessage( hTree, TVM_SETINDENT, 0, 0 );
632 ulMinIndent = (int)SendMessage( hTree, TVM_GETINDENT, 0, 0 );
634 /* Checking an indent that is more than twice the default indent */
635 ulMoreThanTwiceMin = 2*ulMinIndent+1;
636 SendMessage( hTree, TVM_SETINDENT, ulMoreThanTwiceMin, 0 );
637 ulIndent = (DWORD)SendMessage( hTree, TVM_GETINDENT, 0, 0 );
638 ok(ulIndent == ulMoreThanTwiceMin, "Indent reported as %d, expected %d\n", ulIndent, ulMoreThanTwiceMin);
640 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_indent_seq,
641 "test get set indent", FALSE);
643 DestroyWindow(hTree);
646 static void test_get_set_insertmark(void)
648 COLORREF crColor = RGB(0,0,0);
651 hTree = create_treeview_control();
654 flush_sequences(sequences, NUM_MSG_SEQUENCES);
656 SendMessage( hTree, TVM_SETINSERTMARKCOLOR, 0, crColor );
657 crColor = (COLORREF)SendMessage( hTree, TVM_GETINSERTMARKCOLOR, 0, 0 );
658 ok(crColor == RGB(0,0,0), "Insert mark color reported as 0x%.8x, expected 0x00000000\n", crColor);
660 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_insertmarkcolor_seq,
661 "test get set insertmark color", FALSE);
663 DestroyWindow(hTree);
666 static void test_get_set_item(void)
668 TVITEMA tviRoot = {0};
669 int nBufferSize = 80;
670 char szBuffer[80] = {0};
673 hTree = create_treeview_control();
676 flush_sequences(sequences, NUM_MSG_SEQUENCES);
678 /* Test the root item */
679 tviRoot.hItem = hRoot;
680 tviRoot.mask = TVIF_TEXT;
681 tviRoot.cchTextMax = nBufferSize;
682 tviRoot.pszText = szBuffer;
683 SendMessage( hTree, TVM_GETITEMA, 0, (LPARAM)&tviRoot );
684 ok(!strcmp("Root", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Root\"\n", szBuffer);
686 /* Change the root text */
687 strncpy(szBuffer, "Testing123", nBufferSize);
688 SendMessage( hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot );
689 memset(szBuffer, 0, nBufferSize);
690 SendMessage( hTree, TVM_GETITEMA, 0, (LPARAM)&tviRoot );
691 ok(!strcmp("Testing123", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Testing123\"\n", szBuffer);
693 /* Reset the root text */
694 memset(szBuffer, 0, nBufferSize);
695 strncpy(szBuffer, "Root", nBufferSize);
696 SendMessage( hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot );
698 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_item_seq,
699 "test get set item", FALSE);
701 DestroyWindow(hTree);
704 static void test_get_set_itemheight(void)
710 hTree = create_treeview_control();
713 flush_sequences(sequences, NUM_MSG_SEQUENCES);
715 /* Assuming default height to begin with */
716 ulOldHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
718 /* Explicitly setting and getting the default height */
719 SendMessage( hTree, TVM_SETITEMHEIGHT, -1, 0 );
720 ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
721 ok(ulNewHeight == ulOldHeight, "Default height not set properly, reported %d, expected %d\n", ulNewHeight, ulOldHeight);
723 /* Explicitly setting and getting the height of twice the normal */
724 SendMessage( hTree, TVM_SETITEMHEIGHT, 2*ulOldHeight, 0 );
725 ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
726 ok(ulNewHeight == 2*ulOldHeight, "New height not set properly, reported %d, expected %d\n", ulNewHeight, 2*ulOldHeight);
728 /* Assuming tree doesn't have TVS_NONEVENHEIGHT set, so a set of 9 will round down to 8 */
729 SendMessage( hTree, TVM_SETITEMHEIGHT, 9, 0 );
730 ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
731 ok(ulNewHeight == 8, "Uneven height not set properly, reported %d, expected %d\n", ulNewHeight, 8);
733 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_itemheight_seq,
734 "test get set item height", FALSE);
736 /* without TVS_NONEVENHEIGHT */
737 SetWindowLong(hTree, GWL_STYLE, GetWindowLong(hTree, GWL_STYLE) & ~TVS_NONEVENHEIGHT);
739 ulOldHeight = SendMessage( hTree, TVM_SETITEMHEIGHT, 3, 0);
740 ok(ulOldHeight == 8, "got %d, expected %d\n", ulOldHeight, 8);
741 ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
742 ok(ulNewHeight == 2, "got %d, expected %d\n", ulNewHeight, 2);
744 ulOldHeight = SendMessage( hTree, TVM_SETITEMHEIGHT, 4, 0);
745 ok(ulOldHeight == 2, "got %d, expected %d\n", ulOldHeight, 2);
746 ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
747 ok(ulNewHeight == 4, "got %d, expected %d\n", ulNewHeight, 4);
749 /* with TVS_NONEVENHEIGHT */
750 SetWindowLong(hTree, GWL_STYLE, GetWindowLong(hTree, GWL_STYLE) | TVS_NONEVENHEIGHT);
752 ulOldHeight = SendMessage( hTree, TVM_SETITEMHEIGHT, 3, 0);
753 ok(ulOldHeight == 4, "got %d, expected %d\n", ulOldHeight, 4);
754 ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
755 ok(ulNewHeight == 3, "got %d, expected %d\n", ulNewHeight, 3);
757 ulOldHeight = SendMessage( hTree, TVM_SETITEMHEIGHT, 10, 0);
758 ok(ulOldHeight == 3, "got %d, expected %d\n", ulOldHeight, 3);
759 ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
760 ok(ulNewHeight == 10, "got %d, expected %d\n", ulNewHeight, 10);
762 DestroyWindow(hTree);
765 static void test_get_set_scrolltime(void)
767 int ulExpectedTime = 20;
771 hTree = create_treeview_control();
774 flush_sequences(sequences, NUM_MSG_SEQUENCES);
776 SendMessage( hTree, TVM_SETSCROLLTIME, ulExpectedTime, 0 );
777 ulTime = (int)SendMessage( hTree, TVM_GETSCROLLTIME, 0, 0 );
778 ok(ulTime == ulExpectedTime, "Scroll time reported as %d, expected %d\n", ulTime, ulExpectedTime);
780 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_scrolltime_seq,
781 "test get set scroll time", FALSE);
783 DestroyWindow(hTree);
786 static void test_get_set_textcolor(void)
788 /* If the value is -1, the control is using the system color for the text color. */
789 COLORREF crColor = RGB(0,0,0);
792 hTree = create_treeview_control();
795 flush_sequences(sequences, NUM_MSG_SEQUENCES);
797 crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 );
798 ok(crColor == -1, "Default text color reported as 0x%.8x\n", crColor);
800 /* Test for black text */
801 SendMessage( hTree, TVM_SETTEXTCOLOR, 0, RGB(0,0,0) );
802 crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 );
803 ok(crColor == RGB(0,0,0), "Black text color reported as 0x%.8x\n", crColor);
805 /* Test for white text */
806 SendMessage( hTree, TVM_SETTEXTCOLOR, 0, RGB(255,255,255) );
807 crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 );
808 ok(crColor == RGB(255,255,255), "White text color reported as 0x%.8x\n", crColor);
810 /* Reset the default text color */
811 SendMessage( hTree, TVM_SETTEXTCOLOR, 0, CLR_NONE );
813 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_textcolor_seq,
814 "test get set text color", FALSE);
816 DestroyWindow(hTree);
819 static void test_get_set_tooltips(void)
821 HWND hwndLastToolTip = NULL;
825 hTree = create_treeview_control();
828 flush_sequences(sequences, NUM_MSG_SEQUENCES);
830 /* show even WS_POPUP treeview don't send NM_TOOLTIPSCREATED */
831 hPopupTreeView = CreateWindow(WC_TREEVIEW, NULL, WS_POPUP|WS_VISIBLE, 0, 0, 100, 100, hMainWnd, NULL, NULL, NULL);
832 DestroyWindow(hPopupTreeView);
834 /* Testing setting a NULL ToolTip */
835 SendMessage( hTree, TVM_SETTOOLTIPS, 0, 0 );
836 hwndLastToolTip = (HWND)SendMessage( hTree, TVM_GETTOOLTIPS, 0, 0 );
837 ok(hwndLastToolTip == NULL, "NULL tool tip, reported as 0x%p, expected 0.\n", hwndLastToolTip);
839 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_tooltips_seq,
840 "test get set tooltips", TRUE);
842 /* TODO: Add a test of an actual tooltip */
843 DestroyWindow(hTree);
846 static void test_get_set_unicodeformat(void)
848 BOOL bPreviousSetting = 0;
849 BOOL bNewSetting = 0;
852 hTree = create_treeview_control();
855 flush_sequences(sequences, NUM_MSG_SEQUENCES);
858 bPreviousSetting = (BOOL)SendMessage( hTree, TVM_SETUNICODEFORMAT, 1, 0 );
859 bNewSetting = (BOOL)SendMessage( hTree, TVM_GETUNICODEFORMAT, 0, 0 );
860 ok(bNewSetting == 1, "Unicode setting did not work.\n");
863 SendMessage( hTree, TVM_SETUNICODEFORMAT, 0, 0 );
864 bNewSetting = (BOOL)SendMessage( hTree, TVM_GETUNICODEFORMAT, 0, 0 );
865 ok(bNewSetting == 0, "ANSI setting did not work.\n");
867 /* Revert to original setting */
868 SendMessage( hTree, TVM_SETUNICODEFORMAT, bPreviousSetting, 0 );
870 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_unicodeformat_seq,
871 "test get set unicode format", FALSE);
873 DestroyWindow(hTree);
876 static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
878 static LONG defwndproc_counter = 0;
882 HTREEITEM visibleItem;
884 msg.message = message;
885 msg.flags = sent|wparam|lparam;
886 if (defwndproc_counter) msg.flags |= defwinproc;
889 if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
891 /* log system messages, except for painting */
892 if (message < WM_USER &&
893 message != WM_PAINT &&
894 message != WM_ERASEBKGND &&
895 message != WM_NCPAINT &&
896 message != WM_NCHITTEST &&
897 message != WM_GETTEXT &&
898 message != WM_GETICON &&
899 message != WM_DEVICECHANGE)
901 trace("parent: %p, %04x, %08lx, %08lx\n", hWnd, message, wParam, lParam);
902 add_message(sequences, PARENT_SEQ_INDEX, &msg);
908 NMHDR *pHdr = (NMHDR *)lParam;
910 ok(pHdr->code != NM_TOOLTIPSCREATED, "Treeview should not send NM_TOOLTIPSCREATED\n");
911 if (pHdr->idFrom == 100)
913 NMTREEVIEWA *pTreeView = (LPNMTREEVIEWA) lParam;
916 case TVN_SELCHANGINGA:
918 IdentifyItem(pTreeView->itemOld.hItem);
919 IdentifyItem(pTreeView->itemNew.hItem);
921 case TVN_SELCHANGEDA:
923 IdentifyItem(pTreeView->itemOld.hItem);
924 IdentifyItem(pTreeView->itemNew.hItem);
926 case TVN_GETDISPINFOA: {
927 NMTVDISPINFOA *disp = (NMTVDISPINFOA *)lParam;
928 if (disp->item.mask & TVIF_TEXT) {
929 lstrcpyn(disp->item.pszText, TEST_CALLBACK_TEXT, disp->item.cchTextMax);
932 if (g_disp_A_to_W && (disp->item.mask & TVIF_TEXT)) {
933 static const WCHAR testW[] = {'T','E','S','T','2',0};
935 disp->hdr.code = TVN_GETDISPINFOW;
936 memcpy(disp->item.pszText, testW, sizeof(testW));
941 case TVN_ENDLABELEDIT: return TRUE;
942 case TVN_ITEMEXPANDINGA:
943 ok(pTreeView->itemNew.mask ==
944 (TVIF_HANDLE | TVIF_SELECTEDIMAGE | TVIF_IMAGE | TVIF_PARAM | TVIF_STATE),
945 "got wrong mask %x\n", pTreeView->itemNew.mask);
946 ok((pTreeView->itemNew.state & TVIS_EXPANDED) == 0,
947 "got wrong state %x\n", pTreeView->itemNew.state);
948 ok(pTreeView->itemOld.mask == 0,
949 "got wrong mask %x\n", pTreeView->itemOld.mask);
951 if (g_get_from_expand)
953 g_item_expanding.mask = TVIF_STATE;
954 g_item_expanding.hItem = hRoot;
955 ret = SendMessageA(pHdr->hwndFrom, TVM_GETITEMA, 0, (LPARAM)&g_item_expanding);
956 ok(ret == TRUE, "got %lu\n", ret);
959 case TVN_ITEMEXPANDEDA:
960 ok(pTreeView->itemNew.mask & TVIF_STATE, "got wrong mask %x\n", pTreeView->itemNew.mask);
961 ok(pTreeView->itemNew.state & (TVIS_EXPANDED|TVIS_EXPANDEDONCE),
962 "got wrong mask %x\n", pTreeView->itemNew.mask);
963 ok(pTreeView->itemOld.mask == 0,
964 "got wrong mask %x\n", pTreeView->itemOld.mask);
966 if (g_get_from_expand)
968 g_item_expanded.mask = TVIF_STATE;
969 g_item_expanded.hItem = hRoot;
970 ret = SendMessageA(pHdr->hwndFrom, TVM_GETITEMA, 0, (LPARAM)&g_item_expanded);
971 ok(ret == TRUE, "got %lu\n", ret);
973 if (g_get_rect_in_expand)
975 visibleItem = TreeView_GetNextItem(pHdr->hwndFrom, NULL, TVGN_FIRSTVISIBLE);
976 ok(pTreeView->itemNew.hItem == visibleItem, "expanded item == first visible item\n");
977 *(HTREEITEM*)&rect = visibleItem;
978 ok(SendMessage(pHdr->hwndFrom, TVM_GETITEMRECT, TRUE, (LPARAM)&rect), "Failed to get rect for first visible item.\n");
979 visibleItem = TreeView_GetNextItem(pHdr->hwndFrom, visibleItem, TVGN_NEXTVISIBLE);
980 *(HTREEITEM*)&rect = visibleItem;
981 ok(visibleItem != NULL, "There must be a visible item after the first visisble item.\n");
982 ok(SendMessage(pHdr->hwndFrom, TVM_GETITEMRECT, TRUE, (LPARAM)&rect), "Failed to get rect for second visible item.\n");
985 case TVN_DELETEITEMA:
989 ok(pTreeView->itemNew.mask == 0, "got wrong mask 0x%x\n", pTreeView->itemNew.mask);
991 ok(pTreeView->itemOld.mask == (TVIF_HANDLE | TVIF_PARAM), "got wrong mask 0x%x\n", pTreeView->itemOld.mask);
992 ok(pTreeView->itemOld.hItem != NULL, "got %p\n", pTreeView->itemOld.hItem);
994 memset(&item, 0, sizeof(item));
995 item.lParam = (LPARAM)pTreeView->itemOld.hItem;
996 add_message(item_sequence, 0, &item);
1009 defwndproc_counter++;
1010 ret = DefWindowProcA(hWnd, message, wParam, lParam);
1011 defwndproc_counter--;
1016 static void test_expandinvisible(void)
1018 static CHAR nodeText[][5] = {"0", "1", "2", "3", "4"};
1019 TVINSERTSTRUCTA ins;
1026 hTree = create_treeview_control();
1028 /* The test builds the following tree and expands then node 1, while node 0 is collapsed.
1038 ret = TreeView_DeleteAllItems(hTree);
1039 ok(ret == TRUE, "ret\n");
1040 ins.hParent = TVI_ROOT;
1041 ins.hInsertAfter = TVI_ROOT;
1042 U(ins).item.mask = TVIF_TEXT;
1043 U(ins).item.pszText = nodeText[0];
1044 node[0] = TreeView_InsertItem(hTree, &ins);
1047 ins.hInsertAfter = TVI_LAST;
1048 U(ins).item.mask = TVIF_TEXT;
1049 ins.hParent = node[0];
1051 U(ins).item.pszText = nodeText[1];
1052 node[1] = TreeView_InsertItem(hTree, &ins);
1054 U(ins).item.pszText = nodeText[4];
1055 node[4] = TreeView_InsertItem(hTree, &ins);
1058 ins.hParent = node[1];
1060 U(ins).item.pszText = nodeText[2];
1061 node[2] = TreeView_InsertItem(hTree, &ins);
1063 U(ins).item.pszText = nodeText[3];
1064 node[3] = TreeView_InsertItem(hTree, &ins);
1068 nodeVisible = TreeView_GetItemRect(hTree, node[1], &dummyRect, FALSE);
1069 ok(!nodeVisible, "Node 1 should not be visible.\n");
1070 nodeVisible = TreeView_GetItemRect(hTree, node[2], &dummyRect, FALSE);
1071 ok(!nodeVisible, "Node 2 should not be visible.\n");
1072 nodeVisible = TreeView_GetItemRect(hTree, node[3], &dummyRect, FALSE);
1073 ok(!nodeVisible, "Node 3 should not be visible.\n");
1074 nodeVisible = TreeView_GetItemRect(hTree, node[4], &dummyRect, FALSE);
1075 ok(!nodeVisible, "Node 4 should not be visible.\n");
1077 ok(TreeView_Expand(hTree, node[1], TVE_EXPAND), "Expand of node 1 failed.\n");
1079 nodeVisible = TreeView_GetItemRect(hTree, node[1], &dummyRect, FALSE);
1080 ok(!nodeVisible, "Node 1 should not be visible.\n");
1081 nodeVisible = TreeView_GetItemRect(hTree, node[2], &dummyRect, FALSE);
1082 ok(!nodeVisible, "Node 2 should not be visible.\n");
1083 nodeVisible = TreeView_GetItemRect(hTree, node[3], &dummyRect, FALSE);
1084 ok(!nodeVisible, "Node 3 should not be visible.\n");
1085 nodeVisible = TreeView_GetItemRect(hTree, node[4], &dummyRect, FALSE);
1086 ok(!nodeVisible, "Node 4 should not be visible.\n");
1088 DestroyWindow(hTree);
1091 static void test_itemedit(void)
1099 hTree = create_treeview_control();
1102 /* try with null item */
1103 edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, 0);
1104 ok(!IsWindow(edit), "Expected valid handle\n");
1107 edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
1108 ok(IsWindow(edit), "Expected valid handle\n");
1109 /* item shouldn't be selected automatically after TVM_EDITLABEL */
1110 r = SendMessage(hTree, TVM_GETITEMSTATE, (WPARAM)hRoot, TVIS_SELECTED);
1112 /* try to cancel with wrong edit handle */
1113 r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), 0);
1115 ok(IsWindow(edit), "Expected edit control to be valid\n");
1116 r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
1118 ok(!IsWindow(edit), "Expected edit control to be destroyed\n");
1119 /* try to cancel without creating edit */
1120 r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), 0);
1123 /* try to cancel with wrong (not null) handle */
1124 edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
1125 ok(IsWindow(edit), "Expected valid handle\n");
1126 r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hTree);
1128 ok(IsWindow(edit), "Expected edit control to be valid\n");
1129 r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
1132 /* remove selection after starting edit */
1133 r = TreeView_SelectItem(hTree, hRoot);
1135 edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
1136 ok(IsWindow(edit), "Expected valid handle\n");
1137 r = TreeView_SelectItem(hTree, NULL);
1140 strncpy(buff, "x", sizeof(buff)/sizeof(CHAR));
1141 r = SendMessage(edit, WM_SETTEXT, 0, (LPARAM)buff);
1143 r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
1145 ok(!IsWindow(edit), "Expected edit control to be destroyed\n");
1146 /* check that text is saved */
1147 item.mask = TVIF_TEXT;
1149 item.pszText = buff;
1150 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
1151 r = SendMessage(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1153 ok(!strcmp("x", buff), "Expected item text to change\n");
1155 DestroyWindow(hTree);
1158 static void test_treeview_classinfo(void)
1162 memset(&cls, 0, sizeof(cls));
1163 GetClassInfo(GetModuleHandleA("comctl32.dll"), WC_TREEVIEWA, &cls);
1164 ok(cls.hbrBackground == NULL, "Expected NULL background brush, got %p\n", cls.hbrBackground);
1165 ok(cls.style == (CS_GLOBALCLASS | CS_DBLCLKS), "Expected got %x\n", cls.style);
1166 expect(0, cls.cbClsExtra);
1169 static void test_get_linecolor(void)
1174 hTree = create_treeview_control();
1176 /* newly created control has default color */
1177 clr = (COLORREF)SendMessage(hTree, TVM_GETLINECOLOR, 0, 0);
1179 win_skip("TVM_GETLINECOLOR is not supported on comctl32 < 5.80\n");
1181 expect(CLR_DEFAULT, clr);
1183 DestroyWindow(hTree);
1186 static void test_get_insertmarkcolor(void)
1191 hTree = create_treeview_control();
1193 /* newly created control has default color */
1194 clr = (COLORREF)SendMessage(hTree, TVM_GETINSERTMARKCOLOR, 0, 0);
1196 win_skip("TVM_GETINSERTMARKCOLOR is not supported on comctl32 < 5.80\n");
1198 expect(CLR_DEFAULT, clr);
1200 DestroyWindow(hTree);
1203 static void test_expandnotify(void)
1209 hTree = create_treeview_control();
1213 item.mask = TVIF_STATE;
1215 item.state = TVIS_EXPANDED;
1216 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1217 ok(ret == TRUE, "got %d\n", ret);
1218 ok((item.state & TVIS_EXPANDED) == 0, "expected collapsed\n");
1220 /* preselect root node here */
1221 ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);
1222 ok(ret == TRUE, "got %d\n", ret);
1224 g_get_from_expand = TRUE;
1226 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1227 g_item_expanding.state = 0xdeadbeef;
1228 g_item_expanded.state = 0xdeadbeef;
1229 ret = SendMessageA(hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)hRoot);
1230 ok(ret == TRUE, "got %d\n", ret);
1231 ok(g_item_expanding.state == TVIS_SELECTED, "got state on TVN_ITEMEXPANDING 0x%08x\n",
1232 g_item_expanding.state);
1233 ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1234 g_item_expanded.state);
1235 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_seq, "expand notifications", FALSE);
1236 g_get_from_expand = FALSE;
1238 /* check that it's expanded */
1239 item.state = TVIS_EXPANDED;
1240 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1241 ok(ret == TRUE, "got %d\n", ret);
1242 ok((item.state & TVIS_EXPANDED) == TVIS_EXPANDED, "expected expanded\n");
1245 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1246 ret = SendMessageA(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot);
1247 ok(ret == TRUE, "got %d\n", ret);
1248 item.state = TVIS_EXPANDED;
1249 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1250 ok(ret == TRUE, "got %d\n", ret);
1251 ok((item.state & TVIS_EXPANDED) == 0, "expected collapsed\n");
1252 /* all next collapse/expand attempts won't produce any notifications,
1253 the only way is to reset with all children removed */
1254 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "collapse after expand notifications", FALSE);
1256 DestroyWindow(hTree);
1258 /* test TVM_GETITEMRECT inside TVN_ITEMEXPANDED notification */
1259 hTree = create_treeview_control();
1261 g_get_rect_in_expand = TRUE;
1262 ret = TreeView_Select(hTree, hChild, TVGN_CARET);
1263 g_get_rect_in_expand = FALSE;
1264 ok(ret, "got %d\n", ret);
1265 DestroyWindow(hTree);
1268 static void test_expandedimage(void)
1274 hTree = create_treeview_control();
1277 item.mask = TVIF_EXPANDEDIMAGE;
1278 item.iExpandedImage = 1;
1280 ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item);
1281 ok(ret, "got %d\n", ret);
1283 item.mask = TVIF_EXPANDEDIMAGE;
1284 item.iExpandedImage = -1;
1286 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1287 ok(ret, "got %d\n", ret);
1289 if (item.iExpandedImage != 1)
1291 win_skip("TVIF_EXPANDEDIMAGE not supported\n");
1292 DestroyWindow(hTree);
1296 /* test for default iExpandedImage value */
1297 item.mask = TVIF_EXPANDEDIMAGE;
1298 item.iExpandedImage = -1;
1299 item.hItem = hChild;
1300 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1301 ok(ret, "got %d\n", ret);
1302 ok(item.iExpandedImage == (WORD)I_IMAGENONE, "got %d\n", item.iExpandedImage);
1304 DestroyWindow(hTree);
1307 static void test_TVS_SINGLEEXPAND(void)
1312 hTree = create_treeview_control();
1313 SetWindowLongA(hTree, GWL_STYLE, GetWindowLong(hTree, GWL_STYLE) | TVS_SINGLEEXPAND);
1314 /* to avoid paiting related notifications */
1315 ShowWindow(hTree, SW_HIDE);
1318 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1319 ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);
1320 ok(ret, "got %d\n", ret);
1321 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_singleexpand_seq, "singleexpand notifications", FALSE);
1323 /* a workaround for NT4 that sends expanding notification when nothing is about to expand */
1324 ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hRoot);
1325 ok(ret, "got %d\n", ret);
1327 ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0);
1328 ok(ret, "got %d\n", ret);
1330 DestroyWindow(hTree);
1333 static void test_WM_PAINT(void)
1341 hTree = create_treeview_control();
1343 clr = SendMessageA(hTree, TVM_SETBKCOLOR, 0, RGB(255, 0, 0));
1344 ok(clr == -1, "got %d, expected -1\n", clr);
1346 hdc = GetDC(hMainWnd);
1348 GetClientRect(hMainWnd, &rc);
1349 FillRect(hdc, &rc, GetStockObject(BLACK_BRUSH));
1351 clr = GetPixel(hdc, 1, 1);
1352 ok(clr == RGB(0, 0, 0), "got 0x%x\n", clr);
1354 ret = SendMessageA(hTree, WM_PAINT, (WPARAM)hdc, 0);
1355 ok(ret == 0, "got %d\n", ret);
1357 clr = GetPixel(hdc, 1, 1);
1358 ok(clr == RGB(255, 0, 0) || broken(clr == RGB(0, 0, 0)) /* win98 */,
1361 ReleaseDC(hMainWnd, hdc);
1363 DestroyWindow(hTree);
1366 static void test_delete_items(void)
1368 const struct message *msg;
1372 hTree = create_treeview_control();
1375 /* check delete order */
1376 flush_sequences(item_sequence, 1);
1377 ret = SendMessage(hTree, TVM_DELETEITEM, 0, 0);
1378 ok(ret == TRUE, "got %d\n", ret);
1380 msg = item_sequence[0]->sequence;
1381 ok(item_sequence[0]->count == 2, "expected 2 items, got %d\n", item_sequence[0]->count);
1383 if (item_sequence[0]->count == 2)
1385 ok(msg[0].lParam == (LPARAM)hChild, "expected %p, got 0x%lx\n", hChild, msg[0].lParam);
1386 ok(msg[1].lParam == (LPARAM)hRoot, "expected %p, got 0x%lx\n", hRoot, msg[1].lParam);
1389 ret = SendMessageA(hTree, TVM_GETCOUNT, 0, 0);
1390 ok(ret == 0, "got %d\n", ret);
1392 DestroyWindow(hTree);
1397 HTREEITEM parent; /* for root value of parent field is unidetified */
1398 HTREEITEM nextsibling;
1399 HTREEITEM firstchild;
1402 static void _check_item(HTREEITEM item, HTREEITEM parent, HTREEITEM nextsibling, HTREEITEM firstchild, int line)
1404 struct _ITEM_DATA *data = (struct _ITEM_DATA*)item;
1406 ok_(__FILE__, line)(data->parent == parent, "parent %p, got %p\n", parent, data->parent);
1407 ok_(__FILE__, line)(data->nextsibling == nextsibling, "sibling %p, got %p\n", nextsibling, data->nextsibling);
1408 ok_(__FILE__, line)(data->firstchild == firstchild, "firstchild %p, got %p\n", firstchild, data->firstchild);
1411 #define check_item(a, b, c, d) _check_item(a, b, c, d, __LINE__)
1413 static void test_htreeitem_layout(void)
1415 TVINSERTSTRUCTA ins;
1416 HTREEITEM item1, item2;
1419 hTree = create_treeview_control();
1422 /* root has some special pointer in parent field */
1423 check_item(hRoot, ((struct _ITEM_DATA*)hRoot)->parent, 0, hChild);
1424 check_item(hChild, hRoot, 0, 0);
1426 ins.hParent = hChild;
1427 ins.hInsertAfter = TVI_FIRST;
1429 item1 = TreeView_InsertItem(hTree, &ins);
1431 check_item(item1, hChild, 0, 0);
1433 ins.hParent = hRoot;
1434 ins.hInsertAfter = TVI_FIRST;
1436 item2 = TreeView_InsertItem(hTree, &ins);
1438 check_item(item2, hRoot, hChild, 0);
1440 SendMessage(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild);
1442 /* without children now */
1443 check_item(hRoot, ((struct _ITEM_DATA*)hRoot)->parent, 0, item2);
1445 DestroyWindow(hTree);
1448 START_TEST(treeview)
1451 BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
1455 ULONG_PTR ctx_cookie;
1459 hComctl32 = GetModuleHandleA("comctl32.dll");
1460 pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
1461 if (pInitCommonControlsEx)
1463 INITCOMMONCONTROLSEX iccex;
1464 iccex.dwSize = sizeof(iccex);
1465 iccex.dwICC = ICC_TREEVIEW_CLASSES;
1466 pInitCommonControlsEx(&iccex);
1469 InitCommonControls();
1471 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1472 init_msg_sequences(item_sequence, 1);
1474 wc.style = CS_HREDRAW | CS_VREDRAW;
1477 wc.hInstance = GetModuleHandleA(NULL);
1479 wc.hCursor = LoadCursorA(NULL, IDC_IBEAM);
1480 wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
1481 wc.lpszMenuName = NULL;
1482 wc.lpszClassName = "MyTestWnd";
1483 wc.lpfnWndProc = parent_wnd_proc;
1484 RegisterClassA(&wc);
1486 hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW,
1487 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105, NULL, NULL, GetModuleHandleA(NULL), 0);
1489 ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n");
1490 if (!hMainWnd) return;
1496 test_get_set_bkcolor();
1497 test_get_set_imagelist();
1498 test_get_set_indent();
1499 test_get_set_insertmark();
1500 test_get_set_item();
1501 test_get_set_itemheight();
1502 test_get_set_scrolltime();
1503 test_get_set_textcolor();
1504 test_get_linecolor();
1505 test_get_insertmarkcolor();
1506 test_get_set_tooltips();
1507 test_get_set_unicodeformat();
1509 test_expandinvisible();
1511 test_treeview_classinfo();
1512 test_expandnotify();
1513 test_TVS_SINGLEEXPAND();
1515 test_delete_items();
1516 test_htreeitem_layout();
1518 if (!load_v6_module(&ctx_cookie, &hCtx))
1520 DestroyWindow(hMainWnd);
1524 /* this is a XP SP3 failure workaround */
1525 hwnd = CreateWindowExA(0, WC_TREEVIEW, "foo",
1526 WS_CHILD | WS_BORDER | WS_VISIBLE,
1528 hMainWnd, NULL, GetModuleHandleA(NULL), NULL);
1529 if (!IsWindow(hwnd))
1531 win_skip("FIXME: failed to create TreeView window.\n");
1532 unload_v6_module(ctx_cookie, hCtx);
1533 DestroyWindow(hMainWnd);
1537 DestroyWindow(hwnd);
1539 /* comctl32 version 6 tests start here */
1540 test_expandedimage();
1541 test_htreeitem_layout();
1543 unload_v6_module(ctx_cookie, hCtx);
1545 PostMessageA(hMainWnd, WM_CLOSE, 0, 0);
1546 while(GetMessageA(&msg, 0, 0, 0))
1548 TranslateMessage(&msg);
1549 DispatchMessageA(&msg);