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 <stdarg.h> 22 #include <stdio.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 "wine/commctrl.h" 31 32 #include "wine/test.h" 33 #include "v6util.h" 34 #include "msg.h" 35 36 static BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); 37 static const char *TEST_CALLBACK_TEXT = "callback_text"; 38 39 static TVITEMA g_item_expanding, g_item_expanded; 40 static BOOL g_get_from_expand; 41 static BOOL g_get_rect_in_expand; 42 static BOOL g_disp_A_to_W; 43 static BOOL g_disp_set_stateimage; 44 static BOOL g_beginedit_alter_text; 45 static HFONT g_customdraw_font; 46 static BOOL g_v6; 47 48 #define NUM_MSG_SEQUENCES 3 49 #define TREEVIEW_SEQ_INDEX 0 50 #define PARENT_SEQ_INDEX 1 51 #define PARENT_CD_SEQ_INDEX 2 52 53 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got) 54 55 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; 56 static struct msg_sequence *item_sequence[1]; 57 58 static void flush_events(void) 59 { 60 MSG msg; 61 int diff = 200; 62 int min_timeout = 100; 63 DWORD time = GetTickCount() + diff; 64 65 while (diff > 0) 66 { 67 if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT) break; 68 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); 69 diff = time - GetTickCount(); 70 } 71 } 72 73 static const struct message FillRootSeq[] = { 74 { TVM_INSERTITEMA, sent }, 75 { TVM_INSERTITEMA, sent }, 76 { 0 } 77 }; 78 79 static const struct message rootnone_select_seq[] = { 80 { TVM_SELECTITEM, sent|wparam, 9 }, 81 { TVM_SELECTITEM, sent|wparam, 9 }, 82 { TVM_SELECTITEM, sent|wparam, 9 }, 83 { TVM_SELECTITEM, sent|wparam, 9 }, 84 { TVM_SELECTITEM, sent|wparam, 9 }, 85 { TVM_SELECTITEM, sent|wparam, 9 }, 86 { 0 } 87 }; 88 89 static const struct message rootchild_select_seq[] = { 90 { TVM_SELECTITEM, sent|wparam, 9 }, 91 { TVM_SELECTITEM, sent|wparam, 9 }, 92 { TVM_SELECTITEM, sent|wparam, 9 }, 93 { TVM_SELECTITEM, sent|wparam, 9 }, 94 { TVM_SELECTITEM, sent|wparam, 9 }, 95 { TVM_SELECTITEM, sent|wparam, 9 }, 96 { 0 } 97 }; 98 99 static const struct message getitemtext_seq[] = { 100 { TVM_INSERTITEMA, sent }, 101 { TVM_GETITEMA, sent }, 102 { TVM_DELETEITEM, sent }, 103 { 0 } 104 }; 105 106 static const struct message focus_seq[] = { 107 { TVM_INSERTITEMA, sent }, 108 { TVM_INSERTITEMA, sent }, 109 { TVM_SELECTITEM, sent|wparam, 9 }, 110 /* The following end up out of order in wine */ 111 { WM_WINDOWPOSCHANGING, sent|defwinproc }, 112 { WM_NCCALCSIZE, sent|wparam|defwinproc, TRUE }, 113 { WM_WINDOWPOSCHANGED, sent|defwinproc }, 114 { WM_SIZE, sent|defwinproc }, 115 { WM_WINDOWPOSCHANGING, sent|defwinproc|optional }, 116 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, TRUE }, 117 { WM_WINDOWPOSCHANGED, sent|defwinproc|optional }, 118 { WM_SIZE, sent|defwinproc|optional }, 119 { WM_PAINT, sent|defwinproc }, 120 { WM_NCPAINT, sent|wparam|defwinproc, 1 }, 121 { WM_ERASEBKGND, sent|defwinproc }, 122 { TVM_EDITLABELA, sent }, 123 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_UPDATE) }, 124 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_CHANGE) }, 125 { WM_PARENTNOTIFY, sent|wparam|defwinproc, MAKEWPARAM(WM_CREATE, 0) }, 126 { WM_KILLFOCUS, sent|defwinproc }, 127 { WM_PAINT, sent|defwinproc }, 128 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, 129 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_SETFOCUS) }, 130 { WM_ERASEBKGND, sent|defwinproc|optional }, 131 { WM_CTLCOLOREDIT, sent|defwinproc|optional }, 132 { WM_CTLCOLOREDIT, sent|defwinproc|optional }, 133 { 0 } 134 }; 135 136 static const struct message test_get_set_bkcolor_seq[] = { 137 { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 }, 138 { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0 }, 139 { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 }, 140 { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0x00ffffff }, 141 { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 }, 142 { TVM_SETBKCOLOR, sent|wparam|lparam, 0, -1 }, 143 { 0 } 144 }; 145 146 static const struct message test_get_set_imagelist_seq[] = { 147 { TVM_SETIMAGELIST, sent|wparam|lparam, 0, 0 }, 148 { TVM_GETIMAGELIST, sent|wparam|lparam, 0, 0 }, 149 { 0 } 150 }; 151 152 static const struct message test_get_set_indent_seq[] = { 153 { TVM_SETINDENT, sent|wparam|lparam, 0, 0 }, 154 { TVM_GETINDENT, sent|wparam|lparam, 0, 0 }, 155 /* The actual amount to indent is dependent on the system for this message */ 156 { TVM_SETINDENT, sent }, 157 { TVM_GETINDENT, sent|wparam|lparam, 0, 0 }, 158 { 0 } 159 }; 160 161 static const struct message test_get_set_insertmarkcolor_seq[] = { 162 { TVM_SETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 }, 163 { TVM_GETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 }, 164 { 0 } 165 }; 166 167 static const struct message test_get_set_item_seq[] = { 168 { TVM_GETITEMA, sent }, 169 { TVM_SETITEMA, sent }, 170 { TVM_GETITEMA, sent }, 171 { TVM_SETITEMA, sent }, 172 { 0 } 173 }; 174 175 static const struct message test_get_set_itemheight_seq[] = { 176 { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 }, 177 { TVM_SETITEMHEIGHT, sent|wparam|lparam, -1, 0 }, 178 { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 }, 179 { TVM_SETITEMHEIGHT, sent|lparam, 0xcccccccc, 0 }, 180 { TVM_GETITEMHEIGHT, sent|wparam|lparam|optional, 0, 0 }, 181 { TVM_SETITEMHEIGHT, sent|wparam|lparam|optional, 9, 0 }, 182 { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 }, 183 { 0 } 184 }; 185 186 static const struct message test_get_set_scrolltime_seq[] = { 187 { TVM_SETSCROLLTIME, sent|wparam|lparam, 20, 0 }, 188 { TVM_GETSCROLLTIME, sent|wparam|lparam, 0, 0 }, 189 { 0 } 190 }; 191 192 static const struct message test_get_set_textcolor_seq[] = { 193 { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 }, 194 { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, 0 }, 195 { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 }, 196 { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, RGB(255, 255, 255) }, 197 { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 }, 198 { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, CLR_NONE }, 199 { 0 } 200 }; 201 202 static const struct message test_get_set_tooltips_seq[] = { 203 { WM_KILLFOCUS, sent }, 204 { WM_IME_SETCONTEXT, sent|optional }, 205 { WM_IME_NOTIFY, sent|optional }, 206 { TVM_SETTOOLTIPS, sent|wparam|lparam, 0, 0 }, 207 { TVM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 }, 208 { 0 } 209 }; 210 211 static const struct message test_get_set_unicodeformat_seq[] = { 212 { TVM_SETUNICODEFORMAT, sent|wparam|lparam, TRUE, 0 }, 213 { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 }, 214 { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0 }, 215 { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 }, 216 { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0 }, 217 { 0 } 218 }; 219 220 static const struct message test_right_click_seq[] = { 221 { WM_RBUTTONDOWN, sent|wparam, MK_RBUTTON }, 222 { WM_CAPTURECHANGED, sent|defwinproc }, 223 { TVM_GETNEXTITEM, sent|wparam|lparam|defwinproc, TVGN_CARET, 0 }, 224 { WM_NCHITTEST, sent|optional }, 225 { WM_SETCURSOR, sent|optional }, 226 { WM_MOUSEMOVE, sent|optional }, 227 { 0 } 228 }; 229 230 static const struct message parent_expand_seq[] = { 231 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, 232 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, 233 { 0 } 234 }; 235 236 static const struct message parent_expand_kb_seq[] = { 237 { WM_NOTIFY, sent|id, 0, 0, TVN_KEYDOWN }, 238 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, 239 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, 240 { WM_CHANGEUISTATE, sent|optional }, 241 { 0 } 242 }; 243 244 static const struct message parent_collapse_2nd_kb_seq[] = { 245 { WM_NOTIFY, sent|id|optional, 0, 0, TVN_KEYDOWN }, 246 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, 247 { WM_CHANGEUISTATE, sent|optional }, 248 { 0 } 249 }; 250 251 static const struct message parent_expand_empty_kb_seq[] = { 252 { WM_NOTIFY, sent|id, 0, 0, TVN_KEYDOWN }, 253 { WM_CHANGEUISTATE, sent|optional }, 254 { 0 } 255 }; 256 257 static const struct message parent_singleexpand_seq0[] = { 258 /* alpha expands */ 259 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA }, 260 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA }, 261 { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND }, 262 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, 263 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, 264 { 0 } 265 }; 266 267 static const struct message parent_singleexpand_seq1[] = { 268 /* bravo expands */ 269 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA }, 270 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA }, 271 { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND }, 272 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, 273 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, 274 { 0 } 275 }; 276 277 static const struct message parent_singleexpand_seq2[] = { 278 /* delta expands, bravo collapses */ 279 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA }, 280 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA }, 281 { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND }, 282 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, 283 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, 284 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, 285 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, 286 { 0 } 287 }; 288 289 static const struct message parent_singleexpand_seq3[] = { 290 /* foxtrot expands, alpha and delta collapse */ 291 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA }, 292 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA }, 293 { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND }, 294 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, 295 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, 296 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, 297 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, 298 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, 299 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, 300 { 0 } 301 }; 302 303 static const struct message parent_singleexpand_seq4[] = { 304 /* alpha expands, foxtrot collapses */ 305 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA }, 306 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA }, 307 { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND }, 308 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, 309 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, 310 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, 311 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, 312 { 0 } 313 }; 314 315 static const struct message parent_singleexpand_seq5[] = { 316 /* foxtrot expands while golf is selected, then golf expands and alpha collapses */ 317 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA }, 318 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, 319 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, 320 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA }, 321 { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND }, 322 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, 323 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, 324 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, 325 { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, 326 { 0 } 327 }; 328 329 static const struct message parent_singleexpand_seq6[] = { 330 /* hotel does not expand and india does not collapse because they have no children */ 331 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA }, 332 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA }, 333 { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND }, 334 { 0 } 335 }; 336 337 static const struct message parent_singleexpand_seq7[] = { 338 /* india does not expand and hotel does not collapse because they have no children */ 339 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA }, 340 { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA }, 341 { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND }, 342 { 0 } 343 }; 344 345 static const struct message parent_get_dispinfo_seq[] = { 346 { WM_NOTIFY, sent|id, 0, 0, TVN_GETDISPINFOA }, 347 { 0 } 348 }; 349 350 static const struct message empty_seq[] = { 351 { 0 } 352 }; 353 354 static const struct message parent_cd_seq[] = { 355 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT }, 356 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT }, 357 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT }, 358 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT }, 359 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT }, 360 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT }, 361 { 0 } 362 }; 363 364 static const struct message parent_vk_return_seq[] = { 365 { WM_NOTIFY, sent|id, 0, 0, TVN_KEYDOWN }, 366 { WM_NOTIFY, sent|id, 0, 0, NM_RETURN }, 367 { WM_CHANGEUISTATE, sent|optional }, 368 { 0 } 369 }; 370 371 static const struct message parent_right_click_seq[] = { 372 { WM_NOTIFY, sent|id, 0, 0, NM_RCLICK }, 373 { WM_CONTEXTMENU, sent }, 374 { WM_NOTIFY, sent|optional }, 375 { WM_SETCURSOR, sent|optional }, 376 { 0 } 377 }; 378 379 static HWND hMainWnd; 380 381 static HTREEITEM hRoot, hChild; 382 383 static int pos = 0; 384 static char sequence[256]; 385 386 static void Clear(void) 387 { 388 pos = 0; 389 sequence[0] = '\0'; 390 } 391 392 static void AddItem(char ch) 393 { 394 sequence[pos++] = ch; 395 sequence[pos] = '\0'; 396 } 397 398 static void IdentifyItem(HTREEITEM hItem) 399 { 400 if (hItem == hRoot) { 401 AddItem('R'); 402 return; 403 } 404 if (hItem == hChild) { 405 AddItem('C'); 406 return; 407 } 408 if (hItem == NULL) { 409 AddItem('n'); 410 return; 411 } 412 AddItem('?'); 413 } 414 415 /* This function hooks in and records all messages to the treeview control */ 416 static LRESULT WINAPI TreeviewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 417 { 418 static LONG defwndproc_counter = 0; 419 LRESULT ret; 420 WNDPROC lpOldProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); 421 struct message msg = { 0 }; 422 423 msg.message = message; 424 msg.flags = sent|wparam|lparam; 425 if (defwndproc_counter) msg.flags |= defwinproc; 426 msg.wParam = wParam; 427 msg.lParam = lParam; 428 add_message(sequences, TREEVIEW_SEQ_INDEX, &msg); 429 430 defwndproc_counter++; 431 ret = CallWindowProcA(lpOldProc, hwnd, message, wParam, lParam); 432 defwndproc_counter--; 433 434 return ret; 435 } 436 437 static HWND create_treeview_control(DWORD style) 438 { 439 WNDPROC pOldWndProc; 440 HWND hTree; 441 442 hTree = CreateWindowExA(WS_EX_CLIENTEDGE, WC_TREEVIEWA, NULL, WS_CHILD|WS_VISIBLE| 443 TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS|TVS_EDITLABELS|style, 444 0, 0, 120, 100, hMainWnd, (HMENU)100, GetModuleHandleA(0), 0); 445 446 SetFocus(hTree); 447 448 /* Record the old WNDPROC so we can call it after recording the messages */ 449 pOldWndProc = (WNDPROC)SetWindowLongPtrA(hTree, GWLP_WNDPROC, (LONG_PTR)TreeviewWndProc); 450 SetWindowLongPtrA(hTree, GWLP_USERDATA, (LONG_PTR)pOldWndProc); 451 452 return hTree; 453 } 454 455 static void fill_tree(HWND hTree) 456 { 457 TVINSERTSTRUCTA ins; 458 static CHAR root[] = "Root", 459 child[] = "Child"; 460 461 ins.hParent = TVI_ROOT; 462 ins.hInsertAfter = TVI_ROOT; 463 U(ins).item.mask = TVIF_TEXT; 464 U(ins).item.pszText = root; 465 hRoot = TreeView_InsertItemA(hTree, &ins); 466 467 ins.hParent = hRoot; 468 ins.hInsertAfter = TVI_FIRST; 469 U(ins).item.mask = TVIF_TEXT; 470 U(ins).item.pszText = child; 471 hChild = TreeView_InsertItemA(hTree, &ins); 472 } 473 474 static void test_fillroot(void) 475 { 476 TVITEMA tvi; 477 HWND hTree; 478 479 hTree = create_treeview_control(0); 480 481 flush_sequences(sequences, NUM_MSG_SEQUENCES); 482 483 fill_tree(hTree); 484 485 Clear(); 486 AddItem('A'); 487 ok(hRoot != NULL, "failed to set root\n"); 488 AddItem('B'); 489 ok(hChild != NULL, "failed to set child\n"); 490 AddItem('.'); 491 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, FillRootSeq, "FillRoot", FALSE); 492 ok(!strcmp(sequence, "AB."), "Item creation\n"); 493 494 /* UMLPad 1.15 depends on this being not -1 (I_IMAGECALLBACK) */ 495 tvi.hItem = hRoot; 496 tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE; 497 SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&tvi); 498 ok(tvi.iImage == 0, "tvi.iImage=%d\n", tvi.iImage); 499 ok(tvi.iSelectedImage == 0, "tvi.iSelectedImage=%d\n", tvi.iSelectedImage); 500 501 DestroyWindow(hTree); 502 } 503 504 static void test_callback(void) 505 { 506 HTREEITEM hRoot; 507 HTREEITEM hItem1, hItem2; 508 TVINSERTSTRUCTA ins; 509 TVITEMA tvi; 510 CHAR test_string[] = "Test_string"; 511 static const CHAR test2A[] = "TEST2"; 512 CHAR buf[128]; 513 HWND hTree; 514 DWORD ret; 515 516 hTree = create_treeview_control(0); 517 518 ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT); 519 expect(TRUE, ret); 520 ins.hParent = TVI_ROOT; 521 ins.hInsertAfter = TVI_ROOT; 522 U(ins).item.mask = TVIF_TEXT; 523 U(ins).item.pszText = LPSTR_TEXTCALLBACKA; 524 hRoot = TreeView_InsertItemA(hTree, &ins); 525 ok(hRoot != NULL, "failed to set root\n"); 526 527 tvi.hItem = hRoot; 528 tvi.mask = TVIF_TEXT; 529 tvi.pszText = buf; 530 tvi.cchTextMax = sizeof(buf)/sizeof(buf[0]); 531 ret = TreeView_GetItemA(hTree, &tvi); 532 expect(TRUE, ret); 533 ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Callback item text mismatch %s vs %s\n", 534 tvi.pszText, TEST_CALLBACK_TEXT); 535 536 ins.hParent = hRoot; 537 ins.hInsertAfter = TVI_FIRST; 538 U(ins).item.mask = TVIF_TEXT; 539 U(ins).item.pszText = test_string; 540 hItem1 = TreeView_InsertItemA(hTree, &ins); 541 ok(hItem1 != NULL, "failed to set Item1\n"); 542 543 tvi.hItem = hItem1; 544 ret = TreeView_GetItemA(hTree, &tvi); 545 expect(TRUE, ret); 546 ok(strcmp(tvi.pszText, test_string) == 0, "Item text mismatch %s vs %s\n", 547 tvi.pszText, test_string); 548 549 /* undocumented: pszText of NULL also means LPSTR_CALLBACK: */ 550 tvi.pszText = NULL; 551 ret = TreeView_SetItemA(hTree, &tvi); 552 expect(TRUE, ret); 553 tvi.pszText = buf; 554 ret = TreeView_GetItemA(hTree, &tvi); 555 expect(TRUE, ret); 556 ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n", 557 tvi.pszText, TEST_CALLBACK_TEXT); 558 559 U(ins).item.pszText = NULL; 560 hItem2 = TreeView_InsertItemA(hTree, &ins); 561 ok(hItem2 != NULL, "failed to set Item2\n"); 562 tvi.hItem = hItem2; 563 memset(buf, 0, sizeof(buf)); 564 ret = TreeView_GetItemA(hTree, &tvi); 565 expect(TRUE, ret); 566 ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n", 567 tvi.pszText, TEST_CALLBACK_TEXT); 568 569 /* notification handler changed A->W */ 570 g_disp_A_to_W = TRUE; 571 tvi.hItem = hItem2; 572 memset(buf, 0, sizeof(buf)); 573 ret = TreeView_GetItemA(hTree, &tvi); 574 expect(TRUE, ret); 575 ok(strcmp(tvi.pszText, test2A) == 0, "got %s, expected %s\n", 576 tvi.pszText, test2A); 577 g_disp_A_to_W = FALSE; 578 579 /* handler changes state image index */ 580 SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_CHECKBOXES); 581 582 /* clear selection, handler will set selected state */ 583 ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0); 584 expect(TRUE, ret); 585 586 flush_sequences(sequences, NUM_MSG_SEQUENCES); 587 588 tvi.hItem = hRoot; 589 tvi.mask = TVIF_STATE; 590 tvi.state = TVIS_SELECTED; 591 ret = TreeView_GetItemA(hTree, &tvi); 592 expect(TRUE, ret); 593 ok(tvi.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", tvi.state); 594 595 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, 596 "no TVN_GETDISPINFO for a state seq", FALSE); 597 598 tvi.hItem = hRoot; 599 tvi.mask = TVIF_IMAGE | TVIF_STATE; 600 tvi.state = TVIS_FOCUSED; 601 tvi.stateMask = TVIS_FOCUSED; 602 tvi.iImage = I_IMAGECALLBACK; 603 ret = TreeView_SetItemA(hTree, &tvi); 604 expect(TRUE, ret); 605 606 /* ask for item image index through callback - state is also set with state image index */ 607 flush_sequences(sequences, NUM_MSG_SEQUENCES); 608 609 tvi.hItem = hRoot; 610 tvi.mask = TVIF_IMAGE; 611 tvi.state = 0; 612 ret = TreeView_GetItemA(hTree, &tvi); 613 expect(TRUE, ret); 614 ok(tvi.state == (INDEXTOSTATEIMAGEMASK(1) | TVIS_FOCUSED), "got 0x%x\n", tvi.state); 615 616 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_get_dispinfo_seq, 617 "callback for state/overlay image index, noop seq", FALSE); 618 619 /* ask for image again and overwrite state to some value in handler */ 620 flush_sequences(sequences, NUM_MSG_SEQUENCES); 621 622 g_disp_set_stateimage = TRUE; 623 tvi.hItem = hRoot; 624 tvi.mask = TVIF_IMAGE; 625 tvi.state = INDEXTOSTATEIMAGEMASK(1); 626 tvi.stateMask = 0; 627 ret = TreeView_GetItemA(hTree, &tvi); 628 expect(TRUE, ret); 629 /* handler sets TVIS_SELECTED as well */ 630 ok(tvi.state == (TVIS_FOCUSED | TVIS_SELECTED | INDEXTOSTATEIMAGEMASK(2) | INDEXTOOVERLAYMASK(3)), "got 0x%x\n", tvi.state); 631 g_disp_set_stateimage = FALSE; 632 633 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_get_dispinfo_seq, 634 "callback for state/overlay image index seq", FALSE); 635 636 DestroyWindow(hTree); 637 } 638 639 static void test_select(void) 640 { 641 BOOL r; 642 HWND hTree; 643 644 hTree = create_treeview_control(0); 645 fill_tree(hTree); 646 647 /* root-none select tests */ 648 flush_sequences(sequences, NUM_MSG_SEQUENCES); 649 r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0); 650 expect(TRUE, r); 651 Clear(); 652 AddItem('1'); 653 r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); 654 expect(TRUE, r); 655 AddItem('2'); 656 r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); 657 expect(TRUE, r); 658 AddItem('3'); 659 r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0); 660 expect(TRUE, r); 661 AddItem('4'); 662 r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0); 663 expect(TRUE, r); 664 AddItem('5'); 665 r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); 666 expect(TRUE, r); 667 AddItem('.'); 668 ok(!strcmp(sequence, "1(nR)nR23(Rn)Rn45(nR)nR."), "root-none select test\n"); 669 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, rootnone_select_seq, 670 "root-none select seq", FALSE); 671 672 /* root-child select tests */ 673 flush_sequences(sequences, NUM_MSG_SEQUENCES); 674 r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0); 675 expect(TRUE, r); 676 677 Clear(); 678 AddItem('1'); 679 r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); 680 expect(TRUE, r); 681 AddItem('2'); 682 r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); 683 expect(TRUE, r); 684 AddItem('3'); 685 r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild); 686 expect(TRUE, r); 687 AddItem('4'); 688 r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild); 689 expect(TRUE, r); 690 AddItem('5'); 691 r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); 692 expect(TRUE, r); 693 AddItem('.'); 694 ok(!strcmp(sequence, "1(nR)nR23(RC)RC45(CR)CR."), "root-child select test\n"); 695 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, rootchild_select_seq, 696 "root-child select seq", FALSE); 697 698 DestroyWindow(hTree); 699 } 700 701 static void test_getitemtext(void) 702 { 703 TVINSERTSTRUCTA ins; 704 HTREEITEM hChild; 705 TVITEMA tvi; 706 HWND hTree; 707 708 CHAR szBuffer[80] = "Blah"; 709 int nBufferSize = sizeof(szBuffer)/sizeof(CHAR); 710 711 hTree = create_treeview_control(0); 712 fill_tree(hTree); 713 714 flush_sequences(sequences, NUM_MSG_SEQUENCES); 715 716 /* add an item without TVIF_TEXT mask and pszText == NULL */ 717 ins.hParent = hRoot; 718 ins.hInsertAfter = TVI_ROOT; 719 U(ins).item.mask = 0; 720 U(ins).item.pszText = NULL; 721 U(ins).item.cchTextMax = 0; 722 hChild = TreeView_InsertItemA(hTree, &ins); 723 ok(hChild != NULL, "failed to set hChild\n"); 724 725 /* retrieve it with TVIF_TEXT mask */ 726 tvi.hItem = hChild; 727 tvi.mask = TVIF_TEXT; 728 tvi.cchTextMax = nBufferSize; 729 tvi.pszText = szBuffer; 730 731 SendMessageA( hTree, TVM_GETITEMA, 0, (LPARAM)&tvi ); 732 ok(!strcmp(szBuffer, ""), "szBuffer=\"%s\", expected \"\"\n", szBuffer); 733 ok(SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild), "DeleteItem failed\n"); 734 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, getitemtext_seq, "get item text seq", FALSE); 735 736 DestroyWindow(hTree); 737 } 738 739 static void test_focus(void) 740 { 741 TVINSERTSTRUCTA ins; 742 static CHAR child1[] = "Edit", 743 child2[] = "A really long string"; 744 HTREEITEM hChild1, hChild2; 745 HWND hTree; 746 HWND hEdit; 747 748 hTree = create_treeview_control(0); 749 fill_tree(hTree); 750 751 flush_sequences(sequences, NUM_MSG_SEQUENCES); 752 753 /* This test verifies that when a label is being edited, scrolling 754 * the treeview does not cause the label to lose focus. To test 755 * this, first some additional entries are added to generate 756 * scrollbars. 757 */ 758 ins.hParent = hRoot; 759 ins.hInsertAfter = hChild; 760 U(ins).item.mask = TVIF_TEXT; 761 U(ins).item.pszText = child1; 762 hChild1 = TreeView_InsertItemA(hTree, &ins); 763 ok(hChild1 != NULL, "failed to set hChild1\n"); 764 ins.hInsertAfter = hChild1; 765 U(ins).item.mask = TVIF_TEXT; 766 U(ins).item.pszText = child2; 767 hChild2 = TreeView_InsertItemA(hTree, &ins); 768 ok(hChild2 != NULL, "failed to set hChild2\n"); 769 770 ShowWindow(hMainWnd,SW_SHOW); 771 SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild); 772 hEdit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hChild); 773 ScrollWindowEx(hTree, -10, 0, NULL, NULL, NULL, NULL, SW_SCROLLCHILDREN); 774 ok(GetFocus() == hEdit, "Edit control should have focus\n"); 775 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, focus_seq, "focus test", TRUE); 776 777 DestroyWindow(hTree); 778 } 779 780 static void test_get_set_bkcolor(void) 781 { 782 COLORREF crColor; 783 HWND hTree; 784 785 hTree = create_treeview_control(0); 786 fill_tree(hTree); 787 788 flush_sequences(sequences, NUM_MSG_SEQUENCES); 789 790 /* If the value is -1, the control is using the system color for the background color. */ 791 crColor = SendMessageA(hTree, TVM_GETBKCOLOR, 0, 0); 792 ok(crColor == ~0u, "Default background color reported as 0x%.8x\n", crColor); 793 794 /* Test for black background */ 795 SendMessageA(hTree, TVM_SETBKCOLOR, 0, RGB(0,0,0)); 796 crColor = SendMessageA(hTree, TVM_GETBKCOLOR, 0, 0); 797 ok(crColor == RGB(0,0,0), "Black background color reported as 0x%.8x\n", crColor); 798 799 /* Test for white background */ 800 SendMessageA(hTree, TVM_SETBKCOLOR, 0, RGB(255,255,255)); 801 crColor = SendMessageA(hTree, TVM_GETBKCOLOR, 0, 0); 802 ok(crColor == RGB(255,255,255), "White background color reported as 0x%.8x\n", crColor); 803 804 /* Reset the default background */ 805 SendMessageA(hTree, TVM_SETBKCOLOR, 0, -1); 806 807 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_bkcolor_seq, 808 "test get set bkcolor", FALSE); 809 810 DestroyWindow(hTree); 811 } 812 813 static void test_get_set_imagelist(void) 814 { 815 HIMAGELIST himl; 816 HWND hTree; 817 818 hTree = create_treeview_control(0); 819 fill_tree(hTree); 820 821 flush_sequences(sequences, NUM_MSG_SEQUENCES); 822 823 /* Test a NULL HIMAGELIST */ 824 SendMessageA(hTree, TVM_SETIMAGELIST, TVSIL_NORMAL, 0); 825 himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_NORMAL, 0); 826 ok(himl == NULL, "NULL image list, reported as %p, expected 0.\n", himl); 827 828 /* TODO: Test an actual image list */ 829 830 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_imagelist_seq, 831 "test get imagelist", FALSE); 832 833 DestroyWindow(hTree); 834 } 835 836 static void test_get_set_indent(void) 837 { 838 int ulIndent; 839 int ulMinIndent; 840 int ulMoreThanTwiceMin; 841 HWND hTree; 842 843 hTree = create_treeview_control(0); 844 fill_tree(hTree); 845 846 flush_sequences(sequences, NUM_MSG_SEQUENCES); 847 848 /* Finding the minimum indent */ 849 SendMessageA(hTree, TVM_SETINDENT, 0, 0); 850 ulMinIndent = SendMessageA(hTree, TVM_GETINDENT, 0, 0); 851 852 /* Checking an indent that is more than twice the default indent */ 853 ulMoreThanTwiceMin = 2*ulMinIndent+1; 854 SendMessageA(hTree, TVM_SETINDENT, ulMoreThanTwiceMin, 0); 855 ulIndent = SendMessageA(hTree, TVM_GETINDENT, 0, 0); 856 ok(ulIndent == ulMoreThanTwiceMin, "Indent reported as %d, expected %d\n", ulIndent, ulMoreThanTwiceMin); 857 858 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_indent_seq, 859 "test get set indent", FALSE); 860 861 DestroyWindow(hTree); 862 } 863 864 static void test_get_set_insertmark(void) 865 { 866 COLORREF crColor = RGB(0,0,0); 867 HWND hTree; 868 869 hTree = create_treeview_control(0); 870 fill_tree(hTree); 871 872 flush_sequences(sequences, NUM_MSG_SEQUENCES); 873 874 SendMessageA(hTree, TVM_SETINSERTMARKCOLOR, 0, crColor); 875 crColor = SendMessageA(hTree, TVM_GETINSERTMARKCOLOR, 0, 0); 876 ok(crColor == RGB(0,0,0), "Insert mark color reported as 0x%.8x, expected 0x00000000\n", crColor); 877 878 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_insertmarkcolor_seq, 879 "test get set insertmark color", FALSE); 880 881 DestroyWindow(hTree); 882 } 883 884 static void test_get_set_item(void) 885 { 886 TVITEMA tviRoot = {0}; 887 int nBufferSize = 80; 888 char szBuffer[80] = {0}; 889 HWND hTree, hTree2; 890 DWORD ret; 891 892 hTree = create_treeview_control(0); 893 fill_tree(hTree); 894 895 tviRoot.hItem = hRoot; 896 tviRoot.mask = TVIF_STATE; 897 tviRoot.state = TVIS_FOCUSED; 898 tviRoot.stateMask = TVIS_FOCUSED; 899 ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot); 900 expect(TRUE, ret); 901 902 flush_sequences(sequences, NUM_MSG_SEQUENCES); 903 904 /* Test the root item, state is set even when not requested */ 905 tviRoot.hItem = hRoot; 906 tviRoot.mask = TVIF_TEXT; 907 tviRoot.state = 0; 908 tviRoot.stateMask = 0; 909 tviRoot.cchTextMax = nBufferSize; 910 tviRoot.pszText = szBuffer; 911 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&tviRoot); 912 expect(TRUE, ret); 913 ok(!strcmp("Root", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Root\"\n", szBuffer); 914 ok(tviRoot.state == TVIS_FOCUSED, "got 0x%0x\n", tviRoot.state); 915 916 /* Change the root text */ 917 lstrcpynA(szBuffer, "Testing123", nBufferSize); 918 ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot); 919 expect(TRUE, ret); 920 memset(szBuffer, 0, nBufferSize); 921 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&tviRoot); 922 expect(TRUE, ret); 923 ok(!strcmp("Testing123", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Testing123\"\n", szBuffer); 924 925 /* Reset the root text */ 926 memset(szBuffer, 0, nBufferSize); 927 lstrcpynA(szBuffer, "Root", nBufferSize); 928 ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot); 929 expect(TRUE, ret); 930 931 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_item_seq, 932 "test get set item", FALSE); 933 934 /* get item from a different tree */ 935 hTree2 = create_treeview_control(0); 936 937 tviRoot.hItem = hRoot; 938 tviRoot.mask = TVIF_STATE; 939 tviRoot.state = 0; 940 ret = SendMessageA(hTree2, TVM_GETITEMA, 0, (LPARAM)&tviRoot); 941 expect(TRUE, ret); 942 ok(tviRoot.state == TVIS_FOCUSED, "got state 0x%0x\n", tviRoot.state); 943 944 /* invalid item pointer, nt4 crashes here but later versions just return 0 */ 945 tviRoot.hItem = (HTREEITEM)0xdeadbeef; 946 tviRoot.mask = TVIF_STATE; 947 tviRoot.state = 0; 948 ret = SendMessageA(hTree2, TVM_GETITEMA, 0, (LPARAM)&tviRoot); 949 expect(FALSE, ret); 950 951 DestroyWindow(hTree); 952 DestroyWindow(hTree2); 953 } 954 955 static void test_get_set_itemheight(void) 956 { 957 int ulOldHeight = 0; 958 int ulNewHeight = 0; 959 HWND hTree; 960 961 hTree = create_treeview_control(0); 962 fill_tree(hTree); 963 964 flush_sequences(sequences, NUM_MSG_SEQUENCES); 965 966 /* Assuming default height to begin with */ 967 ulOldHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0); 968 969 /* Explicitly setting and getting the default height */ 970 SendMessageA(hTree, TVM_SETITEMHEIGHT, -1, 0); 971 ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0); 972 ok(ulNewHeight == ulOldHeight, "Default height not set properly, reported %d, expected %d\n", ulNewHeight, ulOldHeight); 973 974 /* Explicitly setting and getting the height of twice the normal */ 975 SendMessageA(hTree, TVM_SETITEMHEIGHT, 2*ulOldHeight, 0); 976 ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0); 977 ok(ulNewHeight == 2*ulOldHeight, "New height not set properly, reported %d, expected %d\n", ulNewHeight, 2*ulOldHeight); 978 979 /* Assuming tree doesn't have TVS_NONEVENHEIGHT set, so a set of 9 will round down to 8 */ 980 SendMessageA(hTree, TVM_SETITEMHEIGHT, 9, 0); 981 ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0); 982 ok(ulNewHeight == 8, "Uneven height not set properly, reported %d, expected %d\n", ulNewHeight, 8); 983 984 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_itemheight_seq, 985 "test get set item height", FALSE); 986 987 /* without TVS_NONEVENHEIGHT */ 988 SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) & ~TVS_NONEVENHEIGHT); 989 /* odd value */ 990 ulOldHeight = SendMessageA(hTree, TVM_SETITEMHEIGHT, 3, 0); 991 ok(ulOldHeight == 8, "got %d, expected %d\n", ulOldHeight, 8); 992 ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0); 993 ok(ulNewHeight == 2, "got %d, expected %d\n", ulNewHeight, 2); 994 995 ulOldHeight = SendMessageA(hTree, TVM_SETITEMHEIGHT, 4, 0); 996 ok(ulOldHeight == 2, "got %d, expected %d\n", ulOldHeight, 2); 997 ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0); 998 ok(ulNewHeight == 4, "got %d, expected %d\n", ulNewHeight, 4); 999 1000 /* with TVS_NONEVENHEIGHT */ 1001 SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_NONEVENHEIGHT); 1002 /* odd value */ 1003 ulOldHeight = SendMessageA(hTree, TVM_SETITEMHEIGHT, 3, 0); 1004 ok(ulOldHeight == 4, "got %d, expected %d\n", ulOldHeight, 4); 1005 ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0); 1006 ok(ulNewHeight == 3, "got %d, expected %d\n", ulNewHeight, 3); 1007 /* even value */ 1008 ulOldHeight = SendMessageA(hTree, TVM_SETITEMHEIGHT, 10, 0); 1009 ok(ulOldHeight == 3, "got %d, expected %d\n", ulOldHeight, 3); 1010 ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0); 1011 ok(ulNewHeight == 10, "got %d, expected %d\n", ulNewHeight, 10); 1012 1013 DestroyWindow(hTree); 1014 } 1015 1016 static void test_get_set_scrolltime(void) 1017 { 1018 int ulExpectedTime = 20; 1019 int ulTime = 0; 1020 HWND hTree; 1021 1022 hTree = create_treeview_control(0); 1023 fill_tree(hTree); 1024 1025 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1026 1027 SendMessageA(hTree, TVM_SETSCROLLTIME, ulExpectedTime, 0); 1028 ulTime = SendMessageA(hTree, TVM_GETSCROLLTIME, 0, 0); 1029 ok(ulTime == ulExpectedTime, "Scroll time reported as %d, expected %d\n", ulTime, ulExpectedTime); 1030 1031 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_scrolltime_seq, 1032 "test get set scroll time", FALSE); 1033 1034 DestroyWindow(hTree); 1035 } 1036 1037 static void test_get_set_textcolor(void) 1038 { 1039 /* If the value is -1, the control is using the system color for the text color. */ 1040 COLORREF crColor; 1041 HWND hTree; 1042 1043 hTree = create_treeview_control(0); 1044 fill_tree(hTree); 1045 1046 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1047 1048 crColor = SendMessageA(hTree, TVM_GETTEXTCOLOR, 0, 0); 1049 ok(crColor == ~0u, "Default text color reported as 0x%.8x\n", crColor); 1050 1051 /* Test for black text */ 1052 SendMessageA(hTree, TVM_SETTEXTCOLOR, 0, RGB(0,0,0)); 1053 crColor = SendMessageA(hTree, TVM_GETTEXTCOLOR, 0, 0); 1054 ok(crColor == RGB(0,0,0), "Black text color reported as 0x%.8x\n", crColor); 1055 1056 /* Test for white text */ 1057 SendMessageA(hTree, TVM_SETTEXTCOLOR, 0, RGB(255,255,255)); 1058 crColor = SendMessageA(hTree, TVM_GETTEXTCOLOR, 0, 0); 1059 ok(crColor == RGB(255,255,255), "White text color reported as 0x%.8x\n", crColor); 1060 1061 /* Reset the default text color */ 1062 SendMessageA(hTree, TVM_SETTEXTCOLOR, 0, CLR_NONE); 1063 1064 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_textcolor_seq, 1065 "test get set text color", FALSE); 1066 1067 DestroyWindow(hTree); 1068 } 1069 1070 static void test_get_set_tooltips(void) 1071 { 1072 HWND hTree, tooltips, hwnd; 1073 DWORD style; 1074 int i; 1075 1076 /* TVS_NOTOOLTIPS */ 1077 hTree = create_treeview_control(TVS_NOTOOLTIPS); 1078 1079 tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); 1080 ok(tooltips == NULL, "Unexpected tooltip window %p.\n", tooltips); 1081 1082 tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, 0, 0); 1083 ok(tooltips == NULL, "Unexpected ret value %p.\n", tooltips); 1084 1085 /* Toggle style */ 1086 style = GetWindowLongA(hTree, GWL_STYLE); 1087 SetWindowLongA(hTree, GWL_STYLE, style & ~TVS_NOTOOLTIPS); 1088 1089 tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); 1090 ok(IsWindow(tooltips), "Unexpected tooltip window %p.\n", tooltips); 1091 1092 style = GetWindowLongA(hTree, GWL_STYLE); 1093 SetWindowLongA(hTree, GWL_STYLE, style | TVS_NOTOOLTIPS); 1094 1095 tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); 1096 ok(tooltips == NULL, "Unexpected tooltip window %p.\n", tooltips); 1097 1098 DestroyWindow(hTree); 1099 1100 /* Set some valid window, does not have to be tooltips class. */ 1101 hTree = create_treeview_control(TVS_NOTOOLTIPS); 1102 1103 hwnd = CreateWindowA(WC_STATICA, "Test", WS_VISIBLE|WS_CHILD, 5, 5, 100, 100, hMainWnd, NULL, NULL, 0); 1104 ok(hwnd != NULL, "Failed to create child window.\n"); 1105 1106 tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, (WPARAM)hwnd, 0); 1107 ok(tooltips == NULL, "Unexpected ret value %p.\n", tooltips); 1108 1109 tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); 1110 ok(tooltips == hwnd, "Unexpected tooltip window %p.\n", tooltips); 1111 1112 /* Externally set tooltips window, disable style. */ 1113 style = GetWindowLongA(hTree, GWL_STYLE); 1114 SetWindowLongA(hTree, GWL_STYLE, style & ~TVS_NOTOOLTIPS); 1115 1116 tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); 1117 ok(IsWindow(tooltips) && tooltips != hwnd, "Unexpected tooltip window %p.\n", tooltips); 1118 ok(IsWindow(hwnd), "Expected valid window.\n"); 1119 1120 style = GetWindowLongA(hTree, GWL_STYLE); 1121 SetWindowLongA(hTree, GWL_STYLE, style | TVS_NOTOOLTIPS); 1122 ok(!IsWindow(tooltips), "Unexpected tooltip window %p.\n", tooltips); 1123 1124 tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); 1125 ok(tooltips == NULL, "Unexpected tooltip window %p.\n", tooltips); 1126 ok(IsWindow(hwnd), "Expected valid window.\n"); 1127 1128 DestroyWindow(hTree); 1129 ok(IsWindow(hwnd), "Expected valid window.\n"); 1130 1131 /* Set window, disable tooltips. */ 1132 hTree = create_treeview_control(0); 1133 1134 tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, (WPARAM)hwnd, 0); 1135 ok(IsWindow(tooltips), "Unexpected ret value %p.\n", tooltips); 1136 1137 style = GetWindowLongA(hTree, GWL_STYLE); 1138 SetWindowLongA(hTree, GWL_STYLE, style | TVS_NOTOOLTIPS); 1139 ok(!IsWindow(hwnd), "Unexpected tooltip window %p.\n", tooltips); 1140 ok(IsWindow(tooltips), "Expected valid window %p.\n", tooltips); 1141 1142 DestroyWindow(hTree); 1143 ok(IsWindow(tooltips), "Expected valid window %p.\n", tooltips); 1144 DestroyWindow(tooltips); 1145 DestroyWindow(hwnd); 1146 1147 for (i = 0; i < 2; i++) 1148 { 1149 DWORD style = i == 0 ? 0 : TVS_NOTOOLTIPS; 1150 1151 hwnd = CreateWindowA(WC_STATICA, "Test", WS_VISIBLE|WS_CHILD, 5, 5, 100, 100, hMainWnd, NULL, NULL, 0); 1152 ok(hwnd != NULL, "Failed to create child window.\n"); 1153 1154 hTree = create_treeview_control(style); 1155 1156 tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, (WPARAM)hwnd, 0); 1157 ok(style & TVS_NOTOOLTIPS ? tooltips == NULL : IsWindow(tooltips), "Unexpected ret value %p.\n", tooltips); 1158 DestroyWindow(tooltips); 1159 1160 tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); 1161 ok(tooltips == hwnd, "Unexpected tooltip window %p.\n", tooltips); 1162 1163 /* TreeView is destroyed, check if set window is still around. */ 1164 DestroyWindow(hTree); 1165 ok(!IsWindow(hwnd), "Unexpected window.\n"); 1166 } 1167 1168 hTree = create_treeview_control(0); 1169 fill_tree(hTree); 1170 1171 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1172 1173 /* show even WS_POPUP treeview don't send NM_TOOLTIPSCREATED */ 1174 hwnd = CreateWindowA(WC_TREEVIEWA, NULL, WS_POPUP|WS_VISIBLE, 0, 0, 100, 100, 1175 hMainWnd, NULL, NULL, NULL); 1176 DestroyWindow(hwnd); 1177 1178 /* Testing setting a NULL ToolTip */ 1179 tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, 0, 0); 1180 ok(IsWindow(tooltips), "Unexpected ret value %p.\n", tooltips); 1181 1182 hwnd = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); 1183 ok(hwnd == NULL, "Unexpected tooltip window %p.\n", hwnd); 1184 1185 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_tooltips_seq, 1186 "test get set tooltips", TRUE); 1187 1188 DestroyWindow(hTree); 1189 ok(IsWindow(tooltips), "Expected valid window.\n"); 1190 DestroyWindow(tooltips); 1191 } 1192 1193 static void test_get_set_unicodeformat(void) 1194 { 1195 BOOL bPreviousSetting; 1196 BOOL bNewSetting; 1197 HWND hTree; 1198 1199 hTree = create_treeview_control(0); 1200 fill_tree(hTree); 1201 1202 /* Check that an invalid format returned by NF_QUERY defaults to ANSI */ 1203 bPreviousSetting = SendMessageA(hTree, TVM_GETUNICODEFORMAT, 0, 0); 1204 ok(bPreviousSetting == FALSE, "Format should be ANSI.\n"); 1205 1206 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1207 1208 /* Set to Unicode */ 1209 bPreviousSetting = SendMessageA(hTree, TVM_SETUNICODEFORMAT, 1, 0); 1210 bNewSetting = SendMessageA(hTree, TVM_GETUNICODEFORMAT, 0, 0); 1211 ok(bNewSetting == TRUE, "Unicode setting did not work.\n"); 1212 1213 /* Set to ANSI */ 1214 SendMessageA(hTree, TVM_SETUNICODEFORMAT, 0, 0); 1215 bNewSetting = SendMessageA(hTree, TVM_GETUNICODEFORMAT, 0, 0); 1216 ok(bNewSetting == FALSE, "ANSI setting did not work.\n"); 1217 1218 /* Revert to original setting */ 1219 SendMessageA(hTree, TVM_SETUNICODEFORMAT, bPreviousSetting, 0); 1220 1221 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_unicodeformat_seq, 1222 "test get set unicode format", FALSE); 1223 1224 DestroyWindow(hTree); 1225 } 1226 1227 static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 1228 { 1229 static LONG defwndproc_counter = 0; 1230 struct message msg = { 0 }; 1231 LRESULT ret; 1232 RECT rect; 1233 HTREEITEM visibleItem; 1234 1235 msg.message = message; 1236 msg.flags = sent|wparam|lparam; 1237 if (defwndproc_counter) msg.flags |= defwinproc; 1238 msg.wParam = wParam; 1239 msg.lParam = lParam; 1240 if (message == WM_NOTIFY && lParam) 1241 msg.id = ((NMHDR*)lParam)->code; 1242 1243 /* log system messages, except for painting */ 1244 if (message < WM_USER && 1245 message != WM_PAINT && 1246 message != WM_ERASEBKGND && 1247 message != WM_NCPAINT && 1248 message != WM_NCHITTEST && 1249 message != WM_GETTEXT && 1250 message != WM_GETICON && 1251 message != WM_DEVICECHANGE) 1252 { 1253 add_message(sequences, PARENT_SEQ_INDEX, &msg); 1254 } 1255 1256 switch(message) { 1257 case WM_NOTIFYFORMAT: 1258 { 1259 /* Make NF_QUERY return an invalid format to show that it defaults to ANSI */ 1260 if (lParam == NF_QUERY) return 0; 1261 break; 1262 } 1263 1264 case WM_NOTIFY: 1265 { 1266 NMHDR *pHdr = (NMHDR *)lParam; 1267 1268 ok(pHdr->code != NM_TOOLTIPSCREATED, "Treeview should not send NM_TOOLTIPSCREATED\n"); 1269 if (pHdr->idFrom == 100) 1270 { 1271 NMTREEVIEWA *pTreeView = (LPNMTREEVIEWA) lParam; 1272 switch(pHdr->code) 1273 { 1274 case TVN_SELCHANGINGA: 1275 AddItem('('); 1276 IdentifyItem(pTreeView->itemOld.hItem); 1277 IdentifyItem(pTreeView->itemNew.hItem); 1278 break; 1279 case TVN_SELCHANGEDA: 1280 AddItem(')'); 1281 IdentifyItem(pTreeView->itemOld.hItem); 1282 IdentifyItem(pTreeView->itemNew.hItem); 1283 break; 1284 case TVN_GETDISPINFOA: { 1285 NMTVDISPINFOA *disp = (NMTVDISPINFOA *)lParam; 1286 if (disp->item.mask & TVIF_TEXT) { 1287 lstrcpynA(disp->item.pszText, TEST_CALLBACK_TEXT, disp->item.cchTextMax); 1288 } 1289 1290 if (g_disp_A_to_W && (disp->item.mask & TVIF_TEXT)) { 1291 static const WCHAR testW[] = {'T','E','S','T','2',0}; 1292 1293 disp->hdr.code = TVN_GETDISPINFOW; 1294 memcpy(disp->item.pszText, testW, sizeof(testW)); 1295 } 1296 1297 if (g_disp_set_stateimage) 1298 { 1299 ok(disp->item.mask == TVIF_IMAGE, "got %x\n", disp->item.mask); 1300 /* both masks set here are necessary to change state bits */ 1301 disp->item.mask |= TVIF_STATE; 1302 disp->item.state = TVIS_SELECTED | INDEXTOSTATEIMAGEMASK(2) | INDEXTOOVERLAYMASK(3); 1303 disp->item.stateMask = TVIS_SELECTED | TVIS_OVERLAYMASK | TVIS_STATEIMAGEMASK; 1304 } 1305 1306 break; 1307 } 1308 case TVN_BEGINLABELEDITA: 1309 { 1310 if (g_beginedit_alter_text) 1311 { 1312 static const char* textA = "<edittextaltered>"; 1313 HWND edit; 1314 1315 edit = (HWND)SendMessageA(pHdr->hwndFrom, TVM_GETEDITCONTROL, 0, 0); 1316 ok(IsWindow(edit), "failed to get edit handle\n"); 1317 SetWindowTextA(edit, textA); 1318 } 1319 1320 break; 1321 } 1322 1323 case TVN_ENDLABELEDITA: return TRUE; 1324 case TVN_ITEMEXPANDINGA: 1325 { 1326 UINT newmask = pTreeView->itemNew.mask & ~TVIF_CHILDREN; 1327 ok(newmask == 1328 (TVIF_HANDLE | TVIF_SELECTEDIMAGE | TVIF_IMAGE | TVIF_PARAM | TVIF_STATE), 1329 "got wrong mask %x\n", pTreeView->itemNew.mask); 1330 ok(pTreeView->itemOld.mask == 0, 1331 "got wrong mask %x\n", pTreeView->itemOld.mask); 1332 1333 if (g_get_from_expand) 1334 { 1335 g_item_expanding.mask = TVIF_STATE; 1336 g_item_expanding.hItem = hRoot; 1337 ret = SendMessageA(pHdr->hwndFrom, TVM_GETITEMA, 0, (LPARAM)&g_item_expanding); 1338 ok(ret == TRUE, "got %lu\n", ret); 1339 } 1340 break; 1341 } 1342 case TVN_ITEMEXPANDEDA: 1343 ok(pTreeView->itemNew.mask & TVIF_STATE, "got wrong mask %x\n", pTreeView->itemNew.mask); 1344 ok(pTreeView->itemNew.state & (TVIS_EXPANDED|TVIS_EXPANDEDONCE), 1345 "got wrong mask %x\n", pTreeView->itemNew.mask); 1346 ok(pTreeView->itemOld.mask == 0, 1347 "got wrong mask %x\n", pTreeView->itemOld.mask); 1348 1349 if (g_get_from_expand) 1350 { 1351 g_item_expanded.mask = TVIF_STATE; 1352 g_item_expanded.hItem = hRoot; 1353 ret = SendMessageA(pHdr->hwndFrom, TVM_GETITEMA, 0, (LPARAM)&g_item_expanded); 1354 ok(ret == TRUE, "got %lu\n", ret); 1355 } 1356 if (g_get_rect_in_expand) 1357 { 1358 visibleItem = (HTREEITEM)SendMessageA(pHdr->hwndFrom, TVM_GETNEXTITEM, 1359 TVGN_FIRSTVISIBLE, 0); 1360 ok(pTreeView->itemNew.hItem == visibleItem, "expanded item == first visible item\n"); 1361 *(HTREEITEM*)&rect = visibleItem; 1362 ok(SendMessageA(pHdr->hwndFrom, TVM_GETITEMRECT, TRUE, (LPARAM)&rect), 1363 "Failed to get rect for first visible item.\n"); 1364 visibleItem = (HTREEITEM)SendMessageA(pHdr->hwndFrom, TVM_GETNEXTITEM, 1365 TVGN_NEXTVISIBLE, (LPARAM)visibleItem); 1366 *(HTREEITEM*)&rect = visibleItem; 1367 ok(visibleItem != NULL, "There must be a visible item after the first visisble item.\n"); 1368 ok(SendMessageA(pHdr->hwndFrom, TVM_GETITEMRECT, TRUE, (LPARAM)&rect), 1369 "Failed to get rect for second visible item.\n"); 1370 } 1371 break; 1372 case TVN_DELETEITEMA: 1373 { 1374 struct message item; 1375 1376 ok(pTreeView->itemNew.mask == 0, "got wrong mask 0x%x\n", pTreeView->itemNew.mask); 1377 1378 ok(pTreeView->itemOld.mask == (TVIF_HANDLE | TVIF_PARAM), "got wrong mask 0x%x\n", pTreeView->itemOld.mask); 1379 ok(pTreeView->itemOld.hItem != NULL, "got %p\n", pTreeView->itemOld.hItem); 1380 1381 memset(&item, 0, sizeof(item)); 1382 item.lParam = (LPARAM)pTreeView->itemOld.hItem; 1383 add_message(item_sequence, 0, &item); 1384 1385 break; 1386 } 1387 case NM_CUSTOMDRAW: 1388 { 1389 NMTVCUSTOMDRAW *nmcd = (NMTVCUSTOMDRAW*)lParam; 1390 COLORREF c0ffee = RGB(0xc0,0xff,0xee), cafe = RGB(0xca,0xfe,0x00); 1391 COLORREF text = GetTextColor(nmcd->nmcd.hdc), bkgnd = GetBkColor(nmcd->nmcd.hdc); 1392 1393 msg.flags |= custdraw; 1394 msg.stage = nmcd->nmcd.dwDrawStage; 1395 add_message(sequences, PARENT_CD_SEQ_INDEX, &msg); 1396 1397 switch (msg.stage) 1398 { 1399 case CDDS_PREPAINT: 1400 return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYITEMERASE|CDRF_NOTIFYPOSTPAINT; 1401 case CDDS_ITEMPREPAINT: 1402 ok(text == nmcd->clrText || (g_v6 && nmcd->clrText == 0xffffffff), 1403 "got %08x vs %08x\n", text, nmcd->clrText); 1404 ok(bkgnd == nmcd->clrTextBk || (g_v6 && nmcd->clrTextBk == 0xffffffff), 1405 "got %08x vs %08x\n", bkgnd, nmcd->clrTextBk); 1406 nmcd->clrText = cafe; 1407 nmcd->clrTextBk = c0ffee; 1408 SetTextColor(nmcd->nmcd.hdc, c0ffee); 1409 SetBkColor(nmcd->nmcd.hdc, cafe); 1410 if (g_customdraw_font) 1411 SelectObject(nmcd->nmcd.hdc, g_customdraw_font); 1412 return CDRF_NOTIFYPOSTPAINT|CDRF_NEWFONT; 1413 case CDDS_ITEMPOSTPAINT: 1414 /* at the point of post paint notification colors are already restored */ 1415 ok(nmcd->clrText == cafe, "got 0%x\n", nmcd->clrText); 1416 ok(nmcd->clrTextBk == c0ffee, "got 0%x\n", nmcd->clrTextBk); 1417 ok(text != cafe, "got 0%x\n", text); 1418 ok(bkgnd != c0ffee, "got 0%x\n", bkgnd); 1419 if (g_customdraw_font) 1420 ok(GetCurrentObject(nmcd->nmcd.hdc, OBJ_FONT) != g_customdraw_font, "got %p\n", 1421 GetCurrentObject(nmcd->nmcd.hdc, OBJ_FONT)); 1422 break; 1423 default: 1424 ; 1425 } 1426 break; 1427 } 1428 case NM_RCLICK: 1429 { 1430 HTREEITEM selected = (HTREEITEM)SendMessageA(((NMHDR *)lParam)->hwndFrom, 1431 TVM_GETNEXTITEM, TVGN_CARET, 0); 1432 ok(selected == hChild, "child item should still be selected\n"); 1433 break; 1434 } 1435 } 1436 } 1437 break; 1438 } 1439 1440 } 1441 1442 defwndproc_counter++; 1443 ret = DefWindowProcA(hWnd, message, wParam, lParam); 1444 defwndproc_counter--; 1445 1446 return ret; 1447 } 1448 1449 static void test_expandinvisible(void) 1450 { 1451 static CHAR nodeText[][5] = {"0", "1", "2", "3", "4"}; 1452 TVINSERTSTRUCTA ins; 1453 HTREEITEM node[5]; 1454 RECT dummyRect; 1455 BOOL nodeVisible; 1456 LRESULT ret; 1457 HWND hTree; 1458 1459 hTree = create_treeview_control(0); 1460 1461 /* The test builds the following tree and expands node 1, while node 0 is collapsed. 1462 * 1463 * 0 1464 * |- 1 1465 * | |- 2 1466 * | |- 3 1467 * |- 4 1468 * 1469 */ 1470 1471 ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT); 1472 ok(ret == TRUE, "ret\n"); 1473 ins.hParent = TVI_ROOT; 1474 ins.hInsertAfter = TVI_ROOT; 1475 U(ins).item.mask = TVIF_TEXT; 1476 U(ins).item.pszText = nodeText[0]; 1477 node[0] = TreeView_InsertItemA(hTree, &ins); 1478 ok(node[0] != NULL, "failed to set node[0]\n"); 1479 1480 ins.hInsertAfter = TVI_LAST; 1481 U(ins).item.mask = TVIF_TEXT; 1482 ins.hParent = node[0]; 1483 1484 U(ins).item.pszText = nodeText[1]; 1485 node[1] = TreeView_InsertItemA(hTree, &ins); 1486 ok(node[1] != NULL, "failed to set node[1]\n"); 1487 U(ins).item.pszText = nodeText[4]; 1488 node[4] = TreeView_InsertItemA(hTree, &ins); 1489 ok(node[4] != NULL, "failed to set node[4]\n"); 1490 1491 ins.hParent = node[1]; 1492 1493 U(ins).item.pszText = nodeText[2]; 1494 node[2] = TreeView_InsertItemA(hTree, &ins); 1495 ok(node[2] != NULL, "failed to set node[2]\n"); 1496 U(ins).item.pszText = nodeText[3]; 1497 node[3] = TreeView_InsertItemA(hTree, &ins); 1498 ok(node[3] != NULL, "failed to set node[3]\n"); 1499 1500 *(HTREEITEM *)&dummyRect = node[1]; 1501 nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect); 1502 ok(!nodeVisible, "Node 1 should not be visible.\n"); 1503 *(HTREEITEM *)&dummyRect = node[2]; 1504 nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect); 1505 ok(!nodeVisible, "Node 2 should not be visible.\n"); 1506 *(HTREEITEM *)&dummyRect = node[3]; 1507 nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect); 1508 ok(!nodeVisible, "Node 3 should not be visible.\n"); 1509 *(HTREEITEM *)&dummyRect = node[4]; 1510 nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect); 1511 ok(!nodeVisible, "Node 4 should not be visible.\n"); 1512 1513 ok(SendMessageA(hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)node[1]), "Expand of node 1 failed.\n"); 1514 1515 *(HTREEITEM *)&dummyRect = node[1]; 1516 nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect); 1517 ok(!nodeVisible, "Node 1 should not be visible.\n"); 1518 *(HTREEITEM *)&dummyRect = node[2]; 1519 nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect); 1520 ok(!nodeVisible, "Node 2 should not be visible.\n"); 1521 *(HTREEITEM *)&dummyRect = node[3]; 1522 nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect); 1523 ok(!nodeVisible, "Node 3 should not be visible.\n"); 1524 *(HTREEITEM *)&dummyRect = node[4]; 1525 nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect); 1526 ok(!nodeVisible, "Node 4 should not be visible.\n"); 1527 1528 DestroyWindow(hTree); 1529 } 1530 1531 static void test_itemedit(void) 1532 { 1533 DWORD r; 1534 HWND edit; 1535 TVITEMA item; 1536 CHAR buffA[20]; 1537 HWND hTree; 1538 1539 hTree = create_treeview_control(0); 1540 fill_tree(hTree); 1541 1542 /* try with null item */ 1543 edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, 0); 1544 ok(!IsWindow(edit), "Expected valid handle\n"); 1545 1546 /* trigger edit */ 1547 edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot); 1548 ok(IsWindow(edit), "Expected valid handle\n"); 1549 /* item shouldn't be selected automatically after TVM_EDITLABELA */ 1550 r = SendMessageA(hTree, TVM_GETITEMSTATE, (WPARAM)hRoot, TVIS_SELECTED); 1551 expect(0, r); 1552 /* try to cancel with wrong edit handle */ 1553 r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), 0); 1554 expect(0, r); 1555 ok(IsWindow(edit), "Expected edit control to be valid\n"); 1556 r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); 1557 expect(0, r); 1558 ok(!IsWindow(edit), "Expected edit control to be destroyed\n"); 1559 /* try to cancel without creating edit */ 1560 r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), 0); 1561 expect(0, r); 1562 1563 /* try to cancel with wrong (not null) handle */ 1564 edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot); 1565 ok(IsWindow(edit), "Expected valid handle\n"); 1566 r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hTree); 1567 expect(0, r); 1568 ok(IsWindow(edit), "Expected edit control to be valid\n"); 1569 r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); 1570 expect(0, r); 1571 1572 /* remove selection after starting edit */ 1573 r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); 1574 expect(TRUE, r); 1575 edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot); 1576 ok(IsWindow(edit), "Expected valid handle\n"); 1577 r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0); 1578 expect(TRUE, r); 1579 /* alter text */ 1580 strcpy(buffA, "x"); 1581 r = SendMessageA(edit, WM_SETTEXT, 0, (LPARAM)buffA); 1582 expect(TRUE, r); 1583 r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); 1584 expect(0, r); 1585 ok(!IsWindow(edit), "Expected edit control to be destroyed\n"); 1586 /* check that text is saved */ 1587 item.mask = TVIF_TEXT; 1588 item.hItem = hRoot; 1589 item.pszText = buffA; 1590 item.cchTextMax = sizeof(buffA)/sizeof(CHAR); 1591 r = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 1592 expect(TRUE, r); 1593 ok(!strcmp("x", buffA), "Expected item text to change\n"); 1594 1595 /* try A/W messages */ 1596 edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot); 1597 ok(IsWindow(edit), "Expected valid handle\n"); 1598 ok(IsWindowUnicode(edit), "got ansi window\n"); 1599 r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); 1600 expect(0, r); 1601 ok(!IsWindow(edit), "expected invalid handle\n"); 1602 1603 edit = (HWND)SendMessageA(hTree, TVM_EDITLABELW, 0, (LPARAM)hRoot); 1604 ok(IsWindow(edit), "Expected valid handle\n"); 1605 ok(IsWindowUnicode(edit), "got ansi window\n"); 1606 r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); 1607 expect(0, r); 1608 1609 /* alter text during TVM_BEGINLABELEDIT, check that it's preserved */ 1610 strcpy(buffA, "<root>"); 1611 1612 item.mask = TVIF_TEXT; 1613 item.hItem = hRoot; 1614 item.pszText = buffA; 1615 item.cchTextMax = 0; 1616 r = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item); 1617 expect(TRUE, r); 1618 1619 g_beginedit_alter_text = TRUE; 1620 edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot); 1621 ok(IsWindow(edit), "Expected valid handle\n"); 1622 g_beginedit_alter_text = FALSE; 1623 1624 GetWindowTextA(edit, buffA, sizeof(buffA)/sizeof(CHAR)); 1625 ok(!strcmp(buffA, "<edittextaltered>"), "got string %s\n", buffA); 1626 1627 DestroyWindow(hTree); 1628 } 1629 1630 static void test_treeview_classinfo(void) 1631 { 1632 WNDCLASSA cls; 1633 1634 memset(&cls, 0, sizeof(cls)); 1635 GetClassInfoA(GetModuleHandleA("comctl32.dll"), WC_TREEVIEWA, &cls); 1636 ok(cls.hbrBackground == NULL, "Expected NULL background brush, got %p\n", cls.hbrBackground); 1637 ok(cls.style == (CS_GLOBALCLASS | CS_DBLCLKS), "Expected got %x\n", cls.style); 1638 expect(0, cls.cbClsExtra); 1639 } 1640 1641 static void test_get_linecolor(void) 1642 { 1643 COLORREF clr; 1644 HWND hTree; 1645 1646 hTree = create_treeview_control(0); 1647 1648 /* newly created control has default color */ 1649 clr = SendMessageA(hTree, TVM_GETLINECOLOR, 0, 0); 1650 if (clr == 0) 1651 win_skip("TVM_GETLINECOLOR is not supported on comctl32 < 5.80\n"); 1652 else 1653 expect(CLR_DEFAULT, clr); 1654 1655 DestroyWindow(hTree); 1656 } 1657 1658 static void test_get_insertmarkcolor(void) 1659 { 1660 COLORREF clr; 1661 HWND hTree; 1662 1663 hTree = create_treeview_control(0); 1664 1665 /* newly created control has default color */ 1666 clr = SendMessageA(hTree, TVM_GETINSERTMARKCOLOR, 0, 0); 1667 if (clr == 0) 1668 win_skip("TVM_GETINSERTMARKCOLOR is not supported on comctl32 < 5.80\n"); 1669 else 1670 expect(CLR_DEFAULT, clr); 1671 1672 DestroyWindow(hTree); 1673 } 1674 1675 static void test_expandnotify(void) 1676 { 1677 HTREEITEM hitem; 1678 HWND hTree; 1679 BOOL ret; 1680 TVITEMA item; 1681 1682 hTree = create_treeview_control(0); 1683 fill_tree(hTree); 1684 1685 item.hItem = hRoot; 1686 item.mask = TVIF_STATE; 1687 1688 item.state = TVIS_EXPANDED; 1689 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 1690 expect(TRUE, ret); 1691 ok((item.state & TVIS_EXPANDED) == 0, "expected collapsed\n"); 1692 1693 /* preselect root node here */ 1694 ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); 1695 expect(TRUE, ret); 1696 1697 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1698 ret = SendMessageA(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot); 1699 expect(FALSE, ret); 1700 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "no collapse notifications", FALSE); 1701 1702 g_get_from_expand = TRUE; 1703 /* expand */ 1704 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1705 g_item_expanding.state = 0xdeadbeef; 1706 g_item_expanded.state = 0xdeadbeef; 1707 ret = SendMessageA(hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)hRoot); 1708 expect(TRUE, ret); 1709 ok(g_item_expanding.state == TVIS_SELECTED, "got state on TVN_ITEMEXPANDING 0x%08x\n", 1710 g_item_expanding.state); 1711 ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED), "got state on TVN_ITEMEXPANDED 0x%08x\n", 1712 g_item_expanded.state); 1713 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_seq, "expand notifications", FALSE); 1714 g_get_from_expand = FALSE; 1715 1716 /* check that it's expanded */ 1717 item.state = TVIS_EXPANDED; 1718 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 1719 expect(TRUE, ret); 1720 ok((item.state & TVIS_EXPANDED) == TVIS_EXPANDED, "expected expanded\n"); 1721 1722 /* collapse */ 1723 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1724 ret = SendMessageA(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot); 1725 expect(TRUE, ret); 1726 item.state = TVIS_EXPANDED; 1727 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 1728 expect(TRUE, ret); 1729 ok((item.state & TVIS_EXPANDED) == 0, "expected collapsed\n"); 1730 /* all further collapse/expand attempts won't produce any notifications, 1731 the only way is to reset with all children removed */ 1732 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "collapse after expand notifications", FALSE); 1733 1734 /* try to toggle child that doesn't have children itself */ 1735 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1736 ret = SendMessageA(hTree, TVM_EXPAND, TVE_TOGGLE, (LPARAM)hChild); 1737 expect(FALSE, ret); 1738 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "toggle node without children", FALSE); 1739 1740 DestroyWindow(hTree); 1741 1742 /* test TVM_GETITEMRECT inside TVN_ITEMEXPANDED notification */ 1743 hTree = create_treeview_control(0); 1744 fill_tree(hTree); 1745 g_get_rect_in_expand = TRUE; 1746 ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild); 1747 expect(TRUE, ret); 1748 g_get_rect_in_expand = FALSE; 1749 1750 DestroyWindow(hTree); 1751 1752 /* TVE_TOGGLE acts as any other TVM_EXPAND */ 1753 hTree = create_treeview_control(0); 1754 fill_tree(hTree); 1755 1756 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1757 ret = SendMessageA(hTree, TVM_EXPAND, TVE_TOGGLE, (LPARAM)hRoot); 1758 expect(TRUE, ret); 1759 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_seq, "toggle node (expand)", FALSE); 1760 1761 /* toggle again - no notifications */ 1762 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1763 ret = SendMessageA(hTree, TVM_EXPAND, TVE_TOGGLE, (LPARAM)hRoot); 1764 expect(TRUE, ret); 1765 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "toggle node (collapse)", FALSE); 1766 1767 DestroyWindow(hTree); 1768 1769 /* some keyboard events are also translated to expand */ 1770 hTree = create_treeview_control(0); 1771 fill_tree(hTree); 1772 1773 /* preselect root node here */ 1774 ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); 1775 expect(TRUE, ret); 1776 1777 g_get_from_expand = TRUE; 1778 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1779 ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0); 1780 expect(FALSE, ret); 1781 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_kb_seq, "expand node", FALSE); 1782 ok(g_item_expanding.state == TVIS_SELECTED, "got state on TVN_ITEMEXPANDING 0x%08x\n", 1783 g_item_expanding.state); 1784 ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED), "got state on TVN_ITEMEXPANDED 0x%08x\n", 1785 g_item_expanded.state); 1786 1787 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1788 ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0); 1789 expect(FALSE, ret); 1790 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_kb_seq, "expand node again", FALSE); 1791 ok(g_item_expanding.state == (TVIS_SELECTED|TVIS_EXPANDED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDING 0x%08x\n", 1792 g_item_expanding.state); 1793 ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDED 0x%08x\n", 1794 g_item_expanded.state); 1795 1796 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1797 ret = SendMessageA(hTree, WM_KEYDOWN, VK_SUBTRACT, 0); 1798 expect(FALSE, ret); 1799 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_kb_seq, "collapse node", FALSE); 1800 ok(g_item_expanding.state == (TVIS_SELECTED|TVIS_EXPANDED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDING 0x%08x\n", 1801 g_item_expanding.state); 1802 ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDED 0x%08x\n", 1803 g_item_expanded.state); 1804 1805 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1806 ret = SendMessageA(hTree, WM_KEYDOWN, VK_SUBTRACT, 0); 1807 expect(FALSE, ret); 1808 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_collapse_2nd_kb_seq, "collapse node again", FALSE); 1809 ok(g_item_expanding.state == (TVIS_SELECTED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDING 0x%08x\n", 1810 g_item_expanding.state); 1811 g_get_from_expand = FALSE; 1812 1813 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1814 ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0); 1815 expect(FALSE, ret); 1816 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_kb_seq, "expand node", FALSE); 1817 1818 /* go to child */ 1819 ret = SendMessageA(hTree, WM_KEYDOWN, VK_RIGHT, 0); 1820 expect(FALSE, ret); 1821 1822 /* try to expand child that doesn't have children itself */ 1823 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1824 ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0); 1825 expect(FALSE, ret); 1826 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_empty_kb_seq, "expand node with no children", FALSE); 1827 1828 /* stay on current selection and set non-zero children count */ 1829 hitem = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CARET, 0); 1830 ok(hitem != NULL, "got %p\n", hitem); 1831 1832 item.hItem = hitem; 1833 item.mask = TVIF_CHILDREN; 1834 item.cChildren = 0x80000000; 1835 1836 ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item); 1837 expect(TRUE, ret); 1838 1839 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1840 ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0); 1841 expect(FALSE, ret); 1842 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_collapse_2nd_kb_seq, "expand node with children", FALSE); 1843 1844 DestroyWindow(hTree); 1845 } 1846 1847 static void test_expandedimage(void) 1848 { 1849 TVITEMEXA item; 1850 HWND hTree; 1851 BOOL ret; 1852 1853 hTree = create_treeview_control(0); 1854 fill_tree(hTree); 1855 1856 item.mask = TVIF_EXPANDEDIMAGE; 1857 item.iExpandedImage = 1; 1858 item.hItem = hRoot; 1859 ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item); 1860 ok(ret, "got %d\n", ret); 1861 1862 item.mask = TVIF_EXPANDEDIMAGE; 1863 item.iExpandedImage = -1; 1864 item.hItem = hRoot; 1865 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 1866 ok(ret, "got %d\n", ret); 1867 1868 if (item.iExpandedImage != 1) 1869 { 1870 win_skip("TVIF_EXPANDEDIMAGE not supported\n"); 1871 DestroyWindow(hTree); 1872 return; 1873 } 1874 1875 /* test for default iExpandedImage value */ 1876 item.mask = TVIF_EXPANDEDIMAGE; 1877 item.iExpandedImage = -1; 1878 item.hItem = hChild; 1879 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 1880 ok(ret, "got %d\n", ret); 1881 ok(item.iExpandedImage == (WORD)I_IMAGENONE, "got %d\n", item.iExpandedImage); 1882 1883 DestroyWindow(hTree); 1884 } 1885 1886 static void test_TVS_SINGLEEXPAND(void) 1887 { 1888 HWND hTree; 1889 HTREEITEM alpha, bravo, charlie, delta, echo, foxtrot, golf, hotel, india, juliet; 1890 TVINSERTSTRUCTA ins; 1891 char foo[] = "foo"; 1892 char context[32]; 1893 int i; 1894 BOOL ret; 1895 1896 /* build a fairly complex tree 1897 * - TVI_ROOT 1898 * - alpha 1899 * - bravo 1900 * - charlie 1901 * - delta 1902 * - echo 1903 * - foxtrot 1904 * - golf 1905 * - hotel 1906 * - india 1907 * - juliet 1908 */ 1909 struct 1910 { 1911 HTREEITEM *handle; 1912 HTREEITEM *parent; 1913 UINT final_state; 1914 } 1915 items[] = 1916 { 1917 { &alpha, NULL, TVIS_EXPANDEDONCE }, 1918 { &bravo, &alpha, TVIS_EXPANDEDONCE }, 1919 { &charlie, &bravo, 0 }, 1920 { &delta, &alpha, TVIS_EXPANDEDONCE }, 1921 { &echo, &delta, 0 }, 1922 { &foxtrot, NULL, TVIS_EXPANDEDONCE|TVIS_EXPANDED }, 1923 { &golf, &foxtrot, TVIS_EXPANDEDONCE|TVIS_EXPANDED }, 1924 { &hotel, &golf, 0 }, 1925 { &india, &golf, TVIS_SELECTED }, 1926 { &juliet, &foxtrot, 0 } 1927 }; 1928 1929 struct 1930 { 1931 HTREEITEM *select; 1932 const struct message *sequence; 1933 } 1934 sequence_tests[] = 1935 { 1936 { &alpha, parent_singleexpand_seq0 }, 1937 { &bravo, parent_singleexpand_seq1 }, 1938 { &delta, parent_singleexpand_seq2 }, 1939 { &foxtrot, parent_singleexpand_seq3 }, 1940 { &alpha, parent_singleexpand_seq4 }, 1941 { &golf, parent_singleexpand_seq5 }, 1942 { &hotel, parent_singleexpand_seq6 }, 1943 { &india, parent_singleexpand_seq7 }, 1944 { &india, empty_seq } 1945 }; 1946 1947 hTree = create_treeview_control(0); 1948 SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_SINGLEEXPAND); 1949 /* to avoid painting related notifications */ 1950 ShowWindow(hTree, SW_HIDE); 1951 for (i = 0; i < sizeof(items)/sizeof(items[0]); i++) 1952 { 1953 ins.hParent = items[i].parent ? *items[i].parent : TVI_ROOT; 1954 ins.hInsertAfter = TVI_FIRST; 1955 U(ins).item.mask = TVIF_TEXT; 1956 U(ins).item.pszText = foo; 1957 *items[i].handle = TreeView_InsertItemA(hTree, &ins); 1958 } 1959 1960 for (i = 0; i < sizeof(sequence_tests)/sizeof(sequence_tests[0]); i++) 1961 { 1962 flush_sequences(sequences, NUM_MSG_SEQUENCES); 1963 ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)(*sequence_tests[i].select)); 1964 ok(ret, "got %d\n", ret); 1965 sprintf(context, "singleexpand notifications %d", i); 1966 ok_sequence(sequences, PARENT_SEQ_INDEX, sequence_tests[i].sequence, context, FALSE); 1967 } 1968 1969 for (i = 0; i < sizeof(items)/sizeof(items[0]); i++) 1970 { 1971 ret = SendMessageA(hTree, TVM_GETITEMSTATE, (WPARAM)(*items[i].handle), 0xFFFF); 1972 ok(ret == items[i].final_state, "singleexpand items[%d]: expected state 0x%x got 0x%x\n", 1973 i, items[i].final_state, ret); 1974 } 1975 1976 /* a workaround for NT4 that sends expand notifications when nothing is about to expand */ 1977 ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT); 1978 ok(ret, "got %d\n", ret); 1979 fill_tree(hTree); 1980 ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0); 1981 ok(ret, "got %d\n", ret); 1982 1983 DestroyWindow(hTree); 1984 } 1985 1986 static void test_WM_PAINT(void) 1987 { 1988 HWND hTree; 1989 COLORREF clr; 1990 LONG ret; 1991 RECT rc; 1992 HDC hdc; 1993 1994 hTree = create_treeview_control(0); 1995 1996 clr = SendMessageA(hTree, TVM_SETBKCOLOR, 0, RGB(255, 0, 0)); 1997 ok(clr == ~0u, "got %d, expected -1\n", clr); 1998 1999 hdc = GetDC(hMainWnd); 2000 2001 GetClientRect(hMainWnd, &rc); 2002 FillRect(hdc, &rc, GetStockObject(BLACK_BRUSH)); 2003 2004 clr = GetPixel(hdc, 1, 1); 2005 ok(clr == RGB(0, 0, 0), "got 0x%x\n", clr); 2006 2007 ret = SendMessageA(hTree, WM_PAINT, (WPARAM)hdc, 0); 2008 ok(ret == 0, "got %d\n", ret); 2009 2010 clr = GetPixel(hdc, 1, 1); 2011 ok(clr == RGB(255, 0, 0) || broken(clr == RGB(0, 0, 0)) /* win98 */, 2012 "got 0x%x\n", clr); 2013 2014 ReleaseDC(hMainWnd, hdc); 2015 2016 DestroyWindow(hTree); 2017 } 2018 2019 static void test_delete_items(void) 2020 { 2021 const struct message *msg; 2022 HWND hTree; 2023 HTREEITEM hItem1, hItem2; 2024 TVINSERTSTRUCTA ins; 2025 INT ret; 2026 2027 static CHAR item1[] = "Item 1"; 2028 static CHAR item2[] = "Item 2"; 2029 2030 hTree = create_treeview_control(0); 2031 fill_tree(hTree); 2032 2033 /* check delete order */ 2034 flush_sequences(item_sequence, 1); 2035 ret = SendMessageA(hTree, TVM_DELETEITEM, 0, 0); 2036 ok(ret == TRUE, "got %d\n", ret); 2037 2038 msg = item_sequence[0]->sequence; 2039 ok(item_sequence[0]->count == 2, "expected 2 items, got %d\n", item_sequence[0]->count); 2040 2041 if (item_sequence[0]->count == 2) 2042 { 2043 ok(msg[0].lParam == (LPARAM)hChild, "expected %p, got 0x%lx\n", hChild, msg[0].lParam); 2044 ok(msg[1].lParam == (LPARAM)hRoot, "expected %p, got 0x%lx\n", hRoot, msg[1].lParam); 2045 } 2046 2047 ret = SendMessageA(hTree, TVM_GETCOUNT, 0, 0); 2048 ok(ret == 0, "got %d\n", ret); 2049 2050 DestroyWindow(hTree); 2051 2052 /* Regression test for a crash when deleting the first visible item while bRedraw == false. */ 2053 hTree = create_treeview_control(0); 2054 2055 ret = SendMessageA(hTree, WM_SETREDRAW, FALSE, 0); 2056 ok(ret == 0, "got %d\n", ret); 2057 2058 ins.hParent = TVI_ROOT; 2059 ins.hInsertAfter = TVI_ROOT; 2060 U(ins).item.mask = TVIF_TEXT; 2061 U(ins).item.pszText = item1; 2062 hItem1 = TreeView_InsertItemA(hTree, &ins); 2063 ok(hItem1 != NULL, "InsertItem failed\n"); 2064 2065 ins.hParent = TVI_ROOT; 2066 ins.hInsertAfter = hItem1; 2067 U(ins).item.mask = TVIF_TEXT; 2068 U(ins).item.pszText = item2; 2069 hItem2 = TreeView_InsertItemA(hTree, &ins); 2070 ok(hItem2 != NULL, "InsertItem failed\n"); 2071 2072 ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hItem1); 2073 ok(ret == TRUE, "got %d\n", ret); 2074 2075 ret = SendMessageA(hTree, WM_SETREDRAW, TRUE, 0); 2076 ok(ret == 0, "got %d\n", ret); 2077 2078 DestroyWindow(hTree); 2079 } 2080 2081 static void test_cchildren(void) 2082 { 2083 HWND hTree; 2084 INT ret; 2085 TVITEMA item; 2086 2087 hTree = create_treeview_control(0); 2088 fill_tree(hTree); 2089 2090 ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild); 2091 expect(TRUE, ret); 2092 2093 /* check cChildren - automatic mode */ 2094 item.hItem = hRoot; 2095 item.mask = TVIF_CHILDREN; 2096 2097 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 2098 expect(TRUE, ret); 2099 expect(0, item.cChildren); 2100 2101 DestroyWindow(hTree); 2102 2103 /* start over */ 2104 hTree = create_treeview_control(0); 2105 fill_tree(hTree); 2106 2107 /* turn off automatic mode by setting cChildren explicitly */ 2108 item.hItem = hRoot; 2109 item.mask = TVIF_CHILDREN; 2110 2111 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 2112 expect(TRUE, ret); 2113 expect(1, item.cChildren); 2114 2115 ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item); 2116 expect(TRUE, ret); 2117 2118 ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild); 2119 expect(TRUE, ret); 2120 2121 /* check cChildren */ 2122 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 2123 expect(TRUE, ret); 2124 todo_wine 2125 expect(1, item.cChildren); 2126 2127 DestroyWindow(hTree); 2128 } 2129 2130 struct _ITEM_DATA 2131 { 2132 HTREEITEM parent; /* for root value of parent field is unidetified */ 2133 HTREEITEM nextsibling; 2134 HTREEITEM firstchild; 2135 }; 2136 2137 static void _check_item(HTREEITEM item, HTREEITEM parent, HTREEITEM nextsibling, HTREEITEM firstchild, int line) 2138 { 2139 struct _ITEM_DATA *data = (struct _ITEM_DATA*)item; 2140 2141 ok_(__FILE__, line)(data->parent == parent, "parent %p, got %p\n", parent, data->parent); 2142 ok_(__FILE__, line)(data->nextsibling == nextsibling, "sibling %p, got %p\n", nextsibling, data->nextsibling); 2143 ok_(__FILE__, line)(data->firstchild == firstchild, "firstchild %p, got %p\n", firstchild, data->firstchild); 2144 } 2145 2146 #define check_item(a, b, c, d) _check_item(a, b, c, d, __LINE__) 2147 2148 static void test_htreeitem_layout(void) 2149 { 2150 TVINSERTSTRUCTA ins; 2151 HTREEITEM item1, item2; 2152 HWND hTree; 2153 2154 hTree = create_treeview_control(0); 2155 fill_tree(hTree); 2156 2157 /* root has some special pointer in parent field */ 2158 check_item(hRoot, ((struct _ITEM_DATA*)hRoot)->parent, 0, hChild); 2159 check_item(hChild, hRoot, 0, 0); 2160 2161 ins.hParent = hChild; 2162 ins.hInsertAfter = TVI_FIRST; 2163 U(ins).item.mask = 0; 2164 item1 = TreeView_InsertItemA(hTree, &ins); 2165 2166 check_item(item1, hChild, 0, 0); 2167 2168 ins.hParent = hRoot; 2169 ins.hInsertAfter = TVI_FIRST; 2170 U(ins).item.mask = 0; 2171 item2 = TreeView_InsertItemA(hTree, &ins); 2172 2173 check_item(item2, hRoot, hChild, 0); 2174 2175 SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild); 2176 2177 /* without children now */ 2178 check_item(hRoot, ((struct _ITEM_DATA*)hRoot)->parent, 0, item2); 2179 2180 DestroyWindow(hTree); 2181 } 2182 2183 static void test_TVS_CHECKBOXES(void) 2184 { 2185 HIMAGELIST himl, himl2; 2186 HWND hTree, hTree2; 2187 TVITEMA item; 2188 DWORD ret; 2189 MSG msg; 2190 2191 hTree = create_treeview_control(0); 2192 fill_tree(hTree); 2193 2194 himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); 2195 ok(himl == NULL, "got %p\n", himl); 2196 2197 item.hItem = hRoot; 2198 item.mask = TVIF_STATE; 2199 item.state = INDEXTOSTATEIMAGEMASK(1); 2200 item.stateMask = TVIS_STATEIMAGEMASK; 2201 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 2202 expect(TRUE, ret); 2203 ok(item.state == 0, "got 0x%x\n", item.state); 2204 2205 /* set some index for a child */ 2206 item.hItem = hChild; 2207 item.mask = TVIF_STATE; 2208 item.state = INDEXTOSTATEIMAGEMASK(4); 2209 item.stateMask = TVIS_STATEIMAGEMASK; 2210 ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item); 2211 expect(TRUE, ret); 2212 2213 /* enabling check boxes set all items to 1 state image index */ 2214 SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_CHECKBOXES); 2215 himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); 2216 ok(himl != NULL, "got %p\n", himl); 2217 2218 himl2 = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); 2219 ok(himl2 != NULL, "got %p\n", himl2); 2220 ok(himl2 == himl, "got %p, expected %p\n", himl2, himl); 2221 2222 item.hItem = hRoot; 2223 item.mask = TVIF_STATE; 2224 item.state = 0; 2225 item.stateMask = TVIS_STATEIMAGEMASK; 2226 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 2227 expect(TRUE, ret); 2228 ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state); 2229 2230 item.hItem = hChild; 2231 item.mask = TVIF_STATE; 2232 item.state = 0; 2233 item.stateMask = TVIS_STATEIMAGEMASK; 2234 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 2235 expect(TRUE, ret); 2236 ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state); 2237 2238 /* create another control and check its checkbox list */ 2239 hTree2 = create_treeview_control(0); 2240 fill_tree(hTree2); 2241 2242 /* set some index for a child */ 2243 item.hItem = hChild; 2244 item.mask = TVIF_STATE; 2245 item.state = INDEXTOSTATEIMAGEMASK(4); 2246 item.stateMask = TVIS_STATEIMAGEMASK; 2247 ret = SendMessageA(hTree2, TVM_SETITEMA, 0, (LPARAM)&item); 2248 expect(TRUE, ret); 2249 2250 /* enabling check boxes set all items to 1 state image index */ 2251 SetWindowLongA(hTree2, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_CHECKBOXES); 2252 himl2 = (HIMAGELIST)SendMessageA(hTree2, TVM_GETIMAGELIST, TVSIL_STATE, 0); 2253 ok(himl2 != NULL, "got %p\n", himl2); 2254 ok(himl != himl2, "got %p, expected %p\n", himl2, himl); 2255 2256 DestroyWindow(hTree2); 2257 DestroyWindow(hTree); 2258 2259 /* the same, but initially created with TVS_CHECKBOXES */ 2260 hTree = create_treeview_control(TVS_CHECKBOXES); 2261 fill_tree(hTree); 2262 himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); 2263 ok(himl == NULL, "got %p\n", himl); 2264 2265 item.hItem = hRoot; 2266 item.mask = TVIF_STATE; 2267 item.state = 0; 2268 item.stateMask = TVIS_STATEIMAGEMASK; 2269 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 2270 expect(TRUE, ret); 2271 ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state); 2272 2273 item.hItem = hChild; 2274 item.mask = TVIF_STATE; 2275 item.state = 0; 2276 item.stateMask = TVIS_STATEIMAGEMASK; 2277 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 2278 expect(TRUE, ret); 2279 ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state); 2280 2281 item.hItem = hChild; 2282 item.mask = TVIF_STATE; 2283 item.state = INDEXTOSTATEIMAGEMASK(2); 2284 item.stateMask = TVIS_STATEIMAGEMASK; 2285 ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item); 2286 expect(TRUE, ret); 2287 2288 item.hItem = hChild; 2289 item.mask = TVIF_STATE; 2290 item.state = 0; 2291 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 2292 expect(TRUE, ret); 2293 ok(item.state == INDEXTOSTATEIMAGEMASK(2), "got 0x%x\n", item.state); 2294 2295 while(GetMessageA(&msg, 0, 0, 0)) 2296 { 2297 TranslateMessage(&msg); 2298 DispatchMessageA(&msg); 2299 2300 if((msg.hwnd == hTree) && (msg.message == WM_PAINT)) 2301 break; 2302 } 2303 2304 item.hItem = hChild; 2305 item.mask = TVIF_STATE; 2306 item.state = 0; 2307 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 2308 expect(TRUE, ret); 2309 ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state); 2310 2311 himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); 2312 ok(himl != NULL, "got %p\n", himl); 2313 2314 DestroyWindow(hTree); 2315 2316 /* check what happens if TVSIL_STATE image list is removed */ 2317 hTree = create_treeview_control(0); 2318 fill_tree(hTree); 2319 himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); 2320 ok(himl == NULL, "got %p\n", himl); 2321 2322 SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_CHECKBOXES); 2323 himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); 2324 ok(himl != NULL, "got %p\n", himl); 2325 2326 himl2 = (HIMAGELIST)SendMessageA(hTree, TVM_SETIMAGELIST, TVSIL_STATE, 0); 2327 ok(himl2 == himl, "got %p\n", himl2); 2328 2329 himl2 = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); 2330 ok(himl2 == NULL, "got %p\n", himl2); 2331 2332 item.hItem = hChild; 2333 item.mask = TVIF_STATE; 2334 item.state = INDEXTOSTATEIMAGEMASK(2); 2335 item.stateMask = TVIS_STATEIMAGEMASK; 2336 ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item); 2337 expect(TRUE, ret); 2338 2339 item.hItem = hChild; 2340 item.mask = TVIF_STATE; 2341 item.state = 0; 2342 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 2343 expect(TRUE, ret); 2344 ok(item.state == INDEXTOSTATEIMAGEMASK(2), "got 0x%x\n", item.state); 2345 2346 while(GetMessageA(&msg, 0, 0, 0)) 2347 { 2348 TranslateMessage(&msg); 2349 DispatchMessageA(&msg); 2350 2351 if((msg.hwnd == hTree) && (msg.message == WM_PAINT)) 2352 break; 2353 } 2354 2355 item.hItem = hChild; 2356 item.mask = TVIF_STATE; 2357 item.state = 0; 2358 ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); 2359 expect(TRUE, ret); 2360 ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state); 2361 2362 himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); 2363 ok(himl != NULL, "got %p\n", himl); 2364 2365 DestroyWindow(hTree); 2366 } 2367 2368 static void test_TVM_GETNEXTITEM(void) 2369 { 2370 HTREEITEM item; 2371 HWND hTree; 2372 2373 hTree = create_treeview_control(0); 2374 fill_tree(hTree); 2375 2376 item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_ROOT, 0); 2377 ok(item == hRoot, "got %p, expected %p\n", item, hRoot); 2378 2379 item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_ROOT, (LPARAM)TVI_ROOT); 2380 ok(item == hRoot, "got %p, expected %p\n", item, hRoot); 2381 2382 item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_ROOT, (LPARAM)hRoot); 2383 ok(item == hRoot, "got %p, expected %p\n", item, hRoot); 2384 2385 item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_ROOT, (LPARAM)hChild); 2386 ok(item == hRoot, "got %p, expected %p\n", item, hRoot); 2387 2388 item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CHILD, 0); 2389 ok(item == hRoot, "got %p, expected %p\n", item, hRoot); 2390 2391 item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hRoot); 2392 ok(item == hChild, "got %p, expected %p\n", item, hChild); 2393 2394 item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)TVI_ROOT); 2395 ok(item == hRoot, "got %p, expected %p\n", item, hRoot); 2396 2397 item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_PARENT, 0); 2398 ok(item == NULL, "got %p\n", item); 2399 2400 item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hChild); 2401 ok(item == hRoot, "got %p, expected %p\n", item, hRoot); 2402 2403 DestroyWindow(hTree); 2404 } 2405 2406 static void test_TVM_HITTEST(void) 2407 { 2408 HWND hTree; 2409 LRESULT ret; 2410 RECT rc; 2411 TVHITTESTINFO ht; 2412 2413 hTree = create_treeview_control(0); 2414 fill_tree(hTree); 2415 2416 *(HTREEITEM*)&rc = hRoot; 2417 ret = SendMessageA(hTree, TVM_GETITEMRECT, TRUE, (LPARAM)&rc); 2418 expect(TRUE, (BOOL)ret); 2419 2420 ht.pt.x = rc.left-1; 2421 ht.pt.y = rc.top; 2422 2423 ret = SendMessageA(hTree, TVM_HITTEST, 0, (LPARAM)&ht); 2424 ok((HTREEITEM)ret == hRoot, "got %p, expected %p\n", (HTREEITEM)ret, hRoot); 2425 ok(ht.hItem == hRoot, "got %p, expected %p\n", ht.hItem, hRoot); 2426 ok(ht.flags == TVHT_ONITEMBUTTON, "got %d, expected %d\n", ht.flags, TVHT_ONITEMBUTTON); 2427 2428 ret = SendMessageA(hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)hRoot); 2429 expect(TRUE, (BOOL)ret); 2430 2431 *(HTREEITEM*)&rc = hChild; 2432 ret = SendMessageA(hTree, TVM_GETITEMRECT, TRUE, (LPARAM)&rc); 2433 expect(TRUE, (BOOL)ret); 2434 2435 ht.pt.x = rc.left-1; 2436 ht.pt.y = rc.top; 2437 2438 ret = SendMessageA(hTree, TVM_HITTEST, 0, (LPARAM)&ht); 2439 ok((HTREEITEM)ret == hChild, "got %p, expected %p\n", (HTREEITEM)ret, hChild); 2440 ok(ht.hItem == hChild, "got %p, expected %p\n", ht.hItem, hChild); 2441 /* Wine returns item button here, but this item has no button */ 2442 todo_wine ok(ht.flags == TVHT_ONITEMINDENT, "got %d, expected %d\n", ht.flags, TVHT_ONITEMINDENT); 2443 2444 DestroyWindow(hTree); 2445 } 2446 2447 static void test_WM_GETDLGCODE(void) 2448 { 2449 DWORD code; 2450 HWND hTree; 2451 2452 hTree = create_treeview_control(0); 2453 2454 code = SendMessageA(hTree, WM_GETDLGCODE, VK_TAB, 0); 2455 ok(code == (DLGC_WANTCHARS | DLGC_WANTARROWS), "0x%08x\n", code); 2456 2457 DestroyWindow(hTree); 2458 } 2459 2460 static void test_customdraw(void) 2461 { 2462 LOGFONTA lf; 2463 HWND hwnd; 2464 2465 hwnd = create_treeview_control(0); 2466 fill_tree(hwnd); 2467 SendMessageA(hwnd, TVM_EXPAND, TVE_EXPAND, (WPARAM)hRoot); 2468 2469 /* create additional font, custom draw handler will select it */ 2470 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0); 2471 lf.lfHeight *= 2; 2472 g_customdraw_font = CreateFontIndirectA(&lf); 2473 flush_sequences(sequences, NUM_MSG_SEQUENCES); 2474 InvalidateRect(hwnd, NULL, TRUE); 2475 UpdateWindow(hwnd); 2476 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_cd_seq, "custom draw notifications", FALSE); 2477 DeleteObject(g_customdraw_font); 2478 g_customdraw_font = NULL; 2479 2480 DestroyWindow(hwnd); 2481 } 2482 2483 static void test_WM_KEYDOWN(void) 2484 { 2485 static const char *rootA = "root"; 2486 TVINSERTSTRUCTA ins; 2487 HTREEITEM hRoot; 2488 HWND hwnd; 2489 2490 hwnd = create_treeview_control(0); 2491 2492 ins.hParent = TVI_ROOT; 2493 ins.hInsertAfter = TVI_ROOT; 2494 U(ins).item.mask = TVIF_TEXT; 2495 U(ins).item.pszText = (char*)rootA; 2496 hRoot = TreeView_InsertItemA(hwnd, &ins); 2497 ok(hRoot != NULL, "got %p\n", hRoot); 2498 2499 flush_sequences(sequences, NUM_MSG_SEQUENCES); 2500 SendMessageA(hwnd, WM_KEYDOWN, VK_RETURN, 0); 2501 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_vk_return_seq, "WM_KEYDOWN/VK_RETURN parent notification", TRUE); 2502 2503 DestroyWindow(hwnd); 2504 } 2505 2506 static void test_TVS_FULLROWSELECT(void) 2507 { 2508 DWORD style; 2509 HWND hwnd; 2510 2511 /* try to create both with TVS_HASLINES and TVS_FULLROWSELECT */ 2512 hwnd = create_treeview_control(TVS_FULLROWSELECT); 2513 2514 style = GetWindowLongA(hwnd, GWL_STYLE); 2515 ok((style & (TVS_FULLROWSELECT | TVS_HASLINES)) == (TVS_FULLROWSELECT | TVS_HASLINES), "got style 0x%08x\n", style); 2516 2517 DestroyWindow(hwnd); 2518 2519 /* create just with TVS_HASLINES, try to enable TVS_FULLROWSELECT later */ 2520 hwnd = create_treeview_control(0); 2521 2522 style = GetWindowLongA(hwnd, GWL_STYLE); 2523 SetWindowLongA(hwnd, GWL_STYLE, style | TVS_FULLROWSELECT); 2524 style = GetWindowLongA(hwnd, GWL_STYLE); 2525 ok(style & TVS_FULLROWSELECT, "got style 0x%08x\n", style); 2526 2527 DestroyWindow(hwnd); 2528 } 2529 2530 static void get_item_names_string(HWND hwnd, HTREEITEM item, char *str) 2531 { 2532 TVITEMA tvitem = { 0 }; 2533 HTREEITEM child; 2534 char name[16]; 2535 2536 if (!item) 2537 { 2538 item = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_ROOT, 0); 2539 str[0] = 0; 2540 } 2541 2542 child = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)item); 2543 2544 tvitem.mask = TVIF_TEXT; 2545 tvitem.hItem = item; 2546 tvitem.pszText = name; 2547 tvitem.cchTextMax = sizeof(name); 2548 SendMessageA(hwnd, TVM_GETITEMA, 0, (LPARAM)&tvitem); 2549 strcat(str, tvitem.pszText); 2550 2551 while (child != NULL) 2552 { 2553 get_item_names_string(hwnd, child, str); 2554 child = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)child); 2555 } 2556 } 2557 2558 static void fill_treeview_sort_test(HWND hwnd) 2559 { 2560 static const char *itemnames[] = 2561 { 2562 "root", "Wasp", "Caribou", "Vacuum", 2563 "Ocelot", "Newspaper", "Litter bin" 2564 }; 2565 2566 HTREEITEM root, children[2]; 2567 TVINSERTSTRUCTA ins; 2568 unsigned i = 0; 2569 2570 SendMessageA(hwnd, TVM_DELETEITEM, 0, 0); 2571 2572 /* root, two children, with two children each */ 2573 ins.hParent = TVI_ROOT; 2574 ins.hInsertAfter = TVI_ROOT; 2575 U(ins).item.mask = TVIF_TEXT; 2576 U(ins).item.pszText = (char *)itemnames[i++]; 2577 root = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins); 2578 2579 ins.hParent = root; 2580 ins.hInsertAfter = TVI_LAST; 2581 U(ins).item.mask = TVIF_TEXT; 2582 U(ins).item.pszText = (char *)itemnames[i++]; 2583 children[0] = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins); 2584 2585 U(ins).item.pszText = (char *)itemnames[i++]; 2586 children[1] = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins); 2587 2588 ins.hParent = children[0]; 2589 U(ins).item.pszText = (char *)itemnames[i++]; 2590 SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins); 2591 2592 U(ins).item.pszText = (char *)itemnames[i++]; 2593 SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins); 2594 2595 ins.hParent = children[1]; 2596 U(ins).item.pszText = (char *)itemnames[i++]; 2597 SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins); 2598 2599 U(ins).item.pszText = (char *)itemnames[i++]; 2600 SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins); 2601 } 2602 2603 static void test_TVM_SORTCHILDREN(void) 2604 { 2605 static const char *initial_order = "rootWaspVacuumOcelotCaribouNewspaperLitter bin"; 2606 static const char *sorted_order = "rootCaribouNewspaperLitter binWaspVacuumOcelot"; 2607 TVINSERTSTRUCTA ins; 2608 char buff[256]; 2609 HTREEITEM root; 2610 HWND hwnd; 2611 BOOL ret; 2612 2613 hwnd = create_treeview_control(0); 2614 2615 /* call on empty tree */ 2616 ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, 0); 2617 ok(!ret, "Unexpected ret value %d\n", ret); 2618 2619 ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, (LPARAM)TVI_ROOT); 2620 ok(!ret, "Unexpected ret value %d\n", ret); 2621 2622 /* add only root, sort from it */ 2623 ins.hParent = TVI_ROOT; 2624 ins.hInsertAfter = TVI_ROOT; 2625 U(ins).item.mask = TVIF_TEXT; 2626 U(ins).item.pszText = (char *)"root"; 2627 root = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins); 2628 ok(root != NULL, "Expected root node\n"); 2629 2630 ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, (LPARAM)root); 2631 ok(!ret, "Unexpected ret value %d\n", ret); 2632 2633 ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, (LPARAM)root); 2634 ok(!ret, "Unexpected ret value %d\n", ret); 2635 2636 /* root, two children, with two children each */ 2637 fill_treeview_sort_test(hwnd); 2638 get_item_names_string(hwnd, NULL, buff); 2639 ok(!strcmp(buff, initial_order), "Wrong initial order %s, expected %s\n", buff, initial_order); 2640 2641 /* with NULL item nothing is sorted */ 2642 fill_treeview_sort_test(hwnd); 2643 ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, 0); 2644 todo_wine 2645 ok(ret, "Unexpected ret value %d\n", ret); 2646 get_item_names_string(hwnd, NULL, buff); 2647 ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, initial_order); 2648 2649 /* TVI_ROOT as item */ 2650 fill_treeview_sort_test(hwnd); 2651 ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, (LPARAM)TVI_ROOT); 2652 todo_wine 2653 ok(ret, "Unexpected ret value %d\n", ret); 2654 get_item_names_string(hwnd, NULL, buff); 2655 ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, initial_order); 2656 2657 /* zero WPARAM, item is specified */ 2658 fill_treeview_sort_test(hwnd); 2659 root = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_ROOT, 0); 2660 ok(root != NULL, "Failed to get root item\n"); 2661 ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, (LPARAM)root); 2662 ok(ret, "Unexpected ret value %d\n", ret); 2663 get_item_names_string(hwnd, NULL, buff); 2664 ok(!strcmp(buff, sorted_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order); 2665 2666 /* non-zero WPARAM, NULL item */ 2667 fill_treeview_sort_test(hwnd); 2668 ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, 0); 2669 todo_wine 2670 ok(ret, "Unexpected ret value %d\n", ret); 2671 get_item_names_string(hwnd, NULL, buff); 2672 ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order); 2673 2674 /* TVI_ROOT as item */ 2675 fill_treeview_sort_test(hwnd); 2676 ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, (LPARAM)TVI_ROOT); 2677 todo_wine 2678 ok(ret, "Unexpected ret value %d\n", ret); 2679 get_item_names_string(hwnd, NULL, buff); 2680 ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order); 2681 2682 /* non-zero WPARAM, item is specified */ 2683 fill_treeview_sort_test(hwnd); 2684 root = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_ROOT, 0); 2685 ok(root != NULL, "Failed to get root item\n"); 2686 ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, (LPARAM)root); 2687 ok(ret, "Unexpected ret value %d\n", ret); 2688 get_item_names_string(hwnd, NULL, buff); 2689 ok(!strcmp(buff, sorted_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order); 2690 2691 /* case insensitive comparison */ 2692 SendMessageA(hwnd, TVM_DELETEITEM, 0, 0); 2693 2694 ins.hParent = TVI_ROOT; 2695 ins.hInsertAfter = TVI_ROOT; 2696 U(ins).item.mask = TVIF_TEXT; 2697 U(ins).item.pszText = (char *)"root"; 2698 root = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins); 2699 ok(root != NULL, "Expected root node\n"); 2700 2701 ins.hParent = root; 2702 ins.hInsertAfter = TVI_LAST; 2703 U(ins).item.pszText = (char *)"I1"; 2704 SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins); 2705 2706 ins.hParent = root; 2707 ins.hInsertAfter = TVI_LAST; 2708 U(ins).item.pszText = (char *)"i1"; 2709 SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins); 2710 2711 ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, (LPARAM)root); 2712 ok(ret, "Unexpected ret value %d\n", ret); 2713 get_item_names_string(hwnd, NULL, buff); 2714 ok(!strcmp(buff, "rootI1i1"), "Wrong sorted order %s\n", buff); 2715 2716 DestroyWindow(hwnd); 2717 } 2718 2719 static void test_right_click(void) 2720 { 2721 HWND hTree; 2722 HTREEITEM selected; 2723 RECT rc; 2724 LRESULT result; 2725 POINT pt; 2726 2727 #ifdef __REACTOS__ 2728 if (!winetest_interactive) 2729 { 2730 skip("test_right_click() (set WINETEST_INTERACTIVE=1), until CORE-14975 is fixed upstream and WINESYNC\n"); 2731 return; 2732 } 2733 #endif 2734 2735 hTree = create_treeview_control(0); 2736 fill_tree(hTree); 2737 2738 SendMessageA(hTree, TVM_ENSUREVISIBLE, 0, (LPARAM)hChild); 2739 SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild); 2740 selected = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CARET, 0); 2741 ok(selected == hChild, "child item not selected\n"); 2742 2743 *(HTREEITEM *)&rc = hRoot; 2744 result = SendMessageA(hTree, TVM_GETITEMRECT, TRUE, (LPARAM)&rc); 2745 ok(result, "TVM_GETITEMRECT failed\n"); 2746 2747 flush_events(); 2748 2749 pt.x = (rc.left + rc.right) / 2; 2750 pt.y = (rc.top + rc.bottom) / 2; 2751 ClientToScreen(hMainWnd, &pt); 2752 2753 flush_events(); 2754 flush_sequences(sequences, NUM_MSG_SEQUENCES); 2755 2756 PostMessageA(hTree, WM_RBUTTONDOWN, MK_RBUTTON, MAKELPARAM(pt.x, pt.y)); 2757 PostMessageA(hTree, WM_RBUTTONUP, 0, MAKELPARAM(pt.x, pt.y)); 2758 2759 flush_events(); 2760 2761 ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_right_click_seq, "right click sequence", FALSE); 2762 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_right_click_seq, "parent right click sequence", FALSE); 2763 2764 selected = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CARET, 0); 2765 ok(selected == hChild, "child item should still be selected\n"); 2766 2767 DestroyWindow(hTree); 2768 } 2769 2770 static void init_functions(void) 2771 { 2772 HMODULE hComCtl32 = LoadLibraryA("comctl32.dll"); 2773 2774 #define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f); 2775 X(InitCommonControlsEx); 2776 #undef X 2777 } 2778 2779 START_TEST(treeview) 2780 { 2781 INITCOMMONCONTROLSEX iccex; 2782 ULONG_PTR ctx_cookie; 2783 HANDLE hCtx; 2784 WNDCLASSA wc; 2785 2786 init_functions(); 2787 2788 iccex.dwSize = sizeof(iccex); 2789 iccex.dwICC = ICC_TREEVIEW_CLASSES; 2790 pInitCommonControlsEx(&iccex); 2791 2792 init_msg_sequences(sequences, NUM_MSG_SEQUENCES); 2793 init_msg_sequences(item_sequence, 1); 2794 2795 wc.style = CS_HREDRAW | CS_VREDRAW; 2796 wc.cbClsExtra = 0; 2797 wc.cbWndExtra = 0; 2798 wc.hInstance = GetModuleHandleA(NULL); 2799 wc.hIcon = NULL; 2800 wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_IBEAM); 2801 wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); 2802 wc.lpszMenuName = NULL; 2803 wc.lpszClassName = "MyTestWnd"; 2804 wc.lpfnWndProc = parent_wnd_proc; 2805 RegisterClassA(&wc); 2806 2807 hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, 2808 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105, NULL, NULL, GetModuleHandleA(NULL), 0); 2809 2810 ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n"); 2811 if (!hMainWnd) return; 2812 2813 test_fillroot(); 2814 test_select(); 2815 test_getitemtext(); 2816 test_focus(); 2817 test_get_set_bkcolor(); 2818 test_get_set_imagelist(); 2819 test_get_set_indent(); 2820 test_get_set_insertmark(); 2821 test_get_set_item(); 2822 test_get_set_itemheight(); 2823 test_get_set_scrolltime(); 2824 test_get_set_textcolor(); 2825 test_get_linecolor(); 2826 test_get_insertmarkcolor(); 2827 test_get_set_tooltips(); 2828 test_get_set_unicodeformat(); 2829 test_callback(); 2830 test_expandinvisible(); 2831 test_itemedit(); 2832 test_treeview_classinfo(); 2833 test_expandnotify(); 2834 test_TVS_SINGLEEXPAND(); 2835 test_WM_PAINT(); 2836 test_delete_items(); 2837 test_cchildren(); 2838 test_htreeitem_layout(); 2839 test_TVS_CHECKBOXES(); 2840 test_TVM_GETNEXTITEM(); 2841 test_TVM_HITTEST(); 2842 test_WM_GETDLGCODE(); 2843 test_customdraw(); 2844 test_WM_KEYDOWN(); 2845 test_TVS_FULLROWSELECT(); 2846 test_TVM_SORTCHILDREN(); 2847 test_right_click(); 2848 2849 if (!load_v6_module(&ctx_cookie, &hCtx)) 2850 { 2851 DestroyWindow(hMainWnd); 2852 return; 2853 } 2854 2855 /* comctl32 version 6 tests start here */ 2856 g_v6 = TRUE; 2857 2858 test_fillroot(); 2859 test_getitemtext(); 2860 test_get_set_insertmark(); 2861 test_get_set_item(); 2862 test_get_set_scrolltime(); 2863 test_get_set_textcolor(); 2864 test_get_linecolor(); 2865 test_get_insertmarkcolor(); 2866 test_expandedimage(); 2867 test_get_set_tooltips(); 2868 test_get_set_unicodeformat(); 2869 test_expandinvisible(); 2870 test_itemedit(); 2871 test_treeview_classinfo(); 2872 test_delete_items(); 2873 test_cchildren(); 2874 test_htreeitem_layout(); 2875 test_TVM_GETNEXTITEM(); 2876 test_TVM_HITTEST(); 2877 test_WM_GETDLGCODE(); 2878 test_customdraw(); 2879 test_WM_KEYDOWN(); 2880 test_TVS_FULLROWSELECT(); 2881 test_TVM_SORTCHILDREN(); 2882 2883 unload_v6_module(ctx_cookie, hCtx); 2884 } 2885