comctl32/treeview: Always return state from TVM_GETITEM handler.

oldstable
Nikolay Sivov 2011-05-14 15:12:06 +04:00 committed by Alexandre Julliard
parent 3174ea94c1
commit 1fa1c72d90
2 changed files with 106 additions and 25 deletions

View File

@ -39,6 +39,7 @@ static TVITEMA g_item_expanding, g_item_expanded;
static BOOL g_get_from_expand; static BOOL g_get_from_expand;
static BOOL g_get_rect_in_expand; static BOOL g_get_rect_in_expand;
static BOOL g_disp_A_to_W; static BOOL g_disp_A_to_W;
static BOOL g_disp_set_stateimage;
#define NUM_MSG_SEQUENCES 2 #define NUM_MSG_SEQUENCES 2
#define TREEVIEW_SEQ_INDEX 0 #define TREEVIEW_SEQ_INDEX 0
@ -211,6 +212,11 @@ static const struct message parent_singleexpand_seq[] = {
{ 0 } { 0 }
}; };
static const struct message parent_get_dispinfo_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, TVN_GETDISPINFOA },
{ 0 }
};
static const struct message empty_seq[] = { static const struct message empty_seq[] = {
{ 0 } { 0 }
}; };
@ -349,13 +355,13 @@ static void test_callback(void)
CHAR test_string[] = "Test_string"; CHAR test_string[] = "Test_string";
static const CHAR test2A[] = "TEST2"; static const CHAR test2A[] = "TEST2";
CHAR buf[128]; CHAR buf[128];
LRESULT ret;
HWND hTree; HWND hTree;
DWORD ret;
hTree = create_treeview_control(); hTree = create_treeview_control();
ret = TreeView_DeleteAllItems(hTree); ret = TreeView_DeleteAllItems(hTree);
ok(ret == TRUE, "ret\n"); expect(TRUE, ret);
ins.hParent = TVI_ROOT; ins.hParent = TVI_ROOT;
ins.hInsertAfter = TVI_ROOT; ins.hInsertAfter = TVI_ROOT;
U(ins).item.mask = TVIF_TEXT; U(ins).item.mask = TVIF_TEXT;
@ -368,7 +374,7 @@ static void test_callback(void)
tvi.pszText = buf; tvi.pszText = buf;
tvi.cchTextMax = sizeof(buf)/sizeof(buf[0]); tvi.cchTextMax = sizeof(buf)/sizeof(buf[0]);
ret = TreeView_GetItem(hTree, &tvi); ret = TreeView_GetItem(hTree, &tvi);
ok(ret == 1, "ret\n"); expect(TRUE, ret);
ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Callback item text mismatch %s vs %s\n", ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Callback item text mismatch %s vs %s\n",
tvi.pszText, TEST_CALLBACK_TEXT); tvi.pszText, TEST_CALLBACK_TEXT);
@ -381,17 +387,17 @@ static void test_callback(void)
tvi.hItem = hItem1; tvi.hItem = hItem1;
ret = TreeView_GetItem(hTree, &tvi); ret = TreeView_GetItem(hTree, &tvi);
ok(ret == TRUE, "ret\n"); expect(TRUE, ret);
ok(strcmp(tvi.pszText, test_string) == 0, "Item text mismatch %s vs %s\n", ok(strcmp(tvi.pszText, test_string) == 0, "Item text mismatch %s vs %s\n",
tvi.pszText, test_string); tvi.pszText, test_string);
/* undocumented: pszText of NULL also means LPSTR_CALLBACK: */ /* undocumented: pszText of NULL also means LPSTR_CALLBACK: */
tvi.pszText = NULL; tvi.pszText = NULL;
ret = TreeView_SetItem(hTree, &tvi); ret = TreeView_SetItem(hTree, &tvi);
ok(ret == 1, "Expected SetItem return 1, got %ld\n", ret); expect(TRUE, ret);
tvi.pszText = buf; tvi.pszText = buf;
ret = TreeView_GetItem(hTree, &tvi); ret = TreeView_GetItem(hTree, &tvi);
ok(ret == TRUE, "Expected GetItem return TRUE, got %ld\n", ret); expect(TRUE, ret);
ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n", ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
tvi.pszText, TEST_CALLBACK_TEXT); tvi.pszText, TEST_CALLBACK_TEXT);
@ -401,7 +407,7 @@ static void test_callback(void)
tvi.hItem = hItem2; tvi.hItem = hItem2;
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
ret = TreeView_GetItem(hTree, &tvi); ret = TreeView_GetItem(hTree, &tvi);
ok(ret == TRUE, "Expected GetItem return TRUE, got %ld\n", ret); expect(TRUE, ret);
ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n", ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
tvi.pszText, TEST_CALLBACK_TEXT); tvi.pszText, TEST_CALLBACK_TEXT);
@ -410,11 +416,67 @@ static void test_callback(void)
tvi.hItem = hItem2; tvi.hItem = hItem2;
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
ret = TreeView_GetItem(hTree, &tvi); ret = TreeView_GetItem(hTree, &tvi);
ok(ret == TRUE, "got %ld\n", ret); expect(TRUE, ret);
ok(strcmp(tvi.pszText, test2A) == 0, "got %s, expected %s\n", ok(strcmp(tvi.pszText, test2A) == 0, "got %s, expected %s\n",
tvi.pszText, test2A); tvi.pszText, test2A);
g_disp_A_to_W = FALSE; 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_GetItem(hTree, &tvi);
expect(TRUE, ret);
todo_wine 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_SetItem(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_GetItem(hTree, &tvi);
expect(TRUE, ret);
todo_wine 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);
ret = TreeView_GetItem(hTree, &tvi);
expect(TRUE, ret);
/* handler sets TVIS_SELECTED as well */
todo_wine 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);
DestroyWindow(hTree); DestroyWindow(hTree);
} }
@ -668,32 +730,47 @@ static void test_get_set_item(void)
TVITEMA tviRoot = {0}; TVITEMA tviRoot = {0};
int nBufferSize = 80; int nBufferSize = 80;
char szBuffer[80] = {0}; char szBuffer[80] = {0};
DWORD ret;
HWND hTree; HWND hTree;
hTree = create_treeview_control(); hTree = create_treeview_control();
fill_tree(hTree); fill_tree(hTree);
tviRoot.hItem = hRoot;
tviRoot.mask = TVIF_STATE;
tviRoot.state = TVIS_FOCUSED;
tviRoot.stateMask = TVIS_FOCUSED;
ret = SendMessage( hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot );
expect(TRUE, ret);
flush_sequences(sequences, NUM_MSG_SEQUENCES); flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* Test the root item */ /* Test the root item, state is set even when not requested */
tviRoot.hItem = hRoot; tviRoot.hItem = hRoot;
tviRoot.mask = TVIF_TEXT; tviRoot.mask = TVIF_TEXT;
tviRoot.state = 0;
tviRoot.stateMask = 0;
tviRoot.cchTextMax = nBufferSize; tviRoot.cchTextMax = nBufferSize;
tviRoot.pszText = szBuffer; tviRoot.pszText = szBuffer;
SendMessage( hTree, TVM_GETITEMA, 0, (LPARAM)&tviRoot ); ret = SendMessage( hTree, TVM_GETITEMA, 0, (LPARAM)&tviRoot );
expect(TRUE, ret);
ok(!strcmp("Root", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Root\"\n", szBuffer); 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 */ /* Change the root text */
strncpy(szBuffer, "Testing123", nBufferSize); strncpy(szBuffer, "Testing123", nBufferSize);
SendMessage( hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot ); ret = SendMessage( hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot );
expect(TRUE, ret);
memset(szBuffer, 0, nBufferSize); memset(szBuffer, 0, nBufferSize);
SendMessage( hTree, TVM_GETITEMA, 0, (LPARAM)&tviRoot ); ret = SendMessage( hTree, TVM_GETITEMA, 0, (LPARAM)&tviRoot );
expect(TRUE, ret);
ok(!strcmp("Testing123", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Testing123\"\n", szBuffer); ok(!strcmp("Testing123", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Testing123\"\n", szBuffer);
/* Reset the root text */ /* Reset the root text */
memset(szBuffer, 0, nBufferSize); memset(szBuffer, 0, nBufferSize);
strncpy(szBuffer, "Root", nBufferSize); strncpy(szBuffer, "Root", nBufferSize);
SendMessage( hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot ); ret = SendMessage( hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot );
expect(TRUE, ret);
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_item_seq, ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_item_seq,
"test get set item", FALSE); "test get set item", FALSE);
@ -936,6 +1013,15 @@ static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam,
memcpy(disp->item.pszText, testW, sizeof(testW)); memcpy(disp->item.pszText, testW, sizeof(testW));
} }
if (g_disp_set_stateimage)
{
ok(disp->item.mask == TVIF_IMAGE, "got %x\n", disp->item.mask);
/* both masks set here are necessary to change state bits */
disp->item.mask |= TVIF_STATE;
disp->item.state = TVIS_SELECTED | INDEXTOSTATEIMAGEMASK(2) | INDEXTOOVERLAYMASK(3);
disp->item.stateMask = TVIS_SELECTED | TVIS_OVERLAYMASK | TVIS_STATEIMAGEMASK;
}
break; break;
} }
case TVN_ENDLABELEDIT: return TRUE; case TVN_ENDLABELEDIT: return TRUE;

