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"
35 const char *TEST_CALLBACK_TEXT = "callback_text";
37 #define NUM_MSG_SEQUENCES 1
38 #define TREEVIEW_SEQ_INDEX 0
40 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
42 static struct msg_sequence *MsgSequences[NUM_MSG_SEQUENCES];
44 static const struct message FillRootSeq[] = {
45 { TVM_INSERTITEM, sent },
46 { TVM_INSERTITEM, sent },
50 static const struct message rootnone_select_seq[] = {
51 { TVM_SELECTITEM, sent|wparam, 9 },
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 },
60 static const struct message rootchild_select_seq[] = {
61 { TVM_SELECTITEM, sent|wparam, 9 },
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 },
70 static const struct message getitemtext_seq[] = {
71 { TVM_INSERTITEM, sent },
72 { TVM_GETITEM, sent },
73 { TVM_DELETEITEM, sent },
77 static const struct message focus_seq[] = {
78 { TVM_INSERTITEM, sent },
79 { TVM_INSERTITEM, sent },
80 { TVM_SELECTITEM, sent|wparam, 9 },
81 /* The following end up out of order in wine */
82 { WM_WINDOWPOSCHANGING, sent|defwinproc },
83 { WM_NCCALCSIZE, sent|wparam|defwinproc, TRUE },
84 { WM_WINDOWPOSCHANGED, sent|defwinproc },
85 { WM_SIZE, sent|defwinproc },
86 { WM_PAINT, sent|defwinproc },
87 { WM_NCPAINT, sent|wparam|defwinproc, 1 },
88 { WM_ERASEBKGND, sent|defwinproc },
89 { TVM_EDITLABEL, sent },
90 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_UPDATE) },
91 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_CHANGE) },
92 { WM_PARENTNOTIFY, sent|wparam|defwinproc, MAKEWPARAM(WM_CREATE, 0) },
93 { WM_KILLFOCUS, sent|defwinproc },
94 { WM_PAINT, sent|defwinproc },
95 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
96 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_SETFOCUS) },
97 { WM_CTLCOLOREDIT, sent|defwinproc|optional },
98 { WM_CTLCOLOREDIT, sent|defwinproc|optional },
102 static const struct message TestGetSetBkColorSeq[] = {
103 { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
104 { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0 },
105 { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
106 { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0x00ffffff },
107 { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
108 { TVM_SETBKCOLOR, sent|wparam|lparam, 0, -1 },
112 static const struct message TestGetSetImageListSeq[] = {
113 { TVM_SETIMAGELIST, sent|wparam|lparam, 0, 0 },
114 { TVM_GETIMAGELIST, sent|wparam|lparam, 0, 0 },
118 static const struct message TestGetSetIndentSeq[] = {
119 { TVM_SETINDENT, sent|wparam|lparam, 0, 0 },
120 { TVM_GETINDENT, sent|wparam|lparam, 0, 0 },
121 /* The actual amount to indent is dependent on the system for this message */
122 { TVM_SETINDENT, sent },
123 { TVM_GETINDENT, sent|wparam|lparam, 0, 0 },
127 static const struct message TestGetSetInsertMarkColorSeq[] = {
128 { TVM_SETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 },
129 { TVM_GETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 },
133 static const struct message TestGetSetItemSeq[] = {
134 { TVM_GETITEM, sent },
135 { TVM_SETITEM, sent },
136 { TVM_GETITEM, sent },
137 { TVM_SETITEM, sent },
141 static const struct message TestGetSetItemHeightSeq[] = {
142 { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
143 { TVM_SETITEMHEIGHT, sent|wparam|lparam, -1, 0 },
144 { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
145 { TVM_SETITEMHEIGHT, sent|lparam, 0xcccccccc, 0 },
146 { TVM_GETITEMHEIGHT, sent|wparam|lparam|optional, 0, 0 },
147 { TVM_SETITEMHEIGHT, sent|wparam|lparam|optional, 9, 0 },
148 { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
152 static const struct message TestGetSetScrollTimeSeq[] = {
153 { TVM_SETSCROLLTIME, sent|wparam|lparam, 20, 0 },
154 { TVM_GETSCROLLTIME, sent|wparam|lparam, 0, 0 },
158 static const struct message TestGetSetTextColorSeq[] = {
159 { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
160 { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
161 { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
162 { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, 0x00ffffff },
163 { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
164 { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, -1 },
168 static const struct message TestGetSetToolTipsSeq[] = {
169 { WM_KILLFOCUS, sent },
170 { TVM_SETTOOLTIPS, sent|wparam|lparam, 0, 0 },
171 { TVM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 },
175 static const struct message TestGetSetUnicodeFormatSeq[] = {
176 { TVM_SETUNICODEFORMAT, sent|wparam|lparam, TRUE, 0 },
177 { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
178 { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
179 { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
180 { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
184 static HWND hMainWnd;
186 static HWND hTree, hEdit;
187 static HTREEITEM hRoot, hChild;
190 static char sequence[256];
192 static void Clear(void)
198 static void AddItem(char ch)
200 sequence[pos++] = ch;
201 sequence[pos] = '\0';
204 static void IdentifyItem(HTREEITEM hItem)
206 if (hItem == hRoot) {
210 if (hItem == hChild) {
221 /* This function hooks in and records all messages to the treeview control */
222 static LRESULT WINAPI TreeviewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
224 static LONG defwndproc_counter = 0;
227 WNDPROC lpOldProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
229 msg.message = message;
230 msg.flags = sent|wparam|lparam;
231 if (defwndproc_counter) msg.flags |= defwinproc;
234 add_message(MsgSequences, TREEVIEW_SEQ_INDEX, &msg);
236 defwndproc_counter++;
237 ret = CallWindowProcA(lpOldProc, hwnd, message, wParam, lParam);
238 defwndproc_counter--;
243 static HWND create_treeview_control(void)
248 hTree = CreateWindowExA(WS_EX_CLIENTEDGE, WC_TREEVIEWA, NULL, WS_CHILD|WS_VISIBLE|
249 TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS|TVS_EDITLABELS,
250 0, 0, 120, 100, hMainWnd, (HMENU)100, GetModuleHandleA(0), 0);
254 /* Record the old WNDPROC so we can call it after recording the messages */
255 pOldWndProc = (WNDPROC)SetWindowLongPtrA(hTree, GWLP_WNDPROC, (LONG_PTR)TreeviewWndProc);
256 SetWindowLongPtrA(hTree, GWLP_USERDATA, (LONG_PTR)pOldWndProc);
261 static void fill_tree(HWND hTree)
264 static CHAR root[] = "Root",
267 ins.hParent = TVI_ROOT;
268 ins.hInsertAfter = TVI_ROOT;
269 U(ins).item.mask = TVIF_TEXT;
270 U(ins).item.pszText = root;
271 hRoot = TreeView_InsertItem(hTree, &ins);
274 ins.hInsertAfter = TVI_FIRST;
275 U(ins).item.mask = TVIF_TEXT;
276 U(ins).item.pszText = child;
277 hChild = TreeView_InsertItem(hTree, &ins);
280 static void test_fillroot(void)
284 hTree = create_treeview_control();
286 flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
296 ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, FillRootSeq, "FillRoot", FALSE);
297 ok(!strcmp(sequence, "AB."), "Item creation\n");
299 /* UMLPad 1.15 depends on this being not -1 (I_IMAGECALLBACK) */
301 tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
302 SendMessage( hTree, TVM_GETITEM, 0, (LPARAM)&tvi );
303 ok(tvi.iImage == 0, "tvi.iImage=%d\n", tvi.iImage);
304 ok(tvi.iSelectedImage == 0, "tvi.iSelectedImage=%d\n", tvi.iSelectedImage);
306 DestroyWindow(hTree);
309 static void test_callback(void)
312 HTREEITEM hItem1, hItem2;
315 CHAR test_string[] = "Test_string";
319 hTree = create_treeview_control();
322 ret = TreeView_DeleteAllItems(hTree);
323 ok(ret == TRUE, "ret\n");
324 ins.hParent = TVI_ROOT;
325 ins.hInsertAfter = TVI_ROOT;
326 U(ins).item.mask = TVIF_TEXT;
327 U(ins).item.pszText = LPSTR_TEXTCALLBACK;
328 hRoot = TreeView_InsertItem(hTree, &ins);
332 tvi.mask = TVIF_TEXT;
334 tvi.cchTextMax = sizeof(buf)/sizeof(buf[0]);
335 ret = TreeView_GetItem(hTree, &tvi);
336 ok(ret == 1, "ret\n");
337 ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Callback item text mismatch %s vs %s\n",
338 tvi.pszText, TEST_CALLBACK_TEXT);
341 ins.hInsertAfter = TVI_FIRST;
342 U(ins).item.mask = TVIF_TEXT;
343 U(ins).item.pszText = test_string;
344 hItem1 = TreeView_InsertItem(hTree, &ins);
348 ret = TreeView_GetItem(hTree, &tvi);
349 ok(ret == TRUE, "ret\n");
350 ok(strcmp(tvi.pszText, test_string) == 0, "Item text mismatch %s vs %s\n",
351 tvi.pszText, test_string);
353 /* undocumented: pszText of NULL also means LPSTR_CALLBACK: */
355 ret = TreeView_SetItem(hTree, &tvi);
356 ok(ret == 1, "Expected SetItem return 1, got %ld\n", ret);
358 ret = TreeView_GetItem(hTree, &tvi);
359 ok(ret == TRUE, "Expected GetItem return TRUE, got %ld\n", ret);
360 ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
361 tvi.pszText, TEST_CALLBACK_TEXT);
363 U(ins).item.pszText = NULL;
364 hItem2 = TreeView_InsertItem(hTree, &ins);
367 memset(buf, 0, sizeof(buf));
368 ret = TreeView_GetItem(hTree, &tvi);
369 ok(ret == TRUE, "Expected GetItem return TRUE, got %ld\n", ret);
370 ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
371 tvi.pszText, TEST_CALLBACK_TEXT);
373 DestroyWindow(hTree);
376 static void test_select(void)
380 hTree = create_treeview_control();
383 /* root-none select tests */
384 flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
385 r = TreeView_SelectItem(hTree, NULL);
388 r = TreeView_SelectItem(hTree, hRoot);
390 r = TreeView_SelectItem(hTree, hRoot);
392 r = TreeView_SelectItem(hTree, NULL);
394 r = TreeView_SelectItem(hTree, NULL);
396 r = TreeView_SelectItem(hTree, hRoot);
398 ok(!strcmp(sequence, "1(nR)nR23(Rn)Rn45(nR)nR."), "root-none select test\n");
399 ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, rootnone_select_seq,
400 "root-none select seq", FALSE);
402 /* root-child select tests */
403 flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
404 r = TreeView_SelectItem(hTree, NULL);
407 r = TreeView_SelectItem(hTree, hRoot);
409 r = TreeView_SelectItem(hTree, hRoot);
411 r = TreeView_SelectItem(hTree, hChild);
413 r = TreeView_SelectItem(hTree, hChild);
415 r = TreeView_SelectItem(hTree, hRoot);
417 ok(!strcmp(sequence, "1(nR)nR23(RC)RC45(CR)CR."), "root-child select test\n");
418 ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, rootchild_select_seq,
419 "root-child select seq", FALSE);
421 DestroyWindow(hTree);
424 static void test_getitemtext(void)
430 CHAR szBuffer[80] = "Blah";
431 int nBufferSize = sizeof(szBuffer)/sizeof(CHAR);
433 hTree = create_treeview_control();
436 flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
438 /* add an item without TVIF_TEXT mask and pszText == NULL */
440 ins.hInsertAfter = TVI_ROOT;
441 U(ins).item.mask = 0;
442 U(ins).item.pszText = NULL;
443 U(ins).item.cchTextMax = 0;
444 hChild = TreeView_InsertItem(hTree, &ins);
447 /* retrieve it with TVIF_TEXT mask */
449 tvi.mask = TVIF_TEXT;
450 tvi.cchTextMax = nBufferSize;
451 tvi.pszText = szBuffer;
453 SendMessageA( hTree, TVM_GETITEM, 0, (LPARAM)&tvi );
454 ok(!strcmp(szBuffer, ""), "szBuffer=\"%s\", expected \"\"\n", szBuffer);
455 ok(SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild), "DeleteItem failed\n");
456 ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, getitemtext_seq, "get item text seq", FALSE);
458 DestroyWindow(hTree);
461 static void test_focus(void)
464 static CHAR child1[] = "Edit",
465 child2[] = "A really long string";
466 HTREEITEM hChild1, hChild2;
468 hTree = create_treeview_control();
471 flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
473 /* This test verifies that when a label is being edited, scrolling
474 * the treeview does not cause the label to lose focus. To test
475 * this, first some additional entries are added to generate
479 ins.hInsertAfter = hChild;
480 U(ins).item.mask = TVIF_TEXT;
481 U(ins).item.pszText = child1;
482 hChild1 = TreeView_InsertItem(hTree, &ins);
484 ins.hInsertAfter = hChild1;
485 U(ins).item.mask = TVIF_TEXT;
486 U(ins).item.pszText = child2;
487 hChild2 = TreeView_InsertItem(hTree, &ins);
490 ShowWindow(hMainWnd,SW_SHOW);
491 SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild);
492 hEdit = TreeView_EditLabel(hTree, hChild);
493 ScrollWindowEx(hTree, -10, 0, NULL, NULL, NULL, NULL, SW_SCROLLCHILDREN);
494 ok(GetFocus() == hEdit, "Edit control should have focus\n");
495 ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, focus_seq, "focus test", TRUE);
497 DestroyWindow(hTree);
500 static void TestGetSetBkColor(void)
502 COLORREF crColor = RGB(0,0,0);
504 /* If the value is -1, the control is using the system color for the background color. */
505 crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 );
506 ok(crColor == -1, "Default background color reported as 0x%.8x\n", crColor);
508 /* Test for black background */
509 SendMessage( hTree, TVM_SETBKCOLOR, 0, (LPARAM)RGB(0,0,0) );
510 crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 );
511 ok(crColor == RGB(0,0,0), "Black background color reported as 0x%.8x\n", crColor);
513 /* Test for white background */
514 SendMessage( hTree, TVM_SETBKCOLOR, 0, (LPARAM)RGB(255,255,255) );
515 crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 );
516 ok(crColor == RGB(255,255,255), "White background color reported as 0x%.8x\n", crColor);
518 /* Reset the default background */
519 SendMessage( hTree, TVM_SETBKCOLOR, 0, -1 );
522 static void TestGetSetImageList(void)
524 HIMAGELIST hImageList = NULL;
526 /* Test a NULL HIMAGELIST */
527 SendMessage( hTree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)hImageList );
528 hImageList = (HIMAGELIST)SendMessage( hTree, TVM_GETIMAGELIST, TVSIL_NORMAL, 0 );
529 ok(hImageList == NULL, "NULL image list, reported as 0x%p, expected 0.\n", hImageList);
531 /* TODO: Test an actual image list */
534 static void TestGetSetIndent(void)
537 int ulMinIndent = -1;
538 int ulMoreThanTwiceMin = -1;
540 /* Finding the minimum indent */
541 SendMessage( hTree, TVM_SETINDENT, 0, 0 );
542 ulMinIndent = (int)SendMessage( hTree, TVM_GETINDENT, 0, 0 );
544 /* Checking an indent that is more than twice the default indent */
545 ulMoreThanTwiceMin = 2*ulMinIndent+1;
546 SendMessage( hTree, TVM_SETINDENT, ulMoreThanTwiceMin, 0 );
547 ulIndent = (DWORD)SendMessage( hTree, TVM_GETINDENT, 0, 0 );
548 ok(ulIndent == ulMoreThanTwiceMin, "Indent reported as %d, expected %d\n", ulIndent, ulMoreThanTwiceMin);
551 static void TestGetSetInsertMarkColor(void)
553 COLORREF crColor = RGB(0,0,0);
554 SendMessage( hTree, TVM_SETINSERTMARKCOLOR, 0, crColor );
555 crColor = (COLORREF)SendMessage( hTree, TVM_GETINSERTMARKCOLOR, 0, 0 );
556 ok(crColor == RGB(0,0,0), "Insert mark color reported as 0x%.8x, expected 0x00000000\n", crColor);
559 static void TestGetSetItem(void)
561 TVITEM tviRoot = {0};
562 int nBufferSize = 80;
563 char szBuffer[80] = {0};
565 /* Test the root item */
566 tviRoot.hItem = hRoot;
567 tviRoot.mask = TVIF_TEXT;
568 tviRoot.cchTextMax = nBufferSize;
569 tviRoot.pszText = szBuffer;
570 SendMessage( hTree, TVM_GETITEM, 0, (LPARAM)&tviRoot );
571 ok(!strcmp("Root", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Root\"\n", szBuffer);
573 /* Change the root text */
574 strncpy(szBuffer, "Testing123", nBufferSize);
575 SendMessage( hTree, TVM_SETITEM, 0, (LPARAM)&tviRoot );
576 memset(szBuffer, 0, nBufferSize);
577 SendMessage( hTree, TVM_GETITEM, 0, (LPARAM)&tviRoot );
578 ok(!strcmp("Testing123", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Testing123\"\n", szBuffer);
580 /* Reset the root text */
581 memset(szBuffer, 0, nBufferSize);
582 strncpy(szBuffer, "Root", nBufferSize);
583 SendMessage( hTree, TVM_SETITEM, 0, (LPARAM)&tviRoot );
586 static void TestGetSetItemHeight(void)
591 /* Assuming default height to begin with */
592 ulOldHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
594 /* Explicitly setting and getting the default height */
595 SendMessage( hTree, TVM_SETITEMHEIGHT, -1, 0 );
596 ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
597 ok(ulNewHeight == ulOldHeight, "Default height not set properly, reported %d, expected %d\n", ulNewHeight, ulOldHeight);
599 /* Explicitly setting and getting the height of twice the normal */
600 SendMessage( hTree, TVM_SETITEMHEIGHT, 2*ulOldHeight, 0 );
601 ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
602 ok(ulNewHeight == 2*ulOldHeight, "New height not set properly, reported %d, expected %d\n", ulNewHeight, 2*ulOldHeight);
604 /* Assuming tree doesn't have TVS_NONEVENHEIGHT set, so a set of 9 will round down to 8 */
605 SendMessage( hTree, TVM_SETITEMHEIGHT, 9, 0 );
606 ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
607 ok(ulNewHeight == 8, "Uneven height not set properly, reported %d, expected %d\n", ulNewHeight, 8);
610 static void TestGetSetScrollTime(void)
612 int ulExpectedTime = 20;
614 SendMessage( hTree, TVM_SETSCROLLTIME, ulExpectedTime, 0 );
615 ulTime = (int)SendMessage( hTree, TVM_GETSCROLLTIME, 0, 0 );
616 ok(ulTime == ulExpectedTime, "Scroll time reported as %d, expected %d\n", ulTime, ulExpectedTime);
619 static void TestGetSetTextColor(void)
621 /* If the value is -1, the control is using the system color for the text color. */
622 COLORREF crColor = RGB(0,0,0);
623 crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 );
624 ok(crColor == -1, "Default text color reported as 0x%.8x\n", crColor);
626 /* Test for black text */
627 SendMessage( hTree, TVM_SETTEXTCOLOR, 0, (LPARAM)RGB(0,0,0) );
628 crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 );
629 ok(crColor == RGB(0,0,0), "Black text color reported as 0x%.8x\n", crColor);
631 /* Test for white text */
632 SendMessage( hTree, TVM_SETTEXTCOLOR, 0, (LPARAM)RGB(255,255,255) );
633 crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 );
634 ok(crColor == RGB(255,255,255), "White text color reported as 0x%.8x\n", crColor);
636 /* Reset the default text color */
637 SendMessage( hTree, TVM_SETTEXTCOLOR, 0, -1 );
640 static void TestGetSetToolTips(void)
642 HWND hwndLastToolTip = NULL;
645 /* show even WS_POPUP treeview don't send NM_TOOLTIPSCREATED */
646 hPopupTreeView = CreateWindow(WC_TREEVIEW, NULL, WS_POPUP|WS_VISIBLE, 0, 0, 100, 100, hMainWnd, NULL, NULL, NULL);
647 DestroyWindow(hPopupTreeView);
649 /* Testing setting a NULL ToolTip */
650 SendMessage( hTree, TVM_SETTOOLTIPS, 0, 0 );
651 hwndLastToolTip = (HWND)SendMessage( hTree, TVM_GETTOOLTIPS, 0, 0 );
652 ok(hwndLastToolTip == NULL, "NULL tool tip, reported as 0x%p, expected 0.\n", hwndLastToolTip);
654 /* TODO: Add a test of an actual tooltip */
657 static void TestGetSetUnicodeFormat(void)
659 BOOL bPreviousSetting = 0;
660 BOOL bNewSetting = 0;
663 bPreviousSetting = (BOOL)SendMessage( hTree, TVM_SETUNICODEFORMAT, 1, 0 );
664 bNewSetting = (BOOL)SendMessage( hTree, TVM_GETUNICODEFORMAT, 0, 0 );
665 ok(bNewSetting == 1, "Unicode setting did not work.\n");
668 SendMessage( hTree, TVM_SETUNICODEFORMAT, 0, 0 );
669 bNewSetting = (BOOL)SendMessage( hTree, TVM_GETUNICODEFORMAT, 0, 0 );
670 ok(bNewSetting == 0, "ANSI setting did not work.\n");
672 /* Revert to original setting */
673 SendMessage( hTree, TVM_SETUNICODEFORMAT, (LPARAM)bPreviousSetting, 0 );
676 static void test_getset(void)
678 hTree = create_treeview_control();
681 /* TVM_GETBKCOLOR and TVM_SETBKCOLOR */
682 flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
684 ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetBkColorSeq,
685 "TestGetSetBkColor", FALSE);
687 /* TVM_GETIMAGELIST and TVM_SETIMAGELIST */
688 flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
689 TestGetSetImageList();
690 ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetImageListSeq,
691 "TestGetImageList", FALSE);
693 /* TVM_SETINDENT and TVM_GETINDENT */
694 flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
696 ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetIndentSeq,
697 "TestGetSetIndent", FALSE);
699 /* TVM_GETINSERTMARKCOLOR and TVM_GETINSERTMARKCOLOR */
700 flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
701 TestGetSetInsertMarkColor();
702 ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetInsertMarkColorSeq,
703 "TestGetSetInsertMarkColor", FALSE);
705 /* TVM_GETITEM and TVM_SETITEM */
706 flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
708 ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetItemSeq,
709 "TestGetSetItem", FALSE);
711 /* TVM_GETITEMHEIGHT and TVM_SETITEMHEIGHT */
712 flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
713 TestGetSetItemHeight();
714 ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetItemHeightSeq,
715 "TestGetSetItemHeight", FALSE);
717 /* TVM_GETSCROLLTIME and TVM_SETSCROLLTIME */
718 flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
719 TestGetSetScrollTime();
720 ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetScrollTimeSeq,
721 "TestGetSetScrollTime", FALSE);
723 /* TVM_GETTEXTCOLOR and TVM_SETTEXTCOLOR */
724 flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
725 TestGetSetTextColor();
726 ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetTextColorSeq,
727 "TestGetSetTextColor", FALSE);
729 /* TVM_GETTOOLTIPS and TVM_SETTOOLTIPS */
730 flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
731 TestGetSetToolTips();
732 ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetToolTipsSeq,
733 "TestGetSetToolTips", TRUE);
735 /* TVM_GETUNICODEFORMAT and TVM_SETUNICODEFORMAT */
736 flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
737 TestGetSetUnicodeFormat();
738 ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetUnicodeFormatSeq,
739 "TestGetSetUnicodeFormat", FALSE);
741 DestroyWindow(hTree);
744 static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
749 NMHDR *pHdr = (NMHDR *)lParam;
751 ok(pHdr->code != NM_FIRST - 19, "Treeview should not send NM_TOOLTIPSCREATED\n");
752 if (pHdr->idFrom == 100) {
753 NMTREEVIEWA *pTreeView = (LPNMTREEVIEWA) lParam;
755 case TVN_SELCHANGINGA:
757 IdentifyItem(pTreeView->itemOld.hItem);
758 IdentifyItem(pTreeView->itemNew.hItem);
760 case TVN_SELCHANGEDA:
762 IdentifyItem(pTreeView->itemOld.hItem);
763 IdentifyItem(pTreeView->itemNew.hItem);
765 case TVN_GETDISPINFOA: {
766 NMTVDISPINFOA *disp = (NMTVDISPINFOA *)lParam;
767 if (disp->item.mask & TVIF_TEXT) {
768 lstrcpyn(disp->item.pszText, TEST_CALLBACK_TEXT, disp->item.cchTextMax);
772 case TVN_ENDLABELEDIT: return TRUE;
783 return DefWindowProcA(hWnd, msg, wParam, lParam);
788 static void test_expandinvisible(void)
790 static CHAR nodeText[][5] = {"0", "1", "2", "3", "4"};
797 hTree = create_treeview_control();
799 /* The test builds the following tree and expands then node 1, while node 0 is collapsed.
809 ret = TreeView_DeleteAllItems(hTree);
810 ok(ret == TRUE, "ret\n");
811 ins.hParent = TVI_ROOT;
812 ins.hInsertAfter = TVI_ROOT;
813 U(ins).item.mask = TVIF_TEXT;
814 U(ins).item.pszText = nodeText[0];
815 node[0] = TreeView_InsertItem(hTree, &ins);
818 ins.hInsertAfter = TVI_LAST;
819 U(ins).item.mask = TVIF_TEXT;
820 ins.hParent = node[0];
822 U(ins).item.pszText = nodeText[1];
823 node[1] = TreeView_InsertItem(hTree, &ins);
825 U(ins).item.pszText = nodeText[4];
826 node[4] = TreeView_InsertItem(hTree, &ins);
829 ins.hParent = node[1];
831 U(ins).item.pszText = nodeText[2];
832 node[2] = TreeView_InsertItem(hTree, &ins);
834 U(ins).item.pszText = nodeText[3];
835 node[3] = TreeView_InsertItem(hTree, &ins);
839 nodeVisible = TreeView_GetItemRect(hTree, node[1], &dummyRect, FALSE);
840 ok(!nodeVisible, "Node 1 should not be visible.\n");
841 nodeVisible = TreeView_GetItemRect(hTree, node[2], &dummyRect, FALSE);
842 ok(!nodeVisible, "Node 2 should not be visible.\n");
843 nodeVisible = TreeView_GetItemRect(hTree, node[3], &dummyRect, FALSE);
844 ok(!nodeVisible, "Node 3 should not be visible.\n");
845 nodeVisible = TreeView_GetItemRect(hTree, node[4], &dummyRect, FALSE);
846 ok(!nodeVisible, "Node 4 should not be visible.\n");
848 ok(TreeView_Expand(hTree, node[1], TVE_EXPAND), "Expand of node 1 failed.\n");
850 nodeVisible = TreeView_GetItemRect(hTree, node[1], &dummyRect, FALSE);
851 ok(!nodeVisible, "Node 1 should not be visible.\n");
852 nodeVisible = TreeView_GetItemRect(hTree, node[2], &dummyRect, FALSE);
853 ok(!nodeVisible, "Node 2 should not be visible.\n");
854 nodeVisible = TreeView_GetItemRect(hTree, node[3], &dummyRect, FALSE);
855 ok(!nodeVisible, "Node 3 should not be visible.\n");
856 nodeVisible = TreeView_GetItemRect(hTree, node[4], &dummyRect, FALSE);
857 ok(!nodeVisible, "Node 4 should not be visible.\n");
859 DestroyWindow(hTree);
862 static void test_itemedit(void)
869 hTree = create_treeview_control();
872 /* try with null item */
873 edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)NULL);
874 ok(!IsWindow(edit), "Expected valid handle\n");
877 edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
878 ok(IsWindow(edit), "Expected valid handle\n");
879 /* item shouldn't be selected automatically after TVM_EDITLABEL */
880 r = SendMessage(hTree, TVM_GETITEMSTATE, (WPARAM)hRoot, TVIS_SELECTED);
882 r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
884 ok(!IsWindow(edit), "Expected edit control to be destroyed\n");
886 /* remove selection after starting edit */
887 r = TreeView_SelectItem(hTree, hRoot);
889 edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
890 ok(IsWindow(edit), "Expected valid handle\n");
891 r = TreeView_SelectItem(hTree, NULL);
894 strncpy(buff, "x", sizeof(buff)/sizeof(CHAR));
895 r = SendMessage(edit, WM_SETTEXT, 0, (LPARAM)buff);
897 r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
899 ok(!IsWindow(edit), "Expected edit control to be destroyed\n");
900 /* check that text is saved */
901 item.mask = TVIF_TEXT;
904 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
905 r = SendMessage(hTree, TVM_GETITEM, 0, (LPARAM)&item);
907 ok(!strcmp("x", buff), "Expected item text to change\n");
909 DestroyWindow(hTree);
915 BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
919 hComctl32 = GetModuleHandleA("comctl32.dll");
920 pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
921 if (pInitCommonControlsEx)
923 INITCOMMONCONTROLSEX iccex;
924 iccex.dwSize = sizeof(iccex);
925 iccex.dwICC = ICC_TREEVIEW_CLASSES;
926 pInitCommonControlsEx(&iccex);
929 InitCommonControls();
931 init_msg_sequences(MsgSequences, NUM_MSG_SEQUENCES);
933 wc.style = CS_HREDRAW | CS_VREDRAW;
936 wc.hInstance = GetModuleHandleA(NULL);
938 wc.hCursor = LoadCursorA(NULL, IDC_IBEAM);
939 wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
940 wc.lpszMenuName = NULL;
941 wc.lpszClassName = "MyTestWnd";
942 wc.lpfnWndProc = MyWndProc;
946 hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW,
947 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105, NULL, NULL, GetModuleHandleA(NULL), 0);
949 if ( !ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n") )
958 test_expandinvisible();
961 PostMessageA(hMainWnd, WM_CLOSE, 0, 0);
962 while(GetMessageA(&msg,0,0,0)) {
963 TranslateMessage(&msg);
964 DispatchMessageA(&msg);