~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/comctl32/tests/treeview.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  1 /* Unit tests for treeview.
  2  *
  3  * Copyright 2005 Krzysztof Foltman
  4  * Copyright 2007 Christopher James Peterson
  5  *
  6  * This library is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU Lesser General Public
  8  * License as published by the Free Software Foundation; either
  9  * version 2.1 of the License, or (at your option) any later version.
 10  *
 11  * This library is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14  * Lesser General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU Lesser General Public
 17  * License along with this library; if not, write to the Free Software
 18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 19  */
 20 
 21 #include <assert.h>
 22 #include <stdarg.h>
 23 
 24 #include "windef.h"
 25 #include "winbase.h"
 26 #include "wingdi.h"
 27 #include "winuser.h"
 28 #include "winnls.h"
 29 #include "winreg.h"
 30 #include "commctrl.h" 
 31 
 32 #include "wine/test.h"
 33 #include "msg.h"
 34 
 35 const char *TEST_CALLBACK_TEXT = "callback_text";
 36 
 37 #define NUM_MSG_SEQUENCES   1
 38 #define TREEVIEW_SEQ_INDEX  0
 39 
 40 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
 41 
 42 static struct msg_sequence *MsgSequences[NUM_MSG_SEQUENCES];
 43 
 44 static const struct message FillRootSeq[] = {
 45     { TVM_INSERTITEM, sent },
 46     { TVM_INSERTITEM, sent },
 47     { 0 }
 48 };
 49 
 50 static const struct message rootnone_select_seq[] = {
 51     { TVM_SELECTITEM, sent|wparam, 9 },
 52     { TVM_SELECTITEM, sent|wparam, 9 },
 53     { TVM_SELECTITEM, sent|wparam, 9 },
 54     { TVM_SELECTITEM, sent|wparam, 9 },
 55     { TVM_SELECTITEM, sent|wparam, 9 },
 56     { TVM_SELECTITEM, sent|wparam, 9 },
 57     { 0 }
 58 };
 59 
 60 static const struct message rootchild_select_seq[] = {
 61     { TVM_SELECTITEM, sent|wparam, 9 },
 62     { TVM_SELECTITEM, sent|wparam, 9 },
 63     { TVM_SELECTITEM, sent|wparam, 9 },
 64     { TVM_SELECTITEM, sent|wparam, 9 },
 65     { TVM_SELECTITEM, sent|wparam, 9 },
 66     { TVM_SELECTITEM, sent|wparam, 9 },
 67     { 0 }
 68 };
 69 
 70 static const struct message getitemtext_seq[] = {
 71     { TVM_INSERTITEM, sent },
 72     { TVM_GETITEM, sent },
 73     { TVM_DELETEITEM, sent },
 74     { 0 }
 75 };
 76 
 77 static const struct message focus_seq[] = {
 78     { TVM_INSERTITEM, sent },
 79     { TVM_INSERTITEM, sent },
 80     { TVM_SELECTITEM, sent|wparam, 9 },
 81     /* The following end up out of order in wine */
 82     { WM_WINDOWPOSCHANGING, sent|defwinproc },
 83     { WM_NCCALCSIZE, sent|wparam|defwinproc, TRUE },
 84     { WM_WINDOWPOSCHANGED, sent|defwinproc },
 85     { WM_SIZE, sent|defwinproc },
 86     { WM_PAINT, sent|defwinproc },
 87     { WM_NCPAINT, sent|wparam|defwinproc, 1 },
 88     { WM_ERASEBKGND, sent|defwinproc },
 89     { TVM_EDITLABEL, sent },
 90     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_UPDATE) },
 91     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_CHANGE) },
 92     { WM_PARENTNOTIFY, sent|wparam|defwinproc, MAKEWPARAM(WM_CREATE, 0) },
 93     { WM_KILLFOCUS, sent|defwinproc },
 94     { WM_PAINT, sent|defwinproc },
 95     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
 96     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_SETFOCUS) },
 97     { WM_ERASEBKGND, sent|defwinproc|optional },
 98     { WM_CTLCOLOREDIT, sent|defwinproc|optional },
 99     { WM_CTLCOLOREDIT, sent|defwinproc|optional },
