Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060/* 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 <stdio.h>
#include "windef.h"#include "winbase.h"#include "wingdi.h"#include "winuser.h"#include "winnls.h"#include "winreg.h"#include "wine/commctrl.h"
#include "wine/test.h"#include "v6util.h"#include "msg.h"
static BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);static const char *TEST_CALLBACK_TEXT = "callback_text";
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 const char *g_endedit_overwrite_contents;static char *g_endedit_overwrite_ptr;static HFONT g_customdraw_font;static BOOL g_v6;
#define NUM_MSG_SEQUENCES 3#define TREEVIEW_SEQ_INDEX 0#define PARENT_SEQ_INDEX 1#define PARENT_CD_SEQ_INDEX 2
#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 }, { 0 }};
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 }, { 0 }};
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 }, { 0 }};
static const struct message getitemtext_seq[] = { { TVM_INSERTITEMA, sent }, { TVM_GETITEMA, sent }, { TVM_DELETEITEM, sent }, { 0 }};
static const struct message focus_seq[] = { { TVM_INSERTITEMA, sent }, { TVM_INSERTITEMA, sent }, { TVM_SELECTITEM, sent|wparam, 9 }, /* The following end up out of order in wine */ { WM_WINDOWPOSCHANGING, sent|defwinproc }, { 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 }, { WM_NCPAINT, sent|wparam|defwinproc, 1 }, { WM_ERASEBKGND, sent|defwinproc }, { TVM_EDITLABELA, sent }, { 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 }, { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_SETFOCUS) }, { WM_ERASEBKGND, sent|defwinproc|optional }, { WM_CTLCOLOREDIT, sent|defwinproc|optional }, { WM_CTLCOLOREDIT, sent|defwinproc|optional }, { 0 }};
static const struct message test_get_set_bkcolor_seq[] = { { 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 }, { 0 }};
static const struct message test_get_set_imagelist_seq[] = { { TVM_SETIMAGELIST, sent|wparam|lparam, 0, 0 }, { TVM_GETIMAGELIST, sent|wparam|lparam, 0, 0 }, { 0 }};
static const struct message test_get_set_indent_seq[] = { { 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 }, { TVM_GETINDENT, sent|wparam|lparam, 0, 0 }, { 0 }};
static const struct message test_get_set_insertmarkcolor_seq[] = { { TVM_SETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 }, { TVM_GETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 }, { 0 }};
static const struct message test_get_set_item_seq[] = { { TVM_GETITEMA, sent }, { TVM_SETITEMA, sent }, { TVM_GETITEMA, sent }, { TVM_SETITEMA, sent }, { 0 }};
static const struct message test_get_set_itemheight_seq[] = { { 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 }, { 0 }};
static const struct message test_get_set_scrolltime_seq[] = { { TVM_SETSCROLLTIME, sent|wparam|lparam, 20, 0 }, { TVM_GETSCROLLTIME, sent|wparam|lparam, 0, 0 }, { 0 }};
static const struct message test_get_set_textcolor_seq[] = { { 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) }, { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 }, { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, CLR_NONE }, { 0 }};
static const struct message test_get_set_tooltips_seq[] = { { WM_KILLFOCUS, sent }, { WM_IME_SETCONTEXT, sent|optional }, { WM_IME_NOTIFY, sent|optional }, { TVM_SETTOOLTIPS, sent|wparam|lparam, 0, 0 }, { TVM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 }, { 0 }};
static const struct message test_get_set_unicodeformat_seq[] = { { 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 }, { 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[] = { { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, { 0 }};
static const struct message parent_expand_kb_seq[] = { { WM_NOTIFY, sent|id, 0, 0, TVN_KEYDOWN }, { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, { WM_CHANGEUISTATE, sent|optional }, { 0 }};
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 }};
static const struct message parent_expand_empty_kb_seq[] = { { WM_NOTIFY, sent|id, 0, 0, TVN_KEYDOWN }, { 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 }};
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];
static void Clear(void){ 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('?');}
/* 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 };
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);
defwndproc_counter++; ret = CallWindowProcA(lpOldProc, hwnd, message, wParam, lParam); defwndproc_counter--;
return ret;}
static HWND create_treeview_control(DWORD style){ WNDPROC pOldWndProc; HWND hTree;
hTree = CreateWindowExA(WS_EX_CLIENTEDGE, WC_TREEVIEWA, NULL, WS_CHILD|WS_VISIBLE| TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS|TVS_EDITLABELS|style, 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; U(ins).item.pszText = root; 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);}
static void test_fillroot(void){ TVITEMA tvi; HWND hTree;
hTree = create_treeview_control(0);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
fill_tree(hTree);
Clear(); AddItem('A'); ok(hRoot != NULL, "failed to set root\n"); 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");
/* 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); ok(tvi.iImage == 0, "tvi.iImage=%d\n", tvi.iImage); ok(tvi.iSelectedImage == 0, "tvi.iSelectedImage=%d\n", tvi.iSelectedImage);
DestroyWindow(hTree);}
static void test_callback(void){ HTREEITEM hRoot; HTREEITEM hItem1, hItem2; TVINSERTSTRUCTA ins; TVITEMA tvi; CHAR test_string[] = "Test_string"; static const CHAR test2A[] = "TEST2"; CHAR buf[128]; HWND hTree; DWORD ret;
hTree = create_treeview_control(0);
ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT); expect(TRUE, ret); 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");
tvi.hItem = hRoot; tvi.mask = TVIF_TEXT; tvi.pszText = buf; tvi.cchTextMax = ARRAY_SIZE(buf); ret = TreeView_GetItemA(hTree, &tvi); expect(TRUE, ret); 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");
tvi.hItem = hItem1; ret = TreeView_GetItemA(hTree, &tvi); expect(TRUE, ret); 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); 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", tvi.pszText, TEST_CALLBACK_TEXT);
U(ins).item.pszText = NULL; hItem2 = TreeView_InsertItemA(hTree, &ins); ok(hItem2 != NULL, "failed to set Item2\n"); 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", tvi.pszText, TEST_CALLBACK_TEXT);
/* 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); 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); 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); 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);
DestroyWindow(hTree);}
static void test_select(void){ BOOL r; HWND hTree;
hTree = create_treeview_control(0); fill_tree(hTree);
/* root-none select tests */ flush_sequences(sequences, NUM_MSG_SEQUENCES); r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0); expect(TRUE, r); Clear(); AddItem('1'); r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); expect(TRUE, r); AddItem('2'); r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); expect(TRUE, r); AddItem('3'); r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0); expect(TRUE, r); AddItem('4'); r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0); expect(TRUE, r); AddItem('5'); r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); 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, "root-none select seq", FALSE);
/* root-child select tests */ flush_sequences(sequences, NUM_MSG_SEQUENCES); r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0); expect(TRUE, r);
Clear(); AddItem('1'); r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); expect(TRUE, r); AddItem('2'); r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); expect(TRUE, r); AddItem('3'); r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild); expect(TRUE, r); AddItem('4'); r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild); expect(TRUE, r); AddItem('5'); r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); 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, "root-child select seq", FALSE);
DestroyWindow(hTree);}
static void test_getitemtext(void){ TVINSERTSTRUCTA ins; HTREEITEM hChild; TVITEMA tvi; HWND hTree;
CHAR szBuffer[80] = "Blah"; int nBufferSize = ARRAY_SIZE(szBuffer);
hTree = create_treeview_control(0); fill_tree(hTree);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* 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;
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);
DestroyWindow(hTree);}
static void test_focus(void){ TVINSERTSTRUCTA ins; static CHAR child1[] = "Edit", child2[] = "A really long string"; HTREEITEM hChild1, hChild2; HWND hTree; HWND hEdit;
hTree = create_treeview_control(0); fill_tree(hTree);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* 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);
DestroyWindow(hTree);}
static void test_get_set_bkcolor(void){ COLORREF crColor; HWND hTree;
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){ HIMAGELIST himl; HWND hTree;
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); 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;
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;
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){ TVITEMA tviRoot = {0}; int nBufferSize = 80; char szBuffer[80] = {0}; HWND hTree, hTree2; DWORD ret;
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;
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 */ SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_NONEVENHEIGHT); /* odd value */ ulOldHeight = SendMessageA(hTree, TVM_SETITEMHEIGHT, 3, 0); ok(ulOldHeight == 4, "got %d, expected %d\n", ulOldHeight, 4); ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0); ok(ulNewHeight == 3, "got %d, expected %d\n", ulNewHeight, 3); /* even value */ ulOldHeight = SendMessageA(hTree, TVM_SETITEMHEIGHT, 10, 0); ok(ulOldHeight == 3, "got %d, expected %d\n", ulOldHeight, 3); ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0); ok(ulNewHeight == 10, "got %d, expected %d\n", ulNewHeight, 10);
DestroyWindow(hTree);}
static void test_get_set_scrolltime(void){ int ulExpectedTime = 20; int ulTime = 0; HWND hTree;
hTree = create_treeview_control(0); fill_tree(hTree);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
SendMessageA(hTree, TVM_SETSCROLLTIME, ulExpectedTime, 0); ulTime = SendMessageA(hTree, TVM_GETSCROLLTIME, 0, 0); ok(ulTime == ulExpectedTime, "Scroll time reported as %d, expected %d\n", ulTime, ulExpectedTime);
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_scrolltime_seq, "test get set scroll time", FALSE);
DestroyWindow(hTree);}
static void test_get_set_textcolor(void){ /* If the value is -1, the control is using the system color for the text color. */ COLORREF crColor; HWND hTree;
hTree = create_treeview_control(0); fill_tree(hTree);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
crColor = SendMessageA(hTree, TVM_GETTEXTCOLOR, 0, 0); ok(crColor == ~0u, "Default text color reported as 0x%.8x\n", crColor);
/* Test for black text */ SendMessageA(hTree, TVM_SETTEXTCOLOR, 0, RGB(0,0,0)); crColor = SendMessageA(hTree, TVM_GETTEXTCOLOR, 0, 0); ok(crColor == RGB(0,0,0), "Black text color reported as 0x%.8x\n", crColor);
/* Test for white text */ SendMessageA(hTree, TVM_SETTEXTCOLOR, 0, RGB(255,255,255)); crColor = SendMessageA(hTree, TVM_GETTEXTCOLOR, 0, 0); ok(crColor == RGB(255,255,255), "White text color reported as 0x%.8x\n", crColor);
/* Reset the default text color */ SendMessageA(hTree, TVM_SETTEXTCOLOR, 0, CLR_NONE);
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_textcolor_seq, "test get set text color", FALSE);
DestroyWindow(hTree);}
static void test_get_set_tooltips(void){ HWND hTree, tooltips, hwnd; DWORD style; int i;
/* TVS_NOTOOLTIPS */ hTree = create_treeview_control(TVS_NOTOOLTIPS);
tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); ok(tooltips == NULL, "Unexpected tooltip window %p.\n", tooltips);
tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, 0, 0); ok(tooltips == NULL, "Unexpected ret value %p.\n", tooltips);
/* Toggle style */ style = GetWindowLongA(hTree, GWL_STYLE); SetWindowLongA(hTree, GWL_STYLE, style & ~TVS_NOTOOLTIPS);
tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); ok(IsWindow(tooltips), "Unexpected tooltip window %p.\n", tooltips);
style = GetWindowLongA(hTree, GWL_STYLE); SetWindowLongA(hTree, GWL_STYLE, style | TVS_NOTOOLTIPS);
tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); ok(tooltips == NULL, "Unexpected tooltip window %p.\n", tooltips);
DestroyWindow(hTree);
/* Set some valid window, does not have to be tooltips class. */ hTree = create_treeview_control(TVS_NOTOOLTIPS);
hwnd = CreateWindowA(WC_STATICA, "Test", WS_VISIBLE|WS_CHILD, 5, 5, 100, 100, hMainWnd, NULL, NULL, 0); ok(hwnd != NULL, "Failed to create child window.\n");
tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, (WPARAM)hwnd, 0); ok(tooltips == NULL, "Unexpected ret value %p.\n", tooltips);
tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); ok(tooltips == hwnd, "Unexpected tooltip window %p.\n", tooltips);
/* Externally set tooltips window, disable style. */ style = GetWindowLongA(hTree, GWL_STYLE); SetWindowLongA(hTree, GWL_STYLE, style & ~TVS_NOTOOLTIPS);
tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); ok(IsWindow(tooltips) && tooltips != hwnd, "Unexpected tooltip window %p.\n", tooltips); ok(IsWindow(hwnd), "Expected valid window.\n");
style = GetWindowLongA(hTree, GWL_STYLE); SetWindowLongA(hTree, GWL_STYLE, style | TVS_NOTOOLTIPS); ok(!IsWindow(tooltips), "Unexpected tooltip window %p.\n", tooltips);
tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); ok(tooltips == NULL, "Unexpected tooltip window %p.\n", tooltips); ok(IsWindow(hwnd), "Expected valid window.\n");
DestroyWindow(hTree); ok(IsWindow(hwnd), "Expected valid window.\n");
/* Set window, disable tooltips. */ hTree = create_treeview_control(0);
tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, (WPARAM)hwnd, 0); ok(IsWindow(tooltips), "Unexpected ret value %p.\n", tooltips);
style = GetWindowLongA(hTree, GWL_STYLE); SetWindowLongA(hTree, GWL_STYLE, style | TVS_NOTOOLTIPS); ok(!IsWindow(hwnd), "Unexpected tooltip window %p.\n", tooltips); ok(IsWindow(tooltips), "Expected valid window %p.\n", tooltips);
DestroyWindow(hTree); ok(IsWindow(tooltips), "Expected valid window %p.\n", tooltips); DestroyWindow(tooltips); DestroyWindow(hwnd);
for (i = 0; i < 2; i++) { DWORD style = i == 0 ? 0 : TVS_NOTOOLTIPS;
hwnd = CreateWindowA(WC_STATICA, "Test", WS_VISIBLE|WS_CHILD, 5, 5, 100, 100, hMainWnd, NULL, NULL, 0); ok(hwnd != NULL, "Failed to create child window.\n");
hTree = create_treeview_control(style);
tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, (WPARAM)hwnd, 0); ok(style & TVS_NOTOOLTIPS ? tooltips == NULL : IsWindow(tooltips), "Unexpected ret value %p.\n", tooltips); DestroyWindow(tooltips);
tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); ok(tooltips == hwnd, "Unexpected tooltip window %p.\n", tooltips);
/* TreeView is destroyed, check if set window is still around. */ DestroyWindow(hTree); ok(!IsWindow(hwnd), "Unexpected window.\n"); }
hTree = create_treeview_control(0); fill_tree(hTree);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* show even WS_POPUP treeview don't send NM_TOOLTIPSCREATED */ hwnd = CreateWindowA(WC_TREEVIEWA, NULL, WS_POPUP|WS_VISIBLE, 0, 0, 100, 100, hMainWnd, NULL, NULL, NULL); DestroyWindow(hwnd);
/* Testing setting a NULL ToolTip */ tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, 0, 0); ok(IsWindow(tooltips), "Unexpected ret value %p.\n", tooltips);
hwnd = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); ok(hwnd == NULL, "Unexpected tooltip window %p.\n", hwnd);
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_tooltips_seq, "test get set tooltips", TRUE);
DestroyWindow(hTree); ok(IsWindow(tooltips), "Expected valid window.\n"); DestroyWindow(tooltips);}
static void test_get_set_unicodeformat(void){ BOOL bPreviousSetting; BOOL bNewSetting; HWND hTree;
hTree = create_treeview_control(0); fill_tree(hTree);
/* Check that an invalid format returned by NF_QUERY defaults to ANSI */ bPreviousSetting = SendMessageA(hTree, TVM_GETUNICODEFORMAT, 0, 0); ok(bPreviousSetting == FALSE, "Format should be ANSI.\n");
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* Set to Unicode */ bPreviousSetting = SendMessageA(hTree, TVM_SETUNICODEFORMAT, 1, 0); bNewSetting = SendMessageA(hTree, TVM_GETUNICODEFORMAT, 0, 0); ok(bNewSetting == TRUE, "Unicode setting did not work.\n");
/* Set to ANSI */ SendMessageA(hTree, TVM_SETUNICODEFORMAT, 0, 0); bNewSetting = SendMessageA(hTree, TVM_GETUNICODEFORMAT, 0, 0); ok(bNewSetting == FALSE, "ANSI setting did not work.\n");
/* Revert to original setting */ SendMessageA(hTree, TVM_SETUNICODEFORMAT, bPreviousSetting, 0);
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_unicodeformat_seq, "test get set unicode format", FALSE);
DestroyWindow(hTree);}
static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ static LONG defwndproc_counter = 0; struct message msg = { 0 }; LRESULT ret; RECT rect; HTREEITEM visibleItem;
msg.message = message; msg.flags = sent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wParam; msg.lParam = lParam; if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
/* log system messages, except for painting */ if (message < WM_USER && message != WM_PAINT && message != WM_ERASEBKGND && message != WM_NCPAINT && message != WM_NCHITTEST && message != WM_GETTEXT && message != WM_GETICON && message != WM_DEVICECHANGE) { add_message(sequences, PARENT_SEQ_INDEX, &msg); }
switch(message) { case WM_NOTIFYFORMAT: { /* Make NF_QUERY return an invalid format to show that it defaults to ANSI */ if (lParam == NF_QUERY) return 0; break; }
case WM_NOTIFY: { NMHDR *pHdr = (NMHDR *)lParam;
ok(pHdr->code != NM_TOOLTIPSCREATED, "Treeview should not send NM_TOOLTIPSCREATED\n"); if (pHdr->idFrom == 100) { NMTREEVIEWA *pTreeView = (LPNMTREEVIEWA) lParam; switch(pHdr->code) { case TVN_SELCHANGINGA: AddItem('('); IdentifyItem(pTreeView->itemOld.hItem); IdentifyItem(pTreeView->itemNew.hItem); break; case TVN_SELCHANGEDA: AddItem(')'); IdentifyItem(pTreeView->itemOld.hItem); IdentifyItem(pTreeView->itemNew.hItem); break; case TVN_GETDISPINFOA: { NMTVDISPINFOA *disp = (NMTVDISPINFOA *)lParam; if (disp->item.mask & TVIF_TEXT) { lstrcpynA(disp->item.pszText, TEST_CALLBACK_TEXT, disp->item.cchTextMax); }
if (g_disp_A_to_W && (disp->item.mask & TVIF_TEXT)) { static const WCHAR testW[] = {'T','E','S','T','2',0};
disp->hdr.code = TVN_GETDISPINFOW; 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; } case TVN_BEGINLABELEDITA: { if (g_beginedit_alter_text) { static const char* textA = "<edittextaltered>"; HWND edit;
edit = (HWND)SendMessageA(pHdr->hwndFrom, TVM_GETEDITCONTROL, 0, 0); ok(IsWindow(edit), "failed to get edit handle\n"); SetWindowTextA(edit, textA); }
break; }
case TVN_ENDLABELEDITA: { NMTVDISPINFOA *disp = (NMTVDISPINFOA *)lParam; if (disp->item.mask & TVIF_TEXT) { ok(disp->item.cchTextMax == MAX_PATH, "cchTextMax is %d\n", disp->item.cchTextMax); if (g_endedit_overwrite_contents) strcpy(disp->item.pszText, g_endedit_overwrite_contents); if (g_endedit_overwrite_ptr) disp->item.pszText = g_endedit_overwrite_ptr; } return TRUE; } case TVN_ITEMEXPANDINGA: { UINT newmask = pTreeView->itemNew.mask & ~TVIF_CHILDREN; ok(newmask == (TVIF_HANDLE | TVIF_SELECTEDIMAGE | TVIF_IMAGE | TVIF_PARAM | TVIF_STATE), "got wrong mask %x\n", pTreeView->itemNew.mask); ok(pTreeView->itemOld.mask == 0, "got wrong mask %x\n", pTreeView->itemOld.mask);
if (g_get_from_expand) { g_item_expanding.mask = TVIF_STATE; g_item_expanding.hItem = hRoot; ret = SendMessageA(pHdr->hwndFrom, TVM_GETITEMA, 0, (LPARAM)&g_item_expanding); ok(ret == TRUE, "got %lu\n", ret); } break; } case TVN_ITEMEXPANDEDA: ok(pTreeView->itemNew.mask & TVIF_STATE, "got wrong mask %x\n", pTreeView->itemNew.mask); ok(pTreeView->itemNew.state & (TVIS_EXPANDED|TVIS_EXPANDEDONCE), "got wrong mask %x\n", pTreeView->itemNew.mask); ok(pTreeView->itemOld.mask == 0, "got wrong mask %x\n", pTreeView->itemOld.mask);
if (g_get_from_expand) { g_item_expanded.mask = TVIF_STATE; g_item_expanded.hItem = hRoot; ret = SendMessageA(pHdr->hwndFrom, TVM_GETITEMA, 0, (LPARAM)&g_item_expanded); ok(ret == TRUE, "got %lu\n", ret); } if (g_get_rect_in_expand) { visibleItem = (HTREEITEM)SendMessageA(pHdr->hwndFrom, TVM_GETNEXTITEM, TVGN_FIRSTVISIBLE, 0); ok(pTreeView->itemNew.hItem == visibleItem, "expanded item == first visible item\n"); *(HTREEITEM*)&rect = visibleItem; ok(SendMessageA(pHdr->hwndFrom, TVM_GETITEMRECT, TRUE, (LPARAM)&rect), "Failed to get rect for first visible item.\n"); visibleItem = (HTREEITEM)SendMessageA(pHdr->hwndFrom, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)visibleItem); *(HTREEITEM*)&rect = visibleItem; ok(visibleItem != NULL, "There must be a visible item after the first one.\n"); ok(SendMessageA(pHdr->hwndFrom, TVM_GETITEMRECT, TRUE, (LPARAM)&rect), "Failed to get rect for second visible item.\n"); } break; case TVN_DELETEITEMA: { struct message item;
ok(pTreeView->itemNew.mask == 0, "got wrong mask 0x%x\n", pTreeView->itemNew.mask);
ok(pTreeView->itemOld.mask == (TVIF_HANDLE | TVIF_PARAM), "got wrong mask 0x%x\n", pTreeView->itemOld.mask); ok(pTreeView->itemOld.hItem != NULL, "got %p\n", pTreeView->itemOld.hItem);
memset(&item, 0, sizeof(item)); item.lParam = (LPARAM)pTreeView->itemOld.hItem; add_message(item_sequence, 0, &item);
break; } case NM_CUSTOMDRAW: { NMTVCUSTOMDRAW *nmcd = (NMTVCUSTOMDRAW*)lParam; COLORREF c0ffee = RGB(0xc0,0xff,0xee), cafe = RGB(0xca,0xfe,0x00); COLORREF text = GetTextColor(nmcd->nmcd.hdc), bkgnd = GetBkColor(nmcd->nmcd.hdc);
msg.flags |= custdraw; msg.stage = nmcd->nmcd.dwDrawStage; add_message(sequences, PARENT_CD_SEQ_INDEX, &msg);
switch (msg.stage) { case CDDS_PREPAINT: return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYITEMERASE|CDRF_NOTIFYPOSTPAINT; case CDDS_ITEMPREPAINT: ok(text == nmcd->clrText || (g_v6 && nmcd->clrText == 0xffffffff), "got %08x vs %08x\n", text, nmcd->clrText); ok(bkgnd == nmcd->clrTextBk || (g_v6 && nmcd->clrTextBk == 0xffffffff), "got %08x vs %08x\n", bkgnd, nmcd->clrTextBk); nmcd->clrText = cafe; nmcd->clrTextBk = c0ffee; SetTextColor(nmcd->nmcd.hdc, c0ffee); SetBkColor(nmcd->nmcd.hdc, cafe); if (g_customdraw_font) SelectObject(nmcd->nmcd.hdc, g_customdraw_font); return CDRF_NOTIFYPOSTPAINT|CDRF_NEWFONT; case CDDS_ITEMPOSTPAINT: /* at the point of post paint notification colors are already restored */ ok(nmcd->clrText == cafe, "got 0%x\n", nmcd->clrText); ok(nmcd->clrTextBk == c0ffee, "got 0%x\n", nmcd->clrTextBk); ok(text != cafe, "got 0%x\n", text); ok(bkgnd != c0ffee, "got 0%x\n", bkgnd); if (g_customdraw_font) ok(GetCurrentObject(nmcd->nmcd.hdc, OBJ_FONT) != g_customdraw_font, "got %p\n", GetCurrentObject(nmcd->nmcd.hdc, OBJ_FONT)); break; default: ; } break; } case NM_RCLICK: { HTREEITEM selected = (HTREEITEM)SendMessageA(((NMHDR *)lParam)->hwndFrom, TVM_GETNEXTITEM, TVGN_CARET, 0); ok(selected == hChild, "child item should still be selected\n"); break; } } } break; }
}
defwndproc_counter++; ret = DefWindowProcA(hWnd, message, wParam, lParam); defwndproc_counter--;
return ret;}
static void test_expandinvisible(void){ static CHAR nodeText[][5] = {"0", "1", "2", "3", "4"}; TVINSERTSTRUCTA ins; HTREEITEM node[5]; RECT dummyRect; BOOL nodeVisible; LRESULT ret; HWND hTree;
hTree = create_treeview_control(0);
/* The test builds the following tree and expands node 1, while node 0 is collapsed. * * 0 * |- 1 * | |- 2 * | |- 3 * |- 4 * */
ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT); ok(ret == TRUE, "ret\n"); ins.hParent = TVI_ROOT; ins.hInsertAfter = TVI_ROOT; U(ins).item.mask = TVIF_TEXT; U(ins).item.pszText = nodeText[0]; node[0] = TreeView_InsertItemA(hTree, &ins); ok(node[0] != NULL, "failed to set node[0]\n");
ins.hInsertAfter = TVI_LAST; U(ins).item.mask = TVIF_TEXT; ins.hParent = node[0];
U(ins).item.pszText = nodeText[1]; node[1] = TreeView_InsertItemA(hTree, &ins); ok(node[1] != NULL, "failed to set node[1]\n"); U(ins).item.pszText = nodeText[4]; node[4] = TreeView_InsertItemA(hTree, &ins); ok(node[4] != NULL, "failed to set node[4]\n");
ins.hParent = node[1];
U(ins).item.pszText = nodeText[2]; node[2] = TreeView_InsertItemA(hTree, &ins); ok(node[2] != NULL, "failed to set node[2]\n"); U(ins).item.pszText = nodeText[3]; node[3] = TreeView_InsertItemA(hTree, &ins); ok(node[3] != NULL, "failed to set node[3]\n");
*(HTREEITEM *)&dummyRect = node[1]; nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect); ok(!nodeVisible, "Node 1 should not be visible.\n"); *(HTREEITEM *)&dummyRect = node[2]; nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect); ok(!nodeVisible, "Node 2 should not be visible.\n"); *(HTREEITEM *)&dummyRect = node[3]; nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect); ok(!nodeVisible, "Node 3 should not be visible.\n"); *(HTREEITEM *)&dummyRect = node[4]; nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect); ok(!nodeVisible, "Node 4 should not be visible.\n");
ok(SendMessageA(hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)node[1]), "Expand of node 1 failed.\n");
*(HTREEITEM *)&dummyRect = node[1]; nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect); ok(!nodeVisible, "Node 1 should not be visible.\n"); *(HTREEITEM *)&dummyRect = node[2]; nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect); ok(!nodeVisible, "Node 2 should not be visible.\n"); *(HTREEITEM *)&dummyRect = node[3]; nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect); ok(!nodeVisible, "Node 3 should not be visible.\n"); *(HTREEITEM *)&dummyRect = node[4]; nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect); ok(!nodeVisible, "Node 4 should not be visible.\n");
DestroyWindow(hTree);}
static void test_expand(void){ HTREEITEM first, second, last, child; TVINSERTSTRUCTA ins; BOOL visible; RECT rect; HWND tv; int i;
tv = create_treeview_control(0);
ins.hParent = TVI_ROOT; ins.hInsertAfter = TVI_LAST; U(ins).item.mask = 0; first = TreeView_InsertItemA(tv, &ins); ok(first != NULL, "failed to insert first node\n"); second = TreeView_InsertItemA(tv, &ins); ok(second != NULL, "failed to insert second node\n"); for (i=0; i<100; i++) { last = TreeView_InsertItemA(tv, &ins); ok(last != NULL, "failed to insert %d node\n", i); }
ins.hParent = second; child = TreeView_InsertItemA(tv, &ins); ok(child != NULL, "failed to insert child node\n");
ok(SendMessageA(tv, TVM_SELECTITEM, TVGN_CARET, (LPARAM)last), "last node selection failed\n"); ok(SendMessageA(tv, TVM_EXPAND, TVE_EXPAND, (LPARAM)second), "expand of second node failed\n"); ok(SendMessageA(tv, TVM_SELECTITEM, TVGN_CARET, (LPARAM)first), "first node selection failed\n");
*(HTREEITEM *)&rect = first; visible = SendMessageA(tv, TVM_GETITEMRECT, FALSE, (LPARAM)&rect); ok(visible, "first node should be visible\n"); ok(!rect.left, "rect.left = %d\n", rect.left); ok(!rect.top, "rect.top = %d\n", rect.top); ok(rect.right, "rect.right = 0\n"); ok(rect.bottom, "rect.bottom = 0\n");
DestroyWindow(tv);}
static void test_itemedit(void){ DWORD r; HWND edit; TVITEMA item; CHAR buffA[500]; HWND hTree;
hTree = create_treeview_control(0); fill_tree(hTree);
/* try with null item */ edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, 0); ok(!IsWindow(edit), "Expected valid handle\n");
/* trigger edit */ edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot); ok(IsWindow(edit), "Expected valid handle\n"); /* item shouldn't be selected automatically after TVM_EDITLABELA */ r = SendMessageA(hTree, TVM_GETITEMSTATE, (WPARAM)hRoot, TVIS_SELECTED); expect(0, r); /* try to cancel with wrong edit handle */ r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), 0); expect(0, r); ok(IsWindow(edit), "Expected edit control to be valid\n"); r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); expect(0, r); ok(!IsWindow(edit), "Expected edit control to be destroyed\n"); /* try to cancel without creating edit */ r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), 0); expect(0, r);
/* try to cancel with wrong (not null) handle */ edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot); ok(IsWindow(edit), "Expected valid handle\n"); r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hTree); expect(0, r); ok(IsWindow(edit), "Expected edit control to be valid\n"); r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); expect(0, r);
/* remove selection after starting edit */ r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); expect(TRUE, r); edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot); ok(IsWindow(edit), "Expected valid handle\n"); r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0); expect(TRUE, r); /* alter text */ strcpy(buffA, "x"); r = SendMessageA(edit, WM_SETTEXT, 0, (LPARAM)buffA); expect(TRUE, r); r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); expect(0, r); ok(!IsWindow(edit), "Expected edit control to be destroyed\n"); /* check that text is saved */ item.mask = TVIF_TEXT; item.hItem = hRoot; item.pszText = buffA; item.cchTextMax = ARRAY_SIZE(buffA); r = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, r); ok(!strcmp("x", buffA), "Expected item text to change\n");
/* try A/W messages */ edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot); ok(IsWindow(edit), "Expected valid handle\n"); ok(IsWindowUnicode(edit), "got ansi window\n"); r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); expect(0, r); ok(!IsWindow(edit), "expected invalid handle\n");
edit = (HWND)SendMessageA(hTree, TVM_EDITLABELW, 0, (LPARAM)hRoot); ok(IsWindow(edit), "Expected valid handle\n"); ok(IsWindowUnicode(edit), "got ansi window\n"); r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); expect(0, r);
/* alter text during TVM_BEGINLABELEDIT, check that it's preserved */ strcpy(buffA, "<root>");
item.mask = TVIF_TEXT; item.hItem = hRoot; item.pszText = buffA; item.cchTextMax = 0; r = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item); expect(TRUE, r);
g_beginedit_alter_text = TRUE; edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot); ok(IsWindow(edit), "Expected valid handle\n"); g_beginedit_alter_text = FALSE;
GetWindowTextA(edit, buffA, ARRAY_SIZE(buffA)); ok(!strcmp(buffA, "<edittextaltered>"), "got string %s\n", buffA);
r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); expect(0, r);
/* How much text can be typed? */ edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot); ok(IsWindow(edit), "Expected valid handle\n"); r = SendMessageA(edit, EM_GETLIMITTEXT, 0, 0); expect(MAX_PATH - 1, r); /* WM_SETTEXT can set more... */ memset(buffA, 'a', ARRAY_SIZE(buffA)); buffA[ARRAY_SIZE(buffA)-1] = 0; r = SetWindowTextA(edit, buffA); expect(TRUE, r); r = GetWindowTextA(edit, buffA, ARRAY_SIZE(buffA)); ok( r == ARRAY_SIZE(buffA) - 1, "got %d\n", r ); /* ...but it's trimmed to MAX_PATH chars when editing ends */ r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); expect(0, r); item.mask = TVIF_TEXT; item.hItem = hRoot; item.pszText = buffA; item.cchTextMax = ARRAY_SIZE(buffA); r = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, r); expect(MAX_PATH - 1, lstrlenA(item.pszText));
/* We can't get around that MAX_PATH limit by increasing EM_SETLIMITTEXT */ edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot); ok(IsWindow(edit), "Expected valid handle\n"); SendMessageA(edit, EM_SETLIMITTEXT, ARRAY_SIZE(buffA)-1, 0); memset(buffA, 'a', ARRAY_SIZE(buffA)); buffA[ARRAY_SIZE(buffA)-1] = 0; r = SetWindowTextA(edit, buffA); expect(TRUE, r); r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); expect(0, r); item.mask = TVIF_TEXT; item.hItem = hRoot; item.pszText = buffA; item.cchTextMax = ARRAY_SIZE(buffA); r = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, r); expect(MAX_PATH - 1, lstrlenA(item.pszText));
/* Overwriting of pszText contents in TVN_ENDLABELEDIT */ edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot); ok(IsWindow(edit), "Expected valid handle\n"); r = SetWindowTextA(edit, "old"); expect(TRUE, r); g_endedit_overwrite_contents = "<new_contents>"; r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); expect(0, r); g_endedit_overwrite_contents = NULL; item.mask = TVIF_TEXT; item.hItem = hRoot; item.pszText = buffA; item.cchTextMax = ARRAY_SIZE(buffA); r = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, r); expect(0, strcmp(item.pszText, "<new_contents>"));
/* Overwriting of pszText pointer in TVN_ENDLABELEDIT */ edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot); ok(IsWindow(edit), "Expected valid handle\n"); r = SetWindowTextA(edit, "old"); expect(TRUE, r); g_endedit_overwrite_ptr = (char*) "<new_ptr>"; r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); expect(0, r); g_endedit_overwrite_ptr = NULL; item.mask = TVIF_TEXT; item.hItem = hRoot; item.pszText = buffA; item.cchTextMax = ARRAY_SIZE(buffA); r = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, r); expect(0, strcmp(item.pszText, "<new_ptr>"));
DestroyWindow(hTree);}
static void test_treeview_classinfo(void){ WNDCLASSA cls;
memset(&cls, 0, sizeof(cls)); GetClassInfoA(GetModuleHandleA("comctl32.dll"), WC_TREEVIEWA, &cls); ok(cls.hbrBackground == NULL, "Expected NULL background brush, got %p\n", cls.hbrBackground); ok(cls.style == (CS_GLOBALCLASS | CS_DBLCLKS), "Expected got %x\n", cls.style); expect(0, cls.cbClsExtra);}
static void test_get_linecolor(void){ COLORREF clr; HWND hTree;
hTree = create_treeview_control(0);
/* newly created control has default color */ clr = SendMessageA(hTree, TVM_GETLINECOLOR, 0, 0); if (clr == 0) win_skip("TVM_GETLINECOLOR is not supported on comctl32 < 5.80\n"); else expect(CLR_DEFAULT, clr);
DestroyWindow(hTree);}
static void test_get_insertmarkcolor(void){ COLORREF clr; HWND hTree;
hTree = create_treeview_control(0);
/* newly created control has default color */ clr = SendMessageA(hTree, TVM_GETINSERTMARKCOLOR, 0, 0); if (clr == 0) win_skip("TVM_GETINSERTMARKCOLOR is not supported on comctl32 < 5.80\n"); else expect(CLR_DEFAULT, clr);
DestroyWindow(hTree);}
static void test_expandnotify(void){ HTREEITEM hitem; HWND hTree; BOOL ret; TVITEMA item;
hTree = create_treeview_control(0); fill_tree(hTree);
item.hItem = hRoot; item.mask = TVIF_STATE;
item.state = TVIS_EXPANDED; ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, ret); ok((item.state & TVIS_EXPANDED) == 0, "expected collapsed\n");
/* preselect root node here */ ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); expect(TRUE, ret);
flush_sequences(sequences, NUM_MSG_SEQUENCES); ret = SendMessageA(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot); expect(FALSE, ret); ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "no collapse notifications", FALSE);
g_get_from_expand = TRUE; /* expand */ flush_sequences(sequences, NUM_MSG_SEQUENCES); g_item_expanding.state = 0xdeadbeef; g_item_expanded.state = 0xdeadbeef; ret = SendMessageA(hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)hRoot); expect(TRUE, ret); ok(g_item_expanding.state == TVIS_SELECTED, "got state on TVN_ITEMEXPANDING 0x%08x\n", g_item_expanding.state); ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED), "got state on TVN_ITEMEXPANDED 0x%08x\n", g_item_expanded.state); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_seq, "expand notifications", FALSE); g_get_from_expand = FALSE;
/* check that it's expanded */ item.state = TVIS_EXPANDED; ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, ret); ok((item.state & TVIS_EXPANDED) == TVIS_EXPANDED, "expected expanded\n");
/* collapse */ flush_sequences(sequences, NUM_MSG_SEQUENCES); ret = SendMessageA(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot); expect(TRUE, ret); item.state = TVIS_EXPANDED; ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, ret); ok((item.state & TVIS_EXPANDED) == 0, "expected collapsed\n"); /* all further collapse/expand attempts won't produce any notifications, the only way is to reset with all children removed */ ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "collapse after expand notifications", FALSE);
/* try to toggle child that doesn't have children itself */ flush_sequences(sequences, NUM_MSG_SEQUENCES); ret = SendMessageA(hTree, TVM_EXPAND, TVE_TOGGLE, (LPARAM)hChild); expect(FALSE, ret); ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "toggle node without children", FALSE);
DestroyWindow(hTree);
/* test TVM_GETITEMRECT inside TVN_ITEMEXPANDED notification */ hTree = create_treeview_control(0); fill_tree(hTree); g_get_rect_in_expand = TRUE; ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild); expect(TRUE, ret); g_get_rect_in_expand = FALSE;
DestroyWindow(hTree);
/* TVE_TOGGLE acts as any other TVM_EXPAND */ hTree = create_treeview_control(0); fill_tree(hTree);
flush_sequences(sequences, NUM_MSG_SEQUENCES); ret = SendMessageA(hTree, TVM_EXPAND, TVE_TOGGLE, (LPARAM)hRoot); expect(TRUE, ret); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_seq, "toggle node (expand)", FALSE);
/* toggle again - no notifications */ flush_sequences(sequences, NUM_MSG_SEQUENCES); ret = SendMessageA(hTree, TVM_EXPAND, TVE_TOGGLE, (LPARAM)hRoot); expect(TRUE, ret); ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "toggle node (collapse)", FALSE);
DestroyWindow(hTree);
/* some keyboard events are also translated to expand */ hTree = create_treeview_control(0); fill_tree(hTree);
/* preselect root node here */ ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); expect(TRUE, ret);
g_get_from_expand = TRUE; flush_sequences(sequences, NUM_MSG_SEQUENCES); ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0); expect(FALSE, ret); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_kb_seq, "expand node", FALSE); ok(g_item_expanding.state == TVIS_SELECTED, "got state on TVN_ITEMEXPANDING 0x%08x\n", g_item_expanding.state); ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED), "got state on TVN_ITEMEXPANDED 0x%08x\n", g_item_expanded.state);
flush_sequences(sequences, NUM_MSG_SEQUENCES); ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0); expect(FALSE, ret); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_kb_seq, "expand node again", FALSE); ok(g_item_expanding.state == (TVIS_SELECTED|TVIS_EXPANDED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDING 0x%08x\n", g_item_expanding.state); ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDED 0x%08x\n", g_item_expanded.state);
flush_sequences(sequences, NUM_MSG_SEQUENCES); ret = SendMessageA(hTree, WM_KEYDOWN, VK_SUBTRACT, 0); expect(FALSE, ret); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_kb_seq, "collapse node", FALSE); ok(g_item_expanding.state == (TVIS_SELECTED|TVIS_EXPANDED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDING 0x%08x\n", g_item_expanding.state); ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDED 0x%08x\n", g_item_expanded.state);
flush_sequences(sequences, NUM_MSG_SEQUENCES); ret = SendMessageA(hTree, WM_KEYDOWN, VK_SUBTRACT, 0); expect(FALSE, ret); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_collapse_2nd_kb_seq, "collapse node again", FALSE); ok(g_item_expanding.state == (TVIS_SELECTED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDING 0x%08x\n", g_item_expanding.state); g_get_from_expand = FALSE;
flush_sequences(sequences, NUM_MSG_SEQUENCES); ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0); expect(FALSE, ret); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_kb_seq, "expand node", FALSE);
/* go to child */ ret = SendMessageA(hTree, WM_KEYDOWN, VK_RIGHT, 0); expect(FALSE, ret);
/* try to expand child that doesn't have children itself */ flush_sequences(sequences, NUM_MSG_SEQUENCES); ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0); expect(FALSE, ret); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_empty_kb_seq, "expand node with no children", FALSE);
/* stay on current selection and set non-zero children count */ hitem = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CARET, 0); ok(hitem != NULL, "got %p\n", hitem);
item.hItem = hitem; item.mask = TVIF_CHILDREN; item.cChildren = 0x80000000;
ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item); expect(TRUE, ret);
flush_sequences(sequences, NUM_MSG_SEQUENCES); ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0); expect(FALSE, ret); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_collapse_2nd_kb_seq, "expand node with children", FALSE);
DestroyWindow(hTree);}
static void test_expandedimage(void){ TVITEMEXA item; HWND hTree; BOOL ret;
hTree = create_treeview_control(0); fill_tree(hTree);
item.mask = TVIF_EXPANDEDIMAGE; item.iExpandedImage = 1; item.hItem = hRoot; ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item); ok(ret, "got %d\n", ret);
item.mask = TVIF_EXPANDEDIMAGE; item.iExpandedImage = -1; item.hItem = hRoot; ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); ok(ret, "got %d\n", ret);
if (item.iExpandedImage != 1) { win_skip("TVIF_EXPANDEDIMAGE not supported\n"); DestroyWindow(hTree); return; }
/* test for default iExpandedImage value */ item.mask = TVIF_EXPANDEDIMAGE; item.iExpandedImage = -1; item.hItem = hChild; ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); ok(ret, "got %d\n", ret); ok(item.iExpandedImage == (WORD)I_IMAGENONE, "got %d\n", item.iExpandedImage);
DestroyWindow(hTree);}
static void test_TVS_SINGLEEXPAND(void){ HWND hTree; HTREEITEM alpha, bravo, charlie, delta, echo, foxtrot, golf, hotel, india, juliet; TVINSERTSTRUCTA ins; char foo[] = "foo"; char context[32]; int i; BOOL ret;
/* build a fairly complex tree * - TVI_ROOT * - alpha * - bravo * - charlie * - delta * - echo * - foxtrot * - golf * - hotel * - india * - juliet */ struct { HTREEITEM *handle; HTREEITEM *parent; UINT final_state; } items[] = { { &alpha, NULL, TVIS_EXPANDEDONCE }, { &bravo, &alpha, TVIS_EXPANDEDONCE }, { &charlie, &bravo, 0 }, { &delta, &alpha, TVIS_EXPANDEDONCE }, { &echo, &delta, 0 }, { &foxtrot, NULL, TVIS_EXPANDEDONCE|TVIS_EXPANDED }, { &golf, &foxtrot, TVIS_EXPANDEDONCE|TVIS_EXPANDED }, { &hotel, &golf, 0 }, { &india, &golf, TVIS_SELECTED }, { &juliet, &foxtrot, 0 } };
struct { HTREEITEM *select; const struct message *sequence; } sequence_tests[] = { { &alpha, parent_singleexpand_seq0 }, { &bravo, parent_singleexpand_seq1 }, { &delta, parent_singleexpand_seq2 }, { &foxtrot, parent_singleexpand_seq3 }, { &alpha, parent_singleexpand_seq4 }, { &golf, parent_singleexpand_seq5 }, { &hotel, parent_singleexpand_seq6 }, { &india, parent_singleexpand_seq7 }, { &india, empty_seq } };
hTree = create_treeview_control(0); SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_SINGLEEXPAND); /* to avoid painting related notifications */ ShowWindow(hTree, SW_HIDE); for (i = 0; i < ARRAY_SIZE(items); i++) { ins.hParent = items[i].parent ? *items[i].parent : TVI_ROOT; ins.hInsertAfter = TVI_FIRST; U(ins).item.mask = TVIF_TEXT; U(ins).item.pszText = foo; *items[i].handle = TreeView_InsertItemA(hTree, &ins); }
for (i = 0; i < ARRAY_SIZE(sequence_tests); i++) { flush_sequences(sequences, NUM_MSG_SEQUENCES); ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)(*sequence_tests[i].select)); ok(ret, "got %d\n", ret); sprintf(context, "singleexpand notifications %d", i); ok_sequence(sequences, PARENT_SEQ_INDEX, sequence_tests[i].sequence, context, FALSE); }
for (i = 0; i < ARRAY_SIZE(items); i++) { ret = SendMessageA(hTree, TVM_GETITEMSTATE, (WPARAM)(*items[i].handle), 0xFFFF); ok(ret == items[i].final_state, "singleexpand items[%d]: expected state 0x%x got 0x%x\n", i, items[i].final_state, ret); }
/* a workaround for NT4 that sends expand notifications when nothing is about to expand */ ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT); ok(ret, "got %d\n", ret); fill_tree(hTree); ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0); ok(ret, "got %d\n", ret);
DestroyWindow(hTree);}
static void test_WM_PAINT(void){ HWND hTree; COLORREF clr; LONG ret; RECT rc; HDC hdc;
hTree = create_treeview_control(0);
clr = SendMessageA(hTree, TVM_SETBKCOLOR, 0, RGB(255, 0, 0)); ok(clr == ~0u, "got %d, expected -1\n", clr);
hdc = GetDC(hMainWnd);
GetClientRect(hMainWnd, &rc); FillRect(hdc, &rc, GetStockObject(BLACK_BRUSH));
clr = GetPixel(hdc, 1, 1); ok(clr == RGB(0, 0, 0), "got 0x%x\n", clr);
ret = SendMessageA(hTree, WM_PAINT, (WPARAM)hdc, 0); ok(ret == 0, "got %d\n", ret);
clr = GetPixel(hdc, 1, 1); ok(clr == RGB(255, 0, 0) || broken(clr == RGB(0, 0, 0)) /* win98 */, "got 0x%x\n", clr);
ReleaseDC(hMainWnd, hdc);
DestroyWindow(hTree);}
static void test_delete_items(void){ const struct message *msg; HWND hTree; HTREEITEM hItem1, hItem2; TVINSERTSTRUCTA ins; INT ret;
static CHAR item1[] = "Item 1"; static CHAR item2[] = "Item 2";
hTree = create_treeview_control(0); fill_tree(hTree);
/* check delete order */ flush_sequences(item_sequence, 1); ret = SendMessageA(hTree, TVM_DELETEITEM, 0, 0); ok(ret == TRUE, "got %d\n", ret);
msg = item_sequence[0]->sequence; ok(item_sequence[0]->count == 2, "expected 2 items, got %d\n", item_sequence[0]->count);
if (item_sequence[0]->count == 2) { ok(msg[0].lParam == (LPARAM)hChild, "expected %p, got 0x%lx\n", hChild, msg[0].lParam); ok(msg[1].lParam == (LPARAM)hRoot, "expected %p, got 0x%lx\n", hRoot, msg[1].lParam); }
ret = SendMessageA(hTree, TVM_GETCOUNT, 0, 0); ok(ret == 0, "got %d\n", ret);
DestroyWindow(hTree);
/* Regression test for a crash when deleting the first visible item while bRedraw == false. */ hTree = create_treeview_control(0);
ret = SendMessageA(hTree, WM_SETREDRAW, FALSE, 0); ok(ret == 0, "got %d\n", ret);
ins.hParent = TVI_ROOT; ins.hInsertAfter = TVI_ROOT; U(ins).item.mask = TVIF_TEXT; U(ins).item.pszText = item1; hItem1 = TreeView_InsertItemA(hTree, &ins); ok(hItem1 != NULL, "InsertItem failed\n");
ins.hParent = TVI_ROOT; ins.hInsertAfter = hItem1; U(ins).item.mask = TVIF_TEXT; U(ins).item.pszText = item2; hItem2 = TreeView_InsertItemA(hTree, &ins); ok(hItem2 != NULL, "InsertItem failed\n");
ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hItem1); ok(ret == TRUE, "got %d\n", ret);
ret = SendMessageA(hTree, WM_SETREDRAW, TRUE, 0); ok(ret == 0, "got %d\n", ret);
DestroyWindow(hTree);}
static void test_cchildren(void){ HWND hTree; INT ret; TVITEMA item;
hTree = create_treeview_control(0); fill_tree(hTree);
ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild); expect(TRUE, ret);
/* check cChildren - automatic mode */ item.hItem = hRoot; item.mask = TVIF_CHILDREN;
ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, ret); expect(0, item.cChildren);
DestroyWindow(hTree);
/* start over */ hTree = create_treeview_control(0); fill_tree(hTree);
/* turn off automatic mode by setting cChildren explicitly */ item.hItem = hRoot; item.mask = TVIF_CHILDREN;
ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, ret); expect(1, item.cChildren);
ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item); expect(TRUE, ret);
ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild); expect(TRUE, ret);
/* check cChildren */ ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, ret);todo_wine expect(1, item.cChildren);
DestroyWindow(hTree);}
struct _ITEM_DATA{ HTREEITEM parent; /* for root value of parent field is unidetified */ HTREEITEM nextsibling; HTREEITEM firstchild; void *unk[2]; DWORD unk2; WORD pad; WORD width;};
struct _ITEM_DATA_V6{ HTREEITEM parent; /* for root value of parent field is unidetified */ HTREEITEM nextsibling; HTREEITEM firstchild; void *unk[3]; DWORD unk2[2]; WORD pad; WORD width;};
static void _check_item(HWND hwnd, HTREEITEM item, BOOL is_version_6, int line){ struct _ITEM_DATA *data = (struct _ITEM_DATA *)item; HTREEITEM parent, nextsibling, firstchild, root; RECT rect; BOOL ret;
root = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_ROOT, (LPARAM)item); parent = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)item); nextsibling = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)item); firstchild = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)item);
*(HTREEITEM*)&rect = item; ret = SendMessageA(hwnd, TVM_GETITEMRECT, TRUE, (LPARAM)&rect);
ok_(__FILE__, line)(item == root ? data->parent != NULL : data->parent == parent, "Unexpected parent item %p, got %p, %p\n", parent, data->parent, hwnd); ok_(__FILE__, line)(data->nextsibling == nextsibling, "Unexpected sibling %p, got %p\n", nextsibling, data->nextsibling); ok_(__FILE__, line)(data->firstchild == firstchild, "Unexpected first child %p, got %p\n", firstchild, data->firstchild); if (ret) { WORD width;
if (is_version_6) { struct _ITEM_DATA_V6 *data_v6 = (struct _ITEM_DATA_V6 *)item; width = data_v6->width; } else width = data->width; todo_wine ok_(__FILE__, line)(width == (rect.right - rect.left) || broken(is_version_6 && width == 0) /* XP */, "Width %d, rect width %d.\n", width, rect.right - rect.left); }}
#define CHECK_ITEM(a, b) _check_item(a, b, is_version_6, __LINE__)
static void test_htreeitem_layout(BOOL is_version_6){ TVINSERTSTRUCTA ins; HTREEITEM item1, item2; HWND hTree;
hTree = create_treeview_control(0); fill_tree(hTree);
/* root has some special pointer in parent field */ CHECK_ITEM(hTree, hRoot); CHECK_ITEM(hTree, hChild);
ins.hParent = hChild; ins.hInsertAfter = TVI_FIRST; U(ins).item.mask = 0; item1 = TreeView_InsertItemA(hTree, &ins);
CHECK_ITEM(hTree, item1);
ins.hParent = hRoot; ins.hInsertAfter = TVI_FIRST; U(ins).item.mask = 0; item2 = TreeView_InsertItemA(hTree, &ins);
CHECK_ITEM(hTree, item2);
SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild);
/* without children now */ CHECK_ITEM(hTree, hRoot);
DestroyWindow(hTree);}
static void test_TVS_CHECKBOXES(void){ HIMAGELIST himl, himl2; HWND hTree, hTree2; TVITEMA item; DWORD ret; MSG msg;
hTree = create_treeview_control(0); fill_tree(hTree);
himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); ok(himl == NULL, "got %p\n", himl);
item.hItem = hRoot; item.mask = TVIF_STATE; item.state = INDEXTOSTATEIMAGEMASK(1); item.stateMask = TVIS_STATEIMAGEMASK; ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, ret); ok(item.state == 0, "got 0x%x\n", item.state);
/* set some index for a child */ item.hItem = hChild; item.mask = TVIF_STATE; item.state = INDEXTOSTATEIMAGEMASK(4); item.stateMask = TVIS_STATEIMAGEMASK; ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item); expect(TRUE, ret);
/* enabling check boxes set all items to 1 state image index */ SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_CHECKBOXES); himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); ok(himl != NULL, "got %p\n", himl);
himl2 = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); ok(himl2 != NULL, "got %p\n", himl2); ok(himl2 == himl, "got %p, expected %p\n", himl2, himl);
item.hItem = hRoot; item.mask = TVIF_STATE; item.state = 0; item.stateMask = TVIS_STATEIMAGEMASK; ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, ret); ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
item.hItem = hChild; item.mask = TVIF_STATE; item.state = 0; item.stateMask = TVIS_STATEIMAGEMASK; ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, ret); ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
/* create another control and check its checkbox list */ hTree2 = create_treeview_control(0); fill_tree(hTree2);
/* set some index for a child */ item.hItem = hChild; item.mask = TVIF_STATE; item.state = INDEXTOSTATEIMAGEMASK(4); item.stateMask = TVIS_STATEIMAGEMASK; ret = SendMessageA(hTree2, TVM_SETITEMA, 0, (LPARAM)&item); expect(TRUE, ret);
/* enabling check boxes set all items to 1 state image index */ SetWindowLongA(hTree2, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_CHECKBOXES); himl2 = (HIMAGELIST)SendMessageA(hTree2, TVM_GETIMAGELIST, TVSIL_STATE, 0); ok(himl2 != NULL, "got %p\n", himl2); ok(himl != himl2, "got %p, expected %p\n", himl2, himl);
DestroyWindow(hTree2); DestroyWindow(hTree);
/* the same, but initially created with TVS_CHECKBOXES */ hTree = create_treeview_control(TVS_CHECKBOXES); fill_tree(hTree); himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); ok(himl == NULL, "got %p\n", himl);
item.hItem = hRoot; item.mask = TVIF_STATE; item.state = 0; item.stateMask = TVIS_STATEIMAGEMASK; ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, ret); ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
item.hItem = hChild; item.mask = TVIF_STATE; item.state = 0; item.stateMask = TVIS_STATEIMAGEMASK; ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, ret); ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
item.hItem = hChild; item.mask = TVIF_STATE; item.state = INDEXTOSTATEIMAGEMASK(2); item.stateMask = TVIS_STATEIMAGEMASK; ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item); expect(TRUE, ret);
item.hItem = hChild; item.mask = TVIF_STATE; item.state = 0; ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, ret); ok(item.state == INDEXTOSTATEIMAGEMASK(2), "got 0x%x\n", item.state);
while(GetMessageA(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessageA(&msg);
if((msg.hwnd == hTree) && (msg.message == WM_PAINT)) break; }
item.hItem = hChild; item.mask = TVIF_STATE; item.state = 0; ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, ret); ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); ok(himl != NULL, "got %p\n", himl);
DestroyWindow(hTree);
/* check what happens if TVSIL_STATE image list is removed */ hTree = create_treeview_control(0); fill_tree(hTree); himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); ok(himl == NULL, "got %p\n", himl);
SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_CHECKBOXES); himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); ok(himl != NULL, "got %p\n", himl);
himl2 = (HIMAGELIST)SendMessageA(hTree, TVM_SETIMAGELIST, TVSIL_STATE, 0); ok(himl2 == himl, "got %p\n", himl2);
himl2 = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); ok(himl2 == NULL, "got %p\n", himl2);
item.hItem = hChild; item.mask = TVIF_STATE; item.state = INDEXTOSTATEIMAGEMASK(2); item.stateMask = TVIS_STATEIMAGEMASK; ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item); expect(TRUE, ret);
item.hItem = hChild; item.mask = TVIF_STATE; item.state = 0; ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, ret); ok(item.state == INDEXTOSTATEIMAGEMASK(2), "got 0x%x\n", item.state);
while(GetMessageA(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessageA(&msg);
if((msg.hwnd == hTree) && (msg.message == WM_PAINT)) break; }
item.hItem = hChild; item.mask = TVIF_STATE; item.state = 0; ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item); expect(TRUE, ret); ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0); ok(himl != NULL, "got %p\n", himl);
DestroyWindow(hTree);}
static void test_TVM_GETNEXTITEM(void){ HTREEITEM item; HWND hTree;
hTree = create_treeview_control(0); fill_tree(hTree);
item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_ROOT, 0); ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_ROOT, (LPARAM)TVI_ROOT); ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_ROOT, (LPARAM)hRoot); ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_ROOT, (LPARAM)hChild); ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CHILD, 0); ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hRoot); ok(item == hChild, "got %p, expected %p\n", item, hChild);
item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)TVI_ROOT); ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_PARENT, 0); ok(item == NULL, "got %p\n", item);
item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hChild); ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
DestroyWindow(hTree);}
static void test_TVM_HITTEST(void){ HWND hTree; LRESULT ret; RECT rc; TVHITTESTINFO ht;
hTree = create_treeview_control(0); fill_tree(hTree);
*(HTREEITEM*)&rc = hRoot; ret = SendMessageA(hTree, TVM_GETITEMRECT, TRUE, (LPARAM)&rc); expect(TRUE, (BOOL)ret);
ht.pt.x = rc.left-1; ht.pt.y = rc.top;
ret = SendMessageA(hTree, TVM_HITTEST, 0, (LPARAM)&ht); ok((HTREEITEM)ret == hRoot, "got %p, expected %p\n", (HTREEITEM)ret, hRoot); ok(ht.hItem == hRoot, "got %p, expected %p\n", ht.hItem, hRoot); ok(ht.flags == TVHT_ONITEMBUTTON, "got %d, expected %d\n", ht.flags, TVHT_ONITEMBUTTON);
ret = SendMessageA(hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)hRoot); expect(TRUE, (BOOL)ret);
*(HTREEITEM*)&rc = hChild; ret = SendMessageA(hTree, TVM_GETITEMRECT, TRUE, (LPARAM)&rc); expect(TRUE, (BOOL)ret);
ht.pt.x = rc.left-1; ht.pt.y = rc.top;
ret = SendMessageA(hTree, TVM_HITTEST, 0, (LPARAM)&ht); ok((HTREEITEM)ret == hChild, "got %p, expected %p\n", (HTREEITEM)ret, hChild); ok(ht.hItem == hChild, "got %p, expected %p\n", ht.hItem, hChild); /* Wine returns item button here, but this item has no button */ todo_wine ok(ht.flags == TVHT_ONITEMINDENT, "got %d, expected %d\n", ht.flags, TVHT_ONITEMINDENT);
DestroyWindow(hTree);}
static void test_WM_GETDLGCODE(void){ DWORD code; HWND hTree;
hTree = create_treeview_control(0);
code = SendMessageA(hTree, WM_GETDLGCODE, VK_TAB, 0); ok(code == (DLGC_WANTCHARS | DLGC_WANTARROWS), "0x%08x\n", code);
DestroyWindow(hTree);}
static void test_customdraw(void){ LOGFONTA lf; HWND hwnd;
hwnd = create_treeview_control(0); fill_tree(hwnd); SendMessageA(hwnd, TVM_EXPAND, TVE_EXPAND, (WPARAM)hRoot);
/* create additional font, custom draw handler will select it */ SystemParametersInfoA(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0); lf.lfHeight *= 2; g_customdraw_font = CreateFontIndirectA(&lf); flush_sequences(sequences, NUM_MSG_SEQUENCES); InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_cd_seq, "custom draw notifications", FALSE); DeleteObject(g_customdraw_font); g_customdraw_font = NULL;
DestroyWindow(hwnd);}
static void test_WM_KEYDOWN(void){ static const char *rootA = "root"; TVINSERTSTRUCTA ins; HTREEITEM hRoot; HWND hwnd;
hwnd = create_treeview_control(0);
ins.hParent = TVI_ROOT; ins.hInsertAfter = TVI_ROOT; U(ins).item.mask = TVIF_TEXT; U(ins).item.pszText = (char*)rootA; hRoot = TreeView_InsertItemA(hwnd, &ins); ok(hRoot != NULL, "got %p\n", hRoot);
flush_sequences(sequences, NUM_MSG_SEQUENCES); SendMessageA(hwnd, WM_KEYDOWN, VK_RETURN, 0); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_vk_return_seq, "WM_KEYDOWN/VK_RETURN parent notification", TRUE);
DestroyWindow(hwnd);}
static void test_TVS_FULLROWSELECT(void){ DWORD style; HWND hwnd;
/* try to create both with TVS_HASLINES and TVS_FULLROWSELECT */ hwnd = create_treeview_control(TVS_FULLROWSELECT);
style = GetWindowLongA(hwnd, GWL_STYLE); ok((style & (TVS_FULLROWSELECT | TVS_HASLINES)) == (TVS_FULLROWSELECT | TVS_HASLINES), "got style 0x%08x\n", style);
DestroyWindow(hwnd);
/* create just with TVS_HASLINES, try to enable TVS_FULLROWSELECT later */ hwnd = create_treeview_control(0);
style = GetWindowLongA(hwnd, GWL_STYLE); SetWindowLongA(hwnd, GWL_STYLE, style | TVS_FULLROWSELECT); style = GetWindowLongA(hwnd, GWL_STYLE); ok(style & TVS_FULLROWSELECT, "got style 0x%08x\n", style);
DestroyWindow(hwnd);}
static void get_item_names_string(HWND hwnd, HTREEITEM item, char *str){ TVITEMA tvitem = { 0 }; HTREEITEM child; char name[16];
if (!item) { item = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_ROOT, 0); str[0] = 0; }
child = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)item);
tvitem.mask = TVIF_TEXT; tvitem.hItem = item; tvitem.pszText = name; tvitem.cchTextMax = sizeof(name); SendMessageA(hwnd, TVM_GETITEMA, 0, (LPARAM)&tvitem); strcat(str, tvitem.pszText);
while (child != NULL) { get_item_names_string(hwnd, child, str); child = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)child); }}
static void fill_treeview_sort_test(HWND hwnd){ static const char *itemnames[] = { "root", "Wasp", "Caribou", "Vacuum", "Ocelot", "Newspaper", "Litter bin" };
HTREEITEM root, children[2]; TVINSERTSTRUCTA ins; unsigned i = 0;
SendMessageA(hwnd, TVM_DELETEITEM, 0, 0);
/* root, two children, with two children each */ ins.hParent = TVI_ROOT; ins.hInsertAfter = TVI_ROOT; U(ins).item.mask = TVIF_TEXT; U(ins).item.pszText = (char *)itemnames[i++]; root = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
ins.hParent = root; ins.hInsertAfter = TVI_LAST; U(ins).item.mask = TVIF_TEXT; U(ins).item.pszText = (char *)itemnames[i++]; children[0] = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
U(ins).item.pszText = (char *)itemnames[i++]; children[1] = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
ins.hParent = children[0]; U(ins).item.pszText = (char *)itemnames[i++]; SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
U(ins).item.pszText = (char *)itemnames[i++]; SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
ins.hParent = children[1]; U(ins).item.pszText = (char *)itemnames[i++]; SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
U(ins).item.pszText = (char *)itemnames[i++]; SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);}
static void test_TVM_SORTCHILDREN(void){ static const char *initial_order = "rootWaspVacuumOcelotCaribouNewspaperLitter bin"; static const char *sorted_order = "rootCaribouNewspaperLitter binWaspVacuumOcelot"; TVINSERTSTRUCTA ins; char buff[256]; HTREEITEM root; HWND hwnd; BOOL ret;
hwnd = create_treeview_control(0);
/* call on empty tree */ ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, 0); ok(!ret, "Unexpected ret value %d\n", ret);
ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, (LPARAM)TVI_ROOT); ok(!ret, "Unexpected ret value %d\n", ret);
/* add only root, sort from it */ ins.hParent = TVI_ROOT; ins.hInsertAfter = TVI_ROOT; U(ins).item.mask = TVIF_TEXT; U(ins).item.pszText = (char *)"root"; root = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins); ok(root != NULL, "Expected root node\n");
ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, (LPARAM)root); ok(!ret, "Unexpected ret value %d\n", ret);
ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, (LPARAM)root); ok(!ret, "Unexpected ret value %d\n", ret);
/* root, two children, with two children each */ fill_treeview_sort_test(hwnd); get_item_names_string(hwnd, NULL, buff); ok(!strcmp(buff, initial_order), "Wrong initial order %s, expected %s\n", buff, initial_order);
/* with NULL item nothing is sorted */ fill_treeview_sort_test(hwnd); ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, 0);todo_wine ok(ret, "Unexpected ret value %d\n", ret); get_item_names_string(hwnd, NULL, buff); ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, initial_order);
/* TVI_ROOT as item */ fill_treeview_sort_test(hwnd); ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, (LPARAM)TVI_ROOT);todo_wine ok(ret, "Unexpected ret value %d\n", ret); get_item_names_string(hwnd, NULL, buff); ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, initial_order);
/* zero WPARAM, item is specified */ fill_treeview_sort_test(hwnd); root = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_ROOT, 0); ok(root != NULL, "Failed to get root item\n"); ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, (LPARAM)root); ok(ret, "Unexpected ret value %d\n", ret); get_item_names_string(hwnd, NULL, buff); ok(!strcmp(buff, sorted_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order);
/* non-zero WPARAM, NULL item */ fill_treeview_sort_test(hwnd); ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, 0);todo_wine ok(ret, "Unexpected ret value %d\n", ret); get_item_names_string(hwnd, NULL, buff); ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order);
/* TVI_ROOT as item */ fill_treeview_sort_test(hwnd); ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, (LPARAM)TVI_ROOT);todo_wine ok(ret, "Unexpected ret value %d\n", ret); get_item_names_string(hwnd, NULL, buff); ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order);
/* non-zero WPARAM, item is specified */ fill_treeview_sort_test(hwnd); root = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_ROOT, 0); ok(root != NULL, "Failed to get root item\n"); ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, (LPARAM)root); ok(ret, "Unexpected ret value %d\n", ret); get_item_names_string(hwnd, NULL, buff); ok(!strcmp(buff, sorted_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order);
/* case insensitive comparison */ SendMessageA(hwnd, TVM_DELETEITEM, 0, 0);
ins.hParent = TVI_ROOT; ins.hInsertAfter = TVI_ROOT; U(ins).item.mask = TVIF_TEXT; U(ins).item.pszText = (char *)"root"; root = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins); ok(root != NULL, "Expected root node\n");
ins.hParent = root; ins.hInsertAfter = TVI_LAST; U(ins).item.pszText = (char *)"I1"; SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
ins.hParent = root; ins.hInsertAfter = TVI_LAST; U(ins).item.pszText = (char *)"i1"; SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, (LPARAM)root); ok(ret, "Unexpected ret value %d\n", ret); get_item_names_string(hwnd, NULL, buff); ok(!strcmp(buff, "rootI1i1"), "Wrong sorted order %s\n", buff);
DestroyWindow(hwnd);}
static void test_right_click(void){ HWND hTree; HTREEITEM selected; RECT rc; LRESULT result; POINT pt, orig_pos;
hTree = create_treeview_control(0); fill_tree(hTree);
SendMessageA(hTree, TVM_ENSUREVISIBLE, 0, (LPARAM)hChild); SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild); selected = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CARET, 0); ok(selected == hChild, "child item not selected\n");
*(HTREEITEM *)&rc = hRoot; result = SendMessageA(hTree, TVM_GETITEMRECT, TRUE, (LPARAM)&rc); ok(result, "TVM_GETITEMRECT failed\n");
flush_events();
pt.x = (rc.left + rc.right) / 2; pt.y = (rc.top + rc.bottom) / 2; ClientToScreen(hMainWnd, &pt); GetCursorPos(&orig_pos); SetCursorPos(pt.x, pt.y);
flush_events(); flush_sequences(sequences, NUM_MSG_SEQUENCES);
PostMessageA(hTree, WM_RBUTTONDOWN, MK_RBUTTON, MAKELPARAM(pt.x, pt.y)); PostMessageA(hTree, WM_RBUTTONUP, 0, MAKELPARAM(pt.x, pt.y));
flush_events();
ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_right_click_seq, "right click sequence", FALSE); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_right_click_seq, "parent right click sequence", FALSE);
selected = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CARET, 0); ok(selected == hChild, "child item should still be selected\n");
SetCursorPos(orig_pos.x, orig_pos.y); DestroyWindow(hTree);}
static void init_functions(void){ HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
#define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f); X(InitCommonControlsEx);#undef X}
START_TEST(treeview){ INITCOMMONCONTROLSEX iccex; ULONG_PTR ctx_cookie; HANDLE hCtx; WNDCLASSA wc;
init_functions();
iccex.dwSize = sizeof(iccex); iccex.dwICC = ICC_TREEVIEW_CLASSES; pInitCommonControlsEx(&iccex);
init_msg_sequences(sequences, NUM_MSG_SEQUENCES); init_msg_sequences(item_sequence, 1); wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = GetModuleHandleA(NULL); wc.hIcon = NULL; wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_IBEAM); wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); wc.lpszMenuName = NULL; wc.lpszClassName = "MyTestWnd"; wc.lpfnWndProc = parent_wnd_proc; RegisterClassA(&wc);
hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 130, 105, NULL, NULL, GetModuleHandleA(NULL), 0);
ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n"); if (!hMainWnd) return;
test_fillroot(); test_select(); test_getitemtext(); test_focus(); test_get_set_bkcolor(); test_get_set_imagelist(); test_get_set_indent(); test_get_set_insertmark(); test_get_set_item(); test_get_set_itemheight(); test_get_set_scrolltime(); test_get_set_textcolor(); test_get_linecolor(); test_get_insertmarkcolor(); test_get_set_tooltips(); test_get_set_unicodeformat(); test_callback(); test_expandinvisible(); test_itemedit(); test_treeview_classinfo(); test_expandnotify(); test_TVS_SINGLEEXPAND(); test_WM_PAINT(); test_delete_items(); test_cchildren(); test_htreeitem_layout(FALSE); test_TVS_CHECKBOXES(); test_TVM_GETNEXTITEM(); test_TVM_HITTEST(); test_WM_GETDLGCODE(); test_customdraw(); test_WM_KEYDOWN(); test_TVS_FULLROWSELECT(); test_TVM_SORTCHILDREN(); test_right_click();
if (!load_v6_module(&ctx_cookie, &hCtx)) { DestroyWindow(hMainWnd); return; }
/* comctl32 version 6 tests start here */ g_v6 = TRUE;
test_fillroot(); test_getitemtext(); test_get_set_insertmark(); test_get_set_item(); test_get_set_scrolltime(); test_get_set_textcolor(); test_get_linecolor(); test_get_insertmarkcolor(); test_expandedimage(); test_get_set_tooltips(); test_get_set_unicodeformat(); test_expandinvisible(); test_expand(); test_itemedit(); test_treeview_classinfo(); test_delete_items(); test_cchildren(); test_htreeitem_layout(TRUE); test_TVM_GETNEXTITEM(); test_TVM_HITTEST(); test_WM_GETDLGCODE(); test_customdraw(); test_WM_KEYDOWN(); test_TVS_FULLROWSELECT(); test_TVM_SORTCHILDREN();
unload_v6_module(ctx_cookie, hCtx);}