summaryrefslogtreecommitdiffstats
path: root/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse
diff options
context:
space:
mode:
authorSilenio Quarti <silenio>2009-07-01 14:50:54 +0000
committerSilenio Quarti <silenio>2009-07-01 14:50:54 +0000
commit093c579a4ffd9551acb901bba9617e7aa776989d (patch)
tree71cf23798b651ef92f188390841a8d130908fb11 /bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse
parentf664d297f7bb009784868bf3fcf0b3e3bb9a646b (diff)
downloadeclipse.platform.swt-093c579a4ffd9551acb901bba9617e7aa776989d.tar.gz
eclipse.platform.swt-093c579a4ffd9551acb901bba9617e7aa776989d.tar.xz
eclipse.platform.swt-093c579a4ffd9551acb901bba9617e7aa776989d.zip
restore HEAD after accidental deletion by error in automated build script
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse')
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Color.java266
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Cursor.java467
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Device.java748
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/DeviceData.java23
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Font.java370
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/FontData.java447
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/FontMetrics.java133
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java3918
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GCData.java63
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java1192
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Path.java759
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Pattern.java217
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Region.java839
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/TextLayout.java1980
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Transform.java477
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Button.java846
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Canvas.java512
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Caret.java505
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ColorDialog.java165
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Combo.java1617
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Composite.java1005
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Control.java4114
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/DateTime.java591
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Decorations.java682
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/DirectoryDialog.java182
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java4900
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/FileDialog.java461
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/FontDialog.java223
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Group.java241
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/IME.java510
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Label.java521
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Link.java532
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/List.java1429
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Menu.java926
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/MenuItem.java850
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/MessageBox.java331
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ProgressBar.java330
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Sash.java478
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Scale.java362
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ScrollBar.java685
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Scrollable.java335
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Shell.java1829
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Slider.java527
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Spinner.java1064
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TabFolder.java652
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TabItem.java373
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Table.java3087
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TableColumn.java677
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TableItem.java1031
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Text.java1983
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ToolBar.java536
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ToolItem.java992
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tracker.java1113
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TrayItem.java537
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tree.java2974
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TreeColumn.java675
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TreeItem.java1456
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Widget.java1767
58 files changed, 56505 insertions, 0 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Color.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Color.java
new file mode 100755
index 0000000000..dc1823530d
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Color.java
@@ -0,0 +1,266 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.*;
+
+/**
+ * Instances of this class manage the operating system resources that
+ * implement SWT's RGB color model. To create a color you can either
+ * specify the individual color components as integers in the range
+ * 0 to 255 or provide an instance of an <code>RGB</code>.
+ * <p>
+ * Application code must explicitly invoke the <code>Color.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ *
+ * @see RGB
+ * @see Device#getSystemColor
+ * @see <a href="http://www.eclipse.org/swt/snippets/#color">Color and RGB snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: PaintExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+public final class Color extends Resource {
+ /**
+ * the handle to the OS color resource
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public float /*double*/ [] handle;
+
+Color(Device device) {
+ super(device);
+}
+
+/**
+ * Constructs a new instance of this class given a device and the
+ * desired red, green and blue values expressed as ints in the range
+ * 0 to 255 (where 0 is black and 255 is full brightness). On limited
+ * color devices, the color instance created by this call may not have
+ * the same RGB values as the ones specified by the arguments. The
+ * RGB values on the returned instance will be the color values of
+ * the operating system color.
+ * <p>
+ * You must dispose the color when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the color
+ * @param red the amount of red in the color
+ * @param green the amount of green in the color
+ * @param blue the amount of blue in the color
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the red, green or blue argument is not between 0 and 255</li>
+ * </ul>
+ *
+ * @see #dispose
+ */
+public Color(Device device, int red, int green, int blue) {
+ super(device);
+ init(red, green, blue);
+ init();
+}
+
+/**
+ * Constructs a new instance of this class given a device and an
+ * <code>RGB</code> describing the desired red, green and blue values.
+ * On limited color devices, the color instance created by this call
+ * may not have the same RGB values as the ones specified by the
+ * argument. The RGB values on the returned instance will be the color
+ * values of the operating system color.
+ * <p>
+ * You must dispose the color when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the color
+ * @param rgb the RGB values of the desired color
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the rgb argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the red, green or blue components of the argument are not between 0 and 255</li>
+ * </ul>
+ *
+ * @see #dispose
+ */
+public Color(Device device, RGB rgb) {
+ super(device);
+ if (rgb == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ init(rgb.red, rgb.green, rgb.blue);
+ init();
+}
+
+void destroy() {
+ handle = null;
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the <em>same</em> object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
+ *
+ * @see #hashCode
+ */
+public boolean equals(Object object) {
+ if (object == this) return true;
+ if (!(object instanceof Color)) return false;
+ Color color = (Color)object;
+ float /*double*/ [] rgbColor = color.handle;
+ if (handle == rgbColor) return true;
+ return device == color.device &&
+ (int)(handle[0] * 255) == (int)(rgbColor[0] * 255) &&
+ (int)(handle[1] * 255) == (int)(rgbColor[1] * 255) &&
+ (int)(handle[2] * 255) == (int)(rgbColor[2] * 255);
+}
+
+/**
+ * Returns the amount of blue in the color, from 0 to 255.
+ *
+ * @return the blue component of the color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getBlue() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return (int)(handle[2] * 255);
+}
+
+/**
+ * Returns the amount of green in the color, from 0 to 255.
+ *
+ * @return the green component of the color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getGreen() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return (int)(handle[1] * 255);
+}
+
+/**
+ * Returns the amount of red in the color, from 0 to 255.
+ *
+ * @return the red component of the color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getRed() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return (int)(handle[0] * 255);
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return <code>true</code> when passed to
+ * <code>equals</code> must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+public int hashCode() {
+ if (isDisposed()) return 0;
+ return (int)(handle[0] * 255) ^ (int)(handle[1] * 255) ^ (int)(handle[2] * 255);
+}
+
+/**
+ * Returns an <code>RGB</code> representing the receiver.
+ *
+ * @return the RGB for the color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public RGB getRGB () {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return new RGB(getRed(), getGreen(), getBlue());
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new color.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Color</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param device the device on which to allocate the color
+ * @param handle the handle for the color
+ *
+ * @private
+ */
+public static Color cocoa_new(Device device, float /*double*/ [] rgbColor) {
+ Color color = new Color(device);
+ color.handle = rgbColor;
+ return color;
+}
+
+void init(int red, int green, int blue) {
+ if ((red > 255) || (red < 0) ||
+ (green > 255) || (green < 0) ||
+ (blue > 255) || (blue < 0)) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ float /*double*/ [] rgbColor = new float /*double*/ [4];
+ rgbColor[0] = red / 255f;
+ rgbColor[1] = green / 255f;
+ rgbColor[2] = blue / 255f;
+ rgbColor[3] = 1;
+ handle = rgbColor;
+}
+
+/**
+ * Returns <code>true</code> if the color has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the color.
+ * When a color has been disposed, it is an error to
+ * invoke any other method using the color.
+ *
+ * @return <code>true</code> when the color is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return handle == null;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+public String toString () {
+ if (isDisposed()) return "Color {*DISPOSED*}";
+ return "Color {" + getRed() + ", " + getGreen() + ", " + getBlue() + "}";
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Cursor.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Cursor.java
new file mode 100755
index 0000000000..64e4531750
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Cursor.java
@@ -0,0 +1,467 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+import org.eclipse.swt.*;
+
+/**
+ * Instances of this class manage operating system resources that
+ * specify the appearance of the on-screen pointer. To create a
+ * cursor you specify the device and either a simple cursor style
+ * describing one of the standard operating system provided cursors
+ * or the image and mask data for the desired appearance.
+ * <p>
+ * Application code must explicitly invoke the <code>Cursor.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>
+ * CURSOR_ARROW, CURSOR_WAIT, CURSOR_CROSS, CURSOR_APPSTARTING, CURSOR_HELP,
+ * CURSOR_SIZEALL, CURSOR_SIZENESW, CURSOR_SIZENS, CURSOR_SIZENWSE, CURSOR_SIZEWE,
+ * CURSOR_SIZEN, CURSOR_SIZES, CURSOR_SIZEE, CURSOR_SIZEW, CURSOR_SIZENE, CURSOR_SIZESE,
+ * CURSOR_SIZESW, CURSOR_SIZENW, CURSOR_UPARROW, CURSOR_IBEAM, CURSOR_NO, CURSOR_HAND
+ * </dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the above styles may be specified.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#cursor">Cursor snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+
+public final class Cursor extends Resource {
+
+ static final byte[] WAIT_SOURCE = new byte[] {
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ };
+
+ /**
+ * the handle to the OS cursor resource
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public NSCursor handle;
+
+/**
+ * Prevents uninitialized instances from being created outside the package.
+ */
+Cursor(Device device) {
+ super(device);
+}
+
+/**
+ * Constructs a new cursor given a device and a style
+ * constant describing the desired cursor appearance.
+ * <p>
+ * You must dispose the cursor when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the cursor
+ * @param style the style of cursor to allocate
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_INVALID_ARGUMENT - when an unknown style is specified</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES - if a handle could not be obtained for cursor creation</li>
+ * </ul>
+ *
+ * @see SWT#CURSOR_ARROW
+ * @see SWT#CURSOR_WAIT
+ * @see SWT#CURSOR_CROSS
+ * @see SWT#CURSOR_APPSTARTING
+ * @see SWT#CURSOR_HELP
+ * @see SWT#CURSOR_SIZEALL
+ * @see SWT#CURSOR_SIZENESW
+ * @see SWT#CURSOR_SIZENS
+ * @see SWT#CURSOR_SIZENWSE
+ * @see SWT#CURSOR_SIZEWE
+ * @see SWT#CURSOR_SIZEN
+ * @see SWT#CURSOR_SIZES
+ * @see SWT#CURSOR_SIZEE
+ * @see SWT#CURSOR_SIZEW
+ * @see SWT#CURSOR_SIZENE
+ * @see SWT#CURSOR_SIZESE
+ * @see SWT#CURSOR_SIZESW
+ * @see SWT#CURSOR_SIZENW
+ * @see SWT#CURSOR_UPARROW
+ * @see SWT#CURSOR_IBEAM
+ * @see SWT#CURSOR_NO
+ * @see SWT#CURSOR_HAND
+ */
+public Cursor(Device device, int style) {
+ super(device);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ switch (style) {
+ case SWT.CURSOR_HAND: handle = NSCursor.pointingHandCursor(); break;
+ case SWT.CURSOR_ARROW: handle = NSCursor.arrowCursor(); break;
+ case SWT.CURSOR_WAIT: break;
+ case SWT.CURSOR_CROSS: handle = NSCursor.crosshairCursor(); break;
+ case SWT.CURSOR_APPSTARTING: handle = NSCursor.arrowCursor(); break;
+ case SWT.CURSOR_HELP: handle = NSCursor.crosshairCursor(); break;
+ case SWT.CURSOR_SIZEALL: handle = NSCursor.crosshairCursor(); break;
+ case SWT.CURSOR_SIZENESW: handle = NSCursor.crosshairCursor(); break;
+ case SWT.CURSOR_SIZENS: handle = NSCursor.resizeUpDownCursor(); break;
+ case SWT.CURSOR_SIZENWSE: handle = NSCursor.crosshairCursor(); break;
+ case SWT.CURSOR_SIZEWE: handle = NSCursor.resizeLeftRightCursor(); break;
+ case SWT.CURSOR_SIZEN: handle = NSCursor.resizeUpCursor(); break;
+ case SWT.CURSOR_SIZES: handle = NSCursor.resizeDownCursor(); break;
+ case SWT.CURSOR_SIZEE: handle = NSCursor.resizeRightCursor(); break;
+ case SWT.CURSOR_SIZEW: handle = NSCursor.resizeLeftCursor(); break;
+ case SWT.CURSOR_SIZENE: handle = NSCursor.crosshairCursor(); break;
+ case SWT.CURSOR_SIZESE: handle = NSCursor.crosshairCursor(); break;
+ case SWT.CURSOR_SIZESW: handle = NSCursor.crosshairCursor(); break;
+ case SWT.CURSOR_SIZENW: handle = NSCursor.crosshairCursor(); break;
+ case SWT.CURSOR_UPARROW: handle = NSCursor.crosshairCursor(); break;
+ case SWT.CURSOR_IBEAM: handle = NSCursor.IBeamCursor(); break;
+ case SWT.CURSOR_NO: handle = NSCursor.crosshairCursor(); break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ if (handle == null && style == SWT.CURSOR_WAIT) {
+ NSImage nsImage = (NSImage)new NSImage().alloc();
+ NSBitmapImageRep nsImageRep = (NSBitmapImageRep)new NSBitmapImageRep().alloc();
+ handle = (NSCursor)new NSCursor().alloc();
+ int width = 16, height = 16;
+ NSSize size = new NSSize();
+ size.width = width;
+ size.height = height;
+ nsImage = nsImage.initWithSize(size);
+ nsImageRep = nsImageRep.initWithBitmapDataPlanes(0, width, height, 8, 4, true, false, OS.NSDeviceRGBColorSpace,
+ OS.NSAlphaFirstBitmapFormat | OS.NSAlphaNonpremultipliedBitmapFormat, width*4, 32);
+ OS.memmove(nsImageRep.bitmapData(), WAIT_SOURCE, WAIT_SOURCE.length);
+ nsImage.addRepresentation(nsImageRep);
+ NSPoint point = new NSPoint();
+ point.x = 0;
+ point.y = 0;
+ handle = handle.initWithImage(nsImage, point);
+ nsImageRep.release();
+ nsImage.release();
+ } else {
+ handle.retain();
+ }
+ handle.setOnMouseEntered(true);
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Constructs a new cursor given a device, image and mask
+ * data describing the desired cursor appearance, and the x
+ * and y coordinates of the <em>hotspot</em> (that is, the point
+ * within the area covered by the cursor which is considered
+ * to be where the on-screen pointer is "pointing").
+ * <p>
+ * The mask data is allowed to be null, but in this case the source
+ * must be an ImageData representing an icon that specifies both
+ * color data and mask data.
+ * <p>
+ * You must dispose the cursor when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the cursor
+ * @param source the color data for the cursor
+ * @param mask the mask data for the cursor (or null)
+ * @param hotspotX the x coordinate of the cursor's hotspot
+ * @param hotspotY the y coordinate of the cursor's hotspot
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the source is null</li>
+ * <li>ERROR_NULL_ARGUMENT - if the mask is null and the source does not have a mask</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the source and the mask are not the same
+ * size, or if the hotspot is outside the bounds of the image</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES - if a handle could not be obtained for cursor creation</li>
+ * </ul>
+ */
+public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int hotspotY) {
+ super(device);
+ if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (mask == null) {
+ if (source.getTransparencyType() != SWT.TRANSPARENCY_MASK) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ mask = source.getTransparencyMask();
+ }
+ /* Check the bounds. Mask must be the same size as source */
+ if (mask.width != source.width || mask.height != source.height) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ /* Check the hotspots */
+ if (hotspotX >= source.width || hotspotX < 0 ||
+ hotspotY >= source.height || hotspotY < 0) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ byte[] data = new byte[source.width * source.height * 4];
+ for (int y = 0; y < source.height; y++) {
+ int offset = y * source.width * 4;
+ for (int x = 0; x < source.width; x++) {
+ int pixel = source.getPixel(x, y);
+ int maskPixel = mask.getPixel(x, y);
+ if (pixel == 0 && maskPixel == 0) {
+ // BLACK
+ data[offset] = (byte)0xFF;
+ } else if (pixel == 0 && maskPixel == 1) {
+ // WHITE - cursor color
+ data[offset] = data[offset + 1] = data[offset + 2] = data[offset + 3] = (byte)0xFF;
+ } else if (pixel == 1 && maskPixel == 0) {
+ // SCREEN
+ } else {
+ /*
+ * Feature in the Macintosh. It is not possible to have
+ * the reverse screen case using NSCursor.
+ * Reverse screen will be the same as screen.
+ */
+ // REVERSE SCREEN -> SCREEN
+ }
+ offset += 4;
+ }
+ }
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ createNSCursor(hotspotX, hotspotY, data, source.width, source.height);
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+void createNSCursor(int hotspotX, int hotspotY, byte[] buffer, int width, int height) {
+ NSImage nsImage = (NSImage)new NSImage().alloc();
+ NSBitmapImageRep nsImageRep = (NSBitmapImageRep)new NSBitmapImageRep().alloc();
+ handle = (NSCursor)new NSCursor().alloc();
+ NSSize size = new NSSize();
+ size.width = width;
+ size.height = height;
+ nsImage = nsImage.initWithSize(size);
+ nsImageRep = nsImageRep.initWithBitmapDataPlanes(0, width, height,
+ 8, 4, true, false, new NSString(OS.NSDeviceRGBColorSpace()),
+ OS.NSAlphaFirstBitmapFormat | OS.NSAlphaNonpremultipliedBitmapFormat, width * 4, 32);
+ OS.memmove(nsImageRep.bitmapData(), buffer, buffer.length);
+ nsImage.addRepresentation(nsImageRep);
+ NSPoint point = new NSPoint();
+ point.x = hotspotX;
+ point.y = hotspotY;
+ handle = handle.initWithImage(nsImage, point);
+ nsImageRep.release();
+ nsImage.release();
+}
+
+/**
+ * Constructs a new cursor given a device, image data describing
+ * the desired cursor appearance, and the x and y coordinates of
+ * the <em>hotspot</em> (that is, the point within the area
+ * covered by the cursor which is considered to be where the
+ * on-screen pointer is "pointing").
+ * <p>
+ * You must dispose the cursor when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the cursor
+ * @param source the image data for the cursor
+ * @param hotspotX the x coordinate of the cursor's hotspot
+ * @param hotspotY the y coordinate of the cursor's hotspot
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the image is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the hotspot is outside the bounds of the
+ * image</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES - if a handle could not be obtained for cursor creation</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public Cursor(Device device, ImageData source, int hotspotX, int hotspotY) {
+ super(device);
+ if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (hotspotX >= source.width || hotspotX < 0 ||
+ hotspotY >= source.height || hotspotY < 0) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ byte[] data = new byte[source.width * source.height * 4];
+ PaletteData palette = source.palette;
+ if (palette.isDirect) {
+ ImageData.blit(ImageData.BLIT_SRC,
+ source.data, source.depth, source.bytesPerLine, source.getByteOrder(), 0, 0, source.width, source.height, palette.redMask, palette.greenMask, palette.blueMask,
+ ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+ data, 32, source.width * 4, ImageData.MSB_FIRST, 0, 0, source.width, source.height, 0xFF0000, 0xFF00, 0xFF,
+ false, false);
+ } else {
+ RGB[] rgbs = palette.getRGBs();
+ int length = rgbs.length;
+ byte[] srcReds = new byte[length];
+ byte[] srcGreens = new byte[length];
+ byte[] srcBlues = new byte[length];
+ for (int i = 0; i < rgbs.length; i++) {
+ RGB rgb = rgbs[i];
+ if (rgb == null) continue;
+ srcReds[i] = (byte)rgb.red;
+ srcGreens[i] = (byte)rgb.green;
+ srcBlues[i] = (byte)rgb.blue;
+ }
+ ImageData.blit(ImageData.BLIT_SRC,
+ source.data, source.depth, source.bytesPerLine, source.getByteOrder(), 0, 0, source.width, source.height, srcReds, srcGreens, srcBlues,
+ ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+ data, 32, source.width * 4, ImageData.MSB_FIRST, 0, 0, source.width, source.height, 0xFF0000, 0xFF00, 0xFF,
+ false, false);
+ }
+ if (source.maskData != null || source.transparentPixel != -1) {
+ ImageData mask = source.getTransparencyMask();
+ byte[] maskData = mask.data;
+ int maskBpl = mask.bytesPerLine;
+ int offset = 0, maskOffset = 0;
+ for (int y = 0; y<source.height; y++) {
+ for (int x = 0; x<source.width; x++) {
+ data[offset] = ((maskData[maskOffset + (x >> 3)]) & (1 << (7 - (x & 0x7)))) != 0 ? (byte)0xff : 0;
+ offset += 4;
+ }
+ maskOffset += maskBpl;
+ }
+ } else if (source.alpha != -1) {
+ byte alpha = (byte)source.alpha;
+ for (int i=0; i<data.length; i+=4) {
+ data[i] = alpha;
+ }
+ } else if (source.alphaData != null) {
+ byte[] alphaData = source.alphaData;
+ for (int i=0; i<data.length; i+=4) {
+ data[i] = alphaData[i/4];
+ }
+ }
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ createNSCursor(hotspotX, hotspotY, data, source.width, source.height);
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+void destroy() {
+ handle.release();
+ handle = null;
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the <em>same</em> object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
+ *
+ * @see #hashCode
+ */
+public boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof Cursor)) return false;
+ Cursor cursor = (Cursor) object;
+ return device == cursor.device && handle == cursor.handle;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return <code>true</code> when passed to
+ * <code>equals</code> must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+public int hashCode () {
+ return handle != null ? (int)/*64*/handle.id : 0;
+}
+
+/**
+ * Returns <code>true</code> if the cursor has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the cursor.
+ * When a cursor has been disposed, it is an error to
+ * invoke any other method using the cursor.
+ *
+ * @return <code>true</code> when the cursor is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return handle == null;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+public String toString () {
+ if (isDisposed()) return "Cursor {*DISPOSED*}";
+ return "Cursor {" + handle + "}";
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new cursor.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Cursor</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param device the device on which to allocate the color
+ * @param handle the handle for the cursor
+ *
+ * @private
+ */
+public static Cursor cocoa_new(Device device, NSCursor handle) {
+ Cursor cursor = new Cursor(device);
+ cursor.handle = handle;
+ return cursor;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Device.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Device.java
new file mode 100755
index 0000000000..932e1d49f6
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Device.java
@@ -0,0 +1,748 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.Compatibility;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * This class is the abstract superclass of all device objects,
+ * such as the Display device and the Printer device. Devices
+ * can have a graphics context (GC) created for them, and they
+ * can be drawn on by sending messages to the associated GC.
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+public abstract class Device implements Drawable {
+
+ /* Debugging */
+ public static boolean DEBUG;
+ boolean debug = DEBUG;
+ boolean tracking = DEBUG;
+ Error [] errors;
+ Object [] objects;
+ Object trackingLock;
+
+ /* Disposed flag */
+ boolean disposed, warnings;
+
+ Color COLOR_BLACK, COLOR_DARK_RED, COLOR_DARK_GREEN, COLOR_DARK_YELLOW, COLOR_DARK_BLUE;
+ Color COLOR_DARK_MAGENTA, COLOR_DARK_CYAN, COLOR_GRAY, COLOR_DARK_GRAY, COLOR_RED;
+ Color COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE;
+
+ /* System Font */
+ Font systemFont;
+
+ NSMutableParagraphStyle paragraphStyle;
+
+ /* Device DPI */
+ Point dpi;
+
+ /*
+ * TEMPORARY CODE. When a graphics object is
+ * created and the device parameter is null,
+ * the current Display is used. This presents
+ * a problem because SWT graphics does not
+ * reference classes in SWT widgets. The correct
+ * fix is to remove this feature. Unfortunately,
+ * too many application programs rely on this
+ * feature.
+ */
+ protected static Device CurrentDevice;
+ protected static Runnable DeviceFinder;
+ static {
+ try {
+ Class.forName ("org.eclipse.swt.widgets.Display");
+ } catch (ClassNotFoundException e) {}
+ }
+
+/*
+* TEMPORARY CODE.
+*/
+static synchronized Device getDevice () {
+ if (DeviceFinder != null) DeviceFinder.run();
+ Device device = CurrentDevice;
+ CurrentDevice = null;
+ return device;
+}
+
+/**
+ * Constructs a new instance of this class.
+ * <p>
+ * You must dispose the device when it is no longer required.
+ * </p>
+ *
+ * @see #create
+ * @see #init
+ *
+ * @since 3.1
+ */
+public Device() {
+ this(null);
+}
+
+/**
+ * Constructs a new instance of this class.
+ * <p>
+ * You must dispose the device when it is no longer required.
+ * </p>
+ *
+ * @param data the DeviceData which describes the receiver
+ *
+ * @see #create
+ * @see #init
+ * @see DeviceData
+ */
+public Device(DeviceData data) {
+ synchronized (Device.class) {
+ if (data != null) {
+ debug = data.debug;
+ tracking = data.tracking;
+ }
+ if (tracking) {
+ errors = new Error [128];
+ objects = new Object [128];
+ trackingLock = new Object ();
+ }
+ if (NSThread.isMainThread()) {
+ NSAutoreleasePool pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ NSThread nsthread = NSThread.currentThread();
+ NSMutableDictionary dictionary = nsthread.threadDictionary();
+ NSString key = NSString.stringWith("SWT_NSAutoreleasePool");
+ id obj = dictionary.objectForKey(key);
+ if (obj == null) {
+ NSNumber nsnumber = NSNumber.numberWithInteger(pool.id);
+ dictionary.setObject(nsnumber, key);
+ } else {
+ pool.release();
+ }
+ }
+ //check and create pool
+ create (data);
+ init ();
+ }
+}
+
+/**
+ * Throws an <code>SWTException</code> if the receiver can not
+ * be accessed by the caller. This may include both checks on
+ * the state of the receiver and more generally on the entire
+ * execution context. This method <em>should</em> be called by
+ * device implementors to enforce the standard SWT invariants.
+ * <p>
+ * Currently, it is an error to invoke any method (other than
+ * <code>isDisposed()</code> and <code>dispose()</code>) on a
+ * device that has had its <code>dispose()</code> method called.
+ * </p><p>
+ * In future releases of SWT, there may be more or fewer error
+ * checks and exceptions may be thrown for different reasons.
+ * <p>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+protected void checkDevice () {
+ if (disposed) SWT.error(SWT.ERROR_DEVICE_DISPOSED);
+}
+
+/**
+ * Creates the device in the operating system. If the device
+ * does not have a handle, this method may do nothing depending
+ * on the device.
+ * <p>
+ * This method is called before <code>init</code>.
+ * </p><p>
+ * Subclasses are supposed to reimplement this method and not
+ * call the <code>super</code> implementation.
+ * </p>
+ *
+ * @param data the DeviceData which describes the receiver
+ *
+ * @see #init
+ */
+protected void create (DeviceData data) {
+}
+
+/**
+ * Disposes of the operating system resources associated with
+ * the receiver. After this method has been invoked, the receiver
+ * will answer <code>true</code> when sent the message
+ * <code>isDisposed()</code>.
+ *
+ * @see #release
+ * @see #destroy
+ * @see #checkDevice
+ */
+public void dispose () {
+ synchronized (Device.class) {
+ if (isDisposed()) return;
+ checkDevice ();
+ release ();
+ destroy ();
+ disposed = true;
+ if (tracking) {
+ synchronized (trackingLock) {
+ printErrors ();
+ objects = null;
+ errors = null;
+ trackingLock = null;
+ }
+ }
+ }
+}
+
+void dispose_Object (Object object) {
+ synchronized (trackingLock) {
+ for (int i=0; i<objects.length; i++) {
+ if (objects [i] == object) {
+ objects [i] = null;
+ errors [i] = null;
+ return;
+ }
+ }
+ }
+}
+
+/**
+ * Destroys the device in the operating system and releases
+ * the device's handle. If the device does not have a handle,
+ * this method may do nothing depending on the device.
+ * <p>
+ * This method is called after <code>release</code>.
+ * </p><p>
+ * Subclasses are supposed to reimplement this method and not
+ * call the <code>super</code> implementation.
+ * </p>
+ *
+ * @see #dispose
+ * @see #release
+ */
+protected void destroy () {
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location.
+ *
+ * @return the bounding rectangle
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Rectangle getBounds () {
+ checkDevice ();
+ NSRect frame = getPrimaryScreen().frame();
+ return new Rectangle((int)frame.x, (int)frame.y, (int)frame.width, (int)frame.height);
+}
+
+/**
+ * Returns a <code>DeviceData</code> based on the receiver.
+ * Modifications made to this <code>DeviceData</code> will not
+ * affect the receiver.
+ *
+ * @return a <code>DeviceData</code> containing the device's data and attributes
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see DeviceData
+ */
+public DeviceData getDeviceData () {
+ checkDevice();
+ DeviceData data = new DeviceData ();
+ data.debug = debug;
+ data.tracking = tracking;
+ if (tracking) {
+ synchronized (trackingLock) {
+ int count = 0, length = objects.length;
+ for (int i=0; i<length; i++) {
+ if (objects [i] != null) count++;
+ }
+ int index = 0;
+ data.objects = new Object [count];
+ data.errors = new Error [count];
+ for (int i=0; i<length; i++) {
+ if (objects [i] != null) {
+ data.objects [index] = objects [i];
+ data.errors [index] = errors [i];
+ index++;
+ }
+ }
+ }
+ } else {
+ data.objects = new Object [0];
+ data.errors = new Error [0];
+ }
+ return data;
+}
+
+/**
+ * Returns a rectangle which describes the area of the
+ * receiver which is capable of displaying data.
+ *
+ * @return the client area
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getBounds
+ */
+public Rectangle getClientArea () {
+ checkDevice ();
+ return getBounds ();
+}
+
+/**
+ * Returns the bit depth of the screen, which is the number of
+ * bits it takes to represent the number of unique colors that
+ * the screen is currently capable of displaying. This number
+ * will typically be one of 1, 8, 15, 16, 24 or 32.
+ *
+ * @return the depth of the screen
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getDepth () {
+ checkDevice ();
+ return (int)/*64*/OS.NSBitsPerPixelFromDepth(getPrimaryScreen().depth());
+}
+
+/**
+ * Returns a point whose x coordinate is the horizontal
+ * dots per inch of the display, and whose y coordinate
+ * is the vertical dots per inch of the display.
+ *
+ * @return the horizontal and vertical DPI
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Point getDPI () {
+ checkDevice ();
+ return getScreenDPI();
+}
+
+NSScreen getPrimaryScreen () {
+ NSArray screens = NSScreen.screens();
+ return new NSScreen(screens.objectAtIndex(0));
+}
+
+/**
+ * Returns <code>FontData</code> objects which describe
+ * the fonts that match the given arguments. If the
+ * <code>faceName</code> is null, all fonts will be returned.
+ *
+ * @param faceName the name of the font to look for, or null
+ * @param scalable if true only scalable fonts are returned, otherwise only non-scalable fonts are returned.
+ * @return the matching font data
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public FontData[] getFontList (String faceName, boolean scalable) {
+ checkDevice ();
+ if (!scalable) return new FontData[0];
+ int count = 0;
+ NSArray families = NSFontManager.sharedFontManager().availableFontFamilies();
+ int /*long*/ familyCount = families.count();
+ FontData[] fds = new FontData[100];
+ for (int i = 0; i < familyCount; i++) {
+ NSString nsFamily = new NSString(families.objectAtIndex(i));
+ String name = nsFamily.getString();
+ NSArray fonts = NSFontManager.sharedFontManager().availableMembersOfFontFamily(nsFamily);
+ int fontCount = (int)/*64*/fonts.count();
+ for (int j = 0; j < fontCount; j++) {
+ NSArray fontDetails = new NSArray(fonts.objectAtIndex(j));
+ String nsName = new NSString(fontDetails.objectAtIndex(0)).getString();
+ int /*long*/ weight = new NSNumber(fontDetails.objectAtIndex(2)).integerValue();
+ int /*long*/ traits = new NSNumber(fontDetails.objectAtIndex(3)).integerValue();
+ int style = SWT.NORMAL;
+ if ((traits & OS.NSItalicFontMask) != 0) style |= SWT.ITALIC;
+ if (weight == 9) style |= SWT.BOLD;
+ if (faceName == null || Compatibility.equalsIgnoreCase(faceName, name)) {
+ FontData data = new FontData(name, 0, style);
+ data.nsName = nsName;
+ if (count == fds.length) {
+ FontData[] newFds = new FontData[fds.length + 100];
+ System.arraycopy(fds, 0, newFds, 0, fds.length);
+ fds = newFds;
+ }
+ fds[count++] = data;
+ }
+ }
+ }
+ if (count == fds.length) return fds;
+ FontData[] result = new FontData[count];
+ System.arraycopy(fds, 0, result, 0, count);
+ return result;
+}
+
+Point getScreenDPI () {
+ NSDictionary dictionary = getPrimaryScreen().deviceDescription();
+ NSValue value = new NSValue(dictionary.objectForKey(new id(OS.NSDeviceResolution())).id);
+ NSSize size = value.sizeValue();
+ return new Point((int)size.width, (int)size.height);
+}
+
+/**
+ * Returns the matching standard color for the given
+ * constant, which should be one of the color constants
+ * specified in class <code>SWT</code>. Any value other
+ * than one of the SWT color constants which is passed
+ * in will result in the color black. This color should
+ * not be freed because it was allocated by the system,
+ * not the application.
+ *
+ * @param id the color constant
+ * @return the matching color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see SWT
+ */
+public Color getSystemColor (int id) {
+ checkDevice ();
+ switch (id) {
+ case SWT.COLOR_BLACK: return COLOR_BLACK;
+ case SWT.COLOR_DARK_RED: return COLOR_DARK_RED;
+ case SWT.COLOR_DARK_GREEN: return COLOR_DARK_GREEN;
+ case SWT.COLOR_DARK_YELLOW: return COLOR_DARK_YELLOW;
+ case SWT.COLOR_DARK_BLUE: return COLOR_DARK_BLUE;
+ case SWT.COLOR_DARK_MAGENTA: return COLOR_DARK_MAGENTA;
+ case SWT.COLOR_DARK_CYAN: return COLOR_DARK_CYAN;
+ case SWT.COLOR_GRAY: return COLOR_GRAY;
+ case SWT.COLOR_DARK_GRAY: return COLOR_DARK_GRAY;
+ case SWT.COLOR_RED: return COLOR_RED;
+ case SWT.COLOR_GREEN: return COLOR_GREEN;
+ case SWT.COLOR_YELLOW: return COLOR_YELLOW;
+ case SWT.COLOR_BLUE: return COLOR_BLUE;
+ case SWT.COLOR_MAGENTA: return COLOR_MAGENTA;
+ case SWT.COLOR_CYAN: return COLOR_CYAN;
+ case SWT.COLOR_WHITE: return COLOR_WHITE;
+ }
+ return COLOR_BLACK;
+}
+
+/**
+ * Returns a reasonable font for applications to use.
+ * On some platforms, this will match the "default font"
+ * or "system font" if such can be found. This font
+ * should not be freed because it was allocated by the
+ * system, not the application.
+ * <p>
+ * Typically, applications which want the default look
+ * should simply not set the font on the widgets they
+ * create. Widgets are always created with the correct
+ * default font for the class of user-interface component
+ * they represent.
+ * </p>
+ *
+ * @return a font
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Font getSystemFont () {
+ checkDevice ();
+ return systemFont;
+}
+
+/**
+ * Returns <code>true</code> if the underlying window system prints out
+ * warning messages on the console, and <code>setWarnings</code>
+ * had previously been called with <code>true</code>.
+ *
+ * @return <code>true</code>if warnings are being handled, and <code>false</code> otherwise
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean getWarnings () {
+ checkDevice ();
+ return warnings;
+}
+
+/**
+ * Initializes any internal resources needed by the
+ * device.
+ * <p>
+ * This method is called after <code>create</code>.
+ * </p><p>
+ * If subclasses reimplement this method, they must
+ * call the <code>super</code> implementation.
+ * </p>
+ *
+ * @see #create
+ */
+protected void init () {
+ /* Create the standard colors */
+ COLOR_BLACK = new Color (this, 0,0,0);
+ COLOR_DARK_RED = new Color (this, 0x80,0,0);
+ COLOR_DARK_GREEN = new Color (this, 0,0x80,0);
+ COLOR_DARK_YELLOW = new Color (this, 0x80,0x80,0);
+ COLOR_DARK_BLUE = new Color (this, 0,0,0x80);
+ COLOR_DARK_MAGENTA = new Color (this, 0x80,0,0x80);
+ COLOR_DARK_CYAN = new Color (this, 0,0x80,0x80);
+ COLOR_GRAY = new Color (this, 0xC0,0xC0,0xC0);
+ COLOR_DARK_GRAY = new Color (this, 0x80,0x80,0x80);
+ COLOR_RED = new Color (this, 0xFF,0,0);
+ COLOR_GREEN = new Color (this, 0,0xFF,0);
+ COLOR_YELLOW = new Color (this, 0xFF,0xFF,0);
+ COLOR_BLUE = new Color (this, 0,0,0xFF);
+ COLOR_MAGENTA = new Color (this, 0xFF,0,0xFF);
+ COLOR_CYAN = new Color (this, 0,0xFF,0xFF);
+ COLOR_WHITE = new Color (this, 0xFF,0xFF,0xFF);
+
+ paragraphStyle = (NSMutableParagraphStyle)new NSMutableParagraphStyle().alloc().init();
+ paragraphStyle.setAlignment(OS.NSLeftTextAlignment);
+ paragraphStyle.setLineBreakMode(OS.NSLineBreakByClipping);
+ NSArray tabs = new NSArray(new NSArray().alloc().init());
+ paragraphStyle.setTabStops(tabs);
+ tabs.release();
+
+ /* Initialize the system font slot */
+ boolean smallFonts = System.getProperty("org.eclipse.swt.internal.carbon.smallFonts") != null;
+ float /*double*/ systemFontSize = smallFonts ? NSFont.smallSystemFontSize() : NSFont.systemFontSize();
+ Point dpi = this.dpi = getDPI(), screenDPI = getScreenDPI();
+ NSFont font = NSFont.systemFontOfSize(systemFontSize * dpi.y / screenDPI.y);
+ font.retain();
+ systemFont = Font.cocoa_new(this, font);
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Device</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param data the platform specific GC data
+ * @return the platform specific GC handle
+ */
+public abstract int /*long*/ internal_new_GC (GCData data);
+
+/**
+ * Invokes platform specific functionality to dispose a GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Device</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param hDC the platform specific GC handle
+ * @param data the platform specific GC data
+ */
+public abstract void internal_dispose_GC (int /*long*/ handle, GCData data);
+
+/**
+ * Returns <code>true</code> if the device has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the device.
+ * When a device has been disposed, it is an error to
+ * invoke any other method using the device.
+ *
+ * @return <code>true</code> when the device is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed () {
+ synchronized (Device.class) {
+ return disposed;
+ }
+}
+
+/**
+ * Loads the font specified by a file. The font will be
+ * present in the list of fonts available to the application.
+ *
+ * @param path the font file path
+ * @return whether the font was successfully loaded
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if path is null</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Font
+ *
+ * @since 3.3
+ */
+public boolean loadFont (String path) {
+ checkDevice();
+ if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ boolean result = false;
+ NSString nsPath = NSString.stringWith(path);
+ int /*long*/ fsRepresentation = nsPath.fileSystemRepresentation();
+
+ if (fsRepresentation != 0) {
+ byte [] fsRef = new byte [80];
+ boolean [] isDirectory = new boolean[1];
+ if (OS.FSPathMakeRef (fsRepresentation, fsRef, isDirectory) == OS.noErr) {
+ result = OS.ATSFontActivateFromFileReference (fsRef, OS.kATSFontContextLocal, OS.kATSFontFormatUnspecified, 0, OS.kATSOptionFlagsDefault, null) == OS.noErr;
+ }
+ }
+
+ return result;
+}
+
+void new_Object (Object object) {
+ synchronized (trackingLock) {
+ for (int i=0; i<objects.length; i++) {
+ if (objects [i] == null) {
+ objects [i] = object;
+ errors [i] = new Error ();
+ return;
+ }
+ }
+ Object [] newObjects = new Object [objects.length + 128];
+ System.arraycopy (objects, 0, newObjects, 0, objects.length);
+ newObjects [objects.length] = object;
+ objects = newObjects;
+ Error [] newErrors = new Error [errors.length + 128];
+ System.arraycopy (errors, 0, newErrors, 0, errors.length);
+ newErrors [errors.length] = new Error ();
+ errors = newErrors;
+ }
+}
+
+void printErrors () {
+ if (!DEBUG) return;
+ if (tracking) {
+ synchronized (trackingLock) {
+ if (objects == null || errors == null) return;
+ int objectCount = 0;
+ int colors = 0, cursors = 0, fonts = 0, gcs = 0, images = 0;
+ int paths = 0, patterns = 0, regions = 0, textLayouts = 0, transforms = 0;
+ for (int i=0; i<objects.length; i++) {
+ Object object = objects [i];
+ if (object != null) {
+ objectCount++;
+ if (object instanceof Color) colors++;
+ if (object instanceof Cursor) cursors++;
+ if (object instanceof Font) fonts++;
+ if (object instanceof GC) gcs++;
+ if (object instanceof Image) images++;
+ if (object instanceof Path) paths++;
+ if (object instanceof Pattern) patterns++;
+ if (object instanceof Region) regions++;
+ if (object instanceof TextLayout) textLayouts++;
+ if (object instanceof Transform) transforms++;
+ }
+ }
+ if (objectCount != 0) {
+ String string = "Summary: ";
+ if (colors != 0) string += colors + " Color(s), ";
+ if (cursors != 0) string += cursors + " Cursor(s), ";
+ if (fonts != 0) string += fonts + " Font(s), ";
+ if (gcs != 0) string += gcs + " GC(s), ";
+ if (images != 0) string += images + " Image(s), ";
+ if (paths != 0) string += paths + " Path(s), ";
+ if (patterns != 0) string += patterns + " Pattern(s), ";
+ if (regions != 0) string += regions + " Region(s), ";
+ if (textLayouts != 0) string += textLayouts + " TextLayout(s), ";
+ if (transforms != 0) string += transforms + " Transforms(s), ";
+ if (string.length () != 0) {
+ string = string.substring (0, string.length () - 2);
+ System.out.println (string);
+ }
+ for (int i=0; i<errors.length; i++) {
+ if (errors [i] != null) errors [i].printStackTrace (System.out);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Releases any internal resources back to the operating
+ * system and clears all fields except the device handle.
+ * <p>
+ * When a device is destroyed, resources that were acquired
+ * on behalf of the programmer need to be returned to the
+ * operating system. For example, if the device allocated a
+ * font to be used as the system font, this font would be
+ * freed in <code>release</code>. Also,to assist the garbage
+ * collector and minimize the amount of memory that is not
+ * reclaimed when the programmer keeps a reference to a
+ * disposed device, all fields except the handle are zero'd.
+ * The handle is needed by <code>destroy</code>.
+ * </p>
+ * This method is called before <code>destroy</code>.
+ * </p><p>
+ * If subclasses reimplement this method, they must
+ * call the <code>super</code> implementation.
+ * </p>
+ *
+ * @see #dispose
+ * @see #destroy
+ */
+protected void release () {
+ if (paragraphStyle != null) paragraphStyle.release();
+ paragraphStyle = null;
+
+ if (systemFont != null) systemFont.dispose();
+ systemFont = null;
+
+ if (COLOR_BLACK != null) COLOR_BLACK.dispose();
+ if (COLOR_DARK_RED != null) COLOR_DARK_RED.dispose();
+ if (COLOR_DARK_GREEN != null) COLOR_DARK_GREEN.dispose();
+ if (COLOR_DARK_YELLOW != null) COLOR_DARK_YELLOW.dispose();
+ if (COLOR_DARK_BLUE != null) COLOR_DARK_BLUE.dispose();
+ if (COLOR_DARK_MAGENTA != null) COLOR_DARK_MAGENTA.dispose();
+ if (COLOR_DARK_CYAN != null) COLOR_DARK_CYAN.dispose();
+ if (COLOR_GRAY != null) COLOR_GRAY.dispose();
+ if (COLOR_DARK_GRAY != null) COLOR_DARK_GRAY.dispose();
+ if (COLOR_RED != null) COLOR_RED.dispose();
+ if (COLOR_GREEN != null) COLOR_GREEN.dispose();
+ if (COLOR_YELLOW != null) COLOR_YELLOW.dispose();
+ if (COLOR_BLUE != null) COLOR_BLUE.dispose();
+ if (COLOR_MAGENTA != null) COLOR_MAGENTA.dispose();
+ if (COLOR_CYAN != null) COLOR_CYAN.dispose();
+ if (COLOR_WHITE != null) COLOR_WHITE.dispose();
+ COLOR_BLACK = COLOR_DARK_RED = COLOR_DARK_GREEN = COLOR_DARK_YELLOW = COLOR_DARK_BLUE =
+ COLOR_DARK_MAGENTA = COLOR_DARK_CYAN = COLOR_GRAY = COLOR_DARK_GRAY = COLOR_RED =
+ COLOR_GREEN = COLOR_YELLOW = COLOR_BLUE = COLOR_MAGENTA = COLOR_CYAN = COLOR_WHITE = null;
+}
+
+/**
+ * If the underlying window system supports printing warning messages
+ * to the console, setting warnings to <code>false</code> prevents these
+ * messages from being printed. If the argument is <code>true</code> then
+ * message printing is not blocked.
+ *
+ * @param warnings <code>true</code>if warnings should be printed, and <code>false</code> otherwise
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setWarnings (boolean warnings) {
+ checkDevice ();
+ this.warnings = warnings;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/DeviceData.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/DeviceData.java
new file mode 100755
index 0000000000..ad0c2b2afe
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/DeviceData.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+public class DeviceData {
+ /*
+ * Debug fields - may not be honoured
+ * on some SWT platforms.
+ */
+ public boolean debug;
+ public boolean tracking;
+ public Error [] errors;
+ public Object [] objects;
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Font.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Font.java
new file mode 100755
index 0000000000..b30ab417f2
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Font.java
@@ -0,0 +1,370 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+import org.eclipse.swt.*;
+
+/**
+ * Instances of this class manage operating system resources that
+ * define how text looks when it is displayed. Fonts may be constructed
+ * by providing a device and either name, size and style information
+ * or a <code>FontData</code> object which encapsulates this data.
+ * <p>
+ * Application code must explicitly invoke the <code>Font.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ *
+ * @see FontData
+ * @see <a href="http://www.eclipse.org/swt/snippets/#font">Font snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: GraphicsExample, PaintExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+public final class Font extends Resource {
+
+ /**
+ * the handle to the OS font resource
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public NSFont handle;
+
+ /**
+ * the traits not supported to the OS font resource
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public int extraTraits;
+
+ static final double SYNTHETIC_BOLD = -2.5;
+ static final double SYNTHETIC_ITALIC = 0.2;
+
+Font(Device device) {
+ super(device);
+}
+
+/**
+ * Constructs a new font given a device and font data
+ * which describes the desired font's appearance.
+ * <p>
+ * You must dispose the font when it is no longer required.
+ * </p>
+ *
+ * @param device the device to create the font on
+ * @param fd the FontData that describes the desired font (must not be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the fd argument is null</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES - if a font could not be created from the given font data</li>
+ * </ul>
+ */
+public Font(Device device, FontData fd) {
+ super(device);
+ if (fd == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ init(fd.getName(), fd.getHeightF(), fd.getStyle(), fd.nsName);
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Constructs a new font given a device and an array
+ * of font data which describes the desired font's
+ * appearance.
+ * <p>
+ * You must dispose the font when it is no longer required.
+ * </p>
+ *
+ * @param device the device to create the font on
+ * @param fds the array of FontData that describes the desired font (must not be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the fds argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the length of fds is zero</li>
+ * <li>ERROR_NULL_ARGUMENT - if any fd in the array is null</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES - if a font could not be created from the given font data</li>
+ * </ul>
+ *
+ * @since 2.1
+ */
+public Font(Device device, FontData[] fds) {
+ super(device);
+ if (fds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (fds.length == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ for (int i=0; i<fds.length; i++) {
+ if (fds[i] == null) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ FontData fd = fds[0];
+ init(fd.getName(), fd.getHeightF(), fd.getStyle(), fd.nsName);
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Constructs a new font given a device, a font name,
+ * the height of the desired font in points, and a font
+ * style.
+ * <p>
+ * You must dispose the font when it is no longer required.
+ * </p>
+ *
+ * @param device the device to create the font on
+ * @param name the name of the font (must not be null)
+ * @param height the font height in points
+ * @param style a bit or combination of NORMAL, BOLD, ITALIC
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the name argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the height is negative</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES - if a font could not be created from the given arguments</li>
+ * </ul>
+ */
+public Font(Device device, String name, int height, int style) {
+ super(device);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ init(name, height, style, null);
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/*public*/ Font(Device device, String name, float height, int style) {
+ super(device);
+ init(name, height, style, null);
+ init();
+}
+
+void addTraits(NSMutableAttributedString attrStr, NSRange range) {
+ if ((extraTraits & OS.NSBoldFontMask) != 0) {
+ attrStr.addAttribute(OS.NSStrokeWidthAttributeName, NSNumber.numberWithDouble(SYNTHETIC_BOLD), range);
+ }
+ if ((extraTraits & OS.NSItalicFontMask) != 0) {
+ attrStr.addAttribute(OS.NSObliquenessAttributeName, NSNumber.numberWithDouble(SYNTHETIC_ITALIC), range);
+ }
+}
+
+void addTraits(NSMutableDictionary dict) {
+ if ((extraTraits & OS.NSBoldFontMask) != 0) {
+ dict.setObject(NSNumber.numberWithDouble(SYNTHETIC_BOLD), OS.NSStrokeWidthAttributeName);
+ }
+ if ((extraTraits & OS.NSItalicFontMask) != 0) {
+ dict.setObject(NSNumber.numberWithDouble(SYNTHETIC_ITALIC), OS.NSObliquenessAttributeName);
+ }
+}
+
+void destroy() {
+ handle.release();
+ handle = null;
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the <em>same</em> object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
+ *
+ * @see #hashCode
+ */
+public boolean equals(Object object) {
+ if (object == this) return true;
+ if (!(object instanceof Font)) return false;
+ Font font = (Font)object;
+ return handle == font.handle;
+}
+
+/**
+ * Returns an array of <code>FontData</code>s representing the receiver.
+ * On Windows, only one FontData will be returned per font. On X however,
+ * a <code>Font</code> object <em>may</em> be composed of multiple X
+ * fonts. To support this case, we return an array of font data objects.
+ *
+ * @return an array of font data objects describing the receiver
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public FontData[] getFontData() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSString family = handle.familyName();
+ String name = family.getString();
+ NSString str = handle.fontName();
+ String nsName = str.getString();
+ NSFontManager manager = NSFontManager.sharedFontManager();
+ int /*long*/ traits = manager.traitsOfFont(handle);
+ int style = SWT.NORMAL;
+ if ((traits & OS.NSItalicFontMask) != 0) style |= SWT.ITALIC;
+ if ((traits & OS.NSBoldFontMask) != 0) style |= SWT.BOLD;
+ if ((extraTraits & OS.NSItalicFontMask) != 0) style |= SWT.ITALIC;
+ if ((extraTraits & OS.NSBoldFontMask) != 0) style |= SWT.BOLD;
+ Point dpi = device.dpi, screenDPI = device.getScreenDPI();
+ FontData data = new FontData(name, (float)/*64*/handle.pointSize() * screenDPI.y / dpi.y, style);
+ data.nsName = nsName;
+ return new FontData[]{data};
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new font.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Font</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param device the device on which to allocate the color
+ * @param handle the handle for the font
+ * @param style the style for the font
+ * @param size the size for the font
+ *
+ * @private
+ */
+public static Font cocoa_new(Device device, NSFont handle) {
+ Font font = new Font(device);
+ font.handle = handle;
+ return font;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return <code>true</code> when passed to
+ * <code>equals</code> must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+public int hashCode() {
+ return handle != null ? (int)/*64*/handle.id : 0;
+}
+
+void init(String name, float height, int style, String nsName) {
+ if (name == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ Point dpi = device.dpi, screenDPI = device.getScreenDPI();
+ float size = height * dpi.y / screenDPI.y;
+ if (nsName != null) {
+ handle = NSFont.fontWithName(NSString.stringWith(nsName), size);
+ } else {
+ NSString family = NSString.stringWith(name);
+ NSFont nsFont = NSFont.fontWithName(family, size);
+ if (nsFont == null) nsFont = NSFont.systemFontOfSize(size);
+ NSFontManager manager = NSFontManager.sharedFontManager();
+ if (nsFont != null) {
+ if ((style & (SWT.BOLD | SWT.ITALIC)) == 0) {
+ handle = nsFont;
+ } else {
+ int traits = 0;
+ if ((style & SWT.ITALIC) != 0) traits |= OS.NSItalicFontMask;
+ if ((style & SWT.BOLD) != 0) traits |= OS.NSBoldFontMask;
+ handle = manager.convertFont(nsFont, traits);
+ if ((style & SWT.ITALIC) != 0 && (handle == null || (manager.traitsOfFont(handle) & OS.NSItalicFontMask) == 0)) {
+ traits &= ~OS.NSItalicFontMask;
+ handle = null;
+ if ((style & SWT.BOLD) != 0) {
+ handle = manager.convertFont(nsFont, traits);
+ }
+ }
+ if ((style & SWT.BOLD) != 0 && handle == null) {
+ traits &= ~OS.NSBoldFontMask;
+ if ((style & SWT.ITALIC) != 0) {
+ traits |= OS.NSItalicFontMask;
+ handle = manager.convertFont(nsFont, traits);
+ }
+ }
+ if (handle == null) handle = nsFont;
+ }
+ }
+ if (handle == null) {
+ handle = NSFont.systemFontOfSize(size);
+ }
+ if ((style & SWT.ITALIC) != 0 && (manager.traitsOfFont(handle) & OS.NSItalicFontMask) == 0) {
+ extraTraits |= OS.NSItalicFontMask;
+ }
+ if ((style & SWT.BOLD) != 0 && (manager.traitsOfFont(handle) & OS.NSBoldFontMask) == 0) {
+ extraTraits |= OS.NSBoldFontMask;
+ }
+ }
+ if (handle == null) {
+ handle = device.systemFont.handle;
+ }
+ handle.retain();
+}
+
+/**
+ * Returns <code>true</code> if the font has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the font.
+ * When a font has been disposed, it is an error to
+ * invoke any other method using the font.
+ *
+ * @return <code>true</code> when the font is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return handle == null;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+public String toString () {
+ if (isDisposed()) return "Font {*DISPOSED*}";
+ return "Font {" + handle + "}";
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/FontData.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/FontData.java
new file mode 100755
index 0000000000..589f151ebe
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/FontData.java
@@ -0,0 +1,447 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.*;
+
+/**
+ * Instances of this class describe operating system fonts.
+ * <p>
+ * For platform-independent behaviour, use the get and set methods
+ * corresponding to the following properties:
+ * <dl>
+ * <dt>height</dt><dd>the height of the font in points</dd>
+ * <dt>name</dt><dd>the face name of the font, which may include the foundry</dd>
+ * <dt>style</dt><dd>A bitwise combination of NORMAL, ITALIC and BOLD</dd>
+ * </dl>
+ * If extra, platform-dependent functionality is required:
+ * <ul>
+ * <li>On <em>Windows</em>, the data member of the <code>FontData</code>
+ * corresponds to a Windows <code>LOGFONT</code> structure whose fields
+ * may be retrieved and modified.</li>
+ * <li>On <em>X</em>, the fields of the <code>FontData</code> correspond
+ * to the entries in the font's XLFD name and may be retrieved and modified.
+ * </ul>
+ * Application code does <em>not</em> need to explicitly release the
+ * resources managed by each instance when those instances are no longer
+ * required, and thus no <code>dispose()</code> method is provided.
+ *
+ * @see Font
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+public final class FontData {
+ /**
+ * the font name
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public String name;
+
+ /**
+ * The height of the font data in points
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public float height;
+
+ /**
+ * the font style
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public int style;
+
+ /**
+ * the NSFont font name
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public String nsName;
+
+ /**
+ * The locales of the font
+ */
+ String lang, country, variant;
+
+/**
+ * Constructs a new uninitialized font data.
+ */
+public FontData () {
+ this("", 12, SWT.NORMAL);
+}
+
+/**
+ * Constructs a new FontData given a string representation
+ * in the form generated by the <code>FontData.toString</code>
+ * method.
+ * <p>
+ * Note that the representation varies between platforms,
+ * and a FontData can only be created from a string that was
+ * generated on the same platform.
+ * </p>
+ *
+ * @param string the string representation of a <code>FontData</code> (must not be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument does not represent a valid description</li>
+ * </ul>
+ *
+ * @see #toString
+ */
+public FontData(String string) {
+ if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ int start = 0;
+ int end = string.indexOf('|');
+ if (end == -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ String version1 = string.substring(start, end);
+ try {
+ if (Integer.parseInt(version1) != 1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ } catch (NumberFormatException e) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ String name = string.substring(start, end);
+
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ float height = 0;
+ try {
+ height = Float.parseFloat(string.substring(start, end));
+ } catch (NumberFormatException e) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ int style = 0;
+ try {
+ style = Integer.parseInt(string.substring(start, end));
+ } catch (NumberFormatException e) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+
+ start = end + 1;
+ end = string.indexOf('|', start);
+ setName(name);
+ setHeight(height);
+ setStyle(style);
+ if (end == -1) return;
+ String platform = string.substring(start, end);
+
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) return;
+ String version2 = string.substring(start, end);
+
+ if (platform.equals("COCOA") && version2.equals("1")) {
+ start = end + 1;
+ end = string.length();
+ if (start < end) nsName = string.substring(start, end);
+ }
+}
+
+/**
+ * Constructs a new font data given a font name,
+ * the height of the desired font in points,
+ * and a font style.
+ *
+ * @param name the name of the font (must not be null)
+ * @param height the font height in points
+ * @param style a bit or combination of NORMAL, BOLD, ITALIC
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - when the font name is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the height is negative</li>
+ * </ul>
+ */
+public FontData(String name, int height, int style) {
+ setName(name);
+ setHeight(height);
+ setStyle(style);
+}
+
+/*public*/ FontData(String name, float height, int style) {
+ setName(name);
+ setHeight(height);
+ setStyle(style);
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the <em>same</em> object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
+ *
+ * @see #hashCode
+ */
+public boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof FontData)) return false;
+ FontData data = (FontData)object;
+ return name.equals(data.name) && height == data.height && style == data.style;
+}
+
+/**
+ * Returns the height of the receiver in points.
+ *
+ * @return the height of this FontData
+ *
+ * @see #setHeight(int)
+ */
+public int getHeight() {
+ return (int)height;
+}
+
+/*public*/ float getHeightF() {
+ return height;
+}
+
+/**
+ * Returns the locale of the receiver.
+ * <p>
+ * The locale determines which platform character set this
+ * font is going to use. Widgets and graphics operations that
+ * use this font will convert UNICODE strings to the platform
+ * character set of the specified locale.
+ * </p>
+ * <p>
+ * On platforms where there are multiple character sets for a
+ * given language/country locale, the variant portion of the
+ * locale will determine the character set.
+ * </p>
+ *
+ * @return the <code>String</code> representing a Locale object
+ * @since 3.0
+ */
+public String getLocale () {
+ StringBuffer buffer = new StringBuffer ();
+ char sep = '_';
+ if (lang != null) {
+ buffer.append (lang);
+ buffer.append (sep);
+ }
+ if (country != null) {
+ buffer.append (country);
+ buffer.append (sep);
+ }
+ if (variant != null) {
+ buffer.append (variant);
+ }
+
+ String result = buffer.toString ();
+ int length = result.length ();
+ if (length > 0) {
+ if (result.charAt (length - 1) == sep) {
+ result = result.substring (0, length - 1);
+ }
+ }
+ return result;
+}
+
+/**
+ * Returns the name of the receiver.
+ * On platforms that support font foundries, the return value will
+ * be the foundry followed by a dash ("-") followed by the face name.
+ *
+ * @return the name of this <code>FontData</code>
+ *
+ * @see #setName
+ */
+public String getName() {
+ return name;
+}
+
+/**
+ * Returns the style of the receiver which is a bitwise OR of
+ * one or more of the <code>SWT</code> constants NORMAL, BOLD
+ * and ITALIC.
+ *
+ * @return the style of this <code>FontData</code>
+ *
+ * @see #setStyle
+ */
+public int getStyle() {
+ return style;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return <code>true</code> when passed to
+ * <code>equals</code> must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+public int hashCode () {
+ return name.hashCode() ^ getHeight() ^ style;
+}
+
+/**
+ * Sets the height of the receiver. The parameter is
+ * specified in terms of points, where a point is one
+ * seventy-second of an inch.
+ *
+ * @param height the height of the <code>FontData</code>
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the height is negative</li>
+ * </ul>
+ *
+ * @see #getHeight
+ */
+public void setHeight(int height) {
+ if (height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ this.height = height;
+}
+
+/*public*/ void setHeight(float height) {
+ if (height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ this.height = height;
+}
+
+/**
+ * Sets the locale of the receiver.
+ * <p>
+ * The locale determines which platform character set this
+ * font is going to use. Widgets and graphics operations that
+ * use this font will convert UNICODE strings to the platform
+ * character set of the specified locale.
+ * </p>
+ * <p>
+ * On platforms where there are multiple character sets for a
+ * given language/country locale, the variant portion of the
+ * locale will determine the character set.
+ * </p>
+ *
+ * @param locale the <code>String</code> representing a Locale object
+ * @see java.util.Locale#toString
+ */
+public void setLocale(String locale) {
+ lang = country = variant = null;
+ if (locale != null) {
+ char sep = '_';
+ int length = locale.length();
+ int firstSep, secondSep;
+
+ firstSep = locale.indexOf(sep);
+ if (firstSep == -1) {
+ firstSep = secondSep = length;
+ } else {
+ secondSep = locale.indexOf(sep, firstSep + 1);
+ if (secondSep == -1) secondSep = length;
+ }
+ if (firstSep > 0) lang = locale.substring(0, firstSep);
+ if (secondSep > firstSep + 1) country = locale.substring(firstSep + 1, secondSep);
+ if (length > secondSep + 1) variant = locale.substring(secondSep + 1);
+ }
+}
+
+/**
+ * Sets the name of the receiver.
+ * <p>
+ * Some platforms support font foundries. On these platforms, the name
+ * of the font specified in setName() may have one of the following forms:
+ * <ol>
+ * <li>a face name (for example, "courier")</li>
+ * <li>a foundry followed by a dash ("-") followed by a face name (for example, "adobe-courier")</li>
+ * </ol>
+ * In either case, the name returned from getName() will include the
+ * foundry.
+ * </p>
+ * <p>
+ * On platforms that do not support font foundries, only the face name
+ * (for example, "courier") is used in <code>setName()</code> and
+ * <code>getName()</code>.
+ * </p>
+ *
+ * @param name the name of the font data (must not be null)
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - when the font name is null</li>
+ * </ul>
+ *
+ * @see #getName
+ */
+public void setName(String name) {
+ if (name == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ this.name = name;
+ nsName = null;
+}
+
+/**
+ * Sets the style of the receiver to the argument which must
+ * be a bitwise OR of one or more of the <code>SWT</code>
+ * constants NORMAL, BOLD and ITALIC. All other style bits are
+ * ignored.
+ *
+ * @param style the new style for this <code>FontData</code>
+ *
+ * @see #getStyle
+ */
+public void setStyle(int style) {
+ this.style = style;
+ nsName = null;
+}
+
+/**
+ * Returns a string representation of the receiver which is suitable
+ * for constructing an equivalent instance using the
+ * <code>FontData(String)</code> constructor.
+ *
+ * @return a string representation of the FontData
+ *
+ * @see FontData
+ */
+public String toString() {
+ StringBuffer buffer = new StringBuffer(128);
+ buffer.append("1|");
+ buffer.append(getName());
+ buffer.append("|");
+ buffer.append(getHeightF());
+ buffer.append("|");
+ buffer.append(getStyle());
+ buffer.append("|");
+ buffer.append("COCOA|1|");
+ if (nsName != null) buffer.append(nsName);
+ return buffer.toString();
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/FontMetrics.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/FontMetrics.java
new file mode 100755
index 0000000000..2c0d6a7a3f
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/FontMetrics.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+/**
+ * Instances of this class provide measurement information
+ * about fonts including ascent, descent, height, leading
+ * space between rows, and average character width.
+ * <code>FontMetrics</code> are obtained from <code>GC</code>s
+ * using the <code>getFontMetrics()</code> method.
+ *
+ * @see GC#getFontMetrics
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+public final class FontMetrics {
+ int ascent, descent, averageCharWidth, leading, height;
+
+FontMetrics() {
+}
+
+public static FontMetrics cocoa_new(int ascent, int descent, int averageCharWidth, int leading, int height) {
+ FontMetrics fontMetrics = new FontMetrics();
+ fontMetrics.ascent = ascent;
+ fontMetrics.descent = descent;
+ fontMetrics.averageCharWidth = averageCharWidth;
+ fontMetrics.leading = leading;
+ fontMetrics.height = height;
+ return fontMetrics;
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the <em>same</em> object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
+ *
+ * @see #hashCode
+ */
+public boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof FontMetrics)) return false;
+ FontMetrics metrics = (FontMetrics)object;
+ return ascent == metrics.ascent && descent == metrics.descent &&
+ averageCharWidth == metrics.averageCharWidth && leading == metrics.leading &&
+ height == metrics.height;
+}
+
+/**
+ * Returns the ascent of the font described by the receiver. A
+ * font's <em>ascent</em> is the distance from the baseline to the
+ * top of actual characters, not including any of the leading area,
+ * measured in pixels.
+ *
+ * @return the ascent of the font
+ */
+public int getAscent() {
+ return ascent;
+}
+
+/**
+ * Returns the average character width, measured in pixels,
+ * of the font described by the receiver.
+ *
+ * @return the average character width of the font
+ */
+public int getAverageCharWidth() {
+ return averageCharWidth;
+}
+
+/**
+ * Returns the descent of the font described by the receiver. A
+ * font's <em>descent</em> is the distance from the baseline to the
+ * bottom of actual characters, not including any of the leading area,
+ * measured in pixels.
+ *
+ * @return the descent of the font
+ */
+public int getDescent() {
+ return descent;
+}
+
+/**
+ * Returns the height of the font described by the receiver,
+ * measured in pixels. A font's <em>height</em> is the sum of
+ * its ascent, descent and leading area.
+ *
+ * @return the height of the font
+ *
+ * @see #getAscent
+ * @see #getDescent
+ * @see #getLeading
+ */
+public int getHeight() {
+ return height;
+}
+
+/**
+ * Returns the leading area of the font described by the
+ * receiver. A font's <em>leading area</em> is the space
+ * above its ascent which may include accents or other marks.
+ *
+ * @return the leading space of the font
+ */
+public int getLeading() {
+ return leading;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return <code>true</code> when passed to
+ * <code>equals</code> must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+public int hashCode() {
+ return ascent ^ descent ^ averageCharWidth ^ leading ^ height;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java
new file mode 100755
index 0000000000..0d34639929
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java
@@ -0,0 +1,3918 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Class <code>GC</code> is where all of the drawing capabilities that are
+ * supported by SWT are located. Instances are used to draw on either an
+ * <code>Image</code>, a <code>Control</code>, or directly on a <code>Display</code>.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>LEFT_TO_RIGHT, RIGHT_TO_LEFT</dd>
+ * </dl>
+ *
+ * <p>
+ * The SWT drawing coordinate system is the two-dimensional space with the origin
+ * (0,0) at the top left corner of the drawing area and with (x,y) values increasing
+ * to the right and downward respectively.
+ * </p>
+ *
+ * <p>
+ * The result of drawing on an image that was created with an indexed
+ * palette using a color that is not in the palette is platform specific.
+ * Some platforms will match to the nearest color while other will draw
+ * the color itself. This happens because the allocated image might use
+ * a direct palette on platforms that do not support indexed palette.
+ * </p>
+ *
+ * <p>
+ * Application code must explicitly invoke the <code>GC.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required. This is <em>particularly</em>
+ * important on Windows95 and Windows98 where the operating system has a limited
+ * number of device contexts available.
+ * </p>
+ *
+ * <p>
+ * Note: Only one of LEFT_TO_RIGHT and RIGHT_TO_LEFT may be specified.
+ * </p>
+ *
+ * @see org.eclipse.swt.events.PaintEvent
+ * @see <a href="http://www.eclipse.org/swt/snippets/#gc">GC snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: GraphicsExample, PaintExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+public final class GC extends Resource {
+ /**
+ * the handle to the OS device context
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public NSGraphicsContext handle;
+
+ Drawable drawable;
+ GCData data;
+
+ CGPathElement element;
+ int count, typeCount;
+ byte[] types;
+ float /*double*/[] points;
+ float /*double*/ [] point;
+
+ static final int TAB_COUNT = 32;
+
+ final static int FOREGROUND = 1 << 0;
+ final static int BACKGROUND = 1 << 1;
+ final static int FONT = 1 << 2;
+ final static int LINE_STYLE = 1 << 3;
+ final static int LINE_CAP = 1 << 4;
+ final static int LINE_JOIN = 1 << 5;
+ final static int LINE_WIDTH = 1 << 6;
+ final static int LINE_MITERLIMIT = 1 << 7;
+ final static int FOREGROUND_FILL = 1 << 8;
+ final static int DRAW_OFFSET = 1 << 9;
+ final static int CLIPPING = 1 << 10;
+ final static int TRANSFORM = 1 << 11;
+ final static int VISIBLE_REGION = 1 << 12;
+ final static int DRAW = CLIPPING | TRANSFORM | FOREGROUND | LINE_WIDTH | LINE_STYLE | LINE_CAP | LINE_JOIN | LINE_MITERLIMIT | DRAW_OFFSET;
+ final static int FILL = CLIPPING | TRANSFORM | BACKGROUND;
+
+ static final float[] LINE_DOT = new float[]{1, 1};
+ static final float[] LINE_DASH = new float[]{3, 1};
+ static final float[] LINE_DASHDOT = new float[]{3, 1, 1, 1};
+ static final float[] LINE_DASHDOTDOT = new float[]{3, 1, 1, 1, 1, 1};
+ static final float[] LINE_DOT_ZERO = new float[]{3, 3};
+ static final float[] LINE_DASH_ZERO = new float[]{18, 6};
+ static final float[] LINE_DASHDOT_ZERO = new float[]{9, 6, 3, 6};
+ static final float[] LINE_DASHDOTDOT_ZERO = new float[]{9, 3, 3, 3, 3, 3};
+
+GC() {
+}
+
+/**
+ * Constructs a new instance of this class which has been
+ * configured to draw on the specified drawable. Sets the
+ * foreground color, background color and font in the GC
+ * to match those in the drawable.
+ * <p>
+ * You must dispose the graphics context when it is no longer required.
+ * </p>
+ * @param drawable the drawable to draw on
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the drawable is null</li>
+ * <li>ERROR_NULL_ARGUMENT - if there is no current device</li>
+ * <li>ERROR_INVALID_ARGUMENT
+ * - if the drawable is an image that is not a bitmap or an icon
+ * - if the drawable is an image or printer that is already selected
+ * into another graphics context</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for GC creation</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li>
+ * </ul>
+ */
+public GC(Drawable drawable) {
+ this(drawable, 0);
+}
+
+/**
+ * Constructs a new instance of this class which has been
+ * configured to draw on the specified drawable. Sets the
+ * foreground color, background color and font in the GC
+ * to match those in the drawable.
+ * <p>
+ * You must dispose the graphics context when it is no longer required.
+ * </p>
+ *
+ * @param drawable the drawable to draw on
+ * @param style the style of GC to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the drawable is null</li>
+ * <li>ERROR_NULL_ARGUMENT - if there is no current device</li>
+ * <li>ERROR_INVALID_ARGUMENT
+ * - if the drawable is an image that is not a bitmap or an icon
+ * - if the drawable is an image or printer that is already selected
+ * into another graphics context</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for GC creation</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li>
+ * </ul>
+ *
+ * @since 2.1.2
+ */
+public GC(Drawable drawable, int style) {
+ if (drawable == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ GCData data = new GCData();
+ data.style = checkStyle(style);
+ int /*long*/ contextId = drawable.internal_new_GC(data);
+ Device device = data.device;
+ if (device == null) device = Device.getDevice();
+ if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ this.device = data.device = device;
+ init(drawable, data, contextId);
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+static int checkStyle (int style) {
+ if ((style & SWT.LEFT_TO_RIGHT) != 0) style &= ~SWT.RIGHT_TO_LEFT;
+ return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new graphics context.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>GC</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param drawable the Drawable for the receiver.
+ * @param data the data for the receiver.
+ *
+ * @return a new <code>GC</code>
+ *
+ * @private
+ */
+public static GC cocoa_new(Drawable drawable, GCData data) {
+ GC gc = new GC();
+ int /*long*/ context = drawable.internal_new_GC(data);
+ gc.device = data.device;
+ gc.init(drawable, data, context);
+ return gc;
+}
+
+int /*long*/ applierFunc(int /*long*/ info, int /*long*/ elementPtr) {
+ OS.memmove(element, elementPtr, CGPathElement.sizeof);
+ int type = 0, length = 1;
+ switch (element.type) {
+ case OS.kCGPathElementMoveToPoint: type = SWT.PATH_MOVE_TO; break;
+ case OS.kCGPathElementAddLineToPoint: type = SWT.PATH_LINE_TO; break;
+ case OS.kCGPathElementAddQuadCurveToPoint: type = SWT.PATH_QUAD_TO; length = 2; break;
+ case OS.kCGPathElementAddCurveToPoint: type = SWT.PATH_CUBIC_TO; length = 3; break;
+ case OS.kCGPathElementCloseSubpath: type = SWT.PATH_CLOSE; length = 0; break;
+ }
+ if (types != null) {
+ types[typeCount] = (byte)type;
+ if (length > 0) {
+ OS.memmove(point, element.points, length * CGPoint.sizeof);
+ System.arraycopy(point, 0, points, count, length * 2);
+ }
+ }
+ typeCount++;
+ count += length * 2;
+ return 0;
+}
+
+NSAutoreleasePool checkGC (int mask) {
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ if (data.flippedContext != null && !handle.isEqual(NSGraphicsContext.currentContext())) {
+ data.restoreContext = true;
+ NSGraphicsContext.static_saveGraphicsState();
+ NSGraphicsContext.setCurrentContext(handle);
+ }
+ if ((mask & (CLIPPING | TRANSFORM)) != 0) {
+ NSView view = data.view;
+ if ((data.state & CLIPPING) == 0 || (data.state & TRANSFORM) == 0 || (data.state & VISIBLE_REGION) == 0) {
+ boolean antialias = handle.shouldAntialias();
+ handle.restoreGraphicsState();
+ handle.saveGraphicsState();
+ handle.setShouldAntialias(antialias);
+ if (view != null && (data.paintRect == null || !view.isFlipped())) {
+ NSAffineTransform transform = NSAffineTransform.transform();
+ NSRect rect = view.convertRect_toView_(view.bounds(), null);
+ if (data.paintRect == null) {
+ transform.translateXBy(rect.x, rect.y + rect.height);
+ } else {
+ transform.translateXBy(0, rect.height);
+ }
+ transform.scaleXBy(1, -1);
+ transform.concat();
+ if (data.visibleRgn != 0) {
+ if (data.visiblePath == null || (data.state & VISIBLE_REGION) == 0) {
+ if (data.visiblePath != null) data.visiblePath.release();
+ data.visiblePath = Region.cocoa_new(device, data.visibleRgn).getPath();
+ }
+ data.visiblePath.addClip();
+ data.state |= VISIBLE_REGION;
+ }
+ }
+ if (data.clipPath != null) data.clipPath.addClip();
+ if (data.transform != null) data.transform.concat();
+ mask &= ~(TRANSFORM | CLIPPING);
+ data.state |= TRANSFORM | CLIPPING;
+ data.state &= ~(BACKGROUND | FOREGROUND);
+ }
+ }
+
+ int state = data.state;
+ if ((state & mask) == mask) return pool;
+ state = (state ^ mask) & mask;
+ data.state |= mask;
+
+ if ((state & FOREGROUND) != 0) {
+ Pattern pattern = data.foregroundPattern;
+ if (pattern != null) {
+ if (pattern.color != null) pattern.color.setStroke();
+ } else {
+ float /*double*/ [] color = data.foreground;
+ if (data.fg != null) data.fg.release();
+ NSColor fg = data.fg = NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f);
+ fg.retain();
+ fg.setStroke();
+ }
+ }
+ if ((state & FOREGROUND_FILL) != 0) {
+ Pattern pattern = data.foregroundPattern;
+ if (pattern != null) {
+ if (pattern.color != null) pattern.color.setFill();
+ } else {
+ float /*double*/ [] color = data.foreground;
+ if (data.fg != null) data.fg.release();
+ NSColor fg = data.fg = NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f);
+ fg.retain();
+ fg.setFill();
+ }
+ data.state &= ~BACKGROUND;
+ }
+ if ((state & BACKGROUND) != 0) {
+ Pattern pattern = data.backgroundPattern;
+ if (pattern != null) {
+ if (pattern.color != null) pattern.color.setFill();
+ } else {
+ float /*double*/ [] color = data.background;
+ if (data.bg != null) data.bg.release();
+ NSColor bg = data.bg = NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f);
+ bg.retain();
+ bg.setFill();
+ }
+ data.state &= ~FOREGROUND_FILL;
+ }
+ NSBezierPath path = data.path;
+ if ((state & LINE_WIDTH) != 0) {
+ path.setLineWidth(data.lineWidth == 0 ? 1 : data.lineWidth);
+ switch (data.lineStyle) {
+ case SWT.LINE_DOT:
+ case SWT.LINE_DASH:
+ case SWT.LINE_DASHDOT:
+ case SWT.LINE_DASHDOTDOT:
+ state |= LINE_STYLE;
+ }
+ }
+ if ((state & LINE_STYLE) != 0) {
+ float[] dashes = null;
+ float width = data.lineWidth;
+ switch (data.lineStyle) {
+ case SWT.LINE_SOLID: break;
+ case SWT.LINE_DASH: dashes = width != 0 ? LINE_DASH : LINE_DASH_ZERO; break;
+ case SWT.LINE_DOT: dashes = width != 0 ? LINE_DOT : LINE_DOT_ZERO; break;
+ case SWT.LINE_DASHDOT: dashes = width != 0 ? LINE_DASHDOT : LINE_DASHDOT_ZERO; break;
+ case SWT.LINE_DASHDOTDOT: dashes = width != 0 ? LINE_DASHDOTDOT : LINE_DASHDOTDOT_ZERO; break;
+ case SWT.LINE_CUSTOM: dashes = data.lineDashes; break;
+ }
+ if (dashes != null) {
+ float /*double*/[] lengths = new float /*double*/[dashes.length];
+ for (int i = 0; i < lengths.length; i++) {
+ lengths[i] = width == 0 || data.lineStyle == SWT.LINE_CUSTOM ? dashes[i] : dashes[i] * width;
+ }
+ path.setLineDash(lengths, lengths.length, data.lineDashesOffset);
+ } else {
+ path.setLineDash(null, 0, 0);
+ }
+ }
+ if ((state & LINE_MITERLIMIT) != 0) {
+ path.setMiterLimit(data.lineMiterLimit);
+ }
+ if ((state & LINE_JOIN) != 0) {
+ int joinStyle = 0;
+ switch (data.lineJoin) {
+ case SWT.JOIN_MITER: joinStyle = OS.NSMiterLineJoinStyle; break;
+ case SWT.JOIN_ROUND: joinStyle = OS.NSRoundLineJoinStyle; break;
+ case SWT.JOIN_BEVEL: joinStyle = OS.NSBevelLineJoinStyle; break;
+ }
+ path.setLineJoinStyle(joinStyle);
+ }
+ if ((state & LINE_CAP) != 0) {
+ int capStyle = 0;
+ switch (data.lineCap) {
+ case SWT.CAP_ROUND: capStyle = OS.NSRoundLineCapStyle; break;
+ case SWT.CAP_FLAT: capStyle = OS.NSButtLineCapStyle; break;
+ case SWT.CAP_SQUARE: capStyle = OS.NSSquareLineCapStyle; break;
+ }
+ path.setLineCapStyle(capStyle);
+ }
+ if ((state & DRAW_OFFSET) != 0) {
+ data.drawXOffset = data.drawYOffset = 0;
+ NSSize size = new NSSize();
+ size.width = size.height = 1;
+ if (data.transform != null) {
+ size = data.transform.transformSize(size);
+ }
+ float /*double*/ scaling = size.width;
+ if (scaling < 0) scaling = -scaling;
+ float /*double*/ strokeWidth = data.lineWidth * scaling;
+ if (strokeWidth == 0 || ((int)strokeWidth % 2) == 1) {
+ data.drawXOffset = 0.5f / scaling;
+ }
+ scaling = size.height;
+ if (scaling < 0) scaling = -scaling;
+ strokeWidth = data.lineWidth * scaling;
+ if (strokeWidth == 0 || ((int)strokeWidth % 2) == 1) {
+ data.drawYOffset = 0.5f / scaling;
+ }
+ }
+ return pool;
+}
+
+/**
+ * Copies a rectangular area of the receiver at the specified
+ * position into the image, which must be of type <code>SWT.BITMAP</code>.
+ *
+ * @param image the image to copy into
+ * @param x the x coordinate in the receiver of the area to be copied
+ * @param y the y coordinate in the receiver of the area to be copied
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the image is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the image is not a bitmap or has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void copyArea(Image image, int x, int y) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (image.type != SWT.BITMAP || image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = checkGC(TRANSFORM | CLIPPING);
+ try {
+ if (data.image != null) {
+ int srcX = x, srcY = y, destX = 0, destY = 0;
+ NSSize srcSize = data.image.handle.size();
+ int imgHeight = (int)srcSize.height;
+ int destWidth = (int)srcSize.width - x, destHeight = (int)srcSize.height - y;
+ int srcWidth = destWidth, srcHeight = destHeight;
+ NSGraphicsContext context = NSGraphicsContext.graphicsContextWithBitmapImageRep(image.getRepresentation());
+ NSGraphicsContext.static_saveGraphicsState();
+ NSGraphicsContext.setCurrentContext(context);
+ NSAffineTransform transform = NSAffineTransform.transform();
+ NSSize size = image.handle.size();
+ transform.translateXBy(0, size.height-(destHeight + 2 * destY));
+ transform.concat();
+ NSRect srcRect = new NSRect();
+ srcRect.x = srcX;
+ srcRect.y = imgHeight - (srcY + srcHeight);
+ srcRect.width = srcWidth;
+ srcRect.height = srcHeight;
+ NSRect destRect = new NSRect();
+ destRect.x = destX;
+ destRect.y = destY;
+ destRect.width = destWidth;
+ destRect.height = destHeight;
+ data.image.handle.drawInRect(destRect, srcRect, OS.NSCompositeCopy, 1);
+ NSGraphicsContext.static_restoreGraphicsState();
+ return;
+ }
+ if (data.view != null) {
+ NSPoint pt = new NSPoint();
+ pt.x = x;
+ pt.y = y;
+ NSWindow window = data.view.window();
+ pt = data.view.convertPoint_toView_(pt, window.contentView().superview());
+ NSRect frame = window.frame();
+ pt.y = frame.height - pt.y;
+ NSSize size = image.handle.size();
+ CGRect destRect = new CGRect();
+ destRect.size.width = size.width;
+ destRect.size.height = size.height;
+ CGRect srcRect = new CGRect();
+ srcRect.origin.x = pt.x;
+ srcRect.origin.y = pt.y;
+ srcRect.size.width = size.width;
+ srcRect.size.height = size.height;
+ NSBitmapImageRep imageRep = image.getRepresentation();
+ NSGraphicsContext context = NSGraphicsContext.graphicsContextWithBitmapImageRep(imageRep);
+ NSGraphicsContext.static_saveGraphicsState();
+ NSGraphicsContext.setCurrentContext(context);
+ int /*long*/ contextID = OS.objc_msgSend(NSApplication.sharedApplication().id, OS.sel_contextID);
+ OS.CGContextCopyWindowContentsToRect(context.graphicsPort(), destRect, contextID, window.windowNumber(), srcRect);
+ NSGraphicsContext.static_restoreGraphicsState();
+ return;
+ }
+ if (handle.isDrawingToScreen()) {
+ NSImage imageHandle = image.handle;
+ NSSize size = imageHandle.size();
+ CGRect rect = new CGRect();
+ rect.origin.x = x;
+ rect.origin.y = y;
+ rect.size.width = size.width;
+ rect.size.height = size.height;
+ int displayCount = 16;
+ int /*long*/ displays = OS.malloc(4 * displayCount), countPtr = OS.malloc(4);
+ if (OS.CGGetDisplaysWithRect(rect, displayCount, displays, countPtr) != 0) return;
+ int[] count = new int[1], display = new int[1];
+ OS.memmove(count, countPtr, OS.PTR_SIZEOF);
+ for (int i = 0; i < count[0]; i++) {
+ OS.memmove(display, displays + (i * 4), 4);
+ OS.CGDisplayBounds(display[0], rect);
+ int /*long*/ address = OS.CGDisplayBaseAddress(display[0]);
+ if (address != 0) {
+ int /*long*/ width = OS.CGDisplayPixelsWide(display[0]);
+ int /*long*/ height = OS.CGDisplayPixelsHigh(display[0]);
+ int /*long*/ bpr = OS.CGDisplayBytesPerRow(display[0]);
+ int /*long*/ bpp = OS.CGDisplayBitsPerPixel(display[0]);
+ int /*long*/ bps = OS.CGDisplayBitsPerSample(display[0]);
+ int bitmapInfo = OS.kCGImageAlphaNoneSkipFirst;
+ switch ((int)/*63*/bpp) {
+ case 16: bitmapInfo |= OS.kCGBitmapByteOrder16Host; break;
+ case 32: bitmapInfo |= OS.kCGBitmapByteOrder32Host; break;
+ }
+ int /*long*/ srcImage = 0;
+ if (OS.__BIG_ENDIAN__() && OS.VERSION >= 0x1040) {
+ int /*long*/ colorspace = OS.CGColorSpaceCreateDeviceRGB();
+ int /*long*/ context = OS.CGBitmapContextCreate(address, width, height, bps, bpr, colorspace, bitmapInfo);
+ OS.CGColorSpaceRelease(colorspace);
+ srcImage = OS.CGBitmapContextCreateImage(context);
+ OS.CGContextRelease(context);
+ } else {
+ int /*long*/ provider = OS.CGDataProviderCreateWithData(0, address, bpr * height, 0);
+ int /*long*/ colorspace = OS.CGColorSpaceCreateDeviceRGB();
+ srcImage = OS.CGImageCreate(width, height, bps, bpp, bpr, colorspace, bitmapInfo, provider, 0, true, 0);
+ OS.CGColorSpaceRelease(colorspace);
+ OS.CGDataProviderRelease(provider);
+ }
+ copyArea(image, x - (int)rect.origin.x, y - (int)rect.origin.y, srcImage);
+ if (srcImage != 0) OS.CGImageRelease(srcImage);
+ }
+ }
+ OS.free(displays);
+ OS.free(countPtr);
+ }
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+void copyArea (Image image, int x, int y, int /*long*/ srcImage) {
+ if (srcImage == 0) return;
+ NSBitmapImageRep rep = image.getRepresentation();
+ int /*long*/ bpc = rep.bitsPerSample();
+ int /*long*/ width = rep.pixelsWide();
+ int /*long*/ height = rep.pixelsHigh();
+ int /*long*/ bpr = rep.bytesPerRow();
+ int alphaInfo = rep.hasAlpha() ? OS.kCGImageAlphaFirst : OS.kCGImageAlphaNoneSkipFirst;
+ int /*long*/ colorspace = OS.CGColorSpaceCreateDeviceRGB();
+ int /*long*/ context = OS.CGBitmapContextCreate(rep.bitmapData(), width, height, bpc, bpr, colorspace, alphaInfo);
+ OS.CGColorSpaceRelease(colorspace);
+ if (context != 0) {
+ CGRect rect = new CGRect();
+ rect.origin.x = -x;
+ rect.origin.y = y;
+ rect.size.width = OS.CGImageGetWidth(srcImage);
+ rect.size.height = OS.CGImageGetHeight(srcImage);
+ OS.CGContextTranslateCTM(context, 0, -(rect.size.height - height));
+ OS.CGContextDrawImage(context, rect, srcImage);
+ OS.CGContextRelease(context);
+ }
+}
+
+/**
+ * Copies a rectangular area of the receiver at the source
+ * position onto the receiver at the destination position.
+ *
+ * @param srcX the x coordinate in the receiver of the area to be copied
+ * @param srcY the y coordinate in the receiver of the area to be copied
+ * @param width the width of the area to copy
+ * @param height the height of the area to copy
+ * @param destX the x coordinate in the receiver of the area to copy to
+ * @param destY the y coordinate in the receiver of the area to copy to
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY) {
+ copyArea(srcX, srcY, width, height, destX, destY, true);
+}
+/**
+ * Copies a rectangular area of the receiver at the source
+ * position onto the receiver at the destination position.
+ *
+ * @param srcX the x coordinate in the receiver of the area to be copied
+ * @param srcY the y coordinate in the receiver of the area to be copied
+ * @param width the width of the area to copy
+ * @param height the height of the area to copy
+ * @param destX the x coordinate in the receiver of the area to copy to
+ * @param destY the y coordinate in the receiver of the area to copy to
+ * @param paint if <code>true</code> paint events will be generated for old and obscured areas
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY, boolean paint) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (width <= 0 || height <= 0) return;
+ int deltaX = destX - srcX, deltaY = destY - srcY;
+ if (deltaX == 0 && deltaY == 0) return;
+ NSAutoreleasePool pool = checkGC(TRANSFORM | CLIPPING);
+ try {
+ Image image = data.image;
+ if (image != null) {
+ NSImage imageHandle = image.handle;
+ NSSize size = imageHandle.size();
+ int imgHeight = (int)size.height;
+ handle.saveGraphicsState();
+ NSAffineTransform transform = NSAffineTransform.transform();
+ transform.scaleXBy(1, -1);
+ transform.translateXBy(0, -(height + 2 * destY));
+ transform.concat();
+ NSRect srcRect = new NSRect();
+ srcRect.x = srcX;
+ srcRect.y = imgHeight - (srcY + height);
+ srcRect.width = width;
+ srcRect.height = height;
+ NSRect destRect = new NSRect();
+ destRect.x = destX;
+ destRect.y = destY;
+ destRect.width = width;
+ destRect.height = height;
+ imageHandle.drawInRect(destRect, srcRect, OS.NSCompositeCopy, 1);
+ handle.restoreGraphicsState();
+ return;
+ }
+ if (data.view != null) {
+ NSView view = data.view;
+ NSRect visibleRect = view.visibleRect();
+ if (visibleRect.width <= 0 || visibleRect.height <= 0) return;
+ NSRect damage = new NSRect();
+ damage.x = srcX;
+ damage.y = srcY;
+ damage.width = width;
+ damage.height = height;
+ NSPoint dest = new NSPoint();
+ dest.x = destX;
+ dest.y = destY;
+
+ view.lockFocus();
+ OS.NSCopyBits(0, damage , dest);
+ view.unlockFocus();
+
+ if (paint) {
+ boolean disjoint = (destX + width < srcX) || (srcX + width < destX) || (destY + height < srcY) || (srcY + height < destY);
+ if (disjoint) {
+ view.setNeedsDisplayInRect(damage);
+ } else {
+ if (deltaX != 0) {
+ int newX = destX - deltaX;
+ if (deltaX < 0) newX = destX + width;
+ damage.x = newX;
+ damage.width = Math.abs(deltaX);
+ view.setNeedsDisplayInRect(damage);
+ }
+ if (deltaY != 0) {
+ int newY = destY - deltaY;
+ if (deltaY < 0) newY = destY + height;
+ damage.x = srcX;
+ damage.y = newY;
+ damage.width = width;
+ damage.height = Math.abs (deltaY);
+ view.setNeedsDisplayInRect(damage);
+ }
+ }
+
+ NSRect srcRect = new NSRect();
+ srcRect.x = srcX;
+ srcRect.y = srcY;
+ srcRect.width = width;
+ srcRect.height = height;
+ OS.NSIntersectionRect(visibleRect, visibleRect, srcRect);
+
+ if (!OS.NSEqualRects(visibleRect, srcRect)) {
+ if (srcRect.x != visibleRect.x) {
+ damage.x = srcRect.x + deltaX;
+ damage.y = srcRect.y + deltaY;
+ damage.width = visibleRect.x - srcRect.x;
+ damage.height = srcRect.height;
+ view.setNeedsDisplayInRect(damage);
+ }
+ if (visibleRect.x + visibleRect.width != srcRect.x + srcRect.width) {
+ damage.x = srcRect.x + visibleRect.width + deltaX;
+ damage.y = srcRect.y + deltaY;
+ damage.width = srcRect.width - visibleRect.width;
+ damage.height = srcRect.height;
+ view.setNeedsDisplayInRect(damage);
+ }
+ if (visibleRect.y != srcRect.y) {
+ damage.x = visibleRect.x + deltaX;
+ damage.y = srcRect.y + deltaY;
+ damage.width = visibleRect.width;
+ damage.height = visibleRect.y - srcRect.y;
+ view.setNeedsDisplayInRect(damage);
+ }
+ if (visibleRect.y + visibleRect.height != srcRect.y + srcRect.height) {
+ damage.x = visibleRect.x + deltaX;
+ damage.y = visibleRect.y + visibleRect.height + deltaY;
+ damage.width = visibleRect.width;
+ damage.height = srcRect.y + srcRect.height - (visibleRect.y + visibleRect.height);
+ view.setNeedsDisplayInRect(damage);
+ }
+ }
+ }
+ return;
+ }
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+static int /*long*/ createCGPathRef(NSBezierPath nsPath) {
+ int /*long*/ count = nsPath.elementCount();
+ if (count > 0) {
+ int /*long*/ cgPath = OS.CGPathCreateMutable();
+ if (cgPath == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ points = OS.malloc(NSPoint.sizeof * 3);
+ if (points == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ float /*double*/ [] pt = new float /*double*/ [6];
+ for (int i = 0; i < count; i++) {
+ int element = (int)/*64*/nsPath.elementAtIndex(i, points);
+ switch (element) {
+ case OS.NSMoveToBezierPathElement:
+ OS.memmove(pt, points, NSPoint.sizeof);
+ OS.CGPathMoveToPoint(cgPath, 0, pt[0], pt[1]);
+ break;
+ case OS.NSLineToBezierPathElement:
+ OS.memmove(pt, points, NSPoint.sizeof);
+ OS.CGPathAddLineToPoint(cgPath, 0, pt[0], pt[1]);
+ break;
+ case OS.NSCurveToBezierPathElement:
+ OS.memmove(pt, points, NSPoint.sizeof * 3);
+ OS.CGPathAddCurveToPoint(cgPath, 0, pt[0], pt[1], pt[2], pt[3], pt[4], pt[5]);
+ break;
+ case OS.NSClosePathBezierPathElement:
+ OS.CGPathCloseSubpath(cgPath);
+ break;
+ }
+ }
+ OS.free(points);
+ return cgPath;
+ }
+ return 0;
+}
+
+
+
+NSBezierPath createNSBezierPath (int /*long*/ cgPath) {
+ Callback callback = new Callback(this, "applierFunc", 2);
+ int /*long*/ proc = callback.getAddress();
+ if (proc == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
+ count = typeCount = 0;
+ element = new CGPathElement();
+ OS.CGPathApply(cgPath, 0, proc);
+ types = new byte[typeCount];
+ points = new float /*double*/ [count];
+ point = new float /*double*/ [6];
+ count = typeCount = 0;
+ OS.CGPathApply(cgPath, 0, proc);
+ callback.dispose();
+
+ NSBezierPath bezierPath = NSBezierPath.bezierPath();
+ NSPoint nsPoint = new NSPoint(), nsPoint2 = new NSPoint(), nsPoint3 = new NSPoint();
+ for (int i = 0, j = 0; i < types.length; i++) {
+ switch (types[i]) {
+ case SWT.PATH_MOVE_TO:
+ nsPoint.x = points[j++];
+ nsPoint.y = points[j++];
+ bezierPath.moveToPoint(nsPoint);
+ break;
+ case SWT.PATH_LINE_TO:
+ nsPoint.x = points[j++];
+ nsPoint.y = points[j++];
+ bezierPath.lineToPoint(nsPoint);
+ break;
+ case SWT.PATH_CUBIC_TO:
+ nsPoint2.x = points[j++];
+ nsPoint2.y = points[j++];
+ nsPoint3.x = points[j++];
+ nsPoint3.y = points[j++];
+ nsPoint.x = points[j++];
+ nsPoint.y = points[j++];
+ bezierPath.curveToPoint(nsPoint, nsPoint2, nsPoint3);
+ break;
+ case SWT.PATH_QUAD_TO:
+ float /*double*/ currentX = nsPoint.x;
+ float /*double*/ currentY = nsPoint.y;
+ nsPoint2.x = points[j++];
+ nsPoint2.y = points[j++];
+ nsPoint.x = points[j++];
+ nsPoint.y = points[j++];
+ float /*double*/ x0 = currentX;
+ float /*double*/ y0 = currentY;
+ float /*double*/ cx1 = x0 + 2 * (nsPoint2.x - x0) / 3;
+ float /*double*/ cy1 = y0 + 2 * (nsPoint2.y - y0) / 3;
+ float /*double*/ cx2 = cx1 + (nsPoint.x - x0) / 3;
+ float /*double*/ cy2 = cy1 + (nsPoint.y - y0) / 3;
+ nsPoint2.x = cx1;
+ nsPoint2.y = cy1;
+ nsPoint3.x = cx2;
+ nsPoint3.y = cy2;
+ bezierPath.curveToPoint(nsPoint, nsPoint2, nsPoint3);
+ break;
+ case SWT.PATH_CLOSE:
+ bezierPath.closePath();
+ break;
+ default:
+ dispose();
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ }
+ element = null;
+ types = null;
+ points = null;
+ nsPoint = null;
+ return bezierPath;
+}
+
+NSAttributedString createString(String string, int flags, boolean draw) {
+ NSMutableDictionary dict = ((NSMutableDictionary)new NSMutableDictionary().alloc()).initWithCapacity(5);
+ Font font = data.font;
+ dict.setObject(font.handle, OS.NSFontAttributeName);
+ font.addTraits(dict);
+ if (draw) {
+ Pattern pattern = data.foregroundPattern;
+ if (pattern != null) {
+ if (pattern.color != null) dict.setObject(pattern.color, OS.NSForegroundColorAttributeName);
+ } else {
+ NSColor fg = data.fg;
+ if (fg == null) {
+ float /*double*/ [] color = data.foreground;
+ fg = data.fg = NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f);
+ fg.retain();
+ }
+ dict.setObject(fg, OS.NSForegroundColorAttributeName);
+ }
+ }
+ if ((flags & SWT.DRAW_TAB) == 0) {
+ dict.setObject(device.paragraphStyle, OS.NSParagraphStyleAttributeName);
+ }
+ int length = string.length();
+ char[] chars = new char[length];
+ string.getChars(0, length, chars, 0);
+ int breakCount = 0;
+ int[] breaks = null;
+ if ((flags & SWT.DRAW_MNEMONIC) !=0 || (flags & SWT.DRAW_DELIMITER) == 0) {
+ int i=0, j=0;
+ while (i < chars.length) {
+ char c = chars [j++] = chars [i++];
+ switch (c) {
+ case '&': {
+ if ((flags & SWT.DRAW_MNEMONIC) != 0) {
+ if (i == chars.length) {continue;}
+ if (chars [i] == '&') {i++; continue;}
+ j--;
+ }
+ break;
+ }
+ case '\r':
+ case '\n': {
+ if ((flags & SWT.DRAW_DELIMITER) == 0) {
+ if (c == '\r' && i != chars.length && chars[i] == '\n') i++;
+ j--;
+ if (breaks == null) {
+ breaks = new int[4];
+ } else if (breakCount == breaks.length) {
+ int[] newBreaks = new int[breaks.length + 4];
+ System.arraycopy(breaks, 0, newBreaks, 0, breaks.length);
+ breaks = newBreaks;
+ }
+ breaks[breakCount++] = j;
+ }
+ break;
+ }
+ }
+ }
+ length = j;
+ }
+ NSString str = ((NSString)new NSString().alloc()).initWithCharacters(chars, length);
+ NSAttributedString attribStr = ((NSAttributedString)new NSAttributedString().alloc()).initWithString(str, dict);
+ dict.release();
+ str.release();
+ return attribStr;
+}
+
+void destroy() {
+ /* Free resources */
+ Image image = data.image;
+ if (image != null) {
+ image.memGC = null;
+ image.createAlpha();
+ }
+ if (data.fg != null) data.fg.release();
+ if (data.bg != null) data.bg.release();
+ if (data.path != null) data.path.release();
+ if (data.clipPath != null) data.clipPath.release();
+ if (data.visiblePath != null) data.visiblePath.release();
+ if (data.transform != null) data.transform.release();
+ if (data.inverseTransform != null) data.inverseTransform.release();
+ data.path = data.clipPath = data.visiblePath = null;
+ data.transform = data.inverseTransform = null;
+ data.fg = data.bg = null;
+
+ /* Dispose the GC */
+ if (drawable != null) drawable.internal_dispose_GC(handle.id, data);
+ handle.restoreGraphicsState();
+ handle.release();
+
+ drawable = null;
+ data.image = null;
+ data = null;
+ handle = null;
+}
+
+/**
+ * Draws the outline of a circular or elliptical arc
+ * within the specified rectangular area.
+ * <p>
+ * The resulting arc begins at <code>startAngle</code> and extends
+ * for <code>arcAngle</code> degrees, using the current color.
+ * Angles are interpreted such that 0 degrees is at the 3 o'clock
+ * position. A positive value indicates a counter-clockwise rotation
+ * while a negative value indicates a clockwise rotation.
+ * </p><p>
+ * The center of the arc is the center of the rectangle whose origin
+ * is (<code>x</code>, <code>y</code>) and whose size is specified by the
+ * <code>width</code> and <code>height</code> arguments.
+ * </p><p>
+ * The resulting arc covers an area <code>width + 1</code> pixels wide
+ * by <code>height + 1</code> pixels tall.
+ * </p>
+ *
+ * @param x the x coordinate of the upper-left corner of the arc to be drawn
+ * @param y the y coordinate of the upper-left corner of the arc to be drawn
+ * @param width the width of the arc to be drawn
+ * @param height the height of the arc to be drawn
+ * @param startAngle the beginning angle
+ * @param arcAngle the angular extent of the arc, relative to the start angle
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (width < 0) {
+ x = x + width;
+ width = -width;
+ }
+ if (height < 0) {
+ y = y + height;
+ height = -height;
+ }
+ if (width == 0 || height == 0 || arcAngle == 0) return;
+ NSAutoreleasePool pool = checkGC(DRAW);
+ try {
+ handle.saveGraphicsState();
+ NSAffineTransform transform = NSAffineTransform.transform();
+ float /*double*/ xOffset = data.drawXOffset, yOffset = data.drawYOffset;
+ transform.translateXBy(x + xOffset + width / 2f, y + yOffset + height / 2f);
+ transform.scaleXBy(width / 2f, height / 2f);
+ NSBezierPath path = data.path;
+ NSPoint center = new NSPoint();
+ float sAngle = -startAngle;
+ float eAngle = -(startAngle + arcAngle);
+ path.appendBezierPathWithArcWithCenter(center, 1, sAngle, eAngle, arcAngle>0);
+ path.transformUsingAffineTransform(transform);
+ Pattern pattern = data.foregroundPattern;
+ if (pattern != null && pattern.gradient != null) {
+ strokePattern(path, pattern);
+ } else {
+ path.stroke();
+ }
+ path.removeAllPoints();
+ handle.restoreGraphicsState();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Draws a rectangle, based on the specified arguments, which has
+ * the appearance of the platform's <em>focus rectangle</em> if the
+ * platform supports such a notion, and otherwise draws a simple
+ * rectangle in the receiver's foreground color.
+ *
+ * @param x the x coordinate of the rectangle
+ * @param y the y coordinate of the rectangle
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawRectangle(int, int, int, int)
+ */
+public void drawFocus(int x, int y, int width, int height) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = checkGC(CLIPPING | TRANSFORM);
+ try {
+ int[] metric = new int[1];
+ OS.GetThemeMetric(OS.kThemeMetricFocusRectOutset, metric);
+ CGRect rect = new CGRect();
+ rect.origin.x = x + metric[0];
+ rect.origin.y = y + metric[0];
+ rect.size.width = width - metric[0] * 2;
+ rect.size.height = height - metric[0] * 2;
+ OS.HIThemeDrawFocusRect(rect, true, handle.graphicsPort(), OS.kHIThemeOrientationNormal);
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Draws the given image in the receiver at the specified
+ * coordinates.
+ *
+ * @param image the image to draw
+ * @param x the x coordinate of where to draw
+ * @param y the y coordinate of where to draw
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the image is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the given coordinates are outside the bounds of the image</li>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES - if no handles are available to perform the operation</li>
+ * </ul>
+ */
+public void drawImage(Image image, int x, int y) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ drawImage(image, 0, 0, -1, -1, x, y, -1, -1, true);
+}
+
+/**
+ * Copies a rectangular area from the source image into a (potentially
+ * different sized) rectangular area in the receiver. If the source
+ * and destination areas are of differing sizes, then the source
+ * area will be stretched or shrunk to fit the destination area
+ * as it is copied. The copy fails if any part of the source rectangle
+ * lies outside the bounds of the source image, or if any of the width
+ * or height arguments are negative.
+ *
+ * @param image the source image
+ * @param srcX the x coordinate in the source image to copy from
+ * @param srcY the y coordinate in the source image to copy from
+ * @param srcWidth the width in pixels to copy from the source
+ * @param srcHeight the height in pixels to copy from the source
+ * @param destX the x coordinate in the destination to copy to
+ * @param destY the y coordinate in the destination to copy to
+ * @param destWidth the width in pixels of the destination rectangle
+ * @param destHeight the height in pixels of the destination rectangle
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the image is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * <li>ERROR_INVALID_ARGUMENT - if any of the width or height arguments are negative.
+ * <li>ERROR_INVALID_ARGUMENT - if the source rectangle is not contained within the bounds of the source image</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES - if no handles are available to perform the operation</li>
+ * </ul>
+ */
+public void drawImage(Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (srcWidth == 0 || srcHeight == 0 || destWidth == 0 || destHeight == 0) return;
+ if (srcX < 0 || srcY < 0 || srcWidth < 0 || srcHeight < 0 || destWidth < 0 || destHeight < 0) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ drawImage(image, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, false);
+}
+
+void drawImage(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) {
+ NSImage imageHandle = srcImage.handle;
+ NSSize size = imageHandle.size();
+ int imgWidth = (int)size.width;
+ int imgHeight = (int)size.height;
+ if (simple) {
+ srcWidth = destWidth = imgWidth;
+ srcHeight = destHeight = imgHeight;
+ } else {
+ simple = srcX == 0 && srcY == 0 &&
+ srcWidth == destWidth && destWidth == imgWidth &&
+ srcHeight == destHeight && destHeight == imgHeight;
+ if (srcX + srcWidth > imgWidth || srcY + srcHeight > imgHeight) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ }
+ NSAutoreleasePool pool = checkGC(CLIPPING | TRANSFORM);
+ try {
+ if (srcImage.memGC != null) {
+ srcImage.createAlpha();
+ }
+ handle.saveGraphicsState();
+ NSAffineTransform transform = NSAffineTransform.transform();
+ transform.scaleXBy(1, -1);
+ transform.translateXBy(0, -(destHeight + 2 * destY));
+ transform.concat();
+ NSRect srcRect = new NSRect();
+ srcRect.x = srcX;
+ srcRect.y = imgHeight - (srcY + srcHeight);
+ srcRect.width = srcWidth;
+ srcRect.height = srcHeight;
+ NSRect destRect = new NSRect();
+ destRect.x = destX;
+ destRect.y = destY;
+ destRect.width = destWidth;
+ destRect.height = destHeight;
+ imageHandle.drawInRect(destRect, srcRect, OS.NSCompositeSourceOver, 1);
+ handle.restoreGraphicsState();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Draws a line, using the foreground color, between the points
+ * (<code>x1</code>, <code>y1</code>) and (<code>x2</code>, <code>y2</code>).
+ *
+ * @param x1 the first point's x coordinate
+ * @param y1 the first point's y coordinate
+ * @param x2 the second point's x coordinate
+ * @param y2 the second point's y coordinate
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawLine(int x1, int y1, int x2, int y2) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = checkGC(DRAW);
+ try {
+ NSBezierPath path = data.path;
+ NSPoint pt = new NSPoint();
+ pt.x = x1 + data.drawXOffset;
+ pt.y = y1 + data.drawYOffset;
+ path.moveToPoint(pt);
+ pt.x = x2 + data.drawXOffset;
+ pt.y = y2 + data.drawYOffset;
+ path.lineToPoint(pt);
+ Pattern pattern = data.foregroundPattern;
+ if (pattern != null && pattern.gradient != null) {
+ strokePattern(path, pattern);
+ } else {
+ path.stroke();
+ }
+ path.removeAllPoints();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Draws the outline of an oval, using the foreground color,
+ * within the specified rectangular area.
+ * <p>
+ * The result is a circle or ellipse that fits within the
+ * rectangle specified by the <code>x</code>, <code>y</code>,
+ * <code>width</code>, and <code>height</code> arguments.
+ * </p><p>
+ * The oval covers an area that is <code>width + 1</code>
+ * pixels wide and <code>height + 1</code> pixels tall.
+ * </p>
+ *
+ * @param x the x coordinate of the upper left corner of the oval to be drawn
+ * @param y the y coordinate of the upper left corner of the oval to be drawn
+ * @param width the width of the oval to be drawn
+ * @param height the height of the oval to be drawn
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawOval(int x, int y, int width, int height) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = checkGC(DRAW);
+ try {
+ if (width < 0) {
+ x = x + width;
+ width = -width;
+ }
+ if (height < 0) {
+ y = y + height;
+ height = -height;
+ }
+ NSBezierPath path = data.path;
+ NSRect rect = new NSRect();
+ rect.x = x + data.drawXOffset;
+ rect.y = y + data.drawXOffset;
+ rect.width = width;
+ rect.height = height;
+ path.appendBezierPathWithOvalInRect(rect);
+ Pattern pattern = data.foregroundPattern;
+ if (pattern != null && pattern.gradient != null) {
+ strokePattern(path, pattern);
+ } else {
+ path.stroke();
+ }
+ path.removeAllPoints();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Draws the path described by the parameter.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param path the path to draw
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see Path
+ *
+ * @since 3.1
+ */
+public void drawPath(Path path) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (path.handle == null) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = checkGC(DRAW);
+ try {
+ handle.saveGraphicsState();
+ NSAffineTransform transform = NSAffineTransform.transform();
+ transform.translateXBy(data.drawXOffset, data.drawYOffset);
+ transform.concat();
+ NSBezierPath drawPath = data.path;
+ drawPath.appendBezierPath(path.handle);
+ Pattern pattern = data.foregroundPattern;
+ if (pattern != null && pattern.gradient != null) {
+ strokePattern(drawPath, pattern);
+ } else {
+ drawPath.stroke();
+ }
+ drawPath.removeAllPoints();
+ handle.restoreGraphicsState();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Draws a pixel, using the foreground color, at the specified
+ * point (<code>x</code>, <code>y</code>).
+ * <p>
+ * Note that the receiver's line attributes do not affect this
+ * operation.
+ * </p>
+ *
+ * @param x the point's x coordinate
+ * @param y the point's y coordinate
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void drawPoint(int x, int y) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = checkGC(FOREGROUND_FILL | CLIPPING | TRANSFORM);
+ try {
+ NSRect rect = new NSRect();
+ rect.x = x;
+ rect.y = y;
+ rect.width = 1;
+ rect.height = 1;
+ NSBezierPath path = data.path;
+ path.appendBezierPathWithRect(rect);
+ path.fill();
+ path.removeAllPoints();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Draws the closed polygon which is defined by the specified array
+ * of integer coordinates, using the receiver's foreground color. The array
+ * contains alternating x and y values which are considered to represent
+ * points which are the vertices of the polygon. Lines are drawn between
+ * each consecutive pair, and between the first pair and last pair in the
+ * array.
+ *
+ * @param pointArray an array of alternating x and y values which are the vertices of the polygon
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT if pointArray is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawPolygon(int[] pointArray) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (pointArray.length < 4) return;
+ NSAutoreleasePool pool = checkGC(DRAW);
+ try {
+ float /*double*/ xOffset = data.drawXOffset, yOffset = data.drawYOffset;
+ NSBezierPath path = data.path;
+ NSPoint pt = new NSPoint();
+ pt.x = pointArray[0] + xOffset;
+ pt.y = pointArray[1] + yOffset;
+ path.moveToPoint(pt);
+ int end = pointArray.length / 2 * 2;
+ for (int i = 2; i < end; i+=2) {
+ pt.x = pointArray[i] + xOffset;
+ pt.y = pointArray[i+1] + yOffset;
+ path.lineToPoint(pt);
+ }
+ path.closePath();
+ Pattern pattern = data.foregroundPattern;
+ if (pattern != null && pattern.gradient != null) {
+ strokePattern(path, pattern);
+ } else {
+ path.stroke();
+ }
+ path.removeAllPoints();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Draws the polyline which is defined by the specified array
+ * of integer coordinates, using the receiver's foreground color. The array
+ * contains alternating x and y values which are considered to represent
+ * points which are the corners of the polyline. Lines are drawn between
+ * each consecutive pair, but not between the first pair and last pair in
+ * the array.
+ *
+ * @param pointArray an array of alternating x and y values which are the corners of the polyline
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point array is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawPolyline(int[] pointArray) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (pointArray.length < 4) return;
+ NSAutoreleasePool pool = checkGC(DRAW);
+ try {
+ float /*double*/ xOffset = data.drawXOffset, yOffset = data.drawYOffset;
+ NSBezierPath path = data.path;
+ NSPoint pt = new NSPoint();
+ pt.x = pointArray[0] + xOffset;
+ pt.y = pointArray[1] + yOffset;
+ path.moveToPoint(pt);
+ int end = pointArray.length / 2 * 2;
+ for (int i = 2; i < end; i+=2) {
+ pt.x = pointArray[i] + xOffset;
+ pt.y = pointArray[i+1] + yOffset;
+ path.lineToPoint(pt);
+ }
+ Pattern pattern = data.foregroundPattern;
+ if (pattern != null && pattern.gradient != null) {
+ strokePattern(path, pattern);
+ } else {
+ path.stroke();
+ }
+ path.removeAllPoints();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Draws the outline of the rectangle specified by the arguments,
+ * using the receiver's foreground color. The left and right edges
+ * of the rectangle are at <code>x</code> and <code>x + width</code>.
+ * The top and bottom edges are at <code>y</code> and <code>y + height</code>.
+ *
+ * @param x the x coordinate of the rectangle to be drawn
+ * @param y the y coordinate of the rectangle to be drawn
+ * @param width the width of the rectangle to be drawn
+ * @param height the height of the rectangle to be drawn
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawRectangle(int x, int y, int width, int height) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = checkGC(DRAW);
+ try {
+ if (width < 0) {
+ x = x + width;
+ width = -width;
+ }
+ if (height < 0) {
+ y = y + height;
+ height = -height;
+ }
+ NSRect rect = new NSRect();
+ rect.x = x + data.drawXOffset;
+ rect.y = y + data.drawYOffset;
+ rect.width = width;
+ rect.height = height;
+ NSBezierPath path = data.path;
+ path.appendBezierPathWithRect(rect);
+ Pattern pattern = data.foregroundPattern;
+ if (pattern != null && pattern.gradient != null) {
+ strokePattern(path, pattern);
+ } else {
+ path.stroke();
+ }
+ path.removeAllPoints();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Draws the outline of the specified rectangle, using the receiver's
+ * foreground color. The left and right edges of the rectangle are at
+ * <code>rect.x</code> and <code>rect.x + rect.width</code>. The top
+ * and bottom edges are at <code>rect.y</code> and
+ * <code>rect.y + rect.height</code>.
+ *
+ * @param rect the rectangle to draw
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawRectangle(Rectangle rect) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ drawRectangle (rect.x, rect.y, rect.width, rect.height);
+}
+
+/**
+ * Draws the outline of the round-cornered rectangle specified by
+ * the arguments, using the receiver's foreground color. The left and
+ * right edges of the rectangle are at <code>x</code> and <code>x + width</code>.
+ * The top and bottom edges are at <code>y</code> and <code>y + height</code>.
+ * The <em>roundness</em> of the corners is specified by the
+ * <code>arcWidth</code> and <code>arcHeight</code> arguments, which
+ * are respectively the width and height of the ellipse used to draw
+ * the corners.
+ *
+ * @param x the x coordinate of the rectangle to be drawn
+ * @param y the y coordinate of the rectangle to be drawn
+ * @param width the width of the rectangle to be drawn
+ * @param height the height of the rectangle to be drawn
+ * @param arcWidth the width of the arc
+ * @param arcHeight the height of the arc
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawRoundRectangle(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (arcWidth == 0 || arcHeight == 0) {
+ drawRectangle(x, y, width, height);
+ return;
+ }
+ NSAutoreleasePool pool = checkGC(DRAW);
+ try {
+ NSBezierPath path = data.path;
+ NSRect rect = new NSRect();
+ rect.x = x + data.drawXOffset;
+ rect.y = y + data.drawYOffset;
+ rect.width = width;
+ rect.height = height;
+ path.appendBezierPathWithRoundedRect(rect, arcWidth / 2f, arcHeight / 2f);
+ Pattern pattern = data.foregroundPattern;
+ if (pattern != null && pattern.gradient != null) {
+ strokePattern(path, pattern);
+ } else {
+ path.stroke();
+ }
+ path.removeAllPoints();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Draws the given string, using the receiver's current font and
+ * foreground color. No tab expansion or carriage return processing
+ * will be performed. The background of the rectangular area where
+ * the string is being drawn will be filled with the receiver's
+ * background color.
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the string is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the string is to be drawn
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawString (String string, int x, int y) {
+ drawString(string, x, y, false);
+}
+
+/**
+ * Draws the given string, using the receiver's current font and
+ * foreground color. No tab expansion or carriage return processing
+ * will be performed. If <code>isTransparent</code> is <code>true</code>,
+ * then the background of the rectangular area where the string is being
+ * drawn will not be modified, otherwise it will be filled with the
+ * receiver's background color.
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the string is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the string is to be drawn
+ * @param isTransparent if <code>true</code> the background will be transparent, otherwise it will be opaque
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawString(String string, int x, int y, boolean isTransparent) {
+ drawText(string, x, y, isTransparent ? SWT.DRAW_TRANSPARENT : 0);
+}
+
+/**
+ * Draws the given string, using the receiver's current font and
+ * foreground color. Tab expansion and carriage return processing
+ * are performed. The background of the rectangular area where
+ * the text is being drawn will be filled with the receiver's
+ * background color.
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawText(String string, int x, int y) {
+ drawText(string, x, y, SWT.DRAW_DELIMITER | SWT.DRAW_TAB);
+}
+
+/**
+ * Draws the given string, using the receiver's current font and
+ * foreground color. Tab expansion and carriage return processing
+ * are performed. If <code>isTransparent</code> is <code>true</code>,
+ * then the background of the rectangular area where the text is being
+ * drawn will not be modified, otherwise it will be filled with the
+ * receiver's background color.
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param isTransparent if <code>true</code> the background will be transparent, otherwise it will be opaque
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawText(String string, int x, int y, boolean isTransparent) {
+ int flags = SWT.DRAW_DELIMITER | SWT.DRAW_TAB;
+ if (isTransparent) flags |= SWT.DRAW_TRANSPARENT;
+ drawText(string, x, y, flags);
+}
+
+/**
+ * Draws the given string, using the receiver's current font and
+ * foreground color. Tab expansion, line delimiter and mnemonic
+ * processing are performed according to the specified flags. If
+ * <code>flags</code> includes <code>DRAW_TRANSPARENT</code>,
+ * then the background of the rectangular area where the text is being
+ * drawn will not be modified, otherwise it will be filled with the
+ * receiver's background color.
+ * <p>
+ * The parameter <code>flags</code> may be a combination of:
+ * <dl>
+ * <dt><b>DRAW_DELIMITER</b></dt>
+ * <dd>draw multiple lines</dd>
+ * <dt><b>DRAW_TAB</b></dt>
+ * <dd>expand tabs</dd>
+ * <dt><b>DRAW_MNEMONIC</b></dt>
+ * <dd>underline the mnemonic character</dd>
+ * <dt><b>DRAW_TRANSPARENT</b></dt>
+ * <dd>transparent background</dd>
+ * </dl>
+ * </p>
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param flags the flags specifying how to process the text
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawText (String string, int x, int y, int flags) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ NSAutoreleasePool pool = checkGC(CLIPPING | TRANSFORM | FONT);
+ try {
+ handle.saveGraphicsState();
+ boolean mode = true;
+ switch (data.textAntialias) {
+ case SWT.DEFAULT:
+ /* Printer is off by default */
+ if (!handle.isDrawingToScreen()) mode = false;
+ break;
+ case SWT.OFF: mode = false; break;
+ case SWT.ON: mode = true; break;
+ }
+ handle.setShouldAntialias(mode);
+ NSAttributedString str = createString(string, flags, true);
+ if ((flags & SWT.DRAW_TRANSPARENT) == 0) {
+ NSSize size = str.size();
+ NSRect rect = new NSRect();
+ rect.x = x;
+ rect.y = y;
+ rect.width = size.width;
+ rect.height = size.height;
+ NSColor bg = data.bg;
+ if (bg == null) {
+ float /*double*/ [] color = data.background;
+ bg = data.bg = NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f);
+ bg.retain();
+ }
+ bg.setFill();
+ NSBezierPath.fillRect(rect);
+ str.drawInRect(rect);
+ } else {
+ NSPoint pt = new NSPoint();
+ pt.x = x;
+ pt.y = y;
+ str.drawAtPoint(pt);
+ }
+ str.release();
+ handle.restoreGraphicsState();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the <em>same</em> object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
+ *
+ * @see #hashCode
+ */
+public boolean equals(Object object) {
+ if (object == this) return true;
+ if (!(object instanceof GC)) return false;
+ return handle == ((GC)object).handle;
+}
+
+/**
+ * Fills the interior of a circular or elliptical arc within
+ * the specified rectangular area, with the receiver's background
+ * color.
+ * <p>
+ * The resulting arc begins at <code>startAngle</code> and extends
+ * for <code>arcAngle</code> degrees, using the current color.
+ * Angles are interpreted such that 0 degrees is at the 3 o'clock
+ * position. A positive value indicates a counter-clockwise rotation
+ * while a negative value indicates a clockwise rotation.
+ * </p><p>
+ * The center of the arc is the center of the rectangle whose origin
+ * is (<code>x</code>, <code>y</code>) and whose size is specified by the
+ * <code>width</code> and <code>height</code> arguments.
+ * </p><p>
+ * The resulting arc covers an area <code>width + 1</code> pixels wide
+ * by <code>height + 1</code> pixels tall.
+ * </p>
+ *
+ * @param x the x coordinate of the upper-left corner of the arc to be filled
+ * @param y the y coordinate of the upper-left corner of the arc to be filled
+ * @param width the width of the arc to be filled
+ * @param height the height of the arc to be filled
+ * @param startAngle the beginning angle
+ * @param arcAngle the angular extent of the arc, relative to the start angle
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawArc
+ */
+public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (width < 0) {
+ x = x + width;
+ width = -width;
+ }
+ if (height < 0) {
+ y = y + height;
+ height = -height;
+ }
+ if (width == 0 || height == 0 || arcAngle == 0) return;
+ NSAutoreleasePool pool = checkGC(FILL);
+ try {
+ handle.saveGraphicsState();
+ NSAffineTransform transform = NSAffineTransform.transform();
+ float /*double*/ xOffset = data.drawXOffset, yOffset = data.drawYOffset;
+ transform.translateXBy(x + xOffset + width / 2f, y + yOffset + height / 2f);
+ transform.scaleXBy(width / 2f, height / 2f);
+ NSBezierPath path = data.path;
+ NSPoint center = new NSPoint();
+ path.moveToPoint(center);
+ float sAngle = -startAngle;
+ float eAngle = -(startAngle + arcAngle);
+ path.appendBezierPathWithArcWithCenter(center, 1, sAngle, eAngle, arcAngle>0);
+ path.closePath();
+ path.transformUsingAffineTransform(transform);
+ Pattern pattern = data.backgroundPattern;
+ if (pattern != null && pattern.gradient != null) {
+ fillPattern(path, pattern);
+ } else {
+ path.fill();
+ }
+ path.removeAllPoints();
+ handle.restoreGraphicsState();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Fills the interior of the specified rectangle with a gradient
+ * sweeping from left to right or top to bottom progressing
+ * from the receiver's foreground color to its background color.
+ *
+ * @param x the x coordinate of the rectangle to be filled
+ * @param y the y coordinate of the rectangle to be filled
+ * @param width the width of the rectangle to be filled, may be negative
+ * (inverts direction of gradient if horizontal)
+ * @param height the height of the rectangle to be filled, may be negative
+ * (inverts direction of gradient if vertical)
+ * @param vertical if true sweeps from top to bottom, else
+ * sweeps from left to right
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawRectangle(int, int, int, int)
+ */
+public void fillGradientRectangle(int x, int y, int width, int height, boolean vertical) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if ((width == 0) || (height == 0)) return;
+ NSAutoreleasePool pool = checkGC(CLIPPING | TRANSFORM);
+ try {
+ RGB backgroundRGB, foregroundRGB;
+ backgroundRGB = getBackground().getRGB();
+ foregroundRGB = getForeground().getRGB();
+
+ RGB fromRGB, toRGB;
+ fromRGB = foregroundRGB;
+ toRGB = backgroundRGB;
+ boolean swapColors = false;
+ if (width < 0) {
+ x += width; width = -width;
+ if (! vertical) swapColors = true;
+ }
+ if (height < 0) {
+ y += height; height = -height;
+ if (vertical) swapColors = true;
+ }
+ if (swapColors) {
+ fromRGB = backgroundRGB;
+ toRGB = foregroundRGB;
+ }
+ if (fromRGB.equals(toRGB)) {
+ fillRectangle(x, y, width, height);
+ } else {
+ NSColor startingColor = NSColor.colorWithDeviceRed(fromRGB.red / 255f, fromRGB.green / 255f, fromRGB.blue / 255f, data.alpha / 255f);
+ NSColor endingColor = NSColor.colorWithDeviceRed(toRGB.red / 255f, toRGB.green / 255f, toRGB.blue / 255f, data.alpha / 255f);
+ NSGradient gradient = ((NSGradient)new NSGradient().alloc()).initWithStartingColor(startingColor, endingColor);
+ NSRect rect = new NSRect();
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ gradient.drawInRect(rect, vertical ? 90 : 0);
+ gradient.release();
+ }
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Fills the interior of an oval, within the specified
+ * rectangular area, with the receiver's background
+ * color.
+ *
+ * @param x the x coordinate of the upper left corner of the oval to be filled
+ * @param y the y coordinate of the upper left corner of the oval to be filled
+ * @param width the width of the oval to be filled
+ * @param height the height of the oval to be filled
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawOval
+ */
+public void fillOval(int x, int y, int width, int height) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = checkGC(FILL);
+ try {
+ if (width < 0) {
+ x = x + width;
+ width = -width;
+ }
+ if (height < 0) {
+ y = y + height;
+ height = -height;
+ }
+ NSBezierPath path = data.path;
+ NSRect rect = new NSRect();
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ path.appendBezierPathWithOvalInRect(rect);
+ Pattern pattern = data.backgroundPattern;
+ if (pattern != null && pattern.gradient != null) {
+ fillPattern(path, pattern);
+ } else {
+ path.fill();
+ }
+ path.removeAllPoints();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+void fillPattern(NSBezierPath path, Pattern pattern) {
+ handle.saveGraphicsState();
+ path.addClip();
+ NSRect bounds = path.bounds();
+ NSPoint start = new NSPoint();
+ start.x = pattern.pt1.x;
+ start.y = pattern.pt1.y;
+ NSPoint end = new NSPoint();
+ end.x = pattern.pt2.x;
+ end.y = pattern.pt2.y;
+ float /*double*/ difx = end.x - start.x;
+ float /*double*/ dify = end.y - start.y;
+ if (difx == 0 && dify == 0) {
+ float /*double*/ [] color = pattern.color1;
+ NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f).setFill();
+ path.fill();
+ handle.restoreGraphicsState();
+ return;
+ }
+ float /*double*/ startx, starty, endx, endy;
+ if (difx == 0 || dify == 0) {
+ startx = bounds.x;
+ starty = bounds.y;
+ endx = bounds.x + bounds.width;
+ endy = bounds.y + bounds.height;
+ if (difx < 0 || dify < 0) {
+ startx = endx;
+ starty = endy;
+ endx = bounds.x;
+ endy = bounds.y;
+ }
+ } else {
+ float /*double*/ m = (end.y-start.y)/(end.x - start.x);
+ float /*double*/ b = end.y - (m * end.x);
+ float /*double*/ m2 = -1/m; //perpendicular slope
+ float /*double*/ b2 = bounds.y - (m2 * bounds.x);
+ startx = endx = (b - b2) / (m2 - m);
+ b2 = (bounds.y + bounds.height) - (m2 * bounds.x);
+ float /*double*/ x2 = (b - b2) / (m2 - m);
+ startx = difx > 0 ? Math.min(startx, x2) : Math.max(startx, x2);
+ endx = difx < 0 ? Math.min(endx, x2) : Math.max(endx, x2);
+ b2 = bounds.y - (m2 * (bounds.x + bounds.width));
+ x2 = (b - b2) / (m2 - m);
+ startx = difx > 0 ? Math.min(startx, x2) : Math.max(startx, x2);
+ endx = difx < 0 ? Math.min(endx, x2) : Math.max(endx, x2);
+ b2 = (bounds.y + bounds.height) - (m2 * (bounds.x + bounds.width));
+ x2 = (b - b2) / (m2 - m);
+ startx = difx > 0 ? Math.min(startx, x2) : Math.max(startx, x2);
+ endx = difx < 0 ? Math.min(endx, x2) : Math.max(endx, x2);
+ starty = (m * startx) + b;
+ endy = (m * endx) + b;
+ }
+ if (difx != 0) {
+ while ((difx > 0 && start.x >= startx) || (difx < 0 && start.x <= startx)) {
+ start.x -= difx;
+ start.y -= dify;
+ }
+ } else {
+ while ((dify > 0 && start.y >= starty) || (dify < 0 && start.y <= starty)) {
+ start.x -= difx;
+ start.y -= dify;
+ }
+ }
+ end.x = start.x;
+ end.y = start.y;
+ do {
+ end.x += difx;
+ end.y += dify;
+ pattern.gradient.drawFromPoint(start, end, 0);
+ start.x = end.x;
+ start.y = end.y;
+ } while (
+ (difx > 0 && end.x <= endx) ||
+ (difx < 0 && end.x >= endx) ||
+ (difx == 0 && ((dify > 0 && end.y <= endy) || (dify < 0 && end.y >= endy)))
+ );
+ handle.restoreGraphicsState();
+}
+
+/**
+ * Fills the path described by the parameter.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param path the path to fill
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see Path
+ *
+ * @since 3.1
+ */
+public void fillPath(Path path) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (path.handle == null) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = checkGC(FILL);
+ try {
+ NSBezierPath drawPath = data.path;
+ drawPath.appendBezierPath(path.handle);
+ Pattern pattern = data.backgroundPattern;
+ if (pattern != null && pattern.gradient != null) {
+ fillPattern(drawPath, pattern);
+ } else {
+ drawPath.fill();
+ }
+ drawPath.removeAllPoints();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Fills the interior of the closed polygon which is defined by the
+ * specified array of integer coordinates, using the receiver's
+ * background color. The array contains alternating x and y values
+ * which are considered to represent points which are the vertices of
+ * the polygon. Lines are drawn between each consecutive pair, and
+ * between the first pair and last pair in the array.
+ *
+ * @param pointArray an array of alternating x and y values which are the vertices of the polygon
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT if pointArray is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawPolygon
+ */
+public void fillPolygon(int[] pointArray) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (pointArray.length < 4) return;
+ NSAutoreleasePool pool = checkGC(FILL);
+ try {
+ NSBezierPath path = data.path;
+ NSPoint pt = new NSPoint();
+ pt.x = pointArray[0];
+ pt.y = pointArray[1];
+ path.moveToPoint(pt);
+ int end = pointArray.length / 2 * 2;
+ for (int i = 2; i < end; i+=2) {
+ pt.x = pointArray[i];
+ pt.y = pointArray[i+1];
+ path.lineToPoint(pt);
+ }
+ path.closePath();
+ Pattern pattern = data.backgroundPattern;
+ if (pattern != null && pattern.gradient != null) {
+ fillPattern(path, pattern);
+ } else {
+ path.fill();
+ }
+ path.removeAllPoints();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Fills the interior of the rectangle specified by the arguments,
+ * using the receiver's background color.
+ *
+ * @param x the x coordinate of the rectangle to be filled
+ * @param y the y coordinate of the rectangle to be filled
+ * @param width the width of the rectangle to be filled
+ * @param height the height of the rectangle to be filled
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawRectangle(int, int, int, int)
+ */
+public void fillRectangle(int x, int y, int width, int height) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = checkGC(FILL);
+ try {
+ if (width < 0) {
+ x = x + width;
+ width = -width;
+ }
+ if (height < 0) {
+ y = y + height;
+ height = -height;
+ }
+ NSRect rect = new NSRect();
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ NSBezierPath path = data.path;
+ path.appendBezierPathWithRect(rect);
+ Pattern pattern = data.backgroundPattern;
+ if (pattern != null && pattern.gradient != null) {
+ fillPattern(path, pattern);
+ } else {
+ path.fill();
+ }
+ path.removeAllPoints();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Fills the interior of the specified rectangle, using the receiver's
+ * background color.
+ *
+ * @param rect the rectangle to be filled
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawRectangle(int, int, int, int)
+ */
+public void fillRectangle(Rectangle rect) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ fillRectangle(rect.x, rect.y, rect.width, rect.height);
+}
+
+/**
+ * Fills the interior of the round-cornered rectangle specified by
+ * the arguments, using the receiver's background color.
+ *
+ * @param x the x coordinate of the rectangle to be filled
+ * @param y the y coordinate of the rectangle to be filled
+ * @param width the width of the rectangle to be filled
+ * @param height the height of the rectangle to be filled
+ * @param arcWidth the width of the arc
+ * @param arcHeight the height of the arc
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawRoundRectangle
+ */
+public void fillRoundRectangle(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (arcWidth == 0 || arcHeight == 0) {
+ fillRectangle(x, y, width, height);
+ return;
+ }
+ NSAutoreleasePool pool = checkGC(FILL);
+ try {
+ NSBezierPath path = data.path;
+ NSRect rect = new NSRect();
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ path.appendBezierPathWithRoundedRect(rect, arcWidth / 2f, arcHeight / 2f);
+ Pattern pattern = data.backgroundPattern;
+ if (pattern != null && pattern.gradient != null) {
+ fillPattern(path, pattern);
+ } else {
+ path.fill();
+ }
+ path.removeAllPoints();
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+void strokePattern(NSBezierPath path, Pattern pattern) {
+ handle.saveGraphicsState();
+ int /*long*/ cgPath = createCGPathRef(path);
+ int /*long*/ cgContext = handle.graphicsPort();
+ OS.CGContextSaveGState(cgContext);
+ initCGContext(cgContext);
+ OS.CGContextAddPath(cgContext, cgPath);
+ OS.CGContextReplacePathWithStrokedPath(cgContext);
+ OS.CGPathRelease(cgPath);
+ cgPath = 0;
+ cgPath = OS.CGContextCopyPath(cgContext);
+ if (cgPath == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.CGContextRestoreGState(cgContext);
+ NSBezierPath strokePath = createNSBezierPath(cgPath);
+ OS.CGPathRelease(cgPath);
+ fillPattern(strokePath, pattern);
+ handle.restoreGraphicsState();
+}
+
+void flush () {
+ handle.flushGraphics();
+}
+
+/**
+ * Returns the <em>advance width</em> of the specified character in
+ * the font which is currently selected into the receiver.
+ * <p>
+ * The advance width is defined as the horizontal distance the cursor
+ * should move after printing the character in the selected font.
+ * </p>
+ *
+ * @param ch the character to measure
+ * @return the distance in the x direction to move past the character before painting the next
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getAdvanceWidth(char ch) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ //NOT DONE
+ return stringExtent(new String(new char[]{ch})).x;
+}
+
+/**
+ * Returns the background color.
+ *
+ * @return the receiver's background color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Color getBackground() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return Color.cocoa_new (data.device, data.background);
+}
+
+/**
+ * Returns the background pattern. The default value is
+ * <code>null</code>.
+ *
+ * @return the receiver's background pattern
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Pattern
+ *
+ * @since 3.1
+ */
+public Pattern getBackgroundPattern() {
+ if (handle == null) SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ return data.backgroundPattern;
+}
+
+/**
+ * Returns <code>true</code> if receiver is using the operating system's
+ * advanced graphics subsystem. Otherwise, <code>false</code> is returned
+ * to indicate that normal graphics are in use.
+ * <p>
+ * Advanced graphics may not be installed for the operating system. In this
+ * case, <code>false</code> is always returned. Some operating system have
+ * only one graphics subsystem. If this subsystem supports advanced graphics,
+ * then <code>true</code> is always returned. If any graphics operation such
+ * as alpha, antialias, patterns, interpolation, paths, clipping or transformation
+ * has caused the receiver to switch from regular to advanced graphics mode,
+ * <code>true</code> is returned. If the receiver has been explicitly switched
+ * to advanced mode and this mode is supported, <code>true</code> is returned.
+ * </p>
+ *
+ * @return the advanced value
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setAdvanced
+ *
+ * @since 3.1
+ */
+public boolean getAdvanced() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return true;
+}
+
+/**
+ * Returns the receiver's alpha value. The alpha value
+ * is between 0 (transparent) and 255 (opaque).
+ *
+ * @return the alpha value
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int getAlpha() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data.alpha;
+}
+
+/**
+ * Returns the receiver's anti-aliasing setting value, which will be
+ * one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or
+ * <code>SWT.ON</code>. Note that this controls anti-aliasing for all
+ * <em>non-text drawing</em> operations.
+ *
+ * @return the anti-aliasing setting
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getTextAntialias
+ *
+ * @since 3.1
+ */
+public int getAntialias() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data.antialias;
+}
+
+/**
+ * Returns the width of the specified character in the font
+ * selected into the receiver.
+ * <p>
+ * The width is defined as the space taken up by the actual
+ * character, not including the leading and tailing whitespace
+ * or overhang.
+ * </p>
+ *
+ * @param ch the character to measure
+ * @return the width of the character
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getCharWidth(char ch) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ //NOT DONE
+ return stringExtent(new String(new char[]{ch})).x;
+}
+
+/**
+ * Returns the bounding rectangle of the receiver's clipping
+ * region. If no clipping region is set, the return value
+ * will be a rectangle which covers the entire bounds of the
+ * object the receiver is drawing on.
+ *
+ * @return the bounding rectangle of the clipping region
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Rectangle getClipping() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSRect rect = null;
+ if (data.view != null) {
+ rect = data.view.visibleRect();
+ } else {
+ rect = new NSRect();
+ if (data.image != null) {
+ NSSize size = data.image.handle.size();
+ rect.width = size.width;
+ rect.height = size.height;
+ } else if (data.size != null) {
+ rect.width = data.size.width;
+ rect.height = data.size.height;
+ }
+ }
+ if (data.paintRect != null || data.clipPath != null || data.inverseTransform != null) {
+ if (data.paintRect != null) {
+ OS.NSIntersectionRect(rect, rect, data.paintRect);
+ }
+ if (data.clipPath != null) {
+ NSRect clip = data.clipPath.bounds();
+ OS.NSIntersectionRect(rect, rect, clip);
+ }
+ if (data.inverseTransform != null && rect.width > 0 && rect.height > 0) {
+ NSPoint pt = new NSPoint();
+ pt.x = rect.x;
+ pt.y = rect.y;
+ NSSize size = new NSSize();
+ size.width = rect.width;
+ size.height = rect.height;
+ pt = data.inverseTransform.transformPoint(pt);
+ size = data.inverseTransform.transformSize(size);
+ rect.x = pt.x;
+ rect.y = pt.y;
+ rect.width = size.width;
+ rect.height = size.height;
+ }
+ }
+ return new Rectangle((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Sets the region managed by the argument to the current
+ * clipping region of the receiver.
+ *
+ * @param region the region to fill with the clipping region
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the region is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the region is disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void getClipping(Region region) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ region.subtract(region);
+ NSRect rect = null;
+ if (data.view != null) {
+ rect = data.view.visibleRect();
+ } else {
+ rect = new NSRect();
+ if (data.image != null) {
+ NSSize size = data.image.handle.size();
+ rect.width = size.width;
+ rect.height = size.height;
+ } else if (data.size != null) {
+ rect.width = data.size.width;
+ rect.height = data.size.height;
+ }
+ }
+ region.add((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
+ NSRect paintRect = data.paintRect;
+ if (paintRect != null) {
+ region.intersect((int)paintRect.x, (int)paintRect.y, (int)paintRect.width, (int)paintRect.height);
+ }
+ if (data.clipPath != null) {
+ NSBezierPath clip = data.clipPath.bezierPathByFlatteningPath();
+ int count = (int)/*64*/clip.elementCount();
+ int pointCount = 0;
+ Region clipRgn = new Region(device);
+ int[] pointArray = new int[count * 2];
+ int /*long*/ points = OS.malloc(NSPoint.sizeof);
+ if (points == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ NSPoint pt = new NSPoint();
+ for (int i = 0; i < count; i++) {
+ int element = (int)/*64*/clip.elementAtIndex(i, points);
+ switch (element) {
+ case OS.NSMoveToBezierPathElement:
+ if (pointCount != 0) clipRgn.add(pointArray, pointCount);
+ pointCount = 0;
+ OS.memmove(pt, points, NSPoint.sizeof);
+ pointArray[pointCount++] = (int)pt.x;
+ pointArray[pointCount++] = (int)pt.y;
+ break;
+ case OS.NSLineToBezierPathElement:
+ OS.memmove(pt, points, NSPoint.sizeof);
+ pointArray[pointCount++] = (int)pt.x;
+ pointArray[pointCount++] = (int)pt.y;
+ break;
+ case OS.NSClosePathBezierPathElement:
+ if (pointCount != 0) clipRgn.add(pointArray, pointCount);
+ pointCount = 0;
+ break;
+ }
+ }
+ if (pointCount != 0) clipRgn.add(pointArray, pointCount);
+ OS.free(points);
+ region.intersect(clipRgn);
+ clipRgn.dispose();
+ }
+ if (data.inverseTransform != null) {
+ region.convertRgn(data.inverseTransform);
+ }
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns the receiver's fill rule, which will be one of
+ * <code>SWT.FILL_EVEN_ODD</code> or <code>SWT.FILL_WINDING</code>.
+ *
+ * @return the receiver's fill rule
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int getFillRule() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data.fillRule;
+}
+
+/**
+ * Returns the font currently being used by the receiver
+ * to draw and measure text.
+ *
+ * @return the receiver's font
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Font getFont() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data.font;
+}
+
+/**
+ * Returns a FontMetrics which contains information
+ * about the font currently being used by the receiver
+ * to draw and measure text.
+ *
+ * @return font metrics for the receiver's font
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public FontMetrics getFontMetrics() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = checkGC(FONT);
+ try {
+ NSFont font = data.font.handle;
+ int ascent = (int)(0.5f + font.ascender());
+ int descent = (int)(0.5f + (-font.descender() + font.leading()));
+ String s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ int averageCharWidth = stringExtent(s).x / s.length();
+ return FontMetrics.cocoa_new(ascent, descent, averageCharWidth, 0, ascent + descent);
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Returns the receiver's foreground color.
+ *
+ * @return the color used for drawing foreground things
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Color getForeground() {
+ if (handle == null) SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ return Color.cocoa_new(data.device, data.foreground);
+}
+
+/**
+ * Returns the foreground pattern. The default value is
+ * <code>null</code>.
+ *
+ * @return the receiver's foreground pattern
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Pattern
+ *
+ * @since 3.1
+ */
+public Pattern getForegroundPattern() {
+ if (handle == null) SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ return data.foregroundPattern;
+}
+
+/**
+ * Returns the GCData.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>GC</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @return the receiver's GCData
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see GCData
+ *
+ * @since 3.2
+ * @noreference This method is not intended to be referenced by clients.
+ */
+public GCData getGCData() {
+ if (handle == null) SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ return data;
+}
+
+/**
+ * Returns the receiver's interpolation setting, which will be one of
+ * <code>SWT.DEFAULT</code>, <code>SWT.NONE</code>,
+ * <code>SWT.LOW</code> or <code>SWT.HIGH</code>.
+ *
+ * @return the receiver's interpolation setting
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int getInterpolation() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ int interpolation = (int)/*64*/handle.imageInterpolation();
+ switch (interpolation) {
+ case OS.NSImageInterpolationDefault: return SWT.DEFAULT;
+ case OS.NSImageInterpolationNone: return SWT.NONE;
+ case OS.NSImageInterpolationLow: return SWT.LOW;
+ case OS.NSImageInterpolationHigh: return SWT.HIGH;
+ }
+ return SWT.DEFAULT;
+}
+
+/**
+ * Returns the receiver's line attributes.
+ *
+ * @return the line attributes used for drawing lines
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.3
+ */
+public LineAttributes getLineAttributes() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ float[] dashes = null;
+ if (data.lineDashes != null) {
+ dashes = new float[data.lineDashes.length];
+ System.arraycopy(data.lineDashes, 0, dashes, 0, dashes.length);
+ }
+ return new LineAttributes(data.lineWidth, data.lineCap, data.lineJoin, data.lineStyle, dashes, data.lineDashesOffset, data.lineMiterLimit);
+}
+
+/**
+ * Returns the receiver's line cap style, which will be one
+ * of the constants <code>SWT.CAP_FLAT</code>, <code>SWT.CAP_ROUND</code>,
+ * or <code>SWT.CAP_SQUARE</code>.
+ *
+ * @return the cap style used for drawing lines
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int getLineCap() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data.lineCap;
+}
+
+/**
+ * Returns the receiver's line dash style. The default value is
+ * <code>null</code>.
+ *
+ * @return the line dash style used for drawing lines
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int[] getLineDash() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.lineDashes == null) return null;
+ int[] lineDashes = new int[data.lineDashes.length];
+ for (int i = 0; i < lineDashes.length; i++) {
+ lineDashes[i] = (int)data.lineDashes[i];
+ }
+ return lineDashes;
+}
+
+/**
+ * Returns the receiver's line join style, which will be one
+ * of the constants <code>SWT.JOIN_MITER</code>, <code>SWT.JOIN_ROUND</code>,
+ * or <code>SWT.JOIN_BEVEL</code>.
+ *
+ * @return the join style used for drawing lines
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int getLineJoin() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data.lineJoin;
+}
+
+/**
+ * Returns the receiver's line style, which will be one
+ * of the constants <code>SWT.LINE_SOLID</code>, <code>SWT.LINE_DASH</code>,
+ * <code>SWT.LINE_DOT</code>, <code>SWT.LINE_DASHDOT</code> or
+ * <code>SWT.LINE_DASHDOTDOT</code>.
+ *
+ * @return the style used for drawing lines
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getLineStyle() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data.lineStyle;
+}
+
+/**
+ * Returns the width that will be used when drawing lines
+ * for all of the figure drawing operations (that is,
+ * <code>drawLine</code>, <code>drawRectangle</code>,
+ * <code>drawPolyline</code>, and so forth.
+ *
+ * @return the receiver's line width
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getLineWidth() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return (int)data.lineWidth;
+}
+
+/**
+ * Returns the receiver's style information.
+ * <p>
+ * Note that the value which is returned by this method <em>may
+ * not match</em> the value which was provided to the constructor
+ * when the receiver was created. This can occur when the underlying
+ * operating system does not support a particular combination of
+ * requested styles.
+ * </p>
+ *
+ * @return the style bits
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 2.1.2
+ */
+public int getStyle () {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data.style;
+}
+
+/**
+ * Returns the receiver's text drawing anti-aliasing setting value,
+ * which will be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or
+ * <code>SWT.ON</code>. Note that this controls anti-aliasing
+ * <em>only</em> for text drawing operations.
+ *
+ * @return the anti-aliasing setting
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getAntialias
+ *
+ * @since 3.1
+ */
+public int getTextAntialias() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data.textAntialias;
+}
+
+/**
+ * Sets the parameter to the transform that is currently being
+ * used by the receiver.
+ *
+ * @param transform the destination to copy the transform into
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Transform
+ *
+ * @since 3.1
+ */
+public void getTransform (Transform transform) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (transform == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (transform.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAffineTransform cmt = data.transform;
+ if (cmt != null) {
+ NSAffineTransformStruct struct = cmt.transformStruct();
+ transform.handle.setTransformStruct(struct);
+ } else {
+ transform.setElements(1, 0, 0, 1, 0, 0);
+ }
+}
+
+/**
+ * Returns <code>true</code> if this GC is drawing in the mode
+ * where the resulting color in the destination is the
+ * <em>exclusive or</em> of the color values in the source
+ * and the destination, and <code>false</code> if it is
+ * drawing in the mode where the destination color is being
+ * replaced with the source color value.
+ *
+ * @return <code>true</code> true if the receiver is in XOR mode, and false otherwise
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean getXORMode() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data.xorMode;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return <code>true</code> when passed to
+ * <code>equals</code> must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #equals
+ */
+public int hashCode() {
+ return handle != null ? (int)/*64*/handle.id : 0;
+}
+
+void init(Drawable drawable, GCData data, int /*long*/ context) {
+ if (data.foreground != null) data.state &= ~(FOREGROUND | FOREGROUND_FILL);
+ if (data.background != null) data.state &= ~BACKGROUND;
+ if (data.font != null) data.state &= ~FONT;
+ data.state &= ~DRAW_OFFSET;
+
+ Image image = data.image;
+ if (image != null) image.memGC = this;
+ this.drawable = drawable;
+ this.data = data;
+ handle = new NSGraphicsContext(context);
+ handle.retain();
+ handle.saveGraphicsState();
+ data.path = NSBezierPath.bezierPath();
+ data.path.setWindingRule(data.fillRule == SWT.FILL_WINDING ? OS.NSNonZeroWindingRule : OS.NSEvenOddWindingRule);
+ data.path.retain();
+}
+
+void initCGContext(int /*long*/ cgContext) {
+ int state = data.state;
+ if ((state & LINE_WIDTH) != 0) {
+ OS.CGContextSetLineWidth(cgContext, data.lineWidth == 0 ? 1 : data.lineWidth);
+ switch (data.lineStyle) {
+ case SWT.LINE_DOT:
+ case SWT.LINE_DASH:
+ case SWT.LINE_DASHDOT:
+ case SWT.LINE_DASHDOTDOT:
+ state |= LINE_STYLE;
+ }
+ }
+ if ((state & LINE_STYLE) != 0) {
+ float[] dashes = null;
+ float width = data.lineWidth;
+ switch (data.lineStyle) {
+ case SWT.LINE_SOLID: break;
+ case SWT.LINE_DASH: dashes = width != 0 ? LINE_DASH : LINE_DASH_ZERO; break;
+ case SWT.LINE_DOT: dashes = width != 0 ? LINE_DOT : LINE_DOT_ZERO; break;
+ case SWT.LINE_DASHDOT: dashes = width != 0 ? LINE_DASHDOT : LINE_DASHDOT_ZERO; break;
+ case SWT.LINE_DASHDOTDOT: dashes = width != 0 ? LINE_DASHDOTDOT : LINE_DASHDOTDOT_ZERO; break;
+ case SWT.LINE_CUSTOM: dashes = data.lineDashes; break;
+ }
+ if (dashes != null) {
+ float[] lengths = new float[dashes.length];
+ for (int i = 0; i < lengths.length; i++) {
+ lengths[i] = width == 0 || data.lineStyle == SWT.LINE_CUSTOM ? dashes[i] : dashes[i] * width;
+ }
+ OS.CGContextSetLineDash(cgContext, data.lineDashesOffset, lengths, lengths.length);
+ } else {
+ OS.CGContextSetLineDash(cgContext, 0, null, 0);
+ }
+ }
+ if ((state & LINE_MITERLIMIT) != 0) {
+ OS.CGContextSetMiterLimit(cgContext, data.lineMiterLimit);
+ }
+ if ((state & LINE_JOIN) != 0) {
+ int joinStyle = 0;
+ switch (data.lineJoin) {
+ case SWT.JOIN_MITER: joinStyle = OS.kCGLineJoinMiter; break;
+ case SWT.JOIN_ROUND: joinStyle = OS.kCGLineJoinRound; break;
+ case SWT.JOIN_BEVEL: joinStyle = OS.kCGLineJoinBevel; break;
+ }
+ OS.CGContextSetLineJoin(cgContext, joinStyle);
+ }
+ if ((state & LINE_CAP) != 0) {
+ int capStyle = 0;
+ switch (data.lineCap) {
+ case SWT.CAP_ROUND: capStyle = OS.kCGLineCapRound; break;
+ case SWT.CAP_FLAT: capStyle = OS.kCGLineCapButt; break;
+ case SWT.CAP_SQUARE: capStyle = OS.kCGLineCapSquare; break;
+ }
+ OS.CGContextSetLineCap(cgContext, capStyle);
+ }
+}
+
+/**
+ * Returns <code>true</code> if the receiver has a clipping
+ * region set into it, and <code>false</code> otherwise.
+ * If this method returns false, the receiver will draw on all
+ * available space in the destination. If it returns true,
+ * it will draw only in the area that is covered by the region
+ * that can be accessed with <code>getClipping(region)</code>.
+ *
+ * @return <code>true</code> if the GC has a clipping region, and <code>false</code> otherwise
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean isClipped() {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data.clipPath != null;
+}
+
+/**
+ * Returns <code>true</code> if the GC has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the GC.
+ * When a GC has been disposed, it is an error to
+ * invoke any other method using the GC.
+ *
+ * @return <code>true</code> when the GC is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return handle == null;
+}
+
+boolean isIdentity(float[] transform) {
+ return transform[0] == 1 && transform[1] == 0 && transform[2] == 0
+ && transform[3] == 1 && transform[4] == 0 && transform[5] == 0;
+}
+
+/**
+ * Sets the receiver to always use the operating system's advanced graphics
+ * subsystem for all graphics operations if the argument is <code>true</code>.
+ * If the argument is <code>false</code>, the advanced graphics subsystem is
+ * no longer used, advanced graphics state is cleared and the normal graphics
+ * subsystem is used from now on.
+ * <p>
+ * Normally, the advanced graphics subsystem is invoked automatically when
+ * any one of the alpha, antialias, patterns, interpolation, paths, clipping
+ * or transformation operations in the receiver is requested. When the receiver
+ * is switched into advanced mode, the advanced graphics subsystem performs both
+ * advanced and normal graphics operations. Because the two subsystems are
+ * different, their output may differ. Switching to advanced graphics before
+ * any graphics operations are performed ensures that the output is consistent.
+ * </p><p>
+ * Advanced graphics may not be installed for the operating system. In this
+ * case, this operation does nothing. Some operating system have only one
+ * graphics subsystem, so switching from normal to advanced graphics does
+ * nothing. However, switching from advanced to normal graphics will always
+ * clear the advanced graphics state, even for operating systems that have
+ * only one graphics subsystem.
+ * </p>
+ *
+ * @param advanced the new advanced graphics state
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setAlpha
+ * @see #setAntialias
+ * @see #setBackgroundPattern
+ * @see #setClipping(Path)
+ * @see #setForegroundPattern
+ * @see #setLineAttributes
+ * @see #setInterpolation
+ * @see #setTextAntialias
+ * @see #setTransform
+ * @see #getAdvanced
+ *
+ * @since 3.1
+ */
+public void setAdvanced(boolean advanced) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (!advanced) {
+ setAlpha(0xFF);
+ setAntialias(SWT.DEFAULT);
+ setBackgroundPattern(null);
+ setClipping((Rectangle)null);
+ setForegroundPattern(null);
+ setInterpolation(SWT.DEFAULT);
+ setTextAntialias(SWT.DEFAULT);
+ setTransform(null);
+ }
+}
+
+/**
+ * Sets the receiver's alpha value which must be
+ * between 0 (transparent) and 255 (opaque).
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ * @param alpha the alpha value
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see #getAdvanced
+ * @see #setAdvanced
+ *
+ * @since 3.1
+ */
+public void setAlpha(int alpha) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ data.alpha = alpha & 0xFF;
+ data.state &= ~(BACKGROUND | FOREGROUND | FOREGROUND_FILL);
+
+}
+
+/**
+ * Sets the receiver's anti-aliasing value to the parameter,
+ * which must be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code>
+ * or <code>SWT.ON</code>. Note that this controls anti-aliasing for all
+ * <em>non-text drawing</em> operations.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param antialias the anti-aliasing setting
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the parameter is not one of <code>SWT.DEFAULT</code>,
+ * <code>SWT.OFF</code> or <code>SWT.ON</code></li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see #getAdvanced
+ * @see #setAdvanced
+ * @see #setTextAntialias
+ *
+ * @since 3.1
+ */
+public void setAntialias(int antialias) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ boolean mode = true;
+ switch (antialias) {
+ case SWT.DEFAULT:
+ /* Printer is off by default */
+ if (!handle.isDrawingToScreen()) mode = false;
+ break;
+ case SWT.OFF: mode = false; break;
+ case SWT.ON: mode = true; break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ data.antialias = antialias;
+ handle.setShouldAntialias(mode);
+}
+
+/**
+ * Sets the background color. The background color is used
+ * for fill operations and as the background color when text
+ * is drawn.
+ *
+ * @param color the new background color for the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the color is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setBackground(Color color) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (color == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ data.background = color.handle;
+ data.backgroundPattern = null;
+ if (data.bg != null) data.bg.release();
+ data.bg = null;
+ data.state &= ~BACKGROUND;
+}
+
+/**
+ * Sets the background pattern. The default value is <code>null</code>.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param pattern the new background pattern
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see Pattern
+ * @see #getAdvanced
+ * @see #setAdvanced
+ *
+ * @since 3.1
+ */
+public void setBackgroundPattern(Pattern pattern) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pattern != null && pattern.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (data.backgroundPattern == pattern) return;
+ data.backgroundPattern = pattern;
+ data.state &= ~BACKGROUND;
+}
+
+/**
+ * Sets the area of the receiver which can be changed
+ * by drawing operations to the rectangular area specified
+ * by the arguments.
+ *
+ * @param x the x coordinate of the clipping rectangle
+ * @param y the y coordinate of the clipping rectangle
+ * @param width the width of the clipping rectangle
+ * @param height the height of the clipping rectangle
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setClipping(int x, int y, int width, int height) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ if (width < 0) {
+ x = x + width;
+ width = -width;
+ }
+ if (height < 0) {
+ y = y + height;
+ height = -height;
+ }
+ NSRect rect = new NSRect();
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ NSBezierPath path = NSBezierPath.bezierPathWithRect(rect);
+ path.retain();
+ setClipping(path);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Sets the area of the receiver which can be changed
+ * by drawing operations to the path specified
+ * by the argument.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param path the clipping path.
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the path has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see Path
+ * @see #getAdvanced
+ * @see #setAdvanced
+ *
+ * @since 3.1
+ */
+public void setClipping(Path path) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (path != null && path.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ setClipping(new NSBezierPath(path.handle.copy().id));
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Sets the area of the receiver which can be changed
+ * by drawing operations to the rectangular area specified
+ * by the argument. Specifying <code>null</code> for the
+ * rectangle reverts the receiver's clipping area to its
+ * original value.
+ *
+ * @param rect the clipping rectangle or <code>null</code>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setClipping(Rectangle rect) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (rect == null) {
+ setClipping((NSBezierPath)null);
+ } else {
+ setClipping(rect.x, rect.y, rect.width, rect.height);
+ }
+}
+
+/**
+ * Sets the area of the receiver which can be changed
+ * by drawing operations to the region specified
+ * by the argument. Specifying <code>null</code> for the
+ * region reverts the receiver's clipping area to its
+ * original value.
+ *
+ * @param region the clipping region or <code>null</code>
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the region has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setClipping(Region region) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (region != null && region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ setClipping(region != null ? region.getPath() : null);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+void setClipping(NSBezierPath path) {
+ if (data.clipPath != null) {
+ data.clipPath.release();
+ data.clipPath = null;
+ }
+ if (path != null) {
+ data.clipPath = path;
+ if (data.transform != null) {
+ data.clipPath.transformUsingAffineTransform(data.transform);
+ }
+ }
+ data.state &= ~CLIPPING;
+}
+
+/**
+ * Sets the receiver's fill rule to the parameter, which must be one of
+ * <code>SWT.FILL_EVEN_ODD</code> or <code>SWT.FILL_WINDING</code>.
+ *
+ * @param rule the new fill rule
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the rule is not one of <code>SWT.FILL_EVEN_ODD</code>
+ * or <code>SWT.FILL_WINDING</code></li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void setFillRule(int rule) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ switch (rule) {
+ case SWT.FILL_WINDING:
+ case SWT.FILL_EVEN_ODD: break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ data.fillRule = rule;
+ data.path.setWindingRule(rule == SWT.FILL_WINDING ? OS.NSNonZeroWindingRule : OS.NSEvenOddWindingRule);
+}
+
+/**
+ * Sets the font which will be used by the receiver
+ * to draw and measure text to the argument. If the
+ * argument is null, then a default font appropriate
+ * for the platform will be used instead.
+ *
+ * @param font the new font for the receiver, or null to indicate a default font
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the font has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setFont(Font font) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (font != null && font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ data.font = font != null ? font : data.device.systemFont;
+ data.state &= ~FONT;
+}
+
+/**
+ * Sets the foreground color. The foreground color is used
+ * for drawing operations including when text is drawn.
+ *
+ * @param color the new foreground color for the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the color is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setForeground(Color color) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (color == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ data.foreground = color.handle;
+ data.foregroundPattern = null;
+ if (data.fg != null) data.fg.release();
+ data.fg = null;
+ data.state &= ~(FOREGROUND | FOREGROUND_FILL);
+}
+
+/**
+ * Sets the foreground pattern. The default value is <code>null</code>.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ * @param pattern the new foreground pattern
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see Pattern
+ * @see #getAdvanced
+ * @see #setAdvanced
+ *
+ * @since 3.1
+ */
+public void setForegroundPattern(Pattern pattern) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pattern != null && pattern.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (data.foregroundPattern == pattern) return;
+ data.foregroundPattern = pattern;
+ data.state &= ~(FOREGROUND | FOREGROUND_FILL);
+}
+
+/**
+ * Sets the receiver's interpolation setting to the parameter, which
+ * must be one of <code>SWT.DEFAULT</code>, <code>SWT.NONE</code>,
+ * <code>SWT.LOW</code> or <code>SWT.HIGH</code>.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param interpolation the new interpolation setting
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the rule is not one of <code>SWT.DEFAULT</code>,
+ * <code>SWT.NONE</code>, <code>SWT.LOW</code> or <code>SWT.HIGH</code>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see #getAdvanced
+ * @see #setAdvanced
+ *
+ * @since 3.1
+ */
+public void setInterpolation(int interpolation) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ int quality = 0;
+ switch (interpolation) {
+ case SWT.DEFAULT: quality = OS.NSImageInterpolationDefault; break;
+ case SWT.NONE: quality = OS.NSImageInterpolationNone; break;
+ case SWT.LOW: quality = OS.NSImageInterpolationLow; break;
+ case SWT.HIGH: quality = OS.NSImageInterpolationHigh; break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ handle.setImageInterpolation(quality);
+}
+
+/**
+ * Sets the receiver's line attributes.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ * @param attributes the line attributes
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the attributes is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if any of the line attributes is not valid</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see LineAttributes
+ * @see #getAdvanced
+ * @see #setAdvanced
+ *
+ * @since 3.3
+ */
+public void setLineAttributes(LineAttributes attributes) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (attributes == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ int mask = 0;
+ float lineWidth = attributes.width;
+ if (lineWidth != data.lineWidth) {
+ mask |= LINE_WIDTH | DRAW_OFFSET;
+ }
+ int lineStyle = attributes.style;
+ if (lineStyle != data.lineStyle) {
+ mask |= LINE_STYLE;
+ switch (lineStyle) {
+ case SWT.LINE_SOLID:
+ case SWT.LINE_DASH:
+ case SWT.LINE_DOT:
+ case SWT.LINE_DASHDOT:
+ case SWT.LINE_DASHDOTDOT:
+ break;
+ case SWT.LINE_CUSTOM:
+ if (attributes.dash == null) lineStyle = SWT.LINE_SOLID;
+ break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ }
+ int join = attributes.join;
+ if (join != data.lineJoin) {
+ mask |= LINE_JOIN;
+ switch (join) {
+ case SWT.CAP_ROUND:
+ case SWT.CAP_FLAT:
+ case SWT.CAP_SQUARE:
+ break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ }
+ int cap = attributes.cap;
+ if (cap != data.lineCap) {
+ mask |= LINE_CAP;
+ switch (cap) {
+ case SWT.JOIN_MITER:
+ case SWT.JOIN_ROUND:
+ case SWT.JOIN_BEVEL:
+ break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ }
+ float[] dashes = attributes.dash;
+ float[] lineDashes = data.lineDashes;
+ if (dashes != null && dashes.length > 0) {
+ boolean changed = lineDashes == null || lineDashes.length != dashes.length;
+ for (int i = 0; i < dashes.length; i++) {
+ float dash = dashes[i];
+ if (dash <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (!changed && lineDashes[i] != dash) changed = true;
+ }
+ if (changed) {
+ float[] newDashes = new float[dashes.length];
+ System.arraycopy(dashes, 0, newDashes, 0, dashes.length);
+ dashes = newDashes;
+ mask |= LINE_STYLE;
+ } else {
+ dashes = lineDashes;
+ }
+ } else {
+ if (lineDashes != null && lineDashes.length > 0) {
+ mask |= LINE_STYLE;
+ } else {
+ dashes = lineDashes;
+ }
+ }
+ float dashOffset = attributes.dashOffset;
+ if (dashOffset != data.lineDashesOffset) {
+ mask |= LINE_STYLE;
+ }
+ float miterLimit = attributes.miterLimit;
+ if (miterLimit != data.lineMiterLimit) {
+ mask |= LINE_MITERLIMIT;
+ }
+ if (mask == 0) return;
+ data.lineWidth = lineWidth;
+ data.lineStyle = lineStyle;
+ data.lineCap = cap;
+ data.lineJoin = join;
+ data.lineDashes = dashes;
+ data.lineDashesOffset = dashOffset;
+ data.lineMiterLimit = miterLimit;
+ data.state &= ~mask;
+}
+
+/**
+ * Sets the receiver's line cap style to the argument, which must be one
+ * of the constants <code>SWT.CAP_FLAT</code>, <code>SWT.CAP_ROUND</code>,
+ * or <code>SWT.CAP_SQUARE</code>.
+ *
+ * @param cap the cap style to be used for drawing lines
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void setLineCap(int cap) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.lineCap == cap) return;
+ switch (cap) {
+ case SWT.CAP_ROUND:
+ case SWT.CAP_FLAT:
+ case SWT.CAP_SQUARE:
+ break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ data.lineCap = cap;
+ data.state &= ~LINE_CAP;
+}
+
+/**
+ * Sets the receiver's line dash style to the argument. The default
+ * value is <code>null</code>. If the argument is not <code>null</code>,
+ * the receiver's line style is set to <code>SWT.LINE_CUSTOM</code>, otherwise
+ * it is set to <code>SWT.LINE_SOLID</code>.
+ *
+ * @param dashes the dash style to be used for drawing lines
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if any of the values in the array is less than or equal 0</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void setLineDash(int[] dashes) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ float[] lineDashes = data.lineDashes;
+ if (dashes != null && dashes.length > 0) {
+ boolean changed = data.lineStyle != SWT.LINE_CUSTOM || lineDashes == null || lineDashes.length != dashes.length;
+ for (int i = 0; i < dashes.length; i++) {
+ int dash = dashes[i];
+ if (dash <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (!changed && lineDashes[i] != dash) changed = true;
+ }
+ if (!changed) return;
+ data.lineDashes = new float[dashes.length];
+ for (int i = 0; i < dashes.length; i++) {
+ data.lineDashes[i] = dashes[i];
+ }
+ data.lineStyle = SWT.LINE_CUSTOM;
+ } else {
+ if (data.lineStyle == SWT.LINE_SOLID && (lineDashes == null || lineDashes.length == 0)) return;
+ data.lineDashes = null;
+ data.lineStyle = SWT.LINE_SOLID;
+ }
+ data.state &= ~LINE_STYLE;
+}
+
+/**
+ * Sets the receiver's line join style to the argument, which must be one
+ * of the constants <code>SWT.JOIN_MITER</code>, <code>SWT.JOIN_ROUND</code>,
+ * or <code>SWT.JOIN_BEVEL</code>.
+ *
+ * @param join the join style to be used for drawing lines
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void setLineJoin(int join) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.lineJoin == join) return;
+ switch (join) {
+ case SWT.JOIN_MITER:
+ case SWT.JOIN_ROUND:
+ case SWT.JOIN_BEVEL:
+ break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ data.lineJoin = join;
+ data.state &= ~LINE_JOIN;
+}
+
+/**
+ * Sets the receiver's line style to the argument, which must be one
+ * of the constants <code>SWT.LINE_SOLID</code>, <code>SWT.LINE_DASH</code>,
+ * <code>SWT.LINE_DOT</code>, <code>SWT.LINE_DASHDOT</code> or
+ * <code>SWT.LINE_DASHDOTDOT</code>.
+ *
+ * @param lineStyle the style to be used for drawing lines
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setLineStyle(int lineStyle) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.lineStyle == lineStyle) return;
+ switch (lineStyle) {
+ case SWT.LINE_SOLID:
+ case SWT.LINE_DASH:
+ case SWT.LINE_DOT:
+ case SWT.LINE_DASHDOT:
+ case SWT.LINE_DASHDOTDOT:
+ break;
+ case SWT.LINE_CUSTOM:
+ if (data.lineDashes == null) lineStyle = SWT.LINE_SOLID;
+ break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ data.lineStyle = lineStyle;
+ data.state &= ~LINE_STYLE;
+}
+
+/**
+ * Sets the width that will be used when drawing lines
+ * for all of the figure drawing operations (that is,
+ * <code>drawLine</code>, <code>drawRectangle</code>,
+ * <code>drawPolyline</code>, and so forth.
+ * <p>
+ * Note that line width of zero is used as a hint to
+ * indicate that the fastest possible line drawing
+ * algorithms should be used. This means that the
+ * output may be different from line width one.
+ * </p>
+ *
+ * @param lineWidth the width of a line
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setLineWidth(int lineWidth) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.lineWidth == lineWidth) return;
+ data.lineWidth = lineWidth;
+ data.state &= ~(LINE_WIDTH | DRAW_OFFSET);
+}
+
+/**
+ * If the argument is <code>true</code>, puts the receiver
+ * in a drawing mode where the resulting color in the destination
+ * is the <em>exclusive or</em> of the color values in the source
+ * and the destination, and if the argument is <code>false</code>,
+ * puts the receiver in a drawing mode where the destination color
+ * is replaced with the source color value.
+ * <p>
+ * Note that this mode in fundamentally unsupportable on certain
+ * platforms, notably Carbon (Mac OS X). Clients that want their
+ * code to run on all platforms need to avoid this method.
+ * </p>
+ *
+ * @param xor if <code>true</code>, then <em>xor</em> mode is used, otherwise <em>source copy</em> mode is used
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @deprecated this functionality is not supported on some platforms
+ */
+public void setXORMode(boolean xor) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ data.xorMode = xor;
+}
+
+/**
+ * Sets the receiver's text anti-aliasing value to the parameter,
+ * which must be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code>
+ * or <code>SWT.ON</code>. Note that this controls anti-aliasing only
+ * for all <em>text drawing</em> operations.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param antialias the anti-aliasing setting
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the parameter is not one of <code>SWT.DEFAULT</code>,
+ * <code>SWT.OFF</code> or <code>SWT.ON</code></li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see #getAdvanced
+ * @see #setAdvanced
+ * @see #setAntialias
+ *
+ * @since 3.1
+ */
+public void setTextAntialias(int antialias) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ switch (antialias) {
+ case SWT.DEFAULT:
+ case SWT.OFF:
+ case SWT.ON:
+ break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ data.textAntialias = antialias;
+}
+
+/**
+ * Sets the transform that is currently being used by the receiver. If
+ * the argument is <code>null</code>, the current transform is set to
+ * the identity transform.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param transform the transform to set
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see Transform
+ * @see #getAdvanced
+ * @see #setAdvanced
+ *
+ * @since 3.1
+ */
+public void setTransform(Transform transform) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (transform != null && transform.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (transform != null) {
+ if (data.transform != null) data.transform.release();
+ if (data.inverseTransform != null) data.inverseTransform.release();
+ data.transform = ((NSAffineTransform)new NSAffineTransform().alloc()).initWithTransform(transform.handle);
+ data.inverseTransform = ((NSAffineTransform)new NSAffineTransform().alloc()).initWithTransform(transform.handle);
+ NSAffineTransformStruct struct = data.inverseTransform.transformStruct();
+ if ((struct.m11 * struct.m22 - struct.m12 * struct.m21) != 0) {
+ data.inverseTransform.invert();
+ }
+ } else {
+ data.transform = data.inverseTransform = null;
+ }
+ data.state &= ~(TRANSFORM | DRAW_OFFSET);
+}
+
+/**
+ * Returns the extent of the given string. No tab
+ * expansion or carriage return processing will be performed.
+ * <p>
+ * The <em>extent</em> of a string is the width and height of
+ * the rectangular area it would cover if drawn in a particular
+ * font (in this case, the current font in the receiver).
+ * </p>
+ *
+ * @param string the string to measure
+ * @return a point containing the extent of the string
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Point stringExtent(String string) {
+ return textExtent(string, 0);
+}
+
+/**
+ * Returns the extent of the given string. Tab expansion and
+ * carriage return processing are performed.
+ * <p>
+ * The <em>extent</em> of a string is the width and height of
+ * the rectangular area it would cover if drawn in a particular
+ * font (in this case, the current font in the receiver).
+ * </p>
+ *
+ * @param string the string to measure
+ * @return a point containing the extent of the string
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Point textExtent(String string) {
+ return textExtent(string, SWT.DRAW_DELIMITER | SWT.DRAW_TAB);
+}
+
+/**
+ * Returns the extent of the given string. Tab expansion, line
+ * delimiter and mnemonic processing are performed according to
+ * the specified flags, which can be a combination of:
+ * <dl>
+ * <dt><b>DRAW_DELIMITER</b></dt>
+ * <dd>draw multiple lines</dd>
+ * <dt><b>DRAW_TAB</b></dt>
+ * <dd>expand tabs</dd>
+ * <dt><b>DRAW_MNEMONIC</b></dt>
+ * <dd>underline the mnemonic character</dd>
+ * <dt><b>DRAW_TRANSPARENT</b></dt>
+ * <dd>transparent background</dd>
+ * </dl>
+ * <p>
+ * The <em>extent</em> of a string is the width and height of
+ * the rectangular area it would cover if drawn in a particular
+ * font (in this case, the current font in the receiver).
+ * </p>
+ *
+ * @param string the string to measure
+ * @param flags the flags specifying how to process the text
+ * @return a point containing the extent of the string
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Point textExtent(String string, int flags) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ NSAutoreleasePool pool = checkGC(FONT);
+ try {
+ NSAttributedString str = createString(string, flags, false);
+ NSSize size = str.size();
+ str.release();
+ return new Point((int)size.width, (int)size.height);
+ } finally {
+ uncheckGC(pool);
+ }
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+public String toString () {
+ if (isDisposed()) return "GC {*DISPOSED*}";
+ return "GC {" + handle + "}";
+}
+
+void uncheckGC(NSAutoreleasePool pool) {
+ if (data.flippedContext != null && data.restoreContext) {
+ NSGraphicsContext.static_restoreGraphicsState();
+ data.restoreContext = false;
+ }
+ NSView view = data.view;
+ if (view != null && data.paintRect == null) {
+ if (data.thread != Thread.currentThread()) flush();
+ }
+ if (pool != null) pool.release();
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GCData.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GCData.java
new file mode 100755
index 0000000000..9e44658e63
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GCData.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class are descriptions of GCs in terms
+ * of unallocated platform-specific data fields.
+ * <p>
+ * <b>IMPORTANT:</b> This class is <em>not</em> part of the public
+ * API for SWT. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms, and should never be called from application code.
+ * </p>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+public final class GCData {
+ public Device device;
+ public int style, state = -1;
+ public float /*double*/ [] foreground;
+ public float /*double*/ [] background;
+ public Pattern foregroundPattern;
+ public Pattern backgroundPattern;
+ public Font font;
+ public int alpha = 0xFF;
+ public float lineWidth;
+ public int lineStyle = SWT.LINE_SOLID;
+ public int lineCap = SWT.CAP_FLAT;
+ public int lineJoin = SWT.JOIN_MITER;
+ public float lineDashesOffset;
+ public float[] lineDashes;
+ public float lineMiterLimit = 10;
+ public boolean xorMode;
+ public int antialias = SWT.DEFAULT;
+ public int textAntialias = SWT.DEFAULT;
+ public int fillRule = SWT.FILL_EVEN_ODD;
+ public Image image;
+
+ public NSColor fg, bg;
+ public float /*double*/ drawXOffset, drawYOffset;
+ public NSRect paintRect;
+ public NSBezierPath path;
+ public NSAffineTransform transform, inverseTransform;
+ public NSBezierPath clipPath, visiblePath;
+ public int /*long*/ visibleRgn;
+ public NSView view;
+ public NSSize size;
+ public Thread thread;
+ public NSGraphicsContext flippedContext;
+ public boolean restoreContext;
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java
new file mode 100755
index 0000000000..646c5de74b
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java
@@ -0,0 +1,1192 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+import org.eclipse.swt.*;
+import java.io.*;
+
+/**
+ * Instances of this class are graphics which have been prepared
+ * for display on a specific device. That is, they are ready
+ * to paint using methods such as <code>GC.drawImage()</code>
+ * and display on widgets with, for example, <code>Button.setImage()</code>.
+ * <p>
+ * If loaded from a file format that supports it, an
+ * <code>Image</code> may have transparency, meaning that certain
+ * pixels are specified as being transparent when drawn. Examples
+ * of file formats that support transparency are GIF and PNG.
+ * </p><p>
+ * There are two primary ways to use <code>Images</code>.
+ * The first is to load a graphic file from disk and create an
+ * <code>Image</code> from it. This is done using an <code>Image</code>
+ * constructor, for example:
+ * <pre>
+ * Image i = new Image(device, "C:\\graphic.bmp");
+ * </pre>
+ * A graphic file may contain a color table specifying which
+ * colors the image was intended to possess. In the above example,
+ * these colors will be mapped to the closest available color in
+ * SWT. It is possible to get more control over the mapping of
+ * colors as the image is being created, using code of the form:
+ * <pre>
+ * ImageData data = new ImageData("C:\\graphic.bmp");
+ * RGB[] rgbs = data.getRGBs();
+ * // At this point, rgbs contains specifications of all
+ * // the colors contained within this image. You may
+ * // allocate as many of these colors as you wish by
+ * // using the Color constructor Color(RGB), then
+ * // create the image:
+ * Image i = new Image(device, data);
+ * </pre>
+ * <p>
+ * Applications which require even greater control over the image
+ * loading process should use the support provided in class
+ * <code>ImageLoader</code>.
+ * </p><p>
+ * Application code must explicitly invoke the <code>Image.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ *
+ * @see Color
+ * @see ImageData
+ * @see ImageLoader
+ * @see <a href="http://www.eclipse.org/swt/snippets/#image">Image snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: GraphicsExample, ImageAnalyzer</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+public final class Image extends Resource implements Drawable {
+
+ /**
+ * specifies whether the receiver is a bitmap or an icon
+ * (one of <code>SWT.BITMAP</code>, <code>SWT.ICON</code>)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public int type;
+
+ /**
+ * the handle to the OS image resource
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public NSImage handle;
+
+ /**
+ * specifies the transparent pixel
+ */
+ int transparentPixel = -1;
+
+ /**
+ * The GC the image is currently selected in.
+ */
+ GC memGC;
+
+ /**
+ * The alpha data of the image.
+ */
+ byte[] alphaData;
+
+ /**
+ * The global alpha value to be used for every pixel.
+ */
+ int alpha = -1;
+
+ /**
+ * The width of the image.
+ */
+ int width = -1;
+
+ /**
+ * The height of the image.
+ */
+ int height = -1;
+
+ /**
+ * Specifies the default scanline padding.
+ */
+ static final int DEFAULT_SCANLINE_PAD = 4;
+
+Image(Device device) {
+ super(device);
+}
+
+/**
+ * Constructs an empty instance of this class with the
+ * specified width and height. The result may be drawn upon
+ * by creating a GC and using any of its drawing operations,
+ * as shown in the following example:
+ * <pre>
+ * Image i = new Image(device, width, height);
+ * GC gc = new GC(i);
+ * gc.drawRectangle(0, 0, 50, 50);
+ * gc.dispose();
+ * </pre>
+ * <p>
+ * Note: Some platforms may have a limitation on the size
+ * of image that can be created (size depends on width, height,
+ * and depth). For example, Windows 95, 98, and ME do not allow
+ * images larger than 16M.
+ * </p>
+ *
+ * @param device the device on which to create the image
+ * @param width the width of the new image
+ * @param height the height of the new image
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_INVALID_ARGUMENT - if either the width or height is negative or zero</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public Image(Device device, int width, int height) {
+ super(device);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ init(width, height);
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Constructs a new instance of this class based on the
+ * provided image, with an appearance that varies depending
+ * on the value of the flag. The possible flag values are:
+ * <dl>
+ * <dt><b>{@link SWT#IMAGE_COPY}</b></dt>
+ * <dd>the result is an identical copy of srcImage</dd>
+ * <dt><b>{@link SWT#IMAGE_DISABLE}</b></dt>
+ * <dd>the result is a copy of srcImage which has a <em>disabled</em> look</dd>
+ * <dt><b>{@link SWT#IMAGE_GRAY}</b></dt>
+ * <dd>the result is a copy of srcImage which has a <em>gray scale</em> look</dd>
+ * </dl>
+ *
+ * @param device the device on which to create the image
+ * @param srcImage the image to use as the source
+ * @param flag the style, either <code>IMAGE_COPY</code>, <code>IMAGE_DISABLE</code> or <code>IMAGE_GRAY</code>
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if srcImage is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the flag is not one of <code>IMAGE_COPY</code>, <code>IMAGE_DISABLE</code> or <code>IMAGE_GRAY</code></li>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon, or is otherwise in an invalid state</li>
+ * <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the image is not supported</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public Image(Device device, Image srcImage, int flag) {
+ super(device);
+ if (srcImage == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (srcImage.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ switch (flag) {
+ case SWT.IMAGE_COPY:
+ case SWT.IMAGE_DISABLE:
+ case SWT.IMAGE_GRAY:
+ break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ device = this.device;
+ this.type = srcImage.type;
+ /* Get source image size */
+ NSSize size = srcImage.handle.size();
+ int width = (int)size.width;
+ int height = (int)size.height;
+ NSBitmapImageRep srcRep = srcImage.getRepresentation();
+ int /*long*/ bpr = srcRep.bytesPerRow();
+
+ /* Copy transparent pixel and alpha data when necessary */
+ transparentPixel = srcImage.transparentPixel;
+ alpha = srcImage.alpha;
+ if (srcImage.alphaData != null) {
+ alphaData = new byte[srcImage.alphaData.length];
+ System.arraycopy(srcImage.alphaData, 0, alphaData, 0, alphaData.length);
+ }
+
+ /* Create the image */
+ handle = (NSImage)new NSImage().alloc();
+ handle = handle.initWithSize(size);
+ NSBitmapImageRep rep = (NSBitmapImageRep)new NSBitmapImageRep().alloc();
+ rep = rep.initWithBitmapDataPlanes(0, width, height, srcRep.bitsPerSample(), srcRep.samplesPerPixel(), srcRep.samplesPerPixel() == 4, srcRep.isPlanar(), OS.NSDeviceRGBColorSpace, OS.NSAlphaFirstBitmapFormat | OS.NSAlphaNonpremultipliedBitmapFormat, srcRep.bytesPerRow(), srcRep.bitsPerPixel());
+ handle.addRepresentation(rep);
+ rep.release();
+ handle.setCacheMode(OS.NSImageCacheNever);
+
+ int /*long*/ data = rep.bitmapData();
+ OS.memmove(data, srcRep.bitmapData(), width * height * 4);
+ if (flag != SWT.IMAGE_COPY) {
+
+ /* Apply transformation */
+ switch (flag) {
+ case SWT.IMAGE_DISABLE: {
+ Color zeroColor = device.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
+ RGB zeroRGB = zeroColor.getRGB();
+ byte zeroRed = (byte)zeroRGB.red;
+ byte zeroGreen = (byte)zeroRGB.green;
+ byte zeroBlue = (byte)zeroRGB.blue;
+ Color oneColor = device.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
+ RGB oneRGB = oneColor.getRGB();
+ byte oneRed = (byte)oneRGB.red;
+ byte oneGreen = (byte)oneRGB.green;
+ byte oneBlue = (byte)oneRGB.blue;
+ byte[] line = new byte[(int)/*64*/bpr];
+ for (int y=0; y<height; y++) {
+ OS.memmove(line, data + (y * bpr), bpr);
+ int offset = 0;
+ for (int x=0; x<width; x++) {
+ int red = line[offset+1] & 0xFF;
+ int green = line[offset+2] & 0xFF;
+ int blue = line[offset+3] & 0xFF;
+ int intensity = red * red + green * green + blue * blue;
+ if (intensity < 98304) {
+ line[offset+1] = zeroRed;
+ line[offset+2] = zeroGreen;
+ line[offset+3] = zeroBlue;
+ } else {
+ line[offset+1] = oneRed;
+ line[offset+2] = oneGreen;
+ line[offset+3] = oneBlue;
+ }
+ offset += 4;
+ }
+ OS.memmove(data + (y * bpr), line, bpr);
+ }
+ break;
+ }
+ case SWT.IMAGE_GRAY: {
+ byte[] line = new byte[(int)/*64*/bpr];
+ for (int y=0; y<height; y++) {
+ OS.memmove(line, data + (y * bpr), bpr);
+ int offset = 0;
+ for (int x=0; x<width; x++) {
+ int red = line[offset+1] & 0xFF;
+ int green = line[offset+2] & 0xFF;
+ int blue = line[offset+3] & 0xFF;
+ byte intensity = (byte)((red+red+green+green+green+green+green+blue) >> 3);
+ line[offset+1] = line[offset+2] = line[offset+3] = intensity;
+ offset += 4;
+ }
+ OS.memmove(data + (y * bpr), line, bpr);
+ }
+ break;
+ }
+ }
+ }
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Constructs an empty instance of this class with the
+ * width and height of the specified rectangle. The result
+ * may be drawn upon by creating a GC and using any of its
+ * drawing operations, as shown in the following example:
+ * <pre>
+ * Image i = new Image(device, boundsRectangle);
+ * GC gc = new GC(i);
+ * gc.drawRectangle(0, 0, 50, 50);
+ * gc.dispose();
+ * </pre>
+ * <p>
+ * Note: Some platforms may have a limitation on the size
+ * of image that can be created (size depends on width, height,
+ * and depth). For example, Windows 95, 98, and ME do not allow
+ * images larger than 16M.
+ * </p>
+ *
+ * @param device the device on which to create the image
+ * @param bounds a rectangle specifying the image's width and height (must not be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the bounds rectangle is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if either the rectangle's width or height is negative</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public Image(Device device, Rectangle bounds) {
+ super(device);
+ if (bounds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ init(bounds.width, bounds.height);
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Constructs an instance of this class from the given
+ * <code>ImageData</code>.
+ *
+ * @param device the device on which to create the image
+ * @param data the image data to create the image from (must not be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the image data is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the ImageData is not supported</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public Image(Device device, ImageData data) {
+ super(device);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ init(data);
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Constructs an instance of this class, whose type is
+ * <code>SWT.ICON</code>, from the two given <code>ImageData</code>
+ * objects. The two images must be the same size. Pixel transparency
+ * in either image will be ignored.
+ * <p>
+ * The mask image should contain white wherever the icon is to be visible,
+ * and black wherever the icon is to be transparent. In addition,
+ * the source image should contain black wherever the icon is to be
+ * transparent.
+ * </p>
+ *
+ * @param device the device on which to create the icon
+ * @param source the color data for the icon
+ * @param mask the mask data for the icon
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if either the source or mask is null </li>
+ * <li>ERROR_INVALID_ARGUMENT - if source and mask are different sizes</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public Image(Device device, ImageData source, ImageData mask) {
+ super(device);
+ if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (mask == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (source.width != mask.width || source.height != mask.height) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ mask = ImageData.convertMask(mask);
+ ImageData image = new ImageData(source.width, source.height, source.depth, source.palette, source.scanlinePad, source.data);
+ image.maskPad = mask.scanlinePad;
+ image.maskData = mask.data;
+ init(image);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Constructs an instance of this class by loading its representation
+ * from the specified input stream. Throws an error if an error
+ * occurs while loading the image, or if the result is an image
+ * of an unsupported type. Application code is still responsible
+ * for closing the input stream.
+ * <p>
+ * This constructor is provided for convenience when loading a single
+ * image only. If the stream contains multiple images, only the first
+ * one will be loaded. To load multiple images, use
+ * <code>ImageLoader.load()</code>.
+ * </p><p>
+ * This constructor may be used to load a resource as follows:
+ * </p>
+ * <pre>
+ * static Image loadImage (Display display, Class clazz, String string) {
+ * InputStream stream = clazz.getResourceAsStream (string);
+ * if (stream == null) return null;
+ * Image image = null;
+ * try {
+ * image = new Image (display, stream);
+ * } catch (SWTException ex) {
+ * } finally {
+ * try {
+ * stream.close ();
+ * } catch (IOException ex) {}
+ * }
+ * return image;
+ * }
+ * </pre>
+ *
+ * @param device the device on which to create the image
+ * @param stream the input stream to load the image from
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the stream is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_IO - if an IO error occurs while reading from the stream</li>
+ * <li>ERROR_INVALID_IMAGE - if the image stream contains invalid data </li>
+ * <li>ERROR_UNSUPPORTED_DEPTH - if the image stream describes an image with an unsupported depth</li>
+ * <li>ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public Image(Device device, InputStream stream) {
+ super(device);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ init(new ImageData(stream));
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Constructs an instance of this class by loading its representation
+ * from the file with the specified name. Throws an error if an error
+ * occurs while loading the image, or if the result is an image
+ * of an unsupported type.
+ * <p>
+ * This constructor is provided for convenience when loading
+ * a single image only. If the specified file contains
+ * multiple images, only the first one will be used.
+ *
+ * @param device the device on which to create the image
+ * @param filename the name of the file to load the image from
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_IO - if an IO error occurs while reading from the file</li>
+ * <li>ERROR_INVALID_IMAGE - if the image file contains invalid data </li>
+ * <li>ERROR_UNSUPPORTED_DEPTH - if the image file describes an image with an unsupported depth</li>
+ * <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public Image(Device device, String filename) {
+ super(device);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ initNative(filename);
+ if (this.handle == null) init(new ImageData(filename));
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+void createAlpha () {
+ if (transparentPixel == -1 && alpha == -1 && alphaData == null) return;
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSBitmapImageRep imageRep = getRepresentation();
+ int /*long*/ height = imageRep.pixelsHigh();
+ int /*long*/ bpr = imageRep.bytesPerRow();
+ int /*long*/ dataSize = height * bpr;
+ byte[] srcData = new byte[(int)/*64*/dataSize];
+ OS.memmove(srcData, imageRep.bitmapData(), dataSize);
+ if (transparentPixel != -1) {
+ for (int i=0; i<dataSize; i+=4) {
+ int pixel = ((srcData[i+1] & 0xFF) << 16) | ((srcData[i+2] & 0xFF) << 8) | (srcData[i+3] & 0xFF);
+ srcData[i] = (byte)(pixel == transparentPixel ? 0 : 0xFF);
+ }
+ } else if (alpha != -1) {
+ byte a = (byte)this.alpha;
+ for (int i=0; i<dataSize; i+=4) {
+ srcData[i] = a;
+ }
+ } else {
+ int /*long*/ width = imageRep.pixelsWide();
+ int offset = 0, alphaOffset = 0;
+ for (int y = 0; y<height; y++) {
+ for (int x = 0; x<width; x++) {
+ srcData[offset] = alphaData[alphaOffset];
+ offset += 4;
+ alphaOffset += 1;
+ }
+ }
+ }
+
+ // Since we just calculated alpha for the image rep, tell it that it now has an alpha component.
+ imageRep.setAlpha(true);
+
+ OS.memmove(imageRep.bitmapData(), srcData, dataSize);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+void destroy() {
+ if (memGC != null) memGC.dispose();
+ handle.release();
+ handle = null;
+ memGC = null;
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the <em>same</em> object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
+ *
+ * @see #hashCode
+ */
+public boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof Image)) return false;
+ Image image = (Image)object;
+ return device == image.device && handle == image.handle &&
+ transparentPixel == image.transparentPixel;
+}
+
+/**
+ * Returns the color to which to map the transparent pixel, or null if
+ * the receiver has no transparent pixel.
+ * <p>
+ * There are certain uses of Images that do not support transparency
+ * (for example, setting an image into a button or label). In these cases,
+ * it may be desired to simulate transparency by using the background
+ * color of the widget to paint the transparent pixels of the image.
+ * Use this method to check which color will be used in these cases
+ * in place of transparency. This value may be set with setBackground().
+ * <p>
+ *
+ * @return the background color of the image, or null if there is no transparency in the image
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Color getBackground() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (transparentPixel == -1) return null;
+ int red = (transparentPixel >> 16) & 0xFF;
+ int green = (transparentPixel >> 8) & 0xFF;
+ int blue = (transparentPixel >> 0) & 0xFF;
+ return Color.cocoa_new(device, new float /*double*/ []{red / 255f, green / 255f, blue / 255f, 1});
+}
+
+/**
+ * Returns the bounds of the receiver. The rectangle will always
+ * have x and y values of 0, and the width and height of the
+ * image.
+ *
+ * @return a rectangle specifying the image's bounds
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li>
+ * </ul>
+ */
+public Rectangle getBounds() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ if (width != -1 && height != -1) {
+ return new Rectangle(0, 0, width, height);
+ }
+ NSSize size = handle.size();
+ return new Rectangle(0, 0, width = (int)size.width, height = (int)size.height);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns an <code>ImageData</code> based on the receiver
+ * Modifications made to this <code>ImageData</code> will not
+ * affect the Image.
+ *
+ * @return an <code>ImageData</code> containing the image's data and attributes
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li>
+ * </ul>
+ *
+ * @see ImageData
+ */
+public ImageData getImageData() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSBitmapImageRep imageRep = getRepresentation();
+ int /*long*/ width = imageRep.pixelsWide();
+ int /*long*/ height = imageRep.pixelsHigh();
+ int /*long*/ bpr = imageRep.bytesPerRow();
+ int /*long*/ bpp = imageRep.bitsPerPixel();
+ int /*long*/ dataSize = height * bpr;
+
+ byte[] srcData = new byte[(int)/*64*/dataSize];
+ OS.memmove(srcData, imageRep.bitmapData(), dataSize);
+
+ PaletteData palette = new PaletteData(0xFF0000, 0xFF00, 0xFF);
+ ImageData data = new ImageData((int)/*64*/width, (int)/*64*/height, (int)/*64*/bpp, palette, 4, srcData);
+ data.bytesPerLine = (int)/*64*/bpr;
+
+ data.transparentPixel = transparentPixel;
+ if (transparentPixel == -1 && type == SWT.ICON) {
+ /* Get the icon mask data */
+ int maskPad = 2;
+ int /*long*/ maskBpl = (((width + 7) / 8) + (maskPad - 1)) / maskPad * maskPad;
+ byte[] maskData = new byte[(int)/*64*/(height * maskBpl)];
+ int offset = 0, maskOffset = 0;
+ for (int y = 0; y<height; y++) {
+ for (int x = 0; x<width; x++) {
+ if (srcData[offset] != 0) {
+ maskData[maskOffset + (x >> 3)] |= (1 << (7 - (x & 0x7)));
+ } else {
+ maskData[maskOffset + (x >> 3)] &= ~(1 << (7 - (x & 0x7)));
+ }
+ offset += 4;
+ }
+ maskOffset += maskBpl;
+ }
+ data.maskData = maskData;
+ data.maskPad = maskPad;
+ }
+ for (int i = 0; i < srcData.length; i+= 4) {
+ srcData[i] = 0;
+ }
+ data.alpha = alpha;
+ if (alpha == -1 && alphaData != null) {
+ data.alphaData = new byte[alphaData.length];
+ System.arraycopy(alphaData, 0, data.alphaData, 0, alphaData.length);
+ }
+ return data;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new image.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Image</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param device the device on which to allocate the color
+ * @param type the type of the image (<code>SWT.BITMAP</code> or <code>SWT.ICON</code>)
+ * @param handle the OS handle for the image
+ * @param data the OS data for the image
+ *
+ * @private
+ */
+public static Image cocoa_new(Device device, int type, NSImage nsImage) {
+ Image image = new Image(device);
+ image.type = type;
+ image.handle = nsImage;
+ return image;
+}
+
+NSBitmapImageRep getRepresentation () {
+ NSImageRep rep = handle.bestRepresentationForDevice(null);
+ if (!rep.isKindOfClass(OS.class_NSBitmapImageRep)) {
+ SWT.error(SWT.ERROR_UNSPECIFIED);
+ }
+ return new NSBitmapImageRep(rep);
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return <code>true</code> when passed to
+ * <code>equals</code> must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+public int hashCode () {
+ return handle != null ? (int)/*64*/handle.id : 0;
+}
+
+void init(int width, int height) {
+ if (width <= 0 || height <= 0) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.type = SWT.BITMAP;
+ this.width = width;
+ this.height = height;
+
+ handle = (NSImage)new NSImage().alloc();
+ NSSize size = new NSSize();
+ size.width = width;
+ size.height = height;
+ handle = handle.initWithSize(size);
+ NSBitmapImageRep rep = (NSBitmapImageRep)new NSBitmapImageRep().alloc();
+ rep = rep.initWithBitmapDataPlanes(0, width, height, 8, 3, false, false, OS.NSDeviceRGBColorSpace, OS.NSAlphaFirstBitmapFormat | OS.NSAlphaNonpremultipliedBitmapFormat, width * 4, 32);
+ OS.memset(rep.bitmapData(), 0xFF, width * height * 4);
+ handle.addRepresentation(rep);
+ rep.release();
+ handle.setCacheMode(OS.NSImageCacheNever);
+}
+
+void init(ImageData image) {
+ if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ this.width = image.width;
+ this.height = image.height;
+ PaletteData palette = image.palette;
+ if (!(((image.depth == 1 || image.depth == 2 || image.depth == 4 || image.depth == 8) && !palette.isDirect) ||
+ ((image.depth == 8) || (image.depth == 16 || image.depth == 24 || image.depth == 32) && palette.isDirect)))
+ SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
+
+ /* Create the image */
+ int dataSize = width * height * 4;
+
+ /* Initialize data */
+ int bpr = width * 4;
+ byte[] buffer = new byte[dataSize];
+ if (palette.isDirect) {
+ ImageData.blit(ImageData.BLIT_SRC,
+ image.data, image.depth, image.bytesPerLine, image.getByteOrder(), 0, 0, width, height, palette.redMask, palette.greenMask, palette.blueMask,
+ ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+ buffer, 32, bpr, ImageData.MSB_FIRST, 0, 0, width, height, 0xFF0000, 0xFF00, 0xFF,
+ false, false);
+ } else {
+ RGB[] rgbs = palette.getRGBs();
+ int length = rgbs.length;
+ byte[] srcReds = new byte[length];
+ byte[] srcGreens = new byte[length];
+ byte[] srcBlues = new byte[length];
+ for (int i = 0; i < rgbs.length; i++) {
+ RGB rgb = rgbs[i];
+ if (rgb == null) continue;
+ srcReds[i] = (byte)rgb.red;
+ srcGreens[i] = (byte)rgb.green;
+ srcBlues[i] = (byte)rgb.blue;
+ }
+ ImageData.blit(ImageData.BLIT_SRC,
+ image.data, image.depth, image.bytesPerLine, image.getByteOrder(), 0, 0, width, height, srcReds, srcGreens, srcBlues,
+ ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+ buffer, 32, bpr, ImageData.MSB_FIRST, 0, 0, width, height, 0xFF0000, 0xFF00, 0xFF,
+ false, false);
+ }
+
+ /* Initialize transparency */
+ int transparency = image.getTransparencyType();
+ boolean hasAlpha = transparency != SWT.TRANSPARENCY_NONE;
+ if (transparency == SWT.TRANSPARENCY_MASK || image.transparentPixel != -1) {
+ this.type = image.transparentPixel != -1 ? SWT.BITMAP : SWT.ICON;
+ if (image.transparentPixel != -1) {
+ int transRed = 0, transGreen = 0, transBlue = 0;
+ if (palette.isDirect) {
+ RGB rgb = palette.getRGB(image.transparentPixel);
+ transRed = rgb.red;
+ transGreen = rgb.green;
+ transBlue = rgb.blue;
+ } else {
+ RGB[] rgbs = palette.getRGBs();
+ if (image.transparentPixel < rgbs.length) {
+ RGB rgb = rgbs[image.transparentPixel];
+ transRed = rgb.red;
+ transGreen = rgb.green;
+ transBlue = rgb.blue;
+ }
+ }
+ transparentPixel = transRed << 16 | transGreen << 8 | transBlue;
+ }
+ ImageData maskImage = image.getTransparencyMask();
+ byte[] maskData = maskImage.data;
+ int maskBpl = maskImage.bytesPerLine;
+ int offset = 0, maskOffset = 0;
+ for (int y = 0; y<height; y++) {
+ for (int x = 0; x<width; x++) {
+ buffer[offset] = ((maskData[maskOffset + (x >> 3)]) & (1 << (7 - (x & 0x7)))) != 0 ? (byte)0xff : 0;
+ offset += 4;
+ }
+ maskOffset += maskBpl;
+ }
+ } else {
+ this.type = SWT.BITMAP;
+ if (image.alpha != -1) {
+ hasAlpha = true;
+ this.alpha = image.alpha;
+ byte a = (byte)this.alpha;
+ for (int dataIndex=0; dataIndex<buffer.length; dataIndex+=4) {
+ buffer[dataIndex] = a;
+ }
+ } else if (image.alphaData != null) {
+ hasAlpha = true;
+ this.alphaData = new byte[image.alphaData.length];
+ System.arraycopy(image.alphaData, 0, this.alphaData, 0, alphaData.length);
+ int offset = 0, alphaOffset = 0;
+ for (int y = 0; y<height; y++) {
+ for (int x = 0; x<width; x++) {
+ buffer[offset] = alphaData[alphaOffset];
+ offset += 4;
+ alphaOffset += 1;
+ }
+ }
+ }
+ }
+
+ if (handle != null) handle.release();
+
+ handle = (NSImage)new NSImage().alloc();
+ NSSize size = new NSSize();
+ size.width = width;
+ size.height = height;
+ handle = handle.initWithSize(size);
+ NSBitmapImageRep rep = (NSBitmapImageRep)new NSBitmapImageRep().alloc();
+ rep = rep.initWithBitmapDataPlanes(0, width, height, 8, hasAlpha ? 4 : 3, hasAlpha, false, OS.NSDeviceRGBColorSpace, OS.NSAlphaFirstBitmapFormat | OS.NSAlphaNonpremultipliedBitmapFormat, bpr, 32);
+ OS.memmove(rep.bitmapData(), buffer, dataSize);
+ handle.addRepresentation(rep);
+ rep.release();
+ handle.setCacheMode(OS.NSImageCacheNever);
+}
+
+void initNative(String filename) {
+ NSAutoreleasePool pool = null;
+ NSImage nativeImage = null;
+
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ nativeImage = new NSImage();
+ nativeImage.alloc();
+
+ // initByReferencingFile returns null if the file can't be found or is
+ // not an image.
+ nativeImage = nativeImage.initWithContentsOfFile(NSString.stringWith(filename));
+ if (nativeImage == null) {
+ // In order to get the same kind of exception, let the file format try to load and throw
+ // the appropriate exception. It is possible file format supports some image formats
+ // that is not natively supported as well.
+ return;
+ }
+
+ NSImageRep nativeRep = nativeImage.bestRepresentationForDevice(null);
+ if (!nativeRep.isKindOfClass(OS.class_NSBitmapImageRep)) {
+ return;
+ }
+
+ width = (int)/*64*/nativeRep.pixelsWide();
+ height = (int)/*64*/nativeRep.pixelsHigh();
+
+ boolean hasAlpha = nativeRep.hasAlpha();
+ int bpr = width * 4;
+ handle = (NSImage)new NSImage().alloc();
+ NSSize size = new NSSize();
+ size.width = width;
+ size.height = height;
+ handle = handle.initWithSize(size);
+ NSBitmapImageRep rep = (NSBitmapImageRep)new NSBitmapImageRep().alloc();
+ rep = rep.initWithBitmapDataPlanes(0, width, height, 8, hasAlpha ? 4 : 3, hasAlpha, false, OS.NSDeviceRGBColorSpace, OS.NSAlphaFirstBitmapFormat | OS.NSAlphaNonpremultipliedBitmapFormat, bpr, 32);
+ handle.addRepresentation(rep);
+ rep.release();
+ handle.setCacheMode(OS.NSImageCacheNever);
+ NSRect rect = new NSRect();
+ rect.width = width;
+ rect.height = height;
+
+ /* Compute the pixels */
+ int /*long*/ colorspace = OS.CGColorSpaceCreateDeviceRGB();
+ int /*long*/ ctx = OS.CGBitmapContextCreate(rep.bitmapData(), width, height, 8, bpr, colorspace, OS.kCGImageAlphaNoneSkipFirst);
+ OS.CGColorSpaceRelease(colorspace);
+ NSGraphicsContext.static_saveGraphicsState();
+ NSGraphicsContext.setCurrentContext(NSGraphicsContext.graphicsContextWithGraphicsPort(ctx, false));
+ if (hasAlpha) OS.objc_msgSend(nativeRep.id, OS.sel_setAlpha_, 0);
+ nativeRep.drawInRect(rect);
+ if (hasAlpha) OS.objc_msgSend(nativeRep.id, OS.sel_setAlpha_, 1);
+ NSGraphicsContext.static_restoreGraphicsState();
+ OS.CGContextRelease(ctx);
+
+ if (hasAlpha) {
+ /* Compute the alpha values */
+ int /*long*/ bitmapBytesPerRow = width;
+ int /*long*/ bitmapByteCount = bitmapBytesPerRow * height;
+ int /*long*/ alphaBitmapData = OS.malloc(bitmapByteCount);
+ int /*long*/ alphaBitmapCtx = OS.CGBitmapContextCreate(alphaBitmapData, width, height, 8, bitmapBytesPerRow, 0, OS.kCGImageAlphaOnly);
+ NSGraphicsContext.static_saveGraphicsState();
+ NSGraphicsContext.setCurrentContext(NSGraphicsContext.graphicsContextWithGraphicsPort(alphaBitmapCtx, false));
+ nativeRep.drawInRect(rect);
+ NSGraphicsContext.static_restoreGraphicsState();
+ byte[] alphaData = new byte[(int)/*64*/bitmapByteCount];
+ OS.memmove(alphaData, alphaBitmapData, bitmapByteCount);
+ OS.free(alphaBitmapData);
+ OS.CGContextRelease(alphaBitmapCtx);
+
+ /* Merge the alpha values with the pixels */
+ byte[] srcData = new byte[height * bpr];
+ OS.memmove(srcData, rep.bitmapData(), srcData.length);
+ for (int a = 0, p = 0; a < alphaData.length; a++, p += 4) {
+ srcData[p] = alphaData[a];
+ }
+ OS.memmove(rep.bitmapData(), srcData, srcData.length);
+
+ // If the alpha has only 0 or 255 (-1) for alpha values, compute the transparent pixel color instead
+ // of a continuous alpha range.
+ int transparentOffset = -1, i = 0;
+ for (i = 0; i < alphaData.length; i++) {
+ int alpha = alphaData[i];
+ if (transparentOffset == -1 && alpha == 0) transparentOffset = i;
+ if (!(alpha == 0 || alpha == -1)) break;
+ }
+ this.alpha = -1;
+ if (i == alphaData.length && transparentOffset != -1) {
+ NSColor color = rep.colorAtX(transparentOffset % width, transparentOffset / width);
+ int red = (int) (color.redComponent() * 255);
+ int green = (int) (color.greenComponent() * 255);
+ int blue = (int) (color.blueComponent() * 255);
+ this.transparentPixel = (red << 16) + (green << 8) + blue;
+ } else {
+ this.alphaData = alphaData;
+ }
+ }
+
+ // For compatibility, images created from .ico files are treated as SWT.ICON format, even though
+ // they are no different than other bitmaps in Cocoa.
+ if (filename.toLowerCase().endsWith(".ico")) {
+ this.type = SWT.ICON;
+ } else {
+ this.type = SWT.BITMAP;
+ }
+ } finally {
+ if (nativeImage != null) nativeImage.release();
+ if (pool != null) pool.release();
+ }
+
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Image</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param data the platform specific GC data
+ * @return the platform specific GC handle
+ */
+public int /*long*/ internal_new_GC (GCData data) {
+ if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (type != SWT.BITMAP || memGC != null) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSBitmapImageRep imageRep = getRepresentation();
+
+ // Can't perform transforms on image reps with alpha.
+ imageRep.setAlpha(false);
+
+ NSGraphicsContext context = NSGraphicsContext.graphicsContextWithBitmapImageRep(imageRep);
+ NSGraphicsContext flippedContext = NSGraphicsContext.graphicsContextWithGraphicsPort(context.graphicsPort(), true);
+ context = flippedContext;
+ context.retain();
+ if (data != null) data.flippedContext = flippedContext;
+ NSGraphicsContext.static_saveGraphicsState();
+ NSGraphicsContext.setCurrentContext(context);
+ NSAffineTransform transform = NSAffineTransform.transform();
+ NSSize size = handle.size();
+ transform.translateXBy(0, size.height);
+ transform.scaleXBy(1, -1);
+ transform.set();
+ NSGraphicsContext.static_restoreGraphicsState();
+ if (data != null) {
+ int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
+ if ((data.style & mask) == 0) {
+ data.style |= SWT.LEFT_TO_RIGHT;
+ }
+ data.device = device;
+ data.background = device.COLOR_WHITE.handle;
+ data.foreground = device.COLOR_BLACK.handle;
+ data.font = device.systemFont;
+ data.image = this;
+ }
+ return context.id;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Invokes platform specific functionality to dispose a GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Image</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param hDC the platform specific GC handle
+ * @param data the platform specific GC data
+ */
+public void internal_dispose_GC (int /*long*/ context, GCData data) {
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ if (context != 0) {
+ NSGraphicsContext contextObj = new NSGraphicsContext(context);
+ contextObj.release();
+ }
+// handle.setCacheMode(OS.NSImageCacheDefault);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns <code>true</code> if the image has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the image.
+ * When an image has been disposed, it is an error to
+ * invoke any other method using the image.
+ *
+ * @return <code>true</code> when the image is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return handle == null;
+}
+
+/**
+ * Sets the color to which to map the transparent pixel.
+ * <p>
+ * There are certain uses of <code>Images</code> that do not support
+ * transparency (for example, setting an image into a button or label).
+ * In these cases, it may be desired to simulate transparency by using
+ * the background color of the widget to paint the transparent pixels
+ * of the image. This method specifies the color that will be used in
+ * these cases. For example:
+ * <pre>
+ * Button b = new Button();
+ * image.setBackground(b.getBackground());
+ * b.setImage(image);
+ * </pre>
+ * </p><p>
+ * The image may be modified by this operation (in effect, the
+ * transparent regions may be filled with the supplied color). Hence
+ * this operation is not reversible and it is not legal to call
+ * this function twice or with a null argument.
+ * </p><p>
+ * This method has no effect if the receiver does not have a transparent
+ * pixel value.
+ * </p>
+ *
+ * @param color the color to use when a transparent pixel is specified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the color is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setBackground(Color color) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (color == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (transparentPixel == -1) return;
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ byte red = (byte)((transparentPixel >> 16) & 0xFF);
+ byte green = (byte)((transparentPixel >> 8) & 0xFF);
+ byte blue = (byte)((transparentPixel >> 0) & 0xFF);
+ byte newRed = (byte)((int)(color.handle[0] * 255) & 0xFF);
+ byte newGreen = (byte)((int)(color.handle[1] * 255) & 0xFF);
+ byte newBlue = (byte)((int)(color.handle[2] * 255) & 0xFF);
+ NSBitmapImageRep imageRep = getRepresentation();
+ int /*long*/ bpr = imageRep.bytesPerRow();
+ int /*long*/ data = imageRep.bitmapData();
+ byte[] line = new byte[(int)bpr];
+ for (int i = 0, offset = 0; i < height; i++, offset += bpr) {
+ OS.memmove(line, data + offset, bpr);
+ for (int j = 0; j < line.length; j += 4) {
+ if (line[j+ 1] == red && line[j + 2] == green && line[j + 3] == blue) {
+ line[j + 1] = newRed;
+ line[j + 2] = newGreen;
+ line[j + 3] = newBlue;
+ }
+ }
+ OS.memmove(data + offset, line, bpr);
+ }
+ transparentPixel = (newRed & 0xFF) << 16 | (newGreen & 0xFF) << 8 | (newBlue & 0xFF);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+public String toString () {
+ if (isDisposed()) return "Image {*DISPOSED*}";
+ return "Image {" + handle + "}";
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Path.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Path.java
new file mode 100755
index 0000000000..7ab8a8b4ea
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Path.java
@@ -0,0 +1,759 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class represent paths through the two-dimensional
+ * coordinate system. Paths do not have to be continuous, and can be
+ * described using lines, rectangles, arcs, cubic or quadratic bezier curves,
+ * glyphs, or other paths.
+ * <p>
+ * Application code must explicitly invoke the <code>Path.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ * <p>
+ * This class requires the operating system's advanced graphics subsystem
+ * which may not be available on some platforms.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#path">Path, Pattern snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: GraphicsExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.1
+ */
+public class Path extends Resource {
+
+ /**
+ * the OS resource for the Path
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public NSBezierPath handle;
+
+/**
+ * Constructs a new empty Path.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the path
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the path could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ */
+public Path (Device device) {
+ super(device);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ handle = NSBezierPath.bezierPath();
+ if (handle == null) SWT.error(SWT.ERROR_NO_HANDLES);
+ handle.retain();
+ handle.moveToPoint(new NSPoint());
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Constructs a new Path that is a copy of <code>path</code>. If
+ * <code>flatness</code> is less than or equal to zero, an unflatten
+ * copy of the path is created. Otherwise, it specifies the maximum
+ * error between the path and its flatten copy. Smaller numbers give
+ * better approximation.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the path
+ * @param path the path to make a copy
+ * @param flatness the flatness value
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the path is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the path has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the path could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ * @since 3.4
+ */
+public Path (Device device, Path path, float flatness) {
+ super(device);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (path.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ flatness = Math.max(0, flatness);
+ if (flatness == 0) {
+ handle = new NSBezierPath(path.handle.copy().id);
+ } else {
+ float /*double*/ defaultFlatness = NSBezierPath.defaultFlatness();
+ NSBezierPath.setDefaultFlatness(flatness);
+ handle = path.handle.bezierPathByFlatteningPath();
+ handle.retain();
+ NSBezierPath.setDefaultFlatness(defaultFlatness);
+ }
+ if (handle == null) SWT.error(SWT.ERROR_NO_HANDLES);
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Constructs a new Path with the specifed PathData.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the path
+ * @param data the data for the path
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the data is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the path could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ * @since 3.4
+ */
+public Path (Device device, PathData data) {
+ this(device);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ init(data);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Adds to the receiver a circular or elliptical arc that lies within
+ * the specified rectangular area.
+ * <p>
+ * The resulting arc begins at <code>startAngle</code> and extends
+ * for <code>arcAngle</code> degrees.
+ * Angles are interpreted such that 0 degrees is at the 3 o'clock
+ * position. A positive value indicates a counter-clockwise rotation
+ * while a negative value indicates a clockwise rotation.
+ * </p><p>
+ * The center of the arc is the center of the rectangle whose origin
+ * is (<code>x</code>, <code>y</code>) and whose size is specified by the
+ * <code>width</code> and <code>height</code> arguments.
+ * </p><p>
+ * The resulting arc covers an area <code>width + 1</code> pixels wide
+ * by <code>height + 1</code> pixels tall.
+ * </p>
+ *
+ * @param x the x coordinate of the upper-left corner of the arc
+ * @param y the y coordinate of the upper-left corner of the arc
+ * @param width the width of the arc
+ * @param height the height of the arc
+ * @param startAngle the beginning angle
+ * @param arcAngle the angular extent of the arc, relative to the start angle
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void addArc(float x, float y, float width, float height, float startAngle, float arcAngle) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSAffineTransform transform = NSAffineTransform.transform();
+ transform.translateXBy(x + width / 2f, y + height / 2f);
+ transform.scaleXBy(width / 2f, height / 2f);
+ NSBezierPath path = NSBezierPath.bezierPath();
+ NSPoint center = new NSPoint();
+ float sAngle = -startAngle;
+ float eAngle = -(startAngle + arcAngle);
+ path.appendBezierPathWithArcWithCenter(center, 1, sAngle, eAngle, arcAngle>0);
+ path.transformUsingAffineTransform(transform);
+ handle.appendBezierPath(path);
+ if (Math.abs(arcAngle) >= 360) handle.closePath();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Adds to the receiver the path described by the parameter.
+ *
+ * @param path the path to add to the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void addPath(Path path) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (path.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ handle.appendBezierPath(path.handle);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Adds to the receiver the rectangle specified by x, y, width and height.
+ *
+ * @param x the x coordinate of the rectangle to add
+ * @param y the y coordinate of the rectangle to add
+ * @param width the width of the rectangle to add
+ * @param height the height of the rectangle to add
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void addRectangle(float x, float y, float width, float height) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSRect rect = new NSRect();
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ handle.appendBezierPathWithRect(rect);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Adds to the receiver the pattern of glyphs generated by drawing
+ * the given string using the given font starting at the point (x, y).
+ *
+ * @param string the text to use
+ * @param x the x coordinate of the starting point
+ * @param y the y coordinate of the starting point
+ * @param font the font to use
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the font is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the font has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void addString(String string, float x, float y, Font font) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (font == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSString str = NSString.stringWith(string);
+ NSTextStorage textStorage = (NSTextStorage)new NSTextStorage().alloc().init();
+ NSLayoutManager layoutManager = (NSLayoutManager)new NSLayoutManager().alloc().init();
+ NSTextContainer textContainer = (NSTextContainer)new NSTextContainer().alloc();
+ NSSize size = new NSSize();
+ size.width = Float.MAX_VALUE;
+ size.height = Float.MAX_VALUE;
+ textContainer.initWithContainerSize(size);
+ textStorage.addLayoutManager(layoutManager);
+ layoutManager.addTextContainer(textContainer);
+ NSRange range = new NSRange();
+ range.length = str.length();
+ /*
+ * Feature in Cocoa. Adding attributes directly to a NSTextStorage causes
+ * output to the console and eventually a segmentation fault when printing
+ * on a thread other than the main thread. The fix is to add attributes to
+ * a separate NSMutableAttributedString and add it to text storage when done.
+ */
+ NSMutableAttributedString attrStr = (NSMutableAttributedString)new NSMutableAttributedString().alloc();
+ attrStr.id = attrStr.initWithString(str).id;
+ attrStr.beginEditing();
+ attrStr.addAttribute(OS.NSFontAttributeName, font.handle, range);
+ font.addTraits(attrStr, range);
+ attrStr.endEditing();
+ textStorage.setAttributedString(attrStr);
+ attrStr.release();
+ range = layoutManager.glyphRangeForTextContainer(textContainer);
+ if (range.length != 0) {
+ int /*long*/ glyphs = OS.malloc(4 * range.length * 2);
+ layoutManager.getGlyphs(glyphs, range);
+ NSBezierPath path = NSBezierPath.bezierPath();
+ NSPoint point = new NSPoint();
+ path.moveToPoint(point);
+ path.appendBezierPathWithGlyphs(glyphs, range.length, font.handle);
+ NSAffineTransform transform = NSAffineTransform.transform();
+ transform.scaleXBy(1, -1);
+ float /*double*/ baseline = layoutManager.defaultBaselineOffsetForFont(font.handle);
+ transform.translateXBy(x, -(y + baseline));
+ path.transformUsingAffineTransform(transform);
+ OS.free(glyphs);
+ handle.appendBezierPath(path);
+ }
+ textContainer.release();
+ layoutManager.release();
+ textStorage.release();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Closes the current sub path by adding to the receiver a line
+ * from the current point of the path back to the starting point
+ * of the sub path.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void close() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ handle.closePath();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns <code>true</code> if the specified point is contained by
+ * the receiver and false otherwise.
+ * <p>
+ * If outline is <code>true</code>, the point (x, y) checked for containment in
+ * the receiver's outline. If outline is <code>false</code>, the point is
+ * checked to see if it is contained within the bounds of the (closed) area
+ * covered by the receiver.
+ *
+ * @param x the x coordinate of the point to test for containment
+ * @param y the y coordinate of the point to test for containment
+ * @param gc the GC to use when testing for containment
+ * @param outline controls whether to check the outline or contained area of the path
+ * @return <code>true</code> if the path contains the point and <code>false</code> otherwise
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the gc is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the gc has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean contains(float x, float y, GC gc, boolean outline) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (gc == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (gc.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ //TODO - see windows
+ if (outline) {
+ int /*long*/ pixel = OS.malloc(4);
+ if (pixel == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int[] buffer = new int[]{0xFFFFFFFF};
+ OS.memmove(pixel, buffer, 4);
+ int /*long*/ colorspace = OS.CGColorSpaceCreateDeviceRGB();
+ int /*long*/ context = OS.CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorspace, OS.kCGImageAlphaNoneSkipFirst);
+ OS.CGColorSpaceRelease(colorspace);
+ if (context == 0) {
+ OS.free(pixel);
+ SWT.error(SWT.ERROR_NO_HANDLES);
+ }
+ GCData data = gc.data;
+ int capStyle = 0;
+ switch (data.lineCap) {
+ case SWT.CAP_ROUND: capStyle = OS.kCGLineCapRound; break;
+ case SWT.CAP_FLAT: capStyle = OS.kCGLineCapButt; break;
+ case SWT.CAP_SQUARE: capStyle = OS.kCGLineCapSquare; break;
+ }
+ OS.CGContextSetLineCap(context, capStyle);
+ int joinStyle = 0;
+ switch (data.lineJoin) {
+ case SWT.JOIN_MITER: joinStyle = OS.kCGLineJoinMiter; break;
+ case SWT.JOIN_ROUND: joinStyle = OS.kCGLineJoinRound; break;
+ case SWT.JOIN_BEVEL: joinStyle = OS.kCGLineJoinBevel; break;
+ }
+ OS.CGContextSetLineJoin(context, joinStyle);
+ OS.CGContextSetLineWidth(context, data.lineWidth);
+ OS.CGContextTranslateCTM(context, -x + 0.5f, -y + 0.5f);
+ int /*long*/ path = GC.createCGPathRef(handle);
+ OS.CGContextAddPath(context, path);
+ OS.CGPathRelease(path);
+ OS.CGContextStrokePath(context);
+ OS.CGContextRelease(context);
+ OS.memmove(buffer, pixel, 4);
+ OS.free(pixel);
+ return buffer[0] != 0xFFFFFFFF;
+ } else {
+ NSPoint point = new NSPoint();
+ point.x = x;
+ point.y = y;
+ return handle.containsPoint(point);
+ }
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Adds to the receiver a cubic bezier curve based on the parameters.
+ *
+ * @param cx1 the x coordinate of the first control point of the spline
+ * @param cy1 the y coordinate of the first control of the spline
+ * @param cx2 the x coordinate of the second control of the spline
+ * @param cy2 the y coordinate of the second control of the spline
+ * @param x the x coordinate of the end point of the spline
+ * @param y the y coordinate of the end point of the spline
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSPoint pt = new NSPoint();
+ pt.x = x;
+ pt.y = y;
+ NSPoint ct1 = new NSPoint();
+ ct1.x = cx1;
+ ct1.y = cy1;
+ NSPoint ct2 = new NSPoint();
+ ct2.x = cx2;
+ ct2.y = cy2;
+ handle.curveToPoint(pt, ct1, ct2);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+void destroy() {
+ handle.release();
+ handle = null;
+}
+
+/**
+ * Replaces the first four elements in the parameter with values that
+ * describe the smallest rectangle that will completely contain the
+ * receiver (i.e. the bounding box).
+ *
+ * @param bounds the array to hold the result
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the parameter is too small to hold the bounding box</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void getBounds(float[] bounds) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (bounds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (bounds.length < 4) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSRect rect = handle.controlPointBounds();
+ bounds[0] = (float)/*64*/rect.x;
+ bounds[1] = (float)/*64*/rect.y;
+ bounds[2] = (float)/*64*/rect.width;
+ bounds[3] = (float)/*64*/rect.height;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Replaces the first two elements in the parameter with values that
+ * describe the current point of the path.
+ *
+ * @param point the array to hold the result
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the parameter is too small to hold the end point</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void getCurrentPoint(float[] point) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (point == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (point.length < 2) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSPoint pt = handle.currentPoint();
+ point[0] = (float)/*64*/pt.x;
+ point[1] = (float)/*64*/pt.y;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns a device independent representation of the receiver.
+ *
+ * @return the PathData for the receiver
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see PathData
+ */
+public PathData getPathData() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ int count = (int)/*64*/handle.elementCount();
+ int pointCount = 0, typeCount = 0;
+ byte[] types = new byte[count];
+ float[] pointArray = new float[count * 6];
+ int /*long*/ points = OS.malloc(3 * NSPoint.sizeof);
+ if (points == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ NSPoint pt = new NSPoint();
+ for (int i = 0; i < count; i++) {
+ int element = (int)/*64*/handle.elementAtIndex(i, points);
+ switch (element) {
+ case OS.NSMoveToBezierPathElement:
+ types[typeCount++] = SWT.PATH_MOVE_TO;
+ OS.memmove(pt, points, NSPoint.sizeof);
+ pointArray[pointCount++] = (int)pt.x;
+ pointArray[pointCount++] = (int)pt.y;
+ break;
+ case OS.NSLineToBezierPathElement:
+ types[typeCount++] = SWT.PATH_LINE_TO;
+ OS.memmove(pt, points, NSPoint.sizeof);
+ pointArray[pointCount++] = (int)pt.x;
+ pointArray[pointCount++] = (int)pt.y;
+ break;
+ case OS.NSCurveToBezierPathElement:
+ types[typeCount++] = SWT.PATH_CUBIC_TO;
+ OS.memmove(pt, points, NSPoint.sizeof);
+ pointArray[pointCount++] = (int)pt.x;
+ pointArray[pointCount++] = (int)pt.y;
+ OS.memmove(pt, points + NSPoint.sizeof, NSPoint.sizeof);
+ pointArray[pointCount++] = (int)pt.x;
+ pointArray[pointCount++] = (int)pt.y;
+ OS.memmove(pt, points + NSPoint.sizeof + NSPoint.sizeof, NSPoint.sizeof);
+ pointArray[pointCount++] = (int)pt.x;
+ pointArray[pointCount++] = (int)pt.y;
+ break;
+ case OS.NSClosePathBezierPathElement:
+ types[typeCount++] = SWT.PATH_CLOSE;
+ break;
+ }
+ }
+ OS.free(points);
+ if (pointCount != pointArray.length) {
+ float[] temp = new float[pointCount];
+ System.arraycopy(pointArray, 0, temp, 0, pointCount);
+ pointArray = temp;
+ }
+ PathData data = new PathData();
+ data.types = types;
+ data.points = pointArray;
+ return data;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+void init(PathData data) {
+ byte[] types = data.types;
+ float[] points = data.points;
+ for (int i = 0, j = 0; i < types.length; i++) {
+ switch (types[i]) {
+ case SWT.PATH_MOVE_TO:
+ moveTo(points[j++], points[j++]);
+ break;
+ case SWT.PATH_LINE_TO:
+ lineTo(points[j++], points[j++]);
+ break;
+ case SWT.PATH_CUBIC_TO:
+ cubicTo(points[j++], points[j++], points[j++], points[j++], points[j++], points[j++]);
+ break;
+ case SWT.PATH_QUAD_TO:
+ quadTo(points[j++], points[j++], points[j++], points[j++]);
+ break;
+ case SWT.PATH_CLOSE:
+ close();
+ break;
+ default:
+ dispose();
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ }
+}
+
+/**
+ * Returns <code>true</code> if the Path has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the Path.
+ * When a Path has been disposed, it is an error to
+ * invoke any other method using the Path.
+ *
+ * @return <code>true</code> when the Path is disposed, and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return handle == null;
+}
+
+/**
+ * Adds to the receiver a line from the current point to
+ * the point specified by (x, y).
+ *
+ * @param x the x coordinate of the end of the line to add
+ * @param y the y coordinate of the end of the line to add
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void lineTo(float x, float y) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSPoint pt = new NSPoint();
+ pt.x = x;
+ pt.y = y;
+ handle.lineToPoint(pt);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Sets the current point of the receiver to the point
+ * specified by (x, y). Note that this starts a new
+ * sub path.
+ *
+ * @param x the x coordinate of the new end point
+ * @param y the y coordinate of the new end point
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void moveTo(float x, float y) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSPoint pt = new NSPoint();
+ pt.x = x;
+ pt.y = y;
+ handle.moveToPoint(pt);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Adds to the receiver a quadratic curve based on the parameters.
+ *
+ * @param cx the x coordinate of the control point of the spline
+ * @param cy the y coordinate of the control point of the spline
+ * @param x the x coordinate of the end point of the spline
+ * @param y the y coordinate of the end point of the spline
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void quadTo(float cx, float cy, float x, float y) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSPoint pt = new NSPoint();
+ pt.x = x;
+ pt.y = y;
+ NSPoint ct = new NSPoint();
+ ct.x = cx;
+ ct.y = cy;
+ handle.curveToPoint(pt, ct, ct);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+public String toString () {
+ if (isDisposed()) return "Path {*DISPOSED*}";
+ return "Path {" + handle + "}";
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Pattern.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Pattern.java
new file mode 100755
index 0000000000..1670e9ab87
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Pattern.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class represent patterns to use while drawing. Patterns
+ * can be specified either as bitmaps or gradients.
+ * <p>
+ * Application code must explicitly invoke the <code>Pattern.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ * <p>
+ * This class requires the operating system's advanced graphics subsystem
+ * which may not be available on some platforms.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#path">Path, Pattern snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: GraphicsExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.1
+ */
+public class Pattern extends Resource {
+ NSColor color;
+ NSGradient gradient;
+ NSPoint pt1, pt2;
+ Image image;
+ float /*double*/ [] color1, color2;
+ int alpha1, alpha2;
+
+/**
+ * Constructs a new Pattern given an image. Drawing with the resulting
+ * pattern will cause the image to be tiled over the resulting area.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the pattern
+ * @param image the image that the pattern will draw
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device, or the image is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the pattern could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ */
+public Pattern(Device device, Image image) {
+ super(device);
+ if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ this.image = image;
+ color = NSColor.colorWithPatternImage(image.handle);
+ color.retain();
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Constructs a new Pattern that represents a linear, two color
+ * gradient. Drawing with the pattern will cause the resulting area to be
+ * tiled with the gradient specified by the arguments.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the pattern
+ * @param x1 the x coordinate of the starting corner of the gradient
+ * @param y1 the y coordinate of the starting corner of the gradient
+ * @param x2 the x coordinate of the ending corner of the gradient
+ * @param y2 the y coordinate of the ending corner of the gradient
+ * @param color1 the starting color of the gradient
+ * @param color2 the ending color of the gradient
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device,
+ * or if either color1 or color2 is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if either color1 or color2 has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the pattern could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ */
+public Pattern(Device device, float x1, float y1, float x2, float y2, Color color1, Color color2) {
+ this(device, x1, y1, x2, y2, color1, 0xFF, color2, 0xFF);
+}
+/**
+ * Constructs a new Pattern that represents a linear, two color
+ * gradient. Drawing with the pattern will cause the resulting area to be
+ * tiled with the gradient specified by the arguments.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the pattern
+ * @param x1 the x coordinate of the starting corner of the gradient
+ * @param y1 the y coordinate of the starting corner of the gradient
+ * @param x2 the x coordinate of the ending corner of the gradient
+ * @param y2 the y coordinate of the ending corner of the gradient
+ * @param color1 the starting color of the gradient
+ * @param alpha1 the starting alpha value of the gradient
+ * @param color2 the ending color of the gradient
+ * @param alpha2 the ending alpha value of the gradient
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device,
+ * or if either color1 or color2 is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if either color1 or color2 has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the pattern could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ *
+ * @since 3.2
+ */
+public Pattern(Device device, float x1, float y1, float x2, float y2, Color color1, int alpha1, Color color2, int alpha2) {
+ super(device);
+ if (color1 == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (color1.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (color2 == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (color2.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ pt1 = new NSPoint();
+ pt2 = new NSPoint();
+ pt1.x = x1;
+ pt1.y = y1;
+ pt2.x = x2;
+ pt2.y = y2;
+ this.color1 = color1.handle;
+ this.color2 = color2.handle;
+ this.alpha1 = alpha1;
+ this.alpha2 = alpha2;
+ NSColor start = NSColor.colorWithDeviceRed(color1.handle[0], color1.handle[1], color1.handle[2], alpha1 / 255f);
+ NSColor end = NSColor.colorWithDeviceRed(color2.handle[0], color2.handle[1], color2.handle[2], alpha2 / 255f);
+ gradient = ((NSGradient)new NSGradient().alloc()).initWithStartingColor(start, end);
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+void destroy() {
+ if (color != null) color.release();
+ color = null;
+ if (gradient != null) gradient.release();
+ gradient = null;
+ image = null;
+ color1 = color2 = null;
+}
+
+/**
+ * Returns <code>true</code> if the Pattern has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the Pattern.
+ * When a Pattern has been disposed, it is an error to
+ * invoke any other method using the Pattern.
+ *
+ * @return <code>true</code> when the Pattern is disposed, and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return device == null;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+public String toString() {
+ if (isDisposed()) return "Pattern {*DISPOSED*}";
+ return "Pattern {" + (color != null ? color.id : gradient.id) + "}";
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Region.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Region.java
new file mode 100755
index 0000000000..c8de98bb3a
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Region.java
@@ -0,0 +1,839 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.cocoa.*;
+import org.eclipse.swt.*;
+
+/**
+ * Instances of this class represent areas of an x-y coordinate
+ * system that are aggregates of the areas covered by a number
+ * of polygons.
+ * <p>
+ * Application code must explicitly invoke the <code>Region.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: GraphicsExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+public final class Region extends Resource {
+ /**
+ * the OS resource for the region
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public int /*long*/ handle;
+
+/**
+ * Constructs a new empty region.
+ *
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for region creation</li>
+ * </ul>
+ */
+public Region() {
+ this(null);
+}
+
+/**
+ * Constructs a new empty region.
+ * <p>
+ * You must dispose the region when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the region
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for region creation</li>
+ * </ul>
+ *
+ * @see #dispose
+ *
+ * @since 3.0
+ */
+public Region(Device device) {
+ super(device);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ handle = OS.NewRgn();
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+Region(Device device, int /*long*/ handle) {
+ super(device);
+ this.handle = handle;
+}
+
+public static Region cocoa_new(Device device, int /*long*/ handle) {
+ return new Region(device, handle);
+}
+
+static int /*long*/ polyToRgn(int[] poly, int length) {
+ short[] r = new short[4];
+ int /*long*/ polyRgn = OS.NewRgn(), rectRgn = OS.NewRgn();
+ int minY = poly[1], maxY = poly[1];
+ for (int y = 3; y < length; y += 2) {
+ if (poly[y] < minY) minY = poly[y];
+ if (poly[y] > maxY) maxY = poly[y];
+ }
+ int[] inter = new int[length + 1];
+ for (int y = minY; y <= maxY; y++) {
+ int count = 0;
+ int x1 = poly[0], y1 = poly[1];
+ for (int p = 2; p < length; p += 2) {
+ int x2 = poly[p], y2 = poly[p + 1];
+ if (y1 != y2 && ((y1 <= y && y < y2) || (y2 <= y && y < y1))) {
+ inter[count++] = (int)((((y - y1) / (float)(y2 - y1)) * (x2 - x1)) + x1 + 0.5f);
+ }
+ x1 = x2;
+ y1 = y2;
+ }
+ int x2 = poly[0], y2 = poly[1];
+ if (y1 != y2 && ((y1 <= y && y < y2) || (y2 <= y && y < y1))) {
+ inter[count++] = (int)((((y - y1) / (float)(y2 - y1)) * (x2 - x1)) + x1 + 0.5f);
+ }
+ for (int gap=count/2; gap>0; gap/=2) {
+ for (int i=gap; i<count; i++) {
+ for (int j=i-gap; j>=0; j-=gap) {
+ if ((inter[j] - inter[j + gap]) <= 0)
+ break;
+ int temp = inter[j];
+ inter[j] = inter[j + gap];
+ inter[j + gap] = temp;
+ }
+ }
+ }
+ for (int i = 0; i < count; i += 2) {
+ OS.SetRect(r, (short)inter[i], (short)y, (short)(inter[i + 1]),(short)(y + 1));
+ OS.RectRgn(rectRgn, r);
+ OS.UnionRgn(polyRgn, rectRgn, polyRgn);
+ }
+ }
+ OS.DisposeRgn(rectRgn);
+ return polyRgn;
+}
+
+static int /*long*/ polyRgn(int[] pointArray, int count) {
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ int /*long*/ polyRgn;
+ if (C.PTR_SIZEOF == 4) {
+ polyRgn = OS.NewRgn();
+ OS.OpenRgn();
+ OS.MoveTo((short)pointArray[0], (short)pointArray[1]);
+ for (int i = 1; i < count / 2; i++) {
+ OS.LineTo((short)pointArray[2 * i], (short)pointArray[2 * i + 1]);
+ }
+ OS.LineTo((short)pointArray[0], (short)pointArray[1]);
+ OS.CloseRgn(polyRgn);
+ } else {
+ polyRgn = polyToRgn(pointArray, count);
+ }
+ return polyRgn;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Adds the given polygon to the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param pointArray points that describe the polygon to merge with the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+*
+ */
+public void add (int[] pointArray) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ add(pointArray, pointArray.length);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+void add(int[] pointArray, int count) {
+ if (count <= 2) return;
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ int /*long*/ polyRgn = polyRgn(pointArray, count);
+ OS.UnionRgn(handle, polyRgn, handle);
+ OS.DisposeRgn(polyRgn);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Adds the given rectangle to the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param rect the rectangle to merge with the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void add(Rectangle rect) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (rect.width < 0 || rect.height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ add (rect.x, rect.y, rect.width, rect.height);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Adds the given rectangle to the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param x the x coordinate of the rectangle
+ * @param y the y coordinate of the rectangle
+ * @param width the width coordinate of the rectangle
+ * @param height the height coordinate of the rectangle
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void add(int x, int y, int width, int height) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ int /*long*/ rectRgn = OS.NewRgn();
+ short[] r = new short[4];
+ OS.SetRect(r, (short)x, (short)y, (short)(x + width),(short)(y + height));
+ OS.RectRgn(rectRgn, r);
+ OS.UnionRgn(handle, rectRgn, handle);
+ OS.DisposeRgn(rectRgn);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Adds all of the polygons which make up the area covered
+ * by the argument to the collection of polygons the receiver
+ * maintains to describe its area.
+ *
+ * @param region the region to merge
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void add(Region region) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ OS.UnionRgn(handle, region.handle, handle);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns <code>true</code> if the point specified by the
+ * arguments is inside the area specified by the receiver,
+ * and <code>false</code> otherwise.
+ *
+ * @param x the x coordinate of the point to test for containment
+ * @param y the y coordinate of the point to test for containment
+ * @return <code>true</code> if the region contains the point and <code>false</code> otherwise
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean contains(int x, int y) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ short[] point = new short[]{(short)y, (short)x};
+ return OS.PtInRgn(point, handle);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns <code>true</code> if the given point is inside the
+ * area specified by the receiver, and <code>false</code>
+ * otherwise.
+ *
+ * @param pt the point to test for containment
+ * @return <code>true</code> if the region contains the point and <code>false</code> otherwise
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean contains(Point pt) {
+ if (pt == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ return contains(pt.x, pt.y);
+}
+
+NSAffineTransform transform;
+void convertRgn(NSAffineTransform transform) {
+ int /*long*/ newRgn = OS.NewRgn();
+ Callback callback = new Callback(this, "convertRgn", 4);
+ int /*long*/ proc = callback.getAddress();
+ if (proc == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
+ this.transform = transform;
+ OS.QDRegionToRects(handle, OS.kQDParseRegionFromTopLeft, proc, newRgn);
+ this.transform = null;
+ callback.dispose();
+ OS.CopyRgn(newRgn, handle);
+ OS.DisposeRgn(newRgn);
+}
+
+int /*long*/ convertRgn(int /*long*/ message, int /*long*/ rgn, int /*long*/ r, int /*long*/ newRgn) {
+ if (message == OS.kQDRegionToRectsMsgParse) {
+ short[] rect = new short[4];
+ OS.memmove(rect, r, rect.length * 2);
+ int i = 0;
+ NSPoint point = new NSPoint();
+ int[] points = new int[10];
+ point.x = rect[1];
+ point.y = rect[0];
+ point = transform.transformPoint(point);
+ short startX, startY;
+ points[i++] = startX = (short)point.x;
+ points[i++] = startY = (short)point.y;
+ point.x = rect[3];
+ point.y = rect[0];
+ point = transform.transformPoint(point);
+ points[i++] = (short)Math.round(point.x);
+ points[i++] = (short)point.y;
+ point.x = rect[3];
+ point.y = rect[2];
+ point = transform.transformPoint(point);
+ points[i++] = (short)Math.round(point.x);
+ points[i++] = (short)Math.round(point.y);
+ point.x = rect[1];
+ point.y = rect[2];
+ point = transform.transformPoint(point);
+ points[i++] = (short)point.x;
+ points[i++] = (short)Math.round(point.y);
+ points[i++] = startX;
+ points[i++] = startY;
+ int /*long*/ polyRgn = polyRgn(points, points.length);
+ OS.UnionRgn(newRgn, polyRgn, newRgn);
+ OS.DisposeRgn(polyRgn);
+ }
+ return 0;
+}
+
+void destroy() {
+ OS.DisposeRgn(handle);
+ handle = 0;
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the <em>same</em> object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
+ *
+ * @see #hashCode
+ */
+public boolean equals(Object object) {
+ if (this == object) return true;
+ if (!(object instanceof Region)) return false;
+ Region region = (Region)object;
+ return handle == region.handle;
+}
+
+/**
+ * Returns a rectangle which represents the rectangular
+ * union of the collection of polygons the receiver
+ * maintains to describe its area.
+ *
+ * @return a bounding rectangle for the region
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Rectangle#union
+ */
+public Rectangle getBounds() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ short[] bounds = new short[4];
+ OS.GetRegionBounds(handle, bounds);
+ int width = bounds[3] - bounds[1];
+ int height = bounds[2] - bounds[0];
+ return new Rectangle(bounds[1], bounds[0], width, height);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+NSBezierPath getPath() {
+ Callback callback = new Callback(this, "regionToRects", 4);
+ if (callback.getAddress() == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
+ NSBezierPath path = NSBezierPath.bezierPath();
+ path.retain();
+ OS.QDRegionToRects(handle, OS.kQDParseRegionFromTopLeft, callback.getAddress(), path.id);
+ callback.dispose();
+ if (path.isEmpty()) path.appendBezierPathWithRect(new NSRect());
+ return path;
+}
+
+NSPoint pt = new NSPoint();
+short[] rect = new short[4];
+int /*long*/ regionToRects(int /*long*/ message, int /*long*/ rgn, int /*long*/ r, int /*long*/ path) {
+ if (message == OS.kQDRegionToRectsMsgParse) {
+ OS.memmove(rect, r, rect.length * 2);
+ pt.x = rect[1];
+ pt.y = rect[0];
+ OS.objc_msgSend(path, OS.sel_moveToPoint_, pt);
+ pt.x = rect[3];
+ OS.objc_msgSend(path, OS.sel_lineToPoint_, pt);
+ pt.x = rect[3];
+ pt.y = rect[2];
+ OS.objc_msgSend(path, OS.sel_lineToPoint_, pt);
+ pt.x = rect[1];
+ OS.objc_msgSend(path, OS.sel_lineToPoint_, pt);
+ OS.objc_msgSend(path, OS.sel_closePath);
+ }
+ return 0;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return <code>true</code> when passed to
+ * <code>equals</code> must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+public int hashCode() {
+ return (int)/*64*/handle;
+}
+
+/**
+ * Intersects the given rectangle to the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param rect the rectangle to intersect with the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void intersect(Rectangle rect) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ intersect (rect.x, rect.y, rect.width, rect.height);
+}
+
+/**
+ * Intersects the given rectangle to the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param x the x coordinate of the rectangle
+ * @param y the y coordinate of the rectangle
+ * @param width the width coordinate of the rectangle
+ * @param height the height coordinate of the rectangle
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void intersect(int x, int y, int width, int height) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ int /*long*/ rectRgn = OS.NewRgn();
+ short[] r = new short[4];
+ OS.SetRect(r, (short)x, (short)y, (short)(x + width),(short)(y + height));
+ OS.RectRgn(rectRgn, r);
+ OS.SectRgn(handle, rectRgn, handle);
+ OS.DisposeRgn(rectRgn);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Intersects all of the polygons which make up the area covered
+ * by the argument to the collection of polygons the receiver
+ * maintains to describe its area.
+ *
+ * @param region the region to intersect
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void intersect(Region region) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ OS.SectRgn(handle, region.handle, handle);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns <code>true</code> if the rectangle described by the
+ * arguments intersects with any of the polygons the receiver
+ * maintains to describe its area, and <code>false</code> otherwise.
+ *
+ * @param x the x coordinate of the origin of the rectangle
+ * @param y the y coordinate of the origin of the rectangle
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ * @return <code>true</code> if the rectangle intersects with the receiver, and <code>false</code> otherwise
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Rectangle#intersects(Rectangle)
+ */
+public boolean intersects (int x, int y, int width, int height) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ short[] r = new short[4];
+ OS.SetRect(r, (short)x, (short)y, (short)(x + width),(short)(y + height));
+ return OS.RectInRgn(r, handle);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns <code>true</code> if the given rectangle intersects
+ * with any of the polygons the receiver maintains to describe
+ * its area and <code>false</code> otherwise.
+ *
+ * @param rect the rectangle to test for intersection
+ * @return <code>true</code> if the rectangle intersects with the receiver, and <code>false</code> otherwise
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Rectangle#intersects(Rectangle)
+ */
+public boolean intersects(Rectangle rect) {
+ if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ return intersects(rect.x, rect.y, rect.width, rect.height);
+}
+
+/**
+ * Returns <code>true</code> if the region has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the region.
+ * When a region has been disposed, it is an error to
+ * invoke any other method using the region.
+ *
+ * @return <code>true</code> when the region is disposed, and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return handle == 0;
+}
+
+/**
+ * Returns <code>true</code> if the receiver does not cover any
+ * area in the (x, y) coordinate plane, and <code>false</code> if
+ * the receiver does cover some area in the plane.
+ *
+ * @return <code>true</code> if the receiver is empty, and <code>false</code> otherwise
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean isEmpty() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ return OS.EmptyRgn(handle);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Subtracts the given polygon from the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param pointArray points that describe the polygon to merge with the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void subtract (int[] pointArray) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (pointArray.length < 2) return;
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ int /*long*/ polyRgn = polyRgn(pointArray, pointArray.length);
+ OS.DiffRgn(handle, polyRgn, handle);
+ OS.DisposeRgn(polyRgn);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Subtracts the given rectangle from the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param rect the rectangle to subtract from the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void subtract(Rectangle rect) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ subtract (rect.x, rect.y, rect.width, rect.height);
+}
+
+/**
+ * Subtracts the given rectangle from the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param x the x coordinate of the rectangle
+ * @param y the y coordinate of the rectangle
+ * @param width the width coordinate of the rectangle
+ * @param height the height coordinate of the rectangle
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void subtract(int x, int y, int width, int height) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ int /*long*/ rectRgn = OS.NewRgn();
+ short[] r = new short[4];
+ OS.SetRect(r, (short)x, (short)y, (short)(x + width),(short)(y + height));
+ OS.RectRgn(rectRgn, r);
+ OS.DiffRgn(handle, rectRgn, handle);
+ OS.DisposeRgn(rectRgn);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Subtracts all of the polygons which make up the area covered
+ * by the argument from the collection of polygons the receiver
+ * maintains to describe its area.
+ *
+ * @param region the region to subtract
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void subtract(Region region) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ OS.DiffRgn(handle, region.handle, handle);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Translate all of the polygons the receiver maintains to describe
+ * its area by the specified point.
+ *
+ * @param x the x coordinate of the point to translate
+ * @param y the y coordinate of the point to translate
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void translate (int x, int y) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ OS.OffsetRgn (handle, (short)x, (short)y);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Translate all of the polygons the receiver maintains to describe
+ * its area by the specified point.
+ *
+ * @param pt the point to translate
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void translate (Point pt) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pt == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ translate (pt.x, pt.y);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+public String toString () {
+ if (isDisposed()) return "Region {*DISPOSED*}";
+ return "Region {" + handle + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/TextLayout.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/TextLayout.java
new file mode 100755
index 0000000000..1d8b96f356
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/TextLayout.java
@@ -0,0 +1,1980 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+import org.eclipse.swt.internal.C;
+import org.eclipse.swt.internal.Compatibility;
+import org.eclipse.swt.internal.cocoa.*;
+import org.eclipse.swt.*;
+
+/**
+ * <code>TextLayout</code> is a graphic object that represents
+ * styled text.
+ * <p>
+ * Instances of this class provide support for drawing, cursor
+ * navigation, hit testing, text wrapping, alignment, tab expansion
+ * line breaking, etc. These are aspects required for rendering internationalized text.
+ * </p><p>
+ * Application code must explicitly invoke the <code>TextLayout#dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#textlayout">TextLayout, TextStyle snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: CustomControlExample, StyledText tab</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.0
+ */
+public final class TextLayout extends Resource {
+
+ NSTextStorage textStorage;
+ NSLayoutManager layoutManager;
+ NSTextContainer textContainer;
+ Font font;
+ String text;
+ StyleItem[] styles;
+ int spacing, ascent, descent, indent;
+ boolean justify;
+ int alignment;
+ int[] tabs;
+ int[] segments;
+ int wrapWidth;
+ int orientation;
+
+ int[] lineOffsets;
+ NSRect[] lineBounds;
+
+ static final int UNDERLINE_THICK = 1 << 16;
+ static final RGB LINK_FOREGROUND = new RGB (0, 51, 153);
+ int[] invalidOffsets;
+ static final char LTR_MARK = '\u200E', RTL_MARK = '\u200F', ZWS = '\u200B';
+
+ static class StyleItem {
+ TextStyle style;
+ int start;
+
+ public String toString () {
+ return "StyleItem {" + start + ", " + style + "}";
+ }
+ }
+
+/**
+ * Constructs a new instance of this class on the given device.
+ * <p>
+ * You must dispose the text layout when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the text layout
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * </ul>
+ *
+ * @see #dispose()
+ */
+public TextLayout (Device device) {
+ super(device);
+ wrapWidth = ascent = descent = -1;
+ alignment = SWT.LEFT;
+ orientation = SWT.LEFT_TO_RIGHT;
+ text = "";
+ styles = new StyleItem[2];
+ styles[0] = new StyleItem();
+ styles[1] = new StyleItem();
+ init();
+}
+
+void checkLayout() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+}
+
+float[] computePolyline(int left, int top, int right, int bottom) {
+ int height = bottom - top; // can be any number
+ int width = 2 * height; // must be even
+ int peaks = Compatibility.ceil(right - left, width);
+ if (peaks == 0 && right - left > 2) {
+ peaks = 1;
+ }
+ int length = ((2 * peaks) + 1) * 2;
+ if (length < 0) return new float[0];
+
+ float[] coordinates = new float[length];
+ for (int i = 0; i < peaks; i++) {
+ int index = 4 * i;
+ coordinates[index] = left + (width * i);
+ coordinates[index+1] = bottom;
+ coordinates[index+2] = coordinates[index] + width / 2;
+ coordinates[index+3] = top;
+ }
+ coordinates[length-2] = left + (width * peaks);
+ coordinates[length-1] = bottom;
+ return coordinates;
+}
+
+
+void computeRuns() {
+ if (textStorage != null) return;
+ String segmentsText = getSegmentsText();
+ NSString str = NSString.stringWith(segmentsText);
+ textStorage = (NSTextStorage)new NSTextStorage().alloc().init();
+ layoutManager = (NSLayoutManager)new NSLayoutManager().alloc().init();
+ layoutManager.setBackgroundLayoutEnabled(NSThread.isMainThread());
+ textContainer = (NSTextContainer)new NSTextContainer().alloc();
+ NSSize size = new NSSize();
+ size.width = wrapWidth != -1 ? wrapWidth : Float.MAX_VALUE;
+ size.height = Float.MAX_VALUE;
+ textContainer.initWithContainerSize(size);
+ textStorage.addLayoutManager(layoutManager);
+ layoutManager.addTextContainer(textContainer);
+
+ /*
+ * Bug in Cocoa. Adding attributes directly to a NSTextStorage causes
+ * output to the console and eventually a segmentation fault when printing
+ * on a thread other than the main thread. The fix is to add attributes to
+ * a separate NSMutableAttributedString and add it to text storage when done.
+ */
+ NSMutableAttributedString attrStr = (NSMutableAttributedString)new NSMutableAttributedString().alloc();
+ attrStr.id = attrStr.initWithString(str).id;
+ attrStr.beginEditing();
+ Font defaultFont = font != null ? font : device.systemFont;
+ NSRange range = new NSRange();
+ range.length = str.length();
+ attrStr.addAttribute(OS.NSFontAttributeName, defaultFont.handle, range);
+ defaultFont.addTraits(attrStr, range);
+ //TODO ascend descent wrap
+ NSMutableParagraphStyle paragraph = (NSMutableParagraphStyle)new NSMutableParagraphStyle().alloc().init();
+ int align = OS.NSLeftTextAlignment;
+ if (justify) {
+ align = OS.NSJustifiedTextAlignment;
+ } else {
+ switch (alignment) {
+ case SWT.CENTER:
+ align = OS.NSCenterTextAlignment;
+ break;
+ case SWT.RIGHT:
+ align = OS.NSRightTextAlignment;
+ }
+ }
+ paragraph.setAlignment(align);
+ paragraph.setLineSpacing(spacing);
+ paragraph.setFirstLineHeadIndent(indent);
+ paragraph.setLineBreakMode(wrapWidth != -1 ? OS.NSLineBreakByWordWrapping : OS.NSLineBreakByClipping);
+ paragraph.setTabStops(NSArray.array());
+ if (tabs != null) {
+ int count = tabs.length;
+ for (int i = 0, pos = 0; i < count; i++) {
+ pos += tabs[i];
+ NSTextTab tab = (NSTextTab)new NSTextTab().alloc();
+ tab = tab.initWithType(OS.NSLeftTabStopType, pos);
+ paragraph.addTabStop(tab);
+ tab.release();
+ }
+ int width = count - 2 >= 0 ? tabs[count - 1] - tabs[count - 2] : tabs[count - 1];
+ paragraph.setDefaultTabInterval(width);
+ }
+ attrStr.addAttribute(OS.NSParagraphStyleAttributeName, paragraph, range);
+ paragraph.release();
+ int /*long*/ textLength = str.length();
+ for (int i = 0; i < styles.length - 1; i++) {
+ StyleItem run = styles[i];
+ if (run.style == null) continue;
+ TextStyle style = run.style;
+ range.location = textLength != 0 ? translateOffset(run.start) : 0;
+ range.length = translateOffset(styles[i + 1].start) - range.location;
+ Font font = style.font;
+ if (font != null) {
+ attrStr.addAttribute(OS.NSFontAttributeName, font.handle, range);
+ font.addTraits(attrStr, range);
+ }
+ Color foreground = style.foreground;
+ if (foreground != null) {
+ NSColor color = NSColor.colorWithDeviceRed(foreground.handle[0], foreground.handle[1], foreground.handle[2], 1);
+ attrStr.addAttribute(OS.NSForegroundColorAttributeName, color, range);
+ }
+ Color background = style.background;
+ if (background != null) {
+ NSColor color = NSColor.colorWithDeviceRed(background.handle[0], background.handle[1], background.handle[2], 1);
+ attrStr.addAttribute(OS.NSBackgroundColorAttributeName, color, range);
+ }
+ if (style.strikeout) {
+ attrStr.addAttribute(OS.NSStrikethroughStyleAttributeName, NSNumber.numberWithInt(OS.NSUnderlineStyleSingle), range);
+ Color strikeColor = style.strikeoutColor;
+ if (strikeColor != null) {
+ NSColor color = NSColor.colorWithDeviceRed(strikeColor.handle[0], strikeColor.handle[1], strikeColor.handle[2], 1);
+ attrStr.addAttribute(OS.NSStrikethroughColorAttributeName, color, range);
+ }
+ }
+ if (isUnderlineSupported(style)) {
+ int underlineStyle = 0;
+ switch (style.underlineStyle) {
+ case SWT.UNDERLINE_SINGLE:
+ underlineStyle = OS.NSUnderlineStyleSingle;
+ break;
+ case SWT.UNDERLINE_DOUBLE:
+ underlineStyle = OS.NSUnderlineStyleDouble;
+ break;
+ case UNDERLINE_THICK:
+ underlineStyle = OS.NSUnderlineStyleThick;
+ break;
+ case SWT.UNDERLINE_LINK: {
+ underlineStyle = OS.NSUnderlineStyleSingle;
+ if (foreground == null) {
+ NSColor color = NSColor.colorWithDeviceRed(LINK_FOREGROUND.red / 255f, LINK_FOREGROUND.green / 255f, LINK_FOREGROUND.blue / 255f, 1);
+ attrStr.addAttribute(OS.NSForegroundColorAttributeName, color, range);
+ }
+ break;
+ }
+ }
+ if (underlineStyle != 0) {
+ attrStr.addAttribute(OS.NSUnderlineStyleAttributeName, NSNumber.numberWithInt(underlineStyle), range);
+ Color underlineColor = style.underlineColor;
+ if (underlineColor != null) {
+ NSColor color = NSColor.colorWithDeviceRed(underlineColor.handle[0], underlineColor.handle[1], underlineColor.handle[2], 1);
+ attrStr.addAttribute(OS.NSUnderlineColorAttributeName, color, range);
+ }
+ }
+ }
+ if (style.rise != 0) {
+ attrStr.addAttribute(OS.NSBaselineOffsetAttributeName, NSNumber.numberWithInt(style.rise), range);
+ }
+ if (style.metrics != null) {
+ //TODO implement metrics
+ }
+ }
+ attrStr.endEditing();
+ textStorage.setAttributedString(attrStr);
+ attrStr.release();
+
+ textContainer.setLineFragmentPadding(0);
+ layoutManager.glyphRangeForTextContainer(textContainer);
+
+ int numberOfLines;
+ int /*long*/ numberOfGlyphs = layoutManager.numberOfGlyphs(), index;
+ int /*long*/ rangePtr = OS.malloc(NSRange.sizeof);
+ NSRange lineRange = new NSRange();
+ for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){
+ layoutManager.lineFragmentUsedRectForGlyphAtIndex(index, rangePtr, true);
+ OS.memmove(lineRange, rangePtr, NSRange.sizeof);
+ index = lineRange.location + lineRange.length;
+ }
+ if (numberOfLines == 0) numberOfLines++;
+ int[] offsets = new int[numberOfLines + 1];
+ NSRect[] bounds = new NSRect[numberOfLines];
+ for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){
+ bounds[numberOfLines] = layoutManager.lineFragmentUsedRectForGlyphAtIndex(index, rangePtr, true);
+ if (numberOfLines < bounds.length - 1) bounds[numberOfLines].height -= spacing;
+ OS.memmove(lineRange, rangePtr, NSRange.sizeof);
+ offsets[numberOfLines] = (int)/*64*/lineRange.location;
+ index = lineRange.location + lineRange.length;
+ }
+ if (numberOfLines == 0) {
+ Font font = this.font != null ? this.font : device.systemFont;
+ NSFont nsFont = font.handle;
+ bounds[0] = new NSRect();
+ bounds[0].height = Math.max(layoutManager.defaultLineHeightForFont(nsFont), ascent + descent);
+ }
+ OS.free(rangePtr);
+ offsets[numberOfLines] = (int)/*64*/textStorage.length();
+ this.lineOffsets = offsets;
+ this.lineBounds = bounds;
+}
+
+void destroy() {
+ freeRuns();
+ font = null;
+ text = null;
+ styles = null;
+}
+
+/**
+ * Draws the receiver's text using the specified GC at the specified
+ * point.
+ *
+ * @param gc the GC to draw
+ * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the gc is null</li>
+ * </ul>
+ */
+public void draw(GC gc, int x, int y) {
+ draw(gc, x, y, -1, -1, null, null);
+}
+
+/**
+ * Draws the receiver's text using the specified GC at the specified
+ * point.
+ *
+ * @param gc the GC to draw
+ * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param selectionStart the offset where the selections starts, or -1 indicating no selection
+ * @param selectionEnd the offset where the selections ends, or -1 indicating no selection
+ * @param selectionForeground selection foreground, or NULL to use the system default color
+ * @param selectionBackground selection background, or NULL to use the system default color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the gc is null</li>
+ * </ul>
+ */
+public void draw(GC gc, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground) {
+ draw(gc, x, y, selectionStart, selectionEnd, selectionForeground, selectionBackground, 0);
+}
+
+/**
+ * Draws the receiver's text using the specified GC at the specified
+ * point.
+ * <p>
+ * The parameter <code>flags</code> can include one of <code>SWT.DELIMITER_SELECTION</code>
+ * or <code>SWT.FULL_SELECTION</code> to specify the selection behavior on all lines except
+ * for the last line, and can also include <code>SWT.LAST_LINE_SELECTION</code> to extend
+ * the specified selection behavior to the last line.
+ * </p>
+ * @param gc the GC to draw
+ * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param selectionStart the offset where the selections starts, or -1 indicating no selection
+ * @param selectionEnd the offset where the selections ends, or -1 indicating no selection
+ * @param selectionForeground selection foreground, or NULL to use the system default color
+ * @param selectionBackground selection background, or NULL to use the system default color
+ * @param flags drawing options
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the gc is null</li>
+ * </ul>
+ *
+ * @since 3.3
+ */
+public void draw(GC gc, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground, int flags) {
+ checkLayout ();
+ if (gc == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (gc.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (selectionForeground != null && selectionForeground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (selectionBackground != null && selectionBackground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = gc.checkGC(GC.CLIPPING | GC.TRANSFORM | GC.FOREGROUND);
+ try {
+ computeRuns();
+ int length = translateOffset(text.length());
+ if (length == 0 && flags == 0) return;
+ gc.handle.saveGraphicsState();
+ NSPoint pt = new NSPoint();
+ pt.x = x;
+ pt.y = y;
+ NSRange range = new NSRange();
+ int /*long*/ numberOfGlyphs = layoutManager.numberOfGlyphs();
+ if (numberOfGlyphs > 0) {
+ range.location = 0;
+ range.length = numberOfGlyphs;
+ layoutManager.drawBackgroundForGlyphRange(range, pt);
+ }
+ boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1;
+ if (hasSelection || (flags & SWT.LAST_LINE_SELECTION) != 0) {
+ if (selectionBackground == null) selectionBackground = device.getSystemColor(SWT.COLOR_LIST_SELECTION);
+ NSColor selectionColor = NSColor.colorWithDeviceRed(selectionBackground.handle[0], selectionBackground.handle[1], selectionBackground.handle[2], selectionBackground.handle[3]);
+ NSBezierPath path = NSBezierPath.bezierPath();
+ NSRect rect = new NSRect();
+ if (hasSelection) {
+ int /*long*/ pRectCount = OS.malloc(C.PTR_SIZEOF);
+ range.location = translateOffset(selectionStart);
+ range.length = translateOffset(selectionEnd - selectionStart + 1);
+ int /*long*/ pArray = layoutManager.rectArrayForCharacterRange(range, range, textContainer, pRectCount);
+ int /*long*/ [] rectCount = new int /*long*/ [1];
+ OS.memmove(rectCount, pRectCount, C.PTR_SIZEOF);
+ OS.free(pRectCount);
+ for (int k = 0; k < rectCount[0]; k++, pArray += NSRect.sizeof) {
+ OS.memmove(rect, pArray, NSRect.sizeof);
+ fixRect(rect);
+ rect.x += pt.x;
+ rect.y += pt.y;
+ rect.height = Math.max(rect.height, ascent + descent);
+ path.appendBezierPathWithRect(rect);
+ }
+ }
+ //TODO draw full selection for wrapped text
+ if ((flags & SWT.LAST_LINE_SELECTION) != 0) {
+ NSRect bounds = lineBounds[lineBounds.length - 1];
+ rect.x = pt.x + bounds.x + bounds.width;
+ rect.y = y + bounds.y;
+ rect.width = (flags & SWT.FULL_SELECTION) != 0 ? 0x7fffffff : bounds.height / 3;
+ rect.height = Math.max(bounds.height, ascent + descent);
+ path.appendBezierPathWithRect(rect);
+ }
+ selectionColor.setFill();
+ path.fill();
+ }
+ if (numberOfGlyphs > 0) {
+ range.location = 0;
+ range.length = numberOfGlyphs;
+ float /*double*/ [] fg = gc.data.foreground;
+ boolean defaultFg = fg[0] == 0 && fg[1] == 0 && fg[2] == 0 && fg[3] == 1;
+ if (!defaultFg) {
+ for (int i = 0; i < styles.length - 1; i++) {
+ StyleItem run = styles[i];
+ if (run.style != null && run.style.foreground != null) continue;
+ if (run.style != null && run.style.underline && run.style.underlineStyle == SWT.UNDERLINE_LINK) continue;
+ range.location = length != 0 ? translateOffset(run.start) : 0;
+ range.length = translateOffset(styles[i + 1].start) - range.location;
+ layoutManager.addTemporaryAttribute(OS.NSForegroundColorAttributeName, gc.data.fg, range);
+ }
+ }
+ range.location = 0;
+ range.length = numberOfGlyphs;
+ layoutManager.drawGlyphsForGlyphRange(range, pt);
+ if (!defaultFg) {
+ range.location = 0;
+ range.length = length;
+ layoutManager.removeTemporaryAttribute(OS.NSForegroundColorAttributeName, range);
+ }
+ NSPoint point = new NSPoint();
+ for (int j = 0; j < styles.length; j++) {
+ StyleItem run = styles[j];
+ TextStyle style = run.style;
+ if (style == null) continue;
+ boolean drawUnderline = style.underline && !isUnderlineSupported(style);
+ drawUnderline = drawUnderline && (j + 1 == styles.length || !style.isAdherentUnderline(styles[j + 1].style));
+ boolean drawBorder = style.borderStyle != SWT.NONE;
+ drawBorder = drawBorder && (j + 1 == styles.length || !style.isAdherentBorder(styles[j + 1].style));
+ if (!drawUnderline && !drawBorder) continue;
+ int end = j + 1 < styles.length ? translateOffset(styles[j + 1].start - 1) : length;
+ for (int i = 0; i < lineOffsets.length - 1; i++) {
+ int lineStart = untranslateOffset(lineOffsets[i]);
+ int lineEnd = untranslateOffset(lineOffsets[i + 1] - 1);
+ if (drawUnderline) {
+ int start = run.start;
+ for (int k = j; k > 0 && style.isAdherentUnderline(styles[k - 1].style); k--) {
+ start = styles[k - 1].start;
+ }
+ start = translateOffset(start);
+ if (!(start > lineEnd || end < lineStart)) {
+ range.location = Math.max(lineStart, start);
+ range.length = Math.min(lineEnd, end) + 1 - range.location;
+ if (range.length > 0) {
+ int /*long*/ pRectCount = OS.malloc(C.PTR_SIZEOF);
+ int /*long*/ pArray = layoutManager.rectArrayForCharacterRange(range, range, textContainer, pRectCount);
+ int /*long*/ [] rectCount = new int /*long*/ [1];
+ OS.memmove(rectCount, pRectCount, C.PTR_SIZEOF);
+ OS.free(pRectCount);
+ NSRect rect = new NSRect();
+ gc.handle.saveGraphicsState();
+ float /*double*/ baseline = layoutManager.typesetter().baselineOffsetInLayoutManager(layoutManager, lineStart);
+ float /*double*/ [] color = null;
+ if (style.underlineColor != null) color = style.underlineColor.handle;
+ if (color == null && style.foreground != null) color = style.foreground.handle;
+ if (color != null) {
+ NSColor.colorWithDeviceRed(color[0], color[1], color[2], color[3]).setStroke();
+ }
+ for (int k = 0; k < rectCount[0]; k++, pArray += NSRect.sizeof) {
+ OS.memmove(rect, pArray, NSRect.sizeof);
+ fixRect(rect);
+ float /*double*/ underlineX = pt.x + rect.x;
+ float /*double*/ underlineY = pt.y + rect.y + rect.height - baseline + 1;
+ NSBezierPath path = NSBezierPath.bezierPath();
+ switch (style.underlineStyle) {
+ case SWT.UNDERLINE_ERROR: {
+ path.setLineWidth(2f);
+ path.setLineCapStyle(OS.NSRoundLineCapStyle);
+ path.setLineJoinStyle(OS.NSRoundLineJoinStyle);
+ path.setLineDash(new float /*double*/ []{1, 3f}, 2, 0);
+ point.x = underlineX;
+ point.y = underlineY + 0.5f;
+ path.moveToPoint(point);
+ point.x = underlineX + rect.width;
+ point.y = underlineY + 0.5f;
+ path.lineToPoint(point);
+ break;
+ }
+ case SWT.UNDERLINE_SQUIGGLE: {
+ gc.handle.setShouldAntialias(false);
+ path.setLineWidth(1.0f);
+ path.setLineCapStyle(OS.NSButtLineCapStyle);
+ path.setLineJoinStyle(OS.NSMiterLineJoinStyle);
+ float /*double*/ lineBottom = pt.y + rect.y + rect.height;
+ float squigglyThickness = 1;
+ float squigglyHeight = 2 * squigglyThickness;
+ float /*double*/ squigglyY = Math.min(underlineY - squigglyHeight / 2, lineBottom - squigglyHeight - 1);
+ float[] points = computePolyline((int)underlineX, (int)squigglyY, (int)(underlineX + rect.width), (int)(squigglyY + squigglyHeight));
+ point.x = points[0] + 0.5f;
+ point.y = points[1] + 0.5f;
+ path.moveToPoint(point);
+ for (int p = 2; p < points.length; p+=2) {
+ point.x = points[p] + 0.5f;
+ point.y = points[p+1] + 0.5f;
+ path.lineToPoint(point);
+ }
+ break;
+ }
+ }
+ path.stroke();
+ }
+ gc.handle.restoreGraphicsState();
+ }
+ }
+ }
+ if (drawBorder) {
+ int start = run.start;
+ for (int k = j; k > 0 && style.isAdherentBorder(styles[k - 1].style); k--) {
+ start = styles[k - 1].start;
+ }
+ start = translateOffset(start);
+ if (!(start > lineEnd || end < lineStart)) {
+ range.location = Math.max(lineStart, start);
+ range.length = Math.min(lineEnd, end) + 1 - range.location;
+ if (range.length > 0) {
+ int /*long*/ pRectCount = OS.malloc(C.PTR_SIZEOF);
+ int /*long*/ pArray = layoutManager.rectArrayForCharacterRange(range, range, textContainer, pRectCount);
+ int /*long*/ [] rectCount = new int /*long*/ [1];
+ OS.memmove(rectCount, pRectCount, C.PTR_SIZEOF);
+ OS.free(pRectCount);
+ NSRect rect = new NSRect();
+ gc.handle.saveGraphicsState();
+ float /*double*/ [] color = null;
+ if (style.borderColor != null) color = style.borderColor.handle;
+ if (color == null && style.foreground != null) color = style.foreground.handle;
+ if (color != null) {
+ NSColor.colorWithDeviceRed(color[0], color[1], color[2], color[3]).setStroke();
+ }
+ int width = 1;
+ float[] dashes = null;
+ switch (style.borderStyle) {
+ case SWT.BORDER_SOLID: break;
+ case SWT.BORDER_DASH: dashes = width != 0 ? GC.LINE_DASH : GC.LINE_DASH_ZERO; break;
+ case SWT.BORDER_DOT: dashes = width != 0 ? GC.LINE_DOT : GC.LINE_DOT_ZERO; break;
+ }
+ float /*double*/ [] lengths = null;
+ if (dashes != null) {
+ lengths = new float /*double*/[dashes.length];
+ for (int k = 0; k < lengths.length; k++) {
+ lengths[k] = width == 0 ? dashes[k] : dashes[k] * width;
+ }
+ }
+ for (int k = 0; k < rectCount[0]; k++, pArray += NSRect.sizeof) {
+ OS.memmove(rect, pArray, NSRect.sizeof);
+ fixRect(rect);
+ rect.x += pt.x + 0.5f;
+ rect.y += pt.y + 0.5f;
+ rect.width -= 0.5f;
+ rect.height -= 0.5f;
+ NSBezierPath path = NSBezierPath.bezierPath();
+ path.setLineDash(lengths, lengths != null ? lengths.length : 0, 0);
+ path.appendBezierPathWithRect(rect);
+ path.stroke();
+ }
+ gc.handle.restoreGraphicsState();
+ }
+ }
+ }
+ }
+ }
+ }
+ gc.handle.restoreGraphicsState();
+ } finally {
+ gc.uncheckGC(pool);
+ }
+}
+
+void fixRect(NSRect rect) {
+ for (int j = 0; j < lineBounds.length; j++) {
+ NSRect line = lineBounds[j];
+ if (line.y <= rect.y && rect.y < line.y + line.height) {
+ if (rect.x + rect.width > line.x + line.width) {
+ rect.width = line.x + line.width - rect.x;
+ }
+ }
+ }
+}
+
+void freeRuns() {
+ if (textStorage == null) return;
+ if (textStorage != null) {
+ textStorage.release();
+ }
+ if (layoutManager != null) {
+ layoutManager.release();
+ }
+ if (textContainer != null) {
+ textContainer.release();
+ }
+ textStorage = null;
+ layoutManager = null;
+ textContainer = null;
+}
+
+/**
+ * Returns the receiver's horizontal text alignment, which will be one
+ * of <code>SWT.LEFT</code>, <code>SWT.CENTER</code> or
+ * <code>SWT.RIGHT</code>.
+ *
+ * @return the alignment used to positioned text horizontally
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getAlignment() {
+ checkLayout();
+ return alignment;
+}
+
+/**
+ * Returns the ascent of the receiver.
+ *
+ * @return the ascent
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getDescent()
+ * @see #setDescent(int)
+ * @see #setAscent(int)
+ * @see #getLineMetrics(int)
+ */
+public int getAscent () {
+ checkLayout();
+ return ascent;
+}
+
+/**
+ * Returns the bounds of the receiver. The width returned is either the
+ * width of the longest line or the width set using {@link TextLayout#setWidth(int)}.
+ * To obtain the text bounds of a line use {@link TextLayout#getLineBounds(int)}.
+ *
+ * @return the bounds of the receiver
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setWidth(int)
+ * @see #getLineBounds(int)
+ */
+public Rectangle getBounds() {
+ checkLayout();
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ computeRuns();
+ NSRect rect = layoutManager.usedRectForTextContainer(textContainer);
+ if (wrapWidth != -1) rect.width = wrapWidth;
+ if (text.length() == 0) {
+ Font font = this.font != null ? this.font : device.systemFont;
+ NSFont nsFont = font.handle;
+ rect.height = layoutManager.defaultLineHeightForFont(nsFont);
+ }
+ rect.height = Math.max(rect.height, ascent + descent) + spacing;
+ return new Rectangle(0, 0, (int)Math.ceil(rect.width), (int)Math.ceil(rect.height));
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns the bounds for the specified range of characters. The
+ * bounds is the smallest rectangle that encompasses all characters
+ * in the range. The start and end offsets are inclusive and will be
+ * clamped if out of range.
+ *
+ * @param start the start offset
+ * @param end the end offset
+ * @return the bounds of the character range
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Rectangle getBounds(int start, int end) {
+ checkLayout();
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ computeRuns();
+ int length = text.length();
+ if (length == 0) return new Rectangle(0, 0, 0, 0);
+ if (start > end) return new Rectangle(0, 0, 0, 0);
+ start = Math.min(Math.max(0, start), length - 1);
+ end = Math.min(Math.max(0, end), length - 1);
+ start = translateOffset(start);
+ end = translateOffset(end);
+ NSRange range = new NSRange();
+ range.location = start;
+ range.length = end - start + 1;
+ int /*long*/ pRectCount = OS.malloc(C.PTR_SIZEOF);
+ int /*long*/ pArray = layoutManager.rectArrayForCharacterRange(range, range, textContainer, pRectCount);
+ int /*long*/ [] rectCount = new int /*long*/ [1];
+ OS.memmove(rectCount, pRectCount, C.PTR_SIZEOF);
+ OS.free(pRectCount);
+ NSRect rect = new NSRect();
+ int left = 0x7FFFFFFF, right = 0;
+ int top = 0x7FFFFFFF, bottom = 0;
+ for (int i = 0; i < rectCount[0]; i++, pArray += NSRect.sizeof) {
+ OS.memmove(rect, pArray, NSRect.sizeof);
+ fixRect(rect);
+ left = Math.min(left, (int)rect.x);
+ right = Math.max(right, (int)Math.ceil(rect.x + rect.width));
+ top = Math.min(top, (int)rect.y);
+ bottom = Math.max(bottom, (int)Math.ceil(rect.y + rect.height));
+ }
+ return new Rectangle(left, top, right - left, bottom - top);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns the descent of the receiver.
+ *
+ * @return the descent
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getAscent()
+ * @see #setAscent(int)
+ * @see #setDescent(int)
+ * @see #getLineMetrics(int)
+ */
+public int getDescent () {
+ checkLayout();
+ return descent;
+}
+
+/**
+ * Returns the default font currently being used by the receiver
+ * to draw and measure text.
+ *
+ * @return the receiver's font
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Font getFont () {
+ checkLayout();
+ return font;
+}
+
+/**
+* Returns the receiver's indent.
+*
+* @return the receiver's indent
+*
+* @exception SWTException <ul>
+* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+* </ul>
+*
+* @since 3.2
+*/
+public int getIndent () {
+ checkLayout();
+ return indent;
+}
+
+/**
+* Returns the receiver's justification.
+*
+* @return the receiver's justification
+*
+* @exception SWTException <ul>
+* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+* </ul>
+*
+* @since 3.2
+*/
+public boolean getJustify () {
+ checkLayout();
+ return justify;
+}
+
+/**
+ * Returns the embedding level for the specified character offset. The
+ * embedding level is usually used to determine the directionality of a
+ * character in bidirectional text.
+ *
+ * @param offset the character offset
+ * @return the embedding level
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the character offset is out of range</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ */
+public int getLevel(int offset) {
+ checkLayout();
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ computeRuns();
+ int length = text.length();
+ if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE);
+ offset = translateOffset(offset);
+ int /*long*/ glyphOffset = layoutManager.glyphIndexForCharacterAtIndex(offset);
+ NSRange range = new NSRange();
+ range.location = glyphOffset;
+ range.length = 1;
+ int /*long*/ pBidiLevels = OS.malloc(1);
+ byte[] bidiLevels = new byte[1];
+ int /*long*/ result = layoutManager.getGlyphsInRange(range, 0, 0, 0, 0, pBidiLevels);
+ if (result > 0) {
+ OS.memmove(bidiLevels, pBidiLevels, 1);
+ }
+ OS.free(pBidiLevels);
+ return bidiLevels[0];
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns the line offsets. Each value in the array is the
+ * offset for the first character in a line except for the last
+ * value, which contains the length of the text.
+ *
+ * @return the line offsets
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int[] getLineOffsets() {
+ checkLayout ();
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ computeRuns();
+ int[] offsets = new int[lineOffsets.length];
+ for (int i = 0; i < offsets.length; i++) {
+ offsets[i] = untranslateOffset(lineOffsets[i]);
+ }
+ return offsets;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns the index of the line that contains the specified
+ * character offset.
+ *
+ * @param offset the character offset
+ * @return the line index
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the character offset is out of range</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getLineIndex(int offset) {
+ checkLayout ();
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ computeRuns();
+ int length = text.length();
+ if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE);
+ offset = translateOffset(offset);
+ for (int line=0; line<lineOffsets.length - 1; line++) {
+ if (lineOffsets[line + 1] > offset) {
+ return line;
+ }
+ }
+ return lineBounds.length - 1;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns the bounds of the line for the specified line index.
+ *
+ * @param lineIndex the line index
+ * @return the line bounds
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the line index is out of range</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Rectangle getLineBounds(int lineIndex) {
+ checkLayout();
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ computeRuns();
+ if (!(0 <= lineIndex && lineIndex < lineBounds.length)) SWT.error(SWT.ERROR_INVALID_RANGE);
+ NSRect rect = lineBounds[lineIndex];
+ int height = Math.max((int)Math.ceil(rect.height), ascent + descent);
+ return new Rectangle((int)rect.x, (int)rect.y, (int)Math.ceil(rect.width), height);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns the receiver's line count. This includes lines caused
+ * by wrapping.
+ *
+ * @return the line count
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getLineCount() {
+ checkLayout ();
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ computeRuns();
+ return lineOffsets.length - 1;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns the font metrics for the specified line index.
+ *
+ * @param lineIndex the line index
+ * @return the font metrics
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the line index is out of range</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public FontMetrics getLineMetrics (int lineIndex) {
+ checkLayout ();
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ computeRuns();
+ int lineCount = getLineCount();
+ if (!(0 <= lineIndex && lineIndex < lineCount)) SWT.error(SWT.ERROR_INVALID_RANGE);
+ int length = text.length();
+ if (length == 0) {
+ Font font = this.font != null ? this.font : device.systemFont;
+ NSFont nsFont = font.handle;
+ int ascent = (int)(0.5f + nsFont.ascender());
+ int descent = (int)(0.5f + (-nsFont.descender() + nsFont.leading()));
+ ascent = Math.max(ascent, this.ascent);
+ descent = Math.max(descent, this.descent);
+ return FontMetrics.cocoa_new(ascent, descent, 0, 0, ascent + descent);
+ }
+ Rectangle rect = getLineBounds(lineIndex);
+ int baseline = (int)layoutManager.typesetter().baselineOffsetInLayoutManager(layoutManager, getLineOffsets()[lineIndex]);
+ return FontMetrics.cocoa_new(rect.height - baseline, baseline, 0, 0, rect.height);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns the location for the specified character offset. The
+ * <code>trailing</code> argument indicates whether the offset
+ * corresponds to the leading or trailing edge of the cluster.
+ *
+ * @param offset the character offset
+ * @param trailing the trailing flag
+ * @return the location of the character offset
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getOffset(Point, int[])
+ * @see #getOffset(int, int, int[])
+ */
+public Point getLocation(int offset, boolean trailing) {
+ checkLayout();
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ computeRuns();
+ int length = text.length();
+ if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE);
+ if (length == 0) return new Point(0, 0);
+ offset = translateOffset(offset);
+ int /*long*/ glyphIndex = layoutManager.glyphIndexForCharacterAtIndex(offset);
+ NSRect rect = layoutManager.lineFragmentUsedRectForGlyphAtIndex(glyphIndex, 0);
+ NSPoint point = layoutManager.locationForGlyphAtIndex(glyphIndex);
+ if (trailing) {
+ NSRange range = new NSRange();
+ range.location = offset;
+ range.length = 1;
+ int /*long*/ pRectCount = OS.malloc(C.PTR_SIZEOF);
+ int /*long*/ pArray = layoutManager.rectArrayForCharacterRange(range, range, textContainer, pRectCount);
+ int /*long*/ [] rectCount = new int /*long*/ [1];
+ OS.memmove(rectCount, pRectCount, C.PTR_SIZEOF);
+ OS.free(pRectCount);
+ if (rectCount[0] > 0) {
+ NSRect bounds = new NSRect();
+ OS.memmove(bounds, pArray, NSRect.sizeof);
+ fixRect(bounds);
+ point.x += bounds.width;
+ }
+ }
+ return new Point((int)point.x, (int)rect.y);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns the next offset for the specified offset and movement
+ * type. The movement is one of <code>SWT.MOVEMENT_CHAR</code>,
+ * <code>SWT.MOVEMENT_CLUSTER</code>, <code>SWT.MOVEMENT_WORD</code>,
+ * <code>SWT.MOVEMENT_WORD_END</code> or <code>SWT.MOVEMENT_WORD_START</code>.
+ *
+ * @param offset the start offset
+ * @param movement the movement type
+ * @return the next offset
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the offset is out of range</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getPreviousOffset(int, int)
+ */
+public int getNextOffset (int offset, int movement) {
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ return _getOffset(offset, movement, true);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+int _getOffset (int offset, int movement, boolean forward) {
+ checkLayout();
+ computeRuns();
+ int length = text.length();
+ if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE);
+ if (length == 0) return 0;
+ offset = translateOffset(offset);
+ length = translateOffset(length);
+ switch (movement) {
+ case SWT.MOVEMENT_CLUSTER://TODO cluster
+ case SWT.MOVEMENT_CHAR: {
+ boolean invalid = false;
+ do {
+ int newOffset = offset;
+ if (forward) {
+ if (newOffset < length) newOffset++;
+ } else {
+ if (newOffset > 0) newOffset--;
+ }
+ if (newOffset == offset) break;
+ offset = newOffset;
+ invalid = false;
+ if (invalidOffsets != null) {
+ for (int i = 0; i < invalidOffsets.length; i++) {
+ if (offset == invalidOffsets[i]) {
+ invalid = true;
+ break;
+ }
+ }
+ }
+ } while (invalid);
+ return untranslateOffset(offset);
+ }
+ case SWT.MOVEMENT_WORD: {
+ return untranslateOffset((int)/*64*/textStorage.nextWordFromIndex(offset, forward));
+ }
+ case SWT.MOVEMENT_WORD_END: {
+ NSRange range = textStorage.doubleClickAtIndex(length == offset ? length - 1 : offset);
+ return untranslateOffset((int)/*64*/(range.location + range.length));
+ }
+ case SWT.MOVEMENT_WORD_START: {
+ NSRange range = textStorage.doubleClickAtIndex(length == offset ? length - 1 : offset);
+ return untranslateOffset((int)/*64*/range.location);
+ }
+ }
+ return untranslateOffset(offset);
+}
+
+/**
+ * Returns the character offset for the specified point.
+ * For a typical character, the trailing argument will be filled in to
+ * indicate whether the point is closer to the leading edge (0) or
+ * the trailing edge (1). When the point is over a cluster composed
+ * of multiple characters, the trailing argument will be filled with the
+ * position of the character in the cluster that is closest to
+ * the point.
+ *
+ * @param point the point
+ * @param trailing the trailing buffer
+ * @return the character offset
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the trailing length is less than <code>1</code></li>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getLocation(int, boolean)
+ */
+public int getOffset(Point point, int[] trailing) {
+ checkLayout();
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ computeRuns();
+ if (point == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ return getOffset(point.x, point.y, trailing);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns the character offset for the specified point.
+ * For a typical character, the trailing argument will be filled in to
+ * indicate whether the point is closer to the leading edge (0) or
+ * the trailing edge (1). When the point is over a cluster composed
+ * of multiple characters, the trailing argument will be filled with the
+ * position of the character in the cluster that is closest to
+ * the point.
+ *
+ * @param x the x coordinate of the point
+ * @param y the y coordinate of the point
+ * @param trailing the trailing buffer
+ * @return the character offset
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the trailing length is less than <code>1</code></li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getLocation(int, boolean)
+ */
+public int getOffset(int x, int y, int[] trailing) {
+ checkLayout();
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ computeRuns();
+ if (trailing != null && trailing.length < 1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ int length = text.length();
+ if (length == 0) return 0;
+ NSPoint pt = new NSPoint();
+ pt.x = x;
+ pt.y = y;
+ float /*double*/[] partialFration = new float /*double*/[1];
+ int /*long*/ glyphIndex = layoutManager.glyphIndexForPoint(pt, textContainer, partialFration);
+ int /*long*/ offset = layoutManager.characterIndexForGlyphAtIndex(glyphIndex);
+ if (trailing != null) trailing[0] = Math.round((float)/*64*/partialFration[0]);
+ return Math.min(untranslateOffset((int)/*64*/offset), length - 1);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns the orientation of the receiver.
+ *
+ * @return the orientation style
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getOrientation() {
+ checkLayout();
+ return orientation;
+}
+
+/**
+ * Returns the previous offset for the specified offset and movement
+ * type. The movement is one of <code>SWT.MOVEMENT_CHAR</code>,
+ * <code>SWT.MOVEMENT_CLUSTER</code> or <code>SWT.MOVEMENT_WORD</code>,
+ * <code>SWT.MOVEMENT_WORD_END</code> or <code>SWT.MOVEMENT_WORD_START</code>.
+ *
+ * @param offset the start offset
+ * @param movement the movement type
+ * @return the previous offset
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the offset is out of range</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getNextOffset(int, int)
+ */
+public int getPreviousOffset (int index, int movement) {
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ return _getOffset(index, movement, false);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Gets the ranges of text that are associated with a <code>TextStyle</code>.
+ *
+ * @return the ranges, an array of offsets representing the start and end of each
+ * text style.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getStyles()
+ *
+ * @since 3.2
+ */
+public int[] getRanges () {
+ checkLayout();
+ int[] result = new int[styles.length * 2];
+ int count = 0;
+ for (int i=0; i<styles.length - 1; i++) {
+ if (styles[i].style != null) {
+ result[count++] = styles[i].start;
+ result[count++] = styles[i + 1].start - 1;
+ }
+ }
+ if (count != result.length) {
+ int[] newResult = new int[count];
+ System.arraycopy(result, 0, newResult, 0, count);
+ result = newResult;
+ }
+ return result;
+}
+
+/**
+ * Returns the text segments offsets of the receiver.
+ *
+ * @return the text segments offsets
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int[] getSegments() {
+ checkLayout();
+ return segments;
+}
+
+String getSegmentsText() {
+ if (segments == null) return text;
+ int nSegments = segments.length;
+ if (nSegments <= 1) return text;
+ int length = text.length();
+ if (length == 0) return text;
+ if (nSegments == 2) {
+ if (segments[0] == 0 && segments[1] == length) return text;
+ }
+ invalidOffsets = new int[nSegments];
+ char[] oldChars = new char[length];
+ text.getChars(0, length, oldChars, 0);
+ char[] newChars = new char[length + nSegments];
+ int charCount = 0, segmentCount = 0;
+ char separator = getOrientation() == SWT.RIGHT_TO_LEFT ? RTL_MARK : LTR_MARK;
+ while (charCount < length) {
+ if (segmentCount < nSegments && charCount == segments[segmentCount]) {
+ invalidOffsets[segmentCount] = charCount + segmentCount;
+ newChars[charCount + segmentCount++] = separator;
+ } else {
+ newChars[charCount + segmentCount] = oldChars[charCount++];
+ }
+ }
+ if (segmentCount < nSegments) {
+ invalidOffsets[segmentCount] = charCount + segmentCount;
+ segments[segmentCount] = charCount;
+ newChars[charCount + segmentCount++] = separator;
+ }
+ if (segmentCount != nSegments) {
+ int[] tmp = new int [segmentCount];
+ System.arraycopy(invalidOffsets, 0, tmp, 0, segmentCount);
+ invalidOffsets = tmp;
+ }
+ return new String(newChars, 0, Math.min(charCount + segmentCount, newChars.length));
+}
+
+/**
+ * Returns the line spacing of the receiver.
+ *
+ * @return the line spacing
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getSpacing () {
+ checkLayout();
+ return spacing;
+}
+
+/**
+ * Gets the style of the receiver at the specified character offset.
+ *
+ * @param offset the text offset
+ * @return the style or <code>null</code> if not set
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the character offset is out of range</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public TextStyle getStyle (int offset) {
+ checkLayout();
+ int length = text.length();
+ if (!(0 <= offset && offset < length)) SWT.error(SWT.ERROR_INVALID_RANGE);
+ for (int i=1; i<styles.length; i++) {
+ StyleItem item = styles[i];
+ if (item.start > offset) {
+ return styles[i - 1].style;
+ }
+ }
+ return null;
+}
+
+/**
+ * Gets all styles of the receiver.
+ *
+ * @return the styles
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getRanges()
+ *
+ * @since 3.2
+ */
+public TextStyle[] getStyles () {
+ checkLayout();
+ TextStyle[] result = new TextStyle[styles.length];
+ int count = 0;
+ for (int i=0; i<styles.length; i++) {
+ if (styles[i].style != null) {
+ result[count++] = styles[i].style;
+ }
+ }
+ if (count != result.length) {
+ TextStyle[] newResult = new TextStyle[count];
+ System.arraycopy(result, 0, newResult, 0, count);
+ result = newResult;
+ }
+ return result;
+}
+
+/**
+ * Returns the tab list of the receiver.
+ *
+ * @return the tab list
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int[] getTabs() {
+ checkLayout();
+ return tabs;
+}
+
+/**
+ * Gets the receiver's text, which will be an empty
+ * string if it has never been set.
+ *
+ * @return the receiver's text
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public String getText () {
+ checkLayout ();
+ return text;
+}
+
+/**
+ * Returns the width of the receiver.
+ *
+ * @return the width
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getWidth () {
+ checkLayout();
+ return wrapWidth;
+}
+
+/**
+ * Returns <code>true</code> if the text layout has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the text layout.
+ * When a text layout has been disposed, it is an error to
+ * invoke any other method using the text layout.
+ * </p>
+ *
+ * @return <code>true</code> when the text layout is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed () {
+ return device == null;
+}
+
+/*
+ * Returns true if the underline style is supported natively
+ */
+boolean isUnderlineSupported (TextStyle style) {
+ if (style != null && style.underline) {
+ int uStyle = style.underlineStyle;
+ return uStyle == SWT.UNDERLINE_SINGLE || uStyle == SWT.UNDERLINE_DOUBLE || uStyle == SWT.UNDERLINE_LINK || uStyle == UNDERLINE_THICK;
+ }
+ return false;
+}
+
+/**
+ * Sets the text alignment for the receiver. The alignment controls
+ * how a line of text is positioned horizontally. The argument should
+ * be one of <code>SWT.LEFT</code>, <code>SWT.RIGHT</code> or <code>SWT.CENTER</code>.
+ * <p>
+ * The default alignment is <code>SWT.LEFT</code>. Note that the receiver's
+ * width must be set in order to use <code>SWT.RIGHT</code> or <code>SWT.CENTER</code>
+ * alignment.
+ * </p>
+ *
+ * @param alignment the new alignment
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setWidth(int)
+ */
+public void setAlignment (int alignment) {
+ checkLayout();
+ int mask = SWT.LEFT | SWT.CENTER | SWT.RIGHT;
+ alignment &= mask;
+ if (alignment == 0) return;
+ if ((alignment & SWT.LEFT) != 0) alignment = SWT.LEFT;
+ if ((alignment & SWT.RIGHT) != 0) alignment = SWT.RIGHT;
+ if (this.alignment == alignment) return;
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ freeRuns();
+ this.alignment = alignment;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Sets the ascent of the receiver. The ascent is distance in pixels
+ * from the baseline to the top of the line and it is applied to all
+ * lines. The default value is <code>-1</code> which means that the
+ * ascent is calculated from the line fonts.
+ *
+ * @param ascent the new ascent
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the ascent is less than <code>-1</code></li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setDescent(int)
+ * @see #getLineMetrics(int)
+ */
+public void setAscent (int ascent) {
+ checkLayout ();
+ if (ascent < -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (this.ascent == ascent) return;
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ freeRuns();
+ this.ascent = ascent;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Sets the descent of the receiver. The descent is distance in pixels
+ * from the baseline to the bottom of the line and it is applied to all
+ * lines. The default value is <code>-1</code> which means that the
+ * descent is calculated from the line fonts.
+ *
+ * @param descent the new descent
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the descent is less than <code>-1</code></li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setAscent(int)
+ * @see #getLineMetrics(int)
+ */
+public void setDescent (int descent) {
+ checkLayout ();
+ if (descent < -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (this.descent == descent) return;
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ freeRuns();
+ this.descent = descent;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Sets the default font which will be used by the receiver
+ * to draw and measure text. If the
+ * argument is null, then a default font appropriate
+ * for the platform will be used instead. Note that a text
+ * style can override the default font.
+ *
+ * @param font the new font for the receiver, or null to indicate a default font
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the font has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setFont (Font font) {
+ checkLayout ();
+ if (font != null && font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ Font oldFont = this.font;
+ if (oldFont == font) return;
+ this.font = font;
+ if (oldFont != null && oldFont.equals(font)) return;
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ freeRuns();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Sets the indent of the receiver. This indent it applied of the first line of
+ * each paragraph.
+ *
+ * @param indent new indent
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.2
+ */
+public void setIndent (int indent) {
+ checkLayout ();
+ if (indent < 0) return;
+ if (this.indent == indent) return;
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ freeRuns();
+ this.indent = indent;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Sets the justification of the receiver. Note that the receiver's
+ * width must be set in order to use justification.
+ *
+ * @param justify new justify
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.2
+ */
+public void setJustify (boolean justify) {
+ checkLayout ();
+ if (justify == this.justify) return;
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ freeRuns();
+ this.justify = justify;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Sets the orientation of the receiver, which must be one
+ * of <code>SWT.LEFT_TO_RIGHT</code> or <code>SWT.RIGHT_TO_LEFT</code>.
+ *
+ * @param orientation new orientation style
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setOrientation(int orientation) {
+ checkLayout();
+ int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
+ orientation &= mask;
+ if (orientation == 0) return;
+ if ((orientation & SWT.LEFT_TO_RIGHT) != 0) orientation = SWT.LEFT_TO_RIGHT;
+ if (this.orientation == orientation) return;
+ this.orientation = orientation;
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ freeRuns();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Sets the offsets of the receiver's text segments. Text segments are used to
+ * override the default behaviour of the bidirectional algorithm.
+ * Bidirectional reordering can happen within a text segment but not
+ * between two adjacent segments.
+ * <p>
+ * Each text segment is determined by two consecutive offsets in the
+ * <code>segments</code> arrays. The first element of the array should
+ * always be zero and the last one should always be equals to length of
+ * the text.
+ * </p>
+ *
+ * @param segments the text segments offset
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setSegments(int[] segments) {
+ checkLayout();
+ if (this.segments == null && segments == null) return;
+ if (this.segments != null && segments !=null) {
+ if (this.segments.length == segments.length) {
+ int i;
+ for (i = 0; i <segments.length; i++) {
+ if (this.segments[i] != segments[i]) break;
+ }
+ if (i == segments.length) return;
+ }
+ }
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ freeRuns();
+ this.segments = segments;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Sets the line spacing of the receiver. The line spacing
+ * is the space left between lines.
+ *
+ * @param spacing the new line spacing
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the spacing is negative</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setSpacing (int spacing) {
+ checkLayout();
+ if (spacing < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (this.spacing == spacing) return;
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ freeRuns();
+ this.spacing = spacing;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Sets the style of the receiver for the specified range. Styles previously
+ * set for that range will be overwritten. The start and end offsets are
+ * inclusive and will be clamped if out of range.
+ *
+ * @param style the style
+ * @param start the start offset
+ * @param end the end offset
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setStyle (TextStyle style, int start, int end) {
+ checkLayout();
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ int length = text.length();
+ if (length == 0) return;
+ if (start > end) return;
+ start = Math.min(Math.max(0, start), length - 1);
+ end = Math.min(Math.max(0, end), length - 1);
+ int low = -1;
+ int high = styles.length;
+ while (high - low > 1) {
+ int index = (high + low) / 2;
+ if (styles[index + 1].start > start) {
+ high = index;
+ } else {
+ low = index;
+ }
+ }
+ if (0 <= high && high < styles.length) {
+ StyleItem item = styles[high];
+ if (item.start == start && styles[high + 1].start - 1 == end) {
+ if (style == null) {
+ if (item.style == null) return;
+ } else {
+ if (style.equals(item.style)) return;
+ }
+ }
+ }
+ freeRuns();
+ int modifyStart = high;
+ int modifyEnd = modifyStart;
+ while (modifyEnd < styles.length) {
+ if (styles[modifyEnd + 1].start > end) break;
+ modifyEnd++;
+ }
+ if (modifyStart == modifyEnd) {
+ int styleStart = styles[modifyStart].start;
+ int styleEnd = styles[modifyEnd + 1].start - 1;
+ if (styleStart == start && styleEnd == end) {
+ styles[modifyStart].style = style;
+ return;
+ }
+ if (styleStart != start && styleEnd != end) {
+ StyleItem[] newStyles = new StyleItem[styles.length + 2];
+ System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1);
+ StyleItem item = new StyleItem();
+ item.start = start;
+ item.style = style;
+ newStyles[modifyStart + 1] = item;
+ item = new StyleItem();
+ item.start = end + 1;
+ item.style = styles[modifyStart].style;
+ newStyles[modifyStart + 2] = item;
+ System.arraycopy(styles, modifyEnd + 1, newStyles, modifyEnd + 3, styles.length - modifyEnd - 1);
+ styles = newStyles;
+ return;
+ }
+ }
+ if (start == styles[modifyStart].start) modifyStart--;
+ if (end == styles[modifyEnd + 1].start - 1) modifyEnd++;
+ int newLength = styles.length + 1 - (modifyEnd - modifyStart - 1);
+ StyleItem[] newStyles = new StyleItem[newLength];
+ System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1);
+ StyleItem item = new StyleItem();
+ item.start = start;
+ item.style = style;
+ newStyles[modifyStart + 1] = item;
+ styles[modifyEnd].start = end + 1;
+ System.arraycopy(styles, modifyEnd, newStyles, modifyStart + 2, styles.length - modifyEnd);
+ styles = newStyles;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Sets the receiver's tab list. Each value in the tab list specifies
+ * the space in pixels from the origin of the text layout to the respective
+ * tab stop. The last tab stop width is repeated continuously.
+ *
+ * @param tabs the new tab list
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setTabs(int[] tabs) {
+ checkLayout();
+ if (this.tabs == null && tabs == null) return;
+ if (this.tabs != null && tabs !=null) {
+ if (this.tabs.length == tabs.length) {
+ int i;
+ for (i = 0; i < tabs.length; i++) {
+ if (this.tabs[i] != tabs[i]) break;
+ }
+ if (i == tabs.length) return;
+ }
+ }
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ freeRuns();
+ this.tabs = tabs;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Sets the receiver's text.
+ *<p>
+ * Note: Setting the text also clears all the styles. This method
+ * returns without doing anything if the new text is the same as
+ * the current text.
+ * </p>
+ *
+ * @param text the new text
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setText (String text) {
+ checkLayout ();
+ if (text == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (text.equals(this.text)) return;
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ freeRuns();
+ this.text = text;
+ styles = new StyleItem[2];
+ styles[0] = new StyleItem();
+ styles[1] = new StyleItem();
+ styles[styles.length - 1].start = text.length();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Sets the line width of the receiver, which determines how
+ * text should be wrapped and aligned. The default value is
+ * <code>-1</code> which means wrapping is disabled.
+ *
+ * @param width the new width
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the width is <code>0</code> or less than <code>-1</code></li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setAlignment(int)
+ */
+public void setWidth (int width) {
+ checkLayout();
+ if (width < -1 || width == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (this.wrapWidth == width) return;
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ freeRuns();
+ this.wrapWidth = width;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+public String toString () {
+ if (isDisposed()) return "TextLayout {*DISPOSED*}";
+ return "TextLayout {" + text + "}";
+}
+
+/*
+ * Translate a client offset to an internal offset
+ */
+int translateOffset (int offset) {
+ int length = text.length();
+ if (length == 0) return offset;
+ if (invalidOffsets == null) return offset;
+ for (int i = 0; i < invalidOffsets.length; i++) {
+ if (offset < invalidOffsets[i]) break;
+ offset++;
+ }
+ return offset;
+}
+
+/*
+ * Translate an internal offset to a client offset
+ */
+int untranslateOffset (int offset) {
+ int length = text.length();
+ if (length == 0) return offset;
+ if (invalidOffsets == null) return offset;
+ for (int i = 0; i < invalidOffsets.length; i++) {
+ if (offset == invalidOffsets[i]) {
+ offset++;
+ continue;
+ }
+ if (offset < invalidOffsets[i]) {
+ return offset - i;
+ }
+ }
+ return offset - invalidOffsets.length;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Transform.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Transform.java
new file mode 100755
index 0000000000..b4eee32e72
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Transform.java
@@ -0,0 +1,477 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class represent transformation matrices for
+ * points expressed as (x, y) pairs of floating point numbers.
+ * <p>
+ * Application code must explicitly invoke the <code>Transform.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ * <p>
+ * This class requires the operating system's advanced graphics subsystem
+ * which may not be available on some platforms.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: GraphicsExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.1
+ */
+public class Transform extends Resource {
+ /**
+ * the OS resource for the Transform
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public NSAffineTransform handle;
+
+/**
+ * Constructs a new identity Transform.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the Transform
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the Transform could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ */
+public Transform (Device device) {
+ this(device, 1, 0, 0, 1, 0, 0);
+}
+
+/**
+ * Constructs a new Transform given an array of elements that represent the
+ * matrix that describes the transformation.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the Transform
+ * @param elements an array of floats that describe the transformation matrix
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device, or the elements array is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the elements array is too small to hold the matrix values</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the Transform could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ */
+public Transform(Device device, float[] elements) {
+ this (device, checkTransform(elements)[0], elements[1], elements[2], elements[3], elements[4], elements[5]);
+}
+
+/**
+ * Constructs a new Transform given all of the elements that represent the
+ * matrix that describes the transformation.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the Transform
+ * @param m11 the first element of the first row of the matrix
+ * @param m12 the second element of the first row of the matrix
+ * @param m21 the first element of the second row of the matrix
+ * @param m22 the second element of the second row of the matrix
+ * @param dx the third element of the first row of the matrix
+ * @param dy the third element of the second row of the matrix
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the Transform could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ */
+public Transform (Device device, float m11, float m12, float m21, float m22, float dx, float dy) {
+ super(device);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ handle = NSAffineTransform.transform();
+ if (handle == null) SWT.error(SWT.ERROR_NO_HANDLES);
+ handle.retain();
+ setElements(m11, m12, m21, m22, dx, dy);
+ init();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+static float[] checkTransform(float[] elements) {
+ if (elements == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (elements.length < 6) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ return elements;
+}
+
+void destroy() {
+ handle.release();
+ handle = null;
+}
+
+/**
+ * Fills the parameter with the values of the transformation matrix
+ * that the receiver represents, in the order {m11, m12, m21, m22, dx, dy}.
+ *
+ * @param elements array to hold the matrix values
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the parameter is too small to hold the matrix values</li>
+ * </ul>
+ */
+public void getElements(float[] elements) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (elements == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (elements.length < 6) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSAffineTransformStruct struct = handle.transformStruct();
+ elements[0] = (float)/*64*/struct.m11;
+ elements[1] = (float)/*64*/struct.m12;
+ elements[2] = (float)/*64*/struct.m21;
+ elements[3] = (float)/*64*/struct.m22;
+ elements[4] = (float)/*64*/struct.tX;
+ elements[5] = (float)/*64*/struct.tY;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Modifies the receiver such that the matrix it represents becomes the
+ * identity matrix.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.4
+ */
+public void identity() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSAffineTransformStruct struct = new NSAffineTransformStruct();
+ struct.m11 = 1;
+ struct.m22 = 1;
+ handle.setTransformStruct(struct);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Modifies the receiver such that the matrix it represents becomes
+ * the mathematical inverse of the matrix it previously represented.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_CANNOT_INVERT_MATRIX - if the matrix is not invertible</li>
+ * </ul>
+ */
+public void invert() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSAffineTransformStruct struct = handle.transformStruct();
+ if ((struct.m11 * struct.m22 - struct.m12 * struct.m21) == 0) {
+ SWT.error(SWT.ERROR_CANNOT_INVERT_MATRIX);
+ }
+ handle.invert();
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns <code>true</code> if the Transform has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the Transform.
+ * When a Transform has been disposed, it is an error to
+ * invoke any other method using the Transform.
+ *
+ * @return <code>true</code> when the Transform is disposed, and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return handle == null;
+}
+
+/**
+ * Returns <code>true</code> if the Transform represents the identity matrix
+ * and false otherwise.
+ *
+ * @return <code>true</code> if the receiver is an identity Transform, and <code>false</code> otherwise
+ */
+public boolean isIdentity() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSAffineTransformStruct struct = handle.transformStruct();
+ return struct.m11 == 1 && struct.m12 == 0 && struct.m21 == 0 && struct.m22 == 1 && struct.tX == 0 && struct.tY == 0;
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Modifies the receiver such that the matrix it represents becomes the
+ * the result of multiplying the matrix it previously represented by the
+ * argument.
+ *
+ * @param matrix the matrix to multiply the receiver by
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ */
+public void multiply(Transform matrix) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (matrix == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (matrix.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ handle.prependTransform(matrix.handle);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Modifies the receiver so that it represents a transformation that is
+ * equivalent to its previous transformation rotated by the specified angle.
+ * The angle is specified in degrees and for the identity transform 0 degrees
+ * is at the 3 o'clock position. A positive value indicates a clockwise rotation
+ * while a negative value indicates a counter-clockwise rotation.
+ *
+ * @param angle the angle to rotate the transformation by
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void rotate(float angle) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ handle.rotateByDegrees(angle);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Modifies the receiver so that it represents a transformation that is
+ * equivalent to its previous transformation scaled by (scaleX, scaleY).
+ *
+ * @param scaleX the amount to scale in the X direction
+ * @param scaleY the amount to scale in the Y direction
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void scale(float scaleX, float scaleY) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ handle.scaleXBy(scaleX, scaleY);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Modifies the receiver to represent a new transformation given all of
+ * the elements that represent the matrix that describes that transformation.
+ *
+ * @param m11 the first element of the first row of the matrix
+ * @param m12 the second element of the first row of the matrix
+ * @param m21 the first element of the second row of the matrix
+ * @param m22 the second element of the second row of the matrix
+ * @param dx the third element of the first row of the matrix
+ * @param dy the third element of the second row of the matrix
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setElements(float m11, float m12, float m21, float m22, float dx, float dy) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSAffineTransformStruct struct = new NSAffineTransformStruct();
+ struct.m11 = m11;
+ struct.m12 = m12;
+ struct.m21 = m21;
+ struct.m22 = m22;
+ struct.tX = dx;
+ struct.tY = dy;
+ handle.setTransformStruct(struct);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Modifies the receiver so that it represents a transformation that is
+ * equivalent to its previous transformation sheared by (shearX, shearY).
+ *
+ * @param shearX the shear factor in the X direction
+ * @param shearY the shear factor in the Y direction
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.4
+ */
+public void shear(float shearX, float shearY) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSAffineTransformStruct struct = new NSAffineTransformStruct();
+ struct.m11 = 1;
+ struct.m12 = shearX;
+ struct.m21 = shearY;
+ struct.m22 = 1;
+ NSAffineTransform matrix = NSAffineTransform.transform();
+ matrix.setTransformStruct(struct);
+ handle.prependTransform(matrix);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Given an array containing points described by alternating x and y values,
+ * modify that array such that each point has been replaced with the result of
+ * applying the transformation represented by the receiver to that point.
+ *
+ * @param pointArray an array of alternating x and y values to be transformed
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point array is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void transform(float[] pointArray) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ NSPoint point = new NSPoint();
+ int length = pointArray.length / 2;
+ for (int i = 0, j = 0; i < length; i++, j += 2) {
+ point.x = pointArray[j];
+ point.y = pointArray[j + 1];
+ point = handle.transformPoint(point);
+ pointArray[j] = (float)/*64*/point.x;
+ pointArray[j + 1] = (float)/*64*/point.y;
+ }
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Modifies the receiver so that it represents a transformation that is
+ * equivalent to its previous transformation translated by (offsetX, offsetY).
+ *
+ * @param offsetX the distance to translate in the X direction
+ * @param offsetY the distance to translate in the Y direction
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void translate(float offsetX, float offsetY) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ NSAutoreleasePool pool = null;
+ if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+ try {
+ handle.translateXBy(offsetX, offsetY);
+ } finally {
+ if (pool != null) pool.release();
+ }
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+public String toString() {
+ if (isDisposed()) return "Transform {*DISPOSED*}";
+ float[] elements = new float[6];
+ getElements(elements);
+ return "Transform {" + elements [0] + ", " + elements [1] + ", " +elements [2] + ", " +elements [3] + ", " +elements [4] + ", " +elements [5] + "}";
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Button.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Button.java
new file mode 100755
index 0000000000..c6386e25a4
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Button.java
@@ -0,0 +1,846 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.accessibility.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class represent a selectable user interface object that
+ * issues notification when pressed and released.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>ARROW, CHECK, PUSH, RADIO, TOGGLE, FLAT</dd>
+ * <dd>UP, DOWN, LEFT, RIGHT, CENTER</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles ARROW, CHECK, PUSH, RADIO, and TOGGLE
+ * may be specified.
+ * </p><p>
+ * Note: Only one of the styles LEFT, RIGHT, and CENTER may be specified.
+ * </p><p>
+ * Note: Only one of the styles UP, DOWN, LEFT, and RIGHT may be specified
+ * when the ARROW style is specified.
+ * </p><p>
+ * IMPORTANT: This class is intended to be subclassed <em>only</em>
+ * within the SWT implementation.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#button">Button snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Button extends Control {
+ String text;
+ Image image;
+ boolean grayed;
+
+ static final int EXTRA_HEIGHT = 2;
+ static final int EXTRA_WIDTH = 6;
+ static final int IMAGE_GAP = 2;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#ARROW
+ * @see SWT#CHECK
+ * @see SWT#PUSH
+ * @see SWT#RADIO
+ * @see SWT#TOGGLE
+ * @see SWT#FLAT
+ * @see SWT#UP
+ * @see SWT#DOWN
+ * @see SWT#LEFT
+ * @see SWT#RIGHT
+ * @see SWT#CENTER
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Button (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+int /*long*/ accessibilityAttributeValue (int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ NSString nsAttributeName = new NSString(arg0);
+
+ if (accessible != null) {
+ id returnObject = accessible.internal_accessibilityAttributeValue(nsAttributeName, ACC.CHILDID_SELF);
+ if (returnObject != null) return returnObject.id;
+ }
+
+ if (nsAttributeName.isEqualToString (OS.NSAccessibilityRoleAttribute) || nsAttributeName.isEqualToString (OS.NSAccessibilityRoleDescriptionAttribute)) {
+ NSString role = null;
+
+ if ((style & SWT.RADIO) != 0) {
+ role = OS.NSAccessibilityRadioButtonRole;
+ } else if ((style & SWT.ARROW) != 0) {
+ role = OS.NSAccessibilityButtonRole;
+ }
+
+ if (role != null) {
+ if (nsAttributeName.isEqualToString (OS.NSAccessibilityRoleAttribute))
+ return role.id;
+ else {
+ return OS.NSAccessibilityRoleDescription(role.id, 0);
+ }
+ }
+ }
+
+ return super.accessibilityAttributeValue(id, sel, arg0);
+}
+
+
+/**
+ * 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 control is selected by the user.
+ * <code>widgetDefaultSelected</code> is not called.
+ * </p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener(listener);
+ addListener(SWT.Selection,typedListener);
+ addListener(SWT.DefaultSelection,typedListener);
+}
+
+NSSize cellSize (int /*long*/ id, int /*long*/ sel) {
+ NSSize size = super.cellSize(id, sel);
+ if (image != null && ((style & (SWT.CHECK|SWT.RADIO)) !=0)) {
+ NSSize imageSize = image.handle.size();
+ size.width += imageSize.width + IMAGE_GAP;
+ size.height = Math.max(size.height, imageSize.height);
+ }
+ return size;
+}
+
+static int checkStyle (int style) {
+ style = checkBits (style, SWT.PUSH, SWT.ARROW, SWT.CHECK, SWT.RADIO, SWT.TOGGLE, 0);
+ if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
+ return checkBits (style, SWT.CENTER, SWT.LEFT, SWT.RIGHT, 0, 0, 0);
+ }
+ if ((style & (SWT.CHECK | SWT.RADIO)) != 0) {
+ return checkBits (style, SWT.LEFT, SWT.RIGHT, SWT.CENTER, 0, 0, 0);
+ }
+ if ((style & SWT.ARROW) != 0) {
+ style |= SWT.NO_FOCUS;
+ return checkBits (style, SWT.UP, SWT.DOWN, SWT.LEFT, SWT.RIGHT, 0, 0);
+ }
+ return style;
+}
+
+void click () {
+ postEvent (SWT.Selection);
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget();
+ if ((style & SWT.ARROW) != 0) {
+ // TODO use some OS metric instead of hardcoded values
+ int width = wHint != SWT.DEFAULT ? wHint : 14;
+ int height = hHint != SWT.DEFAULT ? hHint : 14;
+ return new Point (width, height);
+ }
+ NSSize size = ((NSButton)view).cell ().cellSize ();
+ int width = (int)Math.ceil (size.width);
+ int height = (int)Math.ceil (size.height);
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0 && (style & SWT.FLAT) == 0) {
+ if (display.smallFonts) height += EXTRA_HEIGHT;
+ width += EXTRA_WIDTH;
+ }
+ return new Point (width, height);
+}
+
+NSAttributedString createString() {
+ NSAttributedString attribStr = createString(text, null, foreground, style, true, true);
+ attribStr.autorelease();
+ return attribStr;
+}
+
+void createHandle () {
+ if ((style & SWT.PUSH) == 0) state |= THEME_BACKGROUND;
+ NSButton widget = (NSButton)new SWTButton().alloc();
+ widget.init();
+ /*
+ * Feature in Cocoa. Images touch the edge of rounded buttons
+ * when set to small size. The fix to subclass the button cell
+ * and offset the image drawing.
+ */
+// if (display.smallFonts && (style & (SWT.PUSH | SWT.TOGGLE)) != 0 && (style & SWT.FLAT) == 0) {
+ NSButtonCell cell = (NSButtonCell)new SWTButtonCell ().alloc ().init ();
+ widget.setCell (cell);
+ cell.release ();
+// }
+ int type = OS.NSMomentaryLightButton;
+ if ((style & SWT.PUSH) != 0) {
+ if ((style & SWT.FLAT) != 0) {
+ widget.setBezelStyle(OS.NSShadowlessSquareBezelStyle);
+// if ((style & SWT.BORDER) == 0) widget.setShowsBorderOnlyWhileMouseInside(true);
+ } else {
+ widget.setBezelStyle(OS.NSRoundedBezelStyle);
+ }
+ } else if ((style & SWT.CHECK) != 0) {
+ type = OS.NSSwitchButton;
+ } else if ((style & SWT.RADIO) != 0) {
+ type = OS.NSRadioButton;
+ } else if ((style & SWT.TOGGLE) != 0) {
+ type = OS.NSPushOnPushOffButton;
+ if ((style & SWT.FLAT) != 0) {
+ widget.setBezelStyle(OS.NSShadowlessSquareBezelStyle);
+// if ((style & SWT.BORDER) == 0) widget.setShowsBorderOnlyWhileMouseInside(true);
+ } else {
+ widget.setBezelStyle(OS.NSRoundedBezelStyle);
+ }
+ } else if ((style & SWT.ARROW) != 0) {
+ widget.setBezelStyle(OS.NSShadowlessSquareBezelStyle);
+ }
+ widget.setButtonType(type);
+ widget.setTitle(NSString.stringWith(""));
+ widget.setImagePosition(OS.NSImageLeft);
+ widget.setTarget(widget);
+ widget.setAction(OS.sel_sendSelection);
+ view = widget;
+ _setAlignment(style);
+}
+
+void createWidget() {
+ text = "";
+ super.createWidget ();
+}
+
+NSFont defaultNSFont() {
+ return display.buttonFont;
+}
+
+void deregister () {
+ super.deregister ();
+ display.removeWidget(((NSControl)view).cell());
+}
+
+boolean dragDetect(int x, int y, boolean filter, boolean[] consume) {
+ boolean dragging = super.dragDetect(x, y, filter, consume);
+ consume[0] = dragging;
+ return dragging;
+}
+
+void drawImageWithFrameInView (int /*long*/ id, int /*long*/ sel, int /*long*/ image, NSRect rect, int /*long*/ view) {
+ /*
+ * Feature in Cocoa. Images touch the edge of rounded buttons
+ * when set to small size. The fix to subclass the button cell
+ * and offset the image drawing.
+ */
+ if (display.smallFonts && (style & (SWT.PUSH | SWT.TOGGLE)) != 0 && (style & SWT.FLAT) == 0) {
+ rect.y += EXTRA_HEIGHT / 2;
+ rect.height += EXTRA_HEIGHT;
+ }
+ callSuper (id, sel, image, rect, view);
+}
+
+void drawInteriorWithFrame_inView (int /*long*/ id, int /*long*/ sel, NSRect cellRect, int /*long*/ viewid) {
+ super.drawInteriorWithFrame_inView(id, sel, cellRect, viewid);
+ if (image != null && ((style & (SWT.CHECK|SWT.RADIO)) !=0)) {
+ NSSize imageSize = image.handle.size();
+ NSCell nsCell = new NSCell(id);
+ float /*double*/ x = 0;
+ float /*double*/ y = (imageSize.height - cellRect.height)/2f;
+ NSRect imageRect = nsCell.imageRectForBounds(cellRect);
+ NSSize stringSize = ((NSButton)view).attributedTitle().size();
+ switch (style & (SWT.LEFT|SWT.RIGHT|SWT.CENTER)) {
+ case SWT.LEFT:
+ x = imageRect.x + imageRect.width + IMAGE_GAP;
+ break;
+ case SWT.CENTER:
+ x = cellRect.x + imageRect.x + imageRect.width + ((cellRect.width-stringSize.width)/2f) - imageSize.width - IMAGE_GAP;
+ break;
+ case SWT.RIGHT:
+ x = cellRect.x + cellRect.width - stringSize.width - imageSize.width - IMAGE_GAP;
+ break;
+ }
+ NSRect destRect = new NSRect();
+ destRect.x = x;
+ destRect.y = y;
+ destRect.width = imageSize.width;
+ destRect.height = imageSize.height;
+ NSGraphicsContext.static_saveGraphicsState();
+ NSAffineTransform transform = NSAffineTransform.transform();
+ transform.scaleXBy(1, -1);
+ transform.translateXBy(0, -imageSize.height);
+ transform.concat();
+ image.handle.drawInRect(destRect, new NSRect(), OS.NSCompositeSourceOver, 1);
+ NSGraphicsContext.static_restoreGraphicsState();
+ }
+
+}
+
+void drawWidget (int /*long*/ id, NSGraphicsContext context, NSRect rect) {
+ if ((style & SWT.ARROW) != 0) {
+ NSRect frame = view.frame();
+ int arrowSize = Math.min((int)frame.height, (int)frame.width) / 2;
+ context.saveGraphicsState();
+ NSPoint p1 = new NSPoint();
+ p1.x = -arrowSize / 2;
+ p1.y = -arrowSize / 2;
+ NSPoint p2 = new NSPoint();
+ p2.x = arrowSize / 2;
+ p2.y = p1.y;
+ NSPoint p3 = new NSPoint();
+ p3.y = arrowSize / 2;
+
+ NSBezierPath path = NSBezierPath.bezierPath();
+ path.moveToPoint(p1);
+ path.lineToPoint(p2);
+ path.lineToPoint(p3);
+ path.closePath();
+
+ NSAffineTransform transform = NSAffineTransform.transform();
+ if ((style & SWT.LEFT) != 0) {
+ transform.rotateByDegrees(90);
+ } else if ((style & SWT.UP) != 0) {
+ transform.rotateByDegrees(180);
+ } else if ((style & SWT.RIGHT) != 0) {
+ transform.rotateByDegrees(-90);
+ }
+ path.transformUsingAffineTransform(transform);
+ transform = NSAffineTransform.transform();
+ transform.translateXBy(frame.width / 2, frame.height / 2);
+ path.transformUsingAffineTransform(transform);
+
+ NSColor color = isEnabled() ? NSColor.blackColor() : NSColor.disabledControlTextColor();
+ color.set();
+ path.fill();
+ context.restoreGraphicsState();
+ }
+ super.drawWidget (id, context, rect);
+}
+
+/**
+ * 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>
+ * unless the receiver is an <code>ARROW</code> button, in
+ * which case, the alignment will indicate the direction of
+ * the arrow (one of <code>LEFT</code>, <code>RIGHT</code>,
+ * <code>UP</code> or <code>DOWN</code>).
+ *
+ * @return the alignment
+ *
+ * @exception SWTException <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 & SWT.ARROW) != 0) {
+ if ((style & SWT.UP) != 0) return SWT.UP;
+ if ((style & SWT.DOWN) != 0) return SWT.DOWN;
+ if ((style & SWT.LEFT) != 0) return SWT.LEFT;
+ if ((style & SWT.RIGHT) != 0) return SWT.RIGHT;
+ return SWT.UP;
+ }
+ if ((style & SWT.LEFT) != 0) return SWT.LEFT;
+ if ((style & SWT.CENTER) != 0) return SWT.CENTER;
+ if ((style & SWT.RIGHT) != 0) return SWT.RIGHT;
+ return SWT.LEFT;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is grayed,
+ * and false otherwise. When the widget does not have
+ * the <code>CHECK</code> style, return false.
+ *
+ * @return the grayed state of the checkbox
+ *
+ * @exception SWTException <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.4
+ */
+public boolean getGrayed() {
+ checkWidget ();
+ if ((style & SWT.CHECK) == 0) return false;
+ return grayed;
+}
+
+/**
+ * Returns the receiver's image if it has one, or null
+ * if it does not.
+ *
+ * @return the receiver's image
+ *
+ * @exception SWTException <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 Image getImage () {
+ checkWidget();
+ return image;
+}
+
+String getNameText () {
+ return getText ();
+}
+
+/**
+ * Returns <code>true</code> if the receiver is selected,
+ * and false otherwise.
+ * <p>
+ * When the receiver is of type <code>CHECK</code> or <code>RADIO</code>,
+ * it is selected when it is checked. When it is of type <code>TOGGLE</code>,
+ * it is selected when it is pushed in. If the receiver is of any other type,
+ * this method returns false.
+ *
+ * @return the selection state
+ *
+ * @exception SWTException <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 boolean getSelection () {
+ checkWidget ();
+ if ((style & (SWT.CHECK | SWT.RADIO | SWT.TOGGLE)) == 0) return false;
+ if ((style & SWT.CHECK) != 0 && grayed) return ((NSButton)view).state() == OS.NSMixedState;
+ return ((NSButton)view).state() == OS.NSOnState;
+}
+
+/**
+ * Returns the receiver's text, which will be an empty
+ * string if it has never been set or if the receiver is
+ * an <code>ARROW</code> button.
+ *
+ * @return the receiver's text
+ *
+ * @exception SWTException <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 String getText () {
+ checkWidget ();
+ return text;
+}
+
+boolean isDescribedByLabel () {
+ return false;
+}
+
+/*
+ * Feature in Cocoa. If a checkbox is in multi-state mode, nextState cycles from off to mixed to on and back to off again.
+ * This will cause the on state to momentarily appear while clicking on the checkbox. To avoid this, we override [NSCell nextState]
+ * to go directly to the desired state if we have a grayed checkbox.
+ */
+int /*long*/ nextState(int /*long*/ id, int /*long*/ sel) {
+ if ((style & SWT.CHECK) != 0 && grayed) {
+ return ((NSButton)view).state() == OS.NSMixedState ? OS.NSOffState : OS.NSMixedState;
+ }
+
+ return super.nextState(id, sel);
+}
+
+void register() {
+ super.register();
+ display.addWidget(((NSControl)view).cell(), this);
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ image = null;
+ text = null;
+}
+
+/**
+ * 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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook(SWT.Selection, listener);
+ eventTable.unhook(SWT.DefaultSelection,listener);
+}
+
+void selectRadio () {
+ /*
+ * This code is intentionally commented. When two groups
+ * of radio buttons with the same parent are separated by
+ * another control, the correct behavior should be that
+ * the two groups act independently. This is consistent
+ * with radio tool and menu items. The commented code
+ * implements this behavior.
+ */
+// int index = 0;
+// Control [] children = parent._getChildren ();
+// while (index < children.length && children [index] != this) index++;
+// int i = index - 1;
+// while (i >= 0 && children [i].setRadioSelection (false)) --i;
+// int j = index + 1;
+// while (j < children.length && children [j].setRadioSelection (false)) j++;
+// setSelection (true);
+ Control [] children = parent._getChildren ();
+ for (int i=0; i<children.length; i++) {
+ Control child = children [i];
+ if (this != child) child.setRadioSelection (false);
+ }
+ setSelection (true);
+}
+
+void sendSelection () {
+ if ((style & SWT.RADIO) != 0) {
+ if ((parent.getStyle () & SWT.NO_RADIO_GROUP) == 0) {
+ selectRadio ();
+ }
+ }
+ if ((style & SWT.CHECK) != 0) {
+ if (grayed && ((NSButton)view).state() == OS.NSOnState) {
+ ((NSButton)view).setState(OS.NSOffState);
+ }
+ if (!grayed && ((NSButton)view).state() == OS.NSMixedState) {
+ ((NSButton)view).setState(OS.NSOnState);
+ }
+ }
+ postEvent (SWT.Selection);
+}
+
+
+/**
+ * Controls how text, images and arrows will be displayed
+ * in the receiver. The argument should be one of
+ * <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>
+ * unless the receiver is an <code>ARROW</code> button, in
+ * which case, the argument indicates the direction of
+ * the arrow (one of <code>LEFT</code>, <code>RIGHT</code>,
+ * <code>UP</code> or <code>DOWN</code>).
+ *
+ * @param alignment the new alignment
+ *
+ * @exception SWTException <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 ();
+ _setAlignment (alignment);
+ redraw ();
+}
+
+void _setAlignment (int alignment) {
+ if ((style & SWT.ARROW) != 0) {
+ if ((style & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT)) == 0) return;
+ style &= ~(SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT);
+ style |= alignment & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT);
+// int orientation = OS.kThemeDisclosureRight;
+// if ((style & SWT.UP) != 0) orientation = OS.kThemeDisclosureUp;
+// if ((style & SWT.DOWN) != 0) orientation = OS.kThemeDisclosureDown;
+// if ((style & SWT.LEFT) != 0) orientation = OS.kThemeDisclosureLeft;
+// OS.SetControl32BitValue (handle, orientation);
+ return;
+ }
+ if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) == 0) return;
+ style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER);
+ style |= alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER);
+ /* text is still null when this is called from createHandle() */
+ if (text != null) {
+ ((NSButton)view).setAttributedTitle(createString());
+ }
+// /* Alignment not honoured when image and text is visible */
+// boolean bothVisible = text != null && text.length () > 0 && image != null;
+// if (bothVisible) {
+// if ((style & (SWT.RADIO | SWT.CHECK)) != 0) alignment = SWT.LEFT;
+// if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) alignment = SWT.CENTER;
+// }
+// int textAlignment = 0;
+// int graphicAlignment = 0;
+// if ((alignment & SWT.LEFT) != 0) {
+// textAlignment = OS.kControlBevelButtonAlignTextFlushLeft;
+// graphicAlignment = OS.kControlBevelButtonAlignLeft;
+// }
+// if ((alignment & SWT.CENTER) != 0) {
+// textAlignment = OS.kControlBevelButtonAlignTextCenter;
+// graphicAlignment = OS.kControlBevelButtonAlignCenter;
+// }
+// if ((alignment & SWT.RIGHT) != 0) {
+// textAlignment = OS.kControlBevelButtonAlignTextFlushRight;
+// graphicAlignment = OS.kControlBevelButtonAlignRight;
+// }
+// OS.SetControlData (handle, OS.kControlEntireControl, OS.kControlBevelButtonTextAlignTag, 2, new short [] {(short)textAlignment});
+// OS.SetControlData (handle, OS.kControlEntireControl, OS.kControlBevelButtonGraphicAlignTag, 2, new short [] {(short)graphicAlignment});
+// if (bothVisible) {
+// OS.SetControlData (handle, OS.kControlEntireControl, OS.kControlBevelButtonTextPlaceTag, 2, new short [] {(short)OS.kControlBevelButtonPlaceToRightOfGraphic});
+// }
+}
+
+void updateBackground () {
+ NSColor nsColor = null;
+ if (backgroundImage != null) {
+ nsColor = NSColor.colorWithPatternImage(backgroundImage.handle);
+ } else if (background != null) {
+ nsColor = NSColor.colorWithDeviceRed(background[0], background[1], background[2], background[3]);
+ } else {
+ return; // TODO set to OS default
+ }
+ NSButtonCell cell = new NSButtonCell(((NSButton)view).cell());
+ cell.setBackgroundColor(nsColor);
+}
+
+void setFont (NSFont font) {
+ if (text != null) {
+ ((NSButton)view).setAttributedTitle(createString());
+ }
+}
+
+void setForeground (float /*double*/ [] color) {
+ ((NSButton)view).setAttributedTitle(createString());
+}
+
+/**
+ * Sets the grayed state of the receiver. This state change
+ * only applies if the control was created with the SWT.CHECK
+ * style.
+ *
+ * @param grayed the new grayed state
+ *
+ * @exception SWTException <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.4
+ */
+public void setGrayed(boolean grayed) {
+ checkWidget ();
+ if ((style & SWT.CHECK) == 0) return;
+ boolean checked = getSelection ();
+ this.grayed = grayed;
+ ((NSButton) view).setAllowsMixedState(grayed);
+
+ if (checked) {
+ if (grayed) {
+ ((NSButton) view).setState (OS.NSMixedState);
+ } else {
+ ((NSButton) view).setState (OS.NSOnState);
+ }
+ }
+}
+
+/**
+ * Sets the receiver's image to the argument, which may be
+ * <code>null</code> indicating that no image should be displayed.
+ * <p>
+ * Note that a Button can display an image and text simultaneously
+ * on Windows (starting with XP), GTK+ and OSX. On other platforms,
+ * a Button that has an image and text set into it will display the
+ * image or text that was set most recently.
+ * </p>
+ * @param image the image to display on the receiver (may be <code>null</code>)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setImage (Image image) {
+ checkWidget();
+ if (image != null && image.isDisposed ()) {
+ error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ if ((style & SWT.ARROW) != 0) return;
+ this.image = image;
+ if ((style & (SWT.RADIO|SWT.CHECK)) == 0) {
+ /*
+ * Feature in Cocoa. If the NSImage object being set into the button is
+ * the same NSImage object that is already there then the button does not
+ * redraw itself. This results in the button's image not visually updating
+ * if the NSImage object's content has changed since it was last set
+ * into the button. The workaround is to explicitly redraw the button.
+ */
+ ((NSButton)view).setImage(image != null ? image.handle : null);
+ view.setNeedsDisplay(true);
+ } else {
+ ((NSButton)view).setAttributedTitle(createString());
+ }
+ updateAlignment ();
+}
+
+boolean setRadioSelection (boolean value){
+ if ((style & SWT.RADIO) == 0) return false;
+ if (getSelection () != value) {
+ setSelection (value);
+ postEvent (SWT.Selection);
+ }
+ return true;
+}
+
+/**
+ * Sets the selection state of the receiver, if it is of type <code>CHECK</code>,
+ * <code>RADIO</code>, or <code>TOGGLE</code>.
+ *
+ * <p>
+ * When the receiver is of type <code>CHECK</code> or <code>RADIO</code>,
+ * it is selected when it is checked. When it is of type <code>TOGGLE</code>,
+ * it is selected when it is pushed in.
+ *
+ * @param selected the new selection state
+ *
+ * @exception SWTException <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 setSelection (boolean selected) {
+ checkWidget();
+ if ((style & (SWT.CHECK | SWT.RADIO | SWT.TOGGLE)) == 0) return;
+ if (grayed) {
+ ((NSButton)view).setState (selected ? OS.NSMixedState : OS.NSOffState);
+ } else {
+ ((NSButton)view).setState (selected ? OS.NSOnState : OS.NSOffState);
+ }
+}
+
+/**
+ * Sets the receiver's text.
+ * <p>
+ * This method sets the button label. The label may include
+ * the mnemonic character but must not contain line delimiters.
+ * </p>
+ * <p>
+ * Mnemonics are indicated by an '&amp;' that causes the next
+ * character to be the mnemonic. When the user presses a
+ * key sequence that matches the mnemonic, a selection
+ * event occurs. On most platforms, the mnemonic appears
+ * underlined but may be emphasized in a platform specific
+ * manner. The mnemonic indicator character '&amp;' can be
+ * escaped by doubling it in the string, causing a single
+ * '&amp;' to be displayed.
+ * </p><p>
+ * Note that a Button can display an image and text simultaneously
+ * on Windows (starting with XP), GTK+ and OSX. On other platforms,
+ * a Button that has an image and text set into it will display the
+ * image or text that was set most recently.
+ * </p>
+ * @param string the new text
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
+ * </ul>
+ * @exception SWTException <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 setText (String string) {
+ checkWidget();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if ((style & SWT.ARROW) != 0) return;
+ text = string;
+ ((NSButton)view).setAttributedTitle(createString());
+ updateAlignment ();
+}
+
+NSRect titleRectForBounds (int /*long*/ id, int /*long*/ sel, NSRect cellFrame) {
+ NSRect rect = super.titleRectForBounds(id, sel, cellFrame);
+ if (image != null && ((style & (SWT.CHECK|SWT.RADIO)) !=0)) {
+ NSSize imageSize = image.handle.size();
+ rect.x += imageSize.width + IMAGE_GAP;
+ rect.width -= (imageSize.width + IMAGE_GAP);
+ rect.width = Math.max(0f, rect.width);
+ }
+ return rect;
+}
+
+int traversalCode (int key, NSEvent theEvent) {
+ int code = super.traversalCode (key, theEvent);
+ if ((style & SWT.ARROW) != 0) code &= ~(SWT.TRAVERSE_TAB_NEXT | SWT.TRAVERSE_TAB_PREVIOUS);
+ if ((style & SWT.RADIO) != 0) code |= SWT.TRAVERSE_ARROW_NEXT | SWT.TRAVERSE_ARROW_PREVIOUS;
+ return code;
+}
+
+void updateAlignment () {
+ NSButton widget = (NSButton)view;
+ if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
+ if (text.length() != 0 && image != null) {
+ widget.setImagePosition(OS.NSImageLeft);
+ } else {
+ widget.setImagePosition(text.length() != 0 ? OS.NSNoImage : OS.NSImageOnly);
+ }
+ }
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Canvas.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Canvas.java
new file mode 100755
index 0000000000..97a2300553
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Canvas.java
@@ -0,0 +1,512 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class provide a surface for drawing
+ * arbitrary graphics.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * This class may be subclassed by custom control implementors
+ * who are building controls that are <em>not</em> constructed
+ * from aggregates of other controls. That is, they are either
+ * painted using SWT graphics calls or are handled by native
+ * methods.
+ * </p>
+ *
+ * @see Composite
+ * @see <a href="http://www.eclipse.org/swt/snippets/#canvas">Canvas snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+public class Canvas extends Composite {
+ Caret caret;
+ IME ime;
+ NSOpenGLContext context;
+
+Canvas () {
+ /* Do nothing */
+}
+
+int /*long*/ attributedSubstringFromRange (int /*long*/ id, int /*long*/ sel, int /*long*/ range) {
+ if (ime != null) return ime.attributedSubstringFromRange (id, sel, range);
+ return super.attributedSubstringFromRange(id, sel, range);
+}
+
+void sendFocusEvent(int type) {
+ if (caret != null) {
+ if (type == SWT.FocusIn) {
+ caret.setFocus();
+ } else {
+ caret.killFocus();
+ }
+ }
+ super.sendFocusEvent(type);
+}
+
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ * </ul>
+ *
+ * @see SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Canvas (Composite parent, int style) {
+ super (parent, style);
+}
+
+int /*long*/ characterIndexForPoint (int /*long*/ id, int /*long*/ sel, int /*long*/ point) {
+ if (ime != null) return ime.characterIndexForPoint (id, sel, point);
+ return super.characterIndexForPoint (id, sel, point);
+}
+
+/**
+ * Fills the interior of the rectangle specified by the arguments,
+ * with the receiver's background.
+ *
+ * @param gc the gc where the rectangle is to be filled
+ * @param x the x coordinate of the rectangle to be filled
+ * @param y the y coordinate of the rectangle to be filled
+ * @param width the width of the rectangle to be filled
+ * @param height the height of the rectangle to be filled
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the gc is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the gc has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 drawBackground (GC gc, int x, int y, int width, int height) {
+ checkWidget ();
+ if (gc == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (gc.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ Control control = findBackgroundControl ();
+ if (control != null) {
+ NSRect rect = new NSRect();
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ int imgHeight = -1;
+ GCData data = gc.getGCData();
+ if (data.image != null) imgHeight = data.image.getBounds().height;
+ NSGraphicsContext context = gc.handle;
+ if (data.flippedContext != null) {
+ NSGraphicsContext.static_saveGraphicsState();
+ NSGraphicsContext.setCurrentContext(context);
+ }
+ control.fillBackground (view, context, rect, imgHeight);
+ if (data.flippedContext != null) {
+ NSGraphicsContext.static_restoreGraphicsState();
+ }
+ } else {
+ gc.fillRectangle (x, y, width, height);
+ }
+}
+
+void drawRect (int /*long*/ id, int /*long*/ sel, NSRect rect) {
+ if (context != null && context.view() == null) context.setView(view);
+ super.drawRect(id, sel, rect);
+}
+
+void drawWidget (int /*long*/ id, NSGraphicsContext context, NSRect rect) {
+ if (id != view.id) return;
+ super.drawWidget (id, context, rect);
+ if (caret == null) return;
+ if (caret.isShowing) {
+ Image image = caret.image;
+ if (image != null) {
+ NSImage imageHandle = image.handle;
+ NSImageRep imageRep = imageHandle.bestRepresentationForDevice(null);
+ if (!imageRep.isKindOfClass(OS.class_NSBitmapImageRep)) return;
+ NSBitmapImageRep rep = new NSBitmapImageRep(imageRep);
+ CGRect destRect = new CGRect ();
+ destRect.origin.x = caret.x;
+ destRect.origin.y = caret.y;
+ NSSize size = imageHandle.size();
+ destRect.size.width = size.width;
+ destRect.size.height = size.height;
+ int /*long*/ data = rep.bitmapData();
+ int /*long*/ bpr = rep.bytesPerRow();
+ int alphaInfo = rep.hasAlpha() ? OS.kCGImageAlphaFirst : OS.kCGImageAlphaNoneSkipFirst;
+ int /*long*/ provider = OS.CGDataProviderCreateWithData(0, data, bpr * (int)size.height, 0);
+ int /*long*/ colorspace = OS.CGColorSpaceCreateDeviceRGB();
+ int /*long*/ cgImage = OS.CGImageCreate((int)size.width, (int)size.height, rep.bitsPerSample(), rep.bitsPerPixel(), bpr, colorspace, alphaInfo, provider, 0, true, 0);
+ OS.CGColorSpaceRelease(colorspace);
+ OS.CGDataProviderRelease(provider);
+ int /*long*/ ctx = context.graphicsPort();
+ OS.CGContextSaveGState(ctx);
+ OS.CGContextScaleCTM (ctx, 1, -1);
+ OS.CGContextTranslateCTM (ctx, 0, -(size.height + 2 * destRect.origin.y));
+ OS.CGContextSetBlendMode (ctx, OS.kCGBlendModeDifference);
+ OS.CGContextDrawImage (ctx, destRect, cgImage);
+ OS.CGContextRestoreGState(ctx);
+ OS.CGImageRelease(cgImage);
+ } else {
+ context.saveGraphicsState();
+ context.setCompositingOperation(OS.NSCompositeXOR);
+ NSRect drawRect = new NSRect();
+ drawRect.x = caret.x;
+ drawRect.y = caret.y;
+ drawRect.width = caret.width != 0 ? caret.width : Caret.DEFAULT_WIDTH;
+ drawRect.height = caret.height;
+ context.setShouldAntialias(false);
+ NSColor color = NSColor.colorWithDeviceRed(1, 1, 1, 1);
+ color.set();
+ NSBezierPath.fillRect(drawRect);
+ context.restoreGraphicsState();
+ }
+ }
+}
+
+NSRect firstRectForCharacterRange (int /*long*/ id, int /*long*/ sel, int /*long*/ range) {
+ if (ime != null) return ime.firstRectForCharacterRange (id, sel, range);
+ return super.firstRectForCharacterRange (id, sel, range);
+}
+
+/**
+ * Returns the caret.
+ * <p>
+ * The caret for the control is automatically hidden
+ * and shown when the control is painted or resized,
+ * when focus is gained or lost and when an the control
+ * is scrolled. To avoid drawing on top of the caret,
+ * the programmer must hide and show the caret when
+ * drawing in the window any other time.
+ * </p>
+ *
+ * @return the caret for the receiver, may be null
+ *
+ * @exception SWTException <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 Caret getCaret () {
+ checkWidget();
+ return caret;
+}
+
+/**
+ * Returns the IME.
+ *
+ * @return the IME
+ *
+ * @exception SWTException <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.4
+ */
+public IME getIME () {
+ checkWidget();
+ return ime;
+}
+
+boolean hasMarkedText (int /*long*/ id, int /*long*/ sel) {
+ if (ime != null) return ime.hasMarkedText (id, sel);
+ return super.hasMarkedText (id, sel);
+}
+
+boolean imeInComposition () {
+ return ime != null && ime.isInlineEnabled () && ime.startOffset != -1;
+}
+
+boolean insertText (int /*long*/ id, int /*long*/ sel, int /*long*/ string) {
+ if (ime != null) {
+ if (!ime.insertText (id, sel, string)) return false;
+ }
+ return super.insertText (id, sel, string);
+}
+
+boolean isOpaque (int /*long*/ id, int /*long*/ sel) {
+ if (context != null) return true;
+ return super.isOpaque(id, sel);
+}
+
+NSRange markedRange (int /*long*/ id, int /*long*/ sel) {
+ if (ime != null) return ime.markedRange (id, sel);
+ return super.markedRange (id, sel);
+}
+
+void releaseChildren (boolean destroy) {
+ if (caret != null) {
+ caret.release (false);
+ caret = null;
+ }
+ if (ime != null) {
+ ime.release (false);
+ ime = null;
+ }
+ super.releaseChildren (destroy);
+}
+
+/**
+ * Scrolls a rectangular area of the receiver by first copying
+ * the source area to the destination and then causing the area
+ * of the source which is not covered by the destination to
+ * be repainted. Children that intersect the rectangle are
+ * optionally moved during the operation. In addition, outstanding
+ * paint events are flushed before the source area is copied to
+ * ensure that the contents of the canvas are drawn correctly.
+ *
+ * @param destX the x coordinate of the destination
+ * @param destY the y coordinate of the destination
+ * @param x the x coordinate of the source
+ * @param y the y coordinate of the source
+ * @param width the width of the area
+ * @param height the height of the area
+ * @param all <code>true</code>if children should be scrolled, and <code>false</code> otherwise
+ *
+ * @exception SWTException <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 scroll (int destX, int destY, int x, int y, int width, int height, boolean all) {
+ checkWidget();
+ if (width <= 0 || height <= 0) return;
+ int deltaX = destX - x, deltaY = destY - y;
+ if (deltaX == 0 && deltaY == 0) return;
+ if (!isDrawing ()) return;
+ NSRect visibleRect = view.visibleRect();
+ if (visibleRect.width <= 0 || visibleRect.height <= 0) return;
+ boolean isFocus = caret != null && caret.isFocusCaret ();
+ if (isFocus) caret.killFocus ();
+ Rectangle clientRect = getClientArea ();
+ Rectangle sourceRect = new Rectangle (x, y, width, height);
+ if (sourceRect.intersects (clientRect)) {
+ update (all);
+ }
+ Control control = findBackgroundControl ();
+ boolean redraw = control != null && control.backgroundImage != null;
+ if (!redraw) redraw = isObscured ();
+ if (redraw) {
+ redrawWidget (view, x, y, width, height, false);
+ redrawWidget (view, destX, destY, width, height, false);
+ } else {
+ NSRect damage = new NSRect();
+ damage.x = x;
+ damage.y = y;
+ damage.width = width;
+ damage.height = height;
+ NSPoint dest = new NSPoint();
+ dest.x = destX;
+ dest.y = destY;
+
+ view.lockFocus();
+ OS.NSCopyBits(0, damage , dest);
+ view.unlockFocus();
+
+ boolean disjoint = (destX + width < x) || (x + width < destX) || (destY + height < y) || (y + height < destY);
+ if (disjoint) {
+ view.setNeedsDisplayInRect(damage);
+ } else {
+ if (deltaX != 0) {
+ int newX = destX - deltaX;
+ if (deltaX < 0) newX = destX + width;
+ damage.x = newX;
+ damage.width = Math.abs(deltaX);
+ view.setNeedsDisplayInRect(damage);
+ }
+ if (deltaY != 0) {
+ int newY = destY - deltaY;
+ if (deltaY < 0) newY = destY + height;
+ damage.x = x;
+ damage.y = newY;
+ damage.width = width;
+ damage.height = Math.abs (deltaY);
+ view.setNeedsDisplayInRect(damage);
+ }
+ }
+
+ NSRect srcRect = new NSRect();
+ srcRect.x = sourceRect.x;
+ srcRect.y = sourceRect.y;
+ srcRect.width = sourceRect.width;
+ srcRect.height = sourceRect.height;
+ OS.NSIntersectionRect(visibleRect, visibleRect, srcRect);
+
+ if (!OS.NSEqualRects(visibleRect, srcRect)) {
+ if (srcRect.x != visibleRect.x) {
+ damage.x = srcRect.x + deltaX;
+ damage.y = srcRect.y + deltaY;
+ damage.width = visibleRect.x - srcRect.x;
+ damage.height = srcRect.height;
+ view.setNeedsDisplayInRect(damage);
+ }
+ if (visibleRect.x + visibleRect.width != srcRect.x + srcRect.width) {
+ damage.x = srcRect.x + visibleRect.width + deltaX;
+ damage.y = srcRect.y + deltaY;
+ damage.width = srcRect.width - visibleRect.width;
+ damage.height = srcRect.height;
+ view.setNeedsDisplayInRect(damage);
+ }
+ if (visibleRect.y != srcRect.y) {
+ damage.x = visibleRect.x + deltaX;
+ damage.y = srcRect.y + deltaY;
+ damage.width = visibleRect.width;
+ damage.height = visibleRect.y - srcRect.y;
+ view.setNeedsDisplayInRect(damage);
+ }
+ if (visibleRect.y + visibleRect.height != srcRect.y + srcRect.height) {
+ damage.x = visibleRect.x + deltaX;
+ damage.y = visibleRect.y + visibleRect.height + deltaY;
+ damage.width = visibleRect.width;
+ damage.height = srcRect.y + srcRect.height - (visibleRect.y + visibleRect.height);
+ view.setNeedsDisplayInRect(damage);
+ }
+ }
+ }
+
+ if (all) {
+ Control [] children = _getChildren ();
+ for (int i=0; i<children.length; i++) {
+ Control child = children [i];
+ Rectangle rect = child.getBounds ();
+ if (Math.min(x + width, rect.x + rect.width) >= Math.max (x, rect.x) &&
+ Math.min(y + height, rect.y + rect.height) >= Math.max (y, rect.y)) {
+ child.setLocation (rect.x + deltaX, rect.y + deltaY);
+ }
+ }
+ }
+ if (isFocus) caret.setFocus ();
+}
+
+NSRange selectedRange (int /*long*/ id, int /*long*/ sel) {
+ if (ime != null) return ime.selectedRange (id, sel);
+ return super.selectedRange (id, sel);
+}
+
+boolean sendKeyEvent (NSEvent nsEvent, int type) {
+ if (caret != null) NSCursor.setHiddenUntilMouseMoves (true);
+ return super.sendKeyEvent (nsEvent, type);
+}
+
+/**
+ * Sets the receiver's caret.
+ * <p>
+ * The caret for the control is automatically hidden
+ * and shown when the control is painted or resized,
+ * when focus is gained or lost and when an the control
+ * is scrolled. To avoid drawing on top of the caret,
+ * the programmer must hide and show the caret when
+ * drawing in the window any other time.
+ * </p>
+ * @param caret the new caret for the receiver, may be null
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the caret has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setCaret (Caret caret) {
+ checkWidget();
+ Caret newCaret = caret;
+ Caret oldCaret = this.caret;
+ this.caret = newCaret;
+ if (hasFocus ()) {
+ if (oldCaret != null) oldCaret.killFocus ();
+ if (newCaret != null) {
+ if (newCaret.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ newCaret.setFocus ();
+ }
+ }
+}
+
+public void setFont (Font font) {
+ checkWidget ();
+ if (caret != null) caret.setFont (font);
+ super.setFont (font);
+}
+
+void setOpenGLContext(Object value) {
+ context = (NSOpenGLContext)value;
+}
+
+/**
+ * Sets the receiver's IME.
+ *
+ * @param ime the new IME for the receiver, may be null
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the IME has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.4
+ */
+public void setIME (IME ime) {
+ checkWidget ();
+ if (ime != null && ime.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ this.ime = ime;
+}
+
+boolean setMarkedText_selectedRange (int /*long*/ id, int /*long*/ sel, int /*long*/ string, int /*long*/ range) {
+ if (ime != null) {
+ if (!ime.setMarkedText_selectedRange (id, sel, string, range)) return false;
+ }
+ return super.setMarkedText_selectedRange (id, sel, string, range);
+}
+
+int /*long*/ validAttributesForMarkedText (int /*long*/ id, int /*long*/ sel) {
+ if (ime != null) return ime.validAttributesForMarkedText (id, sel);
+ return super.validAttributesForMarkedText(id, sel);
+}
+
+void updateOpenGLContext(int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+ if (context != null) ((NSOpenGLContext)context).update();
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Caret.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Caret.java
new file mode 100755
index 0000000000..410caaa566
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Caret.java
@@ -0,0 +1,505 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Instances of this class provide an i-beam that is typically used
+ * as the insertion point for text.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * IMPORTANT: This class is intended to be subclassed <em>only</em>
+ * within the SWT implementation.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#caret">Caret snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample, Canvas tab</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Caret extends Widget {
+ Canvas parent;
+ int x, y, width, height;
+ boolean isVisible, isShowing;
+ int blinkRate;
+ Image image;
+ Font font;
+
+ static final int DEFAULT_WIDTH = 1;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Caret (Canvas parent, int style) {
+ super (parent, style);
+ this.parent = parent;
+ createWidget ();
+}
+
+boolean blinkCaret () {
+ if (!isVisible) return true;
+ if (!isShowing) return showCaret ();
+ if (blinkRate == 0) return true;
+ return hideCaret ();
+}
+
+void createWidget () {
+ super.createWidget ();
+ blinkRate = display.getCaretBlinkTime ();
+ isVisible = true;
+ if (parent.getCaret () == null) {
+ parent.setCaret (this);
+ }
+}
+
+boolean drawCaret () {
+ if (parent == null) return false;
+ if (parent.isDisposed ()) return false;
+ int nWidth = width, nHeight = height;
+ if (nWidth <= 0) nWidth = DEFAULT_WIDTH;
+ if (image != null) {
+ NSSize size = image.handle.size();
+ nWidth = (int)size.width;
+ nHeight = (int)size.height;
+ }
+ NSRect rect = new NSRect();
+ rect.x = x;
+ rect.y = y;
+ rect.width = nWidth;
+ rect.height = nHeight;
+ parent.view.setNeedsDisplayInRect(rect);
+ return true;
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location
+ * relative to its parent (or its display if its parent is null).
+ *
+ * @return the receiver's bounding rectangle
+ *
+ * @exception SWTException <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 Rectangle getBounds () {
+ checkWidget();
+ if (image != null) {
+ Rectangle rect = image.getBounds ();
+ return new Rectangle (x, y, rect.width, rect.height);
+ } else {
+ if (width == 0) {
+ return new Rectangle (x, y, DEFAULT_WIDTH, height);
+ }
+ }
+ return new Rectangle (x, y, width, height);
+}
+
+/**
+ * Returns the font that the receiver will use to paint textual information.
+ *
+ * @return the receiver's font
+ *
+ * @exception SWTException <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 Font getFont () {
+ checkWidget();
+ if (font != null) return font;
+ return parent.getFont ();
+}
+
+/**
+ * Returns the image that the receiver will use to paint the caret.
+ *
+ * @return the receiver's image
+ *
+ * @exception SWTException <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 Image getImage () {
+ checkWidget();
+ return image;
+}
+
+/**
+ * Returns a point describing the receiver's location relative
+ * to its parent (or its display if its parent is null).
+ *
+ * @return the receiver's location
+ *
+ * @exception SWTException <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 Point getLocation () {
+ checkWidget();
+ return new Point (x, y);
+}
+
+/**
+ * Returns the receiver's parent, which must be a <code>Canvas</code>.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException <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 Canvas getParent () {
+ checkWidget();
+ return parent;
+}
+
+/**
+ * Returns a point describing the receiver's size.
+ *
+ * @return the receiver's size
+ *
+ * @exception SWTException <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 Point getSize () {
+ checkWidget();
+ if (image != null) {
+ Rectangle rect = image.getBounds ();
+ return new Point (rect.width, rect.height);
+ } else {
+ if (width == 0) {
+ return new Point (DEFAULT_WIDTH, height);
+ }
+ }
+ return new Point (width, height);
+}
+
+/**
+ * Returns <code>true</code> if the receiver is visible, and
+ * <code>false</code> otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ * </p>
+ *
+ * @return the receiver's visibility state
+ *
+ * @exception SWTException <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 boolean getVisible () {
+ checkWidget();
+ return isVisible;
+}
+
+boolean hideCaret () {
+ if (!isShowing) return true;
+ isShowing = false;
+ return drawCaret ();
+}
+
+/**
+ * Returns <code>true</code> if the receiver is visible and all
+ * of the receiver's ancestors are visible and <code>false</code>
+ * otherwise.
+ *
+ * @return the receiver's visibility state
+ *
+ * @exception SWTException <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 #getVisible
+ */
+public boolean isVisible () {
+ checkWidget();
+ return isVisible && parent.isVisible () && parent.hasFocus ();
+}
+
+boolean isFocusCaret () {
+ return this == display.currentCaret;
+}
+
+void killFocus () {
+ if (display.currentCaret != this) return;
+ display.setCurrentCaret (null);
+ if (isVisible) hideCaret ();
+}
+
+void releaseParent () {
+ super.releaseParent ();
+ if (this == parent.getCaret ()) parent.setCaret (null);
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ if (display.currentCaret == this) {
+ hideCaret ();
+ display.setCurrentCaret (null);
+ }
+ parent = null;
+ image = null;
+}
+
+/**
+ * Sets the receiver's size and location to the rectangular
+ * area specified by the arguments. The <code>x</code> and
+ * <code>y</code> arguments are relative to the receiver's
+ * parent (or its display if its parent is null).
+ *
+ * @param x the new x coordinate for the receiver
+ * @param y the new y coordinate for the receiver
+ * @param width the new width for the receiver
+ * @param height the new height for the receiver
+ *
+ * @exception SWTException <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 setBounds (int x, int y, int width, int height) {
+ checkWidget();
+ if (this.x == x && this.y == y && this.width == width && this.height == height) return;
+ boolean isFocus = isFocusCaret ();
+ if (isFocus && isVisible) hideCaret ();
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ if (isFocus && isVisible) showCaret ();
+}
+
+/**
+ * Sets the receiver's size and location to the rectangular
+ * area specified by the argument. The <code>x</code> and
+ * <code>y</code> fields of the rectangle are relative to
+ * the receiver's parent (or its display if its parent is null).
+ *
+ * @param rect the new bounds for the receiver
+ *
+ * @exception SWTException <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 setBounds (Rectangle rect) {
+ checkWidget();
+ if (rect == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setBounds (rect.x, rect.y, rect.width, rect.height);
+}
+
+void setFocus () {
+ if (display.currentCaret == this) return;
+ display.setCurrentCaret (this);
+ if (isVisible) showCaret ();
+}
+
+/**
+ * Sets the font that the receiver will use to paint textual information
+ * to the font specified by the argument, or to the default font for that
+ * kind of control if the argument is null.
+ *
+ * @param font the new font (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the font has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setFont (Font font) {
+ checkWidget();
+ if (font != null && font.isDisposed ()) {
+ error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.font = font;
+}
+
+/**
+ * Sets the image that the receiver will use to paint the caret
+ * to the image specified by the argument, or to the default
+ * which is a filled rectangle if the argument is null
+ *
+ * @param image the new image (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setImage (Image image) {
+ checkWidget();
+ if (image != null && image.isDisposed ()) {
+ error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ boolean isFocus = isFocusCaret ();
+ if (isFocus && isVisible) hideCaret ();
+ this.image = image;
+ if (isFocus && isVisible) showCaret ();
+}
+
+/**
+ * Sets the receiver's location to the point specified by
+ * the arguments which are relative to the receiver's
+ * parent (or its display if its parent is null).
+ *
+ * @param x the new x coordinate for the receiver
+ * @param y the new y coordinate for the receiver
+ *
+ * @exception SWTException <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 setLocation (int x, int y) {
+ checkWidget();
+ setBounds (x, y, width, height);
+}
+
+/**
+ * Sets the receiver's location to the point specified by
+ * the argument which is relative to the receiver's
+ * parent (or its display if its parent is null).
+ *
+ * @param location the new location for the receiver
+ *
+ * @exception SWTException <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 setLocation (Point location) {
+ checkWidget();
+ if (location == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setLocation (location.x, location.y);
+}
+
+/**
+ * Sets the receiver's size to the point specified by the arguments.
+ *
+ * @param width the new width for the receiver
+ * @param height the new height for the receiver
+ *
+ * @exception SWTException <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 setSize (int width, int height) {
+ checkWidget();
+ setBounds (x, y, width, height);
+}
+
+/**
+ * Sets the receiver's size to the point specified by the argument.
+ *
+ * @param size the new extent for the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception SWTException <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 setSize (Point size) {
+ checkWidget();
+ if (size == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setSize (size.x, size.y);
+}
+
+/**
+ * Marks the receiver as visible if the argument is <code>true</code>,
+ * and marks it invisible otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, marking
+ * it visible may not actually cause it to be displayed.
+ * </p>
+ *
+ * @param visible the new visibility state
+ *
+ * @exception SWTException <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 setVisible (boolean visible) {
+ checkWidget();
+ if (visible == isVisible) return;
+ isVisible = visible;
+ if (!isFocusCaret ()) return;
+ if (isVisible) {
+ showCaret ();
+ } else {
+ hideCaret ();
+ }
+}
+
+boolean showCaret () {
+ if (isShowing) return true;
+ isShowing = true;
+ return drawCaret ();
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ColorDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ColorDialog.java
new file mode 100755
index 0000000000..6ae406f67f
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ColorDialog.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class allow the user to select a color
+ * from a predefined set of available colors.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * IMPORTANT: This class is intended to be subclassed <em>only</em>
+ * within the SWT implementation.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample, Dialog tab</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class ColorDialog extends Dialog {
+ RGB rgb;
+ boolean selected;
+
+/**
+ * Constructs a new instance of this class given only its parent.
+ *
+ * @param parent a composite control which will be the parent of the new instance
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <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 SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public ColorDialog(Shell parent) {
+ this(parent, SWT.APPLICATION_MODAL);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public ColorDialog(Shell parent, int style) {
+ super (parent, checkStyle (parent, style));
+ checkSubclass ();
+}
+
+void changeColor(int /*long*/ id, int /*long*/ sel, int /*long*/ sender) {
+ selected = true;
+}
+
+/**
+ * Returns the currently selected color in the receiver.
+ *
+ * @return the RGB value for the selected color, may be null
+ *
+ * @see PaletteData#getRGBs
+ */
+public RGB getRGB() {
+ return rgb;
+}
+
+/**
+ * Makes the receiver visible and brings it to the front
+ * of the display.
+ *
+ * @return the selected color, or null if the dialog was
+ * cancelled, no color was selected, or an error
+ * occurred
+ *
+ * @exception SWTException <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 RGB open() {
+ NSColorPanel panel = NSColorPanel.sharedColorPanel();
+ if (rgb != null) {
+ NSColor color = NSColor.colorWithDeviceRed(rgb.red / 255f, rgb.green / 255f, rgb.blue / 255f, 1);
+ panel.setColor(color);
+ }
+ SWTPanelDelegate delegate = (SWTPanelDelegate)new SWTPanelDelegate().alloc().init();
+ int /*long*/ jniRef = OS.NewGlobalRef(this);
+ if (jniRef == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.object_setInstanceVariable(delegate.id, Display.SWT_OBJECT, jniRef);
+ panel.setDelegate(delegate);
+ rgb = null;
+ selected = false;
+ panel.orderFront(null);
+ NSApplication.sharedApplication().runModalForWindow(panel);
+ panel.setDelegate(null);
+ delegate.release();
+ OS.DeleteGlobalRef(jniRef);
+ if (selected) {
+ NSColor color = panel.color();
+ if (color != null) {
+ color = color.colorUsingColorSpaceName(OS.NSCalibratedRGBColorSpace);
+ rgb = new RGB((int)(color.redComponent() * 255), (int)(color.greenComponent() * 255), (int)(color.blueComponent() * 255));
+ }
+ }
+ return rgb;
+}
+
+/**
+ * Sets the receiver's selected color to be the argument.
+ *
+ * @param rgb the new RGB value for the selected color, may be
+ * null to let the platform select a default when
+ * open() is called
+ * @see PaletteData#getRGBs
+ */
+public void setRGB(RGB rgb) {
+ this.rgb = rgb;
+}
+
+void windowWillClose(int /*long*/ id, int /*long*/ sel, int /*long*/ sender) {
+ NSApplication.sharedApplication().stop(null);
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Combo.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Combo.java
new file mode 100755
index 0000000000..2773e1b3c3
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Combo.java
@@ -0,0 +1,1617 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class are controls that allow the user
+ * to choose an item from a list of items, or optionally
+ * enter a new value by typing it into an editable text
+ * field. Often, <code>Combo</code>s are used in the same place
+ * where a single selection <code>List</code> widget could
+ * be used but space is limited. A <code>Combo</code> takes
+ * less space than a <code>List</code> widget and shows
+ * similar information.
+ * <p>
+ * Note: Since <code>Combo</code>s can contain both a list
+ * and an editable text field, it is possible to confuse methods
+ * which access one versus the other (compare for example,
+ * <code>clearSelection()</code> and <code>deselectAll()</code>).
+ * The API documentation is careful to indicate either "the
+ * receiver's list" or the "the receiver's text field" to
+ * distinguish between the two cases.
+ * </p><p>
+ * Note that although this class is a subclass of <code>Composite</code>,
+ * it does not make sense to add children to it, or set a layout on it.
+ * </p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>DROP_DOWN, READ_ONLY, SIMPLE</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>DefaultSelection, Modify, Selection, Verify</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles DROP_DOWN and SIMPLE may be specified.
+ * </p><p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ *
+ * @see List
+ * @see <a href="http://www.eclipse.org/swt/snippets/#combo">Combo snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Combo extends Composite {
+ int textLimit = LIMIT;
+ boolean receivingFocus;
+ boolean ignoreVerify, ignoreSelection;
+ NSRange selectionRange;
+
+ /**
+ * the operating system limit for the number of characters
+ * that the text field in an instance of this class can hold
+ */
+ public static final int LIMIT;
+
+ /*
+ * These values can be different on different platforms.
+ * Therefore they are not initialized in the declaration
+ * to stop the compiler from inlining.
+ */
+ static {
+ LIMIT = 0x7FFFFFFF;
+ }
+
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#DROP_DOWN
+ * @see SWT#READ_ONLY
+ * @see SWT#SIMPLE
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Combo (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+/**
+ * Adds the argument to the end of the receiver's list.
+ *
+ * @param string the new item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <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 #add(String,int)
+ */
+public void add (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ NSString str = NSString.stringWith(string);
+ if ((style & SWT.READ_ONLY) != 0) {
+ NSPopUpButton widget = (NSPopUpButton)view;
+ int /*long*/ selection = widget.indexOfSelectedItem();
+ NSMenu nsMenu = widget.menu();
+ NSMenuItem nsItem = (NSMenuItem)new NSMenuItem().alloc();
+ nsItem.initWithTitle(str, 0, NSString.stringWith(""));
+ nsMenu.addItem(nsItem);
+ nsItem.release();
+ if (selection == -1) widget.selectItemAtIndex(-1);
+ } else {
+ ((NSComboBox)view).addItemWithObjectValue(str);
+ }
+}
+
+/**
+ * Adds the argument to the receiver's list at the given
+ * zero-relative index.
+ * <p>
+ * Note: To add an item at the end of the list, use the
+ * result of calling <code>getItemCount()</code> as the
+ * index or use <code>add(String)</code>.
+ * </p>
+ *
+ * @param string the new item
+ * @param index the index for the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 #add(String)
+ */
+public void add (String string, int index) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int count = getItemCount ();
+ if (0 > index || index > count) error (SWT.ERROR_INVALID_RANGE);
+ NSString str = NSString.stringWith(string);
+ if ((style & SWT.READ_ONLY) != 0) {
+ NSPopUpButton widget = (NSPopUpButton)view;
+ int /*long*/ selection = widget.indexOfSelectedItem();
+ NSMenu nsMenu = widget.menu();
+ NSMenuItem nsItem = (NSMenuItem)new NSMenuItem().alloc();
+ nsItem.initWithTitle(str, 0, NSString.stringWith(""));
+ nsMenu.insertItem(nsItem, index);
+ nsItem.release();
+ if (selection == -1) widget.selectItemAtIndex(-1);
+ } else {
+ ((NSComboBox)view).insertItemWithObjectValue(str, index);
+ }
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the receiver's text is modified, by sending
+ * it one of the messages defined in the <code>ModifyListener</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 SWTException <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 ModifyListener
+ * @see #removeModifyListener
+ */
+public void addModifyListener (ModifyListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Modify, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's selection, by sending
+ * it one of the messages defined in the <code>SelectionListener</code>
+ * interface.
+ * <p>
+ * <code>widgetSelected</code> is called when the user changes the combo's list selection.
+ * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed the combo's text area.
+ * </p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the receiver's text is verified, by sending
+ * it one of the messages defined in the <code>VerifyListener</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 SWTException <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 VerifyListener
+ * @see #removeVerifyListener
+ *
+ * @since 3.1
+ */
+public void addVerifyListener (VerifyListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Verify, typedListener);
+}
+
+boolean becomeFirstResponder (int /*long*/ id, int /*long*/ sel) {
+ receivingFocus = true;
+ boolean result = super.becomeFirstResponder (id, sel);
+ receivingFocus = false;
+ return result;
+}
+
+static int checkStyle (int style) {
+ /*
+ * Feature in Windows. It is not possible to create
+ * a combo box that has a border using Windows style
+ * bits. All combo boxes draw their own border and
+ * do not use the standard Windows border styles.
+ * Therefore, no matter what style bits are specified,
+ * clear the BORDER bits so that the SWT style will
+ * match the Windows widget.
+ *
+ * The Windows behavior is currently implemented on
+ * all platforms.
+ */
+ style &= ~SWT.BORDER;
+
+ /*
+ * Even though it is legal to create this widget
+ * with scroll bars, they serve no useful purpose
+ * because they do not automatically scroll the
+ * widget's client area. The fix is to clear
+ * the SWT style.
+ */
+ style &= ~(SWT.H_SCROLL | SWT.V_SCROLL);
+ style = checkBits (style, SWT.DROP_DOWN, SWT.SIMPLE, 0, 0, 0, 0);
+ if ((style & SWT.SIMPLE) != 0) return style & ~SWT.READ_ONLY;
+ return style;
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+/**
+ * Sets the selection in the receiver's text field to an empty
+ * selection starting just before the first character. If the
+ * text field is editable, this has the effect of placing the
+ * i-beam at the start of the text.
+ * <p>
+ * Note: To clear the selected items in the receiver's list,
+ * use <code>deselectAll()</code>.
+ * </p>
+ *
+ * @exception SWTException <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 #deselectAll
+ */
+public void clearSelection () {
+ checkWidget();
+ if ((style & SWT.READ_ONLY) == 0) {
+ Point selection = getSelection ();
+ selection.y = selection.x;
+ setSelection (selection);
+ }
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int width = 0, height = 0;
+ NSControl widget = (NSControl)view;
+ NSCell viewCell = widget.cell ();
+ NSSize size = viewCell.cellSize ();
+ width = (int)Math.ceil (size.width);
+ height = (int)Math.ceil (size.height);
+
+ if ((style & SWT.READ_ONLY) == 0) {
+ ignoreVerify = true;
+ NSComboBoxCell cell = new NSComboBoxCell (viewCell.id);
+ NSArray array = cell.objectValues ();
+ int length = (int)/*64*/array.count ();
+ if (length > 0) {
+ cell = new NSComboBoxCell (cell.copy ());
+ for (int i = 0; i < length; i++) {
+ id object = array.objectAtIndex (i);
+ cell.setTitle (new NSString (object));
+ size = cell.cellSize ();
+ width = Math.max (width, (int)Math.ceil (size.width));
+ }
+ cell.release ();
+ }
+ ignoreVerify = false;
+ }
+
+ /*
+ * Feature in Cocoa. Attempting to create an NSComboBox with a
+ * height > 27 spews a very long warning message to stdout and
+ * often draws the combo incorrectly. The workaround is to limit
+ * the returned height of editable Combos to the height that is
+ * required to display their text, even if a larger hHint is specified.
+ */
+ if (hHint != SWT.DEFAULT) {
+ if ((style & SWT.READ_ONLY) != 0 || hHint < height) height = hHint;
+ }
+ if (wHint != SWT.DEFAULT) width = wHint;
+ return new Point (width, height);
+}
+
+/**
+ * Copies the selected text.
+ * <p>
+ * The current selection is copied to the clipboard.
+ * </p>
+ *
+ * @exception SWTException <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 2.1
+ */
+public void copy () {
+ checkWidget ();
+ Point selection = getSelection ();
+ if (selection.x == selection.y) return;
+ copyToClipboard (getText (selection.x, selection.y));
+}
+
+void createHandle () {
+ if ((style & SWT.READ_ONLY) != 0) {
+ NSPopUpButton widget = (NSPopUpButton)new SWTPopUpButton().alloc();
+ widget.initWithFrame(new NSRect(), false);
+ widget.menu().setAutoenablesItems(false);
+ widget.setTarget(widget);
+ widget.setAction(OS.sel_sendSelection);
+ view = widget;
+ } else {
+ NSComboBox widget = (NSComboBox)new SWTComboBox().alloc();
+ widget.init();
+ widget.setDelegate(widget);
+ widget.setTarget(widget);
+ widget.setAction(OS.sel_sendSelection);
+ view = widget;
+ }
+}
+
+/**
+ * Cuts the selected text.
+ * <p>
+ * The current selection is first copied to the
+ * clipboard and then deleted from the widget.
+ * </p>
+ *
+ * @exception SWTException <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 2.1
+ */
+public void cut () {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) return;
+ Point selection = getSelection ();
+ if (selection.x == selection.y) return;
+ int start = selection.x, end = selection.y;
+ String text = getText ();
+ String leftText = text.substring (0, start);
+ String rightText = text.substring (end, text.length ());
+ String oldText = text.substring (start, end);
+ String newText = "";
+ if (hooks (SWT.Verify) || filters (SWT.Verify)) {
+ newText = verifyText (newText, start, end, null);
+ if (newText == null) return;
+ }
+ char [] buffer = new char [oldText.length ()];
+ oldText.getChars (0, buffer.length, buffer, 0);
+ copyToClipboard (buffer);
+ setText (leftText + newText + rightText, false);
+ start += newText.length ();
+ setSelection (new Point (start, start));
+ sendEvent (SWT.Modify);
+}
+
+Color defaultBackground () {
+ return display.getWidgetColor (SWT.COLOR_LIST_BACKGROUND);
+}
+
+NSFont defaultNSFont() {
+ if ((style & SWT.READ_ONLY) != 0) return display.popUpButtonFont;
+ return display.comboBoxFont;
+}
+
+Color defaultForeground () {
+ return display.getWidgetColor (SWT.COLOR_LIST_FOREGROUND);
+}
+
+void deregister() {
+ super.deregister();
+ display.removeWidget(((NSControl)view).cell());
+}
+
+/**
+ * Deselects the item at the given zero-relative index in the receiver's
+ * list. If the item at the index was already deselected, it remains
+ * deselected. Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to deselect
+ *
+ * @exception SWTException <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 deselect (int index) {
+ checkWidget ();
+ if (index == -1) return;
+ if (index == getSelectionIndex ()) {
+ if ((style & SWT.READ_ONLY) != 0) {
+ ((NSPopUpButton)view).selectItem(null);
+ sendEvent (SWT.Modify);
+ } else {
+ ((NSComboBox)view).deselectItemAtIndex(index);
+ }
+ }
+}
+
+/**
+ * Deselects all selected items in the receiver's list.
+ * <p>
+ * Note: To clear the selection in the receiver's text field,
+ * use <code>clearSelection()</code>.
+ * </p>
+ *
+ * @exception SWTException <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 #clearSelection
+ */
+public void deselectAll () {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) {
+ ((NSPopUpButton)view).selectItem(null);
+ sendEvent (SWT.Modify);
+ } else {
+ NSComboBox widget = (NSComboBox)view;
+ int /*long*/ index = widget.indexOfSelectedItem();
+ if (index != -1) widget.deselectItemAtIndex(index);
+ }
+}
+
+boolean dragDetect(int x, int y, boolean filter, boolean[] consume) {
+ if ((style & SWT.READ_ONLY) == 0) {
+ NSText fieldEditor = ((NSControl)view).currentEditor();
+ if (fieldEditor != null) {
+ NSRange selectedRange = fieldEditor.selectedRange();
+ if (selectedRange.length > 0) {
+ NSPoint mouseLocation = NSEvent.mouseLocation();
+ NSTextView feAsTextView = new NSTextView(fieldEditor);
+ int /*long*/ charPosition = feAsTextView.characterIndexForInsertionAtPoint(mouseLocation);
+ if (charPosition != OS.NSNotFound && charPosition >= selectedRange.location && charPosition < (selectedRange.location + selectedRange.length)) {
+ if (super.dragDetect(x, y, filter, consume)) {
+ if (consume != null) consume[0] = true;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ return super.dragDetect(x, y, filter, consume);
+}
+
+int getCharCount() {
+ NSString str;
+ if ((style & SWT.READ_ONLY) != 0) {
+ str = ((NSPopUpButton)view).titleOfSelectedItem();
+ } else {
+ str = new NSCell(((NSComboBox)view).cell()).title();
+ }
+ if (str == null) return 0;
+ return (int)/*64*/str.length();
+}
+
+/**
+ * Returns the item at the given, zero-relative index in the
+ * receiver's list. Throws an exception if the index is out
+ * of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 String getItem (int index) {
+ checkWidget ();
+ int count = getItemCount ();
+ if (0 > index || index >= count) error (SWT.ERROR_INVALID_RANGE);
+ NSString str;
+ if ((style & SWT.READ_ONLY) != 0) {
+ str = ((NSPopUpButton)view).itemTitleAtIndex(index);
+ } else {
+ str = new NSString(((NSComboBox)view).itemObjectValueAtIndex(index));
+ }
+ if (str == null) error(SWT.ERROR_CANNOT_GET_ITEM);
+ return str.getString();
+}
+
+/**
+ * Returns the number of items contained in the receiver's list.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException <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 getItemCount () {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) {
+ return (int)/*64*/((NSPopUpButton)view).numberOfItems();
+ } else {
+ return (int)/*64*/((NSComboBox)view).numberOfItems();
+ }
+}
+
+/**
+ * Returns the height of the area which would be used to
+ * display <em>one</em> of the items in the receiver's list.
+ *
+ * @return the height of one item
+ *
+ * @exception SWTException <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 getItemHeight () {
+ checkWidget ();
+ //TODO - not supported by the OS
+ return 26;
+}
+
+/**
+ * Returns a (possibly empty) array of <code>String</code>s which are
+ * the items in the receiver's list.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ *
+ * @return the items in the receiver's list
+ *
+ * @exception SWTException <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 String [] getItems () {
+ checkWidget ();
+ int count = getItemCount ();
+ String [] result = new String [count];
+ for (int i=0; i<count; i++) result [i] = getItem (i);
+ return result;
+}
+
+/**
+ * Returns <code>true</code> if the receiver's list is visible,
+ * and <code>false</code> otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ * </p>
+ *
+ * @return the receiver's list's visibility state
+ *
+ * @exception SWTException <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.4
+ */
+public boolean getListVisible () {
+ //TODO
+ return false;
+}
+
+int getMininumHeight () {
+ return getTextHeight ();
+}
+
+/**
+ * Returns the orientation of the receiver.
+ *
+ * @return the orientation style
+ *
+ * @exception SWTException <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 2.1.2
+ */
+public int getOrientation () {
+ checkWidget();
+ return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
+}
+
+/**
+ * Returns a <code>Point</code> whose x coordinate is the
+ * character position representing the start of the selection
+ * in the receiver's text field, and whose y coordinate is the
+ * character position representing the end of the selection.
+ * An "empty" selection is indicated by the x and y coordinates
+ * having the same value.
+ * <p>
+ * Indexing is zero based. The range of a selection is from
+ * 0..N where N is the number of characters in the widget.
+ * </p>
+ *
+ * @return a point representing the selection start and end
+ *
+ * @exception SWTException <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 Point getSelection () {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) {
+ return new Point (0, getCharCount ());
+ } else {
+ if (selectionRange == null) {
+ NSString str = new NSTextFieldCell (((NSTextField) view).cell ()).title ();
+ return new Point((int)/*64*/str.length (), (int)/*64*/str.length ());
+ }
+ return new Point((int)/*64*/selectionRange.location, (int)/*64*/(selectionRange.location + selectionRange.length));
+ }
+}
+
+/**
+ * Returns the zero-relative index of the item which is currently
+ * selected in the receiver's list, or -1 if no item is selected.
+ *
+ * @return the index of the selected item
+ *
+ * @exception SWTException <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 getSelectionIndex () {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) {
+ return (int)/*64*/((NSPopUpButton)view).indexOfSelectedItem();
+ } else {
+ return (int)/*64*/((NSComboBox)view).indexOfSelectedItem();
+ }
+}
+
+/**
+ * Returns a string containing a copy of the contents of the
+ * receiver's text field, or an empty string if there are no
+ * contents.
+ *
+ * @return the receiver's text
+ *
+ * @exception SWTException <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 String getText () {
+ checkWidget ();
+ return new String (getText(0, -1));
+}
+
+char [] getText (int start, int end) {
+ NSString str;
+ if ((style & SWT.READ_ONLY) != 0) {
+ str = ((NSPopUpButton)view).titleOfSelectedItem();
+ } else {
+ str = new NSCell(((NSComboBox)view).cell()).title();
+ }
+ if (str == null) return new char[0];
+ NSRange range = new NSRange ();
+ range.location = start;
+ if (end == -1) {
+ int /*long*/ length = str.length();
+ range.length = length - start;
+ } else {
+ range.length = end - start;
+ }
+ char [] buffer= new char [(int)/*64*/range.length];
+ str.getCharacters(buffer, range);
+ return buffer;
+}
+
+/**
+ * Returns the height of the receivers's text field.
+ *
+ * @return the text height
+ *
+ * @exception SWTException <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 getTextHeight () {
+ checkWidget();
+ NSCell cell;
+ if ((style & SWT.READ_ONLY) != 0) {
+ cell = ((NSPopUpButton)view).cell();
+ } else {
+ cell = ((NSComboBox)view).cell();
+ }
+ return (int)cell.cellSize().height;
+}
+
+/**
+ * Returns the maximum number of characters that the receiver's
+ * text field is capable of holding. If this has not been changed
+ * by <code>setTextLimit()</code>, it will be the constant
+ * <code>Combo.LIMIT</code>.
+ *
+ * @return the text limit
+ *
+ * @exception SWTException <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 #LIMIT
+ */
+public int getTextLimit () {
+ checkWidget();
+ return textLimit;
+}
+
+/**
+ * Gets the number of items that are visible in the drop
+ * down portion of the receiver's list.
+ * <p>
+ * Note: This operation is a hint and is not supported on
+ * platforms that do not have this concept.
+ * </p>
+ *
+ * @return the number of items that are visible
+ *
+ * @exception SWTException <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.0
+ */
+public int getVisibleItemCount () {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) {
+ return getItemCount ();
+ } else {
+ return (int)/*64*/((NSComboBox)view).numberOfVisibleItems();
+ }
+}
+
+/**
+ * Searches the receiver's list starting at the first item
+ * (index 0) until an item is found that is equal to the
+ * argument, and returns the index of that item. If no item
+ * is found, returns -1.
+ *
+ * @param string the search item
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <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 indexOf (String string) {
+ return indexOf (string, 0);
+}
+
+/**
+ * Searches the receiver's list starting at the given,
+ * zero-relative index until an item is found that is equal
+ * to the argument, and returns the index of that item. If
+ * no item is found or the starting index is out of range,
+ * returns -1.
+ *
+ * @param string the search item
+ * @param start the zero-relative index at which to begin the search
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <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 indexOf (String string, int start) {
+ checkWidget();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int count = getItemCount ();
+ if (!(0 <= start && start < count)) return -1;
+ for (int i=start; i<count; i++) {
+ if (string.equals (getItem (i))) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void insertEditText (String string) {
+ ignoreVerify = true;
+ int length = string.length ();
+ Point selection = getSelection ();
+ if (hasFocus ()) {
+ if (textLimit != LIMIT) {
+ int charCount = getCharCount();
+ if (charCount - (selection.y - selection.x) + length > textLimit) {
+ length = textLimit - charCount + (selection.y - selection.x);
+ }
+ }
+ char [] buffer = new char [length];
+ string.getChars (0, buffer.length, buffer, 0);
+ NSString nsstring = NSString.stringWithCharacters (buffer, buffer.length);
+ NSText fieldEditor = ((NSTextField) view).currentEditor ();
+ fieldEditor.replaceCharactersInRange (fieldEditor.selectedRange (), nsstring);
+ selectionRange = null;
+ } else {
+ String oldText = getText ();
+ if (textLimit != LIMIT) {
+ int charCount = oldText.length ();
+ if (charCount - (selection.y - selection.x) + length > textLimit) {
+ string = string.substring(0, textLimit - charCount + (selection.y - selection.x));
+ }
+ }
+ String newText = oldText.substring (0, selection.x) + string + oldText.substring (selection.y);
+ NSString nsstring = NSString.stringWith(newText);
+ new NSCell (((NSTextField) view).cell ()).setTitle (nsstring);
+ selectionRange = null;
+ setSelection (new Point(selection.x + string.length (), 0));
+ }
+ ignoreVerify = false;
+}
+
+boolean isEventView (int /*long*/ id) {
+ return true;
+}
+
+void mouseDown(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ // If this is a combo box with an editor field and the control is disposed
+ // while the view's cell editor is open we crash while tearing down the
+ // popup window. Fix is to retain the view before letting Cocoa track
+ // the mouse events.
+
+ // 'view' will be cleared if disposed during the mouseDown so cache it.
+ NSView viewCopy = view;
+ viewCopy.retain();
+ super.mouseDown(id, sel, theEvent);
+ viewCopy.release();
+}
+
+/**
+ * Pastes text from clipboard.
+ * <p>
+ * The selected text is deleted from the widget
+ * and new text inserted from the clipboard.
+ * </p>
+ *
+ * @exception SWTException <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 2.1
+ */
+public void paste () {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) return;
+ Point selection = getSelection ();
+ int start = selection.x, end = selection.y;
+ String text = getText ();
+ String leftText = text.substring (0, start);
+ String rightText = text.substring (end, text.length ());
+ String newText = getClipboardText ();
+ if (newText == null) return;
+ if (hooks (SWT.Verify) || filters (SWT.Verify)) {
+ newText = verifyText (newText, start, end, null);
+ if (newText == null) return;
+ }
+ if (textLimit != LIMIT) {
+ int charCount = text.length ();
+ if (charCount - (end - start) + newText.length() > textLimit) {
+ newText = newText.substring(0, textLimit - charCount + (end - start));
+ }
+ }
+ setText (leftText + newText + rightText, false);
+ start += newText.length ();
+ setSelection (new Point (start, start));
+ sendEvent (SWT.Modify);
+}
+
+void register() {
+ super.register();
+ display.addWidget(((NSControl)view).cell(), this);
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ if ((style & SWT.READ_ONLY) == 0) {
+ ((NSControl)view).abortEditing();
+ }
+ selectionRange = null;
+}
+
+/**
+ * Removes the item from the receiver's list at the given
+ * zero-relative index.
+ *
+ * @param index the index for the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 remove (int index) {
+ checkWidget ();
+ if (index == -1) error (SWT.ERROR_INVALID_RANGE);
+ int count = getItemCount ();
+ if (0 > index || index >= count) error (SWT.ERROR_INVALID_RANGE);
+ if ((style & SWT.READ_ONLY) != 0) {
+ ((NSPopUpButton)view).removeItemAtIndex(index);
+ } else {
+ ((NSComboBox)view).removeItemAtIndex(index);
+ }
+}
+
+/**
+ * Removes the items from the receiver's list which are
+ * between the given zero-relative start and end
+ * indices (inclusive).
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if either the start or end are not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 remove (int start, int end) {
+ checkWidget();
+ if (start > end) return;
+ int count = getItemCount ();
+ if (!(0 <= start && start <= end && end < count)) {
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ int newEnd = Math.min (end, count - 1);
+ for (int i=newEnd; i>=start; i--) {
+ remove(i);
+ }
+}
+
+/**
+ * Searches the receiver's list starting at the first item
+ * until an item is found that is equal to the argument,
+ * and removes that item from the list.
+ *
+ * @param string the item to remove
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the string is not found in the list</li>
+ * </ul>
+ * @exception SWTException <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 remove (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int index = indexOf (string, 0);
+ if (index == -1) error (SWT.ERROR_INVALID_ARGUMENT);
+ remove (index);
+}
+
+/**
+ * Removes all of the items from the receiver's list and clear the
+ * contents of receiver's text field.
+ * <p>
+ * @exception SWTException <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 removeAll () {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) {
+ ((NSPopUpButton)view).removeAllItems();
+ } else {
+ setText ("", true);
+ ((NSComboBox)view).removeAllItems();
+ }
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the receiver's text is modified.
+ *
+ * @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 SWTException <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 ModifyListener
+ * @see #addModifyListener
+ */
+public void removeModifyListener (ModifyListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Modify, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the user changes the receiver's selection.
+ *
+ * @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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the control is verified.
+ *
+ * @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 SWTException <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 VerifyListener
+ * @see #addVerifyListener
+ *
+ * @since 3.1
+ */
+public void removeVerifyListener (VerifyListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Verify, listener);
+}
+
+/**
+ * Selects the item at the given zero-relative index in the receiver's
+ * list. If the item at the index was already selected, it remains
+ * selected. Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to select
+ *
+ * @exception SWTException <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 select (int index) {
+ checkWidget ();
+ int count = getItemCount ();
+ ignoreSelection = true;
+ if (0 <= index && index < count) {
+ if ((style & SWT.READ_ONLY) != 0) {
+ ((NSPopUpButton)view).selectItemAtIndex(index);
+ } else {
+ ((NSComboBox)view).selectItemAtIndex(index);
+ }
+ }
+ ignoreSelection = false;
+ sendEvent (SWT.Modify);
+}
+
+void sendSelection () {
+ sendEvent(SWT.Modify);
+ if (!ignoreSelection) postEvent(SWT.Selection);
+}
+
+boolean sendKeyEvent (NSEvent nsEvent, int type) {
+ boolean result = super.sendKeyEvent (nsEvent, type);
+ if (!result) return result;
+ int stateMask = 0;
+ int /*long*/ modifierFlags = nsEvent.modifierFlags();
+ if ((modifierFlags & OS.NSAlternateKeyMask) != 0) stateMask |= SWT.ALT;
+ if ((modifierFlags & OS.NSShiftKeyMask) != 0) stateMask |= SWT.SHIFT;
+ if ((modifierFlags & OS.NSControlKeyMask) != 0) stateMask |= SWT.CONTROL;
+ if ((modifierFlags & OS.NSCommandKeyMask) != 0) stateMask |= SWT.COMMAND;
+ if (type != SWT.KeyDown) return result;
+ short keyCode = nsEvent.keyCode ();
+ if (stateMask == SWT.COMMAND) {
+ switch (keyCode) {
+ case 7: /* X */
+ cut ();
+ return false;
+ case 8: /* C */
+ copy ();
+ return false;
+ case 9: /* V */
+ paste ();
+ return false;
+ case 0: /* A */
+ if ((style & SWT.READ_ONLY) == 0) {
+ ((NSComboBox)view).selectText(null);
+ return false;
+ }
+ }
+ }
+ switch (keyCode) {
+ case 76: /* KP Enter */
+ case 36: /* Return */
+ postEvent (SWT.DefaultSelection);
+ }
+ return result;
+}
+
+void updateBackground () {
+ NSColor nsColor = null;
+ if (backgroundImage != null) {
+ nsColor = NSColor.colorWithPatternImage(backgroundImage.handle);
+ } else if (background != null) {
+ nsColor = NSColor.colorWithDeviceRed(background[0], background[1], background[2], background[3]);
+ } else {
+ nsColor = NSColor.textBackgroundColor ();
+ }
+
+ if ((style & SWT.READ_ONLY) != 0) {
+ //TODO
+ } else {
+ ((NSTextField)view).setBackgroundColor(nsColor);
+ }
+}
+
+void setBounds (int x, int y, int width, int height, boolean move, boolean resize) {
+ /*
+ * Feature in Cocoa. Attempting to create an NSComboBox with a
+ * height > 27 spews a very long warning message to stdout and
+ * often draws the combo incorrectly. The workaround is to limit
+ * the height of editable Combos to the height that is required
+ * to display their text.
+ */
+ if ((style & SWT.READ_ONLY) == 0) {
+ NSControl widget = (NSControl)view;
+ NSSize size = widget.cell ().cellSize ();
+ height = Math.min (height, (int)Math.ceil (size.height));
+ }
+ super.setBounds (x, y, width, height, move, resize);
+}
+
+void setForeground (float /*double*/ [] color) {
+ NSColor nsColor;
+ if (color == null) {
+ nsColor = NSColor.textColor ();
+ } else {
+ nsColor = NSColor.colorWithDeviceRed(color[0], color[1], color[2], 1);
+ }
+ if ((style & SWT.READ_ONLY) != 0) {
+ //TODO
+ } else {
+ ((NSTextField)view).setTextColor(nsColor);
+ }
+}
+
+/**
+ * Sets the text of the item in the receiver's list at the given
+ * zero-relative index to the string argument.
+ *
+ * @param index the index for the item
+ * @param string the new text for the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <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 setItem (int index, String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int count = getItemCount ();
+ if (0 > index || index >= count) error (SWT.ERROR_INVALID_RANGE);
+ NSString str = NSString.stringWith(string);
+ if ((style & SWT.READ_ONLY) != 0) {
+ NSMenuItem nsItem = ((NSPopUpButton)view).itemAtIndex(index);
+ nsItem.setTitle(str);
+ } else {
+ NSComboBox widget = (NSComboBox)view;
+ widget.insertItemWithObjectValue(str, index);
+ widget.removeItemAtIndex(index + 1);
+ }
+}
+
+/**
+ * Sets the receiver's list to be the given array of items.
+ *
+ * @param items the array of items
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the items array is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if an item in the items array is null</li>
+ * </ul>
+ * @exception SWTException <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 setItems (String [] items) {
+ checkWidget();
+ if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
+ for (int i=0; i<items.length; i++) {
+ if (items [i] == null) error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ removeAll();
+ if (items.length == 0) return;
+ for (int i= 0; i < items.length; i++) {
+ NSString str = NSString.stringWith(items[i]);
+ if ((style & SWT.READ_ONLY) != 0) {
+ NSMenu nsMenu = ((NSPopUpButton)view).menu();
+ NSMenuItem nsItem = (NSMenuItem)new NSMenuItem().alloc();
+ nsItem.initWithTitle(str, 0, NSString.stringWith(""));
+ nsMenu.addItem(nsItem);
+ nsItem.release();
+ //clear the selection
+ ((NSPopUpButton)view).selectItemAtIndex(-1);
+ } else {
+ ((NSComboBox)view).addItemWithObjectValue(str);
+ }
+ }
+}
+
+/**
+ * Marks the receiver's list as visible if the argument is <code>true</code>,
+ * and marks it invisible otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, marking
+ * it visible may not actually cause it to be displayed.
+ * </p>
+ *
+ * @param visible the new visibility state
+ *
+ * @exception SWTException <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.4
+ */
+public void setListVisible (boolean visible) {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) {
+ ((NSPopUpButton)view).setPullsDown(visible);
+ } else {
+ }
+}
+
+/**
+ * Sets the orientation of the receiver, which must be one
+ * of the constants <code>SWT.LEFT_TO_RIGHT</code> or <code>SWT.RIGHT_TO_LEFT</code>.
+ * <p>
+ *
+ * @param orientation new orientation style
+ *
+ * @exception SWTException <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 2.1.2
+ */
+public void setOrientation (int orientation) {
+ checkWidget();
+}
+
+/**
+ * Sets the selection in the receiver's text field to the
+ * range specified by the argument whose x coordinate is the
+ * start of the selection and whose y coordinate is the end
+ * of the selection.
+ *
+ * @param selection a point representing the new selection start and end
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception SWTException <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 setSelection (Point selection) {
+ checkWidget ();
+ if (selection == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if ((style & SWT.READ_ONLY) == 0) {
+ NSComboBox widget = (NSComboBox)view;
+ NSString str = new NSCell(widget.cell()).title();
+ int length = (int)/*64*/str.length();
+ int start = Math.min (Math.max (Math.min (selection.x, selection.y), 0), length);
+ int end = Math.min (Math.max (Math.max (selection.x, selection.y), 0), length);
+ selectionRange = new NSRange();
+ selectionRange.location = start;
+ selectionRange.length = end - start;
+ NSText fieldEditor = widget.currentEditor();
+ if (fieldEditor != null) fieldEditor.setSelectedRange(selectionRange);
+ }
+}
+
+/**
+ * Sets the contents of the receiver's text field to the
+ * given string.
+ * <p>
+ * This call is ignored when the receiver is read only and
+ * the given string is not in the receiver's list.
+ * </p>
+ * <p>
+ * Note: The text field in a <code>Combo</code> is typically
+ * only capable of displaying a single line of text. Thus,
+ * setting the text to a string containing line breaks or
+ * other special characters will probably cause it to
+ * display incorrectly.
+ * </p>
+ *
+ * @param string the new text
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <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 setText (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setText (string, true);
+}
+
+void setText (String string, boolean notify) {
+ ignoreVerify = true;
+ if (notify) {
+ if (hooks (SWT.Verify) || filters (SWT.Verify)) {
+ string = verifyText (string, 0, getCharCount (), null);
+ if (string == null) return;
+ }
+ }
+ if ((style & SWT.READ_ONLY) != 0) {
+ int index = indexOf (string);
+ if (index != -1 && index != getSelectionIndex ()) {
+ select (index);
+ if (notify) sendEvent (SWT.Modify);
+ }
+ } else {
+ char[] buffer = new char [Math.min(string.length (), textLimit)];
+ string.getChars (0, buffer.length, buffer, 0);
+ NSString nsstring = NSString.stringWithCharacters (buffer, buffer.length);
+ new NSCell(((NSComboBox)view).cell()).setTitle(nsstring);
+ if (notify) sendEvent (SWT.Modify);
+ }
+ selectionRange = null;
+ ignoreVerify = false;
+}
+
+/**
+ * Sets the maximum number of characters that the receiver's
+ * text field is capable of holding to be the argument.
+ * <p>
+ * To reset this value to the default, use <code>setTextLimit(Combo.LIMIT)</code>.
+ * Specifying a limit value larger than <code>Combo.LIMIT</code> sets the
+ * receiver's limit to <code>Combo.LIMIT</code>.
+ * </p>
+ * @param limit new text limit
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li>
+ * </ul>
+ * @exception SWTException <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 #LIMIT
+ */
+public void setTextLimit (int limit) {
+ checkWidget ();
+ if (limit == 0) error (SWT.ERROR_CANNOT_BE_ZERO);
+ textLimit = limit;
+}
+
+/**
+ * Sets the number of items that are visible in the drop
+ * down portion of the receiver's list.
+ * <p>
+ * Note: This operation is a hint and is not supported on
+ * platforms that do not have this concept.
+ * </p>
+ *
+ * @param count the new number of items to be visible
+ *
+ * @exception SWTException <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.0
+ */
+public void setVisibleItemCount (int count) {
+ checkWidget ();
+ if (count < 0) return;
+ if ((style & SWT.READ_ONLY) != 0) {
+ //TODO
+ } else {
+ ((NSComboBox)view).setNumberOfVisibleItems(count);
+ }
+}
+
+boolean shouldChangeTextInRange_replacementString(int /*long*/ id, int /*long*/ sel, int /*long*/ affectedCharRange, int /*long*/ replacementString) {
+ NSRange range = new NSRange();
+ OS.memmove(range, affectedCharRange, NSRange.sizeof);
+ boolean result = callSuperBoolean(id, sel, range, replacementString);
+ if (hooks (SWT.Verify)) {
+ String text = new NSString(replacementString).getString();
+ NSEvent currentEvent = display.application.currentEvent();
+ int /*long*/ type = currentEvent.type();
+ if (type != OS.NSKeyDown && type != OS.NSKeyUp) currentEvent = null;
+ String newText = verifyText(text, (int)/*64*/range.location, (int)/*64*/(range.location+range.length), currentEvent);
+ if (newText == null) return false;
+ if (text != newText) {
+ insertEditText(newText);
+ result = false;
+ }
+ if (!result) sendEvent (SWT.Modify);
+ }
+ return result;
+}
+
+void textViewDidChangeSelection(int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+ NSNotification notification = new NSNotification(aNotification);
+ NSText editor = new NSText(notification.object().id);
+ selectionRange = editor.selectedRange();
+}
+
+void textDidChange (int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+ super.textDidChange (id, sel, aNotification);
+ postEvent (SWT.Modify);
+}
+
+NSRange textView_willChangeSelectionFromCharacterRange_toCharacterRange(int /*long*/ id, int /*long*/ sel, int /*long*/ aTextView, int /*long*/ oldSelectedCharRange, int /*long*/ newSelectedCharRange) {
+ /*
+ * If the selection is changing as a result of the receiver getting focus
+ * then return the receiver's last selection range, otherwise the full
+ * text will be automatically selected.
+ */
+ if (receivingFocus && selectionRange != null) return selectionRange;
+
+ /* allow the selection change to proceed */
+ NSRange result = new NSRange();
+ OS.memmove(result, newSelectedCharRange, NSRange.sizeof);
+ return result;
+}
+
+String verifyText (String string, int start, int end, NSEvent keyEvent) {
+ Event event = new Event ();
+ if (keyEvent != null) setKeyState(event, SWT.MouseDown, keyEvent);
+ event.text = string;
+ event.start = start;
+ event.end = end;
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the verify
+ * event. If this happens, answer null to cancel
+ * the operation.
+ */
+ sendEvent (SWT.Verify, event);
+ if (!event.doit || isDisposed ()) return null;
+ return event.text;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Composite.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Composite.java
new file mode 100755
index 0000000000..2929e285bd
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Composite.java
@@ -0,0 +1,1005 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.accessibility.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class are controls which are capable
+ * of containing other controls.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>NO_BACKGROUND, NO_FOCUS, NO_MERGE_PAINTS, NO_REDRAW_RESIZE, NO_RADIO_GROUP, EMBEDDED, DOUBLE_BUFFERED</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * Note: The <code>NO_BACKGROUND</code>, <code>NO_FOCUS</code>, <code>NO_MERGE_PAINTS</code>,
+ * and <code>NO_REDRAW_RESIZE</code> styles are intended for use with <code>Canvas</code>.
+ * They can be used with <code>Composite</code> if you are drawing your own, but their
+ * behavior is undefined if they are used with subclasses of <code>Composite</code> other
+ * than <code>Canvas</code>.
+ * </p><p>
+ * Note: The <code>CENTER</code> style, although undefined for composites, has the
+ * same value as <code>EMBEDDED</code> which is used to embed widgets from other
+ * widget toolkits into SWT. On some operating systems (GTK, Motif), this may cause
+ * the children of this composite to be obscured.
+ * </p><p>
+ * This class may be subclassed by custom control implementors
+ * who are building controls that are constructed from aggregates
+ * of other controls.
+ * </p>
+ *
+ * @see Canvas
+ * @see <a href="http://www.eclipse.org/swt/snippets/#composite">Composite snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+public class Composite extends Scrollable {
+ Layout layout;
+ Control[] tabList;
+ int layoutCount, backgroundMode;
+
+Composite () {
+ /* Do nothing */
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 widget which will be the parent of the new instance (cannot be null)
+ * @param style the style of widget to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ * </ul>
+ *
+ * @see SWT#NO_BACKGROUND
+ * @see SWT#NO_FOCUS
+ * @see SWT#NO_MERGE_PAINTS
+ * @see SWT#NO_REDRAW_RESIZE
+ * @see SWT#NO_RADIO_GROUP
+ * @see SWT#EMBEDDED
+ * @see SWT#DOUBLE_BUFFERED
+ * @see Widget#getStyle
+ */
+public Composite (Composite parent, int style) {
+ super (parent, style);
+}
+
+Control [] _getChildren () {
+ NSArray views = contentView().subviews();
+ int count = (int)/*64*/views.count();
+ Control [] children = new Control [count];
+ if (count == 0) return children;
+ int j = 0;
+ for (int i=0; i<count; i++){
+ Widget widget = display.getWidget (views.objectAtIndex (count - i - 1).id);
+ if (widget != null && widget != this && widget instanceof Control) {
+ children [j++] = (Control) widget;
+ }
+ }
+ if (j == count) return children;
+ Control [] newChildren = new Control [j];
+ System.arraycopy (children, 0, newChildren, 0, j);
+ return newChildren;
+}
+
+Control [] _getTabList () {
+ if (tabList == null) return null;
+ int count = 0;
+ for (int i=0; i<tabList.length; i++) {
+ if (!tabList [i].isDisposed ()) count++;
+ }
+ if (count == tabList.length) return tabList;
+ Control [] newList = new Control [count];
+ int index = 0;
+ for (int i=0; i<tabList.length; i++) {
+ if (!tabList [i].isDisposed ()) {
+ newList [index++] = tabList [i];
+ }
+ }
+ tabList = newList;
+ return tabList;
+}
+
+boolean acceptsFirstResponder (int /*long*/ id, int /*long*/ sel) {
+ if ((state & CANVAS) != 0) {
+ if ((style & SWT.NO_FOCUS) == 0 && hooksKeys ()) {
+ if (contentView().subviews().count() == 0) return true;
+ }
+ return false;
+ }
+ return super.acceptsFirstResponder (id, sel);
+}
+
+int /*long*/ accessibilityAttributeNames(int /*long*/ id, int /*long*/ sel) {
+
+ if (id == view.id) {
+ if (accessible != null) {
+ // If there is an accessible, it may provide its own list of attributes if it's a lightweight control.
+ // If not, let Cocoa handle it for this view.
+ id returnObject = accessible.internal_accessibilityAttributeNames(ACC.CHILDID_SELF);
+ if (returnObject != null) return returnObject.id;
+ }
+ }
+
+ return super.accessibilityAttributeNames(id, sel);
+}
+
+boolean accessibilityIsIgnored(int /*long*/ id, int /*long*/ sel) {
+ // If we have an accessible and it represents a valid accessible role, this view is not ignored.
+ if (view != null && id == view.id) {
+ if (accessible != null) {
+ id role = accessible.internal_accessibilityAttributeValue(OS.NSAccessibilityRoleAttribute, ACC.CHILDID_SELF);
+ if (role != null) return false;
+ }
+ }
+
+ return super.accessibilityIsIgnored(id, sel);
+}
+
+/**
+ * Clears any data that has been cached by a Layout for all widgets that
+ * are in the parent hierarchy of the changed control up to and including the
+ * receiver. If an ancestor does not have a layout, it is skipped.
+ *
+ * @param changed an array of controls that changed state and require a recalculation of size
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the changed array is null any of its controls are null or have been disposed</li>
+ * <li>ERROR_INVALID_PARENT - if any control in changed is not in the widget tree of the receiver</li>
+ * </ul>
+ * @exception SWTException <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.1
+ */
+public void changed (Control[] changed) {
+ checkWidget ();
+ if (changed == null) error (SWT.ERROR_INVALID_ARGUMENT);
+ for (int i=0; i<changed.length; i++) {
+ Control control = changed [i];
+ if (control == null) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ boolean ancestor = false;
+ Composite composite = control.parent;
+ while (composite != null) {
+ ancestor = composite == this;
+ if (ancestor) break;
+ composite = composite.parent;
+ }
+ if (!ancestor) error (SWT.ERROR_INVALID_PARENT);
+ }
+ for (int i=0; i<changed.length; i++) {
+ Control child = changed [i];
+ Composite composite = child.parent;
+ while (child != this) {
+ if (composite.layout == null || !composite.layout.flushCache (child)) {
+ composite.state |= LAYOUT_CHANGED;
+ }
+ child = composite;
+ composite = child.parent;
+ }
+ }
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget();
+ Point size;
+ if (layout != null) {
+ if ((wHint == SWT.DEFAULT) || (hHint == SWT.DEFAULT)) {
+ changed |= (state & LAYOUT_CHANGED) != 0;
+ size = layout.computeSize (this, wHint, hHint, changed);
+ state &= ~LAYOUT_CHANGED;
+ } else {
+ size = new Point (wHint, hHint);
+ }
+ } else {
+ size = minimumSize (wHint, hHint, changed);
+ }
+ if (size.x == 0) size.x = DEFAULT_WIDTH;
+ if (size.y == 0) size.y = DEFAULT_HEIGHT;
+ if (wHint != SWT.DEFAULT) size.x = wHint;
+ if (hHint != SWT.DEFAULT) size.y = hHint;
+ Rectangle trim = computeTrim (0, 0, size.x, size.y);
+ return new Point (trim.width, trim.height);
+}
+
+protected void checkSubclass () {
+ /* Do nothing - Subclassing is allowed */
+}
+
+Widget [] computeTabList () {
+ Widget result [] = super.computeTabList ();
+ if (result.length == 0) return result;
+ Control [] list = tabList != null ? _getTabList () : _getChildren ();
+ for (int i=0; i<list.length; i++) {
+ Control child = list [i];
+ Widget [] childList = child.computeTabList ();
+ if (childList.length != 0) {
+ Widget [] newResult = new Widget [result.length + childList.length];
+ System.arraycopy (result, 0, newResult, 0, result.length);
+ System.arraycopy (childList, 0, newResult, result.length, childList.length);
+ result = newResult;
+ }
+ }
+ return result;
+}
+
+void createHandle () {
+ state |= CANVAS;
+ boolean scrolled = (style & (SWT.V_SCROLL | SWT.H_SCROLL)) != 0;
+ if (!scrolled) state |= THEME_BACKGROUND;
+ NSRect rect = new NSRect();
+ if (scrolled || hasBorder ()) {
+ NSScrollView scrollWidget = (NSScrollView)new SWTScrollView().alloc();
+ scrollWidget.initWithFrame (rect);
+ scrollWidget.setDrawsBackground(false);
+ if ((style & SWT.H_SCROLL) != 0) scrollWidget.setHasHorizontalScroller(true);
+ if ((style & SWT.V_SCROLL) != 0) scrollWidget.setHasVerticalScroller(true);
+ scrollWidget.setBorderType(hasBorder() ? OS.NSBezelBorder : OS.NSNoBorder);
+ scrollView = scrollWidget;
+ }
+ NSView widget = (NSView)new SWTCanvasView().alloc();
+ widget.initWithFrame (rect);
+// widget.setFocusRingType(OS.NSFocusRingTypeExterior);
+ view = widget;
+ if (scrollView != null) {
+ NSClipView contentView = scrollView.contentView();
+ contentView.setAutoresizesSubviews(true);
+ view.setAutoresizingMask(OS.NSViewWidthSizable | OS.NSViewHeightSizable);
+ }
+}
+
+void drawBackground (int /*long*/ id, NSGraphicsContext context, NSRect rect) {
+ if (id != view.id) return;
+ if ((state & CANVAS) != 0) {
+ if ((style & SWT.NO_BACKGROUND) == 0) {
+ fillBackground (view, context, rect, -1);
+ }
+ }
+}
+
+Composite findDeferredControl () {
+ return layoutCount > 0 ? this : parent.findDeferredControl ();
+}
+
+Menu [] findMenus (Control control) {
+ if (control == this) return new Menu [0];
+ Menu result [] = super.findMenus (control);
+ Control [] children = _getChildren ();
+ for (int i=0; i<children.length; i++) {
+ Control child = children [i];
+ Menu [] menuList = child.findMenus (control);
+ if (menuList.length != 0) {
+ Menu [] newResult = new Menu [result.length + menuList.length];
+ System.arraycopy (result, 0, newResult, 0, result.length);
+ System.arraycopy (menuList, 0, newResult, result.length, menuList.length);
+ result = newResult;
+ }
+ }
+ return result;
+}
+
+void fixChildren (Shell newShell, Shell oldShell, Decorations newDecorations, Decorations oldDecorations, Menu [] menus) {
+ super.fixChildren (newShell, oldShell, newDecorations, oldDecorations, menus);
+ Control [] children = _getChildren ();
+ for (int i=0; i<children.length; i++) {
+ children [i].fixChildren (newShell, oldShell, newDecorations, oldDecorations, menus);
+ }
+}
+
+void fixTabList (Control control) {
+ if (tabList == null) return;
+ int count = 0;
+ for (int i=0; i<tabList.length; i++) {
+ if (tabList [i] == control) count++;
+ }
+ if (count == 0) return;
+ Control [] newList = null;
+ int length = tabList.length - count;
+ if (length != 0) {
+ newList = new Control [length];
+ int index = 0;
+ for (int i=0; i<tabList.length; i++) {
+ if (tabList [i] != control) {
+ newList [index++] = tabList [i];
+ }
+ }
+ }
+ tabList = newList;
+}
+
+/**
+ * Returns the receiver's background drawing mode. This
+ * will be one of the following constants defined in class
+ * <code>SWT</code>:
+ * <code>INHERIT_NONE</code>, <code>INHERIT_DEFAULT</code>,
+ * <code>INHERTIT_FORCE</code>.
+ *
+ * @return the background mode
+ *
+ * @exception SWTException <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 SWT
+ *
+ * @since 3.2
+ */
+public int getBackgroundMode () {
+ checkWidget ();
+ return backgroundMode;
+}
+
+/**
+ * Returns a (possibly empty) array containing the receiver's children.
+ * Children are returned in the order that they are drawn. The topmost
+ * control appears at the beginning of the array. Subsequent controls
+ * draw beneath this control and appear later in the array.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of children, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ *
+ * @return an array of children
+ *
+ * @see Control#moveAbove
+ * @see Control#moveBelow
+ *
+ * @exception SWTException <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 Control [] getChildren () {
+ checkWidget();
+ return _getChildren ();
+}
+
+/**
+ * Returns layout which is associated with the receiver, or
+ * null if one has not been set.
+ *
+ * @return the receiver's layout or null
+ *
+ * @exception SWTException <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 Layout getLayout () {
+ checkWidget();
+ return layout;
+}
+
+/**
+ * Returns <code>true</code> if the receiver has deferred
+ * the performing of layout, and <code>false</code> otherwise.
+ *
+ * @return the receiver's deferred layout state
+ *
+ * @exception SWTException <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 #setLayoutDeferred(boolean)
+ * @see #isLayoutDeferred()
+ *
+ * @since 3.1
+ */
+public boolean getLayoutDeferred () {
+ checkWidget ();
+ return layoutCount > 0 ;
+}
+
+/**
+ * Gets the (possibly empty) tabbing order for the control.
+ *
+ * @return tabList the ordered list of controls representing the tab order
+ *
+ * @exception SWTException <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 #setTabList
+ */
+public Control [] getTabList () {
+ checkWidget ();
+ Control [] tabList = _getTabList ();
+ if (tabList == null) {
+ int count = 0;
+ Control [] list =_getChildren ();
+ for (int i=0; i<list.length; i++) {
+ if (list [i].isTabGroup ()) count++;
+ }
+ tabList = new Control [count];
+ int index = 0;
+ for (int i=0; i<list.length; i++) {
+ if (list [i].isTabGroup ()) {
+ tabList [index++] = list [i];
+ }
+ }
+ }
+ return tabList;
+}
+
+boolean hooksKeys () {
+ return hooks (SWT.KeyDown) || hooks (SWT.KeyUp);
+}
+
+void invalidateChildrenVisibleRegion () {
+ Control [] children = _getChildren ();
+ for (int i=0; i<children.length; i++) {
+ Control child = children [i];
+ child.resetVisibleRegion ();
+ child.invalidateChildrenVisibleRegion ();
+ }
+}
+
+/**
+ * Returns <code>true</code> if the receiver or any ancestor
+ * up to and including the receiver's nearest ancestor shell
+ * has deferred the performing of layouts. Otherwise, <code>false</code>
+ * is returned.
+ *
+ * @return the receiver's deferred layout state
+ *
+ * @exception SWTException <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 #setLayoutDeferred(boolean)
+ * @see #getLayoutDeferred()
+ *
+ * @since 3.1
+ */
+public boolean isLayoutDeferred () {
+ checkWidget ();
+ return findDeferredControl () != null;
+}
+
+boolean isOpaque (int /*long*/ id, int /*long*/ sel) {
+ if ((state & CANVAS) != 0) {
+ if (id == view.id) {
+ if (region == null && background != null && background[3] == 1) {
+ return true;
+ }
+ }
+ }
+ return super.isOpaque (id, sel);
+}
+
+boolean isTabGroup () {
+ if ((state & CANVAS) != 0) return true;
+ return super.isTabGroup ();
+}
+
+void keyDown (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (view.window ().firstResponder ().id == id) {
+ if ((state & CANVAS) != 0) {
+ Shell s = this.getShell();
+ NSArray array = NSArray.arrayWithObject (new NSEvent (theEvent));
+ s.keyInputHappened = false;
+ view.interpretKeyEvents (array);
+ if (imeInComposition ()) return;
+ if (!s.keyInputHappened) {
+ NSEvent nsEvent = new NSEvent (theEvent);
+ boolean [] consume = new boolean [1];
+ if (translateTraversal (nsEvent.keyCode (), nsEvent, consume)) return;
+ if (isDisposed ()) return;
+ if (!sendKeyEvent (nsEvent, SWT.KeyDown)) return;
+ if (consume [0]) return;
+ }
+ return;
+ }
+ }
+ super.keyDown (id, sel, theEvent);
+}
+
+/**
+ * If the receiver has a layout, asks the layout to <em>lay out</em>
+ * (that is, set the size and location of) the receiver's children.
+ * If the receiver does not have a layout, do nothing.
+ * <p>
+ * This is equivalent to calling <code>layout(true)</code>.
+ * </p>
+ * <p>
+ * Note: Layout is different from painting. If a child is
+ * moved or resized such that an area in the parent is
+ * exposed, then the parent will paint. If no child is
+ * affected, the parent will not paint.
+ * </p>
+ *
+ * @exception SWTException <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 layout () {
+ checkWidget ();
+ layout (true);
+}
+
+/**
+ * If the receiver has a layout, asks the layout to <em>lay out</em>
+ * (that is, set the size and location of) the receiver's children.
+ * If the argument is <code>true</code> the layout must not rely
+ * on any information it has cached about the immediate children. If it
+ * is <code>false</code> the layout may (potentially) optimize the
+ * work it is doing by assuming that none of the receiver's
+ * children has changed state since the last layout.
+ * If the receiver does not have a layout, do nothing.
+ * <p>
+ * If a child is resized as a result of a call to layout, the
+ * resize event will invoke the layout of the child. The layout
+ * will cascade down through all child widgets in the receiver's widget
+ * tree until a child is encountered that does not resize. Note that
+ * a layout due to a resize will not flush any cached information
+ * (same as <code>layout(false)</code>).
+ * </p>
+ * <p>
+ * Note: Layout is different from painting. If a child is
+ * moved or resized such that an area in the parent is
+ * exposed, then the parent will paint. If no child is
+ * affected, the parent will not paint.
+ * </p>
+ *
+ * @param changed <code>true</code> if the layout must flush its caches, and <code>false</code> otherwise
+ *
+ * @exception SWTException <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 layout (boolean changed) {
+ checkWidget ();
+ if (layout == null) return;
+ layout (changed, false);
+}
+
+/**
+ * If the receiver has a layout, asks the layout to <em>lay out</em>
+ * (that is, set the size and location of) the receiver's children.
+ * If the changed argument is <code>true</code> the layout must not rely
+ * on any information it has cached about its children. If it
+ * is <code>false</code> the layout may (potentially) optimize the
+ * work it is doing by assuming that none of the receiver's
+ * children has changed state since the last layout.
+ * If the all argument is <code>true</code> the layout will cascade down
+ * through all child widgets in the receiver's widget tree, regardless of
+ * whether the child has changed size. The changed argument is applied to
+ * all layouts. If the all argument is <code>false</code>, the layout will
+ * <em>not</em> cascade down through all child widgets in the receiver's widget
+ * tree. However, if a child is resized as a result of a call to layout, the
+ * resize event will invoke the layout of the child. Note that
+ * a layout due to a resize will not flush any cached information
+ * (same as <code>layout(false)</code>).
+ * </p>
+ * <p>
+ * Note: Layout is different from painting. If a child is
+ * moved or resized such that an area in the parent is
+ * exposed, then the parent will paint. If no child is
+ * affected, the parent will not paint.
+ * </p>
+ *
+ * @param changed <code>true</code> if the layout must flush its caches, and <code>false</code> otherwise
+ * @param all <code>true</code> if all children in the receiver's widget tree should be laid out, and <code>false</code> otherwise
+ *
+ * @exception SWTException <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.1
+ */
+public void layout (boolean changed, boolean all) {
+ checkWidget ();
+ if (layout == null && !all) return;
+ markLayout (changed, all);
+ updateLayout (all);
+}
+
+/**
+ * Forces a lay out (that is, sets the size and location) of all widgets that
+ * are in the parent hierarchy of the changed control up to and including the
+ * receiver. The layouts in the hierarchy must not rely on any information
+ * cached about the changed control or any of its ancestors. The layout may
+ * (potentially) optimize the work it is doing by assuming that none of the
+ * peers of the changed control have changed state since the last layout.
+ * If an ancestor does not have a layout, skip it.
+ * <p>
+ * Note: Layout is different from painting. If a child is
+ * moved or resized such that an area in the parent is
+ * exposed, then the parent will paint. If no child is
+ * affected, the parent will not paint.
+ * </p>
+ *
+ * @param changed a control that has had a state change which requires a recalculation of its size
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the changed array is null any of its controls are null or have been disposed</li>
+ * <li>ERROR_INVALID_PARENT - if any control in changed is not in the widget tree of the receiver</li>
+ * </ul>
+ * @exception SWTException <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.1
+ */
+public void layout (Control [] changed) {
+ checkWidget ();
+ if (changed == null) error (SWT.ERROR_INVALID_ARGUMENT);
+ for (int i=0; i<changed.length; i++) {
+ Control control = changed [i];
+ if (control == null) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ boolean ancestor = false;
+ Composite composite = control.parent;
+ while (composite != null) {
+ ancestor = composite == this;
+ if (ancestor) break;
+ composite = composite.parent;
+ }
+ if (!ancestor) error (SWT.ERROR_INVALID_PARENT);
+ }
+ int updateCount = 0;
+ Composite [] update = new Composite [16];
+ for (int i=0; i<changed.length; i++) {
+ Control child = changed [i];
+ Composite composite = child.parent;
+ while (child != this) {
+ if (composite.layout != null) {
+ composite.state |= LAYOUT_NEEDED;
+ if (!composite.layout.flushCache (child)) {
+ composite.state |= LAYOUT_CHANGED;
+ }
+ }
+ if (updateCount == update.length) {
+ Composite [] newUpdate = new Composite [update.length + 16];
+ System.arraycopy (update, 0, newUpdate, 0, update.length);
+ update = newUpdate;
+ }
+ child = update [updateCount++] = composite;
+ composite = child.parent;
+ }
+ }
+ for (int i=updateCount-1; i>=0; i--) {
+ update [i].updateLayout (false);
+ }
+}
+
+void markLayout (boolean changed, boolean all) {
+ if (layout != null) {
+ state |= LAYOUT_NEEDED;
+ if (changed) state |= LAYOUT_CHANGED;
+ }
+ if (all) {
+ Control [] children = _getChildren ();
+ for (int i=0; i<children.length; i++) {
+ children [i].markLayout (changed, all);
+ }
+ }
+}
+
+Point minimumSize (int wHint, int Hint, boolean changed) {
+ Control [] children = _getChildren ();
+ int width = 0, height = 0;
+ for (int i=0; i<children.length; i++) {
+ Rectangle rect = children [i].getBounds ();
+ width = Math.max (width, rect.x + rect.width);
+ height = Math.max (height, rect.y + rect.height);
+ }
+ return new Point (width, height);
+}
+
+boolean mouseEvent (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent, int type) {
+ boolean result = super.mouseEvent (id, sel, theEvent, type);
+ return (state & CANVAS) == 0 ? result : new NSEvent (theEvent).type () != OS.NSLeftMouseDown;
+}
+
+void pageDown(int /*long*/ id, int /*long*/ sel, int /*long*/ sender) {
+ if ((state & CANVAS) != 0) return;
+ super.pageDown(id, sel, sender);
+}
+
+void pageUp(int /*long*/ id, int /*long*/ sel, int /*long*/ sender) {
+ if ((state & CANVAS) != 0) return;
+ super.pageUp(id, sel, sender);
+}
+
+void reflectScrolledClipView (int /*long*/ id, int /*long*/ sel, int /*long*/ aClipView) {
+ if ((state & CANVAS) != 0) return;
+ super.reflectScrolledClipView (id, sel, aClipView);
+}
+
+void releaseChildren (boolean destroy) {
+ Control [] children = _getChildren ();
+ for (int i=0; i<children.length; i++) {
+ Control child = children [i];
+ if (child != null && !child.isDisposed ()) {
+ child.release (false);
+ }
+ }
+ super.releaseChildren (destroy);
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ layout = null;
+ tabList = null;
+}
+
+void removeControl (Control control) {
+ fixTabList (control);
+}
+
+void resized () {
+ super.resized ();
+ if (layout != null) {
+ markLayout (false, false);
+ updateLayout (false);
+ }
+}
+
+void scrollWheel (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if ((state & CANVAS) != 0) {
+ NSView view = scrollView != null ? scrollView : this.view;
+ if (id == view.id) {
+ NSEvent nsEvent = new NSEvent(theEvent);
+ float /*double*/ delta = nsEvent.deltaY();
+ if (delta != 0) {
+ if (hooks (SWT.MouseWheel) || filters (SWT.MouseWheel)) {
+ if (!sendMouseEvent(nsEvent, SWT.MouseWheel, true)) {
+ return;
+ }
+ }
+ }
+ boolean handled = false;
+ ScrollBar bar = verticalBar;
+ if (delta != 0 && bar != null && bar.getEnabled ()) {
+ if (-1 < delta && delta < 0) delta = -1;
+ if (0 < delta && delta < 1) delta = 1;
+ int selection = Math.max (0, (int)(0.5f + bar.getSelection () - bar.getIncrement () * delta));
+ bar.setSelection (selection);
+ Event event = new Event ();
+ event.detail = delta > 0 ? SWT.PAGE_UP : SWT.PAGE_DOWN;
+ bar.sendEvent (SWT.Selection, event);
+ handled = true;
+ }
+ bar = horizontalBar;
+ delta = nsEvent.deltaX ();
+ if (delta != 0 && bar != null && bar.getEnabled ()) {
+ int selection = Math.max (0, (int)(0.5f + bar.getSelection () - bar.getIncrement () * delta));
+ bar.setSelection (selection);
+ Event event = new Event ();
+ event.detail = delta > 0 ? SWT.PAGE_UP : SWT.PAGE_DOWN;
+ bar.sendEvent (SWT.Selection, event);
+ handled = true;
+ }
+ if (!handled) view.superview().scrollWheel(nsEvent);
+ return;
+ }
+ callSuper(id, sel, theEvent);
+ return;
+ }
+ super.scrollWheel (id, sel, theEvent);
+}
+
+/**
+ * Sets the background drawing mode to the argument which should
+ * be one of the following constants defined in class <code>SWT</code>:
+ * <code>INHERIT_NONE</code>, <code>INHERIT_DEFAULT</code>,
+ * <code>INHERIT_FORCE</code>.
+ *
+ * @param mode the new background mode
+ *
+ * @exception SWTException <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 SWT
+ *
+ * @since 3.2
+ */
+public void setBackgroundMode (int mode) {
+ checkWidget ();
+ backgroundMode = mode;
+ Control [] children = _getChildren ();
+ for (int i = 0; i < children.length; i++) {
+ children [i].updateBackgroundMode ();
+ }
+}
+
+public boolean setFocus () {
+ checkWidget ();
+ Control [] children = _getChildren ();
+ for (int i= 0; i < children.length; i++) {
+ if (children [i].setFocus ()) return true;
+ }
+ return super.setFocus ();
+}
+
+/**
+ * Sets the layout which is associated with the receiver to be
+ * the argument which may be null.
+ *
+ * @param layout the receiver's new layout or null
+ *
+ * @exception SWTException <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 setLayout (Layout layout) {
+ checkWidget();
+ this.layout = layout;
+}
+
+/**
+ * If the argument is <code>true</code>, causes subsequent layout
+ * operations in the receiver or any of its children to be ignored.
+ * No layout of any kind can occur in the receiver or any of its
+ * children until the flag is set to false.
+ * Layout operations that occurred while the flag was
+ * <code>true</code> are remembered and when the flag is set to
+ * <code>false</code>, the layout operations are performed in an
+ * optimized manner. Nested calls to this method are stacked.
+ *
+ * @param defer the new defer state
+ *
+ * @exception SWTException <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 #layout(boolean)
+ * @see #layout(Control[])
+ *
+ * @since 3.1
+ */
+public void setLayoutDeferred (boolean defer) {
+ if (!defer) {
+ if (--layoutCount == 0) {
+ if ((state & LAYOUT_CHILD) != 0 || (state & LAYOUT_NEEDED) != 0) {
+ updateLayout (true);
+ }
+ }
+ } else {
+ layoutCount++;
+ }
+}
+
+boolean setScrollBarVisible (ScrollBar bar, boolean visible) {
+ boolean changed = super.setScrollBarVisible (bar, visible);
+ if (changed && layout != null) {
+ markLayout (false, false);
+ updateLayout (false);
+ }
+ return changed;
+}
+
+boolean setTabGroupFocus () {
+ if (isTabItem ()) return setTabItemFocus ();
+ boolean takeFocus = (style & SWT.NO_FOCUS) == 0;
+ if ((state & CANVAS) != 0) takeFocus = hooksKeys ();
+ if (takeFocus && setTabItemFocus ()) return true;
+ Control [] children = _getChildren ();
+ for (int i=0; i<children.length; i++) {
+ Control child = children [i];
+ if (child.isTabItem () && child.setTabItemFocus ()) return true;
+ }
+ return false;
+}
+
+/**
+ * Sets the tabbing order for the specified controls to
+ * match the order that they occur in the argument list.
+ *
+ * @param tabList the ordered list of controls representing the tab order or null
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if a widget in the tabList is null or has been disposed</li>
+ * <li>ERROR_INVALID_PARENT - if widget in the tabList is not in the same widget tree</li>
+ * </ul>
+ * @exception SWTException <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 setTabList (Control [] tabList) {
+ checkWidget ();
+ if (tabList != null) {
+ for (int i=0; i<tabList.length; i++) {
+ Control control = tabList [i];
+ if (control == null) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (control.parent != this) error (SWT.ERROR_INVALID_PARENT);
+ }
+ Control [] newList = new Control [tabList.length];
+ System.arraycopy (tabList, 0, newList, 0, tabList.length);
+ tabList = newList;
+ }
+ this.tabList = tabList;
+}
+
+int traversalCode (int key, NSEvent theEvent) {
+ if ((state & CANVAS) != 0) {
+ if ((style & SWT.NO_FOCUS) != 0) return 0;
+ if (hooksKeys ()) return 0;
+ }
+ return super.traversalCode (key, theEvent);
+}
+
+void updateBackgroundMode () {
+ super.updateBackgroundMode ();
+ Control [] children = _getChildren ();
+ for (int i = 0; i < children.length; i++) {
+ children [i].updateBackgroundMode ();
+ }
+}
+
+void updateCursorRects (boolean enabled) {
+ super.updateCursorRects (enabled);
+ Control [] children = _getChildren ();
+ for (int i = 0; i < children.length; i++) {
+ Control control = children [i];
+ control.updateCursorRects (enabled && control.isEnabled ());
+ }
+}
+
+void updateLayout (boolean all) {
+ Composite parent = findDeferredControl ();
+ if (parent != null) {
+ parent.state |= LAYOUT_CHILD;
+ return;
+ }
+ if ((state & LAYOUT_NEEDED) != 0) {
+ boolean changed = (state & LAYOUT_CHANGED) != 0;
+ state &= ~(LAYOUT_NEEDED | LAYOUT_CHANGED);
+ layout.layout (this, changed);
+ }
+ if (all) {
+ state &= ~LAYOUT_CHILD;
+ Control [] children = _getChildren ();
+ for (int i=0; i<children.length; i++) {
+ children [i].updateLayout (all);
+ }
+ }
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Control.java
new file mode 100755
index 0000000000..c3666bc092
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Control.java
@@ -0,0 +1,4114 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.accessibility.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Control is the abstract superclass of all windowed user interface classes.
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b>
+ * <dd>BORDER</dd>
+ * <dd>LEFT_TO_RIGHT, RIGHT_TO_LEFT</dd>
+ * <dt><b>Events:</b>
+ * <dd>DragDetect, FocusIn, FocusOut, Help, KeyDown, KeyUp, MenuDetect, MouseDoubleClick, MouseDown, MouseEnter,
+ * MouseExit, MouseHover, MouseUp, MouseMove, Move, Paint, Resize, Traverse</dd>
+ * </dl>
+ * </p><p>
+ * Only one of LEFT_TO_RIGHT or RIGHT_TO_LEFT may be specified.
+ * </p><p>
+ * IMPORTANT: This class is intended to be subclassed <em>only</em>
+ * within the SWT implementation.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#control">Control snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public abstract class Control extends Widget implements Drawable {
+ /**
+ * the handle to the OS resource
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public NSView view;
+ Composite parent;
+ String toolTipText;
+ Object layoutData;
+ int drawCount;
+ Menu menu;
+ float /*double*/ [] foreground, background;
+ Image backgroundImage;
+ Font font;
+ Cursor cursor;
+ Region region;
+ NSBezierPath regionPath;
+ int /*long*/ visibleRgn;
+ Accessible accessible;
+
+ final static int CLIPPING = 1 << 10;
+ final static int VISIBLE_REGION = 1 << 12;
+
+ /**
+ * Magic number comes from experience. There's no API for this value in Cocoa or Carbon.
+ */
+ static final int DEFAULT_DRAG_HYSTERESIS = 5;
+
+Control () {
+ /* Do nothing */
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#BORDER
+ * @see SWT#LEFT_TO_RIGHT
+ * @see SWT#RIGHT_TO_LEFT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Control (Composite parent, int style) {
+ super (parent, style);
+ this.parent = parent;
+ createWidget ();
+}
+
+boolean acceptsFirstMouse (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ Shell shell = getShell ();
+ if ((shell.style & SWT.ON_TOP) != 0) return true;
+ return super.acceptsFirstMouse (id, sel, theEvent);
+}
+
+int /*long*/ accessibilityActionNames(int /*long*/ id, int /*long*/ sel) {
+ if (accessible != null) {
+ NSArray returnValue = accessible.internal_accessibilityActionNames(ACC.CHILDID_SELF);
+ if (returnValue != null) return returnValue.id;
+ }
+
+ return super.accessibilityActionNames(id, sel);
+}
+
+int /*long*/ accessibilityAttributeNames(int /*long*/ id, int /*long*/ sel) {
+
+ if (id == view.id || (view instanceof NSControl && ((NSControl)view).cell() != null && ((NSControl)view).cell().id == id)) {
+ if (accessible != null) {
+
+ // First, see if the accessible is going to define a set of attributes for the control.
+ // If it does, return that.
+ NSArray returnValue = accessible.internal_accessibilityAttributeNames(ACC.CHILDID_SELF);
+ if (returnValue != null) return returnValue.id;
+
+ // If not, see if it will override or augment the standard list.
+ // Help, title, and description can be overridden.
+ NSMutableArray extraAttributes = NSMutableArray.arrayWithCapacity(3);
+ extraAttributes.addObject(OS.NSAccessibilityHelpAttribute);
+ extraAttributes.addObject(OS.NSAccessibilityDescriptionAttribute);
+ extraAttributes.addObject(OS.NSAccessibilityTitleAttribute);
+
+ for (int i = (int)/*64*/extraAttributes.count() - 1; i >= 0; i--) {
+ NSString attribute = new NSString(extraAttributes.objectAtIndex(i).id);
+ if (accessible.internal_accessibilityAttributeValue(attribute, ACC.CHILDID_SELF) == null) {
+ extraAttributes.removeObjectAtIndex(i);
+ }
+ }
+
+ if (extraAttributes.count() > 0) {
+ int /*long*/ superResult = super.accessibilityAttributeNames(id, sel);
+ NSArray baseAttributes = new NSArray(superResult);
+ NSMutableArray mutableAttributes = NSMutableArray.arrayWithCapacity(baseAttributes.count() + 1);
+ mutableAttributes.addObjectsFromArray(baseAttributes);
+
+ for (int i = 0; i < extraAttributes.count(); i++) {
+ id currAttribute = extraAttributes.objectAtIndex(i);
+ if (!mutableAttributes.containsObject(currAttribute)) {
+ mutableAttributes.addObject(currAttribute);
+ }
+ }
+
+ return mutableAttributes.id;
+ }
+ }
+ }
+
+ return super.accessibilityAttributeNames(id, sel);
+}
+
+int /*long*/ accessibilityParameterizedAttributeNames(int /*long*/ id, int /*long*/ sel) {
+
+ if (id == view.id || (view instanceof NSControl && ((NSControl)view).cell() != null && ((NSControl)view).cell().id == id)) {
+ if (accessible != null) {
+ NSArray returnValue = accessible.internal_accessibilityParameterizedAttributeNames(ACC.CHILDID_SELF);
+ if (returnValue != null) return returnValue.id;
+ }
+ }
+
+ return super.accessibilityParameterizedAttributeNames(id, sel);
+}
+
+int /*long*/ accessibilityFocusedUIElement(int /*long*/ id, int /*long*/ sel) {
+ id returnValue = null;
+
+ if (id == view.id || (view instanceof NSControl && ((NSControl)view).cell() != null && ((NSControl)view).cell().id == id)) {
+ if (accessible != null) {
+ returnValue = accessible.internal_accessibilityFocusedUIElement(ACC.CHILDID_SELF);
+ }
+ }
+
+ // If we had an accessible and it didn't handle the attribute request, let the
+ // superclass handle it.
+ if (returnValue == null)
+ return super.accessibilityFocusedUIElement(id, sel);
+ else
+ return returnValue.id;
+}
+
+int /*long*/ accessibilityHitTest(int /*long*/ id, int /*long*/ sel, NSPoint point) {
+ id returnValue = null;
+
+ if (id == view.id || (view instanceof NSControl && ((NSControl)view).cell() != null && ((NSControl)view).cell().id == id)) {
+ if (accessible != null) {
+ returnValue = accessible.internal_accessibilityHitTest(point, ACC.CHILDID_SELF);
+ }
+ }
+
+ // If we had an accessible and it didn't handle the attribute request, let the
+ // superclass handle it.
+ if (returnValue == null)
+ return super.accessibilityHitTest(id, sel, point);
+ else
+ return returnValue.id;
+}
+
+int /*long*/ accessibilityAttributeValue(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ NSString attribute = new NSString(arg0);
+ int /*long*/ returnValue = 0;
+ id returnObject = null;
+
+ if (accessible != null) {
+ returnObject = accessible.internal_accessibilityAttributeValue(attribute, ACC.CHILDID_SELF);
+ }
+
+ // If we had an accessible and it didn't handle the attribute request, let the
+ // superclass handle it.
+ if (returnObject == null) {
+ returnValue = super.accessibilityAttributeValue(id, sel, arg0);
+ } else {
+ returnValue = returnObject.id;
+ }
+
+ return returnValue;
+}
+
+int /*long*/ accessibilityAttributeValue_forParameter(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1) {
+ NSString attribute = new NSString(arg0);
+
+ id returnValue = null;
+
+ if (accessible != null) {
+ id parameter = new id(arg1);
+ returnValue = accessible.internal_accessibilityAttributeValue_forParameter(attribute, parameter, ACC.CHILDID_SELF);
+ }
+
+ // If we had an accessible and it didn't handle the attribute request, let the
+ // superclass handle it.
+ if (returnValue == null)
+ return super.accessibilityAttributeValue_forParameter(id, sel, arg0, arg1);
+ else
+ return returnValue.id;
+}
+
+/**
+ * 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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Resize,typedListener);
+ addListener (SWT.Move,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when a drag gesture occurs, by sending it
+ * one of the messages defined in the <code>DragDetectListener</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 SWTException <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 DragDetectListener
+ * @see #removeDragDetectListener
+ *
+ * @since 3.3
+ */
+public void addDragDetectListener (DragDetectListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.DragDetect,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the control gains or loses focus, by sending
+ * it one of the messages defined in the <code>FocusListener</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 SWTException <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 FocusListener
+ * @see #removeFocusListener
+ */
+public void addFocusListener(FocusListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener(SWT.FocusIn,typedListener);
+ addListener(SWT.FocusOut,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when help events are generated for the control,
+ * by sending it one of the messages defined in the
+ * <code>HelpListener</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 SWTException <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 HelpListener
+ * @see #removeHelpListener
+ */
+public void addHelpListener (HelpListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Help, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when keys are pressed and released on the system keyboard, by sending
+ * it one of the messages defined in the <code>KeyListener</code>
+ * interface.
+ * <p>
+ * When a key listener is added to a control, the control
+ * will take part in widget traversal. By default, all
+ * traversal keys (such as the tab key and so on) are
+ * delivered to the control. In order for a control to take
+ * part in traversal, it should listen for traversal events.
+ * Otherwise, the user can traverse into a control but not
+ * out. Note that native controls such as table and tree
+ * implement key traversal in the operating system. It is
+ * not necessary to add traversal listeners for these controls,
+ * unless you want to override the default traversal.
+ * </p>
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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 KeyListener
+ * @see #removeKeyListener
+ */
+public void addKeyListener(KeyListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener(SWT.KeyUp,typedListener);
+ addListener(SWT.KeyDown,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the platform-specific context menu trigger
+ * has occurred, by sending it one of the messages defined in
+ * the <code>MenuDetectListener</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 SWTException <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 MenuDetectListener
+ * @see #removeMenuDetectListener
+ *
+ * @since 3.3
+ */
+public void addMenuDetectListener (MenuDetectListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.MenuDetect, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when mouse buttons are pressed and released, by sending
+ * it one of the messages defined in the <code>MouseListener</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 SWTException <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 MouseListener
+ * @see #removeMouseListener
+ */
+public void addMouseListener(MouseListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener(SWT.MouseDown,typedListener);
+ addListener(SWT.MouseUp,typedListener);
+ addListener(SWT.MouseDoubleClick,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the mouse passes or hovers over controls, by sending
+ * it one of the messages defined in the <code>MouseTrackListener</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 SWTException <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 MouseTrackListener
+ * @see #removeMouseTrackListener
+ */
+public void addMouseTrackListener (MouseTrackListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.MouseEnter,typedListener);
+ addListener (SWT.MouseExit,typedListener);
+ addListener (SWT.MouseHover,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the mouse moves, by sending it one of the
+ * messages defined in the <code>MouseMoveListener</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 SWTException <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 MouseMoveListener
+ * @see #removeMouseMoveListener
+ */
+public void addMouseMoveListener(MouseMoveListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener(SWT.MouseMove,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the mouse wheel is scrolled, by sending
+ * it one of the messages defined in the
+ * <code>MouseWheelListener</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 SWTException <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 MouseWheelListener
+ * @see #removeMouseWheelListener
+ *
+ * @since 3.3
+ */
+public void addMouseWheelListener (MouseWheelListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.MouseWheel, typedListener);
+}
+
+void addRelation (Control control) {
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the receiver needs to be painted, by sending it
+ * one of the messages defined in the <code>PaintListener</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 SWTException <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 PaintListener
+ * @see #removePaintListener
+ */
+public void addPaintListener(PaintListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener(SWT.Paint,typedListener);
+}
+
+static final double SYNTHETIC_BOLD = -2.5;
+static final double SYNTHETIC_ITALIC = 0.2;
+
+void addTraits(NSMutableDictionary dict, Font font) {
+ if ((font.extraTraits & OS.NSBoldFontMask) != 0) {
+ dict.setObject(NSNumber.numberWithDouble(SYNTHETIC_BOLD), OS.NSStrokeWidthAttributeName);
+ }
+ if ((font.extraTraits & OS.NSItalicFontMask) != 0) {
+ dict.setObject(NSNumber.numberWithDouble(SYNTHETIC_ITALIC), OS.NSObliquenessAttributeName);
+ }
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when traversal events occur, by sending it
+ * one of the messages defined in the <code>TraverseListener</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 SWTException <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 TraverseListener
+ * @see #removeTraverseListener
+ */
+public void addTraverseListener (TraverseListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Traverse,typedListener);
+}
+
+boolean becomeFirstResponder (int /*long*/ id, int /*long*/ sel) {
+ if ((state & DISABLED) != 0) return false;
+ return super.becomeFirstResponder (id, sel);
+}
+
+void calculateVisibleRegion (NSView view, int /*long*/ visibleRgn, boolean clipChildren) {
+ int /*long*/ tempRgn = OS.NewRgn ();
+ if (!view.isHiddenOrHasHiddenAncestor() && isDrawing()) {
+ int /*long*/ childRgn = OS.NewRgn ();
+ NSWindow window = view.window ();
+ NSView contentView = window.contentView();
+ NSView frameView = contentView.superview();
+ NSRect bounds = contentView.visibleRect();
+ bounds = contentView.convertRect_toView_(bounds, view);
+ short[] rect = new short[4];
+ OS.SetRect(rect, (short)bounds.x, (short)bounds.y, (short)(bounds.x + bounds.width), (short)(bounds.y + bounds.height));
+ OS.RectRgn(visibleRgn, rect);
+ NSView tempView = view, lastControl = null;
+ while (tempView.id != frameView.id) {
+ bounds = tempView.visibleRect();
+ bounds = tempView.convertRect_toView_(bounds, view);
+ OS.SetRect(rect, (short)bounds.x, (short)bounds.y, (short)(bounds.x + bounds.width), (short)(bounds.y + bounds.height));
+ OS.RectRgn(tempRgn, rect);
+ OS.SectRgn (tempRgn, visibleRgn, visibleRgn);
+ if (OS.EmptyRgn (visibleRgn)) break;
+ if (clipChildren || tempView.id != view.id) {
+ NSArray subviews = tempView.subviews();
+ int /*long*/ count = subviews.count();
+ for (int i = 0; i < count; i++) {
+ NSView child = new NSView (subviews.objectAtIndex(count - i - 1));
+ if (lastControl != null && child.id == lastControl.id) break;
+ if (child.isHidden()) continue;
+ bounds = child.visibleRect();
+ bounds = child.convertRect_toView_(bounds, view);
+ OS.SetRect(rect, (short)bounds.x, (short)bounds.y, (short)(bounds.x + bounds.width), (short)(bounds.y + bounds.height));
+ OS.RectRgn(tempRgn, rect);
+ OS.UnionRgn (tempRgn, childRgn, childRgn);
+ }
+ }
+ lastControl = tempView;
+ tempView = tempView.superview();
+ }
+ OS.DiffRgn (visibleRgn, childRgn, visibleRgn);
+ OS.DisposeRgn (childRgn);
+ } else {
+ OS.CopyRgn (tempRgn, visibleRgn);
+ }
+ OS.DisposeRgn (tempRgn);
+}
+
+void checkBackground () {
+ Shell shell = getShell ();
+ if (this == shell) return;
+ state &= ~PARENT_BACKGROUND;
+ Composite composite = parent;
+ do {
+ int mode = composite.backgroundMode;
+ if (mode != 0) {
+ if (mode == SWT.INHERIT_DEFAULT) {
+ Control control = this;
+ do {
+ if ((control.state & THEME_BACKGROUND) == 0) {
+ return;
+ }
+ control = control.parent;
+ } while (control != composite);
+ }
+ state |= PARENT_BACKGROUND;
+ return;
+ }
+ if (composite == shell) break;
+ composite = composite.parent;
+ } while (true);
+}
+
+void checkBuffered () {
+ style |= SWT.DOUBLE_BUFFERED;
+}
+
+void checkToolTip (Widget target) {
+ if (isVisible () && display.tooltipControl == this && (target == null || display.tooltipTarget == target)) {
+ Shell shell = getShell ();
+ shell.sendToolTipEvent (false);
+ shell.sendToolTipEvent (true);
+ }
+}
+
+/**
+ * Returns the preferred size of the receiver.
+ * <p>
+ * The <em>preferred size</em> of a control is the size that it would
+ * best be displayed at. The width hint and height hint arguments
+ * allow the caller to ask a control questions such as "Given a particular
+ * width, how high does the control need to be to show all of the contents?"
+ * To indicate that the caller does not wish to constrain a particular
+ * dimension, the constant <code>SWT.DEFAULT</code> is passed for the hint.
+ * </p>
+ *
+ * @param wHint the width hint (can be <code>SWT.DEFAULT</code>)
+ * @param hHint the height hint (can be <code>SWT.DEFAULT</code>)
+ * @return the preferred size of the control
+ *
+ * @exception SWTException <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 Layout
+ * @see #getBorderWidth
+ * @see #getBounds
+ * @see #getSize
+ * @see #pack(boolean)
+ * @see "computeTrim, getClientArea for controls that implement them"
+ */
+public Point computeSize (int wHint, int hHint) {
+ return computeSize (wHint, hHint, true);
+}
+
+/**
+ * Returns the preferred size of the receiver.
+ * <p>
+ * The <em>preferred size</em> of a control is the size that it would
+ * best be displayed at. The width hint and height hint arguments
+ * allow the caller to ask a control questions such as "Given a particular
+ * width, how high does the control need to be to show all of the contents?"
+ * To indicate that the caller does not wish to constrain a particular
+ * dimension, the constant <code>SWT.DEFAULT</code> is passed for the hint.
+ * </p><p>
+ * If the changed flag is <code>true</code>, it indicates that the receiver's
+ * <em>contents</em> have changed, therefore any caches that a layout manager
+ * containing the control may have been keeping need to be flushed. When the
+ * control is resized, the changed flag will be <code>false</code>, so layout
+ * manager caches can be retained.
+ * </p>
+ *
+ * @param wHint the width hint (can be <code>SWT.DEFAULT</code>)
+ * @param hHint the height hint (can be <code>SWT.DEFAULT</code>)
+ * @param changed <code>true</code> if the control's contents have changed, and <code>false</code> otherwise
+ * @return the preferred size of the control.
+ *
+ * @exception SWTException <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 Layout
+ * @see #getBorderWidth
+ * @see #getBounds
+ * @see #getSize
+ * @see #pack(boolean)
+ * @see "computeTrim, getClientArea for controls that implement them"
+ */
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int width = DEFAULT_WIDTH;
+ int height = DEFAULT_HEIGHT;
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ int border = getBorderWidth ();
+ width += border * 2;
+ height += border * 2;
+ return new Point (width, height);
+}
+
+Widget computeTabGroup () {
+ if (isTabGroup()) return this;
+ return parent.computeTabGroup ();
+}
+
+Widget[] computeTabList() {
+ if (isTabGroup()) {
+ if (getVisible() && getEnabled()) {
+ return new Widget[] {this};
+ }
+ }
+ return new Widget[0];
+}
+
+Control computeTabRoot () {
+ Control[] tabList = parent._getTabList();
+ if (tabList != null) {
+ int index = 0;
+ while (index < tabList.length) {
+ if (tabList [index] == this) break;
+ index++;
+ }
+ if (index == tabList.length) {
+ if (isTabGroup ()) return this;
+ }
+ }
+ return parent.computeTabRoot ();
+}
+
+NSView contentView () {
+ return view;
+}
+
+NSAttributedString createString (String string, Font font, float /*double*/ [] foreground, int style, boolean enabled, boolean mnemonics) {
+ NSMutableDictionary dict = ((NSMutableDictionary)new NSMutableDictionary().alloc()).initWithCapacity(5);
+ if (font == null) font = this.font != null ? this.font : defaultFont();
+ dict.setObject (font.handle, OS.NSFontAttributeName);
+ addTraits(dict, font);
+ if (enabled) {
+ if (foreground != null) {
+ NSColor color = NSColor.colorWithDeviceRed(foreground[0], foreground[1], foreground[2], foreground[3]);
+ dict.setObject (color, OS.NSForegroundColorAttributeName);
+ }
+ } else {
+ dict.setObject (NSColor.disabledControlTextColor (), OS.NSForegroundColorAttributeName);
+ }
+ if (style != 0) {
+ NSMutableParagraphStyle paragraphStyle = (NSMutableParagraphStyle)new NSMutableParagraphStyle ().alloc ().init ();
+ paragraphStyle.setLineBreakMode (OS.NSLineBreakByClipping);
+ int alignment = SWT.LEFT;
+ if ((style & SWT.CENTER) != 0) {
+ alignment = OS.NSCenterTextAlignment;
+ } else if ((style & SWT.RIGHT) != 0) {
+ alignment = OS.NSRightTextAlignment;
+ }
+ paragraphStyle.setAlignment (alignment);
+ dict.setObject (paragraphStyle, OS.NSParagraphStyleAttributeName);
+ paragraphStyle.release ();
+ }
+ int length = string.length ();
+ char [] chars = new char [length];
+ string.getChars (0, chars.length, chars, 0);
+ if (mnemonics) length = fixMnemonic (chars);
+ NSString str = ((NSString)new NSString().alloc()).initWithCharacters(chars, length);
+ NSAttributedString attribStr = ((NSAttributedString) new NSAttributedString ().alloc ()).initWithString (str, dict);
+ str.release();
+ dict.release();
+ return attribStr;
+}
+
+void createWidget () {
+ state |= DRAG_DETECT;
+ checkOrientation (parent);
+ super.createWidget ();
+ checkBackground ();
+ checkBuffered ();
+ setDefaultFont ();
+ setZOrder ();
+ setRelations ();
+ display.clearPool ();
+}
+
+Color defaultBackground () {
+ return display.getWidgetColor (SWT.COLOR_WIDGET_BACKGROUND);
+}
+
+Font defaultFont () {
+ if (display.smallFonts) return display.getSystemFont ();
+ return Font.cocoa_new (display, defaultNSFont ());
+}
+
+Color defaultForeground () {
+ return display.getWidgetColor (SWT.COLOR_WIDGET_FOREGROUND);
+}
+
+NSFont defaultNSFont () {
+ return display.getSystemFont().handle;
+}
+
+void deregister () {
+ super.deregister ();
+ display.removeWidget (view);
+}
+
+void destroyWidget () {
+ NSView view = topView ();
+ view.removeFromSuperview ();
+ releaseHandle ();
+}
+
+void doCommandBySelector (int /*long*/ id, int /*long*/ sel, int /*long*/ selector) {
+ if (view.window ().firstResponder ().id == id) {
+ if (imeInComposition ()) return;
+ Shell s = this.getShell();
+ NSEvent nsEvent = NSApplication.sharedApplication ().currentEvent ();
+ if (nsEvent != null && nsEvent.type () == OS.NSKeyDown) {
+ /*
+ * Feature in Cocoa. Pressing Alt+UpArrow invokes doCommandBySelector
+ * twice, with selectors moveBackward and moveToBeginningOfParagraph
+ * (Alt+DownArrow behaves similarly). In order to avoid sending
+ * multiple events for these keys, do not send a KeyDown if we already sent one
+ * during this keystroke. This rule does not apply if the command key
+ * is down, because we likely triggered the current key sequence via flagsChanged.
+ */
+ int /*long*/ modifiers = nsEvent.modifierFlags();
+ if (s.keyInputHappened == false || (modifiers & OS.NSCommandKeyMask) != 0) {
+ s.keyInputHappened = true;
+ boolean [] consume = new boolean [1];
+ if (translateTraversal (nsEvent.keyCode (), nsEvent, consume)) return;
+ if (isDisposed ()) return;
+ if (!sendKeyEvent (nsEvent, SWT.KeyDown)) return;
+ if (consume [0]) return;
+ }
+ }
+ if ((state & CANVAS) != 0) return;
+ }
+ super.doCommandBySelector (id, sel, selector);
+}
+
+/**
+ * Detects a drag and drop gesture. This method is used
+ * to detect a drag gesture when called from within a mouse
+ * down listener.
+ *
+ * <p>By default, a drag is detected when the gesture
+ * occurs anywhere within the client area of a control.
+ * Some controls, such as tables and trees, override this
+ * behavior. In addition to the operating system specific
+ * drag gesture, they require the mouse to be inside an
+ * item. Custom widget writers can use <code>setDragDetect</code>
+ * to disable the default detection, listen for mouse down,
+ * and then call <code>dragDetect()</code> from within the
+ * listener to conditionally detect a drag.
+ * </p>
+ *
+ * @param event the mouse down event
+ *
+ * @return <code>true</code> if the gesture occurred, and <code>false</code> otherwise.
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT when the event is null</li>
+ * </ul>
+ * @exception SWTException <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 DragDetectListener
+ * @see #addDragDetectListener
+ *
+ * @see #getDragDetect
+ * @see #setDragDetect
+ *
+ * @since 3.3
+ */
+public boolean dragDetect (Event event) {
+ checkWidget ();
+ if (event == null) error (SWT.ERROR_NULL_ARGUMENT);
+ return dragDetect (event.button, event.count, event.stateMask, event.x, event.y);
+}
+
+/**
+ * Detects a drag and drop gesture. This method is used
+ * to detect a drag gesture when called from within a mouse
+ * down listener.
+ *
+ * <p>By default, a drag is detected when the gesture
+ * occurs anywhere within the client area of a control.
+ * Some controls, such as tables and trees, override this
+ * behavior. In addition to the operating system specific
+ * drag gesture, they require the mouse to be inside an
+ * item. Custom widget writers can use <code>setDragDetect</code>
+ * to disable the default detection, listen for mouse down,
+ * and then call <code>dragDetect()</code> from within the
+ * listener to conditionally detect a drag.
+ * </p>
+ *
+ * @param event the mouse down event
+ *
+ * @return <code>true</code> if the gesture occurred, and <code>false</code> otherwise.
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT when the event is null</li>
+ * </ul>
+ * @exception SWTException <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 DragDetectListener
+ * @see #addDragDetectListener
+ *
+ * @see #getDragDetect
+ * @see #setDragDetect
+ *
+ * @since 3.3
+ */
+public boolean dragDetect (MouseEvent event) {
+ checkWidget ();
+ if (event == null) error (SWT.ERROR_NULL_ARGUMENT);
+ return dragDetect (event.button, event.count, event.stateMask, event.x, event.y);
+}
+
+boolean dragDetect (int button, int count, int stateMask, int x, int y) {
+ if (button != 1 || count != 1) return false;
+ if (!dragDetect (x, y, false, null)) return false;
+ return sendDragEvent (button, stateMask, x, y);
+}
+
+boolean dragDetect (int x, int y, boolean filter, boolean [] consume) {
+ /**
+ * Feature in Cocoa. Mouse drag events do not account for hysteresis.
+ * As soon as the mouse drags a mouse dragged event is fired. Fix is to
+ * check for another mouse drag event that is at least 5 pixels away
+ * from the start of the drag.
+ */
+ NSApplication application = NSApplication.sharedApplication();
+ boolean dragging = false;
+ int /*long*/ eventType = OS.NSLeftMouseDown;
+ float /*double*/ dragX = x;
+ float /*double*/ dragY = y;
+
+ /**
+ * To check for an actual drag we need to pull off mouse moved and mouse up events
+ * to detect if the user dragged outside of a 10 x 10 box centered on the mouse down location.
+ * We still want the view to see the events, so save them and re-post when done checking.
+ */
+ NSEvent mouseUpEvent = null;
+ NSMutableArray dragEvents = NSMutableArray.arrayWithCapacity(10);
+
+ while (eventType != OS.NSLeftMouseUp) {
+ NSEvent event = application.nextEventMatchingMask((OS.NSLeftMouseUpMask | OS.NSLeftMouseDraggedMask),
+ NSDate.distantFuture(), OS.NSEventTrackingRunLoopMode, true);
+ eventType = event.type();
+
+ if (eventType == OS.NSLeftMouseDragged) {
+ dragEvents.addObject(event);
+ NSPoint windowLoc = event.locationInWindow();
+ NSPoint viewLoc = view.convertPoint_fromView_(windowLoc, null);
+ if (!view.isFlipped ()) {
+ viewLoc.y = view.bounds().height - viewLoc.y;
+ }
+ if ((Math.abs(viewLoc.x - dragX) > DEFAULT_DRAG_HYSTERESIS) || (Math.abs(viewLoc.y - dragY) > DEFAULT_DRAG_HYSTERESIS)) {
+ dragging = true;
+ break;
+ }
+ } else if (eventType == OS.NSLeftMouseUp) {
+ mouseUpEvent = event;
+ }
+ }
+
+ // Push back any events we took out of the queue so the control can receive them.
+ if (mouseUpEvent != null) application.postEvent(mouseUpEvent, true);
+
+ if (dragEvents.count() > 0) {
+ while (dragEvents.count() > 0) {
+ NSEvent currEvent = new NSEvent(dragEvents.objectAtIndex(dragEvents.count() - 1).id);
+ dragEvents.removeLastObject();
+ application.postEvent(currEvent, true);
+ }
+ }
+
+ return dragging;
+}
+
+boolean drawGripper (int x, int y, int width, int height, boolean vertical) {
+ return false;
+}
+
+void drawWidget (int /*long*/ id, NSGraphicsContext context, NSRect rect) {
+ if (id != paintView().id) return;
+ if (!hooks (SWT.Paint) && !filters (SWT.Paint)) return;
+
+ /* Send paint event */
+ GCData data = new GCData ();
+ data.paintRect = rect;
+ GC gc = GC.cocoa_new (this, data);
+ Event event = new Event ();
+ event.gc = gc;
+ event.x = (int)rect.x;
+ event.y = (int)rect.y;
+ event.width = (int)rect.width;
+ event.height = (int)rect.height;
+ sendEvent (SWT.Paint, event);
+ event.gc = null;
+ gc.dispose ();
+}
+
+void enableWidget (boolean enabled) {
+ if (view instanceof NSControl) {
+ ((NSControl)view).setEnabled(enabled);
+ }
+ updateCursorRects (isEnabled ());
+}
+
+boolean equals(float /*double*/ [] color1, float /*double*/ [] color2) {
+ if (color1 == color2) return true;
+ if (color1 == null) return color2 == null;
+ if (color2 == null) return color1 == null;
+ for (int i = 0; i < color1.length; i++) {
+ if (color1 [i] != color2 [i]) return false;
+ }
+ return true;
+}
+
+NSView eventView () {
+ return view;
+}
+
+void fillBackground (NSView view, NSGraphicsContext context, NSRect rect, int imgHeight) {
+ Control control = findBackgroundControl();
+ if (control == null) control = this;
+ Image image = control.backgroundImage;
+ if (image != null && !image.isDisposed()) {
+ context.saveGraphicsState();
+ NSColor.colorWithPatternImage(image.handle).setFill();
+ NSPoint phase = new NSPoint();
+ NSView controlView = control.view;
+ if (imgHeight == -1) {
+ NSView contentView = controlView.window().contentView();
+ phase = controlView.convertPoint_toView_(phase, contentView);
+ phase.y = contentView.bounds().height - phase.y;
+ } else {
+ phase = view.convertPoint_toView_(phase, controlView);
+ phase.y += imgHeight - backgroundImage.getBounds().height;
+ }
+ context.setPatternPhase(phase);
+ NSBezierPath.fillRect(rect);
+ context.restoreGraphicsState();
+ return;
+ }
+
+ float /*double*/ [] background = control.background;
+ float /*double*/ alpha;
+ if (background == null) {
+ background = control.defaultBackground ().handle;
+ alpha = getThemeAlpha ();
+ } else {
+ alpha = background[3];
+ }
+ context.saveGraphicsState ();
+ NSColor.colorWithDeviceRed (background [0], background [1], background [2], alpha).setFill ();
+ NSBezierPath.fillRect (rect);
+ context.restoreGraphicsState ();
+}
+
+Cursor findCursor () {
+ if (cursor != null) return cursor;
+ return parent.findCursor ();
+}
+
+Control findBackgroundControl () {
+ if (backgroundImage != null || background != null) return this;
+ return (state & PARENT_BACKGROUND) != 0 ? parent.findBackgroundControl () : null;
+}
+
+Menu [] findMenus (Control control) {
+ if (menu != null && this != control) return new Menu [] {menu};
+ return new Menu [0];
+}
+
+Widget findTooltip (NSPoint pt) {
+ return this;
+}
+
+void fixChildren (Shell newShell, Shell oldShell, Decorations newDecorations, Decorations oldDecorations, Menu [] menus) {
+ oldShell.fixShell (newShell, this);
+ oldDecorations.fixDecorations (newDecorations, this, menus);
+}
+
+void fixFocus (Control focusControl) {
+ Shell shell = getShell ();
+ Control control = this;
+ while (control != shell && (control = control.parent) != null) {
+ if (control.setFocus ()) return;
+ }
+ shell.setSavedFocus (focusControl);
+// int window = OS.GetControlOwner (handle);
+// OS.ClearKeyboardFocus (window);
+}
+
+void flagsChanged (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (view.window ().firstResponder ().id == id) {
+ if ((state & SAFARI_EVENTS_FIX) == 0) {
+ Shell s = this.getShell();
+ s.keyInputHappened = false;
+ int mask = 0;
+ NSEvent nsEvent = new NSEvent (theEvent);
+ int /*long*/ modifiers = nsEvent.modifierFlags ();
+ int keyCode = Display.translateKey (nsEvent.keyCode ());
+ switch (keyCode) {
+ case SWT.ALT: mask = OS.NSAlternateKeyMask; break;
+ case SWT.CONTROL: mask = OS.NSControlKeyMask; break;
+ case SWT.COMMAND: mask = OS.NSCommandKeyMask; break;
+ case SWT.SHIFT: mask = OS.NSShiftKeyMask; break;
+ case SWT.CAPS_LOCK:
+ Event event = new Event();
+ event.keyCode = keyCode;
+ setInputState (event, nsEvent, SWT.KeyDown);
+ sendKeyEvent (SWT.KeyDown, event);
+ setInputState (event, nsEvent, SWT.KeyUp);
+ sendKeyEvent (SWT.KeyUp, event);
+ break;
+ }
+ if (mask != 0) {
+ s.keyInputHappened = true;
+ int type = (mask & modifiers) != 0 ? SWT.KeyDown : SWT.KeyUp;
+ if (type == SWT.KeyDown) s.keyInputHappened = true;
+ Event event = new Event();
+ event.keyCode = keyCode;
+ setInputState (event, nsEvent, type);
+ if (!sendKeyEvent (type, event)) return;
+ }
+ }
+ }
+ super.flagsChanged (id, sel, theEvent);
+}
+
+NSView focusView () {
+ return view;
+}
+
+/**
+ * Forces the receiver to have the <em>keyboard focus</em>, causing
+ * all keyboard events to be delivered to it.
+ *
+ * @return <code>true</code> if the control got focus, and <code>false</code> if it was unable to.
+ *
+ * @exception SWTException <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 #setFocus
+ */
+public boolean forceFocus () {
+ checkWidget();
+ if (display.focusEvent == SWT.FocusOut) return false;
+ Decorations shell = menuShell ();
+ shell.setSavedFocus (this);
+ if (!isEnabled () || !isVisible () || !isActive ()) return false;
+ if (isFocusControl ()) return true;
+ shell.setSavedFocus (null);
+ NSView focusView = focusView ();
+ if (!focusView.canBecomeKeyView()) return false;
+ boolean result = view.window ().makeFirstResponder (focusView);
+ if (isDisposed ()) return false;
+ shell.bringToTop (false);
+ if (isDisposed ()) return false;
+ shell.setSavedFocus (this);
+ return result;
+}
+
+/**
+ * Returns the accessible object for the receiver.
+ * If this is the first time this object is requested,
+ * then the object is created and returned.
+ *
+ * @return the accessible object
+ *
+ * @exception SWTException <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 Accessible#addAccessibleListener
+ * @see Accessible#addAccessibleControlListener
+ *
+ * @since 2.0
+ */
+public Accessible getAccessible () {
+ checkWidget ();
+ if (accessible == null) accessible = new_Accessible (this);
+ return accessible;
+}
+
+/**
+ * Returns the receiver's background color.
+ * <p>
+ * Note: This operation is a hint and may be overridden by the platform.
+ * For example, on some versions of Windows the background of a TabFolder,
+ * is a gradient rather than a solid color.
+ * </p>
+ * @return the background color
+ *
+ * @exception SWTException <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 Color getBackground () {
+ checkWidget();
+ Control control = findBackgroundControl ();
+ if (control == null) control = this;
+ return control.getBackgroundColor ();
+}
+
+Color getBackgroundColor () {
+ return background != null ? Color.cocoa_new (display, background) : defaultBackground ();
+}
+
+/**
+ * Returns the receiver's background image.
+ *
+ * @return the background image
+ *
+ * @exception SWTException <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 Image getBackgroundImage () {
+ checkWidget();
+ Control control = findBackgroundControl ();
+ if (control == null) control = this;
+ return control.backgroundImage;
+}
+
+/**
+ * Returns the receiver's border width.
+ *
+ * @return the border width
+ *
+ * @exception SWTException <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 getBorderWidth () {
+ checkWidget();
+ return 0;
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location
+ * relative to its parent (or its display if its parent is null),
+ * unless the receiver is a shell. In this case, the location is
+ * relative to the display.
+ *
+ * @return the receiver's bounding rectangle
+ *
+ * @exception SWTException <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 Rectangle getBounds () {
+ checkWidget();
+ NSRect rect = topView().frame();
+ return new Rectangle((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
+}
+
+/**
+ * Returns <code>true</code> if the receiver is detecting
+ * drag gestures, and <code>false</code> otherwise.
+ *
+ * @return the receiver's drag detect state
+ *
+ * @exception SWTException <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.3
+ */
+public boolean getDragDetect () {
+ checkWidget ();
+ return (state & DRAG_DETECT) != 0;
+}
+
+boolean getDrawing () {
+ return drawCount <= 0;
+}
+
+/**
+ * Returns the receiver's cursor, or null if it has not been set.
+ * <p>
+ * When the mouse pointer passes over a control its appearance
+ * is changed to match the control's cursor.
+ * </p>
+ *
+ * @return the receiver's cursor or <code>null</code>
+ *
+ * @exception SWTException <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.3
+ */
+public Cursor getCursor () {
+ checkWidget();
+ return cursor;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is enabled, and
+ * <code>false</code> otherwise. A disabled control is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException <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 #isEnabled
+ */
+public boolean getEnabled () {
+ checkWidget();
+ return (state & DISABLED) == 0;
+}
+
+/**
+ * Returns the font that the receiver will use to paint textual information.
+ *
+ * @return the receiver's font
+ *
+ * @exception SWTException <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 Font getFont () {
+ checkWidget();
+ return font != null ? font : defaultFont ();
+}
+
+/**
+ * Returns the foreground color that the receiver will use to draw.
+ *
+ * @return the receiver's foreground color
+ *
+ * @exception SWTException <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 Color getForeground () {
+ checkWidget();
+ return getForegroundColor ();
+}
+
+Color getForegroundColor () {
+ return foreground != null ? Color.cocoa_new (display, foreground) : defaultForeground ();
+}
+
+/**
+ * Returns layout data which is associated with the receiver.
+ *
+ * @return the receiver's layout data
+ *
+ * @exception SWTException <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 Object getLayoutData () {
+ checkWidget();
+ return layoutData;
+}
+
+/**
+ * Returns a point describing the receiver's location relative
+ * to its parent (or its display if its parent is null), unless
+ * the receiver is a shell. In this case, the point is
+ * relative to the display.
+ *
+ * @return the receiver's location
+ *
+ * @exception SWTException <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 Point getLocation () {
+ checkWidget();
+ NSRect rect = topView().frame();
+ return new Point((int)rect.x, (int)rect.y);
+}
+
+/**
+ * Returns the receiver's pop up menu if it has one, or null
+ * if it does not. All controls may optionally have a pop up
+ * menu that is displayed when the user requests one for
+ * the control. The sequence of key strokes, button presses
+ * and/or button releases that are used to request a pop up
+ * menu is platform specific.
+ *
+ * @return the receiver's menu
+ *
+ * @exception SWTException <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 Menu getMenu () {
+ checkWidget();
+ return menu;
+}
+
+int getMininumHeight () {
+ return 0;
+}
+
+/**
+ * Returns the receiver's monitor.
+ *
+ * @return the receiver's monitor
+ *
+ * @since 3.0
+ */
+public Monitor getMonitor () {
+ checkWidget();
+ Monitor [] monitors = display.getMonitors ();
+ if (monitors.length == 1) return monitors [0];
+ int index = -1, value = -1;
+ Rectangle bounds = getBounds ();
+ if (this != getShell ()) {
+ bounds = display.map (this.parent, null, bounds);
+ }
+ for (int i=0; i<monitors.length; i++) {
+ Rectangle rect = bounds.intersection (monitors [i].getBounds ());
+ int area = rect.width * rect.height;
+ if (area > 0 && area > value) {
+ index = i;
+ value = area;
+ }
+ }
+ if (index >= 0) return monitors [index];
+ int centerX = bounds.x + bounds.width / 2, centerY = bounds.y + bounds.height / 2;
+ for (int i=0; i<monitors.length; i++) {
+ Rectangle rect = monitors [i].getBounds ();
+ int x = centerX < rect.x ? rect.x - centerX : centerX > rect.x + rect.width ? centerX - rect.x - rect.width : 0;
+ int y = centerY < rect.y ? rect.y - centerY : centerY > rect.y + rect.height ? centerY - rect.y - rect.height : 0;
+ int distance = x * x + y * y;
+ if (index == -1 || distance < value) {
+ index = i;
+ value = distance;
+ }
+ }
+ return monitors [index];
+}
+
+/**
+ * Returns the receiver's parent, which must be a <code>Composite</code>
+ * or null when the receiver is a shell that was created with null or
+ * a display for a parent.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException <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 Composite getParent () {
+ checkWidget();
+ return parent;
+}
+
+Control [] getPath () {
+ int count = 0;
+ Shell shell = getShell ();
+ Control control = this;
+ while (control != shell) {
+ count++;
+ control = control.parent;
+ }
+ control = this;
+ Control [] result = new Control [count];
+ while (control != shell) {
+ result [--count] = control;
+ control = control.parent;
+ }
+ return result;
+}
+
+NSBezierPath getPath(Region region) {
+ if (region == null) return null;
+ return getPath(region.handle);
+}
+
+NSBezierPath getPath(int /*long*/ region) {
+ Callback callback = new Callback(this, "regionToRects", 4);
+ if (callback.getAddress() == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
+ NSBezierPath path = NSBezierPath.bezierPath();
+ path.retain();
+ OS.QDRegionToRects(region, OS.kQDParseRegionFromTopLeft, callback.getAddress(), path.id);
+ callback.dispose();
+ if (path.isEmpty()) path.appendBezierPathWithRect(new NSRect());
+ return path;
+}
+
+/**
+ * Returns the region that defines the shape of the control,
+ * or null if the control has the default shape.
+ *
+ * @return the region that defines the shape of the shell (or null)
+ *
+ * @exception SWTException <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.4
+ */
+public Region getRegion () {
+ checkWidget ();
+ return region;
+}
+
+/**
+ * Returns the receiver's shell. For all controls other than
+ * shells, this simply returns the control's nearest ancestor
+ * shell. Shells return themselves, even if they are children
+ * of other shells.
+ *
+ * @return the receiver's shell
+ *
+ * @exception SWTException <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 #getParent
+ */
+public Shell getShell () {
+ checkWidget();
+ return parent.getShell ();
+}
+
+/**
+ * Returns a point describing the receiver's size. The
+ * x coordinate of the result is the width of the receiver.
+ * The y coordinate of the result is the height of the
+ * receiver.
+ *
+ * @return the receiver's size
+ *
+ * @exception SWTException <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 Point getSize () {
+ checkWidget();
+ NSRect rect = topView().frame();
+ return new Point((int)rect.width, (int)rect.height);
+}
+
+float getThemeAlpha () {
+ return 1 * parent.getThemeAlpha ();
+}
+
+/**
+ * Returns the receiver's tool tip text, or null if it has
+ * not been set.
+ *
+ * @return the receiver's tool tip text
+ *
+ * @exception SWTException <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 String getToolTipText () {
+ checkWidget();
+ return toolTipText;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is visible, and
+ * <code>false</code> otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ * </p>
+ *
+ * @return the receiver's visibility state
+ *
+ * @exception SWTException <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 boolean getVisible () {
+ checkWidget();
+ return (state & HIDDEN) == 0;
+}
+
+int /*long*/ getVisibleRegion () {
+ if (visibleRgn == 0) {
+ visibleRgn = OS.NewRgn ();
+ calculateVisibleRegion (view, visibleRgn, true);
+ }
+ int /*long*/ result = OS.NewRgn ();
+ OS.CopyRgn (visibleRgn, result);
+ return result;
+}
+
+boolean hasBorder () {
+ return (style & SWT.BORDER) != 0;
+}
+
+boolean hasFocus () {
+ return display.getFocusControl() == this;
+}
+
+int /*long*/ hitTest (int /*long*/ id, int /*long*/ sel, NSPoint point) {
+ if ((state & DISABLED) != 0) return 0;
+ if (!isActive ()) return 0;
+ if (regionPath != null) {
+ NSView superview = new NSView(id).superview();
+ if (superview != null) {
+ NSPoint pt = superview.convertPoint_toView_(point, view);
+ if (!view.isFlipped ()) {
+ pt.y = view.bounds().height - pt.y;
+ }
+ if (!regionPath.containsPoint(pt)) return 0;
+ }
+ }
+ return super.hitTest(id, sel, point);
+}
+
+boolean imeInComposition () {
+ return false;
+}
+
+boolean insertText (int /*long*/ id, int /*long*/ sel, int /*long*/ string) {
+ if (view.window ().firstResponder ().id == id) {
+ Shell s = this.getShell();
+ NSEvent nsEvent = NSApplication.sharedApplication ().currentEvent ();
+ if (nsEvent != null) {
+ int /*long*/ type = nsEvent.type ();
+ if ((!s.keyInputHappened && type == OS.NSKeyDown) || type == OS.NSSystemDefined) {
+ NSString str = new NSString (string);
+ if (str.isKindOfClass (OS.objc_getClass ("NSAttributedString"))) {
+ str = new NSAttributedString (string).string ();
+ }
+ int length = (int)/*64*/str.length ();
+ char[] buffer = new char [length];
+ str.getCharacters(buffer);
+ for (int i = 0; i < buffer.length; i++) {
+ s.keyInputHappened = true;
+ Event event = new Event ();
+ if (i == 0 && type == OS.NSKeyDown) setKeyState (event, SWT.KeyDown, nsEvent);
+ event.character = buffer [i];
+ if (!sendKeyEvent (SWT.KeyDown, event)) return false;
+ }
+ }
+ }
+ if ((state & CANVAS) != 0) return true;
+ }
+ return super.insertText (id, sel, string);
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Control</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param data the platform specific GC data
+ * @return the platform specific GC handle
+ */
+public int /*long*/ internal_new_GC (GCData data) {
+ checkWidget();
+ NSView view = paintView();
+ int /*long*/ context = 0;
+ if (data != null && data.paintRect != null) {
+ NSGraphicsContext graphicsContext = NSGraphicsContext.currentContext();
+ context = graphicsContext.id;
+ if (!view.isFlipped()) data.state &= ~VISIBLE_REGION;
+ } else {
+ NSGraphicsContext graphicsContext = NSGraphicsContext.graphicsContextWithWindow (view.window ());
+ NSGraphicsContext flippedContext = NSGraphicsContext.graphicsContextWithGraphicsPort(graphicsContext.graphicsPort(), true);
+ graphicsContext = flippedContext;
+ context = graphicsContext.id;
+ if (data != null) {
+ data.flippedContext = flippedContext;
+ data.state &= ~VISIBLE_REGION;
+ data.visibleRgn = getVisibleRegion();
+ display.addContext (data);
+ }
+ }
+ if (data != null) {
+ int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
+ if ((data.style & mask) == 0) {
+ data.style |= style & (mask | SWT.MIRRORED);
+ }
+ data.device = display;
+ data.thread = display.thread;
+ data.view = view;
+ data.foreground = getForegroundColor ().handle;
+ Control control = findBackgroundControl ();
+ if (control == null) control = this;
+ data.background = control.getBackgroundColor ().handle;
+ data.font = font != null ? font : defaultFont ();
+ }
+ return context;
+}
+
+/**
+ * Invokes platform specific functionality to dispose a GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Control</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param hDC the platform specific GC handle
+ * @param data the platform specific GC data
+ */
+public void internal_dispose_GC (int /*long*/ context, GCData data) {
+ checkWidget ();
+ NSGraphicsContext graphicsContext = new NSGraphicsContext (context);
+ display.removeContext (data);
+ if (data != null) {
+ if (data.paintRect == null) graphicsContext.flushGraphics ();
+ if (data.visibleRgn != 0) OS.DisposeRgn(data.visibleRgn);
+ data.visibleRgn = 0;
+ }
+}
+
+void invalidateChildrenVisibleRegion () {
+}
+
+void invalidateVisibleRegion () {
+ int index = 0;
+ Control[] siblings = parent._getChildren ();
+ while (index < siblings.length && siblings [index] != this) index++;
+ for (int i=index; i<siblings.length; i++) {
+ Control sibling = siblings [i];
+ sibling.resetVisibleRegion ();
+ sibling.invalidateChildrenVisibleRegion ();
+ }
+ parent.resetVisibleRegion ();
+}
+
+boolean isActive () {
+ return getShell().getModalShell() == null;
+}
+
+/*
+ * Answers a boolean indicating whether a Label that precedes the receiver in
+ * a layout should be read by screen readers as the recevier's label.
+ */
+boolean isDescribedByLabel () {
+ return true;
+}
+
+boolean isDrawing () {
+ return getDrawing() && parent.isDrawing();
+}
+
+/**
+ * Returns <code>true</code> if the receiver is enabled and all
+ * ancestors up to and including the receiver's nearest ancestor
+ * shell are enabled. Otherwise, <code>false</code> is returned.
+ * A disabled control is typically not selectable from the user
+ * interface and draws with an inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException <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 #getEnabled
+ */
+public boolean isEnabled () {
+ checkWidget();
+ return getEnabled () && parent.isEnabled ();
+}
+
+boolean isEnabledCursor () {
+ return isEnabled ();
+}
+
+boolean isFocusAncestor (Control control) {
+ while (control != null && control != this && !(control instanceof Shell)) {
+ control = control.parent;
+ }
+ return control == this;
+}
+
+/**
+ * Returns <code>true</code> if the receiver has the user-interface
+ * focus, and <code>false</code> otherwise.
+ *
+ * @return the receiver's focus state
+ *
+ * @exception SWTException <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 boolean isFocusControl () {
+ checkWidget();
+ Control focusControl = display.focusControl;
+ if (focusControl != null && !focusControl.isDisposed ()) {
+ return this == focusControl;
+ }
+ return hasFocus ();
+}
+
+boolean isObscured () {
+ int /*long*/ visibleRgn = getVisibleRegion(), boundsRgn = OS.NewRgn();
+ short[] rect = new short[4];
+ NSRect bounds = view.visibleRect();
+ OS.SetRect(rect, (short)bounds.x, (short)bounds.y, (short)(bounds.x + bounds.width), (short)(bounds.y + bounds.height));
+ OS.RectRgn(boundsRgn, rect);
+ OS.DiffRgn(boundsRgn, visibleRgn, boundsRgn);
+ boolean obscured = !OS.EmptyRgn (boundsRgn);
+ OS.DisposeRgn(boundsRgn);
+ OS.DisposeRgn(visibleRgn);
+ return obscured;
+}
+
+/**
+ * Returns <code>true</code> if the underlying operating
+ * system supports this reparenting, otherwise <code>false</code>
+ *
+ * @return <code>true</code> if the widget can be reparented, otherwise <code>false</code>
+ *
+ * @exception SWTException <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 boolean isReparentable () {
+ checkWidget();
+ return true;
+}
+
+boolean isShowing () {
+ /*
+ * This is not complete. Need to check if the
+ * widget is obscurred by a parent or sibling.
+ */
+ if (!isVisible ()) return false;
+ Control control = this;
+ while (control != null) {
+ Point size = control.getSize ();
+ if (size.x == 0 || size.y == 0) {
+ return false;
+ }
+ control = control.parent;
+ }
+ return true;
+}
+
+boolean isTabGroup () {
+ Control [] tabList = parent._getTabList ();
+ if (tabList != null) {
+ for (int i=0; i<tabList.length; i++) {
+ if (tabList [i] == this) return true;
+ }
+ }
+ int code = traversalCode (0, null);
+ if ((code & (SWT.TRAVERSE_ARROW_PREVIOUS | SWT.TRAVERSE_ARROW_NEXT)) != 0) return false;
+ return (code & (SWT.TRAVERSE_TAB_PREVIOUS | SWT.TRAVERSE_TAB_NEXT)) != 0;
+}
+
+boolean isTabItem () {
+ Control [] tabList = parent._getTabList ();
+ if (tabList != null) {
+ for (int i=0; i<tabList.length; i++) {
+ if (tabList [i] == this) return false;
+ }
+ }
+ int code = traversalCode (0, null);
+ return (code & (SWT.TRAVERSE_ARROW_PREVIOUS | SWT.TRAVERSE_ARROW_NEXT)) != 0;
+}
+
+boolean isTrim (NSView view) {
+ return false;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is visible and all
+ * ancestors up to and including the receiver's nearest ancestor
+ * shell are visible. Otherwise, <code>false</code> is returned.
+ *
+ * @return the receiver's visibility state
+ *
+ * @exception SWTException <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 #getVisible
+ */
+public boolean isVisible () {
+ checkWidget();
+ return getVisible () && parent.isVisible ();
+}
+
+void keyDown (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (view.window ().firstResponder ().id == id) {
+ Shell s = this.getShell();
+ s.keyInputHappened = false;
+ boolean textInput = OS.objc_msgSend (id, OS.sel_conformsToProtocol_, OS.objc_getProtocol ("NSTextInput")) != 0;
+ if (!textInput) {
+ // Not a text field, so send a key event here.
+ NSEvent nsEvent = new NSEvent (theEvent);
+ boolean [] consume = new boolean [1];
+ if (translateTraversal (nsEvent.keyCode (), nsEvent, consume)) return;
+ if (isDisposed ()) return;
+ if (!sendKeyEvent (nsEvent, SWT.KeyDown)) return;
+ if (consume [0]) return;
+ } else {
+ // Control is some kind of text field, so the key event will be sent from insertText: or doCommandBySelector:
+ super.keyDown (id, sel, theEvent);
+
+ if (imeInComposition ()) return;
+ // If none of those methods triggered a key event send one now.
+ if (!s.keyInputHappened) {
+ NSEvent nsEvent = new NSEvent (theEvent);
+ boolean [] consume = new boolean [1];
+ if (translateTraversal (nsEvent.keyCode (), nsEvent, consume)) return;
+ if (isDisposed ()) return;
+ if (!sendKeyEvent (nsEvent, SWT.KeyDown)) return;
+ if (consume [0]) return;
+ }
+
+ return;
+ }
+ }
+ super.keyDown (id, sel, theEvent);
+}
+
+void keyUp (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (view.window ().firstResponder ().id == id) {
+ NSEvent nsEvent = new NSEvent (theEvent);
+ if (!sendKeyEvent (nsEvent, SWT.KeyUp)) return;
+ }
+ super.keyUp (id, sel, theEvent);
+}
+
+void markLayout (boolean changed, boolean all) {
+ /* Do nothing */
+}
+
+int /*long*/ menuForEvent (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!isEnabled ()) return 0;
+
+ NSPoint pt = NSEvent.mouseLocation();
+ pt.y = (int) (display.getPrimaryFrame().height - pt.y);
+ int x = (int) pt.x;
+ int y = (int) pt.y;
+ Event event = new Event ();
+ event.x = x;
+ event.y = y;
+ sendEvent (SWT.MenuDetect, event);
+ //widget could be disposed at this point
+ if (isDisposed ()) return 0;
+ if (!event.doit) return 0;
+ Menu menu = getMenu ();
+ if (menu != null && !menu.isDisposed ()) {
+ if (x != event.x || y != event.y) {
+ menu.setLocation (event.x, event.y);
+ }
+ menu.setVisible(true);
+ return 0;
+ }
+ return super.menuForEvent (id, sel, theEvent);
+}
+
+Decorations menuShell () {
+ return parent.menuShell ();
+}
+
+void scrollWheel (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (id == view.id) {
+ if (hooks (SWT.MouseWheel) || filters (SWT.MouseWheel)) {
+ NSEvent nsEvent = new NSEvent(theEvent);
+ if (nsEvent.deltaY() != 0) {
+ if (!sendMouseEvent(nsEvent, SWT.MouseWheel, true)) {
+ return;
+ }
+ }
+ }
+ }
+ super.scrollWheel(id, sel, theEvent);
+}
+
+boolean isEventView (int /*long*/ id) {
+ return true;
+}
+
+boolean mouseEvent (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent, int type) {
+ if (!display.sendEvent) return true;
+ display.sendEvent = false;
+ if (!isEventView (id)) return true;
+ boolean dragging = false;
+ boolean[] consume = null;
+ NSEvent nsEvent = new NSEvent(theEvent);
+ int nsType = (int)/*64*/nsEvent.type();
+ NSInputManager manager = NSInputManager.currentInputManager ();
+ if (manager != null && manager.wantsToHandleMouseEvents ()) {
+ if (manager.handleMouseEvent (nsEvent)) {
+ return true;
+ }
+ }
+ switch (nsType) {
+ case OS.NSLeftMouseDown:
+ if (nsEvent.clickCount() == 1 && (state & DRAG_DETECT) != 0 && hooks (SWT.DragDetect)) {
+ consume = new boolean[1];
+ NSPoint location = view.convertPoint_fromView_(nsEvent.locationInWindow(), null);
+ if (!view.isFlipped ()) {
+ location.y = view.bounds().height - location.y;
+ }
+ dragging = dragDetect((int)location.x, (int)location.y, false, consume);
+ }
+ break;
+ case OS.NSLeftMouseDragged:
+ case OS.NSRightMouseDragged:
+ case OS.NSOtherMouseDragged:
+ display.checkEnterExit (this, nsEvent, false);
+ break;
+ case OS.NSLeftMouseUp:
+ case OS.NSRightMouseUp:
+ case OS.NSOtherMouseUp:
+ display.checkEnterExit (display.findControl(true), nsEvent, false);
+ break;
+ }
+ sendMouseEvent (nsEvent, type, false);
+ if (type == SWT.MouseDown && nsEvent.clickCount() == 2) {
+ sendMouseEvent (nsEvent, SWT.MouseDoubleClick, false);
+ }
+ if (dragging) sendMouseEvent(nsEvent, SWT.DragDetect, false);
+ if (consume != null && consume[0]) return false;
+ return true;
+}
+
+void mouseDown(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!mouseEvent(id, sel, theEvent, SWT.MouseDown)) return;
+ boolean tracking = isEventView (id);
+ Display display = this.display;
+ if (tracking) display.trackingControl = this;
+ super.mouseDown(id, sel, theEvent);
+ if (tracking) display.trackingControl = null;
+}
+
+void mouseUp(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!mouseEvent(id, sel, theEvent, SWT.MouseUp)) return;
+ super.mouseUp(id, sel, theEvent);
+}
+
+void mouseDragged(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!mouseEvent(id, sel, theEvent, SWT.MouseMove)) return;
+ super.mouseDragged(id, sel, theEvent);
+}
+
+void rightMouseDown(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!mouseEvent(id, sel, theEvent, SWT.MouseDown)) return;
+ super.rightMouseDown(id, sel, theEvent);
+}
+
+void rightMouseUp(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!mouseEvent(id, sel, theEvent, SWT.MouseUp)) return;
+ super.rightMouseUp(id, sel, theEvent);
+}
+
+void rightMouseDragged(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!mouseEvent(id, sel, theEvent, SWT.MouseMove)) return;
+ super.rightMouseDragged(id, sel, theEvent);
+}
+
+void otherMouseDown(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!mouseEvent(id, sel, theEvent, SWT.MouseDown)) return;
+ super.otherMouseDown(id, sel, theEvent);
+}
+
+void otherMouseUp(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!mouseEvent(id, sel, theEvent, SWT.MouseUp)) return;
+ super.otherMouseUp(id, sel, theEvent);
+}
+
+void otherMouseDragged(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!mouseEvent(id, sel, theEvent, SWT.MouseMove)) return;
+ super.otherMouseDragged(id, sel, theEvent);
+}
+
+void moved () {
+ sendEvent (SWT.Move);
+}
+
+/**
+ * Moves the receiver above the specified control in the
+ * drawing order. If the argument is null, then the receiver
+ * is moved to the top of the drawing order. The control at
+ * the top of the drawing order will not be covered by other
+ * controls even if they occupy intersecting areas.
+ *
+ * @param control the sibling control (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the control has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 Control#moveBelow
+ * @see Composite#getChildren
+ */
+public void moveAbove (Control control) {
+ checkWidget();
+ if (control != null) {
+ if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (parent != control.parent) return;
+ }
+ setZOrder (control, true);
+}
+
+/**
+ * Moves the receiver below the specified control in the
+ * drawing order. If the argument is null, then the receiver
+ * is moved to the bottom of the drawing order. The control at
+ * the bottom of the drawing order will be covered by all other
+ * controls which occupy intersecting areas.
+ *
+ * @param control the sibling control (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the control has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 Control#moveAbove
+ * @see Composite#getChildren
+ */
+public void moveBelow (Control control) {
+ checkWidget();
+ if (control != null) {
+ if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (parent != control.parent) return;
+ }
+ setZOrder (control, false);
+}
+
+Accessible new_Accessible (Control control) {
+ return Accessible.internal_new_Accessible (this);
+}
+
+/**
+ * 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 SWTException <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 #computeSize(int, int, boolean)
+ */
+public void pack () {
+ checkWidget();
+ pack (true);
+}
+
+/**
+ * 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.
+ * <p>
+ * If the changed flag is <code>true</code>, it indicates that the receiver's
+ * <em>contents</em> have changed, therefore any caches that a layout manager
+ * containing the control may have been keeping need to be flushed. When the
+ * control is resized, the changed flag will be <code>false</code>, so layout
+ * manager caches can be retained.
+ * </p>
+ *
+ * @param changed whether or not the receiver's contents have changed
+ *
+ * @exception SWTException <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 #computeSize(int, int, boolean)
+ */
+public void pack (boolean changed) {
+ checkWidget();
+ setSize (computeSize (SWT.DEFAULT, SWT.DEFAULT, changed));
+}
+
+NSView paintView () {
+ return eventView ();
+}
+
+/**
+ * Prints the receiver and all children.
+ *
+ * @param gc the gc where the drawing occurs
+ * @return <code>true</code> if the operation was successful and <code>false</code> otherwise
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the gc is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the gc has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.4
+ */
+public boolean print (GC gc) {
+ checkWidget ();
+ if (gc == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (gc.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+
+ gc.handle.saveGraphicsState();
+ NSGraphicsContext.setCurrentContext(gc.handle);
+ NSAffineTransform transform = NSAffineTransform.transform ();
+ transform.translateXBy (0, view.bounds().height);
+ transform.scaleXBy (1, -1);
+ transform.concat ();
+ view.displayRectIgnoringOpacity(view.bounds(), gc.handle);
+ gc.handle.restoreGraphicsState();
+ return true;
+}
+
+/**
+ * Causes the entire bounds of the receiver to be marked
+ * as needing to be redrawn. The next time a paint request
+ * is processed, the control will be completely painted,
+ * including the background.
+ *
+ * @exception SWTException <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 #update()
+ * @see PaintListener
+ * @see SWT#Paint
+ * @see SWT#NO_BACKGROUND
+ * @see SWT#NO_REDRAW_RESIZE
+ * @see SWT#NO_MERGE_PAINTS
+ * @see SWT#DOUBLE_BUFFERED
+ */
+public void redraw () {
+ checkWidget();
+ view.setNeedsDisplay(true);
+}
+
+void redraw (boolean children) {
+// checkWidget();
+ view.setNeedsDisplay(true);
+}
+
+/**
+ * Causes the rectangular area of the receiver specified by
+ * the arguments to be marked as needing to be redrawn.
+ * The next time a paint request is processed, that area of
+ * the receiver will be painted, including the background.
+ * If the <code>all</code> flag is <code>true</code>, any
+ * children of the receiver which intersect with the specified
+ * area will also paint their intersecting areas. If the
+ * <code>all</code> flag is <code>false</code>, the children
+ * will not be painted.
+ *
+ * @param x the x coordinate of the area to draw
+ * @param y the y coordinate of the area to draw
+ * @param width the width of the area to draw
+ * @param height the height of the area to draw
+ * @param all <code>true</code> if children should redraw, and <code>false</code> otherwise
+ *
+ * @exception SWTException <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 #update()
+ * @see PaintListener
+ * @see SWT#Paint
+ * @see SWT#NO_BACKGROUND
+ * @see SWT#NO_REDRAW_RESIZE
+ * @see SWT#NO_MERGE_PAINTS
+ * @see SWT#DOUBLE_BUFFERED
+ */
+public void redraw (int x, int y, int width, int height, boolean all) {
+ checkWidget ();
+ NSRect rect = new NSRect();
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ view.setNeedsDisplayInRect(rect);
+}
+
+int /*long*/ regionToRects(int /*long*/ message, int /*long*/ rgn, int /*long*/ r, int /*long*/ path) {
+ NSPoint pt = new NSPoint();
+ short[] rect = new short[4];
+ if (message == OS.kQDRegionToRectsMsgParse) {
+ OS.memmove(rect, r, rect.length * 2);
+ pt.x = rect[1];
+ pt.y = rect[0];
+ OS.objc_msgSend(path, OS.sel_moveToPoint_, pt);
+ pt.x = rect[3];
+ OS.objc_msgSend(path, OS.sel_lineToPoint_, pt);
+ pt.x = rect[3];
+ pt.y = rect[2];
+ OS.objc_msgSend(path, OS.sel_lineToPoint_, pt);
+ pt.x = rect[1];
+ OS.objc_msgSend(path, OS.sel_lineToPoint_, pt);
+ OS.objc_msgSend(path, OS.sel_closePath);
+ }
+ return 0;
+}
+
+void register () {
+ super.register ();
+ display.addWidget (view, this);
+}
+
+void release (boolean destroy) {
+ Control next = null, previous = null;
+ if (destroy && parent != null) {
+ Control[] children = parent._getChildren ();
+ int index = 0;
+ while (index < children.length) {
+ if (children [index] == this) break;
+ index++;
+ }
+ if (0 < index && (index + 1) < children.length) {
+ next = children [index + 1];
+ previous = children [index - 1];
+ }
+ }
+ super.release (destroy);
+ if (destroy) {
+ if (previous != null) previous.addRelation (next);
+ }
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (view != null) view.release();
+ view = null;
+ parent = null;
+}
+
+void releaseParent () {
+ invalidateVisibleRegion ();
+ parent.removeControl (this);
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ if (display.currentControl == this) {
+ display.currentControl = null;
+ display.timerExec(-1, display.hoverTimer);
+ }
+ if (display.trackingControl == this) display.trackingControl = null;
+ if (display.tooltipControl == this) display.tooltipControl = null;
+ if (menu != null && !menu.isDisposed ()) {
+ menu.dispose ();
+ }
+ menu = null;
+ if (visibleRgn != 0) OS.DisposeRgn (visibleRgn);
+ visibleRgn = 0;
+ layoutData = null;
+ if (accessible != null) {
+ accessible.internal_dispose_Accessible ();
+ }
+ accessible = null;
+ region = null;
+ if (regionPath != null) regionPath.release();
+ regionPath = 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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Move, listener);
+ eventTable.unhook (SWT.Resize, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when a drag gesture occurs.
+ *
+ * @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 SWTException <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 DragDetectListener
+ * @see #addDragDetectListener
+ *
+ * @since 3.3
+ */
+public void removeDragDetectListener(DragDetectListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.DragDetect, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the control gains or loses focus.
+ *
+ * @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 SWTException <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 FocusListener
+ * @see #addFocusListener
+ */
+public void removeFocusListener(FocusListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook(SWT.FocusIn, listener);
+ eventTable.unhook(SWT.FocusOut, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the help events are generated for the control.
+ *
+ * @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 SWTException <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 HelpListener
+ * @see #addHelpListener
+ */
+public void removeHelpListener (HelpListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Help, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when keys are pressed and released on the system keyboard.
+ *
+ * @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 SWTException <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 KeyListener
+ * @see #addKeyListener
+ */
+public void removeKeyListener(KeyListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook(SWT.KeyUp, listener);
+ eventTable.unhook(SWT.KeyDown, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the platform-specific context menu trigger has
+ * occurred.
+ *
+ * @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 SWTException <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 MenuDetectListener
+ * @see #addMenuDetectListener
+ *
+ * @since 3.3
+ */
+public void removeMenuDetectListener (MenuDetectListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.MenuDetect, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when mouse buttons are pressed and released.
+ *
+ * @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 SWTException <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 MouseListener
+ * @see #addMouseListener
+ */
+public void removeMouseListener(MouseListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook(SWT.MouseDown, listener);
+ eventTable.unhook(SWT.MouseUp, listener);
+ eventTable.unhook(SWT.MouseDoubleClick, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the mouse moves.
+ *
+ * @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 SWTException <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 MouseMoveListener
+ * @see #addMouseMoveListener
+ */
+public void removeMouseMoveListener(MouseMoveListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook(SWT.MouseMove, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the mouse passes or hovers over controls.
+ *
+ * @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 SWTException <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 MouseTrackListener
+ * @see #addMouseTrackListener
+ */
+public void removeMouseTrackListener(MouseTrackListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.MouseEnter, listener);
+ eventTable.unhook (SWT.MouseExit, listener);
+ eventTable.unhook (SWT.MouseHover, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the mouse wheel is scrolled.
+ *
+ * @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 SWTException <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 MouseWheelListener
+ * @see #addMouseWheelListener
+ *
+ * @since 3.3
+ */
+public void removeMouseWheelListener (MouseWheelListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.MouseWheel, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the receiver needs to be painted.
+ *
+ * @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 SWTException <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 PaintListener
+ * @see #addPaintListener
+ */
+public void removePaintListener(PaintListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook(SWT.Paint, listener);
+}
+
+/*
+ * Remove "Labeled by" relations from the receiver.
+ */
+void removeRelation () {
+ if (!isDescribedByLabel()) return;
+ NSObject accessibleElement = focusView();
+
+ if (accessibleElement instanceof NSControl) {
+ NSControl viewAsControl = (NSControl) accessibleElement;
+ if (viewAsControl.cell() != null) accessibleElement = viewAsControl.cell();
+ }
+
+ accessibleElement.accessibilitySetOverrideValue(accessibleElement, OS.NSAccessibilityTitleUIElementAttribute);
+}
+
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when traversal events occur.
+ *
+ * @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 SWTException <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 TraverseListener
+ * @see #addTraverseListener
+ */
+public void removeTraverseListener(TraverseListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Traverse, listener);
+}
+
+void resetVisibleRegion () {
+ if (visibleRgn != 0) {
+ OS.DisposeRgn (visibleRgn);
+ visibleRgn = 0;
+ }
+ GCData[] gcs = display.contexts;
+ if (gcs != null) {
+ int /*long*/ visibleRgn = 0;
+ for (int i=0; i<gcs.length; i++) {
+ GCData data = gcs [i];
+ if (data != null) {
+ if (data.view == view) {
+ if (visibleRgn == 0) visibleRgn = getVisibleRegion ();
+ data.state &= ~VISIBLE_REGION;
+ OS.CopyRgn (visibleRgn, data.visibleRgn);
+ }
+ }
+ }
+ if (visibleRgn != 0) OS.DisposeRgn (visibleRgn);
+ }
+}
+
+void resized () {
+ sendEvent (SWT.Resize);
+}
+
+boolean sendDragEvent (int button, int stateMask, int x, int y) {
+ Event event = new Event ();
+ event.button = button;
+ event.x = x;
+ event.y = y;
+ event.stateMask = stateMask;
+ postEvent (SWT.DragDetect, event);
+ return event.doit;
+}
+
+void sendFocusEvent (int type) {
+ Display display = this.display;
+ Shell shell = getShell ();
+
+ display.focusEvent = type;
+ display.focusControl = this;
+ sendEvent (type);
+ // widget could be disposed at this point
+ display.focusEvent = SWT.None;
+ display.focusControl = null;
+
+ /*
+ * It is possible that the shell may be
+ * disposed at this point. If this happens
+ * don't send the activate and deactivate
+ * events.
+ */
+ if (!shell.isDisposed ()) {
+ switch (type) {
+ case SWT.FocusIn:
+ shell.setActiveControl (this);
+ break;
+ case SWT.FocusOut:
+ if (shell != display.getActiveShell ()) {
+ shell.setActiveControl (null);
+ }
+ break;
+ }
+ }
+}
+
+boolean sendMouseEvent (NSEvent nsEvent, int type, boolean send) {
+ Shell shell = null;
+ Event event = new Event ();
+ switch (type) {
+ case SWT.MouseDown:
+ shell = getShell ();
+ //FALL THROUGH
+ case SWT.MouseUp:
+ case SWT.MouseDoubleClick:
+ case SWT.DragDetect:
+ int button = (int)/*64*/nsEvent.buttonNumber();
+ switch (button) {
+ case 0: event.button = 1; break;
+ case 1: event.button = 3; break;
+ case 2: event.button = 2; break;
+ case 3: event.button = 4; break;
+ case 4: event.button = 5; break;
+ }
+ break;
+ case SWT.MouseWheel:
+ event.detail = SWT.SCROLL_LINE;
+ float /*double*/ delta = nsEvent.deltaY();
+ event.count = delta > 0 ? Math.max (1, (int)delta) : Math.min (-1, (int)delta);
+ break;
+ }
+ if (event.button != 0) event.count = (int)/*64*/nsEvent.clickCount();
+ NSPoint windowPoint;
+ NSView view = eventView ();
+ if (nsEvent == null || nsEvent.type() == OS.NSMouseMoved) {
+ NSWindow window = view.window();
+ windowPoint = window.convertScreenToBase(NSEvent.mouseLocation());
+ } else {
+ windowPoint = nsEvent.locationInWindow();
+ }
+ NSPoint point = view.convertPoint_fromView_(windowPoint, null);
+ if (!view.isFlipped ()) {
+ point.y = view.bounds().height - point.y;
+ }
+ event.x = (int) point.x;
+ event.y = (int) point.y;
+ setInputState (event, nsEvent, type);
+ if (send) {
+ sendEvent (type, event);
+ if (isDisposed ()) return false;
+ } else {
+ postEvent (type, event);
+ }
+ if (shell != null) shell.setActiveControl(this);
+ return event.doit;
+}
+
+void setBackground () {
+// redrawWidget (handle, false);
+}
+
+/**
+ * Sets the receiver's background color to the color specified
+ * by the argument, or to the default system color for the control
+ * if the argument is null.
+ * <p>
+ * Note: This operation is a hint and may be overridden by the platform.
+ * For example, on Windows the background of a Button cannot be changed.
+ * </p>
+ * @param color the new color (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setBackground (Color color) {
+ checkWidget();
+ if (color != null) {
+ if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ float /*double*/ [] background = color != null ? color.handle : null;
+ if (equals (background, this.background)) return;
+ this.background = background;
+ updateBackground ();
+ redrawWidget(view, true);
+}
+
+/**
+ * Sets the receiver's background image to the image specified
+ * by the argument, or to the default system color for the control
+ * if the argument is null. The background image is tiled to fill
+ * the available space.
+ * <p>
+ * Note: This operation is a hint and may be overridden by the platform.
+ * For example, on Windows the background of a Button cannot be changed.
+ * </p>
+ * @param image the new image (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument is not a bitmap</li>
+ * </ul>
+ * @exception SWTException <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 setBackgroundImage (Image image) {
+ checkWidget();
+ if (image != null && image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (image == backgroundImage) return;
+ backgroundImage = image;
+ updateBackground();
+ redrawWidget(view, false);
+}
+
+void updateBackground () {
+}
+
+void setBackground (NSColor nsColor) {
+}
+
+/**
+ * Sets the receiver's size and location to the rectangular
+ * area specified by the arguments. The <code>x</code> and
+ * <code>y</code> arguments are relative to the receiver's
+ * parent (or its display if its parent is null), unless
+ * the receiver is a shell. In this case, the <code>x</code>
+ * and <code>y</code> arguments are relative to the display.
+ * <p>
+ * Note: Attempting to set the width or height of the
+ * receiver to a negative number will cause that
+ * value to be set to zero instead.
+ * </p>
+ *
+ * @param x the new x coordinate for the receiver
+ * @param y the new y coordinate for the receiver
+ * @param width the new width for the receiver
+ * @param height the new height for the receiver
+ *
+ * @exception SWTException <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 setBounds (int x, int y, int width, int height) {
+ checkWidget();
+ setBounds (x, y, Math.max (0, width), Math.max (0, height), true, true);
+}
+
+void setBounds (int x, int y, int width, int height, boolean move, boolean resize) {
+ NSView topView = topView();
+ if (move && resize) {
+ NSRect rect = new NSRect();
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ topView.setFrame (rect);
+ } else if (move) {
+ NSPoint point = new NSPoint();
+ point.x = x;
+ point.y = y;
+ topView.setFrameOrigin(point);
+ } else if (resize) {
+ NSSize size = new NSSize();
+ size.width = width;
+ size.height = height;
+ topView.setFrameSize(size);
+ }
+}
+
+/**
+ * Sets the receiver's size and location to the rectangular
+ * area specified by the argument. The <code>x</code> and
+ * <code>y</code> fields of the rectangle are relative to
+ * the receiver's parent (or its display if its parent is null).
+ * <p>
+ * Note: Attempting to set the width or height of the
+ * receiver to a negative number will cause that
+ * value to be set to zero instead.
+ * </p>
+ *
+ * @param rect the new bounds for the receiver
+ *
+ * @exception SWTException <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 setBounds (Rectangle rect) {
+ checkWidget ();
+ if (rect == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setBounds (rect.x, rect.y, Math.max (0, rect.width), Math.max (0, rect.height), true, true);
+}
+
+/**
+ * If the argument is <code>true</code>, causes the receiver to have
+ * all mouse events delivered to it until the method is called with
+ * <code>false</code> as the argument. Note that on some platforms,
+ * a mouse button must currently be down for capture to be assigned.
+ *
+ * @param capture <code>true</code> to capture the mouse, and <code>false</code> to release it
+ *
+ * @exception SWTException <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 setCapture (boolean capture) {
+ checkWidget();
+}
+
+void setClipRegion (float /*double*/ x, float /*double*/ y) {
+ if (regionPath != null) {
+ NSAffineTransform transform = NSAffineTransform.transform();
+ transform.translateXBy(-x, -y);
+ regionPath.transformUsingAffineTransform(transform);
+ regionPath.addClip();
+ transform.translateXBy(2*x, 2*y);
+ regionPath.transformUsingAffineTransform(transform);
+ }
+ NSRect frame = topView().frame();
+ parent.setClipRegion(frame.x + x, frame.y + y);
+}
+
+/**
+ * Sets the receiver's cursor to the cursor specified by the
+ * argument, or to the default cursor for that kind of control
+ * if the argument is null.
+ * <p>
+ * When the mouse pointer passes over a control its appearance
+ * is changed to match the control's cursor.
+ * </p>
+ *
+ * @param cursor the new cursor (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setCursor (Cursor cursor) {
+ checkWidget();
+ if (cursor != null && cursor.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ this.cursor = cursor;
+ if (!isEnabled()) return;
+ if (!view.window().areCursorRectsEnabled()) return;
+ display.setCursor (display.currentControl);
+}
+
+void setDefaultFont () {
+ if (display.smallFonts) {
+ setFont (defaultFont ().handle);
+ setSmallSize ();
+ }
+}
+
+/**
+ * Sets the receiver's drag detect state. If the argument is
+ * <code>true</code>, the receiver will detect drag gestures,
+ * otherwise these gestures will be ignored.
+ *
+ * @param dragDetect the new drag detect state
+ *
+ * @exception SWTException <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.3
+ */
+public void setDragDetect (boolean dragDetect) {
+ checkWidget ();
+ if (dragDetect) {
+ state |= DRAG_DETECT;
+ } else {
+ state &= ~DRAG_DETECT;
+ }
+}
+
+/**
+ * Enables the receiver if the argument is <code>true</code>,
+ * and disables it otherwise. A disabled control is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @param enabled the new enabled state
+ *
+ * @exception SWTException <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 setEnabled (boolean enabled) {
+ checkWidget();
+ if (((state & DISABLED) == 0) == enabled) return;
+ Control control = null;
+ boolean fixFocus = false;
+ if (!enabled) {
+ if (display.focusEvent != SWT.FocusOut) {
+ control = display.getFocusControl ();
+ fixFocus = isFocusAncestor (control);
+ }
+ }
+ if (enabled) {
+ state &= ~DISABLED;
+ } else {
+ state |= DISABLED;
+ }
+ enableWidget (enabled);
+ if (fixFocus) fixFocus (control);
+}
+
+/**
+ * Causes the receiver to have the <em>keyboard focus</em>,
+ * such that all keyboard events will be delivered to it. Focus
+ * reassignment will respect applicable platform constraints.
+ *
+ * @return <code>true</code> if the control got focus, and <code>false</code> if it was unable to.
+ *
+ * @exception SWTException <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 #forceFocus
+ */
+public boolean setFocus () {
+ checkWidget();
+ if ((style & SWT.NO_FOCUS) != 0) return false;
+ return forceFocus ();
+}
+
+/**
+ * Sets the font that the receiver will use to paint textual information
+ * to the font specified by the argument, or to the default font for that
+ * kind of control if the argument is null.
+ *
+ * @param font the new font (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setFont (Font font) {
+ checkWidget();
+ if (font != null) {
+ if (font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.font = font;
+ setFont (font != null ? font.handle : defaultFont().handle);
+}
+
+void setFont (NSFont font) {
+ if (view instanceof NSControl) {
+ ((NSControl)view).setFont(font);
+ }
+}
+
+/**
+ * Sets the receiver's foreground color to the color specified
+ * by the argument, or to the default system color for the control
+ * if the argument is null.
+ * <p>
+ * Note: This operation is a hint and may be overridden by the platform.
+ * </p>
+ * @param color the new color (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setForeground (Color color) {
+ checkWidget();
+ if (color != null) {
+ if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ float /*double*/ [] foreground = color != null ? color.handle : null;
+ if (equals (foreground, this.foreground)) return;
+ this.foreground = foreground;
+ setForeground (foreground);
+ redrawWidget (view, false);
+}
+
+void setForeground (float /*double*/ [] color) {
+}
+
+void setFrameOrigin (int /*long*/ id, int /*long*/ sel, NSPoint point) {
+ NSView topView = topView ();
+ if (topView.id != id) {
+ super.setFrameOrigin(id, sel, point);
+ return;
+ }
+ NSRect frame = topView.frame();
+ super.setFrameOrigin(id, sel, point);
+ if (frame.x != point.x || frame.y != point.y) {
+ invalidateVisibleRegion();
+ moved ();
+ }
+}
+
+void setFrameSize (int /*long*/ id, int /*long*/ sel, NSSize size) {
+ NSView topView = topView ();
+ if (topView.id != id) {
+ super.setFrameSize(id, sel, size);
+ return;
+ }
+ NSRect frame = topView.frame();
+ super.setFrameSize(id, sel, size);
+ if (frame.width != size.width || frame.height != size.height) {
+ invalidateVisibleRegion();
+ resized ();
+ }
+}
+
+/**
+ * Sets the layout data associated with the receiver to the argument.
+ *
+ * @param layoutData the new layout data for the receiver.
+ *
+ * @exception SWTException <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 setLayoutData (Object layoutData) {
+ checkWidget();
+ this.layoutData = layoutData;
+}
+
+/**
+ * Sets the receiver's location to the point specified by
+ * the arguments which are relative to the receiver's
+ * parent (or its display if its parent is null), unless
+ * the receiver is a shell. In this case, the point is
+ * relative to the display.
+ *
+ * @param x the new x coordinate for the receiver
+ * @param y the new y coordinate for the receiver
+ *
+ * @exception SWTException <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 setLocation (int x, int y) {
+ checkWidget();
+ setBounds (x, y, 0, 0, true, false);
+}
+
+/**
+ * Sets the receiver's location to the point specified by
+ * the arguments which are relative to the receiver's
+ * parent (or its display if its parent is null), unless
+ * the receiver is a shell. In this case, the point is
+ * relative to the display.
+ *
+ * @param location the new location for the receiver
+ *
+ * @exception SWTException <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 setLocation (Point location) {
+ checkWidget();
+ if (location == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setBounds (location.x, location.y, 0, 0, true, false);
+}
+
+/**
+ * Sets the receiver's pop up menu to the argument.
+ * All controls may optionally have a pop up
+ * menu that is displayed when the user requests one for
+ * the control. The sequence of key strokes, button presses
+ * and/or button releases that are used to request a pop up
+ * menu is platform specific.
+ * <p>
+ * Note: Disposing of a control that has a pop up menu will
+ * dispose of the menu. To avoid this behavior, set the
+ * menu to null before the control is disposed.
+ * </p>
+ *
+ * @param menu the new pop up menu
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_MENU_NOT_POP_UP - the menu is not a pop up menu</li>
+ * <li>ERROR_INVALID_PARENT - if the menu is not in the same widget tree</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the menu has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setMenu (Menu menu) {
+ checkWidget();
+ if (menu != null) {
+ if (menu.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if ((menu.style & SWT.POP_UP) == 0) {
+ error (SWT.ERROR_MENU_NOT_POP_UP);
+ }
+ if (menu.parent != menuShell ()) {
+ error (SWT.ERROR_INVALID_PARENT);
+ }
+ }
+ this.menu = menu;
+}
+
+/**
+ * Changes the parent of the widget to be the one provided if
+ * the underlying operating system supports this feature.
+ * Returns <code>true</code> if the parent is successfully changed.
+ *
+ * @param parent the new parent for the control.
+ * @return <code>true</code> if the parent is changed and <code>false</code> otherwise.
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is <code>null</code></li>
+ * </ul>
+ * @exception SWTException <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 boolean setParent (Composite parent) {
+ checkWidget();
+ if (parent == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (parent.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (this.parent == parent) return true;
+ if (!isReparentable ()) return false;
+ releaseParent ();
+ Shell newShell = parent.getShell (), oldShell = getShell ();
+ Decorations newDecorations = parent.menuShell (), oldDecorations = menuShell ();
+ if (oldShell != newShell || oldDecorations != newDecorations) {
+ Menu [] menus = oldShell.findMenus (this);
+ fixChildren (newShell, oldShell, newDecorations, oldDecorations, menus);
+ }
+ NSView topView = topView ();
+ topView.retain();
+ topView.removeFromSuperview();
+ parent.contentView().addSubview(topView, OS.NSWindowBelow, null);
+ topView.release();
+ this.parent = parent;
+ return true;
+}
+
+/**
+ * If the argument is <code>false</code>, causes subsequent drawing
+ * operations in the receiver to be ignored. No drawing of any kind
+ * can occur in the receiver until the flag is set to true.
+ * Graphics operations that occurred while the flag was
+ * <code>false</code> are lost. When the flag is set to <code>true</code>,
+ * the entire widget is marked as needing to be redrawn. Nested calls
+ * to this method are stacked.
+ * <p>
+ * Note: This operation is a hint and may not be supported on some
+ * platforms or for some widgets.
+ * </p>
+ *
+ * @param redraw the new redraw state
+ *
+ * @exception SWTException <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 #redraw(int, int, int, int, boolean)
+ * @see #update()
+ */
+public void setRedraw (boolean redraw) {
+ checkWidget();
+ if (redraw) {
+ if (--drawCount == 0) {
+ invalidateVisibleRegion ();
+ redrawWidget(topView (), true);
+ }
+ } else {
+ if (drawCount == 0) {
+ invalidateVisibleRegion ();
+ }
+ drawCount++;
+ }
+}
+
+/**
+ * Sets the shape of the control to the region specified
+ * by the argument. When the argument is null, the
+ * default shape of the control is restored.
+ *
+ * @param region the region that defines the shape of the control (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the region has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.4
+ */
+public void setRegion (Region region) {
+ checkWidget ();
+ if (region != null && region.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+ this.region = region;
+ if (regionPath != null) regionPath.release();
+ regionPath = getPath(region);
+ redrawWidget(view, true);
+}
+
+void setRelations () {
+ if (parent == null) return;
+ Control [] children = parent._getChildren ();
+ int count = children.length;
+ if (count > 1) {
+ /*
+ * the receiver is the last item in the list, so its predecessor will
+ * be the second-last item in the list
+ */
+ Control child = children [count - 2];
+ if (child != this) {
+ child.addRelation (this);
+ }
+ }
+}
+
+boolean setRadioSelection (boolean value){
+ return false;
+}
+
+/**
+ * Sets the receiver's size to the point specified by the arguments.
+ * <p>
+ * Note: Attempting to set the width or height of the
+ * receiver to a negative number will cause that
+ * value to be set to zero instead.
+ * </p>
+ *
+ * @param width the new width for the receiver
+ * @param height the new height for the receiver
+ *
+ * @exception SWTException <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 setSize (int width, int height) {
+ checkWidget();
+ setBounds (0, 0, Math.max (0, width), Math.max (0, height), false, true);
+}
+
+/**
+ * Sets the receiver's size to the point specified by the argument.
+ * <p>
+ * Note: Attempting to set the width or height of the
+ * receiver to a negative number will cause them to be
+ * set to zero instead.
+ * </p>
+ *
+ * @param size the new size for the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception SWTException <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 setSize (Point size) {
+ checkWidget ();
+ if (size == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setBounds (0, 0, Math.max (0, size.x), Math.max (0, size.y), false, true);
+}
+
+void setSmallSize () {
+ if (view instanceof NSControl) {
+ NSCell cell = ((NSControl)view).cell();
+ if (cell != null) cell.setControlSize (OS.NSSmallControlSize);
+ }
+}
+
+boolean setTabItemFocus () {
+ if (!isShowing ()) return false;
+ return forceFocus ();
+}
+
+/**
+ * Sets the receiver's tool tip text to the argument, which
+ * may be null indicating that the default tool tip for the
+ * control will be shown. For a control that has a default
+ * tool tip, such as the Tree control on Windows, setting
+ * the tool tip text to an empty string replaces the default,
+ * causing no tool tip text to be shown.
+ * <p>
+ * The mnemonic indicator (character '&amp;') is not displayed in a tool tip.
+ * To display a single '&amp;' in the tool tip, the character '&amp;' can be
+ * escaped by doubling it in the string.
+ * </p>
+ *
+ * @param string the new tool tip text (or null)
+ *
+ * @exception SWTException <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 setToolTipText (String string) {
+ checkWidget();
+ toolTipText = string;
+ checkToolTip (null);
+}
+
+/**
+ * Marks the receiver as visible if the argument is <code>true</code>,
+ * and marks it invisible otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, marking
+ * it visible may not actually cause it to be displayed.
+ * </p>
+ *
+ * @param visible the new visibility state
+ *
+ * @exception SWTException <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 setVisible (boolean visible) {
+ checkWidget();
+ if (visible) {
+ if ((state & HIDDEN) == 0) return;
+ state &= ~HIDDEN;
+ } else {
+ if ((state & HIDDEN) != 0) return;
+ state |= HIDDEN;
+ }
+ if (visible) {
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the show
+ * event. If this happens, just return.
+ */
+ sendEvent (SWT.Show);
+ if (isDisposed ()) return;
+ }
+
+ /*
+ * Feature in the Macintosh. If the receiver has focus, hiding
+ * the receiver causes no control to have focus. Also, the focus
+ * needs to be cleared from any TXNObject so that it stops blinking
+ * the caret. The fix is to assign focus to the first ancestor
+ * control that takes focus. If no control will take focus, clear
+ * the focus control.
+ */
+ Control control = null;
+ boolean fixFocus = false;
+ if (!visible) {
+ if (display.focusEvent != SWT.FocusOut) {
+ control = display.getFocusControl ();
+ fixFocus = isFocusAncestor (control);
+ }
+ }
+ topView().setHidden(!visible);
+ invalidateVisibleRegion();
+ if (!visible) {
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the show
+ * event. If this happens, just return.
+ */
+ sendEvent (SWT.Hide);
+ if (isDisposed ()) return;
+ }
+ if (fixFocus) fixFocus (control);
+}
+
+void setZOrder () {
+ NSView topView = topView ();
+ parent.contentView().addSubview(topView, OS.NSWindowBelow, null);
+}
+
+boolean shouldDelayWindowOrderingForEvent (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ Shell shell = getShell ();
+ if ((shell.style & SWT.ON_TOP) != 0) return false;
+ return super.shouldDelayWindowOrderingForEvent (id, sel, theEvent);
+}
+
+void setZOrder (Control sibling, boolean above) {
+ int index = 0, siblingIndex = 0, oldNextIndex = -1;
+ Control[] children = null;
+ /* determine the receiver's and sibling's indexes in the parent */
+ children = parent._getChildren ();
+ while (index < children.length) {
+ if (children [index] == this) break;
+ index++;
+ }
+ if (sibling != null) {
+ while (siblingIndex < children.length) {
+ if (children [siblingIndex] == sibling) break;
+ siblingIndex++;
+ }
+ }
+ /* remove "Labeled by" relationships that will no longer be valid */
+ removeRelation ();
+ if (index + 1 < children.length) {
+ oldNextIndex = index + 1;
+ children [oldNextIndex].removeRelation ();
+ }
+ if (sibling != null) {
+ if (above) {
+ sibling.removeRelation ();
+ } else {
+ if (siblingIndex + 1 < children.length) {
+ children [siblingIndex + 1].removeRelation ();
+ }
+ }
+ }
+
+ NSView otherView = sibling == null ? null : sibling.topView ();
+ view.retain();
+ view.removeFromSuperview();
+ parent.contentView().addSubview(view, above ? OS.NSWindowAbove : OS.NSWindowBelow, otherView);
+ view.release();
+ invalidateVisibleRegion();
+
+ /* determine the receiver's new index in the parent */
+ if (sibling != null) {
+ if (above) {
+ index = siblingIndex - (index < siblingIndex ? 1 : 0);
+ } else {
+ index = siblingIndex + (siblingIndex < index ? 1 : 0);
+ }
+ } else {
+ if (above) {
+ index = 0;
+ } else {
+ index = children.length - 1;
+ }
+ }
+
+ /* add new "Labeled by" relations as needed */
+ children = parent._getChildren ();
+ if (0 < index) {
+ children [index - 1].addRelation (this);
+ }
+ if (index + 1 < children.length) {
+ addRelation (children [index + 1]);
+ }
+ if (oldNextIndex != -1) {
+ if (oldNextIndex <= index) oldNextIndex--;
+ /* the last two conditions below ensure that duplicate relations are not hooked */
+ if (0 < oldNextIndex && oldNextIndex != index && oldNextIndex != index + 1) {
+ children [oldNextIndex - 1].addRelation (children [oldNextIndex]);
+ }
+ }
+}
+
+void sort (int [] items) {
+ /* Shell Sort from K&R, pg 108 */
+ int length = items.length;
+ for (int gap=length/2; gap>0; gap/=2) {
+ for (int i=gap; i<length; i++) {
+ for (int j=i-gap; j>=0; j-=gap) {
+ if (items [j] <= items [j + gap]) {
+ int swap = items [j];
+ items [j] = items [j + gap];
+ items [j + gap] = swap;
+ }
+ }
+ }
+ }
+}
+
+NSSize textExtent (String string) {
+ NSAttributedString attribStr = createString(string, null, null, 0, true, false);
+ NSSize size = attribStr.size();
+ attribStr.release();
+ return size;
+}
+
+String tooltipText () {
+ return toolTipText;
+}
+
+/**
+ * Returns a point which is the result of converting the
+ * argument, which is specified in display relative coordinates,
+ * to coordinates relative to the receiver.
+ * <p>
+ * @param x the x coordinate to be translated
+ * @param y the y coordinate to be translated
+ * @return the translated coordinates
+ *
+ * @exception SWTException <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 2.1
+ */
+public Point toControl (int x, int y) {
+ checkWidget();
+ return display.map (null, this, x, y);
+}
+
+/**
+ * Returns a point which is the result of converting the
+ * argument, which is specified in display relative coordinates,
+ * to coordinates relative to the receiver.
+ * <p>
+ * @param point the point to be translated (must not be null)
+ * @return the translated coordinates
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception SWTException <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 Point toControl (Point point) {
+ checkWidget();
+ if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
+ return toControl (point.x, point.y);
+}
+
+/**
+ * Returns a point which is the result of converting the
+ * argument, which is specified in coordinates relative to
+ * the receiver, to display relative coordinates.
+ * <p>
+ * @param x the x coordinate to be translated
+ * @param y the y coordinate to be translated
+ * @return the translated coordinates
+ *
+ * @exception SWTException <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 2.1
+ */
+public Point toDisplay (int x, int y) {
+ checkWidget();
+ return display.map (this, null, x, y);
+}
+
+/**
+ * Returns a point which is the result of converting the
+ * argument, which is specified in coordinates relative to
+ * the receiver, to display relative coordinates.
+ * <p>
+ * @param point the point to be translated (must not be null)
+ * @return the translated coordinates
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception SWTException <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 Point toDisplay (Point point) {
+ checkWidget();
+ if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
+ return toDisplay (point.x, point.y);
+}
+
+NSView topView () {
+ return view;
+}
+
+boolean translateTraversal (int key, NSEvent theEvent, boolean [] consume) {
+ int detail = SWT.TRAVERSE_NONE;
+ int code = traversalCode (key, theEvent);
+ boolean all = false;
+ switch (key) {
+ case 53: /* Esc */ {
+ all = true;
+ detail = SWT.TRAVERSE_ESCAPE;
+ break;
+ }
+ case 76: /* KP Enter */
+ case 36: /* Return */ {
+ all = true;
+ detail = SWT.TRAVERSE_RETURN;
+ break;
+ }
+ case 48: /* Tab */ {
+ int /*long*/ modifiers = theEvent.modifierFlags ();
+ boolean next = (modifiers & OS.NSShiftKeyMask) == 0;
+ detail = next ? SWT.TRAVERSE_TAB_NEXT : SWT.TRAVERSE_TAB_PREVIOUS;
+ break;
+ }
+ case 126: /* Up arrow */
+ case 123: /* Left arrow */
+ case 125: /* Down arrow */
+ case 124: /* Right arrow */ {
+ boolean next = key == 125 /* Down arrow */ || key == 124 /* Right arrow */;
+ detail = next ? SWT.TRAVERSE_ARROW_NEXT : SWT.TRAVERSE_ARROW_PREVIOUS;
+ break;
+ }
+ case 116: /* Page up */
+ case 121: /* Page down */ {
+ all = true;
+ int /*long*/ modifiers = theEvent.modifierFlags ();
+ if ((modifiers & OS.NSControlKeyMask) == 0) return false;
+ detail = key == 121 /* Page down */ ? SWT.TRAVERSE_PAGE_NEXT : SWT.TRAVERSE_PAGE_PREVIOUS;
+ break;
+ }
+ default:
+ return false;
+ }
+ Event event = new Event ();
+ event.doit = consume [0] = (code & detail) != 0;
+ event.detail = detail;
+ if (!setKeyState (event, SWT.Traverse, theEvent)) return false;
+ Shell shell = getShell ();
+ Control control = this;
+ do {
+ if (control.traverse (event)) return true;
+ if (!event.doit && control.hooks (SWT.Traverse)) {
+ return false;
+ }
+ if (control == shell) return false;
+ control = control.parent;
+ } while (all && control != null);
+ return false;
+}
+
+int traversalCode (int key, NSEvent theEvent) {
+ int code = SWT.TRAVERSE_RETURN | SWT.TRAVERSE_TAB_NEXT | SWT.TRAVERSE_TAB_PREVIOUS | SWT.TRAVERSE_PAGE_NEXT | SWT.TRAVERSE_PAGE_PREVIOUS;
+ Shell shell = getShell ();
+ if (shell.parent != null) code |= SWT.TRAVERSE_ESCAPE;
+ return code;
+}
+
+boolean traverseMnemonic (char key) {
+ return false;
+}
+
+/**
+ * Based on the argument, perform one of the expected platform
+ * traversal action. The argument should be one of the constants:
+ * <code>SWT.TRAVERSE_ESCAPE</code>, <code>SWT.TRAVERSE_RETURN</code>,
+ * <code>SWT.TRAVERSE_TAB_NEXT</code>, <code>SWT.TRAVERSE_TAB_PREVIOUS</code>,
+ * <code>SWT.TRAVERSE_ARROW_NEXT</code> and <code>SWT.TRAVERSE_ARROW_PREVIOUS</code>.
+ *
+ * @param traversal the type of traversal
+ * @return true if the traversal succeeded
+ *
+ * @exception SWTException <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 boolean traverse (int traversal) {
+ checkWidget();
+ Event event = new Event ();
+ event.doit = true;
+ event.detail = traversal;
+ return traverse (event);
+}
+
+boolean traverse (Event event) {
+ sendEvent (SWT.Traverse, event);
+ if (isDisposed ()) return true;
+ if (!event.doit) return false;
+ switch (event.detail) {
+ case SWT.TRAVERSE_NONE: return true;
+ case SWT.TRAVERSE_ESCAPE: return traverseEscape ();
+ case SWT.TRAVERSE_RETURN: return traverseReturn ();
+ case SWT.TRAVERSE_TAB_NEXT: return traverseGroup (true);
+ case SWT.TRAVERSE_TAB_PREVIOUS: return traverseGroup (false);
+ case SWT.TRAVERSE_ARROW_NEXT: return traverseItem (true);
+ case SWT.TRAVERSE_ARROW_PREVIOUS: return traverseItem (false);
+ case SWT.TRAVERSE_MNEMONIC: return traverseMnemonic (event);
+ case SWT.TRAVERSE_PAGE_NEXT: return traversePage (true);
+ case SWT.TRAVERSE_PAGE_PREVIOUS: return traversePage (false);
+ }
+ return false;
+}
+
+boolean traverseEscape () {
+ return false;
+}
+
+boolean traverseGroup (boolean next) {
+ Control root = computeTabRoot ();
+ Widget group = computeTabGroup ();
+ Widget [] list = root.computeTabList ();
+ int length = list.length;
+ int index = 0;
+ while (index < length) {
+ if (list [index] == group) break;
+ index++;
+ }
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in focus in
+ * or out events. Ensure that a disposed widget is
+ * not accessed.
+ */
+ if (index == length) return false;
+ int start = index, offset = (next) ? 1 : -1;
+ while ((index = ((index + offset + length) % length)) != start) {
+ Widget widget = list [index];
+ if (!widget.isDisposed () && widget.setTabGroupFocus ()) {
+ return true;
+ }
+ }
+ if (group.isDisposed ()) return false;
+ return group.setTabGroupFocus ();
+}
+
+boolean traverseItem (boolean next) {
+ Control [] children = parent._getChildren ();
+ int length = children.length;
+ int index = 0;
+ while (index < length) {
+ if (children [index] == this) break;
+ index++;
+ }
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in focus in
+ * or out events. Ensure that a disposed widget is
+ * not accessed.
+ */
+ if (index == length) return false;
+ int start = index, offset = (next) ? 1 : -1;
+ while ((index = (index + offset + length) % length) != start) {
+ Control child = children [index];
+ if (!child.isDisposed () && child.isTabItem ()) {
+ if (child.setTabItemFocus ()) return true;
+ }
+ }
+ return false;
+}
+
+boolean traverseReturn () {
+ return false;
+}
+
+boolean traversePage (boolean next) {
+ return false;
+}
+
+boolean traverseMnemonic (Event event) {
+ return false;
+}
+
+/**
+ * Forces all outstanding paint requests for the widget
+ * to be processed before this method returns. If there
+ * are no outstanding paint request, this method does
+ * nothing.
+ * <p>
+ * Note: This method does not cause a redraw.
+ * </p>
+ *
+ * @exception SWTException <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 #redraw()
+ * @see #redraw(int, int, int, int, boolean)
+ * @see PaintListener
+ * @see SWT#Paint
+ */
+public void update () {
+ checkWidget();
+ update (false);
+}
+
+void update (boolean all) {
+// checkWidget();
+ if (display.isPainting.containsObject(view)) return;
+ //TODO - not all
+ view.displayIfNeeded ();
+}
+
+void updateBackgroundMode () {
+ int oldState = state & PARENT_BACKGROUND;
+ checkBackground ();
+ if (oldState != (state & PARENT_BACKGROUND)) {
+ setBackground ();
+ }
+}
+
+void resetCursorRects (int /*long*/ id, int /*long*/ sel) {
+ if (isEnabled ()) callSuper (id, sel);
+}
+
+void updateTrackingAreas (int /*long*/ id, int /*long*/ sel) {
+ if (isEnabled ()) callSuper (id, sel);
+}
+
+void updateCursorRects (boolean enabled) {
+ updateCursorRects (enabled, view);
+}
+
+void updateCursorRects (boolean enabled, NSView widget) {
+ if (enabled) {
+ widget.resetCursorRects ();
+ widget.updateTrackingAreas ();
+ } else {
+ widget.discardCursorRects ();
+ NSArray areas = widget.trackingAreas ();
+ for (int i = 0; i < areas.count(); i++) {
+ widget.removeTrackingArea (new NSTrackingArea (areas.objectAtIndex (i)));
+ }
+ }
+}
+
+void updateLayout (boolean all) {
+ /* Do nothing */
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/DateTime.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/DateTime.java
new file mode 100755
index 0000000000..5604b200af
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/DateTime.java
@@ -0,0 +1,591 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class are selectable user interface
+ * objects that allow the user to enter and modify date
+ * or time values.
+ * <p>
+ * Note that although this class is a subclass of <code>Composite</code>,
+ * it does not make sense to add children to it, or set a layout on it.
+ * </p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>DATE, TIME, CALENDAR, SHORT, MEDIUM, LONG, DROP_DOWN</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>DefaultSelection, Selection</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles DATE, TIME, or CALENDAR may be specified,
+ * and only one of the styles SHORT, MEDIUM, or LONG may be specified.
+ * The DROP_DOWN style is a <em>HINT</em>, and it is only valid with the DATE style.
+ * </p><p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#datetime">DateTime snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.3
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class DateTime extends Composite {
+ static final int MIN_YEAR = 1752; // Gregorian switchover in North America: September 19, 1752
+ static final int MAX_YEAR = 9999;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#DATE
+ * @see SWT#TIME
+ * @see SWT#CALENDAR
+ * @see SWT#SHORT
+ * @see SWT#MEDIUM
+ * @see SWT#LONG
+ * @see SWT#DROP_DOWN
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public DateTime (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+static int checkStyle (int style) {
+ /*
+ * Even though it is legal to create this widget
+ * with scroll bars, they serve no useful purpose
+ * because they do not automatically scroll the
+ * widget's client area. The fix is to clear
+ * the SWT style.
+ */
+ style &= ~(SWT.H_SCROLL | SWT.V_SCROLL);
+ style = checkBits (style, SWT.MEDIUM, SWT.SHORT, SWT.LONG, 0, 0, 0);
+ return checkBits (style, SWT.DATE, SWT.TIME, SWT.CALENDAR, 0, 0, 0);
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+/**
+ * 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 user changes the control's value.
+ * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed.
+ * </p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection, typedListener);
+ addListener (SWT.DefaultSelection, typedListener);
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int width = 0, height = 0;
+ NSControl widget = (NSControl)view;
+ NSSize size = widget.cell ().cellSize ();
+ width = (int)Math.ceil (size.width);
+ height = (int)Math.ceil (size.height);
+ if (width == 0) width = DEFAULT_WIDTH;
+ if (height == 0) height = DEFAULT_HEIGHT;
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ int border = getBorderWidth ();
+ width += border * 2; height += border * 2;
+ return new Point (width, height);
+}
+
+void createHandle () {
+ NSDatePicker widget = (NSDatePicker)new SWTDatePicker().alloc();
+ widget.init();
+ int pickerStyle = OS.NSTextFieldAndStepperDatePickerStyle;
+ int elementFlags = 0;
+ if ((style & SWT.CALENDAR) != 0) {
+ pickerStyle = OS.NSClockAndCalendarDatePickerStyle;
+ elementFlags = OS.NSYearMonthDayDatePickerElementFlag;
+ } else {
+ if ((style & SWT.TIME) != 0) {
+ elementFlags = (style & SWT.SHORT) != 0 ? OS.NSHourMinuteDatePickerElementFlag : OS.NSHourMinuteSecondDatePickerElementFlag;
+ }
+ if ((style & SWT.DATE) != 0) {
+ elementFlags = (style & SWT.SHORT) != 0 ? OS.NSYearMonthDatePickerElementFlag : OS.NSYearMonthDayDatePickerElementFlag;
+ }
+ }
+ widget.setDrawsBackground(true);
+ widget.setDatePickerStyle(pickerStyle);
+ widget.setDatePickerElements(elementFlags);
+ NSDate date = NSCalendarDate.calendarDate();
+ widget.setDateValue(date);
+ widget.setTarget(widget);
+ widget.setAction(OS.sel_sendSelection);
+ view = widget;
+}
+
+NSFont defaultNSFont() {
+ return display.datePickerFont;
+}
+
+NSCalendarDate getCalendarDate () {
+ NSDate date = ((NSDatePicker)view).dateValue();
+ return date.dateWithCalendarFormat(null, null);
+}
+
+/**
+ * Returns the receiver's date, or day of the month.
+ * <p>
+ * The first day of the month is 1, and the last day depends on the month and year.
+ * </p>
+ *
+ * @return a positive integer beginning with 1
+ *
+ * @exception SWTException <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 getDay () {
+ checkWidget ();
+ return (int)/*64*/getCalendarDate().dayOfMonth();
+}
+
+/**
+ * Returns the receiver's hours.
+ * <p>
+ * Hours is an integer between 0 and 23.
+ * </p>
+ *
+ * @return an integer between 0 and 23
+ *
+ * @exception SWTException <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 getHours () {
+ checkWidget ();
+ return (int)/*64*/getCalendarDate().hourOfDay();
+}
+
+/**
+ * Returns the receiver's minutes.
+ * <p>
+ * Minutes is an integer between 0 and 59.
+ * </p>
+ *
+ * @return an integer between 0 and 59
+ *
+ * @exception SWTException <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 getMinutes () {
+ checkWidget ();
+ return (int)/*64*/getCalendarDate().minuteOfHour();
+}
+
+/**
+ * Returns the receiver's month.
+ * <p>
+ * The first month of the year is 0, and the last month is 11.
+ * </p>
+ *
+ * @return an integer between 0 and 11
+ *
+ * @exception SWTException <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 getMonth () {
+ checkWidget ();
+ return (int)/*64*/getCalendarDate().monthOfYear() - 1;
+}
+
+String getNameText() {
+ return (style & SWT.TIME) != 0 ? getHours() + ":" + getMinutes() + ":" + getSeconds()
+ : (getMonth() + 1) + "/" + getDay() + "/" + getYear();
+}
+
+/**
+ * Returns the receiver's seconds.
+ * <p>
+ * Seconds is an integer between 0 and 59.
+ * </p>
+ *
+ * @return an integer between 0 and 59
+ *
+ * @exception SWTException <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 getSeconds () {
+ checkWidget ();
+ return (int)/*64*/getCalendarDate().secondOfMinute();
+}
+
+/**
+ * Returns the receiver's year.
+ * <p>
+ * The first year is 1752 and the last year is 9999.
+ * </p>
+ *
+ * @return an integer between 1752 and 9999
+ *
+ * @exception SWTException <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 getYear () {
+ checkWidget ();
+ return (int)/*64*/getCalendarDate().yearOfCommonEra();
+}
+
+boolean isEventView (int /*long*/ id) {
+ return true;
+}
+
+boolean isFlipped (int /*long*/ id, int /*long*/ sel) {
+ if ((style & SWT.CALENDAR) != 0) return super.isFlipped (id, sel);
+ return true;
+}
+
+/**
+ * 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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection, listener);
+}
+
+boolean sendKeyEvent (NSEvent nsEvent, int type) {
+ boolean result = super.sendKeyEvent (nsEvent, type);
+ if (!result) return result;
+ if (type != SWT.KeyDown) return result;
+ if ((style & SWT.CALENDAR) == 0) {
+ short keyCode = nsEvent.keyCode ();
+ switch (keyCode) {
+ case 76: /* KP Enter */
+ case 36: /* Return */
+ postEvent (SWT.DefaultSelection);
+ }
+ }
+ return result;
+}
+
+void sendSelection () {
+ NSEvent event = NSApplication.sharedApplication().currentEvent();
+ if (event != null && (style & SWT.CALENDAR) != 0) {
+ if (event.clickCount() == 2) {
+ postEvent (SWT.DefaultSelection);
+ } else if (event.type() == OS.NSLeftMouseUp) {
+ postEvent (SWT.Selection);
+ }
+ } else { // SWT.DATE or SWT.TIME
+ postEvent (SWT.Selection);
+ }
+}
+
+void updateBackground () {
+ NSColor nsColor = null;
+ if (backgroundImage != null) {
+ nsColor = NSColor.colorWithPatternImage(backgroundImage.handle);
+ } else if (background != null) {
+ nsColor = NSColor.colorWithDeviceRed(background[0], background[1], background[2], background[3]);
+ } else {
+ if ((style & SWT.CALENDAR) != 0) {
+ nsColor = NSColor.controlBackgroundColor ();
+ } else {
+ nsColor = NSColor.textBackgroundColor ();
+ }
+
+ }
+ ((NSDatePicker)view).setBackgroundColor(nsColor);
+}
+
+/**
+ * Sets the receiver's year, month, and day in a single operation.
+ * <p>
+ * This is the recommended way to set the date, because setting the year,
+ * month, and day separately may result in invalid intermediate dates.
+ * </p>
+ *
+ * @param year an integer between 1752 and 9999
+ * @param month an integer between 0 and 11
+ * @param day a positive integer beginning with 1
+ *
+ * @exception SWTException <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.4
+ */
+public void setDate (int year, int month, int day) {
+ checkWidget ();
+ if (year < MIN_YEAR || year > MAX_YEAR) return;
+ NSCalendarDate date = getCalendarDate();
+ NSCalendarDate newDate = NSCalendarDate.dateWithYear(year, month + 1, day,
+ date.hourOfDay(), date.minuteOfHour(), date.secondOfMinute(), date.timeZone());
+ if (newDate.yearOfCommonEra() == year && newDate.monthOfYear() == month + 1 && newDate.dayOfMonth() == day) {
+ ((NSDatePicker)view).setDateValue(newDate);
+ }
+}
+
+/**
+ * Sets the receiver's date, or day of the month, to the specified day.
+ * <p>
+ * The first day of the month is 1, and the last day depends on the month and year.
+ * If the specified day is not valid for the receiver's month and year, then it is ignored.
+ * </p>
+ *
+ * @param day a positive integer beginning with 1
+ *
+ * @exception SWTException <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 #setDate
+ */
+public void setDay (int day) {
+ checkWidget ();
+ NSCalendarDate date = getCalendarDate();
+ NSCalendarDate newDate = NSCalendarDate.dateWithYear(date.yearOfCommonEra(), date.monthOfYear(), day,
+ date.hourOfDay(), date.minuteOfHour(), date.secondOfMinute(), date.timeZone());
+ if (newDate.yearOfCommonEra() == date.yearOfCommonEra() && newDate.monthOfYear() == date.monthOfYear() && newDate.dayOfMonth() == day) {
+ ((NSDatePicker)view).setDateValue(newDate);
+ }
+}
+
+void setForeground (float /*double*/ [] color) {
+ NSColor nsColor;
+ if (color == null) {
+ if ((style & SWT.CALENDAR) != 0) {
+ nsColor = NSColor.controlTextColor ();
+ } else {
+ nsColor = NSColor.textColor ();
+ }
+ } else {
+ nsColor = NSColor.colorWithDeviceRed(color[0], color[1], color[2], 1);
+ }
+ ((NSDatePicker)view).setTextColor(nsColor);
+}
+
+/**
+ * Sets the receiver's hours.
+ * <p>
+ * Hours is an integer between 0 and 23.
+ * </p>
+ *
+ * @param hours an integer between 0 and 23
+ *
+ * @exception SWTException <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 setHours (int hours) {
+ checkWidget ();
+ if (hours < 0 || hours > 23) return;
+ NSCalendarDate date = getCalendarDate();
+ NSCalendarDate newDate = NSCalendarDate.dateWithYear(date.yearOfCommonEra(), date.monthOfYear(), date.dayOfMonth(),
+ hours, date.minuteOfHour(), date.secondOfMinute(), date.timeZone());
+ ((NSDatePicker)view).setDateValue(newDate);
+}
+
+/**
+ * Sets the receiver's minutes.
+ * <p>
+ * Minutes is an integer between 0 and 59.
+ * </p>
+ *
+ * @param minutes an integer between 0 and 59
+ *
+ * @exception SWTException <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 setMinutes (int minutes) {
+ checkWidget ();
+ if (minutes < 0 || minutes > 59) return;
+ NSCalendarDate date = getCalendarDate();
+ NSCalendarDate newDate = NSCalendarDate.dateWithYear(date.yearOfCommonEra(), date.monthOfYear(), date.dayOfMonth(),
+ date.hourOfDay(), minutes, date.secondOfMinute(), date.timeZone());
+ ((NSDatePicker)view).setDateValue(newDate);
+}
+
+/**
+ * Sets the receiver's month.
+ * <p>
+ * The first month of the year is 0, and the last month is 11.
+ * If the specified month is not valid for the receiver's day and year, then it is ignored.
+ * </p>
+ *
+ * @param month an integer between 0 and 11
+ *
+ * @exception SWTException <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 #setDate
+ */
+public void setMonth (int month) {
+ checkWidget ();
+ NSCalendarDate date = getCalendarDate();
+ NSCalendarDate newDate = NSCalendarDate.dateWithYear(date.yearOfCommonEra(), month + 1, date.dayOfMonth(),
+ date.hourOfDay(), date.minuteOfHour(), date.secondOfMinute(), date.timeZone());
+ if (newDate.yearOfCommonEra() == date.yearOfCommonEra() && newDate.monthOfYear() == month + 1 && newDate.dayOfMonth() == date.dayOfMonth()) {
+ ((NSDatePicker)view).setDateValue(newDate);
+ }
+}
+
+/**
+ * Sets the receiver's seconds.
+ * <p>
+ * Seconds is an integer between 0 and 59.
+ * </p>
+ *
+ * @param seconds an integer between 0 and 59
+ *
+ * @exception SWTException <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 setSeconds (int seconds) {
+ checkWidget ();
+ if (seconds < 0 || seconds > 59) return;
+ NSCalendarDate date = getCalendarDate();
+ NSCalendarDate newDate = NSCalendarDate.dateWithYear(date.yearOfCommonEra(), date.monthOfYear(), date.dayOfMonth(),
+ date.hourOfDay(), date.minuteOfHour(), seconds, date.timeZone());
+ ((NSDatePicker)view).setDateValue(newDate);
+}
+
+/**
+ * Sets the receiver's hours, minutes, and seconds in a single operation.
+ *
+ * @param hours an integer between 0 and 23
+ * @param minutes an integer between 0 and 59
+ * @param seconds an integer between 0 and 59
+ *
+ * @exception SWTException <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.4
+ */
+public void setTime (int hours, int minutes, int seconds) {
+ checkWidget ();
+ if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59) return;
+ NSCalendarDate date = getCalendarDate();
+ NSCalendarDate newDate = NSCalendarDate.dateWithYear(date.yearOfCommonEra(), date.monthOfYear(), date.dayOfMonth(),
+ hours, minutes, seconds, date.timeZone());
+ ((NSDatePicker)view).setDateValue(newDate);
+}
+
+/**
+ * Sets the receiver's year.
+ * <p>
+ * The first year is 1752 and the last year is 9999.
+ * If the specified year is not valid for the receiver's day and month, then it is ignored.
+ * </p>
+ *
+ * @param year an integer between 1752 and 9999
+ *
+ * @exception SWTException <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 #setDate
+ */
+public void setYear (int year) {
+ checkWidget ();
+ if (year < MIN_YEAR || year > MAX_YEAR) return;
+ NSCalendarDate date = getCalendarDate();
+ NSCalendarDate newDate = NSCalendarDate.dateWithYear(year, date.monthOfYear(), date.dayOfMonth(),
+ date.hourOfDay(), date.minuteOfHour(), date.secondOfMinute(), date.timeZone());
+ if (newDate.yearOfCommonEra() == year && newDate.monthOfYear() == date.monthOfYear() && newDate.dayOfMonth() == date.dayOfMonth()) {
+ ((NSDatePicker)view).setDateValue(newDate);
+ }
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Decorations.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Decorations.java
new file mode 100755
index 0000000000..e0c6c74c29
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Decorations.java
@@ -0,0 +1,682 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class provide the appearance and
+ * behavior of <code>Shells</code>, but are not top
+ * level shells or dialogs. Class <code>Shell</code>
+ * shares a significant amount of code with this class,
+ * and is a subclass.
+ * <p>
+ * IMPORTANT: This class was intended to be abstract and
+ * should <em>never</em> be referenced or instantiated.
+ * Instead, the class <code>Shell</code> should be used.
+ * </p>
+ * <p>
+ * Instances are always displayed in one of the maximized,
+ * minimized or normal states:
+ * <ul>
+ * <li>
+ * When an instance is marked as <em>maximized</em>, the
+ * window manager will typically resize it to fill the
+ * entire visible area of the display, and the instance
+ * is usually put in a state where it can not be resized
+ * (even if it has style <code>RESIZE</code>) until it is
+ * no longer maximized.
+ * </li><li>
+ * When an instance is in the <em>normal</em> state (neither
+ * maximized or minimized), its appearance is controlled by
+ * the style constants which were specified when it was created
+ * and the restrictions of the window manager (see below).
+ * </li><li>
+ * When an instance has been marked as <em>minimized</em>,
+ * its contents (client area) will usually not be visible,
+ * and depending on the window manager, it may be
+ * "iconified" (that is, replaced on the desktop by a small
+ * simplified representation of itself), relocated to a
+ * distinguished area of the screen, or hidden. Combinations
+ * of these changes are also possible.
+ * </li>
+ * </ul>
+ * </p>
+ * Note: The styles supported by this class must be treated
+ * as <em>HINT</em>s, since the window manager for the
+ * desktop on which the instance is visible has ultimate
+ * control over the appearance and behavior of decorations.
+ * For example, some window managers only support resizable
+ * windows and will always assume the RESIZE style, even if
+ * it is not set.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE, ON_TOP, TOOL</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * Class <code>SWT</code> provides two "convenience constants"
+ * for the most commonly required style combinations:
+ * <dl>
+ * <dt><code>SHELL_TRIM</code></dt>
+ * <dd>
+ * the result of combining the constants which are required
+ * to produce a typical application top level shell: (that
+ * is, <code>CLOSE | TITLE | MIN | MAX | RESIZE</code>)
+ * </dd>
+ * <dt><code>DIALOG_TRIM</code></dt>
+ * <dd>
+ * the result of combining the constants which are required
+ * to produce a typical application dialog shell: (that
+ * is, <code>TITLE | CLOSE | BORDER</code>)
+ * </dd>
+ * </dl>
+ * <p>
+ * IMPORTANT: This class is intended to be subclassed <em>only</em>
+ * within the SWT implementation.
+ * </p>
+ *
+ * @see #getMinimized
+ * @see #getMaximized
+ * @see Shell
+ * @see SWT
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Decorations extends Canvas {
+ Image image;
+ Image [] images = new Image [0];
+ Menu menuBar;
+ String text = "";
+ boolean minimized, maximized;
+ Control savedFocus;
+ Button defaultButton;
+
+Decorations () {
+ /* Do nothing */
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#BORDER
+ * @see SWT#CLOSE
+ * @see SWT#MIN
+ * @see SWT#MAX
+ * @see SWT#RESIZE
+ * @see SWT#TITLE
+ * @see SWT#NO_TRIM
+ * @see SWT#SHELL_TRIM
+ * @see SWT#DIALOG_TRIM
+ * @see SWT#ON_TOP
+ * @see SWT#TOOL
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Decorations (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+static int checkStyle (int style) {
+ if ((style & SWT.NO_TRIM) != 0) {
+ style &= ~(SWT.CLOSE | SWT.TITLE | SWT.MIN | SWT.MAX | SWT.RESIZE | SWT.BORDER);
+ }
+ if ((style & (SWT.MENU | SWT.MIN | SWT.MAX | SWT.CLOSE)) != 0) {
+ style |= SWT.TITLE;
+ }
+ return style;
+}
+
+void bringToTop (boolean force) {
+ moveAbove (null);
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+int compare (ImageData data1, ImageData data2) {
+ if (data1.width == data2.width && data1.height == data2.height) {
+ int transparent1 = data1.getTransparencyType ();
+ int transparent2 = data2.getTransparencyType ();
+ if (transparent1 == SWT.TRANSPARENCY_ALPHA) return -1;
+ if (transparent2 == SWT.TRANSPARENCY_ALPHA) return 1;
+ if (transparent1 == SWT.TRANSPARENCY_MASK) return -1;
+ if (transparent2 == SWT.TRANSPARENCY_MASK) return 1;
+ if (transparent1 == SWT.TRANSPARENCY_PIXEL) return -1;
+ if (transparent2 == SWT.TRANSPARENCY_PIXEL) return 1;
+ return 0;
+ }
+ return data1.width > data2.width || data1.height > data2.height ? -1 : 1;
+}
+
+Widget computeTabGroup () {
+ return this;
+}
+
+Control computeTabRoot () {
+ return this;
+}
+
+void fixDecorations (Decorations newDecorations, Control control, Menu [] menus) {
+ if (this == newDecorations) return;
+ if (control == savedFocus) savedFocus = null;
+ if (control == defaultButton) defaultButton = null;
+ if (menus == null) return;
+ Menu menu = control.menu;
+ if (menu != null) {
+ int index = 0;
+ while (index < menus.length) {
+ if (menus [index] == menu) {
+ control.setMenu (null);
+ return;
+ }
+ index++;
+ }
+ menu.fixMenus (newDecorations);
+ }
+}
+
+/**
+ * Returns the receiver's default button if one had
+ * previously been set, otherwise returns null.
+ *
+ * @return the default button or null
+ *
+ * @exception SWTException <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 #setDefaultButton(Button)
+ */
+public Button getDefaultButton () {
+ checkWidget();
+ return defaultButton;
+}
+
+/**
+ * Returns the receiver's image if it had previously been
+ * set using <code>setImage()</code>. The image is typically
+ * displayed by the window manager when the instance is
+ * marked as iconified, and may also be displayed somewhere
+ * in the trim when the instance is in normal or maximized
+ * states.
+ * <p>
+ * Note: This method will return null if called before
+ * <code>setImage()</code> is called. It does not provide
+ * access to a window manager provided, "default" image
+ * even if one exists.
+ * </p>
+ *
+ * @return the image
+ *
+ * @exception SWTException <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 Image getImage () {
+ checkWidget();
+ return image;
+}
+
+/**
+ * Returns the receiver's images if they had previously been
+ * set using <code>setImages()</code>. Images are typically
+ * displayed by the window manager when the instance is
+ * marked as iconified, and may also be displayed somewhere
+ * in the trim when the instance is in normal or maximized
+ * states. Depending where the icon is displayed, the platform
+ * chooses the icon with the "best" attributes. It is expected
+ * that the array will contain the same icon rendered at different
+ * sizes, with different depth and transparency attributes.
+ *
+ * <p>
+ * Note: This method will return an empty array if called before
+ * <code>setImages()</code> is called. It does not provide
+ * access to a window manager provided, "default" image
+ * even if one exists.
+ * </p>
+ *
+ * @return the images
+ *
+ * @exception SWTException <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.0
+ */
+public Image [] getImages () {
+ checkWidget ();
+ if (images == null) return new Image [0];
+ Image [] result = new Image [images.length];
+ System.arraycopy (images, 0, result, 0, images.length);
+ return result;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is currently
+ * maximized, and false otherwise.
+ * <p>
+ *
+ * @return the maximized state
+ *
+ * @exception SWTException <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 #setMaximized
+ */
+public boolean getMaximized () {
+ checkWidget();
+ return maximized;
+}
+
+/**
+ * Returns the receiver's menu bar if one had previously
+ * been set, otherwise returns null.
+ *
+ * @return the menu bar or null
+ *
+ * @exception SWTException <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 Menu getMenuBar () {
+ checkWidget();
+ return menuBar;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is currently
+ * minimized, and false otherwise.
+ * <p>
+ *
+ * @return the minimized state
+ *
+ * @exception SWTException <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 #setMinimized
+ */
+public boolean getMinimized () {
+ checkWidget();
+ return minimized;
+}
+
+String getNameText () {
+ return getText ();
+}
+
+/**
+ * Returns the receiver's text, which is the string that the
+ * window manager will typically display as the receiver's
+ * <em>title</em>. If the text has not previously been set,
+ * returns an empty string.
+ *
+ * @return the text
+ *
+ * @exception SWTException <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 String getText () {
+ checkWidget();
+ return text;
+}
+
+public boolean isReparentable () {
+ checkWidget();
+ return false;
+}
+
+boolean isTabGroup () {
+ return true;
+}
+
+boolean isTabItem () {
+ return false;
+}
+
+Decorations menuShell () {
+ return this;
+}
+
+void releaseChildren (boolean destroy) {
+ if (menuBar != null) {
+ menuBar.dispose ();
+ menuBar = null;
+ }
+ Display display = this.display;
+ super.releaseChildren (destroy);
+ Menu [] menus = display.getMenus (this);
+ if (menus != null) {
+ for (int i=0; i<menus.length; i++) {
+ Menu menu = menus [i];
+ if (menu != null && !menu.isDisposed ()) {
+ menu.dispose ();
+ }
+ }
+ menus = null;
+ }
+}
+void releaseWidget () {
+ super.releaseWidget ();
+ image = null;
+ images = null;
+ savedFocus = null;
+ defaultButton = null;
+}
+
+boolean restoreFocus () {
+ if (savedFocus != null && savedFocus.isDisposed ()) savedFocus = null;
+ if (savedFocus == null) return false;
+ return savedFocus.forceFocus ();
+}
+
+void saveFocus () {
+// int window = OS.GetControlOwner (handle);
+// Control control = display.getFocusControl (window, false);
+// if (control != null && control != this && this == control.menuShell ()) {
+// setSavedFocus (control);
+// }
+}
+
+/**
+ * If the argument is not null, sets the receiver's default
+ * button to the argument, and if the argument is null, sets
+ * the receiver's default button to the first button which
+ * was set as the receiver's default button (called the
+ * <em>saved default button</em>). If no default button had
+ * previously been set, or the saved default button was
+ * disposed, the receiver's default button will be set to
+ * null.
+ * <p>
+ * The default button is the button that is selected when
+ * the receiver is active and the user presses ENTER.
+ * </p>
+ *
+ * @param button the new default button
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the button has been disposed</li>
+ * <li>ERROR_INVALID_PARENT - if the control is not in the same widget tree</li>
+ * </ul>
+ * @exception SWTException <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 setDefaultButton (Button button) {
+ checkWidget();
+ if (button != null) {
+ if (button.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (button.menuShell () != this) error (SWT.ERROR_INVALID_PARENT);
+ if ((button.style & SWT.PUSH) == 0) return;
+ }
+ if (button == defaultButton) return;
+ defaultButton = button;
+ NSButtonCell cell = null;
+ if (defaultButton != null && (defaultButton.style & SWT.PUSH) != 0) {
+ cell = new NSButtonCell (((NSButton)defaultButton.view).cell ());
+ }
+ view.window().setDefaultButtonCell (cell);
+ display.updateDefaultButton();
+}
+
+/**
+ * Sets the receiver's image to the argument, which may
+ * be null. The image is typically displayed by the window
+ * manager when the instance is marked as iconified, and
+ * may also be displayed somewhere in the trim when the
+ * instance is in normal or maximized states.
+ *
+ * @param image the new image (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setImage (Image image) {
+ checkWidget();
+ if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ this.image = image;
+ if (parent != null) return;
+ if (display.dockImage == null) {
+ display.application.setApplicationIconImage (image != null ? image.handle : null);
+ }
+}
+
+/**
+ * Sets the receiver's images to the argument, which may
+ * be an empty array. Images are typically displayed by the
+ * window manager when the instance is marked as iconified,
+ * and may also be displayed somewhere in the trim when the
+ * instance is in normal or maximized states. Depending where
+ * the icon is displayed, the platform chooses the icon with
+ * the "best" attributes. It is expected that the array will
+ * contain the same icon rendered at different sizes, with
+ * different depth and transparency attributes.
+ *
+ * @param images the new image array
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the array of images is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if one of the images is null or has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.0
+ */
+public void setImages (Image [] images) {
+ checkWidget();
+ if (images == null) error(SWT.ERROR_INVALID_ARGUMENT);
+ for (int i = 0; i < images.length; i++) {
+ if (images [i] == null || images [i].isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.images = images;
+ if (parent != null) return;
+ if (display.dockImage == null) {
+ if (images != null && images.length > 1) {
+ Image [] bestImages = new Image [images.length];
+ System.arraycopy (images, 0, bestImages, 0, images.length);
+ sort (bestImages);
+ images = bestImages;
+ }
+ if (images != null && images.length > 0) {
+ display.application.setApplicationIconImage (images [0].handle);
+ } else {
+ display.application.setApplicationIconImage (null);
+ }
+ }
+}
+
+/**
+ * Sets the maximized state of the receiver.
+ * If the argument is <code>true</code> causes the receiver
+ * to switch to the maximized state, and if the argument is
+ * <code>false</code> and the receiver was previously maximized,
+ * causes the receiver to switch back to either the minimized
+ * or normal states.
+ * <p>
+ * Note: The result of intermixing calls to <code>setMaximized(true)</code>
+ * and <code>setMinimized(true)</code> will vary by platform. Typically,
+ * the behavior will match the platform user's expectations, but not
+ * always. This should be avoided if possible.
+ * </p>
+ *
+ * @param maximized the new maximized state
+ *
+ * @exception SWTException <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 #setMinimized
+ */
+public void setMaximized (boolean maximized) {
+ checkWidget();
+ this.maximized = maximized;
+}
+
+/**
+ * Sets the receiver's menu bar to the argument, which
+ * may be null.
+ *
+ * @param menu the new menu bar
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the menu has been disposed</li>
+ * <li>ERROR_INVALID_PARENT - if the menu is not in the same widget tree</li>
+ * </ul>
+ * @exception SWTException <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 setMenuBar (Menu menu) {
+ checkWidget();
+ if (menuBar == menu) return;
+ if (menu != null) {
+ if (menu.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ if ((menu.style & SWT.BAR) == 0) error (SWT.ERROR_MENU_NOT_BAR);
+ if (menu.parent != this) error (SWT.ERROR_INVALID_PARENT);
+ }
+ menuBar = menu;
+}
+
+/**
+ * Sets the minimized stated of the receiver.
+ * If the argument is <code>true</code> causes the receiver
+ * to switch to the minimized state, and if the argument is
+ * <code>false</code> and the receiver was previously minimized,
+ * causes the receiver to switch back to either the maximized
+ * or normal states.
+ * <p>
+ * Note: The result of intermixing calls to <code>setMaximized(true)</code>
+ * and <code>setMinimized(true)</code> will vary by platform. Typically,
+ * the behavior will match the platform user's expectations, but not
+ * always. This should be avoided if possible.
+ * </p>
+ *
+ * @param minimized the new maximized state
+ *
+ * @exception SWTException <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 #setMaximized
+ */
+public void setMinimized (boolean minimized) {
+ checkWidget();
+ this.minimized = minimized;
+}
+
+void setSavedFocus (Control control) {
+ savedFocus = control;
+}
+
+/**
+ * Sets the receiver's text, which is the string that the
+ * window manager will typically display as the receiver's
+ * <em>title</em>, to the argument, which must not be null.
+ *
+ * @param string the new text
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
+ * </ul>
+ * @exception SWTException <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 setText (String string) {
+ checkWidget();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ text = string;
+}
+
+void sort (Image [] images) {
+ /* Shell Sort from K&R, pg 108 */
+ int length = images.length;
+ if (length <= 1) return;
+ ImageData [] datas = new ImageData [length];
+ for (int i = 0; i < length; i++) {
+ datas [i] = images [i].getImageData ();
+ }
+ for (int gap=length/2; gap>0; gap/=2) {
+ for (int i=gap; i<length; i++) {
+ for (int j=i-gap; j>=0; j-=gap) {
+ if (compare (datas [j], datas [j + gap]) >= 0) {
+ Image swap = images [j];
+ images [j] = images [j + gap];
+ images [j + gap] = swap;
+ ImageData swapData = datas [j];
+ datas [j] = datas [j + gap];
+ datas [j + gap] = swapData;
+ }
+ }
+ }
+ }
+}
+
+boolean traverseItem (boolean next) {
+ return false;
+}
+
+boolean traverseReturn () {
+ if (defaultButton == null || defaultButton.isDisposed ()) return false;
+ if (!defaultButton.isVisible () || !defaultButton.isEnabled ()) return false;
+ defaultButton.click ();
+ return true;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/DirectoryDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/DirectoryDialog.java
new file mode 100755
index 0000000000..e12f40c639
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/DirectoryDialog.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+import org.eclipse.swt.*;
+
+
+/**
+ * Instances of this class allow the user to navigate
+ * the file system and select a directory.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * IMPORTANT: This class is intended to be subclassed <em>only</em>
+ * within the SWT implementation.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#directorydialog">DirectoryDialog snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample, Dialog tab</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class DirectoryDialog extends Dialog {
+ String message = "", filterPath = "";
+
+/**
+ * Constructs a new instance of this class given only its parent.
+ *
+ * @param parent a shell which will be the parent of the new instance
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <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>
+ */
+public DirectoryDialog (Shell parent) {
+ this (parent, SWT.APPLICATION_MODAL);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 shell which will be the parent of the new instance
+ * @param style the style of dialog to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <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>
+ */
+public DirectoryDialog (Shell parent, int style) {
+ super (parent, checkStyle (parent, style));
+ if (Display.getSheetEnabled ()) {
+ if (parent != null && (style & SWT.SHEET) != 0) this.style |= SWT.SHEET;
+ }
+ checkSubclass ();
+}
+
+/**
+ * Returns the path which the dialog will use to filter
+ * the directories it shows.
+ *
+ * @return the filter path
+ *
+ * @see #setFilterPath
+ */
+public String getFilterPath () {
+ return filterPath;
+}
+
+/**
+ * Returns the dialog's message, which is a description of
+ * the purpose for which it was opened. This message will be
+ * visible on the dialog while it is open.
+ *
+ * @return the message
+ */
+public String getMessage () {
+ return message;
+}
+
+/**
+ * Makes the dialog visible and brings it to the front
+ * of the display.
+ *
+ * @return a string describing the absolute path of the selected directory,
+ * or null if the dialog was cancelled or an error occurred
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the dialog has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the dialog</li>
+ * </ul>
+ */
+public String open () {
+ String directoryPath = null;
+ NSOpenPanel panel = NSOpenPanel.openPanel();
+ panel.setCanCreateDirectories(true);
+ panel.setAllowsMultipleSelection((style & SWT.MULTI) != 0);
+ panel.setTitle(NSString.stringWith(title != null ? title : ""));
+ panel.setMessage(NSString.stringWith(message != null ? message : ""));
+ panel.setCanChooseFiles(false);
+ panel.setCanChooseDirectories(true);
+ NSApplication application = NSApplication.sharedApplication();
+ if (parent != null && (style & SWT.SHEET) != 0) {
+ application.beginSheet(panel, parent.window, null, 0, 0);
+ }
+ NSString dir = filterPath != null ? NSString.stringWith(filterPath) : null;
+ int /*long*/ response = panel.runModalForDirectory(dir, null);
+ if (parent != null && (style & SWT.SHEET) != 0) {
+ application.endSheet(panel, 0);
+ }
+ if (response == OS.NSFileHandlingPanelOKButton) {
+ NSString filename = panel.filename();
+ directoryPath = filterPath = filename.getString();
+ }
+// options.optionFlags = OS.kNavSupportPackages | OS.kNavAllowOpenPackages | OS.kNavAllowInvisibleFiles;
+ return directoryPath;
+}
+
+/**
+ * Sets the dialog's message, which is a description of
+ * the purpose for which it was opened. This message will be
+ * visible on the dialog while it is open.
+ *
+ * @param string the message
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ */
+public void setMessage (String string) {
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ message = string;
+}
+
+/**
+ * Sets the path that the dialog will use to filter
+ * the directories it shows to the argument, which may
+ * be null. If the string is null, then the operating
+ * system's default filter path will be used.
+ * <p>
+ * Note that the path string is platform dependent.
+ * For convenience, either '/' or '\' can be used
+ * as a path separator.
+ * </p>
+ *
+ * @param string the filter path
+ */
+public void setFilterPath (String string) {
+ filterPath = string;
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java
new file mode 100755
index 0000000000..5c82734c1c
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java
@@ -0,0 +1,4900 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class are responsible for managing the
+ * connection between SWT and the underlying operating
+ * system. Their most important function is to implement
+ * the SWT event loop in terms of the platform event model.
+ * They also provide various methods for accessing information
+ * about the operating system, and have overall control over
+ * the operating system resources which SWT allocates.
+ * <p>
+ * Applications which are built with SWT will <em>almost always</em>
+ * require only a single display. In particular, some platforms
+ * which SWT supports will not allow more than one <em>active</em>
+ * display. In other words, some platforms do not support
+ * creating a new display if one already exists that has not been
+ * sent the <code>dispose()</code> message.
+ * <p>
+ * In SWT, the thread which creates a <code>Display</code>
+ * instance is distinguished as the <em>user-interface thread</em>
+ * for that display.
+ * </p>
+ * The user-interface thread for a particular display has the
+ * following special attributes:
+ * <ul>
+ * <li>
+ * The event loop for that display must be run from the thread.
+ * </li>
+ * <li>
+ * Some SWT API methods (notably, most of the public methods in
+ * <code>Widget</code> and its subclasses), may only be called
+ * from the thread. (To support multi-threaded user-interface
+ * applications, class <code>Display</code> provides inter-thread
+ * communication methods which allow threads other than the
+ * user-interface thread to request that it perform operations
+ * on their behalf.)
+ * </li>
+ * <li>
+ * The thread is not allowed to construct other
+ * <code>Display</code>s until that display has been disposed.
+ * (Note that, this is in addition to the restriction mentioned
+ * above concerning platform support for multiple displays. Thus,
+ * the only way to have multiple simultaneously active displays,
+ * even on platforms which support it, is to have multiple threads.)
+ * </li>
+ * </ul>
+ * Enforcing these attributes allows SWT to be implemented directly
+ * on the underlying operating system's event model. This has
+ * numerous benefits including smaller footprint, better use of
+ * resources, safer memory management, clearer program logic,
+ * better performance, and fewer overall operating system threads
+ * required. The down side however, is that care must be taken
+ * (only) when constructing multi-threaded applications to use the
+ * inter-thread communication mechanisms which this class provides
+ * when required.
+ * </p><p>
+ * All SWT API methods which may only be called from the user-interface
+ * thread are distinguished in their documentation by indicating that
+ * they throw the "<code>ERROR_THREAD_INVALID_ACCESS</code>"
+ * SWT exception.
+ * </p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Close, Dispose, Settings</dd>
+ * </dl>
+ * <p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ * @see #syncExec
+ * @see #asyncExec
+ * @see #wake
+ * @see #readAndDispatch
+ * @see #sleep
+ * @see Device#dispose
+ * @see <a href="http://www.eclipse.org/swt/snippets/#display">Display snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Display extends Device {
+
+ /* Windows and Events */
+ Event [] eventQueue;
+ EventTable eventTable, filterTable;
+ boolean disposing;
+ int sendEventCount;
+
+ /* Key event management */
+ int [] deadKeyState = new int[1];
+ int currentKeyboardUCHRdata;
+ boolean eventSourceDelaySet;
+
+ /* Sync/Async Widget Communication */
+ Synchronizer synchronizer;
+ Thread thread;
+ boolean allowTimers, runAsyncMessages;
+
+ GCData[] contexts;
+
+ Caret currentCaret;
+
+ boolean sendEvent;
+ Control currentControl, trackingControl, tooltipControl;
+ Widget tooltipTarget;
+
+ NSMutableArray isPainting, needsDisplay, needsDisplayInRect;
+
+ NSDictionary markedAttributes;
+
+ /* Fonts */
+ boolean smallFonts;
+ NSFont buttonFont, popUpButtonFont, textFieldFont, secureTextFieldFont;
+ NSFont searchFieldFont, comboBoxFont, sliderFont, scrollerFont;
+ NSFont textViewFont, tableViewFont, outlineViewFont, datePickerFont;
+ NSFont boxFont, tabViewFont, progressIndicatorFont;
+
+ Shell [] modalShells;
+
+ Menu menuBar;
+ Menu[] menus, popups;
+
+ NSApplication application;
+ int /*long*/ applicationClass;
+ NSImage dockImage;
+ boolean isEmbedded;
+ static boolean launched = false;
+
+ /* Focus */
+ Control focusControl, currentFocusControl;
+ int focusEvent;
+
+ NSWindow screenWindow, keyWindow;
+
+ NSAutoreleasePool[] pools;
+ int poolCount, loopCount;
+
+ int[] screenID = new int[32];
+ NSPoint[] screenCascade = new NSPoint[32];
+
+ int /*long*/ runLoopObserver;
+ Callback observerCallback;
+
+ boolean lockCursor = true;
+ int /*long*/ oldCursorSetProc;
+ Callback cursorSetCallback;
+
+ // the following Callbacks are never freed
+ static Callback windowCallback2, windowCallback3, windowCallback4, windowCallback5, windowCallback6;
+ static Callback dialogCallback3, dialogCallback4, dialogCallback5;
+ static Callback applicationCallback2, applicationCallback3, applicationCallback6;
+ static Callback fieldEditorCallback3, fieldEditorCallback4;
+
+ /* Display Shutdown */
+ Runnable [] disposeList;
+
+ /* System Tray */
+ Tray tray;
+ TrayItem currentTrayItem;
+ Menu trayItemMenu;
+
+ /* System Resources */
+ Image errorImage, infoImage, warningImage;
+ Cursor [] cursors = new Cursor [SWT.CURSOR_HAND + 1];
+
+ /* System Colors */
+ float /*double*/ [][] colors;
+ float /*double*/ [] alternateSelectedControlTextColor, selectedControlTextColor;
+ float /*double*/ [] alternateSelectedControlColor, secondarySelectedControlColor;
+
+ /* Key Mappings. */
+ static int [] [] KeyTable = {
+
+ /* Keyboard and Mouse Masks */
+ {58, SWT.ALT},
+ {56, SWT.SHIFT},
+ {59, SWT.CONTROL},
+ {55, SWT.COMMAND},
+ {61, SWT.ALT},
+ {62, SWT.CONTROL},
+ {60, SWT.SHIFT},
+ {54, SWT.COMMAND},
+
+ /* Non-Numeric Keypad Keys */
+ {126, SWT.ARROW_UP},
+ {125, SWT.ARROW_DOWN},
+ {123, SWT.ARROW_LEFT},
+ {124, SWT.ARROW_RIGHT},
+ {116, SWT.PAGE_UP},
+ {121, SWT.PAGE_DOWN},
+ {115, SWT.HOME},
+ {119, SWT.END},
+// {??, SWT.INSERT},
+
+ /* Virtual and Ascii Keys */
+ {51, SWT.BS},
+ {36, SWT.CR},
+ {117, SWT.DEL},
+ {53, SWT.ESC},
+ {76, SWT.LF},
+ {48, SWT.TAB},
+
+ /* Functions Keys */
+ {122, SWT.F1},
+ {120, SWT.F2},
+ {99, SWT.F3},
+ {118, SWT.F4},
+ {96, SWT.F5},
+ {97, SWT.F6},
+ {98, SWT.F7},
+ {100, SWT.F8},
+ {101, SWT.F9},
+ {109, SWT.F10},
+ {103, SWT.F11},
+ {111, SWT.F12},
+ {105, SWT.F13},
+ {107, SWT.F14},
+ {113, SWT.F15},
+
+ /* Numeric Keypad Keys */
+ {67, SWT.KEYPAD_MULTIPLY},
+ {69, SWT.KEYPAD_ADD},
+ {76, SWT.KEYPAD_CR},
+ {78, SWT.KEYPAD_SUBTRACT},
+ {65, SWT.KEYPAD_DECIMAL},
+ {75, SWT.KEYPAD_DIVIDE},
+ {82, SWT.KEYPAD_0},
+ {83, SWT.KEYPAD_1},
+ {84, SWT.KEYPAD_2},
+ {85, SWT.KEYPAD_3},
+ {86, SWT.KEYPAD_4},
+ {87, SWT.KEYPAD_5},
+ {88, SWT.KEYPAD_6},
+ {89, SWT.KEYPAD_7},
+ {91, SWT.KEYPAD_8},
+ {92, SWT.KEYPAD_9},
+ {81, SWT.KEYPAD_EQUAL},
+
+ /* Other keys */
+ {57, SWT.CAPS_LOCK},
+ {71, SWT.NUM_LOCK},
+// {??, SWT.SCROLL_LOCK},
+// {??, SWT.PAUSE},
+// {??, SWT.BREAK},
+// {??, SWT.PRINT_SCREEN},
+ {114, SWT.HELP},
+
+ };
+
+ static String APP_NAME;
+ static final String ADD_WIDGET_KEY = "org.eclipse.swt.internal.addWidget"; //$NON-NLS-1$
+ static final byte[] SWT_OBJECT = {'S', 'W', 'T', '_', 'O', 'B', 'J', 'E', 'C', 'T', '\0'};
+ static final byte[] SWT_IMAGE = {'S', 'W', 'T', '_', 'I', 'M', 'A', 'G', 'E', '\0'};
+ static final byte[] SWT_ROW = {'S', 'W', 'T', '_', 'R', 'O', 'W', '\0'};
+ static final byte[] SWT_COLUMN = {'S', 'W', 'T', '_', 'C', 'O', 'L', 'U', 'M', 'N', '\0'};
+
+ /* Multiple Displays. */
+ static Display Default;
+ static Display [] Displays = new Display [4];
+
+ /* Package Name */
+ static final String PACKAGE_PREFIX = "org.eclipse.swt.widgets.";
+
+ /* Timer */
+ Runnable timerList [];
+ NSTimer nsTimers [];
+ SWTWindowDelegate timerDelegate;
+ static SWTApplicationDelegate applicationDelegate;
+
+ /* Settings */
+ boolean runSettings;
+ SWTWindowDelegate settingsDelegate;
+
+ static final int DEFAULT_BUTTON_INTERVAL = 30;
+
+ /* Display Data */
+ Object data;
+ String [] keys;
+ Object [] values;
+
+ /*
+ * TEMPORARY CODE. Install the runnable that
+ * gets the current display. This code will
+ * be removed in the future.
+ */
+ static {
+ DeviceFinder = new Runnable () {
+ public void run () {
+ Device device = getCurrent ();
+ if (device == null) {
+ device = getDefault ();
+ }
+ setDevice (device);
+ }
+ };
+ }
+
+/*
+* TEMPORARY CODE.
+*/
+static void setDevice (Device device) {
+ CurrentDevice = device;
+}
+
+static byte [] ascii (String name) {
+ int length = name.length ();
+ char [] chars = new char [length];
+ name.getChars (0, length, chars, 0);
+ byte [] buffer = new byte [length + 1];
+ for (int i=0; i<length; i++) {
+ buffer [i] = (byte) chars [i];
+ }
+ return buffer;
+}
+
+static int translateKey (int key) {
+ for (int i=0; i<KeyTable.length; i++) {
+ if (KeyTable [i] [0] == key) return KeyTable [i] [1];
+ }
+ return 0;
+}
+
+static int untranslateKey (int key) {
+ for (int i=0; i<KeyTable.length; i++) {
+ if (KeyTable [i] [1] == key) return KeyTable [i] [0];
+ }
+ return 0;
+}
+
+void addContext (GCData context) {
+ if (contexts == null) contexts = new GCData [12];
+ for (int i=0; i<contexts.length; i++) {
+ if (contexts[i] != null && contexts [i] == context) {
+ contexts [i] = context;
+ return;
+ }
+ }
+ GCData [] newContexts = new GCData [contexts.length + 12];
+ newContexts [contexts.length] = context;
+ System.arraycopy (contexts, 0, newContexts, 0, contexts.length);
+ contexts = newContexts;
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when an event of the given type occurs anywhere
+ * in a widget. The event type is one of the event constants
+ * defined in class <code>SWT</code>. When the event does occur,
+ * the listener is notified by sending it the <code>handleEvent()</code>
+ * message.
+ * <p>
+ * Setting the type of an event to <code>SWT.None</code> from
+ * within the <code>handleEvent()</code> method can be used to
+ * change the event type and stop subsequent Java listeners
+ * from running. Because event filters run before other listeners,
+ * event filters can both block other listeners and set arbitrary
+ * fields within an event. For this reason, event filters are both
+ * powerful and dangerous. They should generally be avoided for
+ * performance, debugging and code maintenance reasons.
+ * </p>
+ *
+ * @param eventType the type of event to listen for
+ * @param listener the listener which should be notified when the event occurs
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Listener
+ * @see SWT
+ * @see #removeFilter
+ * @see #removeListener
+ *
+ * @since 3.0
+ */
+public void addFilter (int eventType, Listener listener) {
+ checkDevice ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (filterTable == null) filterTable = new EventTable ();
+ filterTable.hook (eventType, listener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when an event of the given type occurs. The event
+ * type is one of the event constants defined in class <code>SWT</code>.
+ * When the event does occur in the display, the listener is notified by
+ * sending it the <code>handleEvent()</code> message.
+ *
+ * @param eventType the type of event to listen for
+ * @param listener the listener which should be notified when the event occurs
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Listener
+ * @see SWT
+ * @see #removeListener
+ *
+ * @since 2.0
+ */
+public void addListener (int eventType, Listener listener) {
+ checkDevice ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) eventTable = new EventTable ();
+ eventTable.hook (eventType, listener);
+}
+
+void addMenu (Menu menu) {
+ if (menus == null) menus = new Menu [12];
+ for (int i=0; i<menus.length; i++) {
+ if (menus [i] == null) {
+ menus [i] = menu;
+ return;
+ }
+ }
+ Menu [] newMenus = new Menu [menus.length + 12];
+ newMenus [menus.length] = menu;
+ System.arraycopy (menus, 0, newMenus, 0, menus.length);
+ menus = newMenus;
+}
+
+void addPool () {
+ addPool ((NSAutoreleasePool)new NSAutoreleasePool().alloc().init());
+}
+
+void addPool (NSAutoreleasePool pool) {
+ if (pools == null) pools = new NSAutoreleasePool [4];
+ if (poolCount == pools.length) {
+ NSAutoreleasePool[] temp = new NSAutoreleasePool [poolCount + 4];
+ System.arraycopy (pools, 0, temp, 0, poolCount);
+ pools = temp;
+ }
+ if (poolCount == 0) {
+ NSMutableDictionary dictionary = NSThread.currentThread().threadDictionary();
+ dictionary.setObject(NSNumber.numberWithInteger(pool.id), NSString.stringWith("SWT_NSAutoreleasePool"));
+ }
+ pools [poolCount++] = pool;
+}
+
+void addPopup (Menu menu) {
+ if (popups == null) popups = new Menu [4];
+ int length = popups.length;
+ for (int i=0; i<length; i++) {
+ if (popups [i] == menu) return;
+ }
+ int index = 0;
+ while (index < length) {
+ if (popups [index] == null) break;
+ index++;
+ }
+ if (index == length) {
+ Menu [] newPopups = new Menu [length + 4];
+ System.arraycopy (popups, 0, newPopups, 0, length);
+ popups = newPopups;
+ }
+ popups [index] = menu;
+}
+
+void addWidget (NSObject view, Widget widget) {
+ if (view == null) return;
+ OS.object_setInstanceVariable (view.id, SWT_OBJECT, widget.jniRef);
+}
+
+/**
+ * Causes the <code>run()</code> method of the runnable to
+ * be invoked by the user-interface thread at the next
+ * reasonable opportunity. The caller of this method continues
+ * to run in parallel, and is not notified when the
+ * runnable has completed. Specifying <code>null</code> as the
+ * runnable simply wakes the user-interface thread when run.
+ * <p>
+ * Note that at the time the runnable is invoked, widgets
+ * that have the receiver as their display may have been
+ * disposed. Therefore, it is necessary to check for this
+ * case inside the runnable before accessing the widget.
+ * </p>
+ *
+ * @param runnable code to run on the user-interface thread or <code>null</code>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #syncExec
+ */
+public void asyncExec (Runnable runnable) {
+ synchronized (Device.class) {
+ if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+ synchronizer.asyncExec (runnable);
+ }
+}
+
+/**
+ * Causes the system hardware to emit a short sound
+ * (if it supports this capability).
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void beep () {
+ checkDevice ();
+ OS.NSBeep ();
+}
+
+void cascadeWindow (NSWindow window, NSScreen screen) {
+ NSDictionary dictionary = screen.deviceDescription();
+ int screenNumber = new NSNumber(dictionary.objectForKey(NSString.stringWith("NSScreenNumber")).id).intValue();
+ int index = 0;
+ while (screenID[index] != 0 && screenID[index] != screenNumber) index++;
+ screenID[index] = screenNumber;
+ NSPoint cascade = screenCascade[index];
+ if (cascade == null) {
+ NSRect frame = screen.frame();
+ cascade = new NSPoint();
+ cascade.x = frame.x;
+ cascade.y = frame.y + frame.height;
+ }
+ screenCascade[index] = window.cascadeTopLeftFromPoint(cascade);
+}
+
+protected void checkDevice () {
+ if (thread == null) error (SWT.ERROR_WIDGET_DISPOSED);
+ if (thread != Thread.currentThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
+ if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+}
+
+void checkEnterExit (Control control, NSEvent nsEvent, boolean send) {
+ if (control != currentControl) {
+ if (currentControl != null && !currentControl.isDisposed()) {
+ currentControl.sendMouseEvent (nsEvent, SWT.MouseExit, send);
+ }
+ if (control != null && control.isDisposed()) control = null;
+ currentControl = control;
+ if (control != null) {
+ control.sendMouseEvent (nsEvent, SWT.MouseEnter, send);
+ }
+ setCursor (control);
+ }
+ timerExec (control != null && !control.isDisposed() ? getToolTipTime () : -1, hoverTimer);
+}
+
+void checkFocus () {
+ Control oldControl = currentFocusControl;
+ Control newControl = getFocusControl ();
+ if (oldControl != newControl) {
+ if (oldControl != null && !oldControl.isDisposed ()) {
+ oldControl.sendFocusEvent (SWT.FocusOut);
+ }
+ currentFocusControl = newControl;
+ if (newControl != null && !newControl.isDisposed ()) {
+ newControl.sendFocusEvent (SWT.FocusIn);
+ }
+ }
+}
+
+/**
+ * Checks that this class can be subclassed.
+ * <p>
+ * IMPORTANT: See the comment in <code>Widget.checkSubclass()</code>.
+ * </p>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ *
+ * @see Widget#checkSubclass
+ */
+protected void checkSubclass () {
+ if (!Display.isValidClass (getClass ())) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+/**
+ * Constructs a new instance of this class.
+ * <p>
+ * Note: The resulting display is marked as the <em>current</em>
+ * display. If this is the first display which has been
+ * constructed since the application started, it is also
+ * marked as the <em>default</em> display.
+ * </p>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if called from a thread that already created an existing display</li>
+ * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ *
+ * @see #getCurrent
+ * @see #getDefault
+ * @see Widget#checkSubclass
+ * @see Shell
+ */
+public Display () {
+ this (null);
+}
+
+/**
+ * Constructs a new instance of this class using the parameter.
+ *
+ * @param data the device data
+ */
+public Display (DeviceData data) {
+ super (data);
+}
+
+static void checkDisplay (Thread thread, boolean multiple) {
+ synchronized (Device.class) {
+ for (int i=0; i<Displays.length; i++) {
+ if (Displays [i] != null) {
+ if (!multiple) SWT.error (SWT.ERROR_NOT_IMPLEMENTED, null, " [multiple displays]");
+ if (Displays [i].thread == thread) SWT.error (SWT.ERROR_THREAD_INVALID_ACCESS);
+ }
+ }
+ }
+}
+
+static String convertToLf(String text) {
+ char Cr = '\r';
+ char Lf = '\n';
+ int length = text.length ();
+ if (length == 0) return text;
+
+ /* Check for an LF or CR/LF. Assume the rest of the string
+ * is formated that way. This will not work if the string
+ * contains mixed delimiters. */
+ int i = text.indexOf (Lf, 0);
+ if (i == -1 || i == 0) return text;
+ if (text.charAt (i - 1) != Cr) return text;
+
+ /* The string is formatted with CR/LF.
+ * Create a new string with the LF line delimiter. */
+ i = 0;
+ StringBuffer result = new StringBuffer ();
+ while (i < length) {
+ int j = text.indexOf (Cr, i);
+ if (j == -1) j = length;
+ String s = text.substring (i, j);
+ result.append (s);
+ i = j + 2;
+ result.append (Lf);
+ }
+ return result.toString ();
+}
+
+void clearModal (Shell shell) {
+ if (modalShells == null) return;
+ int index = 0, length = modalShells.length;
+ while (index < length) {
+ if (modalShells [index] == shell) break;
+ if (modalShells [index] == null) return;
+ index++;
+ }
+ if (index == length) return;
+ System.arraycopy (modalShells, index + 1, modalShells, index, --length - index);
+ modalShells [length] = null;
+ if (index == 0 && modalShells [0] == null) modalShells = null;
+ Shell [] shells = getShells ();
+ for (int i=0; i<shells.length; i++) shells [i].updateModal ();
+}
+
+void clearPool () {
+ if (sendEventCount == 0 && loopCount == poolCount - 1 && Callback.getEntryCount () == 0) {
+ removePool ();
+ addPool ();
+ }
+}
+
+/**
+ * Requests that the connection between SWT and the underlying
+ * operating system be closed.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Device#dispose
+ *
+ * @since 2.0
+ */
+public void close () {
+ checkDevice ();
+ Event event = new Event ();
+ sendEvent (SWT.Close, event);
+ if (event.doit) dispose ();
+}
+
+/**
+ * Creates the device in the operating system. If the device
+ * does not have a handle, this method may do nothing depending
+ * on the device.
+ * <p>
+ * This method is called before <code>init</code>.
+ * </p>
+ *
+ * @param data the DeviceData which describes the receiver
+ *
+ * @see #init
+ */
+protected void create (DeviceData data) {
+ checkSubclass ();
+ checkDisplay (thread = Thread.currentThread (), false);
+ createDisplay (data);
+ register (this);
+ synchronizer = new Synchronizer (this);
+ if (Default == null) Default = this;
+}
+
+void createDisplay (DeviceData data) {
+ if (OS.VERSION < 0x1050) {
+ System.out.println ("***WARNING: SWT requires MacOS X version " + 10 + "." + 5 + " or greater"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ System.out.println ("***WARNING: Detected: " + Integer.toHexString((OS.VERSION & 0xFF00) >> 8) + "." + Integer.toHexString((OS.VERSION & 0xF0) >> 4) + "." + Integer.toHexString(OS.VERSION & 0xF)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ error(SWT.ERROR_NOT_IMPLEMENTED);
+ }
+
+ NSThread nsthread = NSThread.currentThread();
+ NSMutableDictionary dictionary = nsthread.threadDictionary();
+ NSString key = NSString.stringWith("SWT_NSAutoreleasePool");
+ NSNumber id = new NSNumber(dictionary.objectForKey(key));
+ addPool(new NSAutoreleasePool(id.integerValue()));
+
+ application = NSApplication.sharedApplication();
+
+ /*
+ * TODO: If an NSApplication is already running we don't want to create another NSApplication.
+ * But if we don't we won't get mouse events, since we currently need to subclass NSApplication and intercept sendEvent to
+ * deliver mouse events correctly to widgets.
+ */
+ if (!application.isRunning()) {
+ /*
+ * Feature in the Macintosh. On OS 10.2, it is necessary
+ * to explicitly check in with the Process Manager and set
+ * the current process to be the front process in order for
+ * windows to come to the front by default. The fix is call
+ * both GetCurrentProcess() and SetFrontProcess().
+ *
+ * NOTE: It is not actually necessary to use the process
+ * serial number returned by GetCurrentProcess() in the
+ * call to SetFrontProcess() (ie. kCurrentProcess can be
+ * used) but both functions must be called in order for
+ * windows to come to the front.
+ */
+ int [] psn = new int [2];
+ if (OS.GetCurrentProcess (psn) == OS.noErr) {
+ int pid = OS.getpid ();
+ int /*long*/ ptr = getAppName().UTF8String();
+ if (ptr != 0) OS.CPSSetProcessName (psn, ptr);
+ OS.TransformProcessType (psn, OS.kProcessTransformToForegroundApplication);
+ OS.SetFrontProcess (psn);
+ ptr = OS.getenv (ascii ("APP_ICON_" + pid));
+ if (ptr != 0) {
+ NSString path = NSString.stringWithUTF8String (ptr);
+ NSImage image = (NSImage) new NSImage().alloc();
+ image = image.initByReferencingFile(path);
+ dockImage = image;
+ application.setApplicationIconImage(image);
+ }
+ }
+
+ String className = "SWTApplication";
+ int /*long*/ cls;
+ if ((cls = OS.objc_lookUpClass (className)) == 0) {
+ Class clazz = getClass();
+ applicationCallback2 = new Callback(clazz, "applicationProc", 2);
+ int /*long*/ proc2 = applicationCallback2.getAddress();
+ if (proc2 == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ applicationCallback3 = new Callback(clazz, "applicationProc", 3);
+ int /*long*/ proc3 = applicationCallback3.getAddress();
+ if (proc3 == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ applicationCallback6 = new Callback(clazz, "applicationProc", 6);
+ int /*long*/ proc6 = applicationCallback6.getAddress();
+ if (proc6 == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ cls = OS.objc_allocateClassPair(OS.class_NSApplication, className, 0);
+ OS.class_addMethod(cls, OS.sel_sendEvent_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_nextEventMatchingMask_untilDate_inMode_dequeue_, proc6, "@:i@@B");
+ OS.class_addMethod(cls, OS.sel_isRunning, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_finishLaunching, proc2, "@:");
+ OS.objc_registerClassPair(cls);
+ }
+ applicationClass = OS.object_setClass(application.id, cls);
+
+ className = "SWTApplicationDelegate";
+ if (OS.objc_lookUpClass (className) == 0) {
+ int /*long*/ appProc3 = applicationCallback3.getAddress();
+ if (appProc3 == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ cls = OS.objc_allocateClassPair(OS.class_NSObject, className, 0);
+ OS.class_addMethod(cls, OS.sel_applicationWillFinishLaunching_, appProc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_terminate_, appProc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_quitRequested_, appProc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_orderFrontStandardAboutPanel_, appProc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_hideOtherApplications_, appProc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_hide_, appProc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_unhideAllApplications_, appProc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_applicationDidBecomeActive_, appProc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_applicationDidResignActive_, appProc3, "@:@");
+ OS.objc_registerClassPair(cls);
+ }
+ if (applicationDelegate == null) {
+ applicationDelegate = (SWTApplicationDelegate)new SWTApplicationDelegate().alloc().init();
+ application.setDelegate(applicationDelegate);
+ }
+ } else {
+ isEmbedded = true;
+ }
+}
+
+void createMainMenu () {
+ NSString appName = getAppName();
+ NSString emptyStr = NSString.stringWith("");
+ NSMenu mainMenu = (NSMenu)new NSMenu().alloc();
+ mainMenu.initWithTitle(emptyStr);
+
+ NSMenuItem menuItem;
+ NSMenu appleMenu;
+ NSString format = NSString.stringWith("%@ %@"), title;
+
+ NSMenuItem appItem = menuItem = mainMenu.addItemWithTitle(emptyStr, 0, emptyStr);
+ appleMenu = (NSMenu)new NSMenu().alloc();
+ appleMenu.initWithTitle(emptyStr);
+ OS.objc_msgSend(application.id, OS.sel_registerName("setAppleMenu:"), appleMenu.id);
+
+ title = new NSString(OS.objc_msgSend(OS.class_NSString, OS.sel_stringWithFormat_, format.id, NSString.stringWith(SWT.getMessage("About")).id, appName.id));
+ menuItem = appleMenu.addItemWithTitle(title, OS.sel_orderFrontStandardAboutPanel_, emptyStr);
+ menuItem.setTarget(applicationDelegate);
+
+ appleMenu.addItem(NSMenuItem.separatorItem());
+
+ title = NSString.stringWith(SWT.getMessage("Preferences..."));
+ menuItem = appleMenu.addItemWithTitle(title, 0, NSString.stringWith(","));
+
+ appleMenu.addItem(NSMenuItem.separatorItem());
+
+ title = NSString.stringWith(SWT.getMessage("Services"));
+ menuItem = appleMenu.addItemWithTitle(title, 0, emptyStr);
+ NSMenu servicesMenu = (NSMenu)new NSMenu().alloc();
+ servicesMenu.initWithTitle(emptyStr);
+ appleMenu.setSubmenu(servicesMenu, menuItem);
+ servicesMenu.release();
+ application.setServicesMenu(servicesMenu);
+
+ appleMenu.addItem(NSMenuItem.separatorItem());
+
+ title = new NSString(OS.objc_msgSend(OS.class_NSString, OS.sel_stringWithFormat_, format.id, NSString.stringWith(SWT.getMessage("Hide")).id, appName.id));
+ menuItem = appleMenu.addItemWithTitle(title, OS.sel_hide_, NSString.stringWith("h"));
+ menuItem.setTarget(applicationDelegate);
+
+ title = NSString.stringWith(SWT.getMessage("Hide Others"));
+ menuItem = appleMenu.addItemWithTitle(title, OS.sel_hideOtherApplications_, NSString.stringWith("h"));
+ menuItem.setKeyEquivalentModifierMask(OS.NSCommandKeyMask | OS.NSAlternateKeyMask);
+ menuItem.setTarget(applicationDelegate);
+
+ title = NSString.stringWith(SWT.getMessage("Show All"));
+ menuItem = appleMenu.addItemWithTitle(title, OS.sel_unhideAllApplications_, emptyStr);
+ menuItem.setTarget(applicationDelegate);
+
+ appleMenu.addItem(NSMenuItem.separatorItem());
+
+ title = new NSString(OS.objc_msgSend(OS.class_NSString, OS.sel_stringWithFormat_, format.id, NSString.stringWith(SWT.getMessage("Quit")).id, appName.id));
+ menuItem = appleMenu.addItemWithTitle(title, OS.sel_quitRequested_, NSString.stringWith("q"));
+ menuItem.setTarget(applicationDelegate);
+
+ mainMenu.setSubmenu(appleMenu, appItem);
+ appleMenu.release();
+ application.setMainMenu(mainMenu);
+ mainMenu.release();
+}
+
+int /*long*/ cursorSetProc (int /*long*/ id, int /*long*/ sel) {
+ if (lockCursor) {
+ if (currentControl != null) {
+ Cursor cursor = currentControl.findCursor ();
+ if (cursor != null && cursor.handle.id != id) return 0;
+ }
+ }
+ OS.call (oldCursorSetProc, id, sel);
+ return 0;
+}
+
+static void deregister (Display display) {
+ synchronized (Device.class) {
+ for (int i=0; i<Displays.length; i++) {
+ if (display == Displays [i]) Displays [i] = null;
+ }
+ }
+}
+
+/**
+ * Destroys the device in the operating system and releases
+ * the device's handle. If the device does not have a handle,
+ * this method may do nothing depending on the device.
+ * <p>
+ * This method is called after <code>release</code>.
+ * </p>
+ * @see Device#dispose
+ * @see #release
+ */
+protected void destroy () {
+ if (this == Default) Default = null;
+ deregister (this);
+ destroyDisplay ();
+}
+
+void destroyDisplay () {
+ application = null;
+}
+
+/**
+ * Causes the <code>run()</code> method of the runnable to
+ * be invoked by the user-interface thread just before the
+ * receiver is disposed. Specifying a <code>null</code> runnable
+ * is ignored.
+ *
+ * @param runnable code to run at dispose time.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void disposeExec (Runnable runnable) {
+ checkDevice ();
+ if (disposeList == null) disposeList = new Runnable [4];
+ for (int i=0; i<disposeList.length; i++) {
+ if (disposeList [i] == null) {
+ disposeList [i] = runnable;
+ return;
+ }
+ }
+ Runnable [] newDisposeList = new Runnable [disposeList.length + 4];
+ System.arraycopy (disposeList, 0, newDisposeList, 0, disposeList.length);
+ newDisposeList [disposeList.length] = runnable;
+ disposeList = newDisposeList;
+}
+
+void error (int code) {
+ SWT.error(code);
+}
+
+boolean filterEvent (Event event) {
+ if (filterTable != null) filterTable.sendEvent (event);
+ return false;
+}
+
+boolean filters (int eventType) {
+ if (filterTable == null) return false;
+ return filterTable.hooks (eventType);
+}
+
+/**
+ * Given the operating system handle for a widget, returns
+ * the instance of the <code>Widget</code> subclass which
+ * represents it in the currently running application, if
+ * such exists, or null if no matching widget can be found.
+ * <p>
+ * <b>IMPORTANT:</b> This method should not be called from
+ * application code. The arguments are platform-specific.
+ * </p>
+ *
+ * @param handle the handle for the widget
+ * @return the SWT widget that the handle represents
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Widget findWidget (int /*long*/ handle) {
+ checkDevice ();
+ return getWidget (handle);
+}
+
+/**
+ * Given the operating system handle for a widget,
+ * and widget-specific id, returns the instance of
+ * the <code>Widget</code> subclass which represents
+ * the handle/id pair in the currently running application,
+ * if such exists, or null if no matching widget can be found.
+ * <p>
+ * <b>IMPORTANT:</b> This method should not be called from
+ * application code. The arguments are platform-specific.
+ * </p>
+ *
+ * @param handle the handle for the widget
+ * @param id the id for the subwidget (usually an item)
+ * @return the SWT widget that the handle/id pair represents
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public Widget findWidget (int /*long*/ handle, int id) {
+ checkDevice ();
+ return getWidget (handle);
+}
+
+/**
+ * Given a widget and a widget-specific id, returns the
+ * instance of the <code>Widget</code> subclass which represents
+ * the widget/id pair in the currently running application,
+ * if such exists, or null if no matching widget can be found.
+ *
+ * @param widget the widget
+ * @param id the id for the subwidget (usually an item)
+ * @return the SWT subwidget (usually an item) that the widget/id pair represents
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.3
+ */
+public Widget findWidget (Widget widget, int id) {
+ checkDevice ();
+ return null;
+}
+
+/**
+ * Returns the display which the given thread is the
+ * user-interface thread for, or null if the given thread
+ * is not a user-interface thread for any display. Specifying
+ * <code>null</code> as the thread will return <code>null</code>
+ * for the display.
+ *
+ * @param thread the user-interface thread
+ * @return the display for the given thread
+ */
+public static Display findDisplay (Thread thread) {
+ synchronized (Device.class) {
+ for (int i=0; i<Displays.length; i++) {
+ Display display = Displays [i];
+ if (display != null && display.thread == thread) {
+ return display;
+ }
+ }
+ return null;
+ }
+}
+
+/**
+ * Returns the currently active <code>Shell</code>, or null
+ * if no shell belonging to the currently running application
+ * is active.
+ *
+ * @return the active shell or null
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Shell getActiveShell () {
+ checkDevice ();
+ NSWindow window = keyWindow != null ? keyWindow : application.keyWindow();
+ if (window != null) {
+ Widget widget = getWidget(window.contentView());
+ if (widget instanceof Shell) {
+ return (Shell)widget;
+ }
+ }
+ return null;
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location. Note that
+ * on multi-monitor systems the origin can be negative.
+ *
+ * @return the bounding rectangle
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Rectangle getBounds () {
+ checkDevice ();
+ NSArray screens = NSScreen.screens();
+ return getBounds (screens);
+}
+
+Rectangle getBounds (NSArray screens) {
+ NSRect primaryFrame = new NSScreen(screens.objectAtIndex(0)).frame();
+ float /*double*/ minX = Float.MAX_VALUE, maxX = Float.MIN_VALUE;
+ float /*double*/ minY = Float.MAX_VALUE, maxY = Float.MIN_VALUE;
+ int /*long*/ count = screens.count();
+ for (int i = 0; i < count; i++) {
+ NSScreen screen = new NSScreen(screens.objectAtIndex(i));
+ NSRect frame = screen.frame();
+ float /*double*/ x1 = frame.x, x2 = frame.x + frame.width;
+ float /*double*/ y1 = primaryFrame.height - frame.y, y2 = primaryFrame.height - (frame.y + frame.height);
+ if (x1 < minX) minX = x1;
+ if (x2 < minX) minX = x2;
+ if (x1 > maxX) maxX = x1;
+ if (x2 > maxX) maxX = x2;
+ if (y1 < minY) minY = y1;
+ if (y2 < minY) minY = y2;
+ if (y1 > maxY) maxY = y1;
+ if (y2 > maxY) maxY = y2;
+ }
+ return new Rectangle ((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY));
+}
+
+/**
+ * Returns the display which the currently running thread is
+ * the user-interface thread for, or null if the currently
+ * running thread is not a user-interface thread for any display.
+ *
+ * @return the current display
+ */
+public static Display getCurrent () {
+ return findDisplay (Thread.currentThread ());
+}
+
+int getCaretBlinkTime () {
+// checkDevice ();
+ return 560;
+}
+
+/**
+ * Returns a rectangle which describes the area of the
+ * receiver which is capable of displaying data.
+ *
+ * @return the client area
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getBounds
+ */
+public Rectangle getClientArea () {
+ checkDevice ();
+ NSArray screens = NSScreen.screens();
+ if (screens.count() != 1) return getBounds (screens);
+ NSScreen screen = new NSScreen(screens.objectAtIndex(0));
+ NSRect frame = screen.frame();
+ NSRect visibleFrame = screen.visibleFrame();
+ float /*double*/ y = frame.height - (visibleFrame.y + visibleFrame.height);
+ return new Rectangle((int)visibleFrame.x, (int)y, (int)visibleFrame.width, (int)visibleFrame.height);
+}
+
+/**
+ * Returns the control which the on-screen pointer is currently
+ * over top of, or null if it is not currently over one of the
+ * controls built by the currently running application.
+ *
+ * @return the control under the cursor
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Control getCursorControl () {
+ checkDevice();
+ return findControl(false);
+}
+
+/**
+ * Returns the location of the on-screen pointer relative
+ * to the top left corner of the screen.
+ *
+ * @return the cursor location
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Point getCursorLocation () {
+ checkDevice ();
+ NSPoint location = NSEvent.mouseLocation();
+ NSRect primaryFrame = getPrimaryFrame();
+ return new Point ((int) location.x, (int) (primaryFrame.height - location.y));
+}
+
+/**
+ * Returns an array containing the recommended cursor sizes.
+ *
+ * @return the array of cursor sizes
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public Point [] getCursorSizes () {
+ checkDevice ();
+ return new Point [] {new Point (16, 16)};
+}
+
+/**
+ * Returns the default display. One is created (making the
+ * thread that invokes this method its user-interface thread)
+ * if it did not already exist.
+ *
+ * @return the default display
+ */
+public static Display getDefault () {
+ synchronized (Device.class) {
+ if (Default == null) Default = new Display ();
+ return Default;
+ }
+}
+
+/**
+ * Returns the application defined property of the receiver
+ * with the specified name, or null if it has not been set.
+ * <p>
+ * Applications may have associated arbitrary objects with the
+ * receiver in this fashion. If the objects stored in the
+ * properties need to be notified when the display is disposed
+ * of, it is the application's responsibility to provide a
+ * <code>disposeExec()</code> handler which does so.
+ * </p>
+ *
+ * @param key the name of the property
+ * @return the value of the property or null if it has not been set
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the key is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setData(String, Object)
+ * @see #disposeExec(Runnable)
+ */
+public Object getData (String key) {
+ checkDevice ();
+ if (key == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (keys == null) return null;
+ for (int i=0; i<keys.length; i++) {
+ if (keys [i].equals (key)) return values [i];
+ }
+ return null;
+}
+
+/**
+ * Returns the application defined, display specific data
+ * associated with the receiver, or null if it has not been
+ * set. The <em>display specific data</em> is a single,
+ * unnamed field that is stored with every display.
+ * <p>
+ * Applications may put arbitrary objects in this field. If
+ * the object stored in the display specific data needs to
+ * be notified when the display is disposed of, it is the
+ * application's responsibility to provide a
+ * <code>disposeExec()</code> handler which does so.
+ * </p>
+ *
+ * @return the display specific data
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setData(Object)
+ * @see #disposeExec(Runnable)
+ */
+public Object getData () {
+ checkDevice ();
+ return data;
+}
+
+/**
+ * Returns the button dismissal alignment, one of <code>LEFT</code> or <code>RIGHT</code>.
+ * The button dismissal alignment is the ordering that should be used when positioning the
+ * default dismissal button for a dialog. For example, in a dialog that contains an OK and
+ * CANCEL button, on platforms where the button dismissal alignment is <code>LEFT</code>, the
+ * button ordering should be OK/CANCEL. When button dismissal alignment is <code>RIGHT</code>,
+ * the button ordering should be CANCEL/OK.
+ *
+ * @return the button dismissal order
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 2.1
+ */
+public int getDismissalAlignment () {
+ checkDevice ();
+ return SWT.RIGHT;
+}
+
+/**
+ * Returns the longest duration, in milliseconds, between
+ * two mouse button clicks that will be considered a
+ * <em>double click</em> by the underlying operating system.
+ *
+ * @return the double click time
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getDoubleClickTime () {
+ checkDevice ();
+ return OS.GetDblTime () * 1000 / 60;
+}
+
+/**
+ * Returns the control which currently has keyboard focus,
+ * or null if keyboard events are not currently going to
+ * any of the controls built by the currently running
+ * application.
+ *
+ * @return the control under the cursor
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Control getFocusControl () {
+ checkDevice ();
+ if (focusControl != null && !focusControl.isDisposed ()) {
+ return focusControl;
+ }
+ NSWindow window = keyWindow != null ? keyWindow : application.keyWindow();
+ return _getFocusControl(window);
+}
+
+Control _getFocusControl (NSWindow window) {
+ if (window != null) {
+ NSResponder responder = window.firstResponder();
+ if (responder != null && !responder.respondsToSelector(OS.sel_superview)) {
+ return null;
+ }
+ NSView view = new NSView(responder.id);
+ if (view != null) {
+ do {
+ Widget widget = GetWidget (view.id);
+ if (widget instanceof Control) {
+ return (Control)widget;
+ }
+ view = view.superview();
+ } while (view != null);
+ }
+ }
+ return null;
+}
+
+/**
+ * Returns true when the high contrast mode is enabled.
+ * Otherwise, false is returned.
+ * <p>
+ * Note: This operation is a hint and is not supported on
+ * platforms that do not have this concept.
+ * </p>
+ *
+ * @return the high contrast mode
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public boolean getHighContrast () {
+ checkDevice ();
+ return false;
+}
+
+/**
+ * Returns the maximum allowed depth of icons on this display, in bits per pixel.
+ * On some platforms, this may be different than the actual depth of the display.
+ *
+ * @return the maximum icon depth
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Device#getDepth
+ */
+public int getIconDepth () {
+ return getDepth ();
+}
+
+/**
+ * Returns an array containing the recommended icon sizes.
+ *
+ * @return the array of icon sizes
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Decorations#setImages(Image[])
+ *
+ * @since 3.0
+ */
+public Point [] getIconSizes () {
+ checkDevice ();
+ return new Point [] {
+ new Point (16, 16), new Point (32, 32),
+ new Point (64, 64), new Point (128, 128)};
+}
+
+int getLastEventTime () {
+ NSEvent event = application.currentEvent();
+ return event != null ? (int)(event.timestamp() * 1000) : 0;
+}
+
+Menu [] getMenus (Decorations shell) {
+ if (menus == null) return new Menu [0];
+ int count = 0;
+ for (int i = 0; i < menus.length; i++) {
+ Menu menu = menus[i];
+ if (menu != null && menu.parent == shell) count++;
+ }
+ int index = 0;
+ Menu[] result = new Menu[count];
+ for (int i = 0; i < menus.length; i++) {
+ Menu menu = menus[i];
+ if (menu != null && menu.parent == shell) {
+ result[index++] = menu;
+ }
+ }
+ return result;
+}
+
+int getMessageCount () {
+ return synchronizer.getMessageCount ();
+}
+
+/**
+ * Returns an array of monitors attached to the device.
+ *
+ * @return the array of monitors
+ *
+ * @since 3.0
+ */
+public Monitor [] getMonitors () {
+ checkDevice ();
+ NSArray screens = NSScreen.screens();
+ NSRect primaryFrame = new NSScreen(screens.objectAtIndex(0)).frame();
+ int count = (int)/*64*/screens.count();
+ Monitor [] monitors = new Monitor [count];
+ for (int i=0; i<count; i++) {
+ Monitor monitor = new Monitor ();
+ NSScreen screen = new NSScreen(screens.objectAtIndex(i));
+ NSRect frame = screen.frame();
+ monitor.x = (int)frame.x;
+ monitor.y = (int)(primaryFrame.height - (frame.y + frame.height));
+ monitor.width = (int)frame.width;
+ monitor.height = (int)frame.height;
+ NSRect visibleFrame = screen.visibleFrame();
+ monitor.clientX = (int)visibleFrame.x;
+ monitor.clientY = (int)(primaryFrame.height - (visibleFrame.y + visibleFrame.height));
+ monitor.clientWidth = (int)visibleFrame.width;
+ monitor.clientHeight = (int)visibleFrame.height;
+ monitors [i] = monitor;
+ }
+ return monitors;
+}
+
+NSRect getPrimaryFrame () {
+ NSArray screens = NSScreen.screens();
+ return new NSScreen(screens.objectAtIndex(0)).frame();
+}
+
+/**
+ * Returns the primary monitor for that device.
+ *
+ * @return the primary monitor
+ *
+ * @since 3.0
+ */
+public Monitor getPrimaryMonitor () {
+ checkDevice ();
+ Monitor monitor = new Monitor ();
+ NSArray screens = NSScreen.screens();
+ NSScreen screen = new NSScreen(screens.objectAtIndex(0));
+ NSRect frame = screen.frame();
+ monitor.x = (int)frame.x;
+ monitor.y = (int)(frame.height - (frame.y + frame.height));
+ monitor.width = (int)frame.width;
+ monitor.height = (int)frame.height;
+ NSRect visibleFrame = screen.visibleFrame();
+ monitor.clientX = (int)visibleFrame.x;
+ monitor.clientY = (int)(frame.height - (visibleFrame.y + visibleFrame.height));
+ monitor.clientWidth = (int)visibleFrame.width;
+ monitor.clientHeight = (int)visibleFrame.height;
+ return monitor;
+}
+
+/**
+ * Returns a (possibly empty) array containing all shells which have
+ * not been disposed and have the receiver as their display.
+ *
+ * @return the receiver's shells
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Shell [] getShells () {
+ checkDevice ();
+ NSArray windows = application.windows();
+ int index = 0;
+ Shell [] result = new Shell [(int)/*64*/windows.count()];
+ for (int i = 0; i < result.length; i++) {
+ NSWindow window = new NSWindow(windows.objectAtIndex(i));
+ Widget widget = getWidget(window.contentView());
+ if (widget instanceof Shell) {
+ result[index++] = (Shell)widget;
+ }
+ }
+ if (index == result.length) return result;
+ Shell [] newResult = new Shell [index];
+ System.arraycopy (result, 0, newResult, 0, index);
+ return newResult;
+}
+
+static boolean getSheetEnabled () {
+ return !"false".equals(System.getProperty("org.eclipse.swt.sheet"));
+}
+
+/**
+ * Gets the synchronizer used by the display.
+ *
+ * @return the receiver's synchronizer
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.4
+ */
+public Synchronizer getSynchronizer () {
+ checkDevice ();
+ return synchronizer;
+}
+
+/**
+ * Returns the thread that has invoked <code>syncExec</code>
+ * or null if no such runnable is currently being invoked by
+ * the user-interface thread.
+ * <p>
+ * Note: If a runnable invoked by asyncExec is currently
+ * running, this method will return null.
+ * </p>
+ *
+ * @return the receiver's sync-interface thread
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Thread getSyncThread () {
+ synchronized (Device.class) {
+ if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+ return synchronizer.syncThread;
+ }
+}
+
+/**
+ * Returns the matching standard color for the given
+ * constant, which should be one of the color constants
+ * specified in class <code>SWT</code>. Any value other
+ * than one of the SWT color constants which is passed
+ * in will result in the color black. This color should
+ * not be free'd because it was allocated by the system,
+ * not the application.
+ *
+ * @param id the color constant
+ * @return the matching color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see SWT
+ */
+public Color getSystemColor (int id) {
+ checkDevice ();
+ Color color = getWidgetColor (id);
+ if (color != null) return color;
+ return super.getSystemColor (id);
+}
+
+Color getWidgetColor (int id) {
+ if (0 <= id && id < colors.length && colors [id] != null) {
+ return Color.cocoa_new (this, colors [id]);
+ }
+ return null;
+}
+
+float /*double*/ [] getWidgetColorRGB (int id) {
+ NSColor color = null;
+ switch (id) {
+ case SWT.COLOR_INFO_FOREGROUND: color = NSColor.blackColor (); break;
+ case SWT.COLOR_INFO_BACKGROUND: return new float /*double*/ [] {0xFF / 255f, 0xFF / 255f, 0xE1 / 255f, 1};
+ case SWT.COLOR_TITLE_FOREGROUND: color = NSColor.windowFrameTextColor(); break;
+ case SWT.COLOR_TITLE_BACKGROUND: color = NSColor.alternateSelectedControlColor(); break;
+ case SWT.COLOR_TITLE_BACKGROUND_GRADIENT: color = NSColor.selectedControlColor(); break;
+ case SWT.COLOR_TITLE_INACTIVE_FOREGROUND: color = NSColor.disabledControlTextColor(); break;
+ case SWT.COLOR_TITLE_INACTIVE_BACKGROUND: color = NSColor.secondarySelectedControlColor(); break;
+ case SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT: color = NSColor.secondarySelectedControlColor(); break;
+ case SWT.COLOR_WIDGET_DARK_SHADOW: color = NSColor.controlDarkShadowColor(); break;
+ case SWT.COLOR_WIDGET_NORMAL_SHADOW: color = NSColor.controlShadowColor(); break;
+ case SWT.COLOR_WIDGET_LIGHT_SHADOW: color = NSColor.controlHighlightColor(); break;
+ case SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW: color = NSColor.controlLightHighlightColor(); break;
+ case SWT.COLOR_WIDGET_BACKGROUND: color = NSColor.controlHighlightColor(); break;
+ case SWT.COLOR_WIDGET_FOREGROUND: color = NSColor.controlTextColor(); break;
+ case SWT.COLOR_WIDGET_BORDER: color = NSColor.blackColor (); break;
+ case SWT.COLOR_LIST_FOREGROUND: color = NSColor.textColor(); break;
+ case SWT.COLOR_LIST_BACKGROUND: color = NSColor.textBackgroundColor(); break;
+ case SWT.COLOR_LIST_SELECTION_TEXT: color = NSColor.selectedTextColor(); break;
+ case SWT.COLOR_LIST_SELECTION: color = NSColor.selectedTextBackgroundColor(); break;
+ }
+ return getWidgetColorRGB (color);
+}
+
+float /*double*/ [] getWidgetColorRGB (NSColor color) {
+ if (color == null) return null;
+ color = color.colorUsingColorSpace(NSColorSpace.deviceRGBColorSpace());
+ if (color == null) return null;
+ float /*double*/[] components = new float /*double*/[(int)/*64*/color.numberOfComponents()];
+ color.getComponents(components);
+ return new float /*double*/ []{components[0], components[1], components[2], components[3]};
+}
+
+/**
+ * Returns the matching standard platform cursor for the given
+ * constant, which should be one of the cursor constants
+ * specified in class <code>SWT</code>. This cursor should
+ * not be free'd because it was allocated by the system,
+ * not the application. A value of <code>null</code> will
+ * be returned if the supplied constant is not an SWT cursor
+ * constant.
+ *
+ * @param id the SWT cursor constant
+ * @return the corresponding cursor or <code>null</code>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see SWT#CURSOR_ARROW
+ * @see SWT#CURSOR_WAIT
+ * @see SWT#CURSOR_CROSS
+ * @see SWT#CURSOR_APPSTARTING
+ * @see SWT#CURSOR_HELP
+ * @see SWT#CURSOR_SIZEALL
+ * @see SWT#CURSOR_SIZENESW
+ * @see SWT#CURSOR_SIZENS
+ * @see SWT#CURSOR_SIZENWSE
+ * @see SWT#CURSOR_SIZEWE
+ * @see SWT#CURSOR_SIZEN
+ * @see SWT#CURSOR_SIZES
+ * @see SWT#CURSOR_SIZEE
+ * @see SWT#CURSOR_SIZEW
+ * @see SWT#CURSOR_SIZENE
+ * @see SWT#CURSOR_SIZESE
+ * @see SWT#CURSOR_SIZESW
+ * @see SWT#CURSOR_SIZENW
+ * @see SWT#CURSOR_UPARROW
+ * @see SWT#CURSOR_IBEAM
+ * @see SWT#CURSOR_NO
+ * @see SWT#CURSOR_HAND
+ *
+ * @since 3.0
+ */
+public Cursor getSystemCursor (int id) {
+ checkDevice ();
+ if (!(0 <= id && id < cursors.length)) return null;
+ if (cursors [id] == null) {
+ cursors [id] = new Cursor (this, id);
+ }
+ return cursors [id];
+}
+
+/**
+ * Returns the matching standard platform image for the given
+ * constant, which should be one of the icon constants
+ * specified in class <code>SWT</code>. This image should
+ * not be free'd because it was allocated by the system,
+ * not the application. A value of <code>null</code> will
+ * be returned either if the supplied constant is not an
+ * SWT icon constant or if the platform does not define an
+ * image that corresponds to the constant.
+ *
+ * @param id the SWT icon constant
+ * @return the corresponding image or <code>null</code>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see SWT#ICON_ERROR
+ * @see SWT#ICON_INFORMATION
+ * @see SWT#ICON_QUESTION
+ * @see SWT#ICON_WARNING
+ * @see SWT#ICON_WORKING
+ *
+ * @since 3.0
+ */
+public Image getSystemImage (int id) {
+ checkDevice ();
+ switch(id) {
+ case SWT.ICON_ERROR: {
+ if (errorImage != null) return errorImage;
+ NSImage nsImage = NSWorkspace.sharedWorkspace ().iconForFileType (new NSString (OS.NSFileTypeForHFSTypeCode (OS.kAlertStopIcon)));
+ if (nsImage == null) return null;
+ nsImage.retain ();
+ return errorImage = Image.cocoa_new (this, SWT.ICON, nsImage);
+ }
+ case SWT.ICON_INFORMATION:
+ case SWT.ICON_QUESTION:
+ case SWT.ICON_WORKING: {
+ if (infoImage != null) return infoImage;
+ NSImage nsImage = NSWorkspace.sharedWorkspace ().iconForFileType (new NSString (OS.NSFileTypeForHFSTypeCode (OS.kAlertNoteIcon)));
+ if (nsImage == null) return null;
+ nsImage.retain ();
+ return infoImage = Image.cocoa_new (this, SWT.ICON, nsImage);
+ }
+ case SWT.ICON_WARNING: {
+ if (warningImage != null) return warningImage;
+ NSImage nsImage = NSWorkspace.sharedWorkspace ().iconForFileType (new NSString (OS.NSFileTypeForHFSTypeCode (OS.kAlertCautionIcon)));
+ if (nsImage == null) return null;
+ nsImage.retain ();
+ return warningImage = Image.cocoa_new (this, SWT.ICON, nsImage);
+ }
+ }
+ return null;
+}
+
+/**
+ * Returns the single instance of the system tray or null
+ * when there is no system tray available for the platform.
+ *
+ * @return the system tray or <code>null</code>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public Tray getSystemTray () {
+ checkDevice ();
+ if (tray != null) return tray;
+ return tray = new Tray (this, SWT.NONE);
+}
+
+/**
+ * Returns the user-interface thread for the receiver.
+ *
+ * @return the receiver's user-interface thread
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Thread getThread () {
+ synchronized (Device.class) {
+ if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+ return thread;
+ }
+}
+
+int getToolTipTime () {
+ checkDevice ();
+ //TODO get OS value (NSTooltipManager?)
+ return 560;
+}
+
+Widget getWidget (int /*long*/ id) {
+ return GetWidget (id);
+}
+
+static Widget GetWidget (int /*long*/ id) {
+ if (id == 0) return null;
+ int /*long*/ [] jniRef = new int /*long*/ [1];
+ OS.object_getInstanceVariable(id, SWT_OBJECT, jniRef);
+ if (jniRef[0] == 0) return null;
+ return (Widget)OS.JNIGetObject(jniRef[0]);
+}
+
+Widget getWidget (NSView view) {
+ if (view == null) return null;
+ return getWidget(view.id);
+}
+
+boolean hasDefaultButton () {
+ NSArray windows = application.windows();
+ int /*long*/ count = windows.count();
+ for (int i = 0; i < count; i++) {
+ NSWindow window = new NSWindow(windows.objectAtIndex(i));
+ if (window.defaultButtonCell() != null) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Initializes any internal resources needed by the
+ * device.
+ * <p>
+ * This method is called after <code>create</code>.
+ * </p>
+ *
+ * @see #create
+ */
+protected void init () {
+ super.init ();
+ initClasses ();
+ initColors ();
+ initFonts ();
+
+ if (!isEmbedded) {
+ /*
+ * Feature in Cocoa: NSApplication.finishLaunching() adds an apple menu to the menu bar that isn't accessible via NSMenu.
+ * If Display objects are created and disposed of multiple times in a single process, another apple menu is added to the menu bar.
+ * It must be called or the dock icon will continue to bounce. So, it should only be called once per process, not just once per
+ * creation of a Display. Use a static so creation of additional Display objects won't affect the menu bar.
+ */
+ if (!Display.launched) {
+ application.finishLaunching();
+ Display.launched = true;
+
+ /* only add the shutdown hook once */
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ public void run() {
+ NSApplication.sharedApplication().terminate(null);
+ }
+ });
+ }
+ }
+
+ observerCallback = new Callback (this, "observerProc", 3); //$NON-NLS-1$
+ int /*long*/ observerProc = observerCallback.getAddress ();
+ if (observerProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ int activities = OS.kCFRunLoopBeforeWaiting;
+ runLoopObserver = OS.CFRunLoopObserverCreate (0, activities, true, 0, observerProc, 0);
+ if (runLoopObserver == 0) error (SWT.ERROR_NO_HANDLES);
+ OS.CFRunLoopAddObserver (OS.CFRunLoopGetCurrent (), runLoopObserver, OS.kCFRunLoopCommonModes ());
+
+ cursorSetCallback = new Callback(this, "cursorSetProc", 2);
+ int /*long*/ cursorSetProc = cursorSetCallback.getAddress();
+ if (cursorSetProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ int /*long*/ method = OS.class_getInstanceMethod(OS.class_NSCursor, OS.sel_set);
+ if (method != 0) oldCursorSetProc = OS.method_setImplementation(method, cursorSetProc);
+
+ timerDelegate = (SWTWindowDelegate)new SWTWindowDelegate().alloc().init();
+
+ settingsDelegate = (SWTWindowDelegate)new SWTWindowDelegate().alloc().init();
+ NSNotificationCenter defaultCenter = NSNotificationCenter.defaultCenter();
+ defaultCenter.addObserver(settingsDelegate, OS.sel_systemSettingsChanged_, OS.NSSystemColorsDidChangeNotification, null);
+ defaultCenter.addObserver(settingsDelegate, OS.sel_systemSettingsChanged_, OS.NSApplicationDidChangeScreenParametersNotification, null);
+
+ NSTextView textView = (NSTextView)new NSTextView().alloc();
+ textView.init ();
+ markedAttributes = textView.markedTextAttributes ();
+ markedAttributes.retain ();
+ textView.release ();
+
+ isPainting = (NSMutableArray)new NSMutableArray().alloc();
+ isPainting = isPainting.initWithCapacity(12);
+}
+
+void addEventMethods (int /*long*/ cls, int /*long*/ proc2, int /*long*/ proc3, int /*long*/ drawRectProc, int /*long*/ hitTestProc, int /*long*/ needsDisplayInRectProc) {
+ if (proc3 != 0) {
+ OS.class_addMethod(cls, OS.sel_mouseDown_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_mouseUp_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_scrollWheel_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_rightMouseDown_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_rightMouseUp_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_rightMouseDragged_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_otherMouseDown_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_otherMouseUp_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_otherMouseDragged_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_mouseDragged_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_mouseMoved_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_mouseEntered_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_mouseExited_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_menuForEvent_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_keyDown_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_keyUp_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_flagsChanged_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_cursorUpdate_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_setNeedsDisplay_, proc3, "@:B");
+ OS.class_addMethod(cls, OS.sel_shouldDelayWindowOrderingForEvent_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_acceptsFirstMouse_, proc3, "@:@");
+ }
+ if (proc2 != 0) {
+ OS.class_addMethod(cls, OS.sel_resignFirstResponder, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_becomeFirstResponder, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_resetCursorRects, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_updateTrackingAreas, proc2, "@:");
+ }
+ if (needsDisplayInRectProc != 0) {
+ OS.class_addMethod(cls, OS.sel_setNeedsDisplayInRect_, needsDisplayInRectProc, "@:{NSRect}");
+ }
+ if (drawRectProc != 0) {
+ OS.class_addMethod(cls, OS.sel_drawRect_, drawRectProc, "@:{NSRect}");
+ }
+ if (hitTestProc != 0) {
+ OS.class_addMethod(cls, OS.sel_hitTest_, hitTestProc, "@:{NSPoint}");
+ }
+}
+
+void addFrameMethods(int /*long*/ cls, int /*long*/ setFrameOriginProc, int /*long*/ setFrameSizeProc) {
+ OS.class_addMethod(cls, OS.sel_setFrameOrigin_, setFrameOriginProc, "@:{NSPoint}");
+ OS.class_addMethod(cls, OS.sel_setFrameSize_, setFrameSizeProc, "@:{NSSize}");
+}
+
+void addAccessibilityMethods(int /*long*/ cls, int /*long*/ proc2, int /*long*/ proc3, int /*long*/ proc4, int /*long*/ accessibilityHitTestProc) {
+ OS.class_addMethod(cls, OS.sel_accessibilityActionNames, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_accessibilityAttributeNames, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_accessibilityParameterizedAttributeNames, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_accessibilityFocusedUIElement, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_accessibilityIsIgnored, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_accessibilityAttributeValue_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_accessibilityHitTest_, accessibilityHitTestProc, "@:{NSPoint}");
+ OS.class_addMethod(cls, OS.sel_accessibilityAttributeValue_forParameter_, proc4, "@:@@");
+ OS.class_addMethod(cls, OS.sel_accessibilityPerformAction_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_accessibilityActionDescription_, proc3, "@:@");
+}
+
+int /*long*/ registerCellSubclass(int /*long*/ cellClass, int size, int align, byte[] types) {
+ String cellClassName = OS.class_getName(cellClass);
+ int /*long*/ cls = OS.objc_allocateClassPair(cellClass, "SWTAccessible" + cellClassName, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.objc_registerClassPair(cls);
+ return cls;
+}
+
+void initClasses () {
+ if (OS.objc_lookUpClass ("SWTView") != 0) return;
+
+ Class clazz = getClass ();
+ dialogCallback3 = new Callback(clazz, "dialogProc", 3);
+ int /*long*/ dialogProc3 = dialogCallback3.getAddress();
+ if (dialogProc3 == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ dialogCallback4 = new Callback(clazz, "dialogProc", 4);
+ int /*long*/ dialogProc4 = dialogCallback4.getAddress();
+ if (dialogProc4 == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ dialogCallback5 = new Callback(clazz, "dialogProc", 5);
+ int /*long*/ dialogProc5 = dialogCallback5.getAddress();
+ if (dialogProc5 == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ windowCallback3 = new Callback(clazz, "windowProc", 3);
+ int /*long*/ proc3 = windowCallback3.getAddress();
+ if (proc3 == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ windowCallback2 = new Callback(clazz, "windowProc", 2);
+ int /*long*/ proc2 = windowCallback2.getAddress();
+ if (proc2 == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ windowCallback4 = new Callback(clazz, "windowProc", 4);
+ int /*long*/ proc4 = windowCallback4.getAddress();
+ if (proc4 == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ windowCallback5 = new Callback(clazz, "windowProc", 5);
+ int /*long*/ proc5 = windowCallback5.getAddress();
+ if (proc5 == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ windowCallback6 = new Callback(clazz, "windowProc", 6);
+ int /*long*/ proc6 = windowCallback6.getAddress();
+ if (proc6 == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ fieldEditorCallback3 = new Callback(clazz, "fieldEditorProc", 3);
+ int /*long*/ fieldEditorProc3 = fieldEditorCallback3.getAddress();
+ if (fieldEditorProc3 == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ fieldEditorCallback4 = new Callback(clazz, "fieldEditorProc", 4);
+ int /*long*/ fieldEditorProc4 = fieldEditorCallback4.getAddress();
+ if (fieldEditorProc4 == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+ int /*long*/ isFlippedProc = OS.isFlipped_CALLBACK();
+ int /*long*/ drawRectProc = OS.CALLBACK_drawRect_(proc3);
+ int /*long*/ drawInteriorWithFrameInViewProc = OS.CALLBACK_drawInteriorWithFrame_inView_ (proc4);
+ int /*long*/ drawWithExpansionFrameProc = OS.CALLBACK_drawWithExpansionFrame_inView_ (proc4);
+ int /*long*/ imageRectForBoundsProc = OS.CALLBACK_imageRectForBounds_ (proc3);
+ int /*long*/ titleRectForBoundsProc = OS.CALLBACK_titleRectForBounds_ (proc3);
+ int /*long*/ hitTestForEvent_inRect_ofViewProc = OS.CALLBACK_hitTestForEvent_inRect_ofView_ (proc5);
+ int /*long*/ cellSizeProc = OS.CALLBACK_cellSize (proc2);
+ int /*long*/ drawImageWithFrameInViewProc = OS.CALLBACK_drawImage_withFrame_inView_ (proc5);
+ int /*long*/ setFrameOriginProc = OS.CALLBACK_setFrameOrigin_(proc3);
+ int /*long*/ setFrameSizeProc = OS.CALLBACK_setFrameSize_(proc3);
+ int /*long*/ hitTestProc = OS.CALLBACK_hitTest_(proc3);
+ int /*long*/ markedRangeProc = OS.CALLBACK_markedRange (proc2);
+ int /*long*/ selectedRangeProc = OS.CALLBACK_selectedRange (proc2);
+ int /*long*/ highlightSelectionInClipRectProc = OS.CALLBACK_highlightSelectionInClipRect_ (proc3);
+ int /*long*/ setMarkedText_selectedRangeProc = OS.CALLBACK_setMarkedText_selectedRange_(proc4);
+ int /*long*/ attributedSubstringFromRangeProc = OS.CALLBACK_attributedSubstringFromRange_(proc3);
+ int /*long*/ characterIndexForPointProc = OS.CALLBACK_characterIndexForPoint_(proc3);
+ int /*long*/ firstRectForCharacterRangeProc = OS.CALLBACK_firstRectForCharacterRange_(proc3);
+ int /*long*/ textWillChangeSelectionProc = OS.CALLBACK_textView_willChangeSelectionFromCharacterRange_toCharacterRange_(proc5);
+ int /*long*/ accessibilityHitTestProc = OS.CALLBACK_accessibilityHitTest_(proc3);
+ int /*long*/ shouldChangeTextInRange_replacementString_Proc = OS.CALLBACK_shouldChangeTextInRange_replacementString_(fieldEditorProc4);
+ int /*long*/ shouldChangeTextInRange_replacementString_fieldEditorProc = shouldChangeTextInRange_replacementString_Proc;
+ int /*long*/ view_stringForToolTip_point_userDataProc = OS.CALLBACK_view_stringForToolTip_point_userData_(proc6);
+ int /*long*/ canDragRowsWithIndexes_atPoint_Proc = OS.CALLBACK_canDragRowsWithIndexes_atPoint_(proc4);
+ int /*long*/ setNeedsDisplayInRectProc = OS.CALLBACK_setNeedsDisplayInRect_(proc3);
+ int /*long*/ expansionFrameWithFrameProc = OS.CALLBACK_expansionFrameWithFrame_inView_ (proc4);
+
+ byte[] types = {'*','\0'};
+ int size = C.PTR_SIZEOF, align = C.PTR_SIZEOF == 4 ? 2 : 3;
+
+ String className;
+ int /*long*/ cls;
+
+ className = "SWTBox";
+ cls = OS.objc_allocateClassPair(OS.class_NSBox, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTButton";
+ cls = OS.objc_allocateClassPair(OS.class_NSButton, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_sendSelection, proc2, "@:");
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ OS.objc_registerClassPair(cls);
+
+ cls = registerCellSubclass(NSButton.cellClass(), size, align, types);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.class_addMethod(cls, OS.sel_nextState, proc2, "@:");
+ NSButton.setCellClass(cls);
+
+ className = "SWTButtonCell";
+ cls = OS.objc_allocateClassPair (OS.class_NSButtonCell, className, 0);
+ OS.class_addIvar (cls, SWT_OBJECT, size, (byte)align, types);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.class_addMethod (cls, OS.sel_drawImage_withFrame_inView_, drawImageWithFrameInViewProc, "@:@{NSFrame}@");
+ OS.class_addMethod(cls, OS.sel_cellSize, cellSizeProc, "@:");
+ OS.class_addMethod(cls, OS.sel_drawInteriorWithFrame_inView_, drawInteriorWithFrameInViewProc, "@:{NSRect}@");
+ OS.class_addMethod(cls, OS.sel_titleRectForBounds_, titleRectForBoundsProc, "@:{NSRect}");
+ OS.objc_registerClassPair (cls);
+
+ className = "SWTCanvasView";
+ cls = OS.objc_allocateClassPair(OS.class_NSView, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ //NSTextInput protocol
+ OS.class_addProtocol(cls, OS.objc_getProtocol("NSTextInput"));
+ OS.class_addMethod(cls, OS.sel_hasMarkedText, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_markedRange, markedRangeProc, "@:");
+ OS.class_addMethod(cls, OS.sel_selectedRange, selectedRangeProc, "@:");
+ OS.class_addMethod(cls, OS.sel_setMarkedText_selectedRange_, setMarkedText_selectedRangeProc, "@:@{NSRange}");
+ OS.class_addMethod(cls, OS.sel_unmarkText, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_validAttributesForMarkedText, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_attributedSubstringFromRange_, attributedSubstringFromRangeProc, "@:{NSRange}");
+ OS.class_addMethod(cls, OS.sel_insertText_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_characterIndexForPoint_, characterIndexForPointProc, "@:{NSPoint}");
+ OS.class_addMethod(cls, OS.sel_firstRectForCharacterRange_, firstRectForCharacterRangeProc, "@:{NSRange}");
+ OS.class_addMethod(cls, OS.sel_doCommandBySelector_, proc3, "@::");
+ //NSTextInput protocol end
+ OS.class_addMethod(cls, OS.sel_canBecomeKeyView, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_isFlipped, isFlippedProc, "@:");
+ OS.class_addMethod(cls, OS.sel_acceptsFirstResponder, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_isOpaque, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_updateOpenGLContext_, proc3, "@:@");
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTComboBox";
+ cls = OS.objc_allocateClassPair(OS.class_NSComboBox, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_sendSelection, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_textDidChange_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_textViewDidChangeSelection_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_textView_willChangeSelectionFromCharacterRange_toCharacterRange_, textWillChangeSelectionProc, "@:@{NSRange}{NSRange}");
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.objc_registerClassPair(cls);
+
+ cls = registerCellSubclass(NSComboBox.cellClass(), size, align, types);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ NSComboBox.setCellClass(cls);
+
+ className = "SWTDatePicker";
+ cls = OS.objc_allocateClassPair(OS.class_NSDatePicker, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_isFlipped, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_sendSelection, proc2, "@:");
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTEditorView";
+ cls = OS.objc_allocateClassPair(OS.class_NSTextView, className, 0);
+ //TODO hitTestProc and drawRectProc should be set Control.setRegion()?
+ addEventMethods(cls, 0, fieldEditorProc3, 0, 0, 0);
+ OS.class_addMethod(cls, OS.sel_insertText_, fieldEditorProc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_doCommandBySelector_, fieldEditorProc3, "@::");
+ OS.class_addMethod(cls, OS.sel_shouldChangeTextInRange_replacementString_, shouldChangeTextInRange_replacementString_fieldEditorProc, "@:{NSRange}@");
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTImageView";
+ cls = OS.objc_allocateClassPair(OS.class_NSImageView, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_isFlipped, isFlippedProc, "@:");
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.objc_registerClassPair(cls);
+
+ cls = registerCellSubclass(NSImageView.cellClass(), size, align, types);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ NSImageView.setCellClass(cls);
+
+ className = "SWTImageTextCell";
+ cls = OS.objc_allocateClassPair (OS.class_NSTextFieldCell, className, 0);
+ OS.class_addIvar (cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addIvar (cls, SWT_IMAGE, size, (byte)align, types);
+ OS.class_addIvar (cls, SWT_ROW, size, (byte)align, types);
+ OS.class_addIvar (cls, SWT_COLUMN, size, (byte)align, types);
+ OS.class_addMethod (cls, OS.sel_drawInteriorWithFrame_inView_, drawInteriorWithFrameInViewProc, "@:{NSRect}@");
+ OS.class_addMethod (cls, OS.sel_drawWithExpansionFrame_inView_, drawWithExpansionFrameProc, "@:{NSRect}@");
+ OS.class_addMethod (cls, OS.sel_imageRectForBounds_, imageRectForBoundsProc, "@:{NSRect}");
+ OS.class_addMethod (cls, OS.sel_titleRectForBounds_, titleRectForBoundsProc, "@:{NSRect}");
+ OS.class_addMethod (cls, OS.sel_hitTestForEvent_inRect_ofView_, hitTestForEvent_inRect_ofViewProc, "@:@{NSRect}@");
+ OS.class_addMethod (cls, OS.sel_cellSize, cellSizeProc, "@:");
+ OS.class_addMethod (cls, OS.sel_image, proc2, "@:");
+ OS.class_addMethod (cls, OS.sel_setImage_, proc3, "@:@");
+ OS.class_addMethod (cls, OS.sel_expansionFrameWithFrame_inView_, expansionFrameWithFrameProc, "@:{NSRect}@");
+ OS.objc_registerClassPair (cls);
+
+ className = "SWTMenu";
+ cls = OS.objc_allocateClassPair(OS.class_NSMenu, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_menuWillOpen_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_menuDidClose_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_menu_willHighlightItem_, proc4, "@:@@");
+ OS.class_addMethod(cls, OS.sel_menuNeedsUpdate_, proc3, "@:@");
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTMenuItem";
+ cls = OS.objc_allocateClassPair(OS.class_NSMenuItem, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_sendSelection, proc2, "@:");
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTOutlineView";
+ cls = OS.objc_allocateClassPair(OS.class_NSOutlineView, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_highlightSelectionInClipRect_, highlightSelectionInClipRectProc, "@:{NSRect}");
+ OS.class_addMethod(cls, OS.sel_sendDoubleSelection, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_outlineViewSelectionDidChange_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_outlineView_child_ofItem_, proc5, "@:@i@");
+ OS.class_addMethod(cls, OS.sel_outlineView_isItemExpandable_, proc4, "@:@@");
+ OS.class_addMethod(cls, OS.sel_outlineView_numberOfChildrenOfItem_, proc4, "@:@@");
+ OS.class_addMethod(cls, OS.sel_outlineView_objectValueForTableColumn_byItem_, proc5, "@:@@@");
+ OS.class_addMethod(cls, OS.sel_outlineView_willDisplayCell_forTableColumn_item_, proc6, "@:@@@@");
+ OS.class_addMethod(cls, OS.sel_outlineView_setObjectValue_forTableColumn_byItem_, proc6, "@:@@@@");
+ OS.class_addMethod(cls, OS.sel_outlineViewColumnDidMove_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_outlineViewColumnDidResize_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_outlineView_didClickTableColumn_, proc4, "@:@@");
+ OS.class_addMethod(cls, OS.sel_canDragRowsWithIndexes_atPoint_, canDragRowsWithIndexes_atPoint_Proc, "@:@{NSPoint=ff}");
+ OS.class_addMethod(cls, OS.sel_outlineView_writeItems_toPasteboard_, proc5, "@:@@@");
+ OS.class_addMethod(cls, OS.sel_expandItem_expandChildren_, proc4, "@:@Z");
+ OS.class_addMethod(cls, OS.sel_collapseItem_collapseChildren_, proc4, "@:@Z");
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTPanelDelegate";
+ cls = OS.objc_allocateClassPair(OS.class_NSObject, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_windowWillClose_, dialogProc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_changeColor_, dialogProc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_changeFont_, dialogProc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_sendSelection_, dialogProc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_panel_shouldShowFilename_, dialogProc4, "@:@@");
+ OS.class_addMethod(cls, OS.sel_panelDidEnd_returnCode_contextInfo_, dialogProc5, "@:@i@");
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTPopUpButton";
+ cls = OS.objc_allocateClassPair(OS.class_NSPopUpButton, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_sendSelection, proc2, "@:");
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.objc_registerClassPair(cls);
+
+ cls = registerCellSubclass(NSPopUpButton.cellClass(), size, align, types);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ NSPopUpButton.setCellClass(cls);
+
+ className = "SWTProgressIndicator";
+ cls = OS.objc_allocateClassPair(OS.class_NSProgressIndicator, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_viewDidMoveToWindow, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel__drawThemeProgressArea_, proc3, "@:c");
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTScroller";
+ cls = OS.objc_allocateClassPair(OS.class_NSScroller, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_sendSelection, proc2, "@:");
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTScrollView";
+ cls = OS.objc_allocateClassPair(OS.class_NSScrollView, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_sendVerticalSelection, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_sendHorizontalSelection, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_pageDown_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_pageUp_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_reflectScrolledClipView_, proc3, "@:@");
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTSearchField";
+ cls = OS.objc_allocateClassPair(OS.class_NSSearchField, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.class_addMethod(cls, OS.sel_textDidChange_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_textViewDidChangeSelection_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_textView_willChangeSelectionFromCharacterRange_toCharacterRange_, textWillChangeSelectionProc, "@:@{NSRange}{NSRange}");
+ OS.class_addMethod(cls, OS.sel_sendSearchSelection, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_sendCancelSelection, proc2, "@:");
+ OS.objc_registerClassPair(cls);
+
+ cls = registerCellSubclass(NSSearchField.cellClass(), size, align, types);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ NSSearchField.setCellClass(cls);
+
+ // Don't subclass NSSecureTextFieldCell -- you'll get an NSException from [NSSecureTextField setCellClass:]!
+ className = "SWTSecureTextField";
+ cls = OS.objc_allocateClassPair(OS.class_NSSecureTextField, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.class_addMethod(cls, OS.sel_textDidChange_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_textViewDidChangeSelection_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_textView_willChangeSelectionFromCharacterRange_toCharacterRange_, textWillChangeSelectionProc, "@:@{NSRange}{NSRange}");
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTSlider";
+ cls = OS.objc_allocateClassPair(OS.class_NSSlider, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_sendSelection, proc2, "@:");
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.objc_registerClassPair(cls);
+
+ cls = registerCellSubclass(NSSlider.cellClass(), size, align, types);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ NSSlider.setCellClass(cls);
+
+ className = "SWTStepper";
+ cls = OS.objc_allocateClassPair(OS.class_NSStepper, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_sendSelection, proc2, "@:");
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.objc_registerClassPair(cls);
+
+ cls = registerCellSubclass(NSStepper.cellClass(), size, align, types);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ NSStepper.setCellClass(cls);
+
+ className = "SWTTableHeaderCell";
+ cls = OS.objc_allocateClassPair (OS.class_NSTableHeaderCell, className, 0);
+ OS.class_addIvar (cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod (cls, OS.sel_drawInteriorWithFrame_inView_, drawInteriorWithFrameInViewProc, "@:{NSRect}@");
+ OS.objc_registerClassPair (cls);
+
+ className = "SWTTableHeaderView";
+ cls = OS.objc_allocateClassPair(OS.class_NSTableHeaderView, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_mouseDown_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_resetCursorRects, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_updateTrackingAreas, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_menuForEvent_, proc3, "@:@");
+ //TODO hitTestProc and drawRectProc should be set Control.setRegion()?
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTTableView";
+ cls = OS.objc_allocateClassPair(OS.class_NSTableView, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_highlightSelectionInClipRect_, highlightSelectionInClipRectProc, "@:{NSRect}");
+ OS.class_addMethod(cls, OS.sel_sendDoubleSelection, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_numberOfRowsInTableView_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_tableView_objectValueForTableColumn_row_, proc5, "@:@:@:@");
+ OS.class_addMethod(cls, OS.sel_tableView_shouldEditTableColumn_row_, proc5, "@:@:@:@");
+ OS.class_addMethod(cls, OS.sel_tableViewSelectionDidChange_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_tableView_willDisplayCell_forTableColumn_row_, proc6, "@:@@@i");
+ OS.class_addMethod(cls, OS.sel_tableView_setObjectValue_forTableColumn_row_, proc6, "@:@@@i");
+ OS.class_addMethod(cls, OS.sel_tableViewColumnDidMove_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_tableViewColumnDidResize_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_tableView_didClickTableColumn_, proc4, "@:@");
+ OS.class_addMethod(cls, OS.sel_canDragRowsWithIndexes_atPoint_, canDragRowsWithIndexes_atPoint_Proc, "@:@{NSPoint=ff}");
+ OS.class_addMethod(cls, OS.sel_tableView_writeRowsWithIndexes_toPasteboard_, proc5, "@:@@@");
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTTabView";
+ cls = OS.objc_allocateClassPair(OS.class_NSTabView, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_tabView_willSelectTabViewItem_, proc4, "@:@@");
+ OS.class_addMethod(cls, OS.sel_tabView_didSelectTabViewItem_, proc4, "@:@@");
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTTextView";
+ cls = OS.objc_allocateClassPair(OS.class_NSTextView, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.class_addMethod(cls, OS.sel_insertText_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_doCommandBySelector_, proc3, "@::");
+ OS.class_addMethod(cls, OS.sel_textDidChange_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_textView_clickedOnLink_atIndex_, proc5, "@:@@@");
+ OS.class_addMethod(cls, OS.sel_dragSelectionWithEvent_offset_slideBack_, proc5, "@:@@@");
+ OS.class_addMethod(cls, OS.sel_shouldChangeTextInRange_replacementString_, shouldChangeTextInRange_replacementString_Proc, "@:{NSRange}@");
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTTextField";
+ cls = OS.objc_allocateClassPair(OS.class_NSTextField, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.class_addMethod(cls, OS.sel_acceptsFirstResponder, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_textDidChange_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_textDidEndEditing_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_textViewDidChangeSelection_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_textView_willChangeSelectionFromCharacterRange_toCharacterRange_, textWillChangeSelectionProc, "@:@{NSRange}{NSRange}");
+ OS.objc_registerClassPair(cls);
+
+ cls = registerCellSubclass(NSTextField.cellClass(), size, align, types);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ NSTextField.setCellClass(cls);
+
+ className = "SWTTreeItem";
+ cls = OS.objc_allocateClassPair(OS.class_NSObject, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTView";
+ cls = OS.objc_allocateClassPair(OS.class_NSView, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_canBecomeKeyView, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_isFlipped, isFlippedProc, "@:");
+ OS.class_addMethod(cls, OS.sel_acceptsFirstResponder, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_isOpaque, proc2, "@:");
+ addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc);
+ addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc);
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTWindow";
+ cls = OS.objc_allocateClassPair(OS.class_NSWindow, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_sendEvent_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_helpRequested_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_canBecomeKeyWindow, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_becomeKeyWindow, proc2, "@:");
+ OS.class_addMethod(cls, OS.sel_makeFirstResponder_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_noResponderFor_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_view_stringForToolTip_point_userData_, view_stringForToolTip_point_userDataProc, "@:@i{NSPoint}@");
+ addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc);
+ OS.objc_registerClassPair(cls);
+
+ className = "SWTWindowDelegate";
+ cls = OS.objc_allocateClassPair(OS.class_NSObject, className, 0);
+ OS.class_addIvar(cls, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(cls, OS.sel_windowDidResize_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_windowDidMove_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_windowShouldClose_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_windowWillClose_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_windowDidResignKey_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_windowDidBecomeKey_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_timerProc_, proc3, "@:@");
+ OS.class_addMethod(cls, OS.sel_systemSettingsChanged_, proc3, "@:@");
+ OS.objc_registerClassPair(cls);
+}
+
+NSFont getFont (int /*long*/ cls, int /*long*/ sel) {
+ int /*long*/ widget = OS.objc_msgSend (OS.objc_msgSend (cls, OS.sel_alloc), OS.sel_initWithFrame_, new NSRect());
+ int /*long*/ font = 0;
+ if (OS.objc_msgSend_bool (widget, OS.sel_respondsToSelector_, sel)) {
+ font = OS.objc_msgSend (widget, sel);
+ }
+ NSFont result = null;
+ if (font != 0) {
+ result = new NSFont (font);
+ } else {
+ result = NSFont.systemFontOfSize (NSFont.systemFontSizeForControlSize (OS.NSRegularControlSize));
+ }
+ result.retain ();
+ OS.objc_msgSend (widget, OS.sel_release);
+ return result;
+}
+
+void initColors () {
+ colors = new float /*double*/ [SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT + 1][];
+ colors[SWT.COLOR_INFO_FOREGROUND] = getWidgetColorRGB(SWT.COLOR_INFO_FOREGROUND);
+ colors[SWT.COLOR_INFO_BACKGROUND] = getWidgetColorRGB(SWT.COLOR_INFO_BACKGROUND);
+ colors[SWT.COLOR_TITLE_FOREGROUND] = getWidgetColorRGB(SWT.COLOR_TITLE_FOREGROUND);
+ colors[SWT.COLOR_TITLE_BACKGROUND] = getWidgetColorRGB(SWT.COLOR_TITLE_BACKGROUND);
+ colors[SWT.COLOR_TITLE_BACKGROUND_GRADIENT] = getWidgetColorRGB(SWT.COLOR_TITLE_BACKGROUND_GRADIENT);
+ colors[SWT.COLOR_TITLE_INACTIVE_FOREGROUND] = getWidgetColorRGB(SWT.COLOR_TITLE_INACTIVE_FOREGROUND);
+ colors[SWT.COLOR_TITLE_INACTIVE_BACKGROUND] = getWidgetColorRGB(SWT.COLOR_TITLE_INACTIVE_BACKGROUND);
+ colors[SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT] = getWidgetColorRGB(SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT);
+ colors[SWT.COLOR_WIDGET_DARK_SHADOW] = getWidgetColorRGB(SWT.COLOR_WIDGET_DARK_SHADOW);
+ colors[SWT.COLOR_WIDGET_NORMAL_SHADOW] = getWidgetColorRGB(SWT.COLOR_WIDGET_NORMAL_SHADOW);
+ colors[SWT.COLOR_WIDGET_LIGHT_SHADOW] = getWidgetColorRGB(SWT.COLOR_WIDGET_LIGHT_SHADOW);
+ colors[SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW] = getWidgetColorRGB(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
+ colors[SWT.COLOR_WIDGET_BACKGROUND] = getWidgetColorRGB(SWT.COLOR_WIDGET_BACKGROUND);
+ colors[SWT.COLOR_WIDGET_FOREGROUND] = getWidgetColorRGB(SWT.COLOR_WIDGET_FOREGROUND);
+ colors[SWT.COLOR_WIDGET_BORDER] = getWidgetColorRGB(SWT.COLOR_WIDGET_BORDER);
+ colors[SWT.COLOR_LIST_FOREGROUND] = getWidgetColorRGB(SWT.COLOR_LIST_FOREGROUND);
+ colors[SWT.COLOR_LIST_BACKGROUND] = getWidgetColorRGB(SWT.COLOR_LIST_BACKGROUND);
+ colors[SWT.COLOR_LIST_SELECTION_TEXT] = getWidgetColorRGB(SWT.COLOR_LIST_SELECTION_TEXT);
+ colors[SWT.COLOR_LIST_SELECTION] = getWidgetColorRGB(SWT.COLOR_LIST_SELECTION);
+
+ alternateSelectedControlColor = getWidgetColorRGB(NSColor.alternateSelectedControlColor());
+ alternateSelectedControlTextColor = getWidgetColorRGB(NSColor.alternateSelectedControlTextColor());
+ secondarySelectedControlColor = getWidgetColorRGB(NSColor.secondarySelectedControlColor());
+ selectedControlTextColor = getWidgetColorRGB(NSColor.selectedControlTextColor());
+}
+
+void initFonts () {
+ smallFonts = System.getProperty("org.eclipse.swt.internal.carbon.smallFonts") != null;
+ buttonFont = getFont (OS.class_NSButton, OS.sel_font);
+ popUpButtonFont = getFont (OS.class_NSPopUpButton, OS.sel_font);
+ textFieldFont = getFont (OS.class_NSTextField, OS.sel_font);
+ secureTextFieldFont = getFont (OS.class_NSSecureTextField, OS.sel_font);
+ searchFieldFont = getFont (OS.class_NSSearchField, OS.sel_font);
+ comboBoxFont = getFont (OS.class_NSComboBox, OS.sel_font);
+ sliderFont = getFont (OS.class_NSSlider, OS.sel_font);
+ scrollerFont = getFont (OS.class_NSScroller, OS.sel_font);
+ textViewFont = getFont (OS.class_NSTextView, OS.sel_font);
+ tableViewFont = getFont (OS.class_NSTableView, OS.sel_font);
+ outlineViewFont = getFont (OS.class_NSOutlineView, OS.sel_font);
+ datePickerFont = getFont (OS.class_NSDatePicker, OS.sel_font);
+ boxFont = getFont (OS.class_NSBox, OS.sel_titleFont);
+ tabViewFont = getFont (OS.class_NSTabView, OS.sel_font);
+ progressIndicatorFont = getFont (OS.class_NSProgressIndicator, OS.sel_font);
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Display</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param data the platform specific GC data
+ * @return the platform specific GC handle
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for gc creation</li>
+ * </ul>
+ */
+public int /*long*/ internal_new_GC (GCData data) {
+ if (isDisposed()) SWT.error(SWT.ERROR_DEVICE_DISPOSED);
+ if (screenWindow == null) {
+ NSWindow window = (NSWindow) new NSWindow ().alloc ();
+ NSRect rect = new NSRect();
+ window = window.initWithContentRect(rect, OS.NSBorderlessWindowMask, OS.NSBackingStoreBuffered, false);
+ window.setReleasedWhenClosed(false);
+ screenWindow = window;
+ }
+ NSGraphicsContext context = screenWindow.graphicsContext();
+// NSAffineTransform transform = NSAffineTransform.transform();
+// NSSize size = handle.size();
+// transform.translateXBy(0, size.height);
+// transform.scaleXBy(1, -1);
+// transform.set();
+ if (data != null) {
+ int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
+ if ((data.style & mask) == 0) {
+ data.style |= SWT.LEFT_TO_RIGHT;
+ }
+ data.device = this;
+ data.background = getSystemColor(SWT.COLOR_WHITE).handle;
+ data.foreground = getSystemColor(SWT.COLOR_BLACK).handle;
+ data.font = getSystemFont();
+ }
+ return context.id;
+}
+
+/**
+ * Invokes platform specific functionality to dispose a GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Display</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param hDC the platform specific GC handle
+ * @param data the platform specific GC data
+ */
+public void internal_dispose_GC (int /*long*/ context, GCData data) {
+ if (isDisposed()) SWT.error(SWT.ERROR_DEVICE_DISPOSED);
+
+}
+
+static boolean isValidClass (Class clazz) {
+ String name = clazz.getName ();
+ int index = name.lastIndexOf ('.');
+ return name.substring (0, index + 1).equals (PACKAGE_PREFIX);
+}
+
+boolean isValidThread () {
+ return thread == Thread.currentThread ();
+}
+
+/**
+ * Generate a low level system event.
+ *
+ * <code>post</code> is used to generate low level keyboard
+ * and mouse events. The intent is to enable automated UI
+ * testing by simulating the input from the user. Most
+ * SWT applications should never need to call this method.
+ * <p>
+ * Note that this operation can fail when the operating system
+ * fails to generate the event for any reason. For example,
+ * this can happen when there is no such key or mouse button
+ * or when the system event queue is full.
+ * </p>
+ * <p>
+ * <b>Event Types:</b>
+ * <p>KeyDown, KeyUp
+ * <p>The following fields in the <code>Event</code> apply:
+ * <ul>
+ * <li>(in) type KeyDown or KeyUp</li>
+ * <p> Either one of:
+ * <li>(in) character a character that corresponds to a keyboard key</li>
+ * <li>(in) keyCode the key code of the key that was typed,
+ * as defined by the key code constants in class <code>SWT</code></li>
+ * </ul>
+ * <p>MouseDown, MouseUp</p>
+ * <p>The following fields in the <code>Event</code> apply:
+ * <ul>
+ * <li>(in) type MouseDown or MouseUp
+ * <li>(in) button the button that is pressed or released
+ * </ul>
+ * <p>MouseMove</p>
+ * <p>The following fields in the <code>Event</code> apply:
+ * <ul>
+ * <li>(in) type MouseMove
+ * <li>(in) x the x coordinate to move the mouse pointer to in screen coordinates
+ * <li>(in) y the y coordinate to move the mouse pointer to in screen coordinates
+ * </ul>
+ * <p>MouseWheel</p>
+ * <p>The following fields in the <code>Event</code> apply:
+ * <ul>
+ * <li>(in) type MouseWheel
+ * <li>(in) detail either SWT.SCROLL_LINE or SWT.SCROLL_PAGE
+ * <li>(in) count the number of lines or pages to scroll
+ * </ul>
+ * </dl>
+ *
+ * @param event the event to be generated
+ *
+ * @return true if the event was generated or false otherwise
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the event is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ *
+ */
+public boolean post(Event event) {
+ synchronized (Device.class) {
+ if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+ if (event == null) error (SWT.ERROR_NULL_ARGUMENT);
+
+ // TODO: Not sure if these calls have any effect on event posting.
+ if (!eventSourceDelaySet) {
+ OS.CGSetLocalEventsSuppressionInterval(0.0);
+ OS.CGEnableEventStateCombining(1);
+ OS.CGSetLocalEventsFilterDuringSuppressionState(OS.kCGEventFilterMaskPermitLocalKeyboardEvents | OS.kCGEventFilterMaskPermitLocalMouseEvents | OS.kCGEventFilterMaskPermitSystemDefinedEvents, OS.kCGEventSuppressionStateSuppressionInterval);
+ OS.CGSetLocalEventsFilterDuringSuppressionState(OS.kCGEventFilterMaskPermitLocalKeyboardEvents | OS.kCGEventFilterMaskPermitLocalMouseEvents | OS.kCGEventFilterMaskPermitSystemDefinedEvents, OS.kCGEventSuppressionStateRemoteMouseDrag);
+ eventSourceDelaySet = true;
+ }
+
+ int type = event.type;
+ switch (type) {
+ case SWT.KeyDown:
+ case SWT.KeyUp: {
+ short vKey = (short)Display.untranslateKey (event.keyCode);
+ if (vKey == 0) {
+ int /*long*/ uchrPtr = 0;
+ int /*long*/ currentKbd = OS.TISCopyCurrentKeyboardInputSource();
+ int /*long*/ uchrCFData = OS.TISGetInputSourceProperty(currentKbd, OS.kTISPropertyUnicodeKeyLayoutData());
+
+ if (uchrCFData == 0) return false;
+ uchrPtr = OS.CFDataGetBytePtr(uchrCFData);
+ if (uchrPtr == 0) return false;
+ if (OS.CFDataGetLength(uchrCFData) == 0) return false;
+ int maxStringLength = 256;
+ vKey = -1;
+ char [] output = new char [maxStringLength];
+ int [] actualStringLength = new int [1];
+ for (short i = 0 ; i <= 0x7F ; i++) {
+ OS.UCKeyTranslate (uchrPtr, i, (short)(type == SWT.KeyDown ? OS.kUCKeyActionDown : OS.kUCKeyActionUp), 0, OS.LMGetKbdType(), 0, deadKeyState, maxStringLength, actualStringLength, output);
+ if (output[0] == event.character) {
+ vKey = i;
+ break;
+ }
+ }
+ if (vKey == -1) {
+ for (short i = 0 ; i <= 0x7F ; i++) {
+ OS.UCKeyTranslate (uchrPtr, i, (short)(type == SWT.KeyDown ? OS.kUCKeyActionDown : OS.kUCKeyActionUp), OS.shiftKey, OS.LMGetKbdType(), 0, deadKeyState, maxStringLength, actualStringLength, output);
+ if (output[0] == event.character) {
+ vKey = i;
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Bug(?) in UCKeyTranslate: If event.keyCode doesn't map to a valid SWT constant and event.characer is 0 we still need to post an event.
+ * In Carbon, KeyTranslate eventually found a key that generated 0 but UCKeyTranslate never generates 0.
+ * When that happens, post an event from key 127, which does nothing.
+ */
+ if (vKey == -1 && event.character == 0) {
+ vKey = 127;
+ }
+
+ if (vKey == -1) return false;
+
+ return OS.CGPostKeyboardEvent((short)0, vKey, type == SWT.KeyDown) == 0;
+ }
+ case SWT.MouseDown:
+ case SWT.MouseMove:
+ case SWT.MouseUp: {
+ CGPoint mouseCursorPosition = new CGPoint ();
+ int chord = OS.GetCurrentButtonState ();
+
+ if (type == SWT.MouseMove) {
+ mouseCursorPosition.x = event.x;
+ mouseCursorPosition.y = event.y;
+ return OS.CGPostMouseEvent (mouseCursorPosition, true, 5, (chord & 0x1) != 0, (chord & 0x2) != 0, (chord & 0x4) != 0, (chord & 0x8) != 0, (chord & 0x10) != 0) == 0;
+ } else {
+ int button = event.button;
+ if (button < 1 || button > 5) return false;
+ boolean button1 = false, button2 = false, button3 = false, button4 = false, button5 = false;
+ switch (button) {
+ case 1: {
+ button1 = type == SWT.MouseDown;
+ button2 = (chord & 0x4) != 0;
+ button3 = (chord & 0x2) != 0;
+ button4 = (chord & 0x8) != 0;
+ button5 = (chord & 0x10) != 0;
+ break;
+ }
+ case 2: {
+ button1 = (chord & 0x1) != 0;
+ button2 = type == SWT.MouseDown;
+ button3 = (chord & 0x2) != 0;
+ button4 = (chord & 0x8) != 0;
+ button5 = (chord & 0x10) != 0;
+ break;
+ }
+ case 3: {
+ button1 = (chord & 0x1) != 0;
+ button2 = (chord & 0x4) != 0;
+ button3 = type == SWT.MouseDown;
+ button4 = (chord & 0x8) != 0;
+ button5 = (chord & 0x10) != 0;
+ break;
+ }
+ case 4: {
+ button1 = (chord & 0x1) != 0;
+ button2 = (chord & 0x4) != 0;
+ button3 = (chord & 0x2) != 0;
+ button4 = type == SWT.MouseDown;
+ button5 = (chord & 0x10) != 0;
+ break;
+ }
+ case 5: {
+ button1 = (chord & 0x1) != 0;
+ button2 = (chord & 0x4) != 0;
+ button3 = (chord & 0x2) != 0;
+ button4 = (chord & 0x8) != 0;
+ button5 = type == SWT.MouseDown;
+ break;
+ }
+ }
+
+ NSPoint nsCursorPosition = NSEvent.mouseLocation();
+ NSRect primaryFrame = getPrimaryFrame();
+ mouseCursorPosition.x = nsCursorPosition.x;
+ mouseCursorPosition.y = (int) (primaryFrame.height - nsCursorPosition.y);
+ return OS.CGPostMouseEvent (mouseCursorPosition, true, 5, button1, button3, button2, button4, button5) == 0;
+ }
+ }
+ case SWT.MouseWheel: {
+ return OS.CGPostScrollWheelEvent(1, event.count) == 0;
+ }
+ }
+ return false;
+ }
+}
+
+void postEvent (Event event) {
+ /*
+ * Place the event at the end of the event queue.
+ * This code is always called in the Display's
+ * thread so it must be re-enterant but does not
+ * need to be synchronized.
+ */
+ if (eventQueue == null) eventQueue = new Event [4];
+ int index = 0;
+ int length = eventQueue.length;
+ while (index < length) {
+ if (eventQueue [index] == null) break;
+ index++;
+ }
+ if (index == length) {
+ Event [] newQueue = new Event [length + 4];
+ System.arraycopy (eventQueue, 0, newQueue, 0, length);
+ eventQueue = newQueue;
+ }
+ eventQueue [index] = event;
+}
+
+/**
+ * Maps a point from one coordinate system to another.
+ * When the control is null, coordinates are mapped to
+ * the display.
+ * <p>
+ * NOTE: On right-to-left platforms where the coordinate
+ * systems are mirrored, special care needs to be taken
+ * when mapping coordinates from one control to another
+ * to ensure the result is correctly mirrored.
+ *
+ * Mapping a point that is the origin of a rectangle and
+ * then adding the width and height is not equivalent to
+ * mapping the rectangle. When one control is mirrored
+ * and the other is not, adding the width and height to a
+ * point that was mapped causes the rectangle to extend
+ * in the wrong direction. Mapping the entire rectangle
+ * instead of just one point causes both the origin and
+ * the corner of the rectangle to be mapped.
+ * </p>
+ *
+ * @param from the source <code>Control</code> or <code>null</code>
+ * @param to the destination <code>Control</code> or <code>null</code>
+ * @param point to be mapped
+ * @return point with mapped coordinates
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 2.1.2
+ */
+public Point map (Control from, Control to, Point point) {
+ checkDevice ();
+ if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
+ return map (from, to, point.x, point.y);
+}
+
+/**
+ * Maps a point from one coordinate system to another.
+ * When the control is null, coordinates are mapped to
+ * the display.
+ * <p>
+ * NOTE: On right-to-left platforms where the coordinate
+ * systems are mirrored, special care needs to be taken
+ * when mapping coordinates from one control to another
+ * to ensure the result is correctly mirrored.
+ *
+ * Mapping a point that is the origin of a rectangle and
+ * then adding the width and height is not equivalent to
+ * mapping the rectangle. When one control is mirrored
+ * and the other is not, adding the width and height to a
+ * point that was mapped causes the rectangle to extend
+ * in the wrong direction. Mapping the entire rectangle
+ * instead of just one point causes both the origin and
+ * the corner of the rectangle to be mapped.
+ * </p>
+ *
+ * @param from the source <code>Control</code> or <code>null</code>
+ * @param to the destination <code>Control</code> or <code>null</code>
+ * @param x coordinates to be mapped
+ * @param y coordinates to be mapped
+ * @return point with mapped coordinates
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 2.1.2
+ */
+public Point map (Control from, Control to, int x, int y) {
+ checkDevice ();
+ if (from != null && from.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (to != null && to.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+ Point point = new Point (x, y);
+ if (from == to) return point;
+ NSPoint pt = new NSPoint();
+ pt.x = x;
+ pt.y = y;
+ NSWindow fromWindow = from != null ? from.view.window() : null;
+ NSWindow toWindow = to != null ? to.view.window() : null;
+ if (toWindow != null && fromWindow != null && toWindow.id == fromWindow.id) {
+ if (!from.view.isFlipped ()) {
+ pt.y = from.view.bounds().height - pt.y;
+ }
+ pt = from.view.convertPoint_toView_(pt, to.view);
+ if (!to.view.isFlipped ()) {
+ pt.y = to.view.bounds().height - pt.y;
+ }
+ } else {
+ NSRect primaryFrame = getPrimaryFrame();
+ if (from != null) {
+ NSView view = from.eventView ();
+ if (!view.isFlipped ()) {
+ pt.y = view.bounds().height - pt.y;
+ }
+ pt = view.convertPoint_toView_(pt, null);
+ pt = fromWindow.convertBaseToScreen(pt);
+ pt.y = primaryFrame.height - pt.y;
+ }
+ if (to != null) {
+ NSView view = to.eventView ();
+ pt.y = primaryFrame.height - pt.y;
+ pt = toWindow.convertScreenToBase(pt);
+ pt = view.convertPoint_fromView_(pt, null);
+ if (!view.isFlipped ()) {
+ pt.y = view.bounds().height - pt.y;
+ }
+ }
+ }
+ point.x = (int)pt.x;
+ point.y = (int)pt.y;
+ return point;
+}
+
+/**
+ * Maps a point from one coordinate system to another.
+ * When the control is null, coordinates are mapped to
+ * the display.
+ * <p>
+ * NOTE: On right-to-left platforms where the coordinate
+ * systems are mirrored, special care needs to be taken
+ * when mapping coordinates from one control to another
+ * to ensure the result is correctly mirrored.
+ *
+ * Mapping a point that is the origin of a rectangle and
+ * then adding the width and height is not equivalent to
+ * mapping the rectangle. When one control is mirrored
+ * and the other is not, adding the width and height to a
+ * point that was mapped causes the rectangle to extend
+ * in the wrong direction. Mapping the entire rectangle
+ * instead of just one point causes both the origin and
+ * the corner of the rectangle to be mapped.
+ * </p>
+ *
+ * @param from the source <code>Control</code> or <code>null</code>
+ * @param to the destination <code>Control</code> or <code>null</code>
+ * @param rectangle to be mapped
+ * @return rectangle with mapped coordinates
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 2.1.2
+ */
+public Rectangle map (Control from, Control to, Rectangle rectangle) {
+ checkDevice ();
+ if (rectangle == null) error (SWT.ERROR_NULL_ARGUMENT);
+ return map (from, to, rectangle.x, rectangle.y, rectangle.width, rectangle.height);
+}
+
+/**
+ * Maps a point from one coordinate system to another.
+ * When the control is null, coordinates are mapped to
+ * the display.
+ * <p>
+ * NOTE: On right-to-left platforms where the coordinate
+ * systems are mirrored, special care needs to be taken
+ * when mapping coordinates from one control to another
+ * to ensure the result is correctly mirrored.
+ *
+ * Mapping a point that is the origin of a rectangle and
+ * then adding the width and height is not equivalent to
+ * mapping the rectangle. When one control is mirrored
+ * and the other is not, adding the width and height to a
+ * point that was mapped causes the rectangle to extend
+ * in the wrong direction. Mapping the entire rectangle
+ * instead of just one point causes both the origin and
+ * the corner of the rectangle to be mapped.
+ * </p>
+ *
+ * @param from the source <code>Control</code> or <code>null</code>
+ * @param to the destination <code>Control</code> or <code>null</code>
+ * @param x coordinates to be mapped
+ * @param y coordinates to be mapped
+ * @param width coordinates to be mapped
+ * @param height coordinates to be mapped
+ * @return rectangle with mapped coordinates
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 2.1.2
+ */
+public Rectangle map (Control from, Control to, int x, int y, int width, int height) {
+ checkDevice ();
+ if (from != null && from.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (to != null && to.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+ Rectangle rectangle = new Rectangle (x, y, width, height);
+ if (from == to) return rectangle;
+ NSPoint pt = new NSPoint();
+ pt.x = x;
+ pt.y = y;
+ NSWindow fromWindow = from != null ? from.view.window() : null;
+ NSWindow toWindow = to != null ? to.view.window() : null;
+ if (toWindow != null && fromWindow != null && toWindow.id == fromWindow.id) {
+ if (!from.view.isFlipped ()) {
+ pt.y = from.view.bounds().height - pt.y;
+ }
+ pt = from.view.convertPoint_toView_(pt, to.view);
+ if (!to.view.isFlipped ()) {
+ pt.y = to.view.bounds().height - pt.y;
+ }
+ } else {
+ NSRect primaryFrame = getPrimaryFrame();
+ if (from != null) {
+ NSView view = from.eventView ();
+ if (!view.isFlipped ()) {
+ pt.y = view.bounds().height - pt.y;
+ }
+ pt = view.convertPoint_toView_(pt, null);
+ pt = fromWindow.convertBaseToScreen(pt);
+ pt.y = primaryFrame.height - pt.y;
+ }
+ if (to != null) {
+ NSView view = to.eventView ();
+ pt.y = primaryFrame.height - pt.y;
+ pt = toWindow.convertScreenToBase(pt);
+ pt = view.convertPoint_fromView_(pt, null);
+ if (!view.isFlipped ()) {
+ pt.y = view.bounds().height - pt.y;
+ }
+ }
+ }
+ rectangle.x = (int)pt.x;
+ rectangle.y = (int)pt.y;
+ return rectangle;
+}
+
+int /*long*/ observerProc (int /*long*/ observer, int /*long*/ activity, int /*long*/ info) {
+ switch ((int)/*64*/activity) {
+ case OS.kCFRunLoopBeforeWaiting:
+ if (runAsyncMessages) {
+ if (runAsyncMessages (false)) wakeThread ();
+ }
+ break;
+ }
+ return 0;
+}
+
+/**
+ * Reads an event from the operating system's event queue,
+ * dispatches it appropriately, and returns <code>true</code>
+ * if there is potentially more work to do, or <code>false</code>
+ * if the caller can sleep until another event is placed on
+ * the event queue.
+ * <p>
+ * In addition to checking the system event queue, this method also
+ * checks if any inter-thread messages (created by <code>syncExec()</code>
+ * or <code>asyncExec()</code>) are waiting to be processed, and if
+ * so handles them before returning.
+ * </p>
+ *
+ * @return <code>false</code> if the caller can sleep upon return from this method
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_FAILED_EXEC - if an exception occurred while running an inter-thread message</li>
+ * </ul>
+ *
+ * @see #sleep
+ * @see #wake
+ */
+public boolean readAndDispatch () {
+ checkDevice ();
+ if (sendEventCount == 0 && loopCount == poolCount - 1 && Callback.getEntryCount () == 0) removePool ();
+ addPool ();
+ loopCount++;
+ boolean events = false;
+ try {
+ events |= runSettings ();
+ events |= runTimers ();
+ events |= runContexts ();
+ events |= runPopups ();
+ NSEvent event = application.nextEventMatchingMask(0, null, OS.NSDefaultRunLoopMode, true);
+ if (event != null) {
+ events = true;
+ application.sendEvent(event);
+ }
+ events |= runPaint ();
+ events |= runDeferredEvents ();
+ if (!events) {
+ events = isDisposed () || runAsyncMessages (false);
+ }
+ } finally {
+ removePool ();
+ loopCount--;
+ if (sendEventCount == 0 && loopCount == poolCount && Callback.getEntryCount () == 0) addPool ();
+ }
+ return events;
+}
+
+static void register (Display display) {
+ synchronized (Device.class) {
+ for (int i=0; i<Displays.length; i++) {
+ if (Displays [i] == null) {
+ Displays [i] = display;
+ return;
+ }
+ }
+ Display [] newDisplays = new Display [Displays.length + 4];
+ System.arraycopy (Displays, 0, newDisplays, 0, Displays.length);
+ newDisplays [Displays.length] = display;
+ Displays = newDisplays;
+ }
+}
+
+/**
+ * Releases any internal resources back to the operating
+ * system and clears all fields except the device handle.
+ * <p>
+ * Disposes all shells which are currently open on the display.
+ * After this method has been invoked, all related related shells
+ * will answer <code>true</code> when sent the message
+ * <code>isDisposed()</code>.
+ * </p><p>
+ * When a device is destroyed, resources that were acquired
+ * on behalf of the programmer need to be returned to the
+ * operating system. For example, if the device allocated a
+ * font to be used as the system font, this font would be
+ * freed in <code>release</code>. Also,to assist the garbage
+ * collector and minimize the amount of memory that is not
+ * reclaimed when the programmer keeps a reference to a
+ * disposed device, all fields except the handle are zero'd.
+ * The handle is needed by <code>destroy</code>.
+ * </p>
+ * This method is called before <code>destroy</code>.
+ *
+ * @see Device#dispose
+ * @see #destroy
+ */
+protected void release () {
+ disposing = true;
+ sendEvent (SWT.Dispose, new Event ());
+ Shell [] shells = getShells ();
+ for (int i=0; i<shells.length; i++) {
+ Shell shell = shells [i];
+ if (!shell.isDisposed ()) shell.dispose ();
+ }
+ if (tray != null) tray.dispose ();
+ tray = null;
+ while (readAndDispatch ()) {}
+ if (disposeList != null) {
+ for (int i=0; i<disposeList.length; i++) {
+ if (disposeList [i] != null) disposeList [i].run ();
+ }
+ }
+ disposeList = null;
+ synchronizer.releaseSynchronizer ();
+ synchronizer = null;
+ releaseDisplay ();
+ super.release ();
+}
+
+void releaseDisplay () {
+ /* Release the System Images */
+ if (errorImage != null) errorImage.dispose ();
+ if (infoImage != null) infoImage.dispose ();
+ if (warningImage != null) warningImage.dispose ();
+ errorImage = infoImage = warningImage = null;
+
+ currentCaret = null;
+
+ /* Release Timers */
+ if (hoverTimer != null) timerExec(-1, hoverTimer);
+ hoverTimer = null;
+ if (caretTimer != null) timerExec(-1, caretTimer);
+ caretTimer = null;
+ if (nsTimers != null) {
+ for (int i=0; i<nsTimers.length; i++) {
+ if (nsTimers [i] != null) {
+ nsTimers [i].invalidate();
+ nsTimers [i].release();
+ }
+ }
+ }
+ nsTimers = null;
+ if (timerDelegate != null) timerDelegate.release();
+ timerDelegate = null;
+
+ /* Release the System Cursors */
+ for (int i = 0; i < cursors.length; i++) {
+ if (cursors [i] != null) cursors [i].dispose ();
+ }
+ cursors = null;
+
+ /* Release default fonts */
+ if (buttonFont != null) buttonFont.release ();
+ if (popUpButtonFont != null) popUpButtonFont.release ();
+ if (textFieldFont != null) textFieldFont.release ();
+ if (secureTextFieldFont != null) secureTextFieldFont.release ();
+ if (searchFieldFont != null) searchFieldFont.release ();
+ if (comboBoxFont != null) comboBoxFont.release ();
+ if (sliderFont != null) sliderFont.release ();
+ if (scrollerFont != null) scrollerFont.release ();
+ if (textViewFont != null) textViewFont.release ();
+ if (tableViewFont != null) tableViewFont.release ();
+ if (outlineViewFont != null) outlineViewFont.release ();
+ if (datePickerFont != null) datePickerFont.release ();
+ if (boxFont != null) boxFont.release ();
+ if (tabViewFont != null) tabViewFont.release ();
+ if (progressIndicatorFont != null) progressIndicatorFont.release ();
+ buttonFont = popUpButtonFont = textFieldFont = secureTextFieldFont = null;
+ searchFieldFont = comboBoxFont = sliderFont = scrollerFont;
+ textViewFont = tableViewFont = outlineViewFont = datePickerFont = null;
+ boxFont = tabViewFont = progressIndicatorFont = null;
+
+ /* Release Dock image */
+ if (dockImage != null) dockImage.release();
+ dockImage = null;
+
+ if (screenWindow != null) screenWindow.release();
+ screenWindow = null;
+
+ if (needsDisplay != null) needsDisplay.release();
+ if (needsDisplayInRect != null) needsDisplayInRect.release();
+ if (isPainting != null) isPainting.release();
+ needsDisplay = needsDisplayInRect = isPainting = null;
+
+ modalShells = null;
+ menuBar = null;
+ menus = null;
+
+ if (markedAttributes != null) markedAttributes.release();
+ markedAttributes = null;
+
+ if (oldCursorSetProc != 0) {
+ int /*long*/ method = OS.class_getInstanceMethod(OS.class_NSCursor, OS.sel_set);
+ OS.method_setImplementation(method, oldCursorSetProc);
+ }
+ if (cursorSetCallback != null) cursorSetCallback.dispose();
+ cursorSetCallback = null;
+
+ deadKeyState = null;
+
+ if (settingsDelegate != null) {
+ NSNotificationCenter.defaultCenter().removeObserver(settingsDelegate);
+ settingsDelegate.release();
+ }
+ settingsDelegate = null;
+
+ // Clear the menu bar if we created it.
+ if (!isEmbedded) {
+ //remove all existing menu items except the application menu
+ NSMenu menubar = application.mainMenu();
+ int /*long*/ count = menubar.numberOfItems();
+ while (count > 1) {
+ menubar.removeItemAtIndex(count - 1);
+ count--;
+ }
+ }
+
+ // The autorelease pool is cleaned up when we call NSApplication.terminate().
+
+ if (application != null && applicationClass != 0) {
+ OS.object_setClass (application.id, applicationClass);
+ }
+ application = null;
+ applicationClass = 0;
+
+ if (runLoopObserver != 0) {
+ OS.CFRunLoopObserverInvalidate (runLoopObserver);
+ OS.CFRelease (runLoopObserver);
+ }
+ runLoopObserver = 0;
+ if (observerCallback != null) observerCallback.dispose();
+ observerCallback = null;
+}
+
+void removeContext (GCData context) {
+ if (contexts == null) return;
+ int count = 0;
+ for (int i = 0; i < contexts.length; i++) {
+ if (contexts[i] != null) {
+ if (contexts [i] == context) {
+ contexts[i] = null;
+ } else {
+ count++;
+ }
+ }
+ }
+ if (count == 0) contexts = null;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when an event of the given type occurs anywhere in
+ * a widget. The event type is one of the event constants defined
+ * in class <code>SWT</code>.
+ *
+ * @param eventType the type of event to listen for
+ * @param listener the listener which should no longer be notified when the event occurs
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see Listener
+ * @see SWT
+ * @see #addFilter
+ * @see #addListener
+ *
+ * @since 3.0
+ */
+public void removeFilter (int eventType, Listener listener) {
+ checkDevice ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (filterTable == null) return;
+ filterTable.unhook (eventType, listener);
+ if (filterTable.size () == 0) filterTable = null;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when an event of the given type occurs. The event type
+ * is one of the event constants defined in class <code>SWT</code>.
+ *
+ * @param eventType the type of event to listen for
+ * @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 SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Listener
+ * @see SWT
+ * @see #addListener
+ *
+ * @since 2.0
+ */
+public void removeListener (int eventType, Listener listener) {
+ checkDevice ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (eventType, listener);
+}
+
+Widget removeWidget (NSObject view) {
+ if (view == null) return null;
+ int /*long*/ [] jniRef = new int /*long*/ [1];
+ OS.object_getInstanceVariable(view.id, SWT_OBJECT, jniRef);
+ if (jniRef[0] == 0) return null;
+ Widget widget = (Widget)OS.JNIGetObject(jniRef[0]);
+ OS.object_setInstanceVariable(view.id, SWT_OBJECT, 0);
+ return widget;
+}
+
+void removeMenu (Menu menu) {
+ if (menus == null) return;
+ for (int i = 0; i < menus.length; i++) {
+ if (menus [i] == menu) {
+ menus[i] = null;
+ break;
+ }
+ }
+}
+
+void removePool () {
+ NSAutoreleasePool pool = pools [poolCount - 1];
+ pools [--poolCount] = null;
+ if (poolCount == 0) {
+ NSMutableDictionary dictionary = NSThread.currentThread().threadDictionary();
+ dictionary.removeObjectForKey(NSString.stringWith("SWT_NSAutoreleasePool"));
+ }
+ pool.release ();
+}
+
+void removePopup (Menu menu) {
+ if (popups == null) return;
+ for (int i=0; i<popups.length; i++) {
+ if (popups [i] == menu) {
+ popups [i] = null;
+ return;
+ }
+ }
+}
+
+boolean runAsyncMessages (boolean all) {
+ return synchronizer.runAsyncMessages (all);
+}
+
+boolean runContexts () {
+ if (contexts != null) {
+ for (int i = 0; i < contexts.length; i++) {
+ if (contexts[i] != null && contexts[i].flippedContext != null) {
+ contexts[i].flippedContext.flushGraphics();
+ }
+ }
+ }
+ return false;
+}
+
+boolean runDeferredEvents () {
+ boolean run = false;
+ /*
+ * Run deferred events. This code is always
+ * called in the Display's thread so it must
+ * be re-enterant need not be synchronized.
+ */
+ while (eventQueue != null) {
+
+ /* Take an event off the queue */
+ Event event = eventQueue [0];
+ if (event == null) break;
+ int length = eventQueue.length;
+ System.arraycopy (eventQueue, 1, eventQueue, 0, --length);
+ eventQueue [length] = null;
+
+ /* Run the event */
+ Widget widget = event.widget;
+ if (widget != null && !widget.isDisposed ()) {
+ Widget item = event.item;
+ if (item == null || !item.isDisposed ()) {
+ run = true;
+ widget.notifyListeners (event.type, event);
+ }
+ }
+
+ /*
+ * At this point, the event queue could
+ * be null due to a recursive invokation
+ * when running the event.
+ */
+ }
+
+ /* Clear the queue */
+ eventQueue = null;
+ return run;
+}
+
+boolean runPaint () {
+ if (needsDisplay == null && needsDisplayInRect == null) return false;
+ if (needsDisplay != null) {
+ int /*long*/ count = needsDisplay.count();
+ for (int i = 0; i < count; i++) {
+ OS.objc_msgSend(needsDisplay.objectAtIndex(i).id, OS.sel_setNeedsDisplay_, true);
+ }
+ needsDisplay.release();
+ needsDisplay = null;
+ }
+ if (needsDisplayInRect != null) {
+ int /*long*/ count = needsDisplayInRect.count();
+ for (int i = 0; i < count; i+=2) {
+ NSValue value = new NSValue(needsDisplayInRect.objectAtIndex(i+1));
+ OS.objc_msgSend(needsDisplayInRect.objectAtIndex(i).id, OS.sel_setNeedsDisplayInRect_, value.rectValue());
+ }
+ needsDisplayInRect.release();
+ needsDisplayInRect = null;
+ }
+ return true;
+}
+
+boolean runPopups () {
+ if (popups == null) return false;
+ boolean result = false;
+ while (popups != null) {
+ Menu menu = popups [0];
+ if (menu == null) break;
+ runDeferredEvents ();
+ int length = popups.length;
+ System.arraycopy (popups, 1, popups, 0, --length);
+ popups [length] = null;
+ if (!menu.isDisposed ()) menu._setVisible (true);
+ result = true;
+ }
+ popups = null;
+ return result;
+}
+
+boolean runSettings () {
+ if (!runSettings) return false;
+ runSettings = false;
+ initColors ();
+ sendEvent (SWT.Settings, null);
+ Shell [] shells = getShells ();
+ for (int i=0; i<shells.length; i++) {
+ Shell shell = shells [i];
+ if (!shell.isDisposed ()) {
+ shell.redraw (true);
+ shell.layout (true, true);
+ }
+ }
+ return true;
+}
+
+boolean runTimers () {
+ if (timerList == null) return false;
+ boolean result = false;
+ for (int i=0; i<timerList.length; i++) {
+ if (nsTimers [i] == null && timerList [i] != null) {
+ Runnable runnable = timerList [i];
+ timerList [i] = null;
+ if (runnable != null) {
+ result = true;
+ runnable.run ();
+ }
+ }
+ }
+ return result;
+}
+
+void sendEvent (int eventType, Event event) {
+ if (eventTable == null && filterTable == null) {
+ return;
+ }
+ if (event == null) event = new Event ();
+ event.display = this;
+ event.type = eventType;
+ if (event.time == 0) event.time = getLastEventTime ();
+ sendEvent(eventTable, event);
+}
+
+void sendEvent (EventTable table, Event event) {
+ try {
+ sendEventCount++;
+ if (!filterEvent (event)) {
+ if (table != null) table.sendEvent (event);
+ }
+ } finally {
+ sendEventCount--;
+ }
+}
+
+static NSString getAppName() {
+ NSString name = null;
+ int pid = OS.getpid ();
+ int /*long*/ ptr = OS.getenv (ascii ("APP_NAME_" + pid));
+ if (ptr != 0) name = NSString.stringWithUTF8String(ptr);
+ if (name == null && APP_NAME != null) name = NSString.stringWith(APP_NAME);
+ if (name == null) {
+ id value = NSBundle.mainBundle().objectForInfoDictionaryKey(NSString.stringWith("CFBundleName"));
+ if (value != null) {
+ name = new NSString(value);
+ }
+ }
+ if (name == null) name = NSString.stringWith("SWT");
+ return name;
+}
+
+/**
+ * On platforms which support it, sets the application name
+ * to be the argument. On Motif, for example, this can be used
+ * to set the name used for resource lookup. Specifying
+ * <code>null</code> for the name clears it.
+ *
+ * @param name the new app name or <code>null</code>
+ */
+public static void setAppName (String name) {
+ APP_NAME = name;
+}
+
+//TODO use custom timer instead of timerExec
+Runnable hoverTimer = new Runnable () {
+ public void run () {
+ if (currentControl != null && !currentControl.isDisposed()) {
+ currentControl.sendMouseEvent (NSApplication.sharedApplication().currentEvent(), SWT.MouseHover, trackingControl != null && !trackingControl.isDisposed());
+ }
+ }
+};
+//TODO - use custom timer instead of timerExec
+Runnable caretTimer = new Runnable () {
+ public void run () {
+ if (currentCaret != null) {
+ if (currentCaret == null || currentCaret.isDisposed()) return;
+ if (currentCaret.blinkCaret ()) {
+ int blinkRate = currentCaret.blinkRate;
+ if (blinkRate != 0) timerExec (blinkRate, this);
+ } else {
+ currentCaret = null;
+ }
+ }
+
+ }
+};
+
+//TODO - use custom timer instead of timerExec
+Runnable defaultButtonTimer = new Runnable() {
+ public void run() {
+ if (isDisposed ()) return;
+ Shell shell = getActiveShell();
+ if (shell != null && !shell.isDisposed()) {
+ Button defaultButton = shell.defaultButton;
+ if (defaultButton != null && !defaultButton.isDisposed()) {
+ NSView view = defaultButton.view;
+ view.display();
+ }
+ }
+ if (isDisposed ()) return;
+ if (hasDefaultButton()) timerExec(DEFAULT_BUTTON_INTERVAL, this);
+ }
+};
+
+void setCurrentCaret (Caret caret) {
+ currentCaret = caret;
+ int blinkRate = currentCaret != null ? currentCaret.blinkRate : -1;
+ timerExec (blinkRate, caretTimer);
+}
+
+void setCursor (Control control) {
+ Cursor cursor = null;
+ if (control != null && !control.isDisposed()) cursor = control.findCursor ();
+ if (cursor == null) {
+ NSWindow window = application.keyWindow();
+ if (window != null) {
+ if (window.areCursorRectsEnabled ()) {
+ window.disableCursorRects ();
+ window.enableCursorRects ();
+ }
+ return;
+ }
+ cursor = getSystemCursor (SWT.CURSOR_ARROW);
+ }
+ lockCursor = false;
+ cursor.handle.set ();
+ lockCursor = true;
+}
+
+/**
+ * Sets the location of the on-screen pointer relative to the top left corner
+ * of the screen. <b>Note: It is typically considered bad practice for a
+ * program to move the on-screen pointer location.</b>
+ *
+ * @param x the new x coordinate for the cursor
+ * @param y the new y coordinate for the cursor
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 2.1
+ */
+public void setCursorLocation (int x, int y) {
+ checkDevice ();
+ CGPoint pt = new CGPoint ();
+ pt.x = x; pt.y = y;
+ OS.CGWarpMouseCursorPosition (pt);
+}
+
+/**
+ * Sets the location of the on-screen pointer relative to the top left corner
+ * of the screen. <b>Note: It is typically considered bad practice for a
+ * program to move the on-screen pointer location.</b>
+ *
+ * @param point new position
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 2.0
+ */
+public void setCursorLocation (Point point) {
+ checkDevice ();
+ if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setCursorLocation (point.x, point.y);
+}
+
+/**
+ * Sets the application defined property of the receiver
+ * with the specified name to the given argument.
+ * <p>
+ * Applications may have associated arbitrary objects with the
+ * receiver in this fashion. If the objects stored in the
+ * properties need to be notified when the display is disposed
+ * of, it is the application's responsibility provide a
+ * <code>disposeExec()</code> handler which does so.
+ * </p>
+ *
+ * @param key the name of the property
+ * @param value the new value for the property
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the key is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getData(String)
+ * @see #disposeExec(Runnable)
+ */
+public void setData (String key, Object value) {
+ checkDevice ();
+ if (key == null) error (SWT.ERROR_NULL_ARGUMENT);
+
+ if (key.equals (ADD_WIDGET_KEY)) {
+ Object [] data = (Object [])value;
+ NSObject object = (NSObject)data [0];
+ Widget widget = (Widget)data [1];
+ if (widget == null) {
+ removeWidget (object);
+ } else {
+ addWidget (object, widget);
+ }
+ }
+
+ /* Remove the key/value pair */
+ if (value == null) {
+ if (keys == null) return;
+ int index = 0;
+ while (index < keys.length && !keys [index].equals (key)) index++;
+ if (index == keys.length) return;
+ if (keys.length == 1) {
+ keys = null;
+ values = null;
+ } else {
+ String [] newKeys = new String [keys.length - 1];
+ Object [] newValues = new Object [values.length - 1];
+ System.arraycopy (keys, 0, newKeys, 0, index);
+ System.arraycopy (keys, index + 1, newKeys, index, newKeys.length - index);
+ System.arraycopy (values, 0, newValues, 0, index);
+ System.arraycopy (values, index + 1, newValues, index, newValues.length - index);
+ keys = newKeys;
+ values = newValues;
+ }
+ return;
+ }
+
+ /* Add the key/value pair */
+ if (keys == null) {
+ keys = new String [] {key};
+ values = new Object [] {value};
+ return;
+ }
+ for (int i=0; i<keys.length; i++) {
+ if (keys [i].equals (key)) {
+ values [i] = value;
+ return;
+ }
+ }
+ String [] newKeys = new String [keys.length + 1];
+ Object [] newValues = new Object [values.length + 1];
+ System.arraycopy (keys, 0, newKeys, 0, keys.length);
+ System.arraycopy (values, 0, newValues, 0, values.length);
+ newKeys [keys.length] = key;
+ newValues [values.length] = value;
+ keys = newKeys;
+ values = newValues;
+}
+
+void setMenuBar (Menu menu) {
+ if (menu == menuBar) return;
+ menuBar = menu;
+ //remove all existing menu items except the application menu
+ NSMenu menubar = application.mainMenu();
+ /*
+ * For some reason, NSMenu.cancelTracking() does not dismisses
+ * the menu right away when the menu bar is set in a stacked
+ * event loop. The fix is to use CancelMenuTracking() instead.
+ */
+// menubar.cancelTracking();
+ OS.CancelMenuTracking (OS.AcquireRootMenu (), true, 0);
+ int /*long*/ count = menubar.numberOfItems();
+ while (count > 1) {
+ menubar.removeItemAtIndex(count - 1);
+ count--;
+ }
+ //set parent of each item to NULL and add them to menubar
+ if (menu != null) {
+ MenuItem[] items = menu.getItems();
+ for (int i = 0; i < items.length; i++) {
+ MenuItem item = items[i];
+ NSMenuItem nsItem = item.nsItem;
+ nsItem.setMenu(null);
+ menubar.addItem(nsItem);
+
+ /*
+ * Bug in Cocoa: Calling NSMenuItem.setEnabled() for menu item of a menu bar only
+ * works when the menu bar is the current menu bar. The underline OS menu does get
+ * enabled/disable when that menu is set later on. The fix is to toggle the
+ * item enabled state to force the underline menu to be updated.
+ */
+ boolean enabled = menu.getEnabled () && item.getEnabled ();
+ nsItem.setEnabled(!enabled);
+ nsItem.setEnabled(enabled);
+ }
+ }
+}
+
+void setModalShell (Shell shell) {
+ if (modalShells == null) modalShells = new Shell [4];
+ int index = 0, length = modalShells.length;
+ while (index < length) {
+ if (modalShells [index] == shell) return;
+ if (modalShells [index] == null) break;
+ index++;
+ }
+ if (index == length) {
+ Shell [] newModalShells = new Shell [length + 4];
+ System.arraycopy (modalShells, 0, newModalShells, 0, length);
+ modalShells = newModalShells;
+ }
+ modalShells [index] = shell;
+ Shell [] shells = getShells ();
+ for (int i=0; i<shells.length; i++) shells [i].updateModal ();
+}
+
+/**
+ * Sets the application defined, display specific data
+ * associated with the receiver, to the argument.
+ * The <em>display specific data</em> is a single,
+ * unnamed field that is stored with every display.
+ * <p>
+ * Applications may put arbitrary objects in this field. If
+ * the object stored in the display specific data needs to
+ * be notified when the display is disposed of, it is the
+ * application's responsibility provide a
+ * <code>disposeExec()</code> handler which does so.
+ * </p>
+ *
+ * @param data the new display specific data
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getData()
+ * @see #disposeExec(Runnable)
+ */
+public void setData (Object data) {
+ checkDevice ();
+ this.data = data;
+}
+
+/**
+ * Sets the synchronizer used by the display to be
+ * the argument, which can not be null.
+ *
+ * @param synchronizer the new synchronizer for the display (must not be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the synchronizer is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_FAILED_EXEC - if an exception occurred while running an inter-thread message</li>
+ * </ul>
+ */
+public void setSynchronizer (Synchronizer synchronizer) {
+ checkDevice ();
+ if (synchronizer == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (synchronizer == this.synchronizer) return;
+ Synchronizer oldSynchronizer;
+ synchronized (Device.class) {
+ oldSynchronizer = this.synchronizer;
+ this.synchronizer = synchronizer;
+ }
+ if (oldSynchronizer != null) {
+ oldSynchronizer.runAsyncMessages(true);
+ }
+}
+
+/**
+ * Causes the user-interface thread to <em>sleep</em> (that is,
+ * to be put in a state where it does not consume CPU cycles)
+ * until an event is received or it is otherwise awakened.
+ *
+ * @return <code>true</code> if an event requiring dispatching was placed on the queue.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #wake
+ */
+public boolean sleep () {
+ checkDevice ();
+ if (getMessageCount () != 0) return true;
+ try {
+ addPool();
+ allowTimers = runAsyncMessages = false;
+ NSRunLoop.currentRunLoop().runMode(OS.NSDefaultRunLoopMode, NSDate.distantFuture());
+ allowTimers = runAsyncMessages = true;
+ } finally {
+ removePool();
+ }
+ return true;
+}
+
+int sourceProc (int info) {
+ return 0;
+}
+
+/**
+ * Causes the <code>run()</code> method of the runnable to
+ * be invoked by the user-interface thread at the next
+ * reasonable opportunity. The thread which calls this method
+ * is suspended until the runnable completes. Specifying <code>null</code>
+ * as the runnable simply wakes the user-interface thread.
+ * <p>
+ * Note that at the time the runnable is invoked, widgets
+ * that have the receiver as their display may have been
+ * disposed. Therefore, it is necessary to check for this
+ * case inside the runnable before accessing the widget.
+ * </p>
+ *
+ * @param runnable code to run on the user-interface thread or <code>null</code>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_FAILED_EXEC - if an exception occurred when executing the runnable</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #asyncExec
+ */
+public void syncExec (Runnable runnable) {
+ Synchronizer synchronizer;
+ synchronized (Device.class) {
+ if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+ synchronizer = this.synchronizer;
+ }
+ synchronizer.syncExec (runnable);
+}
+
+/**
+ * Causes the <code>run()</code> method of the runnable to
+ * be invoked by the user-interface thread after the specified
+ * number of milliseconds have elapsed. If milliseconds is less
+ * than zero, the runnable is not executed.
+ * <p>
+ * Note that at the time the runnable is invoked, widgets
+ * that have the receiver as their display may have been
+ * disposed. Therefore, it is necessary to check for this
+ * case inside the runnable before accessing the widget.
+ * </p>
+ *
+ * @param milliseconds the delay before running the runnable
+ * @param runnable code to run on the user-interface thread
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the runnable is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #asyncExec
+ */
+public void timerExec (int milliseconds, Runnable runnable) {
+ checkDevice ();
+ //TODO - remove a timer, reschedule a timer not tested
+ if (runnable == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (timerList == null) timerList = new Runnable [4];
+ if (nsTimers == null) nsTimers = new NSTimer [4];
+ int index = 0;
+ while (index < timerList.length) {
+ if (timerList [index] == runnable) break;
+ index++;
+ }
+ if (index != timerList.length) {
+ NSTimer timer = nsTimers [index];
+ if (timer == null) {
+ timerList [index] = null;
+ } else {
+ if (milliseconds < 0) {
+ timer.invalidate();
+ timer.release();
+ timerList [index] = null;
+ nsTimers [index] = null;
+ } else {
+ timer.setFireDate(NSDate.dateWithTimeIntervalSinceNow (milliseconds / 1000.0));
+ }
+ return;
+ }
+ }
+ if (milliseconds < 0) return;
+ index = 0;
+ while (index < timerList.length) {
+ if (timerList [index] == null) break;
+ index++;
+ }
+ if (index == timerList.length) {
+ Runnable [] newTimerList = new Runnable [timerList.length + 4];
+ System.arraycopy (timerList, 0, newTimerList, 0, timerList.length);
+ timerList = newTimerList;
+ NSTimer [] newTimerIds = new NSTimer [nsTimers.length + 4];
+ System.arraycopy (nsTimers, 0, newTimerIds, 0, nsTimers.length);
+ nsTimers = newTimerIds;
+ }
+ NSNumber userInfo = NSNumber.numberWithInt(index);
+ NSTimer timer = NSTimer.scheduledTimerWithTimeInterval(milliseconds / 1000.0, timerDelegate, OS.sel_timerProc_, userInfo, false);
+ NSRunLoop.currentRunLoop().addTimer(timer, OS.NSEventTrackingRunLoopMode);
+ timer.retain();
+ if (timer != null) {
+ nsTimers [index] = timer;
+ timerList [index] = runnable;
+ }
+}
+
+int /*long*/ timerProc (int /*long*/ id, int /*long*/ sel, int /*long*/ timerID) {
+ NSTimer timer = new NSTimer (timerID);
+ NSNumber number = new NSNumber(timer.userInfo());
+ int index = number.intValue();
+ if (timerList == null) return 0;
+ if (0 <= index && index < timerList.length) {
+ if (allowTimers) {
+ Runnable runnable = timerList [index];
+ timerList [index] = null;
+ nsTimers [index] = null;
+ if (runnable != null) runnable.run ();
+ } else {
+ nsTimers [index] = null;
+ wakeThread ();
+ }
+ }
+ timer.invalidate();
+ timer.release();
+ return 0;
+}
+
+/**
+ * Forces all outstanding paint requests for the display
+ * to be processed before this method returns.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Control#update()
+ */
+public void update () {
+ checkDevice ();
+ Shell [] shells = getShells ();
+ for (int i=0; i<shells.length; i++) {
+ Shell shell = shells [i];
+ if (!shell.isDisposed ()) shell.update (true);
+ }
+}
+
+void updateDefaultButton () {
+ timerExec(hasDefaultButton() ? DEFAULT_BUTTON_INTERVAL : -1, defaultButtonTimer);
+}
+
+void updateQuitMenu () {
+ boolean enabled = true;
+ Shell [] shells = getShells ();
+ int mask = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL;
+ for (int i=0; i<shells.length; i++) {
+ Shell shell = shells [i];
+ if ((shell.style & mask) != 0 && shell.isVisible ()) {
+ enabled = false;
+ break;
+ }
+ }
+
+ NSMenu mainmenu = application.mainMenu();
+ NSMenuItem appitem = mainmenu.itemAtIndex(0);
+ if (appitem != null) {
+ NSMenu sm = appitem.submenu();
+
+ // Normally this would be sel_terminate_ but we changed it so terminate: doesn't kill the app.
+ int /*long*/ quitIndex = sm.indexOfItemWithTarget(applicationDelegate, OS.sel_quitRequested_);
+
+ if (quitIndex != -1) {
+ NSMenuItem quitItem = sm.itemAtIndex(quitIndex);
+ quitItem.setEnabled(enabled);
+ }
+ }
+}
+
+
+/**
+ * If the receiver's user-interface thread was <code>sleep</code>ing,
+ * causes it to be awakened and start running again. Note that this
+ * method may be called from any thread.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #sleep
+ */
+public void wake () {
+ synchronized (Device.class) {
+ if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+ if (thread == Thread.currentThread ()) return;
+ wakeThread ();
+ }
+}
+
+void wakeThread () {
+ //new pool?
+ NSObject object = new NSObject().alloc().init();
+ object.performSelectorOnMainThread(OS.sel_release, null, false);
+}
+
+Control findControl (boolean checkTrim) {
+ return findControl(checkTrim, null);
+}
+
+Control findControl (boolean checkTrim, NSView[] hitView) {
+ NSView view = null;
+ NSPoint screenLocation = NSEvent.mouseLocation();
+ NSArray windows = application.orderedWindows();
+ for (int i = 0, count = (int)/*64*/windows.count(); i < count && view == null; i++) {
+ NSWindow window = new NSWindow(windows.objectAtIndex(i));
+ NSView contentView = window.contentView();
+ if (contentView != null && OS.NSPointInRect(screenLocation, window.frame())) {
+ NSPoint location = window.convertScreenToBase(screenLocation);
+ view = contentView.hitTest (location);
+ if (view == null && !checkTrim) {
+ view = contentView;
+ }
+ break;
+ }
+ }
+ Control control = null;
+ if (view != null) {
+ do {
+ Widget widget = getWidget (view);
+ if (widget instanceof Control) {
+ control = (Control)widget;
+ break;
+ }
+ view = view.superview();
+ } while (view != null);
+ }
+ if (checkTrim) {
+ if (control != null && control.isTrim (view)) control = null;
+ }
+ if (control != null && hitView != null) hitView[0] = view;
+ return control;
+}
+
+void finishLaunching (int /*long*/ id, int /*long*/ sel) {
+ /*
+ * [NSApplication finishLaunching] cannot run multiple times otherwise
+ * multiple main menus are added.
+ */
+ if (launched) return;
+ launched = true;
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ OS.objc_msgSendSuper(super_struct, sel);
+}
+
+void applicationDidBecomeActive (int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+ checkFocus();
+ checkEnterExit(findControl(true), null, false);
+}
+
+void applicationDidResignActive (int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+ checkFocus();
+ checkEnterExit(null, null, false);
+}
+
+int /*long*/ applicationNextEventMatchingMask (int /*long*/ id, int /*long*/ sel, int /*long*/ mask, int /*long*/ expiration, int /*long*/ mode, int /*long*/ dequeue) {
+ if (dequeue != 0 && trackingControl != null && !trackingControl.isDisposed()) runDeferredEvents();
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ int /*long*/ result = OS.objc_msgSendSuper(super_struct, sel, mask, expiration, mode, dequeue != 0);
+ if (result != 0) {
+ if (dequeue != 0 && trackingControl != null && !trackingControl.isDisposed()) {
+ applicationSendTrackingEvent(new NSEvent(result), trackingControl);
+ }
+ }
+ return result;
+}
+
+void applicationSendTrackingEvent (NSEvent nsEvent, Control trackingControl) {
+ int type = (int)/*64*/nsEvent.type();
+ switch (type) {
+ case OS.NSLeftMouseDown:
+ case OS.NSRightMouseDown:
+ case OS.NSOtherMouseDown:
+ trackingControl.sendMouseEvent (nsEvent, SWT.MouseDown, true);
+ break;
+ case OS.NSLeftMouseUp:
+ case OS.NSRightMouseUp:
+ case OS.NSOtherMouseUp:
+ checkEnterExit (findControl (true), nsEvent, true);
+ if (trackingControl.isDisposed()) return;
+ trackingControl.sendMouseEvent (nsEvent, SWT.MouseUp, true);
+ break;
+ case OS.NSLeftMouseDragged:
+ case OS.NSRightMouseDragged:
+ case OS.NSOtherMouseDragged:
+ checkEnterExit (trackingControl, nsEvent, true);
+ if (trackingControl.isDisposed()) return;
+ //FALL THROUGH
+ case OS.NSMouseMoved:
+ trackingControl.sendMouseEvent (nsEvent, SWT.MouseMove, true);
+ break;
+ }
+}
+
+void applicationSendEvent (int /*long*/ id, int /*long*/ sel, int /*long*/ event) {
+ NSEvent nsEvent = new NSEvent(event);
+ NSWindow window = nsEvent.window ();
+ int type = (int)/*64*/nsEvent.type ();
+ boolean down = false;
+ switch (type) {
+ case OS.NSLeftMouseDown:
+ case OS.NSRightMouseDown:
+ case OS.NSOtherMouseDown:
+ down = true;
+ case OS.NSLeftMouseUp:
+ case OS.NSRightMouseUp:
+ case OS.NSOtherMouseUp:
+ case OS.NSLeftMouseDragged:
+ case OS.NSRightMouseDragged:
+ case OS.NSOtherMouseDragged:
+ case OS.NSMouseMoved:
+ case OS.NSMouseEntered:
+ case OS.NSMouseExited:
+ case OS.NSKeyDown:
+ case OS.NSKeyUp:
+ case OS.NSScrollWheel:
+ if (window != null) {
+ Shell shell = (Shell) getWidget (window.id);
+ if (shell != null) {
+ Shell modalShell = shell.getModalShell ();
+ if (modalShell != null) {
+ if (down) {
+ if (!application.isActive()) {
+ application.activateIgnoringOtherApps(true);
+ }
+ NSRect rect = window.contentRectForFrameRect(window.frame());
+ NSPoint pt = window.convertBaseToScreen(nsEvent.locationInWindow());
+ if (OS.NSPointInRect(pt, rect)) beep ();
+ }
+ return;
+ }
+ }
+ }
+ break;
+ }
+ sendEvent = true;
+
+ /*
+ * Feature in Cocoa. The help key triggers context-sensitive help but doesn't get forwarded to the window as a key event.
+ * If the event is destined for the key window, is the help key, and is an NSKeyDown, send it directly to the window first.
+ */
+ if (window != null && window.isKeyWindow() && nsEvent.type() == OS.NSKeyDown && (nsEvent.modifierFlags() & OS.NSHelpKeyMask) != 0) {
+ window.sendEvent(nsEvent);
+ }
+
+ /*
+ * Feature in Cocoa. NSKeyUp events are not delivered to the window if the command key is down.
+ * If the event is destined for the key window, and it's a key up and the command key is down, send it directly to the window.
+ */
+ if (window != null && window.isKeyWindow() && nsEvent.type() == OS.NSKeyUp && (nsEvent.modifierFlags() & OS.NSCommandKeyMask) != 0) {
+ window.sendEvent(nsEvent);
+ } else {
+ objc_super super_struct = new objc_super ();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend (id, OS.sel_superclass);
+ OS.objc_msgSendSuper (super_struct, sel, event);
+ }
+ sendEvent = false;
+}
+
+void applicationWillFinishLaunching (int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+ boolean loaded = false;
+ NSBundle bundle = NSBundle.bundleWithIdentifier(NSString.stringWith("com.apple.JavaVM"));
+ NSDictionary dict = NSDictionary.dictionaryWithObject(applicationDelegate, NSString.stringWith("NSOwner"));
+ NSString path = bundle.pathForResource(NSString.stringWith("DefaultApp"), NSString.stringWith("nib"));
+ if (!loaded) loaded = path != null && NSBundle.loadNibFile(path, dict, 0);
+ if (!loaded) {
+ NSString resourcePath = bundle.resourcePath();
+ path = resourcePath != null ? resourcePath.stringByAppendingString(NSString.stringWith("/English.lproj/DefaultApp.nib")) : null;
+ loaded = path != null && NSBundle.loadNibFile(path, dict, 0);
+ }
+ if (!loaded) {
+ path = NSString.stringWith(System.getProperty("java.home") + "/../Resources/English.lproj/DefaultApp.nib");
+ loaded = path != null && NSBundle.loadNibFile(path, dict, 0);
+ }
+ if (!loaded) {
+ createMainMenu();
+ }
+ //replace %@ with application name
+ NSMenu mainmenu = application.mainMenu();
+ NSMenuItem appitem = mainmenu.itemAtIndex(0);
+ if (appitem != null) {
+ NSString name = getAppName();
+ NSString match = NSString.stringWith("%@");
+ appitem.setTitle(name);
+ NSMenu sm = appitem.submenu();
+ NSArray ia = sm.itemArray();
+ for(int i = 0; i < ia.count(); i++) {
+ NSMenuItem ni = new NSMenuItem(ia.objectAtIndex(i));
+ NSString title = ni.title().stringByReplacingOccurrencesOfString(match, name);
+ ni.setTitle(title);
+ }
+
+ int /*long*/ quitIndex = sm.indexOfItemWithTarget(applicationDelegate, OS.sel_terminate_);
+
+ if (quitIndex != -1) {
+ NSMenuItem quitItem = sm.itemAtIndex(quitIndex);
+ quitItem.setAction(OS.sel_quitRequested_);
+ }
+ }
+}
+
+static int /*long*/ applicationProc(int /*long*/ id, int /*long*/ sel) {
+ //TODO optimize getting the display
+ Display display = getCurrent ();
+ if (display == null) return 0;
+ if (sel == OS.sel_isRunning) {
+ // #245724: [NSApplication isRunning] must return true to allow the AWT to load correctly.
+ return display.isDisposed() ? 0 : 1;
+ }
+ if (sel == OS.sel_finishLaunching) {
+ display.finishLaunching (id, sel);
+ }
+ return 0;
+}
+
+static int /*long*/ applicationProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ //TODO optimize getting the display
+ Display display = getCurrent ();
+ if (display == null) return 0;
+ NSApplication application = display.application;
+ if (sel == OS.sel_sendEvent_) {
+ display.applicationSendEvent (id, sel, arg0);
+ } else if (sel == OS.sel_applicationWillFinishLaunching_) {
+ display.applicationWillFinishLaunching(id, sel, arg0);
+ } else if (sel == OS.sel_terminate_) {
+ // Do nothing here -- without a definition of sel_terminate we get a warning dumped to the console.
+ } else if (sel == OS.sel_orderFrontStandardAboutPanel_) {
+// application.orderFrontStandardAboutPanel(application);
+ } else if (sel == OS.sel_hideOtherApplications_) {
+ application.hideOtherApplications(application);
+ } else if (sel == OS.sel_hide_) {
+ application.hide(application);
+ } else if (sel == OS.sel_unhideAllApplications_) {
+ application.unhideAllApplications(application);
+ } else if (sel == OS.sel_quitRequested_) {
+ if (!display.disposing) {
+ Event event = new Event ();
+ display.sendEvent (SWT.Close, event);
+ if (event.doit) {
+ display.dispose();
+ }
+ }
+ } else if (sel == OS.sel_applicationDidBecomeActive_) {
+ display.applicationDidBecomeActive(id, sel, arg0);
+ } else if (sel == OS.sel_applicationDidResignActive_) {
+ display.applicationDidResignActive(id, sel, arg0);
+ }
+ return 0;
+}
+
+static int /*long*/ applicationProc(int /*long*/ id, int /*long*/sel, int /*long*/ arg0, int /*long*/ arg1, int /*long*/ arg2, int /*long*/ arg3) {
+ //TODO optimize getting the display
+ Display display = getCurrent ();
+ if (display == null) return 0;
+ if (sel == OS.sel_nextEventMatchingMask_untilDate_inMode_dequeue_) {
+ return display.applicationNextEventMatchingMask(id, sel, arg0, arg1, arg2, arg3);
+ }
+ return 0;
+}
+
+static int /*long*/ dialogProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ int /*long*/ [] jniRef = new int /*long*/ [1];
+ OS.object_getInstanceVariable(id, SWT_OBJECT, jniRef);
+ if (jniRef[0] == 0) return 0;
+ if (sel == OS.sel_changeColor_) {
+ ColorDialog dialog = (ColorDialog)OS.JNIGetObject(jniRef[0]);
+ if (dialog == null) return 0;
+ dialog.changeColor(id, sel, arg0);
+ } else if (sel == OS.sel_changeFont_) {
+ FontDialog dialog = (FontDialog)OS.JNIGetObject(jniRef[0]);
+ if (dialog == null) return 0;
+ dialog.changeFont(id, sel, arg0);
+ } else if (sel == OS.sel_sendSelection_) {
+ FileDialog dialog = (FileDialog)OS.JNIGetObject(jniRef[0]);
+ if (dialog == null) return 0;
+ dialog.sendSelection(id, sel, arg0);
+ } else if (sel == OS.sel_windowWillClose_) {
+ Object object = OS.JNIGetObject(jniRef[0]);
+ if (object instanceof FontDialog) {
+ ((FontDialog)object).windowWillClose(id, sel, arg0);
+ } else if (object instanceof ColorDialog) {
+ ((ColorDialog)object).windowWillClose(id, sel, arg0);
+ }
+ }
+ return 0;
+}
+
+static int /*long*/ dialogProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1) {
+ int /*long*/ [] jniRef = new int /*long*/ [1];
+ OS.object_getInstanceVariable(id, SWT_OBJECT, jniRef);
+ if (jniRef[0] == 0) return 0;
+ if (sel == OS.sel_panel_shouldShowFilename_) {
+ FileDialog dialog = (FileDialog)OS.JNIGetObject(jniRef[0]);
+ if (dialog == null) return 0;
+ return dialog.panel_shouldShowFilename(id, sel, arg0, arg1);
+ }
+ return 0;
+}
+
+static int /*long*/ dialogProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1, int /*long*/ arg2) {
+ int /*long*/ [] jniRef = new int /*long*/ [1];
+ OS.object_getInstanceVariable(id, SWT_OBJECT, jniRef);
+ if (jniRef[0] == 0) return 0;
+ if (sel == OS.sel_panelDidEnd_returnCode_contextInfo_) {
+ MessageBox dialog = (MessageBox)OS.JNIGetObject(jniRef[0]);
+ if (dialog == null) return 0;
+ dialog.panelDidEnd_returnCode_contextInfo(id, sel, arg0, arg1, arg2);
+ }
+ return 0;
+}
+
+static int /*long*/ fieldEditorProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ Widget widget = null;
+ NSView view = new NSView (id);
+ do {
+ widget = GetWidget (view.id);
+ if (widget != null) break;
+ view = view.superview ();
+ } while (view != null);
+ if (widget == null) return 0;
+ if (sel == OS.sel_keyDown_) {
+ widget.keyDown (id, sel, arg0);
+ } else if (sel == OS.sel_keyUp_) {
+ widget.keyUp (id, sel, arg0);
+ } else if (sel == OS.sel_flagsChanged_) {
+ widget.flagsChanged(id, sel, arg0);
+ } else if (sel == OS.sel_insertText_) {
+ return widget.insertText (id, sel, arg0) ? 1 : 0;
+ } else if (sel == OS.sel_doCommandBySelector_) {
+ widget.doCommandBySelector (id, sel, arg0);
+ } else if (sel == OS.sel_menuForEvent_) {
+ return widget.menuForEvent (id, sel, arg0);
+ } else if (sel == OS.sel_mouseDown_) {
+ widget.mouseDown(id, sel, arg0);
+ } else if (sel == OS.sel_mouseUp_) {
+ widget.mouseUp(id, sel, arg0);
+ } else if (sel == OS.sel_mouseMoved_) {
+ widget.mouseMoved(id, sel, arg0);
+ } else if (sel == OS.sel_mouseDragged_) {
+ widget.mouseDragged(id, sel, arg0);
+ } else if (sel == OS.sel_mouseEntered_) {
+ widget.mouseEntered(id, sel, arg0);
+ } else if (sel == OS.sel_mouseExited_) {
+ widget.mouseExited(id, sel, arg0);
+ } else if (sel == OS.sel_cursorUpdate_) {
+ widget.cursorUpdate(id, sel, arg0);
+ } else if (sel == OS.sel_rightMouseDown_) {
+ widget.rightMouseDown(id, sel, arg0);
+ } else if (sel == OS.sel_rightMouseDragged_) {
+ widget.rightMouseDragged(id, sel, arg0);
+ } else if (sel == OS.sel_rightMouseUp_) {
+ widget.rightMouseUp(id, sel, arg0);
+ } else if (sel == OS.sel_otherMouseDown_) {
+ widget.otherMouseDown(id, sel, arg0);
+ } else if (sel == OS.sel_otherMouseUp_) {
+ widget.otherMouseUp(id, sel, arg0);
+ } else if (sel == OS.sel_otherMouseDragged_) {
+ widget.otherMouseDragged(id, sel, arg0);
+ }
+ return 0;
+}
+
+static int /*long*/ fieldEditorProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1) {
+ Widget widget = null;
+ NSView view = new NSView (id);
+ do {
+ widget = GetWidget (view.id);
+ if (widget != null) break;
+ view = view.superview ();
+ } while (view != null);
+ if (sel == OS.sel_shouldChangeTextInRange_replacementString_) {
+ return widget.shouldChangeTextInRange_replacementString(id, sel, arg0, arg1) ? 1 : 0;
+ }
+ return 0;
+}
+
+static int /*long*/ windowProc(int /*long*/ id, int /*long*/ sel) {
+ /*
+ * Feature in Cocoa. In Cocoa, the default button animation is done
+ * in a separate thread that calls drawRect() and isOpaque() from
+ * outside the UI thread. This means that those methods, and application
+ * code that runs as a result of those methods, must be thread safe.
+ * In SWT, paint events must happen in the UI thread. The fix is
+ * to detect a non-UI thread and avoid the drawing. Instead, the
+ * default button is animated by a timer.
+ */
+ if (!NSThread.isMainThread()) {
+ if (sel == OS.sel_isOpaque) {
+ return 1;
+ }
+ }
+ Widget widget = GetWidget(id);
+ if (widget == null) return 0;
+ if (sel == OS.sel_sendSelection) {
+ widget.sendSelection();
+ } else if (sel == OS.sel_sendDoubleSelection) {
+ widget.sendDoubleSelection();
+ } else if (sel == OS.sel_sendVerticalSelection) {
+ widget.sendVerticalSelection();
+ } else if (sel == OS.sel_sendHorizontalSelection) {
+ widget.sendHorizontalSelection();
+ } else if (sel == OS.sel_sendSearchSelection) {
+ widget.sendSearchSelection();
+ } else if (sel == OS.sel_sendCancelSelection) {
+ widget.sendCancelSelection();
+ } else if (sel == OS.sel_acceptsFirstResponder) {
+ return widget.acceptsFirstResponder(id, sel) ? 1 : 0;
+ } else if (sel == OS.sel_becomeFirstResponder) {
+ return widget.becomeFirstResponder(id, sel) ? 1 : 0;
+ } else if (sel == OS.sel_resignFirstResponder) {
+ return widget.resignFirstResponder(id, sel) ? 1 : 0;
+ } else if (sel == OS.sel_isOpaque) {
+ return widget.isOpaque(id, sel) ? 1 : 0;
+ } else if (sel == OS.sel_isFlipped) {
+ return widget.isFlipped(id, sel) ? 1 : 0;
+ } else if (sel == OS.sel_canBecomeKeyView) {
+ return widget.canBecomeKeyView(id,sel) ? 1 : 0;
+ } else if (sel == OS.sel_becomeKeyWindow) {
+ widget.becomeKeyWindow(id, sel);
+ } else if (sel == OS.sel_unmarkText) {
+ //TODO not called?
+ } else if (sel == OS.sel_validAttributesForMarkedText) {
+ return widget.validAttributesForMarkedText (id, sel);
+ } else if (sel == OS.sel_markedRange) {
+ NSRange range = widget.markedRange (id, sel);
+ /* NOTE that this is freed in C */
+ int /*long*/ result = OS.malloc (NSRange.sizeof);
+ OS.memmove (result, range, NSRange.sizeof);
+ return result;
+ } else if (sel == OS.sel_selectedRange) {
+ NSRange range = widget.selectedRange (id, sel);
+ /* NOTE that this is freed in C */
+ int /*long*/ result = OS.malloc (NSRange.sizeof);
+ OS.memmove (result, range, NSRange.sizeof);
+ return result;
+ } else if (sel == OS.sel_cellSize) {
+ NSSize size = widget.cellSize (id, sel);
+ /* NOTE that this is freed in C */
+ int /*long*/ result = OS.malloc (NSSize.sizeof);
+ OS.memmove (result, size, NSSize.sizeof);
+ return result;
+ } else if (sel == OS.sel_hasMarkedText) {
+ return widget.hasMarkedText (id, sel) ? 1 : 0;
+ } else if (sel == OS.sel_canBecomeKeyWindow) {
+ return widget.canBecomeKeyWindow (id, sel) ? 1 : 0;
+ } else if (sel == OS.sel_accessibilityActionNames) {
+ return widget.accessibilityActionNames(id, sel);
+ } else if (sel == OS.sel_accessibilityAttributeNames) {
+ return widget.accessibilityAttributeNames(id, sel);
+ } else if (sel == OS.sel_accessibilityParameterizedAttributeNames) {
+ return widget.accessibilityParameterizedAttributeNames(id, sel);
+ } else if (sel == OS.sel_accessibilityFocusedUIElement) {
+ return widget.accessibilityFocusedUIElement(id, sel);
+ } else if (sel == OS.sel_accessibilityIsIgnored) {
+ return (widget.accessibilityIsIgnored(id, sel) ? 1 : 0);
+ } else if (sel == OS.sel_nextState) {
+ return widget.nextState(id, sel);
+ } else if (sel == OS.sel_resetCursorRects) {
+ widget.resetCursorRects(id, sel);
+ } else if (sel == OS.sel_updateTrackingAreas) {
+ widget.updateTrackingAreas(id, sel);
+ } else if (sel == OS.sel_viewDidMoveToWindow) {
+ widget.viewDidMoveToWindow(id, sel);
+ } else if (sel == OS.sel_image) {
+ return widget.image(id, sel);
+ }
+ return 0;
+}
+
+static int /*long*/ windowProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ /*
+ * Feature in Cocoa. In Cocoa, the default button animation is done
+ * in a separate thread that calls drawRect() and isOpaque() from
+ * outside the UI thread. This means that those methods, and application
+ * code that runs as a result of those methods, must be thread safe.
+ * In SWT, paint events must happen in the UI thread. The fix is
+ * to detect a non-UI thread and avoid the drawing. Instead, the
+ * default button is animated by a timer.
+ */
+ if (!NSThread.isMainThread()) {
+ if (sel == OS.sel_drawRect_) {
+ return 0;
+ }
+ }
+ if (sel == OS.sel_timerProc_) {
+ //TODO optimize getting the display
+ Display display = getCurrent ();
+ if (display == null) return 0;
+ return display.timerProc (id, sel, arg0);
+ }
+ if (sel == OS.sel_systemSettingsChanged_) {
+ //TODO optimize getting the display
+ Display display = getCurrent ();
+ if (display == null) return 0;
+ display.runSettings = true;
+ return 0;
+ }
+ Widget widget = GetWidget(id);
+ if (widget == null) return 0;
+ if (sel == OS.sel_windowWillClose_) {
+ widget.windowWillClose(id, sel, arg0);
+ } else if (sel == OS.sel_drawRect_) {
+ NSRect rect = new NSRect();
+ OS.memmove(rect, arg0, NSRect.sizeof);
+ widget.drawRect(id, sel, rect);
+ } else if (sel == OS.sel__drawThemeProgressArea_) {
+ widget._drawThemeProgressArea(id, sel, arg0);
+ } else if (sel == OS.sel_setFrameOrigin_) {
+ NSPoint point = new NSPoint();
+ OS.memmove(point, arg0, NSPoint.sizeof);
+ widget.setFrameOrigin(id, sel, point);
+ } else if (sel == OS.sel_setFrameSize_) {
+ NSSize size = new NSSize();
+ OS.memmove(size, arg0, NSSize.sizeof);
+ widget.setFrameSize(id, sel, size);
+ } else if (sel == OS.sel_hitTest_) {
+ NSPoint point = new NSPoint();
+ OS.memmove(point, arg0, NSPoint.sizeof);
+ return widget.hitTest(id, sel, point);
+ } else if (sel == OS.sel_windowShouldClose_) {
+ return widget.windowShouldClose(id, sel, arg0) ? 1 : 0;
+ } else if (sel == OS.sel_mouseDown_) {
+ widget.mouseDown(id, sel, arg0);
+ } else if (sel == OS.sel_keyDown_) {
+ widget.keyDown(id, sel, arg0);
+ } else if (sel == OS.sel_keyUp_) {
+ widget.keyUp(id, sel, arg0);
+ } else if (sel == OS.sel_flagsChanged_) {
+ widget.flagsChanged(id, sel, arg0);
+ } else if (sel == OS.sel_mouseUp_) {
+ widget.mouseUp(id, sel, arg0);
+ } else if (sel == OS.sel_rightMouseDown_) {
+ widget.rightMouseDown(id, sel, arg0);
+ } else if (sel == OS.sel_rightMouseDragged_) {
+ widget.rightMouseDragged(id, sel, arg0);
+ } else if (sel == OS.sel_rightMouseUp_) {
+ widget.rightMouseUp(id, sel, arg0);
+ } else if (sel == OS.sel_otherMouseDown_) {
+ widget.otherMouseDown(id, sel, arg0);
+ } else if (sel == OS.sel_otherMouseUp_) {
+ widget.otherMouseUp(id, sel, arg0);
+ } else if (sel == OS.sel_otherMouseDragged_) {
+ widget.otherMouseDragged(id, sel, arg0);
+ } else if (sel == OS.sel_mouseMoved_) {
+ widget.mouseMoved(id, sel, arg0);
+ } else if (sel == OS.sel_mouseDragged_) {
+ widget.mouseDragged(id, sel, arg0);
+ } else if (sel == OS.sel_mouseEntered_) {
+ widget.mouseEntered(id, sel, arg0);
+ } else if (sel == OS.sel_mouseExited_) {
+ widget.mouseExited(id, sel, arg0);
+ } else if (sel == OS.sel_cursorUpdate_) {
+ widget.cursorUpdate(id, sel, arg0);
+ } else if (sel == OS.sel_menuForEvent_) {
+ return widget.menuForEvent(id, sel, arg0);
+ } else if (sel == OS.sel_noResponderFor_) {
+ widget.noResponderFor(id, sel, arg0);
+ } else if (sel == OS.sel_shouldDelayWindowOrderingForEvent_) {
+ return widget.shouldDelayWindowOrderingForEvent(id, sel, arg0) ? 1 : 0;
+ } else if (sel == OS.sel_acceptsFirstMouse_) {
+ return widget.acceptsFirstMouse(id, sel, arg0) ? 1 : 0;
+ } else if (sel == OS.sel_numberOfRowsInTableView_) {
+ return widget.numberOfRowsInTableView(id, sel, arg0);
+ } else if (sel == OS.sel_tableViewSelectionDidChange_) {
+ widget.tableViewSelectionDidChange(id, sel, arg0);
+ } else if (sel == OS.sel_windowDidResignKey_) {
+ widget.windowDidResignKey(id, sel, arg0);
+ } else if (sel == OS.sel_windowDidBecomeKey_) {
+ widget.windowDidBecomeKey(id, sel, arg0);
+ } else if (sel == OS.sel_windowDidResize_) {
+ widget.windowDidResize(id, sel, arg0);
+ } else if (sel == OS.sel_windowDidMove_) {
+ widget.windowDidMove(id, sel, arg0);
+ } else if (sel == OS.sel_menuWillOpen_) {
+ widget.menuWillOpen(id, sel, arg0);
+ } else if (sel == OS.sel_menuDidClose_) {
+ widget.menuDidClose(id, sel, arg0);
+ } else if (sel == OS.sel_menuNeedsUpdate_) {
+ widget.menuNeedsUpdate(id, sel, arg0);
+ } else if (sel == OS.sel_outlineViewSelectionDidChange_) {
+ widget.outlineViewSelectionDidChange(id, sel, arg0);
+ } else if (sel == OS.sel_sendEvent_) {
+ widget.windowSendEvent(id, sel, arg0);
+ } else if (sel == OS.sel_helpRequested_) {
+ widget.helpRequested(id, sel, arg0);
+ } else if (sel == OS.sel_scrollWheel_) {
+ widget.scrollWheel(id, sel, arg0);
+ } else if (sel == OS.sel_pageDown_) {
+ widget.pageDown(id, sel, arg0);
+ } else if (sel == OS.sel_pageUp_) {
+ widget.pageUp(id, sel, arg0);
+ } else if (sel == OS.sel_textViewDidChangeSelection_) {
+ widget.textViewDidChangeSelection(id, sel, arg0);
+ } else if (sel == OS.sel_textDidChange_) {
+ widget.textDidChange(id, sel, arg0);
+ } else if (sel == OS.sel_textDidEndEditing_) {
+ widget.textDidEndEditing(id, sel, arg0);
+ } else if (sel == OS.sel_attributedSubstringFromRange_) {
+ return widget.attributedSubstringFromRange (id, sel, arg0);
+ } else if (sel == OS.sel_characterIndexForPoint_) {
+ return widget.characterIndexForPoint (id, sel, arg0);
+ } else if (sel == OS.sel_firstRectForCharacterRange_) {
+ NSRect rect = widget.firstRectForCharacterRange (id, sel, arg0);
+ /* NOTE that this is freed in C */
+ int /*long*/ result = OS.malloc (NSRect.sizeof);
+ OS.memmove (result, rect, NSRect.sizeof);
+ return result;
+ } else if (sel == OS.sel_insertText_) {
+ return widget.insertText (id, sel, arg0) ? 1 : 0;
+ } else if (sel == OS.sel_doCommandBySelector_) {
+ widget.doCommandBySelector (id, sel, arg0);
+ } else if (sel == OS.sel_highlightSelectionInClipRect_) {
+ widget.highlightSelectionInClipRect (id, sel, arg0);
+ } else if (sel == OS.sel_reflectScrolledClipView_) {
+ widget.reflectScrolledClipView (id, sel, arg0);
+ } else if (sel == OS.sel_accessibilityHitTest_) {
+ NSPoint point = new NSPoint();
+ OS.memmove(point, arg0, NSPoint.sizeof);
+ return widget.accessibilityHitTest(id, sel, point);
+ } else if (sel == OS.sel_accessibilityAttributeValue_) {
+ return widget.accessibilityAttributeValue(id, sel, arg0);
+ } else if (sel == OS.sel_accessibilityPerformAction_) {
+ widget.accessibilityPerformAction(id, sel, arg0);
+ } else if (sel == OS.sel_accessibilityActionDescription_) {
+ widget.accessibilityActionDescription(id, sel, arg0);
+ } else if (sel == OS.sel_makeFirstResponder_) {
+ return widget.makeFirstResponder(id, sel, arg0) ? 1 : 0;
+ } else if (sel == OS.sel_tableViewColumnDidMove_) {
+ widget.tableViewColumnDidMove(id, sel, arg0);
+ } else if (sel == OS.sel_tableViewColumnDidResize_) {
+ widget.tableViewColumnDidResize(id, sel, arg0);
+ } else if (sel == OS.sel_outlineViewColumnDidMove_) {
+ widget.outlineViewColumnDidMove(id, sel, arg0);
+ } else if (sel == OS.sel_outlineViewColumnDidResize_) {
+ widget.outlineViewColumnDidResize(id, sel, arg0);
+ } else if (sel == OS.sel_setNeedsDisplay_) {
+ widget.setNeedsDisplay(id, sel, arg0 != 0);
+ } else if (sel == OS.sel_setNeedsDisplayInRect_) {
+ widget.setNeedsDisplayInRect(id, sel, arg0);
+ } else if (sel == OS.sel_setImage_) {
+ widget.setImage(id, sel, arg0);
+ } else if (sel == OS.sel_imageRectForBounds_) {
+ NSRect rect = new NSRect();
+ OS.memmove(rect, arg0, NSRect.sizeof);
+ rect = widget.imageRectForBounds(id, sel, rect);
+ /* NOTE that this is freed in C */
+ int /*long*/ result = OS.malloc (NSRect.sizeof);
+ OS.memmove (result, rect, NSRect.sizeof);
+ return result;
+ } else if (sel == OS.sel_titleRectForBounds_) {
+ NSRect rect = new NSRect();
+ OS.memmove(rect, arg0, NSRect.sizeof);
+ rect = widget.titleRectForBounds(id, sel, rect);
+ /* NOTE that this is freed in C */
+ int /*long*/ result = OS.malloc (NSRect.sizeof);
+ OS.memmove (result, rect, NSRect.sizeof);
+ return result;
+ } else if (sel == OS.sel_setObjectValue_) {
+ widget.setObjectValue(id, sel, arg0);
+ } else if (sel == OS.sel_updateOpenGLContext_) {
+ widget.updateOpenGLContext(id, sel, arg0);
+ }
+ return 0;
+}
+
+static int /*long*/ windowProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1) {
+ Widget widget = GetWidget(id);
+ if (widget == null) return 0;
+ if (sel == OS.sel_tabView_willSelectTabViewItem_) {
+ widget.tabView_willSelectTabViewItem(id, sel, arg0, arg1);
+ } else if (sel == OS.sel_tabView_didSelectTabViewItem_) {
+ widget.tabView_didSelectTabViewItem(id, sel, arg0, arg1);
+ } else if (sel == OS.sel_outlineView_isItemExpandable_) {
+ return widget.outlineView_isItemExpandable(id, sel, arg0, arg1) ? 1 : 0;
+ } else if (sel == OS.sel_outlineView_numberOfChildrenOfItem_) {
+ return widget.outlineView_numberOfChildrenOfItem(id, sel, arg0, arg1);
+ } else if (sel == OS.sel_menu_willHighlightItem_) {
+ widget.menu_willHighlightItem(id, sel, arg0, arg1);
+ } else if (sel == OS.sel_setMarkedText_selectedRange_) {
+ widget.setMarkedText_selectedRange (id, sel, arg0, arg1);
+ } else if (sel == OS.sel_drawInteriorWithFrame_inView_) {
+ NSRect rect = new NSRect ();
+ OS.memmove (rect, arg0, NSRect.sizeof);
+ widget.drawInteriorWithFrame_inView (id, sel, rect, arg1);
+ } else if (sel == OS.sel_drawWithExpansionFrame_inView_) {
+ NSRect rect = new NSRect();
+ OS.memmove(rect, arg0, NSRect.sizeof);
+ widget.drawWithExpansionFrame_inView (id, sel, rect, arg1);
+ } else if (sel == OS.sel_accessibilityAttributeValue_forParameter_) {
+ return widget.accessibilityAttributeValue_forParameter(id, sel, arg0, arg1);
+ } else if (sel == OS.sel_tableView_didClickTableColumn_) {
+ widget.tableView_didClickTableColumn (id, sel, arg0, arg1);
+ } else if (sel == OS.sel_outlineView_didClickTableColumn_) {
+ widget.outlineView_didClickTableColumn (id, sel, arg0, arg1);
+ } else if (sel == OS.sel_shouldChangeTextInRange_replacementString_) {
+ return widget.shouldChangeTextInRange_replacementString(id, sel, arg0, arg1) ? 1 : 0;
+ } else if (sel == OS.sel_canDragRowsWithIndexes_atPoint_) {
+ return widget.canDragRowsWithIndexes_atPoint(id, sel, arg0, arg1) ? 1 : 0;
+ } else if (sel == OS.sel_expandItem_expandChildren_) {
+ widget.expandItem_expandChildren(id, sel, arg0, arg1 != 0);
+ } else if (sel == OS.sel_collapseItem_collapseChildren_) {
+ widget.collapseItem_collapseChildren(id, sel, arg0, arg1 != 0);
+ } else if (sel == OS.sel_expansionFrameWithFrame_inView_) {
+ NSRect rect = new NSRect();
+ OS.memmove(rect, arg0, NSRect.sizeof);
+ rect = widget.expansionFrameWithFrame_inView(id, sel, rect, arg1);
+ /* NOTE that this is freed in C */
+ int /*long*/ result = OS.malloc (NSRect.sizeof);
+ OS.memmove (result, rect, NSRect.sizeof);
+ return result;
+ }
+ return 0;
+}
+
+static int /*long*/ windowProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1, int /*long*/ arg2) {
+ Widget widget = GetWidget(id);
+ if (widget == null) return 0;
+ if (sel == OS.sel_tableView_objectValueForTableColumn_row_) {
+ return widget.tableView_objectValueForTableColumn_row(id, sel, arg0, arg1, arg2);
+ } else if (sel == OS.sel_tableView_shouldEditTableColumn_row_) {
+ return widget.tableView_shouldEditTableColumn_row(id, sel, arg0, arg1, arg2) ? 1 : 0;
+ } else if (sel == OS.sel_textView_clickedOnLink_atIndex_) {
+ return widget.textView_clickOnLink_atIndex(id, sel, arg0, arg1, arg2) ? 1 : 0;
+ } else if (sel == OS.sel_outlineView_child_ofItem_) {
+ return widget.outlineView_child_ofItem(id, sel, arg0, arg1, arg2);
+ } else if (sel == OS.sel_outlineView_objectValueForTableColumn_byItem_) {
+ return widget.outlineView_objectValueForTableColumn_byItem(id, sel, arg0, arg1, arg2);
+ } else if (sel == OS.sel_textView_willChangeSelectionFromCharacterRange_toCharacterRange_) {
+ NSRange range = widget.textView_willChangeSelectionFromCharacterRange_toCharacterRange(id, sel, arg0, arg1, arg2);
+ /* NOTE that this is freed in C */
+ int /*long*/ result = OS.malloc (NSRange.sizeof);
+ OS.memmove (result, range, NSRange.sizeof);
+ return result;
+ } else if (sel == OS.sel_dragSelectionWithEvent_offset_slideBack_) {
+ NSSize offset = new NSSize();
+ OS.memmove(offset, arg0, NSSize.sizeof);
+ return (widget.dragSelectionWithEvent(id, sel, arg0, arg1, arg2) ? 1 : 0);
+ } else if (sel == OS.sel_drawImage_withFrame_inView_) {
+ NSRect rect = new NSRect ();
+ OS.memmove (rect, arg1, NSRect.sizeof);
+ widget.drawImageWithFrameInView (id, sel, arg0, rect, arg2);
+ } else if (sel == OS.sel_hitTestForEvent_inRect_ofView_) {
+ NSRect rect = new NSRect ();
+ OS.memmove (rect, arg1, NSRect.sizeof);
+ return widget.hitTestForEvent (id, sel, arg0, rect, arg2);
+ } else if (sel == OS.sel_tableView_writeRowsWithIndexes_toPasteboard_) {
+ return (widget.tableView_writeRowsWithIndexes_toPasteboard(id, sel, arg0, arg1, arg2) ? 1 : 0);
+ } else if (sel == OS.sel_outlineView_writeItems_toPasteboard_) {
+ return (widget.outlineView_writeItems_toPasteboard(id, sel, arg0, arg1, arg2) ? 1 : 0);
+ }
+ return 0;
+}
+
+static int /*long*/ windowProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1, int /*long*/ arg2, int /*long*/ arg3) {
+ Widget widget = GetWidget(id);
+ if (widget == null) return 0;
+ if (sel == OS.sel_tableView_willDisplayCell_forTableColumn_row_) {
+ widget.tableView_willDisplayCell_forTableColumn_row(id, sel, arg0, arg1, arg2, arg3);
+ } else if (sel == OS.sel_outlineView_willDisplayCell_forTableColumn_item_) {
+ widget.outlineView_willDisplayCell_forTableColumn_item(id, sel, arg0, arg1, arg2, arg3);
+ } else if (sel == OS.sel_outlineView_setObjectValue_forTableColumn_byItem_) {
+ widget.outlineView_setObjectValue_forTableColumn_byItem(id, sel, arg0, arg1, arg2, arg3);
+ } else if (sel == OS.sel_tableView_setObjectValue_forTableColumn_row_) {
+ widget.tableView_setObjectValue_forTableColumn_row(id, sel, arg0, arg1, arg2, arg3);
+ } else if (sel == OS.sel_view_stringForToolTip_point_userData_) {
+ return widget.view_stringForToolTip_point_userData(id, sel, arg0, arg1, arg2, arg3);
+ }
+ return 0;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/FileDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/FileDialog.java
new file mode 100755
index 0000000000..6192f9414c
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/FileDialog.java
@@ -0,0 +1,461 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class allow the user to navigate
+ * the file system and select or enter a file name.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>SAVE, OPEN, MULTI</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles SAVE and OPEN may be specified.
+ * </p><p>
+ * IMPORTANT: This class is intended to be subclassed <em>only</em>
+ * within the SWT implementation.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#filedialog">FileDialog snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample, Dialog tab</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class FileDialog extends Dialog {
+ NSSavePanel panel;
+ NSPopUpButton popup;
+ String [] filterNames = new String [0];
+ String [] filterExtensions = new String [0];
+ String [] fileNames = new String[0];
+ String filterPath = "", fileName = "";
+ int filterIndex = -1;
+ boolean overwrite = false;
+ static final char EXTENSION_SEPARATOR = ';';
+
+/**
+ * Constructs a new instance of this class given only its parent.
+ *
+ * @param parent a shell which will be the parent of the new instance
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <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>
+ */
+public FileDialog (Shell parent) {
+ this (parent, SWT.APPLICATION_MODAL);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 shell which will be the parent of the new instance
+ * @param style the style of dialog to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <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 SWT#SAVE
+ * @see SWT#OPEN
+ * @see SWT#MULTI
+ */
+public FileDialog (Shell parent, int style) {
+ super (parent, checkStyle (parent, style));
+ if (Display.getSheetEnabled ()) {
+ if (parent != null && (style & SWT.SHEET) != 0) this.style |= SWT.SHEET;
+ }
+ checkSubclass ();
+}
+
+/**
+ * Returns the path of the first file that was
+ * selected in the dialog relative to the filter path, or an
+ * empty string if no such file has been selected.
+ *
+ * @return the relative path of the file
+ */
+public String getFileName () {
+ return fileName;
+}
+
+/**
+ * Returns a (possibly empty) array with the paths of all files
+ * that were selected in the dialog relative to the filter path.
+ *
+ * @return the relative paths of the files
+ */
+public String [] getFileNames () {
+ return fileNames;
+}
+
+/**
+ * Returns the file extensions which the dialog will
+ * use to filter the files it shows.
+ *
+ * @return the file extensions filter
+ */
+public String [] getFilterExtensions () {
+ return filterExtensions;
+}
+
+/**
+ * Get the 0-based index of the file extension filter
+ * which was selected by the user, or -1 if no filter
+ * was selected.
+ * <p>
+ * This is an index into the FilterExtensions array and
+ * the FilterNames array.
+ * </p>
+ *
+ * @return index the file extension filter index
+ *
+ * @see #getFilterExtensions
+ * @see #getFilterNames
+ *
+ * @since 3.4
+ */
+public int getFilterIndex () {
+ return filterIndex;
+}
+
+/**
+ * Returns the names that describe the filter extensions
+ * which the dialog will use to filter the files it shows.
+ *
+ * @return the list of filter names
+ */
+public String [] getFilterNames () {
+ return filterNames;
+}
+
+/**
+ * Returns the directory path that the dialog will use, or an empty
+ * string if this is not set. File names in this path will appear
+ * in the dialog, filtered according to the filter extensions.
+ *
+ * @return the directory path string
+ *
+ * @see #setFilterExtensions
+ */
+public String getFilterPath () {
+ return filterPath;
+}
+
+/**
+ * Returns the flag that the dialog will use to
+ * determine whether to prompt the user for file
+ * overwrite if the selected file already exists.
+ *
+ * @return true if the dialog will prompt for file overwrite, false otherwise
+ *
+ * @since 3.4
+ */
+public boolean getOverwrite () {
+ return overwrite;
+}
+
+/**
+ * Makes the dialog visible and brings it to the front
+ * of the display.
+ *
+ * @return a string describing the absolute path of the first selected file,
+ * or null if the dialog was cancelled or an error occurred
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the dialog has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the dialog</li>
+ * </ul>
+ */
+public String open () {
+ String fullPath = null;
+ fileNames = new String [0];
+ int /*long*/ method = 0;
+ int /*long*/ methodImpl = 0;
+ Callback callback = null;
+ if ((style & SWT.SAVE) != 0) {
+ NSSavePanel savePanel = NSSavePanel.savePanel();
+ panel = savePanel;
+ if (!overwrite) {
+ callback = new Callback(this, "_overwriteExistingFileCheck", 3);
+ int /*long*/ proc = callback.getAddress();
+ if (proc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ method = OS.class_getInstanceMethod(OS.class_NSSavePanel, OS.sel_overwriteExistingFileCheck);
+ if (method != 0) methodImpl = OS.method_setImplementation(method, proc);
+ }
+ } else {
+ NSOpenPanel openPanel = NSOpenPanel.openPanel();
+ openPanel.setAllowsMultipleSelection((style & SWT.MULTI) != 0);
+ panel = openPanel;
+ }
+ panel.setCanCreateDirectories(true);
+ int /*long*/ jniRef = 0;
+ SWTPanelDelegate delegate = null;
+ if (filterExtensions != null && filterExtensions.length != 0) {
+ delegate = (SWTPanelDelegate)new SWTPanelDelegate().alloc().init();
+ jniRef = OS.NewGlobalRef(this);
+ if (jniRef == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.object_setInstanceVariable(delegate.id, Display.SWT_OBJECT, jniRef);
+ panel.setDelegate(delegate);
+ NSPopUpButton widget = (NSPopUpButton)new NSPopUpButton().alloc();
+ widget.initWithFrame(new NSRect(), false);
+ widget.setTarget(delegate);
+ widget.setAction(OS.sel_sendSelection_);
+ NSMenu menu = widget.menu();
+ menu.setAutoenablesItems(false);
+ for (int i = 0; i < filterExtensions.length; i++) {
+ String str = filterExtensions [i];
+ if (filterNames != null && filterNames.length > i) {
+ str = filterNames [i];
+ }
+ NSMenuItem nsItem = (NSMenuItem)new NSMenuItem().alloc();
+ nsItem.initWithTitle(NSString.stringWith(str), 0, NSString.stringWith(""));
+ menu.addItem(nsItem);
+ nsItem.release();
+ }
+ widget.selectItemAtIndex(0 <= filterIndex && filterIndex < filterExtensions.length ? filterIndex : 0);
+ widget.sizeToFit();
+ panel.setAccessoryView(widget);
+ popup = widget;
+ }
+ panel.setTitle(NSString.stringWith(title != null ? title : ""));
+ NSApplication application = NSApplication.sharedApplication();
+ if (parent != null && (style & SWT.SHEET) != 0) {
+ application.beginSheet(panel, parent.window, null, 0, 0);
+ }
+ NSString dir = filterPath != null ? NSString.stringWith(filterPath) : null;
+ NSString file = fileName != null ? NSString.stringWith(fileName) : null;
+ int /*long*/ response = panel.runModalForDirectory(dir, file);
+ if (parent != null && (style & SWT.SHEET) != 0) {
+ application.endSheet(panel, 0);
+ }
+ if (!overwrite) {
+ if (method != 0) OS.method_setImplementation(method, methodImpl);
+ if (callback != null) callback.dispose();
+ }
+ if (response == OS.NSFileHandlingPanelOKButton) {
+ NSString filename = panel.filename();
+ fullPath = filename.getString();
+ if ((style & SWT.SAVE) == 0) {
+ NSArray filenames = ((NSOpenPanel)panel).filenames();
+ int count = (int)/*64*/filenames.count();
+ fileNames = new String[count];
+
+ for (int i = 0; i < count; i++) {
+ filename = new NSString(filenames.objectAtIndex(i));
+ NSString filenameOnly = filename.lastPathComponent();
+ NSString pathOnly = filename.stringByDeletingLastPathComponent();
+
+ if (i == 0) {
+ /* Filter path */
+ filterPath = pathOnly.getString();
+
+ /* File name */
+ fileName = fileNames [0] = filenameOnly.getString();
+ } else {
+ if (pathOnly.getString().equals (filterPath)) {
+ fileNames [i] = filenameOnly.getString();
+ } else {
+ fileNames [i] = filename.getString();
+ }
+ }
+ }
+ }
+ filterIndex = -1;
+ }
+ if (popup != null) {
+ filterIndex = (int)/*64*/popup.indexOfSelectedItem();
+ panel.setAccessoryView(null);
+ popup.release();
+ popup = null;
+ }
+ if (delegate != null) {
+ panel.setDelegate(null);
+ delegate.release();
+ }
+ if (jniRef != 0) OS.DeleteGlobalRef(jniRef);
+ panel = null;
+ return fullPath;
+}
+
+int /*long*/ _overwriteExistingFileCheck (int /*long*/ id, int /*long*/ sel, int /*long*/ str) {
+ return 1;
+}
+
+int /*long*/ panel_shouldShowFilename (int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1) {
+ NSString path = new NSString(arg1);
+ if (filterExtensions != null && filterExtensions.length != 0) {
+ NSFileManager manager = NSFileManager.defaultManager();
+ int /*long*/ ptr = OS.malloc(1);
+ boolean found = manager.fileExistsAtPath(path, ptr);
+ byte[] isDirectory = new byte[1];
+ OS.memmove(isDirectory, ptr, 1);
+ OS.free(ptr);
+ if (found) {
+ if (isDirectory[0] != 0) {
+ return 1;
+ } else {
+ NSString ext = path.pathExtension();
+ if (ext != null) {
+ int filterIndex = (int)/*64*/popup.indexOfSelectedItem();
+ String extension = ext.getString();
+ String extensions = filterExtensions [filterIndex];
+ int start = 0, length = extensions.length ();
+ while (start < length) {
+ int index = extensions.indexOf (EXTENSION_SEPARATOR, start);
+ if (index == -1) index = length;
+ String filter = extensions.substring (start, index).trim ();
+ if (filter.equals ("*") || filter.equals ("*.*")) return 1;
+ if (filter.startsWith ("*.")) filter = filter.substring (2);
+ if (filter.toLowerCase ().equals(extension.toLowerCase ())) return 1;
+ start = index + 1;
+ }
+ }
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+void sendSelection (int /*long*/ id, int /*long*/ sel, int /*long*/ arg) {
+ panel.validateVisibleColumns();
+}
+
+/**
+ * Set the initial filename which the dialog will
+ * select by default when opened to the argument,
+ * which may be null. The name will be prefixed with
+ * the filter path when one is supplied.
+ *
+ * @param string the file name
+ */
+public void setFileName (String string) {
+ fileName = string;
+}
+
+/**
+ * Set the file extensions which the dialog will
+ * use to filter the files it shows to the argument,
+ * which may be null.
+ * <p>
+ * The strings are platform specific. For example, on
+ * some platforms, an extension filter string is typically
+ * of the form "*.extension", where "*.*" matches all files.
+ * For filters with multiple extensions, use semicolon as
+ * a separator, e.g. "*.jpg;*.png".
+ * </p>
+ *
+ * @param extensions the file extension filter
+ *
+ * @see #setFilterNames to specify the user-friendly
+ * names corresponding to the extensions
+ */
+public void setFilterExtensions (String [] extensions) {
+ filterExtensions = extensions;
+}
+
+/**
+ * Set the 0-based index of the file extension filter
+ * which the dialog will use initially to filter the files
+ * it shows to the argument.
+ * <p>
+ * This is an index into the FilterExtensions array and
+ * the FilterNames array.
+ * </p>
+ *
+ * @param index the file extension filter index
+ *
+ * @see #setFilterExtensions
+ * @see #setFilterNames
+ *
+ * @since 3.4
+ */
+public void setFilterIndex (int index) {
+ filterIndex = index;
+}
+
+/**
+ * Sets the names that describe the filter extensions
+ * which the dialog will use to filter the files it shows
+ * to the argument, which may be null.
+ * <p>
+ * Each name is a user-friendly short description shown for
+ * its corresponding filter. The <code>names</code> array must
+ * be the same length as the <code>extensions</code> array.
+ * </p>
+ *
+ * @param names the list of filter names, or null for no filter names
+ *
+ * @see #setFilterExtensions
+ */
+public void setFilterNames (String [] names) {
+ filterNames = names;
+}
+
+/**
+ * Sets the directory path that the dialog will use
+ * to the argument, which may be null. File names in this
+ * path will appear in the dialog, filtered according
+ * to the filter extensions. If the string is null,
+ * then the operating system's default filter path
+ * will be used.
+ * <p>
+ * Note that the path string is platform dependent.
+ * For convenience, either '/' or '\' can be used
+ * as a path separator.
+ * </p>
+ *
+ * @param string the directory path
+ *
+ * @see #setFilterExtensions
+ */
+public void setFilterPath (String string) {
+ filterPath = string;
+}
+
+/**
+ * Sets the flag that the dialog will use to
+ * determine whether to prompt the user for file
+ * overwrite if the selected file already exists.
+ *
+ * @param overwrite true if the dialog will prompt for file overwrite, false otherwise
+ *
+ * @since 3.4
+ */
+public void setOverwrite (boolean overwrite) {
+ this.overwrite = overwrite;
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/FontDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/FontDialog.java
new file mode 100755
index 0000000000..df410af548
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/FontDialog.java
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class allow the user to select a font
+ * from all available fonts in the system.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * IMPORTANT: This class is intended to be subclassed <em>only</em>
+ * within the SWT implementation.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample, Dialog tab</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class FontDialog extends Dialog {
+ FontData fontData;
+ RGB rgb;
+ boolean selected;
+ int fontID, fontSize;
+
+/**
+ * Constructs a new instance of this class given only its parent.
+ *
+ * @param parent a shell which will be the parent of the new instance
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <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>
+ */
+public FontDialog (Shell parent) {
+ this (parent, SWT.APPLICATION_MODAL);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 shell which will be the parent of the new instance
+ * @param style the style of dialog to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <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>
+ */
+public FontDialog (Shell parent, int style) {
+ super (parent, checkStyle (parent, style));
+ checkSubclass ();
+}
+
+void changeFont(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ selected = true;
+}
+
+/**
+ * Returns a FontData object describing the font that was
+ * selected in the dialog, or null if none is available.
+ *
+ * @return the FontData for the selected font, or null
+ * @deprecated use #getFontList ()
+ */
+public FontData getFontData () {
+ return fontData;
+}
+
+/**
+ * Returns a FontData set describing the font that was
+ * selected in the dialog, or null if none is available.
+ *
+ * @return the FontData for the selected font, or null
+ * @since 2.1.1
+ */
+public FontData [] getFontList () {
+ if (fontData == null) return null;
+ FontData [] result = new FontData [1];
+ result [0] = fontData;
+ return result;
+}
+
+/**
+ * Returns an RGB describing the color that was selected
+ * in the dialog, or null if none is available.
+ *
+ * @return the RGB value for the selected color, or null
+ *
+ * @see PaletteData#getRGBs
+ *
+ * @since 2.1
+ */
+public RGB getRGB () {
+ return rgb;
+}
+
+/**
+ * Makes the dialog visible and brings it to the front
+ * of the display.
+ *
+ * @return a FontData object describing the font that was selected,
+ * or null if the dialog was cancelled or an error occurred
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the dialog has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the dialog</li>
+ * </ul>
+ */
+public FontData open () {
+ Display display = parent != null ? parent.display : Display.getCurrent ();
+ NSFontPanel panel = NSFontPanel.sharedFontPanel();
+ panel.setTitle(NSString.stringWith(title != null ? title : ""));
+ boolean create = fontData != null;
+ Font font = create ? new Font(display, fontData) : display.getSystemFont();
+ panel.setPanelFont(font.handle, false);
+ SWTPanelDelegate delegate = (SWTPanelDelegate)new SWTPanelDelegate().alloc().init();
+ int /*long*/ jniRef = OS.NewGlobalRef(this);
+ if (jniRef == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.object_setInstanceVariable(delegate.id, Display.SWT_OBJECT, jniRef);
+ panel.setDelegate(delegate);
+ fontData = null;
+ selected = false;
+ panel.orderFront(null);
+ NSApplication.sharedApplication().runModalForWindow(panel);
+ if (selected) {
+ NSFont nsFont = panel.panelConvertFont(font.handle);
+ if (nsFont != null) {
+ fontData = Font.cocoa_new(display, nsFont).getFontData()[0];
+ }
+ }
+ panel.setDelegate(null);
+ delegate.release();
+ OS.DeleteGlobalRef(jniRef);
+ if (create) font.dispose();
+ return fontData;
+}
+
+/**
+ * Sets a FontData object describing the font to be
+ * selected by default in the dialog, or null to let
+ * the platform choose one.
+ *
+ * @param fontData the FontData to use initially, or null
+ * @deprecated use #setFontList (FontData [])
+ */
+public void setFontData (FontData fontData) {
+ this.fontData = fontData;
+}
+
+/**
+ * Sets the set of FontData objects describing the font to
+ * be selected by default in the dialog, or null to let
+ * the platform choose one.
+ *
+ * @param fontData the set of FontData objects to use initially, or null
+ * to let the platform select a default when open() is called
+ *
+ * @see Font#getFontData
+ *
+ * @since 2.1.1
+ */
+public void setFontList (FontData [] fontData) {
+ if (fontData != null && fontData.length > 0) {
+ this.fontData = fontData [0];
+ } else {
+ this.fontData = null;
+ }
+}
+
+/**
+ * Sets the RGB describing the color to be selected by default
+ * in the dialog, or null to let the platform choose one.
+ *
+ * @param rgb the RGB value to use initially, or null to let
+ * the platform select a default when open() is called
+ *
+ * @see PaletteData#getRGBs
+ *
+ * @since 2.1
+ */
+public void setRGB (RGB rgb) {
+ this.rgb = rgb;
+}
+
+void windowWillClose(int /*long*/ id, int /*long*/ sel, int /*long*/ sender) {
+ NSApplication.sharedApplication().stop(null);
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Group.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Group.java
new file mode 100755
index 0000000000..e5b1dc262e
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Group.java
@@ -0,0 +1,241 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class provide an etched border
+ * with an optional title.
+ * <p>
+ * Shadow styles are hints and may not be honoured
+ * by the platform. To create a group with the
+ * default shadow style for the platform, do not
+ * specify a shadow style.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>SHADOW_ETCHED_IN, SHADOW_ETCHED_OUT, SHADOW_IN, SHADOW_OUT, SHADOW_NONE</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the above styles 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/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Group extends Composite {
+ NSView contentView;
+ String text = "";
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#SHADOW_ETCHED_IN
+ * @see SWT#SHADOW_ETCHED_OUT
+ * @see SWT#SHADOW_IN
+ * @see SWT#SHADOW_OUT
+ * @see SWT#SHADOW_NONE
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Group (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+static int checkStyle (int style) {
+ style |= SWT.NO_FOCUS;
+ /*
+ * Even though it is legal to create this widget
+ * with scroll bars, they serve no useful purpose
+ * because they do not automatically scroll the
+ * widget's client area. The fix is to clear
+ * the SWT style.
+ */
+ return style & ~(SWT.H_SCROLL | SWT.V_SCROLL);
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+public Rectangle computeTrim (int x, int y, int width, int height) {
+ checkWidget ();
+ NSBox widget = (NSBox)view;
+ int border = (int)Math.ceil (widget.borderWidth ());
+ NSSize margins = widget.contentViewMargins();
+ NSRect frame = contentView.frame();
+ width += (margins.width + border) * 2;
+ height += (margins.height + border) * 2 + frame.y;
+ return super.computeTrim(x, y, width, height);
+}
+
+NSView contentView () {
+ return contentView;
+}
+
+void createHandle () {
+ state |= THEME_BACKGROUND;
+ NSBox widget = (NSBox)new SWTBox().alloc();
+ widget.init();
+ widget.setTitlePosition(OS.NSNoTitle);
+ NSView contentWidget = (NSView)new SWTView().alloc();
+ contentWidget.init();
+// contentWidget.setDrawsBackground(false);
+ widget.setContentView(contentWidget);
+ contentView = contentWidget;
+ view = widget;
+}
+
+NSFont defaultNSFont () {
+ return display.boxFont;
+}
+
+void deregister () {
+ super.deregister ();
+ display.removeWidget (contentView);
+ SWTBox box = (SWTBox)view;
+ display.removeWidget (box.titleCell());
+}
+
+void drawBackground (int /*long*/ id, NSGraphicsContext context, NSRect rect) {
+ if (id != view.id) return;
+ fillBackground (view, context, rect, -1);
+}
+
+NSView eventView () {
+ return contentView;
+}
+
+public Rectangle getClientArea () {
+ checkWidget();
+ NSRect rect = contentView.bounds();
+ return new Rectangle((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
+}
+
+String getNameText () {
+ return getText ();
+}
+
+/**
+ * Returns the receiver's text, which is the string that the
+ * is used as the <em>title</em>. If the text has not previously
+ * been set, returns an empty string.
+ *
+ * @return the text
+ *
+ * @exception SWTException <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 String getText () {
+ checkWidget ();
+ return text;
+}
+
+float getThemeAlpha () {
+ return (background != null ? 1 : 0.25f) * parent.getThemeAlpha ();
+}
+
+void register () {
+ super.register ();
+ display.addWidget (contentView, this);
+ SWTBox box = (SWTBox)view;
+ display.addWidget (box.titleCell(), this);
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (contentView != null) contentView.release();
+ contentView = null;
+}
+
+void setFont(NSFont font) {
+ ((NSBox) view).setTitleFont(font);
+}
+
+void setForeground (float /*double*/ [] color) {
+ NSColor nsColor;
+ if (color == null) {
+ nsColor = NSColor.textColor ();
+ } else {
+ nsColor = NSColor.colorWithDeviceRed (color[0], color[1], color[2], 1);
+ }
+ NSTextFieldCell cell = new NSTextFieldCell (((NSBox)view).titleCell ().id);
+ cell.setTextColor (nsColor);
+}
+
+/**
+ * Sets the receiver's text, which is the string that will
+ * be displayed as the receiver's <em>title</em>, to the argument,
+ * which may not be null. The string may include the mnemonic character.
+ * </p>
+ * Mnemonics are indicated by an '&amp;' that causes the next
+ * character to be the mnemonic. When the user presses a
+ * key sequence that matches the mnemonic, focus is assigned
+ * to the first child of the group. On most platforms, the
+ * mnemonic appears underlined but may be emphasised in a
+ * platform specific manner. The mnemonic indicator character
+ * '&amp;' can be escaped by doubling it in the string, causing
+ * a single '&amp;' to be displayed.
+ * </p>
+ * @param string the new text
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
+ * </ul>
+ * @exception SWTException <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 setText (String string) {
+ checkWidget();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ text = string;
+ char [] buffer = new char [text.length ()];
+ text.getChars (0, buffer.length, buffer, 0);
+ int length = fixMnemonic (buffer);
+ NSBox box = (NSBox)view;
+ box.setTitlePosition(length == 0 ? OS.NSNoTitle : OS.NSAtTop);
+ box.setTitle(NSString.stringWithCharacters(buffer, length));
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/IME.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/IME.java
new file mode 100644
index 0000000000..f6c09b0693
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/IME.java
@@ -0,0 +1,510 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class represent input method editors.
+ * These are typically in-line pre-edit text areas that allow
+ * the user to compose characters from Far Eastern languages
+ * such as Japanese, Chinese or Korean.
+ *
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>ImeComposition</dd>
+ * </dl>
+ * <p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.4
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class IME extends Widget {
+ Canvas parent;
+ int caretOffset;
+ int startOffset;
+ int commitCount;
+ String text;
+ int [] ranges;
+ TextStyle [] styles;
+
+ static final int UNDERLINE_THICK = 1 << 16;
+
+/**
+ * Prevents uninitialized instances from being created outside the package.
+ */
+IME () {
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 canvas 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 SWTException <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 Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public IME (Canvas parent, int style) {
+ super (parent, style);
+ this.parent = parent;
+ createWidget ();
+}
+
+int /*long*/ attributedSubstringFromRange (int /*long*/ id, int /*long*/ sel, int /*long*/ rangePtr) {
+ Event event = new Event ();
+ event.detail = SWT.COMPOSITION_SELECTION;
+ sendEvent (SWT.ImeComposition, event);
+ NSRange range = new NSRange ();
+ OS.memmove (range, rangePtr, NSRange.sizeof);
+ int start = (int)/*64*/range.location;
+ int end = (int)/*64*/(range.location + range.length);
+ if (event.start <= start && start <= event.end && event.start <= end && end <= event.end) {
+ NSString str = NSString.stringWith (event.text.substring(start - event.start, end - event.start));
+ NSAttributedString attriStr = ((NSAttributedString)new NSAttributedString().alloc()).initWithString(str, null);
+ attriStr.autorelease ();
+ return attriStr.id;
+ }
+ return 0;
+}
+
+int /*long*/ characterIndexForPoint (int /*long*/ id, int /*long*/ sel, int /*long*/ point) {
+ if (!isInlineEnabled ()) return OS.NSNotFound;
+ NSPoint pt = new NSPoint ();
+ OS.memmove (pt, point, NSPoint.sizeof);
+ NSView view = parent.view;
+ pt = view.window ().convertScreenToBase (pt);
+ pt = view.convertPoint_fromView_ (pt, null);
+ Event event = new Event ();
+ event.detail = SWT.COMPOSITION_OFFSET;
+ event.x = (int) pt.x;
+ event.y = (int) pt.y;
+ sendEvent (SWT.ImeComposition, event);
+ int offset = event.index + event.count;
+ return offset != -1 ? offset : OS.NSNotFound;
+}
+
+void createWidget () {
+ text = "";
+ startOffset = -1;
+ if (parent.getIME () == null) {
+ parent.setIME (this);
+ }
+}
+
+NSRect firstRectForCharacterRange(int /*long*/ id, int /*long*/ sel, int /*long*/ range) {
+ NSRect rect = new NSRect ();
+ Caret caret = parent.caret;
+ if (caret != null) {
+ NSView view = parent.view;
+ NSPoint pt = new NSPoint ();
+ pt.x = caret.x;
+ pt.y = caret.y + caret.height;
+ pt = view.convertPoint_toView_ (pt, null);
+ pt = view.window ().convertBaseToScreen (pt);
+ rect.x = pt.x;
+ rect.y = pt.y;
+ rect.width = caret.width;
+ rect.height = caret.height;
+ }
+ return rect;
+}
+
+/**
+ * Returns the offset of the caret from the start of the document.
+ * The caret is within the current composition.
+ *
+ * @return the caret offset
+ *
+ * @exception SWTException <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 getCaretOffset () {
+ checkWidget ();
+ return startOffset + caretOffset;
+}
+
+/**
+ * Returns the commit count of the composition. This is the
+ * number of characters that have been composed. When the
+ * commit count is equal to the length of the composition
+ * text, then the in-line edit operation is complete.
+ *
+ * @return the commit count
+ *
+ * @exception SWTException <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 IME#getText
+ */
+public int getCommitCount () {
+ checkWidget ();
+ return commitCount;
+}
+
+/**
+ * Returns the offset of the composition from the start of the document.
+ * This is the start offset of the composition within the document and
+ * in not changed by the input method editor itself during the in-line edit
+ * session.
+ *
+ * @return the offset of the composition
+ *
+ * @exception SWTException <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 getCompositionOffset () {
+ checkWidget ();
+ return startOffset;
+}
+
+/**
+ * Returns the ranges for the style that should be applied during the
+ * in-line edit session.
+ * <p>
+ * The ranges array contains start and end pairs. Each pair refers to
+ * the corresponding style in the styles array. For example, the pair
+ * that starts at ranges[n] and ends at ranges[n+1] uses the style
+ * at styles[n/2] returned by <code>getStyles()</code>.
+ * </p>
+ * @return the ranges for the styles
+ *
+ * @exception SWTException <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 IME#getStyles
+ */
+public int [] getRanges () {
+ checkWidget ();
+ if (ranges == null) return new int [0];
+ int [] result = new int [ranges.length];
+ for (int i = 0; i < result.length; i++) {
+ result [i] = ranges [i] + startOffset;
+ }
+ return result;
+}
+
+/**
+ * Returns the styles for the ranges.
+ * <p>
+ * The ranges array contains start and end pairs. Each pair refers to
+ * the corresponding style in the styles array. For example, the pair
+ * that starts at ranges[n] and ends at ranges[n+1] uses the style
+ * at styles[n/2].
+ * </p>
+ *
+ * @return the ranges for the styles
+ *
+ * @exception SWTException <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 IME#getRanges
+ */
+public TextStyle [] getStyles () {
+ checkWidget ();
+ if (styles == null) return new TextStyle [0];
+ TextStyle [] result = new TextStyle [styles.length];
+ System.arraycopy (styles, 0, result, 0, styles.length);
+ return result;
+}
+
+TextStyle getStyle (NSDictionary attribs) {
+ NSArray keys = attribs.allKeys ();
+ int /*long*/ count = keys.count ();
+ TextStyle style = new TextStyle ();
+ for (int j = 0; j < count; j++) {
+ NSString key = new NSString (keys.objectAtIndex (j));
+ if (key.isEqualTo (OS.NSBackgroundColorAttributeName)) {
+ NSColor color = new NSColor (attribs.objectForKey (key)).colorUsingColorSpaceName (OS.NSCalibratedRGBColorSpace);
+ float /*double*/ [] rgbColor = new float /*double*/ []{color.redComponent(), color.greenComponent(), color.blueComponent(), color.alphaComponent()};
+ style.background = Color.cocoa_new (display, rgbColor);
+ } else if (key.isEqualTo (OS.NSForegroundColorAttributeName)) {
+ NSColor color = new NSColor (attribs.objectForKey (key)).colorUsingColorSpaceName (OS.NSCalibratedRGBColorSpace);
+ float /*double*/ [] rgbColor = new float /*double*/ []{color.redComponent(), color.greenComponent(), color.blueComponent(), color.alphaComponent()};
+ style.foreground = Color.cocoa_new (display, rgbColor);
+ } else if (key.isEqualTo (OS.NSUnderlineColorAttributeName)) {
+ NSColor color = new NSColor (attribs.objectForKey (key)).colorUsingColorSpaceName (OS.NSCalibratedRGBColorSpace);
+ float /*double*/ [] rgbColor = new float /*double*/ []{color.redComponent(), color.greenComponent(), color.blueComponent(), color.alphaComponent()};
+ style.underlineColor = Color.cocoa_new (display, rgbColor);
+ } else if (key.isEqualTo (OS.NSUnderlineStyleAttributeName)) {
+ NSNumber value = new NSNumber (attribs.objectForKey (key));
+ switch (value.intValue ()) {
+ case OS.NSUnderlineStyleSingle: style.underlineStyle = SWT.UNDERLINE_SINGLE; break;
+ case OS.NSUnderlineStyleDouble: style.underlineStyle = SWT.UNDERLINE_DOUBLE; break;
+ case OS.NSUnderlineStyleThick: style.underlineStyle = UNDERLINE_THICK; break;
+ }
+ style.underline = value.intValue () != OS.NSUnderlineStyleNone;
+ } else if (key.isEqualTo (OS.NSStrikethroughColorAttributeName)) {
+ NSColor color = new NSColor (attribs.objectForKey (key)).colorUsingColorSpaceName (OS.NSCalibratedRGBColorSpace);
+ float /*double*/ [] rgbColor = new float /*double*/ []{color.redComponent(), color.greenComponent(), color.blueComponent(), color.alphaComponent()};
+ style.strikeoutColor = Color.cocoa_new (display, rgbColor);
+ } else if (key.isEqualTo (OS.NSStrikethroughStyleAttributeName)) {
+ NSNumber value = new NSNumber (attribs.objectForKey (key));
+ style.strikeout = value.intValue () != OS.NSUnderlineStyleNone;
+ } else if (key.isEqualTo (OS.NSFontAttributeName)) {
+ NSFont font = new NSFont (attribs.objectForKey (key));
+ font.retain();
+ style.font = Font.cocoa_new (display, font);
+ }
+ }
+ return style;
+}
+
+/**
+ * Returns the composition text.
+ * <p>
+ * The text for an IME is the characters in the widget that
+ * are in the current composition. When the commit count is
+ * equal to the length of the composition text, then the
+ * in-line edit operation is complete.
+ * </p>
+ *
+ * @return the widget text
+ *
+ * @exception SWTException <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 String getText () {
+ checkWidget ();
+ return text;
+}
+
+/**
+ * Returns <code>true</code> if the caret should be wide, and
+ * <code>false</code> otherwise. In some languages, for example
+ * Korean, the caret is typically widened to the width of the
+ * current character in the in-line edit session.
+ *
+ * @return the wide caret state
+ *
+ * @exception SWTException <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 boolean getWideCaret() {
+ return false;
+}
+
+boolean hasMarkedText (int /*long*/ id, int /*long*/ sel) {
+ return text.length () != 0;
+}
+
+boolean insertText (int /*long*/ id, int /*long*/ sel, int /*long*/ string) {
+ if (startOffset == -1) return true;
+ NSString str = new NSString (string);
+ if (str.isKindOfClass (OS.objc_getClass ("NSAttributedString"))) {
+ str = new NSAttributedString (string).string ();
+ }
+ int length = (int)/*64*/str.length ();
+ int end = startOffset + text.length ();
+ resetStyles ();
+ caretOffset = commitCount = length;
+ Event event = new Event ();
+ event.detail = SWT.COMPOSITION_CHANGED;
+ event.start = startOffset;
+ event.end = end;
+ event.text = text = str.getString();
+ sendEvent (SWT.ImeComposition, event);
+ text = "";
+ caretOffset = commitCount = 0;
+ startOffset = -1;
+ return event.doit;
+}
+
+boolean isInlineEnabled () {
+ return hooks (SWT.ImeComposition);
+}
+
+NSRange markedRange (int /*long*/ id, int /*long*/ sel) {
+ NSRange range = new NSRange ();
+ if (startOffset != -1) {
+ range.location = startOffset;
+ range.length = text.length ();
+ } else {
+ range.location = OS.NSNotFound;
+ }
+ return range;
+}
+
+void resetStyles () {
+ if (styles != null) {
+ for (int i = 0; i < styles.length; i++) {
+ TextStyle style = styles [i];
+ Font font = style.font;
+ if (font != null) font.handle.release ();
+ }
+ }
+ styles = null;
+ ranges = null;
+}
+
+void releaseParent () {
+ super.releaseParent ();
+ if (this == parent.getIME ()) parent.setIME (null);
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ parent = null;
+ text = null;
+ resetStyles ();
+}
+
+NSRange selectedRange (int /*long*/ id, int /*long*/ sel) {
+ Event event = new Event ();
+ event.detail = SWT.COMPOSITION_SELECTION;
+ sendEvent (SWT.ImeComposition, event);
+ NSRange range = new NSRange ();
+ range.location = event.start;
+ range.length = event.text.length ();
+ return range;
+}
+
+/**
+ * Sets the offset of the composition from the start of the document.
+ * This is the start offset of the composition within the document and
+ * in not changed by the input method editor itself during the in-line edit
+ * session but may need to be changed by clients of the IME. For example,
+ * if during an in-line edit operation, a text editor inserts characters
+ * above the IME, then the IME must be informed that the composition
+ * offset has changed.
+ *
+ * @param offset the offset of the composition
+ *
+ * @exception SWTException <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 setCompositionOffset (int offset) {
+ checkWidget ();
+ if (offset < 0) return;
+ if (startOffset != -1) {
+ startOffset = offset;
+ }
+}
+
+boolean setMarkedText_selectedRange (int /*long*/ id, int /*long*/ sel, int /*long*/ string, int /*long*/ selRange) {
+ if (!isInlineEnabled ()) return true;
+ resetStyles ();
+ caretOffset = commitCount = 0;
+ int end = startOffset + text.length ();
+ if (startOffset == -1) {
+ Event event = new Event ();
+ event.detail = SWT.COMPOSITION_SELECTION;
+ sendEvent (SWT.ImeComposition, event);
+ startOffset = event.start;
+ end = event.end;
+ }
+ NSString str = new NSString (string);
+ if (str.isKindOfClass (OS.objc_getClass ("NSAttributedString"))) {
+ NSAttributedString attribStr = new NSAttributedString (string);
+ str = attribStr.string ();
+ int length = (int)/*64*/str.length ();
+ styles = new TextStyle [length];
+ ranges = new int [length * 2];
+ NSRange rangeLimit = new NSRange (), effectiveRange = new NSRange ();
+ rangeLimit.length = length;
+ int rangeCount = 0;
+ int /*long*/ ptr = OS.malloc (NSRange.sizeof);
+ for (int i = 0; i < length;) {
+ NSDictionary attribs = attribStr.attributesAtIndex(i, ptr, rangeLimit);
+ OS.memmove (effectiveRange, ptr, NSRange.sizeof);
+ i = (int)/*64*/(effectiveRange.location + effectiveRange.length);
+ ranges [rangeCount * 2] = (int)/*64*/effectiveRange.location;
+ ranges [rangeCount * 2 + 1] = (int)/*64*/(effectiveRange.location + effectiveRange.length - 1);
+ styles [rangeCount++] = getStyle (attribs);
+ }
+ OS.free (ptr);
+ if (rangeCount != styles.length) {
+ TextStyle [] newStyles = new TextStyle [rangeCount];
+ System.arraycopy (styles, 0, newStyles, 0, newStyles.length);
+ styles = newStyles;
+ int [] newRanges = new int [rangeCount * 2];
+ System.arraycopy (ranges, 0, newRanges, 0, newRanges.length);
+ ranges = newRanges;
+ }
+ }
+ int length = (int)/*64*/str.length ();
+ if (ranges == null && length > 0) {
+ styles = new TextStyle []{getStyle (display.markedAttributes)};
+ ranges = new int[]{0, length - 1};
+ }
+ NSRange range = new NSRange ();
+ OS.memmove (range, selRange, NSRange.sizeof);
+ caretOffset = (int)/*64*/range.location;
+ Event event = new Event ();
+ event.detail = SWT.COMPOSITION_CHANGED;
+ event.start = startOffset;
+ event.end = end;
+ event.text = text = str.getString();
+ sendEvent (SWT.ImeComposition, event);
+ if (isDisposed ()) return false;
+ if (text.length () == 0) {
+ Shell s = parent.getShell ();
+ s.keyInputHappened = true;
+ startOffset = -1;
+ resetStyles ();
+ }
+ return true;
+}
+
+int /*long*/ validAttributesForMarkedText (int /*long*/ id, int /*long*/ sel) {
+ NSMutableArray attribs = NSMutableArray.arrayWithCapacity (6);
+ attribs.addObject (new NSString (OS.NSForegroundColorAttributeName ()));
+ attribs.addObject (new NSString (OS.NSBackgroundColorAttributeName ()));
+ attribs.addObject (new NSString (OS.NSUnderlineStyleAttributeName ()));
+ attribs.addObject (new NSString (OS.NSUnderlineColorAttributeName ()));
+ attribs.addObject (new NSString (OS.NSStrikethroughStyleAttributeName ()));
+ attribs.addObject (new NSString (OS.NSStrikethroughColorAttributeName ()));
+ return attribs.id;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Label.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Label.java
new file mode 100755
index 0000000000..2afd1625e8
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Label.java
@@ -0,0 +1,521 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.accessibility.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class represent a non-selectable
+ * user interface object that displays a string or image.
+ * When SEPARATOR is specified, displays a single
+ * vertical or horizontal line.
+ * <p>
+ * Shadow styles are hints and may not be honored
+ * by the platform. To create a separator label
+ * with the default shadow style for the platform,
+ * do not specify a shadow style.
+ * </p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>SEPARATOR, HORIZONTAL, VERTICAL</dd>
+ * <dd>SHADOW_IN, SHADOW_OUT, SHADOW_NONE</dd>
+ * <dd>CENTER, LEFT, RIGHT, WRAP</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of SHADOW_IN, SHADOW_OUT and SHADOW_NONE may be specified.
+ * SHADOW_NONE is a HINT. Only one of HORIZONTAL and VERTICAL may be specified.
+ * Only one of CENTER, LEFT and RIGHT may be specified.
+ * </p><p>
+ * IMPORTANT: This class is intended to be subclassed <em>only</em>
+ * within the SWT implementation.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#label">Label snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Label extends Control {
+ String text;
+ Image image;
+ boolean isImage;
+ NSTextField textView;
+ NSImageView imageView;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#SEPARATOR
+ * @see SWT#HORIZONTAL
+ * @see SWT#VERTICAL
+ * @see SWT#SHADOW_IN
+ * @see SWT#SHADOW_OUT
+ * @see SWT#SHADOW_NONE
+ * @see SWT#CENTER
+ * @see SWT#LEFT
+ * @see SWT#RIGHT
+ * @see SWT#WRAP
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Label (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+int /*long*/ accessibilityAttributeNames(int /*long*/ id, int /*long*/ sel) {
+ if (accessible != null) {
+ if ((textView != null && (id == textView.id || id == textView.cell().id)) || (imageView != null && (id == imageView.id || id == imageView.cell().id))) {
+ // See if the accessible will override or augment the standard list.
+ // Help, title, and description can be overridden.
+ NSMutableArray extraAttributes = NSMutableArray.arrayWithCapacity(3);
+ extraAttributes.addObject(OS.NSAccessibilityHelpAttribute);
+ extraAttributes.addObject(OS.NSAccessibilityDescriptionAttribute);
+ extraAttributes.addObject(OS.NSAccessibilityTitleAttribute);
+
+ for (int i = (int)/*64*/extraAttributes.count() - 1; i >= 0; i--) {
+ NSString attribute = new NSString(extraAttributes.objectAtIndex(i).id);
+ if (accessible.internal_accessibilityAttributeValue(attribute, ACC.CHILDID_SELF) == null) {
+ extraAttributes.removeObjectAtIndex(i);
+ }
+ }
+
+ if (extraAttributes.count() > 0) {
+ int /*long*/ superResult = super.accessibilityAttributeNames(id, sel);
+ NSArray baseAttributes = new NSArray(superResult);
+ NSMutableArray mutableAttributes = NSMutableArray.arrayWithCapacity(baseAttributes.count() + 1);
+ mutableAttributes.addObjectsFromArray(baseAttributes);
+
+ for (int i = 0; i < extraAttributes.count(); i++) {
+ id currAttribute = extraAttributes.objectAtIndex(i);
+ if (!mutableAttributes.containsObject(currAttribute)) {
+ mutableAttributes.addObject(currAttribute);
+ }
+ }
+
+ return mutableAttributes.id;
+ }
+ }
+ }
+
+ return super.accessibilityAttributeNames(id, sel);
+}
+
+boolean accessibilityIsIgnored(int /*long*/ id, int /*long*/ sel) {
+ if (id == view.id) return true;
+ return super.accessibilityIsIgnored(id, sel);
+}
+
+void addRelation (Control control) {
+ if (!control.isDescribedByLabel ()) return;
+
+ if (textView != null) {
+ NSObject accessibleElement = control.focusView();
+
+ if (accessibleElement instanceof NSControl) {
+ NSControl viewAsControl = (NSControl)accessibleElement;
+ if (viewAsControl.cell() != null) accessibleElement = viewAsControl.cell();
+ }
+
+ accessibleElement.accessibilitySetOverrideValue(textView.cell(), OS.NSAccessibilityTitleUIElementAttribute);
+ NSArray controlArray = NSArray.arrayWithObject(accessibleElement);
+ textView.cell().accessibilitySetOverrideValue(controlArray, OS.NSAccessibilityServesAsTitleForUIElementsAttribute);
+ }
+}
+
+static int checkStyle (int style) {
+ style |= SWT.NO_FOCUS;
+ if ((style & SWT.SEPARATOR) != 0) {
+ style = checkBits (style, SWT.VERTICAL, SWT.HORIZONTAL, 0, 0, 0, 0);
+ return checkBits (style, SWT.SHADOW_OUT, SWT.SHADOW_IN, SWT.SHADOW_NONE, 0, 0, 0);
+ }
+ return checkBits (style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0);
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget();
+ int width = DEFAULT_WIDTH;
+ int height = DEFAULT_HEIGHT;
+ if ((style & SWT.SEPARATOR) != 0) {
+ float /*double*/ lineWidth = ((NSBox)view).borderWidth ();
+ if ((style & SWT.HORIZONTAL) != 0) {
+ height = (int)Math.ceil (lineWidth * 2);
+ } else {
+ width = (int)Math.ceil (lineWidth * 2);
+ }
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ int border = getBorderWidth ();
+ width += border * 2; height += border * 2;
+ return new Point (width, height);
+ }
+ if (isImage) {
+ if (image != null) {
+ NSImage nsimage = image.handle;
+ NSSize size = nsimage.size ();
+ width = (int)size.width;
+ height = (int)size.height;
+ } else {
+ width = height = 0;
+ }
+ } else {
+ NSSize size = null;
+ if ((style & SWT.WRAP) != 0 && wHint != SWT.DEFAULT) {
+ NSRect rect = new NSRect ();
+ rect.width = wHint;
+ rect.height = hHint != SWT.DEFAULT ? hHint : Float.MAX_VALUE;
+ size = textView.cell ().cellSizeForBounds (rect);
+ } else {
+ size = textView.cell ().cellSize ();
+ }
+ width = (int)Math.ceil (size.width);
+ height = (int)Math.ceil (size.height);
+ }
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ return new Point (width, height);
+}
+
+void createHandle () {
+ state |= THEME_BACKGROUND;
+ NSBox widget = (NSBox)new SWTBox().alloc();
+ widget.init();
+ widget.setTitle(NSString.stringWith(""));
+ if ((style & SWT.SEPARATOR) != 0) {
+ widget.setBoxType(OS.NSBoxSeparator);
+ NSView child = (NSView) new SWTView().alloc().init();
+ widget.setContentView(child);
+ child.release();
+ } else {
+ widget.setBorderType(OS.NSNoBorder);
+ widget.setBorderWidth (0);
+ widget.setBoxType (OS.NSBoxCustom);
+ NSSize offsetSize = new NSSize ();
+ widget.setContentViewMargins (offsetSize);
+
+ NSImageView imageWidget = (NSImageView) new SWTImageView ().alloc ();
+ imageWidget.init();
+ imageWidget.setImageScaling (OS.NSScaleNone);
+
+ NSTextField textWidget = (NSTextField)new SWTTextField().alloc();
+ textWidget.init();
+ textWidget.setBordered(false);
+ textWidget.setEditable(false);
+ textWidget.setDrawsBackground(false);
+ NSTextFieldCell cell = new NSTextFieldCell(textWidget.cell());
+ cell.setWraps ((style & SWT.WRAP) != 0);
+
+ widget.addSubview(imageWidget);
+ widget.addSubview(textWidget);
+ widget.setContentView(textWidget);
+
+ imageView = imageWidget;
+ textView = textWidget;
+ _setAlignment();
+ }
+ view = widget;
+}
+
+void createWidget() {
+ text = "";
+ super.createWidget ();
+}
+
+NSAttributedString createString() {
+ NSAttributedString attribStr = createString(text, null, foreground, (style & SWT.WRAP) == 0 ? style : 0, true, true);
+ attribStr.autorelease();
+ return attribStr;
+}
+
+NSFont defaultNSFont () {
+ return display.textFieldFont;
+}
+
+void deregister () {
+ super.deregister ();
+ if (textView != null) {
+ display.removeWidget(textView);
+ display.removeWidget(textView.cell());
+ }
+ if (imageView != null) {
+ display.removeWidget (imageView);
+ display.removeWidget (imageView.cell());
+ }
+}
+
+NSView eventView () {
+ return ((NSBox)view).contentView();
+}
+
+/**
+ * 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>
+ * unless the receiver is a <code>SEPARATOR</code> label, in
+ * which case, <code>NONE</code> is returned.
+ *
+ * @return the alignment
+ *
+ * @exception SWTException <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 & SWT.SEPARATOR) != 0) return SWT.LEFT;
+ if ((style & SWT.CENTER) != 0) return SWT.CENTER;
+ if ((style & SWT.RIGHT) != 0) return SWT.RIGHT;
+ return SWT.LEFT;
+}
+
+/**
+ * Returns the receiver's image if it has one, or null
+ * if it does not.
+ *
+ * @return the receiver's image
+ *
+ * @exception SWTException <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 Image getImage () {
+ checkWidget();
+ return image;
+}
+
+String getNameText () {
+ return getText ();
+}
+
+/**
+ * Returns the receiver's text, which will be an empty
+ * string if it has never been set or if the receiver is
+ * a <code>SEPARATOR</code> label.
+ *
+ * @return the receiver's text
+ *
+ * @exception SWTException <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 String getText () {
+ checkWidget();
+ if ((style & SWT.SEPARATOR) != 0) return "";
+ return text;
+}
+
+boolean isDescribedByLabel () {
+ return false;
+}
+
+void register () {
+ super.register ();
+ if (textView != null) {
+ display.addWidget (textView, this);
+ display.addWidget (textView.cell(), this);
+ }
+ if (imageView != null) {
+ display.addWidget (imageView, this);
+ display.addWidget (imageView.cell(), this);
+ }
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (textView != null) textView.release();
+ if (imageView != null) imageView.release();
+ textView = null;
+ imageView = null;
+}
+
+/*
+ * Remove "Labeled by" relations from the receiver.
+ */
+void removeRelation () {
+ if (textView != null) {
+ textView.cell().accessibilitySetOverrideValue(null, OS.NSAccessibilityServesAsTitleForUIElementsAttribute);
+ }
+}
+
+/**
+ * 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>. If the receiver is a <code>SEPARATOR</code>
+ * label, the argument is ignored and the alignment is not changed.
+ *
+ * @param alignment the new alignment
+ *
+ * @exception SWTException <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 ((style & SWT.SEPARATOR) != 0) return;
+ if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) == 0) return;
+ style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER);
+ style |= alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER);
+ _setAlignment();
+}
+
+void updateBackground () {
+ if ((style & SWT.SEPARATOR) != 0) return;
+ NSColor nsColor = null;
+ if (backgroundImage != null) {
+ nsColor = NSColor.colorWithPatternImage(backgroundImage.handle);
+ } else if (background != null) {
+ nsColor = NSColor.colorWithDeviceRed(background[0], background[1], background[2], background[3]);
+ } else {
+ nsColor = NSColor.clearColor();
+ }
+ ((NSBox)view).setFillColor(nsColor);
+}
+
+void _setAlignment() {
+ if (image != null) {
+ if ((style & SWT.RIGHT) != 0) imageView.setImageAlignment(OS.NSImageAlignRight);
+ if ((style & SWT.LEFT) != 0) imageView.setImageAlignment(OS.NSImageAlignLeft);
+ if ((style & SWT.CENTER) != 0) imageView.setImageAlignment(OS.NSImageAlignCenter);
+ }
+ if (text != null) {
+ NSCell cell = new NSCell(textView.cell());
+ cell.setAttributedStringValue(createString());
+ }
+}
+
+void setFont(NSFont font) {
+ if (textView != null) {
+ NSCell cell = new NSCell(textView.cell());
+ cell.setAttributedStringValue(createString());
+ textView.setFont (font);
+ }
+}
+
+void setForeground (float /*double*/ [] color) {
+ if ((style & SWT.SEPARATOR) != 0) return;
+ NSCell cell = new NSCell(textView.cell());
+ cell.setAttributedStringValue(createString());
+}
+
+boolean setTabItemFocus () {
+ return false;
+}
+
+/**
+ * Sets the receiver's image to the argument, which may be
+ * null indicating that no image should be displayed.
+ *
+ * @param image the image to display on the receiver (may be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setImage (Image image) {
+ checkWidget();
+ if ((style & SWT.SEPARATOR) != 0) return;
+ if (image != null && image.isDisposed ()) {
+ error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.image = image;
+ isImage = true;
+
+ /*
+ * Feature in Cocoa. If the NSImage object being set into the view is
+ * the same NSImage object that is already there then the new image is
+ * not taken. This results in the view's image not changing even if the
+ * NSImage object's content has changed since it was last set into the
+ * view. The workaround is to temporarily set the view's image to null
+ * so that the new image will then be taken.
+ */
+ if (image != null) {
+ NSImage current = imageView.image ();
+ if (current != null && current.id == image.handle.id) {
+ imageView.setImage (null);
+ }
+ }
+ imageView.setImage(image != null ? image.handle : null);
+ ((NSBox)view).setContentView(imageView);
+}
+
+/**
+ * Sets the receiver's text.
+ * <p>
+ * This method sets the widget label. The label may include
+ * the mnemonic character and line delimiters.
+ * </p>
+ * <p>
+ * Mnemonics are indicated by an '&amp;' that causes the next
+ * character to be the mnemonic. When the user presses a
+ * key sequence that matches the mnemonic, focus is assigned
+ * to the control that follows the label. On most platforms,
+ * the mnemonic appears underlined but may be emphasised in a
+ * platform specific manner. The mnemonic indicator character
+ * '&amp;' can be escaped by doubling it in the string, causing
+ * a single '&amp;' to be displayed.
+ * </p>
+ *
+ * @param string the new text
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
+ * </ul>
+ * @exception SWTException <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 setText (String string) {
+ checkWidget();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if ((style & SWT.SEPARATOR) != 0) return;
+ isImage = false;
+ text = string;
+ NSCell cell = new NSCell(textView.cell());
+ cell.setAttributedStringValue(createString());
+ ((NSBox)view).setContentView(textView);
+}
+
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Link.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Link.java
new file mode 100755
index 0000000000..18210ff412
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Link.java
@@ -0,0 +1,532 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.internal.cocoa.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Instances of this class represent a selectable
+ * user interface object that displays a text with
+ * links.
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ * <p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#link">Link snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.1
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Link extends Control {
+ NSScrollView scrollView;
+ String text;
+ Point [] offsets;
+ Point selection;
+ String [] ids;
+ int [] mnemonics;
+ NSColor linkColor;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Link (Composite parent, int style) {
+ super (parent, style);
+}
+
+/**
+ * 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 control is selected by the user.
+ * <code>widgetDefaultSelected</code> is not called.
+ * </p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection, typedListener);
+ addListener (SWT.DefaultSelection, typedListener);
+}
+
+boolean textView_clickOnLink_atIndex(int /*long*/ id, int /*long*/ sel, int /*long*/ textView, int /*long*/ link, int /*long*/ charIndex) {
+ NSString str = new NSString (link);
+ Event event = new Event ();
+ event.text = str.getString();
+ sendEvent (SWT.Selection, event);
+ return true;
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ if (wHint != SWT.DEFAULT && wHint < 0) wHint = 0;
+ if (hHint != SWT.DEFAULT && hHint < 0) hHint = 0;
+ int width, height;
+ //TODO wrapping, wHint
+ int borderStyle = hasBorder() ? OS.NSBezelBorder : OS.NSNoBorder;
+ NSSize borderSize = NSScrollView.frameSizeForContentSize(new NSSize(), false, false, borderStyle);
+ NSTextView widget = (NSTextView)view;
+ NSSize size = widget.textStorage().size();
+ width = (int)(size.width + borderSize.width);
+ height = (int)(size.height + borderSize.height);
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ int border = getBorderWidth ();
+ width += border * 2;
+ height += border * 2;
+
+ // TODO is this true? if so, can this rounding be turned off?
+ /*
+ * Bug in Cocoa. NSTextStorage.size() seems to return a width
+ * value that is rounded down, because its result is never
+ * fractional. The workaround is to increment width by 1
+ * to ensure that it is wide enough to show the full text.
+ */
+ width += 1;
+ return new Point (width, height);
+}
+
+void createHandle () {
+ state |= THEME_BACKGROUND;
+ NSScrollView scrollWidget = (NSScrollView)new SWTScrollView().alloc();
+ scrollWidget.init();
+ scrollWidget.setDrawsBackground(false);
+ scrollWidget.setBorderType(hasBorder() ? OS.NSBezelBorder : OS.NSNoBorder);
+
+ NSTextView widget = (NSTextView)new SWTTextView().alloc();
+ widget.init();
+ widget.setEditable(false);
+ widget.setDrawsBackground(false);
+ widget.setDelegate(widget);
+ widget.setAutoresizingMask (OS.NSViewWidthSizable | OS.NSViewHeightSizable);
+ widget.textContainer().setLineFragmentPadding(0);
+
+ scrollView = scrollWidget;
+ view = widget;
+}
+
+void createWidget () {
+ super.createWidget ();
+ text = "";
+ NSDictionary dict = ((NSTextView)view).linkTextAttributes();
+ linkColor = new NSColor(dict.valueForKey(OS.NSForegroundColorAttributeName));
+}
+
+NSFont defaultNSFont () {
+ return display.textViewFont;
+}
+
+void deregister () {
+ super.deregister ();
+ if (scrollView != null) display.removeWidget (scrollView);
+}
+
+void enableWidget (boolean enabled) {
+ super.enableWidget (enabled);
+ NSColor nsColor = null;
+ if (enabled) {
+ if (foreground == null) {
+ nsColor = NSColor.textColor ();
+ } else {
+ nsColor = NSColor.colorWithDeviceRed (foreground [0], foreground [1], foreground [2], foreground[3]);
+ }
+ } else {
+ nsColor = NSColor.disabledControlTextColor();
+ }
+ NSTextView widget = (NSTextView)view;
+ widget.setTextColor(nsColor);
+ NSDictionary linkTextAttributes = widget.linkTextAttributes();
+ int count = (int)/*64*/linkTextAttributes.count();
+ NSMutableDictionary dict = NSMutableDictionary.dictionaryWithCapacity(count);
+ dict.setDictionary(linkTextAttributes);
+ dict.setValue(enabled ? linkColor : nsColor, OS.NSForegroundColorAttributeName);
+ widget.setLinkTextAttributes(dict);
+}
+
+String getNameText () {
+ return getText ();
+}
+
+
+/**
+ * Returns the receiver's text, which will be an empty
+ * string if it has never been set.
+ *
+ * @return the receiver's text
+ *
+ * @exception SWTException <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 String getText () {
+ checkWidget ();
+ return text;
+}
+
+void register () {
+ super.register ();
+ if (scrollView != null) display.addWidget (scrollView, this);
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ offsets = null;
+ ids = null;
+ mnemonics = null;
+ text = null;
+ linkColor = null;
+}
+
+/**
+ * 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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection, listener);
+}
+
+String parse (String string) {
+ int length = string.length ();
+ offsets = new Point [length / 4];
+ ids = new String [length / 4];
+ mnemonics = new int [length / 4 + 1];
+ StringBuffer result = new StringBuffer ();
+ char [] buffer = new char [length];
+ string.getChars (0, string.length (), buffer, 0);
+ int index = 0, state = 0, linkIndex = 0;
+ int start = 0, tagStart = 0, linkStart = 0, endtagStart = 0, refStart = 0;
+ while (index < length) {
+ char c = Character.toLowerCase (buffer [index]);
+ switch (state) {
+ case 0:
+ if (c == '<') {
+ tagStart = index;
+ state++;
+ }
+ break;
+ case 1:
+ if (c == 'a') state++;
+ break;
+ case 2:
+ switch (c) {
+ case 'h':
+ state = 7;
+ break;
+ case '>':
+ linkStart = index + 1;
+ state++;
+ break;
+ default:
+ if (Character.isWhitespace(c)) break;
+ else state = 13;
+ }
+ break;
+ case 3:
+ if (c == '<') {
+ endtagStart = index;
+ state++;
+ }
+ break;
+ case 4:
+ state = c == '/' ? state + 1 : 3;
+ break;
+ case 5:
+ state = c == 'a' ? state + 1 : 3;
+ break;
+ case 6:
+ if (c == '>') {
+ mnemonics [linkIndex] = parseMnemonics (buffer, start, tagStart, result);
+ int offset = result.length ();
+ parseMnemonics (buffer, linkStart, endtagStart, result);
+ offsets [linkIndex] = new Point (offset, result.length () - 1);
+ if (ids [linkIndex] == null) {
+ ids [linkIndex] = new String (buffer, linkStart, endtagStart - linkStart);
+ }
+ linkIndex++;
+ start = tagStart = linkStart = endtagStart = refStart = index + 1;
+ state = 0;
+ } else {
+ state = 3;
+ }
+ break;
+ case 7:
+ state = c == 'r' ? state + 1 : 0;
+ break;
+ case 8:
+ state = c == 'e' ? state + 1 : 0;
+ break;
+ case 9:
+ state = c == 'f' ? state + 1 : 0;
+ break;
+ case 10:
+ state = c == '=' ? state + 1 : 0;
+ break;
+ case 11:
+ if (c == '"') {
+ state++;
+ refStart = index + 1;
+ } else {
+ state = 0;
+ }
+ break;
+ case 12:
+ if (c == '"') {
+ ids[linkIndex] = new String (buffer, refStart, index - refStart);
+ state = 2;
+ }
+ break;
+ case 13:
+ if (Character.isWhitespace (c)) {
+ state = 0;
+ } else if (c == '='){
+ state++;
+ }
+ break;
+ case 14:
+ state = c == '"' ? state + 1 : 0;
+ break;
+ case 15:
+ if (c == '"') state = 2;
+ break;
+ default:
+ state = 0;
+ break;
+ }
+ index++;
+ }
+ if (start < length) {
+ int tmp = parseMnemonics (buffer, start, tagStart, result);
+ int mnemonic = parseMnemonics (buffer, Math.max (tagStart, linkStart), length, result);
+ if (mnemonic == -1) mnemonic = tmp;
+ mnemonics [linkIndex] = mnemonic;
+ } else {
+ mnemonics [linkIndex] = -1;
+ }
+ if (offsets.length != linkIndex) {
+ Point [] newOffsets = new Point [linkIndex];
+ System.arraycopy (offsets, 0, newOffsets, 0, linkIndex);
+ offsets = newOffsets;
+ String [] newIDs = new String [linkIndex];
+ System.arraycopy (ids, 0, newIDs, 0, linkIndex);
+ ids = newIDs;
+ int [] newMnemonics = new int [linkIndex + 1];
+ System.arraycopy (mnemonics, 0, newMnemonics, 0, linkIndex + 1);
+ mnemonics = newMnemonics;
+ }
+ return result.toString ();
+}
+
+int parseMnemonics (char[] buffer, int start, int end, StringBuffer result) {
+ int mnemonic = -1, index = start;
+ while (index < end) {
+ if (buffer [index] == '&') {
+ if (index + 1 < end && buffer [index + 1] == '&') {
+ result.append (buffer [index]);
+ index++;
+ } else {
+ mnemonic = result.length();
+ }
+ } else {
+ result.append (buffer [index]);
+ }
+ index++;
+ }
+ return mnemonic;
+}
+
+void updateBackground () {
+ NSColor nsColor = null;
+ if (backgroundImage != null) {
+ nsColor = NSColor.colorWithPatternImage(backgroundImage.handle);
+ } else if (background != null) {
+ nsColor = NSColor.colorWithDeviceRed(background[0], background[1], background[2], background[3]);
+ }
+ setBackground(nsColor);
+}
+
+void setBackground(NSColor nsColor) {
+ NSTextView widget = (NSTextView)view;
+ if (nsColor == null) {
+ widget.setDrawsBackground(false);
+ } else {
+ widget.setDrawsBackground(true);
+ widget.setBackgroundColor (nsColor);
+ }
+}
+
+void setFont(NSFont font) {
+ ((NSTextView) view).setFont(font);
+}
+
+void setForeground (float /*double*/ [] color) {
+ if (!getEnabled ()) return;
+ NSColor nsColor;
+ if (color == null) {
+ nsColor = NSColor.textColor ();
+ } else {
+ nsColor = NSColor.colorWithDeviceRed (color [0], color [1], color [2], 1);
+ }
+ ((NSTextView) view).setTextColor (nsColor);
+}
+
+/**
+ * Sets the receiver's text.
+ * <p>
+ * The string can contain both regular text and hyperlinks. A hyperlink
+ * is delimited by an anchor tag, &lt;A&gt; and &lt;/A&gt;. Within an
+ * anchor, a single HREF attribute is supported. When a hyperlink is
+ * selected, the text field of the selection event contains either the
+ * text of the hyperlink or the value of its HREF, if one was specified.
+ * In the rare case of identical hyperlinks within the same string, the
+ * HREF attribute can be used to distinguish between them. The string may
+ * include the mnemonic character and line delimiters. The only delimiter
+ * the HREF attribute supports is the quotation mark (").
+ * </p>
+ *
+ * @param string the new text
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
+ * </ul>
+ * @exception SWTException <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 setText (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (string.equals (text)) return;
+ text = string;
+ NSTextView widget = (NSTextView)view;
+ widget.setString(NSString.stringWith(parse(string)));
+ NSTextStorage textStorage = widget.textStorage();
+ NSRange range = new NSRange();
+ for (int i = 0; i < offsets.length; i++) {
+ range.location = offsets[i].x;
+ range.length = offsets[i].y - offsets[i].x + 1;
+ textStorage.addAttribute(OS.NSLinkAttributeName, NSString.stringWith(ids[i]), range);
+ }
+}
+
+public void setToolTipText(String string) {
+ ((NSTextView)view).setDisplaysLinkToolTips(string == null);
+ super.setToolTipText(string);
+}
+
+void setZOrder () {
+ super.setZOrder ();
+ if (scrollView != null) scrollView.setDocumentView (view);
+}
+
+NSView topView () {
+ return scrollView;
+}
+
+void updateCursorRects (boolean enabled) {
+ super.updateCursorRects (enabled);
+ if (scrollView == null) return;
+ updateCursorRects (enabled, scrollView);
+ NSClipView contentView = scrollView.contentView ();
+ updateCursorRects (enabled, contentView);
+ contentView.setDocumentCursor (enabled ? NSCursor.IBeamCursor () : null);
+}
+
+//int traversalCode (int key, int theEvent) {
+// if (offsets.length == 0) return 0;
+// int bits = super.traversalCode (key, theEvent);
+// if (key == 48 /* Tab */ && theEvent != 0) {
+// int [] modifiers = new int [1];
+// OS.GetEventParameter (theEvent, OS.kEventParamKeyModifiers, OS.typeUInt32, null, 4, null, modifiers);
+// boolean next = (modifiers [0] & OS.shiftKey) == 0;
+// if (next && focusIndex < offsets.length - 1) {
+// return bits & ~ SWT.TRAVERSE_TAB_NEXT;
+// }
+// if (!next && focusIndex > 0) {
+// return bits & ~ SWT.TRAVERSE_TAB_PREVIOUS;
+// }
+// }
+// return bits;
+//}
+
+}
+
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/List.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/List.java
new file mode 100755
index 0000000000..efc9e9af66
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/List.java
@@ -0,0 +1,1429 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.accessibility.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class represent a selectable user interface
+ * object that displays a list of strings and issues notification
+ * when a string is selected. A list may be single or multi select.
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>SINGLE, MULTI</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection, DefaultSelection</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of SINGLE and MULTI 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/#list">List snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class List extends Scrollable {
+ NSTableColumn column;
+ String [] items;
+ int itemCount;
+ boolean ignoreSelect;
+
+ static int NEXT_ID;
+
+ static final int CELL_GAP = 1;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#SINGLE
+ * @see SWT#MULTI
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public List (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+int /*long*/ accessibilityAttributeValue (int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+
+ if (accessible != null) {
+ NSString attribute = new NSString(arg0);
+ id returnValue = accessible.internal_accessibilityAttributeValue(attribute, ACC.CHILDID_SELF);
+ if (returnValue != null) return returnValue.id;
+ }
+
+ NSString attributeName = new NSString(arg0);
+
+ // Accessibility Verifier queries for a title or description. NSOutlineView doesn't
+ // seem to return either, so we return a default description value here.
+ if (attributeName.isEqualToString (OS.NSAccessibilityDescriptionAttribute)) {
+ return NSString.stringWith("").id;
+ }
+
+// if (attributeName.isEqualToString(OS.NSAccessibilityHeaderAttribute)) {
+// /*
+// * Bug in the Macintosh. Even when the header is not visible,
+// * VoiceOver still reports each column header's role for every row.
+// * This is confusing and overly verbose. The fix is to return
+// * "no header" when the screen reader asks for the header, by
+// * returning noErr without setting the event parameter.
+// */
+// return 0;
+// }
+
+ return super.accessibilityAttributeValue(id, sel, arg0);
+}
+
+/**
+ * Adds the argument to the end of the receiver's list.
+ *
+ * @param string the new item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <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 #add(String,int)
+ */
+public void add (String string) {
+ checkWidget();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (itemCount == items.length) {
+ String [] newItems = new String [itemCount + 4];
+ System.arraycopy (items, 0, newItems, 0, items.length);
+ items = newItems;
+ }
+ items [itemCount++] = string;
+ ((NSTableView)view).noteNumberOfRowsChanged ();
+ setScrollWidth(string);
+}
+
+/**
+ * Adds the argument to the receiver's list at the given
+ * zero-relative index.
+ * <p>
+ * Note: To add an item at the end of the list, use the
+ * result of calling <code>getItemCount()</code> as the
+ * index or use <code>add(String)</code>.
+ * </p>
+ *
+ * @param string the new item
+ * @param index the index for the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 #add(String)
+ */
+public void add (String string, int index) {
+ checkWidget();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (!(0 <= index && index <= itemCount)) error (SWT.ERROR_INVALID_RANGE);
+ if (itemCount == items.length) {
+ String [] newItems = new String [itemCount + 4];
+ System.arraycopy (items, 0, newItems, 0, items.length);
+ items = newItems;
+ }
+ System.arraycopy (items, index, items, index + 1, itemCount++ - index);
+ items [index] = string;
+ ((NSTableView)view).noteNumberOfRowsChanged ();
+ if (index != itemCount) fixSelection (index, true);
+ setScrollWidth(string);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's selection, by sending
+ * it one of the messages defined in the <code>SelectionListener</code>
+ * interface.
+ * <p>
+ * <code>widgetSelected</code> is called when the selection changes.
+ * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked.
+ * </p>
+ *
+ * @param listener the listener which should be notified when the user changes the receiver's selection
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener(listener);
+ addListener(SWT.Selection,typedListener);
+ addListener(SWT.DefaultSelection,typedListener);
+}
+
+static int checkStyle (int style) {
+ return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0);
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget();
+ int width = 0;
+ if (wHint == SWT.DEFAULT) {
+ NSCell cell = column.dataCell ();
+ Font font = this.font != null ? this.font : defaultFont ();
+ cell.setFont (font.handle);
+ for (int i = 0; i < items.length; i++) {
+ if (items[i] != null) {
+ cell.setTitle (NSString.stringWith (items[i]));
+ NSSize size = cell.cellSize ();
+ width = Math.max (width, (int)Math.ceil (size.width));
+ }
+ }
+ width += CELL_GAP;
+ } else {
+ width = wHint;
+ }
+ if (width <= 0) width = DEFAULT_WIDTH;
+ int height = 0;
+ if (hHint == SWT.DEFAULT) {
+ int itemHeight = getItemHeight () + CELL_GAP;
+ height = itemCount * itemHeight;
+ } else {
+ height = hHint;
+ }
+ if (height <= 0) height = DEFAULT_HEIGHT;
+ Rectangle rect = computeTrim (0, 0, width, height);
+ return new Point (rect.width, rect.height);
+}
+
+void createHandle () {
+ NSScrollView scrollWidget = (NSScrollView)new SWTScrollView().alloc();
+ scrollWidget.init();
+ if ((style & SWT.H_SCROLL) != 0) scrollWidget.setHasHorizontalScroller(true);
+ if ((style & SWT.V_SCROLL) != 0) scrollWidget.setHasVerticalScroller(true);
+ scrollWidget.setAutohidesScrollers(true);
+ scrollWidget.setBorderType((style & SWT.BORDER) != 0 ? OS.NSBezelBorder : OS.NSNoBorder);
+
+ NSTableView widget = (NSTableView)new SWTTableView().alloc();
+ widget.init();
+ widget.setAllowsMultipleSelection((style & SWT.MULTI) != 0);
+ widget.setDataSource(widget);
+ widget.setHeaderView(null);
+ widget.setDelegate(widget);
+ if ((style & SWT.H_SCROLL) != 0) {
+ widget.setColumnAutoresizingStyle (OS.NSTableViewNoColumnAutoresizing);
+ }
+ NSSize spacing = new NSSize();
+ spacing.width = spacing.height = CELL_GAP;
+ widget.setIntercellSpacing(spacing);
+ widget.setDoubleAction(OS.sel_sendDoubleSelection);
+ if (!hasBorder()) widget.setFocusRingType(OS.NSFocusRingTypeNone);
+
+ column = (NSTableColumn)new NSTableColumn().alloc();
+ column = column.initWithIdentifier(NSString.stringWith(String.valueOf(++NEXT_ID)));
+ column.setWidth(0);
+ widget.addTableColumn (column);
+
+ scrollView = scrollWidget;
+ view = widget;
+}
+
+void createWidget () {
+ super.createWidget ();
+ items = new String [4];
+}
+
+Color defaultBackground () {
+ return display.getWidgetColor (SWT.COLOR_LIST_BACKGROUND);
+}
+
+NSFont defaultNSFont () {
+ return display.tableViewFont;
+}
+
+Color defaultForeground () {
+ return display.getWidgetColor (SWT.COLOR_LIST_FOREGROUND);
+}
+
+/**
+ * Deselects the item at the given zero-relative index in the receiver.
+ * If the item at the index was already deselected, it remains
+ * deselected. Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to deselect
+ *
+ * @exception SWTException <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 deselect (int index) {
+ checkWidget();
+ if (0 <= index && index < itemCount) {
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ widget.deselectRow (index);
+ ignoreSelect = false;
+ }
+}
+
+/**
+ * Deselects the items at the given zero-relative indices in the receiver.
+ * If the item at the given zero-relative index in the receiver
+ * is selected, it is deselected. If the item at the index
+ * was not selected, it remains deselected. The range of the
+ * indices is inclusive. Indices that are out of range are ignored.
+ *
+ * @param start the start index of the items to deselect
+ * @param end the end index of the items to deselect
+ *
+ * @exception SWTException <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 deselect (int start, int end) {
+ checkWidget();
+ if (start > end) return;
+ if (end < 0 || start >= itemCount) return;
+ start = Math.max (0, start);
+ end = Math.min (itemCount - 1, end);
+ if (start == 0 && end == itemCount - 1) {
+ deselectAll ();
+ } else {
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ for (int i=start; i<=end; i++) {
+ widget.deselectRow (i);
+ }
+ ignoreSelect = false;
+ }
+}
+
+/**
+ * Deselects the items at the given zero-relative indices in the receiver.
+ * If the item at the given zero-relative index in the receiver
+ * is selected, it is deselected. If the item at the index
+ * was not selected, it remains deselected. Indices that are out
+ * of range and duplicate indices are ignored.
+ *
+ * @param indices the array of indices for the items to deselect
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the set of indices is null</li>
+ * </ul>
+ * @exception SWTException <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 deselect (int [] indices) {
+ checkWidget();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ for (int i=0; i<indices.length; i++) {
+ widget.deselectRow (indices [i]);
+ }
+ ignoreSelect = false;
+}
+
+/**
+ * Deselects all selected items in the receiver.
+ *
+ * @exception SWTException <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 deselectAll () {
+ checkWidget ();
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ widget.deselectAll(null);
+ ignoreSelect = false;
+}
+
+boolean dragDetect(int x, int y, boolean filter, boolean[] consume) {
+ NSTableView widget = (NSTableView)view;
+ NSPoint pt = new NSPoint();
+ pt.x = x;
+ pt.y = y;
+ int /*long*/ row = widget.rowAtPoint(pt);
+ if (row == -1) return false;
+ boolean dragging = super.dragDetect(x, y, filter, consume);
+ if (dragging) {
+ if (!widget.isRowSelected(row)) {
+ //TODO expand current selection when Shift, Command key pressed??
+ NSIndexSet set = (NSIndexSet)new NSIndexSet().alloc();
+ set = set.initWithIndex(row);
+ widget.selectRowIndexes (set, false);
+ set.release();
+ }
+ }
+ consume[0] = dragging;
+ return dragging;
+}
+
+void fixSelection (int index, boolean add) {
+ int [] selection = getSelectionIndices ();
+ if (selection.length == 0) return;
+ int newCount = 0;
+ boolean fix = false;
+ for (int i = 0; i < selection.length; i++) {
+ if (!add && selection [i] == index) {
+ fix = true;
+ } else {
+ int newIndex = newCount++;
+ selection [newIndex] = selection [i];
+ if (selection [newIndex] >= index) {
+ selection [newIndex] += add ? 1 : -1;
+ fix = true;
+ }
+ }
+ }
+ if (fix) select (selection, newCount, true);
+}
+
+/**
+ * Returns the zero-relative index of the item which currently
+ * has the focus in the receiver, or -1 if no item has focus.
+ *
+ * @return the index of the selected item
+ *
+ * @exception SWTException <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 getFocusIndex () {
+ checkWidget();
+ return (int)/*64*/((NSTableView)view).selectedRow();
+}
+
+/**
+ * Returns the item at the given, zero-relative index in the
+ * receiver. Throws an exception if the index is out of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 String getItem (int index) {
+ checkWidget();
+ if (!(0 <= index && index < itemCount)) error (SWT.ERROR_INVALID_RANGE);
+ return items [index];
+}
+
+/**
+ * Returns the number of items contained in the receiver.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException <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 getItemCount () {
+ checkWidget();
+ return itemCount;
+}
+
+/**
+ * Returns the height of the area which would be used to
+ * display <em>one</em> of the items in the list.
+ *
+ * @return the height of one item
+ *
+ * @exception SWTException <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 getItemHeight () {
+ checkWidget ();
+ return (int)((NSTableView)view).rowHeight();
+}
+
+/**
+ * Returns a (possibly empty) array of <code>String</code>s which
+ * are the items in the receiver.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ *
+ * @return the items in the receiver's list
+ *
+ * @exception SWTException <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 String [] getItems () {
+ checkWidget();
+ String [] result = new String [itemCount];
+ System.arraycopy (items, 0, result, 0, itemCount);
+ return result;
+}
+
+/**
+ * Returns an array of <code>String</code>s that are currently
+ * selected in the receiver. The order of the items is unspecified.
+ * An empty array indicates that no items are selected.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its selection, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ * @return an array representing the selection
+ *
+ * @exception SWTException <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 String [] getSelection () {
+ checkWidget ();
+ NSTableView widget = (NSTableView)view;
+ if (widget.numberOfSelectedRows() == 0) {
+ return new String [0];
+ }
+ NSIndexSet selection = widget.selectedRowIndexes();
+ int count = (int)/*64*/selection.count();
+ int /*long*/ [] indexBuffer = new int /*long*/ [count];
+ selection.getIndexes(indexBuffer, count, 0);
+ String [] result = new String [count];
+ for (int i=0; i<count; i++) {
+ result [i] = items [(int)/*64*/indexBuffer [i]];
+ }
+ return result;
+}
+
+/**
+ * Returns the number of selected items contained in the receiver.
+ *
+ * @return the number of selected items
+ *
+ * @exception SWTException <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 getSelectionCount () {
+ checkWidget ();
+ return (int)/*64*/((NSTableView)view).numberOfSelectedRows();
+}
+
+/**
+ * Returns the zero-relative index of the item which is currently
+ * selected in the receiver, or -1 if no item is selected.
+ *
+ * @return the index of the selected item or -1
+ *
+ * @exception SWTException <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 getSelectionIndex () {
+ checkWidget();
+ NSTableView widget = (NSTableView)view;
+ if (widget.numberOfSelectedRows() == 0) {
+ return -1;
+ }
+ NSIndexSet selection = widget.selectedRowIndexes();
+ int count = (int)/*64*/selection.count();
+ int /*long*/ [] result = new int /*long*/ [count];
+ selection.getIndexes(result, count, 0);
+ return (int)/*64*/result [0];
+}
+
+/**
+ * Returns the zero-relative indices of the items which are currently
+ * selected in the receiver. The order of the indices is unspecified.
+ * The array is empty if no items are selected.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its selection, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ * @return the array of indices of the selected items
+ *
+ * @exception SWTException <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 [] getSelectionIndices () {
+ checkWidget ();
+ NSTableView widget = (NSTableView)view;
+ if (widget.numberOfSelectedRows() == 0) {
+ return new int [0];
+ }
+ NSIndexSet selection = widget.selectedRowIndexes();
+ int count = (int)/*64*/selection.count();
+ int /*long*/ [] indices = new int /*long*/ [count];
+ selection.getIndexes(indices, count, 0);
+ int [] result = new int [count];
+ for (int i = 0; i < result.length; i++) {
+ result [i] = (int)/*64*/indices [i];
+ }
+ return result;
+}
+
+/**
+ * Returns the zero-relative index of the item which is currently
+ * at the top of the receiver. This index can change when items are
+ * scrolled or new items are added or removed.
+ *
+ * @return the index of the top item
+ *
+ * @exception SWTException <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 getTopIndex () {
+ checkWidget();
+ //TODO - partial item at the top
+ NSRect rect = scrollView.documentVisibleRect();
+ NSPoint point = new NSPoint();
+ point.x = rect.x;
+ point.y = rect.y;
+ int result = (int)/*64*/((NSTableView)view).rowAtPoint(point);
+ if (result == -1) result = 0;
+ return result;
+}
+
+/**
+ * Gets the index of an item.
+ * <p>
+ * The list is searched starting at 0 until an
+ * item is found that is equal to the search item.
+ * If no item is found, -1 is returned. Indexing
+ * is zero based.
+ *
+ * @param string the search item
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <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 indexOf (String item) {
+ checkWidget();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ for (int i=0; i<itemCount; i++) {
+ if (items [i].equals (item)) return i;
+ }
+ return -1;
+}
+
+/**
+ * Searches the receiver's list starting at the given,
+ * zero-relative index until an item is found that is equal
+ * to the argument, and returns the index of that item. If
+ * no item is found or the starting index is out of range,
+ * returns -1.
+ *
+ * @param string the search item
+ * @param start the zero-relative index at which to start the search
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <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 indexOf (String string, int start) {
+ checkWidget();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ for (int i=start; i<itemCount; i++) {
+ if (items [i].equals (string)) return i;
+ }
+ return -1;
+}
+
+/**
+ * Returns <code>true</code> if the item is selected,
+ * and <code>false</code> otherwise. Indices out of
+ * range are ignored.
+ *
+ * @param index the index of the item
+ * @return the selection state of the item at the index
+ *
+ * @exception SWTException <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 boolean isSelected (int index) {
+ checkWidget();
+ if (!(0 <= index && index < itemCount)) return false;
+ return ((NSTableView)view).isRowSelected(index);
+}
+
+/*
+ * Feature in Cocoa: Table views do not change the selection when the user
+ * right-clicks or control-clicks on an NSTableView or its subclasses. Fix is to select the
+ * clicked-on row ourselves.
+ */
+int /*long*/ menuForEvent(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ NSEvent event = new NSEvent(theEvent);
+ NSTableView table = (NSTableView)view;
+
+ // get the current selections for the outline view.
+ NSIndexSet selectedRowIndexes = table.selectedRowIndexes();
+
+ // select the row that was clicked before showing the menu for the event
+ NSPoint mousePoint = view.convertPoint_fromView_(event.locationInWindow(), null);
+ int /*long*/ row = table.rowAtPoint(mousePoint);
+
+ // figure out if the row that was just clicked on is currently selected
+ if (selectedRowIndexes.containsIndex(row) == false) {
+ NSIndexSet set = (NSIndexSet)new NSIndexSet().alloc();
+ set = set.initWithIndex(row);
+ table.selectRowIndexes (set, false);
+ set.release();
+ }
+ // else that row is currently selected, so don't change anything.
+
+ return super.menuForEvent(id, sel, theEvent);
+}
+
+int /*long*/ numberOfRowsInTableView(int /*long*/ id, int /*long*/ sel, int /*long*/ aTableView) {
+ return itemCount;
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (column != null) column.release();
+ column = null;
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ items = null;
+}
+
+/**
+ * Removes the item from the receiver at the given
+ * zero-relative index.
+ *
+ * @param index the index for the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 remove (int index) {
+ checkWidget();
+ if (!(0 <= index && index < itemCount)) error (SWT.ERROR_INVALID_RANGE);
+ remove(index, true);
+}
+
+void remove (int index, boolean fixScroll) {
+ if (index != itemCount - 1) fixSelection (index, false);
+ System.arraycopy (items, index + 1, items, index, --itemCount - index);
+ items [itemCount] = null;
+ ((NSTableView)view).noteNumberOfRowsChanged();
+ if (fixScroll) setScrollWidth();
+}
+
+/**
+ * Removes the items from the receiver which are
+ * between the given zero-relative start and end
+ * indices (inclusive).
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if either the start or end are not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 remove (int start, int end) {
+ checkWidget();
+ if (start > end) return;
+ if (!(0 <= start && start <= end && end < itemCount)) {
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ int length = end - start + 1;
+ for (int i=0; i<length; i++) remove (start, false);
+ setScrollWidth();
+}
+
+/**
+ * Searches the receiver's list starting at the first item
+ * until an item is found that is equal to the argument,
+ * and removes that item from the list.
+ *
+ * @param string the item to remove
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the string is not found in the list</li>
+ * </ul>
+ * @exception SWTException <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 remove (String string) {
+ checkWidget();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int index = indexOf (string, 0);
+ if (index == -1) error (SWT.ERROR_INVALID_ARGUMENT);
+ remove (index);
+}
+
+/**
+ * Removes the items from the receiver at the given
+ * zero-relative indices.
+ *
+ * @param indices the array of indices of the items
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * <li>ERROR_NULL_ARGUMENT - if the indices array is null</li>
+ * </ul>
+ * @exception SWTException <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 remove (int [] indices) {
+ checkWidget ();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (indices.length == 0) return;
+ int [] newIndices = new int [indices.length];
+ System.arraycopy (indices, 0, newIndices, 0, indices.length);
+ sort (newIndices);
+ int start = newIndices [newIndices.length - 1], end = newIndices [0];
+ int count = getItemCount ();
+ if (!(0 <= start && start <= end && end < count)) {
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ int last = -1;
+ for (int i=0; i<newIndices.length; i++) {
+ int index = newIndices [i];
+ if (index != last) {
+ remove (index, false);
+ last = index;
+ }
+ }
+ setScrollWidth();
+}
+
+/**
+ * Removes all of the items from the receiver.
+ * <p>
+ * @exception SWTException <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 removeAll () {
+ checkWidget();
+ items = new String [4];
+ itemCount = 0;
+ ((NSTableView)view).noteNumberOfRowsChanged();
+ setScrollWidth();
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the user changes the receiver's selection.
+ *
+ * @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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook(SWT.Selection, listener);
+ eventTable.unhook(SWT.DefaultSelection,listener);
+}
+
+/**
+ * Selects the item at the given zero-relative index in the receiver's
+ * list. If the item at the index was already selected, it remains
+ * selected. Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to select
+ *
+ * @exception SWTException <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 select (int index) {
+ checkWidget();
+ if (0 <= index && index < itemCount) {
+ NSIndexSet set = (NSIndexSet)new NSIndexSet().alloc();
+ set = set.initWithIndex(index);
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ widget.selectRowIndexes(set, (style & SWT.MULTI) != 0);
+ ignoreSelect = false;
+ set.release();
+ }
+}
+
+/**
+ * Selects the items in the range specified by the given zero-relative
+ * indices in the receiver. The range of indices is inclusive.
+ * The current selection is not cleared before the new items are selected.
+ * <p>
+ * If an item in the given range is not selected, it is selected.
+ * If an item in the given range was already selected, it remains selected.
+ * Indices that are out of range are ignored and no items will be selected
+ * if start is greater than end.
+ * If the receiver is single-select and there is more than one item in the
+ * given range, then all indices are ignored.
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ *
+ * @exception SWTException <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 List#setSelection(int,int)
+ */
+public void select (int start, int end) {
+ checkWidget ();
+ if (end < 0 || start > end || ((style & SWT.SINGLE) != 0 && start != end)) return;
+ if (itemCount == 0 || start >= itemCount) return;
+ if (start == 0 && end == itemCount - 1) {
+ selectAll ();
+ } else {
+ start = Math.max (0, start);
+ end = Math.min (end, itemCount - 1);
+ NSRange range = new NSRange();
+ range.location = start;
+ range.length = end - start + 1;
+ NSIndexSet set = (NSIndexSet)new NSIndexSet().alloc();
+ set = set.initWithIndexesInRange(range);
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ widget.selectRowIndexes(set, (style & SWT.MULTI) != 0);
+ ignoreSelect = false;
+ set.release();
+ }
+}
+
+/**
+ * Selects the items at the given zero-relative indices in the receiver.
+ * The current selection is not cleared before the new items are selected.
+ * <p>
+ * If the item at a given index is not selected, it is selected.
+ * If the item at a given index was already selected, it remains selected.
+ * Indices that are out of range and duplicate indices are ignored.
+ * If the receiver is single-select and multiple indices are specified,
+ * then all indices are ignored.
+ *
+ * @param indices the array of indices for the items to select
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li>
+ * </ul>
+ * @exception SWTException <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 List#setSelection(int[])
+ */
+public void select (int [] indices) {
+ checkWidget ();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int length = indices.length;
+ if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
+ int count = 0;
+ NSMutableIndexSet set = (NSMutableIndexSet)new NSMutableIndexSet().alloc().init();
+ for (int i=0; i<length; i++) {
+ int index = indices [i];
+ if (index >= 0 && index < itemCount) {
+ set.addIndex (indices [i]);
+ count++;
+ }
+ }
+ if (count > 0) {
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ widget.selectRowIndexes(set, (style & SWT.MULTI) != 0);
+ ignoreSelect = false;
+ }
+ set.release();
+}
+
+void select (int [] indices, int count, boolean clear) {
+ NSMutableIndexSet set = (NSMutableIndexSet)new NSMutableIndexSet().alloc().init();
+ for (int i=0; i<count; i++) set.addIndex (indices [i]);
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ widget.selectRowIndexes(set, !clear);
+ ignoreSelect = false;
+ set.release();
+}
+
+/**
+ * Selects all of the items in the receiver.
+ * <p>
+ * If the receiver is single-select, do nothing.
+ *
+ * @exception SWTException <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 selectAll () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) return;
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ widget.selectAll(null);
+ ignoreSelect = false;
+}
+
+void sendDoubleSelection() {
+ if (((NSTableView)view).clickedRow () != -1) {
+ postEvent (SWT.DefaultSelection);
+ }
+}
+
+boolean sendKeyEvent (NSEvent nsEvent, int type) {
+ boolean result = super.sendKeyEvent (nsEvent, type);
+ if (!result) return result;
+ if (type != SWT.KeyDown) return result;
+ short keyCode = nsEvent.keyCode ();
+ switch (keyCode) {
+ case 76: /* KP Enter */
+ case 36: { /* Return */
+ postEvent (SWT.DefaultSelection);
+ break;
+ }
+ }
+ return result;
+}
+
+void updateBackground () {
+ NSColor nsColor = null;
+ if (backgroundImage != null) {
+ nsColor = NSColor.colorWithPatternImage(backgroundImage.handle);
+ } else if (background != null) {
+ nsColor = NSColor.colorWithDeviceRed(background[0], background[1], background[2], background[3]);
+ }
+ ((NSTableView) view).setBackgroundColor (nsColor);
+}
+
+void setFont (NSFont font) {
+ super.setFont (font);
+ float /*double*/ ascent = font.ascender ();
+ float /*double*/ descent = -font.descender () + font.leading ();
+ ((NSTableView)view).setRowHeight ((int)Math.ceil (ascent + descent) + 1);
+ setScrollWidth();
+}
+
+/**
+ * Sets the text of the item in the receiver's list at the given
+ * zero-relative index to the string argument.
+ *
+ * @param index the index for the item
+ * @param string the new text for the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <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 setItem (int index, String string) {
+ checkWidget();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (!(0 <= index && index < itemCount)) error (SWT.ERROR_INVALID_RANGE);
+ items [index] = string;
+ NSTableView tableView = (NSTableView)view;
+ NSRect rect = tableView.rectOfRow (index);
+ tableView.setNeedsDisplayInRect (rect);
+ setScrollWidth(string);
+}
+
+/**
+ * Sets the receiver's items to be the given array of items.
+ *
+ * @param items the array of items
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the items array is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if an item in the items array is null</li>
+ * </ul>
+ * @exception SWTException <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 setItems (String [] items) {
+ checkWidget();
+ if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
+ for (int i=0; i<items.length; i++) {
+ if (items [i] == null) error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.items = new String [items.length];
+ System.arraycopy (items, 0, this.items, 0, items.length);
+ itemCount = items.length;
+ ((NSTableView)view).reloadData();
+ setScrollWidth();
+}
+
+boolean setScrollWidth (String item) {
+ if ((style & SWT.H_SCROLL) == 0) return false;
+ NSCell cell = column.dataCell ();
+ Font font = this.font != null ? this.font : defaultFont ();
+ cell.setFont (font.handle);
+ cell.setTitle (NSString.stringWith (item));
+ NSSize size = cell.cellSize ();
+ float /*double*/ oldWidth = column.width ();
+ if (oldWidth < size.width) {
+ column.setWidth (size.width);
+ return true;
+ }
+ return false;
+}
+
+boolean setScrollWidth () {
+ if ((style & SWT.H_SCROLL) == 0) return false;
+ if (items == null) return false;
+ NSCell cell = column.dataCell ();
+ Font font = this.font != null ? this.font : defaultFont ();
+ cell.setFont (font.handle);
+ float /*double*/ width = 0;
+ for (int i = 0; i < itemCount; i++) {
+ cell.setTitle (NSString.stringWith (items[i]));
+ NSSize size = cell.cellSize ();
+ width = Math.max (width, size.width);
+ }
+ column.setWidth (width);
+ return true;
+}
+
+/**
+ * Selects the item at the given zero-relative index in the receiver.
+ * If the item at the index was already selected, it remains selected.
+ * The current selection is first cleared, then the new item is selected.
+ * Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to select
+ *
+ * @exception SWTException <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 List#deselectAll()
+ * @see List#select(int)
+ */
+public void setSelection (int index) {
+ checkWidget();
+ deselectAll ();
+ if (0 <= index && index < itemCount) {
+ NSIndexSet set = (NSIndexSet)new NSIndexSet().alloc();
+ set = set.initWithIndex(index);
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ widget.selectRowIndexes(set, false);
+ ignoreSelect = false;
+ set.release();
+ showIndex (index);
+ }
+}
+
+/**
+ * Selects the items in the range specified by the given zero-relative
+ * indices in the receiver. The range of indices is inclusive.
+ * The current selection is cleared before the new items are selected.
+ * <p>
+ * Indices that are out of range are ignored and no items will be selected
+ * if start is greater than end.
+ * If the receiver is single-select and there is more than one item in the
+ * given range, then all indices are ignored.
+ *
+ * @param start the start index of the items to select
+ * @param end the end index of the items to select
+ *
+ * @exception SWTException <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 List#deselectAll()
+ * @see List#select(int,int)
+ */
+public void setSelection (int start, int end) {
+ checkWidget ();
+ deselectAll ();
+ if (end < 0 || start > end || ((style & SWT.SINGLE) != 0 && start != end)) return;
+ if (itemCount == 0 || start >= itemCount) return;
+ start = Math.max (0, start);
+ end = Math.min (end, itemCount - 1);
+ NSRange range = new NSRange();
+ range.location = start;
+ range.length = end - start + 1;
+ NSIndexSet set = (NSIndexSet)new NSIndexSet().alloc();
+ set = set.initWithIndexesInRange(range);
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ widget.selectRowIndexes(set, false);
+ ignoreSelect = false;
+ set.release();
+ showIndex(end);
+}
+
+/**
+ * Selects the items at the given zero-relative indices in the receiver.
+ * The current selection is cleared before the new items are selected.
+ * <p>
+ * Indices that are out of range and duplicate indices are ignored.
+ * If the receiver is single-select and multiple indices are specified,
+ * then all indices are ignored.
+ *
+ * @param indices the indices of the items to select
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li>
+ * </ul>
+ * @exception SWTException <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 List#deselectAll()
+ * @see List#select(int[])
+ */
+public void setSelection (int [] indices) {
+ checkWidget ();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ deselectAll ();
+ int length = indices.length;
+ if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
+ int [] newIndices = new int [length];
+ int count = 0;
+ for (int i=0; i<length; i++) {
+ int index = indices [length - i - 1];
+ if (index >= 0 && index < itemCount) {
+ newIndices [count++] = index;
+ }
+ }
+ if (count > 0) {
+ select (newIndices, count, true);
+ showIndex (newIndices [0]);
+ }
+}
+
+/**
+ * Sets the receiver's selection to be the given array of items.
+ * The current selection is cleared before the new items are selected.
+ * <p>
+ * Items that are not in the receiver are ignored.
+ * If the receiver is single-select and multiple items are specified,
+ * then all items are ignored.
+ *
+ * @param items the array of items
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the array of items is null</li>
+ * </ul>
+ * @exception SWTException <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 List#deselectAll()
+ * @see List#select(int[])
+ * @see List#setSelection(int[])
+ */
+public void setSelection (String [] items) {
+ checkWidget ();
+ if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
+ deselectAll ();
+ int length = items.length;
+ if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
+ int count = 0;
+ int [] indices = new int [length];
+ for (int i=0; i<length; i++) {
+ String string = items [length - i - 1];
+ if ((style & SWT.SINGLE) != 0) {
+ int index = indexOf (string, 0);
+ if (index != -1) {
+ count = 1;
+ indices = new int [] {index};
+ }
+ } else {
+ int index = 0;
+ while ((index = indexOf (string, index)) != -1) {
+ if (count == indices.length) {
+ int [] newIds = new int [indices.length + 4];
+ System.arraycopy (indices, 0, newIds, 0, indices.length);
+ indices = newIds;
+ }
+ indices [count++] = index;
+ index++;
+ }
+ }
+ }
+ if (count > 0) {
+ select (indices, count, true);
+ showIndex (indices [0]);
+ }
+}
+
+/**
+ * Sets the zero-relative index of the item which is currently
+ * at the top of the receiver. This index can change when items
+ * are scrolled or new items are added and removed.
+ *
+ * @param index the index of the top item
+ *
+ * @exception SWTException <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 setTopIndex (int index) {
+ checkWidget();
+ NSTableView widget = (NSTableView) view;
+ int row = Math.max(0, Math.min(index, itemCount));
+ NSPoint pt = new NSPoint();
+ pt.x = scrollView.contentView().bounds().x;
+ pt.y = widget.frameOfCellAtColumn(0, row).y;
+ view.scrollPoint(pt);
+}
+
+void showIndex (int index) {
+ if (0 <= index && index < itemCount) {
+ ((NSTableView)view).scrollRowToVisible(index);
+ }
+}
+
+/**
+ * Shows the selection. If the selection is already showing in the receiver,
+ * this method simply returns. Otherwise, the items are scrolled until
+ * the selection is visible.
+ *
+ * @exception SWTException <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 showSelection () {
+ checkWidget();
+ int index = getSelectionIndex ();
+ if (index >= 0) showIndex (index);
+}
+
+void tableViewSelectionDidChange (int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+ if (ignoreSelect) return;
+ postEvent (SWT.Selection);
+}
+
+boolean tableView_shouldEditTableColumn_row(int /*long*/ id, int /*long*/ sel, int /*long*/ aTableView, int /*long*/ aTableColumn, int /*long*/ rowIndex) {
+ return false;
+}
+
+int /*long*/ tableView_objectValueForTableColumn_row(int /*long*/ id, int /*long*/ sel, int /*long*/ aTableView, int /*long*/ aTableColumn, int /*long*/ rowIndex) {
+ NSAttributedString attribStr = createString(items[(int)/*64*/rowIndex], null, foreground, 0, true, false);
+ attribStr.autorelease();
+ return attribStr.id;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Menu.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Menu.java
new file mode 100755
index 0000000000..62934535e4
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Menu.java
@@ -0,0 +1,926 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Instances of this class are user interface objects that contain
+ * menu items.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>BAR, DROP_DOWN, POP_UP, NO_RADIO_GROUP</dd>
+ * <dd>LEFT_TO_RIGHT, RIGHT_TO_LEFT</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Help, Hide, Show </dd>
+ * </dl>
+ * <p>
+ * Note: Only one of BAR, DROP_DOWN and POP_UP may be specified.
+ * Only one of LEFT_TO_RIGHT or RIGHT_TO_LEFT 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/#menu">Menu snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Menu extends Widget {
+ /**
+ * the handle to the OS resource
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ NSMenu nsMenu;
+ int x, y, itemCount;
+ boolean hasLocation, visible;
+ MenuItem [] items;
+ MenuItem cascade, defaultItem;
+ Decorations parent;
+
+/**
+ * Constructs a new instance of this class given its parent,
+ * and sets the style for the instance so that the instance
+ * will be a popup menu on the given parent's shell.
+ * <p>
+ * After constructing a menu, it can be set into its parent
+ * using <code>parent.setMenu(menu)</code>. In this case, the parent may
+ * be any control in the same widget tree as the parent.
+ * </p>
+ *
+ * @param parent a control which will be the parent of the new instance (cannot be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <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 SWT#POP_UP
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Menu (Control parent) {
+ this (checkNull (parent).menuShell (), SWT.POP_UP);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>Decorations</code>) and a style value
+ * describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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>
+ * After constructing a menu or menuBar, it can be set into its parent
+ * using <code>parent.setMenu(menu)</code> or <code>parent.setMenuBar(menuBar)</code>.
+ * </p>
+ *
+ * @param parent a decorations control which will be the parent of the new instance (cannot be null)
+ * @param style the style of menu to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <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 SWT#BAR
+ * @see SWT#DROP_DOWN
+ * @see SWT#POP_UP
+ * @see SWT#NO_RADIO_GROUP
+ * @see SWT#LEFT_TO_RIGHT
+ * @see SWT#RIGHT_TO_LEFT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Menu (Decorations parent, int style) {
+ super (parent, checkStyle (style));
+ this.parent = parent;
+ createWidget ();
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>Menu</code>) and sets the style
+ * for the instance so that the instance will be a drop-down
+ * menu on the given parent's parent.
+ * <p>
+ * After constructing a drop-down menu, it can be set into its parentMenu
+ * using <code>parentMenu.setMenu(menu)</code>.
+ * </p>
+ *
+ * @param parentMenu a menu which will be the parent of the new instance (cannot be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <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 SWT#DROP_DOWN
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Menu (Menu parentMenu) {
+ this (checkNull (parentMenu).parent, SWT.DROP_DOWN);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>MenuItem</code>) and sets the style
+ * for the instance so that the instance will be a drop-down
+ * menu on the given parent's parent menu.
+ * <p>
+ * After constructing a drop-down menu, it can be set into its parentItem
+ * using <code>parentItem.setMenu(menu)</code>.
+ * </p>
+ *
+ * @param parentItem a menu item which will be the parent of the new instance (cannot be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <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 SWT#DROP_DOWN
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Menu (MenuItem parentItem) {
+ this (checkNull (parentItem).parent);
+}
+
+static Control checkNull (Control control) {
+ if (control == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return control;
+}
+
+static Menu checkNull (Menu menu) {
+ if (menu == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return menu;
+}
+
+static MenuItem checkNull (MenuItem item) {
+ if (item == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return item;
+}
+
+static int checkStyle (int style) {
+ return checkBits (style, SWT.POP_UP, SWT.BAR, SWT.DROP_DOWN, 0, 0, 0);
+}
+
+void _setVisible (boolean visible) {
+ if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return;
+ TrayItem trayItem = display.currentTrayItem;
+ if (trayItem != null && visible) {
+ trayItem.showMenu (this);
+ return;
+ }
+ if (visible) {
+ Shell shell = getShell ();
+ NSWindow window = shell.window;
+ NSPoint location = null;
+ if (hasLocation) {
+ NSView topView = window.contentView();
+ Point shellCoord = display.map(null, shell, new Point(x,y));
+ location = new NSPoint ();
+ location.x = shellCoord.x;
+ location.y = topView.frame().height - shellCoord.y;
+ } else {
+ location = window.mouseLocationOutsideOfEventStream();
+ }
+
+ // Hold on to window in case it is disposed while the popup is open.
+ window.retain();
+ NSEvent nsEvent = NSEvent.otherEventWithType(OS.NSApplicationDefined, location, 0, 0.0, window.windowNumber(), window.graphicsContext(), (short)0, 0, 0);
+ NSMenu.popUpContextMenu(nsMenu, nsEvent, shell.view);
+ window.release();
+ } else {
+ nsMenu.cancelTracking ();
+ }
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when help events are generated for the control,
+ * by sending it one of the messages defined in the
+ * <code>HelpListener</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 SWTException <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 HelpListener
+ * @see #removeHelpListener
+ */
+public void addHelpListener (HelpListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Help, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when menus are hidden or shown, by sending it
+ * one of the messages defined in the <code>MenuListener</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 SWTException <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 MenuListener
+ * @see #removeMenuListener
+ */
+public void addMenuListener (MenuListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Hide,typedListener);
+ addListener (SWT.Show,typedListener);
+}
+
+void createHandle () {
+ display.addMenu (this);
+ NSMenu widget = (NSMenu)new SWTMenu().alloc();
+ widget = widget.initWithTitle(NSString.stringWith(""));
+ widget.setAutoenablesItems(false);
+ widget.setDelegate(widget);
+ nsMenu = widget;
+}
+
+void createItem (MenuItem item, int index) {
+ if (!(0 <= index && index <= itemCount)) error (SWT.ERROR_INVALID_RANGE);
+ NSMenuItem nsItem = null;
+ if ((item.style & SWT.SEPARATOR) != 0) {
+ nsItem = NSMenuItem.separatorItem();
+ nsItem.retain();
+ } else {
+ nsItem = (NSMenuItem)new SWTMenuItem().alloc();
+ nsItem.initWithTitle(NSString.stringWith(""), 0, NSString.stringWith(""));
+ nsItem.setTarget(nsItem);
+ nsItem.setAction(OS.sel_sendSelection);
+ }
+ item.nsItem = nsItem;
+ item.createJNIRef();
+ item.register();
+ nsMenu.insertItem(nsItem, index);
+ if (itemCount == items.length) {
+ MenuItem [] newItems = new MenuItem [items.length + 4];
+ System.arraycopy (items, 0, newItems, 0, items.length);
+ items = newItems;
+ }
+ System.arraycopy (items, index, items, index + 1, itemCount++ - index);
+ items [index] = item;
+ NSMenu emptyMenu = item.createEmptyMenu ();
+ if (emptyMenu != null) {
+ nsItem.setSubmenu (emptyMenu);
+ emptyMenu.release();
+ }
+ if (display.menuBar == this) {
+ NSApplication application = display.application;
+ NSMenu menubar = application.mainMenu();
+ if (menubar != null) {
+ nsItem.setMenu(null);
+ menubar.insertItem(nsItem, index + 1);
+ }
+ }
+ //TODO - find a way to disable the menu instead of each item
+ if (!getEnabled ()) nsItem.setEnabled (false);
+}
+
+void createWidget () {
+ checkOrientation (parent);
+ super.createWidget ();
+ items = new MenuItem [4];
+}
+
+void deregister () {
+ super.deregister ();
+ display.removeWidget (nsMenu);
+}
+
+void destroyItem (MenuItem item) {
+ int index = 0;
+ while (index < itemCount) {
+ if (items [index] == item) break;
+ index++;
+ }
+ if (index == itemCount) return;
+ System.arraycopy (items, index + 1, items, index, --itemCount - index);
+ items [itemCount] = null;
+ if (itemCount == 0) items = new MenuItem [4];
+ nsMenu.removeItem (item.nsItem);
+ if (display.menuBar == this) {
+ NSApplication application = display.application;
+ NSMenu menubar = application.mainMenu();
+ if (menubar != null) {
+ NSMenuItem nsItem = item.nsItem;
+ menubar.removeItem(nsItem);
+ }
+ }
+}
+
+void fixMenus (Decorations newParent) {
+ this.parent = newParent;
+}
+
+/**
+ * Returns the default menu item or null if none has
+ * been previously set.
+ *
+ * @return the default menu item.
+ *
+ * </ul>
+ * @exception SWTException <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 MenuItem getDefaultItem () {
+ checkWidget();
+ return defaultItem;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is enabled, and
+ * <code>false</code> otherwise. A disabled menu is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException <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 #isEnabled
+ */
+public boolean getEnabled () {
+ checkWidget();
+ return (state & DISABLED) == 0;
+}
+
+/**
+ * Returns the item at the given, zero-relative index in the
+ * receiver. Throws an exception if the index is out of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 MenuItem getItem (int index) {
+ checkWidget ();
+ if (!(0 <= index && index < itemCount)) error (SWT.ERROR_INVALID_RANGE);
+ return items [index];
+}
+
+/**
+ * Returns the number of items contained in the receiver.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException <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 getItemCount () {
+ checkWidget ();
+ return itemCount;
+}
+
+/**
+ * Returns a (possibly empty) array of <code>MenuItem</code>s which
+ * are the items in the receiver.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ *
+ * @return the items in the receiver
+ *
+ * @exception SWTException <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 MenuItem [] getItems () {
+ checkWidget ();
+ MenuItem [] result = new MenuItem [itemCount];
+ int index = 0;
+ if (items != null) {
+ for (int i = 0; i < itemCount; i++) {
+ MenuItem item = items [i];
+ if (item != null && !item.isDisposed ()) {
+ result [index++] = item;
+ }
+ }
+ }
+ if (index != result.length) {
+ MenuItem [] newItems = new MenuItem[index];
+ System.arraycopy(result, 0, newItems, 0, index);
+ result = newItems;
+ }
+ return result;
+}
+
+String getNameText () {
+ String result = "";
+ MenuItem [] items = getItems ();
+ int length = items.length;
+ if (length > 0) {
+ for (int i=0; i<length-1; i++) {
+ result = result + items [i].getNameText() + ", ";
+ }
+ result = result + items [length-1].getNameText ();
+ }
+ return result;
+}
+
+/**
+ * Returns the receiver's parent, which must be a <code>Decorations</code>.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException <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 Decorations getParent () {
+ checkWidget ();
+ return parent;
+}
+
+/**
+ * Returns the receiver's parent item, which must be a
+ * <code>MenuItem</code> or null when the receiver is a
+ * root.
+ *
+ * @return the receiver's parent item
+ *
+ * @exception SWTException <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 MenuItem getParentItem () {
+ checkWidget ();
+ return cascade;
+}
+
+/**
+ * Returns the receiver's parent item, which must be a
+ * <code>Menu</code> or null when the receiver is a
+ * root.
+ *
+ * @return the receiver's parent item
+ *
+ * @exception SWTException <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 Menu getParentMenu () {
+ checkWidget ();
+ if (cascade != null) return cascade.parent;
+ return null;
+}
+
+/**
+ * Returns the receiver's shell. For all controls other than
+ * shells, this simply returns the control's nearest ancestor
+ * shell. Shells return themselves, even if they are children
+ * of other shells.
+ *
+ * @return the receiver's shell
+ *
+ * @exception SWTException <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 #getParent
+ */
+public Shell getShell () {
+ checkWidget ();
+ return parent.getShell ();
+}
+
+/**
+ * Returns <code>true</code> if the receiver is visible, and
+ * <code>false</code> otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ * </p>
+ *
+ * @return the receiver's visibility state
+ *
+ * @exception SWTException <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 boolean getVisible () {
+ checkWidget ();
+ if ((style & SWT.BAR) != 0) {
+ return this == parent.menuShell ().menuBar;
+ }
+ if ((style & SWT.POP_UP) != 0) {
+ Menu [] popups = display.popups;
+ if (popups == null) return false;
+ for (int i=0; i<popups.length; i++) {
+ if (popups [i] == this) return true;
+ }
+ }
+ return visible;
+}
+
+/**
+ * Searches the receiver's list starting at the first item
+ * (index 0) until an item is found that is equal to the
+ * argument, and returns the index of that item. If no item
+ * is found, returns -1.
+ *
+ * @param item the search item
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * </ul>
+ * @exception SWTException <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 indexOf (MenuItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ for (int i=0; i<itemCount; i++) {
+ if (items [i] == item) return i;
+ }
+ return -1;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is enabled and all
+ * of the receiver's ancestors are enabled, and <code>false</code>
+ * otherwise. A disabled menu is typically not selectable from the
+ * user interface and draws with an inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException <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 #getEnabled
+ */
+public boolean isEnabled () {
+ checkWidget ();
+ Menu parentMenu = getParentMenu ();
+ if (parentMenu == null) {
+ return getEnabled () && parent.isEnabled ();
+ }
+ return getEnabled () && parentMenu.isEnabled ();
+}
+
+/**
+ * Returns <code>true</code> if the receiver is visible and all
+ * of the receiver's ancestors are visible and <code>false</code>
+ * otherwise.
+ *
+ * @return the receiver's visibility state
+ *
+ * @exception SWTException <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 #getVisible
+ */
+public boolean isVisible () {
+ checkWidget ();
+ return getVisible ();
+}
+
+void menu_willHighlightItem(int /*long*/ id, int /*long*/ sel, int /*long*/ menu, int /*long*/ itemID) {
+ Widget widget = display.getWidget(itemID);
+ if (widget instanceof MenuItem) {
+ MenuItem item = (MenuItem)widget;
+ item.sendEvent (SWT.Arm);
+ }
+}
+
+void menuNeedsUpdate(int /*long*/ id, int /*long*/ sel, int /*long*/ menu) {
+ //This code is intentionally commented
+ //sendEvent (SWT.Show);
+}
+
+void menuWillOpen(int /*long*/ id, int /*long*/ sel, int /*long*/ menu) {
+ visible = true;
+ sendEvent (SWT.Show);
+ for (int i=0; i<items.length; i++) {
+ MenuItem item = items [i];
+ if (item != null) item.updateAccelerator (true);
+ }
+}
+
+void menuDidClose(int /*long*/ id, int /*long*/ sel, int /*long*/ menu) {
+ sendEvent (SWT.Hide);
+ visible = false;
+ for (int i=0; i<items.length; i++) {
+ MenuItem item = items [i];
+ if (item != null) item.updateAccelerator (false);
+ }
+}
+
+void register () {
+ super.register ();
+ display.addWidget (nsMenu, this);
+}
+
+void releaseChildren (boolean destroy) {
+ if (items != null) {
+ for (int i=0; i<items.length; i++) {
+ MenuItem item = items [i];
+ if (item != null && !item.isDisposed ()) {
+ item.release (false);
+ }
+ }
+ items = null;
+ }
+ super.releaseChildren (destroy);
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (nsMenu != null) nsMenu.release();
+ nsMenu = null;
+}
+
+void releaseParent () {
+ super.releaseParent ();
+ if (cascade != null) cascade.setMenu (null);
+ if ((style & SWT.BAR) != 0 && this == parent.menuBar) {
+ parent.setMenuBar (null);
+ }
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ display.removeMenu (this);
+ parent = null;
+ cascade = defaultItem = null;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the help events are generated for the control.
+ *
+ * @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 SWTException <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 HelpListener
+ * @see #addHelpListener
+ */
+public void removeHelpListener (HelpListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Help, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the menu events are generated for the control.
+ *
+ * @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 SWTException <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 MenuListener
+ * @see #addMenuListener
+ */
+public void removeMenuListener (MenuListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Hide, listener);
+ eventTable.unhook (SWT.Show, listener);
+}
+
+/**
+ * Sets the default menu item to the argument or removes
+ * the default emphasis when the argument is <code>null</code>.
+ *
+ * @param item the default menu item or null
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the menu item has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setDefaultItem (MenuItem item) {
+ checkWidget();
+ if (item != null && item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ defaultItem = item;
+}
+
+/**
+ * Enables the receiver if the argument is <code>true</code>,
+ * and disables it otherwise. A disabled menu is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @param enabled the new enabled state
+ *
+ * @exception SWTException <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 setEnabled (boolean enabled) {
+ checkWidget();
+ if (enabled) {
+ state &= ~DISABLED;
+ } else {
+ state |= DISABLED;
+ }
+ //TODO - find a way to disable the menu instead of each item
+ for (int i=0; i<items.length; i++) {
+ MenuItem item = items [i];
+ if (item != null) {
+ /*
+ * Feature in the Macintosh. When a cascade menu
+ * item is disabled, rather than disabling the item,
+ * the submenu is disabled.
+ *
+ * There is no fix for this at this time.
+ */
+ item.nsItem.setEnabled (enabled && item.getEnabled ());
+ }
+ }
+}
+
+/**
+ * Sets the location of the receiver, which must be a popup,
+ * to the point specified by the arguments which are relative
+ * to the display.
+ * <p>
+ * Note that this is different from most widgets where the
+ * location of the widget is relative to the parent.
+ * </p><p>
+ * Note that the platform window manager ultimately has control
+ * over the location of popup menus.
+ * </p>
+ *
+ * @param x the new x coordinate for the receiver
+ * @param y the new y coordinate for the receiver
+ *
+ * @exception SWTException <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 setLocation (int x, int y) {
+ checkWidget ();
+ this.x = x;
+ this.y = y;
+ hasLocation = true;
+}
+
+/**
+ * Sets the location of the receiver, which must be a popup,
+ * to the point specified by the argument which is relative
+ * to the display.
+ * <p>
+ * Note that this is different from most widgets where the
+ * location of the widget is relative to the parent.
+ * </p><p>
+ * Note that the platform window manager ultimately has control
+ * over the location of popup menus.
+ * </p>
+ *
+ * @param location the new location for the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception SWTException <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 2.1
+ */
+public void setLocation (Point location) {
+ checkWidget ();
+ if (location == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setLocation (location.x, location.y);
+}
+
+/**
+ * Marks the receiver as visible if the argument is <code>true</code>,
+ * and marks it invisible otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, marking
+ * it visible may not actually cause it to be displayed.
+ * </p>
+ *
+ * @param visible the new visibility state
+ *
+ * @exception SWTException <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 setVisible (boolean visible) {
+ checkWidget ();
+ if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return;
+ if (visible) {
+ display.addPopup (this);
+ } else {
+ display.removePopup (this);
+ }
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/MenuItem.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/MenuItem.java
new file mode 100755
index 0000000000..d27761b4f8
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/MenuItem.java
@@ -0,0 +1,850 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.events.*;
+
+/**
+ * Instances of this class represent a selectable user interface object
+ * that issues notification when pressed and released.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>CHECK, CASCADE, PUSH, RADIO, SEPARATOR</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Arm, Help, Selection</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles CHECK, CASCADE, PUSH, RADIO and SEPARATOR
+ * 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/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class MenuItem extends Item {
+ NSMenuItem nsItem;
+ Menu parent, menu;
+ int accelerator;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>Menu</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>SWT</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>SWT</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 menu 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 SWTException <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 SWT#CHECK
+ * @see SWT#CASCADE
+ * @see SWT#PUSH
+ * @see SWT#RADIO
+ * @see SWT#SEPARATOR
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public MenuItem (Menu parent, int style) {
+ super (parent, checkStyle (style));
+ this.parent = parent;
+ parent.createItem (this, parent.getItemCount ());
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>Menu</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>SWT</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>SWT</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 menu 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 SWTException <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 SWT#CHECK
+ * @see SWT#CASCADE
+ * @see SWT#PUSH
+ * @see SWT#RADIO
+ * @see SWT#SEPARATOR
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public MenuItem (Menu 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 arm events are generated for the control, by sending
+ * it one of the messages defined in the <code>ArmListener</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 SWTException <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 ArmListener
+ * @see #removeArmListener
+ */
+public void addArmListener (ArmListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Arm, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the help events are generated for the control, by sending
+ * it one of the messages defined in the <code>HelpListener</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 SWTException <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 HelpListener
+ * @see #removeHelpListener
+ */
+public void addHelpListener (HelpListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Help, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the menu item is selected by the user, by sending
+ * it one of the messages defined in the <code>SelectionListener</code>
+ * interface.
+ * <p>
+ * When <code>widgetSelected</code> is called, the stateMask field of the event object is valid.
+ * <code>widgetDefaultSelected</code> is not called.
+ * </p>
+ *
+ * @param listener the listener which should be notified when the menu item is selected by the user
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener(listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+static int checkStyle (int style) {
+ return checkBits (style, SWT.PUSH, SWT.CHECK, SWT.RADIO, SWT.SEPARATOR, SWT.CASCADE, 0);
+}
+
+NSMenu createEmptyMenu () {
+ if ((parent.style & SWT.BAR) != 0) {
+ return (NSMenu) new SWTMenu ().alloc ().init ();
+ }
+ return null;
+}
+
+void deregister () {
+ super.deregister ();
+ display.removeWidget (nsItem);
+}
+
+void destroyWidget () {
+ parent.destroyItem (this);
+ releaseHandle ();
+}
+
+/**
+ * Returns the widget accelerator. An accelerator is the bit-wise
+ * OR of zero or more modifier masks and a key. Examples:
+ * <code>SWT.CONTROL | SWT.SHIFT | 'T', SWT.ALT | SWT.F2</code>.
+ * The default value is zero, indicating that the menu item does
+ * not have an accelerator.
+ *
+ * @return the accelerator or 0
+ *
+ * </ul>
+ * @exception SWTException <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 getAccelerator () {
+ checkWidget ();
+ return accelerator;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is enabled, and
+ * <code>false</code> otherwise. A disabled menu item is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException <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 #isEnabled
+ */
+public boolean getEnabled () {
+ checkWidget();
+ return (state & DISABLED) == 0;
+}
+
+/**
+ * Returns the receiver's cascade menu if it has one or null
+ * if it does not. Only <code>CASCADE</code> menu items can have
+ * a pull down menu. The sequence of key strokes, button presses
+ * and/or button releases that are used to request a pull down
+ * menu is platform specific.
+ *
+ * @return the receiver's menu
+ *
+ * @exception SWTException <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 Menu getMenu () {
+ checkWidget ();
+ return menu;
+}
+
+String getNameText () {
+ if ((style & SWT.SEPARATOR) != 0) return "|";
+ return super.getNameText ();
+}
+
+/**
+ * Returns the receiver's parent, which must be a <code>Menu</code>.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException <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 Menu getParent () {
+ checkWidget ();
+ return parent;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is selected,
+ * and false otherwise.
+ * <p>
+ * When the receiver is of type <code>CHECK</code> or <code>RADIO</code>,
+ * it is selected when it is checked.
+ *
+ * @return the selection state
+ *
+ * @exception SWTException <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 boolean getSelection () {
+ checkWidget ();
+ if ((style & (SWT.CHECK | SWT.RADIO)) == 0) return false;
+ return nsItem.state() == OS.NSOnState;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is enabled and all
+ * of the receiver's ancestors are enabled, and <code>false</code>
+ * otherwise. A disabled menu item is typically not selectable from the
+ * user interface and draws with an inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException <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 #getEnabled
+ */
+public boolean isEnabled () {
+ return getEnabled () && parent.isEnabled ();
+}
+
+int keyChar (int key) {
+ //TODO - use the NS key constants
+ switch (key) {
+ case SWT.BS: return OS.NSBackspaceCharacter;
+ case SWT.CR: return OS.NSCarriageReturnCharacter;
+ case SWT.DEL: return OS.NSDeleteCharacter;
+ case SWT.ESC: return SWT.ESC;
+ case SWT.LF: return OS.NSNewlineCharacter;
+ case SWT.TAB: return OS.NSTabCharacter;
+// case ' ': return OS.kMenuBlankGlyph;
+// case ' ': return OS.kMenuSpaceGlyph;
+ case SWT.ALT: return 0x2325;
+ case SWT.SHIFT: return 0x21E7;
+ case SWT.CONTROL: return 0xF2303;
+ case SWT.COMMAND: return 0x2318;
+ case SWT.ARROW_UP: return 0x2191;
+ case SWT.ARROW_DOWN: return 0x2193;
+ case SWT.ARROW_LEFT: return 0x2190;
+ case SWT.ARROW_RIGHT: return 0x2192;
+ case SWT.PAGE_UP: return 0x21DE;
+ case SWT.PAGE_DOWN: return 0x21DF;
+ case SWT.KEYPAD_CR: return OS.NSEnterCharacter;
+ case SWT.HELP: return OS.NSHelpFunctionKey;
+ case SWT.HOME: return 0xF729;
+ case SWT.END: return 0xF72B;
+// case SWT.CAPS_LOCK: return ??;
+ case SWT.F1: return 0xF704;
+ case SWT.F2: return 0xF705;
+ case SWT.F3: return 0xF706;
+ case SWT.F4: return 0xF707;
+ case SWT.F5: return 0xF708;
+ case SWT.F6: return 0xF709;
+ case SWT.F7: return 0xF70A;
+ case SWT.F8: return 0xF70B;
+ case SWT.F9: return 0xF70C;
+ case SWT.F10: return 0xF70D;
+ case SWT.F11: return 0xF70E;
+ case SWT.F12: return 0xF70F;
+ case SWT.F13: return 0xF710;
+ case SWT.F14: return 0xF711;
+ case SWT.F15: return 0xF712;
+ /*
+ * The following lines are intentionally commented.
+ */
+// case SWT.INSERT: return ??;
+ }
+ return 0;
+}
+
+
+void register () {
+ super.register ();
+ display.addWidget (nsItem, this);
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (nsItem != null) nsItem.release();
+ nsItem = null;
+ parent = null;
+}
+
+void releaseChildren (boolean destroy) {
+ if (menu != null) {
+ menu.release (false);
+ menu = null;
+ }
+ super.releaseChildren (destroy);
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ accelerator = 0;
+ if (this == parent.defaultItem) parent.defaultItem = null;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the arm events are generated for the control.
+ *
+ * @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 SWTException <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 ArmListener
+ * @see #addArmListener
+ */
+public void removeArmListener (ArmListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Arm, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the help events are generated for the control.
+ *
+ * @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 SWTException <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 HelpListener
+ * @see #addHelpListener
+ */
+public void removeHelpListener (HelpListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Help, 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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+void selectRadio () {
+ int index = 0;
+ MenuItem [] items = parent.getItems ();
+ while (index < items.length && items [index] != this) index++;
+ int i = index - 1;
+ while (i >= 0 && items [i].setRadioSelection (false)) --i;
+ int j = index + 1;
+ while (j < items.length && items [j].setRadioSelection (false)) j++;
+ setSelection (true);
+}
+
+void sendSelection () {
+ if ((style & SWT.CHECK) != 0) {
+ setSelection (!getSelection ());
+ } else {
+ if ((style & SWT.RADIO) != 0) {
+ if ((parent.getStyle () & SWT.NO_RADIO_GROUP) != 0) {
+ setSelection (!getSelection ());
+ } else {
+ selectRadio ();
+ }
+ }
+ }
+ Event event = new Event ();
+ NSEvent nsEvent = NSApplication.sharedApplication ().currentEvent ();
+ if (nsEvent != null) setInputState (event, nsEvent, 0);
+ postEvent (SWT.Selection, event);
+}
+
+/**
+ * Sets the widget accelerator. An accelerator is the bit-wise
+ * OR of zero or more modifier masks and a key. Examples:
+ * <code>SWT.MOD1 | SWT.MOD2 | 'T', SWT.MOD3 | SWT.F2</code>.
+ * <code>SWT.CONTROL | SWT.SHIFT | 'T', SWT.ALT | SWT.F2</code>.
+ * The default value is zero, indicating that the menu item does
+ * not have an accelerator.
+ *
+ * @param accelerator an integer that is the bit-wise OR of masks and a key
+ *
+ * </ul>
+ * @exception SWTException <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 setAccelerator (int accelerator) {
+ checkWidget ();
+ if (this.accelerator == accelerator) return;
+ this.accelerator = accelerator;
+ int key = accelerator & SWT.KEY_MASK;
+ int virtualKey = keyChar (key);
+ NSString string = null;
+ if (virtualKey != 0) {
+ string = NSString.stringWith ((char)virtualKey + "");
+ } else {
+ string = NSString.stringWith ((char)key + "");
+ }
+ nsItem.setKeyEquivalent (string.lowercaseString());
+ int mask = 0;
+ if ((accelerator & SWT.SHIFT) != 0) mask |= OS.NSShiftKeyMask;
+ if ((accelerator & SWT.CONTROL) != 0) mask |= OS.NSControlKeyMask;
+ if ((accelerator & SWT.COMMAND) != 0) mask |= OS.NSCommandKeyMask;
+ if ((accelerator & SWT.ALT) != 0) mask |= OS.NSAlternateKeyMask;
+ nsItem.setKeyEquivalentModifierMask (mask);
+}
+
+/**
+ * Enables the receiver if the argument is <code>true</code>,
+ * and disables it otherwise. A disabled menu item is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @param enabled the new enabled state
+ *
+ * @exception SWTException <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 setEnabled (boolean enabled) {
+ checkWidget ();
+ if (enabled) {
+ state &= ~DISABLED;
+ } else {
+ state |= DISABLED;
+ }
+ nsItem.setEnabled(enabled);
+}
+
+/**
+ * Sets the image the receiver will display to the argument.
+ * <p>
+ * Note: This operation is a hint and is not supported on
+ * platforms that do not have this concept (for example, Windows NT).
+ * Furthermore, some platforms (such as GTK), cannot display both
+ * a check box and an image at the same time. Instead, they hide
+ * the image and display the check box.
+ * </p>
+ *
+ * @param image the image to display
+ *
+ * @exception SWTException <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 setImage (Image image) {
+ checkWidget ();
+ if ((style & SWT.SEPARATOR) != 0) return;
+ super.setImage (image);
+ nsItem.setImage(image != null? image.handle : null);
+}
+
+/**
+ * Sets the receiver's pull down menu to the argument.
+ * Only <code>CASCADE</code> menu items can have a
+ * pull down menu. The sequence of key strokes, button presses
+ * and/or button releases that are used to request a pull down
+ * menu is platform specific.
+ * <p>
+ * Note: Disposing of a menu item that has a pull down menu
+ * will dispose of the menu. To avoid this behavior, set the
+ * menu to null before the menu item is disposed.
+ * </p>
+ *
+ * @param menu the new pull down menu
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_MENU_NOT_DROP_DOWN - if the menu is not a drop down menu</li>
+ * <li>ERROR_MENUITEM_NOT_CASCADE - if the menu item is not a <code>CASCADE</code></li>
+ * <li>ERROR_INVALID_ARGUMENT - if the menu has been disposed</li>
+ * <li>ERROR_INVALID_PARENT - if the menu is not in the same widget tree</li>
+ * </ul>
+ * @exception SWTException <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 setMenu (Menu menu) {
+ checkWidget ();
+
+ /* Check to make sure the new menu is valid */
+ if ((style & SWT.CASCADE) == 0) {
+ error (SWT.ERROR_MENUITEM_NOT_CASCADE);
+ }
+ if (menu != null) {
+ if (menu.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ if ((menu.style & SWT.DROP_DOWN) == 0) {
+ error (SWT.ERROR_MENU_NOT_DROP_DOWN);
+ }
+ if (menu.parent != parent.parent) {
+ error (SWT.ERROR_INVALID_PARENT);
+ }
+ }
+ /* Assign the new menu */
+ Menu oldMenu = this.menu;
+ if (oldMenu == menu) return;
+ if (oldMenu != null) oldMenu.cascade = null;
+ this.menu = menu;
+
+ /* Update the menu in the OS */
+ if (menu == null) {
+ NSMenu emptyMenu = createEmptyMenu ();
+ if (emptyMenu != null) {
+ nsItem.setSubmenu (emptyMenu);
+ emptyMenu.release();
+ }
+ } else {
+ menu.cascade = this;
+ nsItem.setSubmenu (menu.nsMenu);
+ }
+
+ if (menu != null) {
+ nsItem.setTarget(null);
+ nsItem.setAction(0);
+ } else {
+ nsItem.setTarget(nsItem);
+ nsItem.setAction(OS.sel_sendSelection);
+ }
+
+ /* Update menu title with parent item title */
+ updateText ();
+}
+
+boolean setRadioSelection (boolean value) {
+ if ((style & SWT.RADIO) == 0) return false;
+ if (getSelection () != value) {
+ setSelection (value);
+ postEvent (SWT.Selection);
+ }
+ return true;
+}
+
+/**
+ * Sets the selection state of the receiver.
+ * <p>
+ * When the receiver is of type <code>CHECK</code> or <code>RADIO</code>,
+ * it is selected when it is checked.
+ *
+ * @param selected the new selection state
+ *
+ * @exception SWTException <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 setSelection (boolean selected) {
+ checkWidget ();
+ if ((style & (SWT.CHECK | SWT.RADIO)) == 0) return;
+ nsItem.setState(selected ? OS.NSOnState : OS.NSOffState);
+}
+
+/**
+ * Sets the receiver's text. The string may include
+ * the mnemonic character and accelerator text.
+ * <p>
+ * Mnemonics are indicated by an '&amp;' that causes the next
+ * character to be the mnemonic. When the user presses a
+ * key sequence that matches the mnemonic, a selection
+ * event occurs. On most platforms, the mnemonic appears
+ * underlined but may be emphasised in a platform specific
+ * manner. The mnemonic indicator character '&amp;' can be
+ * escaped by doubling it in the string, causing a single
+ * '&amp;' to be displayed.
+ * </p>
+ * <p>
+ * Accelerator text is indicated by the '\t' character.
+ * On platforms that support accelerator text, the text
+ * that follows the '\t' character is displayed to the user,
+ * typically indicating the key stroke that will cause
+ * the item to become selected. On most platforms, the
+ * accelerator text appears right aligned in the menu.
+ * Setting the accelerator text does not install the
+ * accelerator key sequence. The accelerator key sequence
+ * is installed using #setAccelerator.
+ * </p>
+ *
+ * @param string the new text
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
+ * </ul>
+ * @exception SWTException <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 #setAccelerator
+ */
+public void setText (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if ((style & SWT.SEPARATOR) != 0) return;
+ if (text.equals (string)) return;
+ super.setText (string);
+ updateText ();
+}
+
+void updateText () {
+ char [] buffer = new char [text.length ()];
+ text.getChars (0, buffer.length, buffer, 0);
+ int i=0, j=0;
+ while (i < buffer.length) {
+ if (buffer [i] == '\t') break;
+ if ((buffer [j++] = buffer [i++]) == '&') {
+ if (i == buffer.length) {continue;}
+ if (buffer [i] == '&') {i++; continue;}
+ j--;
+ }
+ }
+ String text = new String (buffer, 0, j);
+ NSMenu submenu = nsItem.submenu ();
+ NSString label = NSString.stringWith (text);
+ if(submenu != null && (parent.getStyle () & SWT.BAR) != 0) {
+ submenu.setTitle (label);
+ } else {
+ nsItem.setTitle (label);
+ }
+}
+
+void updateAccelerator (boolean show) {
+ if (accelerator != 0) return;
+ int mask = 0, key = 0;
+ if (show) {
+ char [] buffer = new char [text.length ()];
+ text.getChars (0, buffer.length, buffer, 0);
+ int i=0, j=0;
+ while (i < buffer.length) {
+ if (buffer [i] == '\t') break;
+ if ((buffer [j++] = buffer [i++]) == '&') {
+ if (i == buffer.length) {continue;}
+ if (buffer [i] == '&') {i++; continue;}
+ j--;
+ }
+ }
+ if (i < buffer.length && buffer [i] == '\t') {
+ for (j = i + 1; j < buffer.length; j++) {
+ switch (buffer [j]) {
+ case '\u2303': mask |= OS.NSControlKeyMask; i++; break;
+ case '\u2325': mask |= OS.NSAlternateKeyMask; i++; break;
+ case '\u21E7': mask |= OS.NSShiftKeyMask; i++; break;
+ case '\u2318': mask |= OS.NSCommandKeyMask; i++; break;
+ default:
+ j = buffer.length;
+ break;
+ }
+ }
+ switch (buffer.length - i - 1) {
+ case 1:
+ key = buffer [i + 1];
+ if (key == 0x2423) key = ' ';
+ break;
+ case 2:
+ if (buffer [i + 1] == 'F') {
+ switch (buffer [i + 2]) {
+ case '1': key = 0xF704; break;
+ case '2': key = 0xF705; break;
+ case '3': key = 0xF706; break;
+ case '4': key = 0xF707; break;
+ case '5': key = 0xF708; break;
+ case '6': key = 0xF709; break;
+ case '7': key = 0xF70A; break;
+ case '8': key = 0xF70B; break;
+ case '9': key = 0xF70C; break;
+ }
+ }
+ break;
+ case 3:
+ if (buffer [i + 1] == 'F' && buffer [i + 2] == '1') {
+ switch (buffer [i + 3]) {
+ case '0': key = 0xF70D; break;
+ case '1': key = 0xF70E; break;
+ case '2': key = 0xF70F; break;
+ case '3': key = 0xF710; break;
+ case '4': key = 0xF711; break;
+ case '5': key = 0xF712; break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ NSString string = NSString.stringWith (key == 0 ? "" : String.valueOf ((char)key));
+ nsItem.setKeyEquivalentModifierMask (mask);
+ nsItem.setKeyEquivalent (string.lowercaseString ());
+}
+
+}
+
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/MessageBox.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/MessageBox.java
new file mode 100755
index 0000000000..9d0ff92045
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/MessageBox.java
@@ -0,0 +1,331 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class are used to inform or warn the user.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>ICON_ERROR, ICON_INFORMATION, ICON_QUESTION, ICON_WARNING, ICON_WORKING</dd>
+ * <dd>OK, OK | CANCEL</dd>
+ * <dd>YES | NO, YES | NO | CANCEL</dd>
+ * <dd>RETRY | CANCEL</dd>
+ * <dd>ABORT | RETRY | IGNORE</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles ICON_ERROR, ICON_INFORMATION, ICON_QUESTION,
+ * ICON_WARNING and ICON_WORKING may be specified.
+ * </p><p>
+ * IMPORTANT: This class is intended to be subclassed <em>only</em>
+ * within the SWT implementation.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample, Dialog tab</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class MessageBox extends Dialog {
+ String message = "";
+ int returnCode;
+
+/**
+ * Constructs a new instance of this class given only its parent.
+ *
+ * @param parent a shell which will be the parent of the new instance
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <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>
+ */
+public MessageBox (Shell parent) {
+ this (parent, SWT.OK | SWT.ICON_INFORMATION | SWT.APPLICATION_MODAL);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</code> style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ * @param parent a shell which will be the parent of the new instance
+ * @param style the style of dialog to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <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 SWT#ICON_ERROR
+ * @see SWT#ICON_INFORMATION
+ * @see SWT#ICON_QUESTION
+ * @see SWT#ICON_WARNING
+ * @see SWT#ICON_WORKING
+ * @see SWT#OK
+ * @see SWT#CANCEL
+ * @see SWT#YES
+ * @see SWT#NO
+ * @see SWT#ABORT
+ * @see SWT#RETRY
+ * @see SWT#IGNORE
+ */
+public MessageBox (Shell parent, int style) {
+ super (parent, checkStyle (parent, checkStyle (style)));
+ if (Display.getSheetEnabled ()) {
+ if (parent != null && (style & SWT.SHEET) != 0) this.style |= SWT.SHEET;
+ }
+ checkSubclass ();
+}
+
+static int checkStyle (int style) {
+ int mask = (SWT.YES | SWT.NO | SWT.OK | SWT.CANCEL | SWT.ABORT | SWT.RETRY | SWT.IGNORE);
+ int bits = style & mask;
+ if (bits == SWT.OK || bits == SWT.CANCEL || bits == (SWT.OK | SWT.CANCEL)) return style;
+ if (bits == SWT.YES || bits == SWT.NO || bits == (SWT.YES | SWT.NO) || bits == (SWT.YES | SWT.NO | SWT.CANCEL)) return style;
+ if (bits == (SWT.RETRY | SWT.CANCEL) || bits == (SWT.ABORT | SWT.RETRY | SWT.IGNORE)) return style;
+ style = (style & ~mask) | SWT.OK;
+ return style;
+}
+
+/**
+ * Returns the dialog's message, or an empty string if it does not have one.
+ * The message is a description of the purpose for which the dialog was opened.
+ * This message will be visible in the dialog while it is open.
+ *
+ * @return the message
+ */
+public String getMessage () {
+ return message;
+}
+
+/**
+ * Makes the dialog visible and brings it to the front
+ * of the display.
+ *
+ * @return the ID of the button that was selected to dismiss the
+ * message box (e.g. SWT.OK, SWT.CANCEL, etc.)
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the dialog has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the dialog</li>
+ * </ul>
+ */
+public int open () {
+ NSAlert alert = (NSAlert) new NSAlert().alloc().init();
+ int alertType = OS.NSInformationalAlertStyle;
+ if ((style & SWT.ICON_ERROR) != 0) alertType = OS.NSCriticalAlertStyle;
+ if ((style & SWT.ICON_INFORMATION) != 0) alertType = OS.NSInformationalAlertStyle;
+ if ((style & SWT.ICON_QUESTION) != 0) alertType = OS.NSInformationalAlertStyle;
+ if ((style & SWT.ICON_WARNING) != 0) alertType = OS.NSWarningAlertStyle;
+ if ((style & SWT.ICON_WORKING) != 0) alertType = OS.NSInformationalAlertStyle;
+ alert.setAlertStyle(alertType);
+
+ int mask = (SWT.YES | SWT.NO | SWT.OK | SWT.CANCEL | SWT.ABORT | SWT.RETRY | SWT.IGNORE);
+ int bits = style & mask;
+ NSString title;
+ switch (bits) {
+ case SWT.OK:
+ title = NSString.stringWith(SWT.getMessage("SWT_OK"));
+ alert.addButtonWithTitle(title);
+ break;
+ case SWT.CANCEL:
+ title = NSString.stringWith(SWT.getMessage("SWT_Cancel"));
+ alert.addButtonWithTitle(title);
+ break;
+ case SWT.OK | SWT.CANCEL:
+ title = NSString.stringWith(SWT.getMessage("SWT_OK"));
+ alert.addButtonWithTitle(title);
+ title = NSString.stringWith(SWT.getMessage("SWT_Cancel"));
+ alert.addButtonWithTitle(title);
+ break;
+ case SWT.YES:
+ title = NSString.stringWith(SWT.getMessage("SWT_Yes"));
+ alert.addButtonWithTitle(title);
+ break;
+ case SWT.NO:
+ title = NSString.stringWith(SWT.getMessage("SWT_No"));
+ alert.addButtonWithTitle(title);
+ break;
+ case SWT.YES | SWT.NO:
+ title = NSString.stringWith(SWT.getMessage("SWT_Yes"));
+ alert.addButtonWithTitle(title);
+ title = NSString.stringWith(SWT.getMessage("SWT_No"));
+ alert.addButtonWithTitle(title);
+// no.setKeyEquivalent(NSString.stringWith("\033"));
+ break;
+ case SWT.YES | SWT.NO | SWT.CANCEL:
+ title = NSString.stringWith(SWT.getMessage("SWT_Yes"));
+ alert.addButtonWithTitle(title);
+ title = NSString.stringWith(SWT.getMessage("SWT_Cancel"));
+ alert.addButtonWithTitle(title);
+ title = NSString.stringWith(SWT.getMessage("SWT_No"));
+ alert.addButtonWithTitle(title);
+ break;
+ case SWT.RETRY | SWT.CANCEL:
+ title = NSString.stringWith(SWT.getMessage("SWT_Retry"));
+ alert.addButtonWithTitle(title);
+ title = NSString.stringWith(SWT.getMessage("SWT_Cancel"));
+ alert.addButtonWithTitle(title);
+ break;
+ case SWT.ABORT | SWT.RETRY | SWT.IGNORE:
+ title = NSString.stringWith(SWT.getMessage("SWT_Abort"));
+ alert.addButtonWithTitle(title);
+ title = NSString.stringWith(SWT.getMessage("SWT_Ignore"));
+ alert.addButtonWithTitle(title);
+ title = NSString.stringWith(SWT.getMessage("SWT_Retry"));
+ alert.addButtonWithTitle(title);
+ break;
+ }
+ title = NSString.stringWith(this.title != null ? this.title : "");
+ alert.window().setTitle(title);
+ NSString message = NSString.stringWith(this.message != null ? this.message : "");
+ alert.setMessageText(message);
+ int response = 0;
+ int /*long*/ jniRef = 0;
+ SWTPanelDelegate delegate = null;
+ if ((style & SWT.SHEET) != 0) {
+ delegate = (SWTPanelDelegate)new SWTPanelDelegate().alloc().init();
+ jniRef = OS.NewGlobalRef(this);
+ if (jniRef == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.object_setInstanceVariable(delegate.id, Display.SWT_OBJECT, jniRef);
+ alert.beginSheetModalForWindow(parent.window, delegate, OS.sel_panelDidEnd_returnCode_contextInfo_, 0);
+ if ((style & SWT.APPLICATION_MODAL) != 0) {
+ response = (int)/*64*/alert.runModal();
+ } else {
+ this.returnCode = 0;
+ NSWindow window = alert.window();
+ NSApplication application = NSApplication.sharedApplication();
+ while (window.isVisible()) application.run();
+ response = this.returnCode;
+ }
+ } else {
+ response = (int)/*64*/alert.runModal();
+ }
+ if (delegate != null) delegate.release();
+ if (jniRef != 0) OS.DeleteGlobalRef(jniRef);
+ alert.release();
+ switch (bits) {
+ case SWT.OK:
+ switch (response) {
+ case OS.NSAlertFirstButtonReturn:
+ return SWT.OK;
+ }
+ break;
+ case SWT.CANCEL:
+ switch (response) {
+ case OS.NSAlertFirstButtonReturn:
+ return SWT.CANCEL;
+ }
+ break;
+ case SWT.OK | SWT.CANCEL:
+ switch (response) {
+ case OS.NSAlertFirstButtonReturn:
+ return SWT.OK;
+ case OS.NSAlertSecondButtonReturn:
+ return SWT.CANCEL;
+ }
+ break;
+ case SWT.YES:
+ switch (response) {
+ case OS.NSAlertFirstButtonReturn:
+ return SWT.YES;
+ }
+ break;
+ case SWT.NO:
+ switch (response) {
+ case OS.NSAlertFirstButtonReturn:
+ return SWT.NO;
+ }
+ break;
+ case SWT.YES | SWT.NO:
+ switch (response) {
+ case OS.NSAlertFirstButtonReturn:
+ return SWT.YES;
+ case OS.NSAlertSecondButtonReturn:
+ return SWT.NO;
+ }
+ break;
+ case SWT.YES | SWT.NO | SWT.CANCEL:
+ switch (response) {
+ case OS.NSAlertFirstButtonReturn:
+ return SWT.YES;
+ case OS.NSAlertSecondButtonReturn:
+ return SWT.CANCEL;
+ case OS.NSAlertThirdButtonReturn:
+ return SWT.NO;
+ }
+ break;
+ case SWT.RETRY | SWT.CANCEL:
+ switch (response) {
+ case OS.NSAlertFirstButtonReturn:
+ return SWT.RETRY;
+ case OS.NSAlertSecondButtonReturn:
+ return SWT.CANCEL;
+ }
+ break;
+ case SWT.ABORT | SWT.RETRY | SWT.IGNORE:
+ switch (response) {
+ case OS.NSAlertFirstButtonReturn:
+ return SWT.ABORT;
+ case OS.NSAlertSecondButtonReturn:
+ return SWT.IGNORE;
+ case OS.NSAlertThirdButtonReturn:
+ return SWT.RETRY;
+ }
+ break;
+ }
+ return SWT.CANCEL;
+}
+
+void panelDidEnd_returnCode_contextInfo(int /*long*/ id, int /*long*/ sel, int /*long*/ alert, int /*long*/ returnCode, int /*long*/ contextInfo) {
+ this.returnCode = (int)/*64*/returnCode;
+ NSApplication application = NSApplication.sharedApplication();
+ application.endSheet(new NSAlert(alert).window(), returnCode);
+ if ((style & SWT.PRIMARY_MODAL) != 0) {
+ application.stop(null);
+ }
+}
+
+/**
+ * Sets the dialog's message, which is a description of
+ * the purpose for which it was opened. This message will be
+ * visible on the dialog while it is open.
+ *
+ * @param string the message
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ */
+public void setMessage (String string) {
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ message = string;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ProgressBar.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ProgressBar.java
new file mode 100755
index 0000000000..55cd72486f
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ProgressBar.java
@@ -0,0 +1,330 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+import org.eclipse.swt.*;
+
+/**
+ * Instances of the receiver represent an unselectable
+ * user interface object that is used to display progress,
+ * typically in the form of a bar.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>SMOOTH, HORIZONTAL, VERTICAL, INDETERMINATE</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
+ * </p><p>
+ * IMPORTANT: This class is intended to be subclassed <em>only</em>
+ * within the SWT implementation.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#progressbar">ProgressBar snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class ProgressBar extends Control {
+
+ NSBezierPath visiblePath;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#SMOOTH
+ * @see SWT#HORIZONTAL
+ * @see SWT#VERTICAL
+ * @see SWT#INDETERMINATE
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public ProgressBar (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+static int checkStyle (int style) {
+ style |= SWT.NO_FOCUS;
+ return checkBits (style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0);
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget();
+ int size = OS.NSProgressIndicatorPreferredThickness;
+ int width = 0, height = 0;
+ if ((style & SWT.HORIZONTAL) != 0) {
+ height = size;
+ width = height * 10;
+ } else {
+ width = size;
+ height = width * 10;
+ }
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ return new Point (width, height);
+}
+
+void createHandle () {
+ NSProgressIndicator widget = (NSProgressIndicator)new SWTProgressIndicator().alloc();
+ widget.init();
+ widget.setUsesThreadedAnimation(false);
+ widget.setIndeterminate((style & SWT.INDETERMINATE) != 0);
+ view = widget;
+}
+
+NSFont defaultNSFont () {
+ return display.progressIndicatorFont;
+}
+
+void _drawThemeProgressArea (int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ /*
+ * Bug in Cocoa. When the threaded animation is turned off by calling
+ * setUsesThreadedAnimation(), _drawThemeProgressArea() attempts to
+ * access a deallocated NSBitmapGraphicsContext when drawing a zero sized
+ * progress bar. The fix is to avoid calling super when the progress bar
+ * is zero sized.
+ */
+ NSRect frame = view.frame();
+ if (frame.width == 0 || frame.height == 0) return;
+
+ /*
+ * Bug in Cocoa. When the progress bar is animating it calls
+ * _drawThemeProgressArea() directly without taking into account
+ * obscured areas. The fix is to clip the drawing to the visible
+ * region of the progress bar before calling super.
+ */
+ if (visiblePath == null) {
+ int /*long*/ visibleRegion = getVisibleRegion();
+ visiblePath = getPath(visibleRegion);
+ OS.DisposeRgn(visibleRegion);
+ }
+ NSGraphicsContext context = NSGraphicsContext.currentContext();
+ context.saveGraphicsState();
+ visiblePath.setClip();
+ super._drawThemeProgressArea (id, sel, arg0);
+ context.restoreGraphicsState();
+}
+
+/**
+ * Returns the maximum value which the receiver will allow.
+ *
+ * @return the maximum
+ *
+ * @exception SWTException <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 getMaximum () {
+ checkWidget();
+ return (int)((NSProgressIndicator)view).maxValue();
+}
+
+/**
+ * Returns the minimum value which the receiver will allow.
+ *
+ * @return the minimum
+ *
+ * @exception SWTException <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 getMinimum () {
+ checkWidget();
+ return (int)((NSProgressIndicator)view).minValue();
+}
+
+/**
+ * Returns the single 'selection' that is the receiver's position.
+ *
+ * @return the selection
+ *
+ * @exception SWTException <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 getSelection () {
+ checkWidget();
+ return (int)((NSProgressIndicator)view).doubleValue();
+}
+
+/**
+ * Returns the state of the receiver. The value will be one of:
+ * <ul>
+ * <li>{@link SWT#NORMAL}</li>
+ * <li>{@link SWT#ERROR}</li>
+ * <li>{@link SWT#PAUSED}</li>
+ * </ul>
+ *
+ * @return the state
+ *
+ * @exception SWTException <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.4
+ */
+public int getState () {
+ checkWidget ();
+ return SWT.NORMAL;
+}
+
+/**
+ * Sets the maximum value that the receiver will allow. This new
+ * value will be ignored if it is not greater than the receiver's current
+ * minimum value. If the new maximum is applied then the receiver's
+ * selection value will be adjusted if necessary to fall within its new range.
+ *
+ * @param value the new maximum, which must be greater than the current minimum
+ *
+ * @exception SWTException <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 setMaximum (int value) {
+ checkWidget();
+ int minimum = (int)((NSProgressIndicator)view).minValue();
+ if (value <= minimum) return;
+ ((NSProgressIndicator)view).setMaxValue(value);
+ int selection = (int)((NSProgressIndicator)view).doubleValue();
+ int newSelection = Math.min (selection, value);
+ if (selection != newSelection) {
+ ((NSProgressIndicator)view).setDoubleValue(newSelection);
+ }
+}
+
+/**
+ * Sets the minimum value that the receiver will allow. This new
+ * value will be ignored if it is negative or is not less than the receiver's
+ * current maximum value. If the new minimum is applied then the receiver's
+ * selection value will be adjusted if necessary to fall within its new range.
+ *
+ * @param value the new minimum, which must be nonnegative and less than the current maximum
+ *
+ * @exception SWTException <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 setMinimum (int value) {
+ checkWidget();
+ int maximum = (int)((NSProgressIndicator)view).maxValue();
+ if (!(0 <= value && value < maximum)) return;
+ ((NSProgressIndicator)view).setMinValue(value);
+ int selection = (int)((NSProgressIndicator)view).doubleValue();
+ int newSelection = Math.max (selection, value);
+ if (selection != newSelection) {
+ ((NSProgressIndicator)view).setDoubleValue(newSelection);
+ }
+}
+
+/**
+ * Sets the single 'selection' that is the receiver's
+ * position to the argument which must be greater than or equal
+ * to zero.
+ *
+ * @param value the new selection (must be zero or greater)
+ *
+ * @exception SWTException <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 setSelection (int value) {
+ checkWidget();
+ ((NSProgressIndicator)view).setDoubleValue(value);
+ /*
+ * Feature in Cocoa. The progress bar does
+ * not redraw right away when a value is
+ * changed. This is not strictly incorrect
+ * but unexpected. The fix is to force all
+ * outstanding redraws to be delivered.
+ */
+ update(false);
+}
+
+/**
+ * Sets the state of the receiver. The state must be one of these values:
+ * <ul>
+ * <li>{@link SWT#NORMAL}</li>
+ * <li>{@link SWT#ERROR}</li>
+ * <li>{@link SWT#PAUSED}</li>
+ * </ul>
+ *
+ * @param state the new state
+ *
+ * @exception SWTException <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.4
+ */
+public void setState (int state) {
+ checkWidget ();
+ //NOT IMPLEMENTED
+}
+
+void releaseWidget () {
+ super.releaseWidget();
+ if (visiblePath != null) visiblePath.release();
+ visiblePath = null;
+}
+
+void resetVisibleRegion () {
+ super.resetVisibleRegion ();
+ if (visiblePath != null) visiblePath.release();
+ visiblePath = null;
+}
+
+void viewDidMoveToWindow(int /*long*/ id, int /*long*/ sel) {
+ /*
+ * Bug in Cocoa. An indeterminate progress indicator doesn't start animating until it is in
+ * a visible window. Workaround is to catch when the bar has been added to a window and start
+ * the animation there.
+ */
+ if (view.window() != null) {
+ if ((style & SWT.INDETERMINATE) != 0) {
+ ((NSProgressIndicator)view).startAnimation(null);
+ }
+ }
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Sash.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Sash.java
new file mode 100755
index 0000000000..dd1454aab4
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Sash.java
@@ -0,0 +1,478 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.accessibility.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of the receiver represent a selectable user interface object
+ * that allows the user to drag a rubber banded outline of the sash within
+ * the parent control.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>HORIZONTAL, VERTICAL, SMOOTH</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
+ * </p><p>
+ * IMPORTANT: This class is intended to be subclassed <em>only</em>
+ * within the SWT implementation.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#sash">Sash snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Sash extends Control {
+ Cursor sizeCursor;
+ boolean dragging;
+ int lastX, lastY, startX, startY;
+ private final static int INCREMENT = 1;
+ private final static int PAGE_INCREMENT = 9;
+ NSArray accessibilityAttributes = null;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#HORIZONTAL
+ * @see SWT#VERTICAL
+ * @see SWT#SMOOTH
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Sash (Composite parent, int style) {
+ super (parent, checkStyle (style));
+ int cursorStyle = (style & SWT.VERTICAL) != 0 ? SWT.CURSOR_SIZEWE : SWT.CURSOR_SIZENS;
+ sizeCursor = new Cursor (display, cursorStyle);
+}
+
+int /*long*/ accessibilityAttributeNames(int /*long*/ id, int /*long*/ sel) {
+ if (accessibilityAttributes == null) {
+ NSMutableArray ourAttributes = NSMutableArray.arrayWithCapacity(10);
+ ourAttributes.addObject(OS.NSAccessibilityRoleAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityRoleDescriptionAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityParentAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityPositionAttribute);
+ ourAttributes.addObject(OS.NSAccessibilitySizeAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityWindowAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityTopLevelUIElementAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityFocusedAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityValueAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityMaxValueAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityMinValueAttribute);
+ // The accessibility documentation says that these next two are optional, but the
+ // Accessibility Verifier says they are required.
+ ourAttributes.addObject(OS.NSAccessibilityNextContentsAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityPreviousContentsAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityOrientationAttribute);
+
+ if (accessible != null) {
+ // See if the accessible will override or augment the standard list.
+ // Help, title, and description can be overridden.
+ NSMutableArray extraAttributes = NSMutableArray.arrayWithCapacity(3);
+ extraAttributes.addObject(OS.NSAccessibilityHelpAttribute);
+ extraAttributes.addObject(OS.NSAccessibilityDescriptionAttribute);
+ extraAttributes.addObject(OS.NSAccessibilityTitleAttribute);
+
+ for (int i = (int)/*64*/extraAttributes.count() - 1; i >= 0; i--) {
+ NSString attribute = new NSString(extraAttributes.objectAtIndex(i).id);
+ if (accessible.internal_accessibilityAttributeValue(attribute, ACC.CHILDID_SELF) != null) {
+ ourAttributes.addObject(extraAttributes.objectAtIndex(i));
+ }
+ }
+ }
+
+ accessibilityAttributes = ourAttributes;
+ accessibilityAttributes.retain();
+ }
+
+ return accessibilityAttributes.id;
+}
+
+int /*long*/ accessibilityAttributeValue(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ int /*long*/ returnValue = 0;
+ NSString attributeName = new NSString(arg0);
+
+ if (accessible != null) {
+ id returnObject = accessible.internal_accessibilityAttributeValue(attributeName, ACC.CHILDID_SELF);
+
+ if (returnObject != null) returnValue = returnObject.id;
+ }
+
+ if (returnValue != 0) return returnValue;
+
+ if (attributeName.isEqualToString (OS.NSAccessibilityRoleAttribute) || attributeName.isEqualToString (OS.NSAccessibilityRoleDescriptionAttribute)) {
+ NSString roleText = OS.NSAccessibilitySplitterRole;
+
+ if (attributeName.isEqualToString (OS.NSAccessibilityRoleAttribute)) {
+ return roleText.id;
+ } else { // NSAccessibilityRoleDescriptionAttribute
+ return OS.NSAccessibilityRoleDescription (roleText.id, 0);
+ }
+ } else if (attributeName.isEqualToString (OS.NSAccessibilityEnabledAttribute)) {
+ return NSNumber.numberWithBool(isEnabled()).id;
+ } else if (attributeName.isEqualToString (OS.NSAccessibilityOrientationAttribute)) {
+ NSString orientation = (style & SWT.VERTICAL) != 0 ? OS.NSAccessibilityVerticalOrientationValue : OS.NSAccessibilityHorizontalOrientationValue;
+ return orientation.id;
+ } else if (attributeName.isEqualToString (OS.NSAccessibilityValueAttribute)) {
+ Point location = getLocation();
+ int value = (style & SWT.VERTICAL) != 0 ? location.x : location.y;
+ return NSNumber.numberWithInt(value).id;
+ } else if (attributeName.isEqualToString (OS.NSAccessibilityMaxValueAttribute)) {
+ NSRect parentBounds = view.bounds();
+ float /*double*/ maxValue = (style & SWT.VERTICAL) != 0 ?
+ parentBounds.width :
+ parentBounds.height;
+ return NSNumber.numberWithInt((int)maxValue).id;
+ } else if (attributeName.isEqualToString (OS.NSAccessibilityMinValueAttribute)) {
+ return NSNumber.numberWithInt(0).id;
+ } else if (attributeName.isEqualToString (OS.NSAccessibilityNextContentsAttribute)) {
+ Control[] children = parent._getChildren();
+ Control nextView = null;
+ for (int i = 0; i < children.length; i++) {
+ if (children[i] == this) {
+ if (i < children.length - 1) {
+ nextView = children[i + 1];
+ break;
+ }
+ }
+ }
+
+ if (nextView != null)
+ return NSArray.arrayWithObject(nextView.view).id;
+ else
+ return NSArray.array().id;
+ } else if (attributeName.isEqualToString (OS.NSAccessibilityPreviousContentsAttribute)) {
+ Control[] children = parent._getChildren();
+ Control nextView = null;
+ for (int i = 0; i < children.length; i++) {
+ if (children[i] == this) {
+ if (i > 0) {
+ nextView = children[i - 1];
+ break;
+ }
+ }
+ }
+
+ if (nextView != null)
+ return NSArray.arrayWithObject(nextView.view).id;
+ else
+ return NSArray.array().id;
+ }
+
+ return super.accessibilityAttributeValue(id, sel, arg0);
+}
+
+boolean accessibilityIsIgnored(int /*long*/ id, int /*long*/ sel) {
+ return false;
+}
+
+/**
+ * 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>
+ * When <code>widgetSelected</code> is called, the x, y, width, and height fields of the event object are valid.
+ * If the receiver is being dragged, the event object detail field contains the value <code>SWT.DRAG</code>.
+ * <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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener(listener);
+ addListener(SWT.Selection,typedListener);
+ addListener(SWT.DefaultSelection,typedListener);
+}
+
+static int checkStyle (int style) {
+ /*
+ * Macintosh only supports smooth dragging.
+ */
+ style |= SWT.SMOOTH;
+ return checkBits (style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0);
+}
+
+boolean becomeFirstResponder (int /*long*/ id, int /*long*/ sel) {
+ boolean result = super.becomeFirstResponder(id, sel);
+ NSRect frame = view.frame();
+ lastX = (int)frame.x;
+ lastY = (int)frame.y;
+ return result;
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget();
+ int width = 0, height = 0;
+ if ((style & SWT.HORIZONTAL) != 0) {
+ width += DEFAULT_WIDTH; height += 5;
+ } else {
+ width += 5; height += DEFAULT_HEIGHT;
+ }
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ return new Point (width, height);
+}
+
+void createHandle () {
+ state |= THEME_BACKGROUND;
+ NSView widget = (NSView)new SWTView().alloc();
+ widget.init ();
+ view = widget;
+}
+
+void drawBackground (int /*long*/ id, NSGraphicsContext context, NSRect rect) {
+ if (id != view.id) return;
+ fillBackground (view, context, rect, -1);
+}
+
+Cursor findCursor () {
+ Cursor cursor = super.findCursor ();
+ if (cursor == null) {
+ int cursorType = (style & SWT.HORIZONTAL) != 0 ? SWT.CURSOR_SIZENS : SWT.CURSOR_SIZEWE;
+ cursor = display.getSystemCursor (cursorType);
+ }
+ return cursor;
+}
+
+boolean sendKeyEvent(NSEvent nsEvent, int type) {
+ super.sendKeyEvent (nsEvent, type);
+ if (type == SWT.KeyDown) {
+ int keyCode = nsEvent.keyCode();
+ switch (keyCode) {
+ case 126: /* Up arrow */
+ case 123: /* Left arrow */
+ case 125: /* Down arrow */
+ case 124: /* Right arrow */ {
+ int xChange = 0, yChange = 0;
+ int stepSize = PAGE_INCREMENT;
+ int /*long*/ modifiers = nsEvent.modifierFlags();
+ if ((modifiers & OS.NSControlKeyMask) != 0) stepSize = INCREMENT;
+ if ((style & SWT.VERTICAL) != 0) {
+ if (keyCode == 126 || keyCode == 125) break;
+ xChange = keyCode == 123 ? -stepSize : stepSize;
+ } else {
+ if (keyCode == 123 || keyCode == 124) break;
+ yChange = keyCode == 126 ? -stepSize : stepSize;
+ }
+
+ Rectangle bounds = getBounds ();
+ int width = bounds.width, height = bounds.height;
+ Rectangle parentBounds = parent.getBounds ();
+ int parentWidth = parentBounds.width;
+ int parentHeight = parentBounds.height;
+ int newX = lastX, newY = lastY;
+ if ((style & SWT.VERTICAL) != 0) {
+ newX = Math.min (Math.max (0, lastX + xChange), parentWidth - width);
+ } else {
+ newY = Math.min (Math.max (0, lastY + yChange), parentHeight - height);
+ }
+ if (newX == lastX && newY == lastY) return true;
+ Event event = new Event ();
+ event.x = newX;
+ event.y = newY;
+ event.width = width;
+ event.height = height;
+ sendEvent (SWT.Selection, event);
+ if (isDisposed ()) break;
+ if (event.doit) {
+ setBounds (event.x, event.y, width, height);
+ if (isDisposed ()) break;
+ lastX = event.x;
+ lastY = event.y;
+ if (isDisposed ()) return false;
+ int cursorX = event.x, cursorY = event.y;
+ if ((style & SWT.VERTICAL) != 0) {
+ cursorY += height / 2;
+ } else {
+ cursorX += width / 2;
+ }
+ display.setCursorLocation (parent.toDisplay (cursorX, cursorY));
+ }
+ break;
+ }
+ }
+ }
+ return true;
+}
+
+void mouseDown(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ //TODO use sendMouseEvent
+ super.mouseDown(id, sel, theEvent);
+ if (isDisposed()) return;
+ NSEvent nsEvent = new NSEvent(theEvent);
+ if (nsEvent.clickCount() != 1) return;
+ NSPoint location = nsEvent.locationInWindow();
+ NSPoint point = view.convertPoint_fromView_(location, null);
+ startX = (int)point.x;
+ startY = (int)point.y;
+ NSRect frame = view.frame();
+ Event event = new Event ();
+ event.x = (int)frame.x;
+ event.y = (int)frame.y;
+ event.width = (int)frame.width;
+ event.height = (int)frame.height;
+ sendEvent (SWT.Selection, event);
+ if (isDisposed ()) return;
+ if (event.doit) {
+ lastX = event.x;
+ lastY = event.y;
+ dragging = true;
+ setLocation(event.x, event.y);
+ }
+}
+
+boolean mouseEvent (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent, int type) {
+ super.mouseEvent (id, sel, theEvent, type);
+ return new NSEvent (theEvent).type () != OS.NSLeftMouseDown;
+}
+
+void mouseDragged(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ //TODO use sendMouseEvent
+ super.mouseDragged(id, sel, theEvent);
+ if (isDisposed()) return;
+ if (!dragging) return;
+ NSEvent nsEvent = new NSEvent(theEvent);
+ NSPoint location = nsEvent.locationInWindow();
+ NSPoint point = view.convertPoint_fromView_(location, null);
+ NSRect frame = view.frame();
+ NSRect parentFrame = parent.topView().frame();
+ int newX = lastX, newY = lastY;
+ if ((style & SWT.VERTICAL) != 0) {
+ newX = Math.min (Math.max (0, (int)(point.x + frame.x - startX)), (int)(parentFrame.width - frame.width));
+ } else {
+ newY = Math.min (Math.max (0, (int)(point.y + frame.y - startY)), (int)(parentFrame.height - frame.height));
+ }
+ if (newX == lastX && newY == lastY) return;
+ Event event = new Event ();
+ event.x = newX;
+ event.y = newY;
+ event.width = (int)frame.width;
+ event.height = (int)frame.height;
+ sendEvent (SWT.Selection, event);
+ if (isDisposed ()) return;
+ if (event.doit) {
+ lastX = event.x;
+ lastY = event.y;
+ setBounds (event.x, event.y, (int)frame.width, (int)frame.height);
+ }
+}
+
+void mouseUp(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ //TODO use sendMouseEvent
+ super.mouseUp(id, sel, theEvent);
+ if (isDisposed()) return;
+ if (!dragging) return;
+ dragging = false;
+ NSRect frame = view.frame();
+ Event event = new Event ();
+ event.x = lastX;
+ event.y = lastY;
+ event.width = (int)frame.width;
+ event.height = (int)frame.height;
+ sendEvent (SWT.Selection, event);
+ if (isDisposed ()) return;
+ if (event.doit) {
+ setBounds (event.x, event.y, (int)frame.width, (int)frame.height);
+ }
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (accessibilityAttributes != null) accessibilityAttributes.release();
+ accessibilityAttributes = null;
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ if (sizeCursor != null) sizeCursor.dispose ();
+ sizeCursor = null;
+}
+
+/**
+ * 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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook(SWT.Selection, listener);
+ eventTable.unhook(SWT.DefaultSelection,listener);
+}
+
+void superKeyDown (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+}
+
+void superKeyUp (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+}
+
+int traversalCode (int key, NSEvent theEvent) {
+ return 0;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Scale.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Scale.java
new file mode 100755
index 0000000000..2d120fe32d
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Scale.java
@@ -0,0 +1,362 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Instances of the receiver represent a selectable user
+ * interface object that present a range of continuous
+ * numeric values.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>HORIZONTAL, VERTICAL</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
+ * </p><p>
+ * <p>
+ * IMPORTANT: This class is intended to be subclassed <em>only</em>
+ * within the SWT implementation.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#scale">Scale snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Scale extends Control {
+ int increment = 1;
+ int pageIncrement = 10;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#HORIZONTAL
+ * @see SWT#VERTICAL
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Scale (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's value, by sending
+ * it one of the messages defined in the <code>SelectionListener</code>
+ * interface.
+ * <p>
+ * <code>widgetSelected</code> is called when the user changes the receiver's value.
+ * <code>widgetDefaultSelected</code> is not called.
+ * </p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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
+ */
+public void addSelectionListener(SelectionListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener(listener);
+ addListener(SWT.Selection,typedListener);
+ addListener(SWT.DefaultSelection,typedListener);
+}
+
+static int checkStyle (int style) {
+ return checkBits (style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0);
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget();
+ NSSlider widget = (NSSlider)view;
+ float /*double*/ thickness = widget.knobThickness();
+ int width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT;
+ if ((style & SWT.HORIZONTAL) != 0) {
+ height = (int)Math.ceil(thickness);
+ width = height * 10;
+ } else {
+ width = (int)Math.ceil(thickness);
+ height = width * 10;
+ }
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ return new Point (width, height);
+}
+
+void createHandle () {
+ state |= THEME_BACKGROUND;
+ NSSlider widget = (NSSlider)new SWTSlider().alloc();
+ widget.init();
+ widget.setMaxValue(100);
+ widget.setTarget(widget);
+ widget.setAction(OS.sel_sendSelection);
+ view = widget;
+}
+
+NSFont defaultNSFont () {
+ return display.sliderFont;
+}
+
+void deregister() {
+ super.deregister();
+ display.removeWidget(((NSControl)view).cell());
+}
+
+
+/**
+ * Returns the amount that the receiver's value will be
+ * modified by when the up/down (or right/left) arrows
+ * are pressed.
+ *
+ * @return the increment
+ *
+ * @exception SWTException <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 getIncrement () {
+ checkWidget();
+ return increment;
+}
+
+/**
+ * Returns the maximum value which the receiver will allow.
+ *
+ * @return the maximum
+ *
+ * @exception SWTException <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 getMaximum () {
+ checkWidget();
+ return (int)((NSSlider)view).maxValue();
+}
+
+/**
+ * Returns the minimum value which the receiver will allow.
+ *
+ * @return the minimum
+ *
+ * @exception SWTException <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 getMinimum () {
+ checkWidget();
+ return (int)((NSSlider)view).minValue();
+}
+
+/**
+ * Returns the amount that the receiver's value will be
+ * modified by when the page increment/decrement areas
+ * are selected.
+ *
+ * @return the page increment
+ *
+ * @exception SWTException <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 getPageIncrement () {
+ checkWidget();
+ return pageIncrement;
+}
+
+/**
+ * Returns the 'selection', which is the receiver's position.
+ *
+ * @return the selection
+ *
+ * @exception SWTException <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 getSelection () {
+ checkWidget();
+ return (int)((NSSlider)view).doubleValue();
+}
+
+void register() {
+ super.register();
+ display.addWidget(((NSControl)view).cell(), this);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the user changes the receiver's value.
+ *
+ * @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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook(SWT.Selection, listener);
+ eventTable.unhook(SWT.DefaultSelection,listener);
+}
+
+void sendSelection () {
+ NSEvent currEvent = NSApplication.sharedApplication().currentEvent();
+
+ if (currEvent.type() != OS.NSLeftMouseUp)
+ postEvent (SWT.Selection);
+}
+
+/**
+ * Sets the amount that the receiver's value will be
+ * modified by when the up/down (or right/left) arrows
+ * are pressed to the argument, which must be at least
+ * one.
+ *
+ * @param increment the new increment (must be greater than zero)
+ *
+ * @exception SWTException <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 setIncrement (int value) {
+ checkWidget();
+ if (value < 1) return;
+ increment = value;
+}
+
+/**
+ * Sets the maximum value that the receiver will allow. This new
+ * value will be ignored if it is not greater than the receiver's current
+ * minimum value. If the new maximum is applied then the receiver's
+ * selection value will be adjusted if necessary to fall within its new range.
+ *
+ * @param value the new maximum, which must be greater than the current minimum
+ *
+ * @exception SWTException <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 setMaximum (int value) {
+ checkWidget();
+ int minimum = (int)((NSSlider)view).minValue();
+ if (value <= minimum) return;
+ ((NSSlider)view).setMaxValue(value);
+}
+
+/**
+ * Sets the minimum value that the receiver will allow. This new
+ * value will be ignored if it is negative or is not less than the receiver's
+ * current maximum value. If the new minimum is applied then the receiver's
+ * selection value will be adjusted if necessary to fall within its new range.
+ *
+ * @param value the new minimum, which must be nonnegative and less than the current maximum
+ *
+ * @exception SWTException <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 setMinimum (int value) {
+ checkWidget();
+ int maximum = (int)((NSSlider)view).maxValue();
+ if (!(0 <= value && value < maximum)) return;
+ ((NSSlider)view).setMinValue(value);
+}
+
+/**
+ * Sets the amount that the receiver's value will be
+ * modified by when the page increment/decrement areas
+ * are selected to the argument, which must be at least
+ * one.
+ *
+ * @param pageIncrement the page increment (must be greater than zero)
+ *
+ * @exception SWTException <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 setPageIncrement (int value) {
+ checkWidget();
+ if (value < 1) return;
+ pageIncrement = value;
+}
+
+/**
+ * Sets the 'selection', which is the receiver's value,
+ * to the argument which must be greater than or equal to zero.
+ *
+ * @param value the new selection (must be zero or greater)
+ *
+ * @exception SWTException <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 setSelection (int value) {
+ checkWidget();
+ ((NSSlider)view).setDoubleValue(value);
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ScrollBar.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ScrollBar.java
new file mode 100755
index 0000000000..2a9fee54bd
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ScrollBar.java
@@ -0,0 +1,685 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Instances of this class are selectable user interface
+ * objects that represent a range of positive, numeric values.
+ * <p>
+ * At any given moment, a given scroll bar will have a
+ * single 'selection' that is considered to be its
+ * value, which is constrained to be within the range of
+ * values the scroll bar represents (that is, between its
+ * <em>minimum</em> and <em>maximum</em> values).
+ * </p><p>
+ * Typically, scroll bars will be made up of five areas:
+ * <ol>
+ * <li>an arrow button for decrementing the value</li>
+ * <li>a page decrement area for decrementing the value by a larger amount</li>
+ * <li>a <em>thumb</em> for modifying the value by mouse dragging</li>
+ * <li>a page increment area for incrementing the value by a larger amount</li>
+ * <li>an arrow button for incrementing the value</li>
+ * </ol>
+ * Based on their style, scroll bars are either <code>HORIZONTAL</code>
+ * (which have a left facing button for decrementing the value and a
+ * right facing button for incrementing it) or <code>VERTICAL</code>
+ * (which have an upward facing button for decrementing the value
+ * and a downward facing buttons for incrementing it).
+ * </p><p>
+ * On some platforms, the size of the scroll bar's thumb can be
+ * varied relative to the magnitude of the range of values it
+ * represents (that is, relative to the difference between its
+ * maximum and minimum values). Typically, this is used to
+ * indicate some proportional value such as the ratio of the
+ * visible area of a document to the total amount of space that
+ * it would take to display it. SWT supports setting the thumb
+ * size even if the underlying platform does not, but in this
+ * case the appearance of the scroll bar will not change.
+ * </p><p>
+ * Scroll bars are created by specifying either <code>H_SCROLL</code>,
+ * <code>V_SCROLL</code> or both when creating a <code>Scrollable</code>.
+ * They are accessed from the <code>Scrollable</code> using
+ * <code>getHorizontalBar</code> and <code>getVerticalBar</code>.
+ * </p><p>
+ * Note: Scroll bars are not Controls. On some platforms, scroll bars
+ * that appear as part of some standard controls such as a text or list
+ * have no operating system resources and are not children of the control.
+ * For this reason, scroll bars are treated specially. To create a control
+ * that looks like a scroll bar but has operating system resources, use
+ * <code>Slider</code>.
+ * </p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>HORIZONTAL, VERTICAL</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
+ * </p><p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ *
+ * @see Slider
+ * @see Scrollable
+ * @see Scrollable#getHorizontalBar
+ * @see Scrollable#getVerticalBar
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class ScrollBar extends Widget {
+ NSScroller view;
+ Scrollable parent;
+ int minimum, maximum = 100, thumb = 10;
+ int increment = 1;
+ int pageIncrement = 10;
+ id target;
+ int /*long*/ actionSelector;;
+
+ScrollBar () {
+ /* Do nothing */
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's value, by sending
+ * it one of the messages defined in the <code>SelectionListener</code>
+ * interface.
+ * <p>
+ * When <code>widgetSelected</code> is called, the event object detail field contains one of the following values:
+ * <code>SWT.NONE</code> - for the end of a drag.
+ * <code>SWT.DRAG</code>.
+ * <code>SWT.HOME</code>.
+ * <code>SWT.END</code>.
+ * <code>SWT.ARROW_DOWN</code>.
+ * <code>SWT.ARROW_UP</code>.
+ * <code>SWT.PAGE_DOWN</code>.
+ * <code>SWT.PAGE_UP</code>.
+ * <code>widgetDefaultSelected</code> is not called.
+ * </p>
+ *
+ * @param listener the listener which should be notified when the user changes the receiver's value
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener(listener);
+ addListener(SWT.Selection,typedListener);
+ addListener(SWT.DefaultSelection,typedListener);
+}
+
+static int checkStyle (int style) {
+ return checkBits (style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0);
+}
+
+void deregister () {
+ super.deregister ();
+ display.removeWidget (view);
+}
+
+boolean getDrawing () {
+ return parent.getDrawing ();
+}
+
+/**
+ * Returns <code>true</code> if the receiver is enabled, and
+ * <code>false</code> otherwise. A disabled control is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException <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 #isEnabled
+ */
+public boolean getEnabled () {
+ checkWidget();
+ return (state & DISABLED) == 0;
+}
+
+/**
+ * Returns the amount that the receiver's value will be
+ * modified by when the up/down (or right/left) arrows
+ * are pressed.
+ *
+ * @return the increment
+ *
+ * @exception SWTException <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 getIncrement () {
+ checkWidget();
+ return increment;
+}
+
+/**
+ * Returns the maximum value which the receiver will allow.
+ *
+ * @return the maximum
+ *
+ * @exception SWTException <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 getMaximum () {
+ checkWidget();
+ return maximum;
+}
+
+/**
+ * Returns the minimum value which the receiver will allow.
+ *
+ * @return the minimum
+ *
+ * @exception SWTException <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 getMinimum () {
+ checkWidget();
+ return minimum;
+}
+
+/**
+ * Returns the amount that the receiver's value will be
+ * modified by when the page increment/decrement areas
+ * are selected.
+ *
+ * @return the page increment
+ *
+ * @exception SWTException <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 getPageIncrement () {
+ checkWidget();
+ return pageIncrement;
+}
+
+/**
+ * Returns the receiver's parent, which must be a Scrollable.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException <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 Scrollable getParent () {
+ checkWidget ();
+ return parent;
+}
+
+/**
+ * Returns the single 'selection' that is the receiver's value.
+ *
+ * @return the selection
+ *
+ * @exception SWTException <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 getSelection () {
+ checkWidget();
+ NSScroller widget = (NSScroller)view;
+ double value = widget.doubleValue();
+ return (int)(0.5f + ((maximum - thumb - minimum) * value + minimum));
+}
+
+/**
+ * Returns a point describing the receiver's size. The
+ * x coordinate of the result is the width of the receiver.
+ * The y coordinate of the result is the height of the
+ * receiver.
+ *
+ * @return the receiver's size
+ *
+ * @exception SWTException <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 Point getSize () {
+ checkWidget();
+ NSRect rect = ((NSScroller)view).frame();
+ return new Point((int)rect.width, (int)rect.height);
+}
+
+/**
+ * Returns the size of the receiver's thumb relative to the
+ * difference between its maximum and minimum values.
+ *
+ * @return the thumb value
+ *
+ * @exception SWTException <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 ScrollBar
+ */
+public int getThumb () {
+ checkWidget();
+ return thumb;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is visible, and
+ * <code>false</code> otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ * </p>
+ *
+ * @return the receiver's visibility state
+ *
+ * @exception SWTException <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 boolean getVisible () {
+ checkWidget();
+ return (state & HIDDEN) == 0;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is enabled and all
+ * of the receiver's ancestors are enabled, and <code>false</code>
+ * otherwise. A disabled control is typically not selectable from the
+ * user interface and draws with an inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException <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 #getEnabled
+ */
+public boolean isEnabled () {
+ checkWidget();
+ return getEnabled () && parent.isEnabled ();
+}
+
+boolean isDrawing () {
+ return getDrawing() && parent.isDrawing ();
+}
+
+/**
+ * Returns <code>true</code> if the receiver is visible and all
+ * of the receiver's ancestors are visible and <code>false</code>
+ * otherwise.
+ *
+ * @return the receiver's visibility state
+ *
+ * @exception SWTException <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 #getVisible
+ */
+public boolean isVisible () {
+ checkWidget();
+ return getVisible () && parent.isVisible ();
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the user changes the receiver's value.
+ *
+ * @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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook(SWT.Selection, listener);
+ eventTable.unhook(SWT.DefaultSelection,listener);
+}
+
+void register () {
+ super.register ();
+ display.addWidget (view, this);
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (view != null) view.release();
+ view = null;
+}
+
+void releaseParent () {
+ super.releaseParent ();
+ if (parent.horizontalBar == this) parent.horizontalBar = null;
+ if (parent.verticalBar == this) parent.verticalBar = null;
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ parent = null;
+}
+
+void sendSelection () {
+ int value = 0;
+ if (target != null) {
+ view.sendAction(actionSelector, target);
+ } else {
+ value = getSelection ();
+ }
+ Event event = new Event();
+ int hitPart = (int)/*64*/((NSScroller)view).hitPart();
+ switch (hitPart) {
+ case OS.NSScrollerDecrementLine:
+ value -= increment;
+ event.detail = SWT.ARROW_UP;
+ break;
+ case OS.NSScrollerDecrementPage:
+ value -= pageIncrement;
+ event.detail = SWT.PAGE_UP;
+ break;
+ case OS.NSScrollerIncrementLine:
+ value += increment;
+ event.detail = SWT.ARROW_DOWN;
+ break;
+ case OS.NSScrollerIncrementPage:
+ value += pageIncrement;
+ event.detail = SWT.PAGE_DOWN;
+ break;
+ case OS.NSScrollerKnob:
+ event.detail = SWT.DRAG;
+ break;
+ }
+ if (target == null) {
+ if (event.detail != SWT.DRAG) {
+ setSelection(value);
+ }
+ }
+ sendEvent(SWT.Selection, event);
+}
+
+/**
+ * Sets the amount that the receiver's value will be
+ * modified by when the up/down (or right/left) arrows
+ * are pressed to the argument, which must be at least
+ * one.
+ *
+ * @param value the new increment (must be greater than zero)
+ *
+ * @exception SWTException <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 setIncrement (int value) {
+ checkWidget();
+ if (value < 1) return;
+ increment = value;
+}
+
+void setClipRegion (float /*double*/ x, float /*double*/ y) {
+ NSRect frame = view.frame();
+ parent.setClipRegion(frame.x + x, frame.y + y);
+}
+
+/**
+ * Enables the receiver if the argument is <code>true</code>,
+ * and disables it otherwise. A disabled control is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @param enabled the new enabled state
+ *
+ * @exception SWTException <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 setEnabled (boolean enabled) {
+ checkWidget();
+ if (enabled) {
+ if ((state & DISABLED) == 0) return;
+ state &= ~DISABLED;
+ } else {
+ if ((state & DISABLED) != 0) return;
+ state |= DISABLED;
+ }
+ enableWidget (enabled);
+}
+
+void enableWidget (boolean enabled) {
+ if (!enabled || (state & DISABLED) == 0) {
+ view.setEnabled (enabled);
+ }
+}
+
+/**
+ * Sets the maximum. If this value is negative or less than or
+ * equal to the minimum, the value is ignored. If necessary, first
+ * the thumb and then the selection are adjusted to fit within the
+ * new range.
+ *
+ * @param value the new maximum
+ *
+ * @exception SWTException <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 setMaximum (int value) {
+ checkWidget();
+ if (value < 0) return;
+ if (value <= minimum) return;
+ if (value - minimum < thumb) {
+ thumb = value - minimum;
+ }
+ int selection = Math.max(minimum, Math.min (getSelection (), value - thumb));
+ this.maximum = value;
+ updateBar(selection, minimum, value, thumb);
+}
+
+/**
+ * Sets the minimum value. If this value is negative or greater
+ * than or equal to the maximum, the value is ignored. If necessary,
+ * first the thumb and then the selection are adjusted to fit within
+ * the new range.
+ *
+ * @param value the new minimum
+ *
+ * @exception SWTException <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 setMinimum (int value) {
+ checkWidget();
+ if (value < 0) return;
+ if (value >= maximum) return;
+ if (maximum - value < thumb) {
+ thumb = maximum - value;
+ }
+ int selection = Math.min(maximum - thumb, Math.max (getSelection (), value));
+ this.minimum = value;
+ updateBar(selection, value, maximum, thumb);
+}
+
+/**
+ * Sets the amount that the receiver's value will be
+ * modified by when the page increment/decrement areas
+ * are selected to the argument, which must be at least
+ * one.
+ *
+ * @param value the page increment (must be greater than zero)
+ *
+ * @exception SWTException <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 setPageIncrement (int value) {
+ checkWidget();
+ if (value < 1) return;
+ pageIncrement = value;
+}
+
+/**
+ * Sets the single <em>selection</em> that is the receiver's
+ * value to the argument which must be greater than or equal
+ * to zero.
+ *
+ * @param selection the new selection (must be zero or greater)
+ *
+ * @exception SWTException <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 setSelection (int value) {
+ checkWidget();
+ updateBar(value, minimum, maximum, thumb);
+}
+
+/**
+ * Sets the size of the receiver's thumb relative to the
+ * difference between its maximum and minimum values. This new
+ * value will be ignored if it is less than one, and will be
+ * clamped if it exceeds the receiver's current range.
+ *
+ * @param value the new thumb value, which must be at least one and not
+ * larger than the size of the current range
+ *
+ * @exception SWTException <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 setThumb (int value) {
+ checkWidget();
+ if (value < 1) return;
+ value = Math.min (value, maximum - minimum);
+ updateBar(getSelection(), minimum, maximum, value);
+ this.thumb = value;
+}
+
+/**
+ * Sets the receiver's selection, minimum value, maximum
+ * value, thumb, increment and page increment all at once.
+ * <p>
+ * Note: This is similar to setting the values individually
+ * using the appropriate methods, but may be implemented in a
+ * more efficient fashion on some platforms.
+ * </p>
+ *
+ * @param selection the new selection value
+ * @param minimum the new minimum value
+ * @param maximum the new maximum value
+ * @param thumb the new thumb value
+ * @param increment the new increment value
+ * @param pageIncrement the new pageIncrement value
+ *
+ * @exception SWTException <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 setValues (int selection, int minimum, int maximum, int thumb, int increment, int pageIncrement) {
+ checkWidget();
+ if (minimum < 0) return;
+ if (maximum < 0) return;
+ if (thumb < 1) return;
+ if (increment < 1) return;
+ if (pageIncrement < 1) return;
+ this.thumb = thumb = Math.min (thumb, maximum - minimum);
+ this.maximum = maximum;
+ this.minimum = minimum;
+ this.increment = increment;
+ this.pageIncrement = pageIncrement;
+ updateBar (selection, minimum, maximum, thumb);
+}
+
+/**
+ * Marks the receiver as visible if the argument is <code>true</code>,
+ * and marks it invisible otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, marking
+ * it visible may not actually cause it to be displayed.
+ * </p>
+ *
+ * @param visible the new visibility state
+ *
+ * @exception SWTException <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 setVisible (boolean visible) {
+ checkWidget();
+ parent.setScrollBarVisible (this, visible);
+}
+
+void updateBar (int selection, int minimum, int maximum, int thumb) {
+ NSScroller widget = (NSScroller) view;
+ selection = Math.max (minimum, Math.min (maximum - thumb, selection));
+ int range = maximum - thumb - minimum;
+ float fraction = range <= 0 ? 1 : (float) (selection - minimum) / range;
+ float knob = range <= 0 ? 1 : (float) thumb / (maximum - minimum);
+ widget.setFloatValue (fraction, knob);
+ widget.setEnabled (range > 0);
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Scrollable.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Scrollable.java
new file mode 100755
index 0000000000..50e08c80ba
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Scrollable.java
@@ -0,0 +1,335 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * This class is the abstract superclass of all classes which
+ * represent controls that have standard scroll bars.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>H_SCROLL, V_SCROLL</dd>
+ * <dt><b>Events:</b>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * IMPORTANT: This class is intended to be subclassed <em>only</em>
+ * within the SWT implementation.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public abstract class Scrollable extends Control {
+ NSScrollView scrollView;
+ ScrollBar horizontalBar, verticalBar;
+
+Scrollable () {
+ /* Do nothing */
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#H_SCROLL
+ * @see SWT#V_SCROLL
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Scrollable (Composite parent, int style) {
+ super (parent, style);
+}
+
+boolean accessibilityIsIgnored(int /*long*/ id, int /*long*/ sel) {
+ // Always ignore scrollers.
+ if (scrollView != null && id == scrollView.id) return true;
+ return super.accessibilityIsIgnored(id, sel);
+}
+
+/**
+ * Given a desired <em>client area</em> for the receiver
+ * (as described by the arguments), returns the bounding
+ * rectangle which would be required to produce that client
+ * area.
+ * <p>
+ * In other words, it returns a rectangle such that, if the
+ * receiver's bounds were set to that rectangle, the area
+ * of the receiver which is capable of displaying data
+ * (that is, not covered by the "trimmings") would be the
+ * rectangle described by the arguments (relative to the
+ * receiver's parent).
+ * </p>
+ *
+ * @param x the desired x coordinate of the client area
+ * @param y the desired y coordinate of the client area
+ * @param width the desired width of the client area
+ * @param height the desired height of the client area
+ * @return the required bounds to produce the given client area
+ *
+ * @exception SWTException <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 #getClientArea
+ */
+public Rectangle computeTrim (int x, int y, int width, int height) {
+ checkWidget();
+ if (scrollView != null) {
+ NSSize size = new NSSize();
+ size.width = width;
+ size.height = height;
+ int border = hasBorder() ? OS.NSBezelBorder : OS.NSNoBorder;
+ size = NSScrollView.frameSizeForContentSize(size, (style & SWT.H_SCROLL) != 0, (style & SWT.V_SCROLL) != 0, border);
+ width = (int)size.width;
+ height = (int)size.height;
+ NSRect frame = scrollView.contentView().frame();
+ x -= frame.x;
+ y -= frame.y;
+ }
+ return new Rectangle (x, y, width, height);
+}
+
+ScrollBar createScrollBar (int style) {
+ if (scrollView == null) return null;
+ ScrollBar bar = new ScrollBar ();
+ bar.parent = this;
+ bar.style = style;
+ bar.display = display;
+ NSScroller scroller;
+ int /*long*/ actionSelector;
+ NSRect rect = new NSRect();
+ if ((style & SWT.H_SCROLL) != 0) {
+ rect.width = 1;
+ } else {
+ rect.height = 1;
+ }
+ scroller = (NSScroller)new SWTScroller().alloc();
+ scroller.initWithFrame(rect);
+ if ((style & SWT.H_SCROLL) != 0) {
+ scrollView.setHorizontalScroller(scroller);
+ actionSelector = OS.sel_sendHorizontalSelection;
+ } else {
+ scrollView.setVerticalScroller(scroller);
+ actionSelector = OS.sel_sendVerticalSelection;
+ }
+ bar.view = scroller;
+ bar.createJNIRef();
+ bar.register();
+ if ((state & CANVAS) == 0) {
+ bar.target = scroller.target();
+ bar.actionSelector = scroller.action();
+ }
+ scroller.setTarget(scrollView);
+ scroller.setAction(actionSelector);
+ if ((state & CANVAS) != 0) {
+ bar.updateBar(0, 0, 100, 10);
+ }
+ return bar;
+}
+
+void createWidget () {
+ super.createWidget ();
+ if ((style & SWT.H_SCROLL) != 0) horizontalBar = createScrollBar (SWT.H_SCROLL);
+ if ((style & SWT.V_SCROLL) != 0) verticalBar = createScrollBar (SWT.V_SCROLL);
+}
+
+void deregister () {
+ super.deregister ();
+ if (scrollView != null) display.removeWidget (scrollView);
+}
+
+/**
+ * Returns a rectangle which describes the area of the
+ * receiver which is capable of displaying data (that is,
+ * not covered by the "trimmings").
+ *
+ * @return the client area
+ *
+ * @exception SWTException <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 #computeTrim
+ */
+public Rectangle getClientArea () {
+ checkWidget();
+ if (scrollView != null) {
+ NSSize size = scrollView.contentSize();
+ NSClipView contentView = scrollView.contentView();
+ NSRect bounds = contentView.bounds();
+ return new Rectangle((int)bounds.x, (int)bounds.y, (int)size.width, (int)size.height);
+ } else {
+ NSRect rect = view.bounds();
+ return new Rectangle(0, 0, (int)rect.width, (int)rect.height);
+ }
+}
+
+/**
+ * Returns the receiver's horizontal scroll bar if it has
+ * one, and null if it does not.
+ *
+ * @return the horizontal scroll bar (or null)
+ *
+ * @exception SWTException <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 ScrollBar getHorizontalBar () {
+ checkWidget();
+ return horizontalBar;
+}
+
+/**
+ * Returns the receiver's vertical scroll bar if it has
+ * one, and null if it does not.
+ *
+ * @return the vertical scroll bar (or null)
+ *
+ * @exception SWTException <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 ScrollBar getVerticalBar () {
+ checkWidget();
+ return verticalBar;
+}
+
+boolean hooksKeys () {
+ return hooks (SWT.KeyDown) || hooks (SWT.KeyUp) || hooks (SWT.Traverse);
+}
+
+boolean isEventView (int /*long*/ id) {
+ return id == eventView ().id;
+}
+
+boolean isTrim (NSView view) {
+ if (scrollView != null) {
+ if (scrollView.id == view.id) return true;
+ if (horizontalBar != null && horizontalBar.view.id == view.id) return true;
+ if (verticalBar != null && verticalBar.view.id == view.id) return true;
+ }
+ return super.isTrim (view);
+}
+
+void register () {
+ super.register ();
+ if (scrollView != null) display.addWidget (scrollView, this);
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (scrollView != null) scrollView.release();
+ scrollView = null;
+}
+
+void releaseChildren (boolean destroy) {
+ if (horizontalBar != null) {
+ horizontalBar.release (false);
+ horizontalBar = null;
+ }
+ if (verticalBar != null) {
+ verticalBar.release (false);
+ verticalBar = null;
+ }
+ super.releaseChildren (destroy);
+}
+
+void sendHorizontalSelection () {
+ if (horizontalBar.view.isHiddenOrHasHiddenAncestor()) return;
+ if ((state & CANVAS) == 0 && scrollView != null && visibleRgn == 0) {
+ scrollView.contentView().setCopiesOnScroll(!isObscured());
+ }
+ horizontalBar.sendSelection ();
+}
+
+void sendVerticalSelection () {
+ if (verticalBar.view.isHiddenOrHasHiddenAncestor()) return;
+ if ((state & CANVAS) == 0 && scrollView != null && visibleRgn == 0) {
+ scrollView.contentView().setCopiesOnScroll(!isObscured());
+ }
+ verticalBar.sendSelection ();
+}
+
+void enableWidget (boolean enabled) {
+ super.enableWidget (enabled);
+ if (horizontalBar != null) horizontalBar.enableWidget (enabled);
+ if (verticalBar != null) verticalBar.enableWidget (enabled);
+}
+
+boolean setScrollBarVisible (ScrollBar bar, boolean visible) {
+ if (scrollView == null) return false;
+ if ((state & CANVAS) == 0) return false;
+ if (visible) {
+ if ((bar.state & HIDDEN) == 0) return false;
+ bar.state &= ~HIDDEN;
+ } else {
+ if ((bar.state & HIDDEN) != 0) return false;
+ bar.state |= HIDDEN;
+ }
+ if ((bar.style & SWT.HORIZONTAL) != 0) {
+ scrollView.setHasHorizontalScroller (visible);
+ } else {
+ scrollView.setHasVerticalScroller (visible);
+ }
+ bar.sendEvent (visible ? SWT.Show : SWT.Hide);
+ sendEvent (SWT.Resize);
+ return true;
+}
+
+void setZOrder () {
+ super.setZOrder ();
+ if (scrollView != null) scrollView.setDocumentView (view);
+}
+
+NSView topView () {
+ if (scrollView != null) return scrollView;
+ return super.topView ();
+}
+
+void updateCursorRects (boolean enabled) {
+ super.updateCursorRects (enabled);
+ if (scrollView == null) return;
+ updateCursorRects (enabled, scrollView);
+ NSClipView contentView = scrollView.contentView ();
+ updateCursorRects (enabled, contentView);
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Shell.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Shell.java
new file mode 100755
index 0000000000..3c2f2e66b3
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Shell.java
@@ -0,0 +1,1829 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class represent the "windows"
+ * which the desktop or "window manager" is managing.
+ * Instances that do not have a parent (that is, they
+ * are built using the constructor, which takes a
+ * <code>Display</code> as the argument) are described
+ * as <em>top level</em> shells. Instances that do have
+ * a parent are described as <em>secondary</em> or
+ * <em>dialog</em> shells.
+ * <p>
+ * Instances are always displayed in one of the maximized,
+ * minimized or normal states:
+ * <ul>
+ * <li>
+ * When an instance is marked as <em>maximized</em>, the
+ * window manager will typically resize it to fill the
+ * entire visible area of the display, and the instance
+ * is usually put in a state where it can not be resized
+ * (even if it has style <code>RESIZE</code>) until it is
+ * no longer maximized.
+ * </li><li>
+ * When an instance is in the <em>normal</em> state (neither
+ * maximized or minimized), its appearance is controlled by
+ * the style constants which were specified when it was created
+ * and the restrictions of the window manager (see below).
+ * </li><li>
+ * When an instance has been marked as <em>minimized</em>,
+ * its contents (client area) will usually not be visible,
+ * and depending on the window manager, it may be
+ * "iconified" (that is, replaced on the desktop by a small
+ * simplified representation of itself), relocated to a
+ * distinguished area of the screen, or hidden. Combinations
+ * of these changes are also possible.
+ * </li>
+ * </ul>
+ * </p><p>
+ * The <em>modality</em> of an instance may be specified using
+ * style bits. The modality style bits are used to determine
+ * whether input is blocked for other shells on the display.
+ * The <code>PRIMARY_MODAL</code> style allows an instance to block
+ * input to its parent. The <code>APPLICATION_MODAL</code> style
+ * allows an instance to block input to every other shell in the
+ * display. The <code>SYSTEM_MODAL</code> style allows an instance
+ * to block input to all shells, including shells belonging to
+ * different applications.
+ * </p><p>
+ * Note: The styles supported by this class are treated
+ * as <em>HINT</em>s, since the window manager for the
+ * desktop on which the instance is visible has ultimate
+ * control over the appearance and behavior of decorations
+ * and modality. For example, some window managers only
+ * support resizable windows and will always assume the
+ * RESIZE style, even if it is not set. In addition, if a
+ * modality style is not supported, it is "upgraded" to a
+ * more restrictive modality style that is supported. For
+ * example, if <code>PRIMARY_MODAL</code> is not supported,
+ * it would be upgraded to <code>APPLICATION_MODAL</code>.
+ * A modality style may also be "downgraded" to a less
+ * restrictive style. For example, most operating systems
+ * no longer support <code>SYSTEM_MODAL</code> because
+ * it can freeze up the desktop, so this is typically
+ * downgraded to <code>APPLICATION_MODAL</code>.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE, ON_TOP, TOOL, SHEET</dd>
+ * <dd>APPLICATION_MODAL, MODELESS, PRIMARY_MODAL, SYSTEM_MODAL</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Activate, Close, Deactivate, Deiconify, Iconify</dd>
+ * </dl>
+ * Class <code>SWT</code> provides two "convenience constants"
+ * for the most commonly required style combinations:
+ * <dl>
+ * <dt><code>SHELL_TRIM</code></dt>
+ * <dd>
+ * the result of combining the constants which are required
+ * to produce a typical application top level shell: (that
+ * is, <code>CLOSE | TITLE | MIN | MAX | RESIZE</code>)
+ * </dd>
+ * <dt><code>DIALOG_TRIM</code></dt>
+ * <dd>
+ * the result of combining the constants which are required
+ * to produce a typical application dialog shell: (that
+ * is, <code>TITLE | CLOSE | BORDER</code>)
+ * </dd>
+ * </dl>
+ * </p>
+ * <p>
+ * Note: Only one of the styles APPLICATION_MODAL, MODELESS,
+ * PRIMARY_MODAL and SYSTEM_MODAL may be specified.
+ * </p><p>
+ * IMPORTANT: This class is not intended to be subclassed.
+ * </p>
+ *
+ * @see Decorations
+ * @see SWT
+ * @see <a href="http://www.eclipse.org/swt/snippets/#shell">Shell snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+public class Shell extends Decorations {
+ NSWindow window;
+ SWTWindowDelegate windowDelegate;
+ int /*long*/ tooltipOwner, tooltipTag, tooltipUserData;
+ boolean opened, moved, resized, fullScreen, center;
+ Control lastActive;
+ Rectangle normalBounds;
+ boolean keyInputHappened;
+ NSRect currentFrame;
+ NSRect fullScreenFrame;
+
+ static int DEFAULT_CLIENT_WIDTH = -1;
+ static int DEFAULT_CLIENT_HEIGHT = -1;
+
+/**
+ * Constructs a new instance of this class. This is equivalent
+ * to calling <code>Shell((Display) null)</code>.
+ *
+ * @exception SWTException <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>
+ */
+public Shell () {
+ this ((Display) null);
+}
+
+/**
+ * Constructs a new instance of this class given only the style
+ * value describing its behavior and appearance. This is equivalent
+ * to calling <code>Shell((Display) null, style)</code>.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 style the style of control to construct
+ *
+ * @exception SWTException <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 SWT#BORDER
+ * @see SWT#CLOSE
+ * @see SWT#MIN
+ * @see SWT#MAX
+ * @see SWT#RESIZE
+ * @see SWT#TITLE
+ * @see SWT#TOOL
+ * @see SWT#NO_TRIM
+ * @see SWT#SHELL_TRIM
+ * @see SWT#DIALOG_TRIM
+ * @see SWT#ON_TOP
+ * @see SWT#MODELESS
+ * @see SWT#PRIMARY_MODAL
+ * @see SWT#APPLICATION_MODAL
+ * @see SWT#SYSTEM_MODAL
+ * @see SWT#SHEET
+ */
+public Shell (int style) {
+ this ((Display) null, style);
+}
+
+/**
+ * Constructs a new instance of this class given only the display
+ * to create it on. It is created with style <code>SWT.SHELL_TRIM</code>.
+ * <p>
+ * Note: Currently, null can be passed in for the display argument.
+ * This has the effect of creating the shell on the currently active
+ * display if there is one. If there is no current display, the
+ * shell is created on a "default" display. <b>Passing in null as
+ * the display argument is not considered to be good coding style,
+ * and may not be supported in a future release of SWT.</b>
+ * </p>
+ *
+ * @param display the display to create the shell on
+ *
+ * @exception SWTException <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>
+ */
+public Shell (Display display) {
+ this (display, SWT.SHELL_TRIM);
+}
+
+/**
+ * Constructs a new instance of this class given the display
+ * to create it on and a style value describing its behavior
+ * and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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: Currently, null can be passed in for the display argument.
+ * This has the effect of creating the shell on the currently active
+ * display if there is one. If there is no current display, the
+ * shell is created on a "default" display. <b>Passing in null as
+ * the display argument is not considered to be good coding style,
+ * and may not be supported in a future release of SWT.</b>
+ * </p>
+ *
+ * @param display the display to create the shell on
+ * @param style the style of control to construct
+ *
+ * @exception SWTException <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 SWT#BORDER
+ * @see SWT#CLOSE
+ * @see SWT#MIN
+ * @see SWT#MAX
+ * @see SWT#RESIZE
+ * @see SWT#TITLE
+ * @see SWT#TOOL
+ * @see SWT#NO_TRIM
+ * @see SWT#SHELL_TRIM
+ * @see SWT#DIALOG_TRIM
+ * @see SWT#ON_TOP
+ * @see SWT#MODELESS
+ * @see SWT#PRIMARY_MODAL
+ * @see SWT#APPLICATION_MODAL
+ * @see SWT#SYSTEM_MODAL
+ * @see SWT#SHEET
+ */
+public Shell (Display display, int style) {
+ this (display, null, style, 0, false);
+}
+
+Shell (Display display, Shell parent, int style, int /*long*/handle, boolean embedded) {
+ super ();
+ checkSubclass ();
+ if (display == null) display = Display.getCurrent ();
+ if (display == null) display = Display.getDefault ();
+ if (!display.isValidThread ()) {
+ error (SWT.ERROR_THREAD_INVALID_ACCESS);
+ }
+ if (parent != null && parent.isDisposed ()) {
+ error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ if (!Display.getSheetEnabled ()) {
+ this.center = parent != null && (style & SWT.SHEET) != 0;
+ }
+ this.style = checkStyle (parent, style);
+ this.parent = parent;
+ this.display = display;
+ if (handle != 0) {
+ if (embedded) {
+ view = new NSView(handle);
+ } else {
+ window = new NSWindow(handle);
+ state |= FOREIGN_HANDLE;
+ }
+ }
+ createWidget ();
+}
+
+/**
+ * Constructs a new instance of this class given only its
+ * parent. It is created with style <code>SWT.DIALOG_TRIM</code>.
+ * <p>
+ * Note: Currently, null can be passed in for the parent.
+ * This has the effect of creating the shell on the currently active
+ * display if there is one. If there is no current display, the
+ * shell is created on a "default" display. <b>Passing in null as
+ * the parent is not considered to be good coding style,
+ * and may not be supported in a future release of SWT.</b>
+ * </p>
+ *
+ * @param parent a shell which will be the parent of the new instance
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li>
+ * </ul>
+ * @exception SWTException <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>
+ */
+public Shell (Shell parent) {
+ this (parent, SWT.DIALOG_TRIM);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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: Currently, null can be passed in for the parent.
+ * This has the effect of creating the shell on the currently active
+ * display if there is one. If there is no current display, the
+ * shell is created on a "default" display. <b>Passing in null as
+ * the parent is not considered to be good coding style,
+ * and may not be supported in a future release of SWT.</b>
+ * </p>
+ *
+ * @param parent a shell which will be the parent of the new instance
+ * @param style the style of control to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li>
+ * </ul>
+ * @exception SWTException <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 SWT#BORDER
+ * @see SWT#CLOSE
+ * @see SWT#MIN
+ * @see SWT#MAX
+ * @see SWT#RESIZE
+ * @see SWT#TITLE
+ * @see SWT#NO_TRIM
+ * @see SWT#SHELL_TRIM
+ * @see SWT#DIALOG_TRIM
+ * @see SWT#ON_TOP
+ * @see SWT#TOOL
+ * @see SWT#MODELESS
+ * @see SWT#PRIMARY_MODAL
+ * @see SWT#APPLICATION_MODAL
+ * @see SWT#SYSTEM_MODAL
+ * @see SWT#SHEET
+ */
+public Shell (Shell parent, int style) {
+ this (parent != null ? parent.display : null, parent, style, 0, false);
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new shell
+ * that is not embedded.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Shell</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param display the display for the shell
+ * @param handle the handle for the shell
+ * @return a new shell object containing the specified display and handle
+ *
+ * @since 3.3
+ */
+public static Shell internal_new (Display display, int /*long*/ handle) {
+ return new Shell (display, null, SWT.NO_TRIM, handle, false);
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new shell
+ * that is 'embedded'. In this case, the handle represents an NSView
+ * that acts as an embedded SWT Shell in an AWT Canvas.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Shell</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param display the display for the shell
+ * @param handle the handle for the shell
+ * @return a new shell object containing the specified display and handle
+ *
+ * @since 3.5
+ */
+public static Shell cocoa_new (Display display, int /*long*/ handle) {
+ return new Shell (display, null, SWT.NO_TRIM, handle, true);
+}
+
+static int checkStyle (Shell parent, int style) {
+ style = Decorations.checkStyle (style);
+ style &= ~SWT.TRANSPARENT;
+ int mask = SWT.SYSTEM_MODAL | SWT.APPLICATION_MODAL | SWT.PRIMARY_MODAL;
+ if ((style & SWT.SHEET) != 0) {
+ if (Display.getSheetEnabled ()) {
+ style &= ~(SWT.CLOSE | SWT.TITLE | SWT.MIN | SWT.MAX);
+ if (parent == null) {
+ style &= ~SWT.SHEET;
+ style |= SWT.SHELL_TRIM;
+ }
+ } else {
+ style &= ~SWT.SHEET;
+ style |= parent == null ? SWT.SHELL_TRIM : SWT.DIALOG_TRIM;
+ }
+ if ((style & mask) == 0) {
+ style |= parent == null ? SWT.APPLICATION_MODAL : SWT.PRIMARY_MODAL;
+ }
+ }
+ int bits = style & ~mask;
+ if ((style & SWT.SYSTEM_MODAL) != 0) return bits | SWT.SYSTEM_MODAL;
+ if ((style & SWT.APPLICATION_MODAL) != 0) return bits | SWT.APPLICATION_MODAL;
+ if ((style & SWT.PRIMARY_MODAL) != 0) return bits | SWT.PRIMARY_MODAL;
+ return bits;
+}
+
+boolean accessibilityIsIgnored(int /*long*/ id, int /*long*/ sel) {
+ // The content view of a shell is always ignored.
+ if (id == view.id) return true;
+ return super.accessibilityIsIgnored(id, sel);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when operations are performed on the receiver,
+ * by sending the listener one of the messages defined in the
+ * <code>ShellListener</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 SWTException <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 ShellListener
+ * @see #removeShellListener
+ */
+public void addShellListener(ShellListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener(SWT.Activate,typedListener);
+ addListener(SWT.Close,typedListener);
+ addListener(SWT.Deactivate,typedListener);
+ addListener(SWT.Iconify,typedListener);
+ addListener(SWT.Deiconify,typedListener);
+}
+
+void becomeKeyWindow (int /*long*/ id, int /*long*/ sel) {
+ Display display = this.display;
+ display.keyWindow = window;
+ super.becomeKeyWindow(id, sel);
+ display.checkFocus();
+ display.keyWindow = null;
+}
+
+void bringToTop (boolean force) {
+ if (getMinimized ()) return;
+ if (force) {
+ forceActive ();
+ } else {
+ setActive ();
+ }
+}
+
+boolean canBecomeKeyWindow (int /*long*/ id, int /*long*/ sel) {
+ if (window.styleMask () == OS.NSBorderlessWindowMask) return true;
+ return super.canBecomeKeyWindow (id, sel);
+}
+
+void checkOpen () {
+ if (!opened) resized = false;
+}
+
+void center () {
+ if (parent == null) return;
+ Rectangle rect = getBounds ();
+ Rectangle parentRect = display.map (parent, null, parent.getClientArea());
+ int x = Math.max (parentRect.x, parentRect.x + (parentRect.width - rect.width) / 2);
+ int y = Math.max (parentRect.y, parentRect.y + (parentRect.height - rect.height) / 2);
+ Rectangle monitorRect = parent.getMonitor ().getClientArea();
+ if (x + rect.width > monitorRect.x + monitorRect.width) {
+ x = Math.max (monitorRect.x, monitorRect.x + monitorRect.width - rect.width);
+ } else {
+ x = Math.max (x, monitorRect.x);
+ }
+ if (y + rect.height > monitorRect.y + monitorRect.height) {
+ y = Math.max (monitorRect.y, monitorRect.y + monitorRect.height - rect.height);
+ } else {
+ y = Math.max (y, monitorRect.y);
+ }
+ setLocation (x, y);
+}
+
+/**
+ * Requests that the window manager close the receiver in
+ * the same way it would be closed when the user clicks on
+ * the "close box" or performs some other platform specific
+ * key or mouse combination that indicates the window
+ * should be removed.
+ *
+ * @exception SWTException <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 SWT#Close
+ * @see #dispose
+ */
+public void close () {
+ checkWidget();
+ closeWidget ();
+}
+
+void closeWidget () {
+ Event event = new Event ();
+ sendEvent (SWT.Close, event);
+ if (event.doit && !isDisposed ()) dispose ();
+}
+
+public Rectangle computeTrim (int x, int y, int width, int height) {
+ checkWidget();
+ Rectangle trim = super.computeTrim(x, y, width, height);
+ NSRect rect = new NSRect ();
+ rect.x = trim.x;
+ rect.y = trim.y;
+ rect.width = trim.width;
+ rect.height = trim.height;
+ if (window != null) {
+ if (!fixResize()) {
+ rect = window.frameRectForContentRect(rect);
+ }
+ }
+ return new Rectangle ((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
+}
+
+void createHandle () {
+ state |= HIDDEN;
+ if (window == null) {
+ window = (NSWindow) new SWTWindow ().alloc ();
+ int styleMask = OS.NSBorderlessWindowMask;
+ if ((style & SWT.NO_TRIM) == 0) {
+ if ((style & SWT.TITLE) != 0) styleMask |= OS.NSTitledWindowMask;
+ if ((style & SWT.CLOSE) != 0) styleMask |= OS.NSClosableWindowMask;
+ if ((style & SWT.MIN) != 0) styleMask |= OS.NSMiniaturizableWindowMask;
+ if ((style & SWT.MAX) != 0) styleMask |= OS.NSResizableWindowMask;
+ if ((style & SWT.RESIZE) != 0) styleMask |= OS.NSResizableWindowMask;
+ }
+ NSScreen screen = null;
+ NSScreen primaryScreen = new NSScreen(NSScreen.screens().objectAtIndex(0));
+ if (parent != null) screen = parent.getShell().window.screen();
+ if (screen == null) screen = primaryScreen;
+ window = window.initWithContentRect(new NSRect(), styleMask, OS.NSBackingStoreBuffered, false, screen);
+ if ((style & (SWT.NO_TRIM | SWT.BORDER | SWT.SHELL_TRIM)) == 0 || (style & (SWT.TOOL | SWT.SHEET)) != 0) {
+ window.setHasShadow (true);
+ }
+ if ((style & SWT.NO_TRIM) == 0) {
+ NSSize size = window.minSize();
+ size.width = NSWindow.minFrameWidthWithTitle(NSString.stringWith(""), styleMask);
+ window.setMinSize(size);
+ }
+ if (fixResize ()) {
+ if (window.respondsToSelector(OS.sel_setMovable_)) {
+ OS.objc_msgSend(window.id, OS.sel_setMovable_, 0);
+ }
+ }
+ display.cascadeWindow(window, screen);
+ NSRect screenFrame = screen.frame();
+ float /*double*/ width = screenFrame.width * 5 / 8, height = screenFrame.height * 5 / 8;;
+ NSRect frame = window.frame();
+ NSRect primaryFrame = primaryScreen.frame();
+ frame.y = primaryFrame.height - ((primaryFrame.height - (frame.y + frame.height)) + height);
+ frame.width = width;
+ frame.height = height;
+ window.setFrame(frame, false);
+ if ((style & SWT.ON_TOP) != 0) {
+ window.setLevel(OS.NSStatusWindowLevel);
+ }
+ super.createHandle ();
+ topView ().setHidden (true);
+ } else {
+// int /*long*/ cls = OS.objc_lookUpClass ("SWTWindow");
+// OS.object_setClass(window.id, cls);
+ state &= ~HIDDEN;
+ //TODO - get the content of the foreign window instead of creating it
+ super.createHandle ();
+ style |= SWT.NO_BACKGROUND;
+ }
+ window.setAcceptsMouseMovedEvents(true);
+ windowDelegate = (SWTWindowDelegate)new SWTWindowDelegate().alloc().init();
+ window.setDelegate(windowDelegate);
+ id id = window.fieldEditor (true, null);
+ if (id != null) {
+ OS.object_setClass (id.id, OS.objc_getClass ("SWTEditorView"));
+ }
+}
+
+void deregister () {
+ super.deregister ();
+ if (window != null) display.removeWidget (window);
+ if (windowDelegate != null) display.removeWidget (windowDelegate);
+}
+
+void destroyWidget () {
+ NSWindow window = this.window;
+ Display display = this.display;
+ boolean sheet = (style & (SWT.SHEET)) != 0;
+ releaseHandle ();
+ if (window != null) {
+ if (sheet) {
+ NSApplication application = NSApplication.sharedApplication();
+ application.endSheet(window, 0);
+ }
+ window.close();
+ }
+ //If another shell is not going to become active, clear the menu bar.
+ if (!display.isDisposed () && display.getShells ().length == 0) {
+ display.setMenuBar (null);
+ }
+}
+
+void drawBackground (int /*long*/ id, NSGraphicsContext context, NSRect rect) {
+ if (id != view.id) return;
+ if (regionPath != null && background == null) {
+ context.saveGraphicsState();
+ NSColor.windowBackgroundColor().setFill();
+ NSBezierPath.fillRect(rect);
+ context.restoreGraphicsState();
+ return;
+ }
+ super.drawBackground (id, context, rect);
+}
+
+Control findBackgroundControl () {
+ return background != null || backgroundImage != null ? this : null;
+}
+
+Composite findDeferredControl () {
+ return layoutCount > 0 ? this : null;
+}
+
+Cursor findCursor () {
+ return cursor;
+}
+
+boolean fixResize () {
+ /*
+ * Feature in Cocoa. It is not possible to have a resizable window
+ * without the title bar. The fix is to resize the content view on
+ * top of the title bar.
+ */
+ if ((style & SWT.NO_TRIM) == 0) {
+ if ((style & SWT.RESIZE) != 0 && (style & (SWT.TITLE | SWT.CLOSE | SWT.MIN | SWT.MAX)) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void fixShell (Shell newShell, Control control) {
+ if (this == newShell) return;
+ if (control == lastActive) setActiveControl (null);
+}
+
+/**
+ * If the receiver is visible, moves it to the top of the
+ * drawing order for the display on which it was created
+ * (so that all other shells on that display, which are not
+ * the receiver's children will be drawn behind it) and forces
+ * the window manager to make the shell active.
+ *
+ * @exception SWTException <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 2.0
+ * @see Control#moveAbove
+ * @see Control#setFocus
+ * @see Control#setVisible
+ * @see Display#getActiveShell
+ * @see Decorations#setDefaultButton(Button)
+ * @see Shell#open
+ * @see Shell#setActive
+ */
+public void forceActive () {
+ checkWidget ();
+ if (!isVisible()) return;
+ if (window == null) return;
+ makeKeyAndOrderFront ();
+ NSApplication application = NSApplication.sharedApplication ();
+ application.activateIgnoringOtherApps (true);
+}
+
+/**
+ * Returns the receiver's alpha value. The alpha value
+ * is between 0 (transparent) and 255 (opaque).
+ *
+ * @return the alpha value
+ *
+ * @exception SWTException <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.4
+ */
+public int getAlpha () {
+ checkWidget ();
+ // TODO: Should we support embedded frame alpha?
+ if (window == null) return 255;
+ return (int)(window.alphaValue() * 255);
+}
+
+public Rectangle getBounds () {
+ checkWidget();
+ NSRect frame = (window == null ? view.frame() : window.frame());
+ float /*double*/ y = display.getPrimaryFrame().height - (int)(frame.y + frame.height);
+ return new Rectangle ((int)frame.x, (int)y, (int)frame.width, (int)frame.height);
+}
+
+public Rectangle getClientArea () {
+ checkWidget();
+ NSRect rect;
+ if (window != null) {
+ rect = window.frame();
+ if (!fixResize ()) {
+ rect = window.contentRectForFrameRect(rect);
+ }
+ } else {
+ rect = scrollView != null ? scrollView.frame() : view.frame();
+ }
+ int width = (int)rect.width, height = (int)rect.height;
+ if (scrollView != null) {
+ NSSize size = new NSSize();
+ size.width = width;
+ size.height = height;
+ size = NSScrollView.contentSizeForFrameSize(size, (style & SWT.H_SCROLL) != 0, (style & SWT.V_SCROLL) != 0, OS.NSNoBorder);
+ width = (int)size.width;
+ height = (int)size.height;
+ }
+ return new Rectangle (0, 0, width, height);
+}
+
+/**
+ * Returns <code>true</code> if the receiver is currently
+ * in fullscreen state, and false otherwise.
+ * <p>
+ *
+ * @return the fullscreen state
+ *
+ * @exception SWTException <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.4
+ */
+public boolean getFullScreen () {
+ checkWidget();
+ return fullScreen;
+}
+
+/**
+ * Returns the receiver's input method editor mode. This
+ * will be the result of bitwise OR'ing together one or
+ * more of the following constants defined in class
+ * <code>SWT</code>:
+ * <code>NONE</code>, <code>ROMAN</code>, <code>DBCS</code>,
+ * <code>PHONETIC</code>, <code>NATIVE</code>, <code>ALPHA</code>.
+ *
+ * @return the IME mode
+ *
+ * @exception SWTException <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 SWT
+ */
+public int getImeInputMode () {
+ checkWidget();
+ return SWT.NONE;
+}
+
+public Point getLocation () {
+ checkWidget();
+ // TODO: frame is relative to superview. What does getLocation mean in the embedded case?
+ NSRect frame = (window != null ? window.frame() : view.frame());
+ float /*double*/ y = display.getPrimaryFrame().height - (int)(frame.y + frame.height);
+ return new Point ((int)frame.x, (int)y);
+}
+
+public boolean getMaximized () {
+ checkWidget();
+ if (window == null) return false;
+ return !fullScreen && window.isZoomed();
+}
+
+Shell getModalShell () {
+ Shell shell = null;
+ Shell [] modalShells = display.modalShells;
+ if (modalShells != null) {
+ int bits = SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL;
+ int index = modalShells.length;
+ while (--index >= 0) {
+ Shell modal = modalShells [index];
+ if (modal != null) {
+ if ((modal.style & bits) != 0) {
+ Control control = this;
+ while (control != null) {
+ if (control == modal) break;
+ control = control.parent;
+ }
+ if (control != modal) return modal;
+ break;
+ }
+ if ((modal.style & SWT.PRIMARY_MODAL) != 0) {
+ if (shell == null) shell = getShell ();
+ if (modal.parent == shell) return modal;
+ }
+ }
+ }
+ }
+ return null;
+}
+
+/**
+ * Gets the receiver's modified state.
+ *
+ * </ul>
+ * @exception SWTException <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.5
+ */
+public boolean getModified () {
+ checkWidget ();
+ return window.isDocumentEdited ();
+}
+
+public boolean getMinimized () {
+ checkWidget();
+ if (!getVisible ()) return super.getMinimized ();
+ if (window == null) return false;
+ return window.isMiniaturized();
+}
+
+/**
+ * Returns a point describing the minimum receiver's size. The
+ * x coordinate of the result is the minimum width of the receiver.
+ * The y coordinate of the result is the minimum height of the
+ * receiver.
+ *
+ * @return the receiver's size
+ *
+ * @exception SWTException <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.1
+ */
+public Point getMinimumSize () {
+ checkWidget();
+ if (window == null) return new Point(0, 0);
+ NSSize size = window.minSize();
+ return new Point((int)size.width, (int)size.height);
+}
+
+/**
+ * Returns the region that defines the shape of the shell,
+ * or null if the shell has the default shape.
+ *
+ * @return the region that defines the shape of the shell (or null)
+ *
+ * @exception SWTException <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.0
+ *
+ */
+public Region getRegion () {
+ /* This method is needed for the @since 3.0 Javadoc */
+ checkWidget ();
+ return region;
+}
+
+public Shell getShell () {
+ checkWidget();
+ return this;
+}
+
+/**
+ * Returns an array containing all shells which are
+ * descendants of the receiver.
+ * <p>
+ * @return the dialog shells
+ *
+ * @exception SWTException <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 Shell [] getShells () {
+ checkWidget();
+ int count = 0;
+ Shell [] shells = display.getShells ();
+ for (int i=0; i<shells.length; i++) {
+ Control shell = shells [i];
+ do {
+ shell = shell.parent;
+ } while (shell != null && shell != this);
+ if (shell == this) count++;
+ }
+ int index = 0;
+ Shell [] result = new Shell [count];
+ for (int i=0; i<shells.length; i++) {
+ Control shell = shells [i];
+ do {
+ shell = shell.parent;
+ } while (shell != null && shell != this);
+ if (shell == this) {
+ result [index++] = shells [i];
+ }
+ }
+ return result;
+}
+
+public Point getSize () {
+ checkWidget();
+ NSRect frame = (window != null ? window.frame() : view.frame());
+ return new Point ((int) frame.width, (int) frame.height);
+}
+
+float getThemeAlpha () {
+ return 1;
+}
+
+boolean hasBorder () {
+ return false;
+}
+
+void helpRequested(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ Control control = display.getFocusControl();
+ while (control != null) {
+ if (control.hooks (SWT.Help)) {
+ control.postEvent (SWT.Help);
+ break;
+ }
+ control = control.parent;
+ }
+}
+
+void invalidateVisibleRegion () {
+ resetVisibleRegion ();
+ invalidateChildrenVisibleRegion ();
+}
+
+boolean isDrawing () {
+ return getDrawing ();
+}
+
+public boolean isEnabled () {
+ checkWidget();
+ return getEnabled ();
+}
+
+boolean isEnabledCursor () {
+ return true;
+}
+
+public boolean isVisible () {
+ checkWidget();
+ return getVisible ();
+}
+
+boolean makeFirstResponder (int /*long*/ id, int /*long*/ sel, int /*long*/ responder) {
+ Display display = this.display;
+ boolean result = super.makeFirstResponder(id, sel, responder);
+ display.checkFocus();
+ return result;
+}
+
+void makeKeyAndOrderFront() {
+ /*
+ * Bug in Cocoa. If a child window becomes the key window when its
+ * parent window is miniaturized, the parent window appears as if
+ * restored to its full size without actually being restored. In this
+ * case the parent window does become active when its child is closed
+ * and the user is forced to restore the window from the dock.
+ * The fix is to be sure that the parent window is deminiaturized before
+ * making the child a key window.
+ */
+ if (parent != null) {
+ Shell shell = (Shell) parent;
+ if (shell.window.isMiniaturized()) shell.window.deminiaturize(null);
+ }
+ window.makeKeyAndOrderFront (null);
+}
+
+void noResponderFor(int /*long*/ id, int /*long*/ sel, int /*long*/ selector) {
+ /**
+ * Feature in Cocoa. If the selector is keyDown and nothing has handled the event
+ * a system beep is generated. There's no need to beep, as many keystrokes in the SWT
+ * are listened for and acted upon but not explicitly handled in a keyDown handler. Fix is to
+ * not call the default implementation when a keyDown: is being handled.
+ */
+ if (selector != OS.sel_keyDown_) super.noResponderFor(id, sel, selector);
+}
+
+/**
+ * Moves the receiver to the top of the drawing order for
+ * the display on which it was created (so that all other
+ * shells on that display, which are not the receiver's
+ * children will be drawn behind it), marks it visible,
+ * sets the focus and asks the window manager to make the
+ * shell active.
+ *
+ * @exception SWTException <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 Control#moveAbove
+ * @see Control#setFocus
+ * @see Control#setVisible
+ * @see Display#getActiveShell
+ * @see Decorations#setDefaultButton(Button)
+ * @see Shell#setActive
+ * @see Shell#forceActive
+ */
+public void open () {
+ checkWidget();
+ int mask = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL;
+ if ((style & mask) != 0) {
+ display.setModalShell (this);
+ } else {
+ updateModal ();
+ }
+ bringToTop (false);
+ setWindowVisible (true, true);
+ if (isDisposed ()) return;
+ if (!restoreFocus () && !traverseGroup (true)) {
+ // if the parent shell is minimized, setting focus will cause it
+ // to become unminimized.
+ if (parent == null || !((Shell)parent).window.isMiniaturized()) {
+ setFocus ();
+ }
+ }
+}
+
+public boolean print (GC gc) {
+ checkWidget ();
+ if (gc == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (gc.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ return false;
+}
+
+void register () {
+ super.register ();
+ if (window != null) display.addWidget (window, this);
+ if (windowDelegate != null) display.addWidget (windowDelegate, this);
+}
+
+void releaseChildren (boolean destroy) {
+ Shell [] shells = getShells ();
+ for (int i=0; i<shells.length; i++) {
+ Shell shell = shells [i];
+ if (shell != null && !shell.isDisposed ()) {
+ shell.dispose ();
+ }
+ }
+ super.releaseChildren (destroy);
+}
+
+void releaseHandle () {
+ if (window != null) window.setDelegate(null);
+ if (windowDelegate != null) windowDelegate.release();
+ windowDelegate = null;
+ super.releaseHandle ();
+ window = null;
+}
+
+void releaseParent () {
+ /* Do nothing */
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ display.clearModal (this);
+ updateParent (false);
+ display.updateQuitMenu();
+ lastActive = null;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when operations are performed on the receiver.
+ *
+ * @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 SWTException <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 ShellListener
+ * @see #addShellListener
+ */
+public void removeShellListener(ShellListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook(SWT.Activate, listener);
+ eventTable.unhook(SWT.Close, listener);
+ eventTable.unhook(SWT.Deactivate, listener);
+ eventTable.unhook(SWT.Iconify,listener);
+ eventTable.unhook(SWT.Deiconify,listener);
+}
+
+void sendToolTipEvent (boolean enter) {
+ if (!isVisible()) return;
+ if (tooltipTag == 0) {
+ NSView view = window.contentView();
+ tooltipTag = view.addToolTipRect(new NSRect(), window, 0);
+ if (tooltipTag != 0) {
+ NSTrackingArea trackingArea = new NSTrackingArea(tooltipTag);
+ id owner = trackingArea.owner();
+ if (owner != null) tooltipOwner = owner.id;
+ id userInfo = trackingArea.userInfo();
+ if (userInfo != null) {
+ tooltipUserData = userInfo.id;
+ } else {
+ int /*long*/ [] value = new int /*long*/ [1];
+ OS.object_getInstanceVariable(tooltipTag, new byte[]{'_','u', 's', 'e', 'r', 'I', 'n', 'f', 'o'}, value);
+ tooltipUserData = value[0];
+ }
+ }
+ }
+ if (tooltipTag == 0 || tooltipOwner == 0 || tooltipUserData == 0) return;
+ NSPoint pt = window.convertScreenToBase(NSEvent.mouseLocation());
+ NSEvent event = NSEvent.enterExitEventWithType(enter ? OS.NSMouseEntered : OS.NSMouseExited, pt, 0, 0, window.windowNumber(), null, 0, tooltipTag, tooltipUserData);
+ OS.objc_msgSend(tooltipOwner, enter ? OS.sel_mouseEntered_ : OS.sel_mouseExited_, event.id);
+}
+
+/**
+ * If the receiver is visible, moves it to the top of the
+ * drawing order for the display on which it was created
+ * (so that all other shells on that display, which are not
+ * the receiver's children will be drawn behind it) and asks
+ * the window manager to make the shell active
+ *
+ * @exception SWTException <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 2.0
+ * @see Control#moveAbove
+ * @see Control#setFocus
+ * @see Control#setVisible
+ * @see Display#getActiveShell
+ * @see Decorations#setDefaultButton(Button)
+ * @see Shell#open
+ * @see Shell#setActive
+ */
+public void setActive () {
+ if (window == null) return;
+ checkWidget ();
+ if (!isVisible()) return;
+ makeKeyAndOrderFront ();
+}
+
+void setActiveControl (Control control) {
+ if (control != null && control.isDisposed ()) control = null;
+ if (lastActive != null && lastActive.isDisposed ()) lastActive = null;
+ if (lastActive == control) return;
+
+ /*
+ * Compute the list of controls to be activated and
+ * deactivated by finding the first common parent
+ * control.
+ */
+ Control [] activate = (control == null) ? new Control[0] : control.getPath ();
+ Control [] deactivate = (lastActive == null) ? new Control[0] : lastActive.getPath ();
+ lastActive = control;
+ int index = 0, length = Math.min (activate.length, deactivate.length);
+ while (index < length) {
+ if (activate [index] != deactivate [index]) break;
+ index++;
+ }
+
+ /*
+ * It is possible (but unlikely), that application
+ * code could have destroyed some of the widgets. If
+ * this happens, keep processing those widgets that
+ * are not disposed.
+ */
+ for (int i=deactivate.length-1; i>=index; --i) {
+ if (!deactivate [i].isDisposed ()) {
+ deactivate [i].sendEvent (SWT.Deactivate);
+ }
+ }
+ for (int i=activate.length-1; i>=index; --i) {
+ if (!activate [i].isDisposed ()) {
+ activate [i].sendEvent (SWT.Activate);
+ }
+ }
+}
+
+/**
+ * Sets the receiver's alpha value which must be
+ * between 0 (transparent) and 255 (opaque).
+ * <p>
+ * This operation requires the operating system's advanced
+ * widgets subsystem which may not be available on some
+ * platforms.
+ * </p>
+ * @param alpha the alpha value
+ *
+ * @exception SWTException <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.4
+ */
+public void setAlpha (int alpha) {
+ if (window == null) return;
+ checkWidget ();
+ alpha &= 0xFF;
+ window.setAlphaValue (alpha / 255f);
+}
+
+void setBounds (int x, int y, int width, int height, boolean move, boolean resize) {
+ // Embedded Shells are not resizable.
+ if (window == null) return;
+ if (fullScreen) setFullScreen (false);
+ boolean sheet = window.isSheet();
+ if (sheet && move && !resize) return;
+ int screenHeight = (int) display.getPrimaryFrame().height;
+ NSRect frame = window.frame();
+ if (!move) {
+ x = (int)frame.x;
+ y = screenHeight - (int)(frame.y + frame.height);
+ }
+ if (resize) {
+ NSSize minSize = window.minSize();
+ width = Math.max(width, (int)minSize.width);
+ height = Math.max(height, (int)minSize.height);
+ } else {
+ width = (int)frame.width;
+ height = (int)frame.height;
+ }
+ if (sheet) {
+ y = screenHeight - (int)(frame.y + frame.height);
+ NSRect parentRect = parent.getShell().window.frame();
+ frame.width = width;
+ frame.height = height;
+ frame.x = parentRect.x + (parentRect.width - frame.width) / 2;
+ frame.y = screenHeight - (int)(y + frame.height);
+ window.setFrame(frame, isVisible(), true);
+ } else {
+ frame.x = x;
+ frame.y = screenHeight - (int)(y + height);
+ frame.width = width;
+ frame.height = height;
+ window.setFrame(frame, isVisible());
+ }
+}
+
+void setClipRegion (float /*double*/ x, float /*double*/ y) {
+ if (regionPath != null) {
+ NSAffineTransform transform = NSAffineTransform.transform();
+ transform.translateXBy(-x, -y);
+ regionPath.transformUsingAffineTransform(transform);
+ regionPath.addClip();
+ transform.translateXBy(2*x, 2*y);
+ regionPath.transformUsingAffineTransform(transform);
+ }
+}
+
+public void setEnabled (boolean enabled) {
+ checkWidget();
+ if (((state & DISABLED) == 0) == enabled) return;
+ super.setEnabled (enabled);
+// if (enabled && OS.IsWindowActive (shellHandle)) {
+// if (!restoreFocus ()) traverseGroup (false);
+// }
+}
+
+/**
+ * Sets the full screen state of the receiver.
+ * If the argument is <code>true</code> causes the receiver
+ * to switch to the full screen state, and if the argument is
+ * <code>false</code> and the receiver was previously switched
+ * into full screen state, causes the receiver to switch back
+ * to either the maximized or normal states.
+ * <p>
+ * Note: The result of intermixing calls to <code>setFullScreen(true)</code>,
+ * <code>setMaximized(true)</code> and <code>setMinimized(true)</code> will
+ * vary by platform. Typically, the behavior will match the platform user's
+ * expectations, but not always. This should be avoided if possible.
+ * </p>
+ *
+ * @param fullScreen the new fullscreen state
+ *
+ * @exception SWTException <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.4
+ */
+public void setFullScreen (boolean fullScreen) {
+ checkWidget ();
+ if (this.fullScreen == fullScreen) return;
+ this.fullScreen = fullScreen;
+
+ if (fullScreen) {
+ currentFrame = window.frame();
+ window.setShowsResizeIndicator(false); //only hides resize indicator
+ if (window.respondsToSelector(OS.sel_setMovable_)) {
+ OS.objc_msgSend(window.id, OS.sel_setMovable_, 0);
+ }
+
+ fullScreenFrame = NSScreen.mainScreen().frame();
+ if (getMonitor().equals(display.getPrimaryMonitor ())) {
+ if (menuBar != null) {
+ float /*double*/ menuBarHt = currentFrame.height - contentView().frame().height;
+ fullScreenFrame.height -= menuBarHt;
+ OS.SetSystemUIMode(OS.kUIModeContentHidden, 0);
+ }
+ else {
+ OS.SetSystemUIMode(OS.kUIModeAllHidden, 0);
+ }
+ }
+ window.setFrame(fullScreenFrame, true);
+ window.contentView().setFrame(fullScreenFrame);
+ } else {
+ window.setShowsResizeIndicator(true);
+ if (window.respondsToSelector(OS.sel_setMovable_)) {
+ OS.objc_msgSend(window.id, OS.sel_setMovable_, 1);
+ }
+ OS.SetSystemUIMode(OS.kUIModeNormal, 0);
+ window.setFrame(currentFrame, true);
+ }
+}
+
+public void setMenuBar (Menu menu) {
+ checkWidget();
+ super.setMenuBar (menu);
+ if (display.getActiveShell () == this) {
+ display.setMenuBar (menuBar);
+ }
+}
+
+/**
+ * Sets the input method editor mode to the argument which
+ * should be the result of bitwise OR'ing together one or more
+ * of the following constants defined in class <code>SWT</code>:
+ * <code>NONE</code>, <code>ROMAN</code>, <code>DBCS</code>,
+ * <code>PHONETIC</code>, <code>NATIVE</code>, <code>ALPHA</code>.
+ *
+ * @param mode the new IME mode
+ *
+ * @exception SWTException <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 SWT
+ */
+public void setImeInputMode (int mode) {
+ checkWidget();
+}
+
+public void setMaximized (boolean maximized) {
+ checkWidget();
+ super.setMaximized (maximized);
+ if (window == null) return;
+ if (window.isZoomed () == maximized) return;
+ window.zoom (null);
+}
+
+public void setMinimized (boolean minimized) {
+ checkWidget();
+ super.setMinimized (minimized);
+ if (window == null) return;
+ if (minimized) {
+ window.miniaturize (null);
+ } else {
+ window.deminiaturize (null);
+ }
+}
+
+/**
+ * Sets the receiver's minimum size to the size specified by the arguments.
+ * If the new minimum size is larger than the current size of the receiver,
+ * the receiver is resized to the new minimum size.
+ *
+ * @param width the new minimum width for the receiver
+ * @param height the new minimum height for the receiver
+ *
+ * @exception SWTException <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.1
+ */
+public void setMinimumSize (int width, int height) {
+ checkWidget();
+ if (window == null) return;
+ NSSize size = new NSSize();
+ size.width = width;
+ size.height = height;
+ window.setMinSize(size);
+ NSRect frame = window.frame();
+ if (width > frame.width || height > frame.height) {
+ width = (int)(width > frame.width ? width : frame.width);
+ height = (int)(height > frame.height ? height : frame.height);
+ setBounds(0, 0, width, height, false, true);
+ }
+}
+
+/**
+ * Sets the receiver's minimum size to the size specified by the argument.
+ * If the new minimum size is larger than the current size of the receiver,
+ * the receiver is resized to the new minimum size.
+ *
+ * @param size the new minimum size for the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception SWTException <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.1
+ */
+public void setMinimumSize (Point size) {
+ checkWidget();
+ if (size == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setMinimumSize (size.x, size.y);
+}
+
+/**
+ * Sets the receiver's modified state as specified by the argument.
+ *
+ * @param modified the new modified state for the receiver
+ *
+ * </ul>
+ * @exception SWTException <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.5
+ */
+public void setModified (boolean modified) {
+ checkWidget ();
+ window.setDocumentEdited (modified);
+}
+
+/**
+ * Sets the shape of the shell to the region specified
+ * by the argument. When the argument is null, the
+ * default shape of the shell is restored. The shell
+ * must be created with the style SWT.NO_TRIM in order
+ * to specify a region.
+ *
+ * @param region the region that defines the shape of the shell (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the region has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.0
+ *
+ */
+public void setRegion (Region region) {
+ checkWidget ();
+ if ((style & SWT.NO_TRIM) == 0) return;
+ if (window == null) return;
+ if (region != null && region.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+ this.region = region;
+ if (regionPath != null) regionPath.release();
+ regionPath = getPath(region);
+ if (region != null) {
+ window.setBackgroundColor(NSColor.clearColor());
+ window.setOpaque(false);
+ } else {
+ window.setBackgroundColor(NSColor.windowBackgroundColor());
+ window.setOpaque(true);
+ }
+ window.contentView().setNeedsDisplay(true);
+ if (isVisible() && window.hasShadow()) {
+ window.display();
+ window.invalidateShadow();
+ }
+}
+
+public void setText (String string) {
+ checkWidget();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (window == null) return;
+ super.setText (string);
+ NSString str = NSString.stringWith(string);
+ window.setTitle(str);
+}
+
+public void setVisible (boolean visible) {
+ checkWidget();
+ int mask = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL;
+ if ((style & mask) != 0) {
+ if (visible) {
+ display.setModalShell (this);
+ } else {
+ display.clearModal (this);
+ }
+ } else {
+ updateModal ();
+ }
+ if (window == null) {
+ super.setVisible(visible);
+ } else {
+ setWindowVisible (visible, false);
+ }
+}
+
+void setWindowVisible (boolean visible, boolean key) {
+ if (visible) {
+ if ((state & HIDDEN) == 0) return;
+ state &= ~HIDDEN;
+ } else {
+ if ((state & HIDDEN) != 0) return;
+ state |= HIDDEN;
+ }
+ if (window != null && (window.isVisible() == visible)) return;
+ if (visible) {
+ display.clearPool ();
+ if (center && !moved) {
+ if (isDisposed ()) return;
+ center ();
+ }
+ sendEvent (SWT.Show);
+ if (isDisposed ()) return;
+ topView ().setHidden (false);
+ invalidateVisibleRegion();
+ if ((style & (SWT.SHEET)) != 0) {
+ NSApplication application = NSApplication.sharedApplication();
+ application.beginSheet(window, ((Shell)parent).window, null, 0, 0);
+ if (OS.VERSION <= 0x1060 && window.respondsToSelector(OS.sel__setNeedsToUseHeartBeatWindow_)) {
+ OS.objc_msgSend(window.id, OS.sel__setNeedsToUseHeartBeatWindow_, 0);
+ }
+ } else {
+ // If the parent window is miniaturized, the window will be shown
+ // when its parent is shown.
+ boolean parentMinimized = parent != null && ((Shell)parent).window.isMiniaturized();
+ if (!parentMinimized) {
+ if (key) {
+ makeKeyAndOrderFront ();
+ } else {
+ window.orderFront (null);
+ }
+ }
+ }
+ updateParent (visible);
+ opened = true;
+ if (!moved) {
+ moved = true;
+ sendEvent (SWT.Move);
+ if (isDisposed ()) return;
+ }
+ if (!resized) {
+ resized = true;
+ sendEvent (SWT.Resize);
+ if (isDisposed ()) return;
+ if (layout != null) {
+ markLayout (false, false);
+ updateLayout (false);
+ }
+ }
+ } else {
+ updateParent (visible);
+ if ((style & (SWT.SHEET)) != 0) {
+ NSApplication application = NSApplication.sharedApplication();
+ application.endSheet(window, 0);
+ }
+ window.orderOut (null);
+ topView ().setHidden (true);
+ invalidateVisibleRegion();
+ sendEvent (SWT.Hide);
+ }
+
+ display.updateQuitMenu();
+}
+
+void setZOrder () {
+ if (scrollView != null) scrollView.setDocumentView (view);
+ if (window == null) return;
+ window.setContentView (scrollView != null ? scrollView : view);
+ if (fixResize ()) {
+ NSRect rect = window.frame();
+ rect.x = rect.y = 0;
+ window.contentView().setFrame(rect);
+ }
+}
+
+void setZOrder (Control control, boolean above) {
+ if (window == null) return;
+ if (control == null) {
+ if (above) {
+ window.orderFront(null);
+ } else {
+ window.orderBack(null);
+ }
+ } else {
+ NSWindow otherWindow = control.getShell().window;
+ window.orderWindow(above ? OS.NSWindowAbove : OS.NSWindowBelow, otherWindow.windowNumber());
+ }
+}
+
+boolean traverseEscape () {
+ if (parent == null) return false;
+ if (!isVisible () || !isEnabled ()) return false;
+ close ();
+ return true;
+}
+
+void updateModal () {
+ // do nothing
+}
+
+void updateParent (boolean visible) {
+ if (visible) {
+ if (parent != null && parent.getVisible ()) {
+ ((Shell)parent).window.addChildWindow (window, OS.NSWindowAbove);
+ }
+ } else {
+ NSWindow parentWindow = window.parentWindow ();
+ if (parentWindow != null) parentWindow.removeChildWindow (window);
+ }
+ Shell [] shells = getShells ();
+ for (int i = 0; i < shells.length; i++) {
+ Shell shell = shells [i];
+ if (shell.parent == this && shell.getVisible ()) {
+ shell.updateParent (visible);
+ }
+ }
+}
+
+void updateSystemUIMode () {
+ if (!getMonitor ().equals (display.getPrimaryMonitor ())) return;
+ if (fullScreen) {
+ int mode = OS.kUIModeAllHidden;
+ if (menuBar != null) {
+ mode = OS.kUIModeContentHidden;
+ }
+ OS.SetSystemUIMode (mode, 0);
+ window.setFrame(fullScreenFrame, true);
+ } else {
+ OS.SetSystemUIMode (OS.kUIModeNormal, 0);
+ }
+}
+
+int /*long*/ view_stringForToolTip_point_userData (int /*long*/ id, int /*long*/ sel, int /*long*/ view, int /*long*/ tag, int /*long*/ point, int /*long*/ userData) {
+ NSPoint pt = new NSPoint();
+ OS.memmove (pt, point, NSPoint.sizeof);
+ Control control = display.findControl (false);
+ if (control == null) return 0;
+ Widget target = control.findTooltip (new NSView (view).convertPoint_toView_ (pt, null));
+ String string = target.tooltipText ();
+ if (string == null) return 0;
+ char[] chars = new char [string.length ()];
+ string.getChars (0, chars.length, chars, 0);
+ int length = fixMnemonic (chars);
+ return NSString.stringWithCharacters (chars, length).id;
+}
+
+void windowDidBecomeKey(int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+ super.windowDidBecomeKey(id, sel, notification);
+ Display display = this.display;
+ display.setMenuBar (menuBar);
+ sendEvent (SWT.Activate);
+ if (isDisposed ()) return;
+ Shell parentShell = this;
+ while (parentShell.parent != null) {
+ parentShell = (Shell) parentShell.parent;
+ if (parentShell.fullScreen) {
+ break;
+ }
+ }
+ if (!parentShell.fullScreen || menuBar != null) {
+ updateSystemUIMode ();
+ } else {
+ parentShell.updateSystemUIMode ();
+ }
+}
+
+void windowDidMove(int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+ moved = true;
+ sendEvent(SWT.Move);
+}
+
+void windowDidResize(int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+ if (fullScreen) {
+ window.setFrame(fullScreenFrame, true);
+ window.contentView().setFrame(fullScreenFrame);
+ }
+ if (fixResize ()) {
+ NSRect rect = window.frame ();
+ rect.x = rect.y = 0;
+ window.contentView ().setFrame (rect);
+ }
+ resized = true;
+ sendEvent (SWT.Resize);
+ if (isDisposed ()) return;
+ if (layout != null) {
+ markLayout (false, false);
+ updateLayout (false);
+ }
+}
+
+void windowDidResignKey(int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+ super.windowDidResignKey(id, sel, notification);
+ sendEvent (SWT.Deactivate);
+}
+
+void windowSendEvent (int /*long*/ id, int /*long*/ sel, int /*long*/ event) {
+ NSEvent nsEvent = new NSEvent (event);
+ int type = (int)/*64*/nsEvent.type ();
+ switch (type) {
+ case OS.NSLeftMouseUp:
+ case OS.NSRightMouseUp:
+ case OS.NSOtherMouseUp:
+ case OS.NSMouseMoved:
+ NSView[] hitView = new NSView[1];
+ Control control = display.findControl (false, hitView);
+ if (control != null && (!control.isActive() || !control.isEnabled())) control = null;
+ if (type == OS.NSMouseMoved) {
+ Control trimControl = control;
+ if (trimControl != null && trimControl.isTrim (hitView[0])) trimControl = null;
+ display.checkEnterExit (trimControl, nsEvent, false);
+ if (trimControl != null) trimControl.sendMouseEvent (nsEvent, type, false);
+ }
+ Widget target = null;
+ if (control != null) target = control.findTooltip (nsEvent.locationInWindow());
+ if (display.tooltipControl != control || display.tooltipTarget != target) {
+ Control oldControl = display.tooltipControl;
+ Shell oldShell = oldControl != null && !oldControl.isDisposed() ? oldControl.getShell() : null;
+ Shell shell = control != null && !control.isDisposed() ? control.getShell() : null;
+ if (oldShell != null) oldShell.sendToolTipEvent (false);
+ if (shell != null) shell.sendToolTipEvent (true);
+ }
+ display.tooltipControl = control;
+ display.tooltipTarget = target;
+ break;
+
+ case OS.NSKeyDown:
+ /**
+ * Feature in cocoa. Control+Tab, Ctrl+Shift+Tab, Ctrl+PageDown and Ctrl+PageUp are
+ * swallowed to handle native traversal. If we find that, force the key event to
+ * the first responder.
+ */
+ if ((nsEvent.modifierFlags() & OS.NSControlKeyMask) != 0) {
+ NSString chars = nsEvent.characters();
+
+ if (chars != null && chars.length() == 1) {
+ int firstChar = (int)/*64*/chars.characterAtIndex(0);
+
+ // Shift-tab appears as control-Y.
+ switch (firstChar) {
+ case '\t':
+ case 25:
+ case OS.NSPageDownFunctionKey:
+ case OS.NSPageUpFunctionKey:
+ window.firstResponder().keyDown(nsEvent);
+ return;
+ }
+ }
+ }
+ break;
+ }
+ super.windowSendEvent (id, sel, event);
+}
+
+boolean windowShouldClose(int /*long*/ id, int /*long*/ sel, int /*long*/ window) {
+ closeWidget ();
+ return false;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Slider.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Slider.java
new file mode 100755
index 0000000000..305d47d879
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Slider.java
@@ -0,0 +1,527 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Instances of this class are selectable user interface
+ * objects that represent a range of positive, numeric values.
+ * <p>
+ * At any given moment, a given slider will have a
+ * single 'selection' that is considered to be its
+ * value, which is constrained to be within the range of
+ * values the slider represents (that is, between its
+ * <em>minimum</em> and <em>maximum</em> values).
+ * </p><p>
+ * Typically, sliders will be made up of five areas:
+ * <ol>
+ * <li>an arrow button for decrementing the value</li>
+ * <li>a page decrement area for decrementing the value by a larger amount</li>
+ * <li>a <em>thumb</em> for modifying the value by mouse dragging</li>
+ * <li>a page increment area for incrementing the value by a larger amount</li>
+ * <li>an arrow button for incrementing the value</li>
+ * </ol>
+ * Based on their style, sliders are either <code>HORIZONTAL</code>
+ * (which have a left facing button for decrementing the value and a
+ * right facing button for incrementing it) or <code>VERTICAL</code>
+ * (which have an upward facing button for decrementing the value
+ * and a downward facing buttons for incrementing it).
+ * </p><p>
+ * On some platforms, the size of the slider's thumb can be
+ * varied relative to the magnitude of the range of values it
+ * represents (that is, relative to the difference between its
+ * maximum and minimum values). Typically, this is used to
+ * indicate some proportional value such as the ratio of the
+ * visible area of a document to the total amount of space that
+ * it would take to display it. SWT supports setting the thumb
+ * size even if the underlying platform does not, but in this
+ * case the appearance of the slider will not change.
+ * </p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>HORIZONTAL, VERTICAL</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
+ * </p><p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ *
+ * @see ScrollBar
+ * @see <a href="http://www.eclipse.org/swt/snippets/#slider">Slider snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Slider extends Control {
+ boolean dragging;
+ int minimum, maximum, thumb;
+ int increment = 1;
+ int pageIncrement = 10;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#HORIZONTAL
+ * @see SWT#VERTICAL
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Slider (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's value, by sending
+ * it one of the messages defined in the <code>SelectionListener</code>
+ * interface.
+ * <p>
+ * When <code>widgetSelected</code> is called, the event object detail field contains one of the following values:
+ * <code>SWT.NONE</code> - for the end of a drag.
+ * <code>SWT.DRAG</code>.
+ * <code>SWT.HOME</code>.
+ * <code>SWT.END</code>.
+ * <code>SWT.ARROW_DOWN</code>.
+ * <code>SWT.ARROW_UP</code>.
+ * <code>SWT.PAGE_DOWN</code>.
+ * <code>SWT.PAGE_UP</code>.
+ * <code>widgetDefaultSelected</code> is not called.
+ * </p>
+ *
+ * @param listener the listener which should be notified when the user changes the receiver's value
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener(listener);
+ addListener(SWT.Selection,typedListener);
+ addListener(SWT.DefaultSelection,typedListener);
+}
+
+static int checkStyle (int style) {
+ return checkBits (style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0);
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget();
+ int width = 0, height = 0;
+ if ((style & SWT.HORIZONTAL) != 0) {
+ height = (int)NSScroller.scrollerWidthForControlSize(((NSScroller)view).controlSize());
+ width = height * 10;
+ } else {
+ width = (int)NSScroller.scrollerWidthForControlSize(((NSScroller)view).controlSize());
+ height = width * 10;
+ }
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ return new Point (width, height);
+}
+
+void createHandle () {
+ NSScroller widget = (NSScroller)new SWTScroller().alloc();
+ NSRect rect = new NSRect();
+ if ((style & SWT.HORIZONTAL) != 0) {
+ rect.width = 1;
+ } else {
+ rect.height = 1;
+ }
+ widget.initWithFrame(rect);
+ widget.setEnabled(true);
+ widget.setTarget(widget);
+ widget.setAction(OS.sel_sendSelection);
+ view = widget;
+ updateBar(0, minimum, maximum, thumb);
+}
+
+void createWidget () {
+ maximum = 100;
+ thumb = 10;
+ super.createWidget();
+}
+
+NSFont defaultNSFont () {
+ return display.scrollerFont;
+}
+
+/**
+ * Returns the amount that the receiver's value will be
+ * modified by when the up/down (or right/left) arrows
+ * are pressed.
+ *
+ * @return the increment
+ *
+ * @exception SWTException <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 getIncrement () {
+ checkWidget();
+ return increment;
+}
+
+/**
+ * Returns the maximum value which the receiver will allow.
+ *
+ * @return the maximum
+ *
+ * @exception SWTException <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 getMaximum () {
+ checkWidget();
+ return maximum;
+}
+
+/**
+ * Returns the minimum value which the receiver will allow.
+ *
+ * @return the minimum
+ *
+ * @exception SWTException <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 getMinimum () {
+ checkWidget();
+ return minimum;
+}
+
+/**
+ * Returns the amount that the receiver's value will be
+ * modified by when the page increment/decrement areas
+ * are selected.
+ *
+ * @return the page increment
+ *
+ * @exception SWTException <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 getPageIncrement () {
+ checkWidget();
+ return pageIncrement;
+}
+
+/**
+ * Returns the 'selection', which is the receiver's value.
+ *
+ * @return the selection
+ *
+ * @exception SWTException <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 getSelection () {
+ checkWidget();
+ NSScroller widget = (NSScroller)view;
+ double value = widget.doubleValue();
+ return (int)(0.5f + ((maximum - thumb - minimum) * value + minimum));
+}
+
+/**
+ * Returns the size of the receiver's thumb relative to the
+ * difference between its maximum and minimum values.
+ *
+ * @return the thumb value
+ *
+ * @exception SWTException <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 getThumb () {
+ checkWidget();
+ return thumb;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the user changes the receiver's value.
+ *
+ * @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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook(SWT.Selection, listener);
+ eventTable.unhook(SWT.DefaultSelection,listener);
+}
+
+void sendSelection () {
+ Event event = new Event();
+ int hitPart = (int)/*64*/((NSScroller)view).hitPart();
+ int value = getSelection ();
+ switch (hitPart) {
+ case OS.NSScrollerDecrementLine:
+ event.detail = SWT.ARROW_UP;
+ value -= increment;
+ break;
+ case OS.NSScrollerDecrementPage:
+ value -= pageIncrement;
+ event.detail = SWT.PAGE_UP;
+ break;
+ case OS.NSScrollerIncrementLine:
+ value += increment;
+ event.detail = SWT.ARROW_DOWN;
+ break;
+ case OS.NSScrollerIncrementPage:
+ value += pageIncrement;
+ event.detail = SWT.PAGE_DOWN;
+ break;
+ case OS.NSScrollerKnob:
+ event.detail = SWT.DRAG;
+ break;
+ }
+ if (event.detail != SWT.DRAG) {
+ setSelection(value);
+ }
+ sendEvent(SWT.Selection, event);
+}
+
+/**
+ * Sets the amount that the receiver's value will be
+ * modified by when the up/down (or right/left) arrows
+ * are pressed to the argument, which must be at least
+ * one.
+ *
+ * @param value the new increment (must be greater than zero)
+ *
+ * @exception SWTException <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 setIncrement (int value) {
+ checkWidget();
+ if (value < 1) return;
+ increment = value;
+}
+
+/**
+ * Sets the maximum. If this value is negative or less than or
+ * equal to the minimum, the value is ignored. If necessary, first
+ * the thumb and then the selection are adjusted to fit within the
+ * new range.
+ *
+ * @param value the new maximum, which must be greater than the current minimum
+ *
+ * @exception SWTException <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 setMaximum (int value) {
+ checkWidget();
+ if (value < 0) return;
+ if (value <= minimum) return;
+ if (value - minimum < thumb) {
+ thumb = value - minimum;
+ }
+ int selection = Math.max(minimum, Math.min (getSelection (), value - thumb));
+ this.maximum = value;
+ updateBar(selection, minimum, value, thumb);
+}
+
+/**
+ * Sets the minimum value. If this value is negative or greater
+ * than or equal to the maximum, the value is ignored. If necessary,
+ * first the thumb and then the selection are adjusted to fit within
+ * the new range.
+ *
+ * @param value the new minimum
+ *
+ * @exception SWTException <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 setMinimum (int value) {
+ checkWidget();
+ if (value < 0) return;
+ if (value >= maximum) return;
+ if (maximum - value < thumb) {
+ thumb = maximum - value;
+ }
+ int selection = Math.min(maximum - thumb, Math.max (getSelection (), value));
+ this.minimum = value;
+ updateBar(selection, value, maximum, thumb);
+}
+
+/**
+ * Sets the amount that the receiver's value will be
+ * modified by when the page increment/decrement areas
+ * are selected to the argument, which must be at least
+ * one.
+ *
+ * @param value the page increment (must be greater than zero)
+ *
+ * @exception SWTException <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 setPageIncrement (int value) {
+ checkWidget();
+ if (value < 1) return;
+ pageIncrement = value;
+}
+
+/**
+ * Sets the 'selection', which is the receiver's
+ * value, to the argument which must be greater than or equal
+ * to zero.
+ *
+ * @param value the new selection (must be zero or greater)
+ *
+ * @exception SWTException <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 setSelection (int value) {
+ checkWidget();
+ updateBar(value, minimum, maximum, thumb);
+}
+
+void setSmallSize () {
+ /* This code is intentionally comment */
+// ((NSScroller)view).setControlSize (OS.NSSmallControlSize);
+}
+
+void updateBar (int selection, int minimum, int maximum, int thumb) {
+ NSScroller widget = (NSScroller)view;
+ selection = Math.max (minimum, Math.min (maximum - thumb, selection));
+ int range = maximum - thumb - minimum;
+ float fraction = range <= 0 ? 1 : (float)(selection - minimum) / range;
+ float knob = range <= 0 ? 1 : (float)thumb / (maximum - minimum);
+ widget.setFloatValue (fraction, knob);
+}
+
+/**
+ * Sets the size of the receiver's thumb relative to the
+ * difference between its maximum and minimum values. This new
+ * value will be ignored if it is less than one, and will be
+ * clamped if it exceeds the receiver's current range.
+ *
+ * @param value the new thumb value, which must be at least one and not
+ * larger than the size of the current range
+ *
+ * @exception SWTException <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 setThumb (int value) {
+ checkWidget();
+ if (value < 1) return;
+ value = Math.min (value, maximum - minimum);
+ updateBar(getSelection(), minimum, maximum, value);
+ this.thumb = value;
+}
+
+/**
+ * Sets the receiver's selection, minimum value, maximum
+ * value, thumb, increment and page increment all at once.
+ * <p>
+ * Note: This is similar to setting the values individually
+ * using the appropriate methods, but may be implemented in a
+ * more efficient fashion on some platforms.
+ * </p>
+ *
+ * @param selection the new selection value
+ * @param minimum the new minimum value
+ * @param maximum the new maximum value
+ * @param thumb the new thumb value
+ * @param increment the new increment value
+ * @param pageIncrement the new pageIncrement value
+ *
+ * @exception SWTException <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 setValues (int selection, int minimum, int maximum, int thumb, int increment, int pageIncrement) {
+ checkWidget();
+ if (minimum < 0) return;
+ if (maximum < 0) return;
+ if (thumb < 1) return;
+ if (increment < 1) return;
+ if (pageIncrement < 1) return;
+ thumb = Math.min (thumb, maximum - minimum);
+ this.thumb = thumb;
+ this.maximum = maximum;
+ this.minimum = minimum;
+ this.increment = increment;
+ this.pageIncrement = pageIncrement;
+ updateBar(selection, minimum, maximum, thumb);
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Spinner.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Spinner.java
new file mode 100755
index 0000000000..6c53ac470b
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Spinner.java
@@ -0,0 +1,1064 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class are selectable user interface
+ * objects that allow the user to enter and modify numeric
+ * values.
+ * <p>
+ * Note that although this class is a subclass of <code>Composite</code>,
+ * it does not make sense to add children to it, or set a layout on it.
+ * </p><p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>READ_ONLY, WRAP</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection, Modify, Verify</dd>
+ * </dl>
+ * </p><p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#spinner">Spinner snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.1
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Spinner extends Composite {
+ NSTextField textView;
+ NSNumberFormatter textFormatter;
+ NSStepper buttonView;
+ int pageIncrement = 10;
+ int digits = 0;
+ int textLimit = LIMIT;
+ static int GAP = 0;
+
+ /**
+ * the operating system limit for the number of characters
+ * that the text field in an instance of this class can hold
+ *
+ * @since 3.4
+ */
+ public static final int LIMIT;
+
+ /*
+ * These values can be different on different platforms.
+ * Therefore they are not initialized in the declaration
+ * to stop the compiler from inlining.
+ */
+ static {
+ LIMIT = 0x7FFFFFFF;
+ }
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#READ_ONLY
+ * @see SWT#WRAP
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Spinner (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+boolean acceptsFirstResponder(int /*long*/ id, int /*long*/ sel) {
+ if (id == view.id) return false;
+ return super.acceptsFirstResponder (id, sel);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the receiver's text is modified, by sending
+ * it one of the messages defined in the <code>ModifyListener</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 SWTException <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 ModifyListener
+ * @see #removeModifyListener
+ */
+public void addModifyListener (ModifyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Modify, 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 not called for texts.
+ * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed in a single-line text.
+ * </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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener(listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the receiver's text is verified, by sending
+ * it one of the messages defined in the <code>VerifyListener</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 SWTException <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 VerifyListener
+ * @see #removeVerifyListener
+ */
+void addVerifyListener (VerifyListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Verify, typedListener);
+}
+
+static int checkStyle (int style) {
+ /*
+ * Even though it is legal to create this widget
+ * with scroll bars, they serve no useful purpose
+ * because they do not automatically scroll the
+ * widget's client area. The fix is to clear
+ * the SWT style.
+ */
+ return style & ~(SWT.H_SCROLL | SWT.V_SCROLL);
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ float /*double*/ width = 0, height = 0;
+ String string = Double.toString (buttonView.maxValue ());
+ Font font = Font.cocoa_new(display, textView.font ());
+ NSAttributedString str = parent.createString(string, font, null, 0, true, false);
+ NSSize size = str.size ();
+ str.release ();
+ width = (float)/*64*/size.width;
+ height = (float)/*64*/size.height;
+ NSRect frameRect = textView.frame();
+ NSCell cell = new NSCell (textView.cell ());
+ NSRect cellRect = cell.drawingRectForBounds(frameRect);
+ width += frameRect.width - cellRect.width;
+ height += frameRect.height - cellRect.height;
+ width += GAP;
+ size = buttonView.cell ().cellSize ();
+ width += (int)/*64*/size.width;
+ height = Math.max (height, size.height);
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ Rectangle trim = computeTrim (0, 0, (int)Math.ceil (width), (int)Math.ceil (height));
+ return new Point (trim.width, trim.height);
+}
+
+/**
+ * Copies the selected text.
+ * <p>
+ * The current selection is copied to the clipboard.
+ * </p>
+ *
+ * @exception SWTException <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 copy () {
+ checkWidget ();
+ NSText fieldEditor = textView.currentEditor();
+ if (fieldEditor != null) {
+ fieldEditor.copy(null);
+ } else {
+ //TODO
+ }
+}
+
+void createHandle () {
+ NSView widget = (NSView)new SWTView().alloc();
+ widget.init();
+// widget.setDrawsBackground(false);
+ NSStepper buttonWidget = (NSStepper)new SWTStepper().alloc();
+ buttonWidget.init();
+ buttonWidget.setValueWraps((style & SWT.WRAP) != 0);
+ buttonWidget.setTarget(buttonWidget);
+ buttonWidget.setAction(OS.sel_sendSelection);
+ buttonWidget.setMaxValue(100);
+ NSTextField textWidget = (NSTextField)new SWTTextField().alloc();
+ textWidget.init();
+// textWidget.setTarget(widget);
+ textWidget.setEditable((style & SWT.READ_ONLY) == 0);
+ textFormatter = (NSNumberFormatter)new NSNumberFormatter().alloc();
+ textFormatter.init();
+ widget.addSubview(textWidget);
+ widget.addSubview(buttonWidget);
+ buttonView = buttonWidget;
+ textView = textWidget;
+ view = widget;
+ setSelection (0, false, true, false);
+}
+
+/**
+ * Cuts the selected text.
+ * <p>
+ * The current selection is first copied to the
+ * clipboard and then deleted from the widget.
+ * </p>
+ *
+ * @exception SWTException <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 cut () {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) return;
+ NSText fieldEditor = textView.currentEditor();
+ if (fieldEditor != null) {
+ fieldEditor.cut(null);
+ } else {
+ //TODO
+ }
+}
+
+void enableWidget (boolean enabled) {
+ super.enableWidget(enabled);
+ buttonView.setEnabled(enabled);
+ textView.setEnabled(enabled);
+}
+
+NSFont defaultNSFont () {
+ return display.textFieldFont;
+}
+
+void deregister () {
+ super.deregister ();
+ if (textView != null) {
+ display.removeWidget (textView);
+ display.removeWidget (textView.cell());
+ }
+
+ if (buttonView != null) {
+ display.removeWidget (buttonView);
+ display.removeWidget (buttonView.cell());
+ }
+}
+
+NSView focusView () {
+ return textView;
+}
+
+/**
+ * Returns the number of decimal places used by the receiver.
+ *
+ * @return the digits
+ *
+ * @exception SWTException <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 getDigits () {
+ checkWidget ();
+ return digits;
+}
+
+/**
+ * Returns the amount that the receiver's value will be
+ * modified by when the up/down arrows are pressed.
+ *
+ * @return the increment
+ *
+ * @exception SWTException <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 getIncrement () {
+ checkWidget ();
+ return (int)buttonView.increment();
+}
+
+/**
+ * Returns the maximum value which the receiver will allow.
+ *
+ * @return the maximum
+ *
+ * @exception SWTException <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 getMaximum () {
+ checkWidget ();
+ return (int)buttonView.maxValue();
+}
+
+/**
+ * Returns the minimum value which the receiver will allow.
+ *
+ * @return the minimum
+ *
+ * @exception SWTException <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 getMinimum () {
+ checkWidget ();
+ return (int)buttonView.minValue();
+}
+
+/**
+ * Returns the amount that the receiver's position will be
+ * modified by when the page up/down keys are pressed.
+ *
+ * @return the page increment
+ *
+ * @exception SWTException <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 getPageIncrement () {
+ checkWidget ();
+ return pageIncrement;
+}
+
+/**
+ * Returns the <em>selection</em>, which is the receiver's position.
+ *
+ * @return the selection
+ *
+ * @exception SWTException <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 getSelection () {
+ checkWidget ();
+ return (int)((NSStepper)buttonView).doubleValue();
+}
+
+int getSelectionText (boolean[] parseFail) {
+ String string = textView.stringValue().getString();
+ try {
+ int value;
+ if (digits > 0) {
+ String decimalSeparator = textFormatter.decimalSeparator().getString();
+ int index = string.indexOf (decimalSeparator);
+ if (index != -1) {
+ int startIndex = string.startsWith ("+") || string.startsWith ("-") ? 1 : 0;
+ String wholePart = startIndex != index ? string.substring (startIndex, index) : "0";
+ String decimalPart = string.substring (index + 1);
+ if (decimalPart.length () > digits) {
+ decimalPart = decimalPart.substring (0, digits);
+ } else {
+ int i = digits - decimalPart.length ();
+ for (int j = 0; j < i; j++) {
+ decimalPart = decimalPart + "0";
+ }
+ }
+ int wholeValue = Integer.parseInt (wholePart);
+ int decimalValue = Integer.parseInt (decimalPart);
+ for (int i = 0; i < digits; i++) wholeValue *= 10;
+ value = wholeValue + decimalValue;
+ if (string.startsWith ("-")) value = -value;
+ } else {
+ value = Integer.parseInt (string);
+ for (int i = 0; i < digits; i++) value *= 10;
+ }
+ } else {
+ value = Integer.parseInt (string);
+ }
+ int max = getMaximum();
+ int min = getMinimum();
+ if (min <= value && value <= max) return value;
+ } catch (NumberFormatException e) {
+ }
+ parseFail [0] = true;
+ return -1;
+}
+
+/**
+ * Returns a string containing a copy of the contents of the
+ * receiver's text field, or an empty string if there are no
+ * contents.
+ *
+ * @return the receiver's text
+ *
+ * @exception SWTException <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.4
+ */
+public String getText () {
+ checkWidget ();
+ NSString str = new NSTextFieldCell (textView.cell ()).title ();
+ return str.getString ();
+}
+
+/**
+ * Returns the maximum number of characters that the receiver's
+ * text field is capable of holding. If this has not been changed
+ * by <code>setTextLimit()</code>, it will be the constant
+ * <code>Spinner.LIMIT</code>.
+ *
+ * @return the text limit
+ *
+ * @exception SWTException <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 #LIMIT
+ *
+ * @since 3.4
+ */
+public int getTextLimit () {
+ checkWidget();
+ return textLimit;
+}
+
+boolean isEventView (int /*long*/ id) {
+ return true;
+}
+
+/**
+ * Pastes text from clipboard.
+ * <p>
+ * The selected text is deleted from the widget
+ * and new text inserted from the clipboard.
+ * </p>
+ *
+ * @exception SWTException <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 paste () {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) return;
+ NSText fieldEditor = textView.currentEditor();
+ if (fieldEditor != null) {
+ fieldEditor.paste(null);
+ } else {
+ //TODO
+ }
+}
+
+void register () {
+ super.register ();
+ if (textView != null) {
+ display.addWidget (textView, this);
+ display.addWidget (textView.cell(), this);
+ }
+
+ if (buttonView != null) {
+ display.addWidget (buttonView, this);
+ display.addWidget (buttonView.cell(), this);
+ }
+}
+
+void releaseHandle () {
+ super.releaseHandle();
+ if (textFormatter != null) textFormatter.release();
+ if (buttonView != null) buttonView.release();
+ if (textView != null) textView.release();
+ textFormatter = null;
+ buttonView = null;
+ textView = null;
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ if (textView != null) textView.abortEditing();
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the receiver's text is modified.
+ *
+ * @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 SWTException <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 ModifyListener
+ * @see #addModifyListener
+ */
+public void removeModifyListener (ModifyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Modify, 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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the control is verified.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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 VerifyListener
+ * @see #addVerifyListener
+ */
+void removeVerifyListener (VerifyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Verify, listener);
+}
+
+void resized () {
+ super.resized ();
+ buttonView.sizeToFit();
+ NSSize textSize = textView.cell ().cellSize ();
+ NSRect buttonFrame = buttonView.bounds();
+ NSRect frame = view.frame();
+ buttonFrame.x = frame.width - buttonFrame.width;
+ buttonFrame.y = (frame.height - buttonFrame.height) / 2;
+ int textHeight = (int)Math.min(textSize.height, frame.height);
+ frame.x = 0;
+ frame.y = (frame.height - textHeight) / 2;
+ frame.width -= buttonFrame.width + GAP;
+ frame.height = textHeight;
+ textView.setFrame(frame);
+ buttonView.setFrame(buttonFrame);
+}
+
+boolean sendKeyEvent (NSEvent nsEvent, int type) {
+ boolean result = super.sendKeyEvent (nsEvent, type);
+ if (!result) return result;
+ if (type != SWT.KeyDown) return result;
+ int delta = 0;
+ short keyCode = nsEvent.keyCode ();
+ switch (keyCode) {
+ case 76: /* KP Enter */
+ case 36: { /* Return */
+ postEvent (SWT.DefaultSelection);
+ return true;
+ }
+
+ case 116: delta = pageIncrement; break; /* Page Up */
+ case 121: delta = -pageIncrement; break; /* Page Down */
+ case 125: delta = -getIncrement(); break; /* Down arrow */
+ case 126: delta = getIncrement(); break; /* Up arrow */
+ }
+
+ if (delta != 0) {
+ boolean [] parseFail = new boolean [1];
+ int value = getSelectionText (parseFail);
+ if (parseFail [0]) {
+ value = (int)buttonView.doubleValue();
+ }
+ int newValue = value + delta;
+ int max = (int)buttonView.maxValue();
+ int min = (int)buttonView.minValue();
+ if ((style & SWT.WRAP) != 0) {
+ if (newValue > max) newValue = min;
+ if (newValue < min) newValue = max;
+ }
+ newValue = Math.min (Math.max (min, newValue), max);
+ if (value != newValue) setSelection (newValue, true, true, true);
+ // Prevent the arrow or page up/down from being handled by the text field.
+ result = false;
+ } else {
+ boolean [] parseFail = new boolean [1];
+ int value = getSelectionText (parseFail);
+ if (!parseFail [0]) {
+ int pos = (int)buttonView.doubleValue();
+ if (pos != value) setSelection (value, true, false, true);
+ }
+ }
+
+ return result;
+}
+
+void sendSelection () {
+ setSelection (getSelection(), false, true, true);
+}
+
+void updateBackground () {
+ NSColor nsColor = null;
+ if (backgroundImage != null) {
+ nsColor = NSColor.colorWithPatternImage(backgroundImage.handle);
+ } else if (background != null) {
+ nsColor = NSColor.colorWithDeviceRed(background[0], background[1], background[2], background[3]);
+ } else {
+ nsColor = NSColor.textBackgroundColor ();
+ }
+ ((NSTextField) textView).setBackgroundColor (nsColor);
+}
+
+/**
+ * Sets the number of decimal places used by the receiver.
+ * <p>
+ * The digit setting is used to allow for floating point values in the receiver.
+ * For example, to set the selection to a floating point value of 1.37 call setDigits() with
+ * a value of 2 and setSelection() with a value of 137. Similarly, if getDigits() has a value
+ * of 2 and getSelection() returns 137 this should be interpreted as 1.37. This applies to all
+ * numeric APIs.
+ * </p>
+ *
+ * @param value the new digits (must be greater than or equal to zero)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the value is less than zero</li>
+ * </ul>
+ * @exception SWTException <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 setDigits (int value) {
+ checkWidget ();
+ if (value < 0) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (value == digits) return;
+ digits = value;
+ int pos = (int)buttonView.doubleValue();
+ setSelection (pos, false, true, false);
+}
+
+void setFont(NSFont font) {
+ textView.setFont(font);
+}
+
+void setForeground (float /*double*/ [] color) {
+ NSColor nsColor;
+ if (color == null) {
+ nsColor = NSColor.textColor ();
+ } else {
+ nsColor = NSColor.colorWithDeviceRed (color [0], color [1], color [2], 1);
+ }
+ ((NSTextField) textView).setTextColor (nsColor);
+}
+
+/**
+ * Sets the amount that the receiver's value will be
+ * modified by when the up/down arrows are pressed to
+ * the argument, which must be at least one.
+ *
+ * @param value the new increment (must be greater than zero)
+ *
+ * @exception SWTException <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 setIncrement (int value) {
+ checkWidget ();
+ if (value < 1) return;
+ buttonView.setIncrement(value);
+}
+
+/**
+ * Sets the maximum value that the receiver will allow. This new
+ * value will be ignored if it is not greater than the receiver's current
+ * minimum value. If the new maximum is applied then the receiver's
+ * selection value will be adjusted if necessary to fall within its new range.
+ *
+ * @param value the new maximum, which must be greater than the current minimum
+ *
+ * @exception SWTException <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 setMaximum (int value) {
+ checkWidget ();
+ int min = getMinimum ();
+ if (value <= min) return;
+ int pos = getSelection();
+ buttonView.setMaxValue(value);
+ if (pos > value) setSelection (value, true, true, false);
+}
+
+/**
+ * Sets the minimum value that the receiver will allow. This new
+ * value will be ignored if it is not less than the receiver's
+ * current maximum value. If the new minimum is applied then the receiver's
+ * selection value will be adjusted if necessary to fall within its new range.
+ *
+ * @param value the new minimum, which must be less than the current maximum
+ *
+ * @exception SWTException <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 setMinimum (int value) {
+ checkWidget ();
+ int max = getMaximum();
+ if (value >= max) return;
+ int pos = getSelection();
+ buttonView.setMinValue(value);
+ if (pos < value) setSelection (value, true, true, false);
+}
+
+/**
+ * Sets the amount that the receiver's position will be
+ * modified by when the page up/down keys are pressed
+ * to the argument, which must be at least one.
+ *
+ * @param value the page increment (must be greater than zero)
+ *
+ * @exception SWTException <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 setPageIncrement (int value) {
+ checkWidget ();
+ if (value < 1) return;
+ pageIncrement = value;
+}
+
+/**
+ * Sets the <em>selection</em>, which is the receiver's
+ * position, to the argument. If the argument is not within
+ * the range specified by minimum and maximum, it will be
+ * adjusted to fall within this range.
+ *
+ * @param value the new selection (must be zero or greater)
+ *
+ * @exception SWTException <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 setSelection (int value) {
+ checkWidget ();
+ int min = getMinimum();
+ int max = getMaximum();
+ value = Math.min (Math.max (min, value), max);
+ setSelection (value, true, true, false);
+}
+
+void setSelection (int value, boolean setPos, boolean setText, boolean notify) {
+ if (setPos) {
+ ((NSStepper)buttonView).setDoubleValue(value);
+ }
+ if (setText) {
+ String string = String.valueOf (value);
+ if (digits > 0) {
+ String decimalSeparator = textFormatter.decimalSeparator().getString();
+ int index = string.length () - digits;
+ StringBuffer buffer = new StringBuffer ();
+ if (index > 0) {
+ buffer.append (string.substring (0, index));
+ buffer.append (decimalSeparator);
+ buffer.append (string.substring (index));
+ } else {
+ buffer.append ("0");
+ buffer.append (decimalSeparator);
+ while (index++ < 0) buffer.append ("0");
+ buffer.append (string);
+ }
+ string = buffer.toString ();
+ }
+ NSCell cell = new NSCell(textView.cell());
+ if (hooks (SWT.Verify) || filters (SWT.Verify)) {
+ int length = (int)/*64*/cell.title().length();
+ string = verifyText (string, 0, length, null);
+ if (string == null) return;
+ }
+ textView.setStringValue(NSString.stringWith(string));
+ NSRange selection = new NSRange();
+ selection.location = 0;
+ selection.length = string.length();
+ NSText fieldEditor = textView.currentEditor();
+ if (fieldEditor != null) fieldEditor.setSelectedRange(selection);
+ sendEvent (SWT.Modify);
+ }
+ if (notify) postEvent (SWT.Selection);
+}
+
+void setSmallSize () {
+ textView.cell ().setControlSize (OS.NSSmallControlSize);
+ buttonView.cell ().setControlSize (OS.NSSmallControlSize);
+}
+
+/**
+ * Sets the maximum number of characters that the receiver's
+ * text field is capable of holding to be the argument.
+ * <p>
+ * To reset this value to the default, use <code>setTextLimit(Spinner.LIMIT)</code>.
+ * Specifying a limit value larger than <code>Spinner.LIMIT</code> sets the
+ * receiver's limit to <code>Spinner.LIMIT</code>.
+ * </p>
+ * @param limit new text limit
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li>
+ * </ul>
+ * @exception SWTException <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 #LIMIT
+ *
+ * @since 3.4
+ */
+public void setTextLimit (int limit) {
+ checkWidget();
+ if (limit == 0) error (SWT.ERROR_CANNOT_BE_ZERO);
+ textLimit = limit;
+}
+
+/**
+ * Sets the receiver's selection, minimum value, maximum
+ * value, digits, increment and page increment all at once.
+ * <p>
+ * Note: This is similar to setting the values individually
+ * using the appropriate methods, but may be implemented in a
+ * more efficient fashion on some platforms.
+ * </p>
+ *
+ * @param selection the new selection value
+ * @param minimum the new minimum value
+ * @param maximum the new maximum value
+ * @param digits the new digits value
+ * @param increment the new increment value
+ * @param pageIncrement the new pageIncrement value
+ *
+ * @exception SWTException <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 setValues (int selection, int minimum, int maximum, int digits, int increment, int pageIncrement) {
+ checkWidget ();
+ if (maximum <= minimum) return;
+ if (digits < 0) return;
+ if (increment < 1) return;
+ if (pageIncrement < 1) return;
+ selection = Math.min (Math.max (minimum, selection), maximum);
+ this.pageIncrement = pageIncrement;
+ this.digits = digits;
+ buttonView.setIncrement(increment);
+ buttonView.setMaxValue(maximum);
+ buttonView.setMinValue(minimum);
+ setSelection (selection, true, true, false);
+}
+
+boolean shouldChangeTextInRange_replacementString(int /*long*/ id, int /*long*/ sel, int /*long*/ affectedCharRange, int /*long*/ replacementString) {
+ NSRange range = new NSRange();
+ OS.memmove(range, affectedCharRange, NSRange.sizeof);
+ boolean result = callSuperBoolean(id, sel, range, replacementString);
+ if (hooks (SWT.Verify)) {
+ String text = new NSString(replacementString).getString();
+ NSEvent currentEvent = display.application.currentEvent();
+ int /*long*/ type = currentEvent.type();
+ if (type != OS.NSKeyDown && type != OS.NSKeyUp) currentEvent = null;
+ String newText = verifyText(text, (int)/*64*/range.location, (int)/*64*/(range.location+range.length), currentEvent);
+ if (newText == null) return false;
+ if (text != newText) {
+ int length = newText.length();
+ NSText fieldEditor = textView.currentEditor ();
+ if (fieldEditor != null) {
+ NSRange selectedRange = fieldEditor.selectedRange();
+ if (textLimit != LIMIT) {
+ int /*long*/ charCount = fieldEditor.string().length();
+ if (charCount - selectedRange.length + length > textLimit) {
+ length = (int)/*64*/(textLimit - charCount + selectedRange.length);
+ }
+ }
+ char [] buffer = new char [length];
+ newText.getChars (0, buffer.length, buffer, 0);
+ NSString nsstring = NSString.stringWithCharacters (buffer, buffer.length);
+ fieldEditor.replaceCharactersInRange (fieldEditor.selectedRange (), nsstring);
+ result = false;
+ }
+ }
+ if (!result) sendEvent (SWT.Modify);
+ }
+ return result;
+}
+
+void textDidChange (int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+ super.textDidChange (id, sel, aNotification);
+ boolean [] parseFail = new boolean [1];
+ int value = getSelectionText (parseFail);
+ if (!parseFail [0]) {
+ int pos = (int)buttonView.doubleValue();
+ if (value != pos) {
+ setSelection (value, true, false, true);
+ }
+ }
+ postEvent (SWT.Modify);
+}
+
+NSRange textView_willChangeSelectionFromCharacterRange_toCharacterRange (int /*long*/ id, int /*long*/ sel, int /*long*/ aTextView, int /*long*/ oldSelectedCharRange, int /*long*/ newSelectedCharRange) {
+ /* allow the selection change to proceed */
+ NSRange result = new NSRange ();
+ OS.memmove(result, newSelectedCharRange, NSRange.sizeof);
+ return result;
+}
+
+void textDidEndEditing(int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+ boolean [] parseFail = new boolean [1];
+ int value = getSelectionText (parseFail);
+ if (parseFail [0]) {
+ value = (int)buttonView.doubleValue();
+ setSelection (value, false, true, false);
+ }
+ super.textDidEndEditing(id, sel, aNotification);
+}
+
+void updateCursorRects (boolean enabled) {
+ super.updateCursorRects (enabled);
+ updateCursorRects (enabled, textView);
+ updateCursorRects (enabled, buttonView);
+}
+
+String verifyText (String string, int start, int end, NSEvent keyEvent) {
+ Event event = new Event ();
+ if (keyEvent != null) setKeyState(event, SWT.MouseDown, keyEvent);
+ event.text = string;
+ event.start = start;
+ event.end = end;
+ int index = 0;
+ if (digits > 0) {
+ String decimalSeparator = ".";//getDecimalSeparator ();
+ index = string.indexOf (decimalSeparator);
+ if (index != -1) {
+ string = string.substring (0, index) + string.substring (index + 1);
+ }
+ index = 0;
+ }
+ while (index < string.length ()) {
+ if (!Character.isDigit (string.charAt (index))) break;
+ index++;
+ }
+ event.doit = index == string.length ();
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the verify
+ * event. If this happens, answer null to cancel
+ * the operation.
+ */
+ sendEvent (SWT.Verify, event);
+ if (!event.doit || isDisposed ()) return null;
+ return event.text;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TabFolder.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TabFolder.java
new file mode 100755
index 0000000000..095bb05eda
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TabFolder.java
@@ -0,0 +1,652 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Instances of this class implement the notebook user interface
+ * metaphor. It allows the user to select a notebook page from
+ * set of pages.
+ * <p>
+ * The item children that may be added to instances of this class
+ * must be of type <code>TabItem</code>.
+ * <code>Control</code> children are created and then set into a
+ * tab item using <code>TabItem#setControl</code>.
+ * </p><p>
+ * Note that although this class is a subclass of <code>Composite</code>,
+ * it does not make sense to set a layout on it.
+ * </p><p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>TOP, BOTTOM</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles TOP and BOTTOM 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/#tabfolder">TabFolder, TabItem snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class TabFolder extends Composite {
+ TabItem [] items;
+ int itemCount;
+ boolean ignoreSelect;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT
+ * @see SWT#TOP
+ * @see SWT#BOTTOM
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TabFolder (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's selection, by sending
+ * it one of the messages defined in the <code>SelectionListener</code>
+ * interface.
+ * <p>
+ * When <code>widgetSelected</code> is called, the item field of the event object is valid.
+ * <code>widgetDefaultSelected</code> is not called.
+ * </p>
+ *
+ * @param listener the listener which should be notified when the user changes the receiver's selection
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+static int checkStyle (int style) {
+ style = checkBits (style, SWT.TOP, SWT.BOTTOM, 0, 0, 0, 0);
+ /*
+ * Even though it is legal to create this widget
+ * with scroll bars, they serve no useful purpose
+ * because they do not automatically scroll the
+ * widget's client area. The fix is to clear
+ * the SWT style.
+ */
+ return style & ~(SWT.H_SCROLL | SWT.V_SCROLL);
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ Point size = super.computeSize (wHint, hHint, changed);
+ if (wHint == SWT.DEFAULT && items.length > 0) {
+ NSSize minSize = ((NSTabView)view).minimumSize();
+ Rectangle trim = computeTrim (0, 0, (int)Math.ceil (minSize.width), 0);
+ size.x = Math.max (trim.width, size.x);
+ }
+ return size;
+}
+
+public Rectangle computeTrim (int x, int y, int width, int height) {
+ checkWidget ();
+ NSTabView widget = (NSTabView)view;
+ NSRect rect = widget.contentRect ();
+ x -= rect.x;
+ y -= rect.y;
+ NSRect frame = widget.frame();
+ width += Math.ceil (frame.width - rect.width);
+ height += Math.ceil (frame.height - rect.height);
+ return super.computeTrim (x, y, width, height);
+}
+
+void createHandle () {
+ NSTabView widget = (NSTabView)new SWTTabView().alloc();
+ widget.init ();
+ widget.setDelegate(widget);
+ if ((style & SWT.BOTTOM) != 0) {
+ widget.setTabViewType(OS.NSBottomTabsBezelBorder);
+ }
+ view = widget;
+}
+
+void createItem (TabItem item, int index) {
+ int count = itemCount;
+ if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE);
+ if (count == items.length) {
+ TabItem [] newItems = new TabItem [items.length + 4];
+ System.arraycopy (items, 0, newItems, 0, items.length);
+ items = newItems;
+ }
+ System.arraycopy (items, index, items, index + 1, count - index);
+ items [index] = item;
+ itemCount++;
+ NSTabViewItem nsItem = (NSTabViewItem)new NSTabViewItem().alloc().init();
+ item.nsItem = nsItem;
+ ((NSTabView)view).insertTabViewItem(nsItem, index);
+}
+
+void createWidget () {
+ super.createWidget ();
+ items = new TabItem [4];
+}
+
+NSFont defaultNSFont () {
+ return display.tabViewFont;
+}
+
+void destroyItem (TabItem item) {
+ int count = itemCount;
+ int index = 0;
+ while (index < count) {
+ if (items [index] == item) break;
+ index++;
+ }
+ if (index == count) return;
+ --count;
+ System.arraycopy (items, index + 1, items, index, count - index);
+ items [count] = null;
+ if (count == 0) {
+ items = new TabItem [4];
+ }
+ itemCount = count;
+ ((NSTabView)view).removeTabViewItem(item.nsItem);
+}
+
+Widget findTooltip (NSPoint pt) {
+ pt = view.convertPoint_fromView_ (pt, null);
+ NSTabViewItem nsItem = ((NSTabView)view).tabViewItemAtPoint (pt);
+ if (nsItem != null) {
+ for (int i = 0; i < itemCount; i++) {
+ TabItem item = items [i];
+ if (item.nsItem.id == nsItem.id) return item;
+ }
+ }
+ return super.findTooltip (pt);
+}
+
+public Rectangle getClientArea () {
+ checkWidget ();
+ NSRect rect = ((NSTabView)view).contentRect();
+ int x = Math.max (0, (int)rect.x);
+ int y = Math.max (0, (int)rect.y);
+ int width = Math.max (0, (int)Math.ceil (rect.width));
+ int height = Math.max (0, (int)Math.ceil (rect.height));
+ return new Rectangle (x, y, width, height);
+}
+
+/**
+ * Returns the item at the given, zero-relative index in the
+ * receiver. Throws an exception if the index is out of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 TabItem getItem (int index) {
+ checkWidget ();
+ int count = itemCount;
+ if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE);
+ return items [index];
+}
+
+/**
+ * Returns the tab item at the given point in the receiver
+ * or null if no such item exists. The point is in the
+ * coordinate system of the receiver.
+ *
+ * @param point the point used to locate the item
+ * @return the tab item at the given point, or null if the point is not in a tab item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception SWTException <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.4
+ */
+public TabItem getItem (Point point) {
+ checkWidget ();
+ if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
+ NSPoint nsPoint = new NSPoint ();
+ nsPoint.x = point.x;
+ nsPoint.y = point.y;
+ NSTabView tabView = (NSTabView) view;
+ NSTabViewItem tabViewItem = tabView.tabViewItemAtPoint (nsPoint);
+ for (int i = 0; i < itemCount; i++) {
+ NSTabViewItem item = items[i].nsItem;
+ if (item.isEqual (tabViewItem)) {
+ return items [i];
+ }
+ }
+ return null;
+}
+
+/**
+ * Returns the number of items contained in the receiver.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException <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 getItemCount () {
+ checkWidget ();
+ return itemCount;
+}
+
+/**
+ * Returns an array of <code>TabItem</code>s which are the items
+ * in the receiver.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ *
+ * @return the items in the receiver
+ *
+ * @exception SWTException <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 TabItem [] getItems () {
+ checkWidget ();
+ int count = itemCount;
+ TabItem [] result = new TabItem [count];
+ System.arraycopy (items, 0, result, 0, count);
+ return result;
+}
+
+/**
+ * Returns an array of <code>TabItem</code>s that are currently
+ * selected in the receiver. An empty array indicates that no
+ * items are selected.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its selection, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ * @return an array representing the selection
+ *
+ * @exception SWTException <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 TabItem [] getSelection () {
+ checkWidget ();
+ int index = getSelectionIndex ();
+ if (index == -1) return new TabItem [0];
+ return new TabItem [] {items [index]};
+}
+
+/**
+ * Returns the zero-relative index of the item which is currently
+ * selected in the receiver, or -1 if no item is selected.
+ *
+ * @return the index of the selected item
+ *
+ * @exception SWTException <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 getSelectionIndex () {
+ checkWidget ();
+ NSTabViewItem selected = ((NSTabView)view).selectedTabViewItem();
+ if (selected == null) return -1;
+ for (int i = 0; i < itemCount; i++) {
+ if (items[i].nsItem.id == selected.id) return i;
+ }
+ return -1;
+}
+
+float getThemeAlpha () {
+ return (background != null ? 1 : 0.25f) * parent.getThemeAlpha ();
+}
+
+/**
+ * Searches the receiver's list starting at the first item
+ * (index 0) until an item is found that is equal to the
+ * argument, and returns the index of that item. If no item
+ * is found, returns -1.
+ *
+ * @param item the search item
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * </ul>
+ * @exception SWTException <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 indexOf (TabItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int count = itemCount;
+ for (int i=0; i<count; i++) {
+ if (items [i] == item) return i;
+ }
+ return -1;
+}
+
+Point minimumSize (int wHint, int hHint, boolean flushCache) {
+ Control [] children = _getChildren ();
+ int width = 0, height = 0;
+ for (int i=0; i<children.length; i++) {
+ Control child = children [i];
+ int index = 0;
+ int count = itemCount;
+ while (index < count) {
+ if (items [index].control == child) break;
+ index++;
+ }
+ if (index == count) {
+ Rectangle rect = child.getBounds ();
+ width = Math.max (width, rect.x + rect.width);
+ height = Math.max (height, rect.y + rect.height);
+ } else {
+ Point size = child.computeSize (wHint, hHint, flushCache);
+ width = Math.max (width, size.x);
+ height = Math.max (height, size.y);
+ }
+ }
+ return new Point (width, height);
+}
+
+void releaseChildren (boolean destroy) {
+ if (items != null) {
+ for (int i=0; i<items.length; i++) {
+ TabItem item = items [i];
+ if (item != null && !item.isDisposed ()) {
+ item.release (false);
+ }
+ }
+ items = null;
+ }
+ super.releaseChildren (destroy);
+}
+
+void removeControl (Control control) {
+ super.removeControl (control);
+ int count = itemCount;
+ for (int i=0; i<count; i++) {
+ TabItem item = items [i];
+ if (item.control == control) item.setControl (null);
+ }
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the user changes the receiver's selection.
+ *
+ * @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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+void setFont (NSFont font) {
+ ((NSTabView)view).setFont(font);
+}
+
+/**
+ * Sets the receiver's selection to the given item.
+ * The current selected is first cleared, then the new item is
+ * selected.
+ *
+ * @param item the item to select
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * </ul>
+ * @exception SWTException <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 setSelection (TabItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setSelection (new TabItem [] {item});
+}
+
+/**
+ * Sets the receiver's selection to be the given array of items.
+ * The current selected is first cleared, then the new items are
+ * selected.
+ *
+ * @param items the array of items
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the items array is null</li>
+ * </ul>
+ * @exception SWTException <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 setSelection (TabItem [] items) {
+ checkWidget ();
+ if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (items.length == 0) {
+ setSelection (-1, false, false);
+ } else {
+ for (int i=items.length - 1; i>=0; --i) {
+ int index = indexOf (items [i]);
+ if (index != -1) setSelection (index, false, false);
+ }
+ }
+}
+
+/**
+ * Selects the item at the given zero-relative index in the receiver.
+ * If the item at the index was already selected, it remains selected.
+ * The current selection is first cleared, then the new items are
+ * selected. Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to select
+ *
+ * @exception SWTException <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 setSelection (int index) {
+ checkWidget ();
+ int count = itemCount;
+ if (!(0 <= index && index < count)) return;
+ setSelection (index, false, false);
+}
+
+void setSelection (int index, boolean notify, boolean force) {
+ if (!(0 <= index && index < itemCount)) return;
+ int currentIndex = getSelectionIndex ();
+ if (!force && currentIndex == index) return;
+ if (currentIndex != -1) {
+ TabItem item = items [currentIndex];
+ if (item != null) {
+ Control control = item.control;
+ if (control != null && !control.isDisposed ()) {
+ control.setVisible (false);
+ }
+ }
+ }
+ ignoreSelect = true;
+ ((NSTabView)view).selectTabViewItemAtIndex(index);
+ ignoreSelect = false;
+ index = getSelectionIndex();
+ if (index != -1) {
+ TabItem item = items [index];
+ if (item != null) {
+ Control control = item.control;
+ if (control != null && !control.isDisposed ()) {
+ control.setVisible (true);
+ }
+ if (notify) {
+ Event event = new Event ();
+ event.item = item;
+ sendEvent (SWT.Selection, event);
+ }
+ }
+ }
+}
+
+void setSmallSize () {
+ ((NSTabView)view).setControlSize (OS.NSSmallControlSize);
+}
+
+boolean traversePage (boolean next) {
+ int count = getItemCount ();
+ if (count == 0) return false;
+ int index = getSelectionIndex ();
+ if (index == -1) {
+ index = 0;
+ } else {
+ int offset = (next) ? 1 : -1;
+ index = (index + offset + count) % count;
+ }
+ setSelection (index, true, false);
+ return index == getSelectionIndex ();
+}
+
+void tabView_willSelectTabViewItem(int /*long*/ id, int /*long*/ sel, int /*long*/ tabView, int /*long*/ tabViewItem) {
+ if (tabViewItem == 0) return;
+ for (int i = 0; i < itemCount; i++) {
+ TabItem item = items [i];
+ if (item.nsItem.id == tabViewItem) {
+ int currentIndex = getSelectionIndex ();
+ if (currentIndex != -1) {
+ TabItem selected = items [currentIndex];
+ if (selected != null) {
+ Control control = selected.control;
+ if (control != null && !control.isDisposed ()) {
+ control.setVisible (false);
+ }
+ }
+ }
+ Control control = item.control;
+ if (control != null && !control.isDisposed ()) {
+ control.setVisible (true);
+ }
+ break;
+ }
+ }
+}
+
+void tabView_didSelectTabViewItem(int /*long*/ id, int /*long*/ sel, int /*long*/ tabView, int /*long*/ tabViewItem) {
+ if (tabViewItem == 0) return;
+ for (int i = 0; i < itemCount; i++) {
+ TabItem item = items [i];
+ /*
+ * Feature in Cocoa. For some reason the control on a tab being
+ * deselected has its parent removed natively. The fix is to
+ * re-set the control's parent.
+ */
+ Control control = item.control;
+ if (control != null) {
+ NSView topView = control.topView ();
+ if (topView.superview () == null) {
+ contentView ().addSubview (topView, OS.NSWindowBelow, null);
+ }
+ }
+ if (item.nsItem.id == tabViewItem) {
+ if (!ignoreSelect) {
+ Event event = new Event ();
+ event.item = item;
+ postEvent (SWT.Selection, event);
+ }
+ }
+ }
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TabItem.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TabItem.java
new file mode 100755
index 0000000000..dcbca3e71f
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TabItem.java
@@ -0,0 +1,373 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class represent a selectable user interface object
+ * corresponding to a tab for a page in a tab folder.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#tabfolder">TabFolder, TabItem snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class TabItem extends Item {
+ TabFolder parent;
+ Control control;
+ String toolTipText;
+ NSTabViewItem nsItem;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>TabFolder</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>SWT</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>SWT</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 SWTException <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 SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TabItem (TabFolder parent, int style) {
+ super (parent, style);
+ this.parent = parent;
+ parent.createItem (this, parent.getItemCount ());
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>TabFolder</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>SWT</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>SWT</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
+ * @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 SWTException <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 SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TabItem (TabFolder parent, int style, int index) {
+ super (parent, style);
+ this.parent = parent;
+ parent.createItem (this, index);
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+void destroyWidget () {
+ parent.destroyItem (this);
+ releaseHandle ();
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location
+ * relative to its parent.
+ *
+ * @return the receiver's bounding rectangle
+ *
+ * @exception SWTException <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.4
+ */
+public Rectangle getBounds() {
+ checkWidget();
+ Rectangle result = new Rectangle (0, 0, 0, 0);
+ if (nsItem.respondsToSelector (OS.sel_accessibilityAttributeValue_)) {
+ int /*long*/ posValue = OS.objc_msgSend (nsItem.id, OS.sel_accessibilityAttributeValue_, OS.NSAccessibilityPositionAttribute ());
+ int /*long*/ sizeValue = OS.objc_msgSend (nsItem.id, OS.sel_accessibilityAttributeValue_, OS.NSAccessibilitySizeAttribute ());
+ NSValue val = new NSValue (posValue);
+ NSPoint pt = val.pointValue ();
+ NSWindow window = parent.view.window ();
+ pt.y = display.getPrimaryFrame().height - pt.y;
+ pt = parent.view.convertPoint_fromView_ (pt, null);
+ pt = window.convertScreenToBase (pt);
+ result.x = (int) pt.x;
+ result.y = (int) pt.y;
+ val = new NSValue (sizeValue);
+ NSSize size = val.sizeValue ();
+ result.width = (int) Math.ceil (size.width);
+ result.height = (int) Math.ceil (size.height);
+ }
+ return result;
+}
+
+/**
+ * Returns the control that is used to fill the client area of
+ * the tab folder when the user selects the tab item. If no
+ * control has been set, return <code>null</code>.
+ * <p>
+ * @return the control
+ *
+ * @exception SWTException <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 Control getControl () {
+ checkWidget ();
+ return control;
+}
+
+/**
+ * Returns the receiver's parent, which must be a <code>TabFolder</code>.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException <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 TabFolder getParent () {
+ checkWidget ();
+ return parent;
+}
+
+/**
+ * Returns the receiver's tool tip text, or null if it has
+ * not been set.
+ *
+ * @return the receiver's tool tip text
+ *
+ * @exception SWTException <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 String getToolTipText () {
+ checkWidget ();
+ return toolTipText;
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (nsItem != null) nsItem.release();
+ nsItem = null;
+ parent = null;
+}
+
+void releaseParent () {
+ super.releaseParent ();
+ int index = parent.indexOf (this);
+ if (index == parent.getSelectionIndex ()) {
+ if (control != null) control.setVisible (false);
+ }
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ control = null;
+}
+
+/**
+ * Sets the control that is used to fill the client area of
+ * the tab folder when the user selects the tab item.
+ * <p>
+ * @param control the new control (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the control has been disposed</li>
+ * <li>ERROR_INVALID_PARENT - if the control is not in the same widget tree</li>
+ * </ul>
+ * @exception SWTException <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 setControl (Control control) {
+ checkWidget ();
+ if (control != null) {
+ if (control.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (control.parent != parent) error (SWT.ERROR_INVALID_PARENT);
+ }
+ if (this.control != null && this.control.isDisposed ()) {
+ this.control = null;
+ }
+ Control oldControl = this.control, newControl = control;
+ this.control = control;
+ int index = parent.indexOf (this), selectionIndex = parent.getSelectionIndex();;
+ if (index != selectionIndex) {
+ if (newControl != null) {
+ boolean hideControl = true;
+ if (selectionIndex != -1) {
+ Control selectedControl = parent.getItem(selectionIndex).getControl();
+ if (selectedControl == newControl) hideControl=false;
+ }
+ if (hideControl) newControl.setVisible(false);
+ }
+ } else {
+ if (newControl != null) {
+ newControl.setVisible (true);
+ }
+ if (oldControl != null) oldControl.setVisible (false);
+ }
+ NSView view;
+ if (newControl != null) {
+ view = newControl.topView();
+ } else {
+ view = (NSView)new NSView().alloc();
+ view.init ();
+ view.autorelease();
+ }
+ nsItem.setView (view);
+ /*
+ * Feature in Cocoa. The method setView() removes the old view from
+ * its parent. The fix is to detected it has been removed and add
+ * it back.
+ */
+ if (oldControl != null) {
+ NSView topView = oldControl.topView ();
+ if (topView.superview () == null) {
+ parent.contentView ().addSubview (topView, OS.NSWindowBelow, null);
+ }
+ }
+}
+
+public void setImage (Image image) {
+ checkWidget ();
+ int index = parent.indexOf (this);
+ if (index == -1) return;
+ super.setImage (image);
+}
+
+/**
+ * Sets the receiver's text. The string may include
+ * the mnemonic character.
+ * </p>
+ * <p>
+ * Mnemonics are indicated by an '&amp;' that causes the next
+ * character to be the mnemonic. When the user presses a
+ * key sequence that matches the mnemonic, a selection
+ * event occurs. On most platforms, the mnemonic appears
+ * underlined but may be emphasised in a platform specific
+ * manner. The mnemonic indicator character '&amp;' can be
+ * escaped by doubling it in the string, causing a single
+ * '&amp;' to be displayed.
+ * </p>
+ *
+ * @param string the new text
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
+ * </ul>
+ * @exception SWTException <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 setText (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int index = parent.indexOf (this);
+ if (index == -1) return;
+ super.setText (string);
+ char [] chars = new char [string.length ()];
+ string.getChars (0, chars.length, chars, 0);
+ int length = fixMnemonic (chars);
+ NSString str = NSString.stringWithCharacters (chars, length);
+ nsItem.setLabel (str);
+}
+
+/**
+ * Sets the receiver's tool tip text to the argument, which
+ * may be null indicating that the default tool tip for the
+ * control will be shown. For a control that has a default
+ * tool tip, such as the Tree control on Windows, setting
+ * the tool tip text to an empty string replaces the default,
+ * causing no tool tip text to be shown.
+ * <p>
+ * The mnemonic indicator (character '&amp;') is not displayed in a tool tip.
+ * To display a single '&amp;' in the tool tip, the character '&amp;' can be
+ * escaped by doubling it in the string.
+ * </p>
+ *
+ * @param string the new tool tip text (or null)
+ *
+ * @exception SWTException <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 setToolTipText (String string) {
+ checkWidget();
+ toolTipText = string;
+ parent.checkToolTip (this);
+}
+
+String tooltipText () {
+ return toolTipText;
+}
+
+void update () {
+ setText (text);
+ setImage (image);
+ setToolTipText (toolTipText);
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Table.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Table.java
new file mode 100755
index 0000000000..6eb9b700ac
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Table.java
@@ -0,0 +1,3087 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.accessibility.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class implement a selectable user interface
+ * object that displays a list of images and strings and issues
+ * notification when selected.
+ * <p>
+ * The item children that may be added to instances of this class
+ * must be of type <code>TableItem</code>.
+ * </p><p>
+ * Style <code>VIRTUAL</code> is used to create a <code>Table</code> whose
+ * <code>TableItem</code>s are to be populated by the client on an on-demand basis
+ * instead of up-front. This can provide significant performance improvements for
+ * tables that are very large or for which <code>TableItem</code> population is
+ * expensive (for example, retrieving values from an external source).
+ * </p><p>
+ * Here is an example of using a <code>Table</code> with style <code>VIRTUAL</code>:
+ * <code><pre>
+ * final Table table = new Table (parent, SWT.VIRTUAL | SWT.BORDER);
+ * table.setItemCount (1000000);
+ * table.addListener (SWT.SetData, new Listener () {
+ * public void handleEvent (Event event) {
+ * TableItem item = (TableItem) event.item;
+ * int index = table.indexOf (item);
+ * item.setText ("Item " + index);
+ * System.out.println (item.getText ());
+ * }
+ * });
+ * </pre></code>
+ * </p><p>
+ * Note that although this class is a subclass of <code>Composite</code>,
+ * it does not normally make sense to add <code>Control</code> children to
+ * it, or set a layout on it, unless implementing something like a cell
+ * editor.
+ * </p><p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>SINGLE, MULTI, CHECK, FULL_SELECTION, HIDE_SELECTION, VIRTUAL, NO_SCROLL</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection, DefaultSelection, SetData, MeasureItem, EraseItem, PaintItem</dd>
+ * </dl>
+ * </p><p>
+ * Note: Only one of the styles SINGLE, and MULTI 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/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Table extends Composite {
+ TableItem [] items;
+ TableColumn [] columns;
+ TableColumn sortColumn;
+ TableItem currentItem;
+ NSTableHeaderView headerView;
+ NSTableColumn firstColumn, checkColumn;
+ NSTextFieldCell dataCell;
+ NSButtonCell buttonCell;
+ int columnCount, itemCount, lastIndexOf, sortDirection;
+ boolean ignoreSelect, fixScrollWidth, drawExpansion;
+ Rectangle imageBounds;
+
+ static int NEXT_ID;
+
+ static final int FIRST_COLUMN_MINIMUM_WIDTH = 5;
+ static final int IMAGE_GAP = 3;
+ static final int TEXT_GAP = 2;
+ static final int CELL_GAP = 1;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#SINGLE
+ * @see SWT#MULTI
+ * @see SWT#CHECK
+ * @see SWT#FULL_SELECTION
+ * @see SWT#HIDE_SELECTION
+ * @see SWT#VIRTUAL
+ * @see SWT#NO_SCROLL
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Table (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+int /*long*/ accessibilityAttributeValue (int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+
+ if (accessible != null) {
+ NSString attribute = new NSString(arg0);
+ id returnValue = accessible.internal_accessibilityAttributeValue(attribute, ACC.CHILDID_SELF);
+ if (returnValue != null) return returnValue.id;
+ }
+
+ NSString attributeName = new NSString(arg0);
+
+ // Accessibility Verifier queries for a title or description. NSTableView doesn't
+ // seem to return either, so we return a default description value here.
+ if (attributeName.isEqualToString (OS.NSAccessibilityDescriptionAttribute)) {
+ return NSString.stringWith("").id;
+ }
+
+ return super.accessibilityAttributeValue(id, sel, arg0);
+}
+
+void _addListener (int eventType, Listener listener) {
+ super._addListener (eventType, listener);
+ clearCachedWidth(items);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's selection, by sending
+ * it one of the messages defined in the <code>SelectionListener</code>
+ * interface.
+ * <p>
+ * When <code>widgetSelected</code> is called, the item field of the event object is valid.
+ * If the receiver has the <code>SWT.CHECK</code> style and the check selection changes,
+ * the event object detail field contains the value <code>SWT.CHECK</code>.
+ * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked.
+ * The item field of the event object is valid for default selection, but the detail field is not used.
+ * </p>
+ *
+ * @param listener the listener which should be notified when the user changes the receiver's selection
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection, typedListener);
+ addListener (SWT.DefaultSelection, typedListener);
+}
+
+TableItem _getItem (int index) {
+ if ((style & SWT.VIRTUAL) == 0) return items [index];
+ if (items [index] != null) return items [index];
+ return items [index] = new TableItem (this, SWT.NULL, -1, false);
+}
+
+int calculateWidth (TableItem[] items, int index, GC gc) {
+ int width = 0;
+ for (int i=0; i < itemCount; i++) {
+ TableItem item = items [i];
+ if (item != null && item.cached) {
+ width = Math.max (width, item.calculateWidth (index, gc));
+ }
+ }
+ return width;
+}
+
+NSSize cellSize (int /*long*/ id, int /*long*/ sel) {
+ NSSize size = super.cellSize(id, sel);
+ NSImage image = new NSCell(id).image();
+ if (image != null) size.width += imageBounds.width + IMAGE_GAP;
+ if (hooks(SWT.MeasureItem)) {
+ int /*long*/ [] outValue = new int /*long*/ [1];
+ OS.object_getInstanceVariable(id, Display.SWT_ROW, outValue);
+ int /*long*/ rowIndex = outValue [0];
+ TableItem item = _getItem((int)/*64*/rowIndex);
+ OS.object_getInstanceVariable(id, Display.SWT_COLUMN, outValue);
+ int /*long*/ tableColumn = outValue[0];
+ int columnIndex = 0;
+ for (int i=0; i<columnCount; i++) {
+ if (columns [i].nsColumn.id == tableColumn) {
+ columnIndex = i;
+ break;
+ }
+ }
+ sendMeasureItem (item, columnIndex, size);
+ }
+ return size;
+}
+
+boolean canDragRowsWithIndexes_atPoint(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1) {
+ NSPoint clickPoint = new NSPoint();
+ OS.memmove(clickPoint, arg1, NSPoint.sizeof);
+ NSTableView table = (NSTableView)view;
+
+ // If the current row is not selected and the user is not attempting to modify the selection, select the row first.
+ int /*long*/ row = table.rowAtPoint(clickPoint);
+ int /*long*/ modifiers = NSApplication.sharedApplication().currentEvent().modifierFlags();
+
+ boolean drag = (state & DRAG_DETECT) != 0 && hooks (SWT.DragDetect);
+ if (drag) {
+ if (!table.isRowSelected(row) && (modifiers & (OS.NSCommandKeyMask | OS.NSShiftKeyMask | OS.NSAlternateKeyMask)) == 0) {
+ NSIndexSet set = (NSIndexSet)new NSIndexSet().alloc();
+ set = set.initWithIndex(row);
+ table.selectRowIndexes (set, false);
+ set.release();
+ }
+ }
+
+ // The clicked row must be selected to initiate a drag.
+ return (table.isRowSelected(row) && drag);
+}
+
+boolean checkData (TableItem item) {
+ return checkData (item, indexOf (item));
+}
+
+boolean checkData (TableItem item, int index) {
+ if (item.cached) return true;
+ if ((style & SWT.VIRTUAL) != 0) {
+ item.cached = true;
+ Event event = new Event ();
+ event.item = item;
+ event.index = indexOf (item);
+ currentItem = item;
+ sendEvent (SWT.SetData, event);
+ //widget could be disposed at this point
+ currentItem = null;
+ if (isDisposed () || item.isDisposed ()) return false;
+ if (!setScrollWidth (item)) item.redraw (-1);
+ }
+ return true;
+}
+
+static int checkStyle (int style) {
+ /*
+ * Feature in Windows. Even when WS_HSCROLL or
+ * WS_VSCROLL is not specified, Windows creates
+ * trees and tables with scroll bars. The fix
+ * is to set H_SCROLL and V_SCROLL.
+ *
+ * NOTE: This code appears on all platforms so that
+ * applications have consistent scroll bar behavior.
+ */
+ if ((style & SWT.NO_SCROLL) == 0) {
+ style |= SWT.H_SCROLL | SWT.V_SCROLL;
+ }
+ /* This platform is always FULL_SELECTION */
+ style |= SWT.FULL_SELECTION;
+ return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0);
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+/**
+ * Clears the item at the given zero-relative index in the receiver.
+ * The text, icon and other attributes of the item are set to the default
+ * value. If the table was created with the <code>SWT.VIRTUAL</code> style,
+ * these attributes are requested again as needed.
+ *
+ * @param index the index of the item to clear
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 SWT#VIRTUAL
+ * @see SWT#SetData
+ *
+ * @since 3.0
+ */
+public void clear (int index) {
+ checkWidget ();
+ if (!(0 <= index && index < itemCount)) error (SWT.ERROR_INVALID_RANGE);
+ TableItem item = items [index];
+ if (item != null) {
+ if (currentItem != item) item.clear ();
+ if (currentItem == null) item.redraw (-1);
+ setScrollWidth (item);
+ }
+}
+/**
+ * Removes the items from the receiver which are between the given
+ * zero-relative start and end indices (inclusive). The text, icon
+ * and other attributes of the items are set to their default values.
+ * If the table was created with the <code>SWT.VIRTUAL</code> style,
+ * these attributes are requested again as needed.
+ *
+ * @param start the start index of the item to clear
+ * @param end the end index of the item to clear
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if either the start or end are not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 SWT#VIRTUAL
+ * @see SWT#SetData
+ *
+ * @since 3.0
+ */
+public void clear (int start, int end) {
+ checkWidget ();
+ if (start > end) return;
+ if (!(0 <= start && start <= end && end < itemCount)) {
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ if (start == 0 && end == itemCount - 1) {
+ clearAll ();
+ } else {
+ for (int i=start; i<=end; i++) {
+ clear (i);
+ }
+ }
+}
+
+/**
+ * Clears the items at the given zero-relative indices in the receiver.
+ * The text, icon and other attributes of the items are set to their default
+ * values. If the table was created with the <code>SWT.VIRTUAL</code> style,
+ * these attributes are requested again as needed.
+ *
+ * @param indices the array of indices of the items
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * <li>ERROR_NULL_ARGUMENT - if the indices array is null</li>
+ * </ul>
+ * @exception SWTException <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 SWT#VIRTUAL
+ * @see SWT#SetData
+ *
+ * @since 3.0
+ */
+public void clear (int [] indices) {
+ checkWidget ();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (indices.length == 0) return;
+ for (int i=0; i<indices.length; i++) {
+ if (!(0 <= indices [i] && indices [i] < itemCount)) {
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ }
+ for (int i=0; i<indices.length; i++) {
+ clear (indices [i]);
+ }
+}
+
+/**
+ * Clears all the items in the receiver. The text, icon and other
+ * attributes of the items are set to their default values. If the
+ * table was created with the <code>SWT.VIRTUAL</code> style, these
+ * attributes are requested again as needed.
+ *
+ * @exception SWTException <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 SWT#VIRTUAL
+ * @see SWT#SetData
+ *
+ * @since 3.0
+ */
+public void clearAll () {
+ checkWidget ();
+ for (int i=0; i<itemCount; i++) {
+ TableItem item = items [i];
+ if (item != null) {
+ item.clear ();
+ }
+ }
+ if (currentItem == null && isDrawing ()) view.setNeedsDisplay(true);
+ setScrollWidth (items, true);
+}
+
+void clearCachedWidth (TableItem[] items) {
+ if (items == null) return;
+ for (int i = 0; i < items.length; i++) {
+ if (items [i] != null) items [i].width = -1;
+ }
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int width = 0;
+ if (wHint == SWT.DEFAULT) {
+ if (columnCount != 0) {
+ for (int i=0; i<columnCount; i++) {
+ width += columns [i].getWidth ();
+ }
+ } else {
+ GC gc = new GC (this);
+ width += calculateWidth (items, 0, gc) + CELL_GAP;
+ gc.dispose ();
+ }
+ if ((style & SWT.CHECK) != 0) width += getCheckColumnWidth ();
+ } else {
+ width = wHint;
+ }
+ if (width <= 0) width = DEFAULT_WIDTH;
+ int height = 0;
+ if (hHint == SWT.DEFAULT) {
+ height = itemCount * getItemHeight () + getHeaderHeight();
+ } else {
+ height = hHint;
+ }
+ if (height <= 0) height = DEFAULT_HEIGHT;
+ Rectangle rect = computeTrim (0, 0, width, height);
+ return new Point (rect.width, rect.height);
+}
+
+void createColumn (TableItem item, int index) {
+ String [] strings = item.strings;
+ if (strings != null) {
+ String [] temp = new String [columnCount];
+ System.arraycopy (strings, 0, temp, 0, index);
+ System.arraycopy (strings, index, temp, index+1, columnCount-index-1);
+ temp [index] = "";
+ item.strings = temp;
+ }
+ if (index == 0) item.text = "";
+ Image [] images = item.images;
+ if (images != null) {
+ Image [] temp = new Image [columnCount];
+ System.arraycopy (images, 0, temp, 0, index);
+ System.arraycopy (images, index, temp, index+1, columnCount-index-1);
+ item.images = temp;
+ }
+ if (index == 0) item.image = null;
+ Color [] cellBackground = item.cellBackground;
+ if (cellBackground != null) {
+ Color [] temp = new Color [columnCount];
+ System.arraycopy (cellBackground, 0, temp, 0, index);
+ System.arraycopy (cellBackground, index, temp, index+1, columnCount-index-1);
+ item.cellBackground = temp;
+ }
+ Color [] cellForeground = item.cellForeground;
+ if (cellForeground != null) {
+ Color [] temp = new Color [columnCount];
+ System.arraycopy (cellForeground, 0, temp, 0, index);
+ System.arraycopy (cellForeground, index, temp, index+1, columnCount-index-1);
+ item.cellForeground = temp;
+ }
+ Font [] cellFont = item.cellFont;
+ if (cellFont != null) {
+ Font [] temp = new Font [columnCount];
+ System.arraycopy (cellFont, 0, temp, 0, index);
+ System.arraycopy (cellFont, index, temp, index+1, columnCount-index-1);
+ item.cellFont = temp;
+ }
+}
+
+void createHandle () {
+ NSScrollView scrollWidget = (NSScrollView)new SWTScrollView().alloc();
+ scrollWidget.init();
+ scrollWidget.setHasHorizontalScroller ((style & SWT.H_SCROLL) != 0);
+ scrollWidget.setHasVerticalScroller ((style & SWT.V_SCROLL) != 0);
+ scrollWidget.setAutohidesScrollers(true);
+ scrollWidget.setBorderType(hasBorder() ? OS.NSBezelBorder : OS.NSNoBorder);
+
+ NSTableView widget = (NSTableView)new SWTTableView().alloc();
+ widget.init();
+ widget.setAllowsMultipleSelection((style & SWT.MULTI) != 0);
+ widget.setAllowsColumnReordering (false);
+ widget.setDataSource(widget);
+ widget.setDelegate(widget);
+ widget.setColumnAutoresizingStyle (OS.NSTableViewNoColumnAutoresizing);
+ NSSize spacing = new NSSize();
+ spacing.width = spacing.height = CELL_GAP;
+ widget.setIntercellSpacing(spacing);
+ widget.setDoubleAction(OS.sel_sendDoubleSelection);
+ if (!hasBorder()) widget.setFocusRingType(OS.NSFocusRingTypeNone);
+
+ headerView = (NSTableHeaderView)new SWTTableHeaderView ().alloc ().init ();
+ widget.setHeaderView (null);
+
+ NSString str = NSString.stringWith(""); //$NON-NLS-1$
+ if ((style & SWT.CHECK) != 0) {
+ checkColumn = (NSTableColumn)new NSTableColumn().alloc();
+ checkColumn = checkColumn.initWithIdentifier(NSString.stringWith(String.valueOf(++NEXT_ID)));
+ checkColumn.headerCell().setTitle(str);
+ widget.addTableColumn (checkColumn);
+ checkColumn.setResizingMask(OS.NSTableColumnNoResizing);
+ checkColumn.setEditable(false);
+ int /*long*/ cls = NSButton.cellClass (); /* use our custom cell class */
+ buttonCell = new NSButtonCell (OS.class_createInstance (cls, 0));
+ buttonCell.init ();
+ checkColumn.setDataCell (buttonCell);
+ buttonCell.setButtonType (OS.NSSwitchButton);
+ buttonCell.setImagePosition (OS.NSImageOnly);
+ buttonCell.setAllowsMixedState (true);
+ checkColumn.setWidth(getCheckColumnWidth());
+ }
+
+ firstColumn = (NSTableColumn)new NSTableColumn().alloc();
+ firstColumn = firstColumn.initWithIdentifier(NSString.stringWith(String.valueOf(++NEXT_ID)));
+ /*
+ * Feature in Cocoa. If a column's width is too small to show any content
+ * then tableView_objectValueForTableColumn_row is never invoked to
+ * query for item values, which is a problem for VIRTUAL Tables. The
+ * workaround is to ensure that, for 0-column Tables, the internal first
+ * column always has a minimal width that makes this call come in.
+ */
+ firstColumn.setMinWidth (FIRST_COLUMN_MINIMUM_WIDTH);
+ firstColumn.setWidth(0);
+ firstColumn.setResizingMask (OS.NSTableColumnNoResizing);
+ firstColumn.headerCell ().setTitle (str);
+ widget.addTableColumn (firstColumn);
+ dataCell = (NSTextFieldCell)new SWTImageTextCell ().alloc ().init ();
+ dataCell.setLineBreakMode(OS.NSLineBreakByClipping);
+ firstColumn.setDataCell (dataCell);
+
+ scrollView = scrollWidget;
+ view = widget;
+}
+
+void createItem (TableColumn column, int index) {
+ if (!(0 <= index && index <= columnCount)) error (SWT.ERROR_INVALID_RANGE);
+ if (columnCount == columns.length) {
+ TableColumn [] newColumns = new TableColumn [columnCount + 4];
+ System.arraycopy (columns, 0, newColumns, 0, columns.length);
+ columns = newColumns;
+ }
+ NSTableColumn nsColumn;
+ if (columnCount == 0) {
+ //TODO - clear attributes, alignment etc.
+ nsColumn = firstColumn;
+ nsColumn.setMinWidth (0);
+ nsColumn.setResizingMask (OS.NSTableColumnUserResizingMask);
+ firstColumn = null;
+ } else {
+ //TODO - set attributes, alignment etc.
+ nsColumn = (NSTableColumn)new NSTableColumn().alloc();
+ nsColumn = nsColumn.initWithIdentifier(NSString.stringWith(String.valueOf(++NEXT_ID)));
+ nsColumn.setMinWidth(0);
+ ((NSTableView)view).addTableColumn (nsColumn);
+ int checkColumn = (style & SWT.CHECK) != 0 ? 1 : 0;
+ ((NSTableView)view).moveColumn (columnCount + checkColumn, index + checkColumn);
+ nsColumn.setDataCell (dataCell);
+ }
+ column.createJNIRef ();
+ NSTableHeaderCell headerCell = (NSTableHeaderCell)new SWTTableHeaderCell ().alloc ().init ();
+ nsColumn.setHeaderCell (headerCell);
+ display.addWidget (headerCell, column);
+ column.nsColumn = nsColumn;
+ nsColumn.setWidth(0);
+ System.arraycopy (columns, index, columns, index + 1, columnCount++ - index);
+ columns [index] = column;
+ for (int i = 0; i < itemCount; i++) {
+ TableItem item = items [i];
+ if (item != null) {
+ if (columnCount > 1) {
+ createColumn (item, index);
+ }
+ }
+ }
+}
+
+void createItem (TableItem item, int index) {
+ if (!(0 <= index && index <= itemCount)) error (SWT.ERROR_INVALID_RANGE);
+ if (itemCount == items.length) {
+ /* Grow the array faster when redraw is off */
+ int length = getDrawing () ? items.length + 4 : Math.max (4, items.length * 3 / 2);
+ TableItem [] newItems = new TableItem [length];
+ System.arraycopy (items, 0, newItems, 0, items.length);
+ items = newItems;
+ }
+ System.arraycopy (items, index, items, index + 1, itemCount++ - index);
+ items [index] = item;
+ ((NSTableView)view).noteNumberOfRowsChanged ();
+ if (index != itemCount) fixSelection (index, true);
+}
+
+void createWidget () {
+ super.createWidget ();
+ items = new TableItem [4];
+ columns = new TableColumn [4];
+}
+
+Color defaultBackground () {
+ return display.getWidgetColor (SWT.COLOR_LIST_BACKGROUND);
+}
+
+NSFont defaultNSFont () {
+ return display.tableViewFont;
+}
+
+Color defaultForeground () {
+ return display.getWidgetColor (SWT.COLOR_LIST_FOREGROUND);
+}
+
+void deregister () {
+ super.deregister ();
+ display.removeWidget (headerView);
+ display.removeWidget (dataCell);
+ if (buttonCell != null) display.removeWidget (buttonCell);
+}
+
+/**
+ * Deselects the item at the given zero-relative index in the receiver.
+ * If the item at the index was already deselected, it remains
+ * deselected. Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to deselect
+ *
+ * @exception SWTException <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 deselect (int index) {
+ checkWidget ();
+ if (0 <= index && index < itemCount) {
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ widget.deselectRow (index);
+ ignoreSelect = false;
+ }
+}
+
+/**
+ * Deselects the items at the given zero-relative indices in the receiver.
+ * If the item at the given zero-relative index in the receiver
+ * is selected, it is deselected. If the item at the index
+ * was not selected, it remains deselected. The range of the
+ * indices is inclusive. Indices that are out of range are ignored.
+ *
+ * @param start the start index of the items to deselect
+ * @param end the end index of the items to deselect
+ *
+ * @exception SWTException <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 deselect (int start, int end) {
+ checkWidget();
+ if (start > end) return;
+ if (end < 0 || start >= itemCount) return;
+ start = Math.max (0, start);
+ end = Math.min (itemCount - 1, end);
+ if (start == 0 && end == itemCount - 1) {
+ deselectAll ();
+ } else {
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ for (int i=start; i<=end; i++) {
+ widget.deselectRow (i);
+ }
+ ignoreSelect = false;
+ }
+}
+
+/**
+ * Deselects the items at the given zero-relative indices in the receiver.
+ * If the item at the given zero-relative index in the receiver
+ * is selected, it is deselected. If the item at the index
+ * was not selected, it remains deselected. Indices that are out
+ * of range and duplicate indices are ignored.
+ *
+ * @param indices the array of indices for the items to deselect
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the set of indices is null</li>
+ * </ul>
+ * @exception SWTException <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 deselect (int [] indices) {
+ checkWidget ();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ for (int i=0; i<indices.length; i++) {
+ widget.deselectRow (indices [i]);
+ }
+ ignoreSelect = false;
+}
+
+/**
+ * Deselects all selected items in the receiver.
+ *
+ * @exception SWTException <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 deselectAll () {
+ checkWidget ();
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ widget.deselectAll(null);
+ ignoreSelect = false;
+}
+
+void destroyItem (TableColumn column) {
+ int index = 0;
+ while (index < columnCount) {
+ if (columns [index] == column) break;
+ index++;
+ }
+ for (int i=0; i<itemCount; i++) {
+ TableItem item = items [i];
+ if (item != null) {
+ if (columnCount <= 1) {
+ item.strings = null;
+ item.images = null;
+ item.cellBackground = null;
+ item.cellForeground = null;
+ item.cellFont = null;
+ } else {
+ if (item.strings != null) {
+ String [] strings = item.strings;
+ if (index == 0) {
+ item.text = strings [1] != null ? strings [1] : "";
+ }
+ String [] temp = new String [columnCount - 1];
+ System.arraycopy (strings, 0, temp, 0, index);
+ System.arraycopy (strings, index + 1, temp, index, columnCount - 1 - index);
+ item.strings = temp;
+ } else {
+ if (index == 0) item.text = "";
+ }
+ if (item.images != null) {
+ Image [] images = item.images;
+ if (index == 0) item.image = images [1];
+ Image [] temp = new Image [columnCount - 1];
+ System.arraycopy (images, 0, temp, 0, index);
+ System.arraycopy (images, index + 1, temp, index, columnCount - 1 - index);
+ item.images = temp;
+ } else {
+ if (index == 0) item.image = null;
+ }
+ if (item.cellBackground != null) {
+ Color [] cellBackground = item.cellBackground;
+ Color [] temp = new Color [columnCount - 1];
+ System.arraycopy (cellBackground, 0, temp, 0, index);
+ System.arraycopy (cellBackground, index + 1, temp, index, columnCount - 1 - index);
+ item.cellBackground = temp;
+ }
+ if (item.cellForeground != null) {
+ Color [] cellForeground = item.cellForeground;
+ Color [] temp = new Color [columnCount - 1];
+ System.arraycopy (cellForeground, 0, temp, 0, index);
+ System.arraycopy (cellForeground, index + 1, temp, index, columnCount - 1 - index);
+ item.cellForeground = temp;
+ }
+ if (item.cellFont != null) {
+ Font [] cellFont = item.cellFont;
+ Font [] temp = new Font [columnCount - 1];
+ System.arraycopy (cellFont, 0, temp, 0, index);
+ System.arraycopy (cellFont, index + 1, temp, index, columnCount - 1 - index);
+ item.cellFont = temp;
+ }
+ }
+ }
+ }
+
+ int oldIndex = indexOf (column.nsColumn);
+
+ System.arraycopy (columns, index + 1, columns, index, --columnCount - index);
+ columns [columnCount] = null;
+ if (columnCount == 0) {
+ //TODO - reset attributes
+ firstColumn = column.nsColumn;
+ firstColumn.retain ();
+ /*
+ * Feature in Cocoa. If a column's width is too small to show any content
+ * then tableView_objectValueForTableColumn_row is never invoked to
+ * query for item values, which is a problem for VIRTUAL Tables. The
+ * workaround is to ensure that, for 0-column Tables, the internal first
+ * column always has a minimal width that makes this call come in.
+ */
+ firstColumn.setMinWidth (FIRST_COLUMN_MINIMUM_WIDTH);
+ firstColumn.setResizingMask (OS.NSTableColumnNoResizing);
+ setScrollWidth ();
+ } else {
+ ((NSTableView)view).removeTableColumn(column.nsColumn);
+ }
+
+ NSArray array = ((NSTableView)view).tableColumns ();
+ int arraySize = (int)/*64*/array.count ();
+ for (int i = oldIndex; i < arraySize; i++) {
+ int /*long*/ columnId = array.objectAtIndex (i).id;
+ for (int j = 0; j < columnCount; j++) {
+ if (columns[j].nsColumn.id == columnId) {
+ columns [j].sendEvent (SWT.Move);
+ break;
+ }
+ }
+ }
+}
+
+void destroyItem (TableItem item) {
+ int index = 0;
+ while (index < itemCount) {
+ if (items [index] == item) break;
+ index++;
+ }
+ if (index != itemCount - 1) fixSelection (index, false);
+ System.arraycopy (items, index + 1, items, index, --itemCount - index);
+ items [itemCount] = null;
+ ((NSTableView)view).noteNumberOfRowsChanged();
+ if (itemCount == 0) setTableEmpty ();
+}
+
+boolean dragDetect(int x, int y, boolean filter, boolean[] consume) {
+ // Let Cocoa determine if a drag is starting and fire the notification when we get the callback.
+ return false;
+}
+
+void drawInteriorWithFrame_inView (int /*long*/ id, int /*long*/ sel, NSRect rect, int /*long*/ view) {
+ boolean hooksErase = hooks (SWT.EraseItem);
+ boolean hooksPaint = hooks (SWT.PaintItem);
+ boolean hooksMeasure = hooks (SWT.MeasureItem);
+
+ NSTextFieldCell cell = new NSTextFieldCell (id);
+
+ NSTableView widget = (NSTableView)this.view;
+ int /*long*/ [] outValue = new int /*long*/ [1];
+ OS.object_getInstanceVariable(id, Display.SWT_ROW, outValue);
+ int /*long*/ rowIndex = outValue [0];
+ TableItem item = _getItem((int)/*64*/rowIndex);
+ OS.object_getInstanceVariable(id, Display.SWT_COLUMN, outValue);
+ int /*long*/ tableColumn = outValue[0];
+ int /*long*/ nsColumnIndex = widget.tableColumns().indexOfObjectIdenticalTo(new id(tableColumn));
+ int columnIndex = 0;
+ for (int i=0; i<columnCount; i++) {
+ if (columns [i].nsColumn.id == tableColumn) {
+ columnIndex = i;
+ break;
+ }
+ }
+
+ Color background = item.cellBackground != null ? item.cellBackground [columnIndex] : null;
+ if (background == null) background = item.background;
+ boolean drawBackground = background != null;
+ boolean drawForeground = true;
+ boolean isSelected = cell.isHighlighted();
+ boolean drawSelection = isSelected;
+ boolean hasFocus = hooksErase && hasFocus ();
+
+ Color selectionBackground = null, selectionForeground = null;
+ if (isSelected && (hooksErase || hooksPaint)) {
+ selectionForeground = Color.cocoa_new(display, hasFocus ? display.alternateSelectedControlTextColor : display.selectedControlTextColor);
+ selectionBackground = Color.cocoa_new(display, hasFocus ? display.alternateSelectedControlColor : display.secondarySelectedControlColor);
+ }
+
+ NSSize contentSize = super.cellSize(id, OS.sel_cellSize);
+ NSImage image = cell.image();
+ if (image != null) contentSize.width += imageBounds.width + IMAGE_GAP;
+ int contentWidth = (int)Math.ceil (contentSize.width);
+ NSSize spacing = widget.intercellSpacing();
+ int itemHeight = (int)Math.ceil (widget.rowHeight() + spacing.height);
+
+ NSRect cellRect = widget.rectOfColumn (nsColumnIndex);
+ cellRect.y = rect.y;
+ cellRect.height = rect.height + spacing.height;
+ if (columnCount == 0) {
+ NSRect rowRect = widget.rectOfRow (rowIndex);
+ cellRect.width = rowRect.width;
+ }
+ float /*double*/ offsetX = 0, offsetY = 0;
+ if (hooksPaint || hooksErase) {
+ NSRect frameCell = widget.frameOfCellAtColumn(nsColumnIndex, rowIndex);
+ offsetX = rect.x - frameCell.x;
+ offsetY = rect.y - frameCell.y;
+ if (drawExpansion) {
+ offsetX -= 0.5f;
+ offsetY -= 0.5f;
+ }
+ }
+ int itemX = (int)(rect.x - offsetX), itemY = (int)(rect.y - offsetY);
+ NSGraphicsContext context = NSGraphicsContext.currentContext ();
+
+ if (hooksMeasure) {
+ sendMeasureItem(item, columnIndex, contentSize);
+ }
+
+ Color userForeground = null;
+ if (hooksErase) {
+ context.saveGraphicsState();
+ NSAffineTransform transform = NSAffineTransform.transform();
+ transform.translateXBy(offsetX, offsetY);
+ transform.concat();
+
+ GCData data = new GCData ();
+ data.paintRect = cellRect;
+ GC gc = GC.cocoa_new (this, data);
+ gc.setFont (item.getFont (columnIndex));
+ if (isSelected) {
+ gc.setForeground (selectionForeground);
+ gc.setBackground (selectionBackground);
+ } else {
+ gc.setForeground (item.getForeground (columnIndex));
+ gc.setBackground (item.getBackground (columnIndex));
+ }
+ if (!drawExpansion) {
+ gc.setClipping ((int)(cellRect.x - offsetX), (int)(cellRect.y - offsetY), (int)cellRect.width, (int)cellRect.height);
+ }
+ Event event = new Event ();
+ event.item = item;
+ event.gc = gc;
+ event.index = columnIndex;
+ event.detail = SWT.FOREGROUND;
+ if (drawBackground) event.detail |= SWT.BACKGROUND;
+ if (isSelected) event.detail |= SWT.SELECTED;
+ event.x = (int)cellRect.x;
+ event.y = (int)cellRect.y;
+ event.width = (int)cellRect.width;
+ event.height = (int)cellRect.height;
+ sendEvent (SWT.EraseItem, event);
+ if (!event.doit) {
+ drawForeground = drawBackground = drawSelection = false;
+ } else {
+ drawBackground = drawBackground && (event.detail & SWT.BACKGROUND) != 0;
+ drawForeground = (event.detail & SWT.FOREGROUND) != 0;
+ drawSelection = drawSelection && (event.detail & SWT.SELECTED) != 0;
+ }
+ if (!drawSelection && isSelected) {
+ userForeground = Color.cocoa_new(display, gc.getForeground().handle);
+ }
+ gc.dispose ();
+
+ context.restoreGraphicsState();
+
+ if (isDisposed ()) return;
+ if (item.isDisposed ()) return;
+
+ if (drawSelection && ((style & SWT.HIDE_SELECTION) == 0 || hasFocus)) {
+ cellRect.height -= spacing.height;
+ callSuper (widget.id, OS.sel_highlightSelectionInClipRect_, cellRect);
+ cellRect.height += spacing.height;
+ }
+ }
+
+ if (drawBackground && !drawSelection) {
+ context.saveGraphicsState ();
+ float /*double*/ [] colorRGB = background.handle;
+ NSColor color = NSColor.colorWithDeviceRed (colorRGB[0], colorRGB[1], colorRGB[2], 1f);
+ color.setFill ();
+ NSBezierPath.fillRect (cellRect);
+ context.restoreGraphicsState ();
+ }
+
+ if (drawForeground) {
+ if ((!drawExpansion || hooksMeasure) && image != null) {
+ NSRect destRect = new NSRect();
+ destRect.x = rect.x + IMAGE_GAP;
+ destRect.y = rect.y + (float)Math.ceil((rect.height - imageBounds.height) / 2);
+ destRect.width = imageBounds.width;
+ destRect.height = imageBounds.height;
+ NSRect srcRect = new NSRect();
+ NSSize size = image.size();
+ srcRect.width = size.width;
+ srcRect.height = size.height;
+ context.saveGraphicsState();
+ NSBezierPath.bezierPathWithRect(rect).addClip();
+ NSAffineTransform transform = NSAffineTransform.transform();
+ transform.scaleXBy(1, -1);
+ transform.translateXBy(0, -(destRect.height + 2 * destRect.y));
+ transform.concat();
+ image.drawInRect(destRect, srcRect, OS.NSCompositeSourceOver, 1);
+ context.restoreGraphicsState();
+ int imageWidth = imageBounds.width + IMAGE_GAP;
+ rect.x += imageWidth;
+ rect.width -= imageWidth;
+ }
+ cell.setHighlighted (false);
+ boolean callSuper = false;
+ if (userForeground != null) {
+ /*
+ * Bug in Cocoa. For some reason, it is not possible to change the
+ * foreground color to black when the cell is highlighted. The text
+ * still draws white. The fix is to draw the text and not call super.
+ */
+ float /*double*/ [] color = userForeground.handle;
+ if (color[0] == 0 && color[1] == 0 && color[2] == 0 && color[3] == 1) {
+ NSMutableAttributedString newStr = new NSMutableAttributedString(cell.attributedStringValue().mutableCopy());
+ NSRange range = new NSRange();
+ range.length = newStr.length();
+ newStr.removeAttribute(OS.NSForegroundColorAttributeName, range);
+ NSRect newRect = new NSRect();
+ newRect.x = rect.x + TEXT_GAP;
+ newRect.y = rect.y;
+ newRect.width = rect.width - TEXT_GAP;
+ newRect.height = rect.height;
+ NSSize size = newStr.size();
+ if (newRect.height > size.height) {
+ newRect.y += (newRect.height - size.height) / 2;
+ newRect.height = size.height;
+ }
+ newStr.drawInRect(newRect);
+ newStr.release();
+ } else {
+ NSColor nsColor = NSColor.colorWithDeviceRed(color[0], color[1], color[2], color[3]);
+ cell.setTextColor(nsColor);
+ callSuper = true;
+ }
+ } else {
+ callSuper = true;
+ }
+ if (callSuper) {
+ NSAttributedString attrStr = cell.attributedStringValue();
+ NSSize size = attrStr.size();
+ if (rect.height > size.height) {
+ rect.y += (rect.height - size.height) / 2;
+ rect.height = size.height;
+ }
+ super.drawInteriorWithFrame_inView(id, sel, rect, view);
+ }
+ }
+
+ if (hooksPaint) {
+ context.saveGraphicsState();
+ NSAffineTransform transform = NSAffineTransform.transform();
+ transform.translateXBy(offsetX, offsetY);
+ transform.concat();
+
+ GCData data = new GCData ();
+ data.paintRect = cellRect;
+ GC gc = GC.cocoa_new (this, data);
+ gc.setFont (item.getFont (columnIndex));
+ if (drawSelection) {
+ gc.setForeground (selectionForeground);
+ gc.setBackground (selectionBackground);
+ } else {
+ gc.setForeground (userForeground != null ? userForeground : item.getForeground (columnIndex));
+ gc.setBackground (item.getBackground (columnIndex));
+ }
+ if (!drawExpansion) {
+ gc.setClipping ((int)(cellRect.x - offsetX), (int)(cellRect.y - offsetY), (int)cellRect.width, (int)cellRect.height);
+ }
+ Event event = new Event ();
+ event.item = item;
+ event.gc = gc;
+ event.index = columnIndex;
+ if (drawForeground) event.detail |= SWT.FOREGROUND;
+ if (drawBackground) event.detail |= SWT.BACKGROUND;
+ if (drawSelection) event.detail |= SWT.SELECTED;
+ event.x = itemX;
+ event.y = itemY;
+ event.width = contentWidth;
+ event.height = itemHeight;
+ sendEvent (SWT.PaintItem, event);
+ gc.dispose ();
+
+ context.restoreGraphicsState();
+ }
+}
+
+void drawWithExpansionFrame_inView (int /*long*/ id, int /*long*/ sel, NSRect cellFrame, int /*long*/ view) {
+ drawExpansion = true;
+ super.drawWithExpansionFrame_inView(id, sel, cellFrame, view);
+ drawExpansion = false;
+}
+
+void drawRect(int id, int sel, NSRect rect) {
+ fixScrollWidth = false;
+ super.drawRect(id, sel, rect);
+ if (isDisposed ()) return;
+ if (fixScrollWidth) {
+ fixScrollWidth = false;
+ if (setScrollWidth (items, true)) view.setNeedsDisplay(true);
+ }
+}
+
+NSRect expansionFrameWithFrame_inView(int /*long*/ id, int /*long*/ sel, NSRect cellRect, int /*long*/ view) {
+ if (toolTipText == null) {
+ NSRect rect = super.expansionFrameWithFrame_inView(id, sel, cellRect, view);
+ NSCell cell = new NSCell(id);
+ if (rect.width != 0 && rect.height != 0) {
+ if (hooks(SWT.MeasureItem)) {
+ NSSize cellSize = cell.cellSize();
+ cellRect.width = cellSize.width;
+ return cellRect;
+ }
+ } else {
+ NSRect expansionRect;
+ if (hooks(SWT.MeasureItem)) {
+ expansionRect = cellRect;
+ NSSize cellSize = cell.cellSize();
+ expansionRect.width = cellSize.width;
+ } else {
+ expansionRect = cell.titleRectForBounds(cellRect);
+ NSSize cellSize = super.cellSize(id, OS.sel_cellSize);
+ expansionRect.width = cellSize.width;
+ }
+ NSRect contentRect = scrollView.contentView().bounds();
+ OS.NSIntersectionRect(contentRect, expansionRect, contentRect);
+ if (!OS.NSEqualRects(expansionRect, contentRect)) {
+ return expansionRect;
+ }
+ }
+ return rect;
+ }
+ return new NSRect();
+}
+
+Widget findTooltip (NSPoint pt) {
+ NSTableView widget = (NSTableView)view;
+ NSTableHeaderView headerView = widget.headerView();
+ if (headerView != null) {
+ pt = headerView.convertPoint_fromView_ (pt, null);
+ int /*long*/ index = headerView.columnAtPoint (pt);
+ if (index != -1) {
+ NSArray nsColumns = widget.tableColumns ();
+ id nsColumn = nsColumns.objectAtIndex (index);
+ for (int i = 0; i < columnCount; i++) {
+ TableColumn column = columns [i];
+ if (column.nsColumn.id == nsColumn.id) {
+ return column;
+ }
+ }
+ }
+ }
+ return super.findTooltip (pt);
+}
+
+void fixSelection (int index, boolean add) {
+ int [] selection = getSelectionIndices ();
+ if (selection.length == 0) return;
+ int newCount = 0;
+ boolean fix = false;
+ for (int i = 0; i < selection.length; i++) {
+ if (!add && selection [i] == index) {
+ fix = true;
+ } else {
+ int newIndex = newCount++;
+ selection [newIndex] = selection [i];
+ if (selection [newIndex] >= index) {
+ selection [newIndex] += add ? 1 : -1;
+ fix = true;
+ }
+ }
+ }
+ if (fix) select (selection, newCount, true);
+}
+
+int getCheckColumnWidth () {
+ return (int)checkColumn.dataCell().cellSize().width;
+}
+
+public Rectangle getClientArea () {
+ checkWidget ();
+ Rectangle rect = super.getClientArea ();
+ NSTableHeaderView headerView = ((NSTableView) view).headerView ();
+ if (headerView != null) {
+ int height = (int) headerView.bounds ().height;
+ rect.y -= height;
+ rect.height += height;
+ }
+ return rect;
+}
+
+TableColumn getColumn (id id) {
+ for (int i = 0; i < columnCount; i++) {
+ if (columns[i].nsColumn.id == id.id) {
+ return columns[i];
+ }
+ }
+ return null;
+}
+
+/**
+ * Returns the column at the given, zero-relative index in the
+ * receiver. Throws an exception if the index is out of range.
+ * Columns are returned in the order that they were created.
+ * If no <code>TableColumn</code>s were created by the programmer,
+ * this method will throw <code>ERROR_INVALID_RANGE</code> despite
+ * the fact that a single column of data may be visible in the table.
+ * This occurs when the programmer uses the table like a list, adding
+ * items but never creating a column.
+ *
+ * @param index the index of the column to return
+ * @return the column at the given index
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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#getMoveable()
+ * @see TableColumn#setMoveable(boolean)
+ * @see SWT#Move
+ */
+public TableColumn getColumn (int index) {
+ checkWidget ();
+ if (!(0 <=index && index < columnCount)) error (SWT.ERROR_INVALID_RANGE);
+ return columns [index];
+}
+
+/**
+ * Returns the number of columns contained in the receiver.
+ * If no <code>TableColumn</code>s were created by the programmer,
+ * this value is zero, despite the fact that visually, one column
+ * of items may be visible. This occurs when the programmer uses
+ * the table like a list, adding items but never creating a column.
+ *
+ * @return the number of columns
+ *
+ * @exception SWTException <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 getColumnCount () {
+ checkWidget ();
+ return columnCount;
+}
+
+/**
+ * Returns an array of zero-relative integers that map
+ * the creation order of the receiver's items to the
+ * order in which they are currently being displayed.
+ * <p>
+ * Specifically, the indices of the returned array represent
+ * the current visual order of the items, and the contents
+ * of the array represent the creation order of the items.
+ * </p><p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ *
+ * @return the current visual order of the receiver's items
+ *
+ * @exception SWTException <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 TableColumn#getMoveable()
+ * @see TableColumn#setMoveable(boolean)
+ * @see SWT#Move
+ *
+ * @since 3.1
+ */
+public int [] getColumnOrder () {
+ checkWidget ();
+ int [] order = new int [columnCount];
+ for (int i = 0; i < columnCount; i++) {
+ TableColumn column = columns [i];
+ int index = indexOf (column.nsColumn);
+ if ((style & SWT.CHECK) != 0) index -= 1;
+ order [index] = i;
+ }
+ return order;
+}
+
+/**
+ * Returns an array of <code>TableColumn</code>s which are the
+ * columns in the receiver. Columns are returned in the order
+ * that they were created. If no <code>TableColumn</code>s were
+ * created by the programmer, the array is empty, despite the fact
+ * that visually, one column of items may be visible. This occurs
+ * when the programmer uses the table like a list, adding items but
+ * never creating a column.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ *
+ * @return the items in the receiver
+ *
+ * @exception SWTException <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#getMoveable()
+ * @see TableColumn#setMoveable(boolean)
+ * @see SWT#Move
+ */
+public TableColumn [] getColumns () {
+ checkWidget ();
+ TableColumn [] result = new TableColumn [columnCount];
+ System.arraycopy (columns, 0, result, 0, columnCount);
+ return result;
+}
+
+/**
+ * Returns the width in pixels of a grid line.
+ *
+ * @return the width of a grid line in pixels
+ *
+ * @exception SWTException <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 getGridLineWidth () {
+ checkWidget ();
+ return 0;
+}
+
+/**
+ * Returns the height of the receiver's header
+ *
+ * @return the height of the header or zero if the header is not visible
+ *
+ * @exception SWTException <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 2.0
+ */
+public int getHeaderHeight () {
+ checkWidget ();
+ NSTableHeaderView headerView = ((NSTableView)view).headerView();
+ if (headerView == null) return 0;
+ return (int)headerView.bounds().height;
+}
+
+/**
+ * Returns <code>true</code> if the receiver's header is visible,
+ * and <code>false</code> otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ * </p>
+ *
+ * @return the receiver's header's visibility state
+ *
+ * @exception SWTException <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 boolean getHeaderVisible () {
+ checkWidget ();
+ return ((NSTableView)view).headerView() != null;
+}
+
+/**
+ * Returns the item at the given, zero-relative index in the
+ * receiver. Throws an exception if the index is out of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 TableItem getItem (int index) {
+ checkWidget ();
+ if (!(0 <= index && index < itemCount)) error (SWT.ERROR_INVALID_RANGE);
+ return _getItem (index);
+}
+
+/**
+ * Returns the item at the given point in the receiver
+ * or null if no such item exists. The point is in the
+ * coordinate system of the receiver.
+ * <p>
+ * The item that is returned represents an item that could be selected by the user.
+ * For example, if selection only occurs in items in the first column, then null is
+ * returned if the point is outside of the item.
+ * Note that the SWT.FULL_SELECTION style hint, which specifies the selection policy,
+ * determines the extent of the selection.
+ * </p>
+ *
+ * @param point the point used to locate the item
+ * @return the item at the given point, or null if the point is not in a selectable item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception SWTException <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 TableItem getItem (Point point) {
+ checkWidget ();
+ NSTableView widget = (NSTableView)view;
+ NSPoint pt = new NSPoint();
+ pt.x = point.x;
+ pt.y = point.y;
+ int row = (int)/*64*/widget.rowAtPoint(pt);
+ if (row == -1) return null;
+ return items[row];
+}
+
+/**
+ * Returns the number of items contained in the receiver.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException <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 getItemCount () {
+ checkWidget ();
+ return itemCount;
+}
+
+/**
+ * Returns the height of the area which would be used to
+ * display <em>one</em> of the items in the receiver.
+ *
+ * @return the height of one item
+ *
+ * @exception SWTException <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 getItemHeight () {
+ checkWidget ();
+ return (int)((NSTableView)view).rowHeight() + CELL_GAP;
+}
+
+/**
+ * Returns a (possibly empty) array of <code>TableItem</code>s which
+ * are the items in the receiver.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ *
+ * @return the items in the receiver
+ *
+ * @exception SWTException <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 TableItem [] getItems () {
+ checkWidget ();
+ TableItem [] result = new TableItem [itemCount];
+ if ((style & SWT.VIRTUAL) != 0) {
+ for (int i=0; i<itemCount; i++) {
+ result [i] = _getItem (i);
+ }
+ } else {
+ System.arraycopy (items, 0, result, 0, itemCount);
+ }
+ return result;
+}
+
+/**
+ * Returns <code>true</code> if the receiver's lines are visible,
+ * and <code>false</code> otherwise. Note that some platforms draw
+ * grid lines while others may draw alternating row colors.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ * </p>
+ *
+ * @return the visibility state of the lines
+ *
+ * @exception SWTException <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 boolean getLinesVisible () {
+ checkWidget ();
+ return ((NSTableView)view).usesAlternatingRowBackgroundColors();
+}
+
+/**
+ * Returns an array of <code>TableItem</code>s that are currently
+ * selected in the receiver. The order of the items is unspecified.
+ * An empty array indicates that no items are selected.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its selection, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ * @return an array representing the selection
+ *
+ * @exception SWTException <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 TableItem [] getSelection () {
+ checkWidget ();
+ NSTableView widget = (NSTableView)view;
+ if (widget.numberOfSelectedRows() == 0) {
+ return new TableItem [0];
+ }
+ NSIndexSet selection = widget.selectedRowIndexes();
+ int count = (int)/*64*/selection.count();
+ int /*long*/ [] indexBuffer = new int /*long*/ [count];
+ selection.getIndexes(indexBuffer, count, 0);
+ TableItem [] result = new TableItem [count];
+ for (int i=0; i<count; i++) {
+ result [i] = _getItem ((int)/*64*/indexBuffer [i]);
+ }
+ return result;
+}
+
+/**
+ * Returns the number of selected items contained in the receiver.
+ *
+ * @return the number of selected items
+ *
+ * @exception SWTException <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 getSelectionCount () {
+ checkWidget ();
+ return (int)/*64*/((NSTableView)view).numberOfSelectedRows();
+}
+
+/**
+ * Returns the zero-relative index of the item which is currently
+ * selected in the receiver, or -1 if no item is selected.
+ *
+ * @return the index of the selected item
+ *
+ * @exception SWTException <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 getSelectionIndex () {
+ checkWidget ();
+ NSTableView widget = (NSTableView)view;
+ if (widget.numberOfSelectedRows() == 0) {
+ return -1;
+ }
+ NSIndexSet selection = widget.selectedRowIndexes();
+ int count = (int)/*64*/selection.count();
+ int /*long*/ [] result = new int /*long*/ [count];
+ selection.getIndexes(result, count, 0);
+ return (int)/*64*/result [0];
+}
+
+/**
+ * Returns the zero-relative indices of the items which are currently
+ * selected in the receiver. The order of the indices is unspecified.
+ * The array is empty if no items are selected.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its selection, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ * @return the array of indices of the selected items
+ *
+ * @exception SWTException <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 [] getSelectionIndices () {
+ checkWidget ();
+ NSTableView widget = (NSTableView)view;
+ if (widget.numberOfSelectedRows() == 0) {
+ return new int [0];
+ }
+ NSIndexSet selection = widget.selectedRowIndexes();
+ int count = (int)/*64*/selection.count();
+ int /*long*/ [] indices = new int /*long*/ [count];
+ selection.getIndexes(indices, count, 0);
+ int [] result = new int [count];
+ for (int i = 0; i < indices.length; i++) {
+ result [i] = (int)/*64*/indices [i];
+ }
+ return result;
+}
+
+/**
+ * Returns the column which shows the sort indicator for
+ * the receiver. The value may be null if no column shows
+ * the sort indicator.
+ *
+ * @return the sort indicator
+ *
+ * @exception SWTException <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 #setSortColumn(TableColumn)
+ *
+ * @since 3.2
+ */
+public TableColumn getSortColumn () {
+ checkWidget ();
+ return sortColumn;
+}
+
+/**
+ * Returns the direction of the sort indicator for the receiver.
+ * The value will be one of <code>UP</code>, <code>DOWN</code>
+ * or <code>NONE</code>.
+ *
+ * @return the sort direction
+ *
+ * @exception SWTException <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 #setSortDirection(int)
+ *
+ * @since 3.2
+ */
+public int getSortDirection () {
+ checkWidget ();
+ return sortDirection;
+}
+
+/**
+ * Returns the zero-relative index of the item which is currently
+ * at the top of the receiver. This index can change when items are
+ * scrolled or new items are added or removed.
+ *
+ * @return the index of the top item
+ *
+ * @exception SWTException <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 getTopIndex () {
+ checkWidget ();
+ //TODO - partial item at the top
+ NSRect rect = scrollView.documentVisibleRect();
+ NSPoint point = new NSPoint();
+ point.x = rect.x;
+ point.y = rect.y;
+ return (int)/*64*/((NSTableView)view).rowAtPoint(point);
+}
+
+void highlightSelectionInClipRect(int /*long*/ id, int /*long*/ sel, int /*long*/ rect) {
+ if (hooks (SWT.EraseItem)) return;
+ if ((style & SWT.HIDE_SELECTION) != 0 && !hasFocus()) return;
+ NSRect clipRect = new NSRect ();
+ OS.memmove (clipRect, rect, NSRect.sizeof);
+ callSuper (id, sel, clipRect);
+}
+
+int /*long*/ hitTestForEvent (int /*long*/ id, int /*long*/ sel, int /*long*/ event, NSRect rect, int /*long*/ controlView) {
+ /*
+ * For some reason, the cell class needs to implement hitTestForEvent:inRect:ofView:,
+ * otherwise the double action selector is not called properly.
+ */
+ return callSuper(id, sel, event, rect, controlView);
+}
+
+int /*long*/ image (int /*long*/ id, int /*long*/ sel) {
+ int /*long*/ [] image = new int /*long*/ [1];
+ OS.object_getInstanceVariable(id, Display.SWT_IMAGE, image);
+ return image[0];
+}
+
+NSRect imageRectForBounds (int /*long*/ id, int /*long*/ sel, NSRect cellFrame) {
+ NSImage image = new NSCell(id).image();
+ if (image != null) {
+ cellFrame.x += IMAGE_GAP;
+ cellFrame.width = imageBounds.width;
+ cellFrame.height = imageBounds.height;
+ }
+ return cellFrame;
+}
+
+int indexOf (NSTableColumn column) {
+ return (int)/*64*/((NSTableView)view).tableColumns().indexOfObjectIdenticalTo(column);
+}
+
+/**
+ * Searches the receiver's list starting at the first column
+ * (index 0) until a column is found that is equal to the
+ * argument, and returns the index of that column. If no column
+ * is found, returns -1.
+ *
+ * @param column the search column
+ * @return the index of the column
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the column is null</li>
+ * </ul>
+ * @exception SWTException <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 indexOf (TableColumn column) {
+ checkWidget ();
+ if (column == null) error (SWT.ERROR_NULL_ARGUMENT);
+ for (int i=0; i<columnCount; i++) {
+ if (columns [i] == column) return i;
+ }
+ return -1;
+}
+
+/**
+ * Searches the receiver's list starting at the first item
+ * (index 0) until an item is found that is equal to the
+ * argument, and returns the index of that item. If no item
+ * is found, returns -1.
+ *
+ * @param item the search item
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * </ul>
+ * @exception SWTException <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 indexOf (TableItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (1 <= lastIndexOf && lastIndexOf < itemCount - 1) {
+ if (items [lastIndexOf] == item) return lastIndexOf;
+ if (items [lastIndexOf + 1] == item) return ++lastIndexOf;
+ if (items [lastIndexOf - 1] == item) return --lastIndexOf;
+ }
+ if (lastIndexOf < itemCount / 2) {
+ for (int i=0; i<itemCount; i++) {
+ if (items [i] == item) return lastIndexOf = i;
+ }
+ } else {
+ for (int i=itemCount - 1; i>=0; --i) {
+ if (items [i] == item) return lastIndexOf = i;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Returns <code>true</code> if the item is selected,
+ * and <code>false</code> otherwise. Indices out of
+ * range are ignored.
+ *
+ * @param index the index of the item
+ * @return the selection state of the item at the index
+ *
+ * @exception SWTException <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 boolean isSelected (int index) {
+ checkWidget ();
+ if (!(0 <= index && index < itemCount)) return false;
+ return ((NSTableView)view).isRowSelected(index);
+}
+
+boolean isTrim (NSView view) {
+ if (super.isTrim (view)) return true;
+ return view.id == headerView.id;
+}
+
+int /*long*/ menuForEvent(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (id != headerView.id) {
+ /*
+ * Feature in Cocoa: Table views do not change the selection when the user
+ * right-clicks or control-clicks on an NSTableView or its subclasses. Fix is to select the
+ * clicked-on row ourselves.
+ */
+ NSEvent event = new NSEvent(theEvent);
+ NSTableView table = (NSTableView)view;
+
+ // get the current selections for the table view.
+ NSIndexSet selectedRowIndexes = table.selectedRowIndexes();
+
+ // select the row that was clicked before showing the menu for the event
+ NSPoint mousePoint = view.convertPoint_fromView_(event.locationInWindow(), null);
+ int /*long*/ row = table.rowAtPoint(mousePoint);
+
+ // figure out if the row that was just clicked on is currently selected
+ if (selectedRowIndexes.containsIndex(row) == false) {
+ NSIndexSet set = (NSIndexSet)new NSIndexSet().alloc();
+ set = set.initWithIndex(row);
+ table.selectRowIndexes (set, false);
+ set.release();
+ }
+ // else that row is currently selected, so don't change anything.
+ }
+ return super.menuForEvent(id, sel, theEvent);
+}
+
+void mouseDown (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (headerView != null && id == headerView.id) {
+ NSTableView widget = (NSTableView)view;
+ widget.setAllowsColumnReordering(false);
+ NSPoint pt = headerView.convertPoint_fromView_(new NSEvent(theEvent).locationInWindow(), null);
+ int /*long*/ nsIndex = headerView.columnAtPoint(pt);
+ if (nsIndex != -1) {
+ id nsColumn = widget.tableColumns().objectAtIndex(nsIndex);
+ for (int i = 0; i < columnCount; i++) {
+ if (columns[i].nsColumn.id == nsColumn.id) {
+ widget.setAllowsColumnReordering(columns[i].movable);
+ break;
+ }
+ }
+ }
+ }
+ else if (id == view.id) {
+ // Bug/feature in Cocoa: If the table has a context menu we just set it visible instead of returning
+ // it from menuForEvent:. This has the side effect, however, of sending control-click to the NSTableView,
+ // which is interpreted as a single click that clears the selection. Fix is to ignore control-click if the
+ // view has a context menu.
+ NSEvent event = new NSEvent(theEvent);
+ if ((event.modifierFlags() & OS.NSControlKeyMask) != 0) return;
+ }
+ super.mouseDown(id, sel, theEvent);
+}
+
+/*
+ * Feature in Cocoa. If a checkbox is in multi-state mode, nextState cycles
+ * from off to mixed to on and back to off again. This will cause the on state
+ * to momentarily appear while clicking on the checkbox. To avoid this,
+ * override [NSCell nextState] to go directly to the desired state.
+ */
+int /*long*/ nextState (int /*long*/ id, int /*long*/ sel) {
+ NSTableView tableView = (NSTableView)view;
+ int index = (int)/*64*/tableView.selectedRow ();
+ TableItem item = items[index];
+ if (item.grayed) {
+ return item.checked ? OS.NSOffState : OS.NSMixedState;
+ }
+ return item.checked ? OS.NSOffState : OS.NSOnState;
+}
+
+int /*long*/ numberOfRowsInTableView(int /*long*/ id, int /*long*/ sel, int /*long*/ aTableView) {
+ return itemCount;
+}
+
+void register () {
+ super.register ();
+ display.addWidget (headerView, this);
+ display.addWidget (dataCell, this);
+ if (buttonCell != null) display.addWidget (buttonCell, this);
+}
+
+void releaseChildren (boolean destroy) {
+ if (items != null) {
+ for (int i=0; i<itemCount; i++) {
+ TableItem item = items [i];
+ if (item != null && !item.isDisposed ()) {
+ item.release (false);
+ }
+ }
+ items = null;
+ }
+ if (columns != null) {
+ for (int i=0; i<columnCount; i++) {
+ TableColumn column = columns [i];
+ if (column != null && !column.isDisposed ()) {
+ column.release (false);
+ }
+ }
+ columns = null;
+ }
+ super.releaseChildren (destroy);
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (headerView != null) headerView.release();
+ headerView = null;
+ if (firstColumn != null) firstColumn.release();
+ firstColumn = null;
+ if (checkColumn != null) checkColumn.release();
+ checkColumn = null;
+ if (dataCell != null) dataCell.release();
+ dataCell = null;
+ if (buttonCell != null) buttonCell.release();
+ buttonCell = null;
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ currentItem = null;
+ sortColumn = null;
+}
+
+/**
+ * Removes the item from the receiver at the given
+ * zero-relative index.
+ *
+ * @param index the index for the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 remove (int index) {
+ checkWidget ();
+ if (!(0 <= index && index < itemCount)) error (SWT.ERROR_INVALID_RANGE);
+ TableItem item = items [index];
+ if (item != null) item.release (false);
+ if (index != itemCount - 1) fixSelection (index, false);
+ System.arraycopy (items, index + 1, items, index, --itemCount - index);
+ items [itemCount] = null;
+ ((NSTableView)view).noteNumberOfRowsChanged();
+ if (itemCount == 0) {
+ setTableEmpty ();
+ }
+}
+
+/**
+ * Removes the items from the receiver which are
+ * between the given zero-relative start and end
+ * indices (inclusive).
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if either the start or end are not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 remove (int start, int end) {
+ checkWidget ();
+ if (start > end) return;
+ if (!(0 <= start && start <= end && end < itemCount)) {
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ if (start == 0 && end == itemCount - 1) {
+ removeAll ();
+ } else {
+ int length = end - start + 1;
+ for (int i=0; i<length; i++) remove (start);
+ }
+}
+
+/**
+ * Removes the items from the receiver's list at the given
+ * zero-relative indices.
+ *
+ * @param indices the array of indices of the items
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * <li>ERROR_NULL_ARGUMENT - if the indices array is null</li>
+ * </ul>
+ * @exception SWTException <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 remove (int [] indices) {
+ checkWidget ();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (indices.length == 0) return;
+ int [] newIndices = new int [indices.length];
+ System.arraycopy (indices, 0, newIndices, 0, indices.length);
+ sort (newIndices);
+ int start = newIndices [newIndices.length - 1], end = newIndices [0];
+ if (!(0 <= start && start <= end && end < itemCount)) {
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ int last = -1;
+ for (int i=0; i<newIndices.length; i++) {
+ int index = newIndices [i];
+ if (index != last) {
+ remove (index);
+ last = index;
+ }
+ }
+}
+
+/**
+ * Removes all of the items from the receiver.
+ *
+ * @exception SWTException <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 removeAll () {
+ checkWidget ();
+ for (int i=0; i<itemCount; i++) {
+ TableItem item = items [i];
+ if (item != null && !item.isDisposed ()) item.release (false);
+ }
+ setTableEmpty ();
+ ((NSTableView)view).noteNumberOfRowsChanged();
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the user changes the receiver's selection.
+ *
+ * @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 SWTException <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(SelectionListener)
+ */
+public void removeSelectionListener(SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+/**
+ * Selects the item at the given zero-relative index in the receiver.
+ * If the item at the index was already selected, it remains
+ * selected. Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to select
+ *
+ * @exception SWTException <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 select (int index) {
+ checkWidget ();
+ if (0 <= index && index < itemCount) {
+ NSIndexSet set = (NSIndexSet)new NSIndexSet().alloc();
+ set = set.initWithIndex(index);
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ widget.selectRowIndexes(set, (style & SWT.MULTI) != 0);
+ ignoreSelect = false;
+ set.release();
+ }
+}
+
+/**
+ * Selects the items in the range specified by the given zero-relative
+ * indices in the receiver. The range of indices is inclusive.
+ * The current selection is not cleared before the new items are selected.
+ * <p>
+ * If an item in the given range is not selected, it is selected.
+ * If an item in the given range was already selected, it remains selected.
+ * Indices that are out of range are ignored and no items will be selected
+ * if start is greater than end.
+ * If the receiver is single-select and there is more than one item in the
+ * given range, then all indices are ignored.
+ * </p>
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ *
+ * @exception SWTException <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#setSelection(int,int)
+ */
+public void select (int start, int end) {
+ checkWidget ();
+ if (end < 0 || start > end || ((style & SWT.SINGLE) != 0 && start != end)) return;
+ if (itemCount == 0 || start >= itemCount) return;
+ if (start == 0 && end == itemCount - 1) {
+ selectAll ();
+ } else {
+ start = Math.max (0, start);
+ end = Math.min (end, itemCount - 1);
+ NSRange range = new NSRange();
+ range.location = start;
+ range.length = end - start + 1;
+ NSIndexSet set = (NSIndexSet)new NSIndexSet().alloc();
+ set = set.initWithIndexesInRange(range);
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ widget.selectRowIndexes(set, (style & SWT.MULTI) != 0);
+ ignoreSelect = false;
+ set.release();
+ }
+}
+
+/**
+ * Selects the items at the given zero-relative indices in the receiver.
+ * The current selection is not cleared before the new items are selected.
+ * <p>
+ * If the item at a given index is not selected, it is selected.
+ * If the item at a given index was already selected, it remains selected.
+ * Indices that are out of range and duplicate indices are ignored.
+ * If the receiver is single-select and multiple indices are specified,
+ * then all indices are ignored.
+ * </p>
+ *
+ * @param indices the array of indices for the items to select
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li>
+ * </ul>
+ * @exception SWTException <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#setSelection(int[])
+ */
+public void select (int [] indices) {
+ checkWidget ();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int length = indices.length;
+ if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
+ int count = 0;
+ NSMutableIndexSet set = (NSMutableIndexSet)new NSMutableIndexSet().alloc().init();
+ for (int i=0; i<length; i++) {
+ int index = indices [i];
+ if (index >= 0 && index < itemCount) {
+ set.addIndex (indices [i]);
+ count++;
+ }
+ }
+ if (count > 0) {
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ widget.selectRowIndexes(set, (style & SWT.MULTI) != 0);
+ ignoreSelect = false;
+ }
+ set.release();
+}
+
+void select (int [] indices, int count, boolean clear) {
+ NSMutableIndexSet set = (NSMutableIndexSet)new NSMutableIndexSet().alloc().init();
+ for (int i=0; i<count; i++) set.addIndex (indices [i]);
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ widget.selectRowIndexes(set, !clear);
+ ignoreSelect = false;
+ set.release();
+}
+
+/**
+ * Selects all of the items in the receiver.
+ * <p>
+ * If the receiver is single-select, do nothing.
+ * </p>
+ *
+ * @exception SWTException <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 selectAll () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) return;
+ NSTableView widget = (NSTableView)view;
+ ignoreSelect = true;
+ widget.selectAll(null);
+ ignoreSelect = false;
+}
+
+void updateBackground () {
+ NSColor nsColor = null;
+ if (backgroundImage != null) {
+ nsColor = NSColor.colorWithPatternImage(backgroundImage.handle);
+ } else if (background != null) {
+ nsColor = NSColor.colorWithDeviceRed(background[0], background[1], background[2], background[3]);
+ }
+ ((NSTableView) view).setBackgroundColor (nsColor);
+}
+
+/**
+ * Sets the order that the items in the receiver should
+ * be displayed in to the given argument which is described
+ * in terms of the zero-relative ordering of when the items
+ * were added.
+ *
+ * @param order the new order to display the items
+ *
+ * @exception SWTException <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>
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item order is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the item order is not the same length as the number of items</li>
+ * </ul>
+ *
+ * @see Table#getColumnOrder()
+ * @see TableColumn#getMoveable()
+ * @see TableColumn#setMoveable(boolean)
+ * @see SWT#Move
+ *
+ * @since 3.1
+ */
+public void setColumnOrder (int [] order) {
+ checkWidget ();
+ if (order == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (columnCount == 0) {
+ if (order.length != 0) error (SWT.ERROR_INVALID_ARGUMENT);
+ return;
+ }
+ if (order.length != columnCount) error (SWT.ERROR_INVALID_ARGUMENT);
+ int [] oldOrder = getColumnOrder ();
+ boolean reorder = false;
+ boolean [] seen = new boolean [columnCount];
+ for (int i=0; i<order.length; i++) {
+ int index = order [i];
+ if (index < 0 || index >= columnCount) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (seen [index]) error (SWT.ERROR_INVALID_ARGUMENT);
+ seen [index] = true;
+ if (order [i] != oldOrder [i]) reorder = true;
+ }
+ if (reorder) {
+ NSTableView tableView = (NSTableView)view;
+ int [] oldX = new int [oldOrder.length];
+ int check = (style & SWT.CHECK) != 0 ? 1 : 0;
+ for (int i=0; i<oldOrder.length; i++) {
+ int index = oldOrder[i];
+ oldX [index] = (int)tableView.rectOfColumn (i + check).x;
+ }
+ int [] newX = new int [order.length];
+ for (int i=0; i<order.length; i++) {
+ int index = order [i];
+ TableColumn column = columns[index];
+ int oldIndex = indexOf (column.nsColumn);
+ int newIndex = i + check;
+ tableView.moveColumn (oldIndex, newIndex);
+ newX [index] = (int)tableView.rectOfColumn (newIndex).x;
+ }
+ TableColumn[] newColumns = new TableColumn [columnCount];
+ System.arraycopy (columns, 0, newColumns, 0, columnCount);
+ for (int i=0; i<columnCount; i++) {
+ TableColumn column = newColumns [i];
+ if (!column.isDisposed ()) {
+ if (newX [i] != oldX [i]) {
+ column.sendEvent (SWT.Move);
+ }
+ }
+ }
+ }
+}
+
+void setFont (NSFont font) {
+ super.setFont (font);
+ setItemHeight (null, font, !hooks (SWT.MeasureItem));
+ view.setNeedsDisplay (true);
+ clearCachedWidth (items);
+ setScrollWidth (items, true);
+}
+
+/**
+ * Marks the receiver's header as visible if the argument is <code>true</code>,
+ * and marks it invisible otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, marking
+ * it visible may not actually cause it to be displayed.
+ * </p>
+ *
+ * @param show the new visibility state
+ *
+ * @exception SWTException <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 setHeaderVisible (boolean show) {
+ checkWidget ();
+ ((NSTableView)view).setHeaderView (show ? headerView : null);
+}
+
+void setImage (int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ OS.object_setInstanceVariable(id, Display.SWT_IMAGE, arg0);
+}
+
+/**
+ * Sets the number of items contained in the receiver.
+ *
+ * @param count the number of items
+ *
+ * @exception SWTException <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.0
+ */
+public void setItemCount (int count) {
+ checkWidget ();
+ count = Math.max (0, count);
+ if (count == itemCount) return;
+ if (count == itemCount) return;
+ TableItem [] children = items;
+ if (count < itemCount) {
+ for (int index = count; index < itemCount; index ++) {
+ TableItem item = children [index];
+ if (item != null && !item.isDisposed()) item.release (false);
+ }
+ }
+ if (count > itemCount) {
+ if ((getStyle() & SWT.VIRTUAL) == 0) {
+ for (int i=itemCount; i<count; i++) {
+ new TableItem (this, SWT.NONE, i, true);
+ }
+ return;
+ }
+ }
+ int length = Math.max (4, (count + 3) / 4 * 4);
+ TableItem [] newItems = new TableItem [length];
+ if (children != null) {
+ System.arraycopy (items, 0, newItems, 0, Math.min (count, itemCount));
+ }
+ children = newItems;
+ this.items = newItems;
+ this.itemCount = count;
+ ((NSTableView) view).noteNumberOfRowsChanged ();
+}
+
+/*public*/ void setItemHeight (int itemHeight) {
+ checkWidget ();
+ if (itemHeight < -1) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (itemHeight == -1) {
+ //TODO - reset item height, ensure other API's such as setFont don't do this
+ } else {
+ ((NSTableView)view).setRowHeight (itemHeight);
+ }
+}
+
+void setItemHeight (Image image, NSFont font, boolean set) {
+ if (font == null) font = getFont ().handle;
+ float /*double*/ ascent = font.ascender ();
+ float /*double*/ descent = -font.descender () + font.leading ();
+ int height = (int)Math.ceil (ascent + descent) + 1;
+ Rectangle bounds = image != null ? image.getBounds () : imageBounds;
+ if (bounds != null) {
+ imageBounds = bounds;
+ height = Math.max (height, bounds.height);
+ }
+ NSTableView widget = (NSTableView)view;
+ if (set || widget.rowHeight () < height) {
+ widget.setRowHeight (height);
+ }
+}
+
+public void setRedraw (boolean redraw) {
+ checkWidget ();
+ super.setRedraw (redraw);
+ if (redraw && drawCount == 0) {
+ /* Resize the item array to match the item count */
+ if (items.length > 4 && items.length - itemCount > 3) {
+ int length = Math.max (4, (itemCount + 3) / 4 * 4);
+ TableItem [] newItems = new TableItem [length];
+ System.arraycopy (items, 0, newItems, 0, itemCount);
+ items = newItems;
+ }
+ setScrollWidth ();
+ }
+}
+
+/**
+ * Marks the receiver's lines as visible if the argument is <code>true</code>,
+ * and marks it invisible otherwise. Note that some platforms draw grid lines
+ * while others may draw alternating row colors.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, marking
+ * it visible may not actually cause it to be displayed.
+ * </p>
+ *
+ * @param show the new visibility state
+ *
+ * @exception SWTException <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 setLinesVisible (boolean show) {
+ checkWidget ();
+ ((NSTableView)view).setUsesAlternatingRowBackgroundColors(show);
+}
+
+boolean setScrollWidth () {
+ return setScrollWidth (items, true);
+}
+
+boolean setScrollWidth (TableItem item) {
+ if (columnCount != 0) return false;
+ if (!getDrawing()) return false;
+ if (currentItem != null) {
+ if (currentItem != item) fixScrollWidth = true;
+ return false;
+ }
+ GC gc = new GC (this);
+ int newWidth = item.calculateWidth (0, gc);
+ gc.dispose ();
+ int oldWidth = (int)firstColumn.width ();
+ if (oldWidth < newWidth) {
+ firstColumn.setWidth (newWidth);
+ if (horizontalBar != null && horizontalBar.view != null) redrawWidget (horizontalBar.view, false);
+ return true;
+ }
+ return false;
+}
+
+boolean setScrollWidth (TableItem [] items, boolean set) {
+ if (items == null) return false;
+ if (columnCount != 0) return false;
+ if (!getDrawing()) return false;
+ if (currentItem != null) {
+ fixScrollWidth = true;
+ return false;
+ }
+ GC gc = new GC (this);
+ int newWidth = 0;
+ for (int i = 0; i < items.length; i++) {
+ TableItem item = items [i];
+ if (item != null) {
+ newWidth = Math.max (newWidth, item.calculateWidth (0, gc));
+ }
+ }
+ gc.dispose ();
+ if (!set) {
+ int oldWidth = (int)firstColumn.width ();
+ if (oldWidth >= newWidth) return false;
+ }
+ firstColumn.setWidth (newWidth);
+ if (horizontalBar != null && horizontalBar.view != null) redrawWidget (horizontalBar.view, false);
+ return true;
+}
+
+/**
+ * Selects the item at the given zero-relative index in the receiver.
+ * The current selection is first cleared, then the new item is selected.
+ *
+ * @param index the index of the item to select
+ *
+ * @exception SWTException <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#deselectAll()
+ * @see Table#select(int)
+ */
+public void setSelection (int index) {
+ checkWidget ();
+ //TODO - optimize to use expand flag
+ deselectAll ();
+ if (0 <= index && index < itemCount) {
+ select (index);
+ showIndex (index);
+ }
+}
+
+/**
+ * Selects the items in the range specified by the given zero-relative
+ * indices in the receiver. The range of indices is inclusive.
+ * The current selection is cleared before the new items are selected.
+ * <p>
+ * Indices that are out of range are ignored and no items will be selected
+ * if start is greater than end.
+ * If the receiver is single-select and there is more than one item in the
+ * given range, then all indices are ignored.
+ * </p>
+ *
+ * @param start the start index of the items to select
+ * @param end the end index of the items to select
+ *
+ * @exception SWTException <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#deselectAll()
+ * @see Table#select(int,int)
+ */
+public void setSelection (int start, int end) {
+ checkWidget ();
+ //TODO - optimize to use expand flag
+ deselectAll ();
+ if (end < 0 || start > end || ((style & SWT.SINGLE) != 0 && start != end)) return;
+ if (itemCount == 0 || start >= itemCount) return;
+ start = Math.max (0, start);
+ end = Math.min (end, itemCount - 1);
+ select (start, end);
+ showIndex (start);
+}
+
+/**
+ * Selects the items at the given zero-relative indices in the receiver.
+ * The current selection is cleared before the new items are selected.
+ * <p>
+ * Indices that are out of range and duplicate indices are ignored.
+ * If the receiver is single-select and multiple indices are specified,
+ * then all indices are ignored.
+ * </p>
+ *
+ * @param indices the indices of the items to select
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li>
+ * </ul>
+ * @exception SWTException <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#deselectAll()
+ * @see Table#select(int[])
+ */
+public void setSelection (int [] indices) {
+ checkWidget ();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ //TODO - optimize to use expand flag
+ deselectAll ();
+ int length = indices.length;
+ if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
+ select (indices);
+ showIndex (indices [0]);
+}
+
+/**
+ * Sets the receiver's selection to the given item.
+ * The current selection is cleared before the new item is selected.
+ * <p>
+ * If the item is not in the receiver, then it is ignored.
+ * </p>
+ *
+ * @param item the item to select
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setSelection (TableItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setSelection (new TableItem [] {item});
+}
+
+/**
+ * Sets the receiver's selection to be the given array of items.
+ * The current selection is cleared before the new items are selected.
+ * <p>
+ * Items that are not in the receiver are ignored.
+ * If the receiver is single-select and multiple items are specified,
+ * then all items are ignored.
+ * </p>
+ *
+ * @param items the array of items
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the array of items is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if one of the items has been disposed</li>
+ * </ul>
+ * @exception SWTException <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#deselectAll()
+ * @see Table#select(int[])
+ * @see Table#setSelection(int[])
+ */
+public void setSelection (TableItem [] items) {
+ checkWidget ();
+ if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
+ //TODO - optimize to use expand flag
+ deselectAll ();
+ int length = items.length;
+ if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
+ int [] indices = new int [length];
+ int count = 0;
+ for (int i=0; i<length; i++) {
+ int index = indexOf (items [length - i - 1]);
+ if (index != -1) {
+ indices [count++] = index;
+ }
+ }
+ if (count > 0) {
+ select (indices);
+ showIndex (indices [0]);
+ }
+}
+
+void setSmallSize () {
+ if (checkColumn == null) return;
+ checkColumn.dataCell ().setControlSize (OS.NSSmallControlSize);
+ checkColumn.setWidth (getCheckColumnWidth ());
+}
+
+/**
+ * Sets the column used by the sort indicator for the receiver. A null
+ * value will clear the sort indicator. The current sort column is cleared
+ * before the new column is set.
+ *
+ * @param column the column used by the sort indicator or <code>null</code>
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the column is disposed</li>
+ * </ul>
+ * @exception SWTException <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 setSortColumn (TableColumn column) {
+ checkWidget ();
+ if (column != null && column.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (column == sortColumn) return;
+ sortColumn = column;
+ ((NSTableView)view).setHighlightedTableColumn (column == null ? null : column.nsColumn);
+}
+
+/**
+ * Sets the direction of the sort indicator for the receiver. The value
+ * can be one of <code>UP</code>, <code>DOWN</code> or <code>NONE</code>.
+ *
+ * @param direction the direction of the sort indicator
+ *
+ * @exception SWTException <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 setSortDirection (int direction) {
+ checkWidget ();
+ if (direction != SWT.UP && direction != SWT.DOWN && direction != SWT.NONE) return;
+ if (direction == sortDirection) return;
+ sortDirection = direction;
+ if (sortColumn == null) return;
+ NSTableHeaderView headerView = ((NSTableView)view).headerView ();
+ if (headerView == null) return;
+ int index = indexOf (sortColumn.nsColumn);
+ NSRect rect = headerView.headerRectOfColumn (index);
+ headerView.setNeedsDisplayInRect (rect);
+}
+
+void setTableEmpty () {
+ itemCount = 0;
+ items = new TableItem [4];
+ imageBounds = null;
+}
+
+/**
+ * Sets the zero-relative index of the item which is currently
+ * at the top of the receiver. This index can change when items
+ * are scrolled or new items are added and removed.
+ *
+ * @param index the index of the top item
+ *
+ * @exception SWTException <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 setTopIndex (int index) {
+ checkWidget ();
+ NSTableView widget = (NSTableView) view;
+ int row = Math.max(0, Math.min(index, itemCount));
+ NSPoint pt = new NSPoint();
+ pt.x = scrollView.contentView().bounds().x;
+ pt.y = widget.frameOfCellAtColumn(0, row).y;
+ view.scrollPoint(pt);
+}
+
+/**
+ * Shows the column. If the column is already showing in the receiver,
+ * this method simply returns. Otherwise, the columns are scrolled until
+ * the column is visible.
+ *
+ * @param column the column to be shown
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the column is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the column has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.0
+ */
+public void showColumn (TableColumn column) {
+ checkWidget ();
+ if (column == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (column.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ if (column.parent != this) return;
+ if (columnCount <= 1) return;
+ int index = indexOf (column.nsColumn);
+ if (!(0 <= index && index < columnCount + ((style & SWT.CHECK) != 0 ? 1 : 0))) return;
+ ((NSTableView)view).scrollColumnToVisible (index);
+}
+
+void showIndex (int index) {
+ if (0 <= index && index < itemCount) {
+ ((NSTableView)view).scrollRowToVisible(index);
+ }
+}
+
+/**
+ * Shows the item. If the item is already showing in the receiver,
+ * this method simply returns. Otherwise, the items are scrolled until
+ * the item is visible.
+ *
+ * @param item the item to be shown
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
+ * </ul>
+ * @exception SWTException <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#showSelection()
+ */
+public void showItem (TableItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ int index = indexOf (item);
+ if (index != -1) showIndex (index);
+}
+
+/**
+ * Shows the selection. If the selection is already showing in the receiver,
+ * this method simply returns. Otherwise, the items are scrolled until
+ * the selection is visible.
+ *
+ * @exception SWTException <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#showItem(TableItem)
+ */
+public void showSelection () {
+ checkWidget ();
+ int index = getSelectionIndex ();
+ if (index >= 0) {
+ checkData(_getItem(index));
+ showIndex (index);
+ }
+}
+
+void sendDoubleSelection() {
+ NSTableView tableView = (NSTableView)view;
+ int rowIndex = (int)/*64*/tableView.clickedRow ();
+ if (rowIndex != -1) {
+ if ((style & SWT.CHECK) != 0) {
+ NSArray columns = tableView.tableColumns ();
+ int columnIndex = (int)/*64*/tableView.clickedColumn ();
+ id column = columns.objectAtIndex (columnIndex);
+ if (column.id == checkColumn.id) return;
+ }
+ Event event = new Event ();
+ event.item = _getItem (rowIndex);
+ postEvent (SWT.DefaultSelection, event);
+ }
+}
+
+boolean sendKeyEvent (NSEvent nsEvent, int type) {
+ boolean result = super.sendKeyEvent (nsEvent, type);
+ if (!result) return result;
+ if (type != SWT.KeyDown) return result;
+ short keyCode = nsEvent.keyCode ();
+ switch (keyCode) {
+ case 76: /* KP Enter */
+ case 36: { /* Return */
+ postEvent (SWT.DefaultSelection);
+ break;
+ }
+ }
+ return result;
+}
+
+void sendMeasureItem (TableItem item, int columnIndex, NSSize size) {
+ NSTableView widget = (NSTableView)this.view;
+ int contentWidth = (int)Math.ceil (size.width);
+ NSSize spacing = widget.intercellSpacing();
+ int itemHeight = (int)Math.ceil (widget.rowHeight() + spacing.height);
+ GCData data = new GCData ();
+ data.paintRect = widget.frame ();
+ GC gc = GC.cocoa_new (this, data);
+ gc.setFont (item.getFont (columnIndex));
+ Event event = new Event ();
+ event.item = item;
+ event.gc = gc;
+ event.index = columnIndex;
+ event.width = contentWidth;
+ event.height = itemHeight;
+ sendEvent (SWT.MeasureItem, event);
+ gc.dispose ();
+ if (!isDisposed () && !item.isDisposed ()) {
+ size.width = event.width;
+ size.height = event.height;
+ if (itemHeight < event.height) {
+ widget.setRowHeight (event.height);
+ }
+ if (contentWidth != event.width) {
+ if (columnCount == 0 && columnIndex == 0) {
+ item.width = event.width;
+ if (setScrollWidth (item)) {
+ widget.setNeedsDisplay(true);
+ }
+ }
+ }
+ }
+}
+
+void tableViewColumnDidMove (int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+ NSNotification notification = new NSNotification (aNotification);
+ NSDictionary userInfo = notification.userInfo ();
+ id nsOldIndex = userInfo.valueForKey (NSString.stringWith ("NSOldColumn")); //$NON-NLS-1$
+ id nsNewIndex = userInfo.valueForKey (NSString.stringWith ("NSNewColumn")); //$NON-NLS-1$
+ int oldIndex = new NSNumber (nsOldIndex).intValue ();
+ int newIndex = new NSNumber (nsNewIndex).intValue ();
+ int startIndex = Math.min (oldIndex, newIndex);
+ int endIndex = Math.max (oldIndex, newIndex);
+ NSTableView tableView = (NSTableView)view;
+ NSArray nsColumns = tableView.tableColumns ();
+ for (int i = startIndex; i <= endIndex; i++) {
+ id columnId = nsColumns.objectAtIndex (i);
+ TableColumn column = getColumn (columnId);
+ if (column != null) {
+ column.sendEvent (SWT.Move);
+ if (isDisposed ()) return;
+ }
+ }
+}
+
+void tableViewColumnDidResize (int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+ NSNotification notification = new NSNotification (aNotification);
+ NSDictionary userInfo = notification.userInfo ();
+ id columnId = userInfo.valueForKey (NSString.stringWith ("NSTableColumn")); //$NON-NLS-1$
+ TableColumn column = getColumn (columnId);
+ if (column == null) return; /* either CHECK column or firstColumn in 0-column Table */
+
+ column.sendEvent (SWT.Resize);
+ if (isDisposed ()) return;
+
+ NSTableView tableView = (NSTableView)view;
+ int index = indexOf (column.nsColumn);
+ if (index == -1) return; /* column was disposed in Resize callback */
+
+ NSArray nsColumns = tableView.tableColumns ();
+ int columnCount = (int)/*64*/tableView.numberOfColumns ();
+ for (int i = index + 1; i < columnCount; i++) {
+ columnId = nsColumns.objectAtIndex (i);
+ column = getColumn (columnId);
+ if (column != null) {
+ column.sendEvent (SWT.Move);
+ if (isDisposed ()) return;
+ }
+ }
+}
+
+void tableViewSelectionDidChange (int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+ if (ignoreSelect) return;
+ NSTableView widget = (NSTableView) view;
+ int row = (int)/*64*/widget.selectedRow ();
+ if(row == -1)
+ postEvent (SWT.Selection);
+ else {
+ TableItem item = _getItem (row);
+ Event event = new Event ();
+ event.item = item;
+ event.index = row;
+ postEvent (SWT.Selection, event);
+ }
+}
+
+void tableView_didClickTableColumn (int /*long*/ id, int /*long*/ sel, int /*long*/ tableView, int /*long*/ tableColumn) {
+ TableColumn column = getColumn (new id (tableColumn));
+ if (column == null) return; /* either CHECK column or firstColumn in 0-column Table */
+ column.postEvent (SWT.Selection);
+}
+
+int /*long*/ tableView_objectValueForTableColumn_row (int /*long*/ id, int /*long*/ sel, int /*long*/ aTableView, int /*long*/ aTableColumn, int /*long*/ rowIndex) {
+ int index = (int)/*64*/rowIndex;
+ TableItem item = _getItem (index);
+ checkData (item, index);
+ if (checkColumn != null && aTableColumn == checkColumn.id) {
+ NSNumber value;
+ if (item.checked && item.grayed) {
+ value = NSNumber.numberWithInt (OS.NSMixedState);
+ } else {
+ value = NSNumber.numberWithInt (item.checked ? OS.NSOnState : OS.NSOffState);
+ }
+ return value.id;
+ }
+ for (int i=0; i<columnCount; i++) {
+ if (columns [i].nsColumn.id == aTableColumn) {
+ return item.createString (i).id;
+ }
+ }
+ return item.createString (0).id;
+}
+
+void tableView_setObjectValue_forTableColumn_row (int /*long*/ id, int /*long*/ sel, int /*long*/ aTableView, int /*long*/ anObject, int /*long*/ aTableColumn, int /*long*/ rowIndex) {
+ if (checkColumn != null && aTableColumn == checkColumn.id) {
+ TableItem item = items [(int)/*64*/rowIndex];
+ item.checked = !item.checked;
+ Event event = new Event ();
+ event.detail = SWT.CHECK;
+ event.item = item;
+ event.index = (int)/*64*/rowIndex;
+ postEvent (SWT.Selection, event);
+ item.redraw (-1);
+ }
+}
+
+boolean tableView_shouldEditTableColumn_row (int /*long*/ id, int /*long*/ sel, int /*long*/ aTableView, int /*long*/ aTableColumn, int /*long*/ rowIndex) {
+ return false;
+}
+
+void tableView_willDisplayCell_forTableColumn_row (int /*long*/ id, int /*long*/ sel, int /*long*/ aTableView, int /*long*/ cell, int /*long*/ tableColumn, int /*long*/ rowIndex) {
+ if (checkColumn != null && tableColumn == checkColumn.id) return;
+ TableItem item = items [(int)/*64*/rowIndex];
+ int index = 0;
+ for (int i=0; i<columnCount; i++) {
+ if (columns [i].nsColumn.id == tableColumn) {
+ index = i;
+ break;
+ }
+ }
+ NSTextFieldCell textCell = new NSTextFieldCell (cell);
+ OS.object_setInstanceVariable(cell, Display.SWT_ROW, rowIndex);
+ OS.object_setInstanceVariable(cell, Display.SWT_COLUMN, tableColumn);
+ Image image = index == 0 ? item.image : (item.images == null ? null : item.images [index]);
+ textCell.setImage (image != null ? image.handle : null);
+ NSColor color;
+ if (textCell.isEnabled()) {
+ if (textCell.isHighlighted()) {
+ color = NSColor.selectedControlTextColor();
+ } else {
+ Color foreground = item.cellForeground != null ? item.cellForeground [index] : null;
+ if (foreground == null) foreground = item.foreground;
+ if (foreground == null) foreground = getForegroundColor();
+ color = NSColor.colorWithDeviceRed (foreground.handle [0], foreground.handle [1], foreground.handle [2], 1);
+ }
+ } else {
+ color = NSColor.disabledControlTextColor();
+ }
+ int alignment = OS.NSLeftTextAlignment;
+ if (columnCount > 0) {
+ int style = columns [index].style;
+ if ((style & SWT.CENTER) != 0) {
+ alignment = OS.NSCenterTextAlignment;
+ } else if ((style & SWT.RIGHT) != 0) {
+ alignment = OS.NSRightTextAlignment;
+ }
+ }
+ Font font = item.cellFont != null ? item.cellFont [index] : null;
+ if (font == null) font = item.font;
+ if (font == null) font = this.font;
+ if (font == null) font = defaultFont ();
+ if (font.extraTraits != 0) {
+ NSMutableDictionary dict = ((NSMutableDictionary)new NSMutableDictionary().alloc()).initWithCapacity(5);
+ dict.setObject (color, OS.NSForegroundColorAttributeName);
+ dict.setObject (font.handle, OS.NSFontAttributeName);
+ addTraits(dict, font);
+ NSMutableParagraphStyle paragraphStyle = (NSMutableParagraphStyle)new NSMutableParagraphStyle ().alloc ().init ();
+ paragraphStyle.setLineBreakMode (OS.NSLineBreakByClipping);
+ paragraphStyle.setAlignment (alignment);
+ dict.setObject (paragraphStyle, OS.NSParagraphStyleAttributeName);
+ paragraphStyle.release ();
+ NSAttributedString attribStr = ((NSAttributedString) new NSAttributedString ().alloc ()).initWithString (textCell.title(), dict);
+ textCell.setAttributedStringValue(attribStr);
+ attribStr.release();
+ dict.release();
+ } else {
+ textCell.setFont(font.handle);
+ textCell.setTextColor(color);
+ textCell.setAlignment (alignment);
+ }
+}
+
+boolean tableView_writeRowsWithIndexes_toPasteboard(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1, int /*long*/ arg2) {
+ return sendMouseEvent(NSApplication.sharedApplication().currentEvent(), SWT.DragDetect, true);
+}
+
+NSRect titleRectForBounds (int /*long*/ id, int /*long*/ sel, NSRect cellFrame) {
+ NSImage image = new NSCell(id).image();
+ if (image != null) {
+ int imageWidth = imageBounds.width + IMAGE_GAP;
+ cellFrame.x += imageWidth;
+ cellFrame.width -= imageWidth;
+ }
+ return cellFrame;
+}
+
+void updateCursorRects (boolean enabled) {
+ super.updateCursorRects (enabled);
+ if (headerView == null) return;
+ updateCursorRects (enabled, headerView);
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TableColumn.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TableColumn.java
new file mode 100755
index 0000000000..8bfd6587e4
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TableColumn.java
@@ -0,0 +1,677 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.events.*;
+
+/**
+ * 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>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class TableColumn extends Item {
+ Table parent;
+ NSTableColumn nsColumn;
+ String toolTipText, displayText;
+ boolean movable;
+
+ static final 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>SWT</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>SWT</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 SWTException <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 SWT#LEFT
+ * @see SWT#RIGHT
+ * @see SWT#CENTER
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TableColumn (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>SWT</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>SWT</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 SWTException <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 SWT#LEFT
+ * @see SWT#RIGHT
+ * @see SWT#CENTER
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TableColumn (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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Resize,typedListener);
+ addListener (SWT.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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+static int checkStyle (int style) {
+ return checkBits (style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0);
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.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, NSRect cellRect, int /*long*/ view) {
+ /*
+ * 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.
+ */
+ int columnIndex = parent.indexOf (nsColumn);
+ NSRect headerRect = parent.headerView.headerRectOfColumn (columnIndex);
+ if (headerRect.x != cellRect.x || headerRect.width != 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 != null) {
+ Font font = Font.cocoa_new(display, headerCell.font ());
+ attrString = parent.createString(displayText, font, null, SWT.LEFT, (parent.state & DISABLED) == 0, false);
+ stringSize = attrString.size ();
+ contentWidth += Math.ceil (stringSize.width);
+ if (image != null) contentWidth += MARGIN; /* space between image and text */
+ }
+ if (image != null) {
+ imageSize = image.handle.size ();
+ contentWidth += Math.ceil (imageSize.width);
+ }
+
+ if (parent.sortColumn == this && parent.sortDirection != SWT.NONE) {
+ boolean ascending = parent.sortDirection == SWT.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 & SWT.CENTER) != 0) {
+ drawX = (int)(cellRect.x + Math.max (MARGIN, ((cellRect.width - contentWidth) / 2)));
+ } else if ((style & SWT.RIGHT) != 0) {
+ drawX = (int)(cellRect.x + Math.max (MARGIN, cellRect.width - contentWidth - MARGIN));
+ } else {
+ drawX = (int)cellRect.x + MARGIN;
+ }
+
+ if (image != 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);
+ boolean 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 != null && displayText.length () > 0) {
+ if (image != 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);
+ }
+ if (attrString != null) 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 SWTException <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 & SWT.LEFT) != 0) return SWT.LEFT;
+ if ((style & SWT.CENTER) != 0) return SWT.CENTER;
+ if ((style & SWT.RIGHT) != 0) return SWT.RIGHT;
+ return SWT.LEFT;
+}
+
+String getNameText () {
+ return getText ();
+}
+
+/**
+ * Returns the receiver's parent, which must be a <code>Table</code>.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException <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 SWTException <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(boolean)
+ * @see SWT#Move
+ *
+ * @since 3.1
+ */
+public boolean getMoveable () {
+ checkWidget ();
+ return movable;
+}
+
+/**
+ * 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 SWTException <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 boolean getResizable () {
+ checkWidget ();
+ return nsColumn.resizingMask() != 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 SWTException <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 SWTException <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 ();
+ int width = (int)nsColumn.width();
+ // TODO how to differentiate 0 and 1 cases?
+ if (width > 0) width += Table.CELL_GAP;
+ return 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 SWTException <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 != null) {
+ NSTableHeaderCell headerCell = nsColumn.headerCell ();
+ Font font = Font.cocoa_new(display, headerCell.font ());
+ NSAttributedString attrString = parent.createString(displayText, font, null, 0, true, false);
+ NSSize stringSize = attrString.size ();
+ attrString.release ();
+ width += Math.ceil (stringSize.width);
+ if (image != null) width += MARGIN; /* space between image and text */
+ }
+ if (image != null) {
+ NSSize imageSize = image.handle.size ();
+ width += Math.ceil (imageSize.width);
+ }
+ if (parent.sortColumn == this && parent.sortDirection != SWT.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);
+ width = Math.max (width, parent.calculateWidth (parent.items, index, gc));
+ gc.dispose ();
+ setWidth (width);
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (nsColumn != null) {
+ nsColumn.headerCell ().release ();
+ nsColumn.release ();
+ }
+ nsColumn = null;
+ parent = null;
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ if (parent.sortColumn == 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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Move, listener);
+ eventTable.unhook (SWT.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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.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 SWTException <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 & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) == 0) return;
+ int index = parent.indexOf (this);
+ if (index == -1 || index == 0) return;
+ style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER);
+ style |= alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER);
+ NSTableView tableView = ((NSTableView) parent.view);
+ NSTableHeaderView headerView = tableView.headerView ();
+ if (headerView == null) return;
+ index = parent.indexOf (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 != null && image.isDisposed ()) {
+ error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ super.setImage (image);
+ NSTableHeaderView headerView = ((NSTableView) parent.view).headerView ();
+ if (headerView == null) return;
+ int index = parent.indexOf (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 SWTException <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 SWT#Move
+ *
+ * @since 3.1
+ */
+public void setMoveable (boolean moveable) {
+ checkWidget ();
+ this.movable = moveable;
+}
+
+/**
+ * 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 SWTException <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 (boolean resizable) {
+ checkWidget ();
+ nsColumn.setResizingMask (resizable ? OS.NSTableColumnUserResizingMask : OS.NSTableColumnNoResizing);
+}
+
+public void setText (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.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 = ((NSTableView) parent.view).headerView ();
+ if (headerView == null) return;
+ int index = parent.indexOf (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 the default tool tip for the
+ * control will be shown. For a control that has a default
+ * tool tip, such as the Tree control on Windows, setting
+ * the tool tip text to an empty string replaces the default,
+ * causing no tool tip text to be shown.
+ * <p>
+ * The mnemonic indicator (character '&amp;') is not displayed in a tool tip.
+ * To display a single '&amp;' in the tool tip, the character '&amp;' can be
+ * escaped by doubling it in the string.
+ * </p>
+ *
+ * @param string the new tool tip text (or null)
+ *
+ * @exception SWTException <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;
+ parent.checkToolTip (this);
+}
+
+/**
+ * Sets the width of the receiver.
+ *
+ * @param width the new width
+ *
+ * @exception SWTException <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;
+ // TODO how to differentiate 0 and 1 cases?
+ width = Math.max (0, width - Table.CELL_GAP);
+ nsColumn.setWidth (width);
+}
+
+String tooltipText () {
+ return toolTipText;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TableItem.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TableItem.java
new file mode 100755
index 0000000000..3711d3dfb1
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TableItem.java
@@ -0,0 +1,1031 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Instances of this class represent a selectable user interface object
+ * that represents an item in a table.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <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>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class TableItem extends Item {
+ Table parent;
+ String [] strings;
+ Image [] images;
+ boolean checked, grayed, cached;
+ Color foreground, background;
+ Color[] cellForeground, cellBackground;
+ Font font;
+ Font[] cellFont;
+ int width = -1;
+
+/**
+ * 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>SWT</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>SWT</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 SWTException <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 SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TableItem (Table parent, int style) {
+ this (parent, style, checkNull (parent).getItemCount (), true);
+}
+
+/**
+ * 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>SWT</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>SWT</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
+ * @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 SWTException <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 SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TableItem (Table parent, int style, int index) {
+ this (parent, style, index, true);
+}
+
+TableItem (Table parent, int style, int index, boolean create) {
+ super (parent, style);
+ this.parent = parent;
+ if (create) parent.createItem (this, index);
+}
+
+static Table checkNull (Table control) {
+ if (control == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return control;
+}
+
+int calculateWidth (int index, GC gc) {
+ if (index == 0 && width != -1) return width;
+ Font font = null;
+ if (cellFont != null) font = cellFont[index];
+ if (font == null) font = this.font;
+ if (font == null) font = parent.font;
+ if (font == null) font = parent.defaultFont();
+ String text = index == 0 ? this.text : (strings == null ? "" : strings [index]);
+ Image image = index == 0 ? this.image : (images == null ? null : images [index]);
+ NSCell cell = parent.dataCell;
+ if (font.extraTraits != 0) {
+ NSAttributedString attribStr = parent.createString(text, font, null, 0, true, false);
+ cell.setAttributedStringValue(attribStr);
+ attribStr.release();
+ } else {
+ cell.setFont (font.handle);
+ cell.setTitle (NSString.stringWith(text != null ? text : ""));
+ }
+
+ /* This code is inlined for performance */
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = cell.id;
+ super_struct.super_class = OS.objc_msgSend(cell.id, OS.sel_superclass);
+ NSSize size = new NSSize();
+ OS.objc_msgSendSuper_stret(size, super_struct, OS.sel_cellSize);
+ if (image != null) size.width += parent.imageBounds.width + Table.IMAGE_GAP;
+// cell.setImage (image != null ? image.handle : null);
+// NSSize size = cell.cellSize ();
+
+ int width = (int)Math.ceil (size.width);
+ boolean sendMeasure = true;
+ if ((parent.style & SWT.VIRTUAL) != 0) {
+ sendMeasure = cached;
+ }
+ if (sendMeasure && parent.hooks (SWT.MeasureItem)) {
+ gc.setFont (font);
+ Event event = new Event ();
+ event.item = this;
+ event.index = index;
+ event.gc = gc;
+ NSTableView widget = (NSTableView)parent.view;
+ int height = (int)widget.rowHeight ();
+ event.width = width;
+ event.height = height;
+ parent.sendEvent (SWT.MeasureItem, event);
+ if (height < event.height) {
+ widget.setRowHeight (event.height);
+ widget.setNeedsDisplay (true);
+ }
+ width = event.width;
+ }
+ if (index == 0) this.width = width;
+ return width;
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+void clear () {
+ text = "";
+ image = null;
+ strings = null;
+ images = null;
+ checked = grayed = cached = false;
+ foreground = background = null;
+ cellForeground = cellBackground = null;
+ font = null;
+ cellFont = null;
+ width = -1;
+}
+
+NSObject createString (int index) {
+ String text = index == 0 ? this.text : (strings == null ? "" : strings [index]);
+ return NSString.stringWith(text != null ? text : "");
+}
+
+void destroyWidget () {
+ parent.destroyItem (this);
+ releaseHandle ();
+}
+
+/**
+ * Returns the receiver's background color.
+ *
+ * @return the background color
+ *
+ * @exception SWTException <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 2.0
+ */
+public Color getBackground () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ return background != null ? background : parent.getBackground ();
+}
+
+/**
+ * Returns the background color at the given column index in the receiver.
+ *
+ * @param index the column index
+ * @return the background color
+ *
+ * @exception SWTException <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.0
+ */
+public Color getBackground (int index) {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ int count = Math.max (1, parent.columnCount);
+ if (0 > index || index > count -1) return getBackground ();
+ if (cellBackground == null || cellBackground [index] == null) return getBackground ();
+ return cellBackground [index];
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location
+ * relative to its parent.
+ *
+ * @return the receiver's bounding rectangle
+ *
+ * @exception SWTException <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 Rectangle getBounds () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ NSTableView tableView = (NSTableView) parent.view;
+ NSRect rect = tableView.rectOfRow (parent.indexOf (this));
+ return new Rectangle((int) rect.x, (int) rect.y, (int) rect.width, (int) rect.height);
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location
+ * relative to its parent at a column in the table.
+ *
+ * @param index the index that specifies the column
+ * @return the receiver's bounding column rectangle
+ *
+ * @exception SWTException <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 Rectangle getBounds (int index) {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ if (!(0 <= index && index < Math.max (1, parent.columnCount))) return new Rectangle (0, 0, 0, 0);
+
+ NSTableView tableView = (NSTableView) parent.view;
+ if (parent.columnCount == 0) {
+ index = (parent.style & SWT.CHECK) != 0 ? 1 : 0;
+ } else {
+ TableColumn column = parent.getColumn (index);
+ index = parent.indexOf (column.nsColumn);
+ }
+ NSRect rect = tableView.frameOfCellAtColumn (index, parent.indexOf (this));
+ return new Rectangle ((int) rect.x, (int) rect.y, (int) rect.width, (int) rect.height);
+}
+
+/**
+ * Returns <code>true</code> if the receiver is checked,
+ * and false otherwise. When the parent does not have
+ * the <code>CHECK</code> style, return false.
+ *
+ * @return the checked state of the checkbox
+ *
+ * @exception SWTException <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 boolean getChecked () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ if ((parent.style & SWT.CHECK) == 0) return false;
+ return checked;
+}
+
+/**
+ * Returns the font that the receiver will use to paint textual information for this item.
+ *
+ * @return the receiver's font
+ *
+ * @exception SWTException <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.0
+ */
+public Font getFont () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ return font != null ? font : parent.getFont ();
+}
+
+/**
+ * Returns the font that the receiver will use to paint textual information
+ * for the specified cell in this item.
+ *
+ * @param index the column index
+ * @return the receiver's font
+ *
+ * @exception SWTException <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.0
+ */
+public Font getFont (int index) {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ int count = Math.max (1, parent.columnCount);
+ if (0 > index || index > count -1) return getFont ();
+ if (cellFont == null || cellFont [index] == null) return getFont ();
+ return cellFont [index];
+}
+
+/**
+ * Returns the foreground color that the receiver will use to draw.
+ *
+ * @return the receiver's foreground color
+ *
+ * @exception SWTException <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 2.0
+ */
+public Color getForeground () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ return foreground != null ? foreground : parent.getForeground ();
+}
+
+/**
+ *
+ * Returns the foreground color at the given column index in the receiver.
+ *
+ * @param index the column index
+ * @return the foreground color
+ *
+ * @exception SWTException <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.0
+ */
+public Color getForeground (int index) {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ int count = Math.max (1, parent.columnCount);
+ if (0 > index || index > count -1) return getForeground ();
+ if (cellForeground == null || cellForeground [index] == null) return getForeground ();
+ return cellForeground [index];
+}
+
+/**
+ * Returns <code>true</code> if the receiver is grayed,
+ * and false otherwise. When the parent does not have
+ * the <code>CHECK</code> style, return false.
+ *
+ * @return the grayed state of the checkbox
+ *
+ * @exception SWTException <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 boolean getGrayed () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ if ((parent.style & SWT.CHECK) == 0) return false;
+ return grayed;
+}
+
+public Image getImage () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ return super.getImage ();
+}
+
+/**
+ * Returns the image stored at the given column index in the receiver,
+ * or null if the image has not been set or if the column does not exist.
+ *
+ * @param index the column index
+ * @return the image stored at the given column index in the receiver
+ *
+ * @exception SWTException <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 Image getImage (int index) {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ if (index == 0) return getImage ();
+ if (images != null) {
+ if (0 <= index && index < images.length) return images [index];
+ }
+ return null;
+}
+
+/**
+ * Returns a rectangle describing the size and location
+ * relative to its parent of an image at a column in the
+ * table. An empty rectangle is returned if index exceeds
+ * the index of the table's last column.
+ *
+ * @param index the index that specifies the column
+ * @return the receiver's bounding image rectangle
+ *
+ * @exception SWTException <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 Rectangle getImageBounds (int index) {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ if (!(0 <= index && index < Math.max (1, parent.columnCount))) return new Rectangle (0, 0, 0, 0);
+
+ NSTableView tableView = (NSTableView) parent.view;
+ Image image = index == 0 ? this.image : (images != null) ? images [index] : null;
+ if (parent.columnCount == 0) {
+ index = (parent.style & SWT.CHECK) != 0 ? 1 : 0;
+ } else {
+ TableColumn column = parent.getColumn (index);
+ index = parent.indexOf (column.nsColumn);
+ }
+ NSRect rect = tableView.frameOfCellAtColumn (index, parent.indexOf (this));
+ rect.x += Table.IMAGE_GAP;
+ if (image != null) {
+ rect.width = parent.imageBounds.width;
+ } else {
+ rect.width = 0;
+ }
+ return new Rectangle((int) rect.x, (int) rect.y, (int) rect.width, (int) rect.height);
+}
+
+/**
+ * Gets the image indent.
+ *
+ * @return the indent
+ *
+ * @exception SWTException <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 getImageIndent () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ return 0;
+}
+
+String getNameText () {
+ if ((parent.style & SWT.VIRTUAL) != 0) {
+ if (!cached) return "*virtual*"; //$NON-NLS-1$
+ }
+ return super.getNameText ();
+}
+
+/**
+ * Returns the receiver's parent, which must be a <code>Table</code>.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException <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;
+}
+
+public String getText () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ return super.getText ();
+}
+
+/**
+ * Returns the text stored at the given column index in the receiver,
+ * or empty string if the text has not been set.
+ *
+ * @param index the column index
+ * @return the text stored at the given column index in the receiver
+ *
+ * @exception SWTException <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 String getText (int index) {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ if (index == 0) return getText ();
+ if (strings != null) {
+ if (0 <= index && index < strings.length) {
+ String string = strings [index];
+ return string != null ? string : "";
+ }
+ }
+ return "";
+}
+
+/**
+ * Returns a rectangle describing the size and location
+ * relative to its parent of the text at a column in the
+ * table. An empty rectangle is returned if index exceeds
+ * the index of the table's last column.
+ *
+ * @param index the index that specifies the column
+ * @return the receiver's bounding text rectangle
+ *
+ * @exception SWTException <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.3
+ */
+public Rectangle getTextBounds (int index) {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ if (!(0 <= index && index < Math.max (1, parent.columnCount))) return new Rectangle (0, 0, 0, 0);
+
+ NSTableView tableView = (NSTableView) parent.view;
+ Image image = index == 0 ? this.image : (images != null) ? images [index] : null;
+ if (parent.columnCount == 0) {
+ index = (parent.style & SWT.CHECK) != 0 ? 1 : 0;
+ } else {
+ TableColumn column = parent.getColumn (index);
+ index = parent.indexOf (column.nsColumn);
+ }
+ NSRect rect = tableView.frameOfCellAtColumn (index, parent.indexOf (this));
+ rect.x += Table.TEXT_GAP;
+ rect.width -= Table.TEXT_GAP;
+ if (image != null) {
+ int offset = parent.imageBounds.width + Table.IMAGE_GAP;
+ rect.x += offset;
+ rect.width -= offset;
+ }
+ return new Rectangle((int) rect.x, (int) rect.y, (int) rect.width, (int) rect.height);
+}
+
+void redraw (int columnIndex) {
+ if (parent.currentItem == this || !isDrawing()) return;
+ /* redraw the full item if columnIndex == -1 */
+ NSTableView tableView = (NSTableView) parent.view;
+ NSRect rect = null;
+ if (columnIndex == -1 || parent.hooks (SWT.MeasureItem) || parent.hooks (SWT.EraseItem) || parent.hooks (SWT.PaintItem)) {
+ rect = tableView.rectOfRow (parent.indexOf (this));
+ } else {
+ int index;
+ if (parent.columnCount == 0) {
+ index = (parent.style & SWT.CHECK) != 0 ? 1 : 0;
+ } else {
+ if (0 <= columnIndex && columnIndex < parent.columnCount) {
+ index = parent.indexOf (parent.columns[columnIndex].nsColumn);
+ } else {
+ return;
+ }
+ }
+ rect = tableView.frameOfCellAtColumn (index, parent.indexOf (this));
+ }
+ tableView.setNeedsDisplayInRect (rect);
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ parent = null;
+}
+
+void releaseParent () {
+ super.releaseParent ();
+// parent.checkItems (true);
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ strings = null;
+ images = null;
+ background = foreground = null;
+ font = null;
+ cellBackground = cellForeground = null;
+ cellFont = null;
+}
+
+/**
+ * Sets the receiver's background color to the color specified
+ * by the argument, or to the default system color for the item
+ * if the argument is null.
+ *
+ * @param color the new color (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 2.0
+ */
+public void setBackground (Color color) {
+ checkWidget ();
+ if (color != null && color.isDisposed ()) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ Color oldColor = background;
+ if (oldColor == color) return;
+ background = color;
+ if (oldColor != null && oldColor.equals (color)) return;
+ cached = true;
+ redraw (-1);
+}
+
+/**
+ * Sets the background color at the given column index in the receiver
+ * to the color specified by the argument, or to the default system color for the item
+ * if the argument is null.
+ *
+ * @param index the column index
+ * @param color the new color (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.0
+ */
+public void setBackground (int index, Color color) {
+ checkWidget ();
+ if (color != null && color.isDisposed ()) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ int count = Math.max (1, parent.columnCount);
+ if (0 > index || index > count - 1) return;
+ if (cellBackground == null) {
+ if (color == null) return;
+ cellBackground = new Color [count];
+ }
+ Color oldColor = cellBackground [index];
+ if (oldColor == color) return;
+ cellBackground [index] = color;
+ if (oldColor != null && oldColor.equals (color)) return;
+ cached = true;
+ redraw (index);
+}
+
+/**
+ * Sets the checked state of the checkbox for this item. This state change
+ * only applies if the Table was created with the SWT.CHECK style.
+ *
+ * @param checked the new checked state of the checkbox
+ *
+ * @exception SWTException <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 setChecked (boolean checked) {
+ checkWidget ();
+ if ((parent.style & SWT.CHECK) == 0) return;
+ if (this.checked == checked) return;
+ this.checked = checked;
+ cached = true;
+ redraw (-1);
+}
+
+/**
+ * Sets the font that the receiver will use to paint textual information
+ * for this item to the font specified by the argument, or to the default font
+ * for that kind of control if the argument is null.
+ *
+ * @param font the new font (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.0
+ */
+public void setFont (Font font) {
+ checkWidget ();
+ if (font != null && font.isDisposed ()) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ Font oldFont = this.font;
+ if (oldFont == font) return;
+ this.font = font;
+ if (oldFont != null && oldFont.equals (font)) return;
+ width = -1;
+ cached = true;
+ redraw (-1);
+}
+
+/**
+ * Sets the font that the receiver will use to paint textual information
+ * for the specified cell in this item to the font specified by the
+ * argument, or to the default font for that kind of control if the
+ * argument is null.
+ *
+ * @param index the column index
+ * @param font the new font (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.0
+ */
+public void setFont (int index, Font font) {
+ checkWidget ();
+ if (font != null && font.isDisposed ()) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ int count = Math.max (1, parent.columnCount);
+ if (0 > index || index > count - 1) return;
+ if (cellFont == null) {
+ if (font == null) return;
+ cellFont = new Font [count];
+ }
+ Font oldFont = cellFont [index];
+ if (oldFont == font) return;
+ cellFont [index] = font;
+ if (oldFont != null && oldFont.equals (font)) return;
+ width = -1;
+ cached = true;
+ redraw (index);
+}
+
+/**
+ * Sets the receiver's foreground color to the color specified
+ * by the argument, or to the default system color for the item
+ * if the argument is null.
+ *
+ * @param color the new color (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 2.0
+ */
+public void setForeground (Color color) {
+ checkWidget ();
+ if (color != null && color.isDisposed ()) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ Color oldColor = foreground;
+ if (oldColor == color) return;
+ foreground = color;
+ if (oldColor != null && oldColor.equals (color)) return;
+ cached = true;
+ redraw (-1);
+}
+
+/**
+ * Sets the foreground color at the given column index in the receiver
+ * to the color specified by the argument, or to the default system color for the item
+ * if the argument is null.
+ *
+ * @param index the column index
+ * @param color the new color (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.0
+ */
+public void setForeground (int index, Color color) {
+ checkWidget ();
+ if (color != null && color.isDisposed ()) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ int count = Math.max (1, parent.columnCount);
+ if (0 > index || index > count - 1) return;
+ if (cellForeground == null) {
+ if (color == null) return;
+ cellForeground = new Color [count];
+ }
+ Color oldColor = cellForeground [index];
+ if (oldColor == color) return;
+ cellForeground [index] = color;
+ if (oldColor != null && oldColor.equals (color)) return;
+ cached = true;
+ redraw (index);
+}
+
+/**
+ * Sets the grayed state of the checkbox for this item. This state change
+ * only applies if the Table was created with the SWT.CHECK style.
+ *
+ * @param grayed the new grayed state of the checkbox;
+ *
+ * @exception SWTException <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 setGrayed (boolean grayed) {
+ checkWidget ();
+ if ((parent.style & SWT.CHECK) == 0) return;
+ if (this.grayed == grayed) return;
+ this.grayed = grayed;
+ cached = true;
+ redraw (-1);
+}
+
+/**
+ * Sets the image for multiple columns in the table.
+ *
+ * @param images the array of new images
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the array of images is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if one of the images has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setImage (Image [] images) {
+ checkWidget ();
+ if (images == null) error (SWT.ERROR_NULL_ARGUMENT);
+ for (int i=0; i<images.length; i++) {
+ setImage (i, images [i]);
+ }
+}
+
+/**
+ * Sets the receiver's image at a column.
+ *
+ * @param index the column index
+ * @param image the new image
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setImage (int index, Image image) {
+ checkWidget ();
+ if (image != null && image.isDisposed ()) {
+ error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ int itemIndex = parent.indexOf (this);
+ if (itemIndex == -1) return;
+ if (parent.imageBounds == null && image != null) {
+ parent.setItemHeight (image, null, false);
+ }
+ if (index == 0) {
+ if (image != null && image.type == SWT.ICON) {
+ if (image.equals (this.image)) return;
+ }
+ width = -1;
+ super.setImage (image);
+ }
+ int count = Math.max (1, parent.columnCount);
+ if (0 <= index && index < count) {
+ if (images == null) images = new Image [count];
+ if (image != null && image.type == SWT.ICON) {
+ if (image.equals (images [index])) return;
+ }
+ images [index] = image;
+ }
+ cached = true;
+ if (index == 0) parent.setScrollWidth (this);
+ redraw (index);
+}
+
+public void setImage (Image image) {
+ checkWidget ();
+ setImage (0, image);
+}
+
+/**
+ * Sets the indent of the first column's image, expressed in terms of the image's width.
+ *
+ * @param indent the new indent
+ *
+ * </ul>
+ * @exception SWTException <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>
+ *
+ * @deprecated this functionality is not supported on most platforms
+ */
+public void setImageIndent (int indent) {
+ checkWidget ();
+ if (indent < 0) return;
+ cached = true;
+ /* Image indent is not supported on the Macintosh */
+}
+
+/**
+ * Sets the text for multiple columns in the table.
+ *
+ * @param strings the array of new strings
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
+ * </ul>
+ * @exception SWTException <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 setText (String [] strings) {
+ checkWidget ();
+ if (strings == null) error (SWT.ERROR_NULL_ARGUMENT);
+ for (int i=0; i<strings.length; i++) {
+ String string = strings [i];
+ if (string != null) setText (i, string);
+ }
+}
+
+/**
+ * Sets the receiver's text at a column
+ *
+ * @param index the column index
+ * @param string the new text
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
+ * </ul>
+ * @exception SWTException <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 setText (int index, String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (index == 0) {
+ if (string.equals (text)) return;
+ width = -1;
+ super.setText (string);
+ }
+ int count = Math.max (1, parent.columnCount);
+ if (0 <= index && index < count) {
+ if (strings == null) strings = new String [count];
+ if (string.equals (strings [index])) return;
+ strings [index] = string;
+ }
+ cached = true;
+ if (index == 0) parent.setScrollWidth (this);
+ redraw (index);
+}
+
+public void setText (String string) {
+ checkWidget ();
+ setText (0, string);
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Text.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Text.java
new file mode 100755
index 0000000000..b7876ed9bf
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Text.java
@@ -0,0 +1,1983 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class are selectable user interface
+ * objects that allow the user to enter and modify text.
+ * Text controls can be either single or multi-line.
+ * When a text control is created with a border, the
+ * operating system includes a platform specific inset
+ * around the contents of the control. When created
+ * without a border, an effort is made to remove the
+ * inset such that the preferred size of the control
+ * is the same size as the contents.
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>CENTER, ICON_CANCEL, ICON_SEARCH, LEFT, MULTI, PASSWORD, SEARCH, SINGLE, RIGHT, READ_ONLY, WRAP</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>DefaultSelection, Modify, Verify</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles MULTI and SINGLE may be specified,
+ * and only one of the styles LEFT, CENTER, and RIGHT may be specified.
+ * </p>
+ * <p>
+ * Note: The styles ICON_CANCEL and ICON_SEARCH are hints used in combination with SEARCH.
+ * When the platform supports the hint, the text control shows these icons. When an icon
+ * is selected, a default selection event is sent with the detail field set to one of
+ * ICON_CANCEL or ICON_SEARCH. Normally, application code does not need to check the
+ * detail. In the case of ICON_CANCEL, the text is cleared before the default selection
+ * event is sent causing the application to search for an empty string.
+ * </p>
+ * <p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#text">Text snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Text extends Scrollable {
+ int textLimit = LIMIT, tabs = 8;
+ char echoCharacter;
+ boolean doubleClick, receivingFocus;
+ String hiddenText, message;
+ NSRange selectionRange;
+ id targetSearch, targetCancel;
+ int /*long*/ actionSearch, actionCancel;
+
+ /**
+ * The maximum number of characters that can be entered
+ * into a text widget.
+ * <p>
+ * Note that this value is platform dependent, based upon
+ * the native widget implementation.
+ * </p>
+ */
+ public static final int LIMIT;
+
+ /**
+ * The delimiter used by multi-line text widgets. When text
+ * is queried and from the widget, it will be delimited using
+ * this delimiter.
+ */
+ public static final String DELIMITER;
+ static final char PASSWORD = '\u2022';
+
+ /*
+ * These values can be different on different platforms.
+ * Therefore they are not initialized in the declaration
+ * to stop the compiler from inlining.
+ */
+ static {
+ LIMIT = 0x7FFFFFFF;
+ DELIMITER = "\r";
+ }
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#SINGLE
+ * @see SWT#MULTI
+ * @see SWT#READ_ONLY
+ * @see SWT#WRAP
+ * @see SWT#LEFT
+ * @see SWT#RIGHT
+ * @see SWT#CENTER
+ * @see SWT#PASSWORD
+ * @see SWT#SEARCH
+ * @see SWT#ICON_SEARCH
+ * @see SWT#ICON_CANCEL
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Text (Composite parent, int style) {
+ super (parent, checkStyle (style));
+ if ((style & SWT.SEARCH) != 0) {
+ /*
+ * Ensure that SWT.ICON_CANCEL and ICON_SEARCH are set.
+ * NOTE: ICON_CANCEL has the same value as H_SCROLL and
+ * ICON_SEARCH has the same value as V_SCROLL so it is
+ * necessary to first clear these bits to avoid a scroll
+ * bar and then reset the bit using the original style
+ * supplied by the programmer.
+ */
+ NSSearchFieldCell cell = new NSSearchFieldCell (((NSSearchField) view).cell ());
+ if ((style & SWT.ICON_CANCEL) != 0) {
+ this.style |= SWT.ICON_CANCEL;
+ NSButtonCell cancelCell = cell.cancelButtonCell();
+ targetCancel = cancelCell.target();
+ actionCancel = cancelCell.action();
+ cancelCell.setTarget (view);
+ cancelCell.setAction (OS.sel_sendCancelSelection);
+ } else {
+ cell.setCancelButtonCell (null);
+ }
+ if ((style & SWT.ICON_SEARCH) != 0) {
+ this.style |= SWT.ICON_SEARCH;
+ NSButtonCell searchCell = cell.searchButtonCell();
+ targetSearch = searchCell.target();
+ actionSearch = searchCell.action();
+ searchCell.setTarget (view);
+ searchCell.setAction (OS.sel_sendSearchSelection);
+ } else {
+ cell.setSearchButtonCell (null);
+ }
+ }
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the receiver's text is modified, by sending
+ * it one of the messages defined in the <code>ModifyListener</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 SWTException <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 ModifyListener
+ * @see #removeModifyListener
+ */
+public void addModifyListener (ModifyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Modify, 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 not called for texts.
+ * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed in a single-line text,
+ * or when ENTER is pressed in a search text. If the receiver has the <code>SWT.SEARCH | SWT.CANCEL</code> style
+ * and the user cancels the search, the event object detail field contains the value <code>SWT.CANCEL</code>.
+ * </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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the receiver's text is verified, by sending
+ * it one of the messages defined in the <code>VerifyListener</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 SWTException <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 VerifyListener
+ * @see #removeVerifyListener
+ */
+public void addVerifyListener (VerifyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Verify, typedListener);
+}
+
+/**
+ * Appends a string.
+ * <p>
+ * The new text is appended to the text at
+ * the end of the widget.
+ * </p>
+ *
+ * @param string the string to be appended
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <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 append (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (hooks (SWT.Verify) || filters (SWT.Verify)) {
+ int charCount = getCharCount ();
+ string = verifyText (string, charCount, charCount, null);
+ if (string == null) return;
+ }
+ NSString str = NSString.stringWith (string);
+ if ((style & SWT.SINGLE) != 0) {
+ setSelection (getCharCount ());
+ insertEditText (string);
+ } else {
+ NSTextView widget = (NSTextView) view;
+ NSTextStorage storage = widget.textStorage ();
+ NSRange range = new NSRange();
+ range.location = storage.length();
+ storage.replaceCharactersInRange (range, str);
+ range.location = storage.length();
+ widget.scrollRangeToVisible (range);
+ widget.setSelectedRange(range);
+ }
+ if (string.length () != 0) sendEvent (SWT.Modify);
+}
+
+boolean becomeFirstResponder (int /*long*/ id, int /*long*/ sel) {
+ receivingFocus = true;
+ boolean result = super.becomeFirstResponder (id, sel);
+ receivingFocus = false;
+ return result;
+}
+
+static int checkStyle (int style) {
+ if ((style & SWT.SEARCH) != 0) {
+ style |= SWT.SINGLE | SWT.BORDER;
+ style &= ~SWT.PASSWORD;
+ /*
+ * NOTE: ICON_CANCEL has the same value as H_SCROLL and
+ * ICON_SEARCH has the same value as V_SCROLL so they are
+ * cleared because SWT.SINGLE is set.
+ */
+ }
+ if ((style & SWT.SINGLE) != 0 && (style & SWT.MULTI) != 0) {
+ style &= ~SWT.MULTI;
+ }
+ style = checkBits (style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0);
+ if ((style & SWT.SINGLE) != 0) style &= ~(SWT.H_SCROLL | SWT.V_SCROLL | SWT.WRAP);
+ if ((style & SWT.WRAP) != 0) {
+ style |= SWT.MULTI;
+ style &= ~SWT.H_SCROLL;
+ }
+ if ((style & SWT.MULTI) != 0) style &= ~SWT.PASSWORD;
+ if ((style & (SWT.SINGLE | SWT.MULTI)) != 0) return style;
+ if ((style & (SWT.H_SCROLL | SWT.V_SCROLL)) != 0) return style | SWT.MULTI;
+ return style | SWT.SINGLE;
+}
+
+/**
+ * Clears the selection.
+ *
+ * @exception SWTException <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 clearSelection () {
+ checkWidget ();
+ Point selection = getSelection ();
+ setSelection (selection.x);
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int width = 0, height = 0;
+ if ((style & SWT.SINGLE) != 0) {
+ NSTextField widget = (NSTextField) view;
+ NSSize size = widget.cell ().cellSize ();
+ width = (int)Math.ceil (size.width);
+ height = (int)Math.ceil (size.height);
+
+ Point border = null;
+ if ((style & SWT.BORDER) != 0 && (wHint != SWT.DEFAULT || hHint != SWT.DEFAULT)) {
+ /* determine the size of the cell without its border */
+ NSRect insets = widget.cell ().titleRectForBounds (new NSRect ());
+ border = new Point (-(int)Math.ceil (insets.width), -(int)Math.ceil (insets.height));
+ width -= border.x;
+ height -= border.y;
+ }
+ if (width <= 0) width = DEFAULT_WIDTH;
+ if (height <= 0) height = DEFAULT_HEIGHT;
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ if (border != null) {
+ /* re-add the border size (if any) now that wHint/hHint is taken */
+ width += border.x;
+ height += border.y;
+ }
+ } else {
+ NSLayoutManager layoutManager = (NSLayoutManager)new NSLayoutManager ().alloc ().init ();
+ NSTextContainer textContainer = (NSTextContainer)new NSTextContainer ().alloc ();
+ NSSize size = new NSSize ();
+ size.width = size.height = Float.MAX_VALUE;
+ if ((style & SWT.WRAP) != 0) {
+ if (wHint != SWT.DEFAULT) size.width = wHint;
+ if (hHint != SWT.DEFAULT) size.height = hHint;
+ }
+ textContainer.initWithContainerSize (size);
+ layoutManager.addTextContainer (textContainer);
+
+ NSTextStorage textStorage = (NSTextStorage)new NSTextStorage ().alloc ().init ();
+ textStorage.setAttributedString (((NSTextView)view).textStorage ());
+ layoutManager.setTextStorage (textStorage);
+ layoutManager.glyphRangeForTextContainer (textContainer);
+
+ NSRect rect = layoutManager.usedRectForTextContainer (textContainer);
+ width = layoutManager.numberOfGlyphs () == 0 ? DEFAULT_WIDTH : (int)Math.ceil (rect.width);
+ height = (int)Math.ceil (rect.height);
+ textStorage.release ();
+ textContainer.release ();
+ layoutManager.release ();
+
+ if (width <= 0) width = DEFAULT_WIDTH;
+ if (height <= 0) height = DEFAULT_HEIGHT;
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ Rectangle trim = computeTrim (0, 0, width, height);
+ width = trim.width;
+ height = trim.height;
+ }
+ return new Point (width, height);
+}
+
+public Rectangle computeTrim (int x, int y, int width, int height) {
+ Rectangle result = super.computeTrim (x, y, width, height);
+ if ((style & SWT.SINGLE) != 0) {
+ NSTextField widget = (NSTextField) view;
+ if ((style & SWT.SEARCH) != 0) {
+ NSSearchFieldCell cell = new NSSearchFieldCell (widget.cell ());
+ int testWidth = 100;
+ NSRect rect = new NSRect ();
+ rect.width = testWidth;
+ rect = cell.searchTextRectForBounds (rect);
+ int leftIndent = (int)rect.x;
+ int rightIndent = testWidth - leftIndent - (int)Math.ceil (rect.width);
+ result.x -= leftIndent;
+ result.width += leftIndent + rightIndent;
+ }
+ NSRect inset = widget.cell ().titleRectForBounds (new NSRect ());
+ result.x -= inset.x;
+ result.y -= inset.y;
+ result.width -= inset.width;
+ result.height -= inset.height;
+ }
+ return result;
+}
+
+/**
+ * Copies the selected text.
+ * <p>
+ * The current selection is copied to the clipboard.
+ * </p>
+ *
+ * @exception SWTException <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 copy () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) {
+ Point selection = getSelection ();
+ if (selection.x == selection.y) return;
+ copyToClipboard (getEditText (selection.x, selection.y - 1));
+ } else {
+ NSText text = (NSText) view;
+ if (text.selectedRange ().length == 0) return;
+ text.copy (null);
+ }
+}
+
+void createHandle () {
+ if ((style & SWT.READ_ONLY) != 0) {
+ if ((style & (SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL)) == 0) {
+ state |= THEME_BACKGROUND;
+ }
+ }
+ if ((style & SWT.SINGLE) != 0) {
+ NSTextField widget;
+ if ((style & SWT.PASSWORD) != 0) {
+ widget = (NSTextField) new SWTSecureTextField ().alloc ();
+ } else if ((style & SWT.SEARCH) != 0) {
+ widget = (NSTextField) new SWTSearchField ().alloc ();
+ } else {
+ widget = (NSTextField) new SWTTextField ().alloc ();
+ }
+ widget.init ();
+ widget.setSelectable (true);
+ widget.setEditable((style & SWT.READ_ONLY) == 0);
+ if ((style & SWT.BORDER) == 0) {
+ widget.setFocusRingType (OS.NSFocusRingTypeNone);
+ widget.setBordered (false);
+ }
+ int align = OS.NSLeftTextAlignment;
+ if ((style & SWT.CENTER) != 0) align = OS.NSCenterTextAlignment;
+ if ((style & SWT.RIGHT) != 0) align = OS.NSRightTextAlignment;
+ widget.setAlignment (align);
+ NSCell cell = widget.cell();
+ cell.setWraps(false);
+ cell.setScrollable(true);
+// widget.setTarget(widget);
+// widget.setAction(OS.sel_sendSelection);
+ view = widget;
+ } else {
+ NSScrollView scrollWidget = (NSScrollView) new SWTScrollView ().alloc ();
+ scrollWidget.init ();
+ scrollWidget.setHasVerticalScroller ((style & SWT.VERTICAL) != 0);
+ scrollWidget.setHasHorizontalScroller ((style & SWT.HORIZONTAL) != 0);
+ scrollWidget.setAutoresizesSubviews (true);
+ if ((style & SWT.BORDER) != 0) scrollWidget.setBorderType (OS.NSBezelBorder);
+
+ NSTextView widget = (NSTextView) new SWTTextView ().alloc ();
+ widget.init ();
+ widget.setEditable ((style & SWT.READ_ONLY) == 0);
+
+ NSSize size = new NSSize ();
+ size.width = size.height = Float.MAX_VALUE;
+ widget.setMaxSize (size);
+ widget.setAutoresizingMask (OS.NSViewWidthSizable | OS.NSViewHeightSizable);
+
+ if ((style & SWT.WRAP) == 0) {
+ NSTextContainer textContainer = widget.textContainer ();
+ widget.setHorizontallyResizable (true);
+ textContainer.setWidthTracksTextView (false);
+ NSSize csize = new NSSize ();
+ csize.width = csize.height = Float.MAX_VALUE;
+ textContainer.setContainerSize (csize);
+ }
+
+ int align = OS.NSLeftTextAlignment;
+ if ((style & SWT.CENTER) != 0) align = OS.NSCenterTextAlignment;
+ if ((style & SWT.RIGHT) != 0) align = OS.NSRightTextAlignment;
+ widget.setAlignment (align);
+// widget.setTarget(widget);
+// widget.setAction(OS.sel_sendSelection);
+ widget.setRichText (false);
+ widget.setDelegate(widget);
+ widget.setFont (display.getSystemFont ().handle);
+
+ view = widget;
+ scrollView = scrollWidget;
+ }
+}
+
+void createWidget () {
+ super.createWidget ();
+ doubleClick = true;
+ message = "";
+}
+
+/**
+ * Cuts the selected text.
+ * <p>
+ * The current selection is first copied to the
+ * clipboard and then deleted from the widget.
+ * </p>
+ *
+ * @exception SWTException <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 cut () {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) return;
+ boolean cut = true;
+ char [] oldText = null;
+ Point oldSelection = getSelection ();
+ if (hooks (SWT.Verify) || filters (SWT.Verify)) {
+ if (oldSelection.x != oldSelection.y) {
+ oldText = getEditText (oldSelection.x, oldSelection.y - 1);
+ String newText = verifyText ("", oldSelection.x, oldSelection.y, null);
+ if (newText == null) return;
+ if (newText.length () != 0) {
+ copyToClipboard (oldText);
+ if ((style & SWT.SINGLE) != 0) {
+ insertEditText (newText);
+ } else {
+ NSTextView widget = (NSTextView) view;
+ widget.replaceCharactersInRange (widget.selectedRange (), NSString.stringWith (newText));
+ }
+ cut = false;
+ }
+ }
+ }
+ if (cut) {
+ if ((style & SWT.SINGLE) != 0) {
+ if (oldText == null) oldText = getEditText (oldSelection.x, oldSelection.y - 1);
+ copyToClipboard (oldText);
+ insertEditText ("");
+ } else {
+ ((NSTextView) view).cut (null);
+ }
+ }
+ Point newSelection = getSelection ();
+ if (!cut || !oldSelection.equals (newSelection)) sendEvent (SWT.Modify);
+}
+
+Color defaultBackground () {
+ return display.getWidgetColor (SWT.COLOR_LIST_BACKGROUND);
+}
+
+NSFont defaultNSFont () {
+ if ((style & SWT.MULTI) != 0) return display.textViewFont;
+ if ((style & SWT.SEARCH) != 0) return display.searchFieldFont;
+ if ((style & SWT.PASSWORD) != 0) return display.secureTextFieldFont;
+ return display.textFieldFont;
+}
+
+Color defaultForeground () {
+ return display.getWidgetColor (SWT.COLOR_LIST_FOREGROUND);
+}
+
+void deregister() {
+ super.deregister();
+
+ if ((style & SWT.SINGLE) != 0) {
+ display.removeWidget(((NSControl)view).cell());
+ }
+}
+
+boolean dragDetect (int x, int y, boolean filter, boolean [] consume) {
+ Point selection = getSelection ();
+ if (selection.x != selection.y) {
+ int /*long*/ position = getPosition (x, y);
+ if (selection.x <= position && position < selection.y) {
+ if (super.dragDetect (x, y, filter, consume)) {
+ if (consume != null) consume [0] = true;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Returns the line number of the caret.
+ * <p>
+ * The line number of the caret is returned.
+ * </p>
+ *
+ * @return the line number
+ *
+ * @exception SWTException <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 getCaretLineNumber () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) return 0;
+ return (getTopPixel () + getCaretLocation ().y) / getLineHeight ();
+}
+
+boolean acceptsFirstResponder(int /*long*/ id, int /*long*/ sel) {
+ if ((style & SWT.READ_ONLY) != 0) return true;
+ return super.acceptsFirstResponder(id, sel);
+}
+
+/**
+ * Returns a point describing the receiver's location relative
+ * to its parent (or its display if its parent is null).
+ * <p>
+ * The location of the caret is returned.
+ * </p>
+ *
+ * @return a point, the location of the caret
+ *
+ * @exception SWTException <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 Point getCaretLocation () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) {
+ //TODO - caret location for single text
+ return new Point (0, 0);
+ }
+ NSTextView widget = (NSTextView)view;
+ NSLayoutManager layoutManager = widget.layoutManager();
+ NSTextContainer container = widget.textContainer();
+ NSRange range = widget.selectedRange();
+ int /*long*/ pRectCount = OS.malloc(C.PTR_SIZEOF);
+ int /*long*/ pArray = layoutManager.rectArrayForCharacterRange(range, range, container, pRectCount);
+ int /*long*/ [] rectCount = new int /*long*/ [1];
+ OS.memmove(rectCount, pRectCount, C.PTR_SIZEOF);
+ OS.free(pRectCount);
+ NSRect rect = new NSRect();
+ if (rectCount[0] > 0) OS.memmove(rect, pArray, NSRect.sizeof);
+ return new Point((int)rect.x, (int)rect.y);
+}
+
+/**
+ * Returns the character position of the caret.
+ * <p>
+ * Indexing is zero based.
+ * </p>
+ *
+ * @return the position of the caret
+ *
+ * @exception SWTException <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 getCaretPosition () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) {
+ return selectionRange != null ? (int)/*64*/selectionRange.location : 0;
+ } else {
+ NSRange range = ((NSTextView)view).selectedRange();
+ return (int)/*64*/range.location;
+ }
+}
+
+/**
+ * Returns the number of characters.
+ *
+ * @return number of characters in the widget
+ *
+ * @exception SWTException <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 getCharCount () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) {
+ return (int)/*64*/new NSCell (((NSControl) view).cell ()).title ().length ();
+ } else {
+ return (int)/*64*/((NSTextView) view).textStorage ().length ();
+ }
+}
+
+/**
+ * Returns the double click enabled flag.
+ * <p>
+ * The double click flag enables or disables the
+ * default action of the text widget when the user
+ * double clicks.
+ * </p>
+ *
+ * @return whether or not double click is enabled
+ *
+ * @exception SWTException <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 boolean getDoubleClickEnabled () {
+ checkWidget ();
+ return doubleClick;
+}
+
+/**
+ * Returns the echo character.
+ * <p>
+ * The echo character is the character that is
+ * displayed when the user enters text or the
+ * text is changed by the programmer.
+ * </p>
+ *
+ * @return the echo character
+ *
+ * @exception SWTException <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 #setEchoChar
+ */
+public char getEchoChar () {
+ checkWidget ();
+ return echoCharacter;
+}
+
+/**
+ * Returns the editable state.
+ *
+ * @return whether or not the receiver is editable
+ *
+ * @exception SWTException <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 boolean getEditable () {
+ checkWidget ();
+ return (style & SWT.READ_ONLY) == 0;
+}
+
+char [] getEditText () {
+ NSString str = null;
+ if ((style & SWT.SINGLE) != 0) {
+ str = new NSTextFieldCell (((NSTextField) view).cell ()).title ();
+ } else {
+ str = ((NSTextView)view).textStorage().string();
+ }
+
+ int length = (int)/*64*/str.length ();
+ char [] buffer = new char [length];
+ if (hiddenText != null) {
+ hiddenText.getChars (0, length, buffer, 0);
+ } else {
+ NSRange range = new NSRange ();
+ range.length = length;
+ str.getCharacters (buffer, range);
+ }
+ return buffer;
+}
+
+char [] getEditText (int start, int end) {
+ NSString str = null;
+ if ((style & SWT.SINGLE) != 0) {
+ str = new NSTextFieldCell (((NSTextField) view).cell ()).title ();
+ } else {
+ str = ((NSTextView)view).textStorage().string();
+ }
+
+ int length = (int)/*64*/str.length ();
+ end = Math.min (end, length - 1);
+ if (start > end) return new char [0];
+ start = Math.max (0, start);
+ NSRange range = new NSRange ();
+ range.location = start;
+ range.length = Math.max (0, end - start + 1);
+ char [] buffer = new char [(int)/*64*/range.length];
+ if (hiddenText != null) {
+ hiddenText.getChars ((int)/*64*/range.location, (int)/*64*/(range.location + range.length), buffer, 0);
+ } else {
+ str.getCharacters (buffer, range);
+ }
+ return buffer;
+}
+
+/**
+ * Returns the number of lines.
+ *
+ * @return the number of lines in the widget
+ *
+ * @exception SWTException <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 getLineCount () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) return 1;
+ NSTextStorage storage = ((NSTextView) view).textStorage ();
+ int count = (int)/*64*/storage.paragraphs ().count ();
+ NSString string = storage.string();
+ int /*long*/ length = string.length(), c;
+ if (length == 0 || (c = string.characterAtIndex(length - 1)) == '\n' || c == '\r') {
+ count++;
+ }
+ return count;
+}
+
+/**
+ * Returns the line delimiter.
+ *
+ * @return a string that is the line delimiter
+ *
+ * @exception SWTException <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 #DELIMITER
+ */
+public String getLineDelimiter () {
+ checkWidget ();
+ return DELIMITER;
+}
+
+/**
+ * Returns the height of a line.
+ *
+ * @return the height of a row of text
+ *
+ * @exception SWTException <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 getLineHeight () {
+ checkWidget ();
+ Font font = this.font != null ? this.font : defaultFont();
+ if ((style & SWT.SINGLE) != 0) {
+ NSDictionary dict = NSDictionary.dictionaryWithObject(font.handle, OS.NSFontAttributeName);
+ NSString str = NSString.stringWith(" ");
+ NSAttributedString attribStr = ((NSAttributedString)new NSAttributedString().alloc()).initWithString(str, dict);
+ NSSize size = attribStr.size();
+ attribStr.release();
+ return (int) size.height;
+ } else {
+ NSTextView widget = (NSTextView)view;
+ return (int)Math.ceil(widget.layoutManager().defaultLineHeightForFont(font.handle));
+ }
+}
+
+/**
+ * Returns the orientation of the receiver, which will be one of the
+ * constants <code>SWT.LEFT_TO_RIGHT</code> or <code>SWT.RIGHT_TO_LEFT</code>.
+ *
+ * @return the orientation style
+ *
+ * @exception SWTException <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 2.1.2
+ */
+public int getOrientation () {
+ checkWidget ();
+ return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
+}
+
+/**
+ * Returns the widget message. The message text is displayed
+ * as a hint for the user, indicating the purpose of the field.
+ * <p>
+ * Typically this is used in conjunction with <code>SWT.SEARCH</code>.
+ * </p>
+ *
+ * @return the widget message
+ *
+ * @exception SWTException <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.3
+ */
+public String getMessage () {
+ checkWidget ();
+ return message;
+}
+
+int /*long*/ getPosition (int /*long*/ x, int /*long*/ y) {
+// checkWidget ();
+ if ((style & SWT.MULTI) != 0) {
+ NSTextView widget = (NSTextView) view;
+ NSPoint viewLocation = new NSPoint();
+ viewLocation.x = x;
+ viewLocation.y = y;
+ return widget.characterIndexForInsertionAtPoint(viewLocation);
+ } else {
+ //TODO
+ return 0;
+ }
+}
+
+/**
+ * Returns a <code>Point</code> whose x coordinate is the
+ * character position representing the start of the selected
+ * text, and whose y coordinate is the character position
+ * representing the end of the selection. An "empty" selection
+ * is indicated by the x and y coordinates having the same value.
+ * <p>
+ * Indexing is zero based. The range of a selection is from
+ * 0..N where N is the number of characters in the widget.
+ * </p>
+ *
+ * @return a point representing the selection start and end
+ *
+ * @exception SWTException <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 Point getSelection () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) {
+ if (selectionRange == null) {
+ NSString str = new NSTextFieldCell (((NSTextField) view).cell ()).title ();
+ return new Point((int)/*64*/str.length (), (int)/*64*/str.length ());
+ }
+ return new Point ((int)/*64*/selectionRange.location, (int)/*64*/(selectionRange.location + selectionRange.length));
+ } else {
+ NSTextView widget = (NSTextView) view;
+ NSRange range = widget.selectedRange ();
+ return new Point ((int)/*64*/range.location, (int)/*64*/(range.location + range.length));
+ }
+}
+
+/**
+ * Returns the number of selected characters.
+ *
+ * @return the number of selected characters.
+ *
+ * @exception SWTException <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 getSelectionCount () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) {
+ return selectionRange != null ? (int)/*64*/selectionRange.length : 0;
+ } else {
+ NSTextView widget = (NSTextView) view;
+ NSRange range = widget.selectedRange ();
+ return (int)/*64*/range.length;
+ }
+}
+
+/**
+ * Gets the selected text, or an empty string if there is no current selection.
+ *
+ * @return the selected text
+ *
+ * @exception SWTException <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 String getSelectionText () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) {
+ Point selection = getSelection ();
+ if (selection.x == selection.y) return "";
+ return new String (getEditText (selection.x, selection.y - 1));
+ } else {
+ NSTextView widget = (NSTextView) view;
+ NSRange range = widget.selectedRange ();
+ NSString str = widget.textStorage ().string ();
+ char[] buffer = new char [(int)/*64*/range.length];
+ str.getCharacters (buffer, range);
+ return new String (buffer);
+ }
+}
+
+/**
+ * Returns the number of tabs.
+ * <p>
+ * Tab stop spacing is specified in terms of the
+ * space (' ') character. The width of a single
+ * tab stop is the pixel width of the spaces.
+ * </p>
+ *
+ * @return the number of tab characters
+ *
+ * @exception SWTException <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 getTabs () {
+ checkWidget ();
+ return tabs;
+}
+
+/**
+ * Returns the widget text.
+ * <p>
+ * The text for a text widget is the characters in the widget, or
+ * an empty string if this has never been set.
+ * </p>
+ *
+ * @return the widget text
+ *
+ * @exception SWTException <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 String getText () {
+ checkWidget ();
+ NSString str;
+ if ((style & SWT.SINGLE) != 0) {
+ return new String (getEditText ());
+ } else {
+ str = ((NSTextView)view).textStorage ().string ();
+ }
+ return str.getString();
+}
+
+/**
+ * Returns a range of text. Returns an empty string if the
+ * start of the range is greater than the end.
+ * <p>
+ * Indexing is zero based. The range of
+ * a selection is from 0..N-1 where N is
+ * the number of characters in the widget.
+ * </p>
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ * @return the range of text
+ *
+ * @exception SWTException <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 String getText (int start, int end) {
+ checkWidget ();
+ if (!(start <= end && 0 <= end)) return ""; //$NON-NLS-1$
+ if ((style & SWT.SINGLE) != 0) {
+ return new String (getEditText (start, end));
+ }
+ NSTextStorage storage = ((NSTextView) view).textStorage ();
+ end = Math.min (end, (int)/*64*/storage.length () - 1);
+ if (start > end) return ""; //$NON-NLS-1$
+ start = Math.max (0, start);
+ NSRange range = new NSRange ();
+ range.location = start;
+ range.length = end - start + 1;
+ NSAttributedString substring = storage.attributedSubstringFromRange (range);
+ NSString string = substring.string ();
+ return string.getString();
+}
+
+/**
+ * Returns the maximum number of characters that the receiver is capable of holding.
+ * <p>
+ * If this has not been changed by <code>setTextLimit()</code>,
+ * it will be the constant <code>Text.LIMIT</code>.
+ * </p>
+ *
+ * @return the text limit
+ *
+ * @exception SWTException <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 #LIMIT
+ */
+public int getTextLimit () {
+ checkWidget ();
+ return textLimit;
+}
+
+/**
+ * Returns the zero-relative index of the line which is currently
+ * at the top of the receiver.
+ * <p>
+ * This index can change when lines are scrolled or new lines are added or removed.
+ * </p>
+ *
+ * @return the index of the top line
+ *
+ * @exception SWTException <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 getTopIndex () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) return 0;
+ return getTopPixel () / getLineHeight ();
+}
+
+/**
+ * Returns the top pixel.
+ * <p>
+ * The top pixel is the pixel position of the line
+ * that is currently at the top of the widget. On
+ * some platforms, a text widget can be scrolled by
+ * pixels instead of lines so that a partial line
+ * is displayed at the top of the widget.
+ * </p><p>
+ * The top pixel changes when the widget is scrolled.
+ * The top pixel does not include the widget trimming.
+ * </p>
+ *
+ * @return the pixel position of the top line
+ *
+ * @exception SWTException <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 getTopPixel () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) return 0;
+ return (int)scrollView.contentView().bounds().y;
+}
+
+/**
+ * Inserts a string.
+ * <p>
+ * The old selection is replaced with the new text.
+ * </p>
+ *
+ * @param string the string
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is <code>null</code></li>
+ * </ul>
+ * @exception SWTException <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 insert (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (hooks (SWT.Verify) || filters (SWT.Verify)) {
+ Point selection = getSelection ();
+ string = verifyText (string, selection.x, selection.y, null);
+ if (string == null) return;
+ }
+ if ((style & SWT.SINGLE) != 0) {
+ insertEditText (string);
+ } else {
+ NSString str = NSString.stringWith (string);
+ NSTextView widget = (NSTextView) view;
+ NSRange range = widget.selectedRange ();
+ widget.textStorage ().replaceCharactersInRange (range, str);
+ }
+ if (string.length () != 0) sendEvent (SWT.Modify);
+}
+
+void insertEditText (String string) {
+ int length = string.length ();
+ Point selection = getSelection ();
+ if (hasFocus () && hiddenText == null) {
+ if (textLimit != LIMIT) {
+ int charCount = getCharCount();
+ if (charCount - (selection.y - selection.x) + length > textLimit) {
+ length = textLimit - charCount + (selection.y - selection.x);
+ }
+ }
+ char [] buffer = new char [length];
+ string.getChars (0, buffer.length, buffer, 0);
+ NSString nsstring = NSString.stringWithCharacters (buffer, buffer.length);
+ NSText fieldEditor = ((NSTextField) view).currentEditor ();
+ if (fieldEditor != null) fieldEditor.replaceCharactersInRange (fieldEditor.selectedRange (), nsstring);
+ selectionRange = null;
+ } else {
+ String oldText = getText ();
+ if (textLimit != LIMIT) {
+ int charCount = oldText.length ();
+ if (charCount - (selection.y - selection.x) + length > textLimit) {
+ string = string.substring(0, textLimit - charCount + (selection.y - selection.x));
+ }
+ }
+ String newText = oldText.substring (0, selection.x) + string + oldText.substring (selection.y);
+ setEditText (newText);
+ setSelection (selection.x + string.length ());
+ }
+}
+
+boolean isEventView (int /*long*/ id) {
+ if ((style & SWT.MULTI) != 0) return super.isEventView (id);
+ return true;
+}
+
+/**
+ * Pastes text from clipboard.
+ * <p>
+ * The selected text is deleted from the widget
+ * and new text inserted from the clipboard.
+ * </p>
+ *
+ * @exception SWTException <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 paste () {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) return;
+ boolean paste = true;
+ String oldText = null;
+ if (hooks (SWT.Verify) || filters (SWT.Verify)) {
+ oldText = getClipboardText ();
+ if (oldText != null) {
+ Point selection = getSelection ();
+ String newText = verifyText (oldText, selection.x, selection.y, null);
+ if (newText == null) return;
+ if (!newText.equals (oldText)) {
+ if ((style & SWT.SINGLE) != 0) {
+ insertEditText (newText);
+ } else {
+ NSTextView textView = (NSTextView) view;
+ textView.replaceCharactersInRange (textView.selectedRange (), NSString.stringWith (newText));
+ }
+ paste = false;
+ }
+ }
+ }
+ if (paste) {
+ if ((style & SWT.SINGLE) != 0) {
+ if (oldText == null) oldText = getClipboardText ();
+ if (oldText == null) return;
+ insertEditText (oldText);
+ } else {
+ //TODO check text limit
+ ((NSTextView) view).paste (null);
+ }
+ }
+ sendEvent (SWT.Modify);
+}
+
+void register() {
+ super.register();
+
+ if ((style & SWT.SINGLE) != 0) {
+ display.addWidget(((NSControl)view).cell(), this);
+ }
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ if ((style & SWT.SINGLE) != 0) ((NSControl)view).abortEditing();
+ hiddenText = message = null;
+ selectionRange = null;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the receiver's text is modified.
+ *
+ * @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 SWTException <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 ModifyListener
+ * @see #addModifyListener
+ */
+public void removeModifyListener (ModifyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Modify, 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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the control is verified.
+ *
+ * @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 SWTException <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 VerifyListener
+ * @see #addVerifyListener
+ */
+public void removeVerifyListener (VerifyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Verify, listener);
+}
+
+/**
+ * Selects all the text in the receiver.
+ *
+ * @exception SWTException <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 selectAll () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) {
+ setSelection (0, getCharCount ());
+ } else {
+ ((NSTextView) view).selectAll (null);
+ }
+}
+
+boolean sendKeyEvent (NSEvent nsEvent, int type) {
+ boolean result = super.sendKeyEvent (nsEvent, type);
+ if (!result) return result;
+ if (type != SWT.KeyDown) return result;
+ int stateMask = 0;
+ int /*long*/ modifierFlags = nsEvent.modifierFlags();
+ if ((modifierFlags & OS.NSAlternateKeyMask) != 0) stateMask |= SWT.ALT;
+ if ((modifierFlags & OS.NSShiftKeyMask) != 0) stateMask |= SWT.SHIFT;
+ if ((modifierFlags & OS.NSControlKeyMask) != 0) stateMask |= SWT.CONTROL;
+ if ((modifierFlags & OS.NSCommandKeyMask) != 0) stateMask |= SWT.COMMAND;
+ if (stateMask == SWT.COMMAND) {
+ short keyCode = nsEvent.keyCode ();
+ switch (keyCode) {
+ case 7: /* X */
+ cut ();
+ return false;
+ case 8: /* C */
+ copy ();
+ return false;
+ case 9: /* V */
+ paste ();
+ return false;
+ }
+ }
+ if ((style & SWT.SINGLE) != 0) {
+ short keyCode = nsEvent.keyCode ();
+ switch (keyCode) {
+ case 76: /* KP Enter */
+ case 36: /* Return */
+ postEvent (SWT.DefaultSelection);
+ }
+ }
+ return result;
+}
+
+void sendSearchSelection () {
+ if (targetSearch != null) {
+ ((NSSearchField)view).sendAction(actionSearch, targetSearch);
+ }
+ Event event = new Event ();
+ event.detail = SWT.ICON_SEARCH;
+ postEvent (SWT.DefaultSelection, event);
+}
+
+void sendCancelSelection () {
+ if (targetCancel != null) {
+ ((NSSearchField)view).sendAction(actionCancel, targetCancel);
+ }
+ Event event = new Event ();
+ event.detail = SWT.ICON_CANCEL;
+ postEvent (SWT.DefaultSelection, event);
+}
+
+void updateBackground () {
+ NSColor nsColor = null;
+ if (backgroundImage != null) {
+ nsColor = NSColor.colorWithPatternImage(backgroundImage.handle);
+ } else if (background != null) {
+ nsColor = NSColor.colorWithDeviceRed(background[0], background[1], background[2], background[3]);
+ } else {
+ nsColor = NSColor.textBackgroundColor ();
+ }
+ if ((style & SWT.SINGLE) != 0) {
+ ((NSTextField) view).setBackgroundColor (nsColor);
+ } else {
+ ((NSTextView) view).setBackgroundColor (nsColor);
+ }
+}
+
+/**
+ * Sets the double click enabled flag.
+ * <p>
+ * The double click flag enables or disables the
+ * default action of the text widget when the user
+ * double clicks.
+ * </p><p>
+ * Note: This operation is a hint and is not supported on
+ * platforms that do not have this concept.
+ * </p>
+ *
+ * @param doubleClick the new double click flag
+ *
+ * @exception SWTException <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 setDoubleClickEnabled (boolean doubleClick) {
+ checkWidget ();
+ this.doubleClick = doubleClick;
+}
+
+/**
+ * Sets the echo character.
+ * <p>
+ * The echo character is the character that is
+ * displayed when the user enters text or the
+ * text is changed by the programmer. Setting
+ * the echo character to '\0' clears the echo
+ * character and redraws the original text.
+ * If for any reason the echo character is invalid,
+ * or if the platform does not allow modification
+ * of the echo character, the default echo character
+ * for the platform is used.
+ * </p>
+ *
+ * @param echo the new echo character
+ *
+ * @exception SWTException <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 setEchoChar (char echo) {
+ checkWidget ();
+ if ((style & SWT.MULTI) != 0) return;
+ if ((style & SWT.PASSWORD) == 0) {
+ Point selection = getSelection ();
+ String text = getText ();
+ echoCharacter = echo;
+ setEditText (text);
+ setSelection (selection);
+ }
+ echoCharacter = echo;
+}
+
+/**
+ * Sets the editable state.
+ *
+ * @param editable the new editable state
+ *
+ * @exception SWTException <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 setEditable (boolean editable) {
+ checkWidget ();
+ if (editable) {
+ style &= ~SWT.READ_ONLY;
+ } else {
+ style |= SWT.READ_ONLY;
+ }
+ if ((style & SWT.SINGLE) != 0) {
+ ((NSTextField) view).setEditable (editable);
+ } else {
+ ((NSTextView) view).setEditable (editable);
+ }
+}
+
+void setEditText (String string) {
+ char [] buffer;
+ if ((style & SWT.PASSWORD) == 0 && echoCharacter != '\0') {
+ hiddenText = string;
+ buffer = new char [Math.min(hiddenText.length (), textLimit)];
+ for (int i = 0; i < buffer.length; i++) buffer [i] = echoCharacter;
+ } else {
+ hiddenText = null;
+ buffer = new char [Math.min(string.length (), textLimit)];
+ string.getChars (0, buffer.length, buffer, 0);
+ }
+ NSString nsstring = NSString.stringWithCharacters (buffer, buffer.length);
+ new NSCell (((NSTextField) view).cell ()).setTitle (nsstring);
+ selectionRange = null;
+}
+
+void setFont(NSFont font) {
+ if ((style & SWT.MULTI) != 0) {
+ ((NSTextView) view).setFont (font);
+ return;
+ }
+ super.setFont (font);
+}
+
+void setForeground (float /*double*/ [] color) {
+ NSColor nsColor;
+ if (color == null) {
+ nsColor = NSColor.textColor ();
+ } else {
+ nsColor = NSColor.colorWithDeviceRed (color [0], color [1], color [2], 1);
+ }
+ if ((style & SWT.SINGLE) != 0) {
+ ((NSTextField) view).setTextColor (nsColor);
+ } else {
+ ((NSTextView) view).setTextColor (nsColor);
+ }
+}
+
+/**
+ * Sets the orientation of the receiver, which must be one
+ * of the constants <code>SWT.LEFT_TO_RIGHT</code> or <code>SWT.RIGHT_TO_LEFT</code>.
+ * <p>
+ * Note: This operation is a hint and is not supported on
+ * platforms that do not have this concept.
+ * </p>
+ *
+ * @param orientation new orientation style
+ *
+ * @exception SWTException <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 2.1.2
+ */
+public void setOrientation (int orientation) {
+ checkWidget ();
+}
+
+/**
+ * Sets the widget message. The message text is displayed
+ * as a hint for the user, indicating the purpose of the field.
+ * <p>
+ * Typically this is used in conjunction with <code>SWT.SEARCH</code>.
+ * </p>
+ *
+ * @param message the new message
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the message is null</li>
+ * </ul>
+ * @exception SWTException <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.3
+ */
+public void setMessage (String message) {
+ checkWidget ();
+ if (message == null) error (SWT.ERROR_NULL_ARGUMENT);
+ this.message = message;
+ if ((style & SWT.SINGLE) != 0) {
+ NSString str = NSString.stringWith (message);
+ NSTextFieldCell cell = new NSTextFieldCell (((NSTextField) view).cell ());
+ cell.setPlaceholderString (str);
+ }
+}
+
+/**
+ * Sets the selection.
+ * <p>
+ * Indexing is zero based. The range of
+ * a selection is from 0..N where N is
+ * the number of characters in the widget.
+ * </p><p>
+ * Text selections are specified in terms of
+ * caret positions. In a text widget that
+ * contains N characters, there are N+1 caret
+ * positions, ranging from 0..N. This differs
+ * from other functions that address character
+ * position such as getText () that use the
+ * regular array indexing rules.
+ * </p>
+ *
+ * @param start new caret position
+ *
+ * @exception SWTException <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 setSelection (int start) {
+ checkWidget ();
+ setSelection (start, start);
+}
+
+/**
+ * Sets the selection to the range specified
+ * by the given start and end indices.
+ * <p>
+ * Indexing is zero based. The range of
+ * a selection is from 0..N where N is
+ * the number of characters in the widget.
+ * </p><p>
+ * Text selections are specified in terms of
+ * caret positions. In a text widget that
+ * contains N characters, there are N+1 caret
+ * positions, ranging from 0..N. This differs
+ * from other functions that address character
+ * position such as getText () that use the
+ * usual array indexing rules.
+ * </p>
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ *
+ * @exception SWTException <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 setSelection (int start, int end) {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) {
+ NSString str = new NSCell (((NSTextField) view).cell ()).title ();
+ int length = (int)/*64*/str.length ();
+ int selStart = Math.min (Math.max (Math.min (start, end), 0), length);
+ int selEnd = Math.min (Math.max (Math.max (start, end), 0), length);
+ selectionRange = new NSRange ();
+ selectionRange.location = selStart;
+ selectionRange.length = selEnd - selStart;
+ NSText fieldEditor = ((NSControl)view).currentEditor();
+ if (fieldEditor != null) {
+ fieldEditor.setSelectedRange (selectionRange);
+ }
+ } else {
+ int length = (int)/*64*/((NSTextView) view).textStorage ().length ();
+ int selStart = Math.min (Math.max (Math.min (start, end), 0), length);
+ int selEnd = Math.min (Math.max (Math.max (start, end), 0), length);
+ NSRange range = new NSRange ();
+ range.location = selStart;
+ range.length = selEnd - selStart;
+ ((NSTextView) view).setSelectedRange (range);
+ }
+}
+
+/**
+ * Sets the selection to the range specified
+ * by the given point, where the x coordinate
+ * represents the start index and the y coordinate
+ * represents the end index.
+ * <p>
+ * Indexing is zero based. The range of
+ * a selection is from 0..N where N is
+ * the number of characters in the widget.
+ * </p><p>
+ * Text selections are specified in terms of
+ * caret positions. In a text widget that
+ * contains N characters, there are N+1 caret
+ * positions, ranging from 0..N. This differs
+ * from other functions that address character
+ * position such as getText () that use the
+ * usual array indexing rules.
+ * </p>
+ *
+ * @param selection the point
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception SWTException <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 setSelection (Point selection) {
+ checkWidget ();
+ if (selection == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setSelection (selection.x, selection.y);
+}
+
+/**
+ * Sets the number of tabs.
+ * <p>
+ * Tab stop spacing is specified in terms of the
+ * space (' ') character. The width of a single
+ * tab stop is the pixel width of the spaces.
+ * </p>
+ *
+ * @param tabs the number of tabs
+ *
+ * </ul>
+ * @exception SWTException <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 setTabs (int tabs) {
+ checkWidget ();
+ if (this.tabs == tabs) return;
+ this.tabs = tabs;
+ if ((style & SWT.SINGLE) != 0) return;
+ float /*double*/ size = textExtent("s").width * tabs;
+ NSTextView widget = (NSTextView)view;
+ NSParagraphStyle defaultStyle = widget.defaultParagraphStyle();
+ NSMutableParagraphStyle paragraphStyle = new NSMutableParagraphStyle(defaultStyle.mutableCopy());
+ paragraphStyle.setTabStops(NSArray.array());
+ NSTextTab tab = (NSTextTab)new NSTextTab().alloc();
+ tab = tab.initWithType(OS.NSLeftTabStopType, size);
+ paragraphStyle.addTabStop(tab);
+ tab.release();
+ paragraphStyle.setDefaultTabInterval(size);
+ widget.setDefaultParagraphStyle(paragraphStyle);
+ paragraphStyle.release();
+}
+
+/**
+ * Sets the contents of the receiver to the given string. If the receiver has style
+ * SINGLE and the argument contains multiple lines of text, the result of this
+ * operation is undefined and may vary from platform to platform.
+ *
+ * @param string the new text
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <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 setText (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (hooks (SWT.Verify) || filters (SWT.Verify)) {
+ string = verifyText (string, 0, getCharCount (), null);
+ if (string == null) return;
+ }
+ if ((style & SWT.SINGLE) != 0) {
+ setEditText (string);
+ } else {
+ NSTextView widget = (NSTextView)view;
+ NSString str = NSString.stringWith (string);
+ widget.setString (str);
+ widget.setSelectedRange(new NSRange());
+ }
+ sendEvent (SWT.Modify);
+}
+
+/**
+ * Sets the maximum number of characters that the receiver
+ * is capable of holding to be the argument.
+ * <p>
+ * Instead of trying to set the text limit to zero, consider
+ * creating a read-only text widget.
+ * </p><p>
+ * To reset this value to the default, use <code>setTextLimit(Text.LIMIT)</code>.
+ * Specifying a limit value larger than <code>Text.LIMIT</code> sets the
+ * receiver's limit to <code>Text.LIMIT</code>.
+ * </p>
+ *
+ * @param limit new text limit
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li>
+ * </ul>
+ * @exception SWTException <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 #LIMIT
+ */
+public void setTextLimit (int limit) {
+ checkWidget ();
+ if (limit == 0) error (SWT.ERROR_CANNOT_BE_ZERO);
+ textLimit = limit;
+}
+
+/**
+ * Sets the zero-relative index of the line which is currently
+ * at the top of the receiver. This index can change when lines
+ * are scrolled or new lines are added and removed.
+ *
+ * @param index the index of the top item
+ *
+ * @exception SWTException <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 setTopIndex (int index) {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) return;
+ int row = Math.max(0, Math.min(index, getLineCount() - 1));
+ NSPoint pt = new NSPoint();
+ pt.x = scrollView.contentView().bounds().x;
+ pt.y = getLineHeight() * row;
+ view.scrollPoint(pt);
+}
+
+boolean shouldChangeTextInRange_replacementString(int /*long*/ id, int /*long*/ sel, int /*long*/ affectedCharRange, int /*long*/ replacementString) {
+ NSRange range = new NSRange();
+ OS.memmove(range, affectedCharRange, NSRange.sizeof);
+ boolean result = callSuperBoolean(id, sel, range, replacementString);
+ if (!hooks(SWT.Verify) && echoCharacter =='\0') return result;
+ String text = new NSString(replacementString).getString();
+ String newText = text;
+ if (hooks (SWT.Verify)) {
+ NSEvent currentEvent = display.application.currentEvent();
+ int /*long*/ type = currentEvent.type();
+ if (type != OS.NSKeyDown && type != OS.NSKeyUp) currentEvent = null;
+ newText = verifyText(text, (int)/*64*/range.location, (int)/*64*/(range.location+range.length), currentEvent);
+ }
+ if (newText == null) return false;
+ if ((style & SWT.SINGLE) != 0) {
+ if (text != newText || echoCharacter != '\0') {
+ //handle backspace and delete
+ if (range.length == 1) {
+ NSText editor = new NSText(id);
+ editor.setSelectedRange (range);
+ }
+ insertEditText(newText);
+ result = false;
+ }
+ } else {
+ if (text != newText) {
+ NSTextView widget = (NSTextView) view;
+ Point selection = getSelection();
+ NSRange selRange = new NSRange();
+ selRange.location = selection.x;
+ selRange.length = selection.x + selection.y;
+ widget.textStorage ().replaceCharactersInRange (selRange, NSString.stringWith(newText));
+ result = false;
+ }
+ }
+ if (!result) sendEvent (SWT.Modify);
+ return result;
+}
+
+/**
+ * Shows the selection.
+ * <p>
+ * If the selection is already showing
+ * in the receiver, this method simply returns. Otherwise,
+ * lines are scrolled until the selection is visible.
+ * </p>
+ *
+ * @exception SWTException <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 showSelection () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) {
+ setSelection (getSelection ());
+ } else {
+ NSTextView widget = (NSTextView) view;
+ widget.scrollRangeToVisible (widget.selectedRange ());
+ }
+}
+
+void textViewDidChangeSelection(int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+ NSNotification notification = new NSNotification (aNotification);
+ NSText editor = new NSText (notification.object ().id);
+ selectionRange = editor.selectedRange ();
+}
+
+void textDidChange (int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+ if ((style & SWT.SINGLE) != 0) super.textDidChange (id, sel, aNotification);
+ postEvent (SWT.Modify);
+}
+
+NSRange textView_willChangeSelectionFromCharacterRange_toCharacterRange (int /*long*/ id, int /*long*/ sel, int /*long*/ aTextView, int /*long*/ oldSelectedCharRange, int /*long*/ newSelectedCharRange) {
+ /*
+ * If the selection is changing as a result of the receiver getting focus
+ * then return the receiver's last selection range, otherwise the full
+ * text will be automatically selected.
+ */
+ if (receivingFocus && selectionRange != null) return selectionRange;
+
+ /* allow the selection change to proceed */
+ NSRange result = new NSRange ();
+ OS.memmove(result, newSelectedCharRange, NSRange.sizeof);
+ return result;
+}
+
+int traversalCode (int key, NSEvent theEvent) {
+ int bits = super.traversalCode (key, theEvent);
+ if ((style & SWT.READ_ONLY) != 0) return bits;
+ if ((style & SWT.MULTI) != 0) {
+ bits &= ~SWT.TRAVERSE_RETURN;
+ if (key == 48 /* Tab */ && theEvent != null) {
+ int /*long*/ modifiers = theEvent.modifierFlags ();
+ boolean next = (modifiers & OS.NSShiftKeyMask) == 0;
+ if (next && (modifiers & OS.NSControlKeyMask) == 0) {
+ bits &= ~(SWT.TRAVERSE_TAB_NEXT | SWT.TRAVERSE_TAB_PREVIOUS);
+ }
+ }
+ }
+ return bits;
+}
+
+void updateCursorRects (boolean enabled) {
+ super.updateCursorRects (enabled);
+ if (scrollView == null) return;
+ NSClipView contentView = scrollView.contentView ();
+ contentView.setDocumentCursor (enabled ? NSCursor.IBeamCursor () : null);
+}
+
+String verifyText (String string, int start, int end, NSEvent keyEvent) {
+ Event event = new Event ();
+ if (keyEvent != null) setKeyState(event, SWT.MouseDown, keyEvent);
+ event.text = string;
+ event.start = start;
+ event.end = end;
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the verify
+ * event. If this happens, answer null to cancel
+ * the operation.
+ */
+ sendEvent (SWT.Verify, event);
+ if (!event.doit || isDisposed ()) return null;
+ return event.text;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ToolBar.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ToolBar.java
new file mode 100755
index 0000000000..77d70b71de
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ToolBar.java
@@ -0,0 +1,536 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.accessibility.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Instances of this class support the layout of selectable
+ * tool bar items.
+ * <p>
+ * The item children that may be added to instances of this class
+ * must be of type <code>ToolItem</code>.
+ * </p><p>
+ * Note that although this class is a subclass of <code>Composite</code>,
+ * it does not make sense to add <code>Control</code> children to it,
+ * or set a layout on it.
+ * </p><p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>FLAT, WRAP, RIGHT, HORIZONTAL, VERTICAL, SHADOW_OUT</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles HORIZONTAL and VERTICAL 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/#toolbar">ToolBar, ToolItem snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class ToolBar extends Composite {
+ int itemCount;
+ ToolItem [] items;
+ NSArray accessibilityAttributes = null;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#FLAT
+ * @see SWT#WRAP
+ * @see SWT#RIGHT
+ * @see SWT#HORIZONTAL
+ * @see SWT#SHADOW_OUT
+ * @see SWT#VERTICAL
+ * @see Widget#checkSubclass()
+ * @see Widget#getStyle()
+ */
+public ToolBar (Composite parent, int style) {
+ super (parent, checkStyle (style));
+
+ /*
+ * Ensure that either of HORIZONTAL or VERTICAL is set.
+ * NOTE: HORIZONTAL and VERTICAL have the same values
+ * as H_SCROLL and V_SCROLL so it is necessary to first
+ * clear these bits to avoid scroll bars and then reset
+ * the bits using the original style supplied by the
+ * programmer.
+ */
+ if ((style & SWT.VERTICAL) != 0) {
+ this.style |= SWT.VERTICAL;
+ } else {
+ this.style |= SWT.HORIZONTAL;
+ }
+}
+
+int /*long*/ accessibilityAttributeNames(int /*long*/ id, int /*long*/ sel) {
+
+ if (accessibilityAttributes == null) {
+ NSMutableArray ourAttributes = NSMutableArray.arrayWithCapacity(10);
+ ourAttributes.addObject(OS.NSAccessibilityRoleAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityRoleDescriptionAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityParentAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityPositionAttribute);
+ ourAttributes.addObject(OS.NSAccessibilitySizeAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityWindowAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityTopLevelUIElementAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityHelpAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityEnabledAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityFocusedAttribute);
+ ourAttributes.addObject(OS.NSAccessibilityChildrenAttribute);
+
+ if (accessible != null) {
+ // See if the accessible will override or augment the standard list.
+ // Help, title, and description can be overridden.
+ NSMutableArray extraAttributes = NSMutableArray.arrayWithCapacity(3);
+ extraAttributes.addObject(OS.NSAccessibilityHelpAttribute);
+ extraAttributes.addObject(OS.NSAccessibilityDescriptionAttribute);
+ extraAttributes.addObject(OS.NSAccessibilityTitleAttribute);
+
+ for (int i = (int)/*64*/extraAttributes.count() - 1; i >= 0; i--) {
+ NSString attribute = new NSString(extraAttributes.objectAtIndex(i).id);
+ if (accessible.internal_accessibilityAttributeValue(attribute, ACC.CHILDID_SELF) != null) {
+ ourAttributes.addObject(extraAttributes.objectAtIndex(i));
+ }
+ }
+ }
+
+ accessibilityAttributes = ourAttributes;
+ accessibilityAttributes.retain();
+ }
+
+ return accessibilityAttributes.id;
+}
+
+int /*long*/ accessibilityAttributeValue (int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ NSString nsAttributeName = new NSString(arg0);
+
+ if (accessible != null) {
+ id returnObject = accessible.internal_accessibilityAttributeValue(nsAttributeName, ACC.CHILDID_SELF);
+ if (returnObject != null) return returnObject.id;
+ }
+
+ if (nsAttributeName.isEqualToString (OS.NSAccessibilityRoleAttribute) || nsAttributeName.isEqualToString (OS.NSAccessibilityRoleDescriptionAttribute)) {
+ NSString role = OS.NSAccessibilityToolbarRole;
+
+ if (nsAttributeName.isEqualToString (OS.NSAccessibilityRoleAttribute))
+ return role.id;
+ else {
+ int /*long*/ roleDescription = OS.NSAccessibilityRoleDescription(role.id, 0);
+ return roleDescription;
+ }
+ } else if (nsAttributeName.isEqualToString(OS.NSAccessibilityEnabledAttribute)) {
+ return NSNumber.numberWithBool(isEnabled()).id;
+ } else if (nsAttributeName.isEqualToString(OS.NSAccessibilityFocusedAttribute)) {
+ boolean focused = (view.id == view.window().firstResponder().id);
+ return NSNumber.numberWithBool(focused).id;
+ }
+
+ return super.accessibilityAttributeValue(id, sel, arg0);
+}
+
+boolean accessibilityIsIgnored(int /*long*/ id, int /*long*/ sel) {
+ // Toolbars aren't ignored.
+ return false;
+}
+
+static int checkStyle (int style) {
+ /*
+ * Even though it is legal to create this widget
+ * with scroll bars, they serve no useful purpose
+ * because they do not automatically scroll the
+ * widget's client area. The fix is to clear
+ * the SWT style.
+ */
+ return style & ~(SWT.H_SCROLL | SWT.V_SCROLL);
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget();
+ int width = wHint, height = hHint;
+ if (wHint == SWT.DEFAULT) width = 0x7FFFFFFF;
+ if (hHint == SWT.DEFAULT) height = 0x7FFFFFFF;
+ int [] result = layout (width, height, false);
+ Point extent = new Point (result [1], result [2]);
+ if (wHint != SWT.DEFAULT) extent.x = wHint;
+ if (hHint != SWT.DEFAULT) extent.y = hHint;
+ return extent;
+}
+
+void createHandle () {
+ state |= THEME_BACKGROUND;
+ NSView widget = (NSView)new SWTView().alloc();
+ widget.init();
+// widget.setDrawsBackground(false);
+ view = widget;
+}
+
+void createItem (ToolItem item, int index) {
+ if (!(0 <= index && index <= itemCount)) error (SWT.ERROR_INVALID_RANGE);
+ if (itemCount == items.length) {
+ ToolItem [] newItems = new ToolItem [itemCount + 4];
+ System.arraycopy (items, 0, newItems, 0, items.length);
+ items = newItems;
+ }
+ item.createWidget();
+ view.addSubview(item.view);
+ System.arraycopy (items, index, items, index + 1, itemCount++ - index);
+ items [index] = item;
+ relayout ();
+}
+
+void createWidget () {
+ super.createWidget ();
+ items = new ToolItem [4];
+ itemCount = 0;
+}
+
+void destroyItem (ToolItem item) {
+ int index = 0;
+ while (index < itemCount) {
+ if (items [index] == item) break;
+ index++;
+ }
+ if (index == itemCount) return;
+ System.arraycopy (items, index + 1, items, index, --itemCount - index);
+ items [itemCount] = null;
+ item.view.removeFromSuperview();
+ relayout ();
+}
+
+void drawBackground (int /*long*/ id, NSGraphicsContext context, NSRect rect) {
+ if (id != view.id) return;
+ if (background != null) {
+ fillBackground (view, context, rect, -1);
+ }
+}
+
+void enableWidget(boolean enabled) {
+ super.enableWidget(enabled);
+ for (int i = 0; i < itemCount; i++) {
+ ToolItem item = items[i];
+ if (item != null) {
+ item.enableWidget(enabled);
+ }
+ }
+}
+
+Widget findTooltip (NSPoint pt) {
+ pt = view.convertPoint_fromView_ (pt, null);
+ for (int i = 0; i < itemCount; i++) {
+ ToolItem item = items [i];
+ if (OS.NSPointInRect(pt, item.view.frame())) return item;
+ }
+ return super.findTooltip (pt);
+}
+
+/**
+ * Returns the item at the given, zero-relative index in the
+ * receiver. Throws an exception if the index is out of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 ToolItem getItem (int index) {
+ checkWidget();
+ if (0 <= index && index < itemCount) return items [index];
+ error (SWT.ERROR_INVALID_RANGE);
+ return null;
+}
+
+/**
+ * Returns the item at the given point in the receiver
+ * or null if no such item exists. The point is in the
+ * coordinate system of the receiver.
+ *
+ * @param point the point used to locate the item
+ * @return the item at the given point
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception SWTException <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 ToolItem getItem (Point pt) {
+ checkWidget();
+ if (pt == null) error (SWT.ERROR_NULL_ARGUMENT);
+ for (int i=0; i<itemCount; i++) {
+ Rectangle rect = items [i].getBounds ();
+ if (rect.contains (pt)) return items [i];
+ }
+ return null;
+}
+
+/**
+ * Returns the number of items contained in the receiver.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException <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 getItemCount () {
+ checkWidget();
+ return itemCount;
+}
+
+/**
+ * Returns an array of <code>ToolItem</code>s which are the items
+ * in the receiver.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ *
+ * @return the items in the receiver
+ *
+ * @exception SWTException <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 ToolItem [] getItems () {
+ checkWidget();
+ ToolItem [] result = new ToolItem [itemCount];
+ System.arraycopy (items, 0, result, 0, itemCount);
+ return result;
+}
+
+/**
+ * Returns the number of rows in the receiver. When
+ * the receiver has the <code>WRAP</code> style, the
+ * number of rows can be greater than one. Otherwise,
+ * the number of rows is always one.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException <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 getRowCount () {
+ checkWidget();
+ Rectangle rect = getClientArea ();
+ return layout (rect.width, rect.height, false) [0];
+}
+
+/**
+ * Searches the receiver's list starting at the first item
+ * (index 0) until an item is found that is equal to the
+ * argument, and returns the index of that item. If no item
+ * is found, returns -1.
+ *
+ * @param item the search item
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the tool item is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the tool item has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 indexOf (ToolItem item) {
+ checkWidget();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ for (int i=0; i<itemCount; i++) {
+ if (items [i] == item) return i;
+ }
+ return -1;
+}
+
+int [] layoutHorizontal (int width, int height, boolean resize) {
+ int xSpacing = 0, ySpacing = 2;
+ int marginWidth = 0, marginHeight = 0;
+ int x = marginWidth, y = marginHeight;
+ int maxX = 0, rows = 1;
+ boolean wrap = (style & SWT.WRAP) != 0;
+ int itemHeight = 0;
+ Point [] sizes = new Point [itemCount];
+ for (int i=0; i<itemCount; i++) {
+ Point size = sizes [i] = items [i].computeSize ();
+ itemHeight = Math.max (itemHeight, size.y);
+ }
+ for (int i=0; i<itemCount; i++) {
+ ToolItem item = items [i];
+ Point size = sizes [i];
+ if (wrap && i != 0 && x + size.x > width) {
+ rows++;
+ x = marginWidth;
+ y += ySpacing + itemHeight;
+ }
+ if (resize) {
+ item.setBounds (x, y, size.x, itemHeight);
+ boolean visible = x + size.x <= width && y + itemHeight <= height;
+ item.setVisible (visible);
+ Control control = item.control;
+ if (control != null) {
+ int controlY = y + (itemHeight - size.y) / 2;
+ control.setBounds (x, controlY, size.x, itemHeight - (controlY - y));
+ }
+ }
+ x += xSpacing + size.x;
+ maxX = Math.max (maxX, x);
+ }
+
+ return new int [] {rows, maxX, y + itemHeight};
+}
+
+int [] layoutVertical (int width, int height, boolean resize) {
+ int xSpacing = 2, ySpacing = 0;
+ int marginWidth = 0, marginHeight = 0;
+ int x = marginWidth, y = marginHeight;
+ int maxY = 0, cols = 1;
+ boolean wrap = (style & SWT.WRAP) != 0;
+ int itemWidth = 0;
+ Point [] sizes = new Point [itemCount];
+ for (int i=0; i<itemCount; i++) {
+ Point size = sizes [i] = items [i].computeSize ();
+ itemWidth = Math.max (itemWidth, size.x);
+ }
+ for (int i=0; i<itemCount; i++) {
+ ToolItem item = items [i];
+ Point size = sizes [i];
+ if (wrap && i != 0 && y + size.y > height) {
+ cols++;
+ x += xSpacing + itemWidth;
+ y = marginHeight;
+ }
+ if (resize) {
+ item.setBounds (x, y, itemWidth, size.y);
+ boolean visible = x + itemWidth <= width && y + size.y <= height;
+ item.setVisible (visible);
+ Control control = item.control;
+ if (control != null) {
+ int controlX = x + (itemWidth - size.x) / 2;
+ control.setBounds (controlX, y, itemWidth - (controlX - x), size.y);
+ }
+ }
+ y += ySpacing + size.y;
+ maxY = Math.max (maxY, y);
+ }
+
+ return new int [] {cols, x + itemWidth, maxY};
+}
+
+int [] layout (int nWidth, int nHeight, boolean resize) {
+ if ((style & SWT.VERTICAL) != 0) {
+ return layoutVertical (nWidth, nHeight, resize);
+ } else {
+ return layoutHorizontal (nWidth, nHeight, resize);
+ }
+}
+
+void relayout () {
+ if (!getDrawing()) return;
+ Rectangle rect = getClientArea ();
+ layout (rect.width, rect.height, true);
+}
+
+void releaseChildren (boolean destroy) {
+ if (items != null) {
+ for (int i=0; i<itemCount; i++) {
+ ToolItem item = items [i];
+ if (item != null && !item.isDisposed ()) {
+ item.release (false);
+ }
+ }
+ itemCount = 0;
+ items = null;
+ }
+ super.releaseChildren (destroy);
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (accessibilityAttributes != null) accessibilityAttributes.release();
+ accessibilityAttributes = null;
+}
+
+void removeControl (Control control) {
+ super.removeControl (control);
+ for (int i=0; i<itemCount; i++) {
+ ToolItem item = items [i];
+ if (item.control == control) item.setControl (null);
+ }
+}
+
+void resized () {
+ super.resized ();
+ relayout ();
+}
+
+void setFont(NSFont font) {
+ for (int i = 0; i < itemCount; i++) {
+ ToolItem item = items[i];
+ if (item.button != null) ((NSButton)item.button).setAttributedTitle(item.createString());
+ }
+}
+
+public void setRedraw (boolean redraw) {
+ checkWidget();
+ super.setRedraw (redraw);
+ if (redraw && drawCount == 0) relayout();
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ToolItem.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ToolItem.java
new file mode 100755
index 0000000000..21853d587f
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ToolItem.java
@@ -0,0 +1,992 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class represent a selectable user interface object
+ * that represents a button in a tool bar.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>PUSH, CHECK, RADIO, SEPARATOR, DROP_DOWN</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles CHECK, PUSH, RADIO, SEPARATOR and DROP_DOWN
+ * 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/#toolbar">ToolBar, ToolItem snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class ToolItem extends Item {
+ NSView view;
+ NSButton button;
+ int width = DEFAULT_SEPARATOR_WIDTH;
+ ToolBar parent;
+ Image hotImage, disabledImage;
+ String toolTipText;
+ Control control;
+ boolean selection;
+
+ static final int DEFAULT_WIDTH = 24;
+ static final int DEFAULT_HEIGHT = 22;
+ static final int DEFAULT_SEPARATOR_WIDTH = 6;
+ static final int INSET = 3;
+ static final int ARROW_WIDTH = 5;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>ToolBar</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>SWT</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>SWT</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 SWTException <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 SWT#PUSH
+ * @see SWT#CHECK
+ * @see SWT#RADIO
+ * @see SWT#SEPARATOR
+ * @see SWT#DROP_DOWN
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public ToolItem (ToolBar parent, int style) {
+ super (parent, checkStyle (style));
+ this.parent = parent;
+ parent.createItem (this, parent.getItemCount ());
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>ToolBar</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>SWT</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>SWT</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
+ * @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 SWTException <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 SWT#PUSH
+ * @see SWT#CHECK
+ * @see SWT#RADIO
+ * @see SWT#SEPARATOR
+ * @see SWT#DROP_DOWN
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public ToolItem (ToolBar parent, int style, int index) {
+ super (parent, checkStyle (style));
+ this.parent = parent;
+ parent.createItem (this, index);
+}
+
+int /*long*/ accessibilityAttributeValue(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ NSString nsAttributeName = new NSString(arg0);
+
+ if (nsAttributeName.isEqualToString (OS.NSAccessibilityRoleAttribute) || nsAttributeName.isEqualToString (OS.NSAccessibilityRoleDescriptionAttribute)) {
+ NSString roleText = ((style & SWT.PUSH) != 0) ? OS.NSAccessibilityButtonRole
+ : ((style & SWT.RADIO) != 0) ? OS.NSAccessibilityRadioButtonRole
+ : ((style & SWT.CHECK) != 0) ? OS.NSAccessibilityCheckBoxRole
+ : ((style & SWT.DROP_DOWN) != 0) ? OS.NSAccessibilityMenuButtonRole
+ : null; // SEPARATOR
+ if (roleText != null) {
+ if (nsAttributeName.isEqualToString (OS.NSAccessibilityRoleAttribute)) {
+ return roleText.id;
+ } else { // NSAccessibilityRoleDescriptionAttribute
+ int /*long*/ description = OS.NSAccessibilityRoleDescription (roleText.id, 0);
+ return description;
+ }
+ }
+ } else if (nsAttributeName.isEqualToString (OS.NSAccessibilityTitleAttribute) || nsAttributeName.isEqualToString (OS.NSAccessibilityDescriptionAttribute)) {
+ String accessibleText = toolTipText;
+ if (accessibleText == null || accessibleText.equals("")) accessibleText = text;
+ if (!(accessibleText == null || accessibleText.equals(""))) {
+ return NSString.stringWith(accessibleText).id;
+ } else {
+ return NSString.stringWith("").id;
+ }
+ } else if (nsAttributeName.isEqualToString (OS.NSAccessibilityValueAttribute) && (style & (SWT.CHECK | SWT.RADIO)) != 0) {
+ NSNumber value = NSNumber.numberWithInt(selection ? 1 : 0);
+ return value.id;
+ } else if (nsAttributeName.isEqualToString(OS.NSAccessibilityEnabledAttribute)) {
+ NSNumber value = NSNumber.numberWithInt(getEnabled() ? 1 : 0);
+ return value.id;
+ }
+
+ return super.accessibilityAttributeValue(id, sel, arg0);
+}
+
+/**
+ * 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>
+ * When <code>widgetSelected</code> is called when the mouse is over the arrow portion of a drop-down tool,
+ * the event object detail field contains the value <code>SWT.ARROW</code>.
+ * <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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener(listener);
+ addListener(SWT.Selection,typedListener);
+ addListener(SWT.DefaultSelection,typedListener);
+}
+
+static int checkStyle (int style) {
+ return checkBits (style, SWT.PUSH, SWT.CHECK, SWT.RADIO, SWT.SEPARATOR, SWT.DROP_DOWN, 0);
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+Point computeSize () {
+ checkWidget();
+ int width = 0, height = 0;
+ if ((style & SWT.SEPARATOR) != 0) {
+ if ((parent.style & SWT.HORIZONTAL) != 0) {
+ width = getWidth ();
+ height = DEFAULT_HEIGHT;
+ } else {
+ width = DEFAULT_WIDTH;
+ height = getWidth ();
+ }
+ if (control != null) {
+ height = Math.max (height, control.getMininumHeight ());
+ }
+ } else {
+ if (text.length () != 0 || image != null) {
+ NSButton widget = (NSButton)button;
+ NSSize size = widget.cell().cellSize();
+ width = (int)Math.ceil(size.width);
+ height = (int)Math.ceil(size.height);
+ } else {
+ width = DEFAULT_WIDTH;
+ height = DEFAULT_HEIGHT;
+ }
+ if ((style & SWT.DROP_DOWN) != 0) {
+ width += ARROW_WIDTH + INSET;
+ }
+ width += INSET * 2;
+ height += INSET * 2;
+ }
+ return new Point (width, height);
+}
+
+void createHandle () {
+ if ((style & SWT.SEPARATOR) != 0) {
+ NSBox widget = (NSBox)new SWTBox().alloc();
+ widget.init();
+ widget.setBoxType(OS.NSBoxSeparator);
+ widget.setBorderWidth(0);
+ view = widget;
+ } else {
+ NSView widget = (NSView)new SWTView().alloc();
+ widget.init();
+ button = (NSButton)new SWTButton().alloc();
+ button.init();
+ /*
+ * Feature in Cocoa. NSButtons without borders do not leave any margin
+ * between their edge and their image. The workaround is to provide a
+ * custom cell that displays the image in a better position.
+ */
+ NSButtonCell cell = (NSButtonCell)new SWTButtonCell ().alloc ().init ();
+ button.setCell (cell);
+ cell.release();
+ button.setBordered(false);
+ button.setAction(OS.sel_sendSelection);
+ button.setTarget(button);
+ Font font = parent.font != null ? parent.font : parent.defaultFont ();
+ button.setFont(font.handle);
+ button.setImagePosition(OS.NSImageOverlaps);
+ NSString emptyStr = NSString.stringWith("");
+ button.setTitle(emptyStr);
+ button.setEnabled(parent.getEnabled());
+ widget.addSubview(button);
+ view = widget;
+ }
+}
+
+NSAttributedString createString() {
+ NSAttributedString attribStr = parent.createString(text, null, parent.foreground, SWT.CENTER, true, true);
+ attribStr.autorelease();
+ return attribStr;
+}
+
+void deregister () {
+ super.deregister ();
+ display.removeWidget(view);
+
+ if (button != null) {
+ display.removeWidget (button);
+ display.removeWidget (button.cell());
+ }
+}
+
+void destroyWidget() {
+ parent.destroyItem(this);
+ super.destroyWidget();
+}
+
+void drawImageWithFrameInView (int /*long*/ id, int /*long*/ sel, int /*long*/ image, NSRect rect, int /*long*/ view) {
+ if (text.length () > 0) {
+ if ((parent.style & SWT.RIGHT) != 0) {
+ rect.x += 3;
+ } else {
+ rect.y += 3;
+ }
+ }
+ callSuper (id, sel, image, rect, view);
+}
+
+void drawWidget (int /*long*/ id, NSGraphicsContext context, NSRect rect) {
+ if (id == view.id) {
+ if (getSelection ()) {
+ NSRect bounds = view.bounds();
+ context.saveGraphicsState();
+ NSColor.colorWithDeviceRed(0.1f, 0.1f, 0.1f, 0.1f).setFill();
+ NSColor.colorWithDeviceRed(0.2f, 0.2f, 0.2f, 0.2f).setStroke();
+ NSBezierPath.fillRect(bounds);
+ bounds.x += 0.5f;
+ bounds.y += 0.5f;
+ bounds.width -= 1;
+ bounds.height -= 1;
+ NSBezierPath.strokeRect(bounds);
+ context.restoreGraphicsState();
+ }
+ if ((style & SWT.DROP_DOWN) != 0) {
+ NSRect bounds = view.bounds();
+ context.saveGraphicsState();
+ NSBezierPath path = NSBezierPath.bezierPath();
+ NSPoint pt = new NSPoint();
+ path.moveToPoint(pt);
+ pt.x += ARROW_WIDTH;
+ path.lineToPoint(pt);
+ pt.y += ARROW_WIDTH - 1;
+ pt.x -= ARROW_WIDTH / 2f;
+ path.lineToPoint(pt);
+ path.closePath();
+ NSAffineTransform transform = NSAffineTransform.transform();
+ transform.translateXBy((int)bounds.width - ARROW_WIDTH - INSET, (int)(bounds.height - ARROW_WIDTH / 2) / 2);
+ transform.concat();
+ NSColor color = isEnabled() ? NSColor.blackColor() : NSColor.disabledControlTextColor();
+ color.set();
+ path.fill();
+ context.restoreGraphicsState();
+ }
+ }
+}
+
+void enableWidget(boolean enabled) {
+ if ((style & SWT.SEPARATOR) == 0) {
+ ((NSButton)button).setEnabled(enabled);
+ }
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location
+ * relative to its parent.
+ *
+ * @return the receiver's bounding rectangle
+ *
+ * @exception SWTException <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 Rectangle getBounds () {
+ checkWidget();
+ NSRect rect = view.frame();
+ return new Rectangle((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
+}
+
+void setClipRegion (float /*double*/ x, float /*double*/ y) {
+ NSRect frame = view.frame();
+ parent.setClipRegion(frame.x + x, frame.y + y);
+}
+
+/**
+ * Returns the control that is used to fill the bounds of
+ * the item when the item is a <code>SEPARATOR</code>.
+ *
+ * @return the control
+ *
+ * @exception SWTException <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 Control getControl () {
+ checkWidget();
+ return control;
+}
+
+/**
+ * Returns the receiver's disabled image if it has one, or null
+ * if it does not.
+ * <p>
+ * The disabled image is displayed when the receiver is disabled.
+ * </p>
+ *
+ * @return the receiver's disabled image
+ *
+ * @exception SWTException <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 Image getDisabledImage () {
+ checkWidget();
+ return disabledImage;
+}
+
+boolean getDrawing () {
+ return parent.getDrawing ();
+}
+
+/**
+ * Returns <code>true</code> if the receiver is enabled, and
+ * <code>false</code> otherwise. A disabled control is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException <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 #isEnabled
+ */
+public boolean getEnabled () {
+ checkWidget();
+ return (state & DISABLED) == 0;
+}
+
+/**
+ * Returns the receiver's hot image if it has one, or null
+ * if it does not.
+ * <p>
+ * The hot image is displayed when the mouse enters the receiver.
+ * </p>
+ *
+ * @return the receiver's hot image
+ *
+ * @exception SWTException <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 Image getHotImage () {
+ checkWidget();
+ return hotImage;
+}
+
+/**
+ * Returns the receiver's parent, which must be a <code>ToolBar</code>.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException <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 ToolBar getParent () {
+ checkWidget();
+ return parent;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is selected,
+ * and false otherwise.
+ * <p>
+ * When the receiver is of type <code>CHECK</code> or <code>RADIO</code>,
+ * it is selected when it is checked (which some platforms draw as a
+ * pushed in button). If the receiver is of any other type, this method
+ * returns false.
+ * </p>
+ *
+ * @return the selection state
+ *
+ * @exception SWTException <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 boolean getSelection () {
+ checkWidget();
+ if ((style & (SWT.CHECK | SWT.RADIO)) == 0) return false;
+ return selection;
+}
+
+/**
+ * Returns the receiver's tool tip text, or null if it has not been set.
+ *
+ * @return the receiver's tool tip text
+ *
+ * @exception SWTException <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 String getToolTipText () {
+ checkWidget();
+ return toolTipText;
+}
+
+/**
+ * Gets the width of the receiver.
+ *
+ * @return the width
+ *
+ * @exception SWTException <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 width;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is enabled and all
+ * of the receiver's ancestors are enabled, and <code>false</code>
+ * otherwise. A disabled control is typically not selectable from the
+ * user interface and draws with an inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException <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 #getEnabled
+ */
+public boolean isEnabled () {
+ checkWidget();
+ return getEnabled () && parent.isEnabled ();
+}
+
+boolean isDrawing () {
+ return getDrawing() && parent.isDrawing ();
+}
+
+int /*long*/ menuForEvent (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ return parent.menuForEvent (id, sel, theEvent);
+}
+
+void mouseDown(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!parent.mouseEvent(parent.view.id, sel, theEvent, SWT.MouseDown)) return;
+ Display display = this.display;
+ display.trackingControl = parent;
+ super.mouseDown(id, sel, theEvent);
+ display.trackingControl = null;
+ if ((style & SWT.DROP_DOWN) != 0 && id == view.id) {
+ NSRect frame = view.frame();
+ Event event = new Event ();
+ event.detail = SWT.ARROW;
+ event.x = (int)frame.x;
+ event.y = (int)(frame.y + frame.height);
+ postEvent (SWT.Selection, event);
+ }
+}
+
+void mouseUp(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!parent.mouseEvent(parent.view.id, sel, theEvent, SWT.MouseUp)) return;
+ super.mouseUp(id, sel, theEvent);
+}
+
+void mouseDragged(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!parent.mouseEvent(parent.view.id, sel, theEvent, SWT.MouseMove)) return;
+ super.mouseDragged(id, sel, theEvent);
+}
+
+void rightMouseDown(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!parent.mouseEvent(parent.view.id, sel, theEvent, SWT.MouseDown)) return;
+ super.rightMouseDown(id, sel, theEvent);
+}
+
+void rightMouseUp(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!parent.mouseEvent(parent.view.id, sel, theEvent, SWT.MouseUp)) return;
+ super.rightMouseUp(id, sel, theEvent);
+}
+
+void rightMouseDragged(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!parent.mouseEvent(parent.view.id, sel, theEvent, SWT.MouseMove)) return;
+ super.rightMouseDragged(id, sel, theEvent);
+}
+
+void otherMouseDown(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!parent.mouseEvent(parent.view.id, sel, theEvent, SWT.MouseDown)) return;
+ super.otherMouseDown(id, sel, theEvent);
+}
+
+void otherMouseUp(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!parent.mouseEvent(parent.view.id, sel, theEvent, SWT.MouseUp)) return;
+ super.otherMouseUp(id, sel, theEvent);
+}
+
+void otherMouseDragged(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (!parent.mouseEvent(parent.view.id, sel, theEvent, SWT.MouseMove)) return;
+ super.otherMouseDragged(id, sel, theEvent);
+}
+
+void register () {
+ super.register ();
+ display.addWidget (view, this);
+
+ if (button != null) {
+ display.addWidget (button, this);
+ display.addWidget (button.cell(), this);
+ }
+}
+
+/**
+ * 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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook(SWT.Selection, listener);
+ eventTable.unhook(SWT.DefaultSelection,listener);
+}
+
+void releaseParent () {
+ super.releaseParent ();
+ setVisible (false);
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (view != null) view.release ();
+ if (button != null) button.release ();
+ view = button = null;
+ parent = null;
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ control = null;
+ toolTipText = null;
+ image = disabledImage = hotImage = null;
+}
+
+void selectRadio () {
+ int index = 0;
+ ToolItem [] items = parent.getItems ();
+ while (index < items.length && items [index] != this) index++;
+ int i = index - 1;
+ while (i >= 0 && items [i].setRadioSelection (false)) --i;
+ int j = index + 1;
+ while (j < items.length && items [j].setRadioSelection (false)) j++;
+ setSelection (true);
+}
+
+void sendSelection () {
+ if ((style & SWT.RADIO) != 0) {
+ if ((parent.getStyle () & SWT.NO_RADIO_GROUP) == 0) {
+ selectRadio ();
+ }
+ }
+ if ((style & SWT.CHECK) != 0) setSelection (!getSelection ());
+ postEvent (SWT.Selection);
+}
+
+void setBounds (int x, int y, int width, int height) {
+ NSRect rect = new NSRect();
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ view.setFrame(rect);
+ if (button != null) {
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = width;
+ rect.height = height;
+ if ((style & SWT.DROP_DOWN) != 0) rect.width -= ARROW_WIDTH + INSET;
+ button.setFrame(rect);
+ }
+}
+
+/**
+ * Sets the control that is used to fill the bounds of
+ * the item when the item is a <code>SEPARATOR</code>.
+ *
+ * @param control the new control
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the control has been disposed</li>
+ * <li>ERROR_INVALID_PARENT - if the control is not in the same widget tree</li>
+ * </ul>
+ * @exception SWTException <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 setControl (Control control) {
+ checkWidget();
+ if (control != null) {
+ if (control.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (control.parent != parent) error (SWT.ERROR_INVALID_PARENT);
+ }
+ if ((style & SWT.SEPARATOR) == 0) return;
+ if (this.control == control) return;
+ NSBox widget = (NSBox)view;
+ if (control == null) {
+ widget.setBoxType(OS.NSBoxSeparator);
+ } else {
+ widget.setBoxType(OS.NSBoxCustom);
+ }
+ this.control = control;
+ view.setHidden(control != null);
+ if (control != null && !control.isDisposed ()) {
+ control.moveAbove (null);
+ }
+ parent.relayout ();
+}
+
+/**
+ * Enables the receiver if the argument is <code>true</code>,
+ * and disables it otherwise.
+ * <p>
+ * A disabled control is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ * </p>
+ *
+ * @param enabled the new enabled state
+ *
+ * @exception SWTException <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 setEnabled (boolean enabled) {
+ checkWidget();
+ if ((state & DISABLED) == 0 && enabled) return;
+ if (enabled) {
+ state &= ~DISABLED;
+ } else {
+ state |= DISABLED;
+ }
+ enableWidget(enabled);
+}
+
+/**
+ * Sets the receiver's disabled image to the argument, which may be
+ * null indicating that no disabled image should be displayed.
+ * <p>
+ * The disabled image is displayed when the receiver is disabled.
+ * </p>
+ *
+ * @param image the disabled image to display on the receiver (may be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setDisabledImage (Image image) {
+ checkWidget();
+ if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ if ((style & SWT.SEPARATOR) != 0) return;
+ disabledImage = image;
+ updateImage (true);
+}
+
+/**
+ * Sets the receiver's hot image to the argument, which may be
+ * null indicating that no hot image should be displayed.
+ * <p>
+ * The hot image is displayed when the mouse enters the receiver.
+ * </p>
+ *
+ * @param image the hot image to display on the receiver (may be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setHotImage (Image image) {
+ checkWidget();
+ if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ if ((style & SWT.SEPARATOR) != 0) return;
+ hotImage = image;
+ updateImage (true);
+}
+
+public void setImage (Image image) {
+ checkWidget();
+ if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ if ((style & SWT.SEPARATOR) != 0) return;
+ super.setImage (image);
+ updateImage (true);
+}
+
+boolean setRadioSelection (boolean value) {
+ if ((style & SWT.RADIO) == 0) return false;
+ if (getSelection () != value) {
+ setSelection (value);
+ postEvent (SWT.Selection);
+ }
+ return true;
+}
+
+/**
+ * Sets the selection state of the receiver.
+ * <p>
+ * When the receiver is of type <code>CHECK</code> or <code>RADIO</code>,
+ * it is selected when it is checked (which some platforms draw as a
+ * pushed in button).
+ * </p>
+ *
+ * @param selected the new selection state
+ *
+ * @exception SWTException <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 setSelection (boolean selected) {
+ checkWidget();
+ if ((style & (SWT.CHECK | SWT.RADIO)) == 0) return;
+ this.selection = selected;
+ view.setNeedsDisplay(true);
+}
+
+/**
+ * Sets the receiver's text. The string may include
+ * the mnemonic character.
+ * </p>
+ * <p>
+ * Mnemonics are indicated by an '&amp;' that causes the next
+ * character to be the mnemonic. When the user presses a
+ * key sequence that matches the mnemonic, a selection
+ * event occurs. On most platforms, the mnemonic appears
+ * underlined but may be emphasised in a platform specific
+ * manner. The mnemonic indicator character '&amp;' can be
+ * escaped by doubling it in the string, causing a single
+ * '&amp;' to be displayed.
+ * </p>
+ *
+ * @param string the new text
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
+ * </ul>
+ * @exception SWTException <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 setText (String string) {
+ checkWidget();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if ((style & SWT.SEPARATOR) != 0) return;
+ super.setText (string);
+ NSButton widget = (NSButton)button;
+ widget.setAttributedTitle(createString());
+ if (text.length() != 0 && image != null) {
+ if ((parent.style & SWT.RIGHT) != 0) {
+ widget.setImagePosition(OS.NSImageLeft);
+ } else {
+ widget.setImagePosition(OS.NSImageAbove);
+ }
+ } else {
+ widget.setImagePosition(text.length() != 0 ? OS.NSNoImage : OS.NSImageOnly);
+ }
+ parent.relayout ();
+}
+
+/**
+ * Sets the receiver's tool tip text to the argument, which
+ * may be null indicating that the default tool tip for the
+ * control will be shown. For a control that has a default
+ * tool tip, such as the Tree control on Windows, setting
+ * the tool tip text to an empty string replaces the default,
+ * causing no tool tip text to be shown.
+ * <p>
+ * The mnemonic indicator (character '&amp;') is not displayed in a tool tip.
+ * To display a single '&amp;' in the tool tip, the character '&amp;' can be
+ * escaped by doubling it in the string.
+ * </p>
+ *
+ * @param string the new tool tip text (or null)
+ *
+ * @exception SWTException <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 setToolTipText (String string) {
+ checkWidget();
+ toolTipText = string;
+ parent.checkToolTip (this);
+}
+
+void setVisible (boolean visible) {
+ if (visible) {
+ if ((state & HIDDEN) == 0) return;
+ state &= ~HIDDEN;
+ } else {
+ if ((state & HIDDEN) != 0) return;
+ state |= HIDDEN;
+ }
+ view.setHidden(!visible);
+}
+
+/**
+ * Sets the width of the receiver, for <code>SEPARATOR</code> ToolItems.
+ *
+ * @param width the new width
+ *
+ * @exception SWTException <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 ((style & SWT.SEPARATOR) == 0) return;
+ if (width < 0 || this.width == width) return;
+ this.width = width;
+ parent.relayout();
+}
+
+String tooltipText () {
+ return toolTipText;
+}
+
+void updateImage (boolean layout) {
+ if ((style & SWT.SEPARATOR) != 0) return;
+ Image image = null;
+ if (hotImage != null) {
+ image = hotImage;
+ } else {
+ if (this.image != null) {
+ image = this.image;
+ } else {
+ image = disabledImage;
+ }
+ }
+ NSButton widget = (NSButton)button;
+ /*
+ * Feature in Cocoa. If the NSImage object being set into the button is
+ * the same NSImage object that is already there then the button does not
+ * redraw itself. This results in the button's image not visually updating
+ * if the NSImage object's content has changed since it was last set
+ * into the button. The workaround is to explicitly redraw the button.
+ */
+ widget.setImage(image != null ? image.handle : null);
+ widget.setNeedsDisplay(true);
+ if (text.length() != 0 && image != null) {
+ if ((parent.style & SWT.RIGHT) != 0) {
+ widget.setImagePosition(OS.NSImageLeft);
+ } else {
+ ((NSButton)button).setImagePosition(OS.NSImageAbove);
+ }
+ } else {
+ widget.setImagePosition(text.length() != 0 ? OS.NSNoImage : OS.NSImageOnly);
+ }
+ parent.relayout();
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tracker.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tracker.java
new file mode 100755
index 0000000000..c7a9e95ef4
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tracker.java
@@ -0,0 +1,1113 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class implement rubber banding rectangles that are
+ * drawn onto a parent <code>Composite</code> or <code>Display</code>.
+ * These rectangles can be specified to respond to mouse and key events
+ * by either moving or resizing themselves accordingly. Trackers are
+ * typically used to represent window geometries in a lightweight manner.
+ *
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>LEFT, RIGHT, UP, DOWN, RESIZE</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Move, Resize</dd>
+ * </dl>
+ * <p>
+ * Note: Rectangle move behavior is assumed unless RESIZE is specified.
+ * </p><p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#tracker">Tracker snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Tracker extends Widget {
+ Control parent;
+ boolean tracking, cancelled, stippled;
+ Cursor clientCursor, resizeCursor;
+ Rectangle [] rectangles = new Rectangle [0], proportions = rectangles;
+ Rectangle bounds;
+ int cursorOrientation = SWT.NONE;
+ boolean inEvent = false;
+ NSWindow window;
+ int oldX, oldY;
+
+ /*
+ * The following values mirror step sizes on Windows
+ */
+ final static int STEPSIZE_SMALL = 1;
+ final static int STEPSIZE_LARGE = 9;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 widget which will be the parent of the new instance (cannot be null)
+ * @param style the style of widget to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <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 SWT#LEFT
+ * @see SWT#RIGHT
+ * @see SWT#UP
+ * @see SWT#DOWN
+ * @see SWT#RESIZE
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Tracker (Composite parent, int style) {
+ super (parent, checkStyle (style));
+ this.parent = parent;
+}
+
+/**
+ * Constructs a new instance of this class given the display
+ * to create it on and a style value describing its behavior
+ * and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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: Currently, null can be passed in for the display argument.
+ * This has the effect of creating the tracker on the currently active
+ * display if there is one. If there is no current display, the
+ * tracker is created on a "default" display. <b>Passing in null as
+ * the display argument is not considered to be good coding style,
+ * and may not be supported in a future release of SWT.</b>
+ * </p>
+ *
+ * @param display the display to create the tracker on
+ * @param style the style of control to construct
+ *
+ * @exception SWTException <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 SWT#LEFT
+ * @see SWT#RIGHT
+ * @see SWT#UP
+ * @see SWT#DOWN
+ * @see SWT#RESIZE
+ */
+public Tracker (Display display, int style) {
+ if (display == null) display = Display.getCurrent ();
+ if (display == null) display = Display.getDefault ();
+ if (!display.isValidThread ()) {
+ error (SWT.ERROR_THREAD_INVALID_ACCESS);
+ }
+ this.style = checkStyle (style);
+ this.display = display;
+}
+
+/**
+ * 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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Resize, typedListener);
+ addListener (SWT.Move, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when keys are pressed and released on the system keyboard, by sending
+ * it one of the messages defined in the <code>KeyListener</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 SWTException <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 KeyListener
+ * @see #removeKeyListener
+ */
+public void addKeyListener(KeyListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener(SWT.KeyUp,typedListener);
+ addListener(SWT.KeyDown,typedListener);
+}
+
+Point adjustMoveCursor () {
+ if (bounds == null) return null;
+ int newX = bounds.x + bounds.width / 2;
+ int newY = bounds.y;
+ /*
+ * Convert to screen coordinates if needed
+ */
+ if (parent != null) {
+ Point pt = parent.toDisplay (newX, newY);
+ newX = pt.x;
+ newY = pt.y;
+ }
+ display.setCursorLocation(newX, newY);
+ return new Point (newX, newY);
+}
+
+Point adjustResizeCursor (boolean movePointer) {
+ if (bounds == null) return null;
+ int newX, newY;
+
+ if ((cursorOrientation & SWT.LEFT) != 0) {
+ newX = bounds.x;
+ } else if ((cursorOrientation & SWT.RIGHT) != 0) {
+ newX = bounds.x + bounds.width;
+ } else {
+ newX = bounds.x + bounds.width / 2;
+ }
+
+ if ((cursorOrientation & SWT.UP) != 0) {
+ newY = bounds.y;
+ } else if ((cursorOrientation & SWT.DOWN) != 0) {
+ newY = bounds.y + bounds.height;
+ } else {
+ newY = bounds.y + bounds.height / 2;
+ }
+
+ /*
+ * Convert to screen coordinates if needed
+ */
+ if (parent != null) {
+ Point pt = parent.toDisplay (newX, newY);
+ newX = pt.x;
+ newY = pt.y;
+ }
+ if (movePointer) {
+ display.setCursorLocation(newX, newY);
+ }
+
+ /*
+ * If the client has not provided a custom cursor then determine
+ * the appropriate resize cursor.
+ */
+ if (clientCursor == null) {
+ Cursor newCursor = null;
+ switch (cursorOrientation) {
+ case SWT.UP:
+ newCursor = new Cursor(display, SWT.CURSOR_SIZENS);
+ break;
+ case SWT.DOWN:
+ newCursor = new Cursor(display, SWT.CURSOR_SIZENS);
+ break;
+ case SWT.LEFT:
+ newCursor = new Cursor(display, SWT.CURSOR_SIZEWE);
+ break;
+ case SWT.RIGHT:
+ newCursor = new Cursor(display, SWT.CURSOR_SIZEWE);
+ break;
+ case SWT.LEFT | SWT.UP:
+ newCursor = new Cursor(display, SWT.CURSOR_SIZENWSE);
+ break;
+ case SWT.RIGHT | SWT.DOWN:
+ newCursor = new Cursor(display, SWT.CURSOR_SIZENWSE);
+ break;
+ case SWT.LEFT | SWT.DOWN:
+ newCursor = new Cursor(display, SWT.CURSOR_SIZENESW);
+ break;
+ case SWT.RIGHT | SWT.UP:
+ newCursor = new Cursor(display, SWT.CURSOR_SIZENESW);
+ break;
+ default:
+ newCursor = new Cursor(display, SWT.CURSOR_SIZEALL);
+ break;
+ }
+ display.lockCursor = false;
+ newCursor.handle.set();
+ display.lockCursor = true;
+ if (resizeCursor != null) {
+ resizeCursor.dispose ();
+ }
+ resizeCursor = newCursor;
+ }
+
+ return new Point (newX, newY);
+}
+
+static int checkStyle (int style) {
+ if ((style & (SWT.LEFT | SWT.RIGHT | SWT.UP | SWT.DOWN)) == 0) {
+ style |= SWT.LEFT | SWT.RIGHT | SWT.UP | SWT.DOWN;
+ }
+ return style;
+}
+
+/**
+ * Stops displaying the tracker rectangles. Note that this is not considered
+ * to be a cancelation by the user.
+ *
+ * @exception SWTException <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 close () {
+ checkWidget ();
+ tracking = false;
+}
+Rectangle computeBounds () {
+ if (rectangles.length == 0) return null;
+ int xMin = rectangles [0].x;
+ int yMin = rectangles [0].y;
+ int xMax = rectangles [0].x + rectangles [0].width;
+ int yMax = rectangles [0].y + rectangles [0].height;
+
+ for (int i = 1; i < rectangles.length; i++) {
+ if (rectangles [i].x < xMin) xMin = rectangles [i].x;
+ if (rectangles [i].y < yMin) yMin = rectangles [i].y;
+ int rectRight = rectangles [i].x + rectangles [i].width;
+ if (rectRight > xMax) xMax = rectRight;
+ int rectBottom = rectangles [i].y + rectangles [i].height;
+ if (rectBottom > yMax) yMax = rectBottom;
+ }
+
+ return new Rectangle (xMin, yMin, xMax - xMin, yMax - yMin);
+}
+
+Rectangle [] computeProportions (Rectangle [] rects) {
+ Rectangle [] result = new Rectangle [rects.length];
+ bounds = computeBounds ();
+ if (bounds != null) {
+ for (int i = 0; i < rects.length; i++) {
+ int x = 0, y = 0, width = 0, height = 0;
+ if (bounds.width != 0) {
+ x = (rects [i].x - bounds.x) * 100 / bounds.width;
+ width = rects [i].width * 100 / bounds.width;
+ } else {
+ width = 100;
+ }
+ if (bounds.height != 0) {
+ y = (rects [i].y - bounds.y) * 100 / bounds.height;
+ height = rects [i].height * 100 / bounds.height;
+ } else {
+ height = 100;
+ }
+ result [i] = new Rectangle (x, y, width, height);
+ }
+ }
+ return result;
+}
+
+void drawRectangles (NSWindow window, Rectangle [] rects, boolean erase) {
+ NSGraphicsContext context = window.graphicsContext();
+ NSGraphicsContext.static_saveGraphicsState();
+ NSGraphicsContext.setCurrentContext(context);
+ context.saveGraphicsState();
+ Point parentOrigin;
+ if (parent != null) {
+ parentOrigin = display.map (parent, null, 0, 0);
+ } else {
+ parentOrigin = new Point (0, 0);
+ }
+ context.setCompositingOperation(erase ? OS.NSCompositeClear : OS.NSCompositeSourceOver);
+ NSRect rectFrame = new NSRect();
+ NSPoint globalPoint = new NSPoint();
+ float /*double*/ screenHeight = display.getPrimaryFrame().height;
+ for (int i=0; i<rects.length; i++) {
+ Rectangle rect = rects [i];
+ rectFrame.x = rect.x + parentOrigin.x;
+ rectFrame.y = screenHeight - (int)((rect.y + parentOrigin.y) + rect.height);
+ rectFrame.width = rect.width;
+ rectFrame.height = rect.height;
+ globalPoint.x = rectFrame.x;
+ globalPoint.y = rectFrame.y;
+ globalPoint = window.convertScreenToBase(globalPoint);
+ rectFrame.x = globalPoint.x;
+ rectFrame.y = globalPoint.y;
+
+ if (erase) {
+ rectFrame.width++;
+ rectFrame.height++;
+ NSBezierPath.fillRect(rectFrame);
+ } else {
+ rectFrame.x += 0.5f;
+ rectFrame.y += 0.5f;
+ NSBezierPath.strokeRect(rectFrame);
+ }
+ }
+ if (!erase) context.flushGraphics();
+ context.restoreGraphicsState();
+ NSGraphicsContext.static_restoreGraphicsState();
+}
+
+/**
+ * Returns the bounds that are being drawn, expressed relative to the parent
+ * widget. If the parent is a <code>Display</code> then these are screen
+ * coordinates.
+ *
+ * @return the bounds of the Rectangles being drawn
+ *
+ * @exception SWTException <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 Rectangle [] getRectangles () {
+ checkWidget();
+ Rectangle [] result = new Rectangle [rectangles.length];
+ for (int i = 0; i < rectangles.length; i++) {
+ Rectangle current = rectangles [i];
+ result [i] = new Rectangle (current.x, current.y, current.width, current.height);
+ }
+ return result;
+}
+
+/**
+ * Returns <code>true</code> if the rectangles are drawn with a stippled line, <code>false</code> otherwise.
+ *
+ * @return the stippled effect of the rectangles
+ *
+ * @exception SWTException <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 boolean getStippled () {
+ checkWidget ();
+ return stippled;
+}
+
+void mouse (NSEvent nsEvent) {
+ NSPoint location;
+ if (nsEvent == null || nsEvent.type() == OS.NSMouseMoved) {
+ location = NSEvent.mouseLocation();
+ } else {
+ location = nsEvent.locationInWindow();
+ location = nsEvent.window().convertBaseToScreen(location);
+ }
+ location.y = display.getPrimaryFrame().height - location.y;
+ int newX = (int)location.x, newY = (int)location.y;
+ if (newX != oldX || newY != oldY) {
+ Rectangle [] oldRectangles = rectangles;
+ Rectangle [] rectsToErase = new Rectangle [rectangles.length];
+ for (int i = 0; i < rectangles.length; i++) {
+ Rectangle current = rectangles [i];
+ rectsToErase [i] = new Rectangle (current.x, current.y, current.width, current.height);
+ }
+ Event event = new Event ();
+ event.x = newX;
+ event.y = newY;
+ if ((style & SWT.RESIZE) != 0) {
+ boolean orientationInit = resizeRectangles (newX - oldX, newY - oldY);
+ inEvent = true;
+ sendEvent (SWT.Resize, event);
+ inEvent = false;
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the move
+ * event. If this happens, return false to indicate
+ * that the tracking has failed.
+ */
+ if (isDisposed ()) {
+ cancelled = true;
+ return;
+ }
+ boolean draw = false;
+ /*
+ * It is possible that application code could have
+ * changed the rectangles in the resize event. If this
+ * happens then only redraw the tracker if the rectangle
+ * values have changed.
+ */
+ if (rectangles != oldRectangles) {
+ int length = rectangles.length;
+ if (length != rectsToErase.length) {
+ draw = true;
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (!rectangles [i].equals (rectsToErase [i])) {
+ draw = true;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ draw = true;
+ }
+ if (draw) {
+ drawRectangles (window, rectsToErase, true);
+ drawRectangles (window, rectangles, false);
+ }
+ Point cursorPos = adjustResizeCursor (orientationInit);
+ if (cursorPos != null) {
+ newX = cursorPos.x;
+ newY = cursorPos.y;
+ }
+ } else {
+ moveRectangles (newX - oldX, newY - oldY);
+ inEvent = true;
+ sendEvent (SWT.Move, event);
+ inEvent = false;
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the move
+ * event. If this happens, return false to indicate
+ * that the tracking has failed.
+ */
+ if (isDisposed ()) {
+ cancelled = true;
+ return;
+ }
+ boolean draw = false;
+ /*
+ * It is possible that application code could have
+ * changed the rectangles in the move event. If this
+ * happens then only redraw the tracker if the rectangle
+ * values have changed.
+ */
+ if (rectangles != oldRectangles) {
+ int length = rectangles.length;
+ if (length != rectsToErase.length) {
+ draw = true;
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (!rectangles [i].equals (rectsToErase [i])) {
+ draw = true;
+ break;
+ }
+ }
+ }
+ } else {
+ draw = true;
+ }
+ if (draw) {
+ drawRectangles (window, rectsToErase, true);
+ drawRectangles (window, rectangles, false);
+ }
+ }
+ oldX = newX; oldY = newY;
+ }
+ switch ((int)/*64*/nsEvent.type()) {
+ case OS.NSLeftMouseUp:
+ case OS.NSRightMouseUp:
+ case OS.NSOtherMouseUp:
+ tracking = false;
+ }
+}
+
+void key (NSEvent nsEvent) {
+ //TODO send event
+// if (!sendKeyEvent (SWT.KeyDown, theEvent)) return OS.noErr;
+ int /*long*/ modifierFlags = nsEvent.modifierFlags();
+ int stepSize = (modifierFlags & OS.NSControlKeyMask) != 0 ? STEPSIZE_SMALL : STEPSIZE_LARGE;
+ int xChange = 0, yChange = 0;
+ switch (nsEvent.keyCode()) {
+ case 53: /* Esc */
+ cancelled = true;
+ tracking = false;
+ break;
+ case 76: /* KP Enter */
+ case 36: /* Return */
+ tracking = false;
+ break;
+ case 123: /* Left arrow */
+ xChange = -stepSize;
+ break;
+ case 124: /* Right arrow */
+ xChange = stepSize;
+ break;
+ case 126: /* Up arrow */
+ yChange = -stepSize;
+ break;
+ case 125: /* Down arrow */
+ yChange = stepSize;
+ break;
+ }
+ if (xChange != 0 || yChange != 0) {
+ Rectangle [] oldRectangles = rectangles;
+ Rectangle [] rectsToErase = new Rectangle [rectangles.length];
+ for (int i = 0; i < rectangles.length; i++) {
+ Rectangle current = rectangles [i];
+ rectsToErase [i] = new Rectangle (current.x, current.y, current.width, current.height);
+ }
+ Event event = new Event ();
+ int newX = oldX + xChange;
+ int newY = oldY + yChange;
+ event.x = newX;
+ event.y = newY;
+ Point cursorPos;
+ if ((style & SWT.RESIZE) != 0) {
+ resizeRectangles (xChange, yChange);
+ inEvent = true;
+ sendEvent (SWT.Resize, event);
+ inEvent = false;
+ /*
+ * It is possible (but unlikely) that application
+ * code could have disposed the widget in the move
+ * event. If this happens return false to indicate
+ * that the tracking has failed.
+ */
+ if (isDisposed ()) {
+ cancelled = true;
+ return;
+ }
+ boolean draw = false;
+ /*
+ * It is possible that application code could have
+ * changed the rectangles in the resize event. If this
+ * happens then only redraw the tracker if the rectangle
+ * values have changed.
+ */
+ if (rectangles != oldRectangles) {
+ int length = rectangles.length;
+ if (length != rectsToErase.length) {
+ draw = true;
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (!rectangles [i].equals (rectsToErase [i])) {
+ draw = true;
+ break;
+ }
+ }
+ }
+ } else {
+ draw = true;
+ }
+ if (draw) {
+ drawRectangles (window, rectsToErase, true);
+ drawRectangles (window, rectangles, false);
+ }
+ cursorPos = adjustResizeCursor (true);
+ } else {
+ moveRectangles (xChange, yChange);
+ inEvent = true;
+ sendEvent (SWT.Move, event);
+ inEvent = false;
+ /*
+ * It is possible (but unlikely) that application
+ * code could have disposed the widget in the move
+ * event. If this happens return false to indicate
+ * that the tracking has failed.
+ */
+ if (isDisposed ()) {
+ cancelled = true;
+ return;
+ }
+ boolean draw = false;
+ /*
+ * It is possible that application code could have
+ * changed the rectangles in the move event. If this
+ * happens then only redraw the tracker if the rectangle
+ * values have changed.
+ */
+ if (rectangles != oldRectangles) {
+ int length = rectangles.length;
+ if (length != rectsToErase.length) {
+ draw = true;
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (!rectangles [i].equals (rectsToErase [i])) {
+ draw = true;
+ break;
+ }
+ }
+ }
+ } else {
+ draw = true;
+ }
+ if (draw) {
+ drawRectangles (window, rectsToErase, true);
+ drawRectangles (window, rectangles, false);
+ }
+ cursorPos = adjustMoveCursor ();
+ }
+ if (cursorPos != null) {
+ oldX = cursorPos.x;
+ oldY = cursorPos.y;
+ }
+ }
+}
+
+void moveRectangles (int xChange, int yChange) {
+ if (bounds == null) return;
+ if (xChange < 0 && ((style & SWT.LEFT) == 0)) xChange = 0;
+ if (xChange > 0 && ((style & SWT.RIGHT) == 0)) xChange = 0;
+ if (yChange < 0 && ((style & SWT.UP) == 0)) yChange = 0;
+ if (yChange > 0 && ((style & SWT.DOWN) == 0)) yChange = 0;
+ if (xChange == 0 && yChange == 0) return;
+ bounds.x += xChange; bounds.y += yChange;
+ for (int i = 0; i < rectangles.length; i++) {
+ rectangles [i].x += xChange;
+ rectangles [i].y += yChange;
+ }
+}
+
+/**
+ * Displays the Tracker rectangles for manipulation by the user. Returns when
+ * the user has either finished manipulating the rectangles or has cancelled the
+ * Tracker.
+ *
+ * @return <code>true</code> if the user did not cancel the Tracker, <code>false</code> otherwise
+ *
+ * @exception SWTException <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 boolean open () {
+ checkWidget ();
+ Display display = this.display;
+ cancelled = false;
+ tracking = true;
+ window = (NSWindow)new NSWindow().alloc();
+ NSArray screens = NSScreen.screens();
+ float /*double*/ minX = Float.MAX_VALUE, maxX = Float.MIN_VALUE;
+ float /*double*/ minY = Float.MAX_VALUE, maxY = Float.MIN_VALUE;
+ int count = (int)/*64*/screens.count();
+ for (int i = 0; i < count; i++) {
+ NSScreen screen = new NSScreen(screens.objectAtIndex(i));
+ NSRect frame = screen.frame();
+ float /*double*/ x1 = frame.x, x2 = frame.x + frame.width;
+ float /*double*/ y1 = frame.y, y2 = frame.y + frame.height;
+ if (x1 < minX) minX = x1;
+ if (x2 < minX) minX = x2;
+ if (x1 > maxX) maxX = x1;
+ if (x2 > maxX) maxX = x2;
+ if (y1 < minY) minY = y1;
+ if (y2 < minY) minY = y2;
+ if (y1 > maxY) maxY = y1;
+ if (y2 > maxY) maxY = y2;
+ }
+ NSRect frame = new NSRect();
+ frame.x = minX;
+ frame.y = minY;
+ frame.width = maxX - minX;
+ frame.height = maxY - minY;
+ window = window.initWithContentRect(frame, OS.NSBorderlessWindowMask, OS.NSBackingStoreBuffered, false);
+ window.setOpaque(false);
+ window.setContentView(null);
+ window.setBackgroundColor(NSColor.clearColor());
+ NSGraphicsContext context = window.graphicsContext();
+ NSGraphicsContext.static_saveGraphicsState();
+ NSGraphicsContext.setCurrentContext(context);
+ context.setCompositingOperation(OS.NSCompositeClear);
+ frame.x = frame.y = 0;
+ NSBezierPath.fillRect(frame);
+ NSGraphicsContext.static_restoreGraphicsState();
+ window.orderFrontRegardless();
+
+ drawRectangles (window, rectangles, false);
+
+ /*
+ * If exactly one of UP/DOWN is specified as a style then set the cursor
+ * orientation accordingly (the same is done for LEFT/RIGHT styles below).
+ */
+ int vStyle = style & (SWT.UP | SWT.DOWN);
+ if (vStyle == SWT.UP || vStyle == SWT.DOWN) {
+ cursorOrientation |= vStyle;
+ }
+ int hStyle = style & (SWT.LEFT | SWT.RIGHT);
+ if (hStyle == SWT.LEFT || hStyle == SWT.RIGHT) {
+ cursorOrientation |= hStyle;
+ }
+
+ Point cursorPos;
+ boolean down = false;
+ NSApplication application = NSApplication.sharedApplication();
+ NSEvent currentEvent = application.currentEvent();
+ if (currentEvent != null) {
+ switch ((int)/*64*/currentEvent.type()) {
+ case OS.NSLeftMouseDown:
+ case OS.NSLeftMouseDragged:
+ case OS.NSRightMouseDown:
+ case OS.NSRightMouseDragged:
+ case OS.NSOtherMouseDown:
+ case OS.NSOtherMouseDragged:
+ down = true;
+ }
+ }
+ if (down) {
+ cursorPos = display.getCursorLocation();
+ } else {
+ if ((style & SWT.RESIZE) != 0) {
+ cursorPos = adjustResizeCursor (true);
+ } else {
+ cursorPos = adjustMoveCursor ();
+ }
+ }
+ if (cursorPos != null) {
+ oldX = cursorPos.x;
+ oldY = cursorPos.y;
+ }
+
+ Control oldTrackingControl = display.trackingControl;
+ display.trackingControl = null;
+ /* Tracker behaves like a Dialog with its own OS event loop. */
+ while (tracking && !cancelled) {
+ display.addPool();
+ try {
+ NSEvent event = application.nextEventMatchingMask(0, NSDate.distantFuture(), OS.NSDefaultRunLoopMode, true);
+ if (event == null) continue;
+ int type = (int)/*64*/event.type();
+ switch (type) {
+ case OS.NSLeftMouseUp:
+ case OS.NSRightMouseUp:
+ case OS.NSOtherMouseUp:
+ case OS.NSMouseMoved:
+ case OS.NSLeftMouseDragged:
+ case OS.NSRightMouseDragged:
+ case OS.NSOtherMouseDragged:
+ mouse(event);
+ break;
+ case OS.NSKeyDown:
+// case OS.NSKeyUp:
+ case OS.NSFlagsChanged:
+ key(event);
+ break;
+ }
+ boolean dispatch = true;
+ switch (type) {
+ case OS.NSLeftMouseDown:
+ case OS.NSLeftMouseUp:
+ case OS.NSRightMouseDown:
+ case OS.NSRightMouseUp:
+ case OS.NSOtherMouseDown:
+ case OS.NSOtherMouseUp:
+ case OS.NSMouseMoved:
+ case OS.NSLeftMouseDragged:
+ case OS.NSRightMouseDragged:
+ case OS.NSOtherMouseDragged:
+ case OS.NSMouseEntered:
+ case OS.NSMouseExited:
+ case OS.NSKeyDown:
+ case OS.NSKeyUp:
+ case OS.NSFlagsChanged:
+ dispatch = false;
+ }
+ if (dispatch) application.sendEvent(event);
+ if (clientCursor != null && resizeCursor == null) {
+ display.lockCursor = false;
+ clientCursor.handle.set();
+ display.lockCursor = true;
+ }
+ } finally {
+ display.removePool();
+ }
+ }
+ if (oldTrackingControl != null && !oldTrackingControl.isDisposed()) {
+ display.trackingControl = oldTrackingControl;
+ }
+ display.setCursor(display.findControl(true));
+ if (!isDisposed()) {
+ drawRectangles (window, rectangles, true);
+ }
+ if (window != null) window.close();
+ tracking = false;
+ window = null;
+ return !cancelled;
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ parent = null;
+ rectangles = proportions = null;
+ bounds = 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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Resize, listener);
+ eventTable.unhook (SWT.Move, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when keys are pressed and released on the system keyboard.
+ *
+ * @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 SWTException <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 KeyListener
+ * @see #addKeyListener
+ */
+public void removeKeyListener(KeyListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook(SWT.KeyUp, listener);
+ eventTable.unhook(SWT.KeyDown, listener);
+}
+
+/*
+ * Returns true if the pointer's orientation was initialized in some dimension,
+ * and false otherwise.
+ */
+boolean resizeRectangles (int xChange, int yChange) {
+ if (bounds == null) return false;
+ boolean orientationInit = false;
+ /*
+ * If the cursor orientation has not been set in the orientation of
+ * this change then try to set it here.
+ */
+ if (xChange < 0 && ((style & SWT.LEFT) != 0) && ((cursorOrientation & SWT.RIGHT) == 0)) {
+ if ((cursorOrientation & SWT.LEFT) == 0) {
+ cursorOrientation |= SWT.LEFT;
+ orientationInit = true;
+ }
+ }
+ if (xChange > 0 && ((style & SWT.RIGHT) != 0) && ((cursorOrientation & SWT.LEFT) == 0)) {
+ if ((cursorOrientation & SWT.RIGHT) == 0) {
+ cursorOrientation |= SWT.RIGHT;
+ orientationInit = true;
+ }
+ }
+ if (yChange < 0 && ((style & SWT.UP) != 0) && ((cursorOrientation & SWT.DOWN) == 0)) {
+ if ((cursorOrientation & SWT.UP) == 0) {
+ cursorOrientation |= SWT.UP;
+ orientationInit = true;
+ }
+ }
+ if (yChange > 0 && ((style & SWT.DOWN) != 0) && ((cursorOrientation & SWT.UP) == 0)) {
+ if ((cursorOrientation & SWT.DOWN) == 0) {
+ cursorOrientation |= SWT.DOWN;
+ orientationInit = true;
+ }
+ }
+
+ /*
+ * If the bounds will flip about the x or y axis then apply the adjustment
+ * up to the axis (ie.- where bounds width/height becomes 0), change the
+ * cursor's orientation accordingly, and flip each Rectangle's origin (only
+ * necessary for > 1 Rectangles)
+ */
+ if ((cursorOrientation & SWT.LEFT) != 0) {
+ if (xChange > bounds.width) {
+ if ((style & SWT.RIGHT) == 0) return orientationInit;
+ cursorOrientation |= SWT.RIGHT;
+ cursorOrientation &= ~SWT.LEFT;
+ bounds.x += bounds.width;
+ xChange -= bounds.width;
+ bounds.width = 0;
+ if (proportions.length > 1) {
+ for (int i = 0; i < proportions.length; i++) {
+ Rectangle proportion = proportions [i];
+ proportion.x = 100 - proportion.x - proportion.width;
+ }
+ }
+ }
+ } else if ((cursorOrientation & SWT.RIGHT) != 0) {
+ if (bounds.width < -xChange) {
+ if ((style & SWT.LEFT) == 0) return orientationInit;
+ cursorOrientation |= SWT.LEFT;
+ cursorOrientation &= ~SWT.RIGHT;
+ xChange += bounds.width;
+ bounds.width = 0;
+ if (proportions.length > 1) {
+ for (int i = 0; i < proportions.length; i++) {
+ Rectangle proportion = proportions [i];
+ proportion.x = 100 - proportion.x - proportion.width;
+ }
+ }
+ }
+ }
+ if ((cursorOrientation & SWT.UP) != 0) {
+ if (yChange > bounds.height) {
+ if ((style & SWT.DOWN) == 0) return orientationInit;
+ cursorOrientation |= SWT.DOWN;
+ cursorOrientation &= ~SWT.UP;
+ bounds.y += bounds.height;
+ yChange -= bounds.height;
+ bounds.height = 0;
+ if (proportions.length > 1) {
+ for (int i = 0; i < proportions.length; i++) {
+ Rectangle proportion = proportions [i];
+ proportion.y = 100 - proportion.y - proportion.height;
+ }
+ }
+ }
+ } else if ((cursorOrientation & SWT.DOWN) != 0) {
+ if (bounds.height < -yChange) {
+ if ((style & SWT.UP) == 0) return orientationInit;
+ cursorOrientation |= SWT.UP;
+ cursorOrientation &= ~SWT.DOWN;
+ yChange += bounds.height;
+ bounds.height = 0;
+ if (proportions.length > 1) {
+ for (int i = 0; i < proportions.length; i++) {
+ Rectangle proportion = proportions [i];
+ proportion.y = 100 - proportion.y - proportion.height;
+ }
+ }
+ }
+ }
+
+ // apply the bounds adjustment
+ if ((cursorOrientation & SWT.LEFT) != 0) {
+ bounds.x += xChange;
+ bounds.width -= xChange;
+ } else if ((cursorOrientation & SWT.RIGHT) != 0) {
+ bounds.width += xChange;
+ }
+ if ((cursorOrientation & SWT.UP) != 0) {
+ bounds.y += yChange;
+ bounds.height -= yChange;
+ } else if ((cursorOrientation & SWT.DOWN) != 0) {
+ bounds.height += yChange;
+ }
+
+ Rectangle [] newRects = new Rectangle [rectangles.length];
+ for (int i = 0; i < rectangles.length; i++) {
+ Rectangle proportion = proportions[i];
+ newRects[i] = new Rectangle (
+ proportion.x * bounds.width / 100 + bounds.x,
+ proportion.y * bounds.height / 100 + bounds.y,
+ proportion.width * bounds.width / 100,
+ proportion.height * bounds.height / 100);
+ }
+ rectangles = newRects;
+ return orientationInit;
+}
+
+/**
+ * Sets the <code>Cursor</code> of the Tracker. If this cursor is <code>null</code>
+ * then the cursor reverts to the default.
+ *
+ * @param newCursor the new <code>Cursor</code> to display
+ *
+ * @exception SWTException <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 setCursor (Cursor newCursor) {
+ checkWidget ();
+ clientCursor = newCursor;
+ if (newCursor != null) {
+ display.lockCursor = false;
+ if (inEvent) newCursor.handle.set();
+ display.lockCursor = true;
+ }
+}
+
+/**
+ * Specifies the rectangles that should be drawn, expressed relative to the parent
+ * widget. If the parent is a Display then these are screen coordinates.
+ *
+ * @param rectangles the bounds of the rectangles to be drawn
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the set of rectangles is null or contains a null rectangle</li>
+ * </ul>
+ * @exception SWTException <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 setRectangles (Rectangle [] rectangles) {
+ checkWidget ();
+ if (rectangles == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int length = rectangles.length;
+ this.rectangles = new Rectangle [length];
+ for (int i = 0; i < length; i++) {
+ Rectangle current = rectangles [i];
+ if (current == null) error (SWT.ERROR_NULL_ARGUMENT);
+ this.rectangles [i] = new Rectangle (current.x, current.y, current.width, current.height);
+ }
+ proportions = computeProportions (rectangles);
+}
+
+/**
+ * Changes the appearance of the line used to draw the rectangles.
+ *
+ * @param stippled <code>true</code> if rectangle should appear stippled
+ *
+ * @exception SWTException <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 setStippled (boolean stippled) {
+ checkWidget ();
+ this.stippled = stippled;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TrayItem.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TrayItem.java
new file mode 100755
index 0000000000..ec0a782aa6
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TrayItem.java
@@ -0,0 +1,537 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class represent icons that can be placed on the
+ * system tray or task bar status area.
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>DefaultSelection, MenuDetect, Selection</dd>
+ * </dl>
+ * </p><p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#tray">Tray, TrayItem snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.0
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class TrayItem extends Item {
+ Tray parent;
+ ToolTip toolTip;
+ String toolTipText;
+ boolean visible = true, highlight;
+ NSStatusItem item;
+ NSImageView view;
+
+ static final float BORDER = 8f;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>Tray</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>SWT</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>SWT</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 SWTException <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 SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TrayItem (Tray parent, int style) {
+ super (parent, style);
+ this.parent = parent;
+ parent.createItem (this, parent.getItemCount ());
+ createWidget ();
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the platform-specific context menu trigger
+ * has occurred, by sending it one of the messages defined in
+ * the <code>MenuDetectListener</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 SWTException <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 MenuDetectListener
+ * @see #removeMenuDetectListener
+ *
+ * @since 3.3
+ */
+public void addMenuDetectListener (MenuDetectListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.MenuDetect, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the receiver 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 receiver is selected
+ * <code>widgetDefaultSelected</code> is called when the receiver is double-clicked
+ * </p>
+ *
+ * @param listener the listener which should be notified when the receiver is selected by the user
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+void createHandle () {
+ NSStatusBar statusBar = NSStatusBar.systemStatusBar();
+ item = statusBar.statusItemWithLength(0);
+ if (item == null) error (SWT.ERROR_NO_HANDLES);
+ item.retain();
+ item.setHighlightMode(true);
+ view = (NSImageView)new SWTImageView().alloc();
+ if (view == null) error (SWT.ERROR_NO_HANDLES);
+ view.init ();
+ item.setView(view);
+}
+
+void deregister () {
+ super.deregister ();
+ display.removeWidget (view);
+ display.removeWidget(view.cell());
+}
+
+void destroyWidget () {
+ parent.destroyItem (this);
+ releaseHandle ();
+}
+
+Point getLocation () {
+ NSRect rect = view.frame();
+ NSRect windowRect = view.window().frame();
+ NSPoint pt = new NSPoint();
+ pt.x = rect.width / 2;
+ pt = view.convertPoint_fromView_(pt, null);
+ pt.x += windowRect.x;
+ return new Point ((int)pt.x, (int)pt.y);
+}
+
+/**
+ * Returns the receiver's parent, which must be a <code>Tray</code>.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException <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 Tray getParent () {
+ checkWidget ();
+ return parent;
+}
+
+/**
+ * Returns the receiver's tool tip, or null if it has
+ * not been set.
+ *
+ * @return the receiver's tool tip text
+ *
+ * @exception SWTException <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 ToolTip getToolTip () {
+ checkWidget ();
+ return toolTip;
+}
+
+/**
+ * Returns the receiver's tool tip text, or null if it has
+ * not been set.
+ *
+ * @return the receiver's tool tip text
+ *
+ * @exception SWTException <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 String getToolTipText () {
+ checkWidget ();
+ return toolTipText;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is visible and
+ * <code>false</code> otherwise.
+ *
+ * @return the receiver's visibility
+ *
+ * @exception SWTException <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 boolean getVisible () {
+ checkWidget ();
+ return visible;
+}
+
+void register () {
+ super.register ();
+ display.addWidget (view, this);
+ display.addWidget (((NSControl)view).cell(), this);
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ parent = null;
+ if (item != null) item.release();
+ if (view != null) view.release();
+ item = null;
+ view = null;
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ NSStatusBar statusBar = NSStatusBar.systemStatusBar();
+ statusBar.removeStatusItem(item);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the platform-specific context menu trigger has
+ * occurred.
+ *
+ * @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 SWTException <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 MenuDetectListener
+ * @see #addMenuDetectListener
+ *
+ * @since 3.3
+ */
+public void removeMenuDetectListener (MenuDetectListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.MenuDetect, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the receiver 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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+/**
+ * Sets the receiver's image.
+ *
+ * @param image the new image
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setImage (Image image) {
+ checkWidget ();
+ if (image != null && image.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ super.setImage (image);
+ float /*double*/ width = 0;
+ if (image == null) {
+ view.setImage (null);
+ } else {
+ /*
+ * Feature in Cocoa. If the NSImage object being set into the view is
+ * the same NSImage object that is already there then the new image is
+ * not taken. This results in the view's image not changing even if the
+ * NSImage object's content has changed since it was last set into the
+ * view. The workaround is to temporarily set the view's image to null
+ * so that the new image will then be taken.
+ */
+ NSImage current = view.image ();
+ if (current != null && current.id == image.handle.id) {
+ view.setImage (null);
+ }
+ view.setImage (image.handle);
+ if (visible) {
+ width = image.handle.size ().width + BORDER;
+ }
+ }
+ item.setLength (width);
+}
+
+/**
+ * Sets the receiver's tool tip to the argument, which
+ * may be null indicating that no tool tip should be shown.
+ *
+ * @param toolTip the new tool tip (or null)
+ *
+ * @exception SWTException <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 setToolTip (ToolTip toolTip) {
+ checkWidget ();
+ ToolTip oldTip = this.toolTip, newTip = toolTip;
+ if (oldTip != null) oldTip.item = null;
+ this.toolTip = newTip;
+ if (newTip != null) newTip.item = this;
+}
+
+/**
+ * Sets the receiver's tool tip text to the argument, which
+ * may be null indicating that the default tool tip for the
+ * control will be shown. For a control that has a default
+ * tool tip, such as the Tree control on Windows, setting
+ * the tool tip text to an empty string replaces the default,
+ * causing no tool tip text to be shown.
+ * <p>
+ * The mnemonic indicator (character '&amp;') is not displayed in a tool tip.
+ * To display a single '&amp;' in the tool tip, the character '&amp;' can be
+ * escaped by doubling it in the string.
+ * </p>
+ *
+ * @param string the new tool tip text (or null)
+ *
+ * @exception SWTException <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 setToolTipText (String string) {
+ checkWidget ();
+ toolTipText = string;
+ _setToolTipText (string);
+}
+
+void _setToolTipText (String string) {
+ if (string != null) {
+ char[] chars = new char [string.length ()];
+ string.getChars (0, chars.length, chars, 0);
+ int length = fixMnemonic (chars);
+ NSString str = NSString.stringWithCharacters (chars, length);
+ view.setToolTip (str);
+ } else {
+ view.setToolTip (null);
+ }
+}
+
+/**
+ * Makes the receiver visible if the argument is <code>true</code>,
+ * and makes it invisible otherwise.
+ *
+ * @param visible the new visibility state
+ *
+ * @exception SWTException <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 setVisible (boolean visible) {
+ checkWidget ();
+ if (this.visible == visible) return;
+ if (visible) {
+ sendEvent (SWT.Show);
+ if (isDisposed ()) return;
+ }
+ this.visible = visible;
+ float /*double*/ width = image != null && visible ? image.handle.size().width + BORDER : 0;
+ item.setLength(width);
+ if (!visible) sendEvent (SWT.Hide);
+}
+
+void showMenu (Menu menu) {
+ display.trayItemMenu = menu;
+ item.popUpStatusItemMenu(menu.nsMenu);
+}
+
+void showMenu () {
+ _setToolTipText (null);
+ Display display = this.display;
+ display.currentTrayItem = this;
+ sendEvent (SWT.MenuDetect);
+ if (!isDisposed ()) display.runPopups();
+ display.currentTrayItem = null;
+ if (isDisposed ()) return;
+ _setToolTipText (toolTipText);
+}
+
+void displayMenu () {
+ if (highlight) {
+ view.display();
+ display.trayItemMenu = null;
+ showMenu();
+ if (display.trayItemMenu != null) {
+ display.trayItemMenu = null;
+ highlight = false;
+ view.setNeedsDisplay(true);
+ }
+ }
+}
+
+boolean shouldShowMenu (NSEvent event) {
+ if (!hooks(SWT.MenuDetect)) return false;
+ switch ((int)/*64*/event.type()) {
+ case OS.NSRightMouseDown: return true;
+ case OS.NSLeftMouseDown:
+ if (!(hooks(SWT.Selection) || hooks(SWT.DefaultSelection))) {
+ return true;
+ }
+ if ((event.modifierFlags() & OS.NSDeviceIndependentModifierFlagsMask) == OS.NSControlKeyMask) {
+ return true;
+ }
+ return false;
+ case OS.NSLeftMouseDragged:
+ case OS.NSRightMouseDragged:
+ return true;
+ }
+ return false;
+}
+
+void mouseDown(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ NSEvent nsEvent = new NSEvent(theEvent);
+ highlight = true;
+ view.setNeedsDisplay(true);
+ if (shouldShowMenu(nsEvent)) displayMenu();
+}
+
+void mouseDragged(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ NSEvent nsEvent = new NSEvent(theEvent);
+ NSRect frame = view.frame();
+ highlight = OS.NSPointInRect(nsEvent.locationInWindow(), frame);
+ view.setNeedsDisplay(true);
+ if (shouldShowMenu(nsEvent)) displayMenu();
+}
+
+void mouseUp(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (highlight) {
+ NSEvent nsEvent = new NSEvent(theEvent);
+ if (nsEvent.type() == OS.NSLeftMouseUp) {
+ postEvent(nsEvent.clickCount() == 2 ? SWT.DefaultSelection : SWT.Selection);
+ }
+ }
+ highlight = false;
+ view.setNeedsDisplay(true);
+}
+
+void rightMouseDown(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ mouseDown(id, sel, theEvent);
+}
+
+void rightMouseUp(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ mouseUp(id, sel, theEvent);
+}
+
+void rightMouseDragged(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ mouseDragged(id, sel, theEvent);
+}
+
+void drawRect(int /*long*/ id, int /*long*/ sel, NSRect rect) {
+ item.drawStatusBarBackgroundInRect(rect, highlight);
+ super.drawRect(id, sel, rect);
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tree.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tree.java
new file mode 100755
index 0000000000..efac0d6428
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tree.java
@@ -0,0 +1,2974 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.accessibility.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+/**
+ * Instances of this class provide a selectable user interface object
+ * that displays a hierarchy of items and issues notification when an
+ * item in the hierarchy is selected.
+ * <p>
+ * The item children that may be added to instances of this class
+ * must be of type <code>TreeItem</code>.
+ * </p><p>
+ * Style <code>VIRTUAL</code> is used to create a <code>Tree</code> whose
+ * <code>TreeItem</code>s are to be populated by the client on an on-demand basis
+ * instead of up-front. This can provide significant performance improvements for
+ * trees that are very large or for which <code>TreeItem</code> population is
+ * expensive (for example, retrieving values from an external source).
+ * </p><p>
+ * Here is an example of using a <code>Tree</code> with style <code>VIRTUAL</code>:
+ * <code><pre>
+ * final Tree tree = new Tree(parent, SWT.VIRTUAL | SWT.BORDER);
+ * tree.setItemCount(20);
+ * tree.addListener(SWT.SetData, new Listener() {
+ * public void handleEvent(Event event) {
+ * TreeItem item = (TreeItem)event.item;
+ * TreeItem parentItem = item.getParentItem();
+ * String text = null;
+ * if (parentItem == null) {
+ * text = "node " + tree.indexOf(item);
+ * } else {
+ * text = parentItem.getText() + " - " + parentItem.indexOf(item);
+ * }
+ * item.setText(text);
+ * System.out.println(text);
+ * item.setItemCount(10);
+ * }
+ * });
+ * </pre></code>
+ * </p><p>
+ * Note that although this class is a subclass of <code>Composite</code>,
+ * it does not normally make sense to add <code>Control</code> children to
+ * it, or set a layout on it, unless implementing something like a cell
+ * editor.
+ * </p><p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>SINGLE, MULTI, CHECK, FULL_SELECTION, VIRTUAL, NO_SCROLL</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection, DefaultSelection, Collapse, Expand, SetData, MeasureItem, EraseItem, PaintItem</dd>
+ * </dl>
+ * </p><p>
+ * Note: Only one of the styles SINGLE and MULTI 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/#tree">Tree, TreeItem, TreeColumn snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Tree extends Composite {
+ NSTableColumn firstColumn, checkColumn;
+ NSTextFieldCell dataCell;
+ NSButtonCell buttonCell;
+ NSTableHeaderView headerView;
+ TreeItem [] items;
+ int itemCount;
+ TreeColumn [] columns;
+ TreeColumn sortColumn;
+ int columnCount;
+ int sortDirection;
+ boolean ignoreExpand, ignoreSelect, ignoreRedraw, reloadPending, drawExpansion;
+ Rectangle imageBounds;
+ TreeItem insertItem;
+ boolean insertBefore;
+
+ static int NEXT_ID;
+
+ static final int FIRST_COLUMN_MINIMUM_WIDTH = 5;
+ static final int IMAGE_GAP = 3;
+ static final int TEXT_GAP = 2;
+ static final int CELL_GAP = 1;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 SWTException <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 SWT#SINGLE
+ * @see SWT#MULTI
+ * @see SWT#CHECK
+ * @see SWT#FULL_SELECTION
+ * @see SWT#VIRTUAL
+ * @see SWT#NO_SCROLL
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Tree (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+void _addListener (int eventType, Listener listener) {
+ super._addListener (eventType, listener);
+ clearCachedWidth (items);
+}
+
+TreeItem _getItem (TreeItem parentItem, int index, boolean create) {
+ int count;
+ TreeItem[] items;
+ if (parentItem != null) {
+ count = parentItem.itemCount;
+ items = parentItem.items;
+ } else {
+ count = this.itemCount;
+ items = this.items;
+ }
+ if (index < 0 || index >= count) return null;
+ TreeItem item = items [index];
+ if (item != null || (style & SWT.VIRTUAL) == 0 || !create) return item;
+ item = new TreeItem (this, parentItem, SWT.NONE, index, false);
+ items [index] = item;
+ return item;
+}
+
+int /*long*/ accessibilityAttributeValue (int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+
+ if (accessible != null) {
+ NSString attribute = new NSString(arg0);
+ id returnValue = accessible.internal_accessibilityAttributeValue(attribute, ACC.CHILDID_SELF);
+ if (returnValue != null) return returnValue.id;
+ }
+
+ NSString attributeName = new NSString(arg0);
+
+ // Accessibility Verifier queries for a title or description. NSOutlineView doesn't
+ // seem to return either, so we return a default description value here.
+ if (attributeName.isEqualToString (OS.NSAccessibilityDescriptionAttribute)) {
+ return NSString.stringWith("").id;
+ }
+
+ return super.accessibilityAttributeValue(id, sel, arg0);
+}
+
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's selection, by sending
+ * it one of the messages defined in the <code>SelectionListener</code>
+ * interface.
+ * <p>
+ * When <code>widgetSelected</code> is called, the item field of the event object is valid.
+ * If the receiver has the <code>SWT.CHECK</code> style and the check selection changes,
+ * the event object detail field contains the value <code>SWT.CHECK</code>.
+ * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked.
+ * The item field of the event object is valid for default selection, but the detail field is not used.
+ * </p>
+ *
+ * @param listener the listener which should be notified when the user changes the receiver's selection
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection, typedListener);
+ addListener (SWT.DefaultSelection, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when an item in the receiver is expanded or collapsed
+ * by sending it one of the messages defined in the <code>TreeListener</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 SWTException <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 TreeListener
+ * @see #removeTreeListener
+ */
+public void addTreeListener(TreeListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Expand, typedListener);
+ addListener (SWT.Collapse, typedListener);
+}
+
+int calculateWidth (TreeItem[] items, int index, GC gc, boolean recurse) {
+ if (items == null) return 0;
+ int width = 0;
+ for (int i=0; i<items.length; i++) {
+ TreeItem item = items [i];
+ if (item != null) {
+ int itemWidth = item.calculateWidth (index, gc);
+ width = Math.max (width, itemWidth);
+ if (recurse && item.getExpanded ()) {
+ width = Math.max (width, calculateWidth (item.items, index, gc, recurse));
+ }
+ }
+ }
+ return width;
+}
+
+NSSize cellSize (int /*long*/ id, int /*long*/ sel) {
+ NSSize size = super.cellSize(id, sel);
+ NSImage image = new NSCell(id).image();
+ if (image != null) size.width += imageBounds.width + IMAGE_GAP;
+ if (hooks(SWT.MeasureItem)) {
+ int /*long*/ [] outValue = new int /*long*/ [1];
+ OS.object_getInstanceVariable(id, Display.SWT_ROW, outValue);
+ TreeItem item = (TreeItem) display.getWidget (outValue [0]);
+ OS.object_getInstanceVariable(id, Display.SWT_COLUMN, outValue);
+ int /*long*/ tableColumn = outValue[0];
+ int columnIndex = 0;
+ for (int i=0; i<columnCount; i++) {
+ if (columns [i].nsColumn.id == tableColumn) {
+ columnIndex = i;
+ break;
+ }
+ }
+ sendMeasureItem (item, columnIndex, size);
+ }
+ return size;
+}
+
+boolean canDragRowsWithIndexes_atPoint(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1) {
+ NSPoint clickPoint = new NSPoint();
+ OS.memmove(clickPoint, arg1, NSPoint.sizeof);
+ NSOutlineView tree = (NSOutlineView)view;
+
+ // If the current row is not selected and the user is not attempting to modify the selection, select the row first.
+ int /*long*/ row = tree.rowAtPoint(clickPoint);
+ int /*long*/ modifiers = NSApplication.sharedApplication().currentEvent().modifierFlags();
+
+ boolean drag = (state & DRAG_DETECT) != 0 && hooks (SWT.DragDetect);
+ if (drag) {
+ if (!tree.isRowSelected(row) && (modifiers & (OS.NSCommandKeyMask | OS.NSShiftKeyMask | OS.NSAlternateKeyMask | OS.NSControlKeyMask)) == 0) {
+ NSIndexSet set = (NSIndexSet)new NSIndexSet().alloc();
+ set = set.initWithIndex(row);
+ tree.selectRowIndexes (set, false);
+ set.release();
+ }
+ }
+
+ // The clicked row must be selected to initiate a drag.
+ return (tree.isRowSelected(row) && drag);
+}
+
+boolean checkData (TreeItem item) {
+ if (item.cached) return true;
+ if ((style & SWT.VIRTUAL) != 0) {
+ item.cached = true;
+ Event event = new Event ();
+ TreeItem parentItem = item.getParentItem ();
+ event.item = item;
+ event.index = parentItem == null ? indexOf (item) : parentItem.indexOf (item);
+ ignoreRedraw = true;
+ sendEvent (SWT.SetData, event);
+ //widget could be disposed at this point
+ ignoreRedraw = false;
+ if (isDisposed () || item.isDisposed ()) return false;
+ if (!setScrollWidth (item)) item.redraw (-1);
+ }
+ return true;
+}
+
+static int checkStyle (int style) {
+ /*
+ * Feature in Windows. Even when WS_HSCROLL or
+ * WS_VSCROLL is not specified, Windows creates
+ * trees and tables with scroll bars. The fix
+ * is to set H_SCROLL and V_SCROLL.
+ *
+ * NOTE: This code appears on all platforms so that
+ * applications have consistent scroll bar behavior.
+ */
+ if ((style & SWT.NO_SCROLL) == 0) {
+ style |= SWT.H_SCROLL | SWT.V_SCROLL;
+ }
+ /* This platform is always FULL_SELECTION */
+ style |= SWT.FULL_SELECTION;
+ return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0);
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+void checkItems () {
+ if (!reloadPending) return;
+ reloadPending = false;
+ TreeItem[] selectedItems = getSelection ();
+ ((NSOutlineView)view).reloadData ();
+ selectItems (selectedItems, true);
+ ignoreExpand = true;
+ for (int i = 0; i < itemCount; i++) {
+ if (items[i] != null) items[i].updateExpanded ();
+ }
+ ignoreExpand = false;
+}
+
+void clear (TreeItem parentItem, int index, boolean all) {
+ TreeItem item = _getItem (parentItem, index, false);
+ if (item != null) {
+ item.clear();
+ item.redraw (-1);
+ if (all) {
+ clearAll (item, true);
+ }
+ }
+}
+
+void clearAll (TreeItem parentItem, boolean all) {
+ int count = getItemCount (parentItem);
+ if (count == 0) return;
+ TreeItem [] children = parentItem == null ? items : parentItem.items;
+ for (int i=0; i<count; i++) {
+ TreeItem item = children [i];
+ if (item != null) {
+ item.clear ();
+ item.redraw (-1);
+ if (all) clearAll (item, true);
+ }
+ }
+}
+
+/**
+ * Clears the item at the given zero-relative index in the receiver.
+ * The text, icon and other attributes of the item are set to the default
+ * value. If the tree was created with the <code>SWT.VIRTUAL</code> style,
+ * these attributes are requested again as needed.
+ *
+ * @param index the index of the item to clear
+ * @param all <code>true</code> if all child items of the indexed item should be
+ * cleared recursively, and <code>false</code> otherwise
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 SWT#VIRTUAL
+ * @see SWT#SetData
+ *
+ * @since 3.2
+ */
+public void clear (int index, boolean all) {
+ checkWidget ();
+ int count = getItemCount ();
+ if (index < 0 || index >= count) error (SWT.ERROR_INVALID_RANGE);
+ clear (null, index, all);
+}
+
+/**
+ * Clears all the items in the receiver. The text, icon and other
+ * attributes of the items are set to their default values. If the
+ * tree was created with the <code>SWT.VIRTUAL</code> style, these
+ * attributes are requested again as needed.
+ *
+ * @param all <code>true</code> if all child items should be cleared
+ * recursively, and <code>false</code> otherwise
+ *
+ * @exception SWTException <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 SWT#VIRTUAL
+ * @see SWT#SetData
+ *
+ * @since 3.2
+ */
+public void clearAll (boolean all) {
+ checkWidget ();
+ clearAll (null, all);
+}
+
+void clearCachedWidth (TreeItem[] items) {
+ if (items == null) return;
+ for (int i = 0; i < items.length; i++) {
+ TreeItem item = items [i];
+ if (item == null) break;
+ item.width = -1;
+ clearCachedWidth (item.items);
+ }
+}
+
+void collapseItem_collapseChildren (int /*long*/ id, int /*long*/ sel, int /*long*/ itemID, boolean children) {
+ TreeItem item = (TreeItem)display.getWidget(itemID);
+ if (!ignoreExpand) item.sendExpand (false, children);
+ ignoreExpand = true;
+ super.collapseItem_collapseChildren (id, sel, itemID, children);
+ ignoreExpand = false;
+ if (isDisposed() || item.isDisposed()) return;
+ setScrollWidth ();
+}
+
+public Point computeSize (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int width = 0, height = 0;
+ if (wHint == SWT.DEFAULT) {
+ if (columnCount != 0) {
+ for (int i=0; i<columnCount; i++) {
+ width += columns [i].getWidth ();
+ }
+ } else {
+ GC gc = new GC (this);
+ width = calculateWidth (items, 0, gc, true) + CELL_GAP;
+ gc.dispose ();
+ }
+ if ((style & SWT.CHECK) != 0) width += getCheckColumnWidth ();
+ } else {
+ width = wHint;
+ }
+ if (hHint == SWT.DEFAULT) {
+ height = (int)/*64*/((NSOutlineView) view).numberOfRows () * getItemHeight () + getHeaderHeight ();
+ } else {
+ height = hHint;
+ }
+ if (width <= 0) width = DEFAULT_WIDTH;
+ if (height <= 0) height = DEFAULT_HEIGHT;
+ Rectangle rect = computeTrim (0, 0, width, height);
+ return new Point (rect.width, rect.height);
+}
+
+void createColumn (TreeItem item, int index) {
+ if (item.items != null) {
+ for (int i = 0; i < item.items.length; i++) {
+ if (item.items[i] != null) createColumn (item.items[i], index);
+ }
+ }
+ String [] strings = item.strings;
+ if (strings != null) {
+ String [] temp = new String [columnCount];
+ System.arraycopy (strings, 0, temp, 0, index);
+ System.arraycopy (strings, index, temp, index+1, columnCount-index-1);
+ temp [index] = "";
+ item.strings = temp;
+ }
+ if (index == 0) item.text = "";
+ Image [] images = item.images;
+ if (images != null) {
+ Image [] temp = new Image [columnCount];
+ System.arraycopy (images, 0, temp, 0, index);
+ System.arraycopy (images, index, temp, index+1, columnCount-index-1);
+ item.images = temp;
+ }
+ if (index == 0) item.image = null;
+ Color [] cellBackground = item.cellBackground;
+ if (cellBackground != null) {
+ Color [] temp = new Color [columnCount];
+ System.arraycopy (cellBackground, 0, temp, 0, index);
+ System.arraycopy (cellBackground, index, temp, index+1, columnCount-index-1);
+ item.cellBackground = temp;
+ }
+ Color [] cellForeground = item.cellForeground;
+ if (cellForeground != null) {
+ Color [] temp = new Color [columnCount];
+ System.arraycopy (cellForeground, 0, temp, 0, index);
+ System.arraycopy (cellForeground, index, temp, index+1, columnCount-index-1);
+ item.cellForeground = temp;
+ }
+ Font [] cellFont = item.cellFont;
+ if (cellFont != null) {
+ Font [] temp = new Font [columnCount];
+ System.arraycopy (cellFont, 0, temp, 0, index);
+ System.arraycopy (cellFont, index, temp, index+1, columnCount-index-1);
+ item.cellFont = temp;
+ }
+}
+
+void createHandle () {
+ NSScrollView scrollWidget = (NSScrollView) new SWTScrollView ().alloc ();
+ scrollWidget.init ();
+ scrollWidget.setHasHorizontalScroller ((style & SWT.H_SCROLL) != 0);
+ scrollWidget.setHasVerticalScroller ((style & SWT.V_SCROLL) != 0);
+ scrollWidget.setAutohidesScrollers (true);
+ scrollWidget.setBorderType(hasBorder () ? OS.NSBezelBorder : OS.NSNoBorder);
+
+ NSOutlineView widget = (NSOutlineView) new SWTOutlineView ().alloc ();
+ /*
+ * Bug in Cocoa. Calling init, instead of initWithFrame on an NSOutlineView
+ * cause the NSOutlineView to leak some memory. The work around is to call
+ * initWithFrame and pass an empty NSRect instead of calling init.
+ */
+ widget.initWithFrame(new NSRect());
+ widget.setAllowsMultipleSelection ((style & SWT.MULTI) != 0);
+ widget.setAllowsColumnReordering (false);
+ widget.setAutoresizesOutlineColumn (false);
+ widget.setAutosaveExpandedItems (true);
+ widget.setDataSource (widget);
+ widget.setDelegate (widget);
+ widget.setColumnAutoresizingStyle (OS.NSTableViewNoColumnAutoresizing);
+ NSSize spacing = new NSSize();
+ spacing.width = spacing.height = CELL_GAP;
+ widget.setIntercellSpacing(spacing);
+ widget.setDoubleAction (OS.sel_sendDoubleSelection);
+ if (!hasBorder ()) widget.setFocusRingType (OS.NSFocusRingTypeNone);
+
+ headerView = (NSTableHeaderView)new SWTTableHeaderView ().alloc ().init ();
+ widget.setHeaderView (null);
+
+ NSString str = NSString.stringWith (""); //$NON-NLS-1$
+ if ((style & SWT.CHECK) != 0) {
+ checkColumn = (NSTableColumn) new NSTableColumn ().alloc ();
+ checkColumn = checkColumn.initWithIdentifier(NSString.stringWith(String.valueOf(++NEXT_ID)));
+ checkColumn.headerCell ().setTitle (str);
+ widget.addTableColumn (checkColumn);
+ widget.setOutlineTableColumn (checkColumn);
+ checkColumn.setResizingMask (OS.NSTableColumnNoResizing);
+ checkColumn.setEditable (false);
+ int /*long*/ cls = NSButton.cellClass (); /* use our custom cell class */
+ buttonCell = new NSButtonCell (OS.class_createInstance (cls, 0));
+ buttonCell.init ();
+ checkColumn.setDataCell (buttonCell);
+ buttonCell.setButtonType (OS.NSSwitchButton);
+ buttonCell.setImagePosition (OS.NSImageOnly);
+ buttonCell.setAllowsMixedState (true);
+ checkColumn.setWidth (getCheckColumnWidth ());
+ }
+
+ firstColumn = (NSTableColumn) new NSTableColumn ().alloc ();
+ firstColumn = firstColumn.initWithIdentifier(NSString.stringWith(String.valueOf(++NEXT_ID)));
+ /*
+ * Feature in Cocoa. If a column's width is too small to show any content
+ * then outlineView_objectValueForTableColumn_byItem is never invoked to
+ * query for item values, which is a problem for VIRTUAL Trees. The
+ * workaround is to ensure that, for 0-column Trees, the internal first
+ * column always has a minimal width that makes this call come in.
+ */
+ firstColumn.setMinWidth (FIRST_COLUMN_MINIMUM_WIDTH);
+ firstColumn.setWidth(0);
+ firstColumn.setResizingMask (OS.NSTableColumnNoResizing);
+ firstColumn.headerCell ().setTitle (str);
+ widget.addTableColumn (firstColumn);
+ widget.setOutlineTableColumn (firstColumn);
+ dataCell = (NSTextFieldCell)new SWTImageTextCell ().alloc ().init ();
+ dataCell.setLineBreakMode(OS.NSLineBreakByClipping);
+ firstColumn.setDataCell (dataCell);
+
+ scrollView = scrollWidget;
+ view = widget;
+}
+
+void createItem (TreeColumn column, int index) {
+ if (!(0 <= index && index <= columnCount)) error (SWT.ERROR_INVALID_RANGE);
+ if (index == 0) {
+ // first column must be left aligned
+ column.style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER);
+ column.style |= SWT.LEFT;
+ }
+ if (columnCount == columns.length) {
+ TreeColumn [] newColumns = new TreeColumn [columnCount + 4];
+ System.arraycopy (columns, 0, newColumns, 0, columns.length);
+ columns = newColumns;
+ }
+ NSTableColumn nsColumn;
+ if (columnCount == 0) {
+ //TODO - clear attributes, alignment etc.
+ nsColumn = firstColumn;
+ nsColumn.setMinWidth (0);
+ nsColumn.setResizingMask (OS.NSTableColumnUserResizingMask);
+ firstColumn = null;
+ } else {
+ //TODO - set attributes, alignment etc.
+ NSOutlineView outlineView = (NSOutlineView)view;
+ NSString str = NSString.stringWith ("");
+ nsColumn = (NSTableColumn) new NSTableColumn ().alloc ();
+ nsColumn = nsColumn.initWithIdentifier(NSString.stringWith(String.valueOf(++NEXT_ID)));
+ nsColumn.setMinWidth(0);
+ nsColumn.headerCell ().setTitle (str);
+ outlineView.addTableColumn (nsColumn);
+ int checkColumn = (style & SWT.CHECK) != 0 ? 1 : 0;
+ outlineView.moveColumn (columnCount + checkColumn, index + checkColumn);
+ nsColumn.setDataCell (dataCell);
+ if (index == 0) {
+ outlineView.setOutlineTableColumn (nsColumn);
+ }
+ }
+ column.createJNIRef ();
+ NSTableHeaderCell headerCell = (NSTableHeaderCell)new SWTTableHeaderCell ().alloc ().init ();
+ nsColumn.setHeaderCell (headerCell);
+ display.addWidget (headerCell, column);
+ column.nsColumn = nsColumn;
+ nsColumn.setWidth (0);
+ System.arraycopy (columns, index, columns, index + 1, columnCount++ - index);
+ columns [index] = column;
+ for (int i = 0; i < itemCount; i++) {
+ TreeItem item = items [i];
+ if (item != null) {
+ if (columnCount > 1) {
+ createColumn (item, index);
+ }
+ }
+ }
+}
+
+void createItem (TreeItem item, TreeItem parentItem, int index) {
+ int count;
+ TreeItem [] items;
+ if (parentItem != null) {
+ count = parentItem.itemCount;
+ items = parentItem.items;
+ } else {
+ count = this.itemCount;
+ items = this.items;
+ }
+ if (index == -1) index = count;
+ if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE);
+ if (count == items.length) {
+ TreeItem [] newItems = new TreeItem [items.length + 4];
+ System.arraycopy (items, 0, newItems, 0, items.length);
+ items = newItems;
+ if (parentItem != null) {
+ parentItem.items = items;
+ } else {
+ this.items = items;
+ }
+ }
+ System.arraycopy (items, index, items, index + 1, count++ - index);
+ items [index] = item;
+ item.items = new TreeItem [4];
+ SWTTreeItem handle = (SWTTreeItem) new SWTTreeItem ().alloc ().init ();
+ item.handle = handle;
+ item.createJNIRef ();
+ item.register ();
+ if (parentItem != null) {
+ parentItem.itemCount = count;
+ } else {
+ this.itemCount = count;
+ }
+ ignoreExpand = true;
+ reloadItem (parentItem, true);
+ if (parentItem != null && parentItem.itemCount == 1 && parentItem.expanded) {
+ ((NSOutlineView)view).expandItem (parentItem.handle);
+ }
+ ignoreExpand = false;
+}
+
+void createWidget () {
+ super.createWidget ();
+ items = new TreeItem [4];
+ columns = new TreeColumn [4];
+}
+
+Color defaultBackground () {
+ return display.getWidgetColor (SWT.COLOR_LIST_BACKGROUND);
+}
+
+NSFont defaultNSFont () {
+ return display.outlineViewFont;
+}
+
+Color defaultForeground () {
+ return display.getWidgetColor (SWT.COLOR_LIST_FOREGROUND);
+}
+
+/**
+ * Deselects all selected items in the receiver.
+ *
+ * @exception SWTException <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 deselectAll () {
+ checkWidget ();
+ NSTableView widget = (NSOutlineView) view;
+ ignoreSelect = true;
+ widget.deselectAll (null);
+ ignoreSelect = false;
+}
+
+void deregister () {
+ super.deregister ();
+ display.removeWidget (headerView);
+ display.removeWidget (dataCell);
+ if (buttonCell != null) display.removeWidget (buttonCell);
+}
+
+/**
+ * Deselects an item in the receiver. If the item was already
+ * deselected, it remains deselected.
+ *
+ * @param item the item to be deselected
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.4
+ */
+public void deselect (TreeItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ NSOutlineView widget = (NSOutlineView)view;
+ int /*long*/ row = widget.rowForItem(item.handle);
+ ignoreSelect = true;
+ widget.deselectRow (row);
+ ignoreSelect = false;
+}
+
+void destroyItem (TreeColumn column) {
+ int index = 0;
+ while (index < columnCount) {
+ if (columns [index] == column) break;
+ index++;
+ }
+ for (int i=0; i<items.length; i++) {
+ TreeItem item = items [i];
+ if (item != null) {
+ if (columnCount <= 1) {
+ item.strings = null;
+ item.images = null;
+ item.cellBackground = null;
+ item.cellForeground = null;
+ item.cellFont = null;
+ } else {
+ if (item.strings != null) {
+ String [] strings = item.strings;
+ if (index == 0) {
+ item.text = strings [1] != null ? strings [1] : "";
+ }
+ String [] temp = new String [columnCount - 1];
+ System.arraycopy (strings, 0, temp, 0, index);
+ System.arraycopy (strings, index + 1, temp, index, columnCount - 1 - index);
+ item.strings = temp;
+ } else {
+ if (index == 0) item.text = "";
+ }
+ if (item.images != null) {
+ Image [] images = item.images;
+ if (index == 0) item.image = images [1];
+ Image [] temp = new Image [columnCount - 1];
+ System.arraycopy (images, 0, temp, 0, index);
+ System.arraycopy (images, index + 1, temp, index, columnCount - 1 - index);
+ item.images = temp;
+ } else {
+ if (index == 0) item.image = null;
+ }
+ if (item.cellBackground != null) {
+ Color [] cellBackground = item.cellBackground;
+ Color [] temp = new Color [columnCount - 1];
+ System.arraycopy (cellBackground, 0, temp, 0, index);
+ System.arraycopy (cellBackground, index + 1, temp, index, columnCount - 1 - index);
+ item.cellBackground = temp;
+ }
+ if (item.cellForeground != null) {
+ Color [] cellForeground = item.cellForeground;
+ Color [] temp = new Color [columnCount - 1];
+ System.arraycopy (cellForeground, 0, temp, 0, index);
+ System.arraycopy (cellForeground, index + 1, temp, index, columnCount - 1 - index);
+ item.cellForeground = temp;
+ }
+ if (item.cellFont != null) {
+ Font [] cellFont = item.cellFont;
+ Font [] temp = new Font [columnCount - 1];
+ System.arraycopy (cellFont, 0, temp, 0, index);
+ System.arraycopy (cellFont, index + 1, temp, index, columnCount - 1 - index);
+ item.cellFont = temp;
+ }
+ }
+ }
+ }
+
+ int oldIndex = indexOf (column.nsColumn);
+
+ System.arraycopy (columns, index + 1, columns, index, --columnCount - index);
+ columns [columnCount] = null;
+ if (columnCount == 0) {
+ //TODO - reset attributes
+ firstColumn = column.nsColumn;
+ firstColumn.retain ();
+ /*
+ * Feature in Cocoa. If a column's width is too small to show any content
+ * then outlineView_objectValueForTableColumn_byItem is never invoked to
+ * query for item values, which is a problem for VIRTUAL Trees. The
+ * workaround is to ensure that, for 0-column Trees, the internal first
+ * column always has a minimal width that makes this call come in.
+ */
+ firstColumn.setMinWidth (FIRST_COLUMN_MINIMUM_WIDTH);
+ firstColumn.setResizingMask (OS.NSTableColumnNoResizing);
+ setScrollWidth ();
+ } else {
+ if (index == 0) {
+ ((NSOutlineView)view).setOutlineTableColumn(columns[0].nsColumn);
+ }
+ ((NSOutlineView)view).removeTableColumn(column.nsColumn);
+ }
+
+ NSArray array = ((NSOutlineView)view).tableColumns ();
+ int arraySize = (int)/*64*/array.count ();
+ for (int i = oldIndex; i < arraySize; i++) {
+ int /*long*/ columnId = array.objectAtIndex (i).id;
+ for (int j = 0; j < columnCount; j++) {
+ if (columns[j].nsColumn.id == columnId) {
+ columns [j].sendEvent (SWT.Move);
+ break;
+ }
+ }
+ }
+}
+
+void destroyItem (TreeItem item) {
+ int count;
+ TreeItem[] items;
+ TreeItem parentItem = item.parentItem;
+ if (parentItem != null) {
+ count = parentItem.itemCount;
+ items = parentItem.items;
+ } else {
+ count = this.itemCount;
+ items = this.items;
+ }
+ int index = 0;
+ while (index < count) {
+ if (items [index] == item) break;
+ index++;
+ }
+ System.arraycopy (items, index + 1, items, index, --count - index);
+ items [count] = null;
+ if (parentItem != null) {
+ parentItem.itemCount = count;
+ } else {
+ this.itemCount = count;
+ }
+ reloadItem (parentItem, true);
+ setScrollWidth ();
+ if (this.itemCount == 0) imageBounds = null;
+}
+
+boolean dragDetect(int x, int y, boolean filter, boolean[] consume) {
+ // Let Cocoa determine if a drag is starting and fire the notification when we get the callback.
+ return false;
+}
+
+void drawInteriorWithFrame_inView (int /*long*/ id, int /*long*/ sel, NSRect rect, int /*long*/ view) {
+ boolean hooksErase = hooks (SWT.EraseItem);
+ boolean hooksPaint = hooks (SWT.PaintItem);
+ boolean hooksMeasure = hooks (SWT.MeasureItem);
+
+ NSTextFieldCell cell = new NSTextFieldCell (id);
+
+ NSOutlineView widget = (NSOutlineView)this.view;
+ int /*long*/ [] outValue = new int /*long*/ [1];
+ OS.object_getInstanceVariable(id, Display.SWT_ROW, outValue);
+ TreeItem item = (TreeItem) display.getWidget (outValue [0]);
+ int /*long*/ rowIndex = widget.rowForItem(item.handle);
+ OS.object_getInstanceVariable(id, Display.SWT_COLUMN, outValue);
+ int /*long*/ tableColumn = outValue[0];
+ int /*long*/ nsColumnIndex = widget.tableColumns().indexOfObjectIdenticalTo(new id(tableColumn));
+ int columnIndex = 0;
+ for (int i=0; i<columnCount; i++) {
+ if (columns [i].nsColumn.id == tableColumn) {
+ columnIndex = i;
+ break;
+ }
+ }
+
+ Color background = item.cellBackground != null ? item.cellBackground [columnIndex] : null;
+ if (background == null) background = item.background;
+ boolean drawBackground = background != null;
+ boolean drawForeground = true;
+ boolean isSelected = cell.isHighlighted();
+ boolean drawSelection = isSelected;
+ boolean hasFocus = hooksErase && hasFocus ();
+
+ Color selectionBackground = null, selectionForeground = null;
+ if (isSelected && (hooksErase || hooksPaint)) {
+ selectionForeground = Color.cocoa_new(display, hasFocus ? display.alternateSelectedControlTextColor : display.selectedControlTextColor);
+ selectionBackground = Color.cocoa_new(display, hasFocus ? display.alternateSelectedControlColor : display.secondarySelectedControlColor);
+ }
+
+ NSSize contentSize = super.cellSize(id, OS.sel_cellSize);
+ NSImage image = cell.image();
+ if (image != null) contentSize.width += imageBounds.width + IMAGE_GAP;
+ int contentWidth = (int)Math.ceil (contentSize.width);
+ NSSize spacing = widget.intercellSpacing();
+ int itemHeight = (int)Math.ceil (widget.rowHeight() + spacing.height);
+
+ NSRect cellRect = widget.rectOfColumn (nsColumnIndex);
+ cellRect.y = rect.y;
+ cellRect.height = rect.height + spacing.height;
+ if (columnCount == 0) {
+ NSRect rowRect = widget.rectOfRow (rowIndex);
+ cellRect.width = rowRect.width;
+ }
+ float /*double*/ offsetX = 0, offsetY = 0;
+ if (hooksPaint || hooksErase) {
+ NSRect frameCell = widget.frameOfCellAtColumn(nsColumnIndex, rowIndex);
+ offsetX = rect.x - frameCell.x;
+ offsetY = rect.y - frameCell.y;
+ if (drawExpansion) {
+ offsetX -= 0.5f;
+ offsetY -= 0.5f;
+ }
+ }
+ int itemX = (int)(rect.x - offsetX), itemY = (int)(rect.y - offsetY);
+ NSGraphicsContext context = NSGraphicsContext.currentContext ();
+
+ if (hooksMeasure) {
+ sendMeasureItem(item, columnIndex, contentSize);
+ }
+
+ Color userForeground = null;
+ if (hooksErase) {
+ context.saveGraphicsState();
+ NSAffineTransform transform = NSAffineTransform.transform();
+ transform.translateXBy(offsetX, offsetY);
+ transform.concat();
+
+ GCData data = new GCData ();
+ data.paintRect = cellRect;
+ GC gc = GC.cocoa_new (this, data);
+ gc.setFont (item.getFont (columnIndex));
+ if (isSelected) {
+ gc.setForeground (selectionForeground);
+ gc.setBackground (selectionBackground);
+ } else {
+ gc.setForeground (item.getForeground (columnIndex));
+ gc.setBackground (item.getBackground (columnIndex));
+ }
+ if (!drawExpansion) {
+ gc.setClipping ((int)(cellRect.x - offsetX), (int)(cellRect.y - offsetY), (int)cellRect.width, (int)cellRect.height);
+ }
+ Event event = new Event ();
+ event.item = item;
+ event.gc = gc;
+ event.index = columnIndex;
+ event.detail = SWT.FOREGROUND;
+ if (drawBackground) event.detail |= SWT.BACKGROUND;
+ if (isSelected) event.detail |= SWT.SELECTED;
+ event.x = (int)cellRect.x;
+ event.y = (int)cellRect.y;
+ event.width = (int)cellRect.width;
+ event.height = (int)cellRect.height;
+ sendEvent (SWT.EraseItem, event);
+ if (!event.doit) {
+ drawForeground = drawBackground = drawSelection = false;
+ } else {
+ drawBackground = drawBackground && (event.detail & SWT.BACKGROUND) != 0;
+ drawForeground = (event.detail & SWT.FOREGROUND) != 0;
+ drawSelection = drawSelection && (event.detail & SWT.SELECTED) != 0;
+ }
+ if (!drawSelection && isSelected) {
+ userForeground = Color.cocoa_new(display, gc.getForeground().handle);
+ }
+ gc.dispose ();
+
+ context.restoreGraphicsState();
+
+ if (isDisposed ()) return;
+ if (item.isDisposed ()) return;
+
+ if (drawSelection && ((style & SWT.HIDE_SELECTION) == 0 || hasFocus)) {
+ cellRect.height -= spacing.height;
+ callSuper (widget.id, OS.sel_highlightSelectionInClipRect_, cellRect);
+ cellRect.height += spacing.height;
+ }
+ }
+
+ if (drawBackground && !drawSelection) {
+ context.saveGraphicsState ();
+ float /*double*/ [] colorRGB = background.handle;
+ NSColor color = NSColor.colorWithDeviceRed (colorRGB[0], colorRGB[1], colorRGB[2], 1f);
+ color.setFill ();
+ NSBezierPath.fillRect (cellRect);
+ context.restoreGraphicsState ();
+ }
+
+ if (insertItem != null && !insertItem.isDisposed()) {
+ context.saveGraphicsState ();
+ NSRect contentRect = cell.titleRectForBounds (rect);
+ GCData data = new GCData ();
+ data.paintRect = contentRect;
+ GC gc = GC.cocoa_new (this, data);
+ gc.setClipping ((int)(contentRect.x - offsetX), (int)(contentRect.y - offsetY), (int)contentRect.width, (int)contentRect.height);
+ Rectangle itemRect = insertItem.getImageBounds(0).union(insertItem.getBounds());
+ Rectangle clientRect = getClientArea();
+ int x = clientRect.x + clientRect.width;
+ int posY = insertBefore ? itemRect.y : itemRect.y + itemRect.height - 1;
+ gc.drawLine(itemRect.x, posY, x, posY);
+ gc.dispose ();
+ context.restoreGraphicsState ();
+ }
+
+ if (drawForeground) {
+ if ((!drawExpansion || hooksMeasure) && image != null) {
+ NSRect destRect = new NSRect();
+ destRect.x = rect.x + IMAGE_GAP;
+ destRect.y = rect.y + (float)Math.ceil((rect.height - imageBounds.height) / 2);
+ destRect.width = imageBounds.width;
+ destRect.height = imageBounds.height;
+ NSRect srcRect = new NSRect();
+ NSSize size = image.size();
+ srcRect.width = size.width;
+ srcRect.height = size.height;
+ context.saveGraphicsState();
+ NSBezierPath.bezierPathWithRect(rect).addClip();
+ NSAffineTransform transform = NSAffineTransform.transform();
+ transform.scaleXBy(1, -1);
+ transform.translateXBy(0, -(destRect.height + 2 * destRect.y));
+ transform.concat();
+ image.drawInRect(destRect, srcRect, OS.NSCompositeSourceOver, 1);
+ context.restoreGraphicsState();
+ int imageWidth = imageBounds.width + IMAGE_GAP;
+ rect.x += imageWidth;
+ rect.width -= imageWidth;
+ }
+ cell.setHighlighted (false);
+ boolean callSuper = false;
+ if (userForeground != null) {
+ /*
+ * Bug in Cocoa. For some reason, it is not possible to change the
+ * foreground color to black when the cell is highlighted. The text
+ * still draws white. The fix is to draw the text and not call super.
+ */
+ float /*double*/ [] color = userForeground.handle;
+ if (color[0] == 0 && color[1] == 0 && color[2] == 0 && color[3] == 1) {
+ NSMutableAttributedString newStr = new NSMutableAttributedString(cell.attributedStringValue().mutableCopy());
+ NSRange range = new NSRange();
+ range.length = newStr.length();
+ newStr.removeAttribute(OS.NSForegroundColorAttributeName, range);
+ NSRect newRect = new NSRect();
+ newRect.x = rect.x + TEXT_GAP;
+ newRect.y = rect.y;
+ newRect.width = rect.width - TEXT_GAP;
+ newRect.height = rect.height;
+ NSSize size = newStr.size();
+ if (newRect.height > size.height) {
+ newRect.y += (newRect.height - size.height) / 2;
+ newRect.height = size.height;
+ }
+ newStr.drawInRect(newRect);
+ newStr.release();
+ } else {
+ NSColor nsColor = NSColor.colorWithDeviceRed(color[0], color[1], color[2], color[3]);
+ cell.setTextColor(nsColor);
+ callSuper = true;
+ }
+ } else {
+ callSuper = true;
+ }
+ if (callSuper) {
+ NSAttributedString attrStr = cell.attributedStringValue();
+ NSSize size = attrStr.size();
+ if (rect.height > size.height) {
+ rect.y += (rect.height - size.height) / 2;
+ rect.height = size.height;
+ }
+ super.drawInteriorWithFrame_inView(id, sel, rect, view);
+ }
+ }
+
+ if (hooksPaint) {
+ context.saveGraphicsState();
+ NSAffineTransform transform = NSAffineTransform.transform();
+ transform.translateXBy(offsetX, offsetY);
+ transform.concat();
+
+ GCData data = new GCData ();
+ data.paintRect = cellRect;
+ GC gc = GC.cocoa_new (this, data);
+ gc.setFont (item.getFont (columnIndex));
+ if (drawSelection) {
+ gc.setForeground (selectionForeground);
+ gc.setBackground (selectionBackground);
+ } else {
+ gc.setForeground (userForeground != null ? userForeground : item.getForeground (columnIndex));
+ gc.setBackground (item.getBackground (columnIndex));
+ }
+ if (!drawExpansion) {
+ gc.setClipping ((int)(cellRect.x - offsetX), (int)(cellRect.y - offsetY), (int)cellRect.width, (int)cellRect.height);
+ }
+ Event event = new Event ();
+ event.item = item;
+ event.gc = gc;
+ event.index = columnIndex;
+ if (drawForeground) event.detail |= SWT.FOREGROUND;
+ if (drawBackground) event.detail |= SWT.BACKGROUND;
+ if (drawSelection) event.detail |= SWT.SELECTED;
+ event.x = itemX;
+ event.y = itemY;
+ event.width = contentWidth;
+ event.height = itemHeight;
+ sendEvent (SWT.PaintItem, event);
+ gc.dispose ();
+
+ context.restoreGraphicsState();
+ }
+}
+
+void drawWithExpansionFrame_inView (int /*long*/ id, int /*long*/ sel, NSRect cellFrame, int /*long*/ view) {
+ drawExpansion = true;
+ super.drawWithExpansionFrame_inView(id, sel, cellFrame, view);
+ drawExpansion = false;
+}
+
+void expandItem_expandChildren (int /*long*/ id, int /*long*/ sel, int /*long*/ itemID, boolean children) {
+ TreeItem item = (TreeItem)display.getWidget(itemID);
+ if (!ignoreExpand) item.sendExpand (true, children);
+ ignoreExpand = true;
+ super.expandItem_expandChildren (id, sel, itemID, children);
+ ignoreExpand = false;
+ if (isDisposed() || item.isDisposed()) return;
+ if (!children) {
+ ignoreExpand = true;
+ TreeItem[] items = item.items;
+ for (int i = 0; i < item.itemCount; i++) {
+ if (items[i] != null) items[i].updateExpanded ();
+ }
+ ignoreExpand = false;
+ }
+ setScrollWidth (false, item.items, true);
+}
+
+NSRect expansionFrameWithFrame_inView(int /*long*/ id, int /*long*/ sel, NSRect cellRect, int /*long*/ view) {
+ if (toolTipText == null) {
+ NSRect rect = super.expansionFrameWithFrame_inView(id, sel, cellRect, view);
+ NSCell cell = new NSCell(id);
+ if (rect.width != 0 && rect.height != 0) {
+ if (hooks(SWT.MeasureItem)) {
+ NSSize cellSize = cell.cellSize();
+ cellRect.width = cellSize.width;
+ return cellRect;
+ }
+ } else {
+ NSRect expansionRect;
+ if (hooks(SWT.MeasureItem)) {
+ expansionRect = cellRect;
+ NSSize cellSize = cell.cellSize();
+ expansionRect.width = cellSize.width;
+ } else {
+ expansionRect = cell.titleRectForBounds(cellRect);
+ NSSize cellSize = super.cellSize(id, OS.sel_cellSize);
+ expansionRect.width = cellSize.width;
+ }
+ NSRect contentRect = scrollView.contentView().bounds();
+ OS.NSIntersectionRect(contentRect, expansionRect, contentRect);
+ if (!OS.NSEqualRects(expansionRect, contentRect)) {
+ return expansionRect;
+ }
+ }
+ return rect;
+ }
+ return new NSRect();
+}
+
+Widget findTooltip (NSPoint pt) {
+ NSTableView widget = (NSTableView)view;
+ NSTableHeaderView headerView = widget.headerView();
+ if (headerView != null) {
+ pt = headerView.convertPoint_fromView_ (pt, null);
+ int /*long*/ index = headerView.columnAtPoint (pt);
+ if (index != -1) {
+ NSArray nsColumns = widget.tableColumns ();
+ id nsColumn = nsColumns.objectAtIndex (index);
+ for (int i = 0; i < columnCount; i++) {
+ TreeColumn column = columns [i];
+ if (column.nsColumn.id == nsColumn.id) {
+ return column;
+ }
+ }
+ }
+ }
+ return super.findTooltip (pt);
+}
+
+int getCheckColumnWidth () {
+ return (int)checkColumn.dataCell().cellSize().width;
+}
+
+public Rectangle getClientArea () {
+ checkWidget ();
+ Rectangle rect = super.getClientArea ();
+ NSTableHeaderView headerView = ((NSTableView) view).headerView ();
+ if (headerView != null) {
+ int height = (int) headerView.bounds ().height;
+ rect.y -= height;
+ rect.height += height;
+ }
+ return rect;
+}
+
+TreeColumn getColumn (id id) {
+ for (int i = 0; i < columnCount; i++) {
+ if (columns[i].nsColumn.id == id.id) {
+ return columns[i];
+ }
+ }
+ return null;
+}
+
+/**
+ * Returns the column at the given, zero-relative index in the
+ * receiver. Throws an exception if the index is out of range.
+ * Columns are returned in the order that they were created.
+ * If no <code>TreeColumn</code>s were created by the programmer,
+ * this method will throw <code>ERROR_INVALID_RANGE</code> despite
+ * the fact that a single column of data may be visible in the tree.
+ * This occurs when the programmer uses the tree like a list, adding
+ * items but never creating a column.
+ *
+ * @param index the index of the column to return
+ * @return the column at the given index
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 Tree#getColumnOrder()
+ * @see Tree#setColumnOrder(int[])
+ * @see TreeColumn#getMoveable()
+ * @see TreeColumn#setMoveable(boolean)
+ * @see SWT#Move
+ *
+ * @since 3.1
+ */
+public TreeColumn getColumn (int index) {
+ checkWidget ();
+ if (!(0 <=index && index < columnCount)) error (SWT.ERROR_INVALID_RANGE);
+ return columns [index];
+}
+
+/**
+ * Returns the number of columns contained in the receiver.
+ * If no <code>TreeColumn</code>s were created by the programmer,
+ * this value is zero, despite the fact that visually, one column
+ * of items may be visible. This occurs when the programmer uses
+ * the tree like a list, adding items but never creating a column.
+ *
+ * @return the number of columns
+ *
+ * @exception SWTException <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.1
+ */
+public int getColumnCount () {
+ checkWidget ();
+ return columnCount;
+}
+
+/**
+ * Returns an array of zero-relative integers that map
+ * the creation order of the receiver's items to the
+ * order in which they are currently being displayed.
+ * <p>
+ * Specifically, the indices of the returned array represent
+ * the current visual order of the items, and the contents
+ * of the array represent the creation order of the items.
+ * </p><p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ *
+ * @return the current visual order of the receiver's items
+ *
+ * @exception SWTException <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 Tree#setColumnOrder(int[])
+ * @see TreeColumn#getMoveable()
+ * @see TreeColumn#setMoveable(boolean)
+ * @see SWT#Move
+ *
+ * @since 3.2
+ */
+public int [] getColumnOrder () {
+ checkWidget ();
+ int [] order = new int [columnCount];
+ for (int i = 0; i < columnCount; i++) {
+ TreeColumn column = columns [i];
+ int index = indexOf (column.nsColumn);
+ if ((style & SWT.CHECK) != 0) index -= 1;
+ order [index] = i;
+ }
+ return order;
+}
+
+/**
+ * Returns an array of <code>TreeColumn</code>s which are the
+ * columns in the receiver. Columns are returned in the order
+ * that they were created. If no <code>TreeColumn</code>s were
+ * created by the programmer, the array is empty, despite the fact
+ * that visually, one column of items may be visible. This occurs
+ * when the programmer uses the tree like a list, adding items but
+ * never creating a column.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ *
+ * @return the items in the receiver
+ *
+ * @exception SWTException <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 Tree#getColumnOrder()
+ * @see Tree#setColumnOrder(int[])
+ * @see TreeColumn#getMoveable()
+ * @see TreeColumn#setMoveable(boolean)
+ * @see SWT#Move
+ *
+ * @since 3.1
+ */
+public TreeColumn [] getColumns () {
+ checkWidget ();
+ TreeColumn [] result = new TreeColumn [columnCount];
+ System.arraycopy (columns, 0, result, 0, columnCount);
+ return result;
+}
+
+/**
+ * Returns the width in pixels of a grid line.
+ *
+ * @return the width of a grid line in pixels
+ *
+ * @exception SWTException <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.1
+ */
+public int getGridLineWidth () {
+ checkWidget ();
+ return 0;
+}
+
+/**
+ * Returns the height of the receiver's header
+ *
+ * @return the height of the header or zero if the header is not visible
+ *
+ * @exception SWTException <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.1
+ */
+public int getHeaderHeight () {
+ checkWidget ();
+ NSTableHeaderView headerView = ((NSOutlineView) view).headerView ();
+ if (headerView == null) return 0;
+ return (int) headerView.bounds ().height;
+}
+
+/**
+ * Returns <code>true</code> if the receiver's header is visible,
+ * and <code>false</code> otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ * </p>
+ *
+ * @return the receiver's header's visibility state
+ *
+ * @exception SWTException <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.1
+ */
+public boolean getHeaderVisible () {
+ checkWidget ();
+ return ((NSOutlineView) view).headerView () != null;
+}
+
+/**
+ * Returns the item at the given, zero-relative index in the
+ * receiver. Throws an exception if the index is out of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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.1
+ */
+public TreeItem getItem (int index) {
+ checkWidget ();
+ int count = getItemCount ();
+ if (index < 0 || index >= count) error (SWT.ERROR_INVALID_RANGE);
+ return _getItem (null, index, true);
+}
+
+/**
+ * Returns the item at the given point in the receiver
+ * or null if no such item exists. The point is in the
+ * coordinate system of the receiver.
+ * <p>
+ * The item that is returned represents an item that could be selected by the user.
+ * For example, if selection only occurs in items in the first column, then null is
+ * returned if the point is outside of the item.
+ * Note that the SWT.FULL_SELECTION style hint, which specifies the selection policy,
+ * determines the extent of the selection.
+ * </p>
+ *
+ * @param point the point used to locate the item
+ * @return the item at the given point, or null if the point is not in a selectable item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception SWTException <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 TreeItem getItem (Point point) {
+ checkWidget ();
+ if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
+ checkItems ();
+ NSOutlineView widget = (NSOutlineView)view;
+ NSPoint pt = new NSPoint();
+ pt.x = point.x;
+ pt.y = point.y;
+ int row = (int)/*64*/widget.rowAtPoint(pt);
+ if (row == -1) return null;
+ NSRect rect = widget.frameOfOutlineCellAtRow(row);
+ if (OS.NSPointInRect(pt, rect)) return null;
+ id id = widget.itemAtRow(row);
+ Widget item = display.getWidget (id.id);
+ if (item != null && item instanceof TreeItem) {
+ return (TreeItem)item;
+ }
+ return null;
+}
+
+/**
+ * Returns the number of items contained in the receiver
+ * that are direct item children of the receiver. The
+ * number that is returned is the number of roots in the
+ * tree.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException <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 getItemCount () {
+ checkWidget ();
+ return itemCount;
+}
+
+int getItemCount (TreeItem item) {
+ return item == null ? itemCount : item.itemCount;
+}
+
+/**
+ * Returns the height of the area which would be used to
+ * display <em>one</em> of the items in the tree.
+ *
+ * @return the height of one item
+ *
+ * @exception SWTException <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 getItemHeight () {
+ checkWidget ();
+ return (int)((NSOutlineView) view).rowHeight () + CELL_GAP;
+}
+
+/**
+ * Returns a (possibly empty) array of items contained in the
+ * receiver that are direct item children of the receiver. These
+ * are the roots of the tree.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ *
+ * @return the items
+ *
+ * @exception SWTException <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 TreeItem [] getItems () {
+ checkWidget ();
+ TreeItem [] result = new TreeItem [itemCount];
+ for (int i=0; i<itemCount; i++) {
+ result [i] = _getItem (null, i, true);
+ }
+ return result;
+}
+
+/**
+ * Returns <code>true</code> if the receiver's lines are visible,
+ * and <code>false</code> otherwise. Note that some platforms draw
+ * grid lines while others may draw alternating row colors.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ * </p>
+ *
+ * @return the visibility state of the lines
+ *
+ * @exception SWTException <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.1
+ */
+public boolean getLinesVisible () {
+ checkWidget ();
+ return ((NSOutlineView) view).usesAlternatingRowBackgroundColors ();
+}
+
+/**
+ * Returns the receiver's parent item, which must be a
+ * <code>TreeItem</code> or null when the receiver is a
+ * root.
+ *
+ * @return the receiver's parent item
+ *
+ * @exception SWTException <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 TreeItem getParentItem () {
+ checkWidget ();
+ return null;
+}
+
+/**
+ * Returns an array of <code>TreeItem</code>s that are currently
+ * selected in the receiver. The order of the items is unspecified.
+ * An empty array indicates that no items are selected.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its selection, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ * @return an array representing the selection
+ *
+ * @exception SWTException <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 TreeItem [] getSelection () {
+ checkWidget ();
+ NSOutlineView widget = (NSOutlineView) view;
+ if (widget.numberOfSelectedRows () == 0) {
+ return new TreeItem [0];
+ }
+ NSIndexSet selection = widget.selectedRowIndexes ();
+ int count = (int)/*64*/selection.count ();
+ int /*long*/ [] indexBuffer = new int /*long*/ [count];
+ selection.getIndexes (indexBuffer, count, 0);
+ TreeItem [] result = new TreeItem [count];
+ for (int i=0; i<count; i++) {
+ id id = widget.itemAtRow (indexBuffer [i]);
+ Widget item = display.getWidget (id.id);
+ if (item != null && item instanceof TreeItem) {
+ result[i] = (TreeItem) item;
+ }
+ }
+ return result;
+}
+
+/**
+ * Returns the number of selected items contained in the receiver.
+ *
+ * @return the number of selected items
+ *
+ * @exception SWTException <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 getSelectionCount () {
+ checkWidget ();
+ return (int)/*64*/((NSOutlineView) view).numberOfSelectedRows ();
+}
+
+/**
+ * Returns the column which shows the sort indicator for
+ * the receiver. The value may be null if no column shows
+ * the sort indicator.
+ *
+ * @return the sort indicator
+ *
+ * @exception SWTException <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 #setSortColumn(TreeColumn)
+ *
+ * @since 3.2
+ */
+public TreeColumn getSortColumn () {
+ checkWidget ();
+ return sortColumn;
+}
+
+/**
+ * Returns the direction of the sort indicator for the receiver.
+ * The value will be one of <code>UP</code>, <code>DOWN</code>
+ * or <code>NONE</code>.
+ *
+ * @return the sort direction
+ *
+ * @exception SWTException <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 #setSortDirection(int)
+ *
+ * @since 3.2
+ */
+public int getSortDirection () {
+ checkWidget ();
+ return sortDirection;
+}
+
+/**
+ * Returns the item which is currently at the top of the receiver.
+ * This item can change when items are expanded, collapsed, scrolled
+ * or new items are added or removed.
+ *
+ * @return the item at the top of the receiver
+ *
+ * @exception SWTException <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 2.1
+ */
+public TreeItem getTopItem () {
+ checkWidget ();
+ //TODO - partial item at the top
+ NSRect rect = scrollView.documentVisibleRect ();
+ NSPoint point = new NSPoint ();
+ point.x = rect.x;
+ point.y = rect.y;
+ NSOutlineView outlineView = (NSOutlineView)view;
+ int /*long*/ index = outlineView.rowAtPoint (point);
+ if (index == -1) return null; /* empty */
+ id item = outlineView.itemAtRow (index);
+ return (TreeItem)display.getWidget (item.id);
+}
+
+void highlightSelectionInClipRect(int /*long*/ id, int /*long*/ sel, int /*long*/ rect) {
+ if (hooks (SWT.EraseItem)) return;
+ if ((style & SWT.HIDE_SELECTION) != 0 && !hasFocus()) return;
+ NSRect clipRect = new NSRect ();
+ OS.memmove (clipRect, rect, NSRect.sizeof);
+ callSuper (id, sel, clipRect);
+}
+
+int /*long*/ hitTestForEvent (int /*long*/ id, int /*long*/ sel, int /*long*/ event, NSRect rect, int /*long*/ controlView) {
+ /*
+ * For some reason, the cell class needs to implement hitTestForEvent:inRect:ofView:,
+ * otherwise the double action selector is not called properly.
+ */
+ return callSuper(id, sel, event, rect, controlView);
+}
+
+int /*long*/ image (int /*long*/ id, int /*long*/ sel) {
+ int /*long*/ [] image = new int /*long*/ [1];
+ OS.object_getInstanceVariable(id, Display.SWT_IMAGE, image);
+ return image[0];
+}
+
+NSRect imageRectForBounds (int /*long*/ id, int /*long*/ sel, NSRect cellFrame) {
+ NSImage image = new NSCell(id).image();
+ if (image != null) {
+ cellFrame.x += IMAGE_GAP;
+ cellFrame.width = imageBounds.width;
+ cellFrame.height = imageBounds.height;
+ }
+ return cellFrame;
+}
+
+int indexOf (NSTableColumn column) {
+ return (int)/*64*/((NSTableView)view).tableColumns().indexOfObjectIdenticalTo(column);
+}
+
+/**
+ * Searches the receiver's list starting at the first column
+ * (index 0) until a column is found that is equal to the
+ * argument, and returns the index of that column. If no column
+ * is found, returns -1.
+ *
+ * @param column the search column
+ * @return the index of the column
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the column is null</li>
+ * </ul>
+ * @exception SWTException <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.1
+ */
+public int indexOf (TreeColumn column) {
+ checkWidget ();
+ if (column == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (column.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ for (int i=0; i<columnCount; i++) {
+ if (columns [i] == column) return i;
+ }
+ return -1;
+}
+
+/**
+ * Searches the receiver's list starting at the first item
+ * (index 0) until an item is found that is equal to the
+ * argument, and returns the index of that item. If no item
+ * is found, returns -1.
+ *
+ * @param item the search item
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.1
+ */
+public int indexOf (TreeItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (item.parentItem != null) return -1;
+ for (int i = 0; i < itemCount; i++) {
+ if (item == items[i]) return i;
+ }
+ return -1;
+}
+
+boolean isTrim (NSView view) {
+ if (super.isTrim (view)) return true;
+ return view.id == headerView.id;
+}
+
+int /*long*/ menuForEvent(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (id != headerView.id) {
+ /*
+ * Feature in Cocoa: Table views do not change the selection when the user
+ * right-clicks or control-clicks on an NSTableView or its subclasses. Fix is to select the
+ * clicked-on row ourselves.
+ */
+ NSEvent event = new NSEvent(theEvent);
+ NSOutlineView tree = (NSOutlineView)view;
+
+ // get the current selections for the outline view.
+ NSIndexSet selectedRowIndexes = tree.selectedRowIndexes();
+
+ // select the row that was clicked before showing the menu for the event
+ NSPoint mousePoint = view.convertPoint_fromView_(event.locationInWindow(), null);
+ int /*long*/ row = tree.rowAtPoint(mousePoint);
+
+ // figure out if the row that was just clicked on is currently selected
+ if (selectedRowIndexes.containsIndex(row) == false) {
+ NSIndexSet set = (NSIndexSet)new NSIndexSet().alloc();
+ set = set.initWithIndex(row);
+ tree.selectRowIndexes (set, false);
+ set.release();
+ }
+ // else that row is currently selected, so don't change anything.
+ }
+
+ return super.menuForEvent(id, sel, theEvent);
+}
+
+void mouseDown (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ if (headerView != null && id == headerView.id) {
+ NSTableView widget = (NSTableView)view;
+ widget.setAllowsColumnReordering(false);
+ NSPoint pt = headerView.convertPoint_fromView_(new NSEvent(theEvent).locationInWindow(), null);
+ int /*long*/ nsIndex = headerView.columnAtPoint(pt);
+ if (nsIndex != -1) {
+ id nsColumn = widget.tableColumns().objectAtIndex(nsIndex);
+ for (int i = 0; i < columnCount; i++) {
+ if (columns[i].nsColumn.id == nsColumn.id) {
+ widget.setAllowsColumnReordering(columns[i].movable);
+ break;
+ }
+ }
+ }
+ }
+ else if (id == view.id) {
+ // Bug/feature in Cocoa: If the tree has a context menu we just set it visible instead of returning
+ // it from menuForEvent:. This has the side effect, however, of sending control-click to the NSTableView,
+ // which is interpreted as a single click that clears the selection. Fix is to ignore control-click,
+ NSEvent event = new NSEvent(theEvent);
+ if ((event.modifierFlags() & OS.NSControlKeyMask) != 0) return;
+ }
+ super.mouseDown(id, sel, theEvent);
+}
+
+/*
+ * Feature in Cocoa. If a checkbox is in multi-state mode, nextState cycles
+ * from off to mixed to on and back to off again. This will cause the on state
+ * to momentarily appear while clicking on the checkbox. To avoid this,
+ * override [NSCell nextState] to go directly to the desired state.
+ */
+int /*long*/ nextState (int /*long*/ id, int /*long*/ sel) {
+ NSOutlineView outlineView = (NSOutlineView)view;
+ int index = (int)/*64*/outlineView.selectedRow ();
+ TreeItem item = (TreeItem)display.getWidget (outlineView.itemAtRow (index).id);
+ if (item.grayed) {
+ return item.checked ? OS.NSOffState : OS.NSMixedState;
+ }
+ return item.checked ? OS.NSOffState : OS.NSOnState;
+}
+
+int /*long*/ outlineView_child_ofItem (int /*long*/ id, int /*long*/ sel, int /*long*/ outlineView, int /*long*/ index, int /*long*/ itemID) {
+ TreeItem parent = (TreeItem) display.getWidget (itemID);
+ TreeItem item = _getItem (parent, (int)/*64*/index, true);
+ return item.handle.id;
+}
+
+void outlineView_didClickTableColumn (int /*long*/ id, int /*long*/ sel, int /*long*/ outlineView, int /*long*/ tableColumn) {
+ TreeColumn column = getColumn (new id (tableColumn));
+ if (column == null) return; /* either CHECK column or firstColumn in 0-column Tree */
+ column.postEvent (SWT.Selection);
+}
+
+int /*long*/ outlineView_objectValueForTableColumn_byItem (int /*long*/ id, int /*long*/ sel, int /*long*/ outlineView, int /*long*/ tableColumn, int /*long*/ itemID) {
+ TreeItem item = (TreeItem) display.getWidget (itemID);
+ checkData (item);
+ if (checkColumn != null && tableColumn == checkColumn.id) {
+ NSNumber value;
+ if (item.checked && item.grayed) {
+ value = NSNumber.numberWithInt (OS.NSMixedState);
+ } else {
+ value = NSNumber.numberWithInt (item.checked ? OS.NSOnState : OS.NSOffState);
+ }
+ return value.id;
+ }
+ for (int i=0; i<columnCount; i++) {
+ if (columns [i].nsColumn.id == tableColumn) {
+ return item.createString (i).id;
+ }
+ }
+ return item.createString (0).id;
+}
+
+boolean outlineView_isItemExpandable (int /*long*/ id, int /*long*/ sel, int /*long*/ outlineView, int /*long*/ item) {
+ if (item == 0) return true;
+ return ((TreeItem) display.getWidget (item)).itemCount != 0;
+}
+
+int /*long*/ outlineView_numberOfChildrenOfItem (int /*long*/ id, int /*long*/ sel, int /*long*/ outlineView, int /*long*/ item) {
+ if (item == 0) return itemCount;
+ return ((TreeItem) display.getWidget (item)).itemCount;
+}
+
+void outlineView_willDisplayCell_forTableColumn_item (int /*long*/ id, int /*long*/ sel, int /*long*/ outlineView, int /*long*/ cell, int /*long*/ tableColumn, int /*long*/ itemID) {
+ if (checkColumn != null && tableColumn == checkColumn.id) return;
+ TreeItem item = (TreeItem) display.getWidget(itemID);
+ int index = 0;
+ for (int i=0; i<columnCount; i++) {
+ if (columns [i].nsColumn.id == tableColumn) {
+ index = i;
+ break;
+ }
+ }
+ NSTextFieldCell textCell = new NSTextFieldCell (cell);
+ OS.object_setInstanceVariable(cell, Display.SWT_ROW, itemID);
+ OS.object_setInstanceVariable(cell, Display.SWT_COLUMN, tableColumn);
+ Image image = index == 0 ? item.image : (item.images == null ? null : item.images [index]);
+ textCell.setImage (image != null ? image.handle : null);
+ NSColor color;
+ if (textCell.isEnabled()) {
+ if (textCell.isHighlighted ()) {
+ color = NSColor.selectedControlTextColor();
+ } else {
+ Color foreground = item.cellForeground != null ? item.cellForeground [index] : null;
+ if (foreground == null) foreground = item.foreground;
+ if (foreground == null) foreground = getForegroundColor ();
+ color = NSColor.colorWithDeviceRed (foreground.handle [0], foreground.handle [1], foreground.handle [2], 1);
+ }
+ } else {
+ color = NSColor.disabledControlTextColor();
+ }
+ int alignment = OS.NSLeftTextAlignment;
+ if (columnCount > 0) {
+ int style = columns [index].style;
+ if ((style & SWT.CENTER) != 0) {
+ alignment = OS.NSCenterTextAlignment;
+ } else if ((style & SWT.RIGHT) != 0) {
+ alignment = OS.NSRightTextAlignment;
+ }
+ }
+ Font font = item.cellFont != null ? item.cellFont [index] : null;
+ if (font == null) font = item.font;
+ if (font == null) font = this.font;
+ if (font == null) font = defaultFont ();
+ if (font.extraTraits != 0) {
+ NSMutableDictionary dict = ((NSMutableDictionary)new NSMutableDictionary().alloc()).initWithCapacity(5);
+ dict.setObject (color, OS.NSForegroundColorAttributeName);
+ dict.setObject (font.handle, OS.NSFontAttributeName);
+ addTraits(dict, font);
+ NSMutableParagraphStyle paragraphStyle = (NSMutableParagraphStyle)new NSMutableParagraphStyle ().alloc ().init ();
+ paragraphStyle.setLineBreakMode (OS.NSLineBreakByClipping);
+ paragraphStyle.setAlignment (alignment);
+ dict.setObject (paragraphStyle, OS.NSParagraphStyleAttributeName);
+ paragraphStyle.release ();
+ NSAttributedString attribStr = ((NSAttributedString) new NSAttributedString ().alloc ()).initWithString (textCell.title(), dict);
+ textCell.setAttributedStringValue(attribStr);
+ attribStr.release();
+ dict.release();
+ } else {
+ textCell.setFont(font.handle);
+ textCell.setTextColor(color);
+ textCell.setAlignment (alignment);
+ }
+}
+
+void outlineViewColumnDidMove (int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+ NSNotification notification = new NSNotification (aNotification);
+ NSDictionary userInfo = notification.userInfo ();
+ id nsOldIndex = userInfo.valueForKey (NSString.stringWith ("NSOldColumn")); //$NON-NLS-1$
+ id nsNewIndex = userInfo.valueForKey (NSString.stringWith ("NSNewColumn")); //$NON-NLS-1$
+ int oldIndex = new NSNumber (nsOldIndex).intValue ();
+ int newIndex = new NSNumber (nsNewIndex).intValue ();
+ int startIndex = Math.min (oldIndex, newIndex);
+ int endIndex = Math.max (oldIndex, newIndex);
+ NSOutlineView outlineView = (NSOutlineView)view;
+ NSArray nsColumns = outlineView.tableColumns ();
+ for (int i = startIndex; i <= endIndex; i++) {
+ id columnId = nsColumns.objectAtIndex (i);
+ TreeColumn column = getColumn (columnId);
+ if (column != null) {
+ column.sendEvent (SWT.Move);
+ if (isDisposed ()) return;
+ }
+ }
+}
+
+void outlineViewColumnDidResize (int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+ NSNotification notification = new NSNotification (aNotification);
+ NSDictionary userInfo = notification.userInfo ();
+ id columnId = userInfo.valueForKey (NSString.stringWith ("NSTableColumn")); //$NON-NLS-1$
+ TreeColumn column = getColumn (columnId);
+ if (column == null) return; /* either CHECK column or firstColumn in 0-column Tree */
+
+ column.sendEvent (SWT.Resize);
+ if (isDisposed ()) return;
+
+ NSOutlineView outlineView = (NSOutlineView)view;
+ int index = indexOf (column.nsColumn);
+ if (index == -1) return; /* column was disposed in Resize callback */
+
+ NSArray nsColumns = outlineView.tableColumns ();
+ int columnCount = (int)/*64*/outlineView.numberOfColumns ();
+ for (int i = index + 1; i < columnCount; i++) {
+ columnId = nsColumns.objectAtIndex (i);
+ column = getColumn (columnId);
+ if (column != null) {
+ column.sendEvent (SWT.Move);
+ if (isDisposed ()) return;
+ }
+ }
+}
+
+void outlineViewSelectionDidChange (int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+ if (ignoreSelect) return;
+ NSOutlineView widget = (NSOutlineView) view;
+ int row = (int)/*64*/widget.selectedRow ();
+ if (row == -1)
+ postEvent (SWT.Selection);
+ else {
+ id _id = widget.itemAtRow (row);
+ TreeItem item = (TreeItem) display.getWidget (_id.id);
+ Event event = new Event ();
+ event.item = item;
+ event.index = row;
+ postEvent (SWT.Selection, event);
+ }
+}
+
+void outlineView_setObjectValue_forTableColumn_byItem (int /*long*/ id, int /*long*/ sel, int /*long*/ outlineView, int /*long*/ object, int /*long*/ tableColumn, int /*long*/ itemID) {
+ if (checkColumn != null && tableColumn == checkColumn.id) {
+ TreeItem item = (TreeItem) display.getWidget (itemID);
+ item.checked = !item.checked;
+ Event event = new Event ();
+ event.detail = SWT.CHECK;
+ event.item = item;
+ postEvent (SWT.Selection, event);
+ item.redraw (-1);
+ }
+}
+
+boolean outlineView_writeItems_toPasteboard(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1, int /*long*/ arg2) {
+ return sendMouseEvent(NSApplication.sharedApplication().currentEvent(), SWT.DragDetect, true);
+}
+
+void register () {
+ super.register ();
+ display.addWidget (headerView, this);
+ display.addWidget (dataCell, this);
+ if (buttonCell != null) display.addWidget (buttonCell, this);
+}
+
+void releaseChildren (boolean destroy) {
+ for (int i=0; i<items.length; i++) {
+ TreeItem item = items [i];
+ if (item != null && !item.isDisposed ()) {
+ item.release (false);
+ }
+ }
+ items = null;
+ if (columns != null) {
+ for (int i=0; i<columnCount; i++) {
+ TreeColumn column = columns [i];
+ if (column != null && !column.isDisposed ()) {
+ column.release (false);
+ }
+ }
+ columns = null;
+ }
+ super.releaseChildren (destroy);
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (headerView != null) headerView.release ();
+ headerView = null;
+ if (firstColumn != null) firstColumn.release ();
+ firstColumn = null;
+ if (checkColumn != null) checkColumn.release ();
+ checkColumn = null;
+ if (dataCell != null) dataCell.release ();
+ dataCell = null;
+ if (buttonCell != null) buttonCell.release();
+ buttonCell = null;
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ sortColumn = null;
+}
+
+void reloadItem (TreeItem item, boolean recurse) {
+ if (getDrawing()) {
+ NSOutlineView widget = (NSOutlineView)view;
+ TreeItem[] selectedItems = getSelection ();
+ if (item != null) {
+ widget.reloadItem (item.handle, recurse);
+ } else {
+ widget.reloadData ();
+ }
+ selectItems (selectedItems, true);
+ } else {
+ reloadPending = true;
+ }
+}
+
+/**
+ * Removes all of the items from the receiver.
+ *
+ * @exception SWTException <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 removeAll () {
+ checkWidget ();
+ for (int i=0; i<items.length; i++) {
+ TreeItem item = items [i];
+ if (item != null && !item.isDisposed ()) item.release (false);
+ }
+ items = new TreeItem [4];
+ itemCount = 0;
+ imageBounds = null;
+ ((NSOutlineView) view).reloadData ();
+ setScrollWidth ();
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the user changes the receiver's selection.
+ *
+ * @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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when items in the receiver are expanded or collapsed.
+ *
+ * @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 SWTException <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 TreeListener
+ * @see #addTreeListener
+ */
+public void removeTreeListener (TreeListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Expand, listener);
+ eventTable.unhook (SWT.Collapse, listener);
+}
+
+void setImage (int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ OS.object_setInstanceVariable(id, Display.SWT_IMAGE, arg0);
+}
+
+/**
+ * Display a mark indicating the point at which an item will be inserted.
+ * The drop insert item has a visual hint to show where a dragged item
+ * will be inserted when dropped on the tree.
+ *
+ * @param item the insert item. Null will clear the insertion mark.
+ * @param before true places the insert mark above 'item'. false places
+ * the insert mark below 'item'.
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setInsertMark (TreeItem item, boolean before) {
+ checkWidget ();
+ if (item != null && item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ TreeItem oldMark = insertItem;
+ insertItem = item;
+ insertBefore = before;
+ if (oldMark != null && !oldMark.isDisposed()) oldMark.redraw (-1);
+ if (item != null) item.redraw (-1);
+}
+
+/**
+ * Selects all of the items in the receiver.
+ * <p>
+ * If the receiver is single-select, do nothing.
+ * </p>
+ *
+ * @exception SWTException <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 selectAll () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) return;
+ checkItems ();
+ NSOutlineView widget = (NSOutlineView) view;
+ ignoreSelect = true;
+ widget.selectAll (null);
+ ignoreSelect = false;
+}
+
+/**
+ * Selects an item in the receiver. If the item was already
+ * selected, it remains selected.
+ *
+ * @param item the item to be selected
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.4
+ */
+public void select (TreeItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ checkItems ();
+ showItem (item);
+ NSOutlineView outlineView = (NSOutlineView) view;
+ int /*long*/ row = outlineView.rowForItem (item.handle);
+ NSIndexSet set = (NSIndexSet)new NSIndexSet().alloc();
+ set = set.initWithIndex(row);
+ ignoreSelect = true;
+ outlineView.selectRowIndexes (set, false);
+ ignoreSelect = false;
+ set.release();
+}
+
+void sendDoubleSelection() {
+ NSOutlineView outlineView = (NSOutlineView)view;
+ int rowIndex = (int)/*64*/outlineView.clickedRow ();
+ if (rowIndex != -1) {
+ if ((style & SWT.CHECK) != 0) {
+ NSArray columns = outlineView.tableColumns ();
+ int columnIndex = (int)/*64*/outlineView.clickedColumn ();
+ id column = columns.objectAtIndex (columnIndex);
+ if (column.id == checkColumn.id) return;
+ }
+ TreeItem item = (TreeItem) display.getWidget (outlineView.itemAtRow (rowIndex).id);
+ Event event = new Event ();
+ event.item = item;
+ postEvent (SWT.DefaultSelection, event);
+ }
+}
+
+boolean sendKeyEvent (NSEvent nsEvent, int type) {
+ boolean result = super.sendKeyEvent (nsEvent, type);
+ if (!result) return result;
+ if (type != SWT.KeyDown) return result;
+ short keyCode = nsEvent.keyCode ();
+ switch (keyCode) {
+ case 76: /* KP Enter */
+ case 36: { /* Return */
+ postEvent (SWT.DefaultSelection);
+ break;
+ }
+ }
+ return result;
+}
+
+void sendMeasureItem (TreeItem item, int columnIndex, NSSize size) {
+ NSOutlineView widget = (NSOutlineView)this.view;
+ int contentWidth = (int)Math.ceil (size.width);
+ NSSize spacing = widget.intercellSpacing();
+ int itemHeight = (int)Math.ceil (widget.rowHeight() + spacing.height);
+ GCData data = new GCData ();
+ data.paintRect = widget.frame ();
+ GC gc = GC.cocoa_new (this, data);
+ gc.setFont (item.getFont (columnIndex));
+ Event event = new Event ();
+ event.item = item;
+ event.gc = gc;
+ event.index = columnIndex;
+ event.width = contentWidth;
+ event.height = itemHeight;
+ sendEvent (SWT.MeasureItem, event);
+ gc.dispose ();
+ if (!isDisposed () && !item.isDisposed ()) {
+ size.width = event.width;
+ size.height = event.height;
+ if (itemHeight < event.height) {
+ widget.setRowHeight (event.height);
+ }
+ if (contentWidth != event.width) {
+ if (columnCount == 0 && columnIndex == 0) {
+ item.width = event.width;
+ item.width += widget.indentationPerLevel () * (1 + widget.levelForItem (item.handle));
+ if (setScrollWidth (item)) {
+ widget.setNeedsDisplay(true);
+ }
+ }
+ }
+ }
+}
+
+void selectItems (TreeItem[] items, boolean ignoreDisposed) {
+ NSOutlineView outlineView = (NSOutlineView) view;
+ NSMutableIndexSet set = (NSMutableIndexSet) new NSMutableIndexSet ().alloc ().init ();
+ int length = items.length;
+ for (int i=0; i<length; i++) {
+ if (items [i] != null) {
+ if (items [i].isDisposed ()) {
+ if (ignoreDisposed) continue;
+ error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ TreeItem item = items [i];
+ if (!ignoreDisposed) showItem (items [i], false);
+ set.addIndex (outlineView.rowForItem (item.handle));
+ }
+ }
+ ignoreSelect = true;
+ outlineView.selectRowIndexes (set, false);
+ ignoreSelect = false;
+ set.release();
+}
+
+NSRect titleRectForBounds (int /*long*/ id, int /*long*/ sel, NSRect cellFrame) {
+ NSImage image = new NSCell(id).image();
+ if (image != null) {
+ int imageWidth = imageBounds.width + IMAGE_GAP;
+ cellFrame.x += imageWidth;
+ cellFrame.width -= imageWidth;
+ }
+ return cellFrame;
+}
+
+void updateBackground () {
+ NSColor nsColor = null;
+ if (backgroundImage != null) {
+ nsColor = NSColor.colorWithPatternImage(backgroundImage.handle);
+ } else if (background != null) {
+ nsColor = NSColor.colorWithDeviceRed(background[0], background[1], background[2], background[3]);
+ }
+ ((NSOutlineView) view).setBackgroundColor (nsColor);
+}
+
+/**
+ * Sets the order that the items in the receiver should
+ * be displayed in to the given argument which is described
+ * in terms of the zero-relative ordering of when the items
+ * were added.
+ *
+ * @param order the new order to display the items
+ *
+ * @exception SWTException <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>
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item order is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the item order is not the same length as the number of items</li>
+ * </ul>
+ *
+ * @see Tree#getColumnOrder()
+ * @see TreeColumn#getMoveable()
+ * @see TreeColumn#setMoveable(boolean)
+ * @see SWT#Move
+ *
+ * @since 3.2
+ */
+public void setColumnOrder (int [] order) {
+ checkWidget ();
+ if (order == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (columnCount == 0) {
+ if (order.length != 0) error (SWT.ERROR_INVALID_ARGUMENT);
+ return;
+ }
+ if (order.length != columnCount) error (SWT.ERROR_INVALID_ARGUMENT);
+ int [] oldOrder = getColumnOrder ();
+ boolean reorder = false;
+ boolean [] seen = new boolean [columnCount];
+ for (int i=0; i<order.length; i++) {
+ int index = order [i];
+ if (index < 0 || index >= columnCount) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (seen [index]) error (SWT.ERROR_INVALID_ARGUMENT);
+ seen [index] = true;
+ if (order [i] != oldOrder [i]) reorder = true;
+ }
+ if (reorder) {
+ NSOutlineView outlineView = (NSOutlineView)view;
+ int [] oldX = new int [oldOrder.length];
+ int check = (style & SWT.CHECK) != 0 ? 1 : 0;
+ for (int i=0; i<oldOrder.length; i++) {
+ int index = oldOrder[i];
+ oldX [index] = (int)outlineView.rectOfColumn (i + check).x;
+ }
+ int [] newX = new int [order.length];
+ for (int i=0; i<order.length; i++) {
+ int index = order [i];
+ TreeColumn column = columns[index];
+ int oldIndex = indexOf (column.nsColumn);
+ int newIndex = i + check;
+ outlineView.moveColumn (oldIndex, newIndex);
+ newX [index] = (int)outlineView.rectOfColumn (newIndex).x;
+ }
+
+ TreeColumn[] newColumns = new TreeColumn [columnCount];
+ System.arraycopy (columns, 0, newColumns, 0, columnCount);
+ for (int i=0; i<columnCount; i++) {
+ TreeColumn column = newColumns [i];
+ if (!column.isDisposed ()) {
+ if (newX [i] != oldX [i]) {
+ column.sendEvent (SWT.Move);
+ }
+ }
+ }
+ }
+}
+
+void setFont (NSFont font) {
+ super.setFont (font);
+ setItemHeight (null, font, !hooks (SWT.MeasureItem));
+ view.setNeedsDisplay (true);
+ clearCachedWidth (items);
+ setScrollWidth ();
+}
+
+/**
+ * Marks the receiver's header as visible if the argument is <code>true</code>,
+ * and marks it invisible otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, marking
+ * it visible may not actually cause it to be displayed.
+ * </p>
+ *
+ * @param show the new visibility state
+ *
+ * @exception SWTException <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.1
+ */
+public void setHeaderVisible (boolean show) {
+ checkWidget ();
+ ((NSOutlineView) view).setHeaderView (show ? headerView : null);
+}
+
+/**
+ * Sets the number of root-level items contained in the receiver.
+ *
+ * @param count the number of items
+ *
+ * @exception SWTException <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 setItemCount (int count) {
+ checkWidget ();
+ checkItems ();
+ count = Math.max (0, count);
+ setItemCount (null, count);
+}
+
+void setItemCount (TreeItem parentItem, int count) {
+ int itemCount = getItemCount (parentItem);
+ if (count == itemCount) return;
+ NSOutlineView widget = (NSOutlineView) view;
+ int length = Math.max (4, (count + 3) / 4 * 4);
+ TreeItem [] children = parentItem == null ? items : parentItem.items;
+ boolean expanded = parentItem == null || parentItem.getExpanded();
+ if (count < itemCount) {
+ /*
+ * Note that the item count has to be updated before the call to reloadItem(), but
+ * the items have to be released after.
+ */
+ if (parentItem == null) {
+ this.itemCount = count;
+ } else {
+ parentItem.itemCount = count;
+ }
+ /*
+ * Bug in Cocoa. When removing selected items from an NSOutlineView, the selection
+ * is not properly updated. The fix is to ensure that the item and its subitems
+ * are deselected before the item is removed by the reloadItem call.
+ */
+ if (expanded) {
+ for (int index = count; index < itemCount; index ++) {
+ TreeItem item = children [index];
+ if (item != null && !item.isDisposed ()) item.clearSelection ();
+ }
+ }
+ TreeItem[] selectedItems = getSelection ();
+ widget.reloadItem (parentItem != null ? parentItem.handle : null, expanded);
+ selectItems (selectedItems, true);
+ for (int index = count; index < itemCount; index ++) {
+ TreeItem item = children [index];
+ if (item != null && !item.isDisposed()) item.release (false);
+ }
+ TreeItem [] newItems = new TreeItem [length];
+ if (children != null) {
+ System.arraycopy (children, 0, newItems, 0, count);
+ }
+ children = newItems;
+ if (parentItem == null) {
+ this.items = newItems;
+ } else {
+ parentItem.items = newItems;
+ }
+ } else {
+ if ((style & SWT.VIRTUAL) == 0) {
+ for (int i=itemCount; i<count; i++) {
+ new TreeItem (this, parentItem, SWT.NONE, i, true);
+ }
+ } else {
+ TreeItem [] newItems = new TreeItem [length];
+ if (children != null) {
+ System.arraycopy (children, 0, newItems, 0, itemCount);
+ }
+ children = newItems;
+ if (parentItem == null) {
+ this.items = newItems;
+ this.itemCount = count;
+ } else {
+ parentItem.items = newItems;
+ parentItem.itemCount = count;
+ }
+ TreeItem[] selectedItems = getSelection ();
+ widget.reloadItem (parentItem != null ? parentItem.handle : null, expanded);
+ selectItems (selectedItems, true);
+
+ if (parentItem != null && itemCount == 0 && parentItem.expanded) {
+ ignoreExpand = true;
+ widget.expandItem (parentItem.handle);
+ ignoreExpand = false;
+ }
+ }
+ }
+}
+
+/*public*/ void setItemHeight (int itemHeight) {
+ checkWidget ();
+ if (itemHeight < -1) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (itemHeight == -1) {
+ setItemHeight (null, null, true);
+ } else {
+ ((NSOutlineView)view).setRowHeight (itemHeight);
+ }
+}
+
+void setItemHeight (Image image, NSFont font, boolean set) {
+ if (font == null) font = getFont ().handle;
+ float /*double*/ ascent = font.ascender ();
+ float /*double*/ descent = -font.descender () + font.leading ();
+ int height = (int)Math.ceil (ascent + descent) + 1;
+ Rectangle bounds = image != null ? image.getBounds () : imageBounds;
+ if (bounds != null) {
+ imageBounds = bounds;
+ height = Math.max (height, bounds.height);
+ }
+ NSTableView widget = (NSTableView)view;
+ if (set || widget.rowHeight () < height) {
+ widget.setRowHeight (height);
+ }
+}
+
+/**
+ * Marks the receiver's lines as visible if the argument is <code>true</code>,
+ * and marks it invisible otherwise. Note that some platforms draw
+ * grid lines while others may draw alternating row colors.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, marking
+ * it visible may not actually cause it to be displayed.
+ * </p>
+ *
+ * @param show the new visibility state
+ *
+ * @exception SWTException <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.1
+ */
+public void setLinesVisible (boolean show) {
+ checkWidget ();
+ ((NSOutlineView) view).setUsesAlternatingRowBackgroundColors (show);
+}
+
+public void setRedraw (boolean redraw) {
+ checkWidget ();
+ super.setRedraw (redraw);
+ if (redraw && drawCount == 0) {
+ checkItems ();
+ setScrollWidth ();
+ }
+}
+
+boolean setScrollWidth () {
+ return setScrollWidth (true, items, true);
+}
+
+boolean setScrollWidth (boolean set, TreeItem[] items, boolean recurse) {
+ if (items == null) return false;
+ if (ignoreRedraw || !getDrawing()) return false;
+ if (columnCount != 0) return false;
+ GC gc = new GC (this);
+ int newWidth = calculateWidth (items, 0, gc, recurse);
+ gc.dispose ();
+ if (!set) {
+ int oldWidth = (int)firstColumn.width ();
+ if (oldWidth >= newWidth) return false;
+ }
+ firstColumn.setWidth (newWidth);
+ if (horizontalBar != null && horizontalBar.view != null) redrawWidget (horizontalBar.view, false);
+ return true;
+}
+
+boolean setScrollWidth (TreeItem item) {
+ if (ignoreRedraw || !getDrawing()) return false;
+ if (columnCount != 0) return false;
+ TreeItem parentItem = item.parentItem;
+ if (parentItem != null && !parentItem.getExpanded ()) return false;
+ GC gc = new GC (this);
+ int newWidth = item.calculateWidth (0, gc);
+ gc.dispose ();
+ int oldWidth = (int)firstColumn.width ();
+ if (oldWidth < newWidth) {
+ firstColumn.setWidth (newWidth);
+ if (horizontalBar != null && horizontalBar.view != null) redrawWidget (horizontalBar.view, false);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Sets the receiver's selection to the given item.
+ * The current selection is cleared before the new item is selected.
+ * <p>
+ * If the item is not in the receiver, then it is ignored.
+ * </p>
+ *
+ * @param item the item to select
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 setSelection (TreeItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setSelection (new TreeItem [] {item});
+}
+
+/**
+ * Sets the receiver's selection to be the given array of items.
+ * The current selection is cleared before the new items are selected.
+ * <p>
+ * Items that are not in the receiver are ignored.
+ * If the receiver is single-select and multiple items are specified,
+ * then all items are ignored.
+ * </p>
+ *
+ * @param items the array of items
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the array of items is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if one of the items has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 Tree#deselectAll()
+ */
+public void setSelection (TreeItem [] items) {
+ checkWidget ();
+ if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
+ checkItems ();
+ deselectAll ();
+ int length = items.length;
+ if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
+ selectItems (items, false);
+ if (items.length > 0) {
+ for (int i = 0; i < items.length; i++) {
+ TreeItem item = items[i];
+ if (item != null) {
+ showItem(item, true);
+ break;
+ }
+ }
+ }
+}
+
+void setSmallSize () {
+ if (checkColumn == null) return;
+ checkColumn.dataCell ().setControlSize (OS.NSSmallControlSize);
+ checkColumn.setWidth (getCheckColumnWidth ());
+}
+
+/**
+ * Sets the column used by the sort indicator for the receiver. A null
+ * value will clear the sort indicator. The current sort column is cleared
+ * before the new column is set.
+ *
+ * @param column the column used by the sort indicator or <code>null</code>
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the column is disposed</li>
+ * </ul>
+ * @exception SWTException <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 setSortColumn (TreeColumn column) {
+ checkWidget ();
+ if (column != null && column.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (column == sortColumn) return;
+ sortColumn = column;
+ ((NSOutlineView)view).setHighlightedTableColumn (column == null ? null : column.nsColumn);
+}
+
+/**
+ * Sets the direction of the sort indicator for the receiver. The value
+ * can be one of <code>UP</code>, <code>DOWN</code> or <code>NONE</code>.
+ *
+ * @param direction the direction of the sort indicator
+ *
+ * @exception SWTException <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 setSortDirection (int direction) {
+ checkWidget ();
+ if (direction != SWT.UP && direction != SWT.DOWN && direction != SWT.NONE) return;
+ if (direction == sortDirection) return;
+ sortDirection = direction;
+ if (sortColumn == null) return;
+ NSTableHeaderView headerView = ((NSOutlineView)view).headerView ();
+ if (headerView == null) return;
+ int index = indexOf (sortColumn.nsColumn);
+ NSRect rect = headerView.headerRectOfColumn (index);
+ headerView.setNeedsDisplayInRect (rect);
+}
+
+/**
+ * Sets the item which is currently at the top of the receiver.
+ * This item can change when items are expanded, collapsed, scrolled
+ * or new items are added or removed.
+ *
+ * @param item the item to be shown
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 Tree#getTopItem()
+ *
+ * @since 2.1
+ */
+public void setTopItem (TreeItem item) {
+ checkWidget();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ checkItems ();
+ showItem (item, false);
+ NSOutlineView widget = (NSOutlineView) view;
+ int /*long*/ row = widget.rowForItem (item.handle);
+ if (row == -1) return;
+ NSPoint pt = new NSPoint();
+ pt.x = scrollView.contentView().bounds().x;
+ pt.y = widget.frameOfCellAtColumn(0, row).y;
+ view.scrollPoint(pt);
+}
+
+/**
+ * Shows the column. If the column is already showing in the receiver,
+ * this method simply returns. Otherwise, the columns are scrolled until
+ * the column is visible.
+ *
+ * @param column the column to be shown
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.1
+ */
+public void showColumn (TreeColumn column) {
+ checkWidget ();
+ if (column == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (column.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (column.parent != this) return;
+ if (columnCount <= 1) return;
+ int index = indexOf (column.nsColumn);
+ if (!(0 <= index && index < columnCount + ((style & SWT.CHECK) != 0 ? 1 : 0))) return;
+ ((NSOutlineView)view).scrollColumnToVisible (index);
+}
+
+/**
+ * Shows the item. If the item is already showing in the receiver,
+ * this method simply returns. Otherwise, the items are scrolled
+ * and expanded until the item is visible.
+ *
+ * @param item the item to be shown
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 Tree#showSelection()
+ */
+public void showItem (TreeItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ checkItems ();
+ showItem (item, true);
+}
+
+void showItem (TreeItem item, boolean scroll) {
+ TreeItem parentItem = item.parentItem;
+ if (parentItem != null) {
+ showItem (parentItem, false);
+ parentItem.setExpanded (true);
+ }
+ if (scroll) {
+ NSOutlineView outlineView = (NSOutlineView) view;
+ outlineView.scrollRowToVisible (outlineView.rowForItem (item.handle));
+ }
+}
+
+/**
+ * Shows the selection. If the selection is already showing in the receiver,
+ * this method simply returns. Otherwise, the items are scrolled until
+ * the selection is visible.
+ *
+ * @exception SWTException <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 Tree#showItem(TreeItem)
+ */
+public void showSelection () {
+ checkWidget ();
+ checkItems ();
+ //TODO - optimize
+ TreeItem [] selection = getSelection ();
+ if (selection.length > 0) {
+ checkData(selection [0]);
+ showItem (selection [0], true);
+ }
+}
+
+void updateCursorRects (boolean enabled) {
+ super.updateCursorRects (enabled);
+ if (headerView == null) return;
+ updateCursorRects (enabled, headerView);
+}
+
+}
+
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TreeColumn.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TreeColumn.java
new file mode 100755
index 0000000000..ed0180f373
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TreeColumn.java
@@ -0,0 +1,675 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.events.*;
+
+/**
+ * Instances of this class represent a column in a tree 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/#tree">Tree, TreeItem, TreeColumn snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.1
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class TreeColumn extends Item {
+ NSTableColumn nsColumn;
+ Tree parent;
+ String toolTipText, displayText;
+ boolean movable;
+
+ static final int MARGIN = 2;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>Tree</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>SWT</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>SWT</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 SWTException <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 SWT#LEFT
+ * @see SWT#RIGHT
+ * @see SWT#CENTER
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TreeColumn (Tree 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>Tree</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>SWT</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>SWT</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 SWTException <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 SWT#LEFT
+ * @see SWT#RIGHT
+ * @see SWT#CENTER
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TreeColumn (Tree 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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Resize,typedListener);
+ addListener (SWT.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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+static int checkStyle (int style) {
+ return checkBits (style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0);
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.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, NSRect cellRect, int /*long*/ view) {
+ /*
+ * 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.
+ */
+ int columnIndex = parent.indexOf (nsColumn);
+ NSRect headerRect = parent.headerView.headerRectOfColumn (columnIndex);
+ if (headerRect.x != cellRect.x || headerRect.width != 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 != null) {
+ Font font = Font.cocoa_new(display, headerCell.font ());
+ attrString = parent.createString(displayText, font, null, SWT.LEFT, (parent.state & DISABLED) == 0, false);
+ stringSize = attrString.size ();
+ contentWidth += Math.ceil (stringSize.width);
+ if (image != null) contentWidth += MARGIN; /* space between image and text */
+ }
+ if (image != null) {
+ imageSize = image.handle.size ();
+ contentWidth += Math.ceil (imageSize.width);
+ }
+
+ if (parent.sortColumn == this && parent.sortDirection != SWT.NONE) {
+ boolean ascending = parent.sortDirection == SWT.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 & SWT.CENTER) != 0) {
+ drawX = (int)(cellRect.x + Math.max (MARGIN, ((cellRect.width - contentWidth) / 2)));
+ } else if ((style & SWT.RIGHT) != 0) {
+ drawX = (int)(cellRect.x + Math.max (MARGIN, cellRect.width - contentWidth - MARGIN));
+ } else {
+ drawX = (int)cellRect.x + MARGIN;
+ }
+
+ if (image != 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);
+ boolean 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 != null && displayText.length () > 0) {
+ if (image != 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);
+ }
+ if (attrString != null) 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 SWTException <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 & SWT.LEFT) != 0) return SWT.LEFT;
+ if ((style & SWT.CENTER) != 0) return SWT.CENTER;
+ if ((style & SWT.RIGHT) != 0) return SWT.RIGHT;
+ return SWT.LEFT;
+}
+
+String getNameText () {
+ return getText ();
+}
+
+/**
+ * Returns the receiver's parent, which must be a <code>Tree</code>.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException <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 Tree 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 SWTException <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 Tree#getColumnOrder()
+ * @see Tree#setColumnOrder(int[])
+ * @see TreeColumn#setMoveable(boolean)
+ * @see SWT#Move
+ *
+ * @since 3.2
+ */
+public boolean getMoveable () {
+ checkWidget ();
+ return movable;
+}
+
+/**
+ * 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 SWTException <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 boolean getResizable () {
+ checkWidget ();
+ return nsColumn.resizingMask() != 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 SWTException <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 SWTException <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 ();
+ int width = (int)nsColumn.width();
+ // TODO how to differentiate 0 and 1 cases?
+ if (width > 0) width += Tree.CELL_GAP;
+ return 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 SWTException <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 != null) {
+ NSTableHeaderCell headerCell = nsColumn.headerCell ();
+ Font font = Font.cocoa_new(display, headerCell.font ());
+ NSAttributedString attrString = parent.createString(displayText, font, null, 0, true, false);
+ NSSize stringSize = attrString.size ();
+ attrString.release ();
+ width += Math.ceil (stringSize.width);
+ if (image != null) width += MARGIN; /* space between image and text */
+ }
+ if (image != null) {
+ NSSize imageSize = image.handle.size ();
+ width += Math.ceil (imageSize.width);
+ }
+ if (parent.sortColumn == this && parent.sortDirection != SWT.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);
+ width = Math.max(width, parent.calculateWidth(parent.items, parent.indexOf (this), gc, true));
+ gc.dispose ();
+ setWidth (width);
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (nsColumn != null) {
+ nsColumn.headerCell ().release ();
+ nsColumn.release ();
+ }
+ nsColumn = null;
+ parent = null;
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ if (parent.sortColumn == 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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Move, listener);
+ eventTable.unhook (SWT.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 SWTException <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 == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.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 SWTException <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 & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) == 0) return;
+ int index = parent.indexOf (this);
+ if (index == -1 || index == 0) return;
+ style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER);
+ style |= alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER);
+ NSOutlineView outlineView = ((NSOutlineView) parent.view);
+ NSTableHeaderView headerView = outlineView.headerView ();
+ if (headerView == null) return;
+ index = parent.indexOf (nsColumn);
+ NSRect rect = headerView.headerRectOfColumn (index);
+ headerView.setNeedsDisplayInRect (rect);
+ rect = outlineView.rectOfColumn (index);
+ parent.view.setNeedsDisplayInRect (rect);
+}
+
+public void setImage (Image image) {
+ checkWidget();
+ if (image != null && image.isDisposed ()) {
+ error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ super.setImage (image);
+ NSTableHeaderView headerView = ((NSOutlineView) parent.view).headerView ();
+ if (headerView == null) return;
+ int index = parent.indexOf (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 SWTException <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 Tree#setColumnOrder(int[])
+ * @see Tree#getColumnOrder()
+ * @see TreeColumn#getMoveable()
+ * @see SWT#Move
+ *
+ * @since 3.2
+ */
+public void setMoveable (boolean moveable) {
+ checkWidget ();
+ this.movable = moveable;
+}
+
+/**
+ * Sets the resizable attribute. 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 SWTException <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 (boolean resizable) {
+ checkWidget ();
+ nsColumn.setResizingMask(resizable ? OS.NSTableColumnUserResizingMask : OS.NSTableColumnNoResizing);
+}
+
+public void setText (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.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 = ((NSOutlineView) parent.view).headerView ();
+ if (headerView == null) return;
+ int index = parent.indexOf (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 the default tool tip for the
+ * control will be shown. For a control that has a default
+ * tool tip, such as the Tree control on Windows, setting
+ * the tool tip text to an empty string replaces the default,
+ * causing no tool tip text to be shown.
+ * <p>
+ * The mnemonic indicator (character '&amp;') is not displayed in a tool tip.
+ * To display a single '&amp;' in the tool tip, the character '&amp;' can be
+ * escaped by doubling it in the string.
+ * </p>
+ *
+ * @param string the new tool tip text (or null)
+ *
+ * @exception SWTException <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;
+ parent.checkToolTip (this);
+}
+
+/**
+ * Sets the width of the receiver.
+ *
+ * @param width the new width
+ *
+ * @exception SWTException <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;
+ // TODO how to differentiate 0 and 1 cases?
+ width = Math.max (0, width - Tree.CELL_GAP);
+ nsColumn.setWidth (width);
+}
+
+String tooltipText () {
+ return toolTipText;
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TreeItem.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TreeItem.java
new file mode 100755
index 0000000000..7a02097ce1
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TreeItem.java
@@ -0,0 +1,1456 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.internal.cocoa.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Instances of this class represent a selectable user interface object
+ * that represents a hierarchy of tree items in a tree widget.
+ *
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <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>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class TreeItem extends Item {
+ Tree parent;
+ TreeItem parentItem;
+ TreeItem[] items;
+ int itemCount;
+ String [] strings;
+ Image [] images;
+ boolean checked, grayed, cached, expanded;
+ Color foreground, background;
+ Color [] cellForeground, cellBackground;
+ Font font;
+ Font [] cellFont;
+ int width = -1;
+ /**
+ * the handle to the OS resource
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public SWTTreeItem handle;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>Tree</code> or a <code>TreeItem</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>SWT</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>SWT</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 tree 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 SWTException <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 SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TreeItem (Tree parent, int style) {
+ this (checkNull (parent), null, style, -1, true);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>Tree</code> or a <code>TreeItem</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>SWT</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>SWT</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 tree 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 SWTException <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 SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TreeItem (Tree parent, int style, int index) {
+ this (checkNull (parent), null, style, checkIndex (index), true);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>Tree</code> or a <code>TreeItem</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>SWT</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>SWT</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 parentItem a tree 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 SWTException <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 SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TreeItem (TreeItem parentItem, int style) {
+ this (checkNull (parentItem).parent, parentItem, style, -1, true);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>Tree</code> or a <code>TreeItem</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>SWT</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>SWT</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 parentItem a tree 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 SWTException <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 SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TreeItem (TreeItem parentItem, int style, int index) {
+ this (checkNull (parentItem).parent, parentItem, style, checkIndex (index), true);
+}
+
+TreeItem (Tree parent, TreeItem parentItem, int style, int index, boolean create) {
+ super (parent, style);
+ this.parent = parent;
+ this.parentItem = parentItem;
+ if (create) {
+ parent.createItem (this, parentItem, index);
+ } else {
+ handle = (SWTTreeItem) new SWTTreeItem ().alloc ().init ();
+ createJNIRef ();
+ register ();
+ items = new TreeItem[4];
+ }
+}
+
+static TreeItem checkNull (TreeItem item) {
+ if (item == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return item;
+}
+
+static Tree checkNull (Tree parent) {
+ if (parent == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return parent;
+}
+
+static int checkIndex (int index) {
+ if (index < 0) SWT.error (SWT.ERROR_INVALID_RANGE);
+ return index;
+}
+
+int calculateWidth (int index, GC gc) {
+ if (index == 0 && width != -1) return width;
+ Font font = null;
+ if (cellFont != null) font = cellFont[index];
+ if (font == null) font = this.font;
+ if (font == null) font = parent.font;
+ if (font == null) font = parent.defaultFont();
+ String text = index == 0 ? this.text : (strings == null ? "" : strings [index]);
+ Image image = index == 0 ? this.image : (images == null ? null : images [index]);
+ NSCell cell = parent.dataCell;
+ if (font.extraTraits != 0) {
+ NSAttributedString attribStr = parent.createString(text, font, null, 0, true, false);
+ cell.setAttributedStringValue(attribStr);
+ attribStr.release();
+ } else {
+ cell.setFont (font.handle);
+ cell.setTitle (NSString.stringWith(text != null ? text : ""));
+ }
+
+ /* This code is inlined for performance */
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = cell.id;
+ super_struct.super_class = OS.objc_msgSend(cell.id, OS.sel_superclass);
+ NSSize size = new NSSize();
+ OS.objc_msgSendSuper_stret(size, super_struct, OS.sel_cellSize);
+ if (image != null) size.width += parent.imageBounds.width + Tree.IMAGE_GAP;
+// cell.setImage (image != null ? image.handle : null);
+// NSSize size = cell.cellSize ();
+
+ int width = (int)Math.ceil (size.width);
+ boolean sendMeasure = true;
+ if ((parent.style & SWT.VIRTUAL) != 0) {
+ sendMeasure = cached;
+ }
+ if (sendMeasure && parent.hooks (SWT.MeasureItem)) {
+ gc.setFont (font);
+ Event event = new Event ();
+ event.item = this;
+ event.index = index;
+ event.gc = gc;
+ NSTableView widget = (NSTableView)parent.view;
+ int height = (int)widget.rowHeight ();
+ event.width = width;
+ event.height = height;
+ parent.sendEvent (SWT.MeasureItem, event);
+ if (height < event.height) {
+ widget.setRowHeight (event.height);
+ widget.setNeedsDisplay (true);
+ }
+ width = event.width;
+ }
+ if (index == 0) {
+ NSOutlineView outlineView = (NSOutlineView)parent.view;
+ width += outlineView.indentationPerLevel () * (1 + outlineView.levelForItem (handle));
+ this.width = width;
+ }
+ return width;
+}
+
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+void clear () {
+ cached = false;
+ text = "";
+ image = null;
+ strings = null;
+ images = null;
+ checked = grayed = false;
+ foreground = background = null;
+ cellForeground = cellBackground = null;
+ font = null;
+ cellFont = null;
+ width = -1;
+}
+
+/**
+ * Clears the item at the given zero-relative index in the receiver.
+ * The text, icon and other attributes of the item are set to the default
+ * value. If the tree was created with the <code>SWT.VIRTUAL</code> style,
+ * these attributes are requested again as needed.
+ *
+ * @param index the index of the item to clear
+ * @param all <code>true</code> if all child items of the indexed item should be
+ * cleared recursively, and <code>false</code> otherwise
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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 SWT#VIRTUAL
+ * @see SWT#SetData
+ *
+ * @since 3.2
+ */
+public void clear (int index, boolean all) {
+ checkWidget ();
+ int count = getItemCount ();
+ if (index < 0 || index >= count)
+ SWT.error (SWT.ERROR_INVALID_RANGE);
+ parent.clear (this, index, all);
+}
+
+
+/**
+ * Clears all the items in the receiver. The text, icon and other
+ * attributes of the items are set to their default values. If the
+ * tree was created with the <code>SWT.VIRTUAL</code> style, these
+ * attributes are requested again as needed.
+ *
+ * @param all <code>true</code> if all child items should be cleared
+ * recursively, and <code>false</code> otherwise
+ *
+ * @exception SWTException <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 SWT#VIRTUAL
+ * @see SWT#SetData
+ *
+ * @since 3.2
+ */
+public void clearAll (boolean all) {
+ checkWidget ();
+ parent.clearAll (this, all);
+}
+
+void clearSelection () {
+ NSOutlineView widget = (NSOutlineView) parent.view;
+ int /*long*/ row = widget.rowForItem (handle);
+ if (widget.isRowSelected(row)) widget.deselectRow (row);
+ if (items != null && getExpanded ()) {
+ for (int i = 0; i < items.length; i++) {
+ TreeItem item = items [i];
+ if (item != null && !item.isDisposed ()) item.clearSelection ();
+ }
+ }
+}
+
+NSObject createString(int index) {
+ String text = index == 0 ? this.text : (strings == null ? "" : strings [index]);
+ return NSString.stringWith(text != null ? text : "");
+}
+
+void deregister () {
+ super.deregister ();
+ display.removeWidget (handle);
+}
+
+void destroyWidget () {
+ parent.destroyItem (this);
+ releaseHandle ();
+}
+
+/**
+ * Returns the receiver's background color.
+ *
+ * @return the background color
+ *
+ * @exception SWTException <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 2.0
+ *
+ */
+public Color getBackground () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ return background != null ? background : parent.getBackground ();
+}
+
+/**
+ * Returns the background color at the given column index in the receiver.
+ *
+ * @param index the column index
+ * @return the background color
+ *
+ * @exception SWTException <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.1
+ */
+public Color getBackground (int index) {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ int count = Math.max (1, parent.columnCount);
+ if (0 > index || index > count -1) return getBackground ();
+ if (cellBackground == null || cellBackground [index] == null) return getBackground ();
+ return cellBackground [index];
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location
+ * relative to its parent.
+ *
+ * @return the receiver's bounding rectangle
+ *
+ * @exception SWTException <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 Rectangle getBounds () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ parent.checkItems ();
+ NSOutlineView outlineView = (NSOutlineView) parent.view;
+ NSRect rect = outlineView.rectOfRow (outlineView.rowForItem (handle));
+ return new Rectangle((int) rect.x, (int) rect.y, (int) rect.width, (int) rect.height);
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location
+ * relative to its parent at a column in the tree.
+ *
+ * @param index the index that specifies the column
+ * @return the receiver's bounding column rectangle
+ *
+ * @exception SWTException <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.1
+ */
+public Rectangle getBounds (int index) {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ if (!(0 <= index && index < Math.max (1, parent.columnCount))) return new Rectangle (0, 0, 0, 0);
+
+ parent.checkItems ();
+ NSOutlineView outlineView = (NSOutlineView) parent.view;
+ if (parent.columnCount == 0) {
+ index = (parent.style & SWT.CHECK) != 0 ? 1 : 0;
+ } else {
+ TreeColumn column = parent.getColumn (index);
+ index = parent.indexOf (column.nsColumn);
+ }
+ NSRect rect = outlineView.frameOfCellAtColumn (index, outlineView.rowForItem (handle));
+ return new Rectangle ((int) rect.x, (int) rect.y, (int) rect.width, (int) rect.height);
+}
+
+/**
+ * Returns <code>true</code> if the receiver is checked,
+ * and false otherwise. When the parent does not have
+ * the <code>CHECK style, return false.
+ * <p>
+ *
+ * @return the checked state
+ *
+ * @exception SWTException <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 boolean getChecked () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ if ((parent.style & SWT.CHECK) == 0) return false;
+ return checked;
+}
+
+/**
+ * Returns <code>true</code> if the receiver is expanded,
+ * and false otherwise.
+ * <p>
+ *
+ * @return the expanded state
+ *
+ * @exception SWTException <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 boolean getExpanded () {
+ checkWidget ();
+ return expanded;
+}
+
+/**
+ * Returns the font that the receiver will use to paint textual information for this item.
+ *
+ * @return the receiver's font
+ *
+ * @exception SWTException <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.0
+ */
+public Font getFont () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ return font != null ? font : parent.getFont ();
+}
+
+/**
+ * Returns the font that the receiver will use to paint textual information
+ * for the specified cell in this item.
+ *
+ * @param index the column index
+ * @return the receiver's font
+ *
+ * @exception SWTException <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.1
+ */
+public Font getFont (int index) {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ int count = Math.max (1, parent.columnCount);
+ if (0 > index || index > count -1) return getFont ();
+ if (cellFont == null || cellFont [index] == null) return getFont ();
+ return cellFont [index];
+}
+
+/**
+ * Returns the foreground color that the receiver will use to draw.
+ *
+ * @return the receiver's foreground color
+ *
+ * @exception SWTException <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 2.0
+ *
+ */
+public Color getForeground () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ return foreground != null ? foreground : parent.getForeground ();
+}
+
+/**
+ *
+ * Returns the foreground color at the given column index in the receiver.
+ *
+ * @param index the column index
+ * @return the foreground color
+ *
+ * @exception SWTException <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.1
+ */
+public Color getForeground (int index) {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ int count = Math.max (1, parent.columnCount);
+ if (0 > index || index > count -1) return getForeground ();
+ if (cellForeground == null || cellForeground [index] == null) return getForeground ();
+ return cellForeground [index];
+}
+
+/**
+ * Returns <code>true</code> if the receiver is grayed,
+ * and false otherwise. When the parent does not have
+ * the <code>CHECK style, return false.
+ * <p>
+ *
+ * @return the grayed state of the checkbox
+ *
+ * @exception SWTException <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 boolean getGrayed () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ if ((parent.style & SWT.CHECK) == 0) return false;
+ return grayed;
+}
+
+public Image getImage () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ return super.getImage ();
+}
+
+/**
+ * Returns the image stored at the given column index in the receiver,
+ * or null if the image has not been set or if the column does not exist.
+ *
+ * @param index the column index
+ * @return the image stored at the given column index in the receiver
+ *
+ * @exception SWTException <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.1
+ */
+public Image getImage (int index) {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ if (index == 0) return getImage ();
+ if (images != null) {
+ if (0 <= index && index < images.length) return images [index];
+ }
+ return null;
+}
+
+/**
+ * Returns a rectangle describing the size and location
+ * relative to its parent of an image at a column in the
+ * tree.
+ *
+ * @param index the index that specifies the column
+ * @return the receiver's bounding image rectangle
+ *
+ * @exception SWTException <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.1
+ */
+public Rectangle getImageBounds (int index) {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ if (!(0 <= index && index < Math.max (1, parent.columnCount))) return new Rectangle (0, 0, 0, 0);
+
+ parent.checkItems ();
+ NSOutlineView outlineView = (NSOutlineView) parent.view;
+ Image image = index == 0 ? this.image : (images != null) ? images [index] : null;
+ if (parent.columnCount == 0) {
+ index = (parent.style & SWT.CHECK) != 0 ? 1 : 0;
+ } else {
+ TreeColumn column = parent.getColumn (index);
+ index = parent.indexOf (column.nsColumn);
+ }
+ NSRect rect = outlineView.frameOfCellAtColumn (index, outlineView.rowForItem (handle));
+ rect.x += Tree.IMAGE_GAP;
+ if (image != null) {
+ rect.width = parent.imageBounds.width;
+ } else {
+ rect.width = 0;
+ }
+ return new Rectangle((int) rect.x, (int) rect.y, (int) rect.width, (int) rect.height);
+}
+
+/**
+ * Returns the item at the given, zero-relative index in the
+ * receiver. Throws an exception if the index is out of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <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.1
+ */
+public TreeItem getItem (int index) {
+ checkWidget ();
+ if (index < 0) error (SWT.ERROR_INVALID_RANGE);
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ if (index >= itemCount) error (SWT.ERROR_INVALID_RANGE);
+ return parent._getItem (this, index, true);
+}
+
+/**
+ * Returns the number of items contained in the receiver
+ * that are direct item children of the receiver.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException <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 getItemCount () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ return itemCount;
+}
+
+/**
+ * Returns a (possibly empty) array of <code>TreeItem</code>s which
+ * are the direct item children of the receiver.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ *
+ * @return the receiver's items
+ *
+ * @exception SWTException <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 TreeItem [] getItems () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ TreeItem [] result = new TreeItem [itemCount];
+ for (int i=0; i<itemCount; i++) {
+ result [i] = parent._getItem (this, i, true);
+ }
+ return result;
+}
+
+String getNameText () {
+ if ((parent.style & SWT.VIRTUAL) != 0) {
+ if (!cached) return "*virtual*"; //$NON-NLS-1$
+ }
+ return super.getNameText ();
+}
+
+/**
+ * Returns the receiver's parent, which must be a <code>Tree</code>.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException <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 Tree getParent () {
+ checkWidget ();
+ return parent;
+}
+
+/**
+ * Returns the receiver's parent item, which must be a
+ * <code>TreeItem</code> or null when the receiver is a
+ * root.
+ *
+ * @return the receiver's parent item
+ *
+ * @exception SWTException <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 TreeItem getParentItem () {
+ checkWidget ();
+ return parentItem;
+}
+
+public String getText () {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ return super.getText ();
+}
+
+/**
+ * Returns the text stored at the given column index in the receiver,
+ * or empty string if the text has not been set.
+ *
+ * @param index the column index
+ * @return the text stored at the given column index in the receiver
+ *
+ * @exception SWTException <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.1
+ */
+public String getText (int index) {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ if (index == 0) return getText ();
+ if (strings != null) {
+ if (0 <= index && index < strings.length) {
+ String string = strings [index];
+ return string != null ? string : "";
+ }
+ }
+ return "";
+}
+
+/**
+ * Returns a rectangle describing the size and location
+ * relative to its parent of the text at a column in the
+ * tree.
+ *
+ * @param index the index that specifies the column
+ * @return the receiver's bounding text rectangle
+ *
+ * @exception SWTException <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.3
+ */
+public Rectangle getTextBounds (int index) {
+ checkWidget ();
+ if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
+ if (!(0 <= index && index < Math.max (1, parent.columnCount))) return new Rectangle (0, 0, 0, 0);
+
+ parent.checkItems ();
+ NSOutlineView outlineView = (NSOutlineView) parent.view;
+ Image image = index == 0 ? this.image : (images != null) ? images [index] : null;
+ if (parent.columnCount == 0) {
+ index = (parent.style & SWT.CHECK) != 0 ? 1 : 0;
+ } else {
+ TreeColumn column = parent.getColumn (index);
+ index = parent.indexOf (column.nsColumn);
+ }
+ NSRect rect = outlineView.frameOfCellAtColumn (index, outlineView.rowForItem (handle));
+ rect.x += Tree.TEXT_GAP;
+ rect.width -= Tree.TEXT_GAP;
+ if (image != null) {
+ int offset = parent.imageBounds.width + Tree.IMAGE_GAP;
+ rect.x += offset;
+ rect.width -= offset;
+ }
+ return new Rectangle((int) rect.x, (int) rect.y, (int) rect.width, (int) rect.height);
+}
+
+/**
+ * Searches the receiver's list starting at the first item
+ * (index 0) until an item is found that is equal to the
+ * argument, and returns the index of that item. If no item
+ * is found, returns -1.
+ *
+ * @param item the search item
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.1
+ */
+public int indexOf (TreeItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (item.parentItem != this) return -1;
+ for (int i = 0; i < itemCount; i++) {
+ if (item == items [i]) return i;
+ }
+ return -1;
+}
+
+void redraw (int columnIndex) {
+ if (parent.ignoreRedraw || !isDrawing()) return;
+ /* redraw the full item if columnIndex == -1 */
+ NSOutlineView outlineView = (NSOutlineView) parent.view;
+ NSRect rect;
+ if (columnIndex == -1 || parent.hooks (SWT.MeasureItem) || parent.hooks (SWT.EraseItem) || parent.hooks (SWT.PaintItem)) {
+ rect = outlineView.rectOfRow (outlineView.rowForItem (handle));
+ } else {
+ int index;
+ if (parent.columnCount == 0) {
+ index = (parent.style & SWT.CHECK) != 0 ? 1 : 0;
+ } else {
+ if (0 <= columnIndex && columnIndex < parent.columnCount) {
+ index = parent.indexOf (parent.columns[columnIndex].nsColumn);
+ } else {
+ return;
+ }
+ }
+ rect = outlineView.frameOfCellAtColumn (index, outlineView.rowForItem (handle));
+ }
+ outlineView.setNeedsDisplayInRect (rect);
+}
+
+void register () {
+ super.register ();
+ display.addWidget (handle, this);
+}
+
+void release(boolean destroy) {
+ /*
+ * Bug in Cocoa. When removing selected items from an NSOutlineView, the selection
+ * is not properly updated. The fix is to ensure that the item and its subitems
+ * are deselected before the item is removed by the reloadItem call.
+ *
+ * This has to be done in release to avoid traversing the tree twice when items are
+ * removed from the tree by setItemCount.
+ */
+ if (destroy) clearSelection ();
+ super.release(destroy);
+}
+
+void releaseChildren (boolean destroy) {
+ for (int i=0; i<items.length; i++) {
+ TreeItem item = items [i];
+ if (item != null && !item.isDisposed ()) {
+ item.release (false);
+ }
+ }
+ items = null;
+ itemCount = 0;
+ super.releaseChildren (destroy);
+}
+
+void releaseHandle () {
+ super.releaseHandle ();
+ if (handle != null) handle.release ();
+ handle = null;
+ parentItem = null;
+ parent = null;
+}
+
+void releaseWidget () {
+ super.releaseWidget ();
+ strings = null;
+ images = null;
+ background = foreground = null;
+ font = null;
+ cellBackground = cellForeground = null;
+ cellFont = null;
+}
+
+/**
+ * Removes all of the items from the receiver.
+ * <p>
+ * @exception SWTException <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.1
+ */
+public void removeAll () {
+ checkWidget ();
+ parent.setItemCount (this, 0);
+}
+
+void sendExpand (boolean expand, boolean recurse) {
+ if (itemCount == 0) return;
+ if (expanded != expand) {
+ Event event = new Event ();
+ event.item = this;
+ parent.sendEvent (expand ? SWT.Expand : SWT.Collapse, event);
+ if (isDisposed ()) return;
+ expanded = expand;
+ }
+ if (recurse) {
+ for (int i = 0; i < itemCount; i++) {
+ if (items[i] != null) items[i].sendExpand (expand, recurse);
+ }
+ }
+}
+
+/**
+ * Sets the receiver's background color to the color specified
+ * by the argument, or to the default system color for the item
+ * if the argument is null.
+ *
+ * @param color the new color (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 2.0
+ *
+ */
+public void setBackground (Color color) {
+ checkWidget ();
+ if (color != null && color.isDisposed ()) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ Color oldColor = background;
+ if (oldColor == color) return;
+ background = color;
+ if (oldColor != null && oldColor.equals (color)) return;
+ cached = true;
+ redraw (-1);
+}
+
+/**
+ * Sets the background color at the given column index in the receiver
+ * to the color specified by the argument, or to the default system color for the item
+ * if the argument is null.
+ *
+ * @param index the column index
+ * @param color the new color (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.1
+ *
+ */
+public void setBackground (int index, Color color) {
+ checkWidget ();
+ if (color != null && color.isDisposed ()) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ int count = Math.max (1, parent.columnCount);
+ if (0 > index || index > count - 1) return;
+ if (cellBackground == null) {
+ if (color == null) return;
+ cellBackground = new Color [count];
+ }
+ Color oldColor = cellBackground [index];
+ if (oldColor == color) return;
+ cellBackground [index] = color;
+ if (oldColor != null && oldColor.equals (color)) return;
+ cached = true;
+ redraw (index);
+}
+
+/**
+ * Sets the checked state of the receiver.
+ * <p>
+ *
+ * @param checked the new checked state
+ *
+ * @exception SWTException <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 setChecked (boolean checked) {
+ checkWidget ();
+ if ((parent.style & SWT.CHECK) == 0) return;
+ if (this.checked == checked) return;
+ this.checked = checked;
+ cached = true;
+ redraw (-1);
+}
+
+/**
+ * Sets the expanded state of the receiver.
+ * <p>
+ *
+ * @param expanded the new expanded state
+ *
+ * @exception SWTException <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 setExpanded (boolean expanded) {
+ checkWidget ();
+
+ /* Do nothing when the item is a leaf or already expanded */
+ if (itemCount == 0 || expanded == getExpanded ()) return;
+
+ parent.checkItems ();
+ parent.ignoreExpand = true;
+ this.expanded = expanded;
+ if (expanded) {
+ ((NSOutlineView) parent.view).expandItem (handle);
+ } else {
+ ((NSOutlineView) parent.view).collapseItem (handle);
+ }
+ parent.ignoreExpand = false;
+ cached = true;
+ if (!expanded) {
+ parent.setScrollWidth ();
+ }
+}
+
+/**
+ * Sets the font that the receiver will use to paint textual information
+ * for this item to the font specified by the argument, or to the default font
+ * for that kind of control if the argument is null.
+ *
+ * @param font the new font (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.0
+ */
+public void setFont (Font font) {
+ checkWidget ();
+ if (font != null && font.isDisposed ()) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ Font oldFont = this.font;
+ if (oldFont == font) return;
+ this.font = font;
+ if (oldFont != null && oldFont.equals (font)) return;
+ width = -1;
+ cached = true;
+ redraw (-1);
+}
+
+/**
+ * Sets the font that the receiver will use to paint textual information
+ * for the specified cell in this item to the font specified by the
+ * argument, or to the default font for that kind of control if the
+ * argument is null.
+ *
+ * @param index the column index
+ * @param font the new font (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.1
+ */
+public void setFont (int index, Font font) {
+ checkWidget ();
+ if (font != null && font.isDisposed ()) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ int count = Math.max (1, parent.columnCount);
+ if (0 > index || index > count - 1) return;
+ if (cellFont == null) {
+ if (font == null) return;
+ cellFont = new Font [count];
+ }
+ Font oldFont = cellFont [index];
+ if (oldFont == font) return;
+ cellFont [index] = font;
+ if (oldFont != null && oldFont.equals (font)) return;
+ width = -1;
+ cached = true;
+ redraw (index);
+}
+
+/**
+ * Sets the receiver's foreground color to the color specified
+ * by the argument, or to the default system color for the item
+ * if the argument is null.
+ *
+ * @param color the new color (or null)
+ *
+ * @since 2.0
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <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 2.0
+ *
+ */
+public void setForeground (Color color) {
+ checkWidget ();
+ if (color != null && color.isDisposed ()) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ Color oldColor = foreground;
+ if (oldColor == color) return;
+ foreground = color;
+ if (oldColor != null && oldColor.equals (color)) return;
+ cached = true;
+ redraw (-1);
+}
+
+/**
+ * Sets the foreground color at the given column index in the receiver
+ * to the color specified by the argument, or to the default system color for the item
+ * if the argument is null.
+ *
+ * @param index the column index
+ * @param color the new color (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.1
+ *
+ */
+public void setForeground (int index, Color color){
+ checkWidget ();
+ if (color != null && color.isDisposed ()) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ int count = Math.max (1, parent.columnCount);
+ if (0 > index || index > count - 1) return;
+ if (cellForeground == null) {
+ if (color == null) return;
+ cellForeground = new Color [count];
+ }
+ Color oldColor = cellForeground [index];
+ if (oldColor == color) return;
+ cellForeground [index] = color;
+ if (oldColor != null && oldColor.equals (color)) return;
+ cached = true;
+ redraw (index);
+}
+
+/**
+ * Sets the grayed state of the checkbox for this item. This state change
+ * only applies if the Tree was created with the SWT.CHECK style.
+ *
+ * @param grayed the new grayed state of the checkbox
+ *
+ * @exception SWTException <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 setGrayed (boolean grayed) {
+ checkWidget ();
+ if ((parent.style & SWT.CHECK) == 0) return;
+ if (this.grayed == grayed) return;
+ this.grayed = grayed;
+ cached = true;
+ redraw (-1);
+}
+
+/**
+ * Sets the image for multiple columns in the tree.
+ *
+ * @param images the array of new images
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the array of images is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if one of the images has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.1
+ */
+public void setImage (Image [] images) {
+ checkWidget ();
+ if (images == null) error (SWT.ERROR_NULL_ARGUMENT);
+ for (int i=0; i<images.length; i++) {
+ setImage (i, images [i]);
+ }
+}
+
+/**
+ * Sets the receiver's image at a column.
+ *
+ * @param index the column index
+ * @param image the new image
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <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.1
+ */
+public void setImage (int index, Image image) {
+ checkWidget ();
+ if (image != null && image.isDisposed ()) {
+ error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ if (parent.imageBounds == null && image != null) {
+ parent.setItemHeight (image, null, false);
+ }
+ if (index == 0) {
+ if (image != null && image.type == SWT.ICON) {
+ if (image.equals (this.image)) return;
+ }
+ width = -1;
+ super.setImage (image);
+ }
+ int count = Math.max (1, parent.columnCount);
+ if (0 <= index && index < count) {
+ if (images == null) images = new Image [count];
+ if (image != null && image.type == SWT.ICON) {
+ if (image.equals (images [index])) return;
+ }
+ images [index] = image;
+ }
+ cached = true;
+ if (index == 0) parent.setScrollWidth (this);
+ if (0 <= index && index < count) redraw (index);
+}
+
+public void setImage (Image image) {
+ checkWidget ();
+ setImage (0, image);
+}
+
+/**
+ * Sets the number of child items contained in the receiver.
+ *
+ * @param count the number of items
+ *
+ * @exception SWTException <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 setItemCount (int count) {
+ checkWidget ();
+ count = Math.max (0, count);
+ parent.setItemCount (this, count);
+}
+
+/**
+ * Sets the text for multiple columns in the tree.
+ *
+ * @param strings the array of new strings
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
+ * </ul>
+ * @exception SWTException <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.1
+ */
+public void setText (String [] strings) {
+ checkWidget ();
+ if (strings == null) error (SWT.ERROR_NULL_ARGUMENT);
+ for (int i=0; i<strings.length; i++) {
+ String string = strings [i];
+ if (string != null) setText (i, string);
+ }
+}
+
+/**
+ * Sets the receiver's text at a column
+ *
+ * @param index the column index
+ * @param string the new text
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
+ * </ul>
+ * @exception SWTException <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.1
+ */
+public void setText (int index, String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (index == 0) {
+ if (string.equals (text)) return;
+ width = -1;
+ super.setText (string);
+ }
+ int count = Math.max (1, parent.columnCount);
+ if (0 <= index && index < count) {
+ if (strings == null) strings = new String [count];
+ if (string.equals (strings [index])) return;
+ strings [index] = string;
+ }
+ cached = true;
+ if (index == 0) parent.setScrollWidth (this);
+ if (0 <= index && index < count) redraw (index);
+}
+
+public void setText (String string) {
+ checkWidget ();
+ setText (0, string);
+}
+
+void updateExpanded () {
+ if (itemCount == 0) return;
+ NSOutlineView outlineView = (NSOutlineView)parent.view;
+ if (expanded != outlineView.isItemExpanded (handle)) {
+ if (expanded) {
+ outlineView.expandItem (handle);
+ } else {
+ outlineView.collapseItem (handle);
+ }
+ }
+ for (int i = 0; i < itemCount; i++) {
+ if (items[i] != null) items[i].updateExpanded ();
+ }
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Widget.java
new file mode 100755
index 0000000000..3ec4eadbcb
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Widget.java
@@ -0,0 +1,1767 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.cocoa.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+
+/**
+ * This class is the abstract superclass of all user interface objects.
+ * Widgets are created, disposed and issue notification to listeners
+ * when events occur which affect them.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Dispose</dd>
+ * </dl>
+ * <p>
+ * IMPORTANT: This class is intended to be subclassed <em>only</em>
+ * within the SWT implementation. However, it has not been marked
+ * final to allow those outside of the SWT development team to implement
+ * patched versions of the class in order to get around specific
+ * limitations in advance of when those limitations can be addressed
+ * by the team. Any class built using subclassing to access the internals
+ * of this class will likely fail to compile or run between releases and
+ * may be strongly platform specific. Subclassing should not be attempted
+ * without an intimate and detailed understanding of the workings of the
+ * hierarchy. No support is provided for user-written classes which are
+ * implemented as subclasses of this class.
+ * </p>
+ *
+ * @see #checkSubclass
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+public abstract class Widget {
+ int style, state;
+ Display display;
+ EventTable eventTable;
+ Object data;
+
+ int /*long*/ jniRef;
+
+ /* Global state flags */
+ static final int DISPOSED = 1 << 0;
+ static final int CANVAS = 1 << 1;
+ static final int KEYED_DATA = 1 << 2;
+ static final int DISABLED = 1 << 3;
+ static final int HIDDEN = 1 << 4;
+ static final int GRAB = 1 << 5;
+ static final int MOVED = 1 << 6;
+ static final int RESIZED = 1 << 7;
+ static final int EXPANDING = 1 << 8;
+ static final int IGNORE_WHEEL = 1 << 9;
+ static final int PARENT_BACKGROUND = 1 << 10;
+ static final int THEME_BACKGROUND = 1 << 11;
+
+ /* A layout was requested on this widget */
+ static final int LAYOUT_NEEDED = 1<<12;
+
+ /* The preferred size of a child has changed */
+ static final int LAYOUT_CHANGED = 1<<13;
+
+ /* A layout was requested in this widget hierachy */
+ static final int LAYOUT_CHILD = 1<<14;
+
+ /* More global state flags */
+ static final int RELEASED = 1<<15;
+ static final int DISPOSE_SENT = 1<<16;
+ static final int FOREIGN_HANDLE = 1<<17;
+ static final int DRAG_DETECT = 1<<18;
+
+ /* Safari fixes */
+ static final int SAFARI_EVENTS_FIX = 1<<19;
+ static final String SAFARI_EVENTS_FIX_KEY = "org.eclipse.swt.internal.safariEventsFix"; //$NON-NLS-1$
+ static final String GLCONTEXT_KEY = "org.eclipse.swt.internal.cocoa.glcontext"; //$NON-NLS-1$
+
+ /* Default size for widgets */
+ static final int DEFAULT_WIDTH = 64;
+ static final int DEFAULT_HEIGHT = 64;
+
+Widget () {
+ /* Do nothing */
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</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>SWT</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 widget which will be the parent of the new instance (cannot be null)
+ * @param style the style of widget to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li>
+ * </ul>
+ * @exception SWTException <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 SWT
+ * @see #checkSubclass
+ * @see #getStyle
+ */
+public Widget (Widget parent, int style) {
+ checkSubclass ();
+ checkParent (parent);
+ this.style = style;
+ display = parent.display;
+}
+
+int /*long*/ accessibilityActionDescription(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ return callSuperObject(id, sel, arg0);
+}
+
+int /*long*/ accessibilityActionNames(int /*long*/ id, int /*long*/ sel) {
+ return callSuperObject(id, sel);
+}
+
+int /*long*/ accessibilityAttributeNames(int /*long*/ id, int /*long*/ sel) {
+ return callSuperObject(id, sel);
+}
+
+int /*long*/ accessibilityAttributeValue(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ return callSuperObject(id, sel, arg0);
+}
+
+int /*long*/ accessibilityAttributeValue_forParameter(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ return OS.objc_msgSendSuper(super_struct, sel, arg0, arg1);
+}
+
+int /*long*/ accessibilityFocusedUIElement(int /*long*/ id, int /*long*/ sel) {
+ return callSuperObject(id, sel);
+}
+
+int /*long*/ accessibilityHitTest(int /*long*/ id, int /*long*/ sel, NSPoint point) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ return OS.objc_msgSendSuper(super_struct, sel, point);
+}
+
+boolean accessibilityIsIgnored(int /*long*/ id, int /*long*/ sel) {
+ return callSuperBoolean(id, sel);
+}
+
+int /*long*/ accessibilityParameterizedAttributeNames(int /*long*/ id, int /*long*/ sel) {
+ return callSuperObject(id, sel);
+}
+
+void accessibilityPerformAction(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ callSuper(id, sel, arg0);
+}
+
+String getClipboardText () {
+ NSPasteboard pasteboard = NSPasteboard.generalPasteboard ();
+ NSString string = pasteboard.stringForType (OS.NSStringPboardType);
+ return string != null ? string.getString () : null;
+}
+
+void setClipRegion (float /*double*/ x, float /*double*/ y) {
+}
+
+int /*long*/ attributedSubstringFromRange (int /*long*/ id, int /*long*/ sel, int /*long*/ range) {
+ return 0;
+}
+
+void callSuper(int /*long*/ id, int /*long*/ sel) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ OS.objc_msgSendSuper(super_struct, sel);
+}
+
+void callSuper(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ OS.objc_msgSendSuper(super_struct, sel, arg0);
+}
+
+void callSuper(int /*long*/ id, int /*long*/ sel, NSRect arg0) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ OS.objc_msgSendSuper(super_struct, sel, arg0);
+}
+
+void callSuper(int /*long*/ id, int /*long*/ sel, NSRect arg0, int /*long*/ arg1) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ OS.objc_msgSendSuper(super_struct, sel, arg0, arg1);
+}
+
+int /*long*/ callSuper(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, NSRect arg1, int /*long*/ arg2) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ return OS.objc_msgSendSuper(super_struct, sel, arg0, arg1, arg2);
+}
+
+boolean callSuperBoolean(int /*long*/ id, int /*long*/ sel) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ return OS.objc_msgSendSuper(super_struct, sel) != 0;
+}
+
+boolean canBecomeKeyWindow (int /*long*/ id, int /*long*/ sel) {
+ return callSuperBoolean (id, sel);
+}
+
+NSSize cellSize (int /*long*/ id, int /*long*/ sel) {
+ NSSize result = new NSSize();
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ OS.objc_msgSendSuper_stret(result, super_struct, sel);
+ return result;
+}
+
+boolean callSuperBoolean(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ return OS.objc_msgSendSuper(super_struct, sel, arg0) != 0;
+}
+
+boolean callSuperBoolean(int /*long*/ id, int /*long*/ sel, NSRange range, int /*long*/ arg1) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ return OS.objc_msgSendSuper_bool(super_struct, sel, range, arg1);
+}
+
+int /*long*/ callSuperObject(int /*long*/ id, int /*long*/ sel) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ return OS.objc_msgSendSuper(super_struct, sel);
+}
+
+int /*long*/ callSuperObject(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ return OS.objc_msgSendSuper(super_struct, sel, arg0);
+}
+
+boolean canDragRowsWithIndexes_atPoint(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1) {
+ // Trees/tables are not draggable unless explicitly told they are.
+ return false;
+}
+
+int /*long*/ characterIndexForPoint (int /*long*/ id, int /*long*/ sel, int /*long*/ point) {
+ return OS.NSNotFound;
+}
+
+boolean acceptsFirstMouse (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ return OS.objc_msgSendSuper(super_struct, sel, theEvent) != 0;
+}
+
+boolean acceptsFirstResponder (int /*long*/ id, int /*long*/ sel) {
+ return callSuperBoolean(id, sel);
+}
+
+boolean becomeFirstResponder (int /*long*/ id, int /*long*/ sel) {
+ return callSuperBoolean(id, sel);
+}
+
+void becomeKeyWindow (int /*long*/ id, int /*long*/ sel) {
+ callSuper(id, sel);
+}
+
+boolean resignFirstResponder (int /*long*/ id, int /*long*/ sel) {
+ return callSuperBoolean(id, sel);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when an event of the given type occurs. When the
+ * event does occur in the widget, the listener is notified by
+ * sending it the <code>handleEvent()</code> message. The event
+ * type is one of the event constants defined in class <code>SWT</code>.
+ *
+ * @param eventType the type of event to listen for
+ * @param listener the listener which should be notified when the event occurs
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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 Listener
+ * @see SWT
+ * @see #getListeners(int)
+ * @see #removeListener(int, Listener)
+ * @see #notifyListeners
+ */
+public void addListener (int eventType, Listener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ _addListener (eventType, listener);
+}
+
+void _addListener (int eventType, Listener listener) {
+ if (eventTable == null) eventTable = new EventTable ();
+ eventTable.hook (eventType, listener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the widget is disposed. When the widget is
+ * disposed, the listener is notified by sending it the
+ * <code>widgetDisposed()</code> message.
+ *
+ * @param listener the listener which should be notified when the receiver is disposed
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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 DisposeListener
+ * @see #removeDisposeListener
+ */
+public void addDisposeListener (DisposeListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Dispose, typedListener);
+}
+
+boolean canBecomeKeyView(int /*long*/ id, int /*long*/ sel) {
+ return true;
+}
+
+static int checkBits (int style, int int0, int int1, int int2, int int3, int int4, int int5) {
+ int mask = int0 | int1 | int2 | int3 | int4 | int5;
+ if ((style & mask) == 0) style |= int0;
+ if ((style & int0) != 0) style = (style & ~mask) | int0;
+ if ((style & int1) != 0) style = (style & ~mask) | int1;
+ if ((style & int2) != 0) style = (style & ~mask) | int2;
+ if ((style & int3) != 0) style = (style & ~mask) | int3;
+ if ((style & int4) != 0) style = (style & ~mask) | int4;
+ if ((style & int5) != 0) style = (style & ~mask) | int5;
+ return style;
+}
+
+void checkOpen () {
+ /* Do nothing */
+}
+
+void checkOrientation (Widget parent) {
+ style &= ~SWT.MIRRORED;
+ if ((style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT)) == 0) {
+ if (parent != null) {
+ if ((parent.style & SWT.LEFT_TO_RIGHT) != 0) style |= SWT.LEFT_TO_RIGHT;
+ if ((parent.style & SWT.RIGHT_TO_LEFT) != 0) style |= SWT.RIGHT_TO_LEFT;
+ }
+ }
+ style = checkBits (style, SWT.LEFT_TO_RIGHT, SWT.RIGHT_TO_LEFT, 0, 0, 0, 0);
+}
+
+void checkParent (Widget parent) {
+ if (parent == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (parent.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ parent.checkWidget ();
+ parent.checkOpen ();
+}
+
+/**
+ * Checks that this class can be subclassed.
+ * <p>
+ * The SWT class library is intended to be subclassed
+ * only at specific, controlled points (most notably,
+ * <code>Composite</code> and <code>Canvas</code> when
+ * implementing new widgets). This method enforces this
+ * rule unless it is overridden.
+ * </p><p>
+ * <em>IMPORTANT:</em> By providing an implementation of this
+ * method that allows a subclass of a class which does not
+ * normally allow subclassing to be created, the implementer
+ * agrees to be fully responsible for the fact that any such
+ * subclass will likely fail between SWT releases and will be
+ * strongly platform specific. No support is provided for
+ * user-written classes which are implemented in this fashion.
+ * </p><p>
+ * The ability to subclass outside of the allowed SWT classes
+ * is intended purely to enable those not on the SWT development
+ * team to implement patches in order to get around specific
+ * limitations in advance of when those limitations can be
+ * addressed by the team. Subclassing should not be attempted
+ * without an intimate and detailed understanding of the hierarchy.
+ * </p>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ */
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+/**
+ * Throws an <code>SWTException</code> if the receiver can not
+ * be accessed by the caller. This may include both checks on
+ * the state of the receiver and more generally on the entire
+ * execution context. This method <em>should</em> be called by
+ * widget implementors to enforce the standard SWT invariants.
+ * <p>
+ * Currently, it is an error to invoke any method (other than
+ * <code>isDisposed()</code>) on a widget that has had its
+ * <code>dispose()</code> method called. It is also an error
+ * to call widget methods from any thread that is different
+ * from the thread that created the widget.
+ * </p><p>
+ * In future releases of SWT, there may be more or fewer error
+ * checks and exceptions may be thrown for different reasons.
+ * </p>
+ *
+ * @exception SWTException <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>
+ */
+protected void checkWidget () {
+ Display display = this.display;
+ if (display == null) error (SWT.ERROR_WIDGET_DISPOSED);
+ if (display.thread != Thread.currentThread () && !display.isEmbedded) error (SWT.ERROR_THREAD_INVALID_ACCESS);
+ if ((state & DISPOSED) != 0) error (SWT.ERROR_WIDGET_DISPOSED);
+}
+
+boolean textView_clickOnLink_atIndex(int /*long*/ id, int /*long*/ sel, int /*long*/ textView, int /*long*/ link, int /*long*/ charIndex) {
+ return true;
+}
+
+void collapseItem_collapseChildren (int /*long*/ id, int /*long*/ sel, int /*long*/ item, boolean children) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ OS.objc_msgSendSuper(super_struct, sel, item, children);
+}
+
+void copyToClipboard (char [] buffer) {
+ if (buffer.length == 0) return;
+ NSPasteboard pasteboard = NSPasteboard.generalPasteboard ();
+ pasteboard.declareTypes (NSArray.arrayWithObject (OS.NSStringPboardType), null);
+ pasteboard.setString (NSString.stringWithCharacters (buffer, buffer.length), OS.NSStringPboardType);
+}
+
+void createHandle () {
+}
+
+void createJNIRef () {
+ jniRef = OS.NewGlobalRef(this);
+ if (jniRef == 0) error (SWT.ERROR_NO_HANDLES);
+}
+
+void createWidget () {
+ createJNIRef ();
+ createHandle ();
+ register ();
+}
+
+void deregister () {
+}
+
+void destroyJNIRef () {
+ if (jniRef != 0) OS.DeleteGlobalRef (jniRef);
+ jniRef = 0;
+}
+
+void destroyWidget () {
+ releaseHandle ();
+}
+
+/**
+ * Disposes of the operating system resources associated with
+ * the receiver and all its descendants. After this method has
+ * been invoked, the receiver and all descendants will answer
+ * <code>true</code> when sent the message <code>isDisposed()</code>.
+ * Any internal connections between the widgets in the tree will
+ * have been removed to facilitate garbage collection.
+ * <p>
+ * NOTE: This method is not called recursively on the descendants
+ * of the receiver. This means that, widget implementers can not
+ * detect when a widget is being disposed of by re-implementing
+ * this method, but should instead listen for the <code>Dispose</code>
+ * event.
+ * </p>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see #addDisposeListener
+ * @see #removeDisposeListener
+ * @see #checkWidget
+ */
+public void dispose () {
+ /*
+ * Note: It is valid to attempt to dispose a widget
+ * more than once. If this happens, fail silently.
+ */
+ if (isDisposed ()) return;
+ if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
+ release (true);
+}
+
+void doCommandBySelector (int /*long*/ id, int /*long*/ sel, int /*long*/ aSelector) {
+ callSuper (id, sel, aSelector);
+}
+
+boolean dragSelectionWithEvent(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1, int /*long*/ arg2) {
+ return false;
+}
+
+void drawBackground (int /*long*/ id, NSGraphicsContext context, NSRect rect) {
+ /* Do nothing */
+}
+
+void drawImageWithFrameInView (int /*long*/ id, int /*long*/ sel, int /*long*/ image, NSRect rect, int /*long*/ view) {
+}
+
+void drawInteriorWithFrame_inView (int /*long*/ id, int /*long*/ sel, NSRect cellFrame, int /*long*/ view) {
+ callSuper(id, sel, cellFrame, view);
+}
+
+void drawWithExpansionFrame_inView (int /*long*/ id, int /*long*/ sel, NSRect cellFrame, int /*long*/ view) {
+ callSuper(id, sel, cellFrame, view);
+}
+
+void drawRect (int /*long*/ id, int /*long*/ sel, NSRect rect) {
+ if (!isDrawing()) return;
+ Display display = this.display;
+ NSView view = new NSView(id);
+ display.isPainting.addObject(view);
+ NSGraphicsContext context = NSGraphicsContext.currentContext();
+ context.saveGraphicsState();
+ setClipRegion(0, 0);
+ drawBackground (id, context, rect);
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ OS.objc_msgSendSuper(super_struct, sel, rect);
+ if (!isDisposed()) {
+ /*
+ * Feature in Cocoa. There are widgets that draw outside of the UI thread,
+ * such as the progress bar and default button. The fix is to draw the
+ * widget but not send paint events.
+ */
+ drawWidget (id, context, rect);
+ }
+ context.restoreGraphicsState();
+ display.isPainting.removeObjectIdenticalTo(view);
+}
+
+void _drawThemeProgressArea (int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ OS.objc_msgSendSuper(super_struct, sel, arg0);
+}
+
+void drawWidget (int /*long*/ id, NSGraphicsContext context, NSRect rect) {
+}
+
+void redrawWidget (NSView view, boolean children) {
+ view.setNeedsDisplay(true);
+}
+
+void redrawWidget (NSView view, int /*long*/ x, int /*long*/ y, int /*long*/ width, int /*long*/ height, boolean children) {
+ NSRect rect = new NSRect();
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ view.setNeedsDisplayInRect(rect);
+}
+
+void error (int code) {
+ SWT.error(code);
+}
+
+void expandItem_expandChildren (int /*long*/ id, int /*long*/ sel, int /*long*/ item, boolean children) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ OS.objc_msgSendSuper(super_struct, sel, item, children);
+}
+
+NSRect expansionFrameWithFrame_inView(int /*long*/ id, int /*long*/ sel, NSRect cellRect, int /*long*/ view) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ NSRect result = new NSRect();
+ OS.objc_msgSendSuper_stret(result, super_struct, sel, cellRect, view);
+ return result;
+}
+
+boolean filters (int eventType) {
+ return display.filters (eventType);
+}
+
+NSRect firstRectForCharacterRange(int /*long*/ id, int /*long*/ sel, int /*long*/ range) {
+ return new NSRect ();
+}
+
+int fixMnemonic (char [] buffer) {
+ int i=0, j=0;
+ while (i < buffer.length) {
+ if ((buffer [j++] = buffer [i++]) == '&') {
+ if (i == buffer.length) {continue;}
+ if (buffer [i] == '&') {i++; continue;}
+ j--;
+ }
+ }
+ return j;
+}
+
+/**
+ * Returns the application defined widget data associated
+ * with the receiver, or null if it has not been set. The
+ * <em>widget data</em> is a single, unnamed field that is
+ * stored with every widget.
+ * <p>
+ * Applications may put arbitrary objects in this field. If
+ * the object stored in the widget data needs to be notified
+ * when the widget is disposed of, it is the application's
+ * responsibility to hook the Dispose event on the widget and
+ * do so.
+ * </p>
+ *
+ * @return the widget data
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - when the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - when called from the wrong thread</li>
+ * </ul>
+ *
+ * @see #setData(Object)
+ */
+public Object getData () {
+ checkWidget();
+ return (state & KEYED_DATA) != 0 ? ((Object []) data) [0] : data;
+}
+
+/**
+ * Returns the application defined property of the receiver
+ * with the specified name, or null if it has not been set.
+ * <p>
+ * Applications may have associated arbitrary objects with the
+ * receiver in this fashion. If the objects stored in the
+ * properties need to be notified when the widget is disposed
+ * of, it is the application's responsibility to hook the
+ * Dispose event on the widget and do so.
+ * </p>
+ *
+ * @param key the name of the property
+ * @return the value of the property or null if it has not been set
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the key is null</li>
+ * </ul>
+ * @exception SWTException <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 #setData(String, Object)
+ */
+public Object getData (String key) {
+ checkWidget();
+ if (key == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if ((state & KEYED_DATA) != 0) {
+ Object [] table = (Object []) data;
+ for (int i=1; i<table.length; i+=2) {
+ if (key.equals (table [i])) return table [i+1];
+ }
+ }
+ return null;
+}
+
+/**
+ * Returns the <code>Display</code> that is associated with
+ * the receiver.
+ * <p>
+ * A widget's display is either provided when it is created
+ * (for example, top level <code>Shell</code>s) or is the
+ * same as its parent's display.
+ * </p>
+ *
+ * @return the receiver's display
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Display getDisplay () {
+ Display display = this.display;
+ if (display == null) error (SWT.ERROR_WIDGET_DISPOSED);
+ return display;
+}
+
+boolean getDrawing () {
+ return true;
+}
+
+/**
+ * Returns an array of listeners who will be notified when an event
+ * of the given type occurs. The event type is one of the event constants
+ * defined in class <code>SWT</code>.
+ *
+ * @param eventType the type of event to listen for
+ * @return an array of listeners that will be notified when the event occurs
+ *
+ * @exception SWTException <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 Listener
+ * @see SWT
+ * @see #addListener(int, Listener)
+ * @see #removeListener(int, Listener)
+ * @see #notifyListeners
+ *
+ * @since 3.4
+ */
+public Listener[] getListeners (int eventType) {
+ checkWidget();
+ if (eventTable == null) return new Listener[0];
+ return eventTable.getListeners(eventType);
+}
+
+String getName () {
+ String string = getClass ().getName ();
+ int index = string.lastIndexOf ('.');
+ if (index == -1) return string;
+ return string.substring (index + 1, string.length ());
+}
+
+String getNameText () {
+ return "";
+}
+
+/**
+ * Returns the receiver's style information.
+ * <p>
+ * Note that the value which is returned by this method <em>may
+ * not match</em> the value which was provided to the constructor
+ * when the receiver was created. This can occur when the underlying
+ * operating system does not support a particular combination of
+ * requested styles. For example, if the platform widget used to
+ * implement a particular SWT widget always has scroll bars, the
+ * result of calling this method would always have the
+ * <code>SWT.H_SCROLL</code> and <code>SWT.V_SCROLL</code> bits set.
+ * </p>
+ *
+ * @return the style bits
+ *
+ * @exception SWTException <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 getStyle () {
+ checkWidget();
+ return style;
+}
+
+boolean hasMarkedText (int /*long*/ id, int /*long*/ sel) {
+ return false;
+}
+
+void helpRequested(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+}
+
+void highlightSelectionInClipRect(int /*long*/ id, int /*long*/ sel, int /*long*/ rect) {
+}
+
+int /*long*/ hitTest (int /*long*/ id, int /*long*/ sel, NSPoint point) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ return OS.objc_msgSendSuper(super_struct, sel, point);
+}
+
+int /*long*/ hitTestForEvent (int /*long*/ id, int /*long*/ sel, int /*long*/ event, NSRect rect, int /*long*/ controlView) {
+ return 0;
+}
+
+boolean hooks (int eventType) {
+ if (eventTable == null) return false;
+ return eventTable.hooks (eventType);
+}
+
+int /*long*/ image (int /*long*/ id, int /*long*/ sel) {
+ return 0;
+}
+
+NSRect imageRectForBounds (int /*long*/ id, int /*long*/ sel, NSRect cellFrame) {
+ return new NSRect();
+}
+
+boolean insertText (int /*long*/ id, int /*long*/ sel, int /*long*/ string) {
+ callSuper (id, sel, string);
+ return true;
+}
+
+/**
+ * Returns <code>true</code> if the widget has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the widget.
+ * When a widget has been disposed, it is an error to
+ * invoke any other method using the widget.
+ * </p>
+ *
+ * @return <code>true</code> when the widget is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed () {
+ return (state & DISPOSED) != 0;
+}
+
+boolean isDrawing () {
+ return true;
+}
+
+boolean isFlipped(int /*long*/ id, int /*long*/ sel) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ return OS.objc_msgSendSuper(super_struct, sel) != 0;
+}
+
+/**
+ * Returns <code>true</code> if there are any listeners
+ * for the specified event type associated with the receiver,
+ * and <code>false</code> otherwise. The event type is one of
+ * the event constants defined in class <code>SWT</code>.
+ *
+ * @param eventType the type of event
+ * @return true if the event is hooked
+ *
+ * @exception SWTException <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 SWT
+ */
+public boolean isListening (int eventType) {
+ checkWidget();
+ return hooks (eventType);
+}
+
+boolean isOpaque(int /*long*/ id, int /*long*/ sel) {
+ return false;
+}
+
+boolean isValidSubclass () {
+ return Display.isValidClass (getClass ());
+}
+
+boolean isValidThread () {
+ return getDisplay ().isValidThread ();
+}
+
+void flagsChanged (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper (id, sel, theEvent);
+}
+
+void keyDown (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ superKeyDown(id, sel, theEvent);
+}
+
+void keyUp (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ superKeyUp(id, sel, theEvent);
+}
+
+void mouseDown(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper(id, sel, theEvent);
+}
+
+void mouseUp(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper(id, sel, theEvent);
+}
+
+void mouseMoved(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper(id, sel, theEvent);
+}
+
+void mouseDragged(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper(id, sel, theEvent);
+}
+
+void mouseEntered(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper(id, sel, theEvent);
+}
+
+void mouseExited(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper(id, sel, theEvent);
+}
+
+void cursorUpdate(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper(id, sel, theEvent);
+}
+
+void rightMouseDown(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper(id, sel, theEvent);
+}
+
+void rightMouseUp(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper(id, sel, theEvent);
+}
+
+void rightMouseDragged(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper(id, sel, theEvent);
+}
+
+void otherMouseDown(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper(id, sel, theEvent);
+}
+
+void otherMouseUp(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper(id, sel, theEvent);
+}
+
+void otherMouseDragged(int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper(id, sel, theEvent);
+}
+
+boolean shouldDelayWindowOrderingForEvent (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ return OS.objc_msgSendSuper(super_struct, sel, theEvent) != 0;
+}
+
+boolean menuHasKeyEquivalent_forEvent_target_action(int /*long*/ id, int /*long*/ sel, int /*long*/ menu, int /*long*/ event, int /*long*/ target, int /*long*/ action) {
+ return true;
+}
+
+int /*long*/ menuForEvent (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ return OS.objc_msgSendSuper(super_struct, sel, theEvent);
+}
+
+void menuNeedsUpdate(int /*long*/ id, int /*long*/ sel, int /*long*/ menu) {
+}
+
+boolean makeFirstResponder(int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+ return callSuperBoolean(id, sel, notification);
+}
+
+NSRange markedRange (int /*long*/ id, int /*long*/ sel) {
+ return new NSRange ();
+}
+
+void menu_willHighlightItem(int /*long*/ id, int /*long*/ sel, int /*long*/ menu, int /*long*/ item) {
+}
+
+void menuDidClose(int /*long*/ id, int /*long*/ sel, int /*long*/ menu) {
+}
+
+void menuWillOpen(int /*long*/ id, int /*long*/ sel, int /*long*/ menu) {
+}
+
+void noResponderFor(int /*long*/ id, int /*long*/ sel, int /*long*/ selector) {
+ callSuper(id, sel, selector);
+}
+
+int /*long*/ numberOfRowsInTableView(int /*long*/ id, int /*long*/ sel, int /*long*/ aTableView) {
+ return 0;
+}
+
+int /*long*/ outlineView_child_ofItem(int /*long*/ id, int /*long*/ sel, int /*long*/ outlineView, int /*long*/ index, int /*long*/ item) {
+ return 0;
+}
+
+void outlineView_didClickTableColumn(int /*long*/ id, int /*long*/ sel, int /*long*/ outlineView, int /*long*/ tableColumn) {
+}
+
+int /*long*/ outlineView_objectValueForTableColumn_byItem(int /*long*/ id, int /*long*/ sel, int /*long*/ outlineView, int /*long*/ tableColumn, int /*long*/ item) {
+ return 0;
+}
+
+boolean outlineView_isItemExpandable(int /*long*/ id, int /*long*/ sel, int /*long*/ outlineView, int /*long*/ item) {
+ return false;
+}
+
+int /*long*/ outlineView_numberOfChildrenOfItem(int /*long*/ id, int /*long*/ sel, int /*long*/ outlineView, int /*long*/ item) {
+ return 0;
+}
+
+void outlineView_willDisplayCell_forTableColumn_item(int /*long*/ id, int /*long*/ sel, int /*long*/ outlineView, int /*long*/ cell, int /*long*/ tableColumn, int /*long*/ item) {
+}
+
+void outlineViewColumnDidMove (int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+}
+
+void outlineViewColumnDidResize (int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+}
+
+void outlineViewSelectionDidChange(int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+}
+
+void outlineView_setObjectValue_forTableColumn_byItem(int /*long*/ id, int /*long*/ sel, int /*long*/ outlineView, int /*long*/ object, int /*long*/ tableColumn, int /*long*/ item) {
+}
+
+boolean outlineView_writeItems_toPasteboard(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1, int /*long*/ arg2) {
+ return false;
+}
+
+
+/**
+ * Notifies all of the receiver's listeners for events
+ * of the given type that one such event has occurred by
+ * invoking their <code>handleEvent()</code> method. The
+ * event type is one of the event constants defined in class
+ * <code>SWT</code>.
+ *
+ * @param eventType the type of event which has occurred
+ * @param event the event data
+ *
+ * @exception SWTException <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 SWT
+ * @see #addListener
+ * @see #getListeners(int)
+ * @see #removeListener(int, Listener)
+ */
+public void notifyListeners (int eventType, Event event) {
+ checkWidget();
+ if (event == null) event = new Event ();
+ sendEvent (eventType, event);
+}
+
+void pageDown (int /*long*/ id, int /*long*/ sel, int /*long*/ sender) {
+ callSuper(id, sel, sender);
+}
+
+void pageUp (int /*long*/ id, int /*long*/ sel, int /*long*/ sender) {
+ callSuper(id, sel, sender);
+}
+
+void postEvent (int eventType) {
+ sendEvent (eventType, null, false);
+}
+
+void postEvent (int eventType, Event event) {
+ sendEvent (eventType, event, false);
+}
+
+void reflectScrolledClipView (int /*long*/ id, int /*long*/ sel, int /*long*/ aClipView) {
+ callSuper (id, sel, aClipView);
+}
+
+void register () {
+}
+
+void release (boolean destroy) {
+ if ((state & DISPOSE_SENT) == 0) {
+ state |= DISPOSE_SENT;
+ sendEvent (SWT.Dispose);
+ }
+ if ((state & DISPOSED) == 0) {
+ releaseChildren (destroy);
+ }
+ if ((state & RELEASED) == 0) {
+ state |= RELEASED;
+ if (destroy) {
+ releaseParent ();
+ releaseWidget ();
+ destroyWidget ();
+ } else {
+ releaseWidget ();
+ releaseHandle ();
+ }
+ }
+}
+
+void releaseChildren (boolean destroy) {
+}
+
+void releaseHandle () {
+ state |= DISPOSED;
+ display = null;
+ destroyJNIRef ();
+}
+
+void releaseParent () {
+ /* Do nothing */
+}
+
+void releaseWidget () {
+ deregister ();
+ if (display.tooltipTarget == this) display.tooltipTarget = null;
+ eventTable = null;
+ data = null;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when an event of the given type occurs. The event
+ * type is one of the event constants defined in class <code>SWT</code>.
+ *
+ * @param eventType the type of event to listen for
+ * @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 SWTException <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 Listener
+ * @see SWT
+ * @see #addListener
+ * @see #getListeners(int)
+ * @see #notifyListeners
+ */
+public void removeListener (int eventType, Listener handler) {
+ checkWidget();
+ if (handler == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (eventType, handler);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when an event of the given type occurs.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It should never be
+ * referenced from application code.
+ * </p>
+ *
+ * @param eventType the type of event to listen for
+ * @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 SWTException <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 Listener
+ * @see #addListener
+ */
+protected void removeListener (int eventType, SWTEventListener handler) {
+ checkWidget();
+ if (handler == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (eventType, handler);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the widget is disposed.
+ *
+ * @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 SWTException <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 DisposeListener
+ * @see #addDisposeListener
+ */
+public void removeDisposeListener (DisposeListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Dispose, listener);
+}
+
+void scrollWheel (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper(id, sel, theEvent);
+}
+
+NSRange selectedRange (int /*long*/ id, int /*long*/ sel) {
+ return new NSRange ();
+}
+
+int /*long*/ nextValidKeyView (int /*long*/ id, int /*long*/ sel) {
+ return callSuperObject(id, sel);
+}
+
+int /*long*/ previousValidKeyView (int /*long*/ id, int /*long*/ sel) {
+ return callSuperObject(id, sel);
+}
+
+void sendDoubleSelection() {
+}
+
+void sendEvent (Event event) {
+ display.sendEvent (eventTable, event);
+}
+
+void sendEvent (int eventType) {
+ sendEvent (eventType, null, true);
+}
+
+void sendEvent (int eventType, Event event) {
+ sendEvent (eventType, event, true);
+}
+
+void sendEvent (int eventType, Event event, boolean send) {
+ if (eventTable == null && !display.filters (eventType)) {
+ return;
+ }
+ if (event == null) event = new Event ();
+ event.type = eventType;
+ event.display = display;
+ event.widget = this;
+ if (event.time == 0) {
+ event.time = display.getLastEventTime ();
+ }
+ if (send) {
+ sendEvent (event);
+ } else {
+ display.postEvent (event);
+ }
+}
+
+boolean sendKeyEvent (NSEvent nsEvent, int type) {
+ if ((state & SAFARI_EVENTS_FIX) != 0) return true;
+ Event event = new Event ();
+ if (!setKeyState (event, type, nsEvent)) return true;
+ return sendKeyEvent (type, event);
+}
+
+boolean sendKeyEvent (int type, Event event) {
+ sendEvent (type, event);
+ // widget could be disposed at this point
+
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the key
+ * events. If this happens, end the processing of
+ * the key by returning false.
+ */
+ if (isDisposed ()) return false;
+ return event.doit;
+}
+
+void sendHorizontalSelection () {
+}
+
+void sendCancelSelection () {
+}
+
+void sendSearchSelection () {
+}
+
+void sendSelection () {
+}
+
+void sendVerticalSelection () {
+}
+
+/**
+ * Sets the application defined widget data associated
+ * with the receiver to be the argument. The <em>widget
+ * data</em> is a single, unnamed field that is stored
+ * with every widget.
+ * <p>
+ * Applications may put arbitrary objects in this field. If
+ * the object stored in the widget data needs to be notified
+ * when the widget is disposed of, it is the application's
+ * responsibility to hook the Dispose event on the widget and
+ * do so.
+ * </p>
+ *
+ * @param data the widget data
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - when the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - when called from the wrong thread</li>
+ * </ul>
+ *
+ * @see #getData()
+ */
+public void setData (Object data) {
+ checkWidget();
+ if (SAFARI_EVENTS_FIX_KEY.equals (data)) {
+ state |= SAFARI_EVENTS_FIX;
+ return;
+ }
+ if ((state & KEYED_DATA) != 0) {
+ ((Object []) this.data) [0] = data;
+ } else {
+ this.data = data;
+ }
+}
+
+/**
+ * Sets the application defined property of the receiver
+ * with the specified name to the given value.
+ * <p>
+ * Applications may associate arbitrary objects with the
+ * receiver in this fashion. If the objects stored in the
+ * properties need to be notified when the widget is disposed
+ * of, it is the application's responsibility to hook the
+ * Dispose event on the widget and do so.
+ * </p>
+ *
+ * @param key the name of the property
+ * @param value the new value for the property
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the key is null</li>
+ * </ul>
+ * @exception SWTException <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 #getData(String)
+ */
+public void setData (String key, Object value) {
+ checkWidget();
+ if (key == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (GLCONTEXT_KEY.equals (key)) {
+ setOpenGLContext(value);
+ return;
+ }
+ int index = 1;
+ Object [] table = null;
+ if ((state & KEYED_DATA) != 0) {
+ table = (Object []) data;
+ while (index < table.length) {
+ if (key.equals (table [index])) break;
+ index += 2;
+ }
+ }
+ if (value != null) {
+ if ((state & KEYED_DATA) != 0) {
+ if (index == table.length) {
+ Object [] newTable = new Object [table.length + 2];
+ System.arraycopy (table, 0, newTable, 0, table.length);
+ data = table = newTable;
+ }
+ } else {
+ table = new Object [3];
+ table [0] = data;
+ data = table;
+ state |= KEYED_DATA;
+ }
+ table [index] = key;
+ table [index + 1] = value;
+ } else {
+ if ((state & KEYED_DATA) != 0) {
+ if (index != table.length) {
+ int length = table.length - 2;
+ if (length == 1) {
+ data = table [0];
+ state &= ~KEYED_DATA;
+ } else {
+ Object [] newTable = new Object [length];
+ System.arraycopy (table, 0, newTable, 0, index);
+ System.arraycopy (table, index + 2, newTable, index, length - index);
+ data = newTable;
+ }
+ }
+ }
+ }
+}
+
+void setOpenGLContext(Object value) {
+}
+
+void setFrameOrigin (int /*long*/ id, int /*long*/ sel, NSPoint point) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ OS.objc_msgSendSuper(super_struct, sel, point);
+}
+
+void setFrameSize (int /*long*/ id, int /*long*/ sel, NSSize size) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ OS.objc_msgSendSuper(super_struct, sel, size);
+}
+
+void setImage (int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+}
+
+boolean setInputState (Event event, NSEvent nsEvent, int type) {
+ if (nsEvent == null) return true;
+ int /*long*/ modifierFlags = nsEvent.modifierFlags();
+ if ((modifierFlags & OS.NSAlternateKeyMask) != 0) event.stateMask |= SWT.ALT;
+ if ((modifierFlags & OS.NSShiftKeyMask) != 0) event.stateMask |= SWT.SHIFT;
+ if ((modifierFlags & OS.NSControlKeyMask) != 0) event.stateMask |= SWT.CONTROL;
+ if ((modifierFlags & OS.NSCommandKeyMask) != 0) event.stateMask |= SWT.COMMAND;
+ //TODO multiple mouse buttons pressed
+ switch ((int)/*64*/nsEvent.type()) {
+ case OS.NSLeftMouseDragged:
+ case OS.NSRightMouseDragged:
+ case OS.NSOtherMouseDragged:
+ switch ((int)/*64*/nsEvent.buttonNumber()) {
+ case 0: event.stateMask |= SWT.BUTTON1; break;
+ case 1: event.stateMask |= SWT.BUTTON3; break;
+ case 2: event.stateMask |= SWT.BUTTON2; break;
+ case 3: event.stateMask |= SWT.BUTTON4; break;
+ case 4: event.stateMask |= SWT.BUTTON5; break;
+ }
+ break;
+ case OS.NSScrollWheel:
+ case OS.NSKeyDown:
+ case OS.NSKeyUp:
+ int state = OS.GetCurrentButtonState ();
+ if ((state & 0x1) != 0) event.stateMask |= SWT.BUTTON1;
+ if ((state & 0x2) != 0) event.stateMask |= SWT.BUTTON3;
+ if ((state & 0x4) != 0) event.stateMask |= SWT.BUTTON2;
+ if ((state & 0x8) != 0) event.stateMask |= SWT.BUTTON4;
+ if ((state & 0x10) != 0) event.stateMask |= SWT.BUTTON5;
+ break;
+ }
+ switch (type) {
+ case SWT.MouseDown:
+ case SWT.MouseDoubleClick:
+ if (event.button == 1) event.stateMask &= ~SWT.BUTTON1;
+ if (event.button == 2) event.stateMask &= ~SWT.BUTTON2;
+ if (event.button == 3) event.stateMask &= ~SWT.BUTTON3;
+ if (event.button == 4) event.stateMask &= ~SWT.BUTTON4;
+ if (event.button == 5) event.stateMask &= ~SWT.BUTTON5;
+ break;
+ case SWT.MouseUp:
+ if (event.button == 1) event.stateMask |= SWT.BUTTON1;
+ if (event.button == 2) event.stateMask |= SWT.BUTTON2;
+ if (event.button == 3) event.stateMask |= SWT.BUTTON3;
+ if (event.button == 4) event.stateMask |= SWT.BUTTON4;
+ if (event.button == 5) event.stateMask |= SWT.BUTTON5;
+ break;
+ case SWT.KeyDown:
+ case SWT.Traverse:
+ if (event.keyCode == SWT.ALT) event.stateMask &= ~SWT.ALT;
+ if (event.keyCode == SWT.SHIFT) event.stateMask &= ~SWT.SHIFT;
+ if (event.keyCode == SWT.CONTROL) event.stateMask &= ~SWT.CONTROL;
+ if (event.keyCode == SWT.COMMAND) event.stateMask &= ~SWT.COMMAND;
+ break;
+ case SWT.KeyUp:
+ if (event.keyCode == SWT.ALT) event.stateMask |= SWT.ALT;
+ if (event.keyCode == SWT.SHIFT) event.stateMask |= SWT.SHIFT;
+ if (event.keyCode == SWT.CONTROL) event.stateMask |= SWT.CONTROL;
+ if (event.keyCode == SWT.COMMAND) event.stateMask |= SWT.COMMAND;
+ break;
+ }
+ return true;
+}
+
+boolean setKeyState (Event event, int type, NSEvent nsEvent) {
+ boolean isNull = false;
+ int keyCode = nsEvent.keyCode ();
+ event.keyCode = Display.translateKey (keyCode);
+ switch (event.keyCode) {
+ case SWT.LF: {
+ /*
+ * Feature in the Macintosh. When the numeric key pad
+ * Enter key is pressed, it generates '\n'. This is the
+ * correct platform behavior but is not portable. The
+ * fix is to convert the '\n' into '\r'.
+ */
+ event.keyCode = SWT.KEYPAD_CR;
+ event.character = '\r';
+ break;
+ }
+ case SWT.BS: event.character = '\b'; break;
+ case SWT.CR: event.character = '\r'; break;
+ case SWT.DEL: event.character = 0x7F; break;
+ case SWT.ESC: event.character = 0x1B; break;
+ case SWT.TAB: event.character = '\t'; break;
+ default:
+ if (event.keyCode == 0 || (SWT.KEYPAD_MULTIPLY <= event.keyCode && event.keyCode <= SWT.KEYPAD_CR)) {
+ NSString chars = nsEvent.characters ();
+ if (chars.length() > 0) event.character = (char)chars.characterAtIndex (0);
+ }
+ if (event.keyCode == 0) {
+ int /*long*/ uchrPtr = 0;
+ int /*long*/ currentKbd = OS.TISCopyCurrentKeyboardInputSource();
+ int /*long*/ uchrCFData = OS.TISGetInputSourceProperty(currentKbd, OS.kTISPropertyUnicodeKeyLayoutData());
+
+ if (uchrCFData != 0) {
+ // If the keyboard changed since the last keystroke clear the dead key state.
+ if (uchrCFData != display.currentKeyboardUCHRdata) display.deadKeyState[0] = 0;
+ uchrPtr = OS.CFDataGetBytePtr(uchrCFData);
+
+ if (uchrPtr != 0 && OS.CFDataGetLength(uchrCFData) > 0) {
+ int /*long*/ cgEvent = nsEvent.CGEvent();
+ long keyboardType = OS.CGEventGetIntegerValueField(cgEvent, OS.kCGKeyboardEventKeyboardType);
+
+ int maxStringLength = 256;
+ char [] output = new char [maxStringLength];
+ int [] actualStringLength = new int [1];
+ OS.UCKeyTranslate (uchrPtr, (short)keyCode, (short)OS.kUCKeyActionDown, 0, (int)keyboardType, 0, display.deadKeyState, maxStringLength, actualStringLength, output);
+ if (actualStringLength[0] < 1) {
+ // part of a multi-key key
+ event.keyCode = 0;
+ } else {
+ event.keyCode = output[0];
+ }
+ }
+ } else {
+ // KCHR keyboard layouts are no longer supported, so fall back to the basic but flawed
+ // method of determining which key was pressed.
+ NSString unmodifiedChars = nsEvent.charactersIgnoringModifiers ().lowercaseString();
+ if (unmodifiedChars.length() > 0) event.keyCode = (char)unmodifiedChars.characterAtIndex(0);
+ }
+
+ if (currentKbd != 0) OS.CFRelease(currentKbd);
+ }
+ }
+ if (event.keyCode == 0 && event.character == 0) {
+ if (!isNull) return false;
+ }
+ setInputState (event, nsEvent, type);
+ return true;
+}
+
+boolean setMarkedText_selectedRange (int /*long*/ id, int /*long*/ sel, int /*long*/ string, int /*long*/ range) {
+ return true;
+}
+
+void setNeedsDisplay (int /*long*/ id, int /*long*/ sel, boolean flag) {
+ if (flag && !isDrawing()) return;
+ NSView view = new NSView(id);
+ if (flag && display.isPainting.containsObject(view)) {
+ NSMutableArray needsDisplay = display.needsDisplay;
+ if (needsDisplay == null) {
+ needsDisplay = (NSMutableArray)new NSMutableArray().alloc();
+ display.needsDisplay = needsDisplay = needsDisplay.initWithCapacity(12);
+ }
+ needsDisplay.addObject(view);
+ return;
+ }
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ OS.objc_msgSendSuper(super_struct, sel, flag);
+}
+
+void setNeedsDisplayInRect (int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ if (!isDrawing()) return;
+ NSRect rect = new NSRect();
+ OS.memmove(rect, arg0, NSRect.sizeof);
+ NSView view = new NSView(id);
+ if (display.isPainting.containsObject(view)) {
+ NSMutableArray needsDisplayInRect = display.needsDisplayInRect;
+ if (needsDisplayInRect == null) {
+ needsDisplayInRect = (NSMutableArray)new NSMutableArray().alloc();
+ display.needsDisplayInRect = needsDisplayInRect = needsDisplayInRect.initWithCapacity(12);
+ }
+ needsDisplayInRect.addObject(view);
+ needsDisplayInRect.addObject(NSValue.valueWithRect(rect));
+ return;
+ }
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ OS.objc_msgSendSuper(super_struct, sel, rect);
+}
+
+void setObjectValue(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ callSuper(id, sel, arg0);
+}
+
+boolean setTabGroupFocus () {
+ return setTabItemFocus ();
+}
+
+boolean setTabItemFocus () {
+ return false;
+}
+
+boolean shouldChangeTextInRange_replacementString(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1) {
+ return true;
+}
+
+void superKeyDown (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper (id, sel, theEvent);
+}
+
+void superKeyUp (int /*long*/ id, int /*long*/ sel, int /*long*/ theEvent) {
+ callSuper (id, sel, theEvent);
+}
+
+void tableViewColumnDidMove (int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+}
+
+void tableViewColumnDidResize (int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+}
+
+void tableViewSelectionDidChange (int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+}
+
+void tableView_didClickTableColumn(int /*long*/ id, int /*long*/ sel, int /*long*/ tableView, int /*long*/ tableColumn) {
+}
+
+int /*long*/ tableView_objectValueForTableColumn_row(int /*long*/ id, int /*long*/ sel, int /*long*/ aTableView, int /*long*/ aTableColumn, int /*long*/ rowIndex) {
+ return 0;
+}
+
+void tableView_setObjectValue_forTableColumn_row(int /*long*/ id, int /*long*/ sel, int /*long*/ aTableView, int /*long*/ anObject, int /*long*/ aTableColumn, int /*long*/ rowIndex) {
+}
+
+boolean tableView_shouldEditTableColumn_row(int /*long*/ id, int /*long*/ sel, int /*long*/ aTableView, int /*long*/ aTableColumn, int /*long*/ rowIndex) {
+ return true;
+}
+
+void tableView_willDisplayCell_forTableColumn_row(int /*long*/ id, int /*long*/ sel, int /*long*/ aTableView, int /*long*/ aCell, int /*long*/ aTableColumn, int /*long*/ rowIndex) {
+}
+
+void textViewDidChangeSelection(int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+}
+
+void textDidChange(int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+ callSuper (id, sel, aNotification);
+}
+
+void textDidEndEditing(int /*long*/ id, int /*long*/ sel, int /*long*/ aNotification) {
+ callSuper(id, sel, aNotification);
+}
+
+NSRange textView_willChangeSelectionFromCharacterRange_toCharacterRange(int /*long*/ id, int /*long*/ sel, int /*long*/ aTextView, int /*long*/ oldSelectedCharRange, int /*long*/ newSelectedCharRange) {
+ return new NSRange();
+}
+
+NSRect titleRectForBounds (int /*long*/ id, int /*long*/ sel, NSRect cellFrame) {
+ objc_super super_struct = new objc_super();
+ super_struct.receiver = id;
+ super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
+ NSRect result = new NSRect();
+ OS.objc_msgSendSuper_stret(result, super_struct, sel, cellFrame);
+ return result;
+}
+
+String tooltipText () {
+ return null;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+public String toString () {
+ String string = "*Disposed*";
+ if (!isDisposed ()) {
+ string = "*Wrong Thread*";
+ if (isValidThread ()) string = getNameText ();
+ }
+ return getName () + " {" + string + "}";
+}
+
+void resetCursorRects (int /*long*/ id, int /*long*/ sel) {
+ callSuper (id, sel);
+}
+
+void updateTrackingAreas (int /*long*/ id, int /*long*/ sel) {
+ callSuper (id, sel);
+}
+
+int /*long*/ validAttributesForMarkedText (int /*long*/ id, int /*long*/ sel) {
+ return 0;
+}
+
+void tabView_didSelectTabViewItem(int /*long*/ id, int /*long*/ sel, int /*long*/ tabView, int /*long*/ tabViewItem) {
+}
+
+void tabView_willSelectTabViewItem(int /*long*/ id, int /*long*/ sel, int /*long*/ tabView, int /*long*/ tabViewItem) {
+}
+
+boolean tableView_writeRowsWithIndexes_toPasteboard(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1, int /*long*/ arg2) {
+ return false;
+}
+
+int /*long*/ view_stringForToolTip_point_userData (int /*long*/ id, int /*long*/ sel, int /*long*/ view, int /*long*/ tag, int /*long*/ point, int /*long*/ userData) {
+ return 0;
+}
+
+void viewDidMoveToWindow(int /*long*/ id, int /*long*/ sel) {
+}
+
+void windowDidMove(int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+}
+
+void windowDidResize(int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+}
+
+void windowDidResignKey(int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+}
+
+void windowDidBecomeKey(int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+}
+
+void windowSendEvent(int /*long*/ id, int /*long*/ sel, int /*long*/ event) {
+ callSuper(id, sel, event);
+}
+
+boolean windowShouldClose(int /*long*/ id, int /*long*/ sel, int /*long*/ window) {
+ return false;
+}
+
+void windowWillClose(int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+}
+
+int /*long*/ nextState(int /*long*/ id, int /*long*/ sel) {
+ return callSuperObject(id, sel);
+}
+
+void updateOpenGLContext(int /*long*/ id, int /*long*/ sel, int /*long*/ notification) {
+}
+
+}