view dwt/widgets/TableColumn.d @ 123:63a09873578e

Fixed compile errors
author Jacob Carlborg <doob@me.com>
date Thu, 15 Jan 2009 23:08:54 +0100
parents c7f7f4d7091a
children
line wrap: on
line source

/*******************************************************************************
 * Copyright (c) 2000, 2008 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     
 * Port to the D programming language:
 *     Jacob Carlborg <doob@me.com>
 *******************************************************************************/
module dwt.widgets.TableColumn;

import dwt.dwthelper.utils;


import dwt.DWT;
import dwt.DWTException;
import dwt.events.ControlListener;
import dwt.events.SelectionEvent;
import dwt.events.SelectionListener;
import dwt.graphics.GC;
import dwt.graphics.Image;
import dwt.internal.cocoa.NSAffineTransform;
import dwt.internal.cocoa.NSAttributedString;
import dwt.internal.cocoa.NSGraphicsContext;
import dwt.internal.cocoa.NSMutableDictionary;
import dwt.internal.cocoa.NSMutableParagraphStyle;
import dwt.internal.cocoa.NSRect;
import dwt.internal.cocoa.NSSize;
import dwt.internal.cocoa.NSString;
import dwt.internal.cocoa.NSTableColumn;
import dwt.internal.cocoa.NSTableHeaderCell;
import dwt.internal.cocoa.NSTableHeaderView;
import dwt.internal.cocoa.NSTableView;
import dwt.internal.cocoa.NSView;
import dwt.internal.cocoa.OS;

import dwt.internal.objc.cocoa.Cocoa;
import objc = dwt.internal.objc.runtime;
import dwt.widgets.Item;
import dwt.widgets.Table;
import dwt.widgets.TableItem;
import dwt.widgets.TypedListener;

/**
 * Instances of this class represent a column in a table widget.
 * <p><dl>
 * <dt><b>Styles:</b></dt>
 * <dd>LEFT, RIGHT, CENTER</dd>
 * <dt><b>Events:</b></dt>
 * <dd> Move, Resize, Selection</dd>
 * </dl>
 * </p><p>
 * Note: Only one of the styles LEFT, RIGHT and CENTER may be specified.
 * </p><p>
 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
 * </p>
 *
 * @see <a href="http://www.eclipse.org/swt/snippets/#table">Table, TableItem, TableColumn snippets</a>
 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
 */
public class TableColumn : Item {
    Table parent;
    NSTableColumn nsColumn;
    String toolTipText, displayText;
    
    static const int MARGIN = 2;
    
/**
 * Constructs a new instance of this class given its parent
 * (which must be a <code>Table</code>) and a style value
 * describing its behavior and appearance. The item is added
 * to the end of the items maintained by its parent.
 * <p>
 * The style value is either one of the style constants defined in
 * class <code>DWT</code> which is applicable to instances of this
 * class, or must be built by <em>bitwise OR</em>'ing together 
 * (that is, using the <code>int</code> "|" operator) two or more
 * of those <code>DWT</code> style constants. The class description
 * lists the style constants that are applicable to the class.
 * Style bits are also inherited from superclasses.
 * </p>
 *
 * @param parent a composite control which will be the parent of the new instance (cannot be null)
 * @param style the style of control to construct
 *
 * @exception IllegalArgumentException <ul>
 *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
 * </ul>
 * @exception DWTException <ul>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
 *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
 * </ul>
 *
 * @see DWT#LEFT
 * @see DWT#RIGHT
 * @see DWT#CENTER
 * @see Widget#checkSubclass
 * @see Widget#getStyle
 */
public this (Table parent, int style) {
    super (parent, checkStyle (style));
    this.parent = parent;
    parent.createItem (this, parent.columnCount);
}

/**
 * Constructs a new instance of this class given its parent
 * (which must be a <code>Table</code>), a style value
 * describing its behavior and appearance, and the index
 * at which to place it in the items maintained by its parent.
 * <p>
 * The style value is either one of the style constants defined in
 * class <code>DWT</code> which is applicable to instances of this
 * class, or must be built by <em>bitwise OR</em>'ing together 
 * (that is, using the <code>int</code> "|" operator) two or more
 * of those <code>DWT</code> style constants. The class description
 * lists the style constants that are applicable to the class.
 * Style bits are also inherited from superclasses.
 * </p>
 * <p>
 * Note that due to a restriction on some platforms, the first column
 * is always left aligned.
 * </p>
 * @param parent a composite control which will be the parent of the new instance (cannot be null)
 * @param style the style of control to construct
 * @param index the zero-relative index to store the receiver in its parent
 *
 * @exception IllegalArgumentException <ul>
 *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
 *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the parent (inclusive)</li>
 * </ul>
 * @exception DWTException <ul>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
 *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
 * </ul>
 *
 * @see DWT#LEFT
 * @see DWT#RIGHT
 * @see DWT#CENTER
 * @see Widget#checkSubclass
 * @see Widget#getStyle
 */
public this (Table parent, int style, int index) {
    super (parent, checkStyle (style));
    this.parent = parent;
    parent.createItem (this, index);
}

/**
 * Adds the listener to the collection of listeners who will
 * be notified when the control is moved or resized, by sending
 * it one of the messages defined in the <code>ControlListener</code>
 * interface.
 *
 * @param listener the listener which should be notified
 *
 * @exception IllegalArgumentException <ul>
 *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
 * </ul>
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 *
 * @see ControlListener
 * @see #removeControlListener
 */
public void addControlListener(ControlListener listener) {
    checkWidget ();
    if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
    TypedListener typedListener = new TypedListener (listener);
    addListener (DWT.Resize,typedListener);
    addListener (DWT.Move,typedListener);
}

/**
 * Adds the listener to the collection of listeners who will
 * be notified when the control is selected by the user, by sending
 * it one of the messages defined in the <code>SelectionListener</code>
 * interface.
 * <p>
 * <code>widgetSelected</code> is called when the column header is selected.
 * <code>widgetDefaultSelected</code> is not called.
 * </p>
 *
 * @param listener the listener which should be notified when the control is selected by the user
 *
 * @exception IllegalArgumentException <ul>
 *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
 * </ul>
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 *
 * @see SelectionListener
 * @see #removeSelectionListener
 * @see SelectionEvent
 */
public void addSelectionListener (SelectionListener listener) {
    checkWidget ();
    if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
    TypedListener typedListener = new TypedListener (listener);
    addListener (DWT.Selection,typedListener);
    addListener (DWT.DefaultSelection,typedListener);
}

static int checkStyle (int style) {
    return checkBits (style, DWT.LEFT, DWT.CENTER, DWT.RIGHT, 0, 0, 0);
}

protected void checkSubclass () {
    if (!isValidSubclass ()) error (DWT.ERROR_INVALID_SUBCLASS);
}

void deregister () {
    super.deregister ();
    display.removeWidget (nsColumn.headerCell());
}

void destroyWidget () {
    parent.destroyItem (this);
    releaseHandle ();
}

void drawInteriorWithFrame_inView (objc.id id, objc.SEL sel, objc.id cellFrame, objc.id view) {
    NSRect cellRect = NSRect ();
    OS.memmove (&cellRect, cellFrame, NSRect.sizeof);
    
    /*
     * Feature in Cocoa.  When the last column in a table does not reach the
     * rightmost edge of the table view, the cell that draws the rightmost-
     * column's header is also invoked to draw the header space between its
     * right edge and the table's right edge.  If this case is detected then
     * nothing should be drawn.
     */
    NSTableView tableView = cast(NSTableView)parent.view;
    NSInteger columnIndex = tableView.columnWithIdentifier (nsColumn);
    NSRect headerRect = parent.headerView.headerRectOfColumn (columnIndex);
    if (headerRect.x !is cellRect.x || headerRect.width !is cellRect.width) return;
    
    NSGraphicsContext context = NSGraphicsContext.currentContext ();
    context.saveGraphicsState ();
    
    int contentWidth = 0;
    NSSize stringSize, imageSize;
    NSAttributedString attrString = null;
    NSTableHeaderCell headerCell = nsColumn.headerCell ();
    if (displayText !is null) {
        NSMutableDictionary dict = NSMutableDictionary.dictionaryWithCapacity(4);
        dict.setObject (headerCell.font (), OS.NSFontAttributeName);
        NSMutableParagraphStyle paragraphStyle = cast(NSMutableParagraphStyle)(new NSMutableParagraphStyle ()).alloc ().init ();
        paragraphStyle.autorelease ();
        paragraphStyle.setLineBreakMode (OS.NSLineBreakByClipping);
        dict.setObject (paragraphStyle, OS.NSParagraphStyleAttributeName);
        NSString string = NSString.stringWith (displayText);
        attrString = (cast(NSAttributedString)(new NSAttributedString ()).alloc ()).initWithString (string, dict);
        stringSize = attrString.size ();
        contentWidth += Math.ceil (stringSize.width);
        if (image !is null) contentWidth += MARGIN; /* space between image and text */
    }
    if (image !is null) {
        imageSize = image.handle.size ();
        contentWidth += Math.ceil (imageSize.width);
    }
    
    if (parent.sortColumn is this && parent.sortDirection !is DWT.NONE) {
        bool ascending = parent.sortDirection is DWT.UP;
        headerCell.drawSortIndicatorWithFrame (cellRect, new NSView(view), ascending, 0);
        /* remove the arrow's space from the available drawing width */
        NSRect sortRect = headerCell.sortIndicatorRectForBounds (cellRect);
        cellRect.width = Math.max (0, sortRect.x - cellRect.x);
    }
    
    int drawX = 0;
    if ((style & DWT.CENTER) !is 0) {
        drawX = cast(int)(cellRect.x + Math.max (MARGIN, ((cellRect.width - contentWidth) / 2)));
    } else if ((style & DWT.RIGHT) !is 0) {
        drawX = cast(int)(cellRect.x + Math.max (MARGIN, cellRect.width - contentWidth - MARGIN));
    } else {
        drawX = cast(int)cellRect.x + MARGIN;
    }
    
    if (image !is null) {
        NSRect destRect = NSRect ();
        destRect.x = drawX;
        destRect.y = cellRect.y;
        destRect.width = Math.min (imageSize.width, cellRect.width - 2 * MARGIN);
        destRect.height = Math.min (imageSize.height, cellRect.height);
        bool isFlipped = (new NSView (view)).isFlipped(); 
        if (isFlipped) {
            context.saveGraphicsState ();
            NSAffineTransform transform = NSAffineTransform.transform ();
            transform.scaleXBy (1, -1);
            transform.translateXBy (0, -(destRect.height + 2 * destRect.y));
            transform.concat ();
        }
        NSRect sourceRect = NSRect ();
        sourceRect.width = destRect.width;
        sourceRect.height = destRect.height;
        image.handle.drawInRect (destRect, sourceRect, OS.NSCompositeSourceOver, 1f);
        if (isFlipped) context.restoreGraphicsState ();
        drawX += destRect.width;
    }
    
    if (displayText !is null && displayText.length () > 0) {
        if (image !is null) drawX += MARGIN; /* space between image and text */
        NSRect destRect = NSRect ();
        destRect.x = drawX;
        destRect.y = cellRect.y;
        destRect.width = Math.min (stringSize.width, cellRect.x + cellRect.width - MARGIN - drawX);
        destRect.height = Math.min (stringSize.height, cellRect.height);
        attrString.drawInRect (destRect);
        attrString.release ();
    }
    
    context.restoreGraphicsState ();
}

/**
 * Returns a value which describes the position of the
 * text or image in the receiver. The value will be one of
 * <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>.
 *
 * @return the alignment 
 *
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 */
public int getAlignment () {
    checkWidget ();
    if ((style & DWT.LEFT) !is 0) return DWT.LEFT;
    if ((style & DWT.CENTER) !is 0) return DWT.CENTER;
    if ((style & DWT.RIGHT) !is 0) return DWT.RIGHT;
    return DWT.LEFT;
}

String getNameText () {
    return getText ();
}

/**
 * Returns the receiver's parent, which must be a <code>Table</code>.
 *
 * @return the receiver's parent
 *
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 */
public Table getParent () {
    checkWidget ();
    return parent;
}

/**
 * Gets the moveable attribute. A column that is
 * not moveable cannot be reordered by the user 
 * by dragging the header but may be reordered 
 * by the programmer.
 *
 * @return the moveable attribute
 *
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 * 
 * @see Table#getColumnOrder()
 * @see Table#setColumnOrder(int[])
 * @see TableColumn#setMoveable(bool)
 * @see DWT#Move
 * 
 * @since 3.1
 */
public bool getMoveable () {
    checkWidget ();
    //  int [] flags = new int [1];
    //  OS.GetDataBrowserPropertyFlags (parent.handle, id, flags);
    //  return (flags [0] & OS.kDataBrowserListViewMovableColumn) !is 0;
    return false;
}

/**
 * Gets the resizable attribute. A column that is
 * not resizable cannot be dragged by the user but
 * may be resized by the programmer.
 *
 * @return the resizable attribute
 *
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 */
public bool getResizable () {
    checkWidget ();
    return nsColumn.resizingMask() !is OS.NSTableColumnNoResizing;
}

/**
 * Returns the receiver's tool tip text, or null if it has
 * not been set.
 *
 * @return the receiver's tool tip text
 *
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 * 
 * @since 3.2
 */
public String getToolTipText () {
    checkWidget ();
    return toolTipText;
}

/**
 * Gets the width of the receiver.
 *
 * @return the width
 *
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 */
public int getWidth () {
    checkWidget ();
    return cast(int)nsColumn.width();
}

/**
 * Causes the receiver to be resized to its preferred size.
 * For a composite, this involves computing the preferred size
 * from its layout, if there is one.
 *
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 *
 */
public void pack () {
    checkWidget ();
    
    int width = 0;
    
    /* compute header width */
    if (displayText !is null) {
        NSMutableDictionary dict = NSMutableDictionary.dictionaryWithCapacity (4);
        NSTableHeaderCell headerCell = nsColumn.headerCell ();
        dict.setObject (headerCell.font (), OS.NSFontAttributeName);
        NSString string = NSString.stringWith (displayText);
        NSAttributedString attrString = (cast(NSAttributedString)(new NSAttributedString ()).alloc ()).initWithString (string, dict);
        NSSize stringSize = attrString.size ();
        attrString.release ();
        width += Math.ceil (stringSize.width);
        if (image !is null) width += MARGIN; /* space between image and text */
    }
    if (image !is null) {
        NSSize imageSize = image.handle.size ();
        width += Math.ceil (imageSize.width);
    }
    if (parent.sortColumn is this && parent.sortDirection !is DWT.NONE) {
        NSTableHeaderCell headerCell = nsColumn.headerCell ();
        NSRect rect = NSRect ();
        rect.width = rect.height = Float.MAX_VALUE;
        NSSize cellSize = headerCell.cellSizeForBounds (rect);
        rect.height = cellSize.height;
        NSRect sortRect = headerCell.sortIndicatorRectForBounds (rect);
        width += Math.ceil (sortRect.width);
    }
    
    /* compute item widths down column */
    GC gc = new GC (parent);
    int index = parent.indexOf (this);
    for (int i=0; i<parent.itemCount; i++) {
        TableItem item = parent.items [i];
        if (item !is null && !item.isDisposed () && item.cached) {
            width = Math.max (width, item.calculateWidth (index, gc, true));
            if (isDisposed ()) {
                gc.dispose ();
                return;
            }
            if (gc.isDisposed ()) gc = new GC (parent);
        }
    }
    gc.dispose ();
    setWidth (width + parent.getInsetWidth ());
}

void releaseHandle () {
    super.releaseHandle ();
    if (nsColumn !is null) {
        nsColumn.headerCell ().release ();
        nsColumn.release ();
    }
    nsColumn = null;
    parent = null;
}

void releaseWidget () {
    super.releaseWidget ();
    if (parent.sortColumn is this) {
        parent.sortColumn = null;
    }
}

/**
 * Removes the listener from the collection of listeners who will
 * be notified when the control is moved or resized.
 *
 * @param listener the listener which should no longer be notified
 *
 * @exception IllegalArgumentException <ul>
 *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
 * </ul>
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 *
 * @see ControlListener
 * @see #addControlListener
 */
public void removeControlListener (ControlListener listener) {
    checkWidget ();
    if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
    if (eventTable is null) return;
    eventTable.unhook (DWT.Move, listener);
    eventTable.unhook (DWT.Resize, listener);
}

/**
 * Removes the listener from the collection of listeners who will
 * be notified when the control is selected by the user.
 *
 * @param listener the listener which should no longer be notified
 *
 * @exception IllegalArgumentException <ul>
 *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
 * </ul>
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 *
 * @see SelectionListener
 * @see #addSelectionListener
 */
public void removeSelectionListener(SelectionListener listener) {
    checkWidget ();
    if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
    if (eventTable is null) return;
    eventTable.unhook (DWT.Selection, listener);
    eventTable.unhook (DWT.DefaultSelection,listener);  
}

/**
 * Controls how text and images will be displayed in the receiver.
 * The argument should be one of <code>LEFT</code>, <code>RIGHT</code>
 * or <code>CENTER</code>.
 * <p>
 * Note that due to a restriction on some platforms, the first column
 * is always left aligned.
 * </p>
 * @param alignment the new alignment 
 *
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 */
public void setAlignment (int alignment) {
    checkWidget ();
    if ((alignment & (DWT.LEFT | DWT.RIGHT | DWT.CENTER)) is 0) return;
    int index = parent.indexOf (this);
    if (index is -1 || index is 0) return;
    style &= ~(DWT.LEFT | DWT.RIGHT | DWT.CENTER);
    style |= alignment & (DWT.LEFT | DWT.RIGHT | DWT.CENTER);
    NSTableView tableView = (cast(NSTableView) parent.view);
    NSTableHeaderView headerView = tableView.headerView ();
    if (headerView is null) return;
    index = cast(int)/*64*/tableView.columnWithIdentifier (nsColumn);
    NSRect rect = headerView.headerRectOfColumn (index);
    headerView.setNeedsDisplayInRect (rect);
    rect = tableView.rectOfColumn (index);
    parent.view.setNeedsDisplayInRect (rect);
}

public void setImage (Image image) {
    checkWidget();
    if (image !is null && image.isDisposed ()) {
        error (DWT.ERROR_INVALID_ARGUMENT);
    }
    super.setImage (image);
    NSTableHeaderView headerView = (cast(NSTableView) parent.view).headerView ();
    if (headerView is null) return;
    NSInteger index = (cast(NSTableView)parent.view).columnWithIdentifier (nsColumn);
    NSRect rect = headerView.headerRectOfColumn (index);
    headerView.setNeedsDisplayInRect (rect);
}

/**
 * Sets the moveable attribute.  A column that is
 * moveable can be reordered by the user by dragging
 * the header. A column that is not moveable cannot be 
 * dragged by the user but may be reordered 
 * by the programmer.
 *
 * @param moveable the moveable attribute
 *
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 * 
 * @see Table#setColumnOrder(int[])
 * @see Table#getColumnOrder()
 * @see TableColumn#getMoveable()
 * @see DWT#Move
 * 
 * @since 3.1
 */
public void setMoveable (bool moveable) {
    checkWidget ();
    // TODO how to make only some columns movable?  And handle moveable is false.
    if (moveable) {
        (cast(NSTableView)parent.view).setAllowsColumnReordering (true);
    }
    //  int [] flags = new int [1];
    //  OS.GetDataBrowserPropertyFlags (parent.handle, id, flags);
    //  if (moveable) {
    //      flags [0] |= OS.kDataBrowserListViewMovableColumn;
    //  } else {
    //      flags [0] &= ~OS.kDataBrowserListViewMovableColumn;
    //  }
    //  OS.SetDataBrowserPropertyFlags (parent.handle, id, flags [0]);
}

/**
 * Sets the resizable attribute.  A column that is
 * resizable can be resized by the user dragging the
 * edge of the header.  A column that is not resizable 
 * cannot be dragged by the user but may be resized 
 * by the programmer.
 *
 * @param resizable the resize attribute
 *
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 */
public void setResizable (bool resizable) {
    checkWidget ();
    nsColumn.setResizingMask (resizable ? OS.NSTableColumnUserResizingMask : OS.NSTableColumnNoResizing);
}

public void setText (String string) {
    checkWidget ();
    if (string is null) error (DWT.ERROR_NULL_ARGUMENT);
    super.setText (string);
    char [] buffer = new char [text.length ()];
    text.getChars (0, buffer.length, buffer, 0);
    int length = fixMnemonic (buffer);
    displayText = new_String (buffer, 0, length);
    NSString title = NSString.stringWith (displayText);
    nsColumn.headerCell ().setTitle (title);
    NSTableHeaderView headerView = (cast(NSTableView) parent.view).headerView ();
    if (headerView is null) return;
    NSInteger index = (cast(NSTableView)parent.view).columnWithIdentifier (nsColumn);
    NSRect rect = headerView.headerRectOfColumn (index);
    headerView.setNeedsDisplayInRect (rect);
}

/**
 * Sets the receiver's tool tip text to the argument, which
 * may be null indicating that no tool tip text should be shown.
 *
 * @param string the new tool tip text (or null)
 *
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 * 
 * @since 3.2
 */
public void setToolTipText (String string) {
    checkWidget();
    toolTipText = string;
}

/**
 * Sets the width of the receiver.
 *
 * @param width the new width
 *
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 */
public void setWidth (int width) {
    checkWidget ();
    if (width < 0) return;
    nsColumn.setWidth (width);
}

}