Newer
Older
/* Unit tests for treeview.
*
* Copyright 2005 Krzysztof Foltman
* Copyright 2007 Christopher James Peterson
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "winreg.h"
#include "commctrl.h"
#include "wine/test.h"
#include "v6util.h"
static BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
static const char *TEST_CALLBACK_TEXT = "callback_text";
Mikołaj Zalewski
committed
Nikolay Sivov
committed
static TVITEMA g_item_expanding, g_item_expanded;
static BOOL g_get_from_expand;
static BOOL g_get_rect_in_expand;
static BOOL g_disp_A_to_W;
static BOOL g_disp_set_stateimage;
static BOOL g_beginedit_alter_text;
static HFONT g_customdraw_font;
Huw Davies
committed
static BOOL g_v6;
Nikolay Sivov
committed
#define NUM_MSG_SEQUENCES 3
#define PARENT_SEQ_INDEX 1
#define PARENT_CD_SEQ_INDEX 2
Nikolay Sivov
committed
#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
static struct msg_sequence *item_sequence[1];
static void flush_events(void)
{
MSG msg;
int diff = 200;
int min_timeout = 100;
DWORD time = GetTickCount() + diff;
while (diff > 0)
{
if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT) break;
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
diff = time - GetTickCount();
}
}
static const struct message FillRootSeq[] = {
{ TVM_INSERTITEMA, sent },
{ TVM_INSERTITEMA, sent },
Nikolay Sivov
committed
static const struct message rootnone_select_seq[] = {
{ TVM_SELECTITEM, sent|wparam, 9 },
{ TVM_SELECTITEM, sent|wparam, 9 },
{ TVM_SELECTITEM, sent|wparam, 9 },
{ TVM_SELECTITEM, sent|wparam, 9 },
{ TVM_SELECTITEM, sent|wparam, 9 },
{ TVM_SELECTITEM, sent|wparam, 9 },
Nikolay Sivov
committed
static const struct message rootchild_select_seq[] = {
{ TVM_SELECTITEM, sent|wparam, 9 },
{ TVM_SELECTITEM, sent|wparam, 9 },
{ TVM_SELECTITEM, sent|wparam, 9 },
{ TVM_SELECTITEM, sent|wparam, 9 },
{ TVM_SELECTITEM, sent|wparam, 9 },
{ TVM_SELECTITEM, sent|wparam, 9 },
Nikolay Sivov
committed
static const struct message getitemtext_seq[] = {
Nikolay Sivov
committed
{ TVM_INSERTITEMA, sent },
{ TVM_GETITEMA, sent },
{ TVM_DELETEITEM, sent },
{ 0 }
};
Nikolay Sivov
committed
static const struct message focus_seq[] = {
{ TVM_INSERTITEMA, sent },
{ TVM_INSERTITEMA, sent },
Nikolay Sivov
committed
{ TVM_SELECTITEM, sent|wparam, 9 },
/* The following end up out of order in wine */
{ WM_WINDOWPOSCHANGING, sent|defwinproc },
Nikolay Sivov
committed
{ WM_NCCALCSIZE, sent|wparam|defwinproc, TRUE },
{ WM_WINDOWPOSCHANGED, sent|defwinproc },
{ WM_SIZE, sent|defwinproc },
{ WM_WINDOWPOSCHANGING, sent|defwinproc|optional },
{ WM_NCCALCSIZE, sent|wparam|defwinproc|optional, TRUE },
{ WM_WINDOWPOSCHANGED, sent|defwinproc|optional },
{ WM_SIZE, sent|defwinproc|optional },
{ WM_PAINT, sent|defwinproc },
Nikolay Sivov
committed
{ WM_NCPAINT, sent|wparam|defwinproc, 1 },
{ WM_ERASEBKGND, sent|defwinproc },
{ TVM_EDITLABELA, sent },
Nikolay Sivov
committed
{ WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_UPDATE) },
{ WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_CHANGE) },
{ WM_PARENTNOTIFY, sent|wparam|defwinproc, MAKEWPARAM(WM_CREATE, 0) },
{ WM_KILLFOCUS, sent|defwinproc },
{ WM_PAINT, sent|defwinproc },
{ WM_IME_SETCONTEXT, sent|defwinproc|optional },
Nikolay Sivov
committed
{ WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_SETFOCUS) },
{ WM_ERASEBKGND, sent|defwinproc|optional },
{ WM_CTLCOLOREDIT, sent|defwinproc|optional },
{ WM_CTLCOLOREDIT, sent|defwinproc|optional },
static const struct message test_get_set_bkcolor_seq[] = {
Nikolay Sivov
committed
{ TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
{ TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0 },
{ TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
{ TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0x00ffffff },
{ TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
{ TVM_SETBKCOLOR, sent|wparam|lparam, 0, -1 },
static const struct message test_get_set_imagelist_seq[] = {
Nikolay Sivov
committed
{ TVM_SETIMAGELIST, sent|wparam|lparam, 0, 0 },
{ TVM_GETIMAGELIST, sent|wparam|lparam, 0, 0 },
static const struct message test_get_set_indent_seq[] = {
Nikolay Sivov
committed
{ TVM_SETINDENT, sent|wparam|lparam, 0, 0 },
{ TVM_GETINDENT, sent|wparam|lparam, 0, 0 },
/* The actual amount to indent is dependent on the system for this message */
{ TVM_SETINDENT, sent },
Nikolay Sivov
committed
{ TVM_GETINDENT, sent|wparam|lparam, 0, 0 },
static const struct message test_get_set_insertmarkcolor_seq[] = {
Nikolay Sivov
committed
{ TVM_SETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 },
{ TVM_GETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 },
static const struct message test_get_set_item_seq[] = {
Nikolay Sivov
committed
{ TVM_GETITEMA, sent },
{ TVM_SETITEMA, sent },
{ TVM_GETITEMA, sent },
{ TVM_SETITEMA, sent },
static const struct message test_get_set_itemheight_seq[] = {
Nikolay Sivov
committed
{ TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
{ TVM_SETITEMHEIGHT, sent|wparam|lparam, -1, 0 },
{ TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
{ TVM_SETITEMHEIGHT, sent|lparam, 0xcccccccc, 0 },
{ TVM_GETITEMHEIGHT, sent|wparam|lparam|optional, 0, 0 },
{ TVM_SETITEMHEIGHT, sent|wparam|lparam|optional, 9, 0 },
{ TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
static const struct message test_get_set_scrolltime_seq[] = {
Nikolay Sivov
committed
{ TVM_SETSCROLLTIME, sent|wparam|lparam, 20, 0 },
{ TVM_GETSCROLLTIME, sent|wparam|lparam, 0, 0 },
static const struct message test_get_set_textcolor_seq[] = {
Nikolay Sivov
committed
{ TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
{ TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
{ TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
{ TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, RGB(255, 255, 255) },
Nikolay Sivov
committed
{ TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
{ TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, CLR_NONE },
static const struct message test_get_set_tooltips_seq[] = {
Nikolay Sivov
committed
{ WM_KILLFOCUS, sent },
{ WM_IME_SETCONTEXT, sent|optional },
{ WM_IME_NOTIFY, sent|optional },
Nikolay Sivov
committed
{ TVM_SETTOOLTIPS, sent|wparam|lparam, 0, 0 },
{ TVM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 },
static const struct message test_get_set_unicodeformat_seq[] = {
Nikolay Sivov
committed
{ TVM_SETUNICODEFORMAT, sent|wparam|lparam, TRUE, 0 },
{ TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
{ TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
{ TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
{ TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
static const struct message test_right_click_seq[] = {
{ WM_RBUTTONDOWN, sent|wparam, MK_RBUTTON },
{ WM_CAPTURECHANGED, sent|defwinproc },
{ TVM_GETNEXTITEM, sent|wparam|lparam|defwinproc, TVGN_CARET, 0 },
{ WM_NCHITTEST, sent|optional },
{ WM_SETCURSOR, sent|optional },
{ WM_MOUSEMOVE, sent|optional },
{ 0 }
};
static const struct message parent_expand_seq[] = {
Nikolay Sivov
committed
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
Daniel Jelinski
committed
static const struct message parent_expand_kb_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, TVN_KEYDOWN },
Daniel Jelinski
committed
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
{ WM_CHANGEUISTATE, sent|optional },
{ 0 }
};
Daniel Jelinski
committed
static const struct message parent_collapse_2nd_kb_seq[] = {
{ WM_NOTIFY, sent|id|optional, 0, 0, TVN_KEYDOWN },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
{ WM_CHANGEUISTATE, sent|optional },
{ 0 }
};
Daniel Jelinski
committed
static const struct message parent_expand_empty_kb_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, TVN_KEYDOWN },
Daniel Jelinski
committed
{ WM_CHANGEUISTATE, sent|optional },
{ 0 }
};
static const struct message parent_singleexpand_seq0[] = {
/* alpha expands */
{ WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
{ 0 }
};
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
static const struct message parent_singleexpand_seq1[] = {
/* bravo expands */
{ WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
{ 0 }
};
static const struct message parent_singleexpand_seq2[] = {
/* delta expands, bravo collapses */
{ WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
{ 0 }
};
static const struct message parent_singleexpand_seq3[] = {
/* foxtrot expands, alpha and delta collapse */
{ WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
{ 0 }
};
static const struct message parent_singleexpand_seq4[] = {
/* alpha expands, foxtrot collapses */
{ WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
{ 0 }
};
static const struct message parent_singleexpand_seq5[] = {
/* foxtrot expands while golf is selected, then golf expands and alpha collapses */
{ WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
{ 0 }
};
static const struct message parent_singleexpand_seq6[] = {
/* hotel does not expand and india does not collapse because they have no children */
{ WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
{ 0 }
};
static const struct message parent_singleexpand_seq7[] = {
/* india does not expand and hotel does not collapse because they have no children */
{ WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
{ WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
{ 0 }
};
static const struct message parent_get_dispinfo_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, TVN_GETDISPINFOA },
{ 0 }
};
static const struct message empty_seq[] = {
{ 0 }
};
static const struct message parent_cd_seq[] = {
{ WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
{ WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT },
{ WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT },
{ WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT },
{ WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT },
{ WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
{ 0 }
};
static const struct message parent_vk_return_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, TVN_KEYDOWN },
{ WM_NOTIFY, sent|id, 0, 0, NM_RETURN },
{ WM_CHANGEUISTATE, sent|optional },
{ 0 }
};
static const struct message parent_right_click_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, NM_RCLICK },
{ WM_CONTEXTMENU, sent },
{ WM_NOTIFY, sent|optional },
{ WM_SETCURSOR, sent|optional },
{ 0 }
};
static HWND hMainWnd;
static HTREEITEM hRoot, hChild;
static int pos = 0;
static char sequence[256];
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
{
pos = 0;
sequence[0] = '\0';
}
static void AddItem(char ch)
{
sequence[pos++] = ch;
sequence[pos] = '\0';
}
static void IdentifyItem(HTREEITEM hItem)
{
if (hItem == hRoot) {
AddItem('R');
return;
}
if (hItem == hChild) {
AddItem('C');
return;
}
if (hItem == NULL) {
AddItem('n');
return;
}
AddItem('?');
}
Nikolay Sivov
committed
/* This function hooks in and records all messages to the treeview control */
static LRESULT WINAPI TreeviewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static LONG defwndproc_counter = 0;
LRESULT ret;
WNDPROC lpOldProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
struct message msg = { 0 };
Nikolay Sivov
committed
msg.message = message;
msg.flags = sent|wparam|lparam;
if (defwndproc_counter) msg.flags |= defwinproc;
msg.wParam = wParam;
msg.lParam = lParam;
add_message(sequences, TREEVIEW_SEQ_INDEX, &msg);
Nikolay Sivov
committed
defwndproc_counter++;
ret = CallWindowProcA(lpOldProc, hwnd, message, wParam, lParam);
defwndproc_counter--;
return ret;
}
Nikolay Sivov
committed
static HWND create_treeview_control(DWORD style)
Nikolay Sivov
committed
{
WNDPROC pOldWndProc;
HWND hTree;
hTree = CreateWindowExA(WS_EX_CLIENTEDGE, WC_TREEVIEWA, NULL, WS_CHILD|WS_VISIBLE|
Nikolay Sivov
committed
TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS|TVS_EDITLABELS|style,
Nikolay Sivov
committed
0, 0, 120, 100, hMainWnd, (HMENU)100, GetModuleHandleA(0), 0);
SetFocus(hTree);
/* Record the old WNDPROC so we can call it after recording the messages */
pOldWndProc = (WNDPROC)SetWindowLongPtrA(hTree, GWLP_WNDPROC, (LONG_PTR)TreeviewWndProc);
SetWindowLongPtrA(hTree, GWLP_USERDATA, (LONG_PTR)pOldWndProc);
return hTree;
}
static void fill_tree(HWND hTree)
{
TVINSERTSTRUCTA ins;
static CHAR root[] = "Root",
child[] = "Child";
ins.hParent = TVI_ROOT;
ins.hInsertAfter = TVI_ROOT;
U(ins).item.mask = TVIF_TEXT;
hRoot = TreeView_InsertItemA(hTree, &ins);
ins.hParent = hRoot;
ins.hInsertAfter = TVI_FIRST;
U(ins).item.mask = TVIF_TEXT;
U(ins).item.pszText = child;
hChild = TreeView_InsertItemA(hTree, &ins);
Nikolay Sivov
committed
}
static void test_fillroot(void)
{
Nikolay Sivov
committed
TVITEMA tvi;
HWND hTree;
Nikolay Sivov
committed
Nikolay Sivov
committed
hTree = create_treeview_control(0);
Nikolay Sivov
committed
flush_sequences(sequences, NUM_MSG_SEQUENCES);
Nikolay Sivov
committed
fill_tree(hTree);
Clear();
AddItem('A');
ok(hRoot != NULL, "failed to set root\n");
Nikolay Sivov
committed
AddItem('B');
ok(hChild != NULL, "failed to set child\n");
AddItem('.');
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, FillRootSeq, "FillRoot", FALSE);
ok(!strcmp(sequence, "AB."), "Item creation\n");
Nikolay Sivov
committed
/* UMLPad 1.15 depends on this being not -1 (I_IMAGECALLBACK) */
tvi.hItem = hRoot;
tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&tvi);
Nikolay Sivov
committed
ok(tvi.iImage == 0, "tvi.iImage=%d\n", tvi.iImage);
ok(tvi.iSelectedImage == 0, "tvi.iSelectedImage=%d\n", tvi.iSelectedImage);
DestroyWindow(hTree);
Nikolay Sivov
committed
static void test_callback(void)
Mikołaj Zalewski
committed
{
HTREEITEM hRoot;
HTREEITEM hItem1, hItem2;
TVINSERTSTRUCTA ins;
Nikolay Sivov
committed
TVITEMA tvi;
Mikołaj Zalewski
committed
CHAR test_string[] = "Test_string";
Nikolay Sivov
committed
static const CHAR test2A[] = "TEST2";
Mikołaj Zalewski
committed
CHAR buf[128];
HWND hTree;
DWORD ret;
Mikołaj Zalewski
committed
Nikolay Sivov
committed
hTree = create_treeview_control(0);
Nikolay Sivov
committed
ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
expect(TRUE, ret);
Mikołaj Zalewski
committed
ins.hParent = TVI_ROOT;
ins.hInsertAfter = TVI_ROOT;
U(ins).item.mask = TVIF_TEXT;
U(ins).item.pszText = LPSTR_TEXTCALLBACKA;
hRoot = TreeView_InsertItemA(hTree, &ins);
ok(hRoot != NULL, "failed to set root\n");
Mikołaj Zalewski
committed
tvi.hItem = hRoot;
tvi.mask = TVIF_TEXT;
tvi.pszText = buf;
tvi.cchTextMax = ARRAY_SIZE(buf);
ret = TreeView_GetItemA(hTree, &tvi);
expect(TRUE, ret);
Mikołaj Zalewski
committed
ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Callback item text mismatch %s vs %s\n",
tvi.pszText, TEST_CALLBACK_TEXT);
ins.hParent = hRoot;
ins.hInsertAfter = TVI_FIRST;
U(ins).item.mask = TVIF_TEXT;
U(ins).item.pszText = test_string;
hItem1 = TreeView_InsertItemA(hTree, &ins);
ok(hItem1 != NULL, "failed to set Item1\n");
Mikołaj Zalewski
committed
tvi.hItem = hItem1;
ret = TreeView_GetItemA(hTree, &tvi);
expect(TRUE, ret);
Mikołaj Zalewski
committed
ok(strcmp(tvi.pszText, test_string) == 0, "Item text mismatch %s vs %s\n",
tvi.pszText, test_string);
/* undocumented: pszText of NULL also means LPSTR_CALLBACK: */
tvi.pszText = NULL;
ret = TreeView_SetItemA(hTree, &tvi);
expect(TRUE, ret);
Mikołaj Zalewski
committed
tvi.pszText = buf;
ret = TreeView_GetItemA(hTree, &tvi);
expect(TRUE, ret);
ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
Mikołaj Zalewski
committed
tvi.pszText, TEST_CALLBACK_TEXT);
U(ins).item.pszText = NULL;
hItem2 = TreeView_InsertItemA(hTree, &ins);
ok(hItem2 != NULL, "failed to set Item2\n");
Mikołaj Zalewski
committed
tvi.hItem = hItem2;
memset(buf, 0, sizeof(buf));
ret = TreeView_GetItemA(hTree, &tvi);
expect(TRUE, ret);
ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
Mikołaj Zalewski
committed
tvi.pszText, TEST_CALLBACK_TEXT);
Nikolay Sivov
committed
Nikolay Sivov
committed
/* notification handler changed A->W */
g_disp_A_to_W = TRUE;
tvi.hItem = hItem2;
memset(buf, 0, sizeof(buf));
ret = TreeView_GetItemA(hTree, &tvi);
expect(TRUE, ret);
Nikolay Sivov
committed
ok(strcmp(tvi.pszText, test2A) == 0, "got %s, expected %s\n",
tvi.pszText, test2A);
g_disp_A_to_W = FALSE;
/* handler changes state image index */
SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_CHECKBOXES);
/* clear selection, handler will set selected state */
ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0);
expect(TRUE, ret);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
tvi.hItem = hRoot;
tvi.mask = TVIF_STATE;
tvi.state = TVIS_SELECTED;
ret = TreeView_GetItemA(hTree, &tvi);
expect(TRUE, ret);
Nikolay Sivov
committed
ok(tvi.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", tvi.state);
ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
"no TVN_GETDISPINFO for a state seq", FALSE);
tvi.hItem = hRoot;
tvi.mask = TVIF_IMAGE | TVIF_STATE;
tvi.state = TVIS_FOCUSED;
tvi.stateMask = TVIS_FOCUSED;
tvi.iImage = I_IMAGECALLBACK;
ret = TreeView_SetItemA(hTree, &tvi);
expect(TRUE, ret);
/* ask for item image index through callback - state is also set with state image index */
flush_sequences(sequences, NUM_MSG_SEQUENCES);
tvi.hItem = hRoot;
tvi.mask = TVIF_IMAGE;
tvi.state = 0;
ret = TreeView_GetItemA(hTree, &tvi);
expect(TRUE, ret);
Nikolay Sivov
committed
ok(tvi.state == (INDEXTOSTATEIMAGEMASK(1) | TVIS_FOCUSED), "got 0x%x\n", tvi.state);
ok_sequence(sequences, PARENT_SEQ_INDEX, parent_get_dispinfo_seq,
"callback for state/overlay image index, noop seq", FALSE);
/* ask for image again and overwrite state to some value in handler */
flush_sequences(sequences, NUM_MSG_SEQUENCES);
g_disp_set_stateimage = TRUE;
tvi.hItem = hRoot;
tvi.mask = TVIF_IMAGE;
tvi.state = INDEXTOSTATEIMAGEMASK(1);
tvi.stateMask = 0;
ret = TreeView_GetItemA(hTree, &tvi);
expect(TRUE, ret);
/* handler sets TVIS_SELECTED as well */
ok(tvi.state == (TVIS_FOCUSED | TVIS_SELECTED | INDEXTOSTATEIMAGEMASK(2) | INDEXTOOVERLAYMASK(3)), "got 0x%x\n", tvi.state);
g_disp_set_stateimage = FALSE;
ok_sequence(sequences, PARENT_SEQ_INDEX, parent_get_dispinfo_seq,
"callback for state/overlay image index seq", FALSE);
Nikolay Sivov
committed
DestroyWindow(hTree);
Mikołaj Zalewski
committed
}
Nikolay Sivov
committed
static void test_select(void)
HWND hTree;
Nikolay Sivov
committed
Nikolay Sivov
committed
hTree = create_treeview_control(0);
Nikolay Sivov
committed
fill_tree(hTree);
Nikolay Sivov
committed
Nikolay Sivov
committed
/* root-none select tests */
flush_sequences(sequences, NUM_MSG_SEQUENCES);
r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0);

Gerald Pfeifer
committed
expect(TRUE, r);
Clear();
AddItem('1');
r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);

Gerald Pfeifer
committed
expect(TRUE, r);
AddItem('2');
r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);

Gerald Pfeifer
committed
expect(TRUE, r);
AddItem('3');
r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0);

Gerald Pfeifer
committed
expect(TRUE, r);
AddItem('4');
r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0);

Gerald Pfeifer
committed
expect(TRUE, r);
AddItem('5');
r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);

Gerald Pfeifer
committed
expect(TRUE, r);
AddItem('.');
ok(!strcmp(sequence, "1(nR)nR23(Rn)Rn45(nR)nR."), "root-none select test\n");
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, rootnone_select_seq,
Nikolay Sivov
committed
"root-none select seq", FALSE);
Nikolay Sivov
committed
Nikolay Sivov
committed
/* root-child select tests */
flush_sequences(sequences, NUM_MSG_SEQUENCES);
r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0);

Gerald Pfeifer
committed
expect(TRUE, r);
Clear();
AddItem('1');
r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);

Gerald Pfeifer
committed
expect(TRUE, r);
AddItem('2');
r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);

Gerald Pfeifer
committed
expect(TRUE, r);
AddItem('3');
r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild);

Gerald Pfeifer
committed
expect(TRUE, r);
AddItem('4');
r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild);

Gerald Pfeifer
committed
expect(TRUE, r);
AddItem('5');
r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);

Gerald Pfeifer
committed
expect(TRUE, r);
AddItem('.');
ok(!strcmp(sequence, "1(nR)nR23(RC)RC45(CR)CR."), "root-child select test\n");
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, rootchild_select_seq,
Nikolay Sivov
committed
"root-child select seq", FALSE);
DestroyWindow(hTree);
Nikolay Sivov
committed
static void test_getitemtext(void)
{
TVINSERTSTRUCTA ins;
HTREEITEM hChild;
Nikolay Sivov
committed
TVITEMA tvi;
HWND hTree;
CHAR szBuffer[80] = "Blah";
int nBufferSize = ARRAY_SIZE(szBuffer);
Nikolay Sivov
committed
Nikolay Sivov
committed
hTree = create_treeview_control(0);
Nikolay Sivov
committed
fill_tree(hTree);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
Nikolay Sivov
committed
/* add an item without TVIF_TEXT mask and pszText == NULL */
ins.hParent = hRoot;
ins.hInsertAfter = TVI_ROOT;
U(ins).item.mask = 0;
U(ins).item.pszText = NULL;
U(ins).item.cchTextMax = 0;
hChild = TreeView_InsertItemA(hTree, &ins);
ok(hChild != NULL, "failed to set hChild\n");
/* retrieve it with TVIF_TEXT mask */
tvi.hItem = hChild;
tvi.mask = TVIF_TEXT;
tvi.cchTextMax = nBufferSize;
tvi.pszText = szBuffer;
Nikolay Sivov
committed
SendMessageA( hTree, TVM_GETITEMA, 0, (LPARAM)&tvi );
ok(!strcmp(szBuffer, ""), "szBuffer=\"%s\", expected \"\"\n", szBuffer);
ok(SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild), "DeleteItem failed\n");
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, getitemtext_seq, "get item text seq", FALSE);
Nikolay Sivov
committed
DestroyWindow(hTree);
Nikolay Sivov
committed
static void test_focus(void)
{
TVINSERTSTRUCTA ins;
static CHAR child1[] = "Edit",
child2[] = "A really long string";
HTREEITEM hChild1, hChild2;
HWND hTree;
HWND hEdit;
Nikolay Sivov
committed
hTree = create_treeview_control(0);
Nikolay Sivov
committed
fill_tree(hTree);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
Nikolay Sivov
committed
/* This test verifies that when a label is being edited, scrolling
* the treeview does not cause the label to lose focus. To test
* this, first some additional entries are added to generate
* scrollbars.
*/
ins.hParent = hRoot;
ins.hInsertAfter = hChild;
U(ins).item.mask = TVIF_TEXT;
U(ins).item.pszText = child1;
hChild1 = TreeView_InsertItemA(hTree, &ins);
ok(hChild1 != NULL, "failed to set hChild1\n");
ins.hInsertAfter = hChild1;
U(ins).item.mask = TVIF_TEXT;
U(ins).item.pszText = child2;
hChild2 = TreeView_InsertItemA(hTree, &ins);
ok(hChild2 != NULL, "failed to set hChild2\n");
ShowWindow(hMainWnd,SW_SHOW);
SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild);
hEdit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hChild);
ScrollWindowEx(hTree, -10, 0, NULL, NULL, NULL, NULL, SW_SCROLLCHILDREN);
ok(GetFocus() == hEdit, "Edit control should have focus\n");
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, focus_seq, "focus test", TRUE);
Nikolay Sivov
committed
DestroyWindow(hTree);
}
static void test_get_set_bkcolor(void)
COLORREF crColor;
HWND hTree;
Nikolay Sivov
committed
hTree = create_treeview_control(0);
fill_tree(hTree);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* If the value is -1, the control is using the system color for the background color. */
crColor = SendMessageA(hTree, TVM_GETBKCOLOR, 0, 0);
ok(crColor == ~0u, "Default background color reported as 0x%.8x\n", crColor);
/* Test for black background */
SendMessageA(hTree, TVM_SETBKCOLOR, 0, RGB(0,0,0));
crColor = SendMessageA(hTree, TVM_GETBKCOLOR, 0, 0);
ok(crColor == RGB(0,0,0), "Black background color reported as 0x%.8x\n", crColor);
/* Test for white background */
SendMessageA(hTree, TVM_SETBKCOLOR, 0, RGB(255,255,255));
crColor = SendMessageA(hTree, TVM_GETBKCOLOR, 0, 0);
ok(crColor == RGB(255,255,255), "White background color reported as 0x%.8x\n", crColor);
/* Reset the default background */
SendMessageA(hTree, TVM_SETBKCOLOR, 0, -1);
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_bkcolor_seq,
"test get set bkcolor", FALSE);
DestroyWindow(hTree);
static void test_get_set_imagelist(void)
Nikolay Sivov
committed
HIMAGELIST himl;
HWND hTree;
Nikolay Sivov
committed
hTree = create_treeview_control(0);
fill_tree(hTree);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* Test a NULL HIMAGELIST */
SendMessageA(hTree, TVM_SETIMAGELIST, TVSIL_NORMAL, 0);
himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_NORMAL, 0);
Nikolay Sivov
committed
ok(himl == NULL, "NULL image list, reported as %p, expected 0.\n", himl);
/* TODO: Test an actual image list */
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_imagelist_seq,
"test get imagelist", FALSE);
DestroyWindow(hTree);
static void test_get_set_indent(void)
int ulIndent;
int ulMinIndent;
int ulMoreThanTwiceMin;
HWND hTree;
Nikolay Sivov
committed
hTree = create_treeview_control(0);
fill_tree(hTree);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* Finding the minimum indent */
SendMessageA(hTree, TVM_SETINDENT, 0, 0);
ulMinIndent = SendMessageA(hTree, TVM_GETINDENT, 0, 0);
/* Checking an indent that is more than twice the default indent */
ulMoreThanTwiceMin = 2*ulMinIndent+1;
SendMessageA(hTree, TVM_SETINDENT, ulMoreThanTwiceMin, 0);
ulIndent = SendMessageA(hTree, TVM_GETINDENT, 0, 0);
ok(ulIndent == ulMoreThanTwiceMin, "Indent reported as %d, expected %d\n", ulIndent, ulMoreThanTwiceMin);
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_indent_seq,
"test get set indent", FALSE);
DestroyWindow(hTree);
static void test_get_set_insertmark(void)
{
COLORREF crColor = RGB(0,0,0);
HWND hTree;
Nikolay Sivov
committed
hTree = create_treeview_control(0);
fill_tree(hTree);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
SendMessageA(hTree, TVM_SETINSERTMARKCOLOR, 0, crColor);
crColor = SendMessageA(hTree, TVM_GETINSERTMARKCOLOR, 0, 0);
ok(crColor == RGB(0,0,0), "Insert mark color reported as 0x%.8x, expected 0x00000000\n", crColor);
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_insertmarkcolor_seq,
"test get set insertmark color", FALSE);
DestroyWindow(hTree);
static void test_get_set_item(void)
Nikolay Sivov
committed
TVITEMA tviRoot = {0};
int nBufferSize = 80;
char szBuffer[80] = {0};
HWND hTree, hTree2;
DWORD ret;
Nikolay Sivov
committed
hTree = create_treeview_control(0);
fill_tree(hTree);
tviRoot.hItem = hRoot;
tviRoot.mask = TVIF_STATE;
tviRoot.state = TVIS_FOCUSED;
tviRoot.stateMask = TVIS_FOCUSED;
ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot);
expect(TRUE, ret);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* Test the root item, state is set even when not requested */
tviRoot.hItem = hRoot;
tviRoot.mask = TVIF_TEXT;
tviRoot.state = 0;
tviRoot.stateMask = 0;
tviRoot.cchTextMax = nBufferSize;
tviRoot.pszText = szBuffer;
ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&tviRoot);
expect(TRUE, ret);
ok(!strcmp("Root", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Root\"\n", szBuffer);
ok(tviRoot.state == TVIS_FOCUSED, "got 0x%0x\n", tviRoot.state);
/* Change the root text */
lstrcpynA(szBuffer, "Testing123", nBufferSize);
ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot);
expect(TRUE, ret);
memset(szBuffer, 0, nBufferSize);
ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&tviRoot);
expect(TRUE, ret);
ok(!strcmp("Testing123", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Testing123\"\n", szBuffer);
/* Reset the root text */
memset(szBuffer, 0, nBufferSize);
lstrcpynA(szBuffer, "Root", nBufferSize);
ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot);
expect(TRUE, ret);
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_item_seq,
"test get set item", FALSE);
/* get item from a different tree */
hTree2 = create_treeview_control(0);
tviRoot.hItem = hRoot;
tviRoot.mask = TVIF_STATE;
tviRoot.state = 0;
ret = SendMessageA(hTree2, TVM_GETITEMA, 0, (LPARAM)&tviRoot);
expect(TRUE, ret);
ok(tviRoot.state == TVIS_FOCUSED, "got state 0x%0x\n", tviRoot.state);
/* invalid item pointer, nt4 crashes here but later versions just return 0 */
tviRoot.hItem = (HTREEITEM)0xdeadbeef;
tviRoot.mask = TVIF_STATE;
tviRoot.state = 0;
ret = SendMessageA(hTree2, TVM_GETITEMA, 0, (LPARAM)&tviRoot);
expect(FALSE, ret);
DestroyWindow(hTree);
DestroyWindow(hTree2);
static void test_get_set_itemheight(void)
{
int ulOldHeight = 0;
int ulNewHeight = 0;
HWND hTree;
Nikolay Sivov
committed
hTree = create_treeview_control(0);
fill_tree(hTree);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* Assuming default height to begin with */
ulOldHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
/* Explicitly setting and getting the default height */
SendMessageA(hTree, TVM_SETITEMHEIGHT, -1, 0);
ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
ok(ulNewHeight == ulOldHeight, "Default height not set properly, reported %d, expected %d\n", ulNewHeight, ulOldHeight);
/* Explicitly setting and getting the height of twice the normal */
SendMessageA(hTree, TVM_SETITEMHEIGHT, 2*ulOldHeight, 0);
ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
ok(ulNewHeight == 2*ulOldHeight, "New height not set properly, reported %d, expected %d\n", ulNewHeight, 2*ulOldHeight);
/* Assuming tree doesn't have TVS_NONEVENHEIGHT set, so a set of 9 will round down to 8 */
SendMessageA(hTree, TVM_SETITEMHEIGHT, 9, 0);
ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
ok(ulNewHeight == 8, "Uneven height not set properly, reported %d, expected %d\n", ulNewHeight, 8);
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_itemheight_seq,
"test get set item height", FALSE);
/* without TVS_NONEVENHEIGHT */
SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) & ~TVS_NONEVENHEIGHT);
/* odd value */
ulOldHeight = SendMessageA(hTree, TVM_SETITEMHEIGHT, 3, 0);
ok(ulOldHeight == 8, "got %d, expected %d\n", ulOldHeight, 8);
ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
ok(ulNewHeight == 2, "got %d, expected %d\n", ulNewHeight, 2);
ulOldHeight = SendMessageA(hTree, TVM_SETITEMHEIGHT, 4, 0);
ok(ulOldHeight == 2, "got %d, expected %d\n", ulOldHeight, 2);
ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
ok(ulNewHeight == 4, "got %d, expected %d\n", ulNewHeight, 4);
/* with TVS_NONEVENHEIGHT */