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 DestroyWindow(hTree
);
909 DestroyWindow(hTree2
);
912 static void test_get_set_itemheight(void)
918 hTree
= create_treeview_control(0);
921 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
923 /* Assuming default height to begin with */
924 ulOldHeight
= SendMessageA(hTree
, TVM_GETITEMHEIGHT
, 0, 0);
926 /* Explicitly setting and getting the default height */
927 SendMessageA(hTree
, TVM_SETITEMHEIGHT
, -1, 0);
928 ulNewHeight
= SendMessageA(hTree
, TVM_GETITEMHEIGHT
, 0, 0);
929 ok(ulNewHeight
== ulOldHeight
, "Default height not set properly, reported %d, expected %d\n", ulNewHeight
, ulOldHeight
);
931 /* Explicitly setting and getting the height of twice the normal */
932 SendMessageA(hTree
, TVM_SETITEMHEIGHT
, 2*ulOldHeight
, 0);
933 ulNewHeight
= SendMessageA(hTree
, TVM_GETITEMHEIGHT
, 0, 0);
934 ok(ulNewHeight
== 2*ulOldHeight
, "New height not set properly, reported %d, expected %d\n", ulNewHeight
, 2*ulOldHeight
);
936 /* Assuming tree doesn't have TVS_NONEVENHEIGHT set, so a set of 9 will round down to 8 */
937 SendMessageA(hTree
, TVM_SETITEMHEIGHT
, 9, 0);
938 ulNewHeight
= SendMessageA(hTree
, TVM_GETITEMHEIGHT
, 0, 0);
939 ok(ulNewHeight
== 8, "Uneven height not set properly, reported %d, expected %d\n", ulNewHeight
, 8);
941 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, test_get_set_itemheight_seq
,
942 "test get set item height", FALSE
);
944 /* without TVS_NONEVENHEIGHT */
945 SetWindowLongA(hTree
, GWL_STYLE
, GetWindowLongA(hTree
, GWL_STYLE
) & ~TVS_NONEVENHEIGHT
);
947 ulOldHeight
= SendMessageA(hTree
, TVM_SETITEMHEIGHT
, 3, 0);
948 ok(ulOldHeight
== 8, "got %d, expected %d\n", ulOldHeight
, 8);
949 ulNewHeight
= SendMessageA(hTree
, TVM_GETITEMHEIGHT
, 0, 0);
950 ok(ulNewHeight
== 2, "got %d, expected %d\n", ulNewHeight
, 2);
952 ulOldHeight
= SendMessageA(hTree
, TVM_SETITEMHEIGHT
, 4, 0);
953 ok(ulOldHeight
== 2, "got %d, expected %d\n", ulOldHeight
, 2);
954 ulNewHeight
= SendMessageA(hTree
, TVM_GETITEMHEIGHT
, 0, 0);
955 ok(ulNewHeight
== 4, "got %d, expected %d\n", ulNewHeight
, 4);
957 /* with TVS_NONEVENHEIGHT */
958 SetWindowLongA(hTree
, GWL_STYLE
, GetWindowLongA(hTree
, GWL_STYLE
) | TVS_NONEVENHEIGHT
);
960 ulOldHeight
= SendMessageA(hTree
, TVM_SETITEMHEIGHT
, 3, 0);
961 ok(ulOldHeight
== 4, "got %d, expected %d\n", ulOldHeight
, 4);
962 ulNewHeight
= SendMessageA(hTree
, TVM_GETITEMHEIGHT
, 0, 0);
963 ok(ulNewHeight
== 3, "got %d, expected %d\n", ulNewHeight
, 3);
965 ulOldHeight
= SendMessageA(hTree
, TVM_SETITEMHEIGHT
, 10, 0);
966 ok(ulOldHeight
== 3, "got %d, expected %d\n", ulOldHeight
, 3);
967 ulNewHeight
= SendMessageA(hTree
, TVM_GETITEMHEIGHT
, 0, 0);
968 ok(ulNewHeight
== 10, "got %d, expected %d\n", ulNewHeight
, 10);
970 DestroyWindow(hTree
);
973 static void test_get_set_scrolltime(void)
975 int ulExpectedTime
= 20;
979 hTree
= create_treeview_control(0);
982 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
984 SendMessageA(hTree
, TVM_SETSCROLLTIME
, ulExpectedTime
, 0);
985 ulTime
= SendMessageA(hTree
, TVM_GETSCROLLTIME
, 0, 0);
986 ok(ulTime
== ulExpectedTime
, "Scroll time reported as %d, expected %d\n", ulTime
, ulExpectedTime
);
988 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, test_get_set_scrolltime_seq
,
989 "test get set scroll time", FALSE
);
991 DestroyWindow(hTree
);
994 static void test_get_set_textcolor(void)
996 /* If the value is -1, the control is using the system color for the text color. */
1000 hTree
= create_treeview_control(0);
1003 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1005 crColor
= SendMessageA(hTree
, TVM_GETTEXTCOLOR
, 0, 0);
1006 ok(crColor
== ~0u, "Default text color reported as 0x%.8x\n", crColor
);
1008 /* Test for black text */
1009 SendMessageA(hTree
, TVM_SETTEXTCOLOR
, 0, RGB(0,0,0));
1010 crColor
= SendMessageA(hTree
, TVM_GETTEXTCOLOR
, 0, 0);
1011 ok(crColor
== RGB(0,0,0), "Black text color reported as 0x%.8x\n", crColor
);
1013 /* Test for white text */
1014 SendMessageA(hTree
, TVM_SETTEXTCOLOR
, 0, RGB(255,255,255));
1015 crColor
= SendMessageA(hTree
, TVM_GETTEXTCOLOR
, 0, 0);
1016 ok(crColor
== RGB(255,255,255), "White text color reported as 0x%.8x\n", crColor
);
1018 /* Reset the default text color */
1019 SendMessageA(hTree
, TVM_SETTEXTCOLOR
, 0, CLR_NONE
);
1021 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, test_get_set_textcolor_seq
,
1022 "test get set text color", FALSE
);
1024 DestroyWindow(hTree
);
1027 static void test_get_set_tooltips(void)
1029 HWND hwndLastToolTip
= NULL
;
1030 HWND hPopupTreeView
;
1033 hTree
= create_treeview_control(0);
1036 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1038 /* show even WS_POPUP treeview don't send NM_TOOLTIPSCREATED */
1039 hPopupTreeView
= CreateWindowA(WC_TREEVIEWA
, NULL
, WS_POPUP
|WS_VISIBLE
, 0, 0, 100, 100,
1040 hMainWnd
, NULL
, NULL
, NULL
);
1041 DestroyWindow(hPopupTreeView
);
1043 /* Testing setting a NULL ToolTip */
1044 SendMessageA(hTree
, TVM_SETTOOLTIPS
, 0, 0);
1045 hwndLastToolTip
= (HWND
)SendMessageA(hTree
, TVM_GETTOOLTIPS
, 0, 0);
1046 ok(hwndLastToolTip
== NULL
, "NULL tool tip, reported as 0x%p, expected 0.\n", hwndLastToolTip
);
1048 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, test_get_set_tooltips_seq
,
1049 "test get set tooltips", TRUE
);
1051 /* TODO: Add a test of an actual tooltip */
1052 DestroyWindow(hTree
);
1055 static void test_get_set_unicodeformat(void)
1057 BOOL bPreviousSetting
;
1061 hTree
= create_treeview_control(0);
1064 /* Check that an invalid format returned by NF_QUERY defaults to ANSI */
1065 bPreviousSetting
= SendMessageA(hTree
, TVM_GETUNICODEFORMAT
, 0, 0);
1066 ok(bPreviousSetting
== FALSE
, "Format should be ANSI.\n");
1068 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1070 /* Set to Unicode */
1071 bPreviousSetting
= SendMessageA(hTree
, TVM_SETUNICODEFORMAT
, 1, 0);
1072 bNewSetting
= SendMessageA(hTree
, TVM_GETUNICODEFORMAT
, 0, 0);
1073 ok(bNewSetting
== TRUE
, "Unicode setting did not work.\n");
1076 SendMessageA(hTree
, TVM_SETUNICODEFORMAT
, 0, 0);
1077 bNewSetting
= SendMessageA(hTree
, TVM_GETUNICODEFORMAT
, 0, 0);
1078 ok(bNewSetting
== FALSE
, "ANSI setting did not work.\n");
1080 /* Revert to original setting */
1081 SendMessageA(hTree
, TVM_SETUNICODEFORMAT
, bPreviousSetting
, 0);
1083 ok_sequence(sequences
, TREEVIEW_SEQ_INDEX
, test_get_set_unicodeformat_seq
,
1084 "test get set unicode format", FALSE
);
1086 DestroyWindow(hTree
);
1089 static LRESULT CALLBACK
parent_wnd_proc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1091 static LONG defwndproc_counter
= 0;
1095 HTREEITEM visibleItem
;
1097 msg
.message
= message
;
1098 msg
.flags
= sent
|wparam
|lparam
;
1099 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
1100 msg
.wParam
= wParam
;
1101 msg
.lParam
= lParam
;
1102 if (message
== WM_NOTIFY
&& lParam
)
1103 msg
.id
= ((NMHDR
*)lParam
)->code
;
1107 /* log system messages, except for painting */
1108 if (message
< WM_USER
&&
1109 message
!= WM_PAINT
&&
1110 message
!= WM_ERASEBKGND
&&
1111 message
!= WM_NCPAINT
&&
1112 message
!= WM_NCHITTEST
&&
1113 message
!= WM_GETTEXT
&&
1114 message
!= WM_GETICON
&&
1115 message
!= WM_DEVICECHANGE
)
1117 add_message(sequences
, PARENT_SEQ_INDEX
, &msg
);
1121 case WM_NOTIFYFORMAT
:
1123 /* Make NF_QUERY return an invalid format to show that it defaults to ANSI */
1124 if (lParam
== NF_QUERY
) return 0;
1130 NMHDR
*pHdr
= (NMHDR
*)lParam
;
1132 ok(pHdr
->code
!= NM_TOOLTIPSCREATED
, "Treeview should not send NM_TOOLTIPSCREATED\n");
1133 if (pHdr
->idFrom
== 100)
1135 NMTREEVIEWA
*pTreeView
= (LPNMTREEVIEWA
) lParam
;
1138 case TVN_SELCHANGINGA
:
1140 IdentifyItem(pTreeView
->itemOld
.hItem
);
1141 IdentifyItem(pTreeView
->itemNew
.hItem
);
1143 case TVN_SELCHANGEDA
:
1145 IdentifyItem(pTreeView
->itemOld
.hItem
);
1146 IdentifyItem(pTreeView
->itemNew
.hItem
);
1148 case TVN_GETDISPINFOA
: {
1149 NMTVDISPINFOA
*disp
= (NMTVDISPINFOA
*)lParam
;
1150 if (disp
->item
.mask
& TVIF_TEXT
) {
1151 lstrcpynA(disp
->item
.pszText
, TEST_CALLBACK_TEXT
, disp
->item
.cchTextMax
);
1154 if (g_disp_A_to_W
&& (disp
->item
.mask
& TVIF_TEXT
)) {
1155 static const WCHAR testW
[] = {'T','E','S','T','2',0};
1157 disp
->hdr
.code
= TVN_GETDISPINFOW
;
1158 memcpy(disp
->item
.pszText
, testW
, sizeof(testW
));
1161 if (g_disp_set_stateimage
)
1163 ok(disp
->item
.mask
== TVIF_IMAGE
, "got %x\n", disp
->item
.mask
);
1164 /* both masks set here are necessary to change state bits */
1165 disp
->item
.mask
|= TVIF_STATE
;
1166 disp
->item
.state
= TVIS_SELECTED
| INDEXTOSTATEIMAGEMASK(2) | INDEXTOOVERLAYMASK(3);
1167 disp
->item
.stateMask
= TVIS_SELECTED
| TVIS_OVERLAYMASK
| TVIS_STATEIMAGEMASK
;
1172 case TVN_BEGINLABELEDITA
:
1174 if (g_beginedit_alter_text
)
1176 static const char* textA
= "<edittextaltered>";
1179 edit
= (HWND
)SendMessageA(pHdr
->hwndFrom
, TVM_GETEDITCONTROL
, 0, 0);
1180 ok(IsWindow(edit
), "failed to get edit handle\n");
1181 SetWindowTextA(edit
, textA
);
1187 case TVN_ENDLABELEDITA
: return TRUE
;
1188 case TVN_ITEMEXPANDINGA
:
1189 ok(pTreeView
->itemNew
.mask
==
1190 (TVIF_HANDLE
| TVIF_SELECTEDIMAGE
| TVIF_IMAGE
| TVIF_PARAM
| TVIF_STATE
),
1191 "got wrong mask %x\n", pTreeView
->itemNew
.mask
);
1192 ok(pTreeView
->itemOld
.mask
== 0,
1193 "got wrong mask %x\n", pTreeView
->itemOld
.mask
);
1195 if (g_get_from_expand
)
1197 g_item_expanding
.mask
= TVIF_STATE
;
1198 g_item_expanding
.hItem
= hRoot
;
1199 ret
= SendMessageA(pHdr
->hwndFrom
, TVM_GETITEMA
, 0, (LPARAM
)&g_item_expanding
);
1200 ok(ret
== TRUE
, "got %lu\n", ret
);
1203 case TVN_ITEMEXPANDEDA
:
1204 ok(pTreeView
->itemNew
.mask
& TVIF_STATE
, "got wrong mask %x\n", pTreeView
->itemNew
.mask
);
1205 ok(pTreeView
->itemNew
.state
& (TVIS_EXPANDED
|TVIS_EXPANDEDONCE
),
1206 "got wrong mask %x\n", pTreeView
->itemNew
.mask
);
1207 ok(pTreeView
->itemOld
.mask
== 0,
1208 "got wrong mask %x\n", pTreeView
->itemOld
.mask
);
1210 if (g_get_from_expand
)
1212 g_item_expanded
.mask
= TVIF_STATE
;
1213 g_item_expanded
.hItem
= hRoot
;
1214 ret
= SendMessageA(pHdr
->hwndFrom
, TVM_GETITEMA
, 0, (LPARAM
)&g_item_expanded
);
1215 ok(ret
== TRUE
, "got %lu\n", ret
);
1217 if (g_get_rect_in_expand
)
1219 visibleItem
= (HTREEITEM
)SendMessageA(pHdr
->hwndFrom
, TVM_GETNEXTITEM
,
1220 TVGN_FIRSTVISIBLE
, 0);
1221 ok(pTreeView
->itemNew
.hItem
== visibleItem
, "expanded item == first visible item\n");
1222 *(HTREEITEM
*)&rect
= visibleItem
;
1223 ok(SendMessageA(pHdr
->hwndFrom
, TVM_GETITEMRECT
, TRUE
, (LPARAM
)&rect
),
1224 "Failed to get rect for first visible item.\n");
1225 visibleItem
= (HTREEITEM
)SendMessageA(pHdr
->hwndFrom
, TVM_GETNEXTITEM
,
1226 TVGN_NEXTVISIBLE
, (LPARAM
)visibleItem
);
1227 *(HTREEITEM
*)&rect
= visibleItem
;
1228 ok(visibleItem
!= NULL
, "There must be a visible item after the first visisble item.\n");
1229 ok(SendMessageA(pHdr
->hwndFrom
, TVM_GETITEMRECT
, TRUE
, (LPARAM
)&rect
),
1230 "Failed to get rect for second visible item.\n");
1233 case TVN_DELETEITEMA
:
1235 struct message item
;
1237 ok(pTreeView
->itemNew
.mask
== 0, "got wrong mask 0x%x\n", pTreeView
->itemNew
.mask
);
1239 ok(pTreeView
->itemOld
.mask
== (TVIF_HANDLE
| TVIF_PARAM
), "got wrong mask 0x%x\n", pTreeView
->itemOld
.mask
);
1240 ok(pTreeView
->itemOld
.hItem
!= NULL
, "got %p\n", pTreeView
->itemOld
.hItem
);
1242 memset(&item
, 0, sizeof(item
));
1243 item
.lParam
= (LPARAM
)pTreeView
->itemOld
.hItem
;
1244 add_message(item_sequence
, 0, &item
);
1250 NMTVCUSTOMDRAW
*nmcd
= (NMTVCUSTOMDRAW
*)lParam
;
1251 COLORREF c0ffee
= RGB(0xc0,0xff,0xee), cafe
= RGB(0xca,0xfe,0x00);
1253 msg
.flags
|= custdraw
;
1254 msg
.stage
= nmcd
->nmcd
.dwDrawStage
;
1255 add_message(sequences
, PARENT_CD_SEQ_INDEX
, &msg
);
1260 return CDRF_NOTIFYITEMDRAW
|CDRF_NOTIFYITEMERASE
|CDRF_NOTIFYPOSTPAINT
;
1261 case CDDS_ITEMPREPAINT
:
1262 nmcd
->clrTextBk
= c0ffee
;
1263 nmcd
->clrText
= cafe
;
1264 if (g_customdraw_font
)
1265 SelectObject(nmcd
->nmcd
.hdc
, g_customdraw_font
);
1266 return CDRF_NOTIFYPOSTPAINT
|CDRF_NEWFONT
;
1267 case CDDS_ITEMPOSTPAINT
:
1268 /* at the point of post paint notification colors are already restored */
1269 ok(GetTextColor(nmcd
->nmcd
.hdc
) != cafe
, "got 0%x\n", GetTextColor(nmcd
->nmcd
.hdc
));
1270 ok(GetBkColor(nmcd
->nmcd
.hdc
) != c0ffee
, "got 0%x\n", GetBkColor(nmcd
->nmcd
.hdc
));
1271 if (g_customdraw_font
)
1272 ok(GetCurrentObject(nmcd
->nmcd
.hdc
, OBJ_FONT
) != g_customdraw_font
, "got %p\n",
1273 GetCurrentObject(nmcd
->nmcd
.hdc
, OBJ_FONT
));
1290 defwndproc_counter
++;
1291 ret
= DefWindowProcA(hWnd
, message
, wParam
, lParam
);
1292 defwndproc_counter
--;
1297 static void test_expandinvisible(void)
1299 static CHAR nodeText
[][5] = {"0", "1", "2", "3", "4"};
1300 TVINSERTSTRUCTA ins
;
1307 hTree
= create_treeview_control(0);
1309 /* The test builds the following tree and expands node 1, while node 0 is collapsed.
1319 ret
= SendMessageA(hTree
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
1320 ok(ret
== TRUE
, "ret\n");
1321 ins
.hParent
= TVI_ROOT
;
1322 ins
.hInsertAfter
= TVI_ROOT
;
1323 U(ins
).item
.mask
= TVIF_TEXT
;
1324 U(ins
).item
.pszText
= nodeText
[0];
1325 node
[0] = TreeView_InsertItemA(hTree
, &ins
);
1326 ok(node
[0] != NULL
, "failed to set node[0]\n");
1328 ins
.hInsertAfter
= TVI_LAST
;
1329 U(ins
).item
.mask
= TVIF_TEXT
;
1330 ins
.hParent
= node
[0];
1332 U(ins
).item
.pszText
= nodeText
[1];
1333 node
[1] = TreeView_InsertItemA(hTree
, &ins
);
1334 ok(node
[1] != NULL
, "failed to set node[1]\n");
1335 U(ins
).item
.pszText
= nodeText
[4];
1336 node
[4] = TreeView_InsertItemA(hTree
, &ins
);
1337 ok(node
[4] != NULL
, "failed to set node[4]\n");
1339 ins
.hParent
= node
[1];
1341 U(ins
).item
.pszText
= nodeText
[2];
1342 node
[2] = TreeView_InsertItemA(hTree
, &ins
);
1343 ok(node
[2] != NULL
, "failed to set node[2]\n");
1344 U(ins
).item
.pszText
= nodeText
[3];
1345 node
[3] = TreeView_InsertItemA(hTree
, &ins
);
1346 ok(node
[3] != NULL
, "failed to set node[3]\n");
1348 *(HTREEITEM
*)&dummyRect
= node
[1];
1349 nodeVisible
= SendMessageA(hTree
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&dummyRect
);
1350 ok(!nodeVisible
, "Node 1 should not be visible.\n");
1351 *(HTREEITEM
*)&dummyRect
= node
[2];
1352 nodeVisible
= SendMessageA(hTree
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&dummyRect
);
1353 ok(!nodeVisible
, "Node 2 should not be visible.\n");
1354 *(HTREEITEM
*)&dummyRect
= node
[3];
1355 nodeVisible
= SendMessageA(hTree
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&dummyRect
);
1356 ok(!nodeVisible
, "Node 3 should not be visible.\n");
1357 *(HTREEITEM
*)&dummyRect
= node
[4];
1358 nodeVisible
= SendMessageA(hTree
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&dummyRect
);
1359 ok(!nodeVisible
, "Node 4 should not be visible.\n");
1361 ok(SendMessageA(hTree
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)node
[1]), "Expand of node 1 failed.\n");
1363 *(HTREEITEM
*)&dummyRect
= node
[1];
1364 nodeVisible
= SendMessageA(hTree
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&dummyRect
);
1365 ok(!nodeVisible
, "Node 1 should not be visible.\n");
1366 *(HTREEITEM
*)&dummyRect
= node
[2];
1367 nodeVisible
= SendMessageA(hTree
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&dummyRect
);
1368 ok(!nodeVisible
, "Node 2 should not be visible.\n");
1369 *(HTREEITEM
*)&dummyRect
= node
[3];
1370 nodeVisible
= SendMessageA(hTree
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&dummyRect
);
1371 ok(!nodeVisible
, "Node 3 should not be visible.\n");
1372 *(HTREEITEM
*)&dummyRect
= node
[4];
1373 nodeVisible
= SendMessageA(hTree
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&dummyRect
);
1374 ok(!nodeVisible
, "Node 4 should not be visible.\n");
1376 DestroyWindow(hTree
);
1379 static void test_itemedit(void)
1387 hTree
= create_treeview_control(0);
1390 /* try with null item */
1391 edit
= (HWND
)SendMessageA(hTree
, TVM_EDITLABELA
, 0, 0);
1392 ok(!IsWindow(edit
), "Expected valid handle\n");
1395 edit
= (HWND
)SendMessageA(hTree
, TVM_EDITLABELA
, 0, (LPARAM
)hRoot
);
1396 ok(IsWindow(edit
), "Expected valid handle\n");
1397 /* item shouldn't be selected automatically after TVM_EDITLABELA */
1398 r
= SendMessageA(hTree
, TVM_GETITEMSTATE
, (WPARAM
)hRoot
, TVIS_SELECTED
);
1400 /* try to cancel with wrong edit handle */
1401 r
= SendMessageA(hTree
, WM_COMMAND
, MAKEWPARAM(0, EN_KILLFOCUS
), 0);
1403 ok(IsWindow(edit
), "Expected edit control to be valid\n");
1404 r
= SendMessageA(hTree
, WM_COMMAND
, MAKEWPARAM(0, EN_KILLFOCUS
), (LPARAM
)edit
);
1406 ok(!IsWindow(edit
), "Expected edit control to be destroyed\n");
1407 /* try to cancel without creating edit */
1408 r
= SendMessageA(hTree
, WM_COMMAND
, MAKEWPARAM(0, EN_KILLFOCUS
), 0);
1411 /* try to cancel with wrong (not null) handle */
1412 edit
= (HWND
)SendMessageA(hTree
, TVM_EDITLABELA
, 0, (LPARAM
)hRoot
);
1413 ok(IsWindow(edit
), "Expected valid handle\n");
1414 r
= SendMessageA(hTree
, WM_COMMAND
, MAKEWPARAM(0, EN_KILLFOCUS
), (LPARAM
)hTree
);
1416 ok(IsWindow(edit
), "Expected edit control to be valid\n");
1417 r
= SendMessageA(hTree
, WM_COMMAND
, MAKEWPARAM(0, EN_KILLFOCUS
), (LPARAM
)edit
);
1420 /* remove selection after starting edit */
1421 r
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hRoot
);
1423 edit
= (HWND
)SendMessageA(hTree
, TVM_EDITLABELA
, 0, (LPARAM
)hRoot
);
1424 ok(IsWindow(edit
), "Expected valid handle\n");
1425 r
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, 0);
1429 r
= SendMessageA(edit
, WM_SETTEXT
, 0, (LPARAM
)buffA
);
1431 r
= SendMessageA(hTree
, WM_COMMAND
, MAKEWPARAM(0, EN_KILLFOCUS
), (LPARAM
)edit
);
1433 ok(!IsWindow(edit
), "Expected edit control to be destroyed\n");
1434 /* check that text is saved */
1435 item
.mask
= TVIF_TEXT
;
1437 item
.pszText
= buffA
;
1438 item
.cchTextMax
= sizeof(buffA
)/sizeof(CHAR
);
1439 r
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1441 ok(!strcmp("x", buffA
), "Expected item text to change\n");
1443 /* try A/W messages */
1444 edit
= (HWND
)SendMessageA(hTree
, TVM_EDITLABELA
, 0, (LPARAM
)hRoot
);
1445 ok(IsWindow(edit
), "Expected valid handle\n");
1446 ok(IsWindowUnicode(edit
), "got ansi window\n");
1447 r
= SendMessageA(hTree
, WM_COMMAND
, MAKEWPARAM(0, EN_KILLFOCUS
), (LPARAM
)edit
);
1449 ok(!IsWindow(edit
), "expected invalid handle\n");
1451 edit
= (HWND
)SendMessageA(hTree
, TVM_EDITLABELW
, 0, (LPARAM
)hRoot
);
1452 ok(IsWindow(edit
), "Expected valid handle\n");
1453 ok(IsWindowUnicode(edit
), "got ansi window\n");
1454 r
= SendMessageA(hTree
, WM_COMMAND
, MAKEWPARAM(0, EN_KILLFOCUS
), (LPARAM
)edit
);
1457 /* alter text during TVM_BEGINLABELEDIT, check that it's preserved */
1458 strcpy(buffA
, "<root>");
1460 item
.mask
= TVIF_TEXT
;
1462 item
.pszText
= buffA
;
1463 item
.cchTextMax
= 0;
1464 r
= SendMessageA(hTree
, TVM_SETITEMA
, 0, (LPARAM
)&item
);
1467 g_beginedit_alter_text
= TRUE
;
1468 edit
= (HWND
)SendMessageA(hTree
, TVM_EDITLABELA
, 0, (LPARAM
)hRoot
);
1469 ok(IsWindow(edit
), "Expected valid handle\n");
1470 g_beginedit_alter_text
= FALSE
;
1472 GetWindowTextA(edit
, buffA
, sizeof(buffA
)/sizeof(CHAR
));
1473 ok(!strcmp(buffA
, "<edittextaltered>"), "got string %s\n", buffA
);
1475 DestroyWindow(hTree
);
1478 static void test_treeview_classinfo(void)
1482 memset(&cls
, 0, sizeof(cls
));
1483 GetClassInfoA(GetModuleHandleA("comctl32.dll"), WC_TREEVIEWA
, &cls
);
1484 ok(cls
.hbrBackground
== NULL
, "Expected NULL background brush, got %p\n", cls
.hbrBackground
);
1485 ok(cls
.style
== (CS_GLOBALCLASS
| CS_DBLCLKS
), "Expected got %x\n", cls
.style
);
1486 expect(0, cls
.cbClsExtra
);
1489 static void test_get_linecolor(void)
1494 hTree
= create_treeview_control(0);
1496 /* newly created control has default color */
1497 clr
= SendMessageA(hTree
, TVM_GETLINECOLOR
, 0, 0);
1499 win_skip("TVM_GETLINECOLOR is not supported on comctl32 < 5.80\n");
1501 expect(CLR_DEFAULT
, clr
);
1503 DestroyWindow(hTree
);
1506 static void test_get_insertmarkcolor(void)
1511 hTree
= create_treeview_control(0);
1513 /* newly created control has default color */
1514 clr
= SendMessageA(hTree
, TVM_GETINSERTMARKCOLOR
, 0, 0);
1516 win_skip("TVM_GETINSERTMARKCOLOR is not supported on comctl32 < 5.80\n");
1518 expect(CLR_DEFAULT
, clr
);
1520 DestroyWindow(hTree
);
1523 static void test_expandnotify(void)
1529 hTree
= create_treeview_control(0);
1533 item
.mask
= TVIF_STATE
;
1535 item
.state
= TVIS_EXPANDED
;
1536 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1538 ok((item
.state
& TVIS_EXPANDED
) == 0, "expected collapsed\n");
1540 /* preselect root node here */
1541 ret
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hRoot
);
1544 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1545 ret
= SendMessageA(hTree
, TVM_EXPAND
, TVE_COLLAPSE
, (LPARAM
)hRoot
);
1547 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
, "no collapse notifications", FALSE
);
1549 g_get_from_expand
= TRUE
;
1551 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1552 g_item_expanding
.state
= 0xdeadbeef;
1553 g_item_expanded
.state
= 0xdeadbeef;
1554 ret
= SendMessageA(hTree
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)hRoot
);
1556 ok(g_item_expanding
.state
== TVIS_SELECTED
, "got state on TVN_ITEMEXPANDING 0x%08x\n",
1557 g_item_expanding
.state
);
1558 ok(g_item_expanded
.state
== (TVIS_SELECTED
|TVIS_EXPANDED
), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1559 g_item_expanded
.state
);
1560 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_expand_seq
, "expand notifications", FALSE
);
1561 g_get_from_expand
= FALSE
;
1563 /* check that it's expanded */
1564 item
.state
= TVIS_EXPANDED
;
1565 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1567 ok((item
.state
& TVIS_EXPANDED
) == TVIS_EXPANDED
, "expected expanded\n");
1570 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1571 ret
= SendMessageA(hTree
, TVM_EXPAND
, TVE_COLLAPSE
, (LPARAM
)hRoot
);
1573 item
.state
= TVIS_EXPANDED
;
1574 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1576 ok((item
.state
& TVIS_EXPANDED
) == 0, "expected collapsed\n");
1577 /* all further collapse/expand attempts won't produce any notifications,
1578 the only way is to reset with all children removed */
1579 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
, "collapse after expand notifications", FALSE
);
1581 /* try to toggle child that doesn't have children itself */
1582 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1583 ret
= SendMessageA(hTree
, TVM_EXPAND
, TVE_TOGGLE
, (LPARAM
)hChild
);
1585 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
, "toggle node without children", FALSE
);
1587 DestroyWindow(hTree
);
1589 /* test TVM_GETITEMRECT inside TVN_ITEMEXPANDED notification */
1590 hTree
= create_treeview_control(0);
1592 g_get_rect_in_expand
= TRUE
;
1593 ret
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hChild
);
1595 g_get_rect_in_expand
= FALSE
;
1597 DestroyWindow(hTree
);
1599 /* TVE_TOGGLE acts as any other TVM_EXPAND */
1600 hTree
= create_treeview_control(0);
1603 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1604 ret
= SendMessageA(hTree
, TVM_EXPAND
, TVE_TOGGLE
, (LPARAM
)hRoot
);
1606 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_expand_seq
, "toggle node (expand)", FALSE
);
1608 /* toggle again - no notifications */
1609 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1610 ret
= SendMessageA(hTree
, TVM_EXPAND
, TVE_TOGGLE
, (LPARAM
)hRoot
);
1612 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
, "toggle node (collapse)", FALSE
);
1614 DestroyWindow(hTree
);
1616 /* some keyboard events are also translated to expand */
1617 hTree
= create_treeview_control(0);
1620 /* preselect root node here */
1621 ret
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hRoot
);
1624 g_get_from_expand
= TRUE
;
1625 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1626 ret
= SendMessageA(hTree
, WM_KEYDOWN
, VK_ADD
, 0);
1628 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_expand_kb_seq
, "expand node", FALSE
);
1629 ok(g_item_expanding
.state
== TVIS_SELECTED
, "got state on TVN_ITEMEXPANDING 0x%08x\n",
1630 g_item_expanding
.state
);
1631 ok(g_item_expanded
.state
== (TVIS_SELECTED
|TVIS_EXPANDED
), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1632 g_item_expanded
.state
);
1634 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1635 ret
= SendMessageA(hTree
, WM_KEYDOWN
, VK_ADD
, 0);
1637 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_expand_kb_seq
, "expand node again", FALSE
);
1638 ok(g_item_expanding
.state
== (TVIS_SELECTED
|TVIS_EXPANDED
|TVIS_EXPANDEDONCE
), "got state on TVN_ITEMEXPANDING 0x%08x\n",
1639 g_item_expanding
.state
);
1640 ok(g_item_expanded
.state
== (TVIS_SELECTED
|TVIS_EXPANDED
|TVIS_EXPANDEDONCE
), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1641 g_item_expanded
.state
);
1643 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1644 ret
= SendMessageA(hTree
, WM_KEYDOWN
, VK_SUBTRACT
, 0);
1646 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_expand_kb_seq
, "collapse node", FALSE
);
1647 ok(g_item_expanding
.state
== (TVIS_SELECTED
|TVIS_EXPANDED
|TVIS_EXPANDEDONCE
), "got state on TVN_ITEMEXPANDING 0x%08x\n",
1648 g_item_expanding
.state
);
1649 ok(g_item_expanded
.state
== (TVIS_SELECTED
|TVIS_EXPANDEDONCE
), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1650 g_item_expanded
.state
);
1652 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1653 ret
= SendMessageA(hTree
, WM_KEYDOWN
, VK_SUBTRACT
, 0);
1655 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_collapse_2nd_kb_seq
, "collapse node again", FALSE
);
1656 ok(g_item_expanding
.state
== (TVIS_SELECTED
|TVIS_EXPANDEDONCE
), "got state on TVN_ITEMEXPANDING 0x%08x\n",
1657 g_item_expanding
.state
);
1658 g_get_from_expand
= FALSE
;
1660 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1661 ret
= SendMessageA(hTree
, WM_KEYDOWN
, VK_ADD
, 0);
1663 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_expand_kb_seq
, "expand node", FALSE
);
1666 ret
= SendMessageA(hTree
, WM_KEYDOWN
, VK_RIGHT
, 0);
1669 /* try to expand child that doesn't have children itself */
1670 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1671 ret
= SendMessageA(hTree
, WM_KEYDOWN
, VK_ADD
, 0);
1673 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_expand_empty_kb_seq
, "expand node with no children", FALSE
);
1675 DestroyWindow(hTree
);
1678 static void test_expandedimage(void)
1684 hTree
= create_treeview_control(0);
1687 item
.mask
= TVIF_EXPANDEDIMAGE
;
1688 item
.iExpandedImage
= 1;
1690 ret
= SendMessageA(hTree
, TVM_SETITEMA
, 0, (LPARAM
)&item
);
1691 ok(ret
, "got %d\n", ret
);
1693 item
.mask
= TVIF_EXPANDEDIMAGE
;
1694 item
.iExpandedImage
= -1;
1696 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1697 ok(ret
, "got %d\n", ret
);
1699 if (item
.iExpandedImage
!= 1)
1701 win_skip("TVIF_EXPANDEDIMAGE not supported\n");
1702 DestroyWindow(hTree
);
1706 /* test for default iExpandedImage value */
1707 item
.mask
= TVIF_EXPANDEDIMAGE
;
1708 item
.iExpandedImage
= -1;
1709 item
.hItem
= hChild
;
1710 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1711 ok(ret
, "got %d\n", ret
);
1712 ok(item
.iExpandedImage
== (WORD
)I_IMAGENONE
, "got %d\n", item
.iExpandedImage
);
1714 DestroyWindow(hTree
);
1717 static void test_TVS_SINGLEEXPAND(void)
1720 HTREEITEM alpha
, bravo
, charlie
, delta
, echo
, foxtrot
, golf
, hotel
, india
, juliet
;
1721 TVINSERTSTRUCTA ins
;
1727 /* build a fairly complex tree
1748 { &alpha
, NULL
, TVIS_EXPANDEDONCE
},
1749 { &bravo
, &alpha
, TVIS_EXPANDEDONCE
},
1750 { &charlie
, &bravo
, 0 },
1751 { &delta
, &alpha
, TVIS_EXPANDEDONCE
},
1752 { &echo
, &delta
, 0 },
1753 { &foxtrot
, NULL
, TVIS_EXPANDEDONCE
|TVIS_EXPANDED
},
1754 { &golf
, &foxtrot
, TVIS_EXPANDEDONCE
|TVIS_EXPANDED
},
1755 { &hotel
, &golf
, 0 },
1756 { &india
, &golf
, TVIS_SELECTED
},
1757 { &juliet
, &foxtrot
, 0 }
1763 const struct message
*sequence
;
1767 { &alpha
, parent_singleexpand_seq0
},
1768 { &bravo
, parent_singleexpand_seq1
},
1769 { &delta
, parent_singleexpand_seq2
},
1770 { &foxtrot
, parent_singleexpand_seq3
},
1771 { &alpha
, parent_singleexpand_seq4
},
1772 { &golf
, parent_singleexpand_seq5
},
1773 { &hotel
, parent_singleexpand_seq6
},
1774 { &india
, parent_singleexpand_seq7
},
1775 { &india
, empty_seq
}
1778 hTree
= create_treeview_control(0);
1779 SetWindowLongA(hTree
, GWL_STYLE
, GetWindowLongA(hTree
, GWL_STYLE
) | TVS_SINGLEEXPAND
);
1780 /* to avoid painting related notifications */
1781 ShowWindow(hTree
, SW_HIDE
);
1782 for (i
= 0; i
< sizeof(items
)/sizeof(items
[0]); i
++)
1784 ins
.hParent
= items
[i
].parent
? *items
[i
].parent
: TVI_ROOT
;
1785 ins
.hInsertAfter
= TVI_FIRST
;
1786 U(ins
).item
.mask
= TVIF_TEXT
;
1787 U(ins
).item
.pszText
= foo
;
1788 *items
[i
].handle
= TreeView_InsertItemA(hTree
, &ins
);
1791 for (i
= 0; i
< sizeof(sequence_tests
)/sizeof(sequence_tests
[0]); i
++)
1793 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1794 ret
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)(*sequence_tests
[i
].select
));
1795 ok(ret
, "got %d\n", ret
);
1796 sprintf(context
, "singleexpand notifications %d", i
);
1797 ok_sequence(sequences
, PARENT_SEQ_INDEX
, sequence_tests
[i
].sequence
, context
, FALSE
);
1800 for (i
= 0; i
< sizeof(items
)/sizeof(items
[0]); i
++)
1802 ret
= SendMessageA(hTree
, TVM_GETITEMSTATE
, (WPARAM
)(*items
[i
].handle
), 0xFFFF);
1803 ok(ret
== items
[i
].final_state
, "singleexpand items[%d]: expected state 0x%x got 0x%x\n",
1804 i
, items
[i
].final_state
, ret
);
1807 /* a workaround for NT4 that sends expand notifications when nothing is about to expand */
1808 ret
= SendMessageA(hTree
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
1809 ok(ret
, "got %d\n", ret
);
1811 ret
= SendMessageA(hTree
, TVM_SELECTITEM
, TVGN_CARET
, 0);
1812 ok(ret
, "got %d\n", ret
);
1814 DestroyWindow(hTree
);
1817 static void test_WM_PAINT(void)
1825 hTree
= create_treeview_control(0);
1827 clr
= SendMessageA(hTree
, TVM_SETBKCOLOR
, 0, RGB(255, 0, 0));
1828 ok(clr
== ~0u, "got %d, expected -1\n", clr
);
1830 hdc
= GetDC(hMainWnd
);
1832 GetClientRect(hMainWnd
, &rc
);
1833 FillRect(hdc
, &rc
, GetStockObject(BLACK_BRUSH
));
1835 clr
= GetPixel(hdc
, 1, 1);
1836 ok(clr
== RGB(0, 0, 0), "got 0x%x\n", clr
);
1838 ret
= SendMessageA(hTree
, WM_PAINT
, (WPARAM
)hdc
, 0);
1839 ok(ret
== 0, "got %d\n", ret
);
1841 clr
= GetPixel(hdc
, 1, 1);
1842 ok(clr
== RGB(255, 0, 0) || broken(clr
== RGB(0, 0, 0)) /* win98 */,
1845 ReleaseDC(hMainWnd
, hdc
);
1847 DestroyWindow(hTree
);
1850 static void test_delete_items(void)
1852 const struct message
*msg
;
1856 hTree
= create_treeview_control(0);
1859 /* check delete order */
1860 flush_sequences(item_sequence
, 1);
1861 ret
= SendMessageA(hTree
, TVM_DELETEITEM
, 0, 0);
1862 ok(ret
== TRUE
, "got %d\n", ret
);
1864 msg
= item_sequence
[0]->sequence
;
1865 ok(item_sequence
[0]->count
== 2, "expected 2 items, got %d\n", item_sequence
[0]->count
);
1867 if (item_sequence
[0]->count
== 2)
1869 ok(msg
[0].lParam
== (LPARAM
)hChild
, "expected %p, got 0x%lx\n", hChild
, msg
[0].lParam
);
1870 ok(msg
[1].lParam
== (LPARAM
)hRoot
, "expected %p, got 0x%lx\n", hRoot
, msg
[1].lParam
);
1873 ret
= SendMessageA(hTree
, TVM_GETCOUNT
, 0, 0);
1874 ok(ret
== 0, "got %d\n", ret
);
1876 DestroyWindow(hTree
);
1879 static void test_cchildren(void)
1885 hTree
= create_treeview_control(0);
1888 ret
= SendMessageA(hTree
, TVM_DELETEITEM
, 0, (LPARAM
)hChild
);
1891 /* check cChildren - automatic mode */
1893 item
.mask
= TVIF_CHILDREN
;
1895 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1897 expect(0, item
.cChildren
);
1899 DestroyWindow(hTree
);
1902 hTree
= create_treeview_control(0);
1905 /* turn off automatic mode by setting cChildren explicitly */
1907 item
.mask
= TVIF_CHILDREN
;
1909 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1911 expect(1, item
.cChildren
);
1913 ret
= SendMessageA(hTree
, TVM_SETITEMA
, 0, (LPARAM
)&item
);
1916 ret
= SendMessageA(hTree
, TVM_DELETEITEM
, 0, (LPARAM
)hChild
);
1919 /* check cChildren */
1920 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
1923 expect(1, item
.cChildren
);
1925 DestroyWindow(hTree
);
1930 HTREEITEM parent
; /* for root value of parent field is unidetified */
1931 HTREEITEM nextsibling
;
1932 HTREEITEM firstchild
;
1935 static void _check_item(HTREEITEM item
, HTREEITEM parent
, HTREEITEM nextsibling
, HTREEITEM firstchild
, int line
)
1937 struct _ITEM_DATA
*data
= (struct _ITEM_DATA
*)item
;
1939 ok_(__FILE__
, line
)(data
->parent
== parent
, "parent %p, got %p\n", parent
, data
->parent
);
1940 ok_(__FILE__
, line
)(data
->nextsibling
== nextsibling
, "sibling %p, got %p\n", nextsibling
, data
->nextsibling
);
1941 ok_(__FILE__
, line
)(data
->firstchild
== firstchild
, "firstchild %p, got %p\n", firstchild
, data
->firstchild
);
1944 #define check_item(a, b, c, d) _check_item(a, b, c, d, __LINE__)
1946 static void test_htreeitem_layout(void)
1948 TVINSERTSTRUCTA ins
;
1949 HTREEITEM item1
, item2
;
1952 hTree
= create_treeview_control(0);
1955 /* root has some special pointer in parent field */
1956 check_item(hRoot
, ((struct _ITEM_DATA
*)hRoot
)->parent
, 0, hChild
);
1957 check_item(hChild
, hRoot
, 0, 0);
1959 ins
.hParent
= hChild
;
1960 ins
.hInsertAfter
= TVI_FIRST
;
1961 U(ins
).item
.mask
= 0;
1962 item1
= TreeView_InsertItemA(hTree
, &ins
);
1964 check_item(item1
, hChild
, 0, 0);
1966 ins
.hParent
= hRoot
;
1967 ins
.hInsertAfter
= TVI_FIRST
;
1968 U(ins
).item
.mask
= 0;
1969 item2
= TreeView_InsertItemA(hTree
, &ins
);
1971 check_item(item2
, hRoot
, hChild
, 0);
1973 SendMessageA(hTree
, TVM_DELETEITEM
, 0, (LPARAM
)hChild
);
1975 /* without children now */
1976 check_item(hRoot
, ((struct _ITEM_DATA
*)hRoot
)->parent
, 0, item2
);
1978 DestroyWindow(hTree
);
1981 static void test_TVS_CHECKBOXES(void)
1983 HIMAGELIST himl
, himl2
;
1989 hTree
= create_treeview_control(0);
1992 himl
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
1993 ok(himl
== NULL
, "got %p\n", himl
);
1996 item
.mask
= TVIF_STATE
;
1997 item
.state
= INDEXTOSTATEIMAGEMASK(1);
1998 item
.stateMask
= TVIS_STATEIMAGEMASK
;
1999 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2001 ok(item
.state
== 0, "got 0x%x\n", item
.state
);
2003 /* set some index for a child */
2004 item
.hItem
= hChild
;
2005 item
.mask
= TVIF_STATE
;
2006 item
.state
= INDEXTOSTATEIMAGEMASK(4);
2007 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2008 ret
= SendMessageA(hTree
, TVM_SETITEMA
, 0, (LPARAM
)&item
);
2011 /* enabling check boxes set all items to 1 state image index */
2012 SetWindowLongA(hTree
, GWL_STYLE
, GetWindowLongA(hTree
, GWL_STYLE
) | TVS_CHECKBOXES
);
2013 himl
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2014 ok(himl
!= NULL
, "got %p\n", himl
);
2016 himl2
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2017 ok(himl2
!= NULL
, "got %p\n", himl2
);
2018 ok(himl2
== himl
, "got %p, expected %p\n", himl2
, himl
);
2021 item
.mask
= TVIF_STATE
;
2023 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2024 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2026 ok(item
.state
== INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item
.state
);
2028 item
.hItem
= hChild
;
2029 item
.mask
= TVIF_STATE
;
2031 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2032 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2034 ok(item
.state
== INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item
.state
);
2036 /* create another control and check its checkbox list */
2037 hTree2
= create_treeview_control(0);
2040 /* set some index for a child */
2041 item
.hItem
= hChild
;
2042 item
.mask
= TVIF_STATE
;
2043 item
.state
= INDEXTOSTATEIMAGEMASK(4);
2044 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2045 ret
= SendMessageA(hTree2
, TVM_SETITEMA
, 0, (LPARAM
)&item
);
2048 /* enabling check boxes set all items to 1 state image index */
2049 SetWindowLongA(hTree2
, GWL_STYLE
, GetWindowLongA(hTree
, GWL_STYLE
) | TVS_CHECKBOXES
);
2050 himl2
= (HIMAGELIST
)SendMessageA(hTree2
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2051 ok(himl2
!= NULL
, "got %p\n", himl2
);
2052 ok(himl
!= himl2
, "got %p, expected %p\n", himl2
, himl
);
2054 DestroyWindow(hTree2
);
2055 DestroyWindow(hTree
);
2057 /* the same, but initially created with TVS_CHECKBOXES */
2058 hTree
= create_treeview_control(TVS_CHECKBOXES
);
2060 himl
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2061 ok(himl
== NULL
, "got %p\n", himl
);
2064 item
.mask
= TVIF_STATE
;
2066 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2067 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2069 ok(item
.state
== INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item
.state
);
2071 item
.hItem
= hChild
;
2072 item
.mask
= TVIF_STATE
;
2074 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2075 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2077 ok(item
.state
== INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item
.state
);
2079 item
.hItem
= hChild
;
2080 item
.mask
= TVIF_STATE
;
2081 item
.state
= INDEXTOSTATEIMAGEMASK(2);
2082 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2083 ret
= SendMessageA(hTree
, TVM_SETITEMA
, 0, (LPARAM
)&item
);
2086 item
.hItem
= hChild
;
2087 item
.mask
= TVIF_STATE
;
2089 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2091 ok(item
.state
== INDEXTOSTATEIMAGEMASK(2), "got 0x%x\n", item
.state
);
2093 while(GetMessageA(&msg
, 0, 0, 0))
2095 TranslateMessage(&msg
);
2096 DispatchMessageA(&msg
);
2098 if((msg
.hwnd
== hTree
) && (msg
.message
== WM_PAINT
))
2102 item
.hItem
= hChild
;
2103 item
.mask
= TVIF_STATE
;
2105 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2107 ok(item
.state
== INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item
.state
);
2109 himl
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2110 ok(himl
!= NULL
, "got %p\n", himl
);
2112 DestroyWindow(hTree
);
2114 /* check what happens if TVSIL_STATE image list is removed */
2115 hTree
= create_treeview_control(0);
2117 himl
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2118 ok(himl
== NULL
, "got %p\n", himl
);
2120 SetWindowLongA(hTree
, GWL_STYLE
, GetWindowLongA(hTree
, GWL_STYLE
) | TVS_CHECKBOXES
);
2121 himl
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2122 ok(himl
!= NULL
, "got %p\n", himl
);
2124 himl2
= (HIMAGELIST
)SendMessageA(hTree
, TVM_SETIMAGELIST
, TVSIL_STATE
, 0);
2125 ok(himl2
== himl
, "got %p\n", himl2
);
2127 himl2
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2128 ok(himl2
== NULL
, "got %p\n", himl2
);
2130 item
.hItem
= hChild
;
2131 item
.mask
= TVIF_STATE
;
2132 item
.state
= INDEXTOSTATEIMAGEMASK(2);
2133 item
.stateMask
= TVIS_STATEIMAGEMASK
;
2134 ret
= SendMessageA(hTree
, TVM_SETITEMA
, 0, (LPARAM
)&item
);
2137 item
.hItem
= hChild
;
2138 item
.mask
= TVIF_STATE
;
2140 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2142 ok(item
.state
== INDEXTOSTATEIMAGEMASK(2), "got 0x%x\n", item
.state
);
2144 while(GetMessageA(&msg
, 0, 0, 0))
2146 TranslateMessage(&msg
);
2147 DispatchMessageA(&msg
);
2149 if((msg
.hwnd
== hTree
) && (msg
.message
== WM_PAINT
))
2153 item
.hItem
= hChild
;
2154 item
.mask
= TVIF_STATE
;
2156 ret
= SendMessageA(hTree
, TVM_GETITEMA
, 0, (LPARAM
)&item
);
2158 ok(item
.state
== INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item
.state
);
2160 himl
= (HIMAGELIST
)SendMessageA(hTree
, TVM_GETIMAGELIST
, TVSIL_STATE
, 0);
2161 ok(himl
!= NULL
, "got %p\n", himl
);
2163 DestroyWindow(hTree
);
2166 static void test_TVM_GETNEXTITEM(void)
2171 hTree
= create_treeview_control(0);
2174 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_ROOT
, 0);
2175 ok(item
== hRoot
, "got %p, expected %p\n", item
, hRoot
);
2177 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_ROOT
, (LPARAM
)TVI_ROOT
);
2178 ok(item
== hRoot
, "got %p, expected %p\n", item
, hRoot
);
2180 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_ROOT
, (LPARAM
)hRoot
);
2181 ok(item
== hRoot
, "got %p, expected %p\n", item
, hRoot
);
2183 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_ROOT
, (LPARAM
)hChild
);
2184 ok(item
== hRoot
, "got %p, expected %p\n", item
, hRoot
);
2186 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_CHILD
, 0);
2187 ok(item
== hRoot
, "got %p, expected %p\n", item
, hRoot
);
2189 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_CHILD
, (LPARAM
)hRoot
);
2190 ok(item
== hChild
, "got %p, expected %p\n", item
, hChild
);
2192 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_CHILD
, (LPARAM
)TVI_ROOT
);
2193 ok(item
== hRoot
, "got %p, expected %p\n", item
, hRoot
);
2195 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_PARENT
, 0);
2196 ok(item
== NULL
, "got %p\n", item
);
2198 item
= (HTREEITEM
)SendMessageA(hTree
, TVM_GETNEXTITEM
, TVGN_PARENT
, (LPARAM
)hChild
);
2199 ok(item
== hRoot
, "got %p, expected %p\n", item
, hRoot
);
2201 DestroyWindow(hTree
);
2204 static void test_TVM_HITTEST(void)
2211 hTree
= create_treeview_control(0);
2214 *(HTREEITEM
*)&rc
= hRoot
;
2215 ret
= SendMessageA(hTree
, TVM_GETITEMRECT
, TRUE
, (LPARAM
)&rc
);
2216 expect(TRUE
, (BOOL
)ret
);
2218 ht
.pt
.x
= rc
.left
-1;
2221 ret
= SendMessageA(hTree
, TVM_HITTEST
, 0, (LPARAM
)&ht
);
2222 ok((HTREEITEM
)ret
== hRoot
, "got %p, expected %p\n", (HTREEITEM
)ret
, hRoot
);
2223 ok(ht
.hItem
== hRoot
, "got %p, expected %p\n", ht
.hItem
, hRoot
);
2224 ok(ht
.flags
== TVHT_ONITEMBUTTON
, "got %d, expected %d\n", ht
.flags
, TVHT_ONITEMBUTTON
);
2226 ret
= SendMessageA(hTree
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)hRoot
);
2227 expect(TRUE
, (BOOL
)ret
);
2229 *(HTREEITEM
*)&rc
= hChild
;
2230 ret
= SendMessageA(hTree
, TVM_GETITEMRECT
, TRUE
, (LPARAM
)&rc
);
2231 expect(TRUE
, (BOOL
)ret
);
2233 ht
.pt
.x
= rc
.left
-1;
2236 ret
= SendMessageA(hTree
, TVM_HITTEST
, 0, (LPARAM
)&ht
);
2237 ok((HTREEITEM
)ret
== hChild
, "got %p, expected %p\n", (HTREEITEM
)ret
, hChild
);
2238 ok(ht
.hItem
== hChild
, "got %p, expected %p\n", ht
.hItem
, hChild
);
2239 /* Wine returns item button here, but this item has no button */
2240 todo_wine
ok(ht
.flags
== TVHT_ONITEMINDENT
, "got %d, expected %d\n", ht
.flags
, TVHT_ONITEMINDENT
);
2242 DestroyWindow(hTree
);
2245 static void test_WM_GETDLGCODE(void)
2250 hTree
= create_treeview_control(0);
2252 code
= SendMessageA(hTree
, WM_GETDLGCODE
, VK_TAB
, 0);
2253 ok(code
== (DLGC_WANTCHARS
| DLGC_WANTARROWS
), "0x%08x\n", code
);
2255 DestroyWindow(hTree
);
2258 static void test_customdraw(void)
2260 static const char *rootA
= "root";
2261 TVINSERTSTRUCTA ins
;
2266 hwnd
= create_treeview_control(0);
2268 ins
.hParent
= TVI_ROOT
;
2269 ins
.hInsertAfter
= TVI_ROOT
;
2270 U(ins
).item
.mask
= TVIF_TEXT
;
2271 U(ins
).item
.pszText
= (char*)rootA
;
2272 hRoot
= TreeView_InsertItemA(hwnd
, &ins
);
2273 ok(hRoot
!= NULL
, "got %p\n", hRoot
);
2275 /* create additional font, custom draw handler will select it */
2276 SystemParametersInfoA(SPI_GETICONTITLELOGFONT
, sizeof(lf
), &lf
, 0);
2278 g_customdraw_font
= CreateFontIndirectA(&lf
);
2279 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2280 InvalidateRect(hwnd
, NULL
, TRUE
);
2282 ok_sequence(sequences
, PARENT_CD_SEQ_INDEX
, parent_cd_seq
, "custom draw notifications", FALSE
);
2283 DeleteObject(g_customdraw_font
);
2284 g_customdraw_font
= NULL
;
2286 DestroyWindow(hwnd
);
2289 static void test_WM_KEYDOWN(void)
2291 static const char *rootA
= "root";
2292 TVINSERTSTRUCTA ins
;
2296 hwnd
= create_treeview_control(0);
2298 ins
.hParent
= TVI_ROOT
;
2299 ins
.hInsertAfter
= TVI_ROOT
;
2300 U(ins
).item
.mask
= TVIF_TEXT
;
2301 U(ins
).item
.pszText
= (char*)rootA
;
2302 hRoot
= TreeView_InsertItemA(hwnd
, &ins
);
2303 ok(hRoot
!= NULL
, "got %p\n", hRoot
);
2305 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2306 SendMessageA(hwnd
, WM_KEYDOWN
, VK_RETURN
, 0);
2307 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_vk_return_seq
, "WM_KEYDOWN/VK_RETURN parent notification", TRUE
);
2309 DestroyWindow(hwnd
);
2312 START_TEST(treeview
)
2315 BOOL (WINAPI
*pInitCommonControlsEx
)(const INITCOMMONCONTROLSEX
*);
2319 ULONG_PTR ctx_cookie
;
2322 hComctl32
= GetModuleHandleA("comctl32.dll");
2323 pInitCommonControlsEx
= (void*)GetProcAddress(hComctl32
, "InitCommonControlsEx");
2324 if (pInitCommonControlsEx
)
2326 INITCOMMONCONTROLSEX iccex
;
2327 iccex
.dwSize
= sizeof(iccex
);
2328 iccex
.dwICC
= ICC_TREEVIEW_CLASSES
;
2329 pInitCommonControlsEx(&iccex
);
2332 InitCommonControls();
2334 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
2335 init_msg_sequences(item_sequence
, 1);
2337 wc
.style
= CS_HREDRAW
| CS_VREDRAW
;
2340 wc
.hInstance
= GetModuleHandleA(NULL
);
2342 wc
.hCursor
= LoadCursorA(NULL
, (LPCSTR
)IDC_IBEAM
);
2343 wc
.hbrBackground
= GetSysColorBrush(COLOR_WINDOW
);
2344 wc
.lpszMenuName
= NULL
;
2345 wc
.lpszClassName
= "MyTestWnd";
2346 wc
.lpfnWndProc
= parent_wnd_proc
;
2347 RegisterClassA(&wc
);
2349 hMainWnd
= CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW
,
2350 CW_USEDEFAULT
, CW_USEDEFAULT
, 130, 105, NULL
, NULL
, GetModuleHandleA(NULL
), 0);
2352 ok(hMainWnd
!= NULL
, "Failed to create parent window. Tests aborted.\n");
2353 if (!hMainWnd
) return;
2359 test_get_set_bkcolor();
2360 test_get_set_imagelist();
2361 test_get_set_indent();
2362 test_get_set_insertmark();
2363 test_get_set_item();
2364 test_get_set_itemheight();
2365 test_get_set_scrolltime();
2366 test_get_set_textcolor();
2367 test_get_linecolor();
2368 test_get_insertmarkcolor();
2369 test_get_set_tooltips();
2370 test_get_set_unicodeformat();
2372 test_expandinvisible();
2374 test_treeview_classinfo();
2375 test_expandnotify();
2376 test_TVS_SINGLEEXPAND();
2378 test_delete_items();
2380 test_htreeitem_layout();
2381 test_TVS_CHECKBOXES();
2382 test_TVM_GETNEXTITEM();
2384 test_WM_GETDLGCODE();
2388 if (!load_v6_module(&ctx_cookie
, &hCtx
))
2390 DestroyWindow(hMainWnd
);
2394 /* comctl32 version 6 tests start here */
2395 test_expandedimage();
2396 test_htreeitem_layout();
2397 test_WM_GETDLGCODE();
2399 unload_v6_module(ctx_cookie
, hCtx
);
2401 PostMessageA(hMainWnd
, WM_CLOSE
, 0, 0);
2402 while(GetMessageA(&msg
, 0, 0, 0))
2404 TranslateMessage(&msg
);
2405 DispatchMessageA(&msg
);