]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/TableColumn.java
Remove invalid SHA-256-Digests
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / widgets / TableColumn.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2017 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.events.*;
19 import org.eclipse.swt.graphics.*;
20 import org.eclipse.swt.internal.*;
21 import org.eclipse.swt.internal.win32.*;
22
23 /**
24  * Instances of this class represent a column in a table widget.
25  * <dl>
26  * <dt><b>Styles:</b></dt>
27  * <dd>LEFT, RIGHT, CENTER</dd>
28  * <dt><b>Events:</b></dt>
29  * <dd> Move, Resize, Selection</dd>
30  * </dl>
31  * <p>
32  * Note: Only one of the styles LEFT, RIGHT and CENTER may be specified.
33  * </p><p>
34  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
35  * </p>
36  *
37  * @see <a href="http://www.eclipse.org/swt/snippets/#table">Table, TableItem, TableColumn snippets</a>
38  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
39  * @noextend This class is not intended to be subclassed by clients.
40  */
41 public class TableColumn extends Item {
42         Table parent;
43         boolean resizable, moveable;
44         String toolTipText;
45         int id;
46
47 /**
48  * Constructs a new instance of this class given its parent
49  * (which must be a <code>Table</code>) and a style value
50  * describing its behavior and appearance. The item is added
51  * to the end of the items maintained by its parent.
52  * <p>
53  * The style value is either one of the style constants defined in
54  * class <code>SWT</code> which is applicable to instances of this
55  * class, or must be built by <em>bitwise OR</em>'ing together
56  * (that is, using the <code>int</code> "|" operator) two or more
57  * of those <code>SWT</code> style constants. The class description
58  * lists the style constants that are applicable to the class.
59  * Style bits are also inherited from superclasses.
60  * </p>
61  *
62  * @param parent a composite control which will be the parent of the new instance (cannot be null)
63  * @param style the style of control to construct
64  *
65  * @exception IllegalArgumentException <ul>
66  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
67  * </ul>
68  * @exception SWTException <ul>
69  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
70  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
71  * </ul>
72  *
73  * @see SWT#LEFT
74  * @see SWT#RIGHT
75  * @see SWT#CENTER
76  * @see Widget#checkSubclass
77  * @see Widget#getStyle
78  */
79 public TableColumn (Table parent, int style) {
80         super (parent, checkStyle (style));
81         resizable = true;
82         this.parent = parent;
83         parent.createItem (this, parent.getColumnCount ());
84 }
85
86 /**
87  * Constructs a new instance of this class given its parent
88  * (which must be a <code>Table</code>), a style value
89  * describing its behavior and appearance, and the index
90  * at which to place it in the items maintained by its parent.
91  * <p>
92  * The style value is either one of the style constants defined in
93  * class <code>SWT</code> which is applicable to instances of this
94  * class, or must be built by <em>bitwise OR</em>'ing together
95  * (that is, using the <code>int</code> "|" operator) two or more
96  * of those <code>SWT</code> style constants. The class description
97  * lists the style constants that are applicable to the class.
98  * Style bits are also inherited from superclasses.
99  * </p>
100  * <p>
101  * Note that due to a restriction on some platforms, the first column
102  * is always left aligned.
103  * </p>
104  * @param parent a composite control which will be the parent of the new instance (cannot be null)
105  * @param style the style of control to construct
106  * @param index the zero-relative index to store the receiver in its parent
107  *
108  * @exception IllegalArgumentException <ul>
109  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
110  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the parent (inclusive)</li>
111  * </ul>
112  * @exception SWTException <ul>
113  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
114  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
115  * </ul>
116  *
117  * @see SWT#LEFT
118  * @see SWT#RIGHT
119  * @see SWT#CENTER
120  * @see Widget#checkSubclass
121  * @see Widget#getStyle
122  */
123 public TableColumn (Table parent, int style, int index) {
124         super (parent, checkStyle (style));
125         resizable = true;
126         this.parent = parent;
127         parent.createItem (this, index);
128 }
129
130 /**
131  * Adds the listener to the collection of listeners who will
132  * be notified when the control is moved or resized, by sending
133  * it one of the messages defined in the <code>ControlListener</code>
134  * interface.
135  *
136  * @param listener the listener which should be notified
137  *
138  * @exception IllegalArgumentException <ul>
139  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
140  * </ul>
141  * @exception SWTException <ul>
142  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
143  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
144  * </ul>
145  *
146  * @see ControlListener
147  * @see #removeControlListener
148  */
149 public void addControlListener(ControlListener listener) {
150         checkWidget ();
151         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
152         TypedListener typedListener = new TypedListener (listener);
153         addListener (SWT.Resize,typedListener);
154         addListener (SWT.Move,typedListener);
155 }
156
157 /**
158  * Adds the listener to the collection of listeners who will
159  * be notified when the control is selected by the user, by sending
160  * it one of the messages defined in the <code>SelectionListener</code>
161  * interface.
162  * <p>
163  * <code>widgetSelected</code> is called when the column header is selected.
164  * <code>widgetDefaultSelected</code> is not called.
165  * </p>
166  *
167  * @param listener the listener which should be notified when the control is selected by the user
168  *
169  * @exception IllegalArgumentException <ul>
170  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
171  * </ul>
172  * @exception SWTException <ul>
173  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
174  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
175  * </ul>
176  *
177  * @see SelectionListener
178  * @see #removeSelectionListener
179  * @see SelectionEvent
180  */
181 public void addSelectionListener (SelectionListener listener) {
182         checkWidget ();
183         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
184         TypedListener typedListener = new TypedListener (listener);
185         addListener (SWT.Selection,typedListener);
186         addListener (SWT.DefaultSelection,typedListener);
187 }
188
189 static int checkStyle (int style) {
190         return checkBits (style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0);
191 }
192
193 @Override
194 protected void checkSubclass () {
195         if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
196 }
197
198 @Override
199 void destroyWidget () {
200         parent.destroyItem (this);
201         releaseHandle ();
202 }
203
204 /**
205  * Returns a value which describes the position of the
206  * text or image in the receiver. The value will be one of
207  * <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>.
208  *
209  * @return the alignment
210  *
211  * @exception SWTException <ul>
212  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
213  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
214  * </ul>
215  */
216 public int getAlignment () {
217         checkWidget ();
218         if ((style & SWT.LEFT) != 0) return SWT.LEFT;
219         if ((style & SWT.CENTER) != 0) return SWT.CENTER;
220         if ((style & SWT.RIGHT) != 0) return SWT.RIGHT;
221         return SWT.LEFT;
222 }
223
224 @Override
225 String getNameText () {
226         return getText ();
227 }
228
229 /**
230  * Returns the receiver's parent, which must be a <code>Table</code>.
231  *
232  * @return the receiver's parent
233  *
234  * @exception SWTException <ul>
235  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
236  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
237  * </ul>
238  */
239 public Table getParent () {
240         checkWidget ();
241         return parent;
242 }
243
244 /**
245  * Gets the moveable attribute. A column that is
246  * not moveable cannot be reordered by the user
247  * by dragging the header but may be reordered
248  * by the programmer.
249  *
250  * @return the moveable attribute
251  *
252  * @exception SWTException <ul>
253  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
254  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
255  * </ul>
256  *
257  * @see Table#getColumnOrder()
258  * @see Table#setColumnOrder(int[])
259  * @see TableColumn#setMoveable(boolean)
260  * @see SWT#Move
261  *
262  * @since 3.1
263  */
264 public boolean getMoveable () {
265         checkWidget ();
266         return moveable;
267 }
268
269 /**
270  * Gets the resizable attribute. A column that is
271  * not resizable cannot be dragged by the user but
272  * may be resized by the programmer.
273  *
274  * @return the resizable attribute
275  *
276  * @exception SWTException <ul>
277  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
278  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
279  * </ul>
280  */
281 public boolean getResizable () {
282         checkWidget ();
283         return resizable;
284 }
285
286 /**
287  * Returns the receiver's tool tip text, or null if it has
288  * not been set.
289  *
290  * @return the receiver's tool tip text
291  *
292  * @exception SWTException <ul>
293  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
294  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
295  * </ul>
296  *
297  * @since 3.2
298  */
299 public String getToolTipText () {
300         checkWidget();
301         return toolTipText;
302 }
303
304 /**
305  * Gets the width of the receiver.
306  *
307  * @return the width
308  *
309  * @exception SWTException <ul>
310  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
311  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
312  * </ul>
313  */
314 public int getWidth () {
315         checkWidget ();
316         return DPIUtil.autoScaleDown(getWidthInPixels());
317 }
318
319 int getWidthInPixels () {
320         int index = parent.indexOf (this);
321         if (index == -1) return 0;
322         long hwnd = parent.handle;
323         return (int)OS.SendMessage (hwnd, OS.LVM_GETCOLUMNWIDTH, index, 0);
324 }
325
326 /**
327  * Causes the receiver to be resized to its preferred size.
328  * For a composite, this involves computing the preferred size
329  * from its layout, if there is one.
330  *
331  * @exception SWTException <ul>
332  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
333  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
334  * </ul>
335  *
336  */
337 public void pack () {
338         checkWidget ();
339         int index = parent.indexOf (this);
340         if (index == -1) return;
341         long hwnd = parent.handle;
342         int oldWidth = (int)OS.SendMessage (hwnd, OS.LVM_GETCOLUMNWIDTH, index, 0);
343         TCHAR buffer = new TCHAR (parent.getCodePage (), text, true);
344         int headerWidth = (int)OS.SendMessage (hwnd, OS.LVM_GETSTRINGWIDTH, 0, buffer) + Table.HEADER_MARGIN;
345         if (OS.IsAppThemed ()) headerWidth += Table.HEADER_EXTRA;
346         boolean hasHeaderImage = false;
347         if (image != null || parent.sortColumn == this) {
348                 hasHeaderImage = true;
349                 if (parent.sortColumn == this && parent.sortDirection != SWT.NONE) {
350                         headerWidth += Table.SORT_WIDTH;
351                 } else if (image != null) {
352                         Rectangle bounds = image.getBoundsInPixels ();
353                         headerWidth += bounds.width;
354                 }
355                 long hwndHeader = OS.SendMessage (hwnd, OS.LVM_GETHEADER, 0, 0);
356                 int margin = (int)OS.SendMessage (hwndHeader, OS.HDM_GETBITMAPMARGIN, 0, 0);
357                 headerWidth += margin * 4;
358         }
359         parent.ignoreColumnResize = true;
360         int columnWidth = 0;
361         if (parent.hooks (SWT.MeasureItem)) {
362                 RECT headerRect = new RECT ();
363                 long hwndHeader = OS.SendMessage (hwnd, OS.LVM_GETHEADER, 0, 0);
364                 OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect);
365                 OS.MapWindowPoints (hwndHeader, hwnd, headerRect, 2);
366                 long hDC = OS.GetDC (hwnd);
367                 long oldFont = 0, newFont = OS.SendMessage (hwnd, OS.WM_GETFONT, 0, 0);
368                 if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
369                 int count = (int)OS.SendMessage (hwnd, OS.LVM_GETITEMCOUNT, 0, 0);
370                 for (int i=0; i<count; i++) {
371                         TableItem item = parent._getItem (i, false);
372                         if (item != null) {
373                                 long hFont = item.fontHandle (index);
374                                 if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
375                                 Event event = parent.sendMeasureItemEvent (item, i, index, hDC);
376                                 if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
377                                 if (isDisposed () || parent.isDisposed ()) break;
378                                 Rectangle bounds = event.getBoundsInPixels();
379                                 columnWidth = Math.max (columnWidth, bounds.x + bounds.width - headerRect.left);
380                         }
381                 }
382                 if (newFont != 0) OS.SelectObject (hDC, oldFont);
383                 OS.ReleaseDC (hwnd, hDC);
384                 OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, columnWidth);
385         } else {
386                 OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, OS.LVSCW_AUTOSIZE);
387                 columnWidth = (int)OS.SendMessage (hwnd, OS.LVM_GETCOLUMNWIDTH, index, 0);
388                 if (index == 0) {
389                         /*
390                         * Bug in Windows.  When LVM_SETCOLUMNWIDTH is used with LVSCW_AUTOSIZE
391                         * where each item has I_IMAGECALLBACK but there are no images in the
392                         * table, the size computed by LVM_SETCOLUMNWIDTH is too small for the
393                         * first column, causing long items to be clipped with '...'.  The fix
394                         * is to increase the column width by a small amount.
395                         */
396                         if (parent.imageList == null) columnWidth += 2;
397                         /*
398                         * Bug in Windows.  When LVM_SETCOLUMNWIDTH is used with LVSCW_AUTOSIZE
399                         * for a table with a state image list, the column is width does not
400                         * include space for the state icon.  The fix is to increase the column
401                         * width by the width of the image list.
402                         */
403                         if ((parent.style & SWT.CHECK) != 0) {
404                                 long hStateList = OS.SendMessage (hwnd, OS.LVM_GETIMAGELIST, OS.LVSIL_STATE, 0);
405                                 if (hStateList != 0) {
406                                         int [] cx = new int [1], cy = new int [1];
407                                         OS.ImageList_GetIconSize (hStateList, cx, cy);
408                                         columnWidth += cx [0];
409                                 }
410                         }
411                 }
412         }
413         if (headerWidth > columnWidth) {
414                 if (!hasHeaderImage) {
415                         /*
416                         * Feature in Windows.  When LVSCW_AUTOSIZE_USEHEADER is used
417                         * with LVM_SETCOLUMNWIDTH to resize the last column, the last
418                         * column is expanded to fill the client area.  The fix is to
419                         * resize the table to be small, set the column width and then
420                         * restore the table to its original size.
421                         */
422                         RECT rect = null;
423                         boolean fixWidth = index == parent.getColumnCount () - 1;
424                         if (fixWidth) {
425                                 rect = new RECT ();
426                                 OS.GetWindowRect (hwnd, rect);
427                                 OS.UpdateWindow (hwnd);
428                                 int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOREDRAW | OS.SWP_NOZORDER;
429                                 OS.SetWindowPos (hwnd, 0, 0, 0, 0, rect.bottom - rect.top, flags);
430                         }
431                         OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, OS.LVSCW_AUTOSIZE_USEHEADER);
432                         if (fixWidth) {
433                                 int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOZORDER;
434                                 OS.SetWindowPos (hwnd, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top, flags);
435                         }
436                 } else {
437                         OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, headerWidth);
438                 }
439         } else {
440                 if (index == 0) {
441                         OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, columnWidth);
442                 }
443         }
444         parent.ignoreColumnResize = false;
445         int newWidth = (int)OS.SendMessage (hwnd, OS.LVM_GETCOLUMNWIDTH, index, 0);
446         if (oldWidth != newWidth) {
447                 updateToolTip (index);
448                 sendEvent (SWT.Resize);
449                 if (isDisposed ()) return;
450                 boolean moved = false;
451                 int [] order = parent.getColumnOrder ();
452                 TableColumn [] columns = parent.getColumns ();
453                 for (int i=0; i<order.length; i++) {
454                         TableColumn column = columns [order [i]];
455                         if (moved && !column.isDisposed ()) {
456                                 column.updateToolTip (order [i]);
457                                 column.sendEvent (SWT.Move);
458                         }
459                         if (column == this) moved = true;
460                 }
461         }
462 }
463
464 @Override
465 void releaseHandle () {
466         super.releaseHandle ();
467         parent = null;
468 }
469
470 @Override
471 void releaseParent () {
472         super.releaseParent ();
473         if (parent.sortColumn == this) {
474                 parent.sortColumn = null;
475         }
476 }
477
478 /**
479  * Removes the listener from the collection of listeners who will
480  * be notified when the control is moved or resized.
481  *
482  * @param listener the listener which should no longer be notified
483  *
484  * @exception IllegalArgumentException <ul>
485  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
486  * </ul>
487  * @exception SWTException <ul>
488  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
489  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
490  * </ul>
491  *
492  * @see ControlListener
493  * @see #addControlListener
494  */
495 public void removeControlListener (ControlListener listener) {
496         checkWidget ();
497         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
498         if (eventTable == null) return;
499         eventTable.unhook (SWT.Move, listener);
500         eventTable.unhook (SWT.Resize, listener);
501 }
502
503 /**
504  * Removes the listener from the collection of listeners who will
505  * be notified when the control is selected by the user.
506  *
507  * @param listener the listener which should no longer be notified
508  *
509  * @exception IllegalArgumentException <ul>
510  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
511  * </ul>
512  * @exception SWTException <ul>
513  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
514  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
515  * </ul>
516  *
517  * @see SelectionListener
518  * @see #addSelectionListener
519  */
520 public void removeSelectionListener(SelectionListener listener) {
521         checkWidget ();
522         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
523         if (eventTable == null) return;
524         eventTable.unhook (SWT.Selection, listener);
525         eventTable.unhook (SWT.DefaultSelection,listener);
526 }
527
528 /**
529  * Controls how text and images will be displayed in the receiver.
530  * The argument should be one of <code>LEFT</code>, <code>RIGHT</code>
531  * or <code>CENTER</code>.
532  * <p>
533  * Note that due to a restriction on some platforms, the first column
534  * is always left aligned.
535  * </p>
536  * @param alignment the new alignment
537  *
538  * @exception SWTException <ul>
539  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
540  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
541  * </ul>
542  */
543 public void setAlignment (int alignment) {
544         checkWidget ();
545         if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) == 0) return;
546         int index = parent.indexOf (this);
547         if (index == -1 || index == 0) return;
548         style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER);
549         style |= alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER);
550         long hwnd = parent.handle;
551         LVCOLUMN lvColumn = new LVCOLUMN ();
552         lvColumn.mask = OS.LVCF_FMT;
553         OS.SendMessage (hwnd, OS.LVM_GETCOLUMN, index, lvColumn);
554         lvColumn.fmt &= ~OS.LVCFMT_JUSTIFYMASK;
555         int fmt = 0;
556         if ((style & SWT.LEFT) == SWT.LEFT) fmt = OS.LVCFMT_LEFT;
557         if ((style & SWT.CENTER) == SWT.CENTER) fmt = OS.LVCFMT_CENTER;
558         if ((style & SWT.RIGHT) == SWT.RIGHT) fmt = OS.LVCFMT_RIGHT;
559         lvColumn.fmt |= fmt;
560         OS.SendMessage (hwnd, OS.LVM_SETCOLUMN, index, lvColumn);
561         /*
562         * Bug in Windows.  When LVM_SETCOLUMN is used to change
563         * the alignment of a column, the column is not redrawn
564         * to show the new alignment.  The fix is to compute the
565         * visible rectangle for the column and redraw it.
566         */
567         if (index != 0) {
568                 parent.forceResize ();
569                 RECT rect = new RECT (), headerRect = new RECT ();
570                 OS.GetClientRect (hwnd, rect);
571                 long hwndHeader = OS.SendMessage (hwnd, OS.LVM_GETHEADER, 0, 0);
572                 OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect);
573                 OS.MapWindowPoints (hwndHeader, hwnd, headerRect, 2);
574                 rect.left = headerRect.left;
575                 rect.right = headerRect.right;
576                 OS.InvalidateRect (hwnd, rect, true);
577         }
578 }
579
580 @Override
581 public void setImage (Image image) {
582         checkWidget();
583         if (image != null && image.isDisposed ()) {
584                 error (SWT.ERROR_INVALID_ARGUMENT);
585         }
586         super.setImage (image);
587         if (parent.sortColumn != this || parent.sortDirection != SWT.NONE) {
588                 setImage (image, false, false);
589         }
590 }
591
592 void setImage (Image image, boolean sort, boolean right) {
593         int index = parent.indexOf (this);
594         if (index == -1) return;
595         long hwnd = parent.handle;
596         LVCOLUMN lvColumn = new LVCOLUMN ();
597         lvColumn.mask = OS.LVCF_FMT | OS.LVCF_IMAGE;
598         OS.SendMessage (hwnd, OS.LVM_GETCOLUMN, index, lvColumn);
599         if (image != null) {
600                 lvColumn.fmt |= OS.LVCFMT_IMAGE;
601                 lvColumn.iImage = parent.imageIndexHeader (image);
602                 if (right) lvColumn.fmt |= OS.LVCFMT_BITMAP_ON_RIGHT;
603         } else {
604                 lvColumn.mask &= ~OS.LVCF_IMAGE;
605                 lvColumn.fmt &= ~(OS.LVCFMT_IMAGE | OS.LVCFMT_BITMAP_ON_RIGHT);
606         }
607         OS.SendMessage (hwnd, OS.LVM_SETCOLUMN, index, lvColumn);
608 }
609
610 /**
611  * Sets the moveable attribute.  A column that is
612  * moveable can be reordered by the user by dragging
613  * the header. A column that is not moveable cannot be
614  * dragged by the user but may be reordered
615  * by the programmer.
616  *
617  * @param moveable the moveable attribute
618  *
619  * @exception SWTException <ul>
620  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
621  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
622  * </ul>
623  *
624  * @see Table#setColumnOrder(int[])
625  * @see Table#getColumnOrder()
626  * @see TableColumn#getMoveable()
627  * @see SWT#Move
628  *
629  * @since 3.1
630  */
631 public void setMoveable (boolean moveable) {
632         checkWidget ();
633         this.moveable = moveable;
634         parent.updateMoveable ();
635 }
636
637 /**
638  * Sets the resizable attribute.  A column that is
639  * resizable can be resized by the user dragging the
640  * edge of the header.  A column that is not resizable
641  * cannot be dragged by the user but may be resized
642  * by the programmer.
643  *
644  * @param resizable the resize attribute
645  *
646  * @exception SWTException <ul>
647  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
648  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
649  * </ul>
650  */
651 public void setResizable (boolean resizable) {
652         checkWidget ();
653         this.resizable = resizable;
654 }
655
656 void setSortDirection (int direction) {
657         int index = parent.indexOf (this);
658         if (index == -1) return;
659         long hwnd = parent.handle;
660         long hwndHeader = OS.SendMessage (hwnd, OS.LVM_GETHEADER, 0, 0);
661         HDITEM hdItem = new HDITEM ();
662         hdItem.mask = OS.HDI_FORMAT | OS.HDI_IMAGE;
663         OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
664         switch (direction) {
665                 case SWT.UP:
666                         hdItem.fmt &= ~(OS.HDF_IMAGE | OS.HDF_SORTDOWN);
667                         hdItem.fmt |= OS.HDF_SORTUP;
668                         if (image == null) hdItem.mask &= ~OS.HDI_IMAGE;
669                         break;
670                 case SWT.DOWN:
671                         hdItem.fmt &= ~(OS.HDF_IMAGE | OS.HDF_SORTUP);
672                         hdItem.fmt |= OS.HDF_SORTDOWN;
673                         if (image == null) hdItem.mask &= ~OS.HDI_IMAGE;
674                         break;
675                 case SWT.NONE:
676                         hdItem.fmt &= ~(OS.HDF_SORTUP | OS.HDF_SORTDOWN);
677                         if (image != null) {
678                                 hdItem.fmt |= OS.HDF_IMAGE;
679                                 hdItem.iImage = parent.imageIndexHeader (image);
680                         } else {
681                                 hdItem.fmt &= ~OS.HDF_IMAGE;
682                                 hdItem.mask &= ~OS.HDI_IMAGE;
683                         }
684                         break;
685         }
686         OS.SendMessage (hwndHeader, OS.HDM_SETITEM, index, hdItem);
687         /*
688         * Bug in Windows.  When LVM_SETSELECTEDCOLUMN is used to
689         * specify a selected column, Windows does not redraw either
690         * the new or the previous selected column.  The fix is to
691         * force a redraw of both.
692         *
693         * Feature in Windows.  When LVM_SETBKCOLOR is used with
694         * CLR_NONE and LVM_SETSELECTEDCOLUMN is used to select
695         * a column, Windows fills the column with the selection
696         * color, drawing on top of the background image and any
697         * other custom drawing.  The fix is to avoid setting the
698         * selected column.
699         */
700         parent.forceResize ();
701         RECT rect = new RECT ();
702         OS.GetClientRect (hwnd, rect);
703         if ((int)OS.SendMessage (hwnd, OS.LVM_GETBKCOLOR, 0, 0) != OS.CLR_NONE) {
704                 int oldColumn = (int)OS.SendMessage (hwnd, OS.LVM_GETSELECTEDCOLUMN, 0, 0);
705                 int newColumn = direction == SWT.NONE ? -1 : index;
706                 OS.SendMessage (hwnd, OS.LVM_SETSELECTEDCOLUMN, newColumn, 0);
707                 RECT headerRect = new RECT ();
708                 if (oldColumn != -1) {
709                         if (OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, oldColumn, headerRect) != 0) {
710                                 OS.MapWindowPoints (hwndHeader, hwnd, headerRect, 2);
711                                 rect.left = headerRect.left;
712                                 rect.right = headerRect.right;
713                                 OS.InvalidateRect (hwnd, rect, true);
714                         }
715                 }
716         }
717         RECT headerRect = new RECT ();
718         if (OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect) != 0) {
719                 OS.MapWindowPoints (hwndHeader, hwnd, headerRect, 2);
720                 rect.left = headerRect.left;
721                 rect.right = headerRect.right;
722                 OS.InvalidateRect (hwnd, rect, true);
723         }
724 }
725
726 @Override
727 public void setText (String string) {
728         checkWidget ();
729         if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
730         if (string.equals (text)) return;
731         int index = parent.indexOf (this);
732         if (index == -1) return;
733         super.setText (string);
734
735         /*
736         * Bug in Windows.  For some reason, when the title
737         * of a column is changed after the column has been
738         * created, the alignment must also be reset or the
739         * text does not draw.  The fix is to query and then
740         * set the alignment.
741         */
742         long hwnd = parent.handle;
743         LVCOLUMN lvColumn = new LVCOLUMN ();
744         lvColumn.mask = OS.LVCF_FMT;
745         OS.SendMessage (hwnd, OS.LVM_GETCOLUMN, index, lvColumn);
746
747         /*
748         * Bug in Windows.  When a column header contains a
749         * mnemonic character, Windows does not measure the
750         * text properly.  This causes '...' to always appear
751         * at the end of the text.  The fix is to remove
752         * mnemonic characters.
753         */
754         long hHeap = OS.GetProcessHeap ();
755         char [] buffer = fixMnemonic (string);
756         int byteCount = buffer.length * TCHAR.sizeof;
757         long pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
758         OS.MoveMemory (pszText, buffer, byteCount);
759         lvColumn.mask |= OS.LVCF_TEXT;
760         lvColumn.pszText = pszText;
761         long result = OS.SendMessage (hwnd, OS.LVM_SETCOLUMN, index, lvColumn);
762         if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
763         if (result == 0) error (SWT.ERROR_CANNOT_SET_TEXT);
764 }
765
766 /**
767  * Sets the receiver's tool tip text to the argument, which
768  * may be null indicating that the default tool tip for the
769  * control will be shown. For a control that has a default
770  * tool tip, such as the Tree control on Windows, setting
771  * the tool tip text to an empty string replaces the default,
772  * causing no tool tip text to be shown.
773  * <p>
774  * The mnemonic indicator (character '&amp;') is not displayed in a tool tip.
775  * To display a single '&amp;' in the tool tip, the character '&amp;' can be
776  * escaped by doubling it in the string.
777  * </p>
778  * <p>
779  * NOTE: This operation is a hint and behavior is platform specific, on Windows
780  * for CJK-style mnemonics of the form " (&amp;C)" at the end of the tooltip text
781  * are not shown in tooltip.
782  * </p>
783  *
784  * @param string the new tool tip text (or null)
785  *
786  * @exception SWTException <ul>
787  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
788  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
789  * </ul>
790  *
791  * @since 3.2
792  */
793 public void setToolTipText (String string) {
794         checkWidget();
795         toolTipText = string;
796         long hwndHeaderToolTip = parent.headerToolTipHandle;
797         if (hwndHeaderToolTip == 0) {
798                 parent.createHeaderToolTips ();
799                 parent.updateHeaderToolTips ();
800         }
801 }
802
803 /**
804  * Sets the width of the receiver.
805  *
806  * @param width the new width
807  *
808  * @exception SWTException <ul>
809  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
810  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
811  * </ul>
812  */
813 public void setWidth (int width) {
814         checkWidget ();
815         setWidthInPixels(DPIUtil.autoScaleUp(width));
816 }
817
818 void setWidthInPixels (int width) {
819         if (width < 0) return;
820         int index = parent.indexOf (this);
821         if (index == -1) return;
822         long hwnd = parent.handle;
823         if (width != (int)OS.SendMessage (hwnd, OS.LVM_GETCOLUMNWIDTH, index, 0)) {
824                 OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, width);
825         }
826 }
827
828 void updateToolTip (int index) {
829         long hwndHeaderToolTip = parent.headerToolTipHandle;
830         if (hwndHeaderToolTip != 0) {
831                 long hwnd = parent.handle;
832                 long hwndHeader = OS.SendMessage (hwnd, OS.LVM_GETHEADER, 0, 0);
833                 RECT rect = new RECT ();
834                 if (OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, rect) != 0) {
835                         TOOLINFO lpti = new TOOLINFO ();
836                         lpti.cbSize = TOOLINFO.sizeof;
837                         lpti.hwnd = hwndHeader;
838                         lpti.uId = id;
839                         lpti.left = rect.left;
840                         lpti.top = rect.top;
841                         lpti.right = rect.right;
842                         lpti.bottom = rect.bottom;
843                         OS.SendMessage (hwndHeaderToolTip, OS.TTM_NEWTOOLRECT, 0, lpti);
844                 }
845         }
846 }
847
848 }