]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/TableItem.java
Remove invalid SHA-256-Digests
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / widgets / TableItem.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2015 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.swt.widgets;
15
16
17 import org.eclipse.swt.*;
18 import org.eclipse.swt.graphics.*;
19 import org.eclipse.swt.internal.*;
20 import org.eclipse.swt.internal.win32.*;
21
22 /**
23  * Instances of this class represent a selectable user interface object
24  * that represents an item in a table.
25  * <dl>
26  * <dt><b>Styles:</b></dt>
27  * <dd>(none)</dd>
28  * <dt><b>Events:</b></dt>
29  * <dd>(none)</dd>
30  * </dl>
31  * <p>
32  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
33  * </p>
34  *
35  * @see <a href="http://www.eclipse.org/swt/snippets/#table">Table, TableItem, TableColumn snippets</a>
36  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
37  * @noextend This class is not intended to be subclassed by clients.
38  */
39 public class TableItem extends Item {
40         Table parent;
41         String [] strings;
42         Image [] images;
43         Font font;
44         Font [] cellFont;
45         boolean checked, grayed, cached;
46         int imageIndent, background = -1, foreground = -1;
47         int [] cellBackground, cellForeground;
48
49 /**
50  * Constructs a new instance of this class given its parent
51  * (which must be a <code>Table</code>) and a style value
52  * describing its behavior and appearance. The item is added
53  * to the end of the items maintained by its parent.
54  * <p>
55  * The style value is either one of the style constants defined in
56  * class <code>SWT</code> which is applicable to instances of this
57  * class, or must be built by <em>bitwise OR</em>'ing together
58  * (that is, using the <code>int</code> "|" operator) two or more
59  * of those <code>SWT</code> style constants. The class description
60  * lists the style constants that are applicable to the class.
61  * Style bits are also inherited from superclasses.
62  * </p>
63  *
64  * @param parent a composite control which will be the parent of the new instance (cannot be null)
65  * @param style the style of control to construct
66  *
67  * @exception IllegalArgumentException <ul>
68  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
69  * </ul>
70  * @exception SWTException <ul>
71  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
72  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
73  * </ul>
74  *
75  * @see SWT
76  * @see Widget#checkSubclass
77  * @see Widget#getStyle
78  */
79 public TableItem (Table parent, int style) {
80         this (parent, style, checkNull (parent).getItemCount (), true);
81 }
82
83 /**
84  * Constructs a new instance of this class given its parent
85  * (which must be a <code>Table</code>), a style value
86  * describing its behavior and appearance, and the index
87  * at which to place it in the items maintained by its parent.
88  * <p>
89  * The style value is either one of the style constants defined in
90  * class <code>SWT</code> which is applicable to instances of this
91  * class, or must be built by <em>bitwise OR</em>'ing together
92  * (that is, using the <code>int</code> "|" operator) two or more
93  * of those <code>SWT</code> style constants. The class description
94  * lists the style constants that are applicable to the class.
95  * Style bits are also inherited from superclasses.
96  * </p>
97  *
98  * @param parent a composite control which will be the parent of the new instance (cannot be null)
99  * @param style the style of control to construct
100  * @param index the zero-relative index to store the receiver in its parent
101  *
102  * @exception IllegalArgumentException <ul>
103  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
104  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the parent (inclusive)</li>
105  * </ul>
106  * @exception SWTException <ul>
107  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
108  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
109  * </ul>
110  *
111  * @see SWT
112  * @see Widget#checkSubclass
113  * @see Widget#getStyle
114  */
115 public TableItem (Table parent, int style, int index) {
116         this (parent, style, index, true);
117 }
118
119 TableItem (Table parent, int style, int index, boolean create) {
120         super (parent, style);
121         this.parent = parent;
122         if (create) parent.createItem (this, index);
123 }
124
125 static Table checkNull (Table control) {
126         if (control == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
127         return control;
128 }
129
130 @Override
131 protected void checkSubclass () {
132         if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
133 }
134
135 void clear () {
136         text = "";
137         image = null;
138         strings = null;
139         images = null;
140         imageIndent = 0;
141         checked = grayed = false;
142         font = null;
143         background = foreground = -1;
144         cellFont = null;
145         cellBackground = cellForeground = null;
146         if ((parent.style & SWT.VIRTUAL) != 0) cached = false;
147 }
148
149 @Override
150 void destroyWidget () {
151         parent.destroyItem (this);
152         releaseHandle ();
153 }
154
155 long fontHandle (int index) {
156         if (cellFont != null && cellFont [index] != null) return cellFont [index].handle;
157         if (font != null) return font.handle;
158         return -1;
159 }
160
161 /**
162  * Returns the receiver's background color.
163  *
164  * @return the background color
165  *
166  * @exception SWTException <ul>
167  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
168  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
169  * </ul>
170  *
171  * @since 2.0
172  */
173 public Color getBackground () {
174         checkWidget ();
175         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
176         if (background == -1) return parent.getBackground ();
177         return Color.win32_new (display, background);
178 }
179
180 /**
181  * Returns the background color at the given column index in the receiver.
182  *
183  * @param index the column index
184  * @return the background color
185  *
186  * @exception SWTException <ul>
187  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
188  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
189  * </ul>
190  *
191  * @since 3.0
192  */
193 public Color getBackground (int index) {
194         checkWidget ();
195         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
196         int count = Math.max (1, parent.getColumnCount ());
197         if (0 > index || index > count - 1) return getBackground ();
198         int pixel = cellBackground != null ? cellBackground [index] : -1;
199         return pixel == -1 ? getBackground () : Color.win32_new (display, pixel);
200 }
201
202 /**
203  * Returns a rectangle describing the size and location of the receiver's
204  * text relative to its parent.
205  *
206  * @return the bounding rectangle of the receiver's text
207  *
208  * @exception SWTException <ul>
209  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
210  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
211  * </ul>
212  *
213  * @since 3.2
214  */
215 public Rectangle getBounds () {
216         checkWidget();
217         return DPIUtil.autoScaleDown(getBoundsInPixels());
218 }
219
220 Rectangle getBoundsInPixels () {
221         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
222         int itemIndex = parent.indexOf (this);
223         if (itemIndex == -1) return new Rectangle (0, 0, 0, 0);
224         RECT rect = getBounds (itemIndex, 0, true, false, false);
225         int width = rect.right - rect.left, height = rect.bottom - rect.top;
226         return new Rectangle (rect.left, rect.top, width, height);
227 }
228
229 /**
230  * Returns a rectangle describing the receiver's size and location
231  * relative to its parent at a column in the table.
232  *
233  * @param index the index that specifies the column
234  * @return the receiver's bounding column rectangle
235  *
236  * @exception SWTException <ul>
237  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
238  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
239  * </ul>
240  */
241 public Rectangle getBounds (int index) {
242         checkWidget();
243         return DPIUtil.autoScaleDown(getBoundsInPixels(index));
244 }
245
246 Rectangle getBoundsInPixels (int index) {
247         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
248         int itemIndex = parent.indexOf (this);
249         if (itemIndex == -1) return new Rectangle (0, 0, 0, 0);
250         RECT rect = getBounds (itemIndex, index, true, true, true);
251         int width = rect.right - rect.left, height = rect.bottom - rect.top;
252         return new Rectangle (rect.left, rect.top, width, height);
253 }
254
255 RECT getBounds (int row, int column, boolean getText, boolean getImage, boolean fullText) {
256         return getBounds (row, column, getText, getImage, fullText, false, 0);
257 }
258
259 RECT getBounds (int row, int column, boolean getText, boolean getImage, boolean fullText, boolean fullImage, long hDC) {
260         if (!getText && !getImage) return new RECT ();
261         int columnCount = parent.getColumnCount ();
262         if (!(0 <= column && column < Math.max (1, columnCount))) {
263                 return new RECT ();
264         }
265         if (parent.fixScrollWidth) parent.setScrollWidth (null, true);
266         RECT rect = new RECT ();
267         long hwnd = parent.handle;
268         int bits = (int)OS.SendMessage (hwnd, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
269         if (column == 0 && (bits & OS.LVS_EX_FULLROWSELECT) == 0) {
270                 if (parent.explorerTheme) {
271                         rect.left = OS.LVIR_ICON;
272                         parent.ignoreCustomDraw = true;
273                         long code = OS.SendMessage (hwnd, OS. LVM_GETITEMRECT, row, rect);
274                         parent.ignoreCustomDraw = false;
275                         if (code == 0) return new RECT ();
276                         if (getText) {
277                                 int width = 0;
278                                 long hFont = fontHandle (column);
279                                 if (hFont == -1 && hDC == 0) {
280                                         TCHAR buffer = new TCHAR (parent.getCodePage (), text, true);
281                                         width = (int)OS.SendMessage (hwnd, OS.LVM_GETSTRINGWIDTH, 0, buffer);
282                                 } else {
283                                         char [] buffer = text.toCharArray ();
284                                         long textDC = hDC != 0 ? hDC : OS.GetDC (hwnd), oldFont = -1;
285                                         if (hDC == 0) {
286                                                 if (hFont == -1) hFont = OS.SendMessage (hwnd, OS.WM_GETFONT, 0, 0);
287                                                 oldFont = OS.SelectObject (textDC, hFont);
288                                         }
289                                         RECT textRect = new RECT ();
290                                         int flags = OS.DT_NOPREFIX | OS.DT_SINGLELINE | OS.DT_CALCRECT;
291                                         OS.DrawText (textDC, buffer, buffer.length, textRect, flags);
292                                         width = textRect.right - textRect.left;
293                                         if (hDC == 0) {
294                                                 if (oldFont != -1) OS.SelectObject (textDC, oldFont);
295                                                 OS.ReleaseDC (hwnd, textDC);
296                                         }
297                                 }
298                                 if (!getImage) rect.left = rect.right;
299                                 rect.right += width + Table.INSET * 2;
300                         }
301                 } else {
302                         if (getText) {
303                                 rect.left = OS.LVIR_SELECTBOUNDS;
304                                 parent.ignoreCustomDraw = true;
305                                 long code = OS.SendMessage (hwnd, OS.LVM_GETITEMRECT, row, rect);
306                                 parent.ignoreCustomDraw = false;
307                                 if (code == 0) return new RECT ();
308                                 if (!getImage) {
309                                         RECT iconRect = new RECT ();
310                                         iconRect.left = OS.LVIR_ICON;
311                                         parent.ignoreCustomDraw = true;
312                                         code = OS.SendMessage (hwnd, OS. LVM_GETITEMRECT, row, iconRect);
313                                         parent.ignoreCustomDraw = false;
314                                         if (code != 0) rect.left = iconRect.right;
315                                 }
316                         } else {
317                                 rect.left = OS.LVIR_ICON;
318                                 parent.ignoreCustomDraw = true;
319                                 long code = OS.SendMessage (hwnd, OS.LVM_GETITEMRECT, row, rect);
320                                 parent.ignoreCustomDraw = false;
321                                 if (code == 0) return new RECT ();
322                         }
323                 }
324                 if (fullText || fullImage) {
325                         RECT headerRect = new RECT ();
326                         long hwndHeader = OS.SendMessage (hwnd, OS.LVM_GETHEADER, 0, 0);
327                         OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, 0, headerRect);
328                         OS.MapWindowPoints (hwndHeader, hwnd, headerRect, 2);
329                         if (getText && fullText) rect.right = headerRect.right;
330                         if (getImage && fullImage) rect.left = headerRect.left;
331                 }
332         } else {
333                 /*
334                 * Feature in Windows.  LVM_GETSUBITEMRECT returns an image width
335                 * even when the subitem does not contain an image.  The fix is to
336                 * test for this case and adjust the rectangle to represent the area
337                 * the table is actually drawing.
338                 */
339                 boolean hasImage = (column == 0 && image != null) || (images != null && images [column] != null);
340                 rect.top = column;
341                 if (fullText || fullImage || hDC == 0) {
342                         /*
343                         * Bug in Windows.  Despite the fact that the documentation states
344                         * that LVIR_BOUNDS and LVIR_LABEL are identical when used with
345                         * LVM_GETSUBITEMRECT, LVIR_BOUNDS can return a zero height.  The
346                         * fix is to use LVIR_LABEL.
347                         */
348                         rect.left = getText ? OS.LVIR_LABEL : OS.LVIR_ICON;
349                         parent.ignoreCustomDraw = true;
350                         long code = OS.SendMessage (hwnd, OS. LVM_GETSUBITEMRECT, row, rect);
351                         parent.ignoreCustomDraw = false;
352                         if (code == 0) return new RECT ();
353                         /*
354                         * Feature in Windows.  Calling LVM_GETSUBITEMRECT with LVIR_LABEL
355                         * and zero for the column number gives the bounds of the first item
356                         * without including the bounds of the icon.  This is undocumented.
357                         * When called with values greater than zero, the icon bounds are
358                         * included and this behavior is documented.  If the icon is needed
359                         * in the bounds of the first item, the fix is to adjust the item
360                         * bounds using the icon bounds.
361                         */
362                         if (column == 0 && getText && getImage) {
363                                 RECT iconRect = new RECT ();
364                                 iconRect.left = OS.LVIR_ICON;
365                                 parent.ignoreCustomDraw = true;
366                                 code = OS.SendMessage (hwnd, OS. LVM_GETSUBITEMRECT, row, iconRect);
367                                 parent.ignoreCustomDraw = false;
368                                 if (code != 0) rect.left = iconRect.left;
369                         }
370                         if (hasImage) {
371                                 if (column != 0 && getText && !getImage) {
372                                         RECT iconRect = new RECT ();
373                                         iconRect.top = column;
374                                         iconRect.left = OS.LVIR_ICON;
375                                         if (OS.SendMessage (hwnd, OS. LVM_GETSUBITEMRECT, row, iconRect) != 0) {
376                                                 rect.left = iconRect.right + Table.INSET / 2;
377                                         }
378                                 }
379                         } else {
380                                 if (getImage && !getText) rect.right = rect.left;
381                         }
382                         if (column == 0 && fullImage) {
383                                 RECT headerRect = new RECT ();
384                                 long hwndHeader = OS.SendMessage (hwnd, OS.LVM_GETHEADER, 0, 0);
385                                 OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, 0, headerRect);
386                                 OS.MapWindowPoints (hwndHeader, hwnd, headerRect, 2);
387                                 rect.left = headerRect.left;
388                         }
389                 } else {
390                         rect.left = OS.LVIR_ICON;
391                         parent.ignoreCustomDraw = true;
392                         long code = OS.SendMessage (hwnd, OS. LVM_GETSUBITEMRECT, row, rect);
393                         parent.ignoreCustomDraw = false;
394                         if (code == 0) return new RECT ();
395                         if (!hasImage) rect.right = rect.left;
396                         if (getText) {
397                                 String string = column == 0 ? text : strings != null ? strings [column] : null;
398                                 if (string != null) {
399                                         RECT textRect = new RECT ();
400                                         char [] buffer = string.toCharArray ();
401                                         int flags = OS.DT_NOPREFIX | OS.DT_SINGLELINE | OS.DT_CALCRECT;
402                                         OS.DrawText (hDC, buffer, buffer.length, textRect, flags);
403                                         rect.right += textRect.right - textRect.left + Table.INSET * 3 + 2;
404                                 }
405                         }
406                 }
407         }
408         /*
409         * Bug in Windows.  In version 5.80 of COMCTL32.DLL, the top
410         * of the rectangle returned by LVM_GETSUBITEMRECT is off by
411         * the grid width when the grid is visible.  The fix is to
412         * move the top of the rectangle up by the grid width.
413         */
414         int gridWidth = parent.getLinesVisible () ? Table.GRID_WIDTH : 0;
415         rect.top -= gridWidth;
416         if (column != 0) rect.left += gridWidth;
417         rect.right = Math.max (rect.right, rect.left);
418         rect.top += gridWidth;
419         rect.bottom = Math.max (rect.bottom - gridWidth, rect.top);
420         return rect;
421 }
422
423 /**
424  * Returns <code>true</code> if the receiver is checked,
425  * and false otherwise.  When the parent does not have
426  * the <code>CHECK</code> style, return false.
427  *
428  * @return the checked state of the checkbox
429  *
430  * @exception SWTException <ul>
431  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
432  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
433  * </ul>
434  */
435 public boolean getChecked () {
436         checkWidget();
437         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
438         if ((parent.style & SWT.CHECK) == 0) return false;
439         return checked;
440 }
441
442 /**
443  * Returns the font that the receiver will use to paint textual information for this item.
444  *
445  * @return the receiver's font
446  *
447  * @exception SWTException <ul>
448  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
449  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
450  * </ul>
451  *
452  * @since 3.0
453  */
454 public Font getFont () {
455         checkWidget ();
456         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
457         return font != null ? font : parent.getFont ();
458 }
459
460 /**
461  * Returns the font that the receiver will use to paint textual information
462  * for the specified cell in this item.
463  *
464  * @param index the column index
465  * @return the receiver's font
466  *
467  * @exception SWTException <ul>
468  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
469  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
470  * </ul>
471  *
472  * @since 3.0
473  */
474 public Font getFont (int index) {
475         checkWidget ();
476         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
477         int count = Math.max (1, parent.getColumnCount ());
478         if (0 > index || index > count -1) return getFont ();
479         if (cellFont == null || cellFont [index] == null) return getFont ();
480         return cellFont [index];
481 }
482
483 /**
484  * Returns the foreground color that the receiver will use to draw.
485  *
486  * @return the receiver's foreground color
487  *
488  * @exception SWTException <ul>
489  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
490  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
491  * </ul>
492  *
493  * @since 2.0
494  */
495 public Color getForeground () {
496         checkWidget ();
497         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
498         if (foreground == -1) return parent.getForeground ();
499         return Color.win32_new (display, foreground);
500 }
501
502 /**
503  *
504  * Returns the foreground color at the given column index in the receiver.
505  *
506  * @param index the column index
507  * @return the foreground color
508  *
509  * @exception SWTException <ul>
510  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
511  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
512  * </ul>
513  *
514  * @since 3.0
515  */
516 public Color getForeground (int index) {
517         checkWidget ();
518         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
519         int count = Math.max (1, parent.getColumnCount ());
520         if (0 > index || index > count -1) return getForeground ();
521         int pixel = cellForeground != null ? cellForeground [index] : -1;
522         return pixel == -1 ? getForeground () : Color.win32_new (display, pixel);
523 }
524
525 /**
526  * Returns <code>true</code> if the receiver is grayed,
527  * and false otherwise. When the parent does not have
528  * the <code>CHECK</code> style, return false.
529  *
530  * @return the grayed state of the checkbox
531  *
532  * @exception SWTException <ul>
533  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
534  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
535  * </ul>
536  */
537 public boolean getGrayed () {
538         checkWidget();
539         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
540         if ((parent.style & SWT.CHECK) == 0) return false;
541         return grayed;
542 }
543
544 @Override
545 public Image getImage () {
546         checkWidget();
547         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
548         return super.getImage ();
549 }
550
551 /**
552  * Returns the image stored at the given column index in the receiver,
553  * or null if the image has not been set or if the column does not exist.
554  *
555  * @param index the column index
556  * @return the image stored at the given column index in the receiver
557  *
558  * @exception SWTException <ul>
559  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
560  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
561  * </ul>
562  */
563 public Image getImage (int index) {
564         checkWidget();
565         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
566         if (index == 0) return getImage ();
567         if (images != null) {
568                 if (0 <= index && index < images.length) return images [index];
569         }
570         return null;
571 }
572
573 /**
574  * Returns a rectangle describing the size and location
575  * relative to its parent of an image at a column in the
576  * table.  An empty rectangle is returned if index exceeds
577  * the index of the table's last column.
578  *
579  * @param index the index that specifies the column
580  * @return the receiver's bounding image rectangle
581  *
582  * @exception SWTException <ul>
583  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
584  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
585  * </ul>
586  */
587 public Rectangle getImageBounds (int index) {
588         checkWidget();
589         return DPIUtil.autoScaleDown(getImageBoundsInPixels(index));
590 }
591
592 Rectangle getImageBoundsInPixels (int index) {
593         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
594         int itemIndex = parent.indexOf (this);
595         if (itemIndex == -1) return new Rectangle (0, 0, 0, 0);
596         RECT rect = getBounds (itemIndex, index, false, true, false);
597         int width = rect.right - rect.left, height = rect.bottom - rect.top;
598         return new Rectangle (rect.left, rect.top, width, height);
599 }
600
601 /**
602  * Gets the image indent.
603  *
604  * @return the indent
605  *
606  * @exception SWTException <ul>
607  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
608  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
609  * </ul>
610  */
611 public int getImageIndent () {
612         checkWidget();
613         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
614         return imageIndent;
615 }
616
617 @Override
618 String getNameText () {
619         if ((parent.style & SWT.VIRTUAL) != 0) {
620                 if (!cached) return "*virtual*"; //$NON-NLS-1$
621         }
622         return super.getNameText ();
623 }
624
625 /**
626  * Returns the receiver's parent, which must be a <code>Table</code>.
627  *
628  * @return the receiver's parent
629  *
630  * @exception SWTException <ul>
631  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
632  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
633  * </ul>
634  */
635 public Table getParent () {
636         checkWidget();
637         return parent;
638 }
639
640 @Override
641 public String getText () {
642         checkWidget();
643         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
644         return super.getText ();
645 }
646
647 /**
648  * Returns the text stored at the given column index in the receiver,
649  * or empty string if the text has not been set.
650  *
651  * @param index the column index
652  * @return the text stored at the given column index in the receiver
653  *
654  * @exception SWTException <ul>
655  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
656  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
657  * </ul>
658  */
659 public String getText (int index) {
660         checkWidget();
661         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
662         if (index == 0) return getText ();
663         if (strings != null) {
664                 if (0 <= index && index < strings.length) {
665                         String string = strings [index];
666                         return string != null ? string : "";
667                 }
668         }
669         return "";
670 }
671
672 /**
673  * Returns a rectangle describing the size and location
674  * relative to its parent of the text at a column in the
675  * table.  An empty rectangle is returned if index exceeds
676  * the index of the table's last column.
677  *
678  * @param index the index that specifies the column
679  * @return the receiver's bounding text rectangle
680  *
681  * @exception SWTException <ul>
682  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
683  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
684  * </ul>
685  *
686  * @since 3.3
687  */
688 public Rectangle getTextBounds (int index) {
689         checkWidget();
690         return DPIUtil.autoScaleDown(getTextBoundsInPixels(index));
691 }
692
693 Rectangle getTextBoundsInPixels (int index) {
694         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
695         int itemIndex = parent.indexOf (this);
696         if (itemIndex == -1) return new Rectangle (0, 0, 0, 0);
697         RECT rect = getBounds (itemIndex, index, true, false, true);
698         rect.left += 2;
699         if (index != 0) rect.left += Table.INSET;
700         rect.left = Math.min (rect.left, rect.right);
701         rect.right = rect.right - Table.INSET;
702         int width = Math.max (0, rect.right - rect.left);
703         int height = Math.max (0, rect.bottom - rect.top);
704         return new Rectangle (rect.left, rect.top, width, height);
705 }
706
707 void redraw () {
708         if (parent.currentItem == this || !parent.getDrawing ()) return;
709         long hwnd = parent.handle;
710         if (!OS.IsWindowVisible (hwnd)) return;
711         int index = parent.indexOf (this);
712         if (index == -1) return;
713         OS.SendMessage (hwnd, OS.LVM_REDRAWITEMS, index, index);
714 }
715
716 void redraw (int column, boolean drawText, boolean drawImage) {
717         if (parent.currentItem == this || !parent.getDrawing ()) return;
718         long hwnd = parent.handle;
719         if (!OS.IsWindowVisible (hwnd)) return;
720         int index = parent.indexOf (this);
721         if (index == -1) return;
722         RECT rect = getBounds (index, column, drawText, drawImage, true);
723         OS.InvalidateRect (hwnd, rect, true);
724 }
725
726 @Override
727 void releaseHandle () {
728         super.releaseHandle ();
729         parent = null;
730 }
731
732 @Override
733 void releaseWidget () {
734         super.releaseWidget ();
735         strings = null;
736         images = null;
737         cellFont = null;
738         cellBackground = cellForeground = null;
739 }
740
741 /**
742  * Sets the receiver's background color to the color specified
743  * by the argument, or to the default system color for the item
744  * if the argument is null.
745  *
746  * @param color the new color (or null)
747  *
748  * @exception IllegalArgumentException <ul>
749  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
750  * </ul>
751  * @exception SWTException <ul>
752  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
753  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
754  * </ul>
755  *
756  * @since 2.0
757  */
758 public void setBackground (Color color) {
759         checkWidget ();
760         if (color != null && color.isDisposed ()) {
761                 error (SWT.ERROR_INVALID_ARGUMENT);
762         }
763         int pixel = -1;
764         if (color != null) {
765                 parent.setCustomDraw (true);
766                 pixel = color.handle;
767         }
768         if (background == pixel) return;
769         background = pixel;
770         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
771         redraw ();
772 }
773
774 /**
775  * Sets the background color at the given column index in the receiver
776  * to the color specified by the argument, or to the default system color for the item
777  * if the argument is null.
778  *
779  * @param index the column index
780  * @param color the new color (or null)
781  *
782  * @exception IllegalArgumentException <ul>
783  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
784  * </ul>
785  * @exception SWTException <ul>
786  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
787  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
788  * </ul>
789  *
790  * @since 3.0
791  */
792 public void setBackground (int index, Color color) {
793         checkWidget ();
794         if (color != null && color.isDisposed ()) {
795                 error (SWT.ERROR_INVALID_ARGUMENT);
796         }
797         int count = Math.max (1, parent.getColumnCount ());
798         if (0 > index || index > count - 1) return;
799         int pixel = -1;
800         if (color != null) {
801                 parent.setCustomDraw (true);
802                 pixel = color.handle;
803         }
804         if (cellBackground == null) {
805                 cellBackground = new int [count];
806                 for (int i = 0; i < count; i++) {
807                         cellBackground [i] = -1;
808                 }
809         }
810         if (cellBackground [index] == pixel) return;
811         cellBackground [index] = pixel;
812         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
813         redraw (index, true, true);
814 }
815
816 /**
817  * Sets the checked state of the checkbox for this item.  This state change
818  * only applies if the Table was created with the SWT.CHECK style.
819  *
820  * @param checked the new checked state of the checkbox
821  *
822  * @exception SWTException <ul>
823  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
824  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
825  * </ul>
826  */
827 public void setChecked (boolean checked) {
828         checkWidget();
829         if ((parent.style & SWT.CHECK) == 0) return;
830         if (this.checked == checked) return;
831         setChecked (checked, false);
832 }
833
834 void setChecked (boolean checked, boolean notify) {
835         this.checked = checked;
836         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
837         if (notify) {
838                 Event event = new Event();
839                 event.item = this;
840                 event.detail = SWT.CHECK;
841                 parent.sendSelectionEvent (SWT.Selection, event, false);
842         }
843         redraw ();
844 }
845
846 /**
847  * Sets the font that the receiver will use to paint textual information
848  * for this item to the font specified by the argument, or to the default font
849  * for that kind of control if the argument is null.
850  *
851  * @param font the new font (or null)
852  *
853  * @exception IllegalArgumentException <ul>
854  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
855  * </ul>
856  * @exception SWTException <ul>
857  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
858  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
859  * </ul>
860  *
861  * @since 3.0
862  */
863 public void setFont (Font font){
864         checkWidget ();
865         if (font != null && font.isDisposed ()) {
866                 error (SWT.ERROR_INVALID_ARGUMENT);
867         }
868         Font oldFont = this.font;
869         if (oldFont == font) return;
870         this.font = font;
871         if (oldFont != null && oldFont.equals (font)) return;
872         if (font != null) parent.setCustomDraw (true);
873         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
874         /*
875         * Bug in Windows.  Despite the fact that every item in the
876         * table always has LPSTR_TEXTCALLBACK, Windows caches the
877         * bounds for the selected items.  This means that
878         * when you change the string to be something else, Windows
879         * correctly asks you for the new string but when the item
880         * is selected, the selection draws using the bounds of the
881         * previous item.  The fix is to reset LPSTR_TEXTCALLBACK
882         * even though it has not changed, causing Windows to flush
883         * cached bounds.
884         */
885         if ((parent.style & SWT.VIRTUAL) == 0 && cached) {
886                 int itemIndex = parent.indexOf (this);
887                 if (itemIndex != -1) {
888                         long hwnd = parent.handle;
889                         LVITEM lvItem = new LVITEM ();
890                         lvItem.mask = OS.LVIF_TEXT;
891                         lvItem.iItem = itemIndex;
892                         lvItem.pszText = OS.LPSTR_TEXTCALLBACK;
893                         OS.SendMessage (hwnd, OS.LVM_SETITEM, 0, lvItem);
894                         cached = false;
895                 }
896         }
897         parent.setScrollWidth (this, false);
898         redraw ();
899 }
900
901 /**
902  * Sets the font that the receiver will use to paint textual information
903  * for the specified cell in this item to the font specified by the
904  * argument, or to the default font for that kind of control if the
905  * argument is null.
906  *
907  * @param index the column index
908  * @param font the new font (or null)
909  *
910  * @exception IllegalArgumentException <ul>
911  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
912  * </ul>
913  * @exception SWTException <ul>
914  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
915  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
916  * </ul>
917  *
918  * @since 3.0
919  */
920 public void setFont (int index, Font font) {
921         checkWidget ();
922         if (font != null && font.isDisposed ()) {
923                 error (SWT.ERROR_INVALID_ARGUMENT);
924         }
925         int count = Math.max (1, parent.getColumnCount ());
926         if (0 > index || index > count - 1) return;
927         if (cellFont == null) {
928                 if (font == null) return;
929                 cellFont = new Font [count];
930         }
931         Font oldFont = cellFont [index];
932         if (oldFont == font) return;
933         cellFont [index] = font;
934         if (oldFont != null && oldFont.equals (font)) return;
935         if (font != null) parent.setCustomDraw (true);
936         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
937         if (index == 0) {
938                 /*
939                 * Bug in Windows.  Despite the fact that every item in the
940                 * table always has LPSTR_TEXTCALLBACK, Windows caches the
941                 * bounds for the selected items.  This means that
942                 * when you change the string to be something else, Windows
943                 * correctly asks you for the new string but when the item
944                 * is selected, the selection draws using the bounds of the
945                 * previous item.  The fix is to reset LPSTR_TEXTCALLBACK
946                 * even though it has not changed, causing Windows to flush
947                 * cached bounds.
948                 */
949                 if ((parent.style & SWT.VIRTUAL) == 0 && cached) {
950                         int itemIndex = parent.indexOf (this);
951                         if (itemIndex != -1) {
952                                 long hwnd = parent.handle;
953                                 LVITEM lvItem = new LVITEM ();
954                                 lvItem.mask = OS.LVIF_TEXT;
955                                 lvItem.iItem = itemIndex;
956                                 lvItem.pszText = OS.LPSTR_TEXTCALLBACK;
957                                 OS.SendMessage (hwnd, OS.LVM_SETITEM, 0, lvItem);
958                                 cached = false;
959                         }
960                 }
961                 parent.setScrollWidth (this, false);
962         }
963         redraw (index, true, false);
964 }
965
966 /**
967  * Sets the receiver's foreground color to the color specified
968  * by the argument, or to the default system color for the item
969  * if the argument is null.
970  *
971  * @param color the new color (or null)
972  *
973  * @exception IllegalArgumentException <ul>
974  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
975  * </ul>
976  * @exception SWTException <ul>
977  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
978  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
979  * </ul>
980  *
981  * @since 2.0
982  */
983 public void setForeground (Color color){
984         checkWidget ();
985         if (color != null && color.isDisposed ()) {
986                 error (SWT.ERROR_INVALID_ARGUMENT);
987         }
988         int pixel = -1;
989         if (color != null) {
990                 parent.setCustomDraw (true);
991                 pixel = color.handle;
992         }
993         if (foreground == pixel) return;
994         foreground = pixel;
995         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
996         redraw ();
997 }
998
999 /**
1000  * Sets the foreground color at the given column index in the receiver
1001  * to the color specified by the argument, or to the default system color for the item
1002  * if the argument is null.
1003  *
1004  * @param index the column index
1005  * @param color the new color (or null)
1006  *
1007  * @exception IllegalArgumentException <ul>
1008  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1009  * </ul>
1010  * @exception SWTException <ul>
1011  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1012  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1013  * </ul>
1014  *
1015  * @since 3.0
1016  */
1017 public void setForeground (int index, Color color){
1018         checkWidget ();
1019         if (color != null && color.isDisposed ()) {
1020                 error (SWT.ERROR_INVALID_ARGUMENT);
1021         }
1022         int count = Math.max (1, parent.getColumnCount ());
1023         if (0 > index || index > count - 1) return;
1024         int pixel = -1;
1025         if (color != null) {
1026                 parent.setCustomDraw (true);
1027                 pixel = color.handle;
1028         }
1029         if (cellForeground == null) {
1030                 cellForeground = new int [count];
1031                 for (int i = 0; i < count; i++) {
1032                         cellForeground [i] = -1;
1033                 }
1034         }
1035         if (cellForeground [index] == pixel) return;
1036         cellForeground [index] = pixel;
1037         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
1038         redraw (index, true, false);
1039 }
1040
1041 /**
1042  * Sets the grayed state of the checkbox for this item.  This state change
1043  * only applies if the Table was created with the SWT.CHECK style.
1044  *
1045  * @param grayed the new grayed state of the checkbox;
1046  *
1047  * @exception SWTException <ul>
1048  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1049  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1050  * </ul>
1051  */
1052 public void setGrayed (boolean grayed) {
1053         checkWidget();
1054         if ((parent.style & SWT.CHECK) == 0) return;
1055         if (this.grayed == grayed) return;
1056         this.grayed = grayed;
1057         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
1058         redraw ();
1059 }
1060
1061 /**
1062  * Sets the image for multiple columns in the table.
1063  *
1064  * @param images the array of new images
1065  *
1066  * @exception IllegalArgumentException <ul>
1067  *    <li>ERROR_NULL_ARGUMENT - if the array of images is null</li>
1068  *    <li>ERROR_INVALID_ARGUMENT - if one of the images has been disposed</li>
1069  * </ul>
1070  * @exception SWTException <ul>
1071  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1072  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1073  * </ul>
1074  */
1075 public void setImage (Image [] images) {
1076         checkWidget();
1077         if (images == null) error (SWT.ERROR_NULL_ARGUMENT);
1078         for (int i=0; i<images.length; i++) {
1079                 setImage (i, images [i]);
1080         }
1081 }
1082
1083 /**
1084  * Sets the receiver's image at a column.
1085  *
1086  * @param index the column index
1087  * @param image the new image
1088  *
1089  * @exception IllegalArgumentException <ul>
1090  *    <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
1091  * </ul>
1092  * @exception SWTException <ul>
1093  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1094  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1095  * </ul>
1096  */
1097 public void setImage (int index, Image image) {
1098         checkWidget();
1099         if (image != null && image.isDisposed ()) {
1100                 error(SWT.ERROR_INVALID_ARGUMENT);
1101         }
1102         Image oldImage = null;
1103         if (index == 0) {
1104                 if (image != null && image.type == SWT.ICON) {
1105                         if (image.equals (this.image)) return;
1106                 }
1107                 oldImage = this.image;
1108                 super.setImage (image);
1109         }
1110         int count = Math.max (1, parent.getColumnCount ());
1111         if (0 > index || index > count - 1) return;
1112         if (images == null && index != 0) {
1113                 images = new Image [count];
1114                 images [0] = image;
1115         }
1116         if (images != null) {
1117                 if (image != null && image.type == SWT.ICON) {
1118                         if (image.equals (images [index])) return;
1119                 }
1120                 oldImage = images [index];
1121                 images [index] = image;
1122         }
1123         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
1124
1125         /* Ensure that the image list is created */
1126         parent.imageIndex (image, index);
1127
1128         if (index == 0) parent.setScrollWidth (this, false);
1129         boolean drawText = (image == null && oldImage != null) || (image != null && oldImage == null);
1130         redraw (index, drawText, true);
1131 }
1132
1133 @Override
1134 public void setImage (Image image) {
1135         checkWidget ();
1136         setImage (0, image);
1137 }
1138
1139 /**
1140  * Sets the indent of the first column's image, expressed in terms of the image's width.
1141  *
1142  * @param indent the new indent
1143  *
1144  * @exception SWTException <ul>
1145  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1146  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1147  * </ul>
1148  *
1149  * @deprecated this functionality is not supported on most platforms
1150  */
1151 @Deprecated
1152 public void setImageIndent (int indent) {
1153         checkWidget();
1154         if (indent < 0) return;
1155         if (imageIndent == indent) return;
1156         imageIndent = indent;
1157         if ((parent.style & SWT.VIRTUAL) != 0) {
1158                 cached = true;
1159         } else {
1160                 int index = parent.indexOf (this);
1161                 if (index != -1) {
1162                         long hwnd = parent.handle;
1163                         LVITEM lvItem = new LVITEM ();
1164                         lvItem.mask = OS.LVIF_INDENT;
1165                         lvItem.iItem = index;
1166                         lvItem.iIndent = indent;
1167                         OS.SendMessage (hwnd, OS.LVM_SETITEM, 0, lvItem);
1168                 }
1169         }
1170         parent.setScrollWidth (this, false);
1171         redraw ();
1172 }
1173
1174 /**
1175  * Sets the text for multiple columns in the table.
1176  * <p>
1177  * Note: If control characters like '\n', '\t' etc. are used
1178  * in the string, then the behavior is platform dependent.
1179  * </p>
1180  * @param strings the array of new strings
1181  *
1182  * @exception IllegalArgumentException <ul>
1183  *    <li>ERROR_NULL_ARGUMENT - if the text is null</li>
1184  * </ul>
1185  * @exception SWTException <ul>
1186  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1187  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1188  * </ul>
1189  */
1190 public void setText (String [] strings) {
1191         checkWidget();
1192         if (strings == null) error (SWT.ERROR_NULL_ARGUMENT);
1193         for (int i=0; i<strings.length; i++) {
1194                 String string = strings [i];
1195                 if (string != null) setText (i, string);
1196         }
1197 }
1198
1199 /**
1200  * Sets the receiver's text at a column
1201  * <p>
1202  * Note: If control characters like '\n', '\t' etc. are used
1203  * in the string, then the behavior is platform dependent.
1204  * </p>
1205  * @param index the column index
1206  * @param string the new text
1207  *
1208  * @exception IllegalArgumentException <ul>
1209  *    <li>ERROR_NULL_ARGUMENT - if the text is null</li>
1210  * </ul>
1211  * @exception SWTException <ul>
1212  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1213  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1214  * </ul>
1215  */
1216 public void setText (int index, String string) {
1217         checkWidget();
1218         if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
1219         if (index == 0) {
1220                 if (string.equals (text)) return;
1221                 super.setText (string);
1222         }
1223         int count = Math.max (1, parent.getColumnCount ());
1224         if (0 > index || index > count - 1) return;
1225         if (strings == null && index != 0)  {
1226                 strings = new String [count];
1227                 strings [0] = text;
1228         }
1229         if (strings != null) {
1230                 if (string.equals (strings [index])) return;
1231                 strings [index] = string;
1232         }
1233         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
1234         if (index == 0) {
1235                 /*
1236                 * Bug in Windows.  Despite the fact that every item in the
1237                 * table always has LPSTR_TEXTCALLBACK, Windows caches the
1238                 * bounds for the selected items.  This means that
1239                 * when you change the string to be something else, Windows
1240                 * correctly asks you for the new string but when the item
1241                 * is selected, the selection draws using the bounds of the
1242                 * previous item.  The fix is to reset LPSTR_TEXTCALLBACK
1243                 * even though it has not changed, causing Windows to flush
1244                 * cached bounds.
1245                 */
1246                 if ((parent.style & SWT.VIRTUAL) == 0 && cached) {
1247                         int itemIndex = parent.indexOf (this);
1248                         if (itemIndex != -1) {
1249                                 long hwnd = parent.handle;
1250                                 LVITEM lvItem = new LVITEM ();
1251                                 lvItem.mask = OS.LVIF_TEXT;
1252                                 lvItem.iItem = itemIndex;
1253                                 lvItem.pszText = OS.LPSTR_TEXTCALLBACK;
1254                                 OS.SendMessage (hwnd, OS.LVM_SETITEM, 0, lvItem);
1255                                 cached = false;
1256                         }
1257                 }
1258                 parent.setScrollWidth (this, false);
1259         }
1260         redraw (index, true, false);
1261 }
1262
1263 @Override
1264 public void setText (String string) {
1265         checkWidget();
1266         setText (0, string);
1267 }
1268
1269 }