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