100     { 0 }
101 };
102 
103 static const struct message TestGetSetBkColorSeq[] = {
104     { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
105     { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0 },
106     { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
107     { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0x00ffffff },
108     { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
109     { TVM_SETBKCOLOR, sent|wparam|lparam, 0, -1 },
110     { 0 }
111 };
112 
113 static const struct message TestGetSetImageListSeq[] = {
114     { TVM_SETIMAGELIST, sent|wparam|lparam, 0, 0 },
115     { TVM_GETIMAGELIST, sent|wparam|lparam, 0, 0 },
116     { 0 }
117 };
118 
119 static const struct message TestGetSetIndentSeq[] = {
120     { TVM_SETINDENT, sent|wparam|lparam, 0, 0 },
121     { TVM_GETINDENT, sent|wparam|lparam, 0, 0 },
122     /* The actual amount to indent is dependent on the system for this message */
123     { TVM_SETINDENT, sent },
124     { TVM_GETINDENT, sent|wparam|lparam, 0, 0 },
125     { 0 }
126 };
127 
128 static const struct message TestGetSetInsertMarkColorSeq[] = {
129     { TVM_SETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 },
130     { TVM_GETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 },
131     { 0 }
132 };
133 
134 static const struct message TestGetSetItemSeq[] = {
135     { TVM_GETITEM, sent },
136     { TVM_SETITEM, sent },
137     { TVM_GETITEM, sent },
138     { TVM_SETITEM, sent },
139     { 0 }
140 };
141 
142 static const struct message TestGetSetItemHeightSeq[] = {
143     { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
144     { TVM_SETITEMHEIGHT, sent|wparam|lparam, -1, 0 },
145     { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
146     { TVM_SETITEMHEIGHT, sent|lparam, 0xcccccccc, 0 },
147     { TVM_GETITEMHEIGHT, sent|wparam|lparam|optional, 0, 0 },
148     { TVM_SETITEMHEIGHT, sent|wparam|lparam|optional, 9, 0 },
149     { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
150     { 0 }
151 };
152 
153 static const struct message TestGetSetScrollTimeSeq[] = {
154     { TVM_SETSCROLLTIME, sent|wparam|lparam, 20, 0 },
155     { TVM_GETSCROLLTIME, sent|wparam|lparam, 0, 0 },
156     { 0 }
157 };
158 
159 static const struct message TestGetSetTextColorSeq[] = {
160     { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
161     { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
162     { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
163     { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, 0x00ffffff },
164     { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
165     { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, -1 },
166     { 0 }
167 };
168 
169 static const struct message TestGetSetToolTipsSeq[] = {
170     { WM_KILLFOCUS,    sent },
171     { WM_IME_SETCONTEXT, sent|optional },
172     { WM_IME_NOTIFY, sent|optional },
173     { TVM_SETTOOLTIPS, sent|wparam|lparam, 0, 0 },
174     { TVM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 },
175     { 0 }
176 };
177 
178 static const struct message TestGetSetUnicodeFormatSeq[] = {
179     { TVM_SETUNICODEFORMAT, sent|wparam|lparam, TRUE, 0 },
180     { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
181     { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
182     { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
183     { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
184     { 0 }
185 };
186 
187 static HWND hMainWnd;
188 
189 static HWND hTree, hEdit;
190 static HTREEITEM hRoot, hChild;
191 
192 static int pos = 0;
193 static char sequence[256];
194 
195 static void Clear(void)
196 {
197     pos = 0;
198     sequence[0] = '\0';
199 }
200 
201 static void AddItem(char ch)
202 {
203     sequence[pos++] = ch;
204     sequence[pos] = '\0';
205 }
206 
207 static void IdentifyItem(HTREEITEM hItem)
208 {
209     if (hItem == hRoot) {
210         AddItem('R');
211         return;
212     }
213     if (hItem == hChild) {
214         AddItem('C');
215         return;
216     }
217     if (hItem == NULL) {
218         AddItem('n');
219         return;
220     }
221     AddItem('?');
222 }
223 
224 /* This function hooks in and records all messages to the treeview control */
225 static LRESULT WINAPI TreeviewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
226 {
227     static LONG defwndproc_counter = 0;
228     LRESULT ret;
229     struct message msg;
230     WNDPROC lpOldProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
231 
232     msg.message = message;
233     msg.flags = sent|wparam|lparam;
234     if (defwndproc_counter) msg.flags |= defwinproc;
235     msg.wParam = wParam;
236     msg.lParam = lParam;
237     add_message(MsgSequences, TREEVIEW_SEQ_INDEX, &msg);
238 
239     defwndproc_counter++;
240     ret = CallWindowProcA(lpOldProc, hwnd, message, wParam, lParam);
241     defwndproc_counter--;
242 
243     return ret;
244 }
245 
246 static HWND create_treeview_control(void)
247 {
248     WNDPROC pOldWndProc;
249     HWND hTree;
250 
251     hTree = CreateWindowExA(WS_EX_CLIENTEDGE, WC_TREEVIEWA, NULL, WS_CHILD|WS_VISIBLE|
252             TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS|TVS_EDITLABELS,
253             0, 0, 120, 100, hMainWnd, (HMENU)100, GetModuleHandleA(0), 0);
254 
255     SetFocus(hTree);
256 
257     /* Record the old WNDPROC so we can call it after recording the messages */
258     pOldWndProc = (WNDPROC)SetWindowLongPtrA(hTree, GWLP_WNDPROC, (LONG_PTR)TreeviewWndProc);
259     SetWindowLongPtrA(hTree, GWLP_USERDATA, (LONG_PTR)pOldWndProc);
260 
261     return hTree;
262 }
263 
264 static void fill_tree(HWND hTree)
265 {
266     TVINSERTSTRUCTA ins;
267     static CHAR root[]  = "Root",
268                 child[] = "Child";
269 
270     ins.hParent = TVI_ROOT;
271     ins.hInsertAfter = TVI_ROOT;
272     U(ins).item.mask = TVIF_TEXT;
273     U(ins).item.pszText = root;
274     hRoot = TreeView_InsertItem(hTree, &ins);
275 
276     ins.hParent = hRoot;
277     ins.hInsertAfter = TVI_FIRST;
278     U(ins).item.mask = TVIF_TEXT;
279     U(ins).item.pszText = child;
280     hChild = TreeView_InsertItem(hTree, &ins);
281 }
282 
283 static void test_fillroot(void)
284 {
285     TVITEM tvi;
286 
287     hTree = create_treeview_control();
288 
289     flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
290 
291     fill_tree(hTree);
292 
293     Clear();
294     AddItem('A');
295     assert(hRoot);
296     AddItem('B');
297     assert(hChild);
298     AddItem('.');
299     ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, FillRootSeq, "FillRoot", FALSE);
300     ok(!strcmp(sequence, "AB."), "Item creation\n");
301 
302     /* UMLPad 1.15 depends on this being not -1 (I_IMAGECALLBACK) */
303     tvi.hItem = hRoot;
304     tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
305     SendMessage( hTree, TVM_GETITEM, 0, (LPARAM)&tvi );
306     ok(tvi.iImage == 0, "tvi.iImage=%d\n", tvi.iImage);
307     ok(tvi.iSelectedImage == 0, "tvi.iSelectedImage=%d\n", tvi.iSelectedImage);
308 
309     DestroyWindow(hTree);
310 }
311 
312 static void test_callback(void)
313 {
314     HTREEITEM hRoot;
315     HTREEITEM hItem1, hItem2;
316     TVINSERTSTRUCTA ins;
317     TVITEM tvi;
318     CHAR test_string[] = "Test_string";
319     CHAR buf[128];
320     LRESULT ret;
321 
322     hTree = create_treeview_control();
323     fill_tree(hTree);
324 
325     ret = TreeView_DeleteAllItems(hTree);
326     ok(ret == TRUE, "ret\n");
327     ins.hParent = TVI_ROOT;
328     ins.hInsertAfter = TVI_ROOT;
329     U(ins).item.mask = TVIF_TEXT;
330     U(ins).item.pszText = LPSTR_TEXTCALLBACK;
331     hRoot = TreeView_InsertItem(hTree, &ins);
332     assert(hRoot);
333 
334     tvi.hItem = hRoot;
335     tvi.mask = TVIF_TEXT;
336     tvi.pszText = buf;
337     tvi.cchTextMax = sizeof(buf)/sizeof(buf[0]);
338     ret = TreeView_GetItem(hTree, &tvi);
339     ok(ret == 1, "ret\n");
340     ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Callback item text mismatch %s vs %s\n",
341         tvi.pszText, TEST_CALLBACK_TEXT);
342 
343     ins.hParent = hRoot;
344     ins.hInsertAfter = TVI_FIRST;
345     U(ins).item.mask = TVIF_TEXT;
346     U(ins).item.pszText = test_string;
347     hItem1 = TreeView_InsertItem(hTree, &ins);
348     assert(hItem1);
349 
350     tvi.hItem = hItem1;
351     ret = TreeView_GetItem(hTree, &tvi);
352     ok(ret == TRUE, "ret\n");
353     ok(strcmp(tvi.pszText, test_string) == 0, "Item text mismatch %s vs %s\n",
354         tvi.pszText, test_string);
355 
356     /* undocumented: pszText of NULL also means LPSTR_CALLBACK: */
357     tvi.pszText = NULL;
358     ret = TreeView_SetItem(hTree, &tvi);
359     ok(ret == 1, "Expected SetItem return 1, got %ld\n", ret);
360     tvi.pszText = buf;
361     ret = TreeView_GetItem(hTree, &tvi);
362     ok(ret == TRUE, "Expected GetItem return TRUE, got %ld\n", ret);
363     ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
364         tvi.pszText, TEST_CALLBACK_TEXT);
365 
366     U(ins).item.pszText = NULL;
367     hItem2 = TreeView_InsertItem(hTree, &ins);
368     assert(hItem2);
369     tvi.hItem = hItem2;
370     memset(buf, 0, sizeof(buf));
371     ret = TreeView_GetItem(hTree, &tvi);
372     ok(ret == TRUE, "Expected GetItem return TRUE, got %ld\n", ret);
373     ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
374         tvi.pszText, TEST_CALLBACK_TEXT);
375 
376     DestroyWindow(hTree);
377 }
378 
379 static void test_select(void)
380 {
381     BOOL r;
382 
383     hTree = create_treeview_control();
384     fill_tree(hTree);
385 
386     /* root-none select tests */
387     flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
388     r = TreeView_SelectItem(hTree, NULL);
389     Clear();
390     AddItem('1');
391     r = TreeView_SelectItem(hTree, hRoot);
392     AddItem('2');
393     r = TreeView_SelectItem(hTree, hRoot);
394     AddItem('3');
395     r = TreeView_SelectItem(hTree, NULL);
396     AddItem('4');
397     r = TreeView_SelectItem(hTree, NULL);
398     AddItem('5');
399     r = TreeView_SelectItem(hTree, hRoot);
400     AddItem('.');
401     ok(!strcmp(sequence, "1(nR)nR23(Rn)Rn45(nR)nR."), "root-none select test\n");
402     ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, rootnone_select_seq,
403                 "root-none select seq", FALSE);
404 
405     /* root-child select tests */
406     flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
407     r = TreeView_SelectItem(hTree, NULL);
408     Clear();
409     AddItem('1');
410     r = TreeView_SelectItem(hTree, hRoot);
411     AddItem('2');
412     r = TreeView_SelectItem(hTree, hRoot);
413     AddItem('3');
414     r = TreeView_SelectItem(hTree, hChild);
415     AddItem('4');
416     r = TreeView_SelectItem(hTree, hChild);
417     AddItem('5');
418     r = TreeView_SelectItem(hTree, hRoot);
419     AddItem('.');
420     ok(!strcmp(sequence, "1(nR)nR23(RC)RC45(CR)CR."), "root-child select test\n");
421     ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, rootchild_select_seq,
422                 "root-child select seq", FALSE);
423 
424     DestroyWindow(hTree);
425 }
426 
427 static void test_getitemtext(void)
428 {
429     TVINSERTSTRUCTA ins;
430     HTREEITEM hChild;
431     TVITEM tvi;
432 
433     CHAR szBuffer[80] = "Blah";
434     int nBufferSize = sizeof(szBuffer)/sizeof(CHAR);
435 
436     hTree = create_treeview_control();
437     fill_tree(hTree);
438 
439     flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
440 
441     /* add an item without TVIF_TEXT mask and pszText == NULL */
442     ins.hParent = hRoot;
443     ins.hInsertAfter = TVI_ROOT;
444     U(ins).item.mask = 0;
445     U(ins).item.pszText = NULL;
446     U(ins).item.cchTextMax = 0;
447     hChild = TreeView_InsertItem(hTree, &ins);
448     assert(hChild);
449 
450     /* retrieve it with TVIF_TEXT mask */
451     tvi.hItem = hChild;
452     tvi.mask = TVIF_TEXT;
453     tvi.cchTextMax = nBufferSize;
454     tvi.pszText = szBuffer;
455 
456     SendMessageA( hTree, TVM_GETITEM, 0, (LPARAM)&tvi );
457     ok(!strcmp(szBuffer, ""), "szBuffer=\"%s\", expected \"\"\n", szBuffer);
458     ok(SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild), "DeleteItem failed\n");
459     ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, getitemtext_seq, "get item text seq", FALSE);
460 
461     DestroyWindow(hTree);
462 }
463 
464 static void test_focus(void)
465 {
466     TVINSERTSTRUCTA ins;
467     static CHAR child1[]  = "Edit",
468                 child2[]  = "A really long string";
469     HTREEITEM hChild1, hChild2;
470 
471     hTree = create_treeview_control();
472     fill_tree(hTree);
473 
474     flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
475 
476     /* This test verifies that when a label is being edited, scrolling
477      * the treeview does not cause the label to lose focus. To test
478      * this, first some additional entries are added to generate
479      * scrollbars.
480      */
481     ins.hParent = hRoot;
482     ins.hInsertAfter = hChild;
483     U(ins).item.mask = TVIF_TEXT;
484     U(ins).item.pszText = child1;
485     hChild1 = TreeView_InsertItem(hTree, &ins);
486     assert(hChild1);
487     ins.hInsertAfter = hChild1;
488     U(ins).item.mask = TVIF_TEXT;
489     U(ins).item.pszText = child2;
490     hChild2 = TreeView_InsertItem(hTree, &ins);
491     assert(hChild2);
492 
493     ShowWindow(hMainWnd,SW_SHOW);
494     SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild);
495     hEdit = TreeView_EditLabel(hTree, hChild);
496     ScrollWindowEx(hTree, -10, 0, NULL, NULL, NULL, NULL, SW_SCROLLCHILDREN);
497     ok(GetFocus() == hEdit, "Edit control should have focus\n");
498     ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, focus_seq, "focus test", TRUE);
499 
500     DestroyWindow(hTree);
501 }
502 
503 static void TestGetSetBkColor(void)
504 {
505     COLORREF crColor = RGB(0,0,0);
506 
507     /* If the value is -1, the control is using the system color for the background color. */
508     crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 );
509     ok(crColor == -1, "Default background color reported as 0x%.8x\n", crColor);
510 
511     /* Test for black background */
512     SendMessage( hTree, TVM_SETBKCOLOR, 0, (LPARAM)RGB(0,0,0) );
513     crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 );
514     ok(crColor == RGB(0,0,0), "Black background color reported as 0x%.8x\n", crColor);
515 
516     /* Test for white background */
517     SendMessage( hTree, TVM_SETBKCOLOR, 0, (LPARAM)RGB(255,255,255) );
518     crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 );
519     ok(crColor == RGB(255,255,255), "White background color reported as 0x%.8x\n", crColor);
520 
521     /* Reset the default background */
522     SendMessage( hTree, TVM_SETBKCOLOR, 0, -1 );
523 }
524 
525 static void TestGetSetImageList(void)
526 {
527     HIMAGELIST hImageList = NULL;
528 
529     /* Test a NULL HIMAGELIST */
530     SendMessage( hTree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)hImageList );
531     hImageList = (HIMAGELIST)SendMessage( hTree, TVM_GETIMAGELIST, TVSIL_NORMAL, 0 );
532     ok(hImageList == NULL, "NULL image list, reported as 0x%p, expected 0.\n", hImageList);
533 
534     /* TODO: Test an actual image list */
535 }
536 
537 static void TestGetSetIndent(void)
538 {
539     int ulIndent = -1;
540     int ulMinIndent = -1;
541     int ulMoreThanTwiceMin = -1;
542 
543     /* Finding the minimum indent */
544     SendMessage( hTree, TVM_SETINDENT, 0, 0 );
545     ulMinIndent = (int)SendMessage( hTree, TVM_GETINDENT, 0, 0 );
546 
547     /* Checking an indent that is more than twice the default indent */
548     ulMoreThanTwiceMin = 2*ulMinIndent+1;
549     SendMessage( hTree, TVM_SETINDENT, ulMoreThanTwiceMin, 0 );
550     ulIndent = (DWORD)SendMessage( hTree, TVM_GETINDENT, 0, 0 );
551     ok(ulIndent == ulMoreThanTwiceMin, "Indent reported as %d, expected %d\n", ulIndent, ulMoreThanTwiceMin);
552 }
553 
554 static void TestGetSetInsertMarkColor(void)
555 {
556     COLORREF crColor = RGB(0,0,0);
557     SendMessage( hTree, TVM_SETINSERTMARKCOLOR, 0, crColor );
558     crColor = (COLORREF)SendMessage( hTree, TVM_GETINSERTMARKCOLOR, 0, 0 );
559     ok(crColor == RGB(0,0,0), "Insert mark color reported as 0x%.8x, expected 0x00000000\n", crColor);
560 }
561 
562 static void TestGetSetItem(void)
563 {
564     TVITEM tviRoot = {0};
565     int nBufferSize = 80;
566     char szBuffer[80] = {0};
567 
568     /* Test the root item */
569     tviRoot.hItem = hRoot;
570     tviRoot.mask = TVIF_TEXT;
571     tviRoot.cchTextMax = nBufferSize;
572     tviRoot.pszText = szBuffer;
573     SendMessage( hTree, TVM_GETITEM, 0, (LPARAM)&tviRoot );
574     ok(!strcmp("Root", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Root\"\n", szBuffer);
575 
576     /* Change the root text */
577     strncpy(szBuffer, "Testing123", nBufferSize);
578     SendMessage( hTree, TVM_SETITEM, 0, (LPARAM)&tviRoot );
579     memset(szBuffer, 0, nBufferSize);
580     SendMessage( hTree, TVM_GETITEM, 0, (LPARAM)&tviRoot );
581     ok(!strcmp("Testing123", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Testing123\"\n", szBuffer);
582 
583     /* Reset the root text */
584     memset(szBuffer, 0, nBufferSize);
585     strncpy(szBuffer, "Root", nBufferSize);
586     SendMessage( hTree, TVM_SETITEM, 0, (LPARAM)&tviRoot );
587 }
588 
589 static void TestGetSetItemHeight(void)
590 {
591     int ulOldHeight = 0;
592     int ulNewHeight = 0;
593 
594     /* Assuming default height to begin with */
595     ulOldHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
596 
597     /* Explicitly setting and getting the default height */
598     SendMessage( hTree, TVM_SETITEMHEIGHT, -1, 0 );
599     ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
600     ok(ulNewHeight == ulOldHeight, "Default height not set properly, reported %d, expected %d\n", ulNewHeight, ulOldHeight);
601 
602     /* Explicitly setting and getting the height of twice the normal */
603     SendMessage( hTree, TVM_SETITEMHEIGHT, 2*ulOldHeight, 0 );
604     ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
605     ok(ulNewHeight == 2*ulOldHeight, "New height not set properly, reported %d, expected %d\n", ulNewHeight, 2*ulOldHeight);
606 
607     /* Assuming tree doesn't have TVS_NONEVENHEIGHT set, so a set of 9 will round down to 8 */
608     SendMessage( hTree, TVM_SETITEMHEIGHT, 9, 0 );
609     ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
610     ok(ulNewHeight == 8, "Uneven height not set properly, reported %d, expected %d\n", ulNewHeight, 8);
611 }
612 
613 static void TestGetSetScrollTime(void)
614 {
615     int ulExpectedTime = 20;
616     int ulTime = 0;
617     SendMessage( hTree, TVM_SETSCROLLTIME, ulExpectedTime, 0 );
618     ulTime = (int)SendMessage( hTree, TVM_GETSCROLLTIME, 0, 0 );
619     ok(ulTime == ulExpectedTime, "Scroll time reported as %d, expected %d\n", ulTime, ulExpectedTime);
620 }
621 
622 static void TestGetSetTextColor(void)
623 {
624     /* If the value is -1, the control is using the system color for the text color. */
625     COLORREF crColor = RGB(0,0,0);
626     crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 );
627     ok(crColor == -1, "Default text color reported as 0x%.8x\n", crColor);
628 
629     /* Test for black text */
630     SendMessage( hTree, TVM_SETTEXTCOLOR, 0, (LPARAM)RGB(0,0,0) );
631     crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 );
632     ok(crColor == RGB(0,0,0), "Black text color reported as 0x%.8x\n", crColor);
633 
634     /* Test for white text */
635     SendMessage( hTree, TVM_SETTEXTCOLOR, 0, (LPARAM)RGB(255,255,255) );
636     crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 );
637     ok(crColor == RGB(255,255,255), "White text color reported as 0x%.8x\n", crColor);
638 
639     /* Reset the default text color */
640     SendMessage( hTree, TVM_SETTEXTCOLOR, 0, -1 );
641 }
642 
643 static void TestGetSetToolTips(void)
644 {
645     HWND hwndLastToolTip = NULL;
646     HWND hPopupTreeView;
647 
648     /* show even WS_POPUP treeview don't send NM_TOOLTIPSCREATED */
649     hPopupTreeView = CreateWindow(WC_TREEVIEW, NULL, WS_POPUP|WS_VISIBLE, 0, 0, 100, 100, hMainWnd, NULL, NULL, NULL);
650     DestroyWindow(hPopupTreeView);
651 
652     /* Testing setting a NULL ToolTip */
653     SendMessage( hTree, TVM_SETTOOLTIPS, 0, 0 );
654     hwndLastToolTip = (HWND)SendMessage( hTree, TVM_GETTOOLTIPS, 0, 0 );
655     ok(hwndLastToolTip == NULL, "NULL tool tip, reported as 0x%p, expected 0.\n", hwndLastToolTip);
656 
657     /* TODO: Add a test of an actual tooltip */
658 }
659 
660 static void TestGetSetUnicodeFormat(void)
661 {
662     BOOL bPreviousSetting = 0;
663     BOOL bNewSetting = 0;
664 
665     /* Set to Unicode */
666     bPreviousSetting = (BOOL)SendMessage( hTree, TVM_SETUNICODEFORMAT, 1, 0 );
667     bNewSetting = (BOOL)SendMessage( hTree, TVM_GETUNICODEFORMAT, 0, 0 );
668     ok(bNewSetting == 1, "Unicode setting did not work.\n");
669 
670     /* Set to ANSI */
671     SendMessage( hTree, TVM_SETUNICODEFORMAT, 0, 0 );
672     bNewSetting = (BOOL)SendMessage( hTree, TVM_GETUNICODEFORMAT, 0, 0 );
673     ok(bNewSetting == 0, "ANSI setting did not work.\n");
674 
675     /* Revert to original setting */
676     SendMessage( hTree, TVM_SETUNICODEFORMAT, (LPARAM)bPreviousSetting, 0 );
677 }
678 
679 static void test_getset(void)
680 {
681     hTree = create_treeview_control();
682     fill_tree(hTree);
683 
684     /* TVM_GETBKCOLOR and TVM_SETBKCOLOR */
685     flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
686     TestGetSetBkColor();
687     ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetBkColorSeq,
688         "TestGetSetBkColor", FALSE);
689 
690     /* TVM_GETIMAGELIST and TVM_SETIMAGELIST */
691     flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
692     TestGetSetImageList();
693     ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetImageListSeq,
694         "TestGetImageList", FALSE);
695 
696     /* TVM_SETINDENT and TVM_GETINDENT */
697     flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
698     TestGetSetIndent();
699     ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetIndentSeq,
700         "TestGetSetIndent", FALSE);
701 
702     /* TVM_GETINSERTMARKCOLOR and TVM_GETINSERTMARKCOLOR */
703     flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
704     TestGetSetInsertMarkColor();
705     ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetInsertMarkColorSeq,
706         "TestGetSetInsertMarkColor", FALSE);
707 
708     /* TVM_GETITEM and TVM_SETITEM */
709     flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
710     TestGetSetItem();
711     ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetItemSeq,
712         "TestGetSetItem", FALSE);
713 
714     /* TVM_GETITEMHEIGHT and TVM_SETITEMHEIGHT */
715     flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
716     TestGetSetItemHeight();
717     ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetItemHeightSeq,
718         "TestGetSetItemHeight", FALSE);
719 
720     /* TVM_GETSCROLLTIME and TVM_SETSCROLLTIME */
721     flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
722     TestGetSetScrollTime();
723     ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetScrollTimeSeq,
724         "TestGetSetScrollTime", FALSE);
725 
726     /* TVM_GETTEXTCOLOR and TVM_SETTEXTCOLOR */
727     flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
728     TestGetSetTextColor();
729     ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetTextColorSeq,
730         "TestGetSetTextColor", FALSE);
731 
732     /* TVM_GETTOOLTIPS and TVM_SETTOOLTIPS */
733     flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
734     TestGetSetToolTips();
735     ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetToolTipsSeq,
736         "TestGetSetToolTips", TRUE);
737 
738     /* TVM_GETUNICODEFORMAT and TVM_SETUNICODEFORMAT */
739     flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
740     TestGetSetUnicodeFormat();
741     ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, TestGetSetUnicodeFormatSeq,
742         "TestGetSetUnicodeFormat", FALSE);
743 
744     DestroyWindow(hTree);
745 }
746 
747 static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
748 {
749     switch(msg) {
750     case WM_NOTIFY:
751     {
752         NMHDR *pHdr = (NMHDR *)lParam;
753     
754         ok(pHdr->code != NM_FIRST - 19, "Treeview should not send NM_TOOLTIPSCREATED\n");
755         if (pHdr->idFrom == 100) {
756             NMTREEVIEWA *pTreeView = (LPNMTREEVIEWA) lParam;
757             switch(pHdr->code) {
758             case TVN_SELCHANGINGA:
759                 AddItem('(');
760                 IdentifyItem(pTreeView->itemOld.hItem);
761                 IdentifyItem(pTreeView->itemNew.hItem);
762                 return 0;
763             case TVN_SELCHANGEDA:
764                 AddItem(')');
765                 IdentifyItem(pTreeView->itemOld.hItem);
766                 IdentifyItem(pTreeView->itemNew.hItem);
767                 return 0;
768             case TVN_GETDISPINFOA: {
769                 NMTVDISPINFOA *disp = (NMTVDISPINFOA *)lParam;
770                 if (disp->item.mask & TVIF_TEXT) {
771                     lstrcpyn(disp->item.pszText, TEST_CALLBACK_TEXT, disp->item.cchTextMax);
772                 }
773                 return 0;
774               }
775             case TVN_ENDLABELEDIT: return TRUE;
776             }
777         }
778         return 0;
779     }
780   
781     case WM_DESTROY:
782         PostQuitMessage(0);
783         break;
784   
785     default:
786         return DefWindowProcA(hWnd, msg, wParam, lParam);
787     }
788     return 0L;
789 }
790 
791 static void test_expandinvisible(void)
792 {
793     static CHAR nodeText[][5] = {"", "1", "2", "3", "4"};
794     TVINSERTSTRUCTA ins;
795     HTREEITEM node[5];
796     RECT dummyRect;
797     BOOL nodeVisible;
798     LRESULT ret;
799 
800     hTree = create_treeview_control();
801 
802     /* The test builds the following tree and expands then node 1, while node 0 is collapsed.
803      *
804      * 0
805      * |- 1
806      * |  |- 2
807      * |  |- 3
808      * |- 4
809      *
810      */
811 
812     ret = TreeView_DeleteAllItems(hTree);
813     ok(ret == TRUE, "ret\n");
814     ins.hParent = TVI_ROOT;
815     ins.hInsertAfter = TVI_ROOT;
816     U(ins).item.mask = TVIF_TEXT;
817     U(ins).item.pszText = nodeText[0];
818     node[0] = TreeView_InsertItem(hTree, &ins);
819     assert(node[0]);
820 
821     ins.hInsertAfter = TVI_LAST;
822     U(ins).item.mask = TVIF_TEXT;
823     ins.hParent = node[0];
824 
825     U(ins).item.pszText = nodeText[1];
826     node[1] = TreeView_InsertItem(hTree, &ins);
827     assert(node[1]);
828     U(ins).item.pszText = nodeText[4];
829     node[4] = TreeView_InsertItem(hTree, &ins);
830     assert(node[4]);
831 
832     ins.hParent = node[1];
833 
834     U(ins).item.pszText = nodeText[2];
835     node[2] = TreeView_InsertItem(hTree, &ins);
836     assert(node[2]);
837     U(ins).item.pszText = nodeText[3];
838     node[3] = TreeView_InsertItem(hTree, &ins);
839     assert(node[3]);
840 
841 
842     nodeVisible = TreeView_GetItemRect(hTree, node[1], &dummyRect, FALSE);
843     ok(!nodeVisible, "Node 1 should not be visible.\n");
844     nodeVisible = TreeView_GetItemRect(hTree, node[2], &dummyRect, FALSE);
845     ok(!nodeVisible, "Node 2 should not be visible.\n");
846     nodeVisible = TreeView_GetItemRect(hTree, node[3], &dummyRect, FALSE);
847     ok(!nodeVisible, "Node 3 should not be visible.\n");
848     nodeVisible = TreeView_GetItemRect(hTree, node[4], &dummyRect, FALSE);
849     ok(!nodeVisible, "Node 4 should not be visible.\n");
850 
851     ok(TreeView_Expand(hTree, node[1], TVE_EXPAND), "Expand of node 1 failed.\n");
852 
853     nodeVisible = TreeView_GetItemRect(hTree, node[1], &dummyRect, FALSE);
854     ok(!nodeVisible, "Node 1 should not be visible.\n");
855     nodeVisible = TreeView_GetItemRect(hTree, node[2], &dummyRect, FALSE);
856     ok(!nodeVisible, "Node 2 should not be visible.\n");
857     nodeVisible = TreeView_GetItemRect(hTree, node[3], &dummyRect, FALSE);
858     ok(!nodeVisible, "Node 3 should not be visible.\n");
859     nodeVisible = TreeView_GetItemRect(hTree, node[4], &dummyRect, FALSE);
860     ok(!nodeVisible, "Node 4 should not be visible.\n");
861 
862     DestroyWindow(hTree);
863 }
864 
865 static void test_itemedit(void)
866 {
867     DWORD r;
868     HWND edit;
869     TVITEMA item;
870     CHAR buff[2];
871 
872     hTree = create_treeview_control();
873     fill_tree(hTree);
874 
875     /* try with null item */
876     edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)NULL);
877     ok(!IsWindow(edit), "Expected valid handle\n");
878 
879     /* trigger edit */
880     edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
881     ok(IsWindow(edit), "Expected valid handle\n");
882     /* item shouldn't be selected automatically after TVM_EDITLABEL */
883     r = SendMessage(hTree, TVM_GETITEMSTATE, (WPARAM)hRoot, TVIS_SELECTED);
884     expect(0, r);
885     /* try to cancel with wrong edit handle */
886     r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)NULL);
887     expect(0, r);
888     ok(IsWindow(edit), "Expected edit control to be valid\n");
889     r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
890     expect(0, r);
891     ok(!IsWindow(edit), "Expected edit control to be destroyed\n");
892     /* try to cancel without creating edit */
893     r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)NULL);
894     expect(0, r);
895 
896     /* try to cancel with wrong (not null) handle */
897     edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
898     ok(IsWindow(edit), "Expected valid handle\n");
899     r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hTree);
900     expect(0, r);
901     ok(IsWindow(edit), "Expected edit control to be valid\n");
902     r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
903     expect(0, r);
904 
905     /* remove selection after starting edit */
906     r = TreeView_SelectItem(hTree, hRoot);
907     expect(TRUE, r);
908     edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
909     ok(IsWindow(edit), "Expected valid handle\n");
910     r = TreeView_SelectItem(hTree, NULL);
911     expect(TRUE, r);
912     /* alter text */
913     strncpy(buff, "x", sizeof(buff)/sizeof(CHAR));
914     r = SendMessage(edit, WM_SETTEXT, 0, (LPARAM)buff);
915     expect(TRUE, r);
916     r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
917     expect(0, r);
918     ok(!IsWindow(edit), "Expected edit control to be destroyed\n");
919     /* check that text is saved */
920     item.mask = TVIF_TEXT;
921     item.hItem = hRoot;
922     item.pszText = buff;
923     item.cchTextMax = sizeof(buff)/sizeof(CHAR);
924     r = SendMessage(hTree, TVM_GETITEM, 0, (LPARAM)&item);
925     expect(TRUE, r);
926     ok(!strcmp("x", buff), "Expected item text to change\n");
927 
928     DestroyWindow(hTree);
929 }
930 
931 static void test_treeview_classinfo(void)
932 {
933     WNDCLASSA cls;
934 
935     memset(&cls, 0, sizeof(cls));
936     GetClassInfo(GetModuleHandleA("comctl32.dll"), WC_TREEVIEWA, &cls);
937     ok(cls.hbrBackground == NULL, "Expected NULL background brush, got %p\n", cls.hbrBackground);
938     ok(cls.style == (CS_GLOBALCLASS | CS_DBLCLKS), "Expected got %x\n", cls.style);
939     expect(0, cls.cbClsExtra);
940 }
941 
942 START_TEST(treeview)
943 {
944     HMODULE hComctl32;
945     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
946     WNDCLASSA wc;
947     MSG msg;
948   
949     hComctl32 = GetModuleHandleA("comctl32.dll");
950     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
951     if (pInitCommonControlsEx)
952     {
953         INITCOMMONCONTROLSEX iccex;
954         iccex.dwSize = sizeof(iccex);
955         iccex.dwICC  = ICC_TREEVIEW_CLASSES;
956         pInitCommonControlsEx(&iccex);
957     }
958     else
959         InitCommonControls();
960 
961     init_msg_sequences(MsgSequences, NUM_MSG_SEQUENCES);
962   
963     wc.style = CS_HREDRAW | CS_VREDRAW;
964     wc.cbClsExtra = 0;
965     wc.cbWndExtra = 0;
966     wc.hInstance = GetModuleHandleA(NULL);
967     wc.hIcon = NULL;
968     wc.hCursor = LoadCursorA(NULL, IDC_IBEAM);
969     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
970     wc.lpszMenuName = NULL;
971     wc.lpszClassName = "MyTestWnd";
972     wc.lpfnWndProc = MyWndProc;
973     RegisterClassA(&wc);
974 
975 
976     hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW,
977       CW_USEDEFAULT, CW_USEDEFAULT, 130, 105, NULL, NULL, GetModuleHandleA(NULL), 0);
978 
979     if ( !ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n") )
980         return;
981 
982     test_fillroot();
983     test_select();
984     test_getitemtext();
985     test_focus();
986     test_getset();
987     test_callback();
988     test_expandinvisible();
989     test_itemedit();
990     test_treeview_classinfo();
991 
992     PostMessageA(hMainWnd, WM_CLOSE, 0, 0);
993     while(GetMessageA(&msg,0,0,0)) {
994         TranslateMessage(&msg);
995         DispatchMessageA(&msg);
996     }
997 }
998 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.