View File

@ -704,7 +704,7 @@ TREEVIEW_UpdateDispInfo(const TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
NMTVDISPINFOEXW callback; NMTVDISPINFOEXW callback;
HWND hwnd = infoPtr->hwnd; HWND hwnd = infoPtr->hwnd;
TRACE("mask %x callbackMask %x\n", mask, wineItem->callbackMask); TRACE("mask=0x%x, callbackmask=0x%x\n", mask, wineItem->callbackMask);
mask &= wineItem->callbackMask; mask &= wineItem->callbackMask;
if (mask == 0) return; if (mask == 0) return;
@ -735,7 +735,7 @@ TREEVIEW_UpdateDispInfo(const TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
if ((mask & TVIF_TEXT) && callback.item.pszText != wineItem->pszText) if ((mask & TVIF_TEXT) && callback.item.pszText != wineItem->pszText)
{ {
/* Instead of copying text into our buffer user specified its own */ /* Instead of copying text into our buffer user specified his own */
if (!infoPtr->bNtfUnicode && (callback.hdr.code == TVN_GETDISPINFOA)) { if (!infoPtr->bNtfUnicode && (callback.hdr.code == TVN_GETDISPINFOA)) {
LPWSTR newText; LPWSTR newText;
int buflen; int buflen;
@ -2100,9 +2100,7 @@ TREEVIEW_GetItemT(const TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW)
if (tvItem->mask & TVIF_INTEGRAL) if (tvItem->mask & TVIF_INTEGRAL)
tvItem->iIntegral = wineItem->iIntegral; tvItem->iIntegral = wineItem->iIntegral;
/* undocumented: windows ignores TVIF_PARAM and /* undocumented: (mask & TVIF_PARAM) ignored and lParam is always set */
* * always sets lParam
*/
tvItem->lParam = wineItem->lParam; tvItem->lParam = wineItem->lParam;
if (tvItem->mask & TVIF_SELECTEDIMAGE) if (tvItem->mask & TVIF_SELECTEDIMAGE)
@ -2111,11 +2109,8 @@ TREEVIEW_GetItemT(const TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW)
if (tvItem->mask & TVIF_EXPANDEDIMAGE) if (tvItem->mask & TVIF_EXPANDEDIMAGE)
tvItem->iExpandedImage = wineItem->iExpandedImage; tvItem->iExpandedImage = wineItem->iExpandedImage;
if (tvItem->mask & TVIF_STATE) /* undocumented: stateMask and (state & TVIF_STATE) ignored, so state is always set */
/* Careful here - Windows ignores the stateMask when you get the state tvItem->state = wineItem->state;
That contradicts the documentation, but makes more common sense, masking
retrieval in this way seems overkill */
tvItem->state = wineItem->state;
if (tvItem->mask & TVIF_TEXT) if (tvItem->mask & TVIF_TEXT)
{ {
@ -2157,8 +2152,8 @@ TREEVIEW_GetItemT(const TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW)
tvItem->uStateEx = 0; tvItem->uStateEx = 0;
} }
TRACE("item <%p>, txt %p, img %p, mask %x\n", TRACE("item <%p>, txt %p, img %d, mask %x\n",
wineItem, tvItem->pszText, &tvItem->iImage, tvItem->mask); wineItem, tvItem->pszText, tvItem->iImage, tvItem->mask);
return TRUE; return TRUE;
} }