1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  * Port to the D programming language:
11  *     Frank Benoit <benoit@tionex.de>
12  *******************************************************************************/
13 module org.eclipse.swt.widgets.TableColumn;
14 
15 import java.lang.all;
16 
17 
18 
19 import org.eclipse.swt.SWT;
20 import org.eclipse.swt.SWTException;
21 import org.eclipse.swt.events.ControlListener;
22 import org.eclipse.swt.events.SelectionEvent;
23 import org.eclipse.swt.events.SelectionListener;
24 import org.eclipse.swt.graphics.Image;
25 import org.eclipse.swt.internal.gtk.OS;
26 import org.eclipse.swt.widgets.Item;
27 import org.eclipse.swt.widgets.Table;
28 import org.eclipse.swt.widgets.Shell;
29 import org.eclipse.swt.widgets.TypedListener;
30 import org.eclipse.swt.widgets.TableItem;
31 import org.eclipse.swt.widgets.ImageList;
32 
33 
34 /**
35  * Instances of this class represent a column in a table widget.
36  * <p><dl>
37  * <dt><b>Styles:</b></dt>
38  * <dd>LEFT, RIGHT, CENTER</dd>
39  * <dt><b>Events:</b></dt>
40  * <dd> Move, Resize, Selection</dd>
41  * </dl>
42  * </p><p>
43  * Note: Only one of the styles LEFT, RIGHT and CENTER may be specified.
44  * </p><p>
45  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
46  * </p>
47  *
48  * @see <a href="http://www.eclipse.org/swt/snippets/#table">Table, TableItem, TableColumn snippets</a>
49  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
50  */
51 public class TableColumn : Item {
52     GtkWidget* labelHandle, imageHandle, buttonHandle;
53     Table parent;
54     int modelIndex, lastButton, lastTime, lastX, lastWidth;
55     bool customDraw, useFixedWidth;
56     String toolTipText;
57 
58 /**
59  * Constructs a new instance of this class given its parent
60  * (which must be a <code>Table</code>) and a style value
61  * describing its behavior and appearance. The item is added
62  * to the end of the items maintained by its parent.
63  * <p>
64  * The style value is either one of the style constants defined in
65  * class <code>SWT</code> which is applicable to instances of this
66  * class, or must be built by <em>bitwise OR</em>'ing together
67  * (that is, using the <code>int</code> "|" operator) two or more
68  * of those <code>SWT</code> style constants. The class description
69  * lists the style constants that are applicable to the class.
70  * Style bits are also inherited from superclasses.
71  * </p>
72  *
73  * @param parent a composite control which will be the parent of the new instance (cannot be null)
74  * @param style the style of control to construct
75  *
76  * @exception IllegalArgumentException <ul>
77  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
78  * </ul>
79  * @exception SWTException <ul>
80  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
81  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
82  * </ul>
83  *
84  * @see SWT#LEFT
85  * @see SWT#RIGHT
86  * @see SWT#CENTER
87  * @see Widget#checkSubclass
88  * @see Widget#getStyle
89  */
90 public this (Table parent, int style) {
91     super (parent, checkStyle (style));
92     this.parent = parent;
93     createWidget (parent.getColumnCount ());
94 }
95 
96 /**
97  * Constructs a new instance of this class given its parent
98  * (which must be a <code>Table</code>), a style value
99  * describing its behavior and appearance, and the index
100  * at which to place it in the items maintained by its parent.
101  * <p>
102  * The style value is either one of the style constants defined in
103  * class <code>SWT</code> which is applicable to instances of this
104  * class, or must be built by <em>bitwise OR</em>'ing together
105  * (that is, using the <code>int</code> "|" operator) two or more
106  * of those <code>SWT</code> style constants. The class description
107  * lists the style constants that are applicable to the class.
108  * Style bits are also inherited from superclasses.
109  * </p>
110  * <p>
111  * Note that due to a restriction on some platforms, the first column
112  * is always left aligned.
113  * </p>
114  * @param parent a composite control which will be the parent of the new instance (cannot be null)
115  * @param style the style of control to construct
116  * @param index the zero-relative index to store the receiver in its parent
117  *
118  * @exception IllegalArgumentException <ul>
119  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
120  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the parent (inclusive)</li>
121  * </ul>
122  * @exception SWTException <ul>
123  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
124  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
125  * </ul>
126  *
127  * @see SWT#LEFT
128  * @see SWT#RIGHT
129  * @see SWT#CENTER
130  * @see Widget#checkSubclass
131  * @see Widget#getStyle
132  */
133 public this (Table parent, int style, int index) {
134     super (parent, checkStyle (style));
135     this.parent = parent;
136     createWidget (index);
137 }
138 
139 /**
140  * Adds the listener to the collection of listeners who will
141  * be notified when the control is moved or resized, by sending
142  * it one of the messages defined in the <code>ControlListener</code>
143  * interface.
144  *
145  * @param listener the listener which should be notified
146  *
147  * @exception IllegalArgumentException <ul>
148  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
149  * </ul>
150  * @exception SWTException <ul>
151  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
152  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
153  * </ul>
154  *
155  * @see ControlListener
156  * @see #removeControlListener
157  */
158 public void addControlListener(ControlListener listener) {
159     checkWidget();
160     if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
161     TypedListener typedListener = new TypedListener (listener);
162     addListener (SWT.Resize,typedListener);
163     addListener (SWT.Move,typedListener);
164 }
165 
166 /**
167  * Adds the listener to the collection of listeners who will
168  * be notified when the control is selected by the user, by sending
169  * it one of the messages defined in the <code>SelectionListener</code>
170  * interface.
171  * <p>
172  * <code>widgetSelected</code> is called when the column header is selected.
173  * <code>widgetDefaultSelected</code> is not called.
174  * </p>
175  *
176  * @param listener the listener which should be notified when the control is selected by the user
177  *
178  * @exception IllegalArgumentException <ul>
179  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
180  * </ul>
181  * @exception SWTException <ul>
182  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
183  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
184  * </ul>
185  *
186  * @see SelectionListener
187  * @see #removeSelectionListener
188  * @see SelectionEvent
189  */
190 public void addSelectionListener (SelectionListener listener) {
191     checkWidget();
192     if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
193     TypedListener typedListener = new TypedListener (listener);
194     addListener (SWT.Selection,typedListener);
195     addListener (SWT.DefaultSelection,typedListener);
196 }
197 
198 static int checkStyle (int style) {
199     return checkBits (style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0);
200 }
201 
202 protected override void checkSubclass () {
203     if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
204 }
205 
206 override void createWidget (int index) {
207     parent.createItem (this, index);
208     setOrientation ();
209     hookEvents ();
210     register ();
211     text = "";
212 }
213 
214 override void deregister() {
215     super.deregister ();
216     display.removeWidget (handle);
217     if (buttonHandle !is null) display.removeWidget (buttonHandle);
218     if (labelHandle !is null) display.removeWidget (labelHandle);
219 }
220 
221 override void destroyWidget () {
222     parent.destroyItem (this);
223     releaseHandle ();
224 }
225 
226 /**
227  * Returns a value which describes the position of the
228  * text or image in the receiver. The value will be one of
229  * <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>.
230  *
231  * @return the alignment
232  *
233  * @exception SWTException <ul>
234  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
235  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
236  * </ul>
237  */
238 public int getAlignment () {
239     checkWidget();
240     if ((style & SWT.LEFT) !is 0) return SWT.LEFT;
241     if ((style & SWT.CENTER) !is 0) return SWT.CENTER;
242     if ((style & SWT.RIGHT) !is 0) return SWT.RIGHT;
243     return SWT.LEFT;
244 }
245 
246 /**
247  * Gets the moveable attribute. A column that is
248  * not moveable cannot be reordered by the user
249  * by dragging the header but may be reordered
250  * by the programmer.
251  *
252  * @return the moveable attribute
253  *
254  * @exception SWTException <ul>
255  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
256  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
257  * </ul>
258  *
259  * @see Table#getColumnOrder()
260  * @see Table#setColumnOrder(int[])
261  * @see TableColumn#setMoveable(bool)
262  * @see SWT#Move
263  *
264  * @since 3.1
265  */
266 public bool getMoveable() {
267     checkWidget();
268     return cast(bool)OS.gtk_tree_view_column_get_reorderable (handle);
269 }
270 
271 /**
272  * Returns the receiver's parent, which must be a <code>Table</code>.
273  *
274  * @return the receiver's parent
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 Table getParent () {
282     checkWidget();
283     return parent;
284 }
285 
286 /**
287  * Gets the resizable attribute. A column that is
288  * not resizable cannot be dragged by the user but
289  * may be resized by the programmer.
290  *
291  * @return the resizable attribute
292  *
293  * @exception SWTException <ul>
294  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
295  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
296  * </ul>
297  */
298 public bool getResizable () {
299     checkWidget();
300     return cast(bool)OS.gtk_tree_view_column_get_resizable (handle);
301 }
302 
303 /**
304  * Returns the receiver's tool tip text, or null if it has
305  * not been set.
306  *
307  * @return the receiver's tool tip text
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  * @since 3.2
315  */
316 public String getToolTipText () {
317     checkWidget();
318     return toolTipText;
319 }
320 
321 /**
322  * Gets the width of the receiver.
323  *
324  * @return the width
325  *
326  * @exception SWTException <ul>
327  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
328  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
329  * </ul>
330  */
331 public int getWidth () {
332     checkWidget();
333     if (!OS.gtk_tree_view_column_get_visible (handle)) {
334         return 0;
335     }
336     if (useFixedWidth) return OS.gtk_tree_view_column_get_fixed_width (handle);
337     return OS.gtk_tree_view_column_get_width (handle);
338 }
339 
340 override int gtk_clicked (GtkWidget* widget) {
341     /*
342     * There is no API to get a double click on a table column.  Normally, when
343     * the mouse is double clicked, this is indicated by GDK_2BUTTON_PRESS
344     * but the table column sends the click signal on button release.  The fix is to
345     * test for double click by remembering the last click time and mouse button
346     * and testing for the double click interval.
347     */
348     bool doubleClick = false;
349     bool postEvent_ = true;
350     auto eventPtr = OS.gtk_get_current_event ();
351     if (eventPtr !is null) {
352         GdkEventButton* gdkEvent = cast(GdkEventButton*)eventPtr;
353         switch (gdkEvent.type) {
354             case OS.GDK_BUTTON_RELEASE: {
355                 int clickTime = display.getDoubleClickTime ();
356                 int eventTime = gdkEvent.time, eventButton = gdkEvent.button;
357                 if (lastButton is eventButton && lastTime !is 0 && Math.abs (lastTime - eventTime) <= clickTime) {
358                     doubleClick = true;
359                 }
360                 lastTime = eventTime is 0 ? 1: eventTime;
361                 lastButton = eventButton;
362                 break;
363             }
364             case OS.GDK_MOTION_NOTIFY: {
365                 /*
366                 * Bug in GTK.  Dragging a column in a GtkTreeView causes a clicked
367                 * signal to be emitted even though the mouse button was never released.
368                 * The fix to ignore the signal if the current GDK event is a motion notify.
369                 * The GTK bug was fixed in version 2.6
370                 */
371                 if (OS.GTK_VERSION < OS.buildVERSION (2, 6, 0)) postEvent_ = false;
372                 break;
373             }
374             default:
375         }
376         OS.gdk_event_free (eventPtr);
377     }
378     if (postEvent_) postEvent (doubleClick ? SWT.DefaultSelection : SWT.Selection);
379     return 0;
380 }
381 
382 override int gtk_mnemonic_activate (GtkWidget* widget, ptrdiff_t arg1) {
383     return parent.gtk_mnemonic_activate (widget, arg1);
384 }
385 
386 override int gtk_size_allocate (GtkWidget* widget, ptrdiff_t allocation) {
387     useFixedWidth = false;
388     int x = OS.GTK_WIDGET_X (widget);
389     int width = OS.GTK_WIDGET_WIDTH (widget);
390     if (x !is lastX) {
391         lastX = x;
392         sendEvent (SWT.Move);
393     }
394     if (width !is lastWidth) {
395         lastWidth = width;
396         sendEvent (SWT.Resize);
397     }
398     return 0;
399 }
400 
401 override void hookEvents () {
402     super.hookEvents ();
403     OS.g_signal_connect_closure (handle, OS.clicked.ptr, display.closures [CLICKED], false);
404     if (buttonHandle !is null) OS.g_signal_connect_closure_by_id (buttonHandle, display.signalIds [SIZE_ALLOCATE], 0, display.closures [SIZE_ALLOCATE], false);
405     if (labelHandle !is null) OS.g_signal_connect_closure_by_id (labelHandle, display.signalIds [MNEMONIC_ACTIVATE], 0, display.closures [MNEMONIC_ACTIVATE], false);
406 }
407 
408 /**
409  * Causes the receiver to be resized to its preferred size.
410  * For a composite, this involves computing the preferred size
411  * from its layout, if there is one.
412  *
413  * @exception SWTException <ul>
414  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
415  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
416  * </ul>
417  *
418  */
419 public void pack () {
420     checkWidget();
421     int width = 0;
422     if (buttonHandle !is null) {
423         GtkRequisition requisition;
424         OS.gtk_widget_size_request (buttonHandle, &requisition);
425         width = requisition.width;
426     }
427     if ((parent.style & SWT.VIRTUAL) !is 0) {
428         for (int i=0; i<parent.items.length; i++) {
429             TableItem item = parent.items [i];
430             if (item !is null && item.cached) {
431                 width = Math.max (width, parent.calculateWidth ( cast(GtkTreeViewColumn*)handle, cast(GtkTreeIter*)item.handle));
432             }
433         }
434     } else {
435         GtkTreeIter iter;
436         if (OS.gtk_tree_model_get_iter_first (parent.modelHandle, &iter)) {
437             do {
438                 width = Math.max (width, parent.calculateWidth (cast(GtkTreeViewColumn*)handle, &iter));
439             } while (OS.gtk_tree_model_iter_next(parent.modelHandle, &iter));
440         }
441     }
442     setWidth(width);
443 }
444 
445 override void register () {
446     super.register ();
447     display.addWidget (handle, this);
448     if (buttonHandle !is null) display.addWidget (buttonHandle, this);
449     if (labelHandle !is null) display.addWidget (labelHandle, this);
450 }
451 
452 override void releaseHandle () {
453     super.releaseHandle ();
454     handle = buttonHandle = labelHandle = imageHandle = null;
455     modelIndex = -1;
456     parent = null;
457 }
458 
459 override void releaseParent () {
460     super.releaseParent ();
461     if (parent.sortColumn is this) {
462         parent.sortColumn = null;
463     }
464 }
465 
466 /**
467  * Removes the listener from the collection of listeners who will
468  * be notified when the control is moved or resized.
469  *
470  * @param listener the listener which should no longer be notified
471  *
472  * @exception IllegalArgumentException <ul>
473  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
474  * </ul>
475  * @exception SWTException <ul>
476  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
477  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
478  * </ul>
479  *
480  * @see ControlListener
481  * @see #addControlListener
482  */
483 public void removeControlListener (ControlListener listener) {
484     checkWidget();
485     if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
486     if (eventTable is null) return;
487     eventTable.unhook (SWT.Move, listener);
488     eventTable.unhook (SWT.Resize, listener);
489 }
490 
491 /**
492  * Removes the listener from the collection of listeners who will
493  * be notified when the control is selected by the user.
494  *
495  * @param listener the listener which should no longer be notified
496  *
497  * @exception IllegalArgumentException <ul>
498  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
499  * </ul>
500  * @exception SWTException <ul>
501  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
502  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
503  * </ul>
504  *
505  * @see SelectionListener
506  * @see #addSelectionListener
507  */
508 public void removeSelectionListener(SelectionListener listener) {
509     checkWidget();
510     if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
511     if (eventTable is null) return;
512     eventTable.unhook (SWT.Selection, listener);
513     eventTable.unhook (SWT.DefaultSelection,listener);
514 }
515 
516 /**
517  * Controls how text and images will be displayed in the receiver.
518  * The argument should be one of <code>LEFT</code>, <code>RIGHT</code>
519  * or <code>CENTER</code>.
520  * <p>
521  * Note that due to a restriction on some platforms, the first column
522  * is always left aligned.
523  * </p>
524  * @param alignment the new alignment
525  *
526  * @exception SWTException <ul>
527  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
528  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
529  * </ul>
530  */
531 public void setAlignment (int alignment) {
532     checkWidget();
533     if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) is 0) return;
534     int index = parent.indexOf (this);
535     if (index is -1 || index is 0) return;
536     style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER);
537     style |= alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER);
538     parent.createRenderers ( cast(GtkTreeViewColumn*)handle, modelIndex, index is 0, style);
539 }
540 
541 void setFontDescription (PangoFontDescription* font) {
542     OS.gtk_widget_modify_font (labelHandle, font);
543     OS.gtk_widget_modify_font (imageHandle, font);
544 }
545 
546 public override void setImage (Image image) {
547     checkWidget ();
548     super.setImage (image);
549     if (image !is null) {
550         ImageList headerImageList = parent.headerImageList;
551         if (headerImageList is null) {
552             headerImageList = parent.headerImageList = new ImageList ();
553         }
554         int imageIndex = headerImageList.indexOf (image);
555         if (imageIndex is -1) imageIndex = headerImageList.add (image);
556         auto pixbuf = headerImageList.getPixbuf (imageIndex);
557         OS.gtk_image_set_from_pixbuf (imageHandle, pixbuf);
558         OS.gtk_widget_show (imageHandle);
559     } else {
560         OS.gtk_image_set_from_pixbuf (imageHandle, null);
561         OS.gtk_widget_hide (imageHandle);
562     }
563 }
564 
565 /**
566  * Sets the resizable attribute.  A column that is
567  * resizable can be resized by the user dragging the
568  * edge of the header.  A column that is not resizable
569  * cannot be dragged by the user but may be resized
570  * by the programmer.
571  *
572  * @param resizable the resize attribute
573  *
574  * @exception SWTException <ul>
575  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
576  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
577  * </ul>
578  */
579 public void setResizable (bool resizable) {
580     checkWidget();
581     OS.gtk_tree_view_column_set_resizable (handle, resizable);
582 }
583 
584 /**
585  * Sets the moveable attribute.  A column that is
586  * moveable can be reordered by the user by dragging
587  * the header. A column that is not moveable cannot be
588  * dragged by the user but may be reordered
589  * by the programmer.
590  *
591  * @param moveable the moveable attribute
592  *
593  * @exception SWTException <ul>
594  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
595  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
596  * </ul>
597  *
598  * @see Table#setColumnOrder(int[])
599  * @see Table#getColumnOrder()
600  * @see TableColumn#getMoveable()
601  * @see SWT#Move
602  *
603  * @since 3.1
604  */
605 public void setMoveable (bool moveable) {
606     checkWidget();
607     OS.gtk_tree_view_column_set_reorderable (handle, moveable);
608 }
609 
610 override void setOrientation() {
611     if ((parent.style & SWT.RIGHT_TO_LEFT) !is 0) {
612         if (buttonHandle !is null) {
613             OS.gtk_widget_set_direction (buttonHandle, OS.GTK_TEXT_DIR_RTL);
614             display.doSetDirectionProc( buttonHandle, OS.GTK_TEXT_DIR_RTL);
615         }
616     }
617 }
618 
619 public override void setText (String string) {
620     checkWidget();
621     // SWT extension: allow null for zero length string
622     //if (string is null) error (SWT.ERROR_NULL_ARGUMENT);
623     super.setText (string);
624     char [] chars = fixMnemonic (string);
625     OS.gtk_label_set_text_with_mnemonic (labelHandle, chars.toStringzValidPtr() );
626     if (string.length !is 0) {
627         OS.gtk_widget_show (labelHandle);
628     } else {
629         OS.gtk_widget_hide (labelHandle);
630     }
631 }
632 
633 /**
634  * Sets the receiver's tool tip text to the argument, which
635  * may be null indicating that no tool tip text should be shown.
636  *
637  * @param string the new tool tip text (or null)
638  *
639  * @exception SWTException <ul>
640  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
641  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
642  * </ul>
643  *
644  * @since 3.2
645  */
646 public void setToolTipText (String string) {
647     checkWidget();
648     Shell shell = parent._getShell ();
649     setToolTipText (shell, string);
650     toolTipText = string;
651 }
652 
653 void setToolTipText (Shell shell, String newString) {
654     shell.setToolTipText (buttonHandle, newString);
655 }
656 
657 /**
658  * Sets the width of the receiver.
659  *
660  * @param width the new width
661  *
662  * @exception SWTException <ul>
663  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
664  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
665  * </ul>
666  */
667 public void setWidth (int width) {
668     checkWidget();
669     if (width < 0) return;
670     if (width is lastWidth) return;
671     if (width > 0) {
672         useFixedWidth = true;
673         OS.gtk_tree_view_column_set_fixed_width (handle, width);
674     }
675     /*
676      * Bug in GTK.  For some reason, calling gtk_tree_view_column_set_visible()
677      * when the parent is not realized fails to show the column. The fix is to
678      * ensure that the table has been realized.
679      */
680     if (width !is 0) OS.gtk_widget_realize (parent.handle);
681     OS.gtk_tree_view_column_set_visible (handle, width !is 0);
682     lastWidth = width;
683     sendEvent (SWT.Resize);
684 }
685 
686 }