comparison 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
comparison
equal deleted inserted replaced
44:ca5e494f2bbf 45:d8635bb48c7c
1 /******************************************************************************* 1 /*******************************************************************************
2 * Copyright (c) 2000, 2007 IBM Corporation and others. 2 * Copyright (c) 2000, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials 3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0 4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at 5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html 6 * http://www.eclipse.org/legal/epl-v10.html
7 * 7 *
16 import dwt.DWT; 16 import dwt.DWT;
17 import dwt.DWTException; 17 import dwt.DWTException;
18 import dwt.events.ControlListener; 18 import dwt.events.ControlListener;
19 import dwt.events.SelectionEvent; 19 import dwt.events.SelectionEvent;
20 import dwt.events.SelectionListener; 20 import dwt.events.SelectionListener;
21 import dwt.graphics.GC;
21 import dwt.graphics.Image; 22 import dwt.graphics.Image;
23 import dwt.internal.cocoa.NSAffineTransform;
24 import dwt.internal.cocoa.NSAttributedString;
25 import dwt.internal.cocoa.NSGraphicsContext;
26 import dwt.internal.cocoa.NSMutableDictionary;
27 import dwt.internal.cocoa.NSMutableParagraphStyle;
28 import dwt.internal.cocoa.NSOutlineView;
29 import dwt.internal.cocoa.NSRect;
30 import dwt.internal.cocoa.NSSize;
22 import dwt.internal.cocoa.NSString; 31 import dwt.internal.cocoa.NSString;
23 import dwt.internal.cocoa.NSTableColumn; 32 import dwt.internal.cocoa.NSTableColumn;
33 import dwt.internal.cocoa.NSTableHeaderCell;
34 import dwt.internal.cocoa.NSTableHeaderView;
35 import dwt.internal.cocoa.NSView;
24 import dwt.internal.cocoa.OS; 36 import dwt.internal.cocoa.OS;
25 37
26 /** 38 /**
27 * Instances of this class represent a column in a tree widget. 39 * Instances of this class represent a column in a tree widget.
28 * <p><dl> 40 * <p><dl>
34 * </p><p> 46 * </p><p>
35 * Note: Only one of the styles LEFT, RIGHT and CENTER may be specified. 47 * Note: Only one of the styles LEFT, RIGHT and CENTER may be specified.
36 * </p><p> 48 * </p><p>
37 * IMPORTANT: This class is <em>not</em> intended to be subclassed. 49 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
38 * </p> 50 * </p>
51 *
52 * @see <a href="http://www.eclipse.org/swt/snippets/#tree">Tree, TreeItem, TreeColumn snippets</a>
53 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
39 * 54 *
40 * @since 3.1 55 * @since 3.1
41 */ 56 */
42 public class TreeColumn : Item { 57 public class TreeColumn : Item {
43 NSTableColumn nsColumn; 58 NSTableColumn nsColumn;
44 Tree parent; 59 Tree parent;
45 String toolTipText; 60 String toolTipText, displayText;
61
62 static final int MARGIN = 2;
46 63
47 /** 64 /**
48 * Constructs a new instance of this class given its parent 65 * Constructs a new instance of this class given its parent
49 * (which must be a <code>Tree</code>) and a style value 66 * (which must be a <code>Tree</code>) and a style value
50 * describing its behavior and appearance. The item is added 67 * describing its behavior and appearance. The item is added
77 * @see Widget#getStyle 94 * @see Widget#getStyle
78 */ 95 */
79 public this (Tree parent, int style) { 96 public this (Tree parent, int style) {
80 super (parent, checkStyle (style)); 97 super (parent, checkStyle (style));
81 this.parent = parent; 98 this.parent = parent;
82 parent.createItem (this, parent.getColumnCount ()); 99 parent.createItem (this, parent.columnCount);
83 } 100 }
84 101
85 /** 102 /**
86 * Constructs a new instance of this class given its parent 103 * Constructs a new instance of this class given its parent
87 * (which must be a <code>Tree</code>), a style value 104 * (which must be a <code>Tree</code>), a style value
94 * (that is, using the <code>int</code> "|" operator) two or more 111 * (that is, using the <code>int</code> "|" operator) two or more
95 * of those <code>DWT</code> style constants. The class description 112 * of those <code>DWT</code> style constants. The class description
96 * lists the style constants that are applicable to the class. 113 * lists the style constants that are applicable to the class.
97 * Style bits are also inherited from superclasses. 114 * Style bits are also inherited from superclasses.
98 * </p> 115 * </p>
99 * 116 * <p>
117 * Note that due to a restriction on some platforms, the first column
118 * is always left aligned.
119 * </p>
100 * @param parent a composite control which will be the parent of the new instance (cannot be null) 120 * @param parent a composite control which will be the parent of the new instance (cannot be null)
101 * @param style the style of control to construct 121 * @param style the style of control to construct
102 * @param index the zero-relative index to store the receiver in its parent 122 * @param index the zero-relative index to store the receiver in its parent
103 * 123 *
104 * @exception IllegalArgumentException <ul> 124 * @exception IllegalArgumentException <ul>
187 207
188 protected void checkSubclass () { 208 protected void checkSubclass () {
189 if (!isValidSubclass ()) error (DWT.ERROR_INVALID_SUBCLASS); 209 if (!isValidSubclass ()) error (DWT.ERROR_INVALID_SUBCLASS);
190 } 210 }
191 211
212 void deregister () {
213 super.deregister ();
214 display.removeWidget (nsColumn.headerCell());
215 }
216
192 void destroyWidget () { 217 void destroyWidget () {
193 parent.destroyItem (this); 218 parent.destroyItem (this);
194 releaseHandle (); 219 releaseHandle ();
220 }
221
222 void drawInteriorWithFrame_inView (int /*long*/ id, int /*long*/ sel, int /*long*/ cellFrame, int /*long*/ view) {
223 NSRect cellRect = new NSRect ();
224 OS.memmove (cellRect, cellFrame, NSRect.sizeof);
225
226 /*
227 * Feature in Cocoa. When the last column in a tree does not reach the
228 * rightmost edge of the tree view, the cell that draws the rightmost-
229 * column's header is also invoked to draw the header space between its
230 * right edge and the tree's right edge. If this case is detected then
231 * nothing should be drawn.
232 */
233 NSOutlineView outlineView = (NSOutlineView)parent.view;
234 int columnIndex = (int)/*64*/outlineView.columnWithIdentifier (nsColumn);
235 NSRect headerRect = parent.headerView.headerRectOfColumn (columnIndex);
236 if (headerRect.x !is cellRect.x || headerRect.width !is cellRect.width) return;
237
238 NSGraphicsContext context = NSGraphicsContext.currentContext ();
239 context.saveGraphicsState ();
240
241 int contentWidth = 0;
242 NSSize stringSize = null, imageSize = null;
243 NSAttributedString attrString = null;
244 NSTableHeaderCell headerCell = nsColumn.headerCell ();
245 if (displayText !is null) {
246 NSMutableDictionary dict = NSMutableDictionary.dictionaryWithCapacity(4);
247 dict.setObject (headerCell.font (), OS.NSFontAttributeName);
248 NSMutableParagraphStyle paragraphStyle = (NSMutableParagraphStyle)new NSMutableParagraphStyle ().alloc ().init ();
249 paragraphStyle.autorelease ();
250 paragraphStyle.setLineBreakMode (OS.NSLineBreakByClipping);
251 dict.setObject (paragraphStyle, OS.NSParagraphStyleAttributeName);
252 NSString string = NSString.stringWith (displayText);
253 attrString = ((NSAttributedString)new NSAttributedString ().alloc ()).initWithString (string, dict);
254 stringSize = attrString.size ();
255 contentWidth += Math.ceil (stringSize.width);
256 if (image !is null) contentWidth += MARGIN; /* space between image and text */
257 }
258 if (image !is null) {
259 imageSize = image.handle.size ();
260 contentWidth += Math.ceil (imageSize.width);
261 }
262
263 if (parent.sortColumn is this && parent.sortDirection !is DWT.NONE) {
264 bool ascending = parent.sortDirection is DWT.UP;
265 headerCell.drawSortIndicatorWithFrame (cellRect, new NSView(view), ascending, 0);
266 /* remove the arrow's space from the available drawing width */
267 NSRect sortRect = headerCell.sortIndicatorRectForBounds (cellRect);
268 cellRect.width = Math.max (0, sortRect.x - cellRect.x);
269 }
270
271 int drawX = 0;
272 if ((style & DWT.CENTER) !is 0) {
273 drawX = (int)(cellRect.x + Math.max (MARGIN, ((cellRect.width - contentWidth) / 2)));
274 } else if ((style & DWT.RIGHT) !is 0) {
275 drawX = (int)(cellRect.x + Math.max (MARGIN, cellRect.width - contentWidth - MARGIN));
276 } else {
277 drawX = (int)cellRect.x + MARGIN;
278 }
279
280 if (image !is null) {
281 NSRect destRect = new NSRect ();
282 destRect.x = drawX;
283 destRect.y = cellRect.y;
284 destRect.width = Math.min (imageSize.width, cellRect.width - 2 * MARGIN);
285 destRect.height = Math.min (imageSize.height, cellRect.height);
286 bool isFlipped = new NSView (view).isFlipped();
287 if (isFlipped) {
288 context.saveGraphicsState ();
289 NSAffineTransform transform = NSAffineTransform.transform ();
290 transform.scaleXBy (1, -1);
291 transform.translateXBy (0, -(destRect.height + 2 * destRect.y));
292 transform.concat ();
293 }
294 NSRect sourceRect = new NSRect ();
295 sourceRect.width = destRect.width;
296 sourceRect.height = destRect.height;
297 image.handle.drawInRect (destRect, sourceRect, OS.NSCompositeSourceOver, 1f);
298 if (isFlipped) context.restoreGraphicsState ();
299 drawX += destRect.width;
300 }
301
302 if (displayText !is null && displayText.length () > 0) {
303 if (image !is null) drawX += MARGIN; /* space between image and text */
304 NSRect destRect = new NSRect ();
305 destRect.x = drawX;
306 destRect.y = cellRect.y;
307 destRect.width = Math.min (stringSize.width, cellRect.x + cellRect.width - MARGIN - drawX);
308 destRect.height = Math.min (stringSize.height, cellRect.height);
309 attrString.drawInRect (destRect);
310 attrString.release ();
311 }
312
313 context.restoreGraphicsState ();
195 } 314 }
196 315
197 /** 316 /**
198 * Returns a value which describes the position of the 317 * Returns a value which describes the position of the
199 * text or image in the receiver. The value will be one of 318 * text or image in the receiver. The value will be one of
322 * </ul> 441 * </ul>
323 * 442 *
324 */ 443 */
325 public void pack () { 444 public void pack () {
326 checkWidget (); 445 checkWidget ();
327 // GC gc = new GC (parent); 446
328 // int width = gc.stringExtent (text).x; 447 int width = 0;
329 //TODO extra header 448
330 // int index = parent.indexOf (this); 449 /* compute header width */
331 // width = Math.max (width, calculateWidth (parent.childIds, index, gc, width)); 450 if (displayText !is null) {
332 // 451 NSMutableDictionary dict = NSMutableDictionary.dictionaryWithCapacity (4);
333 // gc.dispose (); 452 NSTableHeaderCell headerCell = nsColumn.headerCell ();
334 // setWidth (width + parent.getInsetWidth (id, true)); 453 dict.setObject (headerCell.font (), OS.NSFontAttributeName);
335 //TODO this only takes care of the header 454 NSString string = NSString.stringWith (displayText);
336 nsColumn.sizeToFit(); 455 NSAttributedString attrString = ((NSAttributedString)new NSAttributedString ().alloc ()).initWithString (string, dict);
456 NSSize stringSize = attrString.size ();
457 attrString.release ();
458 width += Math.ceil (stringSize.width);
459 if (image !is null) width += MARGIN; /* space between image and text */
460 }
461 if (image !is null) {
462 NSSize imageSize = image.handle.size ();
463 width += Math.ceil (imageSize.width);
464 }
465 if (parent.sortColumn is this && parent.sortDirection !is DWT.NONE) {
466 NSTableHeaderCell headerCell = nsColumn.headerCell ();
467 NSRect rect = new NSRect ();
468 rect.width = rect.height = Float.MAX_VALUE;
469 NSSize cellSize = headerCell.cellSizeForBounds (rect);
470 rect.height = cellSize.height;
471 NSRect sortRect = headerCell.sortIndicatorRectForBounds (rect);
472 width += Math.ceil (sortRect.width);
473 }
474
475 /* compute item widths down column */
476 GC gc = new GC (parent);
477 int index = parent.indexOf (this);
478 for (int i=0; i<parent.itemCount; i++) {
479 TreeItem item = parent.items [i];
480 if (item !is null && !item.isDisposed () && item.cached) {
481 width = Math.max (width, item.calculateWidth (index, gc, true, true));
482 if (isDisposed ()) {
483 gc.dispose ();
484 return;
485 }
486 if (gc.isDisposed ()) gc = new GC (parent);
487 }
488 }
489 gc.dispose ();
490 setWidth (width + parent.getInsetWidth ());
337 } 491 }
338 492
339 void releaseHandle () { 493 void releaseHandle () {
340 super.releaseHandle (); 494 super.releaseHandle ();
341 if (nsColumn !is null) nsColumn.release(); 495 if (nsColumn !is null) {
496 nsColumn.headerCell ().release ();
497 nsColumn.release ();
498 }
342 nsColumn = null; 499 nsColumn = null;
343 parent = null; 500 parent = null;
344 } 501 }
345 502
346 void releaseWidget () { 503 void releaseWidget () {
402 559
403 /** 560 /**
404 * Controls how text and images will be displayed in the receiver. 561 * Controls how text and images will be displayed in the receiver.
405 * The argument should be one of <code>LEFT</code>, <code>RIGHT</code> 562 * The argument should be one of <code>LEFT</code>, <code>RIGHT</code>
406 * or <code>CENTER</code>. 563 * or <code>CENTER</code>.
407 * 564 * <p>
565 * Note that due to a restriction on some platforms, the first column
566 * is always left aligned.
567 * </p>
408 * @param alignment the new alignment 568 * @param alignment the new alignment
409 * 569 *
410 * @exception DWTException <ul> 570 * @exception DWTException <ul>
411 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 571 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
412 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 572 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
417 if ((alignment & (DWT.LEFT | DWT.RIGHT | DWT.CENTER)) is 0) return; 577 if ((alignment & (DWT.LEFT | DWT.RIGHT | DWT.CENTER)) is 0) return;
418 int index = parent.indexOf (this); 578 int index = parent.indexOf (this);
419 if (index is -1 || index is 0) return; 579 if (index is -1 || index is 0) return;
420 style &= ~(DWT.LEFT | DWT.RIGHT | DWT.CENTER); 580 style &= ~(DWT.LEFT | DWT.RIGHT | DWT.CENTER);
421 style |= alignment & (DWT.LEFT | DWT.RIGHT | DWT.CENTER); 581 style |= alignment & (DWT.LEFT | DWT.RIGHT | DWT.CENTER);
422 //TODO 582 NSOutlineView outlineView = ((NSOutlineView) parent.view);
583 NSTableHeaderView headerView = outlineView.headerView ();
584 if (headerView is null) return;
585 index = (int)/*64*/outlineView.columnWithIdentifier (nsColumn);
586 NSRect rect = headerView.headerRectOfColumn (index);
587 headerView.setNeedsDisplayInRect (rect);
588 rect = outlineView.rectOfColumn (index);
589 parent.view.setNeedsDisplayInRect (rect);
423 } 590 }
424 591
425 public void setImage (Image image) { 592 public void setImage (Image image) {
426 checkWidget(); 593 checkWidget();
427 if (image !is null && image.isDisposed ()) { 594 if (image !is null && image.isDisposed ()) {
428 error (DWT.ERROR_INVALID_ARGUMENT); 595 error (DWT.ERROR_INVALID_ARGUMENT);
429 } 596 }
430 // int index = parent.indexOf (this); 597 super.setImage (image);
431 // if (index is -1) return; 598 NSTableHeaderView headerView = ((NSOutlineView) parent.view).headerView ();
432 // if (iconRef !is 0) { 599 if (headerView is null) return;
433 // OS.ReleaseIconRef (iconRef); 600 int /*long*/ index = ((NSOutlineView)parent.view).columnWithIdentifier (nsColumn);
434 // iconRef = 0; 601 NSRect rect = headerView.headerRectOfColumn (index);
435 // } 602 headerView.setNeedsDisplayInRect (rect);
436 // super.setImage (image);
437 // if (image !is null) {
438 // if (OS.VERSION < 0x1040) {
439 // iconRef = createIconRef (image);
440 // }
441 // }
442 // updateHeader ();
443 } 603 }
444 604
445 /** 605 /**
446 * Sets the moveable attribute. A column that is 606 * Sets the moveable attribute. A column that is
447 * moveable can be reordered by the user by dragging 607 * moveable can be reordered by the user by dragging
463 * 623 *
464 * @since 3.2 624 * @since 3.2
465 */ 625 */
466 public void setMoveable (bool moveable) { 626 public void setMoveable (bool moveable) {
467 checkWidget (); 627 checkWidget ();
628 // TODO how to make only some columns movable? And handle moveable is false.
629 if (moveable) {
630 ((NSOutlineView)parent.view).setAllowsColumnReordering (true);
631 }
468 // int [] flags = new int [1]; 632 // int [] flags = new int [1];
469 // OS.GetDataBrowserPropertyFlags (parent.handle, id, flags); 633 // OS.GetDataBrowserPropertyFlags (parent.handle, id, flags);
470 // if (moveable) { 634 // if (moveable) {
471 // flags [0] |= OS.kDataBrowserListViewMovableColumn; 635 // flags [0] |= OS.kDataBrowserListViewMovableColumn;
472 // } else { 636 // } else {
497 if (string is null) error (DWT.ERROR_NULL_ARGUMENT); 661 if (string is null) error (DWT.ERROR_NULL_ARGUMENT);
498 super.setText (string); 662 super.setText (string);
499 char [] buffer = new char [text.length ()]; 663 char [] buffer = new char [text.length ()];
500 text.getChars (0, buffer.length, buffer, 0); 664 text.getChars (0, buffer.length, buffer, 0);
501 int length = fixMnemonic (buffer); 665 int length = fixMnemonic (buffer);
502 nsColumn.headerCell().setTitle(NSString.stringWithCharacters(buffer, length)); 666 displayText = new String (buffer, 0, length);
667 NSString title = NSString.stringWith (displayText);
668 nsColumn.headerCell ().setTitle (title);
669 NSTableHeaderView headerView = ((NSOutlineView) parent.view).headerView ();
670 if (headerView is null) return;
671 int /*long*/ index = ((NSOutlineView)parent.view).columnWithIdentifier (nsColumn);
672 NSRect rect = headerView.headerRectOfColumn (index);
673 headerView.setNeedsDisplayInRect (rect);
503 } 674 }
504 675
505 /** 676 /**
506 * Sets the receiver's tool tip text to the argument, which 677 * Sets the receiver's tool tip text to the argument, which
507 * may be null indicating that no tool tip text should be shown. 678 * may be null indicating that no tool tip text should be shown.