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