diff dwt/widgets/TreeColumn.d @ 45:d8635bb48c7c

Merge with SWT 3.5
author Jacob Carlborg <doob@me.com>
date Mon, 01 Dec 2008 17:07:00 +0100
parents e831403a80a9
children 6c56264306a6
line wrap: on
line diff
--- a/dwt/widgets/TreeColumn.d	Tue Oct 21 15:20:04 2008 +0200
+++ b/dwt/widgets/TreeColumn.d	Mon Dec 01 17:07:00 2008 +0100
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+/*******************************************************************************
+ * 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
@@ -18,9 +18,21 @@
 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.NSOutlineView;
+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.NSView;
 import dwt.internal.cocoa.OS;
 
 /**
@@ -36,13 +48,18 @@
  * </p><p>
  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
  * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#tree">Tree, TreeItem, TreeColumn snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  * 
  * @since 3.1
  */
 public class TreeColumn : Item {
     NSTableColumn nsColumn;
     Tree parent;
-    String toolTipText;
+    String toolTipText, displayText;
+
+    static final int MARGIN = 2;
 
 /**
  * Constructs a new instance of this class given its parent
@@ -79,7 +96,7 @@
 public this (Tree parent, int style) {
     super (parent, checkStyle (style));
     this.parent = parent;
-    parent.createItem (this, parent.getColumnCount ());
+    parent.createItem (this, parent.columnCount);
 }
 
 /**
@@ -96,7 +113,10 @@
  * 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
@@ -189,11 +209,110 @@
     if (!isValidSubclass ()) error (DWT.ERROR_INVALID_SUBCLASS);
 }
 
+void deregister () {
+    super.deregister ();
+    display.removeWidget (nsColumn.headerCell());
+}
+
 void destroyWidget () {
     parent.destroyItem (this);
     releaseHandle ();
 }
 
+void drawInteriorWithFrame_inView (int /*long*/ id, int /*long*/ sel, int /*long*/ cellFrame, int /*long*/ view) {
+    NSRect cellRect = new NSRect ();
+    OS.memmove (cellRect, cellFrame, NSRect.sizeof);
+
+    /*
+     * Feature in Cocoa.  When the last column in a tree does not reach the
+     * rightmost edge of the tree view, the cell that draws the rightmost-
+     * column's header is also invoked to draw the header space between its
+     * right edge and the tree's right edge.  If this case is detected then
+     * nothing should be drawn.
+     */
+    NSOutlineView outlineView = (NSOutlineView)parent.view;
+    int columnIndex = (int)/*64*/outlineView.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 = null, imageSize = null;
+    NSAttributedString attrString = null;
+    NSTableHeaderCell headerCell = nsColumn.headerCell ();
+    if (displayText !is null) {
+        NSMutableDictionary dict = NSMutableDictionary.dictionaryWithCapacity(4);
+        dict.setObject (headerCell.font (), OS.NSFontAttributeName);
+        NSMutableParagraphStyle paragraphStyle = (NSMutableParagraphStyle)new NSMutableParagraphStyle ().alloc ().init ();
+        paragraphStyle.autorelease ();
+        paragraphStyle.setLineBreakMode (OS.NSLineBreakByClipping);
+        dict.setObject (paragraphStyle, OS.NSParagraphStyleAttributeName);
+        NSString string = NSString.stringWith (displayText);
+        attrString = ((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 = (int)(cellRect.x + Math.max (MARGIN, ((cellRect.width - contentWidth) / 2)));
+    } else if ((style & DWT.RIGHT) !is 0) {
+        drawX = (int)(cellRect.x + Math.max (MARGIN, cellRect.width - contentWidth - MARGIN));
+    } else {
+        drawX = (int)cellRect.x + MARGIN;
+    }
+
+    if (image !is null) {
+        NSRect destRect = new 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 = new 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 = new 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
@@ -324,21 +443,59 @@
  */
 public void pack () {
     checkWidget ();
-//  GC gc = new GC (parent);
-//  int width = gc.stringExtent (text).x;
-    //TODO extra header
-//  int index = parent.indexOf (this);
-//  width = Math.max (width, calculateWidth (parent.childIds, index, gc, width));
-//
-//  gc.dispose ();
-//  setWidth (width + parent.getInsetWidth (id, true));
-    //TODO this only takes care of the header
-    nsColumn.sizeToFit();
+
+    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 = ((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 = new 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++) {
+        TreeItem item = parent.items [i];
+        if (item !is null && !item.isDisposed () && item.cached) {
+            width = Math.max (width, item.calculateWidth (index, gc, true, 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.release();
+    if (nsColumn !is null) {
+        nsColumn.headerCell ().release ();
+        nsColumn.release ();
+    }
     nsColumn = null;
     parent = null;
 }
@@ -404,7 +561,10 @@
  * 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>
@@ -419,7 +579,14 @@
     if (index is -1 || index is 0) return;
     style &= ~(DWT.LEFT | DWT.RIGHT | DWT.CENTER);
     style |= alignment & (DWT.LEFT | DWT.RIGHT | DWT.CENTER);
-    //TODO
+    NSOutlineView outlineView = ((NSOutlineView) parent.view);
+    NSTableHeaderView headerView = outlineView.headerView ();
+    if (headerView is null) return;
+    index = (int)/*64*/outlineView.columnWithIdentifier (nsColumn);
+    NSRect rect = headerView.headerRectOfColumn (index);
+    headerView.setNeedsDisplayInRect (rect);
+    rect = outlineView.rectOfColumn (index);
+    parent.view.setNeedsDisplayInRect (rect);
 }
 
 public void setImage (Image image) {
@@ -427,19 +594,12 @@
     if (image !is null && image.isDisposed ()) {
         error (DWT.ERROR_INVALID_ARGUMENT);
     }
-//  int index = parent.indexOf (this);
-//  if (index is -1) return;
-//  if (iconRef !is 0) {
-//      OS.ReleaseIconRef (iconRef);
-//      iconRef = 0;
-//  }
-//  super.setImage (image);
-//  if (image !is null) {
-//      if (OS.VERSION < 0x1040) {
-//          iconRef = createIconRef (image);
-//      }
-//  }
-//  updateHeader ();
+    super.setImage (image);
+    NSTableHeaderView headerView = ((NSOutlineView) parent.view).headerView ();
+    if (headerView is null) return;
+    int /*long*/ index = ((NSOutlineView)parent.view).columnWithIdentifier (nsColumn);
+    NSRect rect = headerView.headerRectOfColumn (index);
+    headerView.setNeedsDisplayInRect (rect);
 }
 
 /**
@@ -465,6 +625,10 @@
  */
 public void setMoveable (bool moveable) {
     checkWidget ();
+    // TODO how to make only some columns movable?  And handle moveable is false.
+    if (moveable) {
+        ((NSOutlineView)parent.view).setAllowsColumnReordering (true);
+    }
 //  int [] flags = new int [1];
 //  OS.GetDataBrowserPropertyFlags (parent.handle, id, flags);
 //  if (moveable) {
@@ -499,7 +663,14 @@
     char [] buffer = new char [text.length ()];
     text.getChars (0, buffer.length, buffer, 0);
     int length = fixMnemonic (buffer);
-    nsColumn.headerCell().setTitle(NSString.stringWithCharacters(buffer, length));
+    displayText = new String (buffer, 0, length);
+    NSString title = NSString.stringWith (displayText);
+    nsColumn.headerCell ().setTitle (title);
+    NSTableHeaderView headerView = ((NSOutlineView) parent.view).headerView ();
+    if (headerView is null) return;
+    int /*long*/ index = ((NSOutlineView)parent.view).columnWithIdentifier (nsColumn);
+    NSRect rect = headerView.headerRectOfColumn (index);
+    headerView.setNeedsDisplayInRect (rect);
 }
 
 /**