1 /* Unit tests for treeview.
3 * Copyright 2005 Krzysztof Foltman
4 * Copyright 2007 Christopher James Peterson
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/commctrl.h"
32 #include "wine/test.h"
36 static const char *TEST_CALLBACK_TEXT
= "callback_text";
38 static TVITEMA g_item_expanding
, g_item_expanded
;
39 static BOOL g_get_from_expand
;
40 static BOOL g_get_rect_in_expand
;
41 static BOOL g_disp_A_to_W
;
42 static BOOL g_disp_set_stateimage
;
43 static BOOL g_beginedit_alter_text
;
44 static HFONT g_customdraw_font
;
46 #define NUM_MSG_SEQUENCES 3
47 #define TREEVIEW_SEQ_INDEX 0
48 #define PARENT_SEQ_INDEX 1
49 #define PARENT_CD_SEQ_INDEX 2
51 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
53 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCES
];
54 static struct msg_sequence
*item_sequence
[1];
56 static const struct message FillRootSeq
[] = {
57 { TVM_INSERTITEMA
, sent
},
58 { TVM_INSERTITEMA
, sent
},
62 static const struct message rootnone_select_seq
[] = {
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 { TVM_SELECTITEM
, sent
|wparam
, 9 },
72 static const struct message rootchild_select_seq
[] = {
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 { TVM_SELECTITEM
, sent
|wparam
, 9 },
82 static const struct message getitemtext_seq
[] = {
83 { TVM_INSERTITEMA
, sent
},
84 { TVM_GETITEMA
, sent
},
85 { TVM_DELETEITEM
, sent
},
89 static const struct message focus_seq
[] = {
90 { TVM_INSERTITEMA
, sent
},
91 { TVM_INSERTITEMA
, sent
},
92 { TVM_SELECTITEM
, sent
|wparam
, 9 },
93 /* The following end up out of order in wine */
94 { WM_WINDOWPOSCHANGING
, sent
|defwinproc
},
95 { WM_NCCALCSIZE
, sent
|wparam
|defwinproc
, TRUE
},
96 { WM_WINDOWPOSCHANGED
, sent
|defwinproc
},
97 { WM_SIZE
, sent
|defwinproc
},
98 { WM_WINDOWPOSCHANGING
, sent
|defwinproc
|optional
},
99 { WM_NCCALCSIZE
, sent
|wparam
|defwinproc
|optional
, TRUE
},
100 { WM_WINDOWPOSCHANGED
, sent
|defwinproc
|optional
},
101 { WM_SIZE
, sent
|defwinproc
|optional
},
102 { WM_PAINT
, sent
|defwinproc
},
103 { WM_NCPAINT
, sent
|wparam
|defwinproc
, 1 },
104 { WM_ERASEBKGND
, sent
|defwinproc
},
105 { TVM_EDITLABELA
, sent
},
106 { WM_COMMAND
, sent
|wparam
|defwinproc
, MAKEWPARAM(0, EN_UPDATE
) },
107 { WM_COMMAND
, sent
|wparam
|defwinproc
, MAKEWPARAM(0, EN_CHANGE
) },
108 { WM_PARENTNOTIFY
, sent
|wparam
|defwinproc
, MAKEWPARAM(WM_CREATE
, 0) },
109 { WM_KILLFOCUS
, sent
|defwinproc
},
110 { WM_PAINT
, sent
|defwinproc
},
111 { WM_IME_SETCONTEXT
, sent
|defwinproc
|optional
},
112 { WM_COMMAND
, sent
|wparam
|defwinproc
, MAKEWPARAM(0, EN_SETFOCUS
) },
113 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
114 { WM_CTLCOLOREDIT
, sent
|defwinproc
|optional
},
115 { WM_CTLCOLOREDIT
, sent
|defwinproc
|optional
},
119 static const struct message test_get_set_bkcolor_seq
[] = {
120 { TVM_GETBKCOLOR
, sent
|wparam
|lparam
, 0, 0 },
121 { TVM_SETBKCOLOR
, sent
|wparam
|lparam
, 0, 0 },
122 { TVM_GETBKCOLOR
, sent
|wparam
|lparam
, 0, 0 },
123 { TVM_SETBKCOLOR
, sent
|wparam
|lparam
, 0, 0x00ffffff },
124 { TVM_GETBKCOLOR
, sent
|wparam
|lparam
, 0, 0 },
125 { TVM_SETBKCOLOR
, sent
|wparam
|lparam
, 0, -1 },
129 static const struct message test_get_set_imagelist_seq
[] = {
130 { TVM_SETIMAGELIST
, sent
|wparam
|lparam
, 0, 0 },
131 { TVM_GETIMAGELIST
, sent
|wparam
|lparam
, 0, 0 },
135 static const struct message test_get_set_indent_seq
[] = {
136 { TVM_SETINDENT
, sent
|wparam
|lparam
, 0, 0 },
137 { TVM_GETINDENT
, sent
|wparam
|lparam
, 0, 0 },
138 /* The actual amount to indent is dependent on the system for this message */
139 { TVM_SETINDENT
, sent
},
140 { TVM_GETINDENT
, sent
|wparam
|lparam
, 0, 0 },
144 static const struct message test_get_set_insertmarkcolor_seq
[] = {
145 { TVM_SETINSERTMARKCOLOR
, sent
|wparam
|lparam
, 0, 0 },
146 { TVM_GETINSERTMARKCOLOR
, sent
|wparam
|lparam
, 0, 0 },
150 static const struct message test_get_set_item_seq
[] = {
151 { TVM_GETITEMA
, sent
},
152 { TVM_SETITEMA
, sent
},
153 { TVM_GETITEMA
, sent
},
154 { TVM_SETITEMA
, sent
},
158 static const struct message test_get_set_itemheight_seq
[] = {
159 { TVM_GETITEMHEIGHT
, sent
|wparam
|lparam
, 0, 0 },
160 { TVM_SETITEMHEIGHT
, sent
|wparam
|lparam
, -1, 0 },
161 { TVM_GETITEMHEIGHT
, sent
|wparam
|lparam
, 0, 0 },
162 { TVM_SETITEMHEIGHT
, sent
|lparam
, 0xcccccccc, 0 },
163 { TVM_GETITEMHEIGHT
, sent
|wparam
|lparam
|optional
, 0, 0 },
164 { TVM_SETITEMHEIGHT
, sent
|wparam
|lparam
|optional
, 9, 0 },
165 { TVM_GETITEMHEIGHT
, sent
|wparam
|lparam
, 0, 0 },
169 static const struct message test_get_set_scrolltime_seq
[] = {
170 { TVM_SETSCROLLTIME
, sent
|wparam
|lparam
, 20, 0 },
171 { TVM_GETSCROLLTIME
, sent
|wparam
|lparam
, 0, 0 },
175 static const struct message test_get_set_textcolor_seq
[] = {
176 { TVM_GETTEXTCOLOR
, sent
|wparam
|lparam
, 0, 0 },
177 { TVM_SETTEXTCOLOR
, sent
|wparam
|lparam
, 0, 0 },
178 { TVM_GETTEXTCOLOR
, sent
|wparam
|lparam
, 0, 0 },
179 { TVM_SETTEXTCOLOR
, sent
|wparam
|lparam
, 0, RGB(255, 255, 255) },
180 { TVM_GETTEXTCOLOR
, sent
|wparam
|lparam
, 0, 0 },
181 { TVM_SETTEXTCOLOR
, sent
|wparam
|lparam
, 0, CLR_NONE
},
185 static const struct message test_get_set_tooltips_seq
[] = {
186 { WM_KILLFOCUS
, sent
},
187 { WM_IME_SETCONTEXT
, sent
|optional
},
188 { WM_IME_NOTIFY
, sent
|optional
},
189 { TVM_SETTOOLTIPS
, sent
|wparam
|lparam
, 0, 0 },
190 { TVM_GETTOOLTIPS
, sent
|wparam
|lparam
, 0, 0 },
194 static const struct message test_get_set_unicodeformat_seq
[] = {
195 { TVM_SETUNICODEFORMAT
, sent
|wparam
|lparam
, TRUE
, 0 },
196 { TVM_GETUNICODEFORMAT
, sent
|wparam
|lparam
, 0, 0 },
197 { TVM_SETUNICODEFORMAT
, sent
|wparam
|lparam
, 0, 0 },
198 { TVM_GETUNICODEFORMAT
, sent
|wparam
|lparam
, 0, 0 },
199 { TVM_SETUNICODEFORMAT
, sent
|wparam
|lparam
, 0, 0 },
203 static const struct message parent_expand_seq
[] = {
204 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDINGA
},
205 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDEDA
},
209 static const struct message parent_expand_kb_seq
[] = {
210 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_KEYDOWN
},
211 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDINGA
},
212 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDEDA
},
213 { WM_CHANGEUISTATE
, sent
|optional
},
217 static const struct message parent_collapse_2nd_kb_seq
[] = {
218 { WM_NOTIFY
, sent
|id
|optional
, 0, 0, TVN_KEYDOWN
},
219 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDINGA
},
220 { WM_CHANGEUISTATE
, sent
|optional
},
224 static const struct message parent_expand_empty_kb_seq
[] = {
225 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_KEYDOWN
},
226 { WM_CHANGEUISTATE
, sent
|optional
},
230 static const struct message parent_singleexpand_seq0
[] = {
232 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SELCHANGINGA
},
233 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SELCHANGEDA
},
234 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SINGLEEXPAND
},
235 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDINGA
},
236 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDEDA
},
240 static const struct message parent_singleexpand_seq1
[] = {
242 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SELCHANGINGA
},
243 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SELCHANGEDA
},
244 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SINGLEEXPAND
},
245 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDINGA
},
246 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDEDA
},
250 static const struct message parent_singleexpand_seq2
[] = {
251 /* delta expands, bravo collapses */
252 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SELCHANGINGA
},
253 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SELCHANGEDA
},
254 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SINGLEEXPAND
},
255 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDINGA
},
256 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDEDA
},
257 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDINGA
},
258 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDEDA
},
262 static const struct message parent_singleexpand_seq3
[] = {
263 /* foxtrot expands, alpha and delta collapse */
264 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SELCHANGINGA
},
265 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SELCHANGEDA
},
266 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SINGLEEXPAND
},
267 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDINGA
},
268 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDEDA
},
269 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDINGA
},
270 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDEDA
},
271 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDINGA
},
272 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDEDA
},
276 static const struct message parent_singleexpand_seq4
[] = {
277 /* alpha expands, foxtrot collapses */
278 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SELCHANGINGA
},
279 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SELCHANGEDA
},
280 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SINGLEEXPAND
},
281 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDINGA
},
282 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDEDA
},
283 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDINGA
},
284 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDEDA
},
288 static const struct message parent_singleexpand_seq5
[] = {
289 /* foxtrot expands while golf is selected, then golf expands and alpha collapses */
290 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SELCHANGINGA
},
291 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDINGA
},
292 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDEDA
},
293 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SELCHANGEDA
},
294 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SINGLEEXPAND
},
295 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDINGA
},
296 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDEDA
},
297 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDINGA
},
298 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_ITEMEXPANDEDA
},
302 static const struct message parent_singleexpand_seq6
[] = {
303 /* hotel does not expand and india does not collapse because they have no children */
304 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SELCHANGINGA
},
305 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SELCHANGEDA
},
306 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SINGLEEXPAND
},
310 static const struct message parent_singleexpand_seq7
[] = {
311 /* india does not expand and hotel does not collapse because they have no children */
312 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SELCHANGINGA
},
313 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SELCHANGEDA
},
314 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_SINGLEEXPAND
},
318 static const struct message parent_get_dispinfo_seq
[] = {
319 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_GETDISPINFOA
},
323 static const struct message empty_seq
[] = {
327 static const struct message parent_cd_seq
[] = {
328 { WM_NOTIFY
, sent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREPAINT
},
329 { WM_NOTIFY
, sent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_ITEMPREPAINT
},
330 { WM_NOTIFY
, sent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_ITEMPOSTPAINT
},
331 { WM_NOTIFY
, sent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_POSTPAINT
},
335 static const struct message parent_vk_return_seq
[] = {
336 { WM_NOTIFY
, sent
|id
, 0, 0, TVN_KEYDOWN
},
337 { WM_NOTIFY
, sent
|id
, 0, 0, NM_RETURN
},
338 { WM_CHANGEUISTATE
, sent
|optional
},
342 static HWND hMainWnd
;
344 static HTREEITEM hRoot
, hChild
;
347 static char sequence
[256];
349 static void Clear(void)
355 static void AddItem(char ch
)
357 sequence
[pos
++] = ch
;
358 sequence
[pos
] = '\0';
361 static void IdentifyItem(HTREEITEM hItem
)
363 if (hItem
== hRoot
) {
367 if (hItem
== hChild
) {
378 /* This function hooks in and records all messages to the treeview control */
379 static LRESULT WINAPI
TreeviewWndProc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
381 static LONG defwndproc_counter
= 0;
384 WNDPROC lpOldProc
= (WNDPROC
)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
386 msg
.message
= message
;
387 msg
.flags
= sent
|wparam
|lparam
;
388 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
392 add_message(sequences
, TREEVIEW_SEQ_INDEX
, &msg
);
394 defwndproc_counter
++;
395 ret
= CallWindowProcA(lpOldProc
, hwnd
, message
, wParam
, lParam
);
396 defwndproc_counter
--;
401 static HWND
create_treeview_control(DWORD style
)
406 hTree
= CreateWindowExA(WS_EX_CLIENTEDGE
, WC_TREEVIEWA
, NULL
, WS_CHILD
|WS_VISIBLE
|
407 TVS_LINESATROOT
|TVS_HASLINES
|TVS_HASBUTTONS
|TVS_EDITLABELS
|style
,
408 0, 0, 120, 100, hMainWnd
, (HMENU
)100, GetModuleHandleA(0), 0);
412 /* Record the old WNDPROC so we can call it after recording the messages */
413 pOldWndProc
= (WNDPROC
)SetWindowLongPtrA(hTree
, GWLP_WNDPROC
, (LONG_PTR
)TreeviewWndProc
);
414 SetWindowLongPtrA(hTree
, GWLP_USERDATA
, (LONG_PTR
)pOldWndProc
);
419 static void fill_tree(HWND hTree
)
422 static CHAR root
[] = "Root",
425 ins
.hParent
= TVI_ROOT
;
426 ins
.hInsertAfter
= TVI_ROOT
;
427 U(ins
).item
.mask
= TVIF_TEXT
;
428 U(ins
).item
.pszText
= root
;
429 hRoot
= TreeView_InsertItemA(hTree
, &ins
);
432 ins
.hInsertAfter
= TVI_FIRST
;
433 U(ins
).item
.mask
= TVIF_TEXT
;
434 U(ins
).item
.pszText
= child
;
435 hChild
= TreeView_InsertItemA(hTree
, &ins
);
438 static void test_fillroot(void)
443 hTree
= create_treeview_control(0);
445 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
451 ok(hRoot
!= NULL
, "failed to set root\n");
453 ok(hChild
!= NULL
, "failed to set child\n");
455 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, FillRootSeq
, "FillRoot", FALSE
);
456 ok(!strcmp(sequence
, "AB."), "Item creation\n");
458 /* UMLPad 1.15 depends on this being not -1 (I_IMAGECALLBACK) */
460 tvi
.mask
= TVIF_IMAGE
| TVIF_SELECTEDIMAGE
;
461 SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&tvi
);
462 ok(tvi
.iImage
== 0, "tvi.iImage=%d\n", tvi
.iImage
);
463 ok(tvi
.iSelectedImage
== 0, "tvi.iSelectedImage=%d\n", tvi
.iSelectedImage
);
465 DestroyWindow(hTree
);
468 static void test_callback(void)
471 HTREEITEM hItem1
, hItem2
;
474 CHAR test_string
[] = "Test_string";
475 static const CHAR test2A
[] = "TEST2";
480 hTree
= create_treeview_control(0);
482 ret
= SendMessageA(hTree
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
484 ins
.hParent
= TVI_ROOT
;
485 ins
.hInsertAfter
= TVI_ROOT
;
486 U(ins
).item
.mask
= TVIF_TEXT
;
487 U(ins
).item
.pszText
= LPSTR_TEXTCALLBACKA
;
488 hRoot
= TreeView_InsertItemA(hTree
, &ins
);
489 ok(hRoot
!= NULL
, "failed to set root\n");
492 tvi
.mask
= TVIF_TEXT
;
494 tvi
.cchTextMax
= sizeof(buf
)/sizeof(buf
[0]);
495 ret
= TreeView_GetItemA(hTree
, &tvi
);
497 ok(strcmp(tvi
.pszText
, TEST_CALLBACK_TEXT
) == 0, "Callback item text mismatch %s vs %s\n",
498 tvi
.pszText
, TEST_CALLBACK_TEXT
);
501 ins
.hInsertAfter
= TVI_FIRST
;
502 U(ins
).item
.mask
= TVIF_TEXT
;
503 U(ins
).item
.pszText
= test_string
;
504 hItem1
= TreeView_InsertItemA(hTree
, &ins
);
505 ok(hItem1
!= NULL
, "failed to set Item1\n");
508 ret
= TreeView_GetItemA(hTree
, &tvi
);
510 ok(strcmp(tvi
.pszText
, test_string
) == 0, "Item text mismatch %s vs %s\n",
511 tvi
.pszText
, test_string
);
513 /* undocumented: pszText of NULL also means LPSTR_CALLBACK: */
515 ret
= TreeView_SetItemA(hTree
, &tvi
);
518 ret
= TreeView_GetItemA(hTree
, &tvi
);
520 ok(strcmp(tvi
.pszText
, TEST_CALLBACK_TEXT
) == 0, "Item text mismatch %s vs %s\n",
521 tvi
.pszText
, TEST_CALLBACK_TEXT
);
523 U(ins
).item
.pszText
= NULL
;
524 hItem2
= TreeView_InsertItemA(hTree
, &ins
);
525 ok(hItem2
!= NULL
, "failed to set Item2\n");
527 memset(buf
, 0, sizeof(buf
));
528 ret
= TreeView_GetItemA(hTree
, &tvi
);
530 ok(strcmp(tvi
.pszText
, TEST_CALLBACK_TEXT
) == 0, "Item text mismatch %s vs %s\n",
531 tvi
.pszText
, TEST_CALLBACK_TEXT
);
533 /* notification handler changed A->W */
534 g_disp_A_to_W
= TRUE
;
536 memset(buf
, 0, sizeof(buf
));
537 ret
= TreeView_GetItemA(hTree
, &tvi
);
539 ok(strcmp(tvi
.pszText
, test2A
) == 0, "got %s, expected %s\n",
540 tvi
.pszText
, test2A
);
541 g_disp_A_to_W
= FALSE
;
543 /* handler changes state image index */
544 SetWindowLongA(hTree
, GWL_STYLE
, GetWindowLongA(hTree
, GWL_STYLE
) | TVS_CHECKBOXES
);
546 /* clear selection, handler will set selected state */
547 ret
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, 0);
550 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
553 tvi
.mask
= TVIF_STATE
;
554 tvi
.state
= TVIS_SELECTED
;
555 ret
= TreeView_GetItemA(hTree
, &tvi
);
557 ok(tvi
.state
== INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", tvi
.state
);
559 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
,
560 "no TVN_GETDISPINFO for a state seq", FALSE
);
563 tvi
.mask
= TVIF_IMAGE
| TVIF_STATE
;
564 tvi
.state
= TVIS_FOCUSED
;
565 tvi
.stateMask
= TVIS_FOCUSED
;
566 tvi
.iImage
= I_IMAGECALLBACK
;
567 ret
= TreeView_SetItemA(hTree
, &tvi
);
570 /* ask for item image index through callback - state is also set with state image index */
571 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
574 tvi
.mask
= TVIF_IMAGE
;
576 ret
= TreeView_GetItemA(hTree
, &tvi
);
578 ok(tvi
.state
== (INDEXTOSTATEIMAGEMASK(1) | TVIS_FOCUSED
), "got 0x%x\n", tvi
.state
);
580 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_get_dispinfo_seq
,
581 "callback for state/overlay image index, noop seq", FALSE
);
583 /* ask for image again and overwrite state to some value in handler */
584 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
586 g_disp_set_stateimage
= TRUE
;
588 tvi
.mask
= TVIF_IMAGE
;
589 tvi
.state
= INDEXTOSTATEIMAGEMASK(1);
591 ret
= TreeView_GetItemA(hTree
, &tvi
);
593 /* handler sets TVIS_SELECTED as well */
594 ok(tvi
.state
== (TVIS_FOCUSED
| TVIS_SELECTED
| INDEXTOSTATEIMAGEMASK(2) | INDEXTOOVERLAYMASK(3)), "got 0x%x\n", tvi
.state
);
595 g_disp_set_stateimage
= FALSE
;
597 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_get_dispinfo_seq
,
598 "callback for state/overlay image index seq", FALSE
);
600 DestroyWindow(hTree
);
603 static void test_select(void)
608 hTree
= create_treeview_control(0);
611 /* root-none select tests */
612 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
613 r
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, 0);
617 r
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hRoot
);
620 r
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hRoot
);
623 r
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, 0);
626 r
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, 0);
629 r
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hRoot
);
632 ok(!strcmp(sequence
, "1(nR)nR23(Rn)Rn45(nR)nR."), "root-none select test\n");
633 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, rootnone_select_seq
,
634 "root-none select seq", FALSE
);
636 /* root-child select tests */
637 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
638 r
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, 0);
643 r
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hRoot
);
646 r
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hRoot
);
649 r
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hChild
);
652 r
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hChild
);
655 r
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hRoot
);
658 ok(!strcmp(sequence
, "1(nR)nR23(RC)RC45(CR)CR."), "root-child select test\n");
659 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, rootchild_select_seq
,
660 "root-child select seq", FALSE
);
662 DestroyWindow(hTree
);
665 static void test_getitemtext(void)
672 CHAR szBuffer
[80] = "Blah";
673 int nBufferSize
= sizeof(szBuffer
)/sizeof(CHAR
);
675 hTree
= create_treeview_control(0);
678 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
680 /* add an item without TVIF_TEXT mask and pszText == NULL */
682 ins
.hInsertAfter
= TVI_ROOT
;
683 U(ins
).item
.mask
= 0;
684 U(ins
).item
.pszText
= NULL
;
685 U(ins
).item
.cchTextMax
= 0;
686 hChild
= TreeView_InsertItemA(hTree
, &ins
);
687 ok(hChild
!= NULL
, "failed to set hChild\n");
689 /* retrieve it with TVIF_TEXT mask */
691 tvi
.mask
= TVIF_TEXT
;
692 tvi
.cchTextMax
= nBufferSize
;
693 tvi
.pszText
= szBuffer
;
695 SendMessageA( hTree
, TVM_GETITEMA
, 0, (LPARAM
)&tvi
);
696 ok(!strcmp(szBuffer
, ""), "szBuffer=\"%s\", expected \"\"\n", szBuffer
);
697 ok(SendMessageA(hTree
, TVM_DELETEITEM
, 0, (LPARAM
)hChild
), "DeleteItem failed\n");
698 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, getitemtext_seq
, "get item text seq", FALSE
);
700 DestroyWindow(hTree
);
703 static void test_focus(void)
706 static CHAR child1
[] = "Edit",
707 child2
[] = "A really long string";
708 HTREEITEM hChild1
, hChild2
;
712 hTree
= create_treeview_control(0);
715 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
717 /* This test verifies that when a label is being edited, scrolling
718 * the treeview does not cause the label to lose focus. To test
719 * this, first some additional entries are added to generate
723 ins
.hInsertAfter
= hChild
;
724 U(ins
).item
.mask
= TVIF_TEXT
;
725 U(ins
).item
.pszText
= child1
;
726 hChild1
= TreeView_InsertItemA(hTree
, &ins
);
727 ok(hChild1
!= NULL
, "failed to set hChild1\n");
728 ins
.hInsertAfter
= hChild1
;
729 U(ins
).item
.mask
= TVIF_TEXT
;
730 U(ins
).item
.pszText
= child2
;
731 hChild2
= TreeView_InsertItemA(hTree
, &ins
);
732 ok(hChild2
!= NULL
, "failed to set hChild2\n");
734 ShowWindow(hMainWnd
,SW_SHOW
);
735 SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hChild
);
736 hEdit
= (HWND
)SendMessageA(hTree
, TVM_EDITLABELA
, 0, (LPARAM
)hChild
);
737 ScrollWindowEx(hTree
, -10, 0, NULL
, NULL
, NULL
, NULL
, SW_SCROLLCHILDREN
);
738 ok(GetFocus() == hEdit
, "Edit control should have focus\n");
739 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, focus_seq
, "focus test", TRUE
);
741 DestroyWindow(hTree
);
744 static void test_get_set_bkcolor(void)
749 hTree
= create_treeview_control(0);
752 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
754 /* If the value is -1, the control is using the system color for the background color. */
755 crColor
= SendMessageA(hTree
, TVM_GETBKCOLOR
, 0, 0);
756 ok(crColor
== ~0u, "Default background color reported as 0x%.8x\n", crColor
);
758 /* Test for black background */
759 SendMessageA(hTree
, TVM_SETBKCOLOR
, 0, RGB(0,0,0));
760 crColor
= SendMessageA(hTree
, TVM_GETBKCOLOR
, 0, 0);
761 ok(crColor
== RGB(0,0,0), "Black background color reported as 0x%.8x\n", crColor
);
763 /* Test for white background */
764 SendMessageA(hTree
, TVM_SETBKCOLOR
, 0, RGB(255,255,255));
765 crColor
= SendMessageA(hTree
, TVM_GETBKCOLOR
, 0, 0);
766 ok(crColor
== RGB(255,255,255), "White background color reported as 0x%.8x\n", crColor
);
768 /* Reset the default background */
769 SendMessageA(hTree
, TVM_SETBKCOLOR
, 0, -1);
771 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, test_get_set_bkcolor_seq
,
772 "test get set bkcolor", FALSE
);
774 DestroyWindow(hTree
);
777 static void test_get_set_imagelist(void)
782 hTree
= create_treeview_control(0);
785 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
787 /* Test a NULL HIMAGELIST */
788 SendMessageA(hTree
, TVM_SETIMAGELIST
, TVSIL_NORMAL
, 0);
789 himl
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_NORMAL
, 0);
790 ok(himl
== NULL
, "NULL image list, reported as %p, expected 0.\n", himl
);
792 /* TODO: Test an actual image list */
794 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, test_get_set_imagelist_seq
,
795 "test get imagelist", FALSE
);
797 DestroyWindow(hTree
);
800 static void test_get_set_indent(void)
804 int ulMoreThanTwiceMin
;
807 hTree
= create_treeview_control(0);
810 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
812 /* Finding the minimum indent */
813 SendMessageA(hTree
, TVM_SETINDENT
, 0, 0);
814 ulMinIndent
= SendMessageA(hTree
, TVM_GETINDENT
, 0, 0);
816 /* Checking an indent that is more than twice the default indent */
817 ulMoreThanTwiceMin
= 2*ulMinIndent
+1;
818 SendMessageA(hTree
, TVM_SETINDENT
, ulMoreThanTwiceMin
, 0);
819 ulIndent
= SendMessageA(hTree
, TVM_GETINDENT
, 0, 0);
820 ok(ulIndent
== ulMoreThanTwiceMin
, "Indent reported as %d, expected %d\n", ulIndent
, ulMoreThanTwiceMin
);
822 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, test_get_set_indent_seq
,
823 "test get set indent", FALSE
);
825 DestroyWindow(hTree
);
828 static void test_get_set_insertmark(void)
830 COLORREF crColor
= RGB(0,0,0);
833 hTree
= create_treeview_control(0);
836 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
838 SendMessageA(hTree
, TVM_SETINSERTMARKCOLOR
, 0, crColor
);
839 crColor
= SendMessageA(hTree
, TVM_GETINSERTMARKCOLOR
, 0, 0);
840 ok(crColor
== RGB(0,0,0), "Insert mark color reported as 0x%.8x, expected 0x00000000\n", crColor
);
842 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, test_get_set_insertmarkcolor_seq
,
843 "test get set insertmark color", FALSE
);
845 DestroyWindow(hTree
);
848 static void test_get_set_item(void)
850 TVITEMA tviRoot
= {0};
851 int nBufferSize
= 80;
852 char szBuffer
[80] = {0};
856 hTree
= create_treeview_control(0);
859 tviRoot
.hItem
= hRoot
;
860 tviRoot
.mask
= TVIF_STATE
;
861 tviRoot
.state
= TVIS_FOCUSED
;
862 tviRoot
.stateMask
= TVIS_FOCUSED
;
863 ret
= SendMessageA(hTree
, TVM_SETITEMA
, 0, (LPARAM
)&tviRoot
);
866 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
868 /* Test the root item, state is set even when not requested */
869 tviRoot
.hItem
= hRoot
;
870 tviRoot
.mask
= TVIF_TEXT
;
872 tviRoot
.stateMask
= 0;
873 tviRoot
.cchTextMax
= nBufferSize
;
874 tviRoot
.pszText
= szBuffer
;
875 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&tviRoot
);
877 ok(!strcmp("Root", szBuffer
), "GetItem: szBuffer=\"%s\", expected \"Root\"\n", szBuffer
);
878 ok(tviRoot
.state
== TVIS_FOCUSED
, "got 0x%0x\n", tviRoot
.state
);
880 /* Change the root text */
881 lstrcpynA(szBuffer
, "Testing123", nBufferSize
);
882 ret
= SendMessageA(hTree
, TVM_SETITEMA
, 0, (LPARAM
)&tviRoot
);
884 memset(szBuffer
, 0, nBufferSize
);
885 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&tviRoot
);
887 ok(!strcmp("Testing123", szBuffer
), "GetItem: szBuffer=\"%s\", expected \"Testing123\"\n", szBuffer
);
889 /* Reset the root text */
890 memset(szBuffer
, 0, nBufferSize
);
891 lstrcpynA(szBuffer
, "Root", nBufferSize
);
892 ret
= SendMessageA(hTree
, TVM_SETITEMA
, 0, (LPARAM
)&tviRoot
);
895 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, test_get_set_item_seq
,
896 "test get set item", FALSE
);
898 /* get item from a different tree */
899 hTree2
= create_treeview_control(0);
901 tviRoot
.hItem
= hRoot
;
902 tviRoot
.mask
= TVIF_STATE
;
904 ret
= SendMessageA(hTree2
, TVM_GETITEMA
, 0, (LPARAM
)&tviRoot
);
906 ok(tviRoot
.state
== TVIS_FOCUSED
, "got state 0x%0x\n", tviRoot
.state
);
908 /* invalid item pointer, nt4 crashes here but later versions just return 0 */
909 tviRoot
.hItem
= (HTREEITEM
)0xdeadbeef;
910 tviRoot
.mask
= TVIF_STATE
;
912 ret
= SendMessageA(hTree2
, TVM_GETITEMA
, 0, (LPARAM
)&tviRoot
);
915 DestroyWindow(hTree
);
916 DestroyWindow(hTree2
);
919 static void test_get_set_itemheight(void)
925 hTree
= create_treeview_control(0);
928 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
930 /* Assuming default height to begin with */
931 ulOldHeight
= SendMessageA(hTree
, TVM_GETITEMHEIGHT
, 0, 0);
933 /* Explicitly setting and getting the default height */
934 SendMessageA(hTree
, TVM_SETITEMHEIGHT
, -1, 0);
935 ulNewHeight
= SendMessageA(hTree
, TVM_GETITEMHEIGHT
, 0, 0);
936 ok(ulNewHeight
== ulOldHeight
, "Default height not set properly, reported %d, expected %d\n", ulNewHeight
, ulOldHeight
);
938 /* Explicitly setting and getting the height of twice the normal */
939 SendMessageA(hTree
, TVM_SETITEMHEIGHT
, 2*ulOldHeight
, 0);
940 ulNewHeight
= SendMessageA(hTree
, TVM_GETITEMHEIGHT
, 0, 0);
941 ok(ulNewHeight
== 2*ulOldHeight
, "New height not set properly, reported %d, expected %d\n", ulNewHeight
, 2*ulOldHeight
);
943 /* Assuming tree doesn't have TVS_NONEVENHEIGHT set, so a set of 9 will round down to 8 */
944 SendMessageA(hTree
, TVM_SETITEMHEIGHT
, 9, 0);
945 ulNewHeight
= SendMessageA(hTree
, TVM_GETITEMHEIGHT
, 0, 0);
946 ok(ulNewHeight
== 8, "Uneven height not set properly, reported %d, expected %d\n", ulNewHeight
, 8);
948 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, test_get_set_itemheight_seq
,
949 "test get set item height", FALSE
);
951 /* without TVS_NONEVENHEIGHT */
952 SetWindowLongA(hTree
, GWL_STYLE
, GetWindowLongA(hTree
, GWL_STYLE
) & ~TVS_NONEVENHEIGHT
);
954 ulOldHeight
= SendMessageA(hTree
, TVM_SETITEMHEIGHT
, 3, 0);
955 ok(ulOldHeight
== 8, "got %d, expected %d\n", ulOldHeight
, 8);
956 ulNewHeight
= SendMessageA(hTree
, TVM_GETITEMHEIGHT
, 0, 0);
957 ok(ulNewHeight
== 2, "got %d, expected %d\n", ulNewHeight
, 2);
959 ulOldHeight
= SendMessageA(hTree
, TVM_SETITEMHEIGHT
, 4, 0);
960 ok(ulOldHeight
== 2, "got %d, expected %d\n", ulOldHeight
, 2);
961 ulNewHeight
= SendMessageA(hTree
, TVM_GETITEMHEIGHT
, 0, 0);
962 ok(ulNewHeight
== 4, "got %d, expected %d\n", ulNewHeight
, 4);
964 /* with TVS_NONEVENHEIGHT */
965 SetWindowLongA(hTree
, GWL_STYLE
, GetWindowLongA(hTree
, GWL_STYLE
) | TVS_NONEVENHEIGHT
);
967 ulOldHeight
= SendMessageA(hTree
, TVM_SETITEMHEIGHT
, 3, 0);
968 ok(ulOldHeight
== 4, "got %d, expected %d\n", ulOldHeight
, 4);
969 ulNewHeight
= SendMessageA(hTree
, TVM_GETITEMHEIGHT
, 0, 0);
970 ok(ulNewHeight
== 3, "got %d, expected %d\n", ulNewHeight
, 3);
972 ulOldHeight
= SendMessageA(hTree
, TVM_SETITEMHEIGHT
, 10, 0);
973 ok(ulOldHeight
== 3, "got %d, expected %d\n", ulOldHeight
, 3);
974 ulNewHeight
= SendMessageA(hTree
, TVM_GETITEMHEIGHT
, 0, 0);
975 ok(ulNewHeight
== 10, "got %d, expected %d\n", ulNewHeight
, 10);
977 DestroyWindow(hTree
);
980 static void test_get_set_scrolltime(void)
982 int ulExpectedTime
= 20;
986 hTree
= create_treeview_control(0);
989 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
991 SendMessageA(hTree
, TVM_SETSCROLLTIME
, ulExpectedTime
, 0);
992 ulTime
= SendMessageA(hTree
, TVM_GETSCROLLTIME
, 0, 0);
993 ok(ulTime
== ulExpectedTime
, "Scroll time reported as %d, expected %d\n", ulTime
, ulExpectedTime
);
995 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, test_get_set_scrolltime_seq
,
996 "test get set scroll time", FALSE
);
998 DestroyWindow(hTree
);
1001 static void test_get_set_textcolor(void)
1003 /* If the value is -1, the control is using the system color for the text color. */
1007 hTree
= create_treeview_control(0);
1010 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1012 crColor
= SendMessageA(hTree
, TVM_GETTEXTCOLOR
, 0, 0);
1013 ok(crColor
== ~0u, "Default text color reported as 0x%.8x\n", crColor
);
1015 /* Test for black text */
1016 SendMessageA(hTree
, TVM_SETTEXTCOLOR
, 0, RGB(0,0,0));
1017 crColor
= SendMessageA(hTree
, TVM_GETTEXTCOLOR
, 0, 0);
1018 ok(crColor
== RGB(0,0,0), "Black text color reported as 0x%.8x\n", crColor
);
1020 /* Test for white text */
1021 SendMessageA(hTree
, TVM_SETTEXTCOLOR
, 0, RGB(255,255,255));
1022 crColor
= SendMessageA(hTree
, TVM_GETTEXTCOLOR
, 0, 0);
1023 ok(crColor
== RGB(255,255,255), "White text color reported as 0x%.8x\n", crColor
);
1025 /* Reset the default text color */
1026 SendMessageA(hTree
, TVM_SETTEXTCOLOR
, 0, CLR_NONE
);
1028 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, test_get_set_textcolor_seq
,
1029 "test get set text color", FALSE
);
1031 DestroyWindow(hTree
);
1034 static void test_get_set_tooltips(void)
1036 HWND hwndLastToolTip
= NULL
;
1037 HWND hPopupTreeView
;
1040 hTree
= create_treeview_control(0);
1043 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1045 /* show even WS_POPUP treeview don't send NM_TOOLTIPSCREATED */
1046 hPopupTreeView
= CreateWindowA(WC_TREEVIEWA
, NULL
, WS_POPUP
|WS_VISIBLE
, 0, 0, 100, 100,
1047 hMainWnd
, NULL
, NULL
, NULL
);
1048 DestroyWindow(hPopupTreeView
);
1050 /* Testing setting a NULL ToolTip */
1051 SendMessageA(hTree
, TVM_SETTOOLTIPS
, 0, 0);
1052 hwndLastToolTip
= (HWND
)SendMessageA(hTree
, TVM_GETTOOLTIPS
, 0, 0);
1053 ok(hwndLastToolTip
== NULL
, "NULL tool tip, reported as 0x%p, expected 0.\n", hwndLastToolTip
);
1055 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, test_get_set_tooltips_seq
,
1056 "test get set tooltips", TRUE
);
1058 /* TODO: Add a test of an actual tooltip */
1059 DestroyWindow(hTree
);
1062 static void test_get_set_unicodeformat(void)
1064 BOOL bPreviousSetting
;
1068 hTree
= create_treeview_control(0);
1071 /* Check that an invalid format returned by NF_QUERY defaults to ANSI */
1072 bPreviousSetting
= SendMessageA(hTree
, TVM_GETUNICODEFORMAT
, 0, 0);
1073 ok(bPreviousSetting
== FALSE
, "Format should be ANSI.\n");
1075 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1077 /* Set to Unicode */
1078 bPreviousSetting
= SendMessageA(hTree
, TVM_SETUNICODEFORMAT
, 1, 0);
1079 bNewSetting
= SendMessageA(hTree
, TVM_GETUNICODEFORMAT
, 0, 0);
1080 ok(bNewSetting
== TRUE
, "Unicode setting did not work.\n");
1083 SendMessageA(hTree
, TVM_SETUNICODEFORMAT
, 0, 0);
1084 bNewSetting
= SendMessageA(hTree
, TVM_GETUNICODEFORMAT
, 0, 0);
1085 ok(bNewSetting
== FALSE
, "ANSI setting did not work.\n");
1087 /* Revert to original setting */
1088 SendMessageA(hTree
, TVM_SETUNICODEFORMAT
, bPreviousSetting
, 0);
1090 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, test_get_set_unicodeformat_seq
,
1091 "test get set unicode format", FALSE
);
1093 DestroyWindow(hTree
);
1096 static LRESULT CALLBACK
parent_wnd_proc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1098 static LONG defwndproc_counter
= 0;
1102 HTREEITEM visibleItem
;
1104 msg
.message
= message
;
1105 msg
.flags
= sent
|wparam
|lparam
;
1106 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
1107 msg
.wParam
= wParam
;
1108 msg
.lParam
= lParam
;
1109 if (message
== WM_NOTIFY
&& lParam
)
1110 msg
.id
= ((NMHDR
*)lParam
)->code
;
1114 /* log system messages, except for painting */
1115 if (message
< WM_USER
&&
1116 message
!= WM_PAINT
&&
1117 message
!= WM_ERASEBKGND
&&
1118 message
!= WM_NCPAINT
&&
1119 message
!= WM_NCHITTEST
&&
1120 message
!= WM_GETTEXT
&&
1121 message
!= WM_GETICON
&&
1122 message
!= WM_DEVICECHANGE
)
1124 add_message(sequences
, PARENT_SEQ_INDEX
, &msg
);
1128 case WM_NOTIFYFORMAT
:
1130 /* Make NF_QUERY return an invalid format to show that it defaults to ANSI */
1131 if (lParam
== NF_QUERY
) return 0;
1137 NMHDR
*pHdr
= (NMHDR
*)lParam
;
1139 ok(pHdr
->code
!= NM_TOOLTIPSCREATED
, "Treeview should not send NM_TOOLTIPSCREATED\n");
1140 if (pHdr
->idFrom
== 100)
1142 NMTREEVIEWA
*pTreeView
= (LPNMTREEVIEWA
) lParam
;
1145 case TVN_SELCHANGINGA
:
1147 IdentifyItem(pTreeView
->itemOld
.hItem
);
1148 IdentifyItem(pTreeView
->itemNew
.hItem
);
1150 case TVN_SELCHANGEDA
:
1152 IdentifyItem(pTreeView
->itemOld
.hItem
);
1153 IdentifyItem(pTreeView
->itemNew
.hItem
);
1155 case TVN_GETDISPINFOA
: {
1156 NMTVDISPINFOA
*disp
= (NMTVDISPINFOA
*)lParam
;
1157 if (disp
->item
.mask
& TVIF_TEXT
) {
1158 lstrcpynA(disp
->item
.pszText
, TEST_CALLBACK_TEXT
, disp
->item
.cchTextMax
);
1161 if (g_disp_A_to_W
&& (disp
->item
.mask
& TVIF_TEXT
)) {
1162 static const WCHAR testW
[] = {'T','E','S','T','2',0};
1164 disp
->hdr
.code
= TVN_GETDISPINFOW
;
1165 memcpy(disp
->item
.pszText
, testW
, sizeof(testW
));
1168 if (g_disp_set_stateimage
)
1170 ok(disp
->item
.mask
== TVIF_IMAGE
, "got %x\n", disp
->item
.mask
);
1171 /* both masks set here are necessary to change state bits */
1172 disp
->item
.mask
|= TVIF_STATE
;
1173 disp
->item
.state
= TVIS_SELECTED
| INDEXTOSTATEIMAGEMASK(2) | INDEXTOOVERLAYMASK(3);
1174 disp
->item
.stateMask
= TVIS_SELECTED
| TVIS_OVERLAYMASK
| TVIS_STATEIMAGEMASK
;
1179 case TVN_BEGINLABELEDITA
:
1181 if (g_beginedit_alter_text
)
1183 static const char* textA
= "<edittextaltered>";
1186 edit
= (HWND
)SendMessageA(pHdr
->hwndFrom
, TVM_GETEDITCONTROL
, 0, 0);
1187 ok(IsWindow(edit
), "failed to get edit handle\n");
1188 SetWindowTextA(edit
, textA
);
1194 case TVN_ENDLABELEDITA
: return TRUE
;
1195 case TVN_ITEMEXPANDINGA
:
1197 UINT newmask
= pTreeView
->itemNew
.mask
& ~TVIF_CHILDREN
;
1199 (TVIF_HANDLE
| TVIF_SELECTEDIMAGE
| TVIF_IMAGE
| TVIF_PARAM
| TVIF_STATE
),
1200 "got wrong mask %x\n", pTreeView
->itemNew
.mask
);
1201 ok(pTreeView
->itemOld
.mask
== 0,
1202 "got wrong mask %x\n", pTreeView
->itemOld
.mask
);
1204 if (g_get_from_expand
)
1206 g_item_expanding
.mask
= TVIF_STATE
;
1207 g_item_expanding
.hItem
= hRoot
;
1208 ret
= SendMessageA(pHdr
->hwndFrom
, TVM_GETITEMA
, 0, (LPARAM
)&g_item_expanding
);
1209 ok(ret
== TRUE
, "got %lu\n", ret
);
1213 case TVN_ITEMEXPANDEDA
:
1214 ok(pTreeView
->itemNew
.mask
& TVIF_STATE
, "got wrong mask %x\n", pTreeView
->itemNew
.mask
);
1215 ok(pTreeView
->itemNew
.state
& (TVIS_EXPANDED
|TVIS_EXPANDEDONCE
),
1216 "got wrong mask %x\n", pTreeView
->itemNew
.mask
);
1217 ok(pTreeView
->itemOld
.mask
== 0,
1218 "got wrong mask %x\n", pTreeView
->itemOld
.mask
);
1220 if (g_get_from_expand
)
1222 g_item_expanded
.mask
= TVIF_STATE
;
1223 g_item_expanded
.hItem
= hRoot
;
1224 ret
= SendMessageA(pHdr
->hwndFrom
, TVM_GETITEMA
, 0, (LPARAM
)&g_item_expanded
);
1225 ok(ret
== TRUE
, "got %lu\n", ret
);
1227 if (g_get_rect_in_expand
)
1229 visibleItem
= (HTREEITEM
)SendMessageA(pHdr
->hwndFrom
, TVM_GETNEXTITEM
,
1230 TVGN_FIRSTVISIBLE
, 0);
1231 ok(pTreeView
->itemNew
.hItem
== visibleItem
, "expanded item == first visible item\n");
1232 *(HTREEITEM
*)&rect
= visibleItem
;
1233 ok(SendMessageA(pHdr
->hwndFrom
, TVM_GETITEMRECT
, TRUE
, (LPARAM
)&rect
),
1234 "Failed to get rect for first visible item.\n");
1235 visibleItem
= (HTREEITEM
)SendMessageA(pHdr
->hwndFrom
, TVM_GETNEXTITEM
,
1236 TVGN_NEXTVISIBLE
, (LPARAM
)visibleItem
);
1237 *(HTREEITEM
*)&rect
= visibleItem
;
1238 ok(visibleItem
!= NULL
, "There must be a visible item after the first visisble item.\n");
1239 ok(SendMessageA(pHdr
->hwndFrom
, TVM_GETITEMRECT
, TRUE
, (LPARAM
)&rect
),
1240 "Failed to get rect for second visible item.\n");
1243 case TVN_DELETEITEMA
:
1245 struct message item
;
1247 ok(pTreeView
->itemNew
.mask
== 0, "got wrong mask 0x%x\n", pTreeView
->itemNew
.mask
);
1249 ok(pTreeView
->itemOld
.mask
== (TVIF_HANDLE
| TVIF_PARAM
), "got wrong mask 0x%x\n", pTreeView
->itemOld
.mask
);
1250 ok(pTreeView
->itemOld
.hItem
!= NULL
, "got %p\n", pTreeView
->itemOld
.hItem
);
1252 memset(&item
, 0, sizeof(item
));
1253 item
.lParam
= (LPARAM
)pTreeView
->itemOld
.hItem
;
1254 add_message(item_sequence
, 0, &item
);
1260 NMTVCUSTOMDRAW
*nmcd
= (NMTVCUSTOMDRAW
*)lParam
;
1261 COLORREF c0ffee
= RGB(0xc0,0xff,0xee), cafe
= RGB(0xca,0xfe,0x00);
1263 msg
.flags
|= custdraw
;
1264 msg
.stage
= nmcd
->nmcd
.dwDrawStage
;
1265 add_message(sequences
, PARENT_CD_SEQ_INDEX
, &msg
);
1270 return CDRF_NOTIFYITEMDRAW
|CDRF_NOTIFYITEMERASE
|CDRF_NOTIFYPOSTPAINT
;
1271 case CDDS_ITEMPREPAINT
:
1272 nmcd
->clrTextBk
= c0ffee
;
1273 nmcd
->clrText
= cafe
;
1274 if (g_customdraw_font
)
1275 SelectObject(nmcd
->nmcd
.hdc
, g_customdraw_font
);
1276 return CDRF_NOTIFYPOSTPAINT
|CDRF_NEWFONT
;
1277 case CDDS_ITEMPOSTPAINT
:
1278 /* at the point of post paint notification colors are already restored */
1279 ok(GetTextColor(nmcd
->nmcd
.hdc
) != cafe
, "got 0%x\n", GetTextColor(nmcd
->nmcd
.hdc
));
1280 ok(GetBkColor(nmcd
->nmcd
.hdc
) != c0ffee
, "got 0%x\n", GetBkColor(nmcd
->nmcd
.hdc
));
1281 if (g_customdraw_font
)
1282 ok(GetCurrentObject(nmcd
->nmcd
.hdc
, OBJ_FONT
) != g_customdraw_font
, "got %p\n",
1283 GetCurrentObject(nmcd
->nmcd
.hdc
, OBJ_FONT
));
1300 defwndproc_counter
++;
1301 ret
= DefWindowProcA(hWnd
, message
, wParam
, lParam
);
1302 defwndproc_counter
--;
1307 static void test_expandinvisible(void)
1309 static CHAR nodeText
[][5] = {"0", "1", "2", "3", "4"};
1310 TVINSERTSTRUCTA ins
;
1317 hTree
= create_treeview_control(0);
1319 /* The test builds the following tree and expands node 1, while node 0 is collapsed.
1329 ret
= SendMessageA(hTree
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
1330 ok(ret
== TRUE
, "ret\n");
1331 ins
.hParent
= TVI_ROOT
;
1332 ins
.hInsertAfter
= TVI_ROOT
;
1333 U(ins
).item
.mask
= TVIF_TEXT
;
1334 U(ins
).item
.pszText
= nodeText
[0];
1335 node
[0] = TreeView_InsertItemA(hTree
, &ins
);
1336 ok(node
[0] != NULL
, "failed to set node[0]\n");
1338 ins
.hInsertAfter
= TVI_LAST
;
1339 U(ins
).item
.mask
= TVIF_TEXT
;
1340 ins
.hParent
= node
[0];
1342 U(ins
).item
.pszText
= nodeText
[1];
1343 node
[1] = TreeView_InsertItemA(hTree
, &ins
);
1344 ok(node
[1] != NULL
, "failed to set node[1]\n");
1345 U(ins
).item
.pszText
= nodeText
[4];
1346 node
[4] = TreeView_InsertItemA(hTree
, &ins
);
1347 ok(node
[4] != NULL
, "failed to set node[4]\n");
1349 ins
.hParent
= node
[1];
1351 U(ins
).item
.pszText
= nodeText
[2];
1352 node
[2] = TreeView_InsertItemA(hTree
, &ins
);
1353 ok(node
[2] != NULL
, "failed to set node[2]\n");
1354 U(ins
).item
.pszText
= nodeText
[3];
1355 node
[3] = TreeView_InsertItemA(hTree
, &ins
);
1356 ok(node
[3] != NULL
, "failed to set node[3]\n");
1358 *(HTREEITEM
*)&dummyRect
= node
[1];
1359 nodeVisible
= SendMessageA(hTree
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&dummyRect
);
1360 ok(!nodeVisible
, "Node 1 should not be visible.\n");
1361 *(HTREEITEM
*)&dummyRect
= node
[2];
1362 nodeVisible
= SendMessageA(hTree
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&dummyRect
);
1363 ok(!nodeVisible
, "Node 2 should not be visible.\n");
1364 *(HTREEITEM
*)&dummyRect
= node
[3];
1365 nodeVisible
= SendMessageA(hTree
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&dummyRect
);
1366 ok(!nodeVisible
, "Node 3 should not be visible.\n");
1367 *(HTREEITEM
*)&dummyRect
= node
[4];
1368 nodeVisible
= SendMessageA(hTree
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&dummyRect
);
1369 ok(!nodeVisible
, "Node 4 should not be visible.\n");
1371 ok(SendMessageA(hTree
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)node
[1]), "Expand of node 1 failed.\n");
1373 *(HTREEITEM
*)&dummyRect
= node
[1];
1374 nodeVisible
= SendMessageA(hTree
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&dummyRect
);
1375 ok(!nodeVisible
, "Node 1 should not be visible.\n");
1376 *(HTREEITEM
*)&dummyRect
= node
[2];
1377 nodeVisible
= SendMessageA(hTree
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&dummyRect
);
1378 ok(!nodeVisible
, "Node 2 should not be visible.\n");
1379 *(HTREEITEM
*)&dummyRect
= node
[3];
1380 nodeVisible
= SendMessageA(hTree
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&dummyRect
);
1381 ok(!nodeVisible
, "Node 3 should not be visible.\n");
1382 *(HTREEITEM
*)&dummyRect
= node
[4];
1383 nodeVisible
= SendMessageA(hTree
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&dummyRect
);
1384 ok(!nodeVisible
, "Node 4 should not be visible.\n");
1386 DestroyWindow(hTree
);
1389 static void test_itemedit(void)
1397 hTree
= create_treeview_control(0);
1400 /* try with null item */
1401 edit
= (HWND
)SendMessageA(hTree
, TVM_EDITLABELA
, 0, 0);
1402 ok(!IsWindow(edit
), "Expected valid handle\n");
1405 edit
= (HWND
)SendMessageA(hTree
, TVM_EDITLABELA
, 0, (LPARAM
)hRoot
);
1406 ok(IsWindow(edit
), "Expected valid handle\n");
1407 /* item shouldn't be selected automatically after TVM_EDITLABELA */
1408 r
= SendMessageA(hTree
, TVM_GETITEMSTATE
, (WPARAM
)hRoot
, TVIS_SELECTED
);
1410 /* try to cancel with wrong edit handle */
1411 r
= SendMessageA(hTree
, WM_COMMAND
, MAKEWPARAM(0, EN_KILLFOCUS
), 0);
1413 ok(IsWindow(edit
), "Expected edit control to be valid\n");
1414 r
= SendMessageA(hTree
, WM_COMMAND
, MAKEWPARAM(0, EN_KILLFOCUS
), (LPARAM
)edit
);
1416 ok(!IsWindow(edit
), "Expected edit control to be destroyed\n");
1417 /* try to cancel without creating edit */
1418 r
= SendMessageA(hTree
, WM_COMMAND
, MAKEWPARAM(0, EN_KILLFOCUS
), 0);
1421 /* try to cancel with wrong (not null) handle */
1422 edit
= (HWND
)SendMessageA(hTree
, TVM_EDITLABELA
, 0, (LPARAM
)hRoot
);
1423 ok(IsWindow(edit
), "Expected valid handle\n");
1424 r
= SendMessageA(hTree
, WM_COMMAND
, MAKEWPARAM(0, EN_KILLFOCUS
), (LPARAM
)hTree
);
1426 ok(IsWindow(edit
), "Expected edit control to be valid\n");
1427 r
= SendMessageA(hTree
, WM_COMMAND
, MAKEWPARAM(0, EN_KILLFOCUS
), (LPARAM
)edit
);
1430 /* remove selection after starting edit */
1431 r
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hRoot
);
1433 edit
= (HWND
)SendMessageA(hTree
, TVM_EDITLABELA
, 0, (LPARAM
)hRoot
);
1434 ok(IsWindow(edit
), "Expected valid handle\n");
1435 r
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, 0);
1439 r
= SendMessageA(edit
, WM_SETTEXT
, 0, (LPARAM
)buffA
);
1441 r
= SendMessageA(hTree
, WM_COMMAND
, MAKEWPARAM(0, EN_KILLFOCUS
), (LPARAM
)edit
);
1443 ok(!IsWindow(edit
), "Expected edit control to be destroyed\n");
1444 /* check that text is saved */
1445 item
.mask
= TVIF_TEXT
;
1447 item
.pszText
= buffA
;
1448 item
.cchTextMax
= sizeof(buffA
)/sizeof(CHAR
);
1449 r
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1451 ok(!strcmp("x", buffA
), "Expected item text to change\n");
1453 /* try A/W messages */
1454 edit
= (HWND
)SendMessageA(hTree
, TVM_EDITLABELA
, 0, (LPARAM
)hRoot
);
1455 ok(IsWindow(edit
), "Expected valid handle\n");
1456 ok(IsWindowUnicode(edit
), "got ansi window\n");
1457 r
= SendMessageA(hTree
, WM_COMMAND
, MAKEWPARAM(0, EN_KILLFOCUS
), (LPARAM
)edit
);
1459 ok(!IsWindow(edit
), "expected invalid handle\n");
1461 edit
= (HWND
)SendMessageA(hTree
, TVM_EDITLABELW
, 0, (LPARAM
)hRoot
);
1462 ok(IsWindow(edit
), "Expected valid handle\n");
1463 ok(IsWindowUnicode(edit
), "got ansi window\n");
1464 r
= SendMessageA(hTree
, WM_COMMAND
, MAKEWPARAM(0, EN_KILLFOCUS
), (LPARAM
)edit
);
1467 /* alter text during TVM_BEGINLABELEDIT, check that it's preserved */
1468 strcpy(buffA
, "<root>");
1470 item
.mask
= TVIF_TEXT
;
1472 item
.pszText
= buffA
;
1473 item
.cchTextMax
= 0;
1474 r
= SendMessageA(hTree
, TVM_SETITEMA
, 0, (LPARAM
)&item
);
1477 g_beginedit_alter_text
= TRUE
;
1478 edit
= (HWND
)SendMessageA(hTree
, TVM_EDITLABELA
, 0, (LPARAM
)hRoot
);
1479 ok(IsWindow(edit
), "Expected valid handle\n");
1480 g_beginedit_alter_text
= FALSE
;
1482 GetWindowTextA(edit
, buffA
, sizeof(buffA
)/sizeof(CHAR
));
1483 ok(!strcmp(buffA
, "<edittextaltered>"), "got string %s\n", buffA
);
1485 DestroyWindow(hTree
);
1488 static void test_treeview_classinfo(void)
1492 memset(&cls
, 0, sizeof(cls
));
1493 GetClassInfoA(GetModuleHandleA("comctl32.dll"), WC_TREEVIEWA
, &cls
);
1494 ok(cls
.hbrBackground
== NULL
, "Expected NULL background brush, got %p\n", cls
.hbrBackground
);
1495 ok(cls
.style
== (CS_GLOBALCLASS
| CS_DBLCLKS
), "Expected got %x\n", cls
.style
);
1496 expect(0, cls
.cbClsExtra
);
1499 static void test_get_linecolor(void)
1504 hTree
= create_treeview_control(0);
1506 /* newly created control has default color */
1507 clr
= SendMessageA(hTree
, TVM_GETLINECOLOR
, 0, 0);
1509 win_skip("TVM_GETLINECOLOR is not supported on comctl32 < 5.80\n");
1511 expect(CLR_DEFAULT
, clr
);
1513 DestroyWindow(hTree
);
1516 static void test_get_insertmarkcolor(void)
1521 hTree
= create_treeview_control(0);
1523 /* newly created control has default color */
1524 clr
= SendMessageA(hTree
, TVM_GETINSERTMARKCOLOR
, 0, 0);
1526 win_skip("TVM_GETINSERTMARKCOLOR is not supported on comctl32 < 5.80\n");
1528 expect(CLR_DEFAULT
, clr
);
1530 DestroyWindow(hTree
);
1533 static void test_expandnotify(void)
1540 hTree
= create_treeview_control(0);
1544 item
.mask
= TVIF_STATE
;
1546 item
.state
= TVIS_EXPANDED
;
1547 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1549 ok((item
.state
& TVIS_EXPANDED
) == 0, "expected collapsed\n");
1551 /* preselect root node here */
1552 ret
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hRoot
);
1555 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1556 ret
= SendMessageA(hTree
, TVM_EXPAND
, TVE_COLLAPSE
, (LPARAM
)hRoot
);
1558 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
, "no collapse notifications", FALSE
);
1560 g_get_from_expand
= TRUE
;
1562 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1563 g_item_expanding
.state
= 0xdeadbeef;
1564 g_item_expanded
.state
= 0xdeadbeef;
1565 ret
= SendMessageA(hTree
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)hRoot
);
1567 ok(g_item_expanding
.state
== TVIS_SELECTED
, "got state on TVN_ITEMEXPANDING 0x%08x\n",
1568 g_item_expanding
.state
);
1569 ok(g_item_expanded
.state
== (TVIS_SELECTED
|TVIS_EXPANDED
), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1570 g_item_expanded
.state
);
1571 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_expand_seq
, "expand notifications", FALSE
);
1572 g_get_from_expand
= FALSE
;
1574 /* check that it's expanded */
1575 item
.state
= TVIS_EXPANDED
;
1576 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1578 ok((item
.state
& TVIS_EXPANDED
) == TVIS_EXPANDED
, "expected expanded\n");
1581 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1582 ret
= SendMessageA(hTree
, TVM_EXPAND
, TVE_COLLAPSE
, (LPARAM
)hRoot
);
1584 item
.state
= TVIS_EXPANDED
;
1585 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1587 ok((item
.state
& TVIS_EXPANDED
) == 0, "expected collapsed\n");
1588 /* all further collapse/expand attempts won't produce any notifications,
1589 the only way is to reset with all children removed */
1590 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
, "collapse after expand notifications", FALSE
);
1592 /* try to toggle child that doesn't have children itself */
1593 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1594 ret
= SendMessageA(hTree
, TVM_EXPAND
, TVE_TOGGLE
, (LPARAM
)hChild
);
1596 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
, "toggle node without children", FALSE
);
1598 DestroyWindow(hTree
);
1600 /* test TVM_GETITEMRECT inside TVN_ITEMEXPANDED notification */
1601 hTree
= create_treeview_control(0);
1603 g_get_rect_in_expand
= TRUE
;
1604 ret
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hChild
);
1606 g_get_rect_in_expand
= FALSE
;
1608 DestroyWindow(hTree
);
1610 /* TVE_TOGGLE acts as any other TVM_EXPAND */
1611 hTree
= create_treeview_control(0);
1614 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1615 ret
= SendMessageA(hTree
, TVM_EXPAND
, TVE_TOGGLE
, (LPARAM
)hRoot
);
1617 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_expand_seq
, "toggle node (expand)", FALSE
);
1619 /* toggle again - no notifications */
1620 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1621 ret
= SendMessageA(hTree
, TVM_EXPAND
, TVE_TOGGLE
, (LPARAM
)hRoot
);
1623 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
, "toggle node (collapse)", FALSE
);
1625 DestroyWindow(hTree
);
1627 /* some keyboard events are also translated to expand */
1628 hTree
= create_treeview_control(0);
1631 /* preselect root node here */
1632 ret
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hRoot
);
1635 g_get_from_expand
= TRUE
;
1636 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1637 ret
= SendMessageA(hTree
, WM_KEYDOWN
, VK_ADD
, 0);
1639 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_expand_kb_seq
, "expand node", FALSE
);
1640 ok(g_item_expanding
.state
== TVIS_SELECTED
, "got state on TVN_ITEMEXPANDING 0x%08x\n",
1641 g_item_expanding
.state
);
1642 ok(g_item_expanded
.state
== (TVIS_SELECTED
|TVIS_EXPANDED
), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1643 g_item_expanded
.state
);
1645 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1646 ret
= SendMessageA(hTree
, WM_KEYDOWN
, VK_ADD
, 0);
1648 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_expand_kb_seq
, "expand node again", FALSE
);
1649 ok(g_item_expanding
.state
== (TVIS_SELECTED
|TVIS_EXPANDED
|TVIS_EXPANDEDONCE
), "got state on TVN_ITEMEXPANDING 0x%08x\n",
1650 g_item_expanding
.state
);
1651 ok(g_item_expanded
.state
== (TVIS_SELECTED
|TVIS_EXPANDED
|TVIS_EXPANDEDONCE
), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1652 g_item_expanded
.state
);
1654 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1655 ret
= SendMessageA(hTree
, WM_KEYDOWN
, VK_SUBTRACT
, 0);
1657 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_expand_kb_seq
, "collapse node", FALSE
);
1658 ok(g_item_expanding
.state
== (TVIS_SELECTED
|TVIS_EXPANDED
|TVIS_EXPANDEDONCE
), "got state on TVN_ITEMEXPANDING 0x%08x\n",
1659 g_item_expanding
.state
);
1660 ok(g_item_expanded
.state
== (TVIS_SELECTED
|TVIS_EXPANDEDONCE
), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1661 g_item_expanded
.state
);
1663 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1664 ret
= SendMessageA(hTree
, WM_KEYDOWN
, VK_SUBTRACT
, 0);
1666 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_collapse_2nd_kb_seq
, "collapse node again", FALSE
);
1667 ok(g_item_expanding
.state
== (TVIS_SELECTED
|TVIS_EXPANDEDONCE
), "got state on TVN_ITEMEXPANDING 0x%08x\n",
1668 g_item_expanding
.state
);
1669 g_get_from_expand
= FALSE
;
1671 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1672 ret
= SendMessageA(hTree
, WM_KEYDOWN
, VK_ADD
, 0);
1674 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_expand_kb_seq
, "expand node", FALSE
);
1677 ret
= SendMessageA(hTree
, WM_KEYDOWN
, VK_RIGHT
, 0);
1680 /* try to expand child that doesn't have children itself */
1681 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1682 ret
= SendMessageA(hTree
, WM_KEYDOWN
, VK_ADD
, 0);
1684 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_expand_empty_kb_seq
, "expand node with no children", FALSE
);
1686 /* stay on current selection and set non-zero children count */
1687 hitem
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_CARET
, 0);
1688 ok(hitem
!= NULL
, "got %p\n", hitem
);
1691 item
.mask
= TVIF_CHILDREN
;
1692 item
.cChildren
= 0x80000000;
1694 ret
= SendMessageA(hTree
, TVM_SETITEMA
, 0, (LPARAM
)&item
);
1697 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1698 ret
= SendMessageA(hTree
, WM_KEYDOWN
, VK_ADD
, 0);
1700 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_collapse_2nd_kb_seq
, "expand node with children", FALSE
);
1702 DestroyWindow(hTree
);
1705 static void test_expandedimage(void)
1711 hTree
= create_treeview_control(0);
1714 item
.mask
= TVIF_EXPANDEDIMAGE
;
1715 item
.iExpandedImage
= 1;
1717 ret
= SendMessageA(hTree
, TVM_SETITEMA
, 0, (LPARAM
)&item
);
1718 ok(ret
, "got %d\n", ret
);
1720 item
.mask
= TVIF_EXPANDEDIMAGE
;
1721 item
.iExpandedImage
= -1;
1723 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1724 ok(ret
, "got %d\n", ret
);
1726 if (item
.iExpandedImage
!= 1)
1728 win_skip("TVIF_EXPANDEDIMAGE not supported\n");
1729 DestroyWindow(hTree
);
1733 /* test for default iExpandedImage value */
1734 item
.mask
= TVIF_EXPANDEDIMAGE
;
1735 item
.iExpandedImage
= -1;
1736 item
.hItem
= hChild
;
1737 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1738 ok(ret
, "got %d\n", ret
);
1739 ok(item
.iExpandedImage
== (WORD
)I_IMAGENONE
, "got %d\n", item
.iExpandedImage
);
1741 DestroyWindow(hTree
);
1744 static void test_TVS_SINGLEEXPAND(void)
1747 HTREEITEM alpha
, bravo
, charlie
, delta
, echo
, foxtrot
, golf
, hotel
, india
, juliet
;
1748 TVINSERTSTRUCTA ins
;
1754 /* build a fairly complex tree
1775 { &alpha
, NULL
, TVIS_EXPANDEDONCE
},
1776 { &bravo
, &alpha
, TVIS_EXPANDEDONCE
},
1777 { &charlie
, &bravo
, 0 },
1778 { &delta
, &alpha
, TVIS_EXPANDEDONCE
},
1779 { &echo
, &delta
, 0 },
1780 { &foxtrot
, NULL
, TVIS_EXPANDEDONCE
|TVIS_EXPANDED
},
1781 { &golf
, &foxtrot
, TVIS_EXPANDEDONCE
|TVIS_EXPANDED
},
1782 { &hotel
, &golf
, 0 },
1783 { &india
, &golf
, TVIS_SELECTED
},
1784 { &juliet
, &foxtrot
, 0 }
1790 const struct message
*sequence
;
1794 { &alpha
, parent_singleexpand_seq0
},
1795 { &bravo
, parent_singleexpand_seq1
},
1796 { &delta
, parent_singleexpand_seq2
},
1797 { &foxtrot
, parent_singleexpand_seq3
},
1798 { &alpha
, parent_singleexpand_seq4
},
1799 { &golf
, parent_singleexpand_seq5
},
1800 { &hotel
, parent_singleexpand_seq6
},
1801 { &india
, parent_singleexpand_seq7
},
1802 { &india
, empty_seq
}
1805 hTree
= create_treeview_control(0);
1806 SetWindowLongA(hTree
, GWL_STYLE
, GetWindowLongA(hTree
, GWL_STYLE
) | TVS_SINGLEEXPAND
);
1807 /* to avoid painting related notifications */
1808 ShowWindow(hTree
, SW_HIDE
);
1809 for (i
= 0; i
< sizeof(items
)/sizeof(items
[0]); i
++)
1811 ins
.hParent
= items
[i
].parent
? *items
[i
].parent
: TVI_ROOT
;
1812 ins
.hInsertAfter
= TVI_FIRST
;
1813 U(ins
).item
.mask
= TVIF_TEXT
;
1814 U(ins
).item
.pszText
= foo
;
1815 *items
[i
].handle
= TreeView_InsertItemA(hTree
, &ins
);
1818 for (i
= 0; i
< sizeof(sequence_tests
)/sizeof(sequence_tests
[0]); i
++)
1820 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1821 ret
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)(*sequence_tests
[i
].select
));
1822 ok(ret
, "got %d\n", ret
);
1823 sprintf(context
, "singleexpand notifications %d", i
);
1824 ok_sequence(sequences
, PARENT_SEQ_INDEX
, sequence_tests
[i
].sequence
, context
, FALSE
);
1827 for (i
= 0; i
< sizeof(items
)/sizeof(items
[0]); i
++)
1829 ret
= SendMessageA(hTree
, TVM_GETITEMSTATE
, (WPARAM
)(*items
[i
].handle
), 0xFFFF);
1830 ok(ret
== items
[i
].final_state
, "singleexpand items[%d]: expected state 0x%x got 0x%x\n",
1831 i
, items
[i
].final_state
, ret
);
1834 /* a workaround for NT4 that sends expand notifications when nothing is about to expand */
1835 ret
= SendMessageA(hTree
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
1836 ok(ret
, "got %d\n", ret
);
1838 ret
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, 0);
1839 ok(ret
, "got %d\n", ret
);
1841 DestroyWindow(hTree
);
1844 static void test_WM_PAINT(void)
1852 hTree
= create_treeview_control(0);
1854 clr
= SendMessageA(hTree
, TVM_SETBKCOLOR
, 0, RGB(255, 0, 0));
1855 ok(clr
== ~0u, "got %d, expected -1\n", clr
);
1857 hdc
= GetDC(hMainWnd
);
1859 GetClientRect(hMainWnd
, &rc
);
1860 FillRect(hdc
, &rc
, GetStockObject(BLACK_BRUSH
));
1862 clr
= GetPixel(hdc
, 1, 1);
1863 ok(clr
== RGB(0, 0, 0), "got 0x%x\n", clr
);
1865 ret
= SendMessageA(hTree
, WM_PAINT
, (WPARAM
)hdc
, 0);
1866 ok(ret
== 0, "got %d\n", ret
);
1868 clr
= GetPixel(hdc
, 1, 1);
1869 ok(clr
== RGB(255, 0, 0) || broken(clr
== RGB(0, 0, 0)) /* win98 */,
1872 ReleaseDC(hMainWnd
, hdc
);
1874 DestroyWindow(hTree
);
1877 static void test_delete_items(void)
1879 const struct message
*msg
;
1881 HTREEITEM hItem1
, hItem2
;
1882 TVINSERTSTRUCTA ins
;
1885 static CHAR item1
[] = "Item 1";
1886 static CHAR item2
[] = "Item 2";
1888 hTree
= create_treeview_control(0);
1891 /* check delete order */
1892 flush_sequences(item_sequence
, 1);
1893 ret
= SendMessageA(hTree
, TVM_DELETEITEM
, 0, 0);
1894 ok(ret
== TRUE
, "got %d\n", ret
);
1896 msg
= item_sequence
[0]->sequence
;
1897 ok(item_sequence
[0]->count
== 2, "expected 2 items, got %d\n", item_sequence
[0]->count
);
1899 if (item_sequence
[0]->count
== 2)
1901 ok(msg
[0].lParam
== (LPARAM
)hChild
, "expected %p, got 0x%lx\n", hChild
, msg
[0].lParam
);
1902 ok(msg
[1].lParam
== (LPARAM
)hRoot
, "expected %p, got 0x%lx\n", hRoot
, msg
[1].lParam
);
1905 ret
= SendMessageA(hTree
, TVM_GETCOUNT
, 0, 0);
1906 ok(ret
== 0, "got %d\n", ret
);
1908 DestroyWindow(hTree
);
1910 /* Regression test for a crash when deleting the first visible item while bRedraw == false. */
1911 hTree
= create_treeview_control(0);
1913 ret
= SendMessageA(hTree
, WM_SETREDRAW
, FALSE
, 0);
1914 ok(ret
== 0, "got %d\n", ret
);
1916 ins
.hParent
= TVI_ROOT
;
1917 ins
.hInsertAfter
= TVI_ROOT
;
1918 U(ins
).item
.mask
= TVIF_TEXT
;
1919 U(ins
).item
.pszText
= item1
;
1920 hItem1
= TreeView_InsertItemA(hTree
, &ins
);
1921 ok(hItem1
!= NULL
, "InsertItem failed\n");
1923 ins
.hParent
= TVI_ROOT
;
1924 ins
.hInsertAfter
= hItem1
;
1925 U(ins
).item
.mask
= TVIF_TEXT
;
1926 U(ins
).item
.pszText
= item2
;
1927 hItem2
= TreeView_InsertItemA(hTree
, &ins
);
1928 ok(hItem2
!= NULL
, "InsertItem failed\n");
1930 ret
= SendMessageA(hTree
, TVM_DELETEITEM
, 0, (LPARAM
)hItem1
);
1931 ok(ret
== TRUE
, "got %d\n", ret
);
1933 ret
= SendMessageA(hTree
, WM_SETREDRAW
, TRUE
, 0);
1934 ok(ret
== 0, "got %d\n", ret
);
1936 DestroyWindow(hTree
);
1939 static void test_cchildren(void)
1945 hTree
= create_treeview_control(0);
1948 ret
= SendMessageA(hTree
, TVM_DELETEITEM
, 0, (LPARAM
)hChild
);
1951 /* check cChildren - automatic mode */
1953 item
.mask
= TVIF_CHILDREN
;
1955 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1957 expect(0, item
.cChildren
);
1959 DestroyWindow(hTree
);
1962 hTree
= create_treeview_control(0);
1965 /* turn off automatic mode by setting cChildren explicitly */
1967 item
.mask
= TVIF_CHILDREN
;
1969 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1971 expect(1, item
.cChildren
);
1973 ret
= SendMessageA(hTree
, TVM_SETITEMA
, 0, (LPARAM
)&item
);
1976 ret
= SendMessageA(hTree
, TVM_DELETEITEM
, 0, (LPARAM
)hChild
);
1979 /* check cChildren */
1980 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1983 expect(1, item
.cChildren
);
1985 DestroyWindow(hTree
);
1990 HTREEITEM parent
; /* for root value of parent field is unidetified */
1991 HTREEITEM nextsibling
;
1992 HTREEITEM firstchild
;
1995 static void _check_item(HTREEITEM item
, HTREEITEM parent
, HTREEITEM nextsibling
, HTREEITEM firstchild
, int line
)
1997 struct _ITEM_DATA
*data
= (struct _ITEM_DATA
*)item
;
1999 ok_(__FILE__
, line
)(data
->parent
== parent
, "parent %p, got %p\n", parent
, data
->parent
);
2000 ok_(__FILE__
, line
)(data
->nextsibling
== nextsibling
, "sibling %p, got %p\n", nextsibling
, data
->nextsibling
);
2001 ok_(__FILE__
, line
)(data
->firstchild
== firstchild
, "firstchild %p, got %p\n", firstchild
, data
->firstchild
);
2004 #define check_item(a, b, c, d) _check_item(a, b, c, d, __LINE__)
2006 static void test_htreeitem_layout(void)
2008 TVINSERTSTRUCTA ins
;
2009 HTREEITEM item1
, item2
;
2012 hTree
= create_treeview_control(0);
2015 /* root has some special pointer in parent field */
2016 check_item(hRoot
, ((struct _ITEM_DATA
*)hRoot
)->parent
, 0, hChild
);
2017 check_item(hChild
, hRoot
, 0, 0);
2019 ins
.hParent
= hChild
;
2020 ins
.hInsertAfter
= TVI_FIRST
;
2021 U(ins
).item
.mask
= 0;
2022 item1
= TreeView_InsertItemA(hTree
, &ins
);
2024 check_item(item1
, hChild
, 0, 0);
2026 ins
.hParent
= hRoot
;
2027 ins
.hInsertAfter
= TVI_FIRST
;
2028 U(ins
).item
.mask
= 0;
2029 item2
= TreeView_InsertItemA(hTree
, &ins
);
2031 check_item(item2
, hRoot
, hChild
, 0);
2033 SendMessageA(hTree
, TVM_DELETEITEM
, 0, (LPARAM
)hChild
);
2035 /* without children now */
2036 check_item(hRoot
, ((struct _ITEM_DATA
*)hRoot
)->parent
, 0, item2
);
2038 DestroyWindow(hTree
);
2041 static void test_TVS_CHECKBOXES(void)
2043 HIMAGELIST himl
, himl2
;
2049 hTree
= create_treeview_control(0);
2052 himl
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2053 ok(himl
== NULL
, "got %p\n", himl
);
2056 item
.mask
= TVIF_STATE
;
2057 item
.state
= INDEXTOSTATEIMAGEMASK(1);
2058 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2059 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2061 ok(item
.state
== 0, "got 0x%x\n", item
.state
);
2063 /* set some index for a child */
2064 item
.hItem
= hChild
;
2065 item
.mask
= TVIF_STATE
;
2066 item
.state
= INDEXTOSTATEIMAGEMASK(4);
2067 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2068 ret
= SendMessageA(hTree
, TVM_SETITEMA
, 0, (LPARAM
)&item
);
2071 /* enabling check boxes set all items to 1 state image index */
2072 SetWindowLongA(hTree
, GWL_STYLE
, GetWindowLongA(hTree
, GWL_STYLE
) | TVS_CHECKBOXES
);
2073 himl
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2074 ok(himl
!= NULL
, "got %p\n", himl
);
2076 himl2
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2077 ok(himl2
!= NULL
, "got %p\n", himl2
);
2078 ok(himl2
== himl
, "got %p, expected %p\n", himl2
, himl
);
2081 item
.mask
= TVIF_STATE
;
2083 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2084 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2086 ok(item
.state
== INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item
.state
);
2088 item
.hItem
= hChild
;
2089 item
.mask
= TVIF_STATE
;
2091 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2092 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2094 ok(item
.state
== INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item
.state
);
2096 /* create another control and check its checkbox list */
2097 hTree2
= create_treeview_control(0);
2100 /* set some index for a child */
2101 item
.hItem
= hChild
;
2102 item
.mask
= TVIF_STATE
;
2103 item
.state
= INDEXTOSTATEIMAGEMASK(4);
2104 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2105 ret
= SendMessageA(hTree2
, TVM_SETITEMA
, 0, (LPARAM
)&item
);
2108 /* enabling check boxes set all items to 1 state image index */
2109 SetWindowLongA(hTree2
, GWL_STYLE
, GetWindowLongA(hTree
, GWL_STYLE
) | TVS_CHECKBOXES
);
2110 himl2
= (HIMAGELIST
)SendMessageA(hTree2
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2111 ok(himl2
!= NULL
, "got %p\n", himl2
);
2112 ok(himl
!= himl2
, "got %p, expected %p\n", himl2
, himl
);
2114 DestroyWindow(hTree2
);
2115 DestroyWindow(hTree
);
2117 /* the same, but initially created with TVS_CHECKBOXES */
2118 hTree
= create_treeview_control(TVS_CHECKBOXES
);
2120 himl
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2121 ok(himl
== NULL
, "got %p\n", himl
);
2124 item
.mask
= TVIF_STATE
;
2126 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2127 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2129 ok(item
.state
== INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item
.state
);
2131 item
.hItem
= hChild
;
2132 item
.mask
= TVIF_STATE
;
2134 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2135 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2137 ok(item
.state
== INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item
.state
);
2139 item
.hItem
= hChild
;
2140 item
.mask
= TVIF_STATE
;
2141 item
.state
= INDEXTOSTATEIMAGEMASK(2);
2142 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2143 ret
= SendMessageA(hTree
, TVM_SETITEMA
, 0, (LPARAM
)&item
);
2146 item
.hItem
= hChild
;
2147 item
.mask
= TVIF_STATE
;
2149 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2151 ok(item
.state
== INDEXTOSTATEIMAGEMASK(2), "got 0x%x\n", item
.state
);
2153 while(GetMessageA(&msg
, 0, 0, 0))
2155 TranslateMessage(&msg
);
2156 DispatchMessageA(&msg
);
2158 if((msg
.hwnd
== hTree
) && (msg
.message
== WM_PAINT
))
2162 item
.hItem
= hChild
;
2163 item
.mask
= TVIF_STATE
;
2165 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2167 ok(item
.state
== INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item
.state
);
2169 himl
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2170 ok(himl
!= NULL
, "got %p\n", himl
);
2172 DestroyWindow(hTree
);
2174 /* check what happens if TVSIL_STATE image list is removed */
2175 hTree
= create_treeview_control(0);
2177 himl
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2178 ok(himl
== NULL
, "got %p\n", himl
);
2180 SetWindowLongA(hTree
, GWL_STYLE
, GetWindowLongA(hTree
, GWL_STYLE
) | TVS_CHECKBOXES
);
2181 himl
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2182 ok(himl
!= NULL
, "got %p\n", himl
);
2184 himl2
= (HIMAGELIST
)SendMessageA(hTree
, TVM_SETIMAGELIST
, TVSIL_STATE
, 0);
2185 ok(himl2
== himl
, "got %p\n", himl2
);
2187 himl2
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2188 ok(himl2
== NULL
, "got %p\n", himl2
);
2190 item
.hItem
= hChild
;
2191 item
.mask
= TVIF_STATE
;
2192 item
.state
= INDEXTOSTATEIMAGEMASK(2);
2193 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2194 ret
= SendMessageA(hTree
, TVM_SETITEMA
, 0, (LPARAM
)&item
);
2197 item
.hItem
= hChild
;
2198 item
.mask
= TVIF_STATE
;
2200 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2202 ok(item
.state
== INDEXTOSTATEIMAGEMASK(2), "got 0x%x\n", item
.state
);
2204 while(GetMessageA(&msg
, 0, 0, 0))
2206 TranslateMessage(&msg
);
2207 DispatchMessageA(&msg
);
2209 if((msg
.hwnd
== hTree
) && (msg
.message
== WM_PAINT
))
2213 item
.hItem
= hChild
;
2214 item
.mask
= TVIF_STATE
;
2216 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2218 ok(item
.state
== INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item
.state
);
2220 himl
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2221 ok(himl
!= NULL
, "got %p\n", himl
);
2223 DestroyWindow(hTree
);
2226 static void test_TVM_GETNEXTITEM(void)
2231 hTree
= create_treeview_control(0);
2234 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_ROOT
, 0);
2235 ok(item
== hRoot
, "got %p, expected %p\n", item
, hRoot
);
2237 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_ROOT
, (LPARAM
)TVI_ROOT
);
2238 ok(item
== hRoot
, "got %p, expected %p\n", item
, hRoot
);
2240 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_ROOT
, (LPARAM
)hRoot
);
2241 ok(item
== hRoot
, "got %p, expected %p\n", item
, hRoot
);
2243 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_ROOT
, (LPARAM
)hChild
);
2244 ok(item
== hRoot
, "got %p, expected %p\n", item
, hRoot
);
2246 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_CHILD
, 0);
2247 ok(item
== hRoot
, "got %p, expected %p\n", item
, hRoot
);
2249 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_CHILD
, (LPARAM
)hRoot
);
2250 ok(item
== hChild
, "got %p, expected %p\n", item
, hChild
);
2252 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_CHILD
, (LPARAM
)TVI_ROOT
);
2253 ok(item
== hRoot
, "got %p, expected %p\n", item
, hRoot
);
2255 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_PARENT
, 0);
2256 ok(item
== NULL
, "got %p\n", item
);
2258 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_PARENT
, (LPARAM
)hChild
);
2259 ok(item
== hRoot
, "got %p, expected %p\n", item
, hRoot
);
2261 DestroyWindow(hTree
);
2264 static void test_TVM_HITTEST(void)
2271 hTree
= create_treeview_control(0);
2274 *(HTREEITEM
*)&rc
= hRoot
;
2275 ret
= SendMessageA(hTree
, TVM_GETITEMRECT
, TRUE
, (LPARAM
)&rc
);
2276 expect(TRUE
, (BOOL
)ret
);
2278 ht
.pt
.x
= rc
.left
-1;
2281 ret
= SendMessageA(hTree
, TVM_HITTEST
, 0, (LPARAM
)&ht
);
2282 ok((HTREEITEM
)ret
== hRoot
, "got %p, expected %p\n", (HTREEITEM
)ret
, hRoot
);
2283 ok(ht
.hItem
== hRoot
, "got %p, expected %p\n", ht
.hItem
, hRoot
);
2284 ok(ht
.flags
== TVHT_ONITEMBUTTON
, "got %d, expected %d\n", ht
.flags
, TVHT_ONITEMBUTTON
);
2286 ret
= SendMessageA(hTree
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)hRoot
);
2287 expect(TRUE
, (BOOL
)ret
);
2289 *(HTREEITEM
*)&rc
= hChild
;
2290 ret
= SendMessageA(hTree
, TVM_GETITEMRECT
, TRUE
, (LPARAM
)&rc
);
2291 expect(TRUE
, (BOOL
)ret
);
2293 ht
.pt
.x
= rc
.left
-1;
2296 ret
= SendMessageA(hTree
, TVM_HITTEST
, 0, (LPARAM
)&ht
);
2297 ok((HTREEITEM
)ret
== hChild
, "got %p, expected %p\n", (HTREEITEM
)ret
, hChild
);
2298 ok(ht
.hItem
== hChild
, "got %p, expected %p\n", ht
.hItem
, hChild
);
2299 /* Wine returns item button here, but this item has no button */
2300 todo_wine
ok(ht
.flags
== TVHT_ONITEMINDENT
, "got %d, expected %d\n", ht
.flags
, TVHT_ONITEMINDENT
);
2302 DestroyWindow(hTree
);
2305 static void test_WM_GETDLGCODE(void)
2310 hTree
= create_treeview_control(0);
2312 code
= SendMessageA(hTree
, WM_GETDLGCODE
, VK_TAB
, 0);
2313 ok(code
== (DLGC_WANTCHARS
| DLGC_WANTARROWS
), "0x%08x\n", code
);
2315 DestroyWindow(hTree
);
2318 static void test_customdraw(void)
2320 static const char *rootA
= "root";
2321 TVINSERTSTRUCTA ins
;
2326 hwnd
= create_treeview_control(0);
2328 ins
.hParent
= TVI_ROOT
;
2329 ins
.hInsertAfter
= TVI_ROOT
;
2330 U(ins
).item
.mask
= TVIF_TEXT
;
2331 U(ins
).item
.pszText
= (char*)rootA
;
2332 hRoot
= TreeView_InsertItemA(hwnd
, &ins
);
2333 ok(hRoot
!= NULL
, "got %p\n", hRoot
);
2335 /* create additional font, custom draw handler will select it */
2336 SystemParametersInfoA(SPI_GETICONTITLELOGFONT
, sizeof(lf
), &lf
, 0);
2338 g_customdraw_font
= CreateFontIndirectA(&lf
);
2339 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2340 InvalidateRect(hwnd
, NULL
, TRUE
);
2342 ok_sequence(sequences
, PARENT_CD_SEQ_INDEX
, parent_cd_seq
, "custom draw notifications", FALSE
);
2343 DeleteObject(g_customdraw_font
);
2344 g_customdraw_font
= NULL
;
2346 DestroyWindow(hwnd
);
2349 static void test_WM_KEYDOWN(void)
2351 static const char *rootA
= "root";
2352 TVINSERTSTRUCTA ins
;
2356 hwnd
= create_treeview_control(0);
2358 ins
.hParent
= TVI_ROOT
;
2359 ins
.hInsertAfter
= TVI_ROOT
;
2360 U(ins
).item
.mask
= TVIF_TEXT
;
2361 U(ins
).item
.pszText
= (char*)rootA
;
2362 hRoot
= TreeView_InsertItemA(hwnd
, &ins
);
2363 ok(hRoot
!= NULL
, "got %p\n", hRoot
);
2365 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2366 SendMessageA(hwnd
, WM_KEYDOWN
, VK_RETURN
, 0);
2367 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_vk_return_seq
, "WM_KEYDOWN/VK_RETURN parent notification", TRUE
);
2369 DestroyWindow(hwnd
);
2372 START_TEST(treeview
)
2375 BOOL (WINAPI
*pInitCommonControlsEx
)(const INITCOMMONCONTROLSEX
*);
2379 ULONG_PTR ctx_cookie
;
2382 hComctl32
= GetModuleHandleA("comctl32.dll");
2383 pInitCommonControlsEx
= (void*)GetProcAddress(hComctl32
, "InitCommonControlsEx");
2384 if (pInitCommonControlsEx
)
2386 INITCOMMONCONTROLSEX iccex
;
2387 iccex
.dwSize
= sizeof(iccex
);
2388 iccex
.dwICC
= ICC_TREEVIEW_CLASSES
;
2389 pInitCommonControlsEx(&iccex
);
2392 InitCommonControls();
2394 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
2395 init_msg_sequences(item_sequence
, 1);
2397 wc
.style
= CS_HREDRAW
| CS_VREDRAW
;
2400 wc
.hInstance
= GetModuleHandleA(NULL
);
2402 wc
.hCursor
= LoadCursorA(NULL
, (LPCSTR
)IDC_IBEAM
);
2403 wc
.hbrBackground
= GetSysColorBrush(COLOR_WINDOW
);
2404 wc
.lpszMenuName
= NULL
;
2405 wc
.lpszClassName
= "MyTestWnd";
2406 wc
.lpfnWndProc
= parent_wnd_proc
;
2407 RegisterClassA(&wc
);
2409 hMainWnd
= CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW
,
2410 CW_USEDEFAULT
, CW_USEDEFAULT
, 130, 105, NULL
, NULL
, GetModuleHandleA(NULL
), 0);
2412 ok(hMainWnd
!= NULL
, "Failed to create parent window. Tests aborted.\n");
2413 if (!hMainWnd
) return;
2419 test_get_set_bkcolor();
2420 test_get_set_imagelist();
2421 test_get_set_indent();
2422 test_get_set_insertmark();
2423 test_get_set_item();
2424 test_get_set_itemheight();
2425 test_get_set_scrolltime();
2426 test_get_set_textcolor();
2427 test_get_linecolor();
2428 test_get_insertmarkcolor();
2429 test_get_set_tooltips();
2430 test_get_set_unicodeformat();
2432 test_expandinvisible();
2434 test_treeview_classinfo();
2435 test_expandnotify();
2436 test_TVS_SINGLEEXPAND();
2438 test_delete_items();
2440 test_htreeitem_layout();
2441 test_TVS_CHECKBOXES();
2442 test_TVM_GETNEXTITEM();
2444 test_WM_GETDLGCODE();
2448 if (!load_v6_module(&ctx_cookie
, &hCtx
))
2450 DestroyWindow(hMainWnd
);
2454 /* comctl32 version 6 tests start here */
2455 test_expandedimage();
2456 test_htreeitem_layout();
2457 test_WM_GETDLGCODE();
2459 unload_v6_module(ctx_cookie
, hCtx
);
2461 PostMessageA(hMainWnd
, WM_CLOSE
, 0, 0);
2462 while(GetMessageA(&msg
, 0, 0, 0))
2464 TranslateMessage(&msg
);
2465 DispatchMessageA(&msg
);