diff options
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT/win32')
54 files changed, 44772 insertions, 44772 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Color.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Color.java index 738893f329..5b3b428410 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Color.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Color.java @@ -1,330 +1,330 @@ -package org.eclipse.swt.graphics;
-
-/*
+package org.eclipse.swt.graphics; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-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
- */
-
-public final class Color {
-
- /**
- * the handle to the OS color resource
- * (Warning: This field is platform dependent)
- */
- public int handle;
-
- /**
- * the device where this color was created
- */
- Device device;
-
-/**
- * Prevents uninitialized instances from being created outside the package.
- */
-Color() {
-}
-
-/**
- * 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) {
- if (device == null) device = Device.getDevice();
- if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- init(device, red, green, blue);
- if (device.tracking) device.new_Object(this);
-}
-
-/**
- * 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) {
- if (device == null) device = Device.getDevice();
- if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- if (rgb == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- init(device, rgb.red, rgb.green, rgb.blue);
- if (device.tracking) device.new_Object(this);
-}
-
-/**
- * Disposes of the operating system resources associated with
- * the color. Applications must dispose of all colors which
- * they allocate.
- */
-public void dispose() {
- if (handle == -1) return;
- if (device.isDisposed()) return;
-
- /*
- * If this is a palette-based device,
- * Decrease the reference count for this color.
- * If the reference count reaches 0, the slot may
- * be reused when another color is allocated.
- */
- int hPal = device.hPalette;
- if (hPal != 0) {
- int index = OS.GetNearestPaletteIndex(hPal, handle);
- int[] colorRefCount = device.colorRefCount;
- if (colorRefCount[index] > 0) {
- colorRefCount[index]--;
- }
- }
- handle = -1;
- if (device.tracking) device.dispose_Object(this);
- device = 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;
- return device == color.device && (handle & 0xFFFFFF) == (color.handle & 0xFFFFFF);
-}
-
-/**
- * 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 (handle & 0xFF0000) >> 16;
-}
-
-/**
- * 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 (handle & 0xFF00) >> 8 ;
-}
-
-/**
- * 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 handle & 0xFF;
-}
-
-/**
- * Returns an <code>RGB</code> representing the receiver.
- *
- * @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(handle & 0xFF, (handle & 0xFF00) >> 8, (handle & 0xFF0000) >> 16);
-}
-
-/**
- * Returns an integer hash code for the receiver. Any two
- * objects which 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;
-}
-
-/**
- * Allocates the operating system resources associated
- * with the receiver.
- *
- * @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_INVALID_ARGUMENT - if the red, green or blue argument is not between 0 and 255</li>
- * </ul>
- *
- * @see #dispose
- */
-void init(Device device, 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);
- }
- this.device = device;
- handle = 0x02000000 | (red & 0xFF) | ((green & 0xFF) << 8) | ((blue & 0xFF) << 16);
-
- /* If this is not a palette-based device, return */
- int hPal = device.hPalette;
- if (hPal == 0) return;
-
- int[] colorRefCount = device.colorRefCount;
- /* Add this color to the default palette now */
- /* First find out if the color already exists */
- int index = OS.GetNearestPaletteIndex(hPal, handle);
- /* See if the nearest color actually is the color */
- byte[] entry = new byte[4];
- OS.GetPaletteEntries(hPal, index, 1, entry);
- if ((entry[0] == (byte)red) && (entry[1] == (byte)green) &&
- (entry[2] == (byte)blue)) {
- /* Found the color. Increment the ref count and return */
- colorRefCount[index]++;
- return;
- }
- /* Didn't find the color, allocate it now. Find the first free entry */
- int i = 0;
- while (i < colorRefCount.length) {
- if (colorRefCount[i] == 0) {
- index = i;
- break;
- }
- i++;
- }
- if (i == colorRefCount.length) {
- /* No free entries, use the closest one */
- /* Remake the handle from the actual rgbs */
- handle = (entry[0] & 0xFF) | ((entry[1] & 0xFF) << 8) |
- ((entry[2] & 0xFF) << 16);
- } else {
- /* Found a free entry */
- entry = new byte[] { (byte)(red & 0xFF), (byte)(green & 0xFF), (byte)(blue & 0xFF), 0 };
- OS.SetPaletteEntries(hPal, index, 1, entry);
- }
- colorRefCount[index]++;
-}
-
-/**
- * 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 == -1;
-}
-
-/**
- * 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() + "}";
-}
-
-/**
- * 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 win32_new(Device device, int handle) {
- if (device == null) device = Device.getDevice();
- Color color = new Color();
- color.handle = handle;
- color.device = device;
- return color;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +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 + */ + +public final class Color { + + /** + * the handle to the OS color resource + * (Warning: This field is platform dependent) + */ + public int handle; + + /** + * the device where this color was created + */ + Device device; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Color() { +} + +/** + * 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) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, red, green, blue); + if (device.tracking) device.new_Object(this); +} + +/** + * 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) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (rgb == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, rgb.red, rgb.green, rgb.blue); + if (device.tracking) device.new_Object(this); +} + +/** + * Disposes of the operating system resources associated with + * the color. Applications must dispose of all colors which + * they allocate. + */ +public void dispose() { + if (handle == -1) return; + if (device.isDisposed()) return; + + /* + * If this is a palette-based device, + * Decrease the reference count for this color. + * If the reference count reaches 0, the slot may + * be reused when another color is allocated. + */ + int hPal = device.hPalette; + if (hPal != 0) { + int index = OS.GetNearestPaletteIndex(hPal, handle); + int[] colorRefCount = device.colorRefCount; + if (colorRefCount[index] > 0) { + colorRefCount[index]--; + } + } + handle = -1; + if (device.tracking) device.dispose_Object(this); + device = 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; + return device == color.device && (handle & 0xFFFFFF) == (color.handle & 0xFFFFFF); +} + +/** + * 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 (handle & 0xFF0000) >> 16; +} + +/** + * 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 (handle & 0xFF00) >> 8 ; +} + +/** + * 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 handle & 0xFF; +} + +/** + * Returns an <code>RGB</code> representing the receiver. + * + * @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(handle & 0xFF, (handle & 0xFF00) >> 8, (handle & 0xFF0000) >> 16); +} + +/** + * Returns an integer hash code for the receiver. Any two + * objects which 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; +} + +/** + * Allocates the operating system resources associated + * with the receiver. + * + * @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_INVALID_ARGUMENT - if the red, green or blue argument is not between 0 and 255</li> + * </ul> + * + * @see #dispose + */ +void init(Device device, 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); + } + this.device = device; + handle = 0x02000000 | (red & 0xFF) | ((green & 0xFF) << 8) | ((blue & 0xFF) << 16); + + /* If this is not a palette-based device, return */ + int hPal = device.hPalette; + if (hPal == 0) return; + + int[] colorRefCount = device.colorRefCount; + /* Add this color to the default palette now */ + /* First find out if the color already exists */ + int index = OS.GetNearestPaletteIndex(hPal, handle); + /* See if the nearest color actually is the color */ + byte[] entry = new byte[4]; + OS.GetPaletteEntries(hPal, index, 1, entry); + if ((entry[0] == (byte)red) && (entry[1] == (byte)green) && + (entry[2] == (byte)blue)) { + /* Found the color. Increment the ref count and return */ + colorRefCount[index]++; + return; + } + /* Didn't find the color, allocate it now. Find the first free entry */ + int i = 0; + while (i < colorRefCount.length) { + if (colorRefCount[i] == 0) { + index = i; + break; + } + i++; + } + if (i == colorRefCount.length) { + /* No free entries, use the closest one */ + /* Remake the handle from the actual rgbs */ + handle = (entry[0] & 0xFF) | ((entry[1] & 0xFF) << 8) | + ((entry[2] & 0xFF) << 16); + } else { + /* Found a free entry */ + entry = new byte[] { (byte)(red & 0xFF), (byte)(green & 0xFF), (byte)(blue & 0xFF), 0 }; + OS.SetPaletteEntries(hPal, index, 1, entry); + } + colorRefCount[index]++; +} + +/** + * 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 == -1; +} + +/** + * 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() + "}"; +} + +/** + * 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 win32_new(Device device, int handle) { + if (device == null) device = Device.getDevice(); + Color color = new Color(); + color.handle = handle; + color.device = device; + return color; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Cursor.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Cursor.java index 945ddbc1aa..00f4435954 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Cursor.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Cursor.java @@ -1,404 +1,404 @@ -package org.eclipse.swt.graphics;
-
-/*
+package org.eclipse.swt.graphics; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-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>
- */
-
-public final class Cursor {
-
- /**
- * the handle to the OS cursor resource
- * (Warning: This field is platform dependent)
- */
- public int handle;
-
- /**
- * the device where this cursor was created
- */
- Device device;
-
- /**
- * data used to create a HAND cursor.
- */
- static final byte[] HAND_SOURCE = {
- (byte)0xf9,(byte)0xff,(byte)0xff,(byte)0xff,
- (byte)0xf0,(byte)0xff,(byte)0xff,(byte)0xff,
- (byte)0xf0,(byte)0xff,(byte)0xff,(byte)0xff,
- (byte)0xf0,(byte)0xff,(byte)0xff,(byte)0xff,
- (byte)0xf0,(byte)0x3f,(byte)0xff,(byte)0xff,
- (byte)0xf0,(byte)0x07,(byte)0xff,(byte)0xff,
- (byte)0xf0,(byte)0x03,(byte)0xff,(byte)0xff,
- (byte)0xf0,(byte)0x00,(byte)0xff,(byte)0xff,
-
- (byte)0x10,(byte)0x00,(byte)0x7f,(byte)0xff,
- (byte)0x00,(byte)0x00,(byte)0x7f,(byte)0xff,
- (byte)0x80,(byte)0x00,(byte)0x7f,(byte)0xff,
- (byte)0xc0,(byte)0x00,(byte)0x7f,(byte)0xff,
- (byte)0xe0,(byte)0x00,(byte)0x7f,(byte)0xff,
- (byte)0xf0,(byte)0x00,(byte)0x7f,(byte)0xff,
- (byte)0xf8,(byte)0x00,(byte)0xff,(byte)0xff,
- (byte)0xfc,(byte)0x01,(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)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)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
- };
- static final byte[] HAND_MASK = {
- (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
- (byte)0x06,(byte)0x00,(byte)0x00,(byte)0x00,
- (byte)0x06,(byte)0x00,(byte)0x00,(byte)0x00,
- (byte)0x06,(byte)0x00,(byte)0x00,(byte)0x00,
- (byte)0x06,(byte)0x00,(byte)0x00,(byte)0x00,
- (byte)0x06,(byte)0xc0,(byte)0x00,(byte)0x00,
- (byte)0x06,(byte)0xd8,(byte)0x00,(byte)0x00,
- (byte)0x06,(byte)0xd8,(byte)0x00,(byte)0x00,
-
- (byte)0x07,(byte)0xdb,(byte)0x00,(byte)0x00,
- (byte)0x67,(byte)0xfb,(byte)0x00,(byte)0x00,
- (byte)0x3f,(byte)0xff,(byte)0x00,(byte)0x00,
- (byte)0x1f,(byte)0xff,(byte)0x00,(byte)0x00,
- (byte)0x0f,(byte)0xff,(byte)0x00,(byte)0x00,
- (byte)0x07,(byte)0xff,(byte)0x00,(byte)0x00,
- (byte)0x03,(byte)0xfe,(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
- };
-
-/**
- * Prevents uninitialized instances from being created outside the package.
- */
-Cursor() {
-}
-
-/**
- * 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) {
- if (device == null) device = Device.getDevice();
- if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- this.device = device;
- int lpCursorName = 0;
- switch (style) {
- case SWT.CURSOR_HAND: lpCursorName = OS.IDC_HAND; break;
- case SWT.CURSOR_ARROW: lpCursorName = OS.IDC_ARROW; break;
- case SWT.CURSOR_WAIT: lpCursorName = OS.IDC_WAIT; break;
- case SWT.CURSOR_CROSS: lpCursorName = OS.IDC_CROSS; break;
- case SWT.CURSOR_APPSTARTING: lpCursorName = OS.IDC_APPSTARTING; break;
- case SWT.CURSOR_HELP: lpCursorName = OS.IDC_HELP; break;
- case SWT.CURSOR_SIZEALL: lpCursorName = OS.IDC_SIZEALL; break;
- case SWT.CURSOR_SIZENESW: lpCursorName = OS.IDC_SIZENESW; break;
- case SWT.CURSOR_SIZENS: lpCursorName = OS.IDC_SIZENS; break;
- case SWT.CURSOR_SIZENWSE: lpCursorName = OS.IDC_SIZENWSE; break;
- case SWT.CURSOR_SIZEWE: lpCursorName = OS.IDC_SIZEWE; break;
- case SWT.CURSOR_SIZEN: lpCursorName = OS.IDC_SIZENS; break;
- case SWT.CURSOR_SIZES: lpCursorName = OS.IDC_SIZENS; break;
- case SWT.CURSOR_SIZEE: lpCursorName = OS.IDC_SIZEWE; break;
- case SWT.CURSOR_SIZEW: lpCursorName = OS.IDC_SIZEWE; break;
- case SWT.CURSOR_SIZENE: lpCursorName = OS.IDC_SIZENESW; break;
- case SWT.CURSOR_SIZESE: lpCursorName = OS.IDC_SIZENWSE; break;
- case SWT.CURSOR_SIZESW: lpCursorName = OS.IDC_SIZENESW; break;
- case SWT.CURSOR_SIZENW: lpCursorName = OS.IDC_SIZENWSE; break;
- case SWT.CURSOR_UPARROW: lpCursorName = OS.IDC_UPARROW; break;
- case SWT.CURSOR_IBEAM: lpCursorName = OS.IDC_IBEAM; break;
- case SWT.CURSOR_NO: lpCursorName = OS.IDC_NO; break;
- default:
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- }
- handle = OS.LoadCursor(0, lpCursorName);
- /*
- * IDC_HAND is supported only on Windows 2000 and Windows 98.
- * Create a hand cursor if running in other Windows platforms.
- */
- if (handle == 0 && style == SWT.CURSOR_HAND) {
- int width = OS.GetSystemMetrics(OS.SM_CXCURSOR);
- int height = OS.GetSystemMetrics(OS.SM_CYCURSOR);
- if (width == 32 && height == 32) {
- int hInst = OS.GetModuleHandle(null);
- if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
- handle = OS.CreateCursor(hInst, 5, 0, 32, 32, HAND_SOURCE, HAND_MASK);
-
- }
- }
- if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- if (device.tracking) device.new_Object(this);
-}
-
-/**
- * Constructs a new cursor given a device, image and mask
- * data describing the desired cursor appearance, and the x
- * and y co-ordinates 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 either is not of depth one, 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) {
- if (device == null) device = Device.getDevice();
- if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- this.device = 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 color depths */
- if (mask.depth != 1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- if (source.depth != 1) 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);
- }
- /* Create the cursor */
- int hInst = OS.GetModuleHandle(null);
- if (OS.IsWinCE) SWT.error (SWT.ERROR_NOT_IMPLEMENTED);
- handle = OS.CreateCursor(hInst, hotspotX, hotspotY, source.width, source.height, source.data, mask.data);
- if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- if (device.tracking) device.new_Object(this);
-}
-
-/**
- * Disposes of the operating system resources associated with
- * the cursor. Applications must dispose of all cursors which
- * they allocate.
- */
-public void dispose () {
- if (handle == 0) return;
- if (device.isDisposed()) return;
-
- /*
- * It is an error in Windows to destroy the current
- * cursor. Check that the cursor that is about to
- * be destroyed is the current cursor. If so, set
- * the current cursor to be IDC_ARROW. Note that
- * Windows shares predefined cursors so the call to
- * LoadCursor() does not leak.
- */
- // TEMPORARY CODE
-// if (OS.GetCursor() == handle) {
-// OS.SetCursor(OS.LoadCursor(0, OS.IDC_ARROW));
-// }
-
- /*
- * The MSDN states that one should not destroy a shared
- * cursor, that is, one obtained from LoadCursor.
- * However, it does not appear to do any harm, so rather
- * than keep track of how a cursor was created, we just
- * destroy them all. If this causes problems in the future,
- * put the flag back in.
- */
- if (!OS.IsWinCE) OS.DestroyCursor(handle);
- handle = 0;
- if (device.tracking) device.dispose_Object(this);
- device = 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 which 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;
-}
-
-/**
- * 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 == 0;
-}
-
-/**
- * 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 win32_new(Device device, int handle) {
- if (device == null) device = Device.getDevice();
- Cursor cursor = new Cursor();
- cursor.handle = handle;
- cursor.device = device;
- return cursor;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +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> + */ + +public final class Cursor { + + /** + * the handle to the OS cursor resource + * (Warning: This field is platform dependent) + */ + public int handle; + + /** + * the device where this cursor was created + */ + Device device; + + /** + * data used to create a HAND cursor. + */ + static final byte[] HAND_SOURCE = { + (byte)0xf9,(byte)0xff,(byte)0xff,(byte)0xff, + (byte)0xf0,(byte)0xff,(byte)0xff,(byte)0xff, + (byte)0xf0,(byte)0xff,(byte)0xff,(byte)0xff, + (byte)0xf0,(byte)0xff,(byte)0xff,(byte)0xff, + (byte)0xf0,(byte)0x3f,(byte)0xff,(byte)0xff, + (byte)0xf0,(byte)0x07,(byte)0xff,(byte)0xff, + (byte)0xf0,(byte)0x03,(byte)0xff,(byte)0xff, + (byte)0xf0,(byte)0x00,(byte)0xff,(byte)0xff, + + (byte)0x10,(byte)0x00,(byte)0x7f,(byte)0xff, + (byte)0x00,(byte)0x00,(byte)0x7f,(byte)0xff, + (byte)0x80,(byte)0x00,(byte)0x7f,(byte)0xff, + (byte)0xc0,(byte)0x00,(byte)0x7f,(byte)0xff, + (byte)0xe0,(byte)0x00,(byte)0x7f,(byte)0xff, + (byte)0xf0,(byte)0x00,(byte)0x7f,(byte)0xff, + (byte)0xf8,(byte)0x00,(byte)0xff,(byte)0xff, + (byte)0xfc,(byte)0x01,(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)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)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 + }; + static final byte[] HAND_MASK = { + (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00, + (byte)0x06,(byte)0x00,(byte)0x00,(byte)0x00, + (byte)0x06,(byte)0x00,(byte)0x00,(byte)0x00, + (byte)0x06,(byte)0x00,(byte)0x00,(byte)0x00, + (byte)0x06,(byte)0x00,(byte)0x00,(byte)0x00, + (byte)0x06,(byte)0xc0,(byte)0x00,(byte)0x00, + (byte)0x06,(byte)0xd8,(byte)0x00,(byte)0x00, + (byte)0x06,(byte)0xd8,(byte)0x00,(byte)0x00, + + (byte)0x07,(byte)0xdb,(byte)0x00,(byte)0x00, + (byte)0x67,(byte)0xfb,(byte)0x00,(byte)0x00, + (byte)0x3f,(byte)0xff,(byte)0x00,(byte)0x00, + (byte)0x1f,(byte)0xff,(byte)0x00,(byte)0x00, + (byte)0x0f,(byte)0xff,(byte)0x00,(byte)0x00, + (byte)0x07,(byte)0xff,(byte)0x00,(byte)0x00, + (byte)0x03,(byte)0xfe,(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 + }; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Cursor() { +} + +/** + * 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) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.device = device; + int lpCursorName = 0; + switch (style) { + case SWT.CURSOR_HAND: lpCursorName = OS.IDC_HAND; break; + case SWT.CURSOR_ARROW: lpCursorName = OS.IDC_ARROW; break; + case SWT.CURSOR_WAIT: lpCursorName = OS.IDC_WAIT; break; + case SWT.CURSOR_CROSS: lpCursorName = OS.IDC_CROSS; break; + case SWT.CURSOR_APPSTARTING: lpCursorName = OS.IDC_APPSTARTING; break; + case SWT.CURSOR_HELP: lpCursorName = OS.IDC_HELP; break; + case SWT.CURSOR_SIZEALL: lpCursorName = OS.IDC_SIZEALL; break; + case SWT.CURSOR_SIZENESW: lpCursorName = OS.IDC_SIZENESW; break; + case SWT.CURSOR_SIZENS: lpCursorName = OS.IDC_SIZENS; break; + case SWT.CURSOR_SIZENWSE: lpCursorName = OS.IDC_SIZENWSE; break; + case SWT.CURSOR_SIZEWE: lpCursorName = OS.IDC_SIZEWE; break; + case SWT.CURSOR_SIZEN: lpCursorName = OS.IDC_SIZENS; break; + case SWT.CURSOR_SIZES: lpCursorName = OS.IDC_SIZENS; break; + case SWT.CURSOR_SIZEE: lpCursorName = OS.IDC_SIZEWE; break; + case SWT.CURSOR_SIZEW: lpCursorName = OS.IDC_SIZEWE; break; + case SWT.CURSOR_SIZENE: lpCursorName = OS.IDC_SIZENESW; break; + case SWT.CURSOR_SIZESE: lpCursorName = OS.IDC_SIZENWSE; break; + case SWT.CURSOR_SIZESW: lpCursorName = OS.IDC_SIZENESW; break; + case SWT.CURSOR_SIZENW: lpCursorName = OS.IDC_SIZENWSE; break; + case SWT.CURSOR_UPARROW: lpCursorName = OS.IDC_UPARROW; break; + case SWT.CURSOR_IBEAM: lpCursorName = OS.IDC_IBEAM; break; + case SWT.CURSOR_NO: lpCursorName = OS.IDC_NO; break; + default: + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + handle = OS.LoadCursor(0, lpCursorName); + /* + * IDC_HAND is supported only on Windows 2000 and Windows 98. + * Create a hand cursor if running in other Windows platforms. + */ + if (handle == 0 && style == SWT.CURSOR_HAND) { + int width = OS.GetSystemMetrics(OS.SM_CXCURSOR); + int height = OS.GetSystemMetrics(OS.SM_CYCURSOR); + if (width == 32 && height == 32) { + int hInst = OS.GetModuleHandle(null); + if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + handle = OS.CreateCursor(hInst, 5, 0, 32, 32, HAND_SOURCE, HAND_MASK); + + } + } + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + if (device.tracking) device.new_Object(this); +} + +/** + * Constructs a new cursor given a device, image and mask + * data describing the desired cursor appearance, and the x + * and y co-ordinates 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 either is not of depth one, 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) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.device = 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 color depths */ + if (mask.depth != 1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (source.depth != 1) 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); + } + /* Create the cursor */ + int hInst = OS.GetModuleHandle(null); + if (OS.IsWinCE) SWT.error (SWT.ERROR_NOT_IMPLEMENTED); + handle = OS.CreateCursor(hInst, hotspotX, hotspotY, source.width, source.height, source.data, mask.data); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + if (device.tracking) device.new_Object(this); +} + +/** + * Disposes of the operating system resources associated with + * the cursor. Applications must dispose of all cursors which + * they allocate. + */ +public void dispose () { + if (handle == 0) return; + if (device.isDisposed()) return; + + /* + * It is an error in Windows to destroy the current + * cursor. Check that the cursor that is about to + * be destroyed is the current cursor. If so, set + * the current cursor to be IDC_ARROW. Note that + * Windows shares predefined cursors so the call to + * LoadCursor() does not leak. + */ + // TEMPORARY CODE +// if (OS.GetCursor() == handle) { +// OS.SetCursor(OS.LoadCursor(0, OS.IDC_ARROW)); +// } + + /* + * The MSDN states that one should not destroy a shared + * cursor, that is, one obtained from LoadCursor. + * However, it does not appear to do any harm, so rather + * than keep track of how a cursor was created, we just + * destroy them all. If this causes problems in the future, + * put the flag back in. + */ + if (!OS.IsWinCE) OS.DestroyCursor(handle); + handle = 0; + if (device.tracking) device.dispose_Object(this); + device = 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 which 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; +} + +/** + * 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 == 0; +} + +/** + * 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 win32_new(Device device, int handle) { + if (device == null) device = Device.getDevice(); + Cursor cursor = new Cursor(); + cursor.handle = handle; + cursor.device = device; + return cursor; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Device.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Device.java index 81607fc0f4..9b3458c6ae 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Device.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Device.java @@ -1,714 +1,714 @@ -package org.eclipse.swt.graphics;
-
-/*
+package org.eclipse.swt.graphics; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.*;
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-
-/**
- * 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.
- */
-public abstract class Device implements Drawable {
-
- /* Debugging */
- public static boolean DEBUG;
- boolean debug = DEBUG;
- boolean tracking = DEBUG;
- Error [] errors;
- Object [] objects;
-
- /* Palette
- * (Warning: This field is platform dependent)
- */
- public int hPalette = 0;
- int [] colorRefCount;
-
- /* System Font */
- int systemFont;
-
- /* Font Enumeration */
- int nFonts = 256;
- LOGFONT [] logFonts;
-
- boolean disposed;
-
- /*
- * 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.
- *
- * This code will be removed in the future.
- */
- protected static Device CurrentDevice;
- protected static Runnable DeviceFinder;
- static {
- try {
- Class.forName ("org.eclipse.swt.widgets.Display");
- } catch (Throwable e) {}
- }
-
-/*
-* TEMPORARY CODE.
-*/
-static 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>
- *
- * @param data the DeviceData which describes the receiver
- *
- * @see #create
- * @see #init
- * @see DeviceData
- */
-public Device(DeviceData data) {
- if (data != null) {
- debug = data.debug;
- tracking = data.tracking;
- }
- create (data);
- init ();
- if (tracking) {
- errors = new Error [128];
- objects = new Object [128];
- }
-
- /* Initialize the system font slot */
- systemFont = getSystemFont().handle;
-}
-
-/**
- * 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) {
-}
-
-int computePixels(int height) {
- int hDC = internal_new_GC (null);
- int pixels = -Compatibility.round(height * OS.GetDeviceCaps(hDC, OS.LOGPIXELSY), 72);
- internal_dispose_GC (hDC, null);
- return pixels;
-}
-
-int computePoints(LOGFONT logFont) {
- int hDC = internal_new_GC (null);
- int logPixelsY = OS.GetDeviceCaps(hDC, OS.LOGPIXELSY);
- int pixels = 0;
- if (logFont.lfHeight > 0) {
- /*
- * Feature in Windows. If the lfHeight of the LOGFONT structure
- * is positive, the lfHeight measures the height of the entire
- * cell, including internal leading, in logical units. Since the
- * height of a font in points does not include the internal leading,
- * we must subtract the internal leading, which requires a TEXTMETRIC,
- * which in turn requires font creation.
- */
- int hFont = OS.CreateFontIndirect(logFont);
- int oldFont = OS.SelectObject(hDC, hFont);
- TEXTMETRIC lptm = new TEXTMETRIC();
- OS.GetTextMetrics(hDC, lptm);
- OS.SelectObject(hDC, oldFont);
- OS.DeleteObject(hFont);
- pixels = logFont.lfHeight - lptm.tmInternalLeading;
- } else {
- pixels = -logFont.lfHeight;
- }
- internal_dispose_GC (hDC, null);
-
- return Compatibility.round(pixels * 72, logPixelsY);
-}
-
-/**
- * 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 () {
-}
-
-/**
- * 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 () {
- if (isDisposed()) return;
- checkDevice ();
- release ();
- destroy ();
- disposed = true;
- if (tracking) {
- objects = null;
- errors = null;
- }
-}
-
-void dispose_Object (Object object) {
- for (int i=0; i<objects.length; i++) {
- if (objects [i] == object) {
- objects [i] = null;
- errors [i] = null;
- return;
- }
- }
-}
-
-int EnumFontFamProc (int lpelfe, int lpntme, int FontType, int lParam) {
- boolean isScalable = (FontType & OS.RASTER_FONTTYPE) == 0;
- if ((lParam == 1) != isScalable) return 1;
-
- /* Add the log font to the list of log fonts */
- if (nFonts == logFonts.length) {
- LOGFONT [] newLogFonts = new LOGFONT [logFonts.length + 128];
- System.arraycopy (logFonts, 0, newLogFonts, 0, nFonts);
- logFonts = newLogFonts;
- }
- LOGFONT logFont = logFonts [nFonts];
- if (logFont == null) logFont = new LOGFONT ();
- OS.MoveMemory (logFont, lpelfe, LOGFONT.sizeof);
- logFonts [nFonts++] = logFont;
- return 1;
-}
-
-/**
- * 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 ();
- int hDC = internal_new_GC (null);
- int width = OS.GetDeviceCaps (hDC, OS.HORZRES);
- int height = OS.GetDeviceCaps (hDC, OS.VERTRES);
- internal_dispose_GC (hDC, null);
- return new Rectangle (0, 0, width, 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;
- int count = 0, length = 0;
- if (tracking) 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++;
- }
- }
- 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 () {
- 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 ();
- int hDC = internal_new_GC (null);
- int bits = OS.GetDeviceCaps (hDC, OS.BITSPIXEL);
- int planes = OS.GetDeviceCaps (hDC, OS.PLANES);
- internal_dispose_GC (hDC, null);
- return bits * planes;
-}
-
-/**
- * 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 ();
- int hDC = internal_new_GC (null);
- int dpiX = OS.GetDeviceCaps (hDC, OS.LOGPIXELSX);
- int dpiY = OS.GetDeviceCaps (hDC, OS.LOGPIXELSY);
- internal_dispose_GC (hDC, null);
- return new Point (dpiX, dpiY);
-}
-
-/**
- * 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 true if scalable fonts should be 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 ();
-
- /* Create the callback */
- Callback callback = new Callback (this, "EnumFontFamProc", 4);
- int lpEnumFontFamProc = callback.getAddress ();
-
- /* Initialize the instance variables */
- logFonts = new LOGFONT [nFonts];
- for (int i=0; i<logFonts.length; i++) {
- logFonts [i] = new LOGFONT ();
- }
- nFonts = 0;
-
- /* Enumerate */
- int offset = 0;
- int hDC = internal_new_GC (null);
- if (faceName == null) {
- /* The user did not specify a face name, so they want all versions of all available face names */
- OS.EnumFontFamilies (hDC, null, lpEnumFontFamProc, scalable ? 1 : 0);
-
- /**
- * For bitmapped fonts, EnumFontFamilies only enumerates once for each font, regardless
- * of how many styles are available. If the user wants bitmapped fonts, enumerate on
- * each face name now.
- */
- offset = nFonts;
- for (int i=0; i<offset; i++) {
- LOGFONT lf = logFonts [i];
- /**
- * Bug in Windows 98. When EnumFontFamiliesEx is called with a specified face name, it
- * should enumerate for each available style of that font. Instead, it only enumerates
- * once. The fix is to call EnumFontFamilies, which works as expected.
- */
- char [] buffer = new char [] {
- lf.lfFaceName0, lf.lfFaceName1, lf.lfFaceName2, lf.lfFaceName3,
- lf.lfFaceName4, lf.lfFaceName5, lf.lfFaceName6, lf.lfFaceName7,
- lf.lfFaceName8, lf.lfFaceName9, lf.lfFaceName10, lf.lfFaceName11,
- lf.lfFaceName12, lf.lfFaceName13, lf.lfFaceName14, lf.lfFaceName15,
- lf.lfFaceName16, lf.lfFaceName17, lf.lfFaceName18, lf.lfFaceName19,
- lf.lfFaceName20, lf.lfFaceName21, lf.lfFaceName22, lf.lfFaceName23,
- lf.lfFaceName24, lf.lfFaceName25, lf.lfFaceName26, lf.lfFaceName27,
- lf.lfFaceName28, lf.lfFaceName29, lf.lfFaceName30, lf.lfFaceName31,
- };
- TCHAR lpFaceName = new TCHAR (0, new String(buffer), true);
- OS.EnumFontFamilies (hDC, lpFaceName, lpEnumFontFamProc, scalable ? 1 : 0);
- }
- } else {
- /* Use the character encoding for the default locale */
- TCHAR lpFaceName = new TCHAR (0, faceName, true);
- /**
- * Bug in Windows 98. When EnumFontFamiliesEx is called with a specified face name, it
- * should enumerate for each available style of that font. Instead, it only enumerates
- * once. The fix is to call EnumFontFamilies, which works as expected.
- */
- OS.EnumFontFamilies (hDC, lpFaceName, lpEnumFontFamProc, scalable ? 1 : 0);
- }
- internal_dispose_GC (hDC, null);
-
- /* Create the fontData from the logfonts */
- int count = nFonts - offset;
- FontData [] result = new FontData [count];
- for (int i=0; i<count; i++) {
- LOGFONT logFont = logFonts [i+offset];
- result [i] = FontData.win32_new (logFont, computePoints(logFont));
- }
-
- /* Clean up */
- callback.dispose ();
- logFonts = null;
- return result;
-}
-
-/**
- * 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_DEVICE_DISPOSED - if the receiver has been disposed</li>
- * </ul>
- *
- * @see SWT
- */
-public Color getSystemColor (int id) {
- checkDevice ();
- int pixel = 0x02000000;
- switch (id) {
- case SWT.COLOR_WHITE: pixel = 0x02FFFFFF; break;
- case SWT.COLOR_BLACK: pixel = 0x02000000; break;
- case SWT.COLOR_RED: pixel = 0x020000FF; break;
- case SWT.COLOR_DARK_RED: pixel = 0x02000080; break;
- case SWT.COLOR_GREEN: pixel = 0x0200FF00; break;
- case SWT.COLOR_DARK_GREEN: pixel = 0x02008000; break;
- case SWT.COLOR_YELLOW: pixel = 0x0200FFFF; break;
- case SWT.COLOR_DARK_YELLOW: pixel = 0x02008080; break;
- case SWT.COLOR_BLUE: pixel = 0x02FF0000; break;
- case SWT.COLOR_DARK_BLUE: pixel = 0x02800000; break;
- case SWT.COLOR_MAGENTA: pixel = 0x02FF00FF; break;
- case SWT.COLOR_DARK_MAGENTA: pixel = 0x02800080; break;
- case SWT.COLOR_CYAN: pixel = 0x02FFFF00; break;
- case SWT.COLOR_DARK_CYAN: pixel = 0x02808000; break;
- case SWT.COLOR_GRAY: pixel = 0x02C0C0C0; break;
- case SWT.COLOR_DARK_GRAY: pixel = 0x02808080; break;
- }
- return Color.win32_new (this, pixel);
-}
-
-/**
- * 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 free'd 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 ();
- int hFont = OS.GetStockObject (OS.SYSTEM_FONT);
- return Font.win32_new (this, hFont);
-}
-
-/**
- * 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 false;
-}
-
-/**
- * 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 () {
-
- /*
- * If we're not on a device which supports palettes,
- * don't create one.
- */
- int hDC = internal_new_GC (null);
- int rc = OS.GetDeviceCaps (hDC, OS.RASTERCAPS);
- int bits = OS.GetDeviceCaps (hDC, OS.BITSPIXEL);
- int planes = OS.GetDeviceCaps (hDC, OS.PLANES);
-
- bits *= planes;
- if ((rc & OS.RC_PALETTE) == 0 || bits != 8) {
- internal_dispose_GC (hDC, null);
- return;
- }
-
- int numReserved = OS.GetDeviceCaps (hDC, OS.NUMRESERVED);
- int numEntries = OS.GetDeviceCaps (hDC, OS.SIZEPALETTE);
-
- if (OS.IsWinCE) {
- /*
- * Feature on WinCE. For some reason, certain 8 bit WinCE
- * devices return 0 for the number of reserved entries in
- * the system palette. Their system palette correctly contains
- * the usual 20 system colors. The workaround is to assume
- * there are 20 reserved system colors instead of 0.
*/
- if (numReserved == 0 && numEntries >= 20) numReserved = 20;
- }
-
- /* Create the palette and reference counter */
- colorRefCount = new int [numEntries];
-
- /* 4 bytes header + 4 bytes per entry * numEntries entries */
- byte [] logPalette = new byte [4 + 4 * numEntries];
-
- /* 2 bytes = special header */
- logPalette [0] = 0x00;
- logPalette [1] = 0x03;
-
- /* 2 bytes = number of colors, LSB first */
- logPalette [2] = 0;
- logPalette [3] = 1;
-
- /*
- * Create a palette which contains the system entries
- * as they are located in the system palette. The
- * MSDN article 'Memory Device Contexts' describes
- * where system entries are located. On an 8 bit
- * display with 20 reserved colors, the system colors
- * will be the first 10 entries and the last 10 ones.
- */
- byte[] lppe = new byte [4 * numEntries];
- OS.GetSystemPaletteEntries (hDC, 0, numEntries, lppe);
- /* Copy all entries from the system palette */
- System.arraycopy (lppe, 0, logPalette, 4, 4 * numEntries);
- /* Lock the indices corresponding to the system entries */
- for (int i = 0; i < numReserved / 2; i++) {
- colorRefCount [i] = 1;
- colorRefCount [numEntries - 1 - i] = 1;
- }
- internal_dispose_GC (hDC, null);
- hPalette = OS.CreatePalette (logPalette);
-}
-/**
- * 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
- *
- * @private
- */
-public abstract int 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 handle the platform specific GC handle
- * @param data the platform specific GC data
- *
- * @private
- */
-public abstract void internal_dispose_GC (int hDC, 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 () {
- return disposed;
-}
-
-void new_Object (Object object) {
- 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;
-}
-
-/**
- * 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 (hPalette != 0) OS.DeleteObject (hPalette);
- hPalette = 0;
- colorRefCount = null;
- logFonts = null;
- nFonts = 0;
-}
-
-/**
- * If the underlying window system supports printing warning messages
- * to the console, setting warnings to <code>true</code> prevents these
- * messages from being printed. If the argument is <code>false</code>
- * message printing is not blocked.
- *
- * @param warnings <code>true</code>if warnings should be handled, 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 ();
-}
-
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; + +/** + * 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. + */ +public abstract class Device implements Drawable { + + /* Debugging */ + public static boolean DEBUG; + boolean debug = DEBUG; + boolean tracking = DEBUG; + Error [] errors; + Object [] objects; + + /* Palette + * (Warning: This field is platform dependent) + */ + public int hPalette = 0; + int [] colorRefCount; + + /* System Font */ + int systemFont; + + /* Font Enumeration */ + int nFonts = 256; + LOGFONT [] logFonts; + + boolean disposed; + + /* + * 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. + * + * This code will be removed in the future. + */ + protected static Device CurrentDevice; + protected static Runnable DeviceFinder; + static { + try { + Class.forName ("org.eclipse.swt.widgets.Display"); + } catch (Throwable e) {} + } + +/* +* TEMPORARY CODE. +*/ +static 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> + * + * @param data the DeviceData which describes the receiver + * + * @see #create + * @see #init + * @see DeviceData + */ +public Device(DeviceData data) { + if (data != null) { + debug = data.debug; + tracking = data.tracking; + } + create (data); + init (); + if (tracking) { + errors = new Error [128]; + objects = new Object [128]; + } + + /* Initialize the system font slot */ + systemFont = getSystemFont().handle; +} + +/** + * 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) { +} + +int computePixels(int height) { + int hDC = internal_new_GC (null); + int pixels = -Compatibility.round(height * OS.GetDeviceCaps(hDC, OS.LOGPIXELSY), 72); + internal_dispose_GC (hDC, null); + return pixels; +} + +int computePoints(LOGFONT logFont) { + int hDC = internal_new_GC (null); + int logPixelsY = OS.GetDeviceCaps(hDC, OS.LOGPIXELSY); + int pixels = 0; + if (logFont.lfHeight > 0) { + /* + * Feature in Windows. If the lfHeight of the LOGFONT structure + * is positive, the lfHeight measures the height of the entire + * cell, including internal leading, in logical units. Since the + * height of a font in points does not include the internal leading, + * we must subtract the internal leading, which requires a TEXTMETRIC, + * which in turn requires font creation. + */ + int hFont = OS.CreateFontIndirect(logFont); + int oldFont = OS.SelectObject(hDC, hFont); + TEXTMETRIC lptm = new TEXTMETRIC(); + OS.GetTextMetrics(hDC, lptm); + OS.SelectObject(hDC, oldFont); + OS.DeleteObject(hFont); + pixels = logFont.lfHeight - lptm.tmInternalLeading; + } else { + pixels = -logFont.lfHeight; + } + internal_dispose_GC (hDC, null); + + return Compatibility.round(pixels * 72, logPixelsY); +} + +/** + * 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 () { +} + +/** + * 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 () { + if (isDisposed()) return; + checkDevice (); + release (); + destroy (); + disposed = true; + if (tracking) { + objects = null; + errors = null; + } +} + +void dispose_Object (Object object) { + for (int i=0; i<objects.length; i++) { + if (objects [i] == object) { + objects [i] = null; + errors [i] = null; + return; + } + } +} + +int EnumFontFamProc (int lpelfe, int lpntme, int FontType, int lParam) { + boolean isScalable = (FontType & OS.RASTER_FONTTYPE) == 0; + if ((lParam == 1) != isScalable) return 1; + + /* Add the log font to the list of log fonts */ + if (nFonts == logFonts.length) { + LOGFONT [] newLogFonts = new LOGFONT [logFonts.length + 128]; + System.arraycopy (logFonts, 0, newLogFonts, 0, nFonts); + logFonts = newLogFonts; + } + LOGFONT logFont = logFonts [nFonts]; + if (logFont == null) logFont = new LOGFONT (); + OS.MoveMemory (logFont, lpelfe, LOGFONT.sizeof); + logFonts [nFonts++] = logFont; + return 1; +} + +/** + * 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 (); + int hDC = internal_new_GC (null); + int width = OS.GetDeviceCaps (hDC, OS.HORZRES); + int height = OS.GetDeviceCaps (hDC, OS.VERTRES); + internal_dispose_GC (hDC, null); + return new Rectangle (0, 0, width, 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; + int count = 0, length = 0; + if (tracking) 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++; + } + } + 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 () { + 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 (); + int hDC = internal_new_GC (null); + int bits = OS.GetDeviceCaps (hDC, OS.BITSPIXEL); + int planes = OS.GetDeviceCaps (hDC, OS.PLANES); + internal_dispose_GC (hDC, null); + return bits * planes; +} + +/** + * 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 (); + int hDC = internal_new_GC (null); + int dpiX = OS.GetDeviceCaps (hDC, OS.LOGPIXELSX); + int dpiY = OS.GetDeviceCaps (hDC, OS.LOGPIXELSY); + internal_dispose_GC (hDC, null); + return new Point (dpiX, dpiY); +} + +/** + * 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 true if scalable fonts should be 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 (); + + /* Create the callback */ + Callback callback = new Callback (this, "EnumFontFamProc", 4); + int lpEnumFontFamProc = callback.getAddress (); + + /* Initialize the instance variables */ + logFonts = new LOGFONT [nFonts]; + for (int i=0; i<logFonts.length; i++) { + logFonts [i] = new LOGFONT (); + } + nFonts = 0; + + /* Enumerate */ + int offset = 0; + int hDC = internal_new_GC (null); + if (faceName == null) { + /* The user did not specify a face name, so they want all versions of all available face names */ + OS.EnumFontFamilies (hDC, null, lpEnumFontFamProc, scalable ? 1 : 0); + + /** + * For bitmapped fonts, EnumFontFamilies only enumerates once for each font, regardless + * of how many styles are available. If the user wants bitmapped fonts, enumerate on + * each face name now. + */ + offset = nFonts; + for (int i=0; i<offset; i++) { + LOGFONT lf = logFonts [i]; + /** + * Bug in Windows 98. When EnumFontFamiliesEx is called with a specified face name, it + * should enumerate for each available style of that font. Instead, it only enumerates + * once. The fix is to call EnumFontFamilies, which works as expected. + */ + char [] buffer = new char [] { + lf.lfFaceName0, lf.lfFaceName1, lf.lfFaceName2, lf.lfFaceName3, + lf.lfFaceName4, lf.lfFaceName5, lf.lfFaceName6, lf.lfFaceName7, + lf.lfFaceName8, lf.lfFaceName9, lf.lfFaceName10, lf.lfFaceName11, + lf.lfFaceName12, lf.lfFaceName13, lf.lfFaceName14, lf.lfFaceName15, + lf.lfFaceName16, lf.lfFaceName17, lf.lfFaceName18, lf.lfFaceName19, + lf.lfFaceName20, lf.lfFaceName21, lf.lfFaceName22, lf.lfFaceName23, + lf.lfFaceName24, lf.lfFaceName25, lf.lfFaceName26, lf.lfFaceName27, + lf.lfFaceName28, lf.lfFaceName29, lf.lfFaceName30, lf.lfFaceName31, + }; + TCHAR lpFaceName = new TCHAR (0, new String(buffer), true); + OS.EnumFontFamilies (hDC, lpFaceName, lpEnumFontFamProc, scalable ? 1 : 0); + } + } else { + /* Use the character encoding for the default locale */ + TCHAR lpFaceName = new TCHAR (0, faceName, true); + /** + * Bug in Windows 98. When EnumFontFamiliesEx is called with a specified face name, it + * should enumerate for each available style of that font. Instead, it only enumerates + * once. The fix is to call EnumFontFamilies, which works as expected. + */ + OS.EnumFontFamilies (hDC, lpFaceName, lpEnumFontFamProc, scalable ? 1 : 0); + } + internal_dispose_GC (hDC, null); + + /* Create the fontData from the logfonts */ + int count = nFonts - offset; + FontData [] result = new FontData [count]; + for (int i=0; i<count; i++) { + LOGFONT logFont = logFonts [i+offset]; + result [i] = FontData.win32_new (logFont, computePoints(logFont)); + } + + /* Clean up */ + callback.dispose (); + logFonts = null; + return result; +} + +/** + * 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_DEVICE_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see SWT + */ +public Color getSystemColor (int id) { + checkDevice (); + int pixel = 0x02000000; + switch (id) { + case SWT.COLOR_WHITE: pixel = 0x02FFFFFF; break; + case SWT.COLOR_BLACK: pixel = 0x02000000; break; + case SWT.COLOR_RED: pixel = 0x020000FF; break; + case SWT.COLOR_DARK_RED: pixel = 0x02000080; break; + case SWT.COLOR_GREEN: pixel = 0x0200FF00; break; + case SWT.COLOR_DARK_GREEN: pixel = 0x02008000; break; + case SWT.COLOR_YELLOW: pixel = 0x0200FFFF; break; + case SWT.COLOR_DARK_YELLOW: pixel = 0x02008080; break; + case SWT.COLOR_BLUE: pixel = 0x02FF0000; break; + case SWT.COLOR_DARK_BLUE: pixel = 0x02800000; break; + case SWT.COLOR_MAGENTA: pixel = 0x02FF00FF; break; + case SWT.COLOR_DARK_MAGENTA: pixel = 0x02800080; break; + case SWT.COLOR_CYAN: pixel = 0x02FFFF00; break; + case SWT.COLOR_DARK_CYAN: pixel = 0x02808000; break; + case SWT.COLOR_GRAY: pixel = 0x02C0C0C0; break; + case SWT.COLOR_DARK_GRAY: pixel = 0x02808080; break; + } + return Color.win32_new (this, pixel); +} + +/** + * 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 free'd 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 (); + int hFont = OS.GetStockObject (OS.SYSTEM_FONT); + return Font.win32_new (this, hFont); +} + +/** + * 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 false; +} + +/** + * 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 () { + + /* + * If we're not on a device which supports palettes, + * don't create one. + */ + int hDC = internal_new_GC (null); + int rc = OS.GetDeviceCaps (hDC, OS.RASTERCAPS); + int bits = OS.GetDeviceCaps (hDC, OS.BITSPIXEL); + int planes = OS.GetDeviceCaps (hDC, OS.PLANES); + + bits *= planes; + if ((rc & OS.RC_PALETTE) == 0 || bits != 8) { + internal_dispose_GC (hDC, null); + return; + } + + int numReserved = OS.GetDeviceCaps (hDC, OS.NUMRESERVED); + int numEntries = OS.GetDeviceCaps (hDC, OS.SIZEPALETTE); + + if (OS.IsWinCE) { + /* + * Feature on WinCE. For some reason, certain 8 bit WinCE + * devices return 0 for the number of reserved entries in + * the system palette. Their system palette correctly contains + * the usual 20 system colors. The workaround is to assume + * there are 20 reserved system colors instead of 0.
*/ + if (numReserved == 0 && numEntries >= 20) numReserved = 20; + } + + /* Create the palette and reference counter */ + colorRefCount = new int [numEntries]; + + /* 4 bytes header + 4 bytes per entry * numEntries entries */ + byte [] logPalette = new byte [4 + 4 * numEntries]; + + /* 2 bytes = special header */ + logPalette [0] = 0x00; + logPalette [1] = 0x03; + + /* 2 bytes = number of colors, LSB first */ + logPalette [2] = 0; + logPalette [3] = 1; + + /* + * Create a palette which contains the system entries + * as they are located in the system palette. The + * MSDN article 'Memory Device Contexts' describes + * where system entries are located. On an 8 bit + * display with 20 reserved colors, the system colors + * will be the first 10 entries and the last 10 ones. + */ + byte[] lppe = new byte [4 * numEntries]; + OS.GetSystemPaletteEntries (hDC, 0, numEntries, lppe); + /* Copy all entries from the system palette */ + System.arraycopy (lppe, 0, logPalette, 4, 4 * numEntries); + /* Lock the indices corresponding to the system entries */ + for (int i = 0; i < numReserved / 2; i++) { + colorRefCount [i] = 1; + colorRefCount [numEntries - 1 - i] = 1; + } + internal_dispose_GC (hDC, null); + hPalette = OS.CreatePalette (logPalette); +} +/** + * 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 + * + * @private + */ +public abstract int 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 handle the platform specific GC handle + * @param data the platform specific GC data + * + * @private + */ +public abstract void internal_dispose_GC (int hDC, 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 () { + return disposed; +} + +void new_Object (Object object) { + 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; +} + +/** + * 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 (hPalette != 0) OS.DeleteObject (hPalette); + hPalette = 0; + colorRefCount = null; + logFonts = null; + nFonts = 0; +} + +/** + * If the underlying window system supports printing warning messages + * to the console, setting warnings to <code>true</code> prevents these + * messages from being printed. If the argument is <code>false</code> + * message printing is not blocked. + * + * @param warnings <code>true</code>if warnings should be handled, 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 (); +} + } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/DeviceData.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/DeviceData.java index 06e99bb30c..d36b10ff4a 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/DeviceData.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/DeviceData.java @@ -1,19 +1,19 @@ -package org.eclipse.swt.graphics;
-
-/*
+package org.eclipse.swt.graphics; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-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;
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +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/win32/org/eclipse/swt/graphics/Font.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Font.java index 3ce6e79c8a..1a3f410bb8 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Font.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Font.java @@ -1,256 +1,256 @@ -package org.eclipse.swt.graphics;
-
-/*
+package org.eclipse.swt.graphics; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-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
- */
-
-public final class Font {
-
- /**
- * the handle to the OS font resource
- * (Warning: This field is platform dependent)
- */
- public int handle;
-
- /**
- * the device where this font was created
- */
- Device device;
-
-/**
- * Prevents uninitialized instances from being created outside the package.
- */
-Font() {
-}
-
-/**
- * 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) {
- if (device == null) device = Device.getDevice();
- if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- init(device, fd);
- if (device.tracking) device.new_Object(this);
-}
-
-/**
- * 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) {
- if (device == null) device = Device.getDevice();
- if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- if (fds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- if (fds.length == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- init(device, fds[0]);
- if (device.tracking) device.new_Object(this);
-}
-
-/**
- * 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) {
- if (device == null) device = Device.getDevice();
- if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- if (name == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- init(device, new FontData (name, height, style));
- if (device.tracking) device.new_Object(this);
-}
-
-/**
- * Disposes of the operating system resources associated with
- * the font. Applications must dispose of all fonts which
- * they allocate.
- */
-public void dispose() {
- if (handle == 0) return;
- if (device.isDisposed()) return;
- OS.DeleteObject(handle);
- handle = 0;
- if (device.tracking) device.dispose_Object(this);
- device = 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 device == font.device && 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);
- LOGFONT logFont = new LOGFONT();
- OS.GetObject(handle, LOGFONT.sizeof, logFont);
- return new FontData[] {FontData.win32_new(logFont, device.computePoints(logFont))};
-}
-
-/**
- * Returns an integer hash code for the receiver. Any two
- * objects which 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;
-}
-
-void init (Device device, FontData fd) {
- if (fd == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- this.device = device;
- LOGFONT logFont = fd.data;
- int lfHeight = logFont.lfHeight;
- logFont.lfHeight = device.computePixels(fd.height);
- handle = OS.CreateFontIndirect(logFont);
- logFont.lfHeight = lfHeight;
- if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
-}
-
-/**
- * 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 == 0;
-}
-
-/**
- * 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 + "}";
-}
-
-/**
- * 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
- *
- * @private
- */
-public static Font win32_new(Device device, int handle) {
- if (device == null) device = Device.getDevice();
- Font font = new Font();
- font.handle = handle;
- font.device = device;
- return font;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +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 + */ + +public final class Font { + + /** + * the handle to the OS font resource + * (Warning: This field is platform dependent) + */ + public int handle; + + /** + * the device where this font was created + */ + Device device; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Font() { +} + +/** + * 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) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, fd); + if (device.tracking) device.new_Object(this); +} + +/** + * 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) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (fds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (fds.length == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + init(device, fds[0]); + if (device.tracking) device.new_Object(this); +} + +/** + * 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) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (name == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, new FontData (name, height, style)); + if (device.tracking) device.new_Object(this); +} + +/** + * Disposes of the operating system resources associated with + * the font. Applications must dispose of all fonts which + * they allocate. + */ +public void dispose() { + if (handle == 0) return; + if (device.isDisposed()) return; + OS.DeleteObject(handle); + handle = 0; + if (device.tracking) device.dispose_Object(this); + device = 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 device == font.device && 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); + LOGFONT logFont = new LOGFONT(); + OS.GetObject(handle, LOGFONT.sizeof, logFont); + return new FontData[] {FontData.win32_new(logFont, device.computePoints(logFont))}; +} + +/** + * Returns an integer hash code for the receiver. Any two + * objects which 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; +} + +void init (Device device, FontData fd) { + if (fd == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.device = device; + LOGFONT logFont = fd.data; + int lfHeight = logFont.lfHeight; + logFont.lfHeight = device.computePixels(fd.height); + handle = OS.CreateFontIndirect(logFont); + logFont.lfHeight = lfHeight; + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); +} + +/** + * 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 == 0; +} + +/** + * 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 + "}"; +} + +/** + * 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 + * + * @private + */ +public static Font win32_new(Device device, int handle) { + if (device == null) device = Device.getDevice(); + Font font = new Font(); + font.handle = handle; + font.device = device; + return font; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/FontData.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/FontData.java index 1a37985314..12620ee2dc 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/FontData.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/FontData.java @@ -1,693 +1,693 @@ -package org.eclipse.swt.graphics;
-
-/*
+package org.eclipse.swt.graphics; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.*;
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-
-/**
- * Instances of this class describe operating system fonts.
- * Only the public API of this type is platform independent.
- * <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
- */
-
-public final class FontData {
-
- /**
- * A Win32 LOGFONT struct
- * (Warning: This field is platform dependent)
- */
- public LOGFONT data;
-
- /**
- * The height of the font data in points
- * (Warning: This field is platform dependent)
- */
- public int height;
-
- /**
- * The locales of the font
- * (Warning: These fields are platform dependent)
- */
- String lang, country, variant;
-
-/**
- * Constructs a new un-initialized font data.
- */
-public FontData() {
- data = new LOGFONT();
- // We set the charset field so that
- // wildcard searching will work properly
- // out of the box
- data.lfCharSet = OS.DEFAULT_CHARSET;
- height = 12;
-}
-
-/**
- * Constructs a new font data given the Windows <code>LOGFONT</code>
- * that it should represent.
- *
- * @param data the <code>LOGFONT</code> for the result
- */
-FontData(LOGFONT data, int height) {
- this.data = data;
- this.height = height;
-}
-
-/**
- * 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);
- int height = 0;
- try {
- height = Integer.parseInt(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);
- data = new LOGFONT();
- data.lfCharSet = OS.DEFAULT_CHARSET;
- 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("WINDOWS") && version2.equals("1")) {
- LOGFONT newData = new LOGFONT();
- try {
- start = end + 1;
- end = string.indexOf('|', start);
- if (end == -1) return;
- newData.lfHeight = Integer.parseInt(string.substring(start, end));
- start = end + 1;
- end = string.indexOf('|', start);
- if (end == -1) return;
- newData.lfWidth = Integer.parseInt(string.substring(start, end));
- start = end + 1;
- end = string.indexOf('|', start);
- if (end == -1) return;
- newData.lfEscapement = Integer.parseInt(string.substring(start, end));
- start = end + 1;
- end = string.indexOf('|', start);
- if (end == -1) return;
- newData.lfOrientation = Integer.parseInt(string.substring(start, end));
- start = end + 1;
- end = string.indexOf('|', start);
- if (end == -1) return;
- newData.lfWeight = Integer.parseInt(string.substring(start, end));
- start = end + 1;
- end = string.indexOf('|', start);
- if (end == -1) return;
- newData.lfItalic = Byte.parseByte(string.substring(start, end));
- start = end + 1;
- end = string.indexOf('|', start);
- if (end == -1) return;
- newData.lfUnderline = Byte.parseByte(string.substring(start, end));
- start = end + 1;
- end = string.indexOf('|', start);
- if (end == -1) return;
- newData.lfStrikeOut = Byte.parseByte(string.substring(start, end));
- start = end + 1;
- end = string.indexOf('|', start);
- if (end == -1) return;
- newData.lfCharSet = Byte.parseByte(string.substring(start, end));
- start = end + 1;
- end = string.indexOf('|', start);
- if (end == -1) return;
- newData.lfOutPrecision = Byte.parseByte(string.substring(start, end));
- start = end + 1;
- end = string.indexOf('|', start);
- if (end == -1) return;
- newData.lfClipPrecision = Byte.parseByte(string.substring(start, end));
- start = end + 1;
- end = string.indexOf('|', start);
- if (end == -1) return;
- newData.lfQuality = Byte.parseByte(string.substring(start, end));
- start = end + 1;
- end = string.indexOf('|', start);
- if (end == -1) return;
- newData.lfPitchAndFamily = Byte.parseByte(string.substring(start, end));
- start = end + 1;
- } catch (NumberFormatException e) {
- setName(name);
- setHeight(height);
- setStyle(style);
- return;
- }
- char[] lfFaceName = new char[32];
- string.getChars(start, string.length(), lfFaceName, 0);
- newData.lfFaceName0 = lfFaceName[0];
- newData.lfFaceName1 = lfFaceName[1];
- newData.lfFaceName2 = lfFaceName[2];
- newData.lfFaceName3 = lfFaceName[3];
- newData.lfFaceName4 = lfFaceName[4];
- newData.lfFaceName5 = lfFaceName[5];
- newData.lfFaceName6 = lfFaceName[6];
- newData.lfFaceName7 = lfFaceName[7];
- newData.lfFaceName8 = lfFaceName[8];
- newData.lfFaceName9 = lfFaceName[9];
- newData.lfFaceName10 = lfFaceName[10];
- newData.lfFaceName11 = lfFaceName[11];
- newData.lfFaceName12 = lfFaceName[12];
- newData.lfFaceName13 = lfFaceName[13];
- newData.lfFaceName14 = lfFaceName[14];
- newData.lfFaceName15 = lfFaceName[15];
- newData.lfFaceName16 = lfFaceName[16];
- newData.lfFaceName17 = lfFaceName[17];
- newData.lfFaceName18 = lfFaceName[18];
- newData.lfFaceName19 = lfFaceName[19];
- newData.lfFaceName20 = lfFaceName[20];
- newData.lfFaceName21 = lfFaceName[21];
- newData.lfFaceName22 = lfFaceName[22];
- newData.lfFaceName23 = lfFaceName[23];
- newData.lfFaceName24 = lfFaceName[24];
- newData.lfFaceName25 = lfFaceName[25];
- newData.lfFaceName26 = lfFaceName[26];
- newData.lfFaceName27 = lfFaceName[27];
- newData.lfFaceName28 = lfFaceName[28];
- newData.lfFaceName29 = lfFaceName[29];
- newData.lfFaceName30 = lfFaceName[30];
- newData.lfFaceName31 = lfFaceName[31];
- data = newData;
- }
-}
-
-/**
- * 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) {
- if (name == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- data = new LOGFONT();
- setName(name);
- setHeight(height);
- setStyle(style);
- // We set the charset field so that
- // wildcard searching will work properly
- // out of the box
- data.lfCharSet = OS.DEFAULT_CHARSET;
-}
-
-/**
- * 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 fd = (FontData)object;
- LOGFONT lf = fd.data;
- return data.lfCharSet == lf.lfCharSet &&
- /*
- * This code is intentionally commented. When creating
- * a FontData, lfHeight is not necessarily set. Instead
- * we check the height field which is always set.
- */
-// data.lfHeight == lf.lfHeight &&
- height == fd.height &&
- data.lfWidth == lf.lfWidth &&
- data.lfEscapement == lf.lfEscapement &&
- data.lfOrientation == lf.lfOrientation &&
- data.lfWeight == lf.lfWeight &&
- data.lfItalic == lf.lfItalic &&
- data.lfUnderline == lf.lfUnderline &&
- data.lfStrikeOut == lf.lfStrikeOut &&
- data.lfCharSet == lf.lfCharSet &&
- data.lfOutPrecision == lf.lfOutPrecision &&
- data.lfClipPrecision == lf.lfClipPrecision &&
- data.lfQuality == lf.lfQuality &&
- data.lfPitchAndFamily == lf.lfPitchAndFamily &&
- data.lfFaceName0 == lf.lfFaceName0 &&
- data.lfFaceName1 == lf.lfFaceName1 &&
- data.lfFaceName2 == lf.lfFaceName2 &&
- data.lfFaceName3 == lf.lfFaceName3 &&
- data.lfFaceName4 == lf.lfFaceName4 &&
- data.lfFaceName5 == lf.lfFaceName5 &&
- data.lfFaceName6 == lf.lfFaceName6 &&
- data.lfFaceName7 == lf.lfFaceName7 &&
- data.lfFaceName8 == lf.lfFaceName8 &&
- data.lfFaceName9 == lf.lfFaceName9 &&
- data.lfFaceName10 == lf.lfFaceName10 &&
- data.lfFaceName11 == lf.lfFaceName11 &&
- data.lfFaceName12 == lf.lfFaceName12 &&
- data.lfFaceName13 == lf.lfFaceName13 &&
- data.lfFaceName14 == lf.lfFaceName14 &&
- data.lfFaceName15 == lf.lfFaceName15 &&
- data.lfFaceName16 == lf.lfFaceName16 &&
- data.lfFaceName17 == lf.lfFaceName17 &&
- data.lfFaceName18 == lf.lfFaceName18 &&
- data.lfFaceName19 == lf.lfFaceName19 &&
- data.lfFaceName20 == lf.lfFaceName20 &&
- data.lfFaceName21 == lf.lfFaceName21 &&
- data.lfFaceName22 == lf.lfFaceName22 &&
- data.lfFaceName23 == lf.lfFaceName23 &&
- data.lfFaceName24 == lf.lfFaceName24 &&
- data.lfFaceName25 == lf.lfFaceName25 &&
- data.lfFaceName26 == lf.lfFaceName26 &&
- data.lfFaceName27 == lf.lfFaceName27 &&
- data.lfFaceName28 == lf.lfFaceName28 &&
- data.lfFaceName29 == lf.lfFaceName29 &&
- data.lfFaceName30 == lf.lfFaceName30 &&
- data.lfFaceName31 == lf.lfFaceName31;
-}
-
-int EnumLocalesProc(int lpLocaleString) {
-
- /* Get the locale ID */
- int length = 8;
- TCHAR buffer = new TCHAR(0, length);
- int byteCount = length * TCHAR.sizeof;
- OS.MoveMemory(buffer, lpLocaleString, byteCount);
- int lcid = Integer.parseInt(buffer.toString(0, buffer.strlen ()), 16);
-
- /* Check the language */
- int size = OS.GetLocaleInfo(lcid, OS.LOCALE_SISO639LANGNAME, buffer, length);
- if (size <= 0 || !lang.equals(buffer.toString(0, size - 1))) return 1;
-
- /* Check the country */
- if (country != null) {
- size = OS.GetLocaleInfo(lcid, OS.LOCALE_SISO3166CTRYNAME, buffer, length);
- if (size <= 0 || !country.equals(buffer.toString(0, size - 1))) return 1;
- }
-
- /* Get the charset */
- size = OS.GetLocaleInfo(lcid, OS.LOCALE_IDEFAULTANSICODEPAGE, buffer, length);
- if (size <= 0) return 1;
- int cp = Integer.parseInt(buffer.toString(0, size - 1));
- int [] lpCs = new int[8];
- OS.TranslateCharsetInfo(cp, lpCs, OS.TCI_SRCCODEPAGE);
- data.lfCharSet = (byte)lpCs[0];
-
- return 0;
-}
-
-/**
- * Returns the height of the receiver in points.
- *
- * @return the height of this FontData
- *
- * @see #setHeight
- */
-public int getHeight() {
- return height;
-}
-
-/**
- * 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() {
- char[] chars = {
- data.lfFaceName0, data.lfFaceName1, data.lfFaceName2, data.lfFaceName3,
- data.lfFaceName4, data.lfFaceName5, data.lfFaceName6, data.lfFaceName7,
- data.lfFaceName8, data.lfFaceName9, data.lfFaceName10, data.lfFaceName11,
- data.lfFaceName12, data.lfFaceName13, data.lfFaceName14, data.lfFaceName15,
- data.lfFaceName16, data.lfFaceName17, data.lfFaceName18, data.lfFaceName19,
- data.lfFaceName20, data.lfFaceName21, data.lfFaceName22, data.lfFaceName23,
- data.lfFaceName24, data.lfFaceName25, data.lfFaceName26, data.lfFaceName27,
- data.lfFaceName28, data.lfFaceName29, data.lfFaceName30, data.lfFaceName31,
- };
- int index = 0;
- while (index < chars.length) {
- if (chars [index] == 0) break;
- index++;
- }
- return new String (chars, 0, index);
-}
-
-/**
- * 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() {
- int style = SWT.NORMAL;
- if (data.lfWeight == 700) style |= SWT.BOLD;
- if (data.lfItalic != 0) style |= SWT.ITALIC;
- return style;
-}
-
-/**
- * Returns an integer hash code for the receiver. Any two
- * objects which 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 data.lfCharSet ^ height ^ data.lfWidth ^ data.lfEscapement ^
- data.lfOrientation ^ data.lfWeight ^ data.lfItalic ^data.lfUnderline ^
- data.lfStrikeOut ^ data.lfCharSet ^ data.lfOutPrecision ^
- data.lfClipPrecision ^ data.lfQuality ^ data.lfPitchAndFamily ^
- data.lfFaceName0 ^ data.lfFaceName1 ^ data.lfFaceName2 ^
- data.lfFaceName3 ^ data.lfFaceName4 ^ data.lfFaceName5 ^
- data.lfFaceName6 ^ data.lfFaceName7 ^ data.lfFaceName8 ^
- data.lfFaceName9 ^ data.lfFaceName10 ^ data.lfFaceName11 ^
- data.lfFaceName12 ^ data.lfFaceName13 ^ data.lfFaceName14 ^
- data.lfFaceName15 ^ data.lfFaceName16 ^ data.lfFaceName17 ^
- data.lfFaceName18 ^ data.lfFaceName19 ^ data.lfFaceName20 ^
- data.lfFaceName21 ^ data.lfFaceName22 ^ data.lfFaceName23 ^
- data.lfFaceName24 ^ data.lfFaceName25 ^ data.lfFaceName26 ^
- data.lfFaceName27 ^ data.lfFaceName28 ^ data.lfFaceName29 ^
- data.lfFaceName30 ^ data.lfFaceName31;
-}
-
-/**
- * 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;
-}
-
-/**
- * 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 which 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);
- }
- if (lang == null) {
- data.lfCharSet = OS.DEFAULT_CHARSET;
- } else {
- Callback callback = new Callback (this, "EnumLocalesProc", 1);
- int lpEnumLocalesProc = callback.getAddress ();
- OS.EnumSystemLocales(lpEnumLocalesProc, OS.LCID_SUPPORTED);
- callback.dispose ();
- }
-}
-
-/**
- * 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);
- char [] chars = new char [32];
-
- /* The field lfFaceName must be NULL terminated */
- int length = name.length();
- name.getChars (0, length <= 31 ? length : 31, chars, 0);
- data.lfFaceName0 = chars[0];
- data.lfFaceName1 = chars[1];
- data.lfFaceName2 = chars[2];
- data.lfFaceName3 = chars[3];
- data.lfFaceName4 = chars[4];
- data.lfFaceName5 = chars[5];
- data.lfFaceName6 = chars[6];
- data.lfFaceName7 = chars[7];
- data.lfFaceName8 = chars[8];
- data.lfFaceName9 = chars[9];
- data.lfFaceName10 = chars[10];
- data.lfFaceName11 = chars[11];
- data.lfFaceName12 = chars[12];
- data.lfFaceName13 = chars[13];
- data.lfFaceName14 = chars[14];
- data.lfFaceName15 = chars[15];
- data.lfFaceName16 = chars[16];
- data.lfFaceName17 = chars[17];
- data.lfFaceName18 = chars[18];
- data.lfFaceName19 = chars[19];
- data.lfFaceName20 = chars[20];
- data.lfFaceName21 = chars[21];
- data.lfFaceName22 = chars[22];
- data.lfFaceName23 = chars[23];
- data.lfFaceName24 = chars[24];
- data.lfFaceName25 = chars[25];
- data.lfFaceName26 = chars[26];
- data.lfFaceName27 = chars[27];
- data.lfFaceName28 = chars[28];
- data.lfFaceName29 = chars[29];
- data.lfFaceName30 = chars[30];
- data.lfFaceName31 = chars[31];
-}
-
-/**
- * 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.
- *
- * @param style the new style for this <code>FontData</code>
- *
- * @see #getStyle
- */
-public void setStyle(int style) {
- if ((style & SWT.BOLD) == SWT.BOLD) {
- data.lfWeight = 700;
- } else {
- data.lfWeight = 0;
- }
- if ((style & SWT.ITALIC) == SWT.ITALIC) {
- data.lfItalic = 1;
- } else {
- data.lfItalic = 0;
- }
-}
-
-/**
- * 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();
- buffer.append("1|");
- buffer.append(getName());
- buffer.append("|");
- buffer.append(getHeight());
- buffer.append("|");
- buffer.append(getStyle());
- buffer.append("|");
- buffer.append("WINDOWS|1|");
- buffer.append(data.lfHeight);
- buffer.append("|");
- buffer.append(data.lfWidth);
- buffer.append("|");
- buffer.append(data.lfEscapement);
- buffer.append("|");
- buffer.append(data.lfOrientation);
- buffer.append("|");
- buffer.append(data.lfWeight);
- buffer.append("|");
- buffer.append(data.lfItalic);
- buffer.append("|");
- buffer.append(data.lfUnderline);
- buffer.append("|");
- buffer.append(data.lfStrikeOut);
- buffer.append("|");
- buffer.append(data.lfCharSet);
- buffer.append("|");
- buffer.append(data.lfOutPrecision);
- buffer.append("|");
- buffer.append(data.lfClipPrecision);
- buffer.append("|");
- buffer.append(data.lfQuality);
- buffer.append("|");
- buffer.append(data.lfPitchAndFamily);
- buffer.append("|");
- char[] faceName = {
- data.lfFaceName0, data.lfFaceName1, data.lfFaceName2, data.lfFaceName3,
- data.lfFaceName4, data.lfFaceName5, data.lfFaceName6, data.lfFaceName7,
- data.lfFaceName8, data.lfFaceName9, data.lfFaceName10, data.lfFaceName11,
- data.lfFaceName12, data.lfFaceName13, data.lfFaceName14, data.lfFaceName15,
- data.lfFaceName16, data.lfFaceName17, data.lfFaceName18, data.lfFaceName19,
- data.lfFaceName20, data.lfFaceName21, data.lfFaceName22, data.lfFaceName23,
- data.lfFaceName24, data.lfFaceName25, data.lfFaceName26, data.lfFaceName27,
- data.lfFaceName28, data.lfFaceName29, data.lfFaceName30, data.lfFaceName31,
- };
- int i = 0;
- while (i < faceName.length && faceName[i] != 0) {
- buffer.append(faceName[i++]);
- }
- return buffer.toString();
-}
-
-/**
- * Invokes platform specific functionality to allocate a new font data.
- * <p>
- * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
- * API for <code>FontData</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 <code>LOGFONT</code> for the font data
- *
- * @private
- */
-public static FontData win32_new(LOGFONT data, int height) {
- return new FontData(data, height);
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; + +/** + * Instances of this class describe operating system fonts. + * Only the public API of this type is platform independent. + * <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 + */ + +public final class FontData { + + /** + * A Win32 LOGFONT struct + * (Warning: This field is platform dependent) + */ + public LOGFONT data; + + /** + * The height of the font data in points + * (Warning: This field is platform dependent) + */ + public int height; + + /** + * The locales of the font + * (Warning: These fields are platform dependent) + */ + String lang, country, variant; + +/** + * Constructs a new un-initialized font data. + */ +public FontData() { + data = new LOGFONT(); + // We set the charset field so that + // wildcard searching will work properly + // out of the box + data.lfCharSet = OS.DEFAULT_CHARSET; + height = 12; +} + +/** + * Constructs a new font data given the Windows <code>LOGFONT</code> + * that it should represent. + * + * @param data the <code>LOGFONT</code> for the result + */ +FontData(LOGFONT data, int height) { + this.data = data; + this.height = height; +} + +/** + * 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); + int height = 0; + try { + height = Integer.parseInt(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); + data = new LOGFONT(); + data.lfCharSet = OS.DEFAULT_CHARSET; + 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("WINDOWS") && version2.equals("1")) { + LOGFONT newData = new LOGFONT(); + try { + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + newData.lfHeight = Integer.parseInt(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + newData.lfWidth = Integer.parseInt(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + newData.lfEscapement = Integer.parseInt(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + newData.lfOrientation = Integer.parseInt(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + newData.lfWeight = Integer.parseInt(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + newData.lfItalic = Byte.parseByte(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + newData.lfUnderline = Byte.parseByte(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + newData.lfStrikeOut = Byte.parseByte(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + newData.lfCharSet = Byte.parseByte(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + newData.lfOutPrecision = Byte.parseByte(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + newData.lfClipPrecision = Byte.parseByte(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + newData.lfQuality = Byte.parseByte(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + newData.lfPitchAndFamily = Byte.parseByte(string.substring(start, end)); + start = end + 1; + } catch (NumberFormatException e) { + setName(name); + setHeight(height); + setStyle(style); + return; + } + char[] lfFaceName = new char[32]; + string.getChars(start, string.length(), lfFaceName, 0); + newData.lfFaceName0 = lfFaceName[0]; + newData.lfFaceName1 = lfFaceName[1]; + newData.lfFaceName2 = lfFaceName[2]; + newData.lfFaceName3 = lfFaceName[3]; + newData.lfFaceName4 = lfFaceName[4]; + newData.lfFaceName5 = lfFaceName[5]; + newData.lfFaceName6 = lfFaceName[6]; + newData.lfFaceName7 = lfFaceName[7]; + newData.lfFaceName8 = lfFaceName[8]; + newData.lfFaceName9 = lfFaceName[9]; + newData.lfFaceName10 = lfFaceName[10]; + newData.lfFaceName11 = lfFaceName[11]; + newData.lfFaceName12 = lfFaceName[12]; + newData.lfFaceName13 = lfFaceName[13]; + newData.lfFaceName14 = lfFaceName[14]; + newData.lfFaceName15 = lfFaceName[15]; + newData.lfFaceName16 = lfFaceName[16]; + newData.lfFaceName17 = lfFaceName[17]; + newData.lfFaceName18 = lfFaceName[18]; + newData.lfFaceName19 = lfFaceName[19]; + newData.lfFaceName20 = lfFaceName[20]; + newData.lfFaceName21 = lfFaceName[21]; + newData.lfFaceName22 = lfFaceName[22]; + newData.lfFaceName23 = lfFaceName[23]; + newData.lfFaceName24 = lfFaceName[24]; + newData.lfFaceName25 = lfFaceName[25]; + newData.lfFaceName26 = lfFaceName[26]; + newData.lfFaceName27 = lfFaceName[27]; + newData.lfFaceName28 = lfFaceName[28]; + newData.lfFaceName29 = lfFaceName[29]; + newData.lfFaceName30 = lfFaceName[30]; + newData.lfFaceName31 = lfFaceName[31]; + data = newData; + } +} + +/** + * 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) { + if (name == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + data = new LOGFONT(); + setName(name); + setHeight(height); + setStyle(style); + // We set the charset field so that + // wildcard searching will work properly + // out of the box + data.lfCharSet = OS.DEFAULT_CHARSET; +} + +/** + * 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 fd = (FontData)object; + LOGFONT lf = fd.data; + return data.lfCharSet == lf.lfCharSet && + /* + * This code is intentionally commented. When creating + * a FontData, lfHeight is not necessarily set. Instead + * we check the height field which is always set. + */ +// data.lfHeight == lf.lfHeight && + height == fd.height && + data.lfWidth == lf.lfWidth && + data.lfEscapement == lf.lfEscapement && + data.lfOrientation == lf.lfOrientation && + data.lfWeight == lf.lfWeight && + data.lfItalic == lf.lfItalic && + data.lfUnderline == lf.lfUnderline && + data.lfStrikeOut == lf.lfStrikeOut && + data.lfCharSet == lf.lfCharSet && + data.lfOutPrecision == lf.lfOutPrecision && + data.lfClipPrecision == lf.lfClipPrecision && + data.lfQuality == lf.lfQuality && + data.lfPitchAndFamily == lf.lfPitchAndFamily && + data.lfFaceName0 == lf.lfFaceName0 && + data.lfFaceName1 == lf.lfFaceName1 && + data.lfFaceName2 == lf.lfFaceName2 && + data.lfFaceName3 == lf.lfFaceName3 && + data.lfFaceName4 == lf.lfFaceName4 && + data.lfFaceName5 == lf.lfFaceName5 && + data.lfFaceName6 == lf.lfFaceName6 && + data.lfFaceName7 == lf.lfFaceName7 && + data.lfFaceName8 == lf.lfFaceName8 && + data.lfFaceName9 == lf.lfFaceName9 && + data.lfFaceName10 == lf.lfFaceName10 && + data.lfFaceName11 == lf.lfFaceName11 && + data.lfFaceName12 == lf.lfFaceName12 && + data.lfFaceName13 == lf.lfFaceName13 && + data.lfFaceName14 == lf.lfFaceName14 && + data.lfFaceName15 == lf.lfFaceName15 && + data.lfFaceName16 == lf.lfFaceName16 && + data.lfFaceName17 == lf.lfFaceName17 && + data.lfFaceName18 == lf.lfFaceName18 && + data.lfFaceName19 == lf.lfFaceName19 && + data.lfFaceName20 == lf.lfFaceName20 && + data.lfFaceName21 == lf.lfFaceName21 && + data.lfFaceName22 == lf.lfFaceName22 && + data.lfFaceName23 == lf.lfFaceName23 && + data.lfFaceName24 == lf.lfFaceName24 && + data.lfFaceName25 == lf.lfFaceName25 && + data.lfFaceName26 == lf.lfFaceName26 && + data.lfFaceName27 == lf.lfFaceName27 && + data.lfFaceName28 == lf.lfFaceName28 && + data.lfFaceName29 == lf.lfFaceName29 && + data.lfFaceName30 == lf.lfFaceName30 && + data.lfFaceName31 == lf.lfFaceName31; +} + +int EnumLocalesProc(int lpLocaleString) { + + /* Get the locale ID */ + int length = 8; + TCHAR buffer = new TCHAR(0, length); + int byteCount = length * TCHAR.sizeof; + OS.MoveMemory(buffer, lpLocaleString, byteCount); + int lcid = Integer.parseInt(buffer.toString(0, buffer.strlen ()), 16); + + /* Check the language */ + int size = OS.GetLocaleInfo(lcid, OS.LOCALE_SISO639LANGNAME, buffer, length); + if (size <= 0 || !lang.equals(buffer.toString(0, size - 1))) return 1; + + /* Check the country */ + if (country != null) { + size = OS.GetLocaleInfo(lcid, OS.LOCALE_SISO3166CTRYNAME, buffer, length); + if (size <= 0 || !country.equals(buffer.toString(0, size - 1))) return 1; + } + + /* Get the charset */ + size = OS.GetLocaleInfo(lcid, OS.LOCALE_IDEFAULTANSICODEPAGE, buffer, length); + if (size <= 0) return 1; + int cp = Integer.parseInt(buffer.toString(0, size - 1)); + int [] lpCs = new int[8]; + OS.TranslateCharsetInfo(cp, lpCs, OS.TCI_SRCCODEPAGE); + data.lfCharSet = (byte)lpCs[0]; + + return 0; +} + +/** + * Returns the height of the receiver in points. + * + * @return the height of this FontData + * + * @see #setHeight + */ +public int getHeight() { + return height; +} + +/** + * 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() { + char[] chars = { + data.lfFaceName0, data.lfFaceName1, data.lfFaceName2, data.lfFaceName3, + data.lfFaceName4, data.lfFaceName5, data.lfFaceName6, data.lfFaceName7, + data.lfFaceName8, data.lfFaceName9, data.lfFaceName10, data.lfFaceName11, + data.lfFaceName12, data.lfFaceName13, data.lfFaceName14, data.lfFaceName15, + data.lfFaceName16, data.lfFaceName17, data.lfFaceName18, data.lfFaceName19, + data.lfFaceName20, data.lfFaceName21, data.lfFaceName22, data.lfFaceName23, + data.lfFaceName24, data.lfFaceName25, data.lfFaceName26, data.lfFaceName27, + data.lfFaceName28, data.lfFaceName29, data.lfFaceName30, data.lfFaceName31, + }; + int index = 0; + while (index < chars.length) { + if (chars [index] == 0) break; + index++; + } + return new String (chars, 0, index); +} + +/** + * 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() { + int style = SWT.NORMAL; + if (data.lfWeight == 700) style |= SWT.BOLD; + if (data.lfItalic != 0) style |= SWT.ITALIC; + return style; +} + +/** + * Returns an integer hash code for the receiver. Any two + * objects which 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 data.lfCharSet ^ height ^ data.lfWidth ^ data.lfEscapement ^ + data.lfOrientation ^ data.lfWeight ^ data.lfItalic ^data.lfUnderline ^ + data.lfStrikeOut ^ data.lfCharSet ^ data.lfOutPrecision ^ + data.lfClipPrecision ^ data.lfQuality ^ data.lfPitchAndFamily ^ + data.lfFaceName0 ^ data.lfFaceName1 ^ data.lfFaceName2 ^ + data.lfFaceName3 ^ data.lfFaceName4 ^ data.lfFaceName5 ^ + data.lfFaceName6 ^ data.lfFaceName7 ^ data.lfFaceName8 ^ + data.lfFaceName9 ^ data.lfFaceName10 ^ data.lfFaceName11 ^ + data.lfFaceName12 ^ data.lfFaceName13 ^ data.lfFaceName14 ^ + data.lfFaceName15 ^ data.lfFaceName16 ^ data.lfFaceName17 ^ + data.lfFaceName18 ^ data.lfFaceName19 ^ data.lfFaceName20 ^ + data.lfFaceName21 ^ data.lfFaceName22 ^ data.lfFaceName23 ^ + data.lfFaceName24 ^ data.lfFaceName25 ^ data.lfFaceName26 ^ + data.lfFaceName27 ^ data.lfFaceName28 ^ data.lfFaceName29 ^ + data.lfFaceName30 ^ data.lfFaceName31; +} + +/** + * 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; +} + +/** + * 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 which 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); + } + if (lang == null) { + data.lfCharSet = OS.DEFAULT_CHARSET; + } else { + Callback callback = new Callback (this, "EnumLocalesProc", 1); + int lpEnumLocalesProc = callback.getAddress (); + OS.EnumSystemLocales(lpEnumLocalesProc, OS.LCID_SUPPORTED); + callback.dispose (); + } +} + +/** + * 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); + char [] chars = new char [32]; + + /* The field lfFaceName must be NULL terminated */ + int length = name.length(); + name.getChars (0, length <= 31 ? length : 31, chars, 0); + data.lfFaceName0 = chars[0]; + data.lfFaceName1 = chars[1]; + data.lfFaceName2 = chars[2]; + data.lfFaceName3 = chars[3]; + data.lfFaceName4 = chars[4]; + data.lfFaceName5 = chars[5]; + data.lfFaceName6 = chars[6]; + data.lfFaceName7 = chars[7]; + data.lfFaceName8 = chars[8]; + data.lfFaceName9 = chars[9]; + data.lfFaceName10 = chars[10]; + data.lfFaceName11 = chars[11]; + data.lfFaceName12 = chars[12]; + data.lfFaceName13 = chars[13]; + data.lfFaceName14 = chars[14]; + data.lfFaceName15 = chars[15]; + data.lfFaceName16 = chars[16]; + data.lfFaceName17 = chars[17]; + data.lfFaceName18 = chars[18]; + data.lfFaceName19 = chars[19]; + data.lfFaceName20 = chars[20]; + data.lfFaceName21 = chars[21]; + data.lfFaceName22 = chars[22]; + data.lfFaceName23 = chars[23]; + data.lfFaceName24 = chars[24]; + data.lfFaceName25 = chars[25]; + data.lfFaceName26 = chars[26]; + data.lfFaceName27 = chars[27]; + data.lfFaceName28 = chars[28]; + data.lfFaceName29 = chars[29]; + data.lfFaceName30 = chars[30]; + data.lfFaceName31 = chars[31]; +} + +/** + * 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. + * + * @param style the new style for this <code>FontData</code> + * + * @see #getStyle + */ +public void setStyle(int style) { + if ((style & SWT.BOLD) == SWT.BOLD) { + data.lfWeight = 700; + } else { + data.lfWeight = 0; + } + if ((style & SWT.ITALIC) == SWT.ITALIC) { + data.lfItalic = 1; + } else { + data.lfItalic = 0; + } +} + +/** + * 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(); + buffer.append("1|"); + buffer.append(getName()); + buffer.append("|"); + buffer.append(getHeight()); + buffer.append("|"); + buffer.append(getStyle()); + buffer.append("|"); + buffer.append("WINDOWS|1|"); + buffer.append(data.lfHeight); + buffer.append("|"); + buffer.append(data.lfWidth); + buffer.append("|"); + buffer.append(data.lfEscapement); + buffer.append("|"); + buffer.append(data.lfOrientation); + buffer.append("|"); + buffer.append(data.lfWeight); + buffer.append("|"); + buffer.append(data.lfItalic); + buffer.append("|"); + buffer.append(data.lfUnderline); + buffer.append("|"); + buffer.append(data.lfStrikeOut); + buffer.append("|"); + buffer.append(data.lfCharSet); + buffer.append("|"); + buffer.append(data.lfOutPrecision); + buffer.append("|"); + buffer.append(data.lfClipPrecision); + buffer.append("|"); + buffer.append(data.lfQuality); + buffer.append("|"); + buffer.append(data.lfPitchAndFamily); + buffer.append("|"); + char[] faceName = { + data.lfFaceName0, data.lfFaceName1, data.lfFaceName2, data.lfFaceName3, + data.lfFaceName4, data.lfFaceName5, data.lfFaceName6, data.lfFaceName7, + data.lfFaceName8, data.lfFaceName9, data.lfFaceName10, data.lfFaceName11, + data.lfFaceName12, data.lfFaceName13, data.lfFaceName14, data.lfFaceName15, + data.lfFaceName16, data.lfFaceName17, data.lfFaceName18, data.lfFaceName19, + data.lfFaceName20, data.lfFaceName21, data.lfFaceName22, data.lfFaceName23, + data.lfFaceName24, data.lfFaceName25, data.lfFaceName26, data.lfFaceName27, + data.lfFaceName28, data.lfFaceName29, data.lfFaceName30, data.lfFaceName31, + }; + int i = 0; + while (i < faceName.length && faceName[i] != 0) { + buffer.append(faceName[i++]); + } + return buffer.toString(); +} + +/** + * Invokes platform specific functionality to allocate a new font data. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>FontData</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 <code>LOGFONT</code> for the font data + * + * @private + */ +public static FontData win32_new(LOGFONT data, int height) { + return new FontData(data, height); +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/FontMetrics.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/FontMetrics.java index 83819f050a..6ee56cbe90 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/FontMetrics.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/FontMetrics.java @@ -1,173 +1,173 @@ -package org.eclipse.swt.graphics;
-
-/*
+package org.eclipse.swt.graphics; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-
-/**
- * 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
- */
-
-public final class FontMetrics {
-
- /**
- * On Windows, handle is a Win32 TEXTMETRIC struct
- * On Photon, handle is a Photon FontQueryInfo struct
- * (Warning: This field is platform dependent)
- */
- public TEXTMETRIC handle;
-
-/**
- * Prevents instances from being created outside the package.
- */
-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;
- TEXTMETRIC metric = ((FontMetrics)object).handle;
- return handle.tmHeight == metric.tmHeight &&
- handle.tmAscent == metric.tmAscent &&
- handle.tmDescent == metric.tmDescent &&
- handle.tmInternalLeading == metric.tmInternalLeading &&
- handle.tmExternalLeading == metric.tmExternalLeading &&
- handle.tmAveCharWidth == metric.tmAveCharWidth &&
- handle.tmMaxCharWidth == metric.tmMaxCharWidth &&
- handle.tmWeight == metric.tmWeight &&
- handle.tmOverhang == metric.tmOverhang &&
- handle.tmDigitizedAspectX == metric.tmDigitizedAspectX &&
- handle.tmDigitizedAspectY == metric.tmDigitizedAspectY &&
-// handle.tmFirstChar == metric.tmFirstChar &&
-// handle.tmLastChar == metric.tmLastChar &&
-// handle.tmDefaultChar == metric.tmDefaultChar &&
-// handle.tmBreakChar == metric.tmBreakChar &&
- handle.tmItalic == metric.tmItalic &&
- handle.tmUnderlined == metric.tmUnderlined &&
- handle.tmStruckOut == metric.tmStruckOut &&
- handle.tmPitchAndFamily == metric.tmPitchAndFamily &&
- handle.tmCharSet == metric.tmCharSet;
-}
-
-/**
- * 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 handle.tmAscent - handle.tmInternalLeading;
-}
-
-/**
- * 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 handle.tmAveCharWidth;
-}
-
-/**
- * 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 handle.tmDescent;
-}
-
-/**
- * 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 handle.tmHeight;
-}
-
-/**
- * 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 handle.tmInternalLeading;
-}
-
-/**
- * Returns an integer hash code for the receiver. Any two
- * objects which 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.tmHeight ^ handle.tmAscent ^ handle.tmDescent ^
- handle.tmInternalLeading ^ handle.tmExternalLeading ^
- handle.tmAveCharWidth ^ handle.tmMaxCharWidth ^ handle.tmWeight ^
- handle.tmOverhang ^ handle.tmDigitizedAspectX ^ handle.tmDigitizedAspectY ^
-// handle.tmFirstChar ^ handle.tmLastChar ^ handle.tmDefaultChar ^ handle.tmBreakChar ^
- handle.tmItalic ^ handle.tmUnderlined ^ handle.tmStruckOut ^
- handle.tmPitchAndFamily ^ handle.tmCharSet;
-}
-
-/**
- * Invokes platform specific functionality to allocate a new font metrics.
- * <p>
- * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
- * API for <code>FontMetrics</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 tm the <code>TEXTMETRIC</code> containing information about a font
- *
- * @private
- */
-public static FontMetrics win32_new(TEXTMETRIC handle) {
- FontMetrics fontMetrics = new FontMetrics();
- fontMetrics.handle = handle;
- return fontMetrics;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; + +/** + * 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 + */ + +public final class FontMetrics { + + /** + * On Windows, handle is a Win32 TEXTMETRIC struct + * On Photon, handle is a Photon FontQueryInfo struct + * (Warning: This field is platform dependent) + */ + public TEXTMETRIC handle; + +/** + * Prevents instances from being created outside the package. + */ +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; + TEXTMETRIC metric = ((FontMetrics)object).handle; + return handle.tmHeight == metric.tmHeight && + handle.tmAscent == metric.tmAscent && + handle.tmDescent == metric.tmDescent && + handle.tmInternalLeading == metric.tmInternalLeading && + handle.tmExternalLeading == metric.tmExternalLeading && + handle.tmAveCharWidth == metric.tmAveCharWidth && + handle.tmMaxCharWidth == metric.tmMaxCharWidth && + handle.tmWeight == metric.tmWeight && + handle.tmOverhang == metric.tmOverhang && + handle.tmDigitizedAspectX == metric.tmDigitizedAspectX && + handle.tmDigitizedAspectY == metric.tmDigitizedAspectY && +// handle.tmFirstChar == metric.tmFirstChar && +// handle.tmLastChar == metric.tmLastChar && +// handle.tmDefaultChar == metric.tmDefaultChar && +// handle.tmBreakChar == metric.tmBreakChar && + handle.tmItalic == metric.tmItalic && + handle.tmUnderlined == metric.tmUnderlined && + handle.tmStruckOut == metric.tmStruckOut && + handle.tmPitchAndFamily == metric.tmPitchAndFamily && + handle.tmCharSet == metric.tmCharSet; +} + +/** + * 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 handle.tmAscent - handle.tmInternalLeading; +} + +/** + * 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 handle.tmAveCharWidth; +} + +/** + * 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 handle.tmDescent; +} + +/** + * 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 handle.tmHeight; +} + +/** + * 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 handle.tmInternalLeading; +} + +/** + * Returns an integer hash code for the receiver. Any two + * objects which 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.tmHeight ^ handle.tmAscent ^ handle.tmDescent ^ + handle.tmInternalLeading ^ handle.tmExternalLeading ^ + handle.tmAveCharWidth ^ handle.tmMaxCharWidth ^ handle.tmWeight ^ + handle.tmOverhang ^ handle.tmDigitizedAspectX ^ handle.tmDigitizedAspectY ^ +// handle.tmFirstChar ^ handle.tmLastChar ^ handle.tmDefaultChar ^ handle.tmBreakChar ^ + handle.tmItalic ^ handle.tmUnderlined ^ handle.tmStruckOut ^ + handle.tmPitchAndFamily ^ handle.tmCharSet; +} + +/** + * Invokes platform specific functionality to allocate a new font metrics. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>FontMetrics</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 tm the <code>TEXTMETRIC</code> containing information about a font + * + * @private + */ +public static FontMetrics win32_new(TEXTMETRIC handle) { + FontMetrics fontMetrics = new FontMetrics(); + fontMetrics.handle = handle; + return fontMetrics; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java index f027948a9c..6c75124849 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java @@ -1,2305 +1,2305 @@ -package org.eclipse.swt.graphics;
-
-/*
+package org.eclipse.swt.graphics; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.*;
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-
-/**
- * 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>.
- * <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>
- *
- * @see org.eclipse.swt.events.PaintEvent
- */
-
-public final class GC {
-
- /**
- * the handle to the OS device context
- * (Warning: This field is platform dependent)
- */
- public int handle;
-
- Drawable drawable;
- GCData data;
-
-/**
- * Prevents uninitialized instances from being created outside the package.
- */
-GC() {
-}
-
-/**
- * Constructs a new instance of this class which has been
- * configured to draw on the specified drawable. Sets the
- * foreground and background color 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>
- * </ul>
- */
-public GC(Drawable drawable) {
- if (drawable == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- GCData data = new GCData ();
- int hDC = drawable.internal_new_GC (data);
- Device device = data.device;
- if (device == null) device = Device.getDevice();
- if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- data.device = device;
- init (drawable, data, hDC);
- if (device.tracking) device.new_Object(this);
-}
-
-/**
- * Copies a rectangular area of the receiver at the specified
- * position into the image, which must be of type <code>SWT.BITMAP</code>.
- *
- * @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 == 0) 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);
-
- /* Get the HDC for the device */
- Device device = data.device;
- int hDC = device.internal_new_GC(null);
-
- /* Copy the bitmap area */
- Rectangle rect = image.getBounds();
- int memHdc = OS.CreateCompatibleDC(hDC);
- int hOldBitmap = OS.SelectObject(memHdc, image.handle);
- OS.BitBlt(memHdc, 0, 0, rect.width, rect.height, handle, x, y, OS.SRCCOPY);
- OS.SelectObject(memHdc, hOldBitmap);
- OS.DeleteDC(memHdc);
-
- /* Release the HDC for the device */
- device.internal_dispose_GC(hDC, null);
-}
-
-/**
- * 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) {
- if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
-
- /*
- * Feature in WinCE. The function WindowFromDC is not part of the
- * WinCE SDK. The fix is to remember the HWND.
- */
- int hwnd = data.hwnd;
- if (hwnd == 0) {
- OS.BitBlt(handle, destX, destY, width, height, handle, srcX, srcY, OS.SRCCOPY);
- } else {
- RECT lprcClip = null;
- int hrgn = OS.CreateRectRgn(0, 0, 0, 0);
- if (OS.GetClipRgn(handle, hrgn) == 1) {
- lprcClip = new RECT();
- OS.GetRgnBox(hrgn, lprcClip);
- }
- OS.DeleteObject(hrgn);
- RECT lprcScroll = new RECT();
- OS.SetRect(lprcScroll, srcX, srcY, srcX + width, srcY + height);
- int res = OS.ScrollWindowEx(hwnd, destX - srcX, destY - srcY, lprcScroll, lprcClip, 0, null, OS.SW_INVALIDATE | OS.SW_ERASE);
-
- /*
- * Feature in WinCE. ScrollWindowEx does not accept combined
- * vertical and horizontal scrolling. The fix is to do a
- * BitBlt and invalidate the appropriate source area.
- */
- if (res == 0 && OS.IsWinCE) {
- OS.BitBlt(handle, destX, destY, width, height, handle, srcX, srcY, OS.SRCCOPY);
- int deltaX = destX - srcX, deltaY = destY - srcY;
- boolean disjoint = (destX + width < srcX) || (srcX + width < destX) || (destY + height < srcY) || (srcY + height < destY);
- if (disjoint) {
- OS.InvalidateRect(hwnd, lprcScroll, true);
- } else {
- if (deltaX != 0) {
- int newX = destX - deltaX;
- if (deltaX < 0) newX = destX + width;
- OS.SetRect(lprcScroll, newX, srcY, newX + Math.abs(deltaX), srcY + height);
- OS.InvalidateRect(hwnd, lprcScroll, true);
- }
- if (deltaY != 0) {
- int newY = destY - deltaY;
- if (deltaY < 0) newY = destY + height;
- OS.SetRect(lprcScroll, srcX, newY, srcX + width, newY + Math.abs(deltaY));
- OS.InvalidateRect(hwnd, lprcScroll, true);
- }
- }
- }
- }
-}
-
-int createDIB(int width, int height) {
- short depth = 32;
-
- BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
- bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
- bmiHeader.biWidth = width;
- bmiHeader.biHeight = -height;
- bmiHeader.biPlanes = 1;
- bmiHeader.biBitCount = depth;
- if (OS.IsWinCE) bmiHeader.biCompression = OS.BI_BITFIELDS;
- else bmiHeader.biCompression = OS.BI_RGB;
- byte[] bmi = new byte[BITMAPINFOHEADER.sizeof + (OS.IsWinCE ? 12 : 0)];
- OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
- /* Set the rgb colors into the bitmap info */
- if (OS.IsWinCE) {
- int redMask = 0xFF00;
- int greenMask = 0xFF0000;
- int blueMask = 0xFF000000;
- /* big endian */
- int offset = BITMAPINFOHEADER.sizeof;
- bmi[offset] = (byte)((redMask & 0xFF000000) >> 24);
- bmi[offset + 1] = (byte)((redMask & 0xFF0000) >> 16);
- bmi[offset + 2] = (byte)((redMask & 0xFF00) >> 8);
- bmi[offset + 3] = (byte)((redMask & 0xFF) >> 0);
- bmi[offset + 4] = (byte)((greenMask & 0xFF000000) >> 24);
- bmi[offset + 5] = (byte)((greenMask & 0xFF0000) >> 16);
- bmi[offset + 6] = (byte)((greenMask & 0xFF00) >> 8);
- bmi[offset + 7] = (byte)((greenMask & 0xFF) >> 0);
- bmi[offset + 8] = (byte)((blueMask & 0xFF000000) >> 24);
- bmi[offset + 9] = (byte)((blueMask & 0xFF0000) >> 16);
- bmi[offset + 10] = (byte)((blueMask & 0xFF00) >> 8);
- bmi[offset + 11] = (byte)((blueMask & 0xFF) >> 0);
- }
-
- int[] pBits = new int[1];
- int hDib = OS.CreateDIBSection(0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
- if (hDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- return hDib;
-}
-
-/**
- * Disposes of the operating system resources associated with
- * the graphics context. Applications must dispose of all GCs
- * which they allocate.
- */
-public void dispose() {
- if (handle == 0) return;
- if (data.device.isDisposed()) return;
-
- /*
- * The only way for pens and brushes to get
- * selected into the HDC is for the receiver to
- * create them. When we are destroying the
- * hDC we also destroy any pens and brushes that
- * we have allocated. This code assumes that it
- * is OK to delete stock objects. This will
- * happen when a GC is disposed and the user has
- * not caused new pens or brushes to be allocated.
- */
- int nullPen = OS.GetStockObject(OS.NULL_PEN);
- int oldPen = OS.SelectObject(handle, nullPen);
- OS.DeleteObject(oldPen);
- int nullBrush = OS.GetStockObject(OS.NULL_BRUSH);
- int oldBrush = OS.SelectObject(handle, nullBrush);
- OS.DeleteObject(oldBrush);
-
- /*
- * Put back the original bitmap into the device context.
- * This will ensure that we have not left a bitmap
- * selected in it when we delete the HDC.
- */
- int hNullBitmap = data.hNullBitmap;
- if (hNullBitmap != 0) {
- OS.SelectObject(handle, hNullBitmap);
- data.hNullBitmap = 0;
- }
- Image image = data.image;
- if (image != null) image.memGC = null;
-
- /*
- * Dispose the HDC.
- */
- Device device = data.device;
- drawable.internal_dispose_GC(handle, data);
- drawable = null;
- handle = 0;
- data.image = null;
- data.ps = null;
- if (device.tracking) device.dispose_Object(this);
- data.device = null;
- data = 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 IllegalArgumentException <ul>
- * <li>ERROR_INVALID_ARGUMENT - if any of the width, height or endAngle is zero.</li>
- * </ul>
- * @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 endAngle) {
- if (handle == 0) 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 || endAngle == 0) {
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- }
- /*
- * Feature in WinCE. The function Arc is not present in the
- * WinCE SDK. The fix is to emulate arc drawing by using
- * Polyline.
- */
- if (OS.IsWinCE) {
- /* compute arc with a simple linear interpolation */
- if (endAngle < 0) {
- startAngle += endAngle;
- endAngle = -endAngle;
- }
- if (endAngle > 360) endAngle = 360;
- int[] points = new int[(endAngle + 1) * 2];
- int cteX = 2 * x + width;
- int cteY = 2 * y + height;
- int index = 0;
- for (int i = 0; i <= endAngle; i++) {
- points[index++] = (Compatibility.cos(startAngle + i, width) + cteX) >> 1;
- points[index++] = (cteY - Compatibility.sin(startAngle + i, height)) >> 1;
- }
- OS.Polyline(handle, points, points.length / 2);
- } else {
- int x1, y1, x2, y2,tmp;
- boolean isNegative;
- if (endAngle >= 360 || endAngle <= -360) {
- x1 = x2 = x + width;
- y1 = y2 = y + height / 2;
- } else {
- isNegative = endAngle < 0;
-
- endAngle = endAngle + startAngle;
- if (isNegative) {
- // swap angles
- tmp = startAngle;
- startAngle = endAngle;
- endAngle = tmp;
- }
- x1 = Compatibility.cos(startAngle, width) + x + width/2;
- y1 = -1 * Compatibility.sin(startAngle, height) + y + height/2;
-
- x2 = Compatibility.cos(endAngle, width) + x + width/2;
- y2 = -1 * Compatibility.sin(endAngle, height) + y + height/2;
- }
- int nullBrush = OS.GetStockObject(OS.NULL_BRUSH);
- int oldBrush = OS.SelectObject(handle, nullBrush);
- OS.Arc(handle, x,y,x+width+1,y+height+1,x1,y1,x2,y2 );
- OS.SelectObject(handle,oldBrush);
- }
-}
-
-/**
- * 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
- */
-public void drawFocus (int x, int y, int width, int height) {
- if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- RECT rect = new RECT();
- OS.SetRect(rect, x, y, x + width, y + height);
- OS.DrawFocusRect(handle, rect);
-}
-
-/**
- * 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 SWTError <ul>
- * <li>ERROR_NO_HANDLES - if no handles are available to perform the operation</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
- * </ul>
- */
-public void drawImage(Image image, int x, int y) {
- if (handle == 0) 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 SWTError <ul>
- * <li>ERROR_NO_HANDLES - if no handles are available to perform the operation</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</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 == 0) 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) {
- switch (srcImage.type) {
- case SWT.BITMAP:
- drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple);
- break;
- case SWT.ICON:
- drawIcon(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple);
- break;
- default:
- SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
- }
-}
-
-void drawIcon(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) {
- /* Simple case: no stretching, entire icon */
- if (simple) {
- OS.DrawIconEx(handle, destX, destY, srcImage.handle, 0, 0, 0, 0, OS.DI_NORMAL);
- return;
- }
-
- /* Get the icon info */
- ICONINFO srcIconInfo = new ICONINFO();
- if (OS.IsWinCE) {
- Image.GetIconInfo(srcImage, srcIconInfo);
- } else {
- OS.GetIconInfo(srcImage.handle, srcIconInfo);
- }
-
- /* Get the icon width and height */
- int hBitmap = srcIconInfo.hbmColor;
- if (hBitmap == 0) hBitmap = srcIconInfo.hbmMask;
- BITMAP bm = new BITMAP();
- OS.GetObject(hBitmap, BITMAP.sizeof, bm);
- int iconWidth = bm.bmWidth, iconHeight = bm.bmHeight;
- if (hBitmap == srcIconInfo.hbmMask) iconHeight /= 2;
-
- if (simple) {
- srcWidth = destWidth = iconWidth;
- srcHeight = destHeight = iconHeight;
- }
-
- /* Draw the icon */
- boolean failed = srcX + srcWidth > iconWidth || srcY + srcHeight > iconHeight;
- if (!failed) {
- simple = srcX == 0 && srcY == 0 &&
- srcWidth == destWidth && srcHeight == destHeight &&
- srcWidth == iconWidth && srcHeight == iconHeight;
- if (simple) {
- /* Simple case: no stretching, entire icon */
- OS.DrawIconEx(handle, destX, destY, srcImage.handle, 0, 0, 0, 0, OS.DI_NORMAL);
- } else {
- /* Get the HDC for the device */
- Device device = data.device;
- int hDC = device.internal_new_GC(null);
-
- /* Create the icon info and HDC's */
- ICONINFO newIconInfo = new ICONINFO();
- newIconInfo.fIcon = true;
- int srcHdc = OS.CreateCompatibleDC(hDC);
- int dstHdc = OS.CreateCompatibleDC(hDC);
-
- /* Blt the color bitmap */
- int srcColorY = srcY;
- int srcColor = srcIconInfo.hbmColor;
- if (srcColor == 0) {
- srcColor = srcIconInfo.hbmMask;
- srcColorY += iconHeight;
- }
- int oldSrcBitmap = OS.SelectObject(srcHdc, srcColor);
- newIconInfo.hbmColor = OS.CreateCompatibleBitmap(srcHdc, destWidth, destHeight);
- if (newIconInfo.hbmColor == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- int oldDestBitmap = OS.SelectObject(dstHdc, newIconInfo.hbmColor);
- if (!OS.IsWinCE) OS.SetStretchBltMode(dstHdc, OS.COLORONCOLOR);
- OS.StretchBlt(dstHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcColorY, srcWidth, srcHeight, OS.SRCCOPY);
-
- /* Blt the mask bitmap */
- OS.SelectObject(srcHdc, srcIconInfo.hbmMask);
- newIconInfo.hbmMask = OS.CreateBitmap(destWidth, destHeight, 1, 1, null);
- if (newIconInfo.hbmMask == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- OS.SelectObject(dstHdc, newIconInfo.hbmMask);
- OS.StretchBlt(dstHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCCOPY);
-
- /* Select old bitmaps before creating the icon */
- OS.SelectObject(srcHdc, oldSrcBitmap);
- OS.SelectObject(dstHdc, oldDestBitmap);
-
- /* Create the new icon */
- int hIcon = OS.CreateIconIndirect(newIconInfo);
- if (hIcon == 0) SWT.error(SWT.ERROR_NO_HANDLES);
-
- /* Draw the new icon */
- OS.DrawIconEx(handle, destX, destY, hIcon, destWidth, destHeight, 0, 0, OS.DI_NORMAL);
-
- /* Destroy the new icon and hdc's*/
- OS.DestroyIcon(hIcon);
- OS.DeleteObject(newIconInfo.hbmMask);
- OS.DeleteObject(newIconInfo.hbmColor);
- OS.DeleteDC(dstHdc);
- OS.DeleteDC(srcHdc);
-
- /* Release the HDC for the device */
- device.internal_dispose_GC(hDC, null);
- }
- }
-
- /* Free icon info */
- OS.DeleteObject(srcIconInfo.hbmMask);
- if (srcIconInfo.hbmColor != 0) {
- OS.DeleteObject(srcIconInfo.hbmColor);
- }
-
- if (failed) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
-}
-
-void drawBitmap(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) {
- BITMAP bm = new BITMAP();
- OS.GetObject(srcImage.handle, BITMAP.sizeof, bm);
- int imgWidth = bm.bmWidth;
- int imgHeight = bm.bmHeight;
- if (simple) {
- srcWidth = destWidth = imgWidth;
- srcHeight = destHeight = imgHeight;
- } else {
- if (srcX + srcWidth > imgWidth || srcY + srcHeight > imgHeight) {
- SWT.error (SWT.ERROR_INVALID_ARGUMENT);
- }
- simple = srcX == 0 && srcY == 0 &&
- srcWidth == destWidth && destWidth == imgWidth &&
- srcHeight == destHeight && destHeight == imgHeight;
- }
- boolean mustRestore = false;
- GC memGC = srcImage.memGC;
- if (memGC != null && !memGC.isDisposed()) {
- mustRestore = true;
- GCData data = memGC.data;
- if (data.hNullBitmap != 0) {
- OS.SelectObject(memGC.handle, data.hNullBitmap);
- data.hNullBitmap = 0;
- }
- }
- if (srcImage.alpha != -1 || srcImage.alphaData != null) {
- drawBitmapAlpha(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
- } else if (srcImage.transparentPixel != -1) {
- drawBitmapTransparent(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
- } else {
- drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
- }
- if (mustRestore) {
- int hOldBitmap = OS.SelectObject(memGC.handle, srcImage.handle);
- memGC.data.hNullBitmap = hOldBitmap;
- }
-}
-
-void drawBitmapAlpha(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, BITMAP bm, int imgWidth, int imgHeight) {
- /* Simple cases */
- if (srcImage.alpha == 0) return;
- if (srcImage.alpha == 255) {
- drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
- return;
- }
-
- /* Check clipping */
- Rectangle rect = getClipping();
- rect = rect.intersection(new Rectangle(destX, destY, destWidth, destHeight));
- if (rect.isEmpty()) return;
-
- /*
- * Optimization. Recalculate src and dest rectangles so that
- * only the clipping area is drawn.
- */
- int sx1 = srcX + (((rect.x - destX) * srcWidth) / destWidth);
- int sx2 = srcX + ((((rect.x + rect.width) - destX) * srcWidth) / destWidth);
- int sy1 = srcY + (((rect.y - destY) * srcHeight) / destHeight);
- int sy2 = srcY + ((((rect.y + rect.height) - destY) * srcHeight) / destHeight);
- destX = rect.x;
- destY = rect.y;
- destWidth = rect.width;
- destHeight = rect.height;
- srcX = sx1;
- srcY = sy1;
- srcWidth = Math.max(1, sx2 - sx1);
- srcHeight = Math.max(1, sy2 - sy1);
-
- /* Create resources */
- int srcHdc = OS.CreateCompatibleDC(handle);
- int oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle);
- int memHdc = OS.CreateCompatibleDC(handle);
- int memDib = createDIB(Math.max(srcWidth, destWidth), Math.max(srcHeight, destHeight));
- int oldMemBitmap = OS.SelectObject(memHdc, memDib);
-
- BITMAP dibBM = new BITMAP();
- OS.GetObject(memDib, BITMAP.sizeof, dibBM);
- int sizeInBytes = dibBM.bmWidthBytes * dibBM.bmHeight;
-
- /* Get the background pixels */
- OS.BitBlt(memHdc, 0, 0, destWidth, destHeight, handle, destX, destY, OS.SRCCOPY);
- byte[] destData = new byte[sizeInBytes];
- OS.MoveMemory(destData, dibBM.bmBits, sizeInBytes);
-
- /* Get the foreground pixels */
- OS.BitBlt(memHdc, 0, 0, srcWidth, srcHeight, srcHdc, srcX, srcY, OS.SRCCOPY);
- byte[] srcData = new byte[sizeInBytes];
- OS.MoveMemory(srcData, dibBM.bmBits, sizeInBytes);
-
- /* Merge the alpha channel in place */
- int alpha = srcImage.alpha;
- final boolean hasAlphaChannel = (srcImage.alpha == -1);
- if (hasAlphaChannel) {
- final int apinc = imgWidth - srcWidth;
- final int spinc = dibBM.bmWidthBytes - srcWidth * 4;
- int ap = srcY * imgWidth + srcX, sp = 3;
- byte[] alphaData = srcImage.alphaData;
- for (int y = 0; y < srcHeight; ++y) {
- for (int x = 0; x < srcWidth; ++x) {
- srcData[sp] = alphaData[ap++];
- sp += 4;
- }
- ap += apinc;
- sp += spinc;
- }
- }
-
- /* Scale the foreground pixels with alpha */
- if (!OS.IsWinCE) OS.SetStretchBltMode(memHdc, OS.COLORONCOLOR);
- OS.MoveMemory(dibBM.bmBits, srcData, sizeInBytes);
- /*
- * Bug in WinCE and Win98. StretchBlt does not correctly stretch when
- * the source and destination HDCs are the same. The workaround is to
- * stretch to a temporary HDC and blit back into the original HDC.
- * Note that on WinCE StretchBlt correctly compresses the image when the
- * source and destination HDCs are the same.
- */
- if ((OS.IsWinCE && (destWidth > srcWidth || destHeight > srcHeight)) || (!OS.IsWinNT && !OS.IsWinCE)) {
- int tempHdc = OS.CreateCompatibleDC(handle);
- int tempDib = createDIB(destWidth, destHeight);
- int oldTempBitmap = OS.SelectObject(tempHdc, tempDib);
- OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, memHdc, 0, 0, srcWidth, srcHeight, OS.SRCCOPY);
- OS.BitBlt(memHdc, 0, 0, destWidth, destHeight, tempHdc, 0, 0, OS.SRCCOPY);
- OS.SelectObject(tempHdc, oldTempBitmap);
- OS.DeleteObject(tempDib);
- OS.DeleteDC(tempHdc);
- } else {
- OS.StretchBlt(memHdc, 0, 0, destWidth, destHeight, memHdc, 0, 0, srcWidth, srcHeight, OS.SRCCOPY);
- }
- OS.MoveMemory(srcData, dibBM.bmBits, sizeInBytes);
-
- /* Compose the pixels */
- final int dpinc = dibBM.bmWidthBytes - destWidth * 4;
- int dp = 0;
- for (int y = 0; y < destHeight; ++y) {
- for (int x = 0; x < destWidth; ++x) {
- if (hasAlphaChannel) alpha = srcData[dp + 3] & 0xff;
- destData[dp] += ((srcData[dp] & 0xff) - (destData[dp] & 0xff)) * alpha / 255;
- destData[dp + 1] += ((srcData[dp + 1] & 0xff) - (destData[dp + 1] & 0xff)) * alpha / 255;
- destData[dp + 2] += ((srcData[dp + 2] & 0xff) - (destData[dp + 2] & 0xff)) * alpha / 255;
- dp += 4;
- }
- dp += dpinc;
- }
-
- /* Draw the composed pixels */
- OS.MoveMemory(dibBM.bmBits, destData, sizeInBytes);
- OS.BitBlt(handle, destX, destY, destWidth, destHeight, memHdc, 0, 0, OS.SRCCOPY);
-
- /* Free resources */
- OS.SelectObject(memHdc, oldMemBitmap);
- OS.DeleteDC(memHdc);
- OS.DeleteObject(memDib);
- OS.SelectObject(srcHdc, oldSrcBitmap);
- OS.DeleteDC(srcHdc);
-}
-
-void drawBitmapTransparent(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, BITMAP bm, int imgWidth, int imgHeight) {
-
- /* Get the HDC for the device */
- Device device = data.device;
- int hDC = device.internal_new_GC(null);
-
- /* Find the RGB values for the transparent pixel. */
- int transBlue = 0, transGreen = 0, transRed = 0;
- boolean isDib = bm.bmBits != 0;
- int hBitmap = srcImage.handle;
- int srcHdc = OS.CreateCompatibleDC(handle);
- int oldSrcBitmap = OS.SelectObject(srcHdc, hBitmap);
- byte[] originalColors = null;
- if (bm.bmBitsPixel <= 8) {
- if (isDib) {
- /* Palette-based DIBSECTION */
- if (OS.IsWinCE) {
- byte[] pBits = new byte[1];
- OS.MoveMemory(pBits, bm.bmBits, 1);
- byte oldValue = pBits[0];
- int mask = (0xFF << (8 - bm.bmBitsPixel)) & 0x00FF;
- pBits[0] = (byte)((srcImage.transparentPixel << (8 - bm.bmBitsPixel)) | (pBits[0] & ~mask));
- OS.MoveMemory(bm.bmBits, pBits, 1);
- int color = OS.GetPixel(srcHdc, 0, 0);
- pBits[0] = oldValue;
- OS.MoveMemory(bm.bmBits, pBits, 1);
- transBlue = (color & 0xFF0000) >> 16;
- transGreen = (color & 0xFF00) >> 8;
- transRed = color & 0xFF;
- } else {
- int maxColors = 1 << bm.bmBitsPixel;
- byte[] oldColors = new byte[maxColors * 4];
- OS.GetDIBColorTable(srcHdc, 0, maxColors, oldColors);
- int offset = srcImage.transparentPixel * 4;
- byte[] newColors = new byte[oldColors.length];
- transRed = transGreen = transBlue = 0xff;
- newColors[offset] = (byte)transBlue;
- newColors[offset+1] = (byte)transGreen;
- newColors[offset+2] = (byte)transRed;
- OS.SetDIBColorTable(srcHdc, 0, maxColors, newColors);
- originalColors = oldColors;
- }
- } else {
- /* Palette-based bitmap */
- int numColors = 1 << bm.bmBitsPixel;
- /* Set the few fields necessary to get the RGB data out */
- BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
- bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
- bmiHeader.biPlanes = bm.bmPlanes;
- bmiHeader.biBitCount = bm.bmBitsPixel;
- byte[] bmi = new byte[BITMAPINFOHEADER.sizeof + numColors * 4];
- OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
- if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
- OS.GetDIBits(srcHdc, srcImage.handle, 0, 0, 0, bmi, OS.DIB_RGB_COLORS);
- int offset = BITMAPINFOHEADER.sizeof + 4 * srcImage.transparentPixel;
- transRed = bmi[offset + 2] & 0xFF;
- transGreen = bmi[offset + 1] & 0xFF;
- transBlue = bmi[offset] & 0xFF;
- }
- } else {
- /* Direct color image */
- int pixel = srcImage.transparentPixel;
- switch (bm.bmBitsPixel) {
- case 16:
- transBlue = (pixel & 0x1F) << 3;
- transGreen = (pixel & 0x3E0) >> 2;
- transRed = (pixel & 0x7C00) >> 7;
- break;
- case 24:
- transBlue = (pixel & 0xFF0000) >> 16;
- transGreen = (pixel & 0xFF00) >> 8;
- transRed = pixel & 0xFF;
- break;
- case 32:
- transBlue = (pixel & 0xFF000000) >>> 24;
- transGreen = (pixel & 0xFF0000) >> 16;
- transRed = (pixel & 0xFF00) >> 8;
- break;
- }
- }
-
- if (OS.IsWinCE) {
- /*
- * Note in WinCE. TransparentImage uses the first entry of a palette
- * based image when there are multiple entries that have the same
- * transparent color.
- */
- int transparentColor = transBlue << 16 | transGreen << 8 | transRed;
- OS.TransparentImage(handle, destX, destY, destWidth, destHeight,
- srcHdc, srcX, srcY, srcWidth, srcHeight, transparentColor);
- } else {
- /* Create the mask for the source image */
- int maskHdc = OS.CreateCompatibleDC(hDC);
- int maskBitmap = OS.CreateBitmap(imgWidth, imgHeight, 1, 1, null);
- int oldMaskBitmap = OS.SelectObject(maskHdc, maskBitmap);
- OS.SetBkColor(srcHdc, (transBlue << 16) | (transGreen << 8) | transRed);
- OS.BitBlt(maskHdc, 0, 0, imgWidth, imgHeight, srcHdc, 0, 0, OS.SRCCOPY);
- if (originalColors != null) OS.SetDIBColorTable(srcHdc, 0, 1 << bm.bmBitsPixel, originalColors);
-
- /* Draw the source bitmap transparently using invert/and mask/invert */
- int tempHdc = OS.CreateCompatibleDC(hDC);
- int tempBitmap = OS.CreateCompatibleBitmap(hDC, destWidth, destHeight);
- int oldTempBitmap = OS.SelectObject(tempHdc, tempBitmap);
- OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, handle, destX, destY, OS.SRCCOPY);
- if (!OS.IsWinCE) OS.SetStretchBltMode(tempHdc, OS.COLORONCOLOR);
- OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCINVERT);
- OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, maskHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCAND);
- OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCINVERT);
- OS.BitBlt(handle, destX, destY, destWidth, destHeight, tempHdc, 0, 0, OS.SRCCOPY);
-
- /* Release resources */
- OS.SelectObject(tempHdc, oldTempBitmap);
- OS.DeleteDC(tempHdc);
- OS.DeleteObject(tempBitmap);
- OS.SelectObject(maskHdc, oldMaskBitmap);
- OS.DeleteDC(maskHdc);
- OS.DeleteObject(maskBitmap);
- }
- OS.SelectObject(srcHdc, oldSrcBitmap);
- if (hBitmap != srcImage.handle) OS.DeleteObject(hBitmap);
- OS.DeleteDC(srcHdc);
-
- /* Release the HDC for the device */
- device.internal_dispose_GC(hDC, null);
-}
-
-void drawBitmap(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, BITMAP bm, int imgWidth, int imgHeight) {
- int srcHdc = OS.CreateCompatibleDC(handle);
- int oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle);
- int mode = 0, rop2 = 0;
- if (!OS.IsWinCE) {
- rop2 = OS.GetROP2(handle);
- mode = OS.SetStretchBltMode(handle, OS.COLORONCOLOR);
- } else {
- rop2 = OS.SetROP2 (handle, OS.R2_COPYPEN);
- OS.SetROP2 (handle, rop2);
- }
- int dwRop = rop2 == OS.R2_XORPEN ? OS.SRCINVERT : OS.SRCCOPY;
- OS.StretchBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, dwRop);
- if (!OS.IsWinCE) {
- OS.SetStretchBltMode(handle, mode);
- }
- OS.SelectObject(srcHdc, oldSrcBitmap);
- OS.DeleteDC(srcHdc);
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- if (OS.IsWinCE) {
- int [] points = new int [] {x1, y1, x2, y2};
- OS.Polyline (handle, points, points.length / 2);
- } else {
- OS.MoveToEx (handle, x1, y1, 0);
- OS.LineTo (handle, x2, y2);
- }
- OS.SetPixel (handle, x2, y2, OS.GetTextColor (handle));
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- // Check performance impact of always setting null brush. If the user has not
- // set the background color, we may not have to do this work?
- int nullBrush = OS.GetStockObject(OS.NULL_BRUSH);
- int oldBrush = OS.SelectObject(handle, nullBrush);
- OS.Ellipse(handle, x,y,x+width+1,y+height+1);
- OS.SelectObject(handle,oldBrush);
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- int nullBrush = OS.GetStockObject(OS.NULL_BRUSH);
- int oldBrush = OS.SelectObject(handle, nullBrush);
- OS.Polygon(handle, pointArray, pointArray.length / 2);
- OS.SelectObject(handle, oldBrush);
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- OS.Polyline(handle, pointArray, pointArray.length / 2);
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- int hOld = OS.SelectObject (handle, OS.GetStockObject (OS.NULL_BRUSH));
- OS.Rectangle (handle, x, y, x + width + 1, y + height + 1);
- OS.SelectObject (handle, hOld);
-}
-
-/**
- * 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 (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.
- *
- * @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 horizontal diameter of the arc at the four corners
- * @param arcHeight the vertical diameter of the arc at the four corners
- *
- * @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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- if (OS.IsWinCE) {
- /*
- * Bug in WinCE PPC. On certain devices, RoundRect does not draw
- * all the pixels. The workaround is to draw a round rectangle
- * using lines and arcs.
- */
- if (width == 0 || height == 0) return;
- if (arcWidth == 0 || arcHeight == 0) {
- drawRectangle(x, y, width, height);
- return;
- }
- if (width < 0) {
- x += width;
- width = -width;
- }
- if (height < 0) {
- y += height;
- height = -height;
- };
- if (arcWidth < 0) arcWidth = -arcWidth;
- if (arcHeight < 0) arcHeight = -arcHeight;
- if (arcWidth > width) arcWidth = width;
- if (arcHeight > height) arcHeight = height;
-
- if (arcWidth < width) {
- drawLine(x+arcWidth/2, y, x+width-arcWidth/2, y);
- drawLine(x+arcWidth/2, y+height-1, x+width-arcWidth/2, y+height-1);
- }
- if (arcHeight < height) {
- drawLine(x, y+arcHeight/2, x, y+height-arcHeight/2);
- drawLine(x+width-1, y+arcHeight/2, x+width-1, y+height-arcHeight/2);
- }
- if (arcWidth != 0 && arcHeight != 0) {
- drawArc(x, y, arcWidth, arcHeight, 90, 90);
- drawArc(x+width-arcWidth-1, y, arcWidth, arcHeight, 0, 90);
- drawArc(x+width-arcWidth-1, y+height-arcHeight-1, arcWidth, arcHeight, 0, -90);
- drawArc(x, y+height-arcHeight-1, arcWidth, arcHeight, 180, 90);
- }
- } else {
- int nullBrush = OS.GetStockObject(OS.NULL_BRUSH);
- int oldBrush = OS.SelectObject(handle, nullBrush);
- OS.RoundRect(handle, x,y,x+width,y+height, arcWidth, arcHeight);
- OS.SelectObject(handle,oldBrush);
- }
-}
-
-/**
- * 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) {
- if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
-// TCHAR buffer = new TCHAR (getCodePage(), string, false);
- int length = string.length();
- char[] buffer = new char [length];
- string.getChars(0, length, buffer, 0);
- int oldBkMode = OS.SetBkMode(handle, isTransparent ? OS.TRANSPARENT : OS.OPAQUE);
- OS.ExtTextOutW(handle, x, y, 0, null, buffer, length, null);
- OS.SetBkMode(handle, oldBkMode);
-}
-
-/**
- * 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 specifing 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- RECT rect = new RECT();
- OS.SetRect(rect, x, y, 0x7FFF, 0x7FFF);
- TCHAR buffer = new TCHAR(getCodePage(), string, false);
- int uFormat = OS.DT_LEFT;
- if ((flags & SWT.DRAW_DELIMITER) == 0) uFormat |= OS.DT_SINGLELINE;
- if ((flags & SWT.DRAW_TAB) != 0) uFormat |= OS.DT_EXPANDTABS;
- if ((flags & SWT.DRAW_MNEMONIC) == 0) uFormat |= OS.DT_NOPREFIX;
- int oldBkMode = OS.SetBkMode(handle, (flags & SWT.DRAW_TRANSPARENT) != 0 ? OS.TRANSPARENT : OS.OPAQUE);
- OS.DrawText(handle, buffer, buffer.length(), rect, uFormat);
- OS.SetBkMode(handle, oldBkMode);
-}
-
-/**
- * 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) {
- return (object == this) || ((object instanceof GC) && (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 IllegalArgumentException <ul>
- * <li>ERROR_INVALID_ARGUMENT - if any of the width, height or endAngle is zero.</li>
- * </ul>
- * @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 endAngle) {
- if (handle == 0) 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 || endAngle == 0) {
- SWT.error (SWT.ERROR_INVALID_ARGUMENT);
- }
-
- /*
- * Feature in WinCE. The function Pie is not present in the
- * WinCE SDK. The fix is to emulate it by using Polygon.
- */
- if (OS.IsWinCE) {
- /* compute arc with a simple linear interpolation */
- if (endAngle < 0) {
- startAngle += endAngle;
- endAngle = -endAngle;
- }
- boolean drawSegments = true;
- if (endAngle >= 360) {
- endAngle = 360;
- drawSegments = false;
- }
- int[] points = new int[(endAngle + 1) * 2 + (drawSegments ? 4 : 0)];
- int cteX = 2 * x + width;
- int cteY = 2 * y + height;
- int index = (drawSegments ? 2 : 0);
- for (int i = 0; i <= endAngle; i++) {
- points[index++] = (Compatibility.cos(startAngle + i, width) + cteX) >> 1;
- points[index++] = (cteY - Compatibility.sin(startAngle + i, height)) >> 1;
- }
- if (drawSegments) {
- points[0] = points[points.length - 2] = cteX >> 1;
- points[1] = points[points.length - 1] = cteY >> 1;
- }
- int nullPen = OS.GetStockObject(OS.NULL_PEN);
- int oldPen = OS.SelectObject(handle, nullPen);
- OS.Polygon(handle, points, points.length / 2);
- OS.SelectObject(handle, oldPen);
- } else {
- int x1, y1, x2, y2,tmp;
- boolean isNegative;
- if (endAngle >= 360 || endAngle <= -360) {
- x1 = x2 = x + width;
- y1 = y2 = y + height / 2;
- } else {
- isNegative = endAngle < 0;
-
- endAngle = endAngle + startAngle;
- if (isNegative) {
- // swap angles
- tmp = startAngle;
- startAngle = endAngle;
- endAngle = tmp;
- }
- x1 = Compatibility.cos(startAngle, width) + x + width/2;
- y1 = -1 * Compatibility.sin(startAngle, height) + y + height/2;
-
- x2 = Compatibility.cos(endAngle, width) + x + width/2;
- y2 = -1 * Compatibility.sin(endAngle, height) + y + height/2;
- }
-
- int nullPen = OS.GetStockObject(OS.NULL_PEN);
- int oldPen = OS.SelectObject(handle, nullPen);
- OS.Pie(handle, x,y,x+width+1,y+height+1,x1,y1,x2,y2 );
- OS.SelectObject(handle,oldPen);
- }
-}
-
-/**
- * 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
- */
-public void fillGradientRectangle(int x, int y, int width, int height, boolean vertical) {
- if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- if (width == 0 || height == 0) return;
- int fromColor = OS.GetTextColor(handle);
- if (fromColor == OS.CLR_INVALID) {
- fromColor = OS.GetSysColor(OS.COLOR_WINDOWTEXT);
- }
- int toColor = OS.GetBkColor(handle);
- if (toColor == OS.CLR_INVALID) {
- toColor = OS.GetSysColor(OS.COLOR_WINDOW);
- }
- 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) {
- final int t = fromColor;
- fromColor = toColor;
- toColor = t;
- }
- final RGB fromRGB = new RGB(fromColor & 0xff, (fromColor >>> 8) & 0xff, (fromColor >>> 16) & 0xff);
- final RGB toRGB = new RGB(toColor & 0xff, (toColor >>> 8) & 0xff, (toColor >>> 16) & 0xff);
- if ((fromRGB.red == toRGB.red) && (fromRGB.green == toRGB.green) && (fromRGB.blue == toRGB.blue)) {
- OS.PatBlt(handle, x, y, width, height, OS.PATCOPY);
- return;
- }
-
- /* Use GradientFill if supported, only on Windows 98, 2000 and newer */
- if (!OS.IsWinCE) {
- final int hHeap = OS.GetProcessHeap();
- final int pMesh = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY,
- GRADIENT_RECT.sizeof + TRIVERTEX.sizeof * 2);
- final int pVertex = pMesh + GRADIENT_RECT.sizeof;
-
- GRADIENT_RECT gradientRect = new GRADIENT_RECT();
- gradientRect.UpperLeft = 0;
- gradientRect.LowerRight = 1;
- OS.MoveMemory(pMesh, gradientRect, GRADIENT_RECT.sizeof);
-
- TRIVERTEX trivertex = new TRIVERTEX();
- trivertex.x = x;
- trivertex.y = y;
- trivertex.Red = (short)((fromRGB.red << 8) | fromRGB.red);
- trivertex.Green = (short)((fromRGB.green << 8) | fromRGB.green);
- trivertex.Blue = (short)((fromRGB.blue << 8) | fromRGB.blue);
- trivertex.Alpha = -1;
- OS.MoveMemory(pVertex, trivertex, TRIVERTEX.sizeof);
-
- trivertex.x = x + width;
- trivertex.y = y + height;
- trivertex.Red = (short)((toRGB.red << 8) | toRGB.red);
- trivertex.Green = (short)((toRGB.green << 8) | toRGB.green);
- trivertex.Blue = (short)((toRGB.blue << 8) | toRGB.blue);
- trivertex.Alpha = -1;
- OS.MoveMemory(pVertex + TRIVERTEX.sizeof, trivertex, TRIVERTEX.sizeof);
-
- boolean success = OS.GradientFill(handle, pVertex, 2, pMesh, 1,
- vertical ? OS.GRADIENT_FILL_RECT_V : OS.GRADIENT_FILL_RECT_H);
- OS.HeapFree(hHeap, 0, pMesh);
- if (success) return;
- }
-
- final int depth = OS.GetDeviceCaps(handle, OS.BITSPIXEL);
- final int bitResolution = (depth >= 24) ? 8 : (depth >= 15) ? 5 : 0;
- ImageData.fillGradientRectangle(this, data.device,
- x, y, width, height, vertical, fromRGB, toRGB,
- bitResolution, bitResolution, bitResolution);
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
-
- /* Assumes that user sets the background color. */
- int nullPen = OS.GetStockObject(OS.NULL_PEN);
- int oldPen = OS.SelectObject(handle, nullPen);
- OS.Ellipse(handle, x,y,x+width+1,y+height+1);
- OS.SelectObject(handle,oldPen);
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- int nullPen = OS.GetStockObject(OS.NULL_PEN);
- int oldPen = OS.SelectObject(handle, nullPen);
- OS.Polygon(handle, pointArray, pointArray.length / 2);
- OS.SelectObject(handle,oldPen);
-}
-
-/**
- * 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
- */
-public void fillRectangle (int x, int y, int width, int height) {
- if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- int rop2 = 0;
- if (OS.IsWinCE) {
- rop2 = OS.SetROP2(handle, OS.R2_COPYPEN);
- OS.SetROP2(handle, rop2);
- } else {
- rop2 = OS.GetROP2(handle);
- }
- int dwRop = rop2 == OS.R2_XORPEN ? OS.PATINVERT : OS.PATCOPY;
- OS.PatBlt(handle, x, y, width, height, dwRop);
-}
-
-/**
- * Fills the interior of the specified rectangle, using the receiver's
- * background color.
- *
- * @param rectangle 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
- */
-public void fillRectangle (Rectangle rect) {
- 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 horizontal diameter of the arc at the four corners
- * @param arcHeight the vertical diameter of the arc at the four corners
- *
- * @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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- int nullPen = OS.GetStockObject(OS.NULL_PEN);
- int oldPen = OS.SelectObject(handle, nullPen);
- OS.RoundRect(handle, x,y,x+width,y+height,arcWidth, arcHeight);
- OS.SelectObject(handle,oldPen);
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- if (OS.IsWinCE) {
- SIZE size = new SIZE();
- OS.GetTextExtentPoint32W(handle, new char[]{ch}, 1, size);
- return size.cx;
- }
- int tch = ch;
- if (ch > 0x7F) {
- TCHAR buffer = new TCHAR(getCodePage(), ch, false);
- tch = buffer.tcharAt(0);
- }
- int[] width = new int[1];
- OS.GetCharWidth(handle, tch, tch, width);
- return width[0];
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- int color = OS.GetBkColor(handle);
- if (color == OS.CLR_INVALID) {
- color = OS.GetSysColor(OS.COLOR_WINDOW);
- }
- return Color.win32_new(data.device, color);
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
-
- /* GetCharABCWidths only succeeds on truetype fonts */
- if (!OS.IsWinCE) {
- int tch = ch;
- if (ch > 0x7F) {
- TCHAR buffer = new TCHAR(getCodePage(), ch, false);
- tch = buffer.tcharAt (0);
- }
- int[] width = new int[3];
- if (OS.GetCharABCWidths(handle, tch, tch, width)) {
- return width[1];
- }
- }
-
- /* It wasn't a truetype font */
- TEXTMETRIC tm = new TEXTMETRIC();
- OS.GetTextMetricsW(handle, tm);
- SIZE size = new SIZE();
- OS.GetTextExtentPoint32W(handle, new char[]{ch}, 1, size);
- return size.cx - tm.tmOverhang;
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- RECT rect = new RECT();
- OS.GetClipBox(handle, rect);
- return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
-}
-
-/**
- * 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>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
- * </ul>
- */
-public void getClipping (Region region) {
- if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- if (region == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
- int result = OS.GetClipRgn (handle, region.handle);
- if (result == 1) return;
- RECT rect = new RECT();
- OS.GetClipBox(handle, rect);
- OS.SetRectRgn(region.handle, rect.left, rect.top, rect.right, rect.bottom);
-}
-
-int getCodePage () {
- if (OS.IsWinCE) return OS.GetACP();
- int[] lpCs = new int[8];
- int cs = OS.GetTextCharset(handle);
- OS.TranslateCharsetInfo(cs, lpCs, OS.TCI_SRCCHARSET);
- return lpCs[1];
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- int hFont = OS.GetCurrentObject(handle, OS.OBJ_FONT);
- return Font.win32_new(data.device, hFont);
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- TEXTMETRIC lptm = new TEXTMETRIC();
- OS.GetTextMetrics(handle, lptm);
- return FontMetrics.win32_new(lptm);
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- int color = OS.GetTextColor(handle);
- if (color == OS.CLR_INVALID) {
- color = OS.GetSysColor(OS.COLOR_WINDOWTEXT);
- }
- return Color.win32_new(data.device, color);
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- int hPen = OS.GetCurrentObject(handle, OS.OBJ_PEN);
- LOGPEN logPen = new LOGPEN();
- OS.GetObject(hPen, LOGPEN.sizeof, logPen);
- switch (logPen.lopnStyle) {
- case OS.PS_SOLID: return SWT.LINE_SOLID;
- case OS.PS_DASH: return SWT.LINE_DASH;
- case OS.PS_DOT: return SWT.LINE_DOT;
- case OS.PS_DASHDOT: return SWT.LINE_DASHDOT;
- case OS.PS_DASHDOTDOT: return SWT.LINE_DASHDOTDOT;
- default: return SWT.LINE_SOLID;
- }
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- int hPen = OS.GetCurrentObject(handle, OS.OBJ_PEN);
- LOGPEN logPen = new LOGPEN();
- OS.GetObject(hPen, LOGPEN.sizeof, logPen);
- return logPen.x;
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- int rop2 = 0;
- if (OS.IsWinCE) {
- rop2 = OS.SetROP2 (handle, OS.R2_COPYPEN);
- OS.SetROP2 (handle, rop2);
- } else {
- rop2 = OS.GetROP2(handle);
- }
- return rop2 == OS.R2_XORPEN;
-}
-
-void init(Drawable drawable, GCData data, int hDC) {
- int foreground = data.foreground;
- if (foreground != -1 && OS.GetTextColor(hDC) != foreground) {
- OS.SetTextColor(hDC, foreground);
- int hPen = OS.CreatePen(OS.PS_SOLID, 0, foreground);
- OS.SelectObject(hDC, hPen);
- }
- int background = data.background;
- if (background != -1 && OS.GetBkColor(hDC) != background) {
- OS.SetBkColor(hDC, background);
- int hBrush = OS.CreateSolidBrush(background);
- OS.SelectObject(hDC, hBrush);
- }
- int hFont = data.hFont;
- if (hFont != 0) OS.SelectObject (hDC, hFont);
- int hPalette = data.device.hPalette;
- if (hPalette != 0) {
- OS.SelectPalette(hDC, hPalette, true);
- OS.RealizePalette(hDC);
- }
- Image image = data.image;
- if (image != null) {
- data.hNullBitmap = OS.SelectObject(hDC, image.handle);
- image.memGC = this;
- }
- this.drawable = drawable;
- this.data = data;
- handle = hDC;
-}
-
-/**
- * Returns an integer hash code for the receiver. Any two
- * objects which 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;
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- int region = OS.CreateRectRgn(0, 0, 0, 0);
- int result = OS.GetClipRgn(handle, region);
- OS.DeleteObject(region);
- return (result > 0);
-}
-
-/**
- * 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 == 0;
-}
-
-/**
- * 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 == 0) 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 (OS.GetBkColor(handle) == color.handle) return;
- OS.SetBkColor (handle, color.handle);
- int newBrush = OS.CreateSolidBrush (color.handle);
- int oldBrush = OS.SelectObject (handle, newBrush);
- OS.DeleteObject (oldBrush);
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- int hRgn = OS.CreateRectRgn (x, y, x + width, y + height);
- OS.SelectClipRgn (handle, hRgn);
- OS.DeleteObject (hRgn);
-}
-
-/**
- * Sets the area of the receiver which can be changed
- * by drawing operations to the rectangular area specified
- * by the argument.
- *
- * @param rect the clipping rectangle
- *
- * @exception SWTException <ul>
- * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
- * </ul>
- */
-public void setClipping (Rectangle rect) {
- if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- if (rect == null) {
- OS.SelectClipRgn (handle, 0);
- return;
- }
- 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.
- *
- * @param rect the clipping region.
- *
- * @exception SWTException <ul>
- * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
- * </ul>
- */
-public void setClipping (Region region) {
- if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- int hRegion = 0;
- if (region != null) hRegion = region.handle;
- OS.SelectClipRgn (handle, hRegion);
-}
-
-/**
- * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- if (font == null) {
- OS.SelectObject(handle, data.device.systemFont);
- } else {
- if (font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- OS.SelectObject(handle, font.handle);
- }
-}
-
-/**
- * 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 == 0) 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 (OS.GetTextColor(handle) == color.handle) return;
- int hPen = OS.GetCurrentObject(handle, OS.OBJ_PEN);
- LOGPEN logPen = new LOGPEN();
- OS.GetObject(hPen, LOGPEN.sizeof, logPen);
- OS.SetTextColor (handle, color.handle);
- int newPen = OS.CreatePen (logPen.lopnStyle, logPen.x, color.handle);
- int oldPen = OS.SelectObject (handle, newPen);
- OS.DeleteObject (oldPen);
-}
-
-/**
- * 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 SWTException <ul>
- * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
- * </ul>
- */
-public void setLineStyle(int lineStyle) {
- if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- int style = -1;
- switch (lineStyle) {
- case SWT.LINE_SOLID: style = OS.PS_SOLID; break;
- case SWT.LINE_DASH: style = OS.PS_DASH; break;
- case SWT.LINE_DOT: style = OS.PS_DOT; break;
- case SWT.LINE_DASHDOT: style = OS.PS_DASHDOT; break;
- case SWT.LINE_DASHDOTDOT: style = OS.PS_DASHDOTDOT; break;
- default:
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- }
- int hPen = OS.GetCurrentObject(handle, OS.OBJ_PEN);
- LOGPEN logPen = new LOGPEN();
- OS.GetObject(hPen, LOGPEN.sizeof, logPen);
- if (logPen.lopnStyle == style) return;
- OS.SetBkMode (handle, style == OS.PS_SOLID ? OS.OPAQUE : OS.TRANSPARENT);
- int newPen = OS.CreatePen(style, logPen.x, logPen.lopnColor);
- int oldPen = OS.SelectObject(handle, newPen);
- OS.DeleteObject(oldPen);
-}
-
-/**
- * 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.
- *
- * @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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- int hPen = OS.GetCurrentObject(handle, OS.OBJ_PEN);
- LOGPEN logPen = new LOGPEN();
- OS.GetObject(hPen, LOGPEN.sizeof, logPen);
- if (logPen.x == lineWidth) return;
- int newPen = OS.CreatePen(logPen.lopnStyle, lineWidth, logPen.lopnColor);
- int oldPen = OS.SelectObject(handle, newPen);
- OS.DeleteObject(oldPen);
-}
-
-/**
- * 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.
- *
- * @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>
- */
-public void setXORMode(boolean xor) {
- if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- if (xor) {
- OS.SetROP2(handle, OS.R2_XORPEN);
- } else {
- OS.SetROP2(handle, OS.R2_COPYPEN);
- }
-}
-
-/**
- * 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) {
- if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
- SIZE size = new SIZE();
- int length = string.length();
- if (length == 0) {
-// OS.GetTextExtentPoint32(handle, SPACE, SPACE.length(), size);
- OS.GetTextExtentPoint32W(handle, new char[]{' '}, 1, size);
- return new Point(0, size.cy);
- } else {
-// TCHAR buffer = new TCHAR (getCodePage(), string, false);
- char[] buffer = new char [length];
- string.getChars(0, length, buffer, 0);
- OS.GetTextExtentPoint32W(handle, buffer, length, size);
- return new Point(size.cx, size.cy);
- }
-}
-
-/**
- * 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 specifing 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
- if (string.length () == 0) {
- SIZE size = new SIZE();
-// OS.GetTextExtentPoint32(handle, SPACE, SPACE.length(), size);
- OS.GetTextExtentPoint32W(handle, new char [] {' '}, 1, size);
- return new Point(0, size.cy);
- }
- RECT rect = new RECT();
- TCHAR buffer = new TCHAR(getCodePage(), string, false);
- int uFormat = OS.DT_LEFT | OS.DT_CALCRECT;
- if ((flags & SWT.DRAW_DELIMITER) == 0) uFormat |= OS.DT_SINGLELINE;
- if ((flags & SWT.DRAW_TAB) != 0) uFormat |= OS.DT_EXPANDTABS;
- if ((flags & SWT.DRAW_MNEMONIC) == 0) uFormat |= OS.DT_NOPREFIX;
- OS.DrawText(handle, buffer, buffer.length(), rect, uFormat);
- return new Point(rect.right, rect.bottom);
-}
-
-/**
- * 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 + "}";
-}
-
-/**
- * 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 win32_new(Drawable drawable, GCData data) {
- GC gc = new GC();
- int hDC = drawable.internal_new_GC(data);
- gc.init(drawable, data, hDC);
- return gc;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; + +/** + * 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>. + * <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> + * + * @see org.eclipse.swt.events.PaintEvent + */ + +public final class GC { + + /** + * the handle to the OS device context + * (Warning: This field is platform dependent) + */ + public int handle; + + Drawable drawable; + GCData data; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +GC() { +} + +/** + * Constructs a new instance of this class which has been + * configured to draw on the specified drawable. Sets the + * foreground and background color 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> + * </ul> + */ +public GC(Drawable drawable) { + if (drawable == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + GCData data = new GCData (); + int hDC = drawable.internal_new_GC (data); + Device device = data.device; + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + data.device = device; + init (drawable, data, hDC); + if (device.tracking) device.new_Object(this); +} + +/** + * Copies a rectangular area of the receiver at the specified + * position into the image, which must be of type <code>SWT.BITMAP</code>. + * + * @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 == 0) 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); + + /* Get the HDC for the device */ + Device device = data.device; + int hDC = device.internal_new_GC(null); + + /* Copy the bitmap area */ + Rectangle rect = image.getBounds(); + int memHdc = OS.CreateCompatibleDC(hDC); + int hOldBitmap = OS.SelectObject(memHdc, image.handle); + OS.BitBlt(memHdc, 0, 0, rect.width, rect.height, handle, x, y, OS.SRCCOPY); + OS.SelectObject(memHdc, hOldBitmap); + OS.DeleteDC(memHdc); + + /* Release the HDC for the device */ + device.internal_dispose_GC(hDC, null); +} + +/** + * 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) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + + /* + * Feature in WinCE. The function WindowFromDC is not part of the + * WinCE SDK. The fix is to remember the HWND. + */ + int hwnd = data.hwnd; + if (hwnd == 0) { + OS.BitBlt(handle, destX, destY, width, height, handle, srcX, srcY, OS.SRCCOPY); + } else { + RECT lprcClip = null; + int hrgn = OS.CreateRectRgn(0, 0, 0, 0); + if (OS.GetClipRgn(handle, hrgn) == 1) { + lprcClip = new RECT(); + OS.GetRgnBox(hrgn, lprcClip); + } + OS.DeleteObject(hrgn); + RECT lprcScroll = new RECT(); + OS.SetRect(lprcScroll, srcX, srcY, srcX + width, srcY + height); + int res = OS.ScrollWindowEx(hwnd, destX - srcX, destY - srcY, lprcScroll, lprcClip, 0, null, OS.SW_INVALIDATE | OS.SW_ERASE); + + /* + * Feature in WinCE. ScrollWindowEx does not accept combined + * vertical and horizontal scrolling. The fix is to do a + * BitBlt and invalidate the appropriate source area. + */ + if (res == 0 && OS.IsWinCE) { + OS.BitBlt(handle, destX, destY, width, height, handle, srcX, srcY, OS.SRCCOPY); + int deltaX = destX - srcX, deltaY = destY - srcY; + boolean disjoint = (destX + width < srcX) || (srcX + width < destX) || (destY + height < srcY) || (srcY + height < destY); + if (disjoint) { + OS.InvalidateRect(hwnd, lprcScroll, true); + } else { + if (deltaX != 0) { + int newX = destX - deltaX; + if (deltaX < 0) newX = destX + width; + OS.SetRect(lprcScroll, newX, srcY, newX + Math.abs(deltaX), srcY + height); + OS.InvalidateRect(hwnd, lprcScroll, true); + } + if (deltaY != 0) { + int newY = destY - deltaY; + if (deltaY < 0) newY = destY + height; + OS.SetRect(lprcScroll, srcX, newY, srcX + width, newY + Math.abs(deltaY)); + OS.InvalidateRect(hwnd, lprcScroll, true); + } + } + } + } +} + +int createDIB(int width, int height) { + short depth = 32; + + BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER(); + bmiHeader.biSize = BITMAPINFOHEADER.sizeof; + bmiHeader.biWidth = width; + bmiHeader.biHeight = -height; + bmiHeader.biPlanes = 1; + bmiHeader.biBitCount = depth; + if (OS.IsWinCE) bmiHeader.biCompression = OS.BI_BITFIELDS; + else bmiHeader.biCompression = OS.BI_RGB; + byte[] bmi = new byte[BITMAPINFOHEADER.sizeof + (OS.IsWinCE ? 12 : 0)]; + OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof); + /* Set the rgb colors into the bitmap info */ + if (OS.IsWinCE) { + int redMask = 0xFF00; + int greenMask = 0xFF0000; + int blueMask = 0xFF000000; + /* big endian */ + int offset = BITMAPINFOHEADER.sizeof; + bmi[offset] = (byte)((redMask & 0xFF000000) >> 24); + bmi[offset + 1] = (byte)((redMask & 0xFF0000) >> 16); + bmi[offset + 2] = (byte)((redMask & 0xFF00) >> 8); + bmi[offset + 3] = (byte)((redMask & 0xFF) >> 0); + bmi[offset + 4] = (byte)((greenMask & 0xFF000000) >> 24); + bmi[offset + 5] = (byte)((greenMask & 0xFF0000) >> 16); + bmi[offset + 6] = (byte)((greenMask & 0xFF00) >> 8); + bmi[offset + 7] = (byte)((greenMask & 0xFF) >> 0); + bmi[offset + 8] = (byte)((blueMask & 0xFF000000) >> 24); + bmi[offset + 9] = (byte)((blueMask & 0xFF0000) >> 16); + bmi[offset + 10] = (byte)((blueMask & 0xFF00) >> 8); + bmi[offset + 11] = (byte)((blueMask & 0xFF) >> 0); + } + + int[] pBits = new int[1]; + int hDib = OS.CreateDIBSection(0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0); + if (hDib == 0) SWT.error(SWT.ERROR_NO_HANDLES); + return hDib; +} + +/** + * Disposes of the operating system resources associated with + * the graphics context. Applications must dispose of all GCs + * which they allocate. + */ +public void dispose() { + if (handle == 0) return; + if (data.device.isDisposed()) return; + + /* + * The only way for pens and brushes to get + * selected into the HDC is for the receiver to + * create them. When we are destroying the + * hDC we also destroy any pens and brushes that + * we have allocated. This code assumes that it + * is OK to delete stock objects. This will + * happen when a GC is disposed and the user has + * not caused new pens or brushes to be allocated. + */ + int nullPen = OS.GetStockObject(OS.NULL_PEN); + int oldPen = OS.SelectObject(handle, nullPen); + OS.DeleteObject(oldPen); + int nullBrush = OS.GetStockObject(OS.NULL_BRUSH); + int oldBrush = OS.SelectObject(handle, nullBrush); + OS.DeleteObject(oldBrush); + + /* + * Put back the original bitmap into the device context. + * This will ensure that we have not left a bitmap + * selected in it when we delete the HDC. + */ + int hNullBitmap = data.hNullBitmap; + if (hNullBitmap != 0) { + OS.SelectObject(handle, hNullBitmap); + data.hNullBitmap = 0; + } + Image image = data.image; + if (image != null) image.memGC = null; + + /* + * Dispose the HDC. + */ + Device device = data.device; + drawable.internal_dispose_GC(handle, data); + drawable = null; + handle = 0; + data.image = null; + data.ps = null; + if (device.tracking) device.dispose_Object(this); + data.device = null; + data = 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 IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if any of the width, height or endAngle is zero.</li> + * </ul> + * @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 endAngle) { + if (handle == 0) 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 || endAngle == 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + /* + * Feature in WinCE. The function Arc is not present in the + * WinCE SDK. The fix is to emulate arc drawing by using + * Polyline. + */ + if (OS.IsWinCE) { + /* compute arc with a simple linear interpolation */ + if (endAngle < 0) { + startAngle += endAngle; + endAngle = -endAngle; + } + if (endAngle > 360) endAngle = 360; + int[] points = new int[(endAngle + 1) * 2]; + int cteX = 2 * x + width; + int cteY = 2 * y + height; + int index = 0; + for (int i = 0; i <= endAngle; i++) { + points[index++] = (Compatibility.cos(startAngle + i, width) + cteX) >> 1; + points[index++] = (cteY - Compatibility.sin(startAngle + i, height)) >> 1; + } + OS.Polyline(handle, points, points.length / 2); + } else { + int x1, y1, x2, y2,tmp; + boolean isNegative; + if (endAngle >= 360 || endAngle <= -360) { + x1 = x2 = x + width; + y1 = y2 = y + height / 2; + } else { + isNegative = endAngle < 0; + + endAngle = endAngle + startAngle; + if (isNegative) { + // swap angles + tmp = startAngle; + startAngle = endAngle; + endAngle = tmp; + } + x1 = Compatibility.cos(startAngle, width) + x + width/2; + y1 = -1 * Compatibility.sin(startAngle, height) + y + height/2; + + x2 = Compatibility.cos(endAngle, width) + x + width/2; + y2 = -1 * Compatibility.sin(endAngle, height) + y + height/2; + } + int nullBrush = OS.GetStockObject(OS.NULL_BRUSH); + int oldBrush = OS.SelectObject(handle, nullBrush); + OS.Arc(handle, x,y,x+width+1,y+height+1,x1,y1,x2,y2 ); + OS.SelectObject(handle,oldBrush); + } +} + +/** + * 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 + */ +public void drawFocus (int x, int y, int width, int height) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + RECT rect = new RECT(); + OS.SetRect(rect, x, y, x + width, y + height); + OS.DrawFocusRect(handle, rect); +} + +/** + * 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 SWTError <ul> + * <li>ERROR_NO_HANDLES - if no handles are available to perform the operation</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void drawImage(Image image, int x, int y) { + if (handle == 0) 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 SWTError <ul> + * <li>ERROR_NO_HANDLES - if no handles are available to perform the operation</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</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 == 0) 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) { + switch (srcImage.type) { + case SWT.BITMAP: + drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple); + break; + case SWT.ICON: + drawIcon(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple); + break; + default: + SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); + } +} + +void drawIcon(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) { + /* Simple case: no stretching, entire icon */ + if (simple) { + OS.DrawIconEx(handle, destX, destY, srcImage.handle, 0, 0, 0, 0, OS.DI_NORMAL); + return; + } + + /* Get the icon info */ + ICONINFO srcIconInfo = new ICONINFO(); + if (OS.IsWinCE) { + Image.GetIconInfo(srcImage, srcIconInfo); + } else { + OS.GetIconInfo(srcImage.handle, srcIconInfo); + } + + /* Get the icon width and height */ + int hBitmap = srcIconInfo.hbmColor; + if (hBitmap == 0) hBitmap = srcIconInfo.hbmMask; + BITMAP bm = new BITMAP(); + OS.GetObject(hBitmap, BITMAP.sizeof, bm); + int iconWidth = bm.bmWidth, iconHeight = bm.bmHeight; + if (hBitmap == srcIconInfo.hbmMask) iconHeight /= 2; + + if (simple) { + srcWidth = destWidth = iconWidth; + srcHeight = destHeight = iconHeight; + } + + /* Draw the icon */ + boolean failed = srcX + srcWidth > iconWidth || srcY + srcHeight > iconHeight; + if (!failed) { + simple = srcX == 0 && srcY == 0 && + srcWidth == destWidth && srcHeight == destHeight && + srcWidth == iconWidth && srcHeight == iconHeight; + if (simple) { + /* Simple case: no stretching, entire icon */ + OS.DrawIconEx(handle, destX, destY, srcImage.handle, 0, 0, 0, 0, OS.DI_NORMAL); + } else { + /* Get the HDC for the device */ + Device device = data.device; + int hDC = device.internal_new_GC(null); + + /* Create the icon info and HDC's */ + ICONINFO newIconInfo = new ICONINFO(); + newIconInfo.fIcon = true; + int srcHdc = OS.CreateCompatibleDC(hDC); + int dstHdc = OS.CreateCompatibleDC(hDC); + + /* Blt the color bitmap */ + int srcColorY = srcY; + int srcColor = srcIconInfo.hbmColor; + if (srcColor == 0) { + srcColor = srcIconInfo.hbmMask; + srcColorY += iconHeight; + } + int oldSrcBitmap = OS.SelectObject(srcHdc, srcColor); + newIconInfo.hbmColor = OS.CreateCompatibleBitmap(srcHdc, destWidth, destHeight); + if (newIconInfo.hbmColor == 0) SWT.error(SWT.ERROR_NO_HANDLES); + int oldDestBitmap = OS.SelectObject(dstHdc, newIconInfo.hbmColor); + if (!OS.IsWinCE) OS.SetStretchBltMode(dstHdc, OS.COLORONCOLOR); + OS.StretchBlt(dstHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcColorY, srcWidth, srcHeight, OS.SRCCOPY); + + /* Blt the mask bitmap */ + OS.SelectObject(srcHdc, srcIconInfo.hbmMask); + newIconInfo.hbmMask = OS.CreateBitmap(destWidth, destHeight, 1, 1, null); + if (newIconInfo.hbmMask == 0) SWT.error(SWT.ERROR_NO_HANDLES); + OS.SelectObject(dstHdc, newIconInfo.hbmMask); + OS.StretchBlt(dstHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCCOPY); + + /* Select old bitmaps before creating the icon */ + OS.SelectObject(srcHdc, oldSrcBitmap); + OS.SelectObject(dstHdc, oldDestBitmap); + + /* Create the new icon */ + int hIcon = OS.CreateIconIndirect(newIconInfo); + if (hIcon == 0) SWT.error(SWT.ERROR_NO_HANDLES); + + /* Draw the new icon */ + OS.DrawIconEx(handle, destX, destY, hIcon, destWidth, destHeight, 0, 0, OS.DI_NORMAL); + + /* Destroy the new icon and hdc's*/ + OS.DestroyIcon(hIcon); + OS.DeleteObject(newIconInfo.hbmMask); + OS.DeleteObject(newIconInfo.hbmColor); + OS.DeleteDC(dstHdc); + OS.DeleteDC(srcHdc); + + /* Release the HDC for the device */ + device.internal_dispose_GC(hDC, null); + } + } + + /* Free icon info */ + OS.DeleteObject(srcIconInfo.hbmMask); + if (srcIconInfo.hbmColor != 0) { + OS.DeleteObject(srcIconInfo.hbmColor); + } + + if (failed) SWT.error(SWT.ERROR_INVALID_ARGUMENT); +} + +void drawBitmap(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) { + BITMAP bm = new BITMAP(); + OS.GetObject(srcImage.handle, BITMAP.sizeof, bm); + int imgWidth = bm.bmWidth; + int imgHeight = bm.bmHeight; + if (simple) { + srcWidth = destWidth = imgWidth; + srcHeight = destHeight = imgHeight; + } else { + if (srcX + srcWidth > imgWidth || srcY + srcHeight > imgHeight) { + SWT.error (SWT.ERROR_INVALID_ARGUMENT); + } + simple = srcX == 0 && srcY == 0 && + srcWidth == destWidth && destWidth == imgWidth && + srcHeight == destHeight && destHeight == imgHeight; + } + boolean mustRestore = false; + GC memGC = srcImage.memGC; + if (memGC != null && !memGC.isDisposed()) { + mustRestore = true; + GCData data = memGC.data; + if (data.hNullBitmap != 0) { + OS.SelectObject(memGC.handle, data.hNullBitmap); + data.hNullBitmap = 0; + } + } + if (srcImage.alpha != -1 || srcImage.alphaData != null) { + drawBitmapAlpha(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight); + } else if (srcImage.transparentPixel != -1) { + drawBitmapTransparent(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight); + } else { + drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight); + } + if (mustRestore) { + int hOldBitmap = OS.SelectObject(memGC.handle, srcImage.handle); + memGC.data.hNullBitmap = hOldBitmap; + } +} + +void drawBitmapAlpha(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, BITMAP bm, int imgWidth, int imgHeight) { + /* Simple cases */ + if (srcImage.alpha == 0) return; + if (srcImage.alpha == 255) { + drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight); + return; + } + + /* Check clipping */ + Rectangle rect = getClipping(); + rect = rect.intersection(new Rectangle(destX, destY, destWidth, destHeight)); + if (rect.isEmpty()) return; + + /* + * Optimization. Recalculate src and dest rectangles so that + * only the clipping area is drawn. + */ + int sx1 = srcX + (((rect.x - destX) * srcWidth) / destWidth); + int sx2 = srcX + ((((rect.x + rect.width) - destX) * srcWidth) / destWidth); + int sy1 = srcY + (((rect.y - destY) * srcHeight) / destHeight); + int sy2 = srcY + ((((rect.y + rect.height) - destY) * srcHeight) / destHeight); + destX = rect.x; + destY = rect.y; + destWidth = rect.width; + destHeight = rect.height; + srcX = sx1; + srcY = sy1; + srcWidth = Math.max(1, sx2 - sx1); + srcHeight = Math.max(1, sy2 - sy1); + + /* Create resources */ + int srcHdc = OS.CreateCompatibleDC(handle); + int oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle); + int memHdc = OS.CreateCompatibleDC(handle); + int memDib = createDIB(Math.max(srcWidth, destWidth), Math.max(srcHeight, destHeight)); + int oldMemBitmap = OS.SelectObject(memHdc, memDib); + + BITMAP dibBM = new BITMAP(); + OS.GetObject(memDib, BITMAP.sizeof, dibBM); + int sizeInBytes = dibBM.bmWidthBytes * dibBM.bmHeight; + + /* Get the background pixels */ + OS.BitBlt(memHdc, 0, 0, destWidth, destHeight, handle, destX, destY, OS.SRCCOPY); + byte[] destData = new byte[sizeInBytes]; + OS.MoveMemory(destData, dibBM.bmBits, sizeInBytes); + + /* Get the foreground pixels */ + OS.BitBlt(memHdc, 0, 0, srcWidth, srcHeight, srcHdc, srcX, srcY, OS.SRCCOPY); + byte[] srcData = new byte[sizeInBytes]; + OS.MoveMemory(srcData, dibBM.bmBits, sizeInBytes); + + /* Merge the alpha channel in place */ + int alpha = srcImage.alpha; + final boolean hasAlphaChannel = (srcImage.alpha == -1); + if (hasAlphaChannel) { + final int apinc = imgWidth - srcWidth; + final int spinc = dibBM.bmWidthBytes - srcWidth * 4; + int ap = srcY * imgWidth + srcX, sp = 3; + byte[] alphaData = srcImage.alphaData; + for (int y = 0; y < srcHeight; ++y) { + for (int x = 0; x < srcWidth; ++x) { + srcData[sp] = alphaData[ap++]; + sp += 4; + } + ap += apinc; + sp += spinc; + } + } + + /* Scale the foreground pixels with alpha */ + if (!OS.IsWinCE) OS.SetStretchBltMode(memHdc, OS.COLORONCOLOR); + OS.MoveMemory(dibBM.bmBits, srcData, sizeInBytes); + /* + * Bug in WinCE and Win98. StretchBlt does not correctly stretch when + * the source and destination HDCs are the same. The workaround is to + * stretch to a temporary HDC and blit back into the original HDC. + * Note that on WinCE StretchBlt correctly compresses the image when the + * source and destination HDCs are the same. + */ + if ((OS.IsWinCE && (destWidth > srcWidth || destHeight > srcHeight)) || (!OS.IsWinNT && !OS.IsWinCE)) { + int tempHdc = OS.CreateCompatibleDC(handle); + int tempDib = createDIB(destWidth, destHeight); + int oldTempBitmap = OS.SelectObject(tempHdc, tempDib); + OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, memHdc, 0, 0, srcWidth, srcHeight, OS.SRCCOPY); + OS.BitBlt(memHdc, 0, 0, destWidth, destHeight, tempHdc, 0, 0, OS.SRCCOPY); + OS.SelectObject(tempHdc, oldTempBitmap); + OS.DeleteObject(tempDib); + OS.DeleteDC(tempHdc); + } else { + OS.StretchBlt(memHdc, 0, 0, destWidth, destHeight, memHdc, 0, 0, srcWidth, srcHeight, OS.SRCCOPY); + } + OS.MoveMemory(srcData, dibBM.bmBits, sizeInBytes); + + /* Compose the pixels */ + final int dpinc = dibBM.bmWidthBytes - destWidth * 4; + int dp = 0; + for (int y = 0; y < destHeight; ++y) { + for (int x = 0; x < destWidth; ++x) { + if (hasAlphaChannel) alpha = srcData[dp + 3] & 0xff; + destData[dp] += ((srcData[dp] & 0xff) - (destData[dp] & 0xff)) * alpha / 255; + destData[dp + 1] += ((srcData[dp + 1] & 0xff) - (destData[dp + 1] & 0xff)) * alpha / 255; + destData[dp + 2] += ((srcData[dp + 2] & 0xff) - (destData[dp + 2] & 0xff)) * alpha / 255; + dp += 4; + } + dp += dpinc; + } + + /* Draw the composed pixels */ + OS.MoveMemory(dibBM.bmBits, destData, sizeInBytes); + OS.BitBlt(handle, destX, destY, destWidth, destHeight, memHdc, 0, 0, OS.SRCCOPY); + + /* Free resources */ + OS.SelectObject(memHdc, oldMemBitmap); + OS.DeleteDC(memHdc); + OS.DeleteObject(memDib); + OS.SelectObject(srcHdc, oldSrcBitmap); + OS.DeleteDC(srcHdc); +} + +void drawBitmapTransparent(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, BITMAP bm, int imgWidth, int imgHeight) { + + /* Get the HDC for the device */ + Device device = data.device; + int hDC = device.internal_new_GC(null); + + /* Find the RGB values for the transparent pixel. */ + int transBlue = 0, transGreen = 0, transRed = 0; + boolean isDib = bm.bmBits != 0; + int hBitmap = srcImage.handle; + int srcHdc = OS.CreateCompatibleDC(handle); + int oldSrcBitmap = OS.SelectObject(srcHdc, hBitmap); + byte[] originalColors = null; + if (bm.bmBitsPixel <= 8) { + if (isDib) { + /* Palette-based DIBSECTION */ + if (OS.IsWinCE) { + byte[] pBits = new byte[1]; + OS.MoveMemory(pBits, bm.bmBits, 1); + byte oldValue = pBits[0]; + int mask = (0xFF << (8 - bm.bmBitsPixel)) & 0x00FF; + pBits[0] = (byte)((srcImage.transparentPixel << (8 - bm.bmBitsPixel)) | (pBits[0] & ~mask)); + OS.MoveMemory(bm.bmBits, pBits, 1); + int color = OS.GetPixel(srcHdc, 0, 0); + pBits[0] = oldValue; + OS.MoveMemory(bm.bmBits, pBits, 1); + transBlue = (color & 0xFF0000) >> 16; + transGreen = (color & 0xFF00) >> 8; + transRed = color & 0xFF; + } else { + int maxColors = 1 << bm.bmBitsPixel; + byte[] oldColors = new byte[maxColors * 4]; + OS.GetDIBColorTable(srcHdc, 0, maxColors, oldColors); + int offset = srcImage.transparentPixel * 4; + byte[] newColors = new byte[oldColors.length]; + transRed = transGreen = transBlue = 0xff; + newColors[offset] = (byte)transBlue; + newColors[offset+1] = (byte)transGreen; + newColors[offset+2] = (byte)transRed; + OS.SetDIBColorTable(srcHdc, 0, maxColors, newColors); + originalColors = oldColors; + } + } else { + /* Palette-based bitmap */ + int numColors = 1 << bm.bmBitsPixel; + /* Set the few fields necessary to get the RGB data out */ + BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER(); + bmiHeader.biSize = BITMAPINFOHEADER.sizeof; + bmiHeader.biPlanes = bm.bmPlanes; + bmiHeader.biBitCount = bm.bmBitsPixel; + byte[] bmi = new byte[BITMAPINFOHEADER.sizeof + numColors * 4]; + OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof); + if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + OS.GetDIBits(srcHdc, srcImage.handle, 0, 0, 0, bmi, OS.DIB_RGB_COLORS); + int offset = BITMAPINFOHEADER.sizeof + 4 * srcImage.transparentPixel; + transRed = bmi[offset + 2] & 0xFF; + transGreen = bmi[offset + 1] & 0xFF; + transBlue = bmi[offset] & 0xFF; + } + } else { + /* Direct color image */ + int pixel = srcImage.transparentPixel; + switch (bm.bmBitsPixel) { + case 16: + transBlue = (pixel & 0x1F) << 3; + transGreen = (pixel & 0x3E0) >> 2; + transRed = (pixel & 0x7C00) >> 7; + break; + case 24: + transBlue = (pixel & 0xFF0000) >> 16; + transGreen = (pixel & 0xFF00) >> 8; + transRed = pixel & 0xFF; + break; + case 32: + transBlue = (pixel & 0xFF000000) >>> 24; + transGreen = (pixel & 0xFF0000) >> 16; + transRed = (pixel & 0xFF00) >> 8; + break; + } + } + + if (OS.IsWinCE) { + /* + * Note in WinCE. TransparentImage uses the first entry of a palette + * based image when there are multiple entries that have the same + * transparent color. + */ + int transparentColor = transBlue << 16 | transGreen << 8 | transRed; + OS.TransparentImage(handle, destX, destY, destWidth, destHeight, + srcHdc, srcX, srcY, srcWidth, srcHeight, transparentColor); + } else { + /* Create the mask for the source image */ + int maskHdc = OS.CreateCompatibleDC(hDC); + int maskBitmap = OS.CreateBitmap(imgWidth, imgHeight, 1, 1, null); + int oldMaskBitmap = OS.SelectObject(maskHdc, maskBitmap); + OS.SetBkColor(srcHdc, (transBlue << 16) | (transGreen << 8) | transRed); + OS.BitBlt(maskHdc, 0, 0, imgWidth, imgHeight, srcHdc, 0, 0, OS.SRCCOPY); + if (originalColors != null) OS.SetDIBColorTable(srcHdc, 0, 1 << bm.bmBitsPixel, originalColors); + + /* Draw the source bitmap transparently using invert/and mask/invert */ + int tempHdc = OS.CreateCompatibleDC(hDC); + int tempBitmap = OS.CreateCompatibleBitmap(hDC, destWidth, destHeight); + int oldTempBitmap = OS.SelectObject(tempHdc, tempBitmap); + OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, handle, destX, destY, OS.SRCCOPY); + if (!OS.IsWinCE) OS.SetStretchBltMode(tempHdc, OS.COLORONCOLOR); + OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCINVERT); + OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, maskHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCAND); + OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCINVERT); + OS.BitBlt(handle, destX, destY, destWidth, destHeight, tempHdc, 0, 0, OS.SRCCOPY); + + /* Release resources */ + OS.SelectObject(tempHdc, oldTempBitmap); + OS.DeleteDC(tempHdc); + OS.DeleteObject(tempBitmap); + OS.SelectObject(maskHdc, oldMaskBitmap); + OS.DeleteDC(maskHdc); + OS.DeleteObject(maskBitmap); + } + OS.SelectObject(srcHdc, oldSrcBitmap); + if (hBitmap != srcImage.handle) OS.DeleteObject(hBitmap); + OS.DeleteDC(srcHdc); + + /* Release the HDC for the device */ + device.internal_dispose_GC(hDC, null); +} + +void drawBitmap(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, BITMAP bm, int imgWidth, int imgHeight) { + int srcHdc = OS.CreateCompatibleDC(handle); + int oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle); + int mode = 0, rop2 = 0; + if (!OS.IsWinCE) { + rop2 = OS.GetROP2(handle); + mode = OS.SetStretchBltMode(handle, OS.COLORONCOLOR); + } else { + rop2 = OS.SetROP2 (handle, OS.R2_COPYPEN); + OS.SetROP2 (handle, rop2); + } + int dwRop = rop2 == OS.R2_XORPEN ? OS.SRCINVERT : OS.SRCCOPY; + OS.StretchBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, dwRop); + if (!OS.IsWinCE) { + OS.SetStretchBltMode(handle, mode); + } + OS.SelectObject(srcHdc, oldSrcBitmap); + OS.DeleteDC(srcHdc); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (OS.IsWinCE) { + int [] points = new int [] {x1, y1, x2, y2}; + OS.Polyline (handle, points, points.length / 2); + } else { + OS.MoveToEx (handle, x1, y1, 0); + OS.LineTo (handle, x2, y2); + } + OS.SetPixel (handle, x2, y2, OS.GetTextColor (handle)); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + // Check performance impact of always setting null brush. If the user has not + // set the background color, we may not have to do this work? + int nullBrush = OS.GetStockObject(OS.NULL_BRUSH); + int oldBrush = OS.SelectObject(handle, nullBrush); + OS.Ellipse(handle, x,y,x+width+1,y+height+1); + OS.SelectObject(handle,oldBrush); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + int nullBrush = OS.GetStockObject(OS.NULL_BRUSH); + int oldBrush = OS.SelectObject(handle, nullBrush); + OS.Polygon(handle, pointArray, pointArray.length / 2); + OS.SelectObject(handle, oldBrush); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + OS.Polyline(handle, pointArray, pointArray.length / 2); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int hOld = OS.SelectObject (handle, OS.GetStockObject (OS.NULL_BRUSH)); + OS.Rectangle (handle, x, y, x + width + 1, y + height + 1); + OS.SelectObject (handle, hOld); +} + +/** + * 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 (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. + * + * @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 horizontal diameter of the arc at the four corners + * @param arcHeight the vertical diameter of the arc at the four corners + * + * @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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (OS.IsWinCE) { + /* + * Bug in WinCE PPC. On certain devices, RoundRect does not draw + * all the pixels. The workaround is to draw a round rectangle + * using lines and arcs. + */ + if (width == 0 || height == 0) return; + if (arcWidth == 0 || arcHeight == 0) { + drawRectangle(x, y, width, height); + return; + } + if (width < 0) { + x += width; + width = -width; + } + if (height < 0) { + y += height; + height = -height; + }; + if (arcWidth < 0) arcWidth = -arcWidth; + if (arcHeight < 0) arcHeight = -arcHeight; + if (arcWidth > width) arcWidth = width; + if (arcHeight > height) arcHeight = height; + + if (arcWidth < width) { + drawLine(x+arcWidth/2, y, x+width-arcWidth/2, y); + drawLine(x+arcWidth/2, y+height-1, x+width-arcWidth/2, y+height-1); + } + if (arcHeight < height) { + drawLine(x, y+arcHeight/2, x, y+height-arcHeight/2); + drawLine(x+width-1, y+arcHeight/2, x+width-1, y+height-arcHeight/2); + } + if (arcWidth != 0 && arcHeight != 0) { + drawArc(x, y, arcWidth, arcHeight, 90, 90); + drawArc(x+width-arcWidth-1, y, arcWidth, arcHeight, 0, 90); + drawArc(x+width-arcWidth-1, y+height-arcHeight-1, arcWidth, arcHeight, 0, -90); + drawArc(x, y+height-arcHeight-1, arcWidth, arcHeight, 180, 90); + } + } else { + int nullBrush = OS.GetStockObject(OS.NULL_BRUSH); + int oldBrush = OS.SelectObject(handle, nullBrush); + OS.RoundRect(handle, x,y,x+width,y+height, arcWidth, arcHeight); + OS.SelectObject(handle,oldBrush); + } +} + +/** + * 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) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); +// TCHAR buffer = new TCHAR (getCodePage(), string, false); + int length = string.length(); + char[] buffer = new char [length]; + string.getChars(0, length, buffer, 0); + int oldBkMode = OS.SetBkMode(handle, isTransparent ? OS.TRANSPARENT : OS.OPAQUE); + OS.ExtTextOutW(handle, x, y, 0, null, buffer, length, null); + OS.SetBkMode(handle, oldBkMode); +} + +/** + * 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 specifing 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + RECT rect = new RECT(); + OS.SetRect(rect, x, y, 0x7FFF, 0x7FFF); + TCHAR buffer = new TCHAR(getCodePage(), string, false); + int uFormat = OS.DT_LEFT; + if ((flags & SWT.DRAW_DELIMITER) == 0) uFormat |= OS.DT_SINGLELINE; + if ((flags & SWT.DRAW_TAB) != 0) uFormat |= OS.DT_EXPANDTABS; + if ((flags & SWT.DRAW_MNEMONIC) == 0) uFormat |= OS.DT_NOPREFIX; + int oldBkMode = OS.SetBkMode(handle, (flags & SWT.DRAW_TRANSPARENT) != 0 ? OS.TRANSPARENT : OS.OPAQUE); + OS.DrawText(handle, buffer, buffer.length(), rect, uFormat); + OS.SetBkMode(handle, oldBkMode); +} + +/** + * 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) { + return (object == this) || ((object instanceof GC) && (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 IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if any of the width, height or endAngle is zero.</li> + * </ul> + * @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 endAngle) { + if (handle == 0) 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 || endAngle == 0) { + SWT.error (SWT.ERROR_INVALID_ARGUMENT); + } + + /* + * Feature in WinCE. The function Pie is not present in the + * WinCE SDK. The fix is to emulate it by using Polygon. + */ + if (OS.IsWinCE) { + /* compute arc with a simple linear interpolation */ + if (endAngle < 0) { + startAngle += endAngle; + endAngle = -endAngle; + } + boolean drawSegments = true; + if (endAngle >= 360) { + endAngle = 360; + drawSegments = false; + } + int[] points = new int[(endAngle + 1) * 2 + (drawSegments ? 4 : 0)]; + int cteX = 2 * x + width; + int cteY = 2 * y + height; + int index = (drawSegments ? 2 : 0); + for (int i = 0; i <= endAngle; i++) { + points[index++] = (Compatibility.cos(startAngle + i, width) + cteX) >> 1; + points[index++] = (cteY - Compatibility.sin(startAngle + i, height)) >> 1; + } + if (drawSegments) { + points[0] = points[points.length - 2] = cteX >> 1; + points[1] = points[points.length - 1] = cteY >> 1; + } + int nullPen = OS.GetStockObject(OS.NULL_PEN); + int oldPen = OS.SelectObject(handle, nullPen); + OS.Polygon(handle, points, points.length / 2); + OS.SelectObject(handle, oldPen); + } else { + int x1, y1, x2, y2,tmp; + boolean isNegative; + if (endAngle >= 360 || endAngle <= -360) { + x1 = x2 = x + width; + y1 = y2 = y + height / 2; + } else { + isNegative = endAngle < 0; + + endAngle = endAngle + startAngle; + if (isNegative) { + // swap angles + tmp = startAngle; + startAngle = endAngle; + endAngle = tmp; + } + x1 = Compatibility.cos(startAngle, width) + x + width/2; + y1 = -1 * Compatibility.sin(startAngle, height) + y + height/2; + + x2 = Compatibility.cos(endAngle, width) + x + width/2; + y2 = -1 * Compatibility.sin(endAngle, height) + y + height/2; + } + + int nullPen = OS.GetStockObject(OS.NULL_PEN); + int oldPen = OS.SelectObject(handle, nullPen); + OS.Pie(handle, x,y,x+width+1,y+height+1,x1,y1,x2,y2 ); + OS.SelectObject(handle,oldPen); + } +} + +/** + * 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 + */ +public void fillGradientRectangle(int x, int y, int width, int height, boolean vertical) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (width == 0 || height == 0) return; + int fromColor = OS.GetTextColor(handle); + if (fromColor == OS.CLR_INVALID) { + fromColor = OS.GetSysColor(OS.COLOR_WINDOWTEXT); + } + int toColor = OS.GetBkColor(handle); + if (toColor == OS.CLR_INVALID) { + toColor = OS.GetSysColor(OS.COLOR_WINDOW); + } + 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) { + final int t = fromColor; + fromColor = toColor; + toColor = t; + } + final RGB fromRGB = new RGB(fromColor & 0xff, (fromColor >>> 8) & 0xff, (fromColor >>> 16) & 0xff); + final RGB toRGB = new RGB(toColor & 0xff, (toColor >>> 8) & 0xff, (toColor >>> 16) & 0xff); + if ((fromRGB.red == toRGB.red) && (fromRGB.green == toRGB.green) && (fromRGB.blue == toRGB.blue)) { + OS.PatBlt(handle, x, y, width, height, OS.PATCOPY); + return; + } + + /* Use GradientFill if supported, only on Windows 98, 2000 and newer */ + if (!OS.IsWinCE) { + final int hHeap = OS.GetProcessHeap(); + final int pMesh = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, + GRADIENT_RECT.sizeof + TRIVERTEX.sizeof * 2); + final int pVertex = pMesh + GRADIENT_RECT.sizeof; + + GRADIENT_RECT gradientRect = new GRADIENT_RECT(); + gradientRect.UpperLeft = 0; + gradientRect.LowerRight = 1; + OS.MoveMemory(pMesh, gradientRect, GRADIENT_RECT.sizeof); + + TRIVERTEX trivertex = new TRIVERTEX(); + trivertex.x = x; + trivertex.y = y; + trivertex.Red = (short)((fromRGB.red << 8) | fromRGB.red); + trivertex.Green = (short)((fromRGB.green << 8) | fromRGB.green); + trivertex.Blue = (short)((fromRGB.blue << 8) | fromRGB.blue); + trivertex.Alpha = -1; + OS.MoveMemory(pVertex, trivertex, TRIVERTEX.sizeof); + + trivertex.x = x + width; + trivertex.y = y + height; + trivertex.Red = (short)((toRGB.red << 8) | toRGB.red); + trivertex.Green = (short)((toRGB.green << 8) | toRGB.green); + trivertex.Blue = (short)((toRGB.blue << 8) | toRGB.blue); + trivertex.Alpha = -1; + OS.MoveMemory(pVertex + TRIVERTEX.sizeof, trivertex, TRIVERTEX.sizeof); + + boolean success = OS.GradientFill(handle, pVertex, 2, pMesh, 1, + vertical ? OS.GRADIENT_FILL_RECT_V : OS.GRADIENT_FILL_RECT_H); + OS.HeapFree(hHeap, 0, pMesh); + if (success) return; + } + + final int depth = OS.GetDeviceCaps(handle, OS.BITSPIXEL); + final int bitResolution = (depth >= 24) ? 8 : (depth >= 15) ? 5 : 0; + ImageData.fillGradientRectangle(this, data.device, + x, y, width, height, vertical, fromRGB, toRGB, + bitResolution, bitResolution, bitResolution); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + + /* Assumes that user sets the background color. */ + int nullPen = OS.GetStockObject(OS.NULL_PEN); + int oldPen = OS.SelectObject(handle, nullPen); + OS.Ellipse(handle, x,y,x+width+1,y+height+1); + OS.SelectObject(handle,oldPen); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int nullPen = OS.GetStockObject(OS.NULL_PEN); + int oldPen = OS.SelectObject(handle, nullPen); + OS.Polygon(handle, pointArray, pointArray.length / 2); + OS.SelectObject(handle,oldPen); +} + +/** + * 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 + */ +public void fillRectangle (int x, int y, int width, int height) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int rop2 = 0; + if (OS.IsWinCE) { + rop2 = OS.SetROP2(handle, OS.R2_COPYPEN); + OS.SetROP2(handle, rop2); + } else { + rop2 = OS.GetROP2(handle); + } + int dwRop = rop2 == OS.R2_XORPEN ? OS.PATINVERT : OS.PATCOPY; + OS.PatBlt(handle, x, y, width, height, dwRop); +} + +/** + * Fills the interior of the specified rectangle, using the receiver's + * background color. + * + * @param rectangle 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 + */ +public void fillRectangle (Rectangle rect) { + 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 horizontal diameter of the arc at the four corners + * @param arcHeight the vertical diameter of the arc at the four corners + * + * @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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int nullPen = OS.GetStockObject(OS.NULL_PEN); + int oldPen = OS.SelectObject(handle, nullPen); + OS.RoundRect(handle, x,y,x+width,y+height,arcWidth, arcHeight); + OS.SelectObject(handle,oldPen); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (OS.IsWinCE) { + SIZE size = new SIZE(); + OS.GetTextExtentPoint32W(handle, new char[]{ch}, 1, size); + return size.cx; + } + int tch = ch; + if (ch > 0x7F) { + TCHAR buffer = new TCHAR(getCodePage(), ch, false); + tch = buffer.tcharAt(0); + } + int[] width = new int[1]; + OS.GetCharWidth(handle, tch, tch, width); + return width[0]; +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int color = OS.GetBkColor(handle); + if (color == OS.CLR_INVALID) { + color = OS.GetSysColor(OS.COLOR_WINDOW); + } + return Color.win32_new(data.device, color); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + + /* GetCharABCWidths only succeeds on truetype fonts */ + if (!OS.IsWinCE) { + int tch = ch; + if (ch > 0x7F) { + TCHAR buffer = new TCHAR(getCodePage(), ch, false); + tch = buffer.tcharAt (0); + } + int[] width = new int[3]; + if (OS.GetCharABCWidths(handle, tch, tch, width)) { + return width[1]; + } + } + + /* It wasn't a truetype font */ + TEXTMETRIC tm = new TEXTMETRIC(); + OS.GetTextMetricsW(handle, tm); + SIZE size = new SIZE(); + OS.GetTextExtentPoint32W(handle, new char[]{ch}, 1, size); + return size.cx - tm.tmOverhang; +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + RECT rect = new RECT(); + OS.GetClipBox(handle, rect); + return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); +} + +/** + * 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> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void getClipping (Region region) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (region == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + int result = OS.GetClipRgn (handle, region.handle); + if (result == 1) return; + RECT rect = new RECT(); + OS.GetClipBox(handle, rect); + OS.SetRectRgn(region.handle, rect.left, rect.top, rect.right, rect.bottom); +} + +int getCodePage () { + if (OS.IsWinCE) return OS.GetACP(); + int[] lpCs = new int[8]; + int cs = OS.GetTextCharset(handle); + OS.TranslateCharsetInfo(cs, lpCs, OS.TCI_SRCCHARSET); + return lpCs[1]; +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int hFont = OS.GetCurrentObject(handle, OS.OBJ_FONT); + return Font.win32_new(data.device, hFont); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + TEXTMETRIC lptm = new TEXTMETRIC(); + OS.GetTextMetrics(handle, lptm); + return FontMetrics.win32_new(lptm); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int color = OS.GetTextColor(handle); + if (color == OS.CLR_INVALID) { + color = OS.GetSysColor(OS.COLOR_WINDOWTEXT); + } + return Color.win32_new(data.device, color); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int hPen = OS.GetCurrentObject(handle, OS.OBJ_PEN); + LOGPEN logPen = new LOGPEN(); + OS.GetObject(hPen, LOGPEN.sizeof, logPen); + switch (logPen.lopnStyle) { + case OS.PS_SOLID: return SWT.LINE_SOLID; + case OS.PS_DASH: return SWT.LINE_DASH; + case OS.PS_DOT: return SWT.LINE_DOT; + case OS.PS_DASHDOT: return SWT.LINE_DASHDOT; + case OS.PS_DASHDOTDOT: return SWT.LINE_DASHDOTDOT; + default: return SWT.LINE_SOLID; + } +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int hPen = OS.GetCurrentObject(handle, OS.OBJ_PEN); + LOGPEN logPen = new LOGPEN(); + OS.GetObject(hPen, LOGPEN.sizeof, logPen); + return logPen.x; +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int rop2 = 0; + if (OS.IsWinCE) { + rop2 = OS.SetROP2 (handle, OS.R2_COPYPEN); + OS.SetROP2 (handle, rop2); + } else { + rop2 = OS.GetROP2(handle); + } + return rop2 == OS.R2_XORPEN; +} + +void init(Drawable drawable, GCData data, int hDC) { + int foreground = data.foreground; + if (foreground != -1 && OS.GetTextColor(hDC) != foreground) { + OS.SetTextColor(hDC, foreground); + int hPen = OS.CreatePen(OS.PS_SOLID, 0, foreground); + OS.SelectObject(hDC, hPen); + } + int background = data.background; + if (background != -1 && OS.GetBkColor(hDC) != background) { + OS.SetBkColor(hDC, background); + int hBrush = OS.CreateSolidBrush(background); + OS.SelectObject(hDC, hBrush); + } + int hFont = data.hFont; + if (hFont != 0) OS.SelectObject (hDC, hFont); + int hPalette = data.device.hPalette; + if (hPalette != 0) { + OS.SelectPalette(hDC, hPalette, true); + OS.RealizePalette(hDC); + } + Image image = data.image; + if (image != null) { + data.hNullBitmap = OS.SelectObject(hDC, image.handle); + image.memGC = this; + } + this.drawable = drawable; + this.data = data; + handle = hDC; +} + +/** + * Returns an integer hash code for the receiver. Any two + * objects which 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; +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int region = OS.CreateRectRgn(0, 0, 0, 0); + int result = OS.GetClipRgn(handle, region); + OS.DeleteObject(region); + return (result > 0); +} + +/** + * 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 == 0; +} + +/** + * 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 == 0) 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 (OS.GetBkColor(handle) == color.handle) return; + OS.SetBkColor (handle, color.handle); + int newBrush = OS.CreateSolidBrush (color.handle); + int oldBrush = OS.SelectObject (handle, newBrush); + OS.DeleteObject (oldBrush); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int hRgn = OS.CreateRectRgn (x, y, x + width, y + height); + OS.SelectClipRgn (handle, hRgn); + OS.DeleteObject (hRgn); +} + +/** + * Sets the area of the receiver which can be changed + * by drawing operations to the rectangular area specified + * by the argument. + * + * @param rect the clipping rectangle + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setClipping (Rectangle rect) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (rect == null) { + OS.SelectClipRgn (handle, 0); + return; + } + 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. + * + * @param rect the clipping region. + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setClipping (Region region) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int hRegion = 0; + if (region != null) hRegion = region.handle; + OS.SelectClipRgn (handle, hRegion); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (font == null) { + OS.SelectObject(handle, data.device.systemFont); + } else { + if (font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + OS.SelectObject(handle, font.handle); + } +} + +/** + * 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 == 0) 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 (OS.GetTextColor(handle) == color.handle) return; + int hPen = OS.GetCurrentObject(handle, OS.OBJ_PEN); + LOGPEN logPen = new LOGPEN(); + OS.GetObject(hPen, LOGPEN.sizeof, logPen); + OS.SetTextColor (handle, color.handle); + int newPen = OS.CreatePen (logPen.lopnStyle, logPen.x, color.handle); + int oldPen = OS.SelectObject (handle, newPen); + OS.DeleteObject (oldPen); +} + +/** + * 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 SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setLineStyle(int lineStyle) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int style = -1; + switch (lineStyle) { + case SWT.LINE_SOLID: style = OS.PS_SOLID; break; + case SWT.LINE_DASH: style = OS.PS_DASH; break; + case SWT.LINE_DOT: style = OS.PS_DOT; break; + case SWT.LINE_DASHDOT: style = OS.PS_DASHDOT; break; + case SWT.LINE_DASHDOTDOT: style = OS.PS_DASHDOTDOT; break; + default: + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + int hPen = OS.GetCurrentObject(handle, OS.OBJ_PEN); + LOGPEN logPen = new LOGPEN(); + OS.GetObject(hPen, LOGPEN.sizeof, logPen); + if (logPen.lopnStyle == style) return; + OS.SetBkMode (handle, style == OS.PS_SOLID ? OS.OPAQUE : OS.TRANSPARENT); + int newPen = OS.CreatePen(style, logPen.x, logPen.lopnColor); + int oldPen = OS.SelectObject(handle, newPen); + OS.DeleteObject(oldPen); +} + +/** + * 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. + * + * @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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int hPen = OS.GetCurrentObject(handle, OS.OBJ_PEN); + LOGPEN logPen = new LOGPEN(); + OS.GetObject(hPen, LOGPEN.sizeof, logPen); + if (logPen.x == lineWidth) return; + int newPen = OS.CreatePen(logPen.lopnStyle, lineWidth, logPen.lopnColor); + int oldPen = OS.SelectObject(handle, newPen); + OS.DeleteObject(oldPen); +} + +/** + * 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. + * + * @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> + */ +public void setXORMode(boolean xor) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (xor) { + OS.SetROP2(handle, OS.R2_XORPEN); + } else { + OS.SetROP2(handle, OS.R2_COPYPEN); + } +} + +/** + * 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) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + SIZE size = new SIZE(); + int length = string.length(); + if (length == 0) { +// OS.GetTextExtentPoint32(handle, SPACE, SPACE.length(), size); + OS.GetTextExtentPoint32W(handle, new char[]{' '}, 1, size); + return new Point(0, size.cy); + } else { +// TCHAR buffer = new TCHAR (getCodePage(), string, false); + char[] buffer = new char [length]; + string.getChars(0, length, buffer, 0); + OS.GetTextExtentPoint32W(handle, buffer, length, size); + return new Point(size.cx, size.cy); + } +} + +/** + * 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 specifing 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + if (string.length () == 0) { + SIZE size = new SIZE(); +// OS.GetTextExtentPoint32(handle, SPACE, SPACE.length(), size); + OS.GetTextExtentPoint32W(handle, new char [] {' '}, 1, size); + return new Point(0, size.cy); + } + RECT rect = new RECT(); + TCHAR buffer = new TCHAR(getCodePage(), string, false); + int uFormat = OS.DT_LEFT | OS.DT_CALCRECT; + if ((flags & SWT.DRAW_DELIMITER) == 0) uFormat |= OS.DT_SINGLELINE; + if ((flags & SWT.DRAW_TAB) != 0) uFormat |= OS.DT_EXPANDTABS; + if ((flags & SWT.DRAW_MNEMONIC) == 0) uFormat |= OS.DT_NOPREFIX; + OS.DrawText(handle, buffer, buffer.length(), rect, uFormat); + return new Point(rect.right, rect.bottom); +} + +/** + * 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 + "}"; +} + +/** + * 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 win32_new(Drawable drawable, GCData data) { + GC gc = new GC(); + int hDC = drawable.internal_new_GC(data); + gc.init(drawable, data, hDC); + return gc; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GCData.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GCData.java index 82c2b4913b..2783b746d6 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GCData.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GCData.java @@ -1,34 +1,34 @@ -package org.eclipse.swt.graphics;
-
-/*
+package org.eclipse.swt.graphics; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-
-/**
- * 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>
- *
- * @private
- */
-
-public final class GCData {
- public Device device;
- public Image image;
- public int foreground = -1;
- public int background = -1;
- public int hFont;
- public int hNullBitmap;
- public int hwnd;
- public PAINTSTRUCT ps;
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; + +/** + * 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> + * + * @private + */ + +public final class GCData { + public Device device; + public Image image; + public int foreground = -1; + public int background = -1; + public int hFont; + public int hNullBitmap; + public int hwnd; + public PAINTSTRUCT ps; } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java index d21dcd7a46..10e16f4dfc 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java @@ -1,1902 +1,1902 @@ -package org.eclipse.swt.graphics;
-
-/*
+package org.eclipse.swt.graphics; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-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 explicitely 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
- */
-
-public final class Image implements Drawable {
-
- /**
- * specifies whether the receiver is a bitmap or an icon
- * (one of <code>SWT.BITMAP</code>, <code>SWT.ICON</code>)
- */
- public int type;
-
- /**
- * the OS resource of the image
- * (Warning: This field is platform dependent)
- */
- public int handle;
-
- /**
- * the device where this image was created
- */
- Device device;
-
- /**
- * specifies the transparent pixel
- * (Warning: This field is platform dependent)
- */
- int transparentPixel = -1;
-
- /**
- * the GC which is drawing on the image
- * (Warning: This field is platform dependent)
- */
- GC memGC;
-
- /**
- * the alpha data for the image
- * (Warning: This field is platform dependent)
- */
- byte[] alphaData;
-
- /**
- * the global alpha value to be used for every pixel
- * (Warning: This field is platform dependent)
- */
- int alpha = -1;
-
- /**
- * the image data used to create this image if it is a
- * icon. Used only in WinCE
- * (Warning: This field is platform dependent)
- */
- ImageData data;
-
- /**
- * specifies the default scanline padding
- * (Warning: This field is platform dependent)
- */
- static final int DEFAULT_SCANLINE_PAD = 4;
-
-/**
- * Prevents uninitialized instances from being created outside the package.
- */
-Image () {
-}
-
-/**
- * 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) {
- if (device == null) device = Device.getDevice();
- if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- init(device, width, height);
- if (device.tracking) device.new_Object(this);
-}
-
-/**
- * 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>IMAGE_COPY</b></dt>
- * <dd>the result is an identical copy of srcImage</dd>
- * <dt><b>IMAGE_DISABLE</b></dt>
- * <dd>the result is a copy of srcImage which has a <em>disabled</em> look</dd>
- * <dt><b>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>
- * </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) {
- if (device == null) device = Device.getDevice();
- if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- this.device = 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: {
- Rectangle r = srcImage.getBounds();
- this.type = srcImage.type;
- switch (type) {
- case SWT.BITMAP:
- /* Get the HDC for the device */
- int hDC = device.internal_new_GC(null);
-
- /* Copy the bitmap */
- int hdcSource = OS.CreateCompatibleDC(hDC);
- int hdcDest = OS.CreateCompatibleDC(hDC);
- int hOldSrc = OS.SelectObject(hdcSource, srcImage.handle);
- handle = OS.CreateCompatibleBitmap(hdcSource, r.width, r.height);
- if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- int hOldDest = OS.SelectObject(hdcDest, handle);
- OS.BitBlt(hdcDest, 0, 0, r.width, r.height, hdcSource, 0, 0, OS.SRCCOPY);
- OS.SelectObject(hdcSource, hOldSrc);
- OS.SelectObject(hdcDest, hOldDest);
- OS.DeleteDC(hdcSource);
- OS.DeleteDC(hdcDest);
-
- /* Release the HDC for the device */
- device.internal_dispose_GC(hDC, null);
-
- 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);
- }
- break;
- case SWT.ICON:
- if (OS.IsWinCE) {
- init(device, srcImage.data);
- } else {
- handle = OS.CopyImage(srcImage.handle, OS.IMAGE_ICON, r.width, r.height, 0);
- if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- }
- break;
- default:
- SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
- }
- if (device.tracking) device.new_Object(this);
- return;
- }
- case SWT.IMAGE_DISABLE: {
- Rectangle r = srcImage.getBounds();
- this.type = srcImage.type;
- byte[] rgbBwBitmapInfo = {
- 40,0,0,0, /* biSize */
- (byte)(r.width & 0xFF), /* biWidth */
- (byte)((r.width & 0xFF00) >> 8),
- (byte)((r.width & 0xFF0000) >> 16),
- (byte)((r.width & 0xFF000000) >> 24),
- (byte)(r.height & 0xFF), /* biHeight */
- (byte)((r.height & 0xFF00) >> 8),
- (byte)((r.height & 0xFF0000) >> 16),
- (byte)((r.height & 0xFF000000) >> 24),
- 1,0, /* biPlanes */
- 1,0, /* biBitCount */
- 0,0,0,0, /* biCompression */
- 0,0,0,0, /* biSizeImage */
- 0,0,0,0, /* biXPelsPerMeter */
- 0,0,0,0, /* biYPelsPerMeter */
- 0,0,0,0, /* biClrUsed */
- 0,0,0,0, /* biClrImportant */
- 0,0,0,0, /* First color: black */
- (byte)0xFF,(byte)0xFF,(byte)0xFF,0 /* Second color: white */
- };
-
- /* Get the HDC for the device */
- int hDC = device.internal_new_GC(null);
-
- /* Source DC */
- int hdcSource = OS.CreateCompatibleDC(hDC);
- if (hdcSource == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- /* Monochrome (Intermediate) DC */
- int bwDC = OS.CreateCompatibleDC(hdcSource);
- if (bwDC == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- /* Destination DC */
- int hdcBmp = OS.CreateCompatibleDC(hDC);
- if (hdcBmp == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- /* Monochrome (Intermediate) DIB section */
- int[] pbitsBW = new int[1];
- int hbmBW = OS.CreateDIBSection(bwDC, rgbBwBitmapInfo, OS.DIB_RGB_COLORS, pbitsBW, 0, 0);
- if (hbmBW == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- switch (type) {
- case SWT.BITMAP:
- /* Attach the bitmap to the source DC */
- int hOldSrc = OS.SelectObject(hdcSource, srcImage.handle);
- /* Create the destination bitmap */
- handle = OS.CreateCompatibleBitmap(hDC, r.width, r.height);
- if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- /* Attach the DIB section and the new bitmap to the DCs */
- int hOldBw = OS.SelectObject(bwDC, hbmBW);
- int hOldBmp = OS.SelectObject(hdcBmp, handle);
- /* BitBlt the bitmap into the monochrome DIB section */
- OS.BitBlt(bwDC, 0, 0, r.width, r.height, hdcSource, 0, 0, OS.SRCCOPY);
- /* Paint the destination rectangle in gray */
- RECT rect = new RECT();
- rect.left = 0;
- rect.top = 0;
- rect.right = r.width;
- rect.bottom = r.height;
- OS.FillRect(hdcBmp, rect, OS.GetSysColorBrush(OS.COLOR_3DFACE));
- /*
- * BitBlt the black bits in the monochrome bitmap into
- * COLOR_3DHILIGHT bits in the destination DC.
- * The magic ROP comes from Charles Petzold's book
- */
- int hb = OS.CreateSolidBrush(OS.GetSysColor(OS.COLOR_3DHILIGHT));
- int oldBrush = OS.SelectObject(hdcBmp, hb);
- OS.BitBlt(hdcBmp, 1, 1, r.width, r.height, bwDC, 0, 0, 0xB8074A);
- /*
- * BitBlt the black bits in the monochrome bitmap into
- * COLOR_3DSHADOW bits in the destination DC.
- */
- hb = OS.CreateSolidBrush(OS.GetSysColor(OS.COLOR_3DSHADOW));
- OS.DeleteObject(OS.SelectObject(hdcBmp, hb));
- OS.BitBlt(hdcBmp, 0, 0, r.width, r.height, bwDC, 0, 0, 0xB8074A);
- OS.DeleteObject(OS.SelectObject(hdcBmp, oldBrush));
- /* Free resources */
- OS.SelectObject(hdcSource, hOldSrc);
- OS.SelectObject(hdcBmp, hOldBmp);
- OS.SelectObject(bwDC, hOldBw);
- OS.DeleteDC(hdcSource);
- OS.DeleteDC(bwDC);
- OS.DeleteDC(hdcBmp);
- OS.DeleteObject(hbmBW);
-
- /* Release the HDC for the device */
- device.internal_dispose_GC(hDC, null);
- break;
- case SWT.ICON:
- /* Get icon information */
- ICONINFO iconInfo = new ICONINFO();
- if (OS.IsWinCE) {
- GetIconInfo(srcImage, iconInfo);
- } else {
- if (!OS.GetIconInfo(srcImage.handle, iconInfo))
- SWT.error(SWT.ERROR_INVALID_IMAGE);
- }
- int hdcMask = OS.CreateCompatibleDC(hDC);
- /* Create the destination bitmaps */
- if (iconInfo.hbmColor == 0)
- hOldSrc = OS.SelectObject(hdcSource, iconInfo.hbmMask);
- else
- hOldSrc = OS.SelectObject(hdcSource, iconInfo.hbmColor);
- int newHbmp = OS.CreateCompatibleBitmap(hdcSource, r.width, r.height);
- if (newHbmp == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- int newHmask = OS.CreateBitmap(r.width, r.height, 1, 1, null);
- if (newHmask == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- /* BitBlt the source mask into the destination mask */
- int hOldMask = OS.SelectObject(hdcMask, newHmask);
- if (iconInfo.hbmColor != 0)
- OS.SelectObject(hdcSource, iconInfo.hbmMask);
- OS.SelectObject(hdcSource, iconInfo.hbmMask);
- OS.BitBlt(hdcMask, 0, 0, r.width, r.height, hdcSource, 0, 0, OS.SRCCOPY);
- /* Attach the monochrome DIB section and the destination bitmap to the DCs */
- hOldBw = OS.SelectObject(bwDC, hbmBW);
- /* BitBlt the bitmap into the monochrome DIB section */
- if (iconInfo.hbmColor == 0) {
- OS.SelectObject(hdcSource, iconInfo.hbmMask);
- OS.BitBlt(bwDC, 0, 0, r.width, r.height, hdcSource, 0, r.height, OS.SRCCOPY);
- } else {
- OS.SelectObject(hdcSource, iconInfo.hbmColor);
- OS.BitBlt(bwDC, 0, 0, r.width, r.height, hdcSource, 0, 0, OS.SRCCOPY);
- }
- /* Paint the destination rectangle in grey */
- rect = new RECT();
- rect.left = 0;
- rect.top = 0;
- rect.right = r.width;
- rect.bottom = r.height;
- hOldBmp = OS.SelectObject(hdcBmp, newHbmp);
- OS.FillRect(hdcBmp, rect, OS.GetSysColorBrush(OS.COLOR_3DFACE));
- /*
- * BitBlt the black bits in the monochrome bitmap into
- * COLOR_3DHILIGHT bits in the destination DC.
- * The magic ROP comes from Charles Petzold's book
- */
- hb = OS.CreateSolidBrush(OS.GetSysColor(OS.COLOR_3DSHADOW));
- oldBrush = OS.SelectObject(hdcBmp, hb);
- OS.BitBlt(hdcBmp, 0, 0, r.width, r.height, bwDC, 0, 0, 0xB8074A);
- /* Invert mask into hdcBw */
- OS.BitBlt(bwDC, 0, 0, r.width, r.height, hdcMask, 0, 0, OS.NOTSRCCOPY);
- /* Select black brush into destination */
- hb = OS.CreateSolidBrush(0);
- OS.DeleteObject(OS.SelectObject(hdcBmp, hb));
- /*
- * Copy black bits from monochrome bitmap into black bits in the
- * destination DC.
- */
- OS.BitBlt(hdcBmp, 0, 0, r.width, r.height, bwDC, 0, 0, 0xB8074A);
- OS.DeleteObject(OS.SelectObject(hdcBmp, oldBrush));
- /* Free resources */
- OS.SelectObject(hdcSource, hOldSrc);
- OS.DeleteDC(hdcSource);
- OS.SelectObject(bwDC, hOldBw);
- OS.DeleteDC(bwDC);
- OS.SelectObject(hdcBmp, hOldBmp);
- OS.DeleteDC(hdcBmp);
- OS.SelectObject(hdcMask, hOldMask);
- OS.DeleteDC(hdcMask);
- OS.DeleteObject(hbmBW);
-
- /* Release the HDC for the device */
- device.internal_dispose_GC(hDC, null);
-
- /* Create the new iconinfo */
- ICONINFO newIconInfo = new ICONINFO();
- newIconInfo.fIcon = iconInfo.fIcon;
- newIconInfo.hbmMask = newHmask;
- newIconInfo.hbmColor = newHbmp;
- /* Create the new icon */
- handle = OS.CreateIconIndirect(newIconInfo);
- if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- /* Free bitmaps */
- OS.DeleteObject(newHbmp);
- OS.DeleteObject(newHmask);
- if (iconInfo.hbmColor != 0)
- OS.DeleteObject(iconInfo.hbmColor);
- OS.DeleteObject(iconInfo.hbmMask);
- break;
- default:
- SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
- }
- if (device.tracking) device.new_Object(this);
- return;
- }
- case SWT.IMAGE_GRAY: {
- Rectangle r = srcImage.getBounds();
- ImageData data = srcImage.getImageData();
- PaletteData palette = data.palette;
- ImageData newData = data;
- if (!palette.isDirect) {
- /* Convert the palette entries to gray. */
- RGB [] rgbs = palette.getRGBs();
- for (int i=0; i<rgbs.length; i++) {
- if (data.transparentPixel != i) {
- RGB color = rgbs [i];
- int red = color.red;
- int green = color.green;
- int blue = color.blue;
- int intensity = (red+red+green+green+green+green+green+blue) >> 3;
- color.red = color.green = color.blue = intensity;
- }
- }
- newData.palette = new PaletteData(rgbs);
- } else {
- /* Create a 8 bit depth image data with a gray palette. */
- RGB[] rgbs = new RGB[256];
- for (int i=0; i<rgbs.length; i++) {
- rgbs[i] = new RGB(i, i, i);
- }
- newData = new ImageData(r.width, r.height, 8, new PaletteData(rgbs));
- newData.maskData = data.maskData;
- newData.maskPad = data.maskPad;
-
- /* Convert the pixels. */
- int[] scanline = new int[r.width];
- int redMask = palette.redMask;
- int greenMask = palette.greenMask;
- int blueMask = palette.blueMask;
- int redShift = palette.redShift;
- int greenShift = palette.greenShift;
- int blueShift = palette.blueShift;
- for (int y=0; y<r.height; y++) {
- int offset = y * newData.bytesPerLine;
- data.getPixels(0, y, r.width, scanline, 0);
- for (int x=0; x<r.width; x++) {
- int pixel = scanline[x];
- int red = pixel & redMask;
- red = (redShift < 0) ? red >>> -redShift : red << redShift;
- int green = pixel & greenMask;
- green = (greenShift < 0) ? green >>> -greenShift : green << greenShift;
- int blue = pixel & blueMask;
- blue = (blueShift < 0) ? blue >>> -blueShift : blue << blueShift;
- newData.data[offset++] =
- (byte)((red+red+green+green+green+green+green+blue) >> 3);
- }
- }
- }
- init (device, newData);
- if (device.tracking) device.new_Object(this);
- return;
- }
- default:
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- }
-}
-
-/**
- * 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) {
- if (device == null) device = Device.getDevice();
- if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- if (bounds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- init(device, bounds.width, bounds.height);
- if (device.tracking) device.new_Object(this);
-}
-
-/**
- * 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 SWTError <ul>
- * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
- * </ul>
- */
-public Image(Device device, ImageData data) {
- if (device == null) device = Device.getDevice();
- if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- init(device, data);
- if (device.tracking) device.new_Object(this);
-}
-
-/**
- * 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, and the mask image
- * must have a color depth of 1. Pixel transparency in either image
- * will be ignored. If either image is an icon to begin with, an
- * exception is thrown.
- * <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 or
- * if the mask is not monochrome, or if either the source or mask
- * is already an icon</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) {
- if (device == null) device = Device.getDevice();
- if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- 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);
- }
- if (mask.depth != 1) {
- /*
- * Feature in Windows. 1-bit DIB sections are buggy on Win98, so we
- * create 4-bit DIBs when given a 1-bit ImageData. In order to allow
- * users to draw on the masks, we must also support 4-bit masks in
- * icon creation by converting them into 1-bit masks.
- */
- if (mask.depth != 4) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- PaletteData palette = new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255,255,255)});
- ImageData tempMask = new ImageData(mask.width, mask.height, 1, palette);
- /* Find index of black in mask palette */
- RGB[] rgbs = mask.getRGBs();
- int blackIndex = 0;
- while (blackIndex < rgbs.length) {
- if (rgbs[blackIndex].equals(palette.colors[0])) break;
- blackIndex++;
- }
- if (blackIndex == rgbs.length) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- int[] pixels = new int[mask.width];
- for (int y = 0; y < mask.height; y++) {
- mask.getPixels(0, y, mask.width, pixels, 0);
- for (int i = 0; i < pixels.length; i++) {
- if (pixels[i] == blackIndex) {
- pixels[i] = 0;
- } else {
- pixels[i] = 1;
- }
- }
- tempMask.setPixels(0, y, mask.width, pixels, 0);
- }
- mask = tempMask;
- }
- /* Create a temporary image and locate the black pixel */
- ImageData image;
- int blackIndex = 0;
- if (source.palette.isDirect) {
- image = new ImageData(source.width, source.height, source.depth, source.palette);
- } else {
- RGB black = new RGB(0, 0, 0);
- RGB[] rgbs = source.getRGBs();
- if (source.transparentPixel != -1) {
- /*
- * The source had transparency, so we can use the transparent pixel
- * for black.
- */
- RGB[] newRGBs = new RGB[rgbs.length];
- System.arraycopy(rgbs, 0, newRGBs, 0, rgbs.length);
- if (source.transparentPixel >= newRGBs.length) {
- /* Grow the palette with black */
- rgbs = new RGB[source.transparentPixel + 1];
- System.arraycopy(newRGBs, 0, rgbs, 0, newRGBs.length);
- for (int i = newRGBs.length; i <= source.transparentPixel; i++) {
- rgbs[i] = new RGB(0, 0, 0);
- }
- } else {
- newRGBs[source.transparentPixel] = black;
- rgbs = newRGBs;
- }
- blackIndex = source.transparentPixel;
- image = new ImageData(source.width, source.height, source.depth, new PaletteData(rgbs));
- } else {
- while (blackIndex < rgbs.length) {
- if (rgbs[blackIndex].equals(black)) break;
- blackIndex++;
- }
- if (blackIndex == rgbs.length) {
- /*
- * We didn't find black in the palette, and there is no transparent
- * pixel we can use.
- */
- if ((1 << source.depth) > rgbs.length) {
- /* We can grow the palette and add black */
- RGB[] newRGBs = new RGB[rgbs.length + 1];
- System.arraycopy(rgbs, 0, newRGBs, 0, rgbs.length);
- newRGBs[rgbs.length] = black;
- rgbs = newRGBs;
- } else {
- /* No room to grow the palette */
- blackIndex = -1;
- }
- }
- image = new ImageData(source.width, source.height, source.depth, new PaletteData(rgbs));
- }
- }
- if (blackIndex == -1) {
- /* There was no black in the palette, so just copy the data over */
- System.arraycopy(source.data, 0, image.data, 0, image.data.length);
- } else {
- /* Modify the source image to contain black wherever the mask is 0 */
- int[] imagePixels = new int[image.width];
- int[] maskPixels = new int[mask.width];
- for (int y = 0; y < image.height; y++) {
- source.getPixels(0, y, image.width, imagePixels, 0);
- mask.getPixels(0, y, mask.width, maskPixels, 0);
- for (int i = 0; i < imagePixels.length; i++) {
- if (maskPixels[i] == 0) imagePixels[i] = blackIndex;
- }
- image.setPixels(0, y, source.width, imagePixels, 0);
- }
- }
- /*
- * Make sure the mask is padded properly. Windows requires icon masks
- * to have a scanline pad of 2.
- */
- int bytesPerLine = (((mask.width + 7) / 8) + 1) / 2 * 2;
- byte[] newMaskData = new byte[bytesPerLine * mask.height];
- ImageData newMask = new ImageData(mask.width, mask.height, 1, mask.palette, 2, newMaskData);
- int[] maskPixels = new int[mask.width];
- for (int y = 0; y < mask.height; y++) {
- mask.getPixels(0, y, mask.width, maskPixels, 0);
- newMask.setPixels(0, y, newMask.width, maskPixels, 0);
- }
- /* Set the fields and create the icon */
- image.maskPad = newMask.scanlinePad;
- image.maskData = newMask.data;
- init(device, image);
- if (device.tracking) device.new_Object(this);
-}
-
-/**
- * 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.
- * <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>
- * new Image(device, clazz.getResourceAsStream("file.gif"));
- * </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_INVALID_IMAGE - if the image file contains invalid data </li>
- * <li>ERROR_IO - if an IO error occurs while reading data</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) {
- if (device == null) device = Device.getDevice();
- if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- init(device, new ImageData(stream));
- if (device.tracking) device.new_Object(this);
-}
-
-/**
- * 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_INVALID_IMAGE - if the image file contains invalid data </li>
- * <li>ERROR_IO - if an IO error occurs while reading data</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) {
- if (device == null) device = Device.getDevice();
- if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- init(device, new ImageData(filename));
- if (device.tracking) device.new_Object(this);
-}
-
-/**
- * Create a DIB from a DDB without using GetDIBits. Note that
- * the DDB should not be selected into a HDC.
- */
-int createDIBFromDDB(int hDC, int hBitmap, int width, int height) {
-
- /* Determine the DDB depth */
- int bits = OS.GetDeviceCaps (hDC, OS.BITSPIXEL);
- int planes = OS.GetDeviceCaps (hDC, OS.PLANES);
- int depth = bits * planes;
-
- /* Determine the DIB palette */
- boolean isDirect = depth > 8;
- RGB[] rgbs = null;
- if (!isDirect) {
- int numColors = 1 << depth;
- byte[] logPalette = new byte[4 * numColors];
- OS.GetPaletteEntries(device.hPalette, 0, numColors, logPalette);
- rgbs = new RGB[numColors];
- for (int i = 0; i < numColors; i++) {
- rgbs[i] = new RGB(logPalette[i] & 0xFF, logPalette[i + 1] & 0xFF, logPalette[i + 2] & 0xFF);
- }
- }
-
- boolean useBitfields = OS.IsWinCE && (depth == 16 || depth == 32);
- BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
- bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
- bmiHeader.biWidth = width;
- bmiHeader.biHeight = -height;
- bmiHeader.biPlanes = 1;
- bmiHeader.biBitCount = (short)depth;
- if (useBitfields) bmiHeader.biCompression = OS.BI_BITFIELDS;
- else bmiHeader.biCompression = OS.BI_RGB;
- byte[] bmi;
- if (isDirect) bmi = new byte[BITMAPINFOHEADER.sizeof + (useBitfields ? 12 : 0)];
- else bmi = new byte[BITMAPINFOHEADER.sizeof + rgbs.length * 4];
- OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
-
- /* Set the rgb colors into the bitmap info */
- int offset = BITMAPINFOHEADER.sizeof;
- if (isDirect) {
- if (useBitfields) {
- int redMask = 0;
- int greenMask = 0;
- int blueMask = 0;
- switch (depth) {
- case 16:
- redMask = 0x7C00;
- greenMask = 0x3E0;
- blueMask = 0x1F;
- /* little endian */
- bmi[offset] = (byte)((redMask & 0xFF) >> 0);
- bmi[offset + 1] = (byte)((redMask & 0xFF00) >> 8);
- bmi[offset + 2] = (byte)((redMask & 0xFF0000) >> 16);
- bmi[offset + 3] = (byte)((redMask & 0xFF000000) >> 24);
- bmi[offset + 4] = (byte)((greenMask & 0xFF) >> 0);
- bmi[offset + 5] = (byte)((greenMask & 0xFF00) >> 8);
- bmi[offset + 6] = (byte)((greenMask & 0xFF0000) >> 16);
- bmi[offset + 7] = (byte)((greenMask & 0xFF000000) >> 24);
- bmi[offset + 8] = (byte)((blueMask & 0xFF) >> 0);
- bmi[offset + 9] = (byte)((blueMask & 0xFF00) >> 8);
- bmi[offset + 10] = (byte)((blueMask & 0xFF0000) >> 16);
- bmi[offset + 11] = (byte)((blueMask & 0xFF000000) >> 24);
- break;
- case 32:
- redMask = 0xFF00;
- greenMask = 0xFF0000;
- blueMask = 0xFF000000;
- /* big endian */
- bmi[offset] = (byte)((redMask & 0xFF000000) >> 24);
- bmi[offset + 1] = (byte)((redMask & 0xFF0000) >> 16);
- bmi[offset + 2] = (byte)((redMask & 0xFF00) >> 8);
- bmi[offset + 3] = (byte)((redMask & 0xFF) >> 0);
- bmi[offset + 4] = (byte)((greenMask & 0xFF000000) >> 24);
- bmi[offset + 5] = (byte)((greenMask & 0xFF0000) >> 16);
- bmi[offset + 6] = (byte)((greenMask & 0xFF00) >> 8);
- bmi[offset + 7] = (byte)((greenMask & 0xFF) >> 0);
- bmi[offset + 8] = (byte)((blueMask & 0xFF000000) >> 24);
- bmi[offset + 9] = (byte)((blueMask & 0xFF0000) >> 16);
- bmi[offset + 10] = (byte)((blueMask & 0xFF00) >> 8);
- bmi[offset + 11] = (byte)((blueMask & 0xFF) >> 0);
- break;
- default:
- SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
- }
- }
- } else {
- for (int j = 0; j < rgbs.length; j++) {
- bmi[offset] = (byte)rgbs[j].blue;
- bmi[offset + 1] = (byte)rgbs[j].green;
- bmi[offset + 2] = (byte)rgbs[j].red;
- bmi[offset + 3] = 0;
- offset += 4;
- }
- }
- int[] pBits = new int[1];
- int hDib = OS.CreateDIBSection(0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
- if (hDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
-
- /* Bitblt DDB into DIB */
- int hdcSource = OS.CreateCompatibleDC(hDC);
- int hdcDest = OS.CreateCompatibleDC(hDC);
- int hOldSrc = OS.SelectObject(hdcSource, hBitmap);
- int hOldDest = OS.SelectObject(hdcDest, hDib);
- OS.BitBlt(hdcDest, 0, 0, width, height, hdcSource, 0, 0, OS.SRCCOPY);
- OS.SelectObject(hdcSource, hOldSrc);
- OS.SelectObject(hdcDest, hOldDest);
- OS.DeleteDC(hdcSource);
- OS.DeleteDC(hdcDest);
-
- return hDib;
-}
-
-/**
- * Disposes of the operating system resources associated with
- * the image. Applications must dispose of all images which
- * they allocate.
- */
-public void dispose () {
- if (handle == 0) return;
- if (device.isDisposed()) return;
- if (type == SWT.ICON) {
- if (OS.IsWinCE) data = null;
- OS.DestroyIcon (handle);
- } else {
- OS.DeleteObject (handle);
- }
- handle = 0;
- memGC = null;
- if (device.tracking) device.dispose_Object(this);
- device = 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;
-}
-
-/**
- * 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;
-
- /* Get the HDC for the device */
- int hDC = device.internal_new_GC(null);
-
- /* Compute the background color */
- BITMAP bm = new BITMAP();
- OS.GetObject(handle, BITMAP.sizeof, bm);
- int hdcMem = OS.CreateCompatibleDC(hDC);
- int hOldObject = OS.SelectObject(hdcMem, handle);
- int red = 0, green = 0, blue = 0;
- if (bm.bmBitsPixel <= 8) {
- if (OS.IsWinCE) {
- byte[] pBits = new byte[1];
- OS.MoveMemory(pBits, bm.bmBits, 1);
- byte oldValue = pBits[0];
- int mask = (0xFF << (8 - bm.bmBitsPixel)) & 0x00FF;
- pBits[0] = (byte)((transparentPixel << (8 - bm.bmBitsPixel)) | (pBits[0] & ~mask));
- OS.MoveMemory(bm.bmBits, pBits, 1);
- int color = OS.GetPixel(hdcMem, 0, 0);
- pBits[0] = oldValue;
- OS.MoveMemory(bm.bmBits, pBits, 1);
- blue = (color & 0xFF0000) >> 16;
- green = (color & 0xFF00) >> 8;
- red = color & 0xFF;
- } else {
- byte[] color = new byte[4];
- OS.GetDIBColorTable(hdcMem, transparentPixel, 1, color);
- blue = color[0] & 0xFF;
- green = color[1] & 0xFF;
- red = color[2] & 0xFF;
- }
- } else {
- switch (bm.bmBitsPixel) {
- case 16:
- blue = (transparentPixel & 0x1F) << 3;
- green = (transparentPixel & 0x3E0) >> 2;
- red = (transparentPixel & 0x7C00) >> 7;
- break;
- case 24:
- blue = (transparentPixel & 0xFF0000) >> 16;
- green = (transparentPixel & 0xFF00) >> 8;
- red = transparentPixel & 0xFF;
- break;
- case 32:
- blue = (transparentPixel & 0xFF000000) >>> 24;
- green = (transparentPixel & 0xFF0000) >> 16;
- red = (transparentPixel & 0xFF00) >> 8;
- break;
- default:
- return null;
- }
- }
- OS.SelectObject(hdcMem, hOldObject);
- OS.DeleteDC(hdcMem);
-
- /* Release the HDC for the device */
- device.internal_dispose_GC(hDC, null);
- return Color.win32_new(device, 0x02000000 | (blue << 16) | (green << 8) | red);
-}
-
-/**
- * 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);
- switch (type) {
- case SWT.BITMAP:
- BITMAP bm = new BITMAP();
- OS.GetObject(handle, BITMAP.sizeof, bm);
- return new Rectangle(0, 0, bm.bmWidth, bm.bmHeight);
- case SWT.ICON:
- if (OS.IsWinCE) {
- return new Rectangle(0, 0, data.width, data.height);
- } else {
- ICONINFO info = new ICONINFO();
- OS.GetIconInfo(handle, info);
- int hBitmap = info.hbmColor;
- if (hBitmap == 0) hBitmap = info.hbmMask;
- bm = new BITMAP();
- OS.GetObject(hBitmap, BITMAP.sizeof, bm);
- if (hBitmap == info.hbmMask) bm.bmHeight /= 2;
- if (info.hbmColor != 0) OS.DeleteObject(info.hbmColor);
- if (info.hbmMask != 0) OS.DeleteObject(info.hbmMask);
- return new Rectangle(0, 0, bm.bmWidth, bm.bmHeight);
- }
- default:
- SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
- return null;
- }
-}
-
-/**
- * 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);
- BITMAP bm;
- int depth, width, height;
- switch (type) {
- case SWT.ICON: {
- if (OS.IsWinCE) return data;
- ICONINFO info = new ICONINFO();
- if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
- OS.GetIconInfo(handle, info);
- /* Get the basic BITMAP information */
- int hBitmap = info.hbmColor;
- if (hBitmap == 0) hBitmap = info.hbmMask;
- bm = new BITMAP();
- OS.GetObject(hBitmap, BITMAP.sizeof, bm);
- depth = bm.bmPlanes * bm.bmBitsPixel;
- width = bm.bmWidth;
- if (hBitmap == info.hbmMask) bm.bmHeight /= 2;
- height = bm.bmHeight;
- int numColors = 0;
- if (depth <= 8) numColors = 1 << depth;
- /* Create the BITMAPINFO */
- BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
- bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
- bmiHeader.biWidth = width;
- bmiHeader.biHeight = -height;
- bmiHeader.biPlanes = 1;
- bmiHeader.biBitCount = (short)depth;
- bmiHeader.biCompression = OS.BI_RGB;
- byte[] bmi = new byte[BITMAPINFOHEADER.sizeof + numColors * 4];
- OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
-
- /* Get the HDC for the device */
- int hDC = device.internal_new_GC(null);
-
- /* Create the DC and select the bitmap */
- int hBitmapDC = OS.CreateCompatibleDC(hDC);
- int hOldBitmap = OS.SelectObject(hBitmapDC, hBitmap);
- /* Select the palette if necessary */
- int oldPalette = 0;
- if (depth <= 8) {
- int hPalette = device.hPalette;
- if (hPalette != 0) {
- oldPalette = OS.SelectPalette(hBitmapDC, hPalette, false);
- OS.RealizePalette(hBitmapDC);
- }
- }
- /* Find the size of the image and allocate data */
- int imageSize;
- /* Call with null lpBits to get the image size */
- if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
- OS.GetDIBits(hBitmapDC, hBitmap, 0, height, 0, bmi, OS.DIB_RGB_COLORS);
- OS.MoveMemory(bmiHeader, bmi, BITMAPINFOHEADER.sizeof);
- imageSize = bmiHeader.biSizeImage;
- byte[] data = new byte[imageSize];
- /* Get the bitmap data */
- int hHeap = OS.GetProcessHeap();
- int lpvBits = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, imageSize);
- if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
- OS.GetDIBits(hBitmapDC, hBitmap, 0, height, lpvBits, bmi, OS.DIB_RGB_COLORS);
- OS.MoveMemory(data, lpvBits, imageSize);
- /* Calculate the palette */
- PaletteData palette = null;
- if (depth <= 8) {
- RGB[] rgbs = new RGB[numColors];
- int srcIndex = 40;
- for (int i = 0; i < numColors; i++) {
- rgbs[i] = new RGB(bmi[srcIndex + 2] & 0xFF, bmi[srcIndex + 1] & 0xFF, bmi[srcIndex] & 0xFF);
- srcIndex += 4;
- }
- palette = new PaletteData(rgbs);
- } else if (depth == 16) {
- palette = new PaletteData(0x7C00, 0x3E0, 0x1F);
- } else if (depth == 24) {
- palette = new PaletteData(0xFF, 0xFF00, 0xFF0000);
- } else if (depth == 32) {
- palette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
- } else {
- SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
- }
-
- /* Do the mask */
- byte [] maskData = null;
- if (info.hbmColor == 0) {
- /* Do the bottom half of the mask */
- maskData = new byte[imageSize];
- if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
- OS.GetDIBits(hBitmapDC, hBitmap, height, height, lpvBits, bmi, OS.DIB_RGB_COLORS);
- OS.MoveMemory(maskData, lpvBits, imageSize);
- } else {
- /* Do the entire mask */
- /* Create the BITMAPINFO */
- bmiHeader = new BITMAPINFOHEADER();
- bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
- bmiHeader.biWidth = width;
- bmiHeader.biHeight = -height;
- bmiHeader.biPlanes = 1;
- bmiHeader.biBitCount = 1;
- bmiHeader.biCompression = OS.BI_RGB;
- bmi = new byte[BITMAPINFOHEADER.sizeof + 8];
- OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
-
- /* First color black, second color white */
- int offset = BITMAPINFOHEADER.sizeof;
- bmi[offset + 4] = bmi[offset + 5] = bmi[offset + 6] = (byte)0xFF;
- bmi[offset + 7] = 0;
- OS.SelectObject(hBitmapDC, info.hbmMask);
- /* Call with null lpBits to get the image size */
- if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
- OS.GetDIBits(hBitmapDC, info.hbmMask, 0, height, 0, bmi, OS.DIB_RGB_COLORS);
- OS.MoveMemory(bmiHeader, bmi, BITMAPINFOHEADER.sizeof);
- imageSize = bmiHeader.biSizeImage;
- maskData = new byte[imageSize];
- int lpvMaskBits = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, imageSize);
- if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
- OS.GetDIBits(hBitmapDC, info.hbmMask, 0, height, lpvMaskBits, bmi, OS.DIB_RGB_COLORS);
- OS.MoveMemory(maskData, lpvMaskBits, imageSize);
- OS.HeapFree(hHeap, 0, lpvMaskBits);
- /* Loop to invert the mask */
- for (int i = 0; i < maskData.length; i++) {
- maskData[i] ^= -1;
- }
- /* Make sure mask scanlinePad is 2 */
- int desiredScanline = (width + 7) / 8;
- desiredScanline = desiredScanline + (desiredScanline % 2);
- int realScanline = imageSize / height;
- if (realScanline != desiredScanline) {
- byte[] newData = new byte[desiredScanline * height];
- int srcIndex = 0;
- int destIndex = 0;
- for (int i = 0; i < height; i++) {
- System.arraycopy(maskData, srcIndex, newData, destIndex, desiredScanline);
- destIndex += desiredScanline;
- srcIndex += realScanline;
- }
- maskData = newData;
- }
- }
- /* Clean up */
- OS.HeapFree(hHeap, 0, lpvBits);
- OS.SelectObject(hBitmapDC, hOldBitmap);
- if (oldPalette != 0) {
- OS.SelectPalette(hBitmapDC, oldPalette, false);
- OS.RealizePalette(hBitmapDC);
- }
- OS.DeleteDC(hBitmapDC);
-
- /* Release the HDC for the device */
- device.internal_dispose_GC(hDC, null);
-
- if (info.hbmColor != 0) OS.DeleteObject(info.hbmColor);
- if (info.hbmMask != 0) OS.DeleteObject(info.hbmMask);
- /* Construct and return the ImageData */
- ImageData imageData = new ImageData(width, height, depth, palette, 4, data);
- imageData.maskData = maskData;
-// imageData.maskPad = 4;
- imageData.maskPad = 2;
- return imageData;
- }
- case SWT.BITMAP: {
- /* Get the basic BITMAP information */
- bm = new BITMAP();
- OS.GetObject(handle, BITMAP.sizeof, bm);
- depth = bm.bmPlanes * bm.bmBitsPixel;
- width = bm.bmWidth;
- height = bm.bmHeight;
- /* Find out whether this is a DIB or a DDB. */
- boolean isDib = (bm.bmBits != 0);
- /* Get the HDC for the device */
- int hDC = device.internal_new_GC(null);
-
- /*
- * Feature in WinCE. GetDIBits is not available in WinCE. The
- * workaround is to create a temporary DIB from the DDB and use
- * the bmBits field of DIBSECTION to retrieve the image data.
- */
- int handle = this.handle;
- if (OS.IsWinCE) {
- if (!isDib) {
- boolean mustRestore = false;
- if (memGC != null && !memGC.isDisposed()) {
- mustRestore = true;
- GCData data = memGC.data;
- if (data.hNullBitmap != 0) {
- OS.SelectObject(memGC.handle, data.hNullBitmap);
- data.hNullBitmap = 0;
- }
- }
- handle = createDIBFromDDB(hDC, this.handle, width, height);
- if (mustRestore) {
- int hOldBitmap = OS.SelectObject(memGC.handle, this.handle);
- memGC.data.hNullBitmap = hOldBitmap;
- }
- isDib = true;
- }
- }
- DIBSECTION dib = null;
- if (isDib) {
- dib = new DIBSECTION();
- OS.GetObject(handle, DIBSECTION.sizeof, dib);
- }
- /* Calculate number of colors */
- int numColors = 0;
- if (depth <= 8) {
- if (isDib) {
- numColors = dib.biClrUsed;
- } else {
- numColors = 1 << depth;
- }
- }
- /* Create the BITMAPINFO */
- byte[] bmi = null;
- BITMAPINFOHEADER bmiHeader = null;
- if (!isDib) {
- bmiHeader = new BITMAPINFOHEADER();
- bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
- bmiHeader.biWidth = width;
- bmiHeader.biHeight = -height;
- bmiHeader.biPlanes = 1;
- bmiHeader.biBitCount = (short)depth;
- bmiHeader.biCompression = OS.BI_RGB;
- bmi = new byte[BITMAPINFOHEADER.sizeof + numColors * 4];
- OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
- }
-
- /* Create the DC and select the bitmap */
- int hBitmapDC = OS.CreateCompatibleDC(hDC);
- int hOldBitmap = OS.SelectObject(hBitmapDC, handle);
- /* Select the palette if necessary */
- int oldPalette = 0;
- if (!isDib && depth <= 8) {
- int hPalette = device.hPalette;
- if (hPalette != 0) {
- oldPalette = OS.SelectPalette(hBitmapDC, hPalette, false);
- OS.RealizePalette(hBitmapDC);
- }
- }
- /* Find the size of the image and allocate data */
- int imageSize;
- if (isDib) {
- imageSize = dib.biSizeImage;
- } else {
- /* Call with null lpBits to get the image size */
- if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
- OS.GetDIBits(hBitmapDC, handle, 0, height, 0, bmi, OS.DIB_RGB_COLORS);
- OS.MoveMemory(bmiHeader, bmi, BITMAPINFOHEADER.sizeof);
- imageSize = bmiHeader.biSizeImage;
- }
- byte[] data = new byte[imageSize];
- /* Get the bitmap data */
- if (isDib) {
- if (OS.IsWinCE && this.handle != handle) {
- /* get image data from the temporary DIB */
- OS.MoveMemory(data, dib.bmBits, imageSize);
- } else {
- OS.MoveMemory(data, bm.bmBits, imageSize);
- }
- } else {
- int hHeap = OS.GetProcessHeap();
- int lpvBits = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, imageSize);
- if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
- OS.GetDIBits(hBitmapDC, handle, 0, height, lpvBits, bmi, OS.DIB_RGB_COLORS);
- OS.MoveMemory(data, lpvBits, imageSize);
- OS.HeapFree(hHeap, 0, lpvBits);
- }
- /* Calculate the palette */
- PaletteData palette = null;
- if (depth <= 8) {
- RGB[] rgbs = new RGB[numColors];
- if (isDib) {
- if (OS.IsWinCE) {
- /*
- * Feature on WinCE. GetDIBColorTable is not supported.
- * The workaround is to set a pixel to the desired
- * palette index and use getPixel to get the corresponding
- * RGB value.
- */
- int red = 0, green = 0, blue = 0;
- byte[] pBits = new byte[1];
- OS.MoveMemory(pBits, bm.bmBits, 1);
- byte oldValue = pBits[0];
- int mask = (0xFF << (8 - bm.bmBitsPixel)) & 0x00FF;
- for (int i = 0; i < numColors; i++) {
- pBits[0] = (byte)((i << (8 - bm.bmBitsPixel)) | (pBits[0] & ~mask));
- OS.MoveMemory(bm.bmBits, pBits, 1);
- int color = OS.GetPixel(hBitmapDC, 0, 0);
- blue = (color & 0xFF0000) >> 16;
- green = (color & 0xFF00) >> 8;
- red = color & 0xFF;
- rgbs[i] = new RGB(red, green, blue);
- }
- pBits[0] = oldValue;
- OS.MoveMemory(bm.bmBits, pBits, 1);
- } else {
- byte[] colors = new byte[numColors * 4];
- OS.GetDIBColorTable(hBitmapDC, 0, numColors, colors);
- int colorIndex = 0;
- for (int i = 0; i < rgbs.length; i++) {
- rgbs[i] = new RGB(colors[colorIndex + 2] & 0xFF, colors[colorIndex + 1] & 0xFF, colors[colorIndex] & 0xFF);
- colorIndex += 4;
- }
- }
- } else {
- int srcIndex = BITMAPINFOHEADER.sizeof;
- for (int i = 0; i < numColors; i++) {
- rgbs[i] = new RGB(bmi[srcIndex + 2] & 0xFF, bmi[srcIndex + 1] & 0xFF, bmi[srcIndex] & 0xFF);
- srcIndex += 4;
- }
- }
- palette = new PaletteData(rgbs);
- } else if (depth == 16) {
- palette = new PaletteData(0x7C00, 0x3E0, 0x1F);
- } else if (depth == 24) {
- palette = new PaletteData(0xFF, 0xFF00, 0xFF0000);
- } else if (depth == 32) {
- palette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
- } else {
- SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
- }
- /* Clean up */
- OS.SelectObject(hBitmapDC, hOldBitmap);
- if (oldPalette != 0) {
- OS.SelectPalette(hBitmapDC, oldPalette, false);
- OS.RealizePalette(hBitmapDC);
- }
- if (OS.IsWinCE) {
- if (handle != this.handle) {
- /* free temporary DIB */
- OS.DeleteObject (handle);
- }
- }
- OS.DeleteDC(hBitmapDC);
-
- /* Release the HDC for the device */
- device.internal_dispose_GC(hDC, null);
-
- /* Construct and return the ImageData */
- ImageData imageData = new ImageData(width, height, depth, palette, 4, data);
- imageData.transparentPixel = this.transparentPixel;
- imageData.alpha = alpha;
- if (alpha == -1 && alphaData != null) {
- imageData.alphaData = new byte[alphaData.length];
- System.arraycopy(alphaData, 0, imageData.alphaData, 0, alphaData.length);
- }
- return imageData;
- }
- default:
- SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
- return null;
- }
-}
-
-/**
- * Returns an integer hash code for the receiver. Any two
- * objects which 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;
-}
-
-void init(Device device, int width, int height) {
- if (width <= 0 || height <= 0) {
- SWT.error (SWT.ERROR_INVALID_ARGUMENT);
- }
- this.device = device;
- type = SWT.BITMAP;
-
- /* Get the HDC for the device */
- int hDC = device.internal_new_GC(null);
-
- /* Fill the bitmap with the current background color */
- handle = OS.CreateCompatibleBitmap(hDC, width, height);
- if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- int memDC = OS.CreateCompatibleDC(hDC);
- int hOldBitmap = OS.SelectObject(memDC, handle);
- OS.PatBlt(memDC, 0, 0, width, height, OS.PATCOPY);
- OS.SelectObject(memDC, hOldBitmap);
- OS.DeleteDC(memDC);
-
- /* Release the HDC for the device */
- device.internal_dispose_GC(hDC, null);
-}
-
-/**
- * Feature in WinCE. GetIconInfo is not available in WinCE.
- * The workaround is to cache the object ImageData for images
- * of type SWT.ICON. The bitmaps hbmMask and hbmColor can then
- * be reconstructed by using our version of getIconInfo.
- * This function takes an ICONINFO object and sets the fields
- * hbmMask and hbmColor with the corresponding bitmaps it has
- * created.
- * Note. These bitmaps must be freed - as they would have to be
- * if the regular GetIconInfo had been used.
- */
-static void GetIconInfo(Image image, ICONINFO info) {
- int[] result = init(image.device, null, image.data);
- info.hbmColor = result[0];
- info.hbmMask = result[1];
-}
-
-static int[] init(Device device, Image image, ImageData i) {
- if (image != null) image.device = device;
-
- /*
- * BUG in Windows 98:
- * A monochrome DIBSection will display as solid black
- * on Windows 98 machines, even though it contains the
- * correct data. The fix is to convert 1-bit ImageData
- * into 4-bit ImageData before creating the image.
- */
- /* Windows does not support 2-bit images. Convert to 4-bit image. */
- if ((i.depth == 1 && i.getTransparencyType() != SWT.TRANSPARENCY_MASK) || i.depth == 2) {
- ImageData img = new ImageData(i.width, i.height, 4, i.palette);
- ImageData.blit(ImageData.BLIT_SRC,
- i.data, i.depth, i.bytesPerLine, i.getByteOrder(), 0, 0, i.width, i.height, null, null, null,
- ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
- img.data, img.depth, img.bytesPerLine, i.getByteOrder(), 0, 0, img.width, img.height, null, null, null,
- false, false);
- img.transparentPixel = i.transparentPixel;
- img.maskPad = i.maskPad;
- img.maskData = i.maskData;
- img.alpha = i.alpha;
- img.alphaData = i.alphaData;
- i = img;
- }
- /*
- * Windows supports 16-bit mask of (0x7C00, 0x3E0, 0x1F),
- * 24-bit mask of (0xFF0000, 0xFF00, 0xFF) and 32-bit mask
- * (0x00FF0000, 0x0000FF00, 0x000000FF) as documented in
- * MSDN BITMAPINFOHEADER. Make sure the image is
- * Windows-supported.
- */
- /*
- * Note on WinCE. CreateDIBSection requires the biCompression
- * field of the BITMAPINFOHEADER to be set to BI_BITFIELDS for
- * 16 and 32 bit direct images (see MSDN for CreateDIBSection).
- * In this case, the color mask can be set to any value. For
- * consistency, it is set to the same mask used by non WinCE
- * platforms in BI_RGB mode.
- */
- if (i.palette.isDirect) {
- final PaletteData palette = i.palette;
- final int redMask = palette.redMask;
- final int greenMask = palette.greenMask;
- final int blueMask = palette.blueMask;
- int newDepth = i.depth;
- int newOrder = ImageData.MSB_FIRST;
- PaletteData newPalette = null;
-
- switch (i.depth) {
- case 8:
- newDepth = 16;
- newOrder = ImageData.LSB_FIRST;
- newPalette = new PaletteData(0x7C00, 0x3E0, 0x1F);
- break;
- case 16:
- newOrder = ImageData.LSB_FIRST;
- if (!(redMask == 0x7C00 && greenMask == 0x3E0 && blueMask == 0x1F)) {
- newPalette = new PaletteData(0x7C00, 0x3E0, 0x1F);
- }
- break;
- case 24:
- if (!(redMask == 0xFF && greenMask == 0xFF00 && blueMask == 0xFF0000)) {
- newPalette = new PaletteData(0xFF, 0xFF00, 0xFF0000);
- }
- break;
- case 32:
- if (!(redMask == 0xFF00 && greenMask == 0xFF0000 && blueMask == 0xFF000000)) {
- newPalette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
- }
- break;
- default:
- SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
- }
- if (newPalette != null) {
- ImageData img = new ImageData(i.width, i.height, newDepth, newPalette);
- ImageData.blit(ImageData.BLIT_SRC,
- i.data, i.depth, i.bytesPerLine, i.getByteOrder(), 0, 0, i.width, i.height, redMask, greenMask, blueMask,
- ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
- img.data, img.depth, img.bytesPerLine, newOrder, 0, 0, img.width, img.height, newPalette.redMask, newPalette.greenMask, newPalette.blueMask,
- false, false);
- if (i.transparentPixel != -1) {
- img.transparentPixel = newPalette.getPixel(palette.getRGB(i.transparentPixel));
- }
- img.maskPad = i.maskPad;
- img.maskData = i.maskData;
- img.alpha = i.alpha;
- img.alphaData = i.alphaData;
- i = img;
- }
- }
- /* Construct bitmap info header by hand */
- RGB[] rgbs = i.palette.getRGBs();
- boolean useBitfields = OS.IsWinCE && (i.depth == 16 || i.depth == 32);
- BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
- bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
- bmiHeader.biWidth = i.width;
- bmiHeader.biHeight = -i.height;
- bmiHeader.biPlanes = 1;
- bmiHeader.biBitCount = (short)i.depth;
- if (useBitfields) bmiHeader.biCompression = OS.BI_BITFIELDS;
- else bmiHeader.biCompression = OS.BI_RGB;
- bmiHeader.biClrUsed = rgbs == null ? 0 : rgbs.length;
- byte[] bmi;
- if (i.palette.isDirect)
- bmi = new byte[BITMAPINFOHEADER.sizeof + (useBitfields ? 12 : 0)];
- else
- bmi = new byte[BITMAPINFOHEADER.sizeof + rgbs.length * 4];
- OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
- /* Set the rgb colors into the bitmap info */
- int offset = BITMAPINFOHEADER.sizeof;
- if (i.palette.isDirect) {
- if (useBitfields) {
- PaletteData palette = i.palette;
- int redMask = palette.redMask;
- int greenMask = palette.greenMask;
- int blueMask = palette.blueMask;
- /*
- * The color masks must be written based on the
- * endianness of the ImageData.
*/
- if (i.getByteOrder() == ImageData.LSB_FIRST) {
- bmi[offset] = (byte)((redMask & 0xFF) >> 0);
- bmi[offset + 1] = (byte)((redMask & 0xFF00) >> 8);
- bmi[offset + 2] = (byte)((redMask & 0xFF0000) >> 16);
- bmi[offset + 3] = (byte)((redMask & 0xFF000000) >> 24);
- bmi[offset + 4] = (byte)((greenMask & 0xFF) >> 0);
- bmi[offset + 5] = (byte)((greenMask & 0xFF00) >> 8);
- bmi[offset + 6] = (byte)((greenMask & 0xFF0000) >> 16);
- bmi[offset + 7] = (byte)((greenMask & 0xFF000000) >> 24);
- bmi[offset + 8] = (byte)((blueMask & 0xFF) >> 0);
- bmi[offset + 9] = (byte)((blueMask & 0xFF00) >> 8);
- bmi[offset + 10] = (byte)((blueMask & 0xFF0000) >> 16);
- bmi[offset + 11] = (byte)((blueMask & 0xFF000000) >> 24);
- } else {
- bmi[offset] = (byte)((redMask & 0xFF000000) >> 24);
- bmi[offset + 1] = (byte)((redMask & 0xFF0000) >> 16);
- bmi[offset + 2] = (byte)((redMask & 0xFF00) >> 8);
- bmi[offset + 3] = (byte)((redMask & 0xFF) >> 0);
- bmi[offset + 4] = (byte)((greenMask & 0xFF000000) >> 24);
- bmi[offset + 5] = (byte)((greenMask & 0xFF0000) >> 16);
- bmi[offset + 6] = (byte)((greenMask & 0xFF00) >> 8);
- bmi[offset + 7] = (byte)((greenMask & 0xFF) >> 0);
- bmi[offset + 8] = (byte)((blueMask & 0xFF000000) >> 24);
- bmi[offset + 9] = (byte)((blueMask & 0xFF0000) >> 16);
- bmi[offset + 10] = (byte)((blueMask & 0xFF00) >> 8);
- bmi[offset + 11] = (byte)((blueMask & 0xFF) >> 0);
- }
- }
- } else {
- for (int j = 0; j < rgbs.length; j++) {
- bmi[offset] = (byte)rgbs[j].blue;
- bmi[offset + 1] = (byte)rgbs[j].green;
- bmi[offset + 2] = (byte)rgbs[j].red;
- bmi[offset + 3] = 0;
- offset += 4;
- }
- }
- int[] pBits = new int[1];
- int hDib = OS.CreateDIBSection(0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
- if (hDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- /* In case of a scanline pad other than 4, do the work to convert it */
- byte[] data = i.data;
- if (i.scanlinePad != 4 && (i.bytesPerLine % 4 != 0)) {
- int newBpl = i.bytesPerLine + (4 - (i.bytesPerLine % 4));
- byte[] newData = new byte[i.height * newBpl];
- int srcPtr = 0;
- int destPtr = 0;
- for (int y = 0; y < i.height; y++) {
- System.arraycopy(data, srcPtr, newData, destPtr, i.bytesPerLine);
- srcPtr += i.bytesPerLine;
- destPtr += newBpl;
- }
- data = newData;
- }
- OS.MoveMemory(pBits[0], data, data.length);
-
- int[] result = null;
- if (i.getTransparencyType() == SWT.TRANSPARENCY_MASK) {
- /* Get the HDC for the device */
- int hDC = device.internal_new_GC(null);
-
- /* Create the color bitmap */
- int hdcSrc = OS.CreateCompatibleDC(hDC);
- OS.SelectObject(hdcSrc, hDib);
- int hBitmap = OS.CreateCompatibleBitmap(hDC, i.width, i.height);
- if (hBitmap == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- int hdcDest = OS.CreateCompatibleDC(hDC);
- OS.SelectObject(hdcDest, hBitmap);
- OS.BitBlt(hdcDest, 0, 0, i.width, i.height, hdcSrc, 0, 0, OS.SRCCOPY);
-
- /* Release the HDC for the device */
- device.internal_dispose_GC(hDC, null);
-
- /* Create the mask */
-// int hHeap = OS.GetProcessHeap();
-// int bmBits = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, i.maskData.length);
-// OS.MoveMemory(bmBits, i.maskData, i.maskData.length);
-// BITMAP bm = new BITMAP();
-// bm.bmWidth = i.width;
-// bm.bmHeight = i.height;
-// bm.bmWidthBytes = (((i.width + 7) / 8) + 3) / 4 * 4;
-// bm.bmPlanes = 1;
-// bm.bmBitsPixel = 1;
-// bm.bmBits = bmBits;
-// int hMask = OS.CreateBitmapIndirect(bm);
-// OS.HeapFree(hHeap, 0, bmBits);
- int hMask = OS.CreateBitmap(i.width, i.height, 1, 1, i.maskData);
- if (hMask == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- OS.SelectObject(hdcSrc, hMask);
- OS.PatBlt(hdcSrc, 0, 0, i.width, i.height, OS.DSTINVERT);
- OS.DeleteDC(hdcSrc);
- OS.DeleteDC(hdcDest);
- OS.DeleteObject(hDib);
-
- if (image == null) {
- result = new int[]{hBitmap, hMask};
- } else {
- /* Create the icon */
- ICONINFO info = new ICONINFO();
- info.fIcon = true;
- info.hbmColor = hBitmap;
- info.hbmMask = hMask;
- int hIcon = OS.CreateIconIndirect(info);
- if (hIcon == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- OS.DeleteObject(hBitmap);
- OS.DeleteObject(hMask);
- image.handle = hIcon;
- image.type = SWT.ICON;
- if (OS.IsWinCE) image.data = i;
- }
- } else {
- if (image == null) {
- result = new int[]{hDib};
- } else {
- image.handle = hDib;
- image.type = SWT.BITMAP;
- image.transparentPixel = i.transparentPixel;
- if (image.transparentPixel == -1) {
- image.alpha = i.alpha;
- if (i.alpha == -1 && i.alphaData != null) {
- int length = i.alphaData.length;
- image.alphaData = new byte[length];
- System.arraycopy(i.alphaData, 0, image.alphaData, 0, length);
- }
- }
- }
- }
- return result;
-}
-
-void init(Device device, ImageData i) {
- if (i == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- init(device, this, i);
-}
-
-/**
- * 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
- *
- * @private
- */
-public int internal_new_GC (GCData data) {
- if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- /*
- * Create a new GC that can draw into the image.
- * Only supported for bitmaps.
- */
- if (type != SWT.BITMAP || memGC != null) {
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- }
-
- /* Create a compatible HDC for the device */
- int hDC = device.internal_new_GC(null);
- int imageDC = OS.CreateCompatibleDC(hDC);
- device.internal_dispose_GC(hDC, null);
- if (imageDC == 0) SWT.error(SWT.ERROR_NO_HANDLES);
-
- if (data != null) {
- /* Set the GCData fields */
- data.device = device;
- data.image = this;
- data.hFont = device.systemFont;
- }
- return imageDC;
-}
-
-/**
- * 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 handle the platform specific GC handle
- * @param data the platform specific GC data
- *
- * @private
- */
-public void internal_dispose_GC (int hDC, GCData data) {
- OS.DeleteDC(hDC);
-}
-
-/**
- * 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 == 0;
-}
-
-/**
- * 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) {
- /*
- * Note. Not implemented on WinCE.
- */
- if (OS.IsWinCE) return;
- 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;
-
- /* Get the HDC for the device */
- int hDC = device.internal_new_GC(null);
-
- /* Change the background color in the image */
- BITMAP bm = new BITMAP();
- OS.GetObject(handle, BITMAP.sizeof, bm);
- int hdcMem = OS.CreateCompatibleDC(hDC);
- OS.SelectObject(hdcMem, handle);
- int maxColors = 1 << bm.bmBitsPixel;
- byte[] colors = new byte[maxColors * 4];
- if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
- int numColors = OS.GetDIBColorTable(hdcMem, 0, maxColors, colors);
- int offset = transparentPixel * 4;
- colors[offset] = (byte)color.getBlue();
- colors[offset + 1] = (byte)color.getGreen();
- colors[offset + 2] = (byte)color.getRed();
- if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
- OS.SetDIBColorTable(hdcMem, 0, numColors, colors);
- OS.DeleteDC(hdcMem);
-
- /* Release the HDC for the device */
- device.internal_dispose_GC(hDC, 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 "Image {*DISPOSED*}";
- return "Image {" + handle + "}";
-}
-
-/**
- * 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 hPalette the OS handle for the palette, or 0
- *
- * @private
- */
-public static Image win32_new(Device device, int type, int handle) {
- if (device == null) device = Device.getDevice();
- Image image = new Image();
- image.type = type;
- image.handle = handle;
- image.device = device;
- return image;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +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 explicitely 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 + */ + +public final class Image implements Drawable { + + /** + * specifies whether the receiver is a bitmap or an icon + * (one of <code>SWT.BITMAP</code>, <code>SWT.ICON</code>) + */ + public int type; + + /** + * the OS resource of the image + * (Warning: This field is platform dependent) + */ + public int handle; + + /** + * the device where this image was created + */ + Device device; + + /** + * specifies the transparent pixel + * (Warning: This field is platform dependent) + */ + int transparentPixel = -1; + + /** + * the GC which is drawing on the image + * (Warning: This field is platform dependent) + */ + GC memGC; + + /** + * the alpha data for the image + * (Warning: This field is platform dependent) + */ + byte[] alphaData; + + /** + * the global alpha value to be used for every pixel + * (Warning: This field is platform dependent) + */ + int alpha = -1; + + /** + * the image data used to create this image if it is a + * icon. Used only in WinCE + * (Warning: This field is platform dependent) + */ + ImageData data; + + /** + * specifies the default scanline padding + * (Warning: This field is platform dependent) + */ + static final int DEFAULT_SCANLINE_PAD = 4; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Image () { +} + +/** + * 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) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, width, height); + if (device.tracking) device.new_Object(this); +} + +/** + * 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>IMAGE_COPY</b></dt> + * <dd>the result is an identical copy of srcImage</dd> + * <dt><b>IMAGE_DISABLE</b></dt> + * <dd>the result is a copy of srcImage which has a <em>disabled</em> look</dd> + * <dt><b>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> + * </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) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.device = 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: { + Rectangle r = srcImage.getBounds(); + this.type = srcImage.type; + switch (type) { + case SWT.BITMAP: + /* Get the HDC for the device */ + int hDC = device.internal_new_GC(null); + + /* Copy the bitmap */ + int hdcSource = OS.CreateCompatibleDC(hDC); + int hdcDest = OS.CreateCompatibleDC(hDC); + int hOldSrc = OS.SelectObject(hdcSource, srcImage.handle); + handle = OS.CreateCompatibleBitmap(hdcSource, r.width, r.height); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + int hOldDest = OS.SelectObject(hdcDest, handle); + OS.BitBlt(hdcDest, 0, 0, r.width, r.height, hdcSource, 0, 0, OS.SRCCOPY); + OS.SelectObject(hdcSource, hOldSrc); + OS.SelectObject(hdcDest, hOldDest); + OS.DeleteDC(hdcSource); + OS.DeleteDC(hdcDest); + + /* Release the HDC for the device */ + device.internal_dispose_GC(hDC, null); + + 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); + } + break; + case SWT.ICON: + if (OS.IsWinCE) { + init(device, srcImage.data); + } else { + handle = OS.CopyImage(srcImage.handle, OS.IMAGE_ICON, r.width, r.height, 0); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + } + break; + default: + SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); + } + if (device.tracking) device.new_Object(this); + return; + } + case SWT.IMAGE_DISABLE: { + Rectangle r = srcImage.getBounds(); + this.type = srcImage.type; + byte[] rgbBwBitmapInfo = { + 40,0,0,0, /* biSize */ + (byte)(r.width & 0xFF), /* biWidth */ + (byte)((r.width & 0xFF00) >> 8), + (byte)((r.width & 0xFF0000) >> 16), + (byte)((r.width & 0xFF000000) >> 24), + (byte)(r.height & 0xFF), /* biHeight */ + (byte)((r.height & 0xFF00) >> 8), + (byte)((r.height & 0xFF0000) >> 16), + (byte)((r.height & 0xFF000000) >> 24), + 1,0, /* biPlanes */ + 1,0, /* biBitCount */ + 0,0,0,0, /* biCompression */ + 0,0,0,0, /* biSizeImage */ + 0,0,0,0, /* biXPelsPerMeter */ + 0,0,0,0, /* biYPelsPerMeter */ + 0,0,0,0, /* biClrUsed */ + 0,0,0,0, /* biClrImportant */ + 0,0,0,0, /* First color: black */ + (byte)0xFF,(byte)0xFF,(byte)0xFF,0 /* Second color: white */ + }; + + /* Get the HDC for the device */ + int hDC = device.internal_new_GC(null); + + /* Source DC */ + int hdcSource = OS.CreateCompatibleDC(hDC); + if (hdcSource == 0) SWT.error(SWT.ERROR_NO_HANDLES); + /* Monochrome (Intermediate) DC */ + int bwDC = OS.CreateCompatibleDC(hdcSource); + if (bwDC == 0) SWT.error(SWT.ERROR_NO_HANDLES); + /* Destination DC */ + int hdcBmp = OS.CreateCompatibleDC(hDC); + if (hdcBmp == 0) SWT.error(SWT.ERROR_NO_HANDLES); + /* Monochrome (Intermediate) DIB section */ + int[] pbitsBW = new int[1]; + int hbmBW = OS.CreateDIBSection(bwDC, rgbBwBitmapInfo, OS.DIB_RGB_COLORS, pbitsBW, 0, 0); + if (hbmBW == 0) SWT.error(SWT.ERROR_NO_HANDLES); + switch (type) { + case SWT.BITMAP: + /* Attach the bitmap to the source DC */ + int hOldSrc = OS.SelectObject(hdcSource, srcImage.handle); + /* Create the destination bitmap */ + handle = OS.CreateCompatibleBitmap(hDC, r.width, r.height); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + /* Attach the DIB section and the new bitmap to the DCs */ + int hOldBw = OS.SelectObject(bwDC, hbmBW); + int hOldBmp = OS.SelectObject(hdcBmp, handle); + /* BitBlt the bitmap into the monochrome DIB section */ + OS.BitBlt(bwDC, 0, 0, r.width, r.height, hdcSource, 0, 0, OS.SRCCOPY); + /* Paint the destination rectangle in gray */ + RECT rect = new RECT(); + rect.left = 0; + rect.top = 0; + rect.right = r.width; + rect.bottom = r.height; + OS.FillRect(hdcBmp, rect, OS.GetSysColorBrush(OS.COLOR_3DFACE)); + /* + * BitBlt the black bits in the monochrome bitmap into + * COLOR_3DHILIGHT bits in the destination DC. + * The magic ROP comes from Charles Petzold's book + */ + int hb = OS.CreateSolidBrush(OS.GetSysColor(OS.COLOR_3DHILIGHT)); + int oldBrush = OS.SelectObject(hdcBmp, hb); + OS.BitBlt(hdcBmp, 1, 1, r.width, r.height, bwDC, 0, 0, 0xB8074A); + /* + * BitBlt the black bits in the monochrome bitmap into + * COLOR_3DSHADOW bits in the destination DC. + */ + hb = OS.CreateSolidBrush(OS.GetSysColor(OS.COLOR_3DSHADOW)); + OS.DeleteObject(OS.SelectObject(hdcBmp, hb)); + OS.BitBlt(hdcBmp, 0, 0, r.width, r.height, bwDC, 0, 0, 0xB8074A); + OS.DeleteObject(OS.SelectObject(hdcBmp, oldBrush)); + /* Free resources */ + OS.SelectObject(hdcSource, hOldSrc); + OS.SelectObject(hdcBmp, hOldBmp); + OS.SelectObject(bwDC, hOldBw); + OS.DeleteDC(hdcSource); + OS.DeleteDC(bwDC); + OS.DeleteDC(hdcBmp); + OS.DeleteObject(hbmBW); + + /* Release the HDC for the device */ + device.internal_dispose_GC(hDC, null); + break; + case SWT.ICON: + /* Get icon information */ + ICONINFO iconInfo = new ICONINFO(); + if (OS.IsWinCE) { + GetIconInfo(srcImage, iconInfo); + } else { + if (!OS.GetIconInfo(srcImage.handle, iconInfo)) + SWT.error(SWT.ERROR_INVALID_IMAGE); + } + int hdcMask = OS.CreateCompatibleDC(hDC); + /* Create the destination bitmaps */ + if (iconInfo.hbmColor == 0) + hOldSrc = OS.SelectObject(hdcSource, iconInfo.hbmMask); + else + hOldSrc = OS.SelectObject(hdcSource, iconInfo.hbmColor); + int newHbmp = OS.CreateCompatibleBitmap(hdcSource, r.width, r.height); + if (newHbmp == 0) SWT.error(SWT.ERROR_NO_HANDLES); + int newHmask = OS.CreateBitmap(r.width, r.height, 1, 1, null); + if (newHmask == 0) SWT.error(SWT.ERROR_NO_HANDLES); + /* BitBlt the source mask into the destination mask */ + int hOldMask = OS.SelectObject(hdcMask, newHmask); + if (iconInfo.hbmColor != 0) + OS.SelectObject(hdcSource, iconInfo.hbmMask); + OS.SelectObject(hdcSource, iconInfo.hbmMask); + OS.BitBlt(hdcMask, 0, 0, r.width, r.height, hdcSource, 0, 0, OS.SRCCOPY); + /* Attach the monochrome DIB section and the destination bitmap to the DCs */ + hOldBw = OS.SelectObject(bwDC, hbmBW); + /* BitBlt the bitmap into the monochrome DIB section */ + if (iconInfo.hbmColor == 0) { + OS.SelectObject(hdcSource, iconInfo.hbmMask); + OS.BitBlt(bwDC, 0, 0, r.width, r.height, hdcSource, 0, r.height, OS.SRCCOPY); + } else { + OS.SelectObject(hdcSource, iconInfo.hbmColor); + OS.BitBlt(bwDC, 0, 0, r.width, r.height, hdcSource, 0, 0, OS.SRCCOPY); + } + /* Paint the destination rectangle in grey */ + rect = new RECT(); + rect.left = 0; + rect.top = 0; + rect.right = r.width; + rect.bottom = r.height; + hOldBmp = OS.SelectObject(hdcBmp, newHbmp); + OS.FillRect(hdcBmp, rect, OS.GetSysColorBrush(OS.COLOR_3DFACE)); + /* + * BitBlt the black bits in the monochrome bitmap into + * COLOR_3DHILIGHT bits in the destination DC. + * The magic ROP comes from Charles Petzold's book + */ + hb = OS.CreateSolidBrush(OS.GetSysColor(OS.COLOR_3DSHADOW)); + oldBrush = OS.SelectObject(hdcBmp, hb); + OS.BitBlt(hdcBmp, 0, 0, r.width, r.height, bwDC, 0, 0, 0xB8074A); + /* Invert mask into hdcBw */ + OS.BitBlt(bwDC, 0, 0, r.width, r.height, hdcMask, 0, 0, OS.NOTSRCCOPY); + /* Select black brush into destination */ + hb = OS.CreateSolidBrush(0); + OS.DeleteObject(OS.SelectObject(hdcBmp, hb)); + /* + * Copy black bits from monochrome bitmap into black bits in the + * destination DC. + */ + OS.BitBlt(hdcBmp, 0, 0, r.width, r.height, bwDC, 0, 0, 0xB8074A); + OS.DeleteObject(OS.SelectObject(hdcBmp, oldBrush)); + /* Free resources */ + OS.SelectObject(hdcSource, hOldSrc); + OS.DeleteDC(hdcSource); + OS.SelectObject(bwDC, hOldBw); + OS.DeleteDC(bwDC); + OS.SelectObject(hdcBmp, hOldBmp); + OS.DeleteDC(hdcBmp); + OS.SelectObject(hdcMask, hOldMask); + OS.DeleteDC(hdcMask); + OS.DeleteObject(hbmBW); + + /* Release the HDC for the device */ + device.internal_dispose_GC(hDC, null); + + /* Create the new iconinfo */ + ICONINFO newIconInfo = new ICONINFO(); + newIconInfo.fIcon = iconInfo.fIcon; + newIconInfo.hbmMask = newHmask; + newIconInfo.hbmColor = newHbmp; + /* Create the new icon */ + handle = OS.CreateIconIndirect(newIconInfo); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + /* Free bitmaps */ + OS.DeleteObject(newHbmp); + OS.DeleteObject(newHmask); + if (iconInfo.hbmColor != 0) + OS.DeleteObject(iconInfo.hbmColor); + OS.DeleteObject(iconInfo.hbmMask); + break; + default: + SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); + } + if (device.tracking) device.new_Object(this); + return; + } + case SWT.IMAGE_GRAY: { + Rectangle r = srcImage.getBounds(); + ImageData data = srcImage.getImageData(); + PaletteData palette = data.palette; + ImageData newData = data; + if (!palette.isDirect) { + /* Convert the palette entries to gray. */ + RGB [] rgbs = palette.getRGBs(); + for (int i=0; i<rgbs.length; i++) { + if (data.transparentPixel != i) { + RGB color = rgbs [i]; + int red = color.red; + int green = color.green; + int blue = color.blue; + int intensity = (red+red+green+green+green+green+green+blue) >> 3; + color.red = color.green = color.blue = intensity; + } + } + newData.palette = new PaletteData(rgbs); + } else { + /* Create a 8 bit depth image data with a gray palette. */ + RGB[] rgbs = new RGB[256]; + for (int i=0; i<rgbs.length; i++) { + rgbs[i] = new RGB(i, i, i); + } + newData = new ImageData(r.width, r.height, 8, new PaletteData(rgbs)); + newData.maskData = data.maskData; + newData.maskPad = data.maskPad; + + /* Convert the pixels. */ + int[] scanline = new int[r.width]; + int redMask = palette.redMask; + int greenMask = palette.greenMask; + int blueMask = palette.blueMask; + int redShift = palette.redShift; + int greenShift = palette.greenShift; + int blueShift = palette.blueShift; + for (int y=0; y<r.height; y++) { + int offset = y * newData.bytesPerLine; + data.getPixels(0, y, r.width, scanline, 0); + for (int x=0; x<r.width; x++) { + int pixel = scanline[x]; + int red = pixel & redMask; + red = (redShift < 0) ? red >>> -redShift : red << redShift; + int green = pixel & greenMask; + green = (greenShift < 0) ? green >>> -greenShift : green << greenShift; + int blue = pixel & blueMask; + blue = (blueShift < 0) ? blue >>> -blueShift : blue << blueShift; + newData.data[offset++] = + (byte)((red+red+green+green+green+green+green+blue) >> 3); + } + } + } + init (device, newData); + if (device.tracking) device.new_Object(this); + return; + } + default: + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } +} + +/** + * 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) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (bounds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, bounds.width, bounds.height); + if (device.tracking) device.new_Object(this); +} + +/** + * 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 SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li> + * </ul> + */ +public Image(Device device, ImageData data) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, data); + if (device.tracking) device.new_Object(this); +} + +/** + * 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, and the mask image + * must have a color depth of 1. Pixel transparency in either image + * will be ignored. If either image is an icon to begin with, an + * exception is thrown. + * <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 or + * if the mask is not monochrome, or if either the source or mask + * is already an icon</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) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + 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); + } + if (mask.depth != 1) { + /* + * Feature in Windows. 1-bit DIB sections are buggy on Win98, so we + * create 4-bit DIBs when given a 1-bit ImageData. In order to allow + * users to draw on the masks, we must also support 4-bit masks in + * icon creation by converting them into 1-bit masks. + */ + if (mask.depth != 4) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + PaletteData palette = new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255,255,255)}); + ImageData tempMask = new ImageData(mask.width, mask.height, 1, palette); + /* Find index of black in mask palette */ + RGB[] rgbs = mask.getRGBs(); + int blackIndex = 0; + while (blackIndex < rgbs.length) { + if (rgbs[blackIndex].equals(palette.colors[0])) break; + blackIndex++; + } + if (blackIndex == rgbs.length) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + int[] pixels = new int[mask.width]; + for (int y = 0; y < mask.height; y++) { + mask.getPixels(0, y, mask.width, pixels, 0); + for (int i = 0; i < pixels.length; i++) { + if (pixels[i] == blackIndex) { + pixels[i] = 0; + } else { + pixels[i] = 1; + } + } + tempMask.setPixels(0, y, mask.width, pixels, 0); + } + mask = tempMask; + } + /* Create a temporary image and locate the black pixel */ + ImageData image; + int blackIndex = 0; + if (source.palette.isDirect) { + image = new ImageData(source.width, source.height, source.depth, source.palette); + } else { + RGB black = new RGB(0, 0, 0); + RGB[] rgbs = source.getRGBs(); + if (source.transparentPixel != -1) { + /* + * The source had transparency, so we can use the transparent pixel + * for black. + */ + RGB[] newRGBs = new RGB[rgbs.length]; + System.arraycopy(rgbs, 0, newRGBs, 0, rgbs.length); + if (source.transparentPixel >= newRGBs.length) { + /* Grow the palette with black */ + rgbs = new RGB[source.transparentPixel + 1]; + System.arraycopy(newRGBs, 0, rgbs, 0, newRGBs.length); + for (int i = newRGBs.length; i <= source.transparentPixel; i++) { + rgbs[i] = new RGB(0, 0, 0); + } + } else { + newRGBs[source.transparentPixel] = black; + rgbs = newRGBs; + } + blackIndex = source.transparentPixel; + image = new ImageData(source.width, source.height, source.depth, new PaletteData(rgbs)); + } else { + while (blackIndex < rgbs.length) { + if (rgbs[blackIndex].equals(black)) break; + blackIndex++; + } + if (blackIndex == rgbs.length) { + /* + * We didn't find black in the palette, and there is no transparent + * pixel we can use. + */ + if ((1 << source.depth) > rgbs.length) { + /* We can grow the palette and add black */ + RGB[] newRGBs = new RGB[rgbs.length + 1]; + System.arraycopy(rgbs, 0, newRGBs, 0, rgbs.length); + newRGBs[rgbs.length] = black; + rgbs = newRGBs; + } else { + /* No room to grow the palette */ + blackIndex = -1; + } + } + image = new ImageData(source.width, source.height, source.depth, new PaletteData(rgbs)); + } + } + if (blackIndex == -1) { + /* There was no black in the palette, so just copy the data over */ + System.arraycopy(source.data, 0, image.data, 0, image.data.length); + } else { + /* Modify the source image to contain black wherever the mask is 0 */ + int[] imagePixels = new int[image.width]; + int[] maskPixels = new int[mask.width]; + for (int y = 0; y < image.height; y++) { + source.getPixels(0, y, image.width, imagePixels, 0); + mask.getPixels(0, y, mask.width, maskPixels, 0); + for (int i = 0; i < imagePixels.length; i++) { + if (maskPixels[i] == 0) imagePixels[i] = blackIndex; + } + image.setPixels(0, y, source.width, imagePixels, 0); + } + } + /* + * Make sure the mask is padded properly. Windows requires icon masks + * to have a scanline pad of 2. + */ + int bytesPerLine = (((mask.width + 7) / 8) + 1) / 2 * 2; + byte[] newMaskData = new byte[bytesPerLine * mask.height]; + ImageData newMask = new ImageData(mask.width, mask.height, 1, mask.palette, 2, newMaskData); + int[] maskPixels = new int[mask.width]; + for (int y = 0; y < mask.height; y++) { + mask.getPixels(0, y, mask.width, maskPixels, 0); + newMask.setPixels(0, y, newMask.width, maskPixels, 0); + } + /* Set the fields and create the icon */ + image.maskPad = newMask.scanlinePad; + image.maskData = newMask.data; + init(device, image); + if (device.tracking) device.new_Object(this); +} + +/** + * 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. + * <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> + * new Image(device, clazz.getResourceAsStream("file.gif")); + * </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_INVALID_IMAGE - if the image file contains invalid data </li> + * <li>ERROR_IO - if an IO error occurs while reading data</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) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, new ImageData(stream)); + if (device.tracking) device.new_Object(this); +} + +/** + * 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_INVALID_IMAGE - if the image file contains invalid data </li> + * <li>ERROR_IO - if an IO error occurs while reading data</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) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, new ImageData(filename)); + if (device.tracking) device.new_Object(this); +} + +/** + * Create a DIB from a DDB without using GetDIBits. Note that + * the DDB should not be selected into a HDC. + */ +int createDIBFromDDB(int hDC, int hBitmap, int width, int height) { + + /* Determine the DDB depth */ + int bits = OS.GetDeviceCaps (hDC, OS.BITSPIXEL); + int planes = OS.GetDeviceCaps (hDC, OS.PLANES); + int depth = bits * planes; + + /* Determine the DIB palette */ + boolean isDirect = depth > 8; + RGB[] rgbs = null; + if (!isDirect) { + int numColors = 1 << depth; + byte[] logPalette = new byte[4 * numColors]; + OS.GetPaletteEntries(device.hPalette, 0, numColors, logPalette); + rgbs = new RGB[numColors]; + for (int i = 0; i < numColors; i++) { + rgbs[i] = new RGB(logPalette[i] & 0xFF, logPalette[i + 1] & 0xFF, logPalette[i + 2] & 0xFF); + } + } + + boolean useBitfields = OS.IsWinCE && (depth == 16 || depth == 32); + BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER(); + bmiHeader.biSize = BITMAPINFOHEADER.sizeof; + bmiHeader.biWidth = width; + bmiHeader.biHeight = -height; + bmiHeader.biPlanes = 1; + bmiHeader.biBitCount = (short)depth; + if (useBitfields) bmiHeader.biCompression = OS.BI_BITFIELDS; + else bmiHeader.biCompression = OS.BI_RGB; + byte[] bmi; + if (isDirect) bmi = new byte[BITMAPINFOHEADER.sizeof + (useBitfields ? 12 : 0)]; + else bmi = new byte[BITMAPINFOHEADER.sizeof + rgbs.length * 4]; + OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof); + + /* Set the rgb colors into the bitmap info */ + int offset = BITMAPINFOHEADER.sizeof; + if (isDirect) { + if (useBitfields) { + int redMask = 0; + int greenMask = 0; + int blueMask = 0; + switch (depth) { + case 16: + redMask = 0x7C00; + greenMask = 0x3E0; + blueMask = 0x1F; + /* little endian */ + bmi[offset] = (byte)((redMask & 0xFF) >> 0); + bmi[offset + 1] = (byte)((redMask & 0xFF00) >> 8); + bmi[offset + 2] = (byte)((redMask & 0xFF0000) >> 16); + bmi[offset + 3] = (byte)((redMask & 0xFF000000) >> 24); + bmi[offset + 4] = (byte)((greenMask & 0xFF) >> 0); + bmi[offset + 5] = (byte)((greenMask & 0xFF00) >> 8); + bmi[offset + 6] = (byte)((greenMask & 0xFF0000) >> 16); + bmi[offset + 7] = (byte)((greenMask & 0xFF000000) >> 24); + bmi[offset + 8] = (byte)((blueMask & 0xFF) >> 0); + bmi[offset + 9] = (byte)((blueMask & 0xFF00) >> 8); + bmi[offset + 10] = (byte)((blueMask & 0xFF0000) >> 16); + bmi[offset + 11] = (byte)((blueMask & 0xFF000000) >> 24); + break; + case 32: + redMask = 0xFF00; + greenMask = 0xFF0000; + blueMask = 0xFF000000; + /* big endian */ + bmi[offset] = (byte)((redMask & 0xFF000000) >> 24); + bmi[offset + 1] = (byte)((redMask & 0xFF0000) >> 16); + bmi[offset + 2] = (byte)((redMask & 0xFF00) >> 8); + bmi[offset + 3] = (byte)((redMask & 0xFF) >> 0); + bmi[offset + 4] = (byte)((greenMask & 0xFF000000) >> 24); + bmi[offset + 5] = (byte)((greenMask & 0xFF0000) >> 16); + bmi[offset + 6] = (byte)((greenMask & 0xFF00) >> 8); + bmi[offset + 7] = (byte)((greenMask & 0xFF) >> 0); + bmi[offset + 8] = (byte)((blueMask & 0xFF000000) >> 24); + bmi[offset + 9] = (byte)((blueMask & 0xFF0000) >> 16); + bmi[offset + 10] = (byte)((blueMask & 0xFF00) >> 8); + bmi[offset + 11] = (byte)((blueMask & 0xFF) >> 0); + break; + default: + SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); + } + } + } else { + for (int j = 0; j < rgbs.length; j++) { + bmi[offset] = (byte)rgbs[j].blue; + bmi[offset + 1] = (byte)rgbs[j].green; + bmi[offset + 2] = (byte)rgbs[j].red; + bmi[offset + 3] = 0; + offset += 4; + } + } + int[] pBits = new int[1]; + int hDib = OS.CreateDIBSection(0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0); + if (hDib == 0) SWT.error(SWT.ERROR_NO_HANDLES); + + /* Bitblt DDB into DIB */ + int hdcSource = OS.CreateCompatibleDC(hDC); + int hdcDest = OS.CreateCompatibleDC(hDC); + int hOldSrc = OS.SelectObject(hdcSource, hBitmap); + int hOldDest = OS.SelectObject(hdcDest, hDib); + OS.BitBlt(hdcDest, 0, 0, width, height, hdcSource, 0, 0, OS.SRCCOPY); + OS.SelectObject(hdcSource, hOldSrc); + OS.SelectObject(hdcDest, hOldDest); + OS.DeleteDC(hdcSource); + OS.DeleteDC(hdcDest); + + return hDib; +} + +/** + * Disposes of the operating system resources associated with + * the image. Applications must dispose of all images which + * they allocate. + */ +public void dispose () { + if (handle == 0) return; + if (device.isDisposed()) return; + if (type == SWT.ICON) { + if (OS.IsWinCE) data = null; + OS.DestroyIcon (handle); + } else { + OS.DeleteObject (handle); + } + handle = 0; + memGC = null; + if (device.tracking) device.dispose_Object(this); + device = 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; +} + +/** + * 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; + + /* Get the HDC for the device */ + int hDC = device.internal_new_GC(null); + + /* Compute the background color */ + BITMAP bm = new BITMAP(); + OS.GetObject(handle, BITMAP.sizeof, bm); + int hdcMem = OS.CreateCompatibleDC(hDC); + int hOldObject = OS.SelectObject(hdcMem, handle); + int red = 0, green = 0, blue = 0; + if (bm.bmBitsPixel <= 8) { + if (OS.IsWinCE) { + byte[] pBits = new byte[1]; + OS.MoveMemory(pBits, bm.bmBits, 1); + byte oldValue = pBits[0]; + int mask = (0xFF << (8 - bm.bmBitsPixel)) & 0x00FF; + pBits[0] = (byte)((transparentPixel << (8 - bm.bmBitsPixel)) | (pBits[0] & ~mask)); + OS.MoveMemory(bm.bmBits, pBits, 1); + int color = OS.GetPixel(hdcMem, 0, 0); + pBits[0] = oldValue; + OS.MoveMemory(bm.bmBits, pBits, 1); + blue = (color & 0xFF0000) >> 16; + green = (color & 0xFF00) >> 8; + red = color & 0xFF; + } else { + byte[] color = new byte[4]; + OS.GetDIBColorTable(hdcMem, transparentPixel, 1, color); + blue = color[0] & 0xFF; + green = color[1] & 0xFF; + red = color[2] & 0xFF; + } + } else { + switch (bm.bmBitsPixel) { + case 16: + blue = (transparentPixel & 0x1F) << 3; + green = (transparentPixel & 0x3E0) >> 2; + red = (transparentPixel & 0x7C00) >> 7; + break; + case 24: + blue = (transparentPixel & 0xFF0000) >> 16; + green = (transparentPixel & 0xFF00) >> 8; + red = transparentPixel & 0xFF; + break; + case 32: + blue = (transparentPixel & 0xFF000000) >>> 24; + green = (transparentPixel & 0xFF0000) >> 16; + red = (transparentPixel & 0xFF00) >> 8; + break; + default: + return null; + } + } + OS.SelectObject(hdcMem, hOldObject); + OS.DeleteDC(hdcMem); + + /* Release the HDC for the device */ + device.internal_dispose_GC(hDC, null); + return Color.win32_new(device, 0x02000000 | (blue << 16) | (green << 8) | red); +} + +/** + * 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); + switch (type) { + case SWT.BITMAP: + BITMAP bm = new BITMAP(); + OS.GetObject(handle, BITMAP.sizeof, bm); + return new Rectangle(0, 0, bm.bmWidth, bm.bmHeight); + case SWT.ICON: + if (OS.IsWinCE) { + return new Rectangle(0, 0, data.width, data.height); + } else { + ICONINFO info = new ICONINFO(); + OS.GetIconInfo(handle, info); + int hBitmap = info.hbmColor; + if (hBitmap == 0) hBitmap = info.hbmMask; + bm = new BITMAP(); + OS.GetObject(hBitmap, BITMAP.sizeof, bm); + if (hBitmap == info.hbmMask) bm.bmHeight /= 2; + if (info.hbmColor != 0) OS.DeleteObject(info.hbmColor); + if (info.hbmMask != 0) OS.DeleteObject(info.hbmMask); + return new Rectangle(0, 0, bm.bmWidth, bm.bmHeight); + } + default: + SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); + return null; + } +} + +/** + * 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); + BITMAP bm; + int depth, width, height; + switch (type) { + case SWT.ICON: { + if (OS.IsWinCE) return data; + ICONINFO info = new ICONINFO(); + if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + OS.GetIconInfo(handle, info); + /* Get the basic BITMAP information */ + int hBitmap = info.hbmColor; + if (hBitmap == 0) hBitmap = info.hbmMask; + bm = new BITMAP(); + OS.GetObject(hBitmap, BITMAP.sizeof, bm); + depth = bm.bmPlanes * bm.bmBitsPixel; + width = bm.bmWidth; + if (hBitmap == info.hbmMask) bm.bmHeight /= 2; + height = bm.bmHeight; + int numColors = 0; + if (depth <= 8) numColors = 1 << depth; + /* Create the BITMAPINFO */ + BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER(); + bmiHeader.biSize = BITMAPINFOHEADER.sizeof; + bmiHeader.biWidth = width; + bmiHeader.biHeight = -height; + bmiHeader.biPlanes = 1; + bmiHeader.biBitCount = (short)depth; + bmiHeader.biCompression = OS.BI_RGB; + byte[] bmi = new byte[BITMAPINFOHEADER.sizeof + numColors * 4]; + OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof); + + /* Get the HDC for the device */ + int hDC = device.internal_new_GC(null); + + /* Create the DC and select the bitmap */ + int hBitmapDC = OS.CreateCompatibleDC(hDC); + int hOldBitmap = OS.SelectObject(hBitmapDC, hBitmap); + /* Select the palette if necessary */ + int oldPalette = 0; + if (depth <= 8) { + int hPalette = device.hPalette; + if (hPalette != 0) { + oldPalette = OS.SelectPalette(hBitmapDC, hPalette, false); + OS.RealizePalette(hBitmapDC); + } + } + /* Find the size of the image and allocate data */ + int imageSize; + /* Call with null lpBits to get the image size */ + if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + OS.GetDIBits(hBitmapDC, hBitmap, 0, height, 0, bmi, OS.DIB_RGB_COLORS); + OS.MoveMemory(bmiHeader, bmi, BITMAPINFOHEADER.sizeof); + imageSize = bmiHeader.biSizeImage; + byte[] data = new byte[imageSize]; + /* Get the bitmap data */ + int hHeap = OS.GetProcessHeap(); + int lpvBits = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, imageSize); + if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + OS.GetDIBits(hBitmapDC, hBitmap, 0, height, lpvBits, bmi, OS.DIB_RGB_COLORS); + OS.MoveMemory(data, lpvBits, imageSize); + /* Calculate the palette */ + PaletteData palette = null; + if (depth <= 8) { + RGB[] rgbs = new RGB[numColors]; + int srcIndex = 40; + for (int i = 0; i < numColors; i++) { + rgbs[i] = new RGB(bmi[srcIndex + 2] & 0xFF, bmi[srcIndex + 1] & 0xFF, bmi[srcIndex] & 0xFF); + srcIndex += 4; + } + palette = new PaletteData(rgbs); + } else if (depth == 16) { + palette = new PaletteData(0x7C00, 0x3E0, 0x1F); + } else if (depth == 24) { + palette = new PaletteData(0xFF, 0xFF00, 0xFF0000); + } else if (depth == 32) { + palette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000); + } else { + SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); + } + + /* Do the mask */ + byte [] maskData = null; + if (info.hbmColor == 0) { + /* Do the bottom half of the mask */ + maskData = new byte[imageSize]; + if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + OS.GetDIBits(hBitmapDC, hBitmap, height, height, lpvBits, bmi, OS.DIB_RGB_COLORS); + OS.MoveMemory(maskData, lpvBits, imageSize); + } else { + /* Do the entire mask */ + /* Create the BITMAPINFO */ + bmiHeader = new BITMAPINFOHEADER(); + bmiHeader.biSize = BITMAPINFOHEADER.sizeof; + bmiHeader.biWidth = width; + bmiHeader.biHeight = -height; + bmiHeader.biPlanes = 1; + bmiHeader.biBitCount = 1; + bmiHeader.biCompression = OS.BI_RGB; + bmi = new byte[BITMAPINFOHEADER.sizeof + 8]; + OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof); + + /* First color black, second color white */ + int offset = BITMAPINFOHEADER.sizeof; + bmi[offset + 4] = bmi[offset + 5] = bmi[offset + 6] = (byte)0xFF; + bmi[offset + 7] = 0; + OS.SelectObject(hBitmapDC, info.hbmMask); + /* Call with null lpBits to get the image size */ + if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + OS.GetDIBits(hBitmapDC, info.hbmMask, 0, height, 0, bmi, OS.DIB_RGB_COLORS); + OS.MoveMemory(bmiHeader, bmi, BITMAPINFOHEADER.sizeof); + imageSize = bmiHeader.biSizeImage; + maskData = new byte[imageSize]; + int lpvMaskBits = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, imageSize); + if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + OS.GetDIBits(hBitmapDC, info.hbmMask, 0, height, lpvMaskBits, bmi, OS.DIB_RGB_COLORS); + OS.MoveMemory(maskData, lpvMaskBits, imageSize); + OS.HeapFree(hHeap, 0, lpvMaskBits); + /* Loop to invert the mask */ + for (int i = 0; i < maskData.length; i++) { + maskData[i] ^= -1; + } + /* Make sure mask scanlinePad is 2 */ + int desiredScanline = (width + 7) / 8; + desiredScanline = desiredScanline + (desiredScanline % 2); + int realScanline = imageSize / height; + if (realScanline != desiredScanline) { + byte[] newData = new byte[desiredScanline * height]; + int srcIndex = 0; + int destIndex = 0; + for (int i = 0; i < height; i++) { + System.arraycopy(maskData, srcIndex, newData, destIndex, desiredScanline); + destIndex += desiredScanline; + srcIndex += realScanline; + } + maskData = newData; + } + } + /* Clean up */ + OS.HeapFree(hHeap, 0, lpvBits); + OS.SelectObject(hBitmapDC, hOldBitmap); + if (oldPalette != 0) { + OS.SelectPalette(hBitmapDC, oldPalette, false); + OS.RealizePalette(hBitmapDC); + } + OS.DeleteDC(hBitmapDC); + + /* Release the HDC for the device */ + device.internal_dispose_GC(hDC, null); + + if (info.hbmColor != 0) OS.DeleteObject(info.hbmColor); + if (info.hbmMask != 0) OS.DeleteObject(info.hbmMask); + /* Construct and return the ImageData */ + ImageData imageData = new ImageData(width, height, depth, palette, 4, data); + imageData.maskData = maskData; +// imageData.maskPad = 4; + imageData.maskPad = 2; + return imageData; + } + case SWT.BITMAP: { + /* Get the basic BITMAP information */ + bm = new BITMAP(); + OS.GetObject(handle, BITMAP.sizeof, bm); + depth = bm.bmPlanes * bm.bmBitsPixel; + width = bm.bmWidth; + height = bm.bmHeight; + /* Find out whether this is a DIB or a DDB. */ + boolean isDib = (bm.bmBits != 0); + /* Get the HDC for the device */ + int hDC = device.internal_new_GC(null); + + /* + * Feature in WinCE. GetDIBits is not available in WinCE. The + * workaround is to create a temporary DIB from the DDB and use + * the bmBits field of DIBSECTION to retrieve the image data. + */ + int handle = this.handle; + if (OS.IsWinCE) { + if (!isDib) { + boolean mustRestore = false; + if (memGC != null && !memGC.isDisposed()) { + mustRestore = true; + GCData data = memGC.data; + if (data.hNullBitmap != 0) { + OS.SelectObject(memGC.handle, data.hNullBitmap); + data.hNullBitmap = 0; + } + } + handle = createDIBFromDDB(hDC, this.handle, width, height); + if (mustRestore) { + int hOldBitmap = OS.SelectObject(memGC.handle, this.handle); + memGC.data.hNullBitmap = hOldBitmap; + } + isDib = true; + } + } + DIBSECTION dib = null; + if (isDib) { + dib = new DIBSECTION(); + OS.GetObject(handle, DIBSECTION.sizeof, dib); + } + /* Calculate number of colors */ + int numColors = 0; + if (depth <= 8) { + if (isDib) { + numColors = dib.biClrUsed; + } else { + numColors = 1 << depth; + } + } + /* Create the BITMAPINFO */ + byte[] bmi = null; + BITMAPINFOHEADER bmiHeader = null; + if (!isDib) { + bmiHeader = new BITMAPINFOHEADER(); + bmiHeader.biSize = BITMAPINFOHEADER.sizeof; + bmiHeader.biWidth = width; + bmiHeader.biHeight = -height; + bmiHeader.biPlanes = 1; + bmiHeader.biBitCount = (short)depth; + bmiHeader.biCompression = OS.BI_RGB; + bmi = new byte[BITMAPINFOHEADER.sizeof + numColors * 4]; + OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof); + } + + /* Create the DC and select the bitmap */ + int hBitmapDC = OS.CreateCompatibleDC(hDC); + int hOldBitmap = OS.SelectObject(hBitmapDC, handle); + /* Select the palette if necessary */ + int oldPalette = 0; + if (!isDib && depth <= 8) { + int hPalette = device.hPalette; + if (hPalette != 0) { + oldPalette = OS.SelectPalette(hBitmapDC, hPalette, false); + OS.RealizePalette(hBitmapDC); + } + } + /* Find the size of the image and allocate data */ + int imageSize; + if (isDib) { + imageSize = dib.biSizeImage; + } else { + /* Call with null lpBits to get the image size */ + if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + OS.GetDIBits(hBitmapDC, handle, 0, height, 0, bmi, OS.DIB_RGB_COLORS); + OS.MoveMemory(bmiHeader, bmi, BITMAPINFOHEADER.sizeof); + imageSize = bmiHeader.biSizeImage; + } + byte[] data = new byte[imageSize]; + /* Get the bitmap data */ + if (isDib) { + if (OS.IsWinCE && this.handle != handle) { + /* get image data from the temporary DIB */ + OS.MoveMemory(data, dib.bmBits, imageSize); + } else { + OS.MoveMemory(data, bm.bmBits, imageSize); + } + } else { + int hHeap = OS.GetProcessHeap(); + int lpvBits = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, imageSize); + if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + OS.GetDIBits(hBitmapDC, handle, 0, height, lpvBits, bmi, OS.DIB_RGB_COLORS); + OS.MoveMemory(data, lpvBits, imageSize); + OS.HeapFree(hHeap, 0, lpvBits); + } + /* Calculate the palette */ + PaletteData palette = null; + if (depth <= 8) { + RGB[] rgbs = new RGB[numColors]; + if (isDib) { + if (OS.IsWinCE) { + /* + * Feature on WinCE. GetDIBColorTable is not supported. + * The workaround is to set a pixel to the desired + * palette index and use getPixel to get the corresponding + * RGB value. + */ + int red = 0, green = 0, blue = 0; + byte[] pBits = new byte[1]; + OS.MoveMemory(pBits, bm.bmBits, 1); + byte oldValue = pBits[0]; + int mask = (0xFF << (8 - bm.bmBitsPixel)) & 0x00FF; + for (int i = 0; i < numColors; i++) { + pBits[0] = (byte)((i << (8 - bm.bmBitsPixel)) | (pBits[0] & ~mask)); + OS.MoveMemory(bm.bmBits, pBits, 1); + int color = OS.GetPixel(hBitmapDC, 0, 0); + blue = (color & 0xFF0000) >> 16; + green = (color & 0xFF00) >> 8; + red = color & 0xFF; + rgbs[i] = new RGB(red, green, blue); + } + pBits[0] = oldValue; + OS.MoveMemory(bm.bmBits, pBits, 1); + } else { + byte[] colors = new byte[numColors * 4]; + OS.GetDIBColorTable(hBitmapDC, 0, numColors, colors); + int colorIndex = 0; + for (int i = 0; i < rgbs.length; i++) { + rgbs[i] = new RGB(colors[colorIndex + 2] & 0xFF, colors[colorIndex + 1] & 0xFF, colors[colorIndex] & 0xFF); + colorIndex += 4; + } + } + } else { + int srcIndex = BITMAPINFOHEADER.sizeof; + for (int i = 0; i < numColors; i++) { + rgbs[i] = new RGB(bmi[srcIndex + 2] & 0xFF, bmi[srcIndex + 1] & 0xFF, bmi[srcIndex] & 0xFF); + srcIndex += 4; + } + } + palette = new PaletteData(rgbs); + } else if (depth == 16) { + palette = new PaletteData(0x7C00, 0x3E0, 0x1F); + } else if (depth == 24) { + palette = new PaletteData(0xFF, 0xFF00, 0xFF0000); + } else if (depth == 32) { + palette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000); + } else { + SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); + } + /* Clean up */ + OS.SelectObject(hBitmapDC, hOldBitmap); + if (oldPalette != 0) { + OS.SelectPalette(hBitmapDC, oldPalette, false); + OS.RealizePalette(hBitmapDC); + } + if (OS.IsWinCE) { + if (handle != this.handle) { + /* free temporary DIB */ + OS.DeleteObject (handle); + } + } + OS.DeleteDC(hBitmapDC); + + /* Release the HDC for the device */ + device.internal_dispose_GC(hDC, null); + + /* Construct and return the ImageData */ + ImageData imageData = new ImageData(width, height, depth, palette, 4, data); + imageData.transparentPixel = this.transparentPixel; + imageData.alpha = alpha; + if (alpha == -1 && alphaData != null) { + imageData.alphaData = new byte[alphaData.length]; + System.arraycopy(alphaData, 0, imageData.alphaData, 0, alphaData.length); + } + return imageData; + } + default: + SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); + return null; + } +} + +/** + * Returns an integer hash code for the receiver. Any two + * objects which 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; +} + +void init(Device device, int width, int height) { + if (width <= 0 || height <= 0) { + SWT.error (SWT.ERROR_INVALID_ARGUMENT); + } + this.device = device; + type = SWT.BITMAP; + + /* Get the HDC for the device */ + int hDC = device.internal_new_GC(null); + + /* Fill the bitmap with the current background color */ + handle = OS.CreateCompatibleBitmap(hDC, width, height); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + int memDC = OS.CreateCompatibleDC(hDC); + int hOldBitmap = OS.SelectObject(memDC, handle); + OS.PatBlt(memDC, 0, 0, width, height, OS.PATCOPY); + OS.SelectObject(memDC, hOldBitmap); + OS.DeleteDC(memDC); + + /* Release the HDC for the device */ + device.internal_dispose_GC(hDC, null); +} + +/** + * Feature in WinCE. GetIconInfo is not available in WinCE. + * The workaround is to cache the object ImageData for images + * of type SWT.ICON. The bitmaps hbmMask and hbmColor can then + * be reconstructed by using our version of getIconInfo. + * This function takes an ICONINFO object and sets the fields + * hbmMask and hbmColor with the corresponding bitmaps it has + * created. + * Note. These bitmaps must be freed - as they would have to be + * if the regular GetIconInfo had been used. + */ +static void GetIconInfo(Image image, ICONINFO info) { + int[] result = init(image.device, null, image.data); + info.hbmColor = result[0]; + info.hbmMask = result[1]; +} + +static int[] init(Device device, Image image, ImageData i) { + if (image != null) image.device = device; + + /* + * BUG in Windows 98: + * A monochrome DIBSection will display as solid black + * on Windows 98 machines, even though it contains the + * correct data. The fix is to convert 1-bit ImageData + * into 4-bit ImageData before creating the image. + */ + /* Windows does not support 2-bit images. Convert to 4-bit image. */ + if ((i.depth == 1 && i.getTransparencyType() != SWT.TRANSPARENCY_MASK) || i.depth == 2) { + ImageData img = new ImageData(i.width, i.height, 4, i.palette); + ImageData.blit(ImageData.BLIT_SRC, + i.data, i.depth, i.bytesPerLine, i.getByteOrder(), 0, 0, i.width, i.height, null, null, null, + ImageData.ALPHA_OPAQUE, null, 0, 0, 0, + img.data, img.depth, img.bytesPerLine, i.getByteOrder(), 0, 0, img.width, img.height, null, null, null, + false, false); + img.transparentPixel = i.transparentPixel; + img.maskPad = i.maskPad; + img.maskData = i.maskData; + img.alpha = i.alpha; + img.alphaData = i.alphaData; + i = img; + } + /* + * Windows supports 16-bit mask of (0x7C00, 0x3E0, 0x1F), + * 24-bit mask of (0xFF0000, 0xFF00, 0xFF) and 32-bit mask + * (0x00FF0000, 0x0000FF00, 0x000000FF) as documented in + * MSDN BITMAPINFOHEADER. Make sure the image is + * Windows-supported. + */ + /* + * Note on WinCE. CreateDIBSection requires the biCompression + * field of the BITMAPINFOHEADER to be set to BI_BITFIELDS for + * 16 and 32 bit direct images (see MSDN for CreateDIBSection). + * In this case, the color mask can be set to any value. For + * consistency, it is set to the same mask used by non WinCE + * platforms in BI_RGB mode. + */ + if (i.palette.isDirect) { + final PaletteData palette = i.palette; + final int redMask = palette.redMask; + final int greenMask = palette.greenMask; + final int blueMask = palette.blueMask; + int newDepth = i.depth; + int newOrder = ImageData.MSB_FIRST; + PaletteData newPalette = null; + + switch (i.depth) { + case 8: + newDepth = 16; + newOrder = ImageData.LSB_FIRST; + newPalette = new PaletteData(0x7C00, 0x3E0, 0x1F); + break; + case 16: + newOrder = ImageData.LSB_FIRST; + if (!(redMask == 0x7C00 && greenMask == 0x3E0 && blueMask == 0x1F)) { + newPalette = new PaletteData(0x7C00, 0x3E0, 0x1F); + } + break; + case 24: + if (!(redMask == 0xFF && greenMask == 0xFF00 && blueMask == 0xFF0000)) { + newPalette = new PaletteData(0xFF, 0xFF00, 0xFF0000); + } + break; + case 32: + if (!(redMask == 0xFF00 && greenMask == 0xFF0000 && blueMask == 0xFF000000)) { + newPalette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000); + } + break; + default: + SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); + } + if (newPalette != null) { + ImageData img = new ImageData(i.width, i.height, newDepth, newPalette); + ImageData.blit(ImageData.BLIT_SRC, + i.data, i.depth, i.bytesPerLine, i.getByteOrder(), 0, 0, i.width, i.height, redMask, greenMask, blueMask, + ImageData.ALPHA_OPAQUE, null, 0, 0, 0, + img.data, img.depth, img.bytesPerLine, newOrder, 0, 0, img.width, img.height, newPalette.redMask, newPalette.greenMask, newPalette.blueMask, + false, false); + if (i.transparentPixel != -1) { + img.transparentPixel = newPalette.getPixel(palette.getRGB(i.transparentPixel)); + } + img.maskPad = i.maskPad; + img.maskData = i.maskData; + img.alpha = i.alpha; + img.alphaData = i.alphaData; + i = img; + } + } + /* Construct bitmap info header by hand */ + RGB[] rgbs = i.palette.getRGBs(); + boolean useBitfields = OS.IsWinCE && (i.depth == 16 || i.depth == 32); + BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER(); + bmiHeader.biSize = BITMAPINFOHEADER.sizeof; + bmiHeader.biWidth = i.width; + bmiHeader.biHeight = -i.height; + bmiHeader.biPlanes = 1; + bmiHeader.biBitCount = (short)i.depth; + if (useBitfields) bmiHeader.biCompression = OS.BI_BITFIELDS; + else bmiHeader.biCompression = OS.BI_RGB; + bmiHeader.biClrUsed = rgbs == null ? 0 : rgbs.length; + byte[] bmi; + if (i.palette.isDirect) + bmi = new byte[BITMAPINFOHEADER.sizeof + (useBitfields ? 12 : 0)]; + else + bmi = new byte[BITMAPINFOHEADER.sizeof + rgbs.length * 4]; + OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof); + /* Set the rgb colors into the bitmap info */ + int offset = BITMAPINFOHEADER.sizeof; + if (i.palette.isDirect) { + if (useBitfields) { + PaletteData palette = i.palette; + int redMask = palette.redMask; + int greenMask = palette.greenMask; + int blueMask = palette.blueMask; + /* + * The color masks must be written based on the + * endianness of the ImageData.
*/ + if (i.getByteOrder() == ImageData.LSB_FIRST) { + bmi[offset] = (byte)((redMask & 0xFF) >> 0); + bmi[offset + 1] = (byte)((redMask & 0xFF00) >> 8); + bmi[offset + 2] = (byte)((redMask & 0xFF0000) >> 16); + bmi[offset + 3] = (byte)((redMask & 0xFF000000) >> 24); + bmi[offset + 4] = (byte)((greenMask & 0xFF) >> 0); + bmi[offset + 5] = (byte)((greenMask & 0xFF00) >> 8); + bmi[offset + 6] = (byte)((greenMask & 0xFF0000) >> 16); + bmi[offset + 7] = (byte)((greenMask & 0xFF000000) >> 24); + bmi[offset + 8] = (byte)((blueMask & 0xFF) >> 0); + bmi[offset + 9] = (byte)((blueMask & 0xFF00) >> 8); + bmi[offset + 10] = (byte)((blueMask & 0xFF0000) >> 16); + bmi[offset + 11] = (byte)((blueMask & 0xFF000000) >> 24); + } else { + bmi[offset] = (byte)((redMask & 0xFF000000) >> 24); + bmi[offset + 1] = (byte)((redMask & 0xFF0000) >> 16); + bmi[offset + 2] = (byte)((redMask & 0xFF00) >> 8); + bmi[offset + 3] = (byte)((redMask & 0xFF) >> 0); + bmi[offset + 4] = (byte)((greenMask & 0xFF000000) >> 24); + bmi[offset + 5] = (byte)((greenMask & 0xFF0000) >> 16); + bmi[offset + 6] = (byte)((greenMask & 0xFF00) >> 8); + bmi[offset + 7] = (byte)((greenMask & 0xFF) >> 0); + bmi[offset + 8] = (byte)((blueMask & 0xFF000000) >> 24); + bmi[offset + 9] = (byte)((blueMask & 0xFF0000) >> 16); + bmi[offset + 10] = (byte)((blueMask & 0xFF00) >> 8); + bmi[offset + 11] = (byte)((blueMask & 0xFF) >> 0); + } + } + } else { + for (int j = 0; j < rgbs.length; j++) { + bmi[offset] = (byte)rgbs[j].blue; + bmi[offset + 1] = (byte)rgbs[j].green; + bmi[offset + 2] = (byte)rgbs[j].red; + bmi[offset + 3] = 0; + offset += 4; + } + } + int[] pBits = new int[1]; + int hDib = OS.CreateDIBSection(0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0); + if (hDib == 0) SWT.error(SWT.ERROR_NO_HANDLES); + /* In case of a scanline pad other than 4, do the work to convert it */ + byte[] data = i.data; + if (i.scanlinePad != 4 && (i.bytesPerLine % 4 != 0)) { + int newBpl = i.bytesPerLine + (4 - (i.bytesPerLine % 4)); + byte[] newData = new byte[i.height * newBpl]; + int srcPtr = 0; + int destPtr = 0; + for (int y = 0; y < i.height; y++) { + System.arraycopy(data, srcPtr, newData, destPtr, i.bytesPerLine); + srcPtr += i.bytesPerLine; + destPtr += newBpl; + } + data = newData; + } + OS.MoveMemory(pBits[0], data, data.length); + + int[] result = null; + if (i.getTransparencyType() == SWT.TRANSPARENCY_MASK) { + /* Get the HDC for the device */ + int hDC = device.internal_new_GC(null); + + /* Create the color bitmap */ + int hdcSrc = OS.CreateCompatibleDC(hDC); + OS.SelectObject(hdcSrc, hDib); + int hBitmap = OS.CreateCompatibleBitmap(hDC, i.width, i.height); + if (hBitmap == 0) SWT.error(SWT.ERROR_NO_HANDLES); + int hdcDest = OS.CreateCompatibleDC(hDC); + OS.SelectObject(hdcDest, hBitmap); + OS.BitBlt(hdcDest, 0, 0, i.width, i.height, hdcSrc, 0, 0, OS.SRCCOPY); + + /* Release the HDC for the device */ + device.internal_dispose_GC(hDC, null); + + /* Create the mask */ +// int hHeap = OS.GetProcessHeap(); +// int bmBits = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, i.maskData.length); +// OS.MoveMemory(bmBits, i.maskData, i.maskData.length); +// BITMAP bm = new BITMAP(); +// bm.bmWidth = i.width; +// bm.bmHeight = i.height; +// bm.bmWidthBytes = (((i.width + 7) / 8) + 3) / 4 * 4; +// bm.bmPlanes = 1; +// bm.bmBitsPixel = 1; +// bm.bmBits = bmBits; +// int hMask = OS.CreateBitmapIndirect(bm); +// OS.HeapFree(hHeap, 0, bmBits); + int hMask = OS.CreateBitmap(i.width, i.height, 1, 1, i.maskData); + if (hMask == 0) SWT.error(SWT.ERROR_NO_HANDLES); + OS.SelectObject(hdcSrc, hMask); + OS.PatBlt(hdcSrc, 0, 0, i.width, i.height, OS.DSTINVERT); + OS.DeleteDC(hdcSrc); + OS.DeleteDC(hdcDest); + OS.DeleteObject(hDib); + + if (image == null) { + result = new int[]{hBitmap, hMask}; + } else { + /* Create the icon */ + ICONINFO info = new ICONINFO(); + info.fIcon = true; + info.hbmColor = hBitmap; + info.hbmMask = hMask; + int hIcon = OS.CreateIconIndirect(info); + if (hIcon == 0) SWT.error(SWT.ERROR_NO_HANDLES); + OS.DeleteObject(hBitmap); + OS.DeleteObject(hMask); + image.handle = hIcon; + image.type = SWT.ICON; + if (OS.IsWinCE) image.data = i; + } + } else { + if (image == null) { + result = new int[]{hDib}; + } else { + image.handle = hDib; + image.type = SWT.BITMAP; + image.transparentPixel = i.transparentPixel; + if (image.transparentPixel == -1) { + image.alpha = i.alpha; + if (i.alpha == -1 && i.alphaData != null) { + int length = i.alphaData.length; + image.alphaData = new byte[length]; + System.arraycopy(i.alphaData, 0, image.alphaData, 0, length); + } + } + } + } + return result; +} + +void init(Device device, ImageData i) { + if (i == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, this, i); +} + +/** + * 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 + * + * @private + */ +public int internal_new_GC (GCData data) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + /* + * Create a new GC that can draw into the image. + * Only supported for bitmaps. + */ + if (type != SWT.BITMAP || memGC != null) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + + /* Create a compatible HDC for the device */ + int hDC = device.internal_new_GC(null); + int imageDC = OS.CreateCompatibleDC(hDC); + device.internal_dispose_GC(hDC, null); + if (imageDC == 0) SWT.error(SWT.ERROR_NO_HANDLES); + + if (data != null) { + /* Set the GCData fields */ + data.device = device; + data.image = this; + data.hFont = device.systemFont; + } + return imageDC; +} + +/** + * 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 handle the platform specific GC handle + * @param data the platform specific GC data + * + * @private + */ +public void internal_dispose_GC (int hDC, GCData data) { + OS.DeleteDC(hDC); +} + +/** + * 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 == 0; +} + +/** + * 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) { + /* + * Note. Not implemented on WinCE. + */ + if (OS.IsWinCE) return; + 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; + + /* Get the HDC for the device */ + int hDC = device.internal_new_GC(null); + + /* Change the background color in the image */ + BITMAP bm = new BITMAP(); + OS.GetObject(handle, BITMAP.sizeof, bm); + int hdcMem = OS.CreateCompatibleDC(hDC); + OS.SelectObject(hdcMem, handle); + int maxColors = 1 << bm.bmBitsPixel; + byte[] colors = new byte[maxColors * 4]; + if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + int numColors = OS.GetDIBColorTable(hdcMem, 0, maxColors, colors); + int offset = transparentPixel * 4; + colors[offset] = (byte)color.getBlue(); + colors[offset + 1] = (byte)color.getGreen(); + colors[offset + 2] = (byte)color.getRed(); + if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + OS.SetDIBColorTable(hdcMem, 0, numColors, colors); + OS.DeleteDC(hdcMem); + + /* Release the HDC for the device */ + device.internal_dispose_GC(hDC, 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 "Image {*DISPOSED*}"; + return "Image {" + handle + "}"; +} + +/** + * 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 hPalette the OS handle for the palette, or 0 + * + * @private + */ +public static Image win32_new(Device device, int type, int handle) { + if (device == null) device = Device.getDevice(); + Image image = new Image(); + image.type = type; + image.handle = handle; + image.device = device; + return image; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Region.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Region.java index 620983418b..a08b88d065 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Region.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Region.java @@ -1,307 +1,307 @@ -package org.eclipse.swt.graphics;
-
-/*
+package org.eclipse.swt.graphics; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-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 rectangles.
- * <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>
- */
-
-public final class Region {
-
- /**
- * the OS resource for the region
- * (Warning: This field is platform dependent)
- */
- public int 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 () {
- handle = OS.CreateRectRgn (0, 0, 0, 0);
- if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
-}
-
-/**
- * Constructs a new region given a handle to the operating
- * system resources that it should represent.
- *
- * @param handle the handle for the result
- */
-Region(int handle) {
- this.handle = handle;
-}
-
-/**
- * Adds the given rectangle to the collection of rectangles
- * 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);
-
- int rectRgn = OS.CreateRectRgn (rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
- OS.CombineRgn (handle, handle, rectRgn, OS.RGN_OR);
- OS.DeleteObject (rectRgn);
-}
-
-/**
- * Adds all of the rectangles which make up the area covered
- * by the argument to the collection of rectangles 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);
- OS.CombineRgn (handle, handle, region.handle, OS.RGN_OR);
-}
-
-/**
- * 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);
- return OS.PtInRegion (handle, x, y);
-}
-
-/**
- * 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);
-}
-
-/**
- * Disposes of the operating system resources associated with
- * the region. Applications must dispose of all regions which
- * they allocate.
- */
-public void dispose () {
- if (handle != 0) OS.DeleteObject (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 rgn = (Region)object;
- return handle == rgn.handle;
-}
-
-/**
- * Returns a rectangle which represents the rectangular
- * union of the collection of rectangles 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);
- RECT rect = new RECT();
- OS.GetRgnBox(handle, rect);
- return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
-}
-
-/**
- * Returns an integer hash code for the receiver. Any two
- * objects which 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;
-}
-
-/**
- * Returns <code>true</code> if the rectangle described by the
- * arguments intersects with any of the rectangles the receiver
- * mainains 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
- */
-public boolean intersects (int x, int y, int width, int height) {
- if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- RECT r = new RECT ();
- OS.SetRect (r, x, y, x + width, y + height);
- return OS.RectInRegion (handle, r);
-}
-
-/**
- * Returns <code>true</code> if the given rectangle intersects
- * with any of the rectangles the receiver mainains 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
- */
-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);
- RECT rect = new RECT ();
- int result = OS.GetRgnBox (handle, rect);
- if (result == OS.NULLREGION) return true;
- return ((rect.right - rect.left) <= 0) || ((rect.bottom - rect.top) <= 0);
-}
-
-/**
- * Invokes platform specific functionality to allocate a new region.
- * <p>
- * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
- * API for <code>Region</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 handle the handle for the region
- *
- * @private
- */
-public static Region win32_new(int handle) {
- return new Region(handle);
-}
-
-/**
- * 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 + "}";
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +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 rectangles. + * <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> + */ + +public final class Region { + + /** + * the OS resource for the region + * (Warning: This field is platform dependent) + */ + public int 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 () { + handle = OS.CreateRectRgn (0, 0, 0, 0); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); +} + +/** + * Constructs a new region given a handle to the operating + * system resources that it should represent. + * + * @param handle the handle for the result + */ +Region(int handle) { + this.handle = handle; +} + +/** + * Adds the given rectangle to the collection of rectangles + * 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); + + int rectRgn = OS.CreateRectRgn (rect.x, rect.y, rect.x + rect.width, rect.y + rect.height); + OS.CombineRgn (handle, handle, rectRgn, OS.RGN_OR); + OS.DeleteObject (rectRgn); +} + +/** + * Adds all of the rectangles which make up the area covered + * by the argument to the collection of rectangles 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); + OS.CombineRgn (handle, handle, region.handle, OS.RGN_OR); +} + +/** + * 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); + return OS.PtInRegion (handle, x, y); +} + +/** + * 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); +} + +/** + * Disposes of the operating system resources associated with + * the region. Applications must dispose of all regions which + * they allocate. + */ +public void dispose () { + if (handle != 0) OS.DeleteObject (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 rgn = (Region)object; + return handle == rgn.handle; +} + +/** + * Returns a rectangle which represents the rectangular + * union of the collection of rectangles 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); + RECT rect = new RECT(); + OS.GetRgnBox(handle, rect); + return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); +} + +/** + * Returns an integer hash code for the receiver. Any two + * objects which 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; +} + +/** + * Returns <code>true</code> if the rectangle described by the + * arguments intersects with any of the rectangles the receiver + * mainains 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 + */ +public boolean intersects (int x, int y, int width, int height) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + RECT r = new RECT (); + OS.SetRect (r, x, y, x + width, y + height); + return OS.RectInRegion (handle, r); +} + +/** + * Returns <code>true</code> if the given rectangle intersects + * with any of the rectangles the receiver mainains 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 + */ +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); + RECT rect = new RECT (); + int result = OS.GetRgnBox (handle, rect); + if (result == OS.NULLREGION) return true; + return ((rect.right - rect.left) <= 0) || ((rect.bottom - rect.top) <= 0); +} + +/** + * Invokes platform specific functionality to allocate a new region. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>Region</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 handle the handle for the region + * + * @private + */ +public static Region win32_new(int handle) { + return new Region(handle); +} + +/** + * 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/win32/org/eclipse/swt/internal/BidiUtil.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/BidiUtil.java index 1b39904fbd..73c1d4cd57 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/BidiUtil.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/BidiUtil.java @@ -1,532 +1,532 @@ -package org.eclipse.swt.internal;
-
-/*
+package org.eclipse.swt.internal; + +/* * Copyright (c) 2001, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.GC;
-import org.eclipse.swt.internal.win32.GCP_RESULTS;
-import org.eclipse.swt.internal.win32.OS;
-import org.eclipse.swt.internal.win32.RECT;
-import org.eclipse.swt.internal.win32.TCHAR;
-import java.util.Hashtable;
-/*
- * Wraps Win32 API used to bidi enable the StyledText widget.
- */
-public class BidiUtil {
-
- // Keyboard language ids
- public static final int KEYBOARD_NON_BIDI = 0;
- public static final int KEYBOARD_BIDI = 1;
-
- // bidi flag
- static int isBidiPlatform = -1;
-
- // getRenderInfo flag values
- public static final int CLASSIN = 1;
- public static final int LINKBEFORE = 2;
- public static final int LINKAFTER = 4;
-
- // variables used for providing a listener mechanism for keyboard language
- // switching
- static Hashtable map = new Hashtable ();
- static Hashtable oldProcMap = new Hashtable ();
- /*
- * This code is intentionally commented. In order
- * to support CLDC, .class cannot be used because
- * it does not compile on some Java compilers when
- * they are targeted for CLDC.
- */
- // static Callback callback = new Callback (BidiUtil.class, "windowProc", 4);
- static final String CLASS_NAME = "org.eclipse.swt.internal.BidiUtil";
- static Callback callback;
- static {
- try {
- callback = new Callback (Class.forName (CLASS_NAME), "windowProc", 4);
- } catch (ClassNotFoundException e) {}
- }
-
- // GetCharacterPlacement constants
- static final int GCP_REORDER = 0x0002;
- static final int GCP_GLYPHSHAPE = 0x0010;
- static final int GCP_LIGATE = 0x0020;
- static final int GCP_CLASSIN = 0x00080000;
- static final byte GCPCLASS_ARABIC = 2;
- static final byte GCPCLASS_HEBREW = 2;
- static final byte GCPCLASS_LOCALNUMBER = 4;
- static final int GCPGLYPH_LINKBEFORE = 0x8000;
- static final int GCPGLYPH_LINKAFTER = 0x4000;
- // ExtTextOut constants
- static final int ETO_GLYPH_INDEX = 0x0010;
- // Windows primary language identifiers
- static final int LANG_ARABIC = 0x01;
- static final int LANG_HEBREW = 0x0d;
- // code page identifiers
- static final String CD_PG_HEBREW = "1255";
- static final String CD_PG_ARABIC = "1256";
- // ActivateKeyboard constants
- static final int HKL_NEXT = 1;
- static final int HKL_PREV = 0;
-
- /*
- * Public character class constants are the same as Windows
- * platform constants.
- * Saves conversion of class array in getRenderInfo to arbitrary
- * constants for now.
- */
- public static final int CLASS_HEBREW = GCPCLASS_ARABIC;
- public static final int CLASS_ARABIC = GCPCLASS_HEBREW;
- public static final int CLASS_LOCALNUMBER = GCPCLASS_LOCALNUMBER;
- public static final int REORDER = GCP_REORDER;
- public static final int LIGATE = GCP_LIGATE;
- public static final int GLYPHSHAPE = GCP_GLYPHSHAPE;
-
-/**
- * Adds a language listener. The listener will get notified when the language of
- * the keyboard changes (via Alt-Shift on Win platforms). Do this by creating a
- * window proc for the Control so that the window messages for the Control can be
- * monitored.
- * <p>
- *
- * @param int the handle of the Control that is listening for keyboard language
- * changes
- * @param runnable the code that should be executed when a keyboard language change
- * occurs
- */
-public static void addLanguageListener (int hwnd, Runnable runnable) {
- map.put (new Integer (hwnd), runnable);
- int oldProc = OS.GetWindowLong (hwnd, OS.GWL_WNDPROC);
- oldProcMap.put (new Integer(hwnd), new Integer(oldProc));
- OS.SetWindowLong (hwnd, OS.GWL_WNDPROC, callback.getAddress ());
-}
-/**
- * Proc used for OS.EnumSystemLanguageGroups call during isBidiPlatform test.
- */
-static int EnumSystemLanguageGroupsProc(int lpLangGrpId, int lpLangGrpIdString, int lpLangGrpName, int options, int lParam) {
- if (lpLangGrpId == OS.LGRPID_HEBREW) {
- isBidiPlatform = 1;
- return 0;
- }
- if (lpLangGrpId == OS.LGRPID_ARABIC) {
- isBidiPlatform = 1;
- return 0;
- }
- return 1;
-}
-/**
- * Wraps the ExtTextOut function.
- * <p>
- *
- * @param gc the gc to use for rendering
- * @param renderBuffer the glyphs to render as an array of characters
- * @param renderDx the width of each glyph in renderBuffer
- * @param x x position to start rendering
- * @param y y position to start rendering
- */
-public static void drawGlyphs(GC gc, char[] renderBuffer, int[] renderDx, int x, int y) {
- RECT rect = null;
- OS.ExtTextOutW(gc.handle, x, y, ETO_GLYPH_INDEX, rect, renderBuffer, renderBuffer.length, renderDx);
-}
-/**
- * Return ordering and rendering information for the given text. Wraps the GetFontLanguageInfo
- * and GetCharacterPlacement functions.
- * <p>
- *
- * @param gc the GC to use for measuring of this line, input parameter
- * @param text text that bidi data should be calculated for, input parameter
- * @param order an array of integers representing the visual position of each character in
- * the text array, output parameter
- * @param classBuffer an array of integers representing the type (e.g., ARABIC, HEBREW,
- * LOCALNUMBER) of each character in the text array, input/output parameter
- * @param dx an array of integers representing the pixel width of each glyph in the returned
- * glyph buffer, output paramteter
- * @param flags an integer representing rendering flag information, input parameter
- * @param offsets text segments that should be measured and reordered separately, input
- * parameter. See org.eclipse.swt.custom.BidiSegmentEvent for details.
- * @return buffer with the glyphs that should be rendered for the given text
- */
-public static char[] getRenderInfo(GC gc, String text, int[] order, byte[] classBuffer, int[] dx, int flags, int [] offsets) {
- int fontLanguageInfo = OS.GetFontLanguageInfo(gc.handle);
- int hHeap = OS.GetProcessHeap();
- int[] lpCs = new int[8];
- int cs = OS.GetTextCharset(gc.handle);
- OS.TranslateCharsetInfo(cs, lpCs, OS.TCI_SRCCHARSET);
- TCHAR textBuffer = new TCHAR(lpCs[1], text, false);
- int byteCount = textBuffer.length();
- boolean linkBefore = (flags & LINKBEFORE) == LINKBEFORE;
- boolean linkAfter = (flags & LINKAFTER) == LINKAFTER;
-
- GCP_RESULTS result = new GCP_RESULTS();
- result.lStructSize = GCP_RESULTS.sizeof;
- result.nGlyphs = byteCount;
- int lpOrder = result.lpOrder = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 4);
- int lpDx = result.lpDx = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 4);
- int lpClass = result.lpClass = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- int lpGlyphs = result.lpGlyphs = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 2);
-
- // set required dwFlags
- int dwFlags = 0;
- int glyphFlags = 0;
- // Always reorder. We assume that if we are calling this function we're
- // on a platform that supports bidi. Fixes 20690.
- dwFlags |= GCP_REORDER;
- if ((fontLanguageInfo & GCP_LIGATE) == GCP_LIGATE) {
- dwFlags |= GCP_LIGATE;
- glyphFlags |= 0;
- }
- if ((fontLanguageInfo & GCP_GLYPHSHAPE) == GCP_GLYPHSHAPE) {
- dwFlags |= GCP_GLYPHSHAPE;
- if (linkBefore) {
- glyphFlags |= GCPGLYPH_LINKBEFORE;
- }
- if (linkAfter) {
- glyphFlags |= GCPGLYPH_LINKAFTER;
- }
- }
- byte[] lpGlyphs2;
- if (linkBefore || linkAfter) {
- lpGlyphs2 = new byte[2];
- lpGlyphs2[0]=(byte)glyphFlags;
- lpGlyphs2[1]=(byte)(glyphFlags >> 8);
- }
- else {
- lpGlyphs2 = new byte[] {(byte) glyphFlags};
- }
- OS.MoveMemory(result.lpGlyphs, lpGlyphs2, lpGlyphs2.length);
-
- if ((flags & CLASSIN) == CLASSIN) {
- // set classification values for the substring
- dwFlags |= GCP_CLASSIN;
- OS.MoveMemory(result.lpClass, classBuffer, classBuffer.length);
- }
-
- char[] glyphBuffer = new char[result.nGlyphs];
- int glyphCount = 0;
- for (int i=0; i<offsets.length-1; i++) {
- int offset = offsets [i];
- int length = offsets [i+1] - offsets [i];
-
- // The number of glyphs expected is <= length (segment length);
- // the actual number returned may be less in case of Arabic ligatures.
- result.nGlyphs = length;
- TCHAR textBuffer2 = new TCHAR(lpCs[1], text.substring(offset, offset + length), false);
- OS.GetCharacterPlacement(gc.handle, textBuffer2, textBuffer2.length(), 0, result, dwFlags);
-
- if (dx != null) {
- int [] dx2 = new int [result.nGlyphs];
- OS.MoveMemory(dx2, result.lpDx, dx2.length * 4);
- System.arraycopy (dx2, 0, dx, glyphCount, dx2.length);
- }
- if (order != null) {
- int [] order2 = new int [length];
- OS.MoveMemory(order2, result.lpOrder, order2.length * 4);
- for (int j=0; j<length; j++) {
- order2 [j] += glyphCount;
- }
- System.arraycopy (order2, 0, order, offset, length);
- }
- if (classBuffer != null) {
- byte [] classBuffer2 = new byte [length];
- OS.MoveMemory(classBuffer2, result.lpClass, classBuffer2.length);
- System.arraycopy (classBuffer2, 0, classBuffer, offset, length);
- }
- char[] glyphBuffer2 = new char[result.nGlyphs];
- OS.MoveMemory(glyphBuffer2, result.lpGlyphs, glyphBuffer2.length * 2);
- System.arraycopy (glyphBuffer2, 0, glyphBuffer, glyphCount, glyphBuffer2.length);
- glyphCount += glyphBuffer2.length;
-
- // We concatenate successive results of calls to GCP.
- // For Arabic, it is the only good method since the number of output
- // glyphs might be less than the number of input characters.
- // This assumes that the whole line is built by successive adjacent
- // segments without overlapping.
- result.lpOrder += length * 4;
- result.lpDx += length * 4;
- result.lpClass += length;
- result.lpGlyphs += glyphBuffer2.length * 2;
- }
-
- /* Free the memory that was allocated. */
- OS.HeapFree(hHeap, 0, lpGlyphs);
- OS.HeapFree(hHeap, 0, lpClass);
- OS.HeapFree(hHeap, 0, lpDx);
- OS.HeapFree(hHeap, 0, lpOrder);
- return glyphBuffer;
-}
-/**
- * Return bidi ordering information for the given text. Does not return rendering
- * information (e.g., glyphs, glyph distances). Use this method when you only need
- * ordering information. Doing so will improve performance. Wraps the
- * GetFontLanguageInfo and GetCharacterPlacement functions.
- * <p>
- *
- * @param gc the GC to use for measuring of this line, input parameter
- * @param text text that bidi data should be calculated for, input parameter
- * @param order an array of integers representing the visual position of each character in
- * the text array, output parameter
- * @param classBuffer an array of integers representing the type (e.g., ARABIC, HEBREW,
- * LOCALNUMBER) of each character in the text array, input/output parameter
- * @param flags an integer representing rendering flag information, input parameter
- * @param offsets text segments that should be measured and reordered separately, input
- * parameter. See org.eclipse.swt.custom.BidiSegmentEvent for details.
- */
-public static void getOrderInfo(GC gc, String text, int[] order, byte[] classBuffer, int flags, int [] offsets) {
- int fontLanguageInfo = OS.GetFontLanguageInfo(gc.handle);
- int hHeap = OS.GetProcessHeap();
- int[] lpCs = new int[8];
- int cs = OS.GetTextCharset(gc.handle);
- OS.TranslateCharsetInfo(cs, lpCs, OS.TCI_SRCCHARSET);
- TCHAR textBuffer = new TCHAR(lpCs[1], text, false);
- int byteCount = textBuffer.length();
-
- GCP_RESULTS result = new GCP_RESULTS();
- result.lStructSize = GCP_RESULTS.sizeof;
- result.nGlyphs = byteCount;
- int lpOrder = result.lpOrder = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 4);
- int lpClass = result.lpClass = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
-
- // set required dwFlags, these values will affect how the text gets rendered and
- // ordered
- int dwFlags = 0;
- // Always reorder. We assume that if we are calling this function we're
- // on a platform that supports bidi. Fixes 20690.
- dwFlags |= GCP_REORDER;
- if ((fontLanguageInfo & GCP_LIGATE) == GCP_LIGATE) {
- dwFlags |= GCP_LIGATE;
- }
- if ((fontLanguageInfo & GCP_GLYPHSHAPE) == GCP_GLYPHSHAPE) {
- dwFlags |= GCP_GLYPHSHAPE;
- }
- if ((flags & CLASSIN) == CLASSIN) {
- // set classification values for the substring, classification values
- // can be specified on input
- dwFlags |= GCP_CLASSIN;
- OS.MoveMemory(result.lpClass, classBuffer, classBuffer.length);
- }
-
- int glyphCount = 0;
- for (int i=0; i<offsets.length-1; i++) {
- int offset = offsets [i];
- int length = offsets [i+1] - offsets [i];
- // The number of glyphs expected is <= length (segment length);
- // the actual number returned may be less in case of Arabic ligatures.
- result.nGlyphs = length;
- TCHAR textBuffer2 = new TCHAR(lpCs[1], text.substring(offset, offset + length), false);
- OS.GetCharacterPlacement(gc.handle, textBuffer2, textBuffer2.length(), 0, result, dwFlags);
-
- if (order != null) {
- int [] order2 = new int [length];
- OS.MoveMemory(order2, result.lpOrder, order2.length * 4);
- for (int j=0; j<length; j++) {
- order2 [j] += glyphCount;
- }
- System.arraycopy (order2, 0, order, offset, length);
- }
- if (classBuffer != null) {
- byte [] classBuffer2 = new byte [length];
- OS.MoveMemory(classBuffer2, result.lpClass, classBuffer2.length);
- System.arraycopy (classBuffer2, 0, classBuffer, offset, length);
- }
- glyphCount += result.nGlyphs;
-
- // We concatenate successive results of calls to GCP.
- // For Arabic, it is the only good method since the number of output
- // glyphs might be less than the number of input characters.
- // This assumes that the whole line is built by successive adjacent
- // segments without overlapping.
- result.lpOrder += length * 4;
- result.lpClass += length;
- }
-
- /* Free the memory that was allocated. */
- OS.HeapFree(hHeap, 0, lpClass);
- OS.HeapFree(hHeap, 0, lpOrder);
-}
-/**
- * Return bidi attribute information for the font in the specified gc.
- * <p>
- *
- * @param gc the gc to query
- * @return bitwise OR of the REORDER, LIGATE and GLYPHSHAPE flags
- * defined by this class.
- */
-public static int getFontBidiAttributes(GC gc) {
- int fontStyle = 0;
- int fontLanguageInfo = OS.GetFontLanguageInfo(gc.handle);
- if (((fontLanguageInfo & GCP_REORDER) != 0)) {
- fontStyle |= REORDER;
- }
- if (((fontLanguageInfo & GCP_LIGATE) != 0)) {
- fontStyle |= LIGATE;
- }
- if (((fontLanguageInfo & GCP_GLYPHSHAPE) != 0)) {
- fontStyle |= GLYPHSHAPE;
- }
- return fontStyle;
-}
-/**
- * Return the active keyboard language type.
- * <p>
- *
- * @return an integer representing the active keyboard language (KEYBOARD_BIDI,
- * KEYBOARD_NON_BIDI)
- */
-public static int getKeyboardLanguage() {
- int layout = OS.GetKeyboardLayout(0);
- // only interested in low 2 bytes, which is the primary
- // language identifier
- layout = layout & 0x000000FF;
- if (layout == LANG_HEBREW) return KEYBOARD_BIDI;
- if (layout == LANG_ARABIC) return KEYBOARD_BIDI;
- // return non-bidi for all other languages
- return KEYBOARD_NON_BIDI;
-}
-/**
- * Return the languages that are installed for the keyboard.
- * <p>
- *
- * @return integer array with an entry for each installed language
- */
-public static int[] getKeyboardLanguageList() {
- int maxSize = 10;
- int[] tempList = new int[maxSize];
- int size = OS.GetKeyboardLayoutList(maxSize, tempList);
- int[] list = new int[size];
- System.arraycopy(tempList, 0, list, 0, size);
- return list;
-}
-/**
- * Return whether or not the platform supports a bidi language. Determine this
- * by looking at the languages that are installed.
- * <p>
- *
- * @return true if bidi is supported, false otherwise. Always
- * false on Windows CE.
- */
-public static boolean isBidiPlatform() {
- if (OS.IsWinCE) return false;
- if (isBidiPlatform != -1) return isBidiPlatform == 1; // already set
-
- isBidiPlatform = 0;
-
- // The following test is a workaround for bug report 27629. On WinXP,
- // both bidi and complex script (e.g., Thai) languages must be installed
- // at the same time. Since the bidi platform calls do not support
- // double byte characters, there is no way to run Eclipse using the
- // complex script languages on XP, so constrain this test to answer true
- // only if a bidi input language is defined. Doing so will allow complex
- // script languages to work (e.g., one can install bidi and complex script
- // languages, but only install the Thai keyboard).
- if (!isKeyboardBidi()) return false;
-
- Callback callback = null;
- try {
- callback = new Callback (Class.forName (CLASS_NAME), "EnumSystemLanguageGroupsProc", 5);
- int lpEnumSystemLanguageGroupsProc = callback.getAddress ();
- if (lpEnumSystemLanguageGroupsProc == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
- OS.EnumSystemLanguageGroups(lpEnumSystemLanguageGroupsProc, OS.LGRPID_INSTALLED, 0);
- callback.dispose ();
- } catch (ClassNotFoundException e) {
- if (callback != null) callback.dispose();
- }
- if (isBidiPlatform == 1) return true;
- // need to look at system code page for NT & 98 platforms since EnumSystemLanguageGroups is
- // not supported for these platforms
- String codePage = String.valueOf(OS.GetACP());
- if (CD_PG_ARABIC.equals(codePage) || CD_PG_HEBREW.equals(codePage)) {
- isBidiPlatform = 1;
- }
- return isBidiPlatform == 1;
-}
-/**
- * Return whether or not the keyboard supports input of a bidi language. Determine this
- * by looking at the languages that are installed for the keyboard.
- * <p>
- *
- * @return true if bidi is supported, false otherwise.
- */
-public static boolean isKeyboardBidi() {
- int[] list = getKeyboardLanguageList();
- for (int i=0; i<list.length; i++) {
- int id = list[i] & 0x000000FF;
- if ((id == LANG_ARABIC) || (id == LANG_HEBREW)) {
- return true;
- }
- }
- return false;
-}
-/**
- * Removes the specified language listener.
- * <p>
- *
- * @param hwnd the handle of the Control that is listening for keyboard language changes
- */
-public static void removeLanguageListener (int hwnd) {
- map.remove (new Integer (hwnd));
- Integer proc = (Integer)oldProcMap.remove (new Integer (hwnd));
- if (proc == null) return;
- OS.SetWindowLong (hwnd, OS.GWL_WNDPROC, proc.intValue());
-}
-/**
- * Switch the keyboard language to the specified language type. We do
- * not distinguish between mulitple bidi or multiple non-bidi languages, so
- * set the keyboard to the first language of the given type.
- * <p>
- *
- * @param language integer representing language. One of
- * KEYBOARD_BIDI, KEYBOARD_NON_BIDI.
- */
-public static void setKeyboardLanguage(int language) {
- // don't switch the keyboard if it doesn't need to be
- if (language == getKeyboardLanguage()) return;
-
- if (language == KEYBOARD_BIDI) {
- // get the list of active languages
- int[] list = getKeyboardLanguageList();
- // set to first bidi language
- for (int i=0; i<list.length; i++) {
- int id = list[i] & 0x000000FF;
- if ((id == LANG_ARABIC) || (id == LANG_HEBREW)) {
- OS.ActivateKeyboardLayout(list[i], 0);
- return;
- }
- }
- } else {
- // get the list of active languages
- int[] list = getKeyboardLanguageList();
- // set to the first non-bidi language (anything not
- // hebrew or arabic)
- for (int i=0; i<list.length; i++) {
- int id = list[i] & 0x000000FF;
- if ((id != LANG_HEBREW) && (id != LANG_ARABIC)) {
- OS.ActivateKeyboardLayout(list[i], 0);
- return;
- }
- }
- }
-
-}
-/**
- * Window proc to intercept keyboard language switch event (WS_INPUTLANGCHANGE).
- * Run the Control's registered runnable when the keyboard language is switched.
- *
- * @param hwnd handle of the control that is listening for the keyboard language
- * change event
- * @param msg window message
- */
-static int windowProc (int hwnd, int msg, int wParam, int lParam) {
- switch (msg) {
- case 0x51 /*OS.WM_INPUTLANGCHANGE*/:
- Runnable runnable = (Runnable) map.get (new Integer (hwnd));
- if (runnable != null) runnable.run ();
- break;
- }
- Integer oldProc = (Integer)oldProcMap.get(new Integer(hwnd));
- return OS.CallWindowProc (oldProc.intValue(), hwnd, msg, wParam, lParam);
-}
-
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.internal.win32.GCP_RESULTS; +import org.eclipse.swt.internal.win32.OS; +import org.eclipse.swt.internal.win32.RECT; +import org.eclipse.swt.internal.win32.TCHAR; +import java.util.Hashtable; +/* + * Wraps Win32 API used to bidi enable the StyledText widget. + */ +public class BidiUtil { + + // Keyboard language ids + public static final int KEYBOARD_NON_BIDI = 0; + public static final int KEYBOARD_BIDI = 1; + + // bidi flag + static int isBidiPlatform = -1; + + // getRenderInfo flag values + public static final int CLASSIN = 1; + public static final int LINKBEFORE = 2; + public static final int LINKAFTER = 4; + + // variables used for providing a listener mechanism for keyboard language + // switching + static Hashtable map = new Hashtable (); + static Hashtable oldProcMap = new Hashtable (); + /* + * This code is intentionally commented. In order + * to support CLDC, .class cannot be used because + * it does not compile on some Java compilers when + * they are targeted for CLDC. + */ + // static Callback callback = new Callback (BidiUtil.class, "windowProc", 4); + static final String CLASS_NAME = "org.eclipse.swt.internal.BidiUtil"; + static Callback callback; + static { + try { + callback = new Callback (Class.forName (CLASS_NAME), "windowProc", 4); + } catch (ClassNotFoundException e) {} + } + + // GetCharacterPlacement constants + static final int GCP_REORDER = 0x0002; + static final int GCP_GLYPHSHAPE = 0x0010; + static final int GCP_LIGATE = 0x0020; + static final int GCP_CLASSIN = 0x00080000; + static final byte GCPCLASS_ARABIC = 2; + static final byte GCPCLASS_HEBREW = 2; + static final byte GCPCLASS_LOCALNUMBER = 4; + static final int GCPGLYPH_LINKBEFORE = 0x8000; + static final int GCPGLYPH_LINKAFTER = 0x4000; + // ExtTextOut constants + static final int ETO_GLYPH_INDEX = 0x0010; + // Windows primary language identifiers + static final int LANG_ARABIC = 0x01; + static final int LANG_HEBREW = 0x0d; + // code page identifiers + static final String CD_PG_HEBREW = "1255"; + static final String CD_PG_ARABIC = "1256"; + // ActivateKeyboard constants + static final int HKL_NEXT = 1; + static final int HKL_PREV = 0; + + /* + * Public character class constants are the same as Windows + * platform constants. + * Saves conversion of class array in getRenderInfo to arbitrary + * constants for now. + */ + public static final int CLASS_HEBREW = GCPCLASS_ARABIC; + public static final int CLASS_ARABIC = GCPCLASS_HEBREW; + public static final int CLASS_LOCALNUMBER = GCPCLASS_LOCALNUMBER; + public static final int REORDER = GCP_REORDER; + public static final int LIGATE = GCP_LIGATE; + public static final int GLYPHSHAPE = GCP_GLYPHSHAPE; + +/** + * Adds a language listener. The listener will get notified when the language of + * the keyboard changes (via Alt-Shift on Win platforms). Do this by creating a + * window proc for the Control so that the window messages for the Control can be + * monitored. + * <p> + * + * @param int the handle of the Control that is listening for keyboard language + * changes + * @param runnable the code that should be executed when a keyboard language change + * occurs + */ +public static void addLanguageListener (int hwnd, Runnable runnable) { + map.put (new Integer (hwnd), runnable); + int oldProc = OS.GetWindowLong (hwnd, OS.GWL_WNDPROC); + oldProcMap.put (new Integer(hwnd), new Integer(oldProc)); + OS.SetWindowLong (hwnd, OS.GWL_WNDPROC, callback.getAddress ()); +} +/** + * Proc used for OS.EnumSystemLanguageGroups call during isBidiPlatform test. + */ +static int EnumSystemLanguageGroupsProc(int lpLangGrpId, int lpLangGrpIdString, int lpLangGrpName, int options, int lParam) { + if (lpLangGrpId == OS.LGRPID_HEBREW) { + isBidiPlatform = 1; + return 0; + } + if (lpLangGrpId == OS.LGRPID_ARABIC) { + isBidiPlatform = 1; + return 0; + } + return 1; +} +/** + * Wraps the ExtTextOut function. + * <p> + * + * @param gc the gc to use for rendering + * @param renderBuffer the glyphs to render as an array of characters + * @param renderDx the width of each glyph in renderBuffer + * @param x x position to start rendering + * @param y y position to start rendering + */ +public static void drawGlyphs(GC gc, char[] renderBuffer, int[] renderDx, int x, int y) { + RECT rect = null; + OS.ExtTextOutW(gc.handle, x, y, ETO_GLYPH_INDEX, rect, renderBuffer, renderBuffer.length, renderDx); +} +/** + * Return ordering and rendering information for the given text. Wraps the GetFontLanguageInfo + * and GetCharacterPlacement functions. + * <p> + * + * @param gc the GC to use for measuring of this line, input parameter + * @param text text that bidi data should be calculated for, input parameter + * @param order an array of integers representing the visual position of each character in + * the text array, output parameter + * @param classBuffer an array of integers representing the type (e.g., ARABIC, HEBREW, + * LOCALNUMBER) of each character in the text array, input/output parameter + * @param dx an array of integers representing the pixel width of each glyph in the returned + * glyph buffer, output paramteter + * @param flags an integer representing rendering flag information, input parameter + * @param offsets text segments that should be measured and reordered separately, input + * parameter. See org.eclipse.swt.custom.BidiSegmentEvent for details. + * @return buffer with the glyphs that should be rendered for the given text + */ +public static char[] getRenderInfo(GC gc, String text, int[] order, byte[] classBuffer, int[] dx, int flags, int [] offsets) { + int fontLanguageInfo = OS.GetFontLanguageInfo(gc.handle); + int hHeap = OS.GetProcessHeap(); + int[] lpCs = new int[8]; + int cs = OS.GetTextCharset(gc.handle); + OS.TranslateCharsetInfo(cs, lpCs, OS.TCI_SRCCHARSET); + TCHAR textBuffer = new TCHAR(lpCs[1], text, false); + int byteCount = textBuffer.length(); + boolean linkBefore = (flags & LINKBEFORE) == LINKBEFORE; + boolean linkAfter = (flags & LINKAFTER) == LINKAFTER; + + GCP_RESULTS result = new GCP_RESULTS(); + result.lStructSize = GCP_RESULTS.sizeof; + result.nGlyphs = byteCount; + int lpOrder = result.lpOrder = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 4); + int lpDx = result.lpDx = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 4); + int lpClass = result.lpClass = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + int lpGlyphs = result.lpGlyphs = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 2); + + // set required dwFlags + int dwFlags = 0; + int glyphFlags = 0; + // Always reorder. We assume that if we are calling this function we're + // on a platform that supports bidi. Fixes 20690. + dwFlags |= GCP_REORDER; + if ((fontLanguageInfo & GCP_LIGATE) == GCP_LIGATE) { + dwFlags |= GCP_LIGATE; + glyphFlags |= 0; + } + if ((fontLanguageInfo & GCP_GLYPHSHAPE) == GCP_GLYPHSHAPE) { + dwFlags |= GCP_GLYPHSHAPE; + if (linkBefore) { + glyphFlags |= GCPGLYPH_LINKBEFORE; + } + if (linkAfter) { + glyphFlags |= GCPGLYPH_LINKAFTER; + } + } + byte[] lpGlyphs2; + if (linkBefore || linkAfter) { + lpGlyphs2 = new byte[2]; + lpGlyphs2[0]=(byte)glyphFlags; + lpGlyphs2[1]=(byte)(glyphFlags >> 8); + } + else { + lpGlyphs2 = new byte[] {(byte) glyphFlags}; + } + OS.MoveMemory(result.lpGlyphs, lpGlyphs2, lpGlyphs2.length); + + if ((flags & CLASSIN) == CLASSIN) { + // set classification values for the substring + dwFlags |= GCP_CLASSIN; + OS.MoveMemory(result.lpClass, classBuffer, classBuffer.length); + } + + char[] glyphBuffer = new char[result.nGlyphs]; + int glyphCount = 0; + for (int i=0; i<offsets.length-1; i++) { + int offset = offsets [i]; + int length = offsets [i+1] - offsets [i]; + + // The number of glyphs expected is <= length (segment length); + // the actual number returned may be less in case of Arabic ligatures. + result.nGlyphs = length; + TCHAR textBuffer2 = new TCHAR(lpCs[1], text.substring(offset, offset + length), false); + OS.GetCharacterPlacement(gc.handle, textBuffer2, textBuffer2.length(), 0, result, dwFlags); + + if (dx != null) { + int [] dx2 = new int [result.nGlyphs]; + OS.MoveMemory(dx2, result.lpDx, dx2.length * 4); + System.arraycopy (dx2, 0, dx, glyphCount, dx2.length); + } + if (order != null) { + int [] order2 = new int [length]; + OS.MoveMemory(order2, result.lpOrder, order2.length * 4); + for (int j=0; j<length; j++) { + order2 [j] += glyphCount; + } + System.arraycopy (order2, 0, order, offset, length); + } + if (classBuffer != null) { + byte [] classBuffer2 = new byte [length]; + OS.MoveMemory(classBuffer2, result.lpClass, classBuffer2.length); + System.arraycopy (classBuffer2, 0, classBuffer, offset, length); + } + char[] glyphBuffer2 = new char[result.nGlyphs]; + OS.MoveMemory(glyphBuffer2, result.lpGlyphs, glyphBuffer2.length * 2); + System.arraycopy (glyphBuffer2, 0, glyphBuffer, glyphCount, glyphBuffer2.length); + glyphCount += glyphBuffer2.length; + + // We concatenate successive results of calls to GCP. + // For Arabic, it is the only good method since the number of output + // glyphs might be less than the number of input characters. + // This assumes that the whole line is built by successive adjacent + // segments without overlapping. + result.lpOrder += length * 4; + result.lpDx += length * 4; + result.lpClass += length; + result.lpGlyphs += glyphBuffer2.length * 2; + } + + /* Free the memory that was allocated. */ + OS.HeapFree(hHeap, 0, lpGlyphs); + OS.HeapFree(hHeap, 0, lpClass); + OS.HeapFree(hHeap, 0, lpDx); + OS.HeapFree(hHeap, 0, lpOrder); + return glyphBuffer; +} +/** + * Return bidi ordering information for the given text. Does not return rendering + * information (e.g., glyphs, glyph distances). Use this method when you only need + * ordering information. Doing so will improve performance. Wraps the + * GetFontLanguageInfo and GetCharacterPlacement functions. + * <p> + * + * @param gc the GC to use for measuring of this line, input parameter + * @param text text that bidi data should be calculated for, input parameter + * @param order an array of integers representing the visual position of each character in + * the text array, output parameter + * @param classBuffer an array of integers representing the type (e.g., ARABIC, HEBREW, + * LOCALNUMBER) of each character in the text array, input/output parameter + * @param flags an integer representing rendering flag information, input parameter + * @param offsets text segments that should be measured and reordered separately, input + * parameter. See org.eclipse.swt.custom.BidiSegmentEvent for details. + */ +public static void getOrderInfo(GC gc, String text, int[] order, byte[] classBuffer, int flags, int [] offsets) { + int fontLanguageInfo = OS.GetFontLanguageInfo(gc.handle); + int hHeap = OS.GetProcessHeap(); + int[] lpCs = new int[8]; + int cs = OS.GetTextCharset(gc.handle); + OS.TranslateCharsetInfo(cs, lpCs, OS.TCI_SRCCHARSET); + TCHAR textBuffer = new TCHAR(lpCs[1], text, false); + int byteCount = textBuffer.length(); + + GCP_RESULTS result = new GCP_RESULTS(); + result.lStructSize = GCP_RESULTS.sizeof; + result.nGlyphs = byteCount; + int lpOrder = result.lpOrder = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 4); + int lpClass = result.lpClass = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + + // set required dwFlags, these values will affect how the text gets rendered and + // ordered + int dwFlags = 0; + // Always reorder. We assume that if we are calling this function we're + // on a platform that supports bidi. Fixes 20690. + dwFlags |= GCP_REORDER; + if ((fontLanguageInfo & GCP_LIGATE) == GCP_LIGATE) { + dwFlags |= GCP_LIGATE; + } + if ((fontLanguageInfo & GCP_GLYPHSHAPE) == GCP_GLYPHSHAPE) { + dwFlags |= GCP_GLYPHSHAPE; + } + if ((flags & CLASSIN) == CLASSIN) { + // set classification values for the substring, classification values + // can be specified on input + dwFlags |= GCP_CLASSIN; + OS.MoveMemory(result.lpClass, classBuffer, classBuffer.length); + } + + int glyphCount = 0; + for (int i=0; i<offsets.length-1; i++) { + int offset = offsets [i]; + int length = offsets [i+1] - offsets [i]; + // The number of glyphs expected is <= length (segment length); + // the actual number returned may be less in case of Arabic ligatures. + result.nGlyphs = length; + TCHAR textBuffer2 = new TCHAR(lpCs[1], text.substring(offset, offset + length), false); + OS.GetCharacterPlacement(gc.handle, textBuffer2, textBuffer2.length(), 0, result, dwFlags); + + if (order != null) { + int [] order2 = new int [length]; + OS.MoveMemory(order2, result.lpOrder, order2.length * 4); + for (int j=0; j<length; j++) { + order2 [j] += glyphCount; + } + System.arraycopy (order2, 0, order, offset, length); + } + if (classBuffer != null) { + byte [] classBuffer2 = new byte [length]; + OS.MoveMemory(classBuffer2, result.lpClass, classBuffer2.length); + System.arraycopy (classBuffer2, 0, classBuffer, offset, length); + } + glyphCount += result.nGlyphs; + + // We concatenate successive results of calls to GCP. + // For Arabic, it is the only good method since the number of output + // glyphs might be less than the number of input characters. + // This assumes that the whole line is built by successive adjacent + // segments without overlapping. + result.lpOrder += length * 4; + result.lpClass += length; + } + + /* Free the memory that was allocated. */ + OS.HeapFree(hHeap, 0, lpClass); + OS.HeapFree(hHeap, 0, lpOrder); +} +/** + * Return bidi attribute information for the font in the specified gc. + * <p> + * + * @param gc the gc to query + * @return bitwise OR of the REORDER, LIGATE and GLYPHSHAPE flags + * defined by this class. + */ +public static int getFontBidiAttributes(GC gc) { + int fontStyle = 0; + int fontLanguageInfo = OS.GetFontLanguageInfo(gc.handle); + if (((fontLanguageInfo & GCP_REORDER) != 0)) { + fontStyle |= REORDER; + } + if (((fontLanguageInfo & GCP_LIGATE) != 0)) { + fontStyle |= LIGATE; + } + if (((fontLanguageInfo & GCP_GLYPHSHAPE) != 0)) { + fontStyle |= GLYPHSHAPE; + } + return fontStyle; +} +/** + * Return the active keyboard language type. + * <p> + * + * @return an integer representing the active keyboard language (KEYBOARD_BIDI, + * KEYBOARD_NON_BIDI) + */ +public static int getKeyboardLanguage() { + int layout = OS.GetKeyboardLayout(0); + // only interested in low 2 bytes, which is the primary + // language identifier + layout = layout & 0x000000FF; + if (layout == LANG_HEBREW) return KEYBOARD_BIDI; + if (layout == LANG_ARABIC) return KEYBOARD_BIDI; + // return non-bidi for all other languages + return KEYBOARD_NON_BIDI; +} +/** + * Return the languages that are installed for the keyboard. + * <p> + * + * @return integer array with an entry for each installed language + */ +public static int[] getKeyboardLanguageList() { + int maxSize = 10; + int[] tempList = new int[maxSize]; + int size = OS.GetKeyboardLayoutList(maxSize, tempList); + int[] list = new int[size]; + System.arraycopy(tempList, 0, list, 0, size); + return list; +} +/** + * Return whether or not the platform supports a bidi language. Determine this + * by looking at the languages that are installed. + * <p> + * + * @return true if bidi is supported, false otherwise. Always + * false on Windows CE. + */ +public static boolean isBidiPlatform() { + if (OS.IsWinCE) return false; + if (isBidiPlatform != -1) return isBidiPlatform == 1; // already set + + isBidiPlatform = 0; + + // The following test is a workaround for bug report 27629. On WinXP, + // both bidi and complex script (e.g., Thai) languages must be installed + // at the same time. Since the bidi platform calls do not support + // double byte characters, there is no way to run Eclipse using the + // complex script languages on XP, so constrain this test to answer true + // only if a bidi input language is defined. Doing so will allow complex + // script languages to work (e.g., one can install bidi and complex script + // languages, but only install the Thai keyboard). + if (!isKeyboardBidi()) return false; + + Callback callback = null; + try { + callback = new Callback (Class.forName (CLASS_NAME), "EnumSystemLanguageGroupsProc", 5); + int lpEnumSystemLanguageGroupsProc = callback.getAddress (); + if (lpEnumSystemLanguageGroupsProc == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); + OS.EnumSystemLanguageGroups(lpEnumSystemLanguageGroupsProc, OS.LGRPID_INSTALLED, 0); + callback.dispose (); + } catch (ClassNotFoundException e) { + if (callback != null) callback.dispose(); + } + if (isBidiPlatform == 1) return true; + // need to look at system code page for NT & 98 platforms since EnumSystemLanguageGroups is + // not supported for these platforms + String codePage = String.valueOf(OS.GetACP()); + if (CD_PG_ARABIC.equals(codePage) || CD_PG_HEBREW.equals(codePage)) { + isBidiPlatform = 1; + } + return isBidiPlatform == 1; +} +/** + * Return whether or not the keyboard supports input of a bidi language. Determine this + * by looking at the languages that are installed for the keyboard. + * <p> + * + * @return true if bidi is supported, false otherwise. + */ +public static boolean isKeyboardBidi() { + int[] list = getKeyboardLanguageList(); + for (int i=0; i<list.length; i++) { + int id = list[i] & 0x000000FF; + if ((id == LANG_ARABIC) || (id == LANG_HEBREW)) { + return true; + } + } + return false; +} +/** + * Removes the specified language listener. + * <p> + * + * @param hwnd the handle of the Control that is listening for keyboard language changes + */ +public static void removeLanguageListener (int hwnd) { + map.remove (new Integer (hwnd)); + Integer proc = (Integer)oldProcMap.remove (new Integer (hwnd)); + if (proc == null) return; + OS.SetWindowLong (hwnd, OS.GWL_WNDPROC, proc.intValue()); +} +/** + * Switch the keyboard language to the specified language type. We do + * not distinguish between mulitple bidi or multiple non-bidi languages, so + * set the keyboard to the first language of the given type. + * <p> + * + * @param language integer representing language. One of + * KEYBOARD_BIDI, KEYBOARD_NON_BIDI. + */ +public static void setKeyboardLanguage(int language) { + // don't switch the keyboard if it doesn't need to be + if (language == getKeyboardLanguage()) return; + + if (language == KEYBOARD_BIDI) { + // get the list of active languages + int[] list = getKeyboardLanguageList(); + // set to first bidi language + for (int i=0; i<list.length; i++) { + int id = list[i] & 0x000000FF; + if ((id == LANG_ARABIC) || (id == LANG_HEBREW)) { + OS.ActivateKeyboardLayout(list[i], 0); + return; + } + } + } else { + // get the list of active languages + int[] list = getKeyboardLanguageList(); + // set to the first non-bidi language (anything not + // hebrew or arabic) + for (int i=0; i<list.length; i++) { + int id = list[i] & 0x000000FF; + if ((id != LANG_HEBREW) && (id != LANG_ARABIC)) { + OS.ActivateKeyboardLayout(list[i], 0); + return; + } + } + } + +} +/** + * Window proc to intercept keyboard language switch event (WS_INPUTLANGCHANGE). + * Run the Control's registered runnable when the keyboard language is switched. + * + * @param hwnd handle of the control that is listening for the keyboard language + * change event + * @param msg window message + */ +static int windowProc (int hwnd, int msg, int wParam, int lParam) { + switch (msg) { + case 0x51 /*OS.WM_INPUTLANGCHANGE*/: + Runnable runnable = (Runnable) map.get (new Integer (hwnd)); + if (runnable != null) runnable.run (); + break; + } + Integer oldProc = (Integer)oldProcMap.get(new Integer(hwnd)); + return OS.CallWindowProc (oldProc.intValue(), hwnd, msg, wParam, lParam); +} + }
\ No newline at end of file diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/Converter.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/Converter.java index 1a5c388a2b..7699a2a0b0 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/Converter.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/Converter.java @@ -1,186 +1,186 @@ -package org.eclipse.swt.internal;
-
-/*
+package org.eclipse.swt.internal; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-
-/**
- * This class implements the conversions between unicode characters
- * and the <em>platform supported</em> representation for characters.
- * <p>
- * Note that, unicode characters which can not be found in the platform
- * encoding will be converted to an arbitrary platform specific character.
- * </p>
- *
- * @deprecated
- */
-
-public final class Converter {
-
- static final byte [] NULL_BYTE_ARRAY = new byte [1];
- static final byte [] EMPTY_BYTE_ARRAY = new byte [0];
- static final char [] EMPTY_CHAR_ARRAY = new char [0];
-
- static int CodePage;
- static {
- CodePage = OS.GetACP ();
- }
-
-/**
- * Returns the default code page for the platform where the
- * application is currently running.
- *
- * @return the default code page
- */
-public static int defaultCodePage () {
- return CodePage;
-}
-
-/**
- * Converts an array of bytes representing the platform's encoding,
- * in the given code page, of some character data into an array of
- * matching unicode characters.
- *
- * @param codePage the code page to use for conversion
- * @param buffer the array of bytes to be converted
- * @return the unicode conversion
- */
-public static char [] mbcsToWcs (int codePage, byte [] buffer) {
-
- /* Check for the simple cases */
- if (codePage < 0 || buffer == null) {
- return EMPTY_CHAR_ARRAY;
- }
- int length = buffer.length;
- if (length == 0) {
- return EMPTY_CHAR_ARRAY;
- }
-
- /*
- * Optimize for English ASCII encoding. If no conversion is
- * performed, it is safe to return any object that will also not
- * be converted if this routine is called again with the result.
- * This ensures that double conversion will not be performed
- * on the same bytes. Note that this relies on the fact that
- * lead bytes are never in the range 0..0x7F.
- */
- char [] lpWideCharStr = new char [length];
- for (int i=0; i<length; i++) {
- if ((buffer [i] & 0xFF) <= 0x7F) {
- lpWideCharStr [i] = (char) buffer [i]; // all bytes <= 0x7F, so no ((char) (buffer[i]&0xFF)) needed
- } else {
- /* Convert from DBCS to UNICODE */
- int cp = codePage != 0 ? codePage : CodePage;
- int cchWideChar = OS.MultiByteToWideChar (cp, OS.MB_PRECOMPOSED, buffer, length, null, 0);
- if (cchWideChar == 0) return EMPTY_CHAR_ARRAY;
- lpWideCharStr = new char [cchWideChar];
- OS.MultiByteToWideChar (cp, OS.MB_PRECOMPOSED, buffer, length, lpWideCharStr, cchWideChar);
- return lpWideCharStr;
- }
- }
- return lpWideCharStr;
-}
-
-/**
- * Converts an array of chars (containing unicode data) to an array
- * of bytes representing the platform's encoding, of those characters
- * in the given code page.
- *
- * @param codePage the code page to use for conversion
- * @param buffer the array of chars to be converted
- * @return the platform encoding
- */
-public static byte [] wcsToMbcs (int codePage, char [] buffer) {
- return wcsToMbcs (0, buffer, false);
-}
-
-/**
- * Converts an array of chars (containing unicode data) to an array
- * of bytes representing the platform's encoding, of those characters
- * in the given code page. If the termination flag is true, the resulting
- * byte data will be null (zero) terminated.
- *
- * @param codePage the code page to use for conversion
- * @param buffer the array of chars to be converted
- * @param terminate <code>true</code> if the result should be null terminated and false otherwise.
- * @return the platform encoding
- */
-public static byte [] wcsToMbcs (int codePage, char [] buffer, boolean terminate) {
-
- /* Check for the simple cases */
- if (codePage < 0 || buffer == null) {
- return (terminate) ? NULL_BYTE_ARRAY : EMPTY_BYTE_ARRAY;
- }
- int length = buffer.length;
- if (length == 0) {
- return (terminate) ? NULL_BYTE_ARRAY : EMPTY_BYTE_ARRAY;
- }
-
- /*
- * Optimize for English ASCII encoding. This optimization
- * relies on the fact that lead bytes can never be in the
- * range 0..0x7F.
- */
- byte [] mbcs = new byte [(terminate) ? length + 1 : length];
- for (int i=0; i<length; i++) {
- if ((buffer [i] & 0xFFFF) <= 0x7F) {
- mbcs [i] = (byte) buffer [i];
- } else {
- /* Convert from UNICODE to DBCS */
- int cp = codePage != 0 ? codePage : CodePage;
- int cchMultiByte = OS.WideCharToMultiByte (cp, 0, buffer, length, null, 0, null, null);
- if (cchMultiByte == 0) return (terminate) ? NULL_BYTE_ARRAY : EMPTY_BYTE_ARRAY;
- byte [] lpMultiByteStr = new byte [(terminate) ? cchMultiByte + 1 : cchMultiByte];
- OS.WideCharToMultiByte (cp, 0, buffer, length, lpMultiByteStr, cchMultiByte, null, null);
- return lpMultiByteStr;
- }
- }
- return mbcs;
-}
-
-/**
- * Converts a String (containing unicode data) to an array
- * of bytes representing the platform's encoding, of those characters
- * in the given code page.
- *
- * @param codePage the code page to use for conversion
- * @param string the string to be converted
- * @return the platform encoding
- */
-public static byte [] wcsToMbcs (int codePage, String string) {
- return wcsToMbcs (0, string, false);
-}
-
-/**
- * Converts a String (containing unicode data) to an array
- * of bytes representing the platform's encoding, of those characters
- * in the given code page. If the termination flag is true, the resulting
- * byte data will be null (zero) terminated.
- *
- * @param codePage the code page to use for conversion
- * @param string the string to be converted
- * @param terminate <code>true</code> if the result should be null terminated and false otherwise.
- * @return the platform encoding
- */
-public static byte [] wcsToMbcs (int codePage, String string, boolean terminate) {
- if (terminate) {
- if (string == null) return NULL_BYTE_ARRAY;
- int count = string.length ();
- char [] buffer = new char [count + 1];
- string.getChars (0, count, buffer, 0);
- return wcsToMbcs (codePage, buffer, false);
- } else {
- if (string == null) return EMPTY_BYTE_ARRAY;
- int count = string.length ();
- char [] buffer = new char [count];
- string.getChars (0, count, buffer, 0);
- return wcsToMbcs (codePage, buffer, false);
- }
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; + +/** + * This class implements the conversions between unicode characters + * and the <em>platform supported</em> representation for characters. + * <p> + * Note that, unicode characters which can not be found in the platform + * encoding will be converted to an arbitrary platform specific character. + * </p> + * + * @deprecated + */ + +public final class Converter { + + static final byte [] NULL_BYTE_ARRAY = new byte [1]; + static final byte [] EMPTY_BYTE_ARRAY = new byte [0]; + static final char [] EMPTY_CHAR_ARRAY = new char [0]; + + static int CodePage; + static { + CodePage = OS.GetACP (); + } + +/** + * Returns the default code page for the platform where the + * application is currently running. + * + * @return the default code page + */ +public static int defaultCodePage () { + return CodePage; +} + +/** + * Converts an array of bytes representing the platform's encoding, + * in the given code page, of some character data into an array of + * matching unicode characters. + * + * @param codePage the code page to use for conversion + * @param buffer the array of bytes to be converted + * @return the unicode conversion + */ +public static char [] mbcsToWcs (int codePage, byte [] buffer) { + + /* Check for the simple cases */ + if (codePage < 0 || buffer == null) { + return EMPTY_CHAR_ARRAY; + } + int length = buffer.length; + if (length == 0) { + return EMPTY_CHAR_ARRAY; + } + + /* + * Optimize for English ASCII encoding. If no conversion is + * performed, it is safe to return any object that will also not + * be converted if this routine is called again with the result. + * This ensures that double conversion will not be performed + * on the same bytes. Note that this relies on the fact that + * lead bytes are never in the range 0..0x7F. + */ + char [] lpWideCharStr = new char [length]; + for (int i=0; i<length; i++) { + if ((buffer [i] & 0xFF) <= 0x7F) { + lpWideCharStr [i] = (char) buffer [i]; // all bytes <= 0x7F, so no ((char) (buffer[i]&0xFF)) needed + } else { + /* Convert from DBCS to UNICODE */ + int cp = codePage != 0 ? codePage : CodePage; + int cchWideChar = OS.MultiByteToWideChar (cp, OS.MB_PRECOMPOSED, buffer, length, null, 0); + if (cchWideChar == 0) return EMPTY_CHAR_ARRAY; + lpWideCharStr = new char [cchWideChar]; + OS.MultiByteToWideChar (cp, OS.MB_PRECOMPOSED, buffer, length, lpWideCharStr, cchWideChar); + return lpWideCharStr; + } + } + return lpWideCharStr; +} + +/** + * Converts an array of chars (containing unicode data) to an array + * of bytes representing the platform's encoding, of those characters + * in the given code page. + * + * @param codePage the code page to use for conversion + * @param buffer the array of chars to be converted + * @return the platform encoding + */ +public static byte [] wcsToMbcs (int codePage, char [] buffer) { + return wcsToMbcs (0, buffer, false); +} + +/** + * Converts an array of chars (containing unicode data) to an array + * of bytes representing the platform's encoding, of those characters + * in the given code page. If the termination flag is true, the resulting + * byte data will be null (zero) terminated. + * + * @param codePage the code page to use for conversion + * @param buffer the array of chars to be converted + * @param terminate <code>true</code> if the result should be null terminated and false otherwise. + * @return the platform encoding + */ +public static byte [] wcsToMbcs (int codePage, char [] buffer, boolean terminate) { + + /* Check for the simple cases */ + if (codePage < 0 || buffer == null) { + return (terminate) ? NULL_BYTE_ARRAY : EMPTY_BYTE_ARRAY; + } + int length = buffer.length; + if (length == 0) { + return (terminate) ? NULL_BYTE_ARRAY : EMPTY_BYTE_ARRAY; + } + + /* + * Optimize for English ASCII encoding. This optimization + * relies on the fact that lead bytes can never be in the + * range 0..0x7F. + */ + byte [] mbcs = new byte [(terminate) ? length + 1 : length]; + for (int i=0; i<length; i++) { + if ((buffer [i] & 0xFFFF) <= 0x7F) { + mbcs [i] = (byte) buffer [i]; + } else { + /* Convert from UNICODE to DBCS */ + int cp = codePage != 0 ? codePage : CodePage; + int cchMultiByte = OS.WideCharToMultiByte (cp, 0, buffer, length, null, 0, null, null); + if (cchMultiByte == 0) return (terminate) ? NULL_BYTE_ARRAY : EMPTY_BYTE_ARRAY; + byte [] lpMultiByteStr = new byte [(terminate) ? cchMultiByte + 1 : cchMultiByte]; + OS.WideCharToMultiByte (cp, 0, buffer, length, lpMultiByteStr, cchMultiByte, null, null); + return lpMultiByteStr; + } + } + return mbcs; +} + +/** + * Converts a String (containing unicode data) to an array + * of bytes representing the platform's encoding, of those characters + * in the given code page. + * + * @param codePage the code page to use for conversion + * @param string the string to be converted + * @return the platform encoding + */ +public static byte [] wcsToMbcs (int codePage, String string) { + return wcsToMbcs (0, string, false); +} + +/** + * Converts a String (containing unicode data) to an array + * of bytes representing the platform's encoding, of those characters + * in the given code page. If the termination flag is true, the resulting + * byte data will be null (zero) terminated. + * + * @param codePage the code page to use for conversion + * @param string the string to be converted + * @param terminate <code>true</code> if the result should be null terminated and false otherwise. + * @return the platform encoding + */ +public static byte [] wcsToMbcs (int codePage, String string, boolean terminate) { + if (terminate) { + if (string == null) return NULL_BYTE_ARRAY; + int count = string.length (); + char [] buffer = new char [count + 1]; + string.getChars (0, count, buffer, 0); + return wcsToMbcs (codePage, buffer, false); + } else { + if (string == null) return EMPTY_BYTE_ARRAY; + int count = string.length (); + char [] buffer = new char [count]; + string.getChars (0, count, buffer, 0); + return wcsToMbcs (codePage, buffer, false); + } +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Button.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Button.java index f3038052a8..f2a42c585e 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Button.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Button.java @@ -1,712 +1,712 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-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>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>
- */
-
-public class Button extends Control {
- Image image;
- static final int ButtonProc;
- static final TCHAR ButtonClass = new TCHAR (0,"BUTTON", true);
- static final int CheckWidth, CheckHeight;
- static {
- int hBitmap = OS.LoadBitmap (0, OS.OBM_CHECKBOXES);
- if (hBitmap == 0) {
- CheckWidth = OS.GetSystemMetrics (OS.IsWinCE ? OS.SM_CXSMICON : OS.SM_CXVSCROLL);
- CheckHeight = OS.GetSystemMetrics (OS.IsWinCE ? OS.SM_CYSMICON : OS.SM_CYVSCROLL);
- } else {
- BITMAP bitmap = new BITMAP ();
- OS.GetObject (hBitmap, BITMAP.sizeof, bitmap);
- OS.DeleteObject (hBitmap);
- CheckWidth = bitmap.bmWidth / 4;
- CheckHeight = bitmap.bmHeight / 3;
- }
- WNDCLASS lpWndClass = new WNDCLASS ();
- OS.GetClassInfo (0, ButtonClass, lpWndClass);
- ButtonProc = lpWndClass.lpfnWndProc;
- }
-
-/**
- * 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#LEFT
- * @see SWT#RIGHT
- * @see SWT#CENTER
- * @see Widget#checkSubclass
- * @see Widget#getStyle
- */
-public Button (Composite parent, int style) {
- super (parent, checkStyle (style));
-}
-
-/**
- * Adds the listener to the collection of listeners who will
- * be notified when the control is selected, 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.
- * <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);
-}
-
-int callWindowProc (int msg, int wParam, int lParam) {
- if (handle == 0) return 0;
- return OS.CallWindowProc (ButtonProc, handle, msg, wParam, lParam);
-}
-
-static int checkStyle (int style) {
- style = checkBits (style, SWT.PUSH, SWT.ARROW, SWT.CHECK, SWT.RADIO, SWT.TOGGLE, 0);
- if ((style & SWT.PUSH) != 0) {
- return checkBits (style, SWT.CENTER, SWT.LEFT, SWT.RIGHT, 0, 0, 0);
- }
- if ((style & (SWT.CHECK | SWT.RADIO | SWT.TOGGLE)) != 0) {
- return checkBits (style, SWT.LEFT, SWT.RIGHT, SWT.CENTER, 0, 0, 0);
- }
- if ((style & SWT.ARROW) != 0) {
- return checkBits (style, SWT.UP, SWT.DOWN, SWT.LEFT, SWT.RIGHT, 0, 0);
- }
- return style;
-}
-
-void click () {
- /*
- * Note: BM_CLICK sends WM_LBUTTONDOWN and WM_LBUTTONUP.
- */
- OS.SendMessage (handle, OS.BM_CLICK, 0, 0);
-}
-
-public Point computeSize (int wHint, int hHint, boolean changed) {
- checkWidget ();
- int border = getBorderWidth ();
- int width = border * 2, height = border * 2;
- if ((style & SWT.ARROW) != 0) {
- if ((style & (SWT.UP | SWT.DOWN)) != 0) {
- width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
- height += OS.GetSystemMetrics (OS.SM_CYVSCROLL);
- } else {
- width += OS.GetSystemMetrics (OS.SM_CXHSCROLL);
- height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
- }
- if (wHint != SWT.DEFAULT) width = wHint + (border * 2);
- if (hHint != SWT.DEFAULT) height = hHint + (border * 2);
- return new Point (width, height);
- }
- int extra = 0;
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & (OS.BS_BITMAP | OS.BS_ICON)) == 0) {
- int oldFont = 0;
- int hDC = OS.GetDC (handle);
- int newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
- TEXTMETRIC lptm = new TEXTMETRIC ();
- OS.GetTextMetrics (hDC, lptm);
- int length = OS.GetWindowTextLength (handle);
- if (length == 0) {
- height += lptm.tmHeight;
- } else {
- extra = Math.max (8, lptm.tmAveCharWidth);
- TCHAR buffer = new TCHAR (getCodePage (), length + 1);
- OS.GetWindowText (handle, buffer, length + 1);
- RECT rect = new RECT ();
- int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE;
- OS.DrawText (hDC, buffer, length, rect, flags);
- width += rect.right - rect.left;
- height += rect.bottom - rect.top;
- }
- if (newFont != 0) OS.SelectObject (hDC, oldFont);
- OS.ReleaseDC (handle, hDC);
- } else {
- if (image != null) {
- Rectangle rect = image.getBounds ();
- width = rect.width;
- height = rect.height;
- extra = 8;
- }
- }
- if ((style & (SWT.CHECK | SWT.RADIO)) != 0) {
- width += CheckWidth + extra;
- height = Math.max (height, CheckHeight + 3);
- }
- if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
- width += 12; height += 10;
- }
- if (wHint != SWT.DEFAULT) width = wHint + (border * 2);
- if (hHint != SWT.DEFAULT) height = hHint + (border * 2);
- return new Point (width, height);
-}
-
-int defaultBackground () {
- if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
- return OS.GetSysColor (OS.COLOR_BTNFACE);
- }
- return super.defaultBackground ();
-}
-
-int defaultForeground () {
- return OS.GetSysColor (OS.COLOR_BTNTEXT);
-}
-
-/**
- * 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;
-}
-
-boolean getDefault () {
- if ((style & SWT.PUSH) == 0) return false;
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- return (bits & OS.BS_DEFPUSHBUTTON) != 0;
-}
-
-/**
- * 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;
- int state = OS.SendMessage (handle, OS.BM_GETCHECK, 0, 0);
- return (state & OS.BST_CHECKED) != 0;
-}
-
-/**
- * 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 ();
- int length = OS.GetWindowTextLength (handle);
- if (length == 0) return "";
- TCHAR buffer = new TCHAR (getCodePage (), length + 1);
- OS.GetWindowText (handle, buffer, length + 1);
- return buffer.toString (0, length);
-}
-
-boolean isTabItem () {
- //TEMPORARY CODE
- //if ((style & SWT.PUSH) != 0) return true;
- return super.isTabItem ();
-}
-
-boolean mnemonicHit (char ch) {
- if (!setFocus ()) return false;
- /*
- * Feature in Windows. When a radio button gets focus,
- * it selects the button in WM_SETFOCUS. Therefore, it
- * is not necessary to click the button or send events
- * because this has already happened in WM_SETFOCUS.
- */
- if ((style & SWT.RADIO) == 0) click ();
- return true;
-}
-
-boolean mnemonicMatch (char key) {
- char mnemonic = findMnemonic (getText ());
- if (mnemonic == '\0') return false;
- return Character.toUpperCase (key) == Character.toUpperCase (mnemonic);
-}
-
-void releaseWidget () {
- super.releaseWidget ();
- image = null;
-}
-
-/**
- * Removes the listener from the collection of listeners who will
- * be notified when the control is selected.
- *
- * @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 #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);
-}
-
-/**
- * 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 ();
- 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);
- OS.InvalidateRect (handle, null, true);
- 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);
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- bits &= ~(OS.BS_LEFT | OS.BS_CENTER | OS.BS_RIGHT);
- if ((style & SWT.LEFT) != 0) bits |= OS.BS_LEFT;
- if ((style & SWT.CENTER) != 0) bits |= OS.BS_CENTER;
- if ((style & SWT.RIGHT) != 0) bits |= OS.BS_RIGHT;
- OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
- OS.InvalidateRect (handle, null, true);
-}
-
-void setDefault (boolean value) {
- if ((style & SWT.PUSH) == 0) return;
- int hwndShell = menuShell ().handle;
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if (value) {
- bits |= OS.BS_DEFPUSHBUTTON;
- OS.SendMessage (hwndShell, OS.DM_SETDEFID, handle, 0);
- } else {
- bits &= ~OS.BS_DEFPUSHBUTTON;
- OS.SendMessage (hwndShell, OS.DM_SETDEFID, 0, 0);
- }
- OS.SendMessage (handle, OS.BM_SETSTYLE, bits, 1);
-}
-
-public boolean setFocus () {
- checkWidget();
- if ((style & SWT.ARROW) != 0) return false;
- return super.setFocus ();
-}
-
-/**
- * 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 ();
- int hImage = 0, imageBits = 0, fImageType = 0;
- if (image != null) {
- if (image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
- hImage = image.handle;
- switch (image.type) {
- case SWT.BITMAP:
- imageBits = OS.BS_BITMAP;
- fImageType = OS.IMAGE_BITMAP;
- break;
- case SWT.ICON:
- imageBits = OS.BS_ICON;
- fImageType = OS.IMAGE_ICON;
- break;
- default:
- return;
- }
- }
- this.image = image;
- int newBits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- int oldBits = newBits;
- newBits &= ~(OS.BS_BITMAP | OS.BS_ICON);
- newBits |= imageBits;
- if (newBits != oldBits) {
- OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
- }
- OS.SendMessage (handle, OS.BM_SETIMAGE, fImageType, hImage);
-}
-
-boolean setRadioFocus () {
- if ((style & SWT.RADIO) == 0 || !getSelection ()) return false;
- return setFocus ();
-}
-
-boolean setRadioSelection (boolean value) {
- if ((style & SWT.RADIO) == 0) return false;
- if (getSelection () != value) {
- setSelection (value);
- postEvent (SWT.Selection);
- }
- return true;
-}
-
-boolean setSavedFocus () {
- /*
- * Feature in Windows. When a radio button gets focus,
- * it selects the button in WM_SETFOCUS. If the previous
- * saved focus widget was a radio button, allowing the shell
- * to automatically restore the focus to the previous radio
- * button will unexpectedly check that button. The fix is
- * to disallow focus to be restored to radio button that is
- * not selected.
- */
- if ((style & SWT.RADIO) != 0 && !getSelection ()) return false;
- return super.setSavedFocus ();
-}
-
-/**
- * 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;
- int flags = selected ? OS.BST_CHECKED : OS.BST_UNCHECKED;
-
- /*
- * Feature in Windows. When BM_SETCHECK is used
- * to set the checked state of a radio or check
- * button, it sets the WM_TABSTOP style. This
- * is undocumented and unwanted. The fix is
- * to save and restore the window style bits.
- */
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- OS.SendMessage (handle, OS.BM_SETCHECK, flags, 0);
- OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
-}
-
-/**
- * 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 '&' 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 '&' can be
- * escaped by doubling it in the string, causing a single
- *'&' 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 newBits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- int oldBits = newBits;
- newBits &= ~(OS.BS_BITMAP | OS.BS_ICON);
- if (newBits != oldBits) {
- OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
- }
- TCHAR buffer = new TCHAR (getCodePage (), string, true);
- OS.SetWindowText (handle, buffer);
-}
-
-int widgetStyle () {
- int bits = super.widgetStyle () | OS.BS_NOTIFY;
- if ((style & SWT.FLAT) != 0) bits |= OS.BS_FLAT;
- if ((style & SWT.ARROW) != 0) return bits | OS.BS_OWNERDRAW;
- if ((style & SWT.LEFT) != 0) bits |= OS.BS_LEFT;
- if ((style & SWT.CENTER) != 0) bits |= OS.BS_CENTER;
- if ((style & SWT.RIGHT) != 0) bits |= OS.BS_RIGHT;
- if ((style & SWT.PUSH) != 0) return bits | OS.BS_PUSHBUTTON | OS.WS_TABSTOP;
- if ((style & SWT.CHECK) != 0) return bits | OS.BS_CHECKBOX | OS.WS_TABSTOP;
- if ((style & SWT.RADIO) != 0) return bits | OS.BS_RADIOBUTTON;
- if ((style & SWT.TOGGLE) != 0) return bits | OS.BS_PUSHLIKE | OS.BS_CHECKBOX;
- return bits | OS.BS_PUSHBUTTON | OS.WS_TABSTOP;
-}
-
-TCHAR windowClass () {
- return ButtonClass;
-}
-
-int windowProc () {
- return ButtonProc;
-}
-
-LRESULT WM_GETDLGCODE (int wParam, int lParam) {
- LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
- if (result != null) return result;
- if ((style & SWT.ARROW) != 0) {
- return new LRESULT (OS.DLGC_STATIC);
- }
- return result;
-}
-
-LRESULT WM_KILLFOCUS (int wParam, int lParam) {
- LRESULT result = super.WM_KILLFOCUS (wParam, lParam);
- if ((style & SWT.PUSH) != 0 && getDefault ()) {
- menuShell ().setDefaultButton (null, false);
- }
- return result;
-}
-
-LRESULT WM_SETFOCUS (int wParam, int lParam) {
- /*
- * Feature in Windows. When Windows sets focus to
- * a radio button, it sets the WM_TABSTOP style.
- * This is undocumented and unwanted. The fix is
- * to save and restore the window style bits.
- */
- int bits = 0;
- if ((style & SWT.RADIO) != 0) {
- bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- }
- LRESULT result = super.WM_SETFOCUS (wParam, lParam);
- if ((style & SWT.RADIO) != 0) {
- OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
- }
- if ((style & SWT.PUSH) != 0) {
- menuShell ().setDefaultButton (this, false);
- }
- return result;
-}
-
-LRESULT wmCommandChild (int wParam, int lParam) {
- int code = wParam >> 16;
- switch (code) {
- case OS.BN_CLICKED:
- case OS.BN_DOUBLECLICKED:
- if ((style & (SWT.CHECK | SWT.TOGGLE)) != 0) {
- setSelection (!getSelection ());
- } else {
- if ((style & SWT.RADIO) != 0) {
- if ((parent.getStyle () & SWT.NO_RADIO_GROUP) != 0) {
- setSelection (!getSelection ());
- } else {
- selectRadio ();
- }
- }
- }
- postEvent (SWT.Selection);
- }
- return super.wmCommandChild (wParam, lParam);
-}
-
-LRESULT wmDrawChild (int wParam, int lParam) {
- if ((style & SWT.ARROW) == 0) return super.wmDrawChild (wParam, lParam);
- DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT ();
- OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof);
- int uState = OS.DFCS_SCROLLLEFT;
- switch (style & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT)) {
- case SWT.UP: uState = OS.DFCS_SCROLLUP; break;
- case SWT.DOWN: uState = OS.DFCS_SCROLLDOWN; break;
- case SWT.LEFT: uState = OS.DFCS_SCROLLLEFT; break;
- case SWT.RIGHT: uState = OS.DFCS_SCROLLRIGHT; break;
- }
- if (!getEnabled ()) uState |= OS.DFCS_INACTIVE;
- if ((style & SWT.FLAT) == SWT.FLAT) uState |= OS.DFCS_FLAT;
- if ((struct.itemState & OS.ODS_SELECTED) != 0) uState |= OS.DFCS_PUSHED;
- RECT rect = new RECT ();
- OS.SetRect (rect, struct.left, struct.top, struct.right, struct.bottom);
- OS.DrawFrameControl (struct.hDC, rect, OS.DFC_SCROLL, uState);
- return null;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +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>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> + */ + +public class Button extends Control { + Image image; + static final int ButtonProc; + static final TCHAR ButtonClass = new TCHAR (0,"BUTTON", true); + static final int CheckWidth, CheckHeight; + static { + int hBitmap = OS.LoadBitmap (0, OS.OBM_CHECKBOXES); + if (hBitmap == 0) { + CheckWidth = OS.GetSystemMetrics (OS.IsWinCE ? OS.SM_CXSMICON : OS.SM_CXVSCROLL); + CheckHeight = OS.GetSystemMetrics (OS.IsWinCE ? OS.SM_CYSMICON : OS.SM_CYVSCROLL); + } else { + BITMAP bitmap = new BITMAP (); + OS.GetObject (hBitmap, BITMAP.sizeof, bitmap); + OS.DeleteObject (hBitmap); + CheckWidth = bitmap.bmWidth / 4; + CheckHeight = bitmap.bmHeight / 3; + } + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, ButtonClass, lpWndClass); + ButtonProc = lpWndClass.lpfnWndProc; + } + +/** + * 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#LEFT + * @see SWT#RIGHT + * @see SWT#CENTER + * @see Widget#checkSubclass + * @see Widget#getStyle + */ +public Button (Composite parent, int style) { + super (parent, checkStyle (style)); +} + +/** + * Adds the listener to the collection of listeners who will + * be notified when the control is selected, 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. + * <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); +} + +int callWindowProc (int msg, int wParam, int lParam) { + if (handle == 0) return 0; + return OS.CallWindowProc (ButtonProc, handle, msg, wParam, lParam); +} + +static int checkStyle (int style) { + style = checkBits (style, SWT.PUSH, SWT.ARROW, SWT.CHECK, SWT.RADIO, SWT.TOGGLE, 0); + if ((style & SWT.PUSH) != 0) { + return checkBits (style, SWT.CENTER, SWT.LEFT, SWT.RIGHT, 0, 0, 0); + } + if ((style & (SWT.CHECK | SWT.RADIO | SWT.TOGGLE)) != 0) { + return checkBits (style, SWT.LEFT, SWT.RIGHT, SWT.CENTER, 0, 0, 0); + } + if ((style & SWT.ARROW) != 0) { + return checkBits (style, SWT.UP, SWT.DOWN, SWT.LEFT, SWT.RIGHT, 0, 0); + } + return style; +} + +void click () { + /* + * Note: BM_CLICK sends WM_LBUTTONDOWN and WM_LBUTTONUP. + */ + OS.SendMessage (handle, OS.BM_CLICK, 0, 0); +} + +public Point computeSize (int wHint, int hHint, boolean changed) { + checkWidget (); + int border = getBorderWidth (); + int width = border * 2, height = border * 2; + if ((style & SWT.ARROW) != 0) { + if ((style & (SWT.UP | SWT.DOWN)) != 0) { + width += OS.GetSystemMetrics (OS.SM_CXVSCROLL); + height += OS.GetSystemMetrics (OS.SM_CYVSCROLL); + } else { + width += OS.GetSystemMetrics (OS.SM_CXHSCROLL); + height += OS.GetSystemMetrics (OS.SM_CYHSCROLL); + } + if (wHint != SWT.DEFAULT) width = wHint + (border * 2); + if (hHint != SWT.DEFAULT) height = hHint + (border * 2); + return new Point (width, height); + } + int extra = 0; + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & (OS.BS_BITMAP | OS.BS_ICON)) == 0) { + int oldFont = 0; + int hDC = OS.GetDC (handle); + int newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); + TEXTMETRIC lptm = new TEXTMETRIC (); + OS.GetTextMetrics (hDC, lptm); + int length = OS.GetWindowTextLength (handle); + if (length == 0) { + height += lptm.tmHeight; + } else { + extra = Math.max (8, lptm.tmAveCharWidth); + TCHAR buffer = new TCHAR (getCodePage (), length + 1); + OS.GetWindowText (handle, buffer, length + 1); + RECT rect = new RECT (); + int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE; + OS.DrawText (hDC, buffer, length, rect, flags); + width += rect.right - rect.left; + height += rect.bottom - rect.top; + } + if (newFont != 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + } else { + if (image != null) { + Rectangle rect = image.getBounds (); + width = rect.width; + height = rect.height; + extra = 8; + } + } + if ((style & (SWT.CHECK | SWT.RADIO)) != 0) { + width += CheckWidth + extra; + height = Math.max (height, CheckHeight + 3); + } + if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) { + width += 12; height += 10; + } + if (wHint != SWT.DEFAULT) width = wHint + (border * 2); + if (hHint != SWT.DEFAULT) height = hHint + (border * 2); + return new Point (width, height); +} + +int defaultBackground () { + if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) { + return OS.GetSysColor (OS.COLOR_BTNFACE); + } + return super.defaultBackground (); +} + +int defaultForeground () { + return OS.GetSysColor (OS.COLOR_BTNTEXT); +} + +/** + * 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; +} + +boolean getDefault () { + if ((style & SWT.PUSH) == 0) return false; + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + return (bits & OS.BS_DEFPUSHBUTTON) != 0; +} + +/** + * 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; + int state = OS.SendMessage (handle, OS.BM_GETCHECK, 0, 0); + return (state & OS.BST_CHECKED) != 0; +} + +/** + * 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 (); + int length = OS.GetWindowTextLength (handle); + if (length == 0) return ""; + TCHAR buffer = new TCHAR (getCodePage (), length + 1); + OS.GetWindowText (handle, buffer, length + 1); + return buffer.toString (0, length); +} + +boolean isTabItem () { + //TEMPORARY CODE + //if ((style & SWT.PUSH) != 0) return true; + return super.isTabItem (); +} + +boolean mnemonicHit (char ch) { + if (!setFocus ()) return false; + /* + * Feature in Windows. When a radio button gets focus, + * it selects the button in WM_SETFOCUS. Therefore, it + * is not necessary to click the button or send events + * because this has already happened in WM_SETFOCUS. + */ + if ((style & SWT.RADIO) == 0) click (); + return true; +} + +boolean mnemonicMatch (char key) { + char mnemonic = findMnemonic (getText ()); + if (mnemonic == '\0') return false; + return Character.toUpperCase (key) == Character.toUpperCase (mnemonic); +} + +void releaseWidget () { + super.releaseWidget (); + image = null; +} + +/** + * Removes the listener from the collection of listeners who will + * be notified when the control is selected. + * + * @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 #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); +} + +/** + * 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 (); + 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); + OS.InvalidateRect (handle, null, true); + 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); + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + bits &= ~(OS.BS_LEFT | OS.BS_CENTER | OS.BS_RIGHT); + if ((style & SWT.LEFT) != 0) bits |= OS.BS_LEFT; + if ((style & SWT.CENTER) != 0) bits |= OS.BS_CENTER; + if ((style & SWT.RIGHT) != 0) bits |= OS.BS_RIGHT; + OS.SetWindowLong (handle, OS.GWL_STYLE, bits); + OS.InvalidateRect (handle, null, true); +} + +void setDefault (boolean value) { + if ((style & SWT.PUSH) == 0) return; + int hwndShell = menuShell ().handle; + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if (value) { + bits |= OS.BS_DEFPUSHBUTTON; + OS.SendMessage (hwndShell, OS.DM_SETDEFID, handle, 0); + } else { + bits &= ~OS.BS_DEFPUSHBUTTON; + OS.SendMessage (hwndShell, OS.DM_SETDEFID, 0, 0); + } + OS.SendMessage (handle, OS.BM_SETSTYLE, bits, 1); +} + +public boolean setFocus () { + checkWidget(); + if ((style & SWT.ARROW) != 0) return false; + return super.setFocus (); +} + +/** + * 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 (); + int hImage = 0, imageBits = 0, fImageType = 0; + if (image != null) { + if (image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); + hImage = image.handle; + switch (image.type) { + case SWT.BITMAP: + imageBits = OS.BS_BITMAP; + fImageType = OS.IMAGE_BITMAP; + break; + case SWT.ICON: + imageBits = OS.BS_ICON; + fImageType = OS.IMAGE_ICON; + break; + default: + return; + } + } + this.image = image; + int newBits = OS.GetWindowLong (handle, OS.GWL_STYLE); + int oldBits = newBits; + newBits &= ~(OS.BS_BITMAP | OS.BS_ICON); + newBits |= imageBits; + if (newBits != oldBits) { + OS.SetWindowLong (handle, OS.GWL_STYLE, newBits); + } + OS.SendMessage (handle, OS.BM_SETIMAGE, fImageType, hImage); +} + +boolean setRadioFocus () { + if ((style & SWT.RADIO) == 0 || !getSelection ()) return false; + return setFocus (); +} + +boolean setRadioSelection (boolean value) { + if ((style & SWT.RADIO) == 0) return false; + if (getSelection () != value) { + setSelection (value); + postEvent (SWT.Selection); + } + return true; +} + +boolean setSavedFocus () { + /* + * Feature in Windows. When a radio button gets focus, + * it selects the button in WM_SETFOCUS. If the previous + * saved focus widget was a radio button, allowing the shell + * to automatically restore the focus to the previous radio + * button will unexpectedly check that button. The fix is + * to disallow focus to be restored to radio button that is + * not selected. + */ + if ((style & SWT.RADIO) != 0 && !getSelection ()) return false; + return super.setSavedFocus (); +} + +/** + * 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; + int flags = selected ? OS.BST_CHECKED : OS.BST_UNCHECKED; + + /* + * Feature in Windows. When BM_SETCHECK is used + * to set the checked state of a radio or check + * button, it sets the WM_TABSTOP style. This + * is undocumented and unwanted. The fix is + * to save and restore the window style bits. + */ + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + OS.SendMessage (handle, OS.BM_SETCHECK, flags, 0); + OS.SetWindowLong (handle, OS.GWL_STYLE, bits); +} + +/** + * 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 '&' 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 '&' can be + * escaped by doubling it in the string, causing a single + *'&' 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 newBits = OS.GetWindowLong (handle, OS.GWL_STYLE); + int oldBits = newBits; + newBits &= ~(OS.BS_BITMAP | OS.BS_ICON); + if (newBits != oldBits) { + OS.SetWindowLong (handle, OS.GWL_STYLE, newBits); + } + TCHAR buffer = new TCHAR (getCodePage (), string, true); + OS.SetWindowText (handle, buffer); +} + +int widgetStyle () { + int bits = super.widgetStyle () | OS.BS_NOTIFY; + if ((style & SWT.FLAT) != 0) bits |= OS.BS_FLAT; + if ((style & SWT.ARROW) != 0) return bits | OS.BS_OWNERDRAW; + if ((style & SWT.LEFT) != 0) bits |= OS.BS_LEFT; + if ((style & SWT.CENTER) != 0) bits |= OS.BS_CENTER; + if ((style & SWT.RIGHT) != 0) bits |= OS.BS_RIGHT; + if ((style & SWT.PUSH) != 0) return bits | OS.BS_PUSHBUTTON | OS.WS_TABSTOP; + if ((style & SWT.CHECK) != 0) return bits | OS.BS_CHECKBOX | OS.WS_TABSTOP; + if ((style & SWT.RADIO) != 0) return bits | OS.BS_RADIOBUTTON; + if ((style & SWT.TOGGLE) != 0) return bits | OS.BS_PUSHLIKE | OS.BS_CHECKBOX; + return bits | OS.BS_PUSHBUTTON | OS.WS_TABSTOP; +} + +TCHAR windowClass () { + return ButtonClass; +} + +int windowProc () { + return ButtonProc; +} + +LRESULT WM_GETDLGCODE (int wParam, int lParam) { + LRESULT result = super.WM_GETDLGCODE (wParam, lParam); + if (result != null) return result; + if ((style & SWT.ARROW) != 0) { + return new LRESULT (OS.DLGC_STATIC); + } + return result; +} + +LRESULT WM_KILLFOCUS (int wParam, int lParam) { + LRESULT result = super.WM_KILLFOCUS (wParam, lParam); + if ((style & SWT.PUSH) != 0 && getDefault ()) { + menuShell ().setDefaultButton (null, false); + } + return result; +} + +LRESULT WM_SETFOCUS (int wParam, int lParam) { + /* + * Feature in Windows. When Windows sets focus to + * a radio button, it sets the WM_TABSTOP style. + * This is undocumented and unwanted. The fix is + * to save and restore the window style bits. + */ + int bits = 0; + if ((style & SWT.RADIO) != 0) { + bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + } + LRESULT result = super.WM_SETFOCUS (wParam, lParam); + if ((style & SWT.RADIO) != 0) { + OS.SetWindowLong (handle, OS.GWL_STYLE, bits); + } + if ((style & SWT.PUSH) != 0) { + menuShell ().setDefaultButton (this, false); + } + return result; +} + +LRESULT wmCommandChild (int wParam, int lParam) { + int code = wParam >> 16; + switch (code) { + case OS.BN_CLICKED: + case OS.BN_DOUBLECLICKED: + if ((style & (SWT.CHECK | SWT.TOGGLE)) != 0) { + setSelection (!getSelection ()); + } else { + if ((style & SWT.RADIO) != 0) { + if ((parent.getStyle () & SWT.NO_RADIO_GROUP) != 0) { + setSelection (!getSelection ()); + } else { + selectRadio (); + } + } + } + postEvent (SWT.Selection); + } + return super.wmCommandChild (wParam, lParam); +} + +LRESULT wmDrawChild (int wParam, int lParam) { + if ((style & SWT.ARROW) == 0) return super.wmDrawChild (wParam, lParam); + DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT (); + OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof); + int uState = OS.DFCS_SCROLLLEFT; + switch (style & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT)) { + case SWT.UP: uState = OS.DFCS_SCROLLUP; break; + case SWT.DOWN: uState = OS.DFCS_SCROLLDOWN; break; + case SWT.LEFT: uState = OS.DFCS_SCROLLLEFT; break; + case SWT.RIGHT: uState = OS.DFCS_SCROLLRIGHT; break; + } + if (!getEnabled ()) uState |= OS.DFCS_INACTIVE; + if ((style & SWT.FLAT) == SWT.FLAT) uState |= OS.DFCS_FLAT; + if ((struct.itemState & OS.ODS_SELECTED) != 0) uState |= OS.DFCS_PUSHED; + RECT rect = new RECT (); + OS.SetRect (rect, struct.left, struct.top, struct.right, struct.bottom); + OS.DrawFrameControl (struct.hDC, rect, OS.DFC_SCROLL, uState); + return null; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Canvas.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Canvas.java index 8de1e053c6..cf1a9c1ac3 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Canvas.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Canvas.java @@ -1,216 +1,216 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-
-/**
- * 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
- */
-
-public class Canvas extends Composite {
- Caret caret;
-
-/**
- * Prevents uninitialized instances from being created outside the package.
- */
-Canvas () {
-}
-
-/**
- * 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 Canvas (Composite parent, int style) {
- super (parent, style);
-}
-
-/*
-* Not currently used.
-*/
-void clearArea (int x, int y, int width, int height) {
- checkWidget ();
- if (OS.IsWindowVisible (handle)) return;
- RECT rect = new RECT ();
- OS.SetRect (rect, x, y, x + width, y + height);
- int hDC = OS.GetDCEx (handle, 0, OS.DCX_CACHE | OS.DCX_CLIPCHILDREN | OS.DCX_CLIPSIBLINGS);
- drawBackground (hDC, rect);
- OS.ReleaseDC (handle, hDC);
-}
-
-/**
- * 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
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if 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;
-}
-
-void releaseWidget () {
- if (caret != null) caret.releaseResources ();
- caret = null;
- super.releaseWidget ();
-}
-
-/**
- * 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 ();
-
- /* Remove the caret so it won't get scrolled */
- boolean isFocus = caret != null && caret.isFocusCaret ();
- if (isFocus) caret.killFocus ();
-
- /* Flush outstanding WM_PAINT's and scroll the window */
- if (OS.IsWinCE) {
- OS.UpdateWindow (handle);
- } else {
- int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
- OS.RedrawWindow (handle, null, 0, flags);
- }
- RECT rect = new RECT ();
- OS.SetRect (rect, x, y, x + width, y + height);
- int deltaX = destX - x, deltaY = destY - y;
- int flags = OS.SW_INVALIDATE | OS.SW_ERASE;
- if (all) flags |= OS.SW_SCROLLCHILDREN;
- OS.ScrollWindowEx (handle, deltaX, deltaY, rect, null, 0, null, flags);
-
- /* Restore the caret */
- if (isFocus) caret.setFocus ();
-}
-
-/**
- * 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 (isFocusControl ()) {
- if (oldCaret != null) oldCaret.killFocus ();
- if (newCaret != null) {
- if (newCaret.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
- newCaret.setFocus ();
- }
- }
-}
-
-public void setFont (Font font) {
- checkWidget ();
- super.setFont (font);
- if (caret != null) caret.setFont (font);
-}
-
-LRESULT WM_KILLFOCUS (int wParam, int lParam) {
- LRESULT result = super.WM_KILLFOCUS (wParam, lParam);
- if (caret != null) caret.killFocus ();
- return result;
-}
-
-LRESULT WM_SETFOCUS (int wParam, int lParam) {
- LRESULT result = super.WM_SETFOCUS (wParam, lParam);
- if (caret != null) caret.setFocus ();
- return result;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; + +/** + * 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 + */ + +public class Canvas extends Composite { + Caret caret; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Canvas () { +} + +/** + * 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 Canvas (Composite parent, int style) { + super (parent, style); +} + +/* +* Not currently used. +*/ +void clearArea (int x, int y, int width, int height) { + checkWidget (); + if (OS.IsWindowVisible (handle)) return; + RECT rect = new RECT (); + OS.SetRect (rect, x, y, x + width, y + height); + int hDC = OS.GetDCEx (handle, 0, OS.DCX_CACHE | OS.DCX_CLIPCHILDREN | OS.DCX_CLIPSIBLINGS); + drawBackground (hDC, rect); + OS.ReleaseDC (handle, hDC); +} + +/** + * 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 + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if 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; +} + +void releaseWidget () { + if (caret != null) caret.releaseResources (); + caret = null; + super.releaseWidget (); +} + +/** + * 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 (); + + /* Remove the caret so it won't get scrolled */ + boolean isFocus = caret != null && caret.isFocusCaret (); + if (isFocus) caret.killFocus (); + + /* Flush outstanding WM_PAINT's and scroll the window */ + if (OS.IsWinCE) { + OS.UpdateWindow (handle); + } else { + int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN; + OS.RedrawWindow (handle, null, 0, flags); + } + RECT rect = new RECT (); + OS.SetRect (rect, x, y, x + width, y + height); + int deltaX = destX - x, deltaY = destY - y; + int flags = OS.SW_INVALIDATE | OS.SW_ERASE; + if (all) flags |= OS.SW_SCROLLCHILDREN; + OS.ScrollWindowEx (handle, deltaX, deltaY, rect, null, 0, null, flags); + + /* Restore the caret */ + if (isFocus) caret.setFocus (); +} + +/** + * 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 (isFocusControl ()) { + if (oldCaret != null) oldCaret.killFocus (); + if (newCaret != null) { + if (newCaret.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); + newCaret.setFocus (); + } + } +} + +public void setFont (Font font) { + checkWidget (); + super.setFont (font); + if (caret != null) caret.setFont (font); +} + +LRESULT WM_KILLFOCUS (int wParam, int lParam) { + LRESULT result = super.WM_KILLFOCUS (wParam, lParam); + if (caret != null) caret.killFocus (); + return result; +} + +LRESULT WM_SETFOCUS (int wParam, int lParam) { + LRESULT result = super.WM_SETFOCUS (wParam, lParam); + if (caret != null) caret.setFocus (); + return result; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Caret.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Caret.java index a10aee3686..3f979d3b10 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Caret.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Caret.java @@ -1,555 +1,555 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-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>
- */
-
-public class Caret extends Widget {
- Canvas parent;
- int x, y, width, height;
- boolean moved, resized;
- boolean isVisible;
- Image image;
- Font font;
- LOGFONT oldFont;
-
-/**
- * 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 ();
-}
-
-void createWidget () {
- isVisible = true;
- if (parent.getCaret () == null) {
- parent.setCaret (this);
- }
-}
-
-int defaultFont () {
- int hwnd = parent.handle;
- int hwndIME = OS.ImmGetDefaultIMEWnd (hwnd);
- if (hwndIME == 0) return parent.defaultFont ();
- int hFont = OS.SendMessage (hwndIME, OS.WM_GETFONT, 0, 0);
- if (hFont == 0) return parent.defaultFont ();
- return hFont;
-}
-
-/**
- * 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);
- }
- return new Rectangle (x, y, width, height);
-}
-
-public Display getDisplay () {
- Composite parent = this.parent;
- if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED);
- return parent.getDisplay ();
-}
-
-/**
- * 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) {
- int hFont = defaultFont ();
- return Font.win32_new (getDisplay (), hFont);
- }
- return font;
-}
-
-/**
- * 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);
- }
- 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 hasFocus () {
- return parent.handle == OS.GetFocus ();
-}
-
-boolean isFocusCaret () {
- return parent.caret == this && hasFocus ();
-}
-
-/**
- * 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 () && hasFocus ();
-}
-
-void killFocus () {
- OS.DestroyCaret ();
- if (font != null) restoreIMEFont ();
-}
-
-void move () {
- moved = false;
- if (!OS.SetCaretPos (x, y)) return;
- if (OS.IsDBLocale) {
- POINT ptCurrentPos = new POINT ();
- if (!OS.GetCaretPos (ptCurrentPos)) return;
- COMPOSITIONFORM lpCompForm = new COMPOSITIONFORM ();
- lpCompForm.dwStyle = OS.CFS_POINT;
- lpCompForm.x = ptCurrentPos.x;
- lpCompForm.y = ptCurrentPos.y;
- int hwnd = parent.handle;
- int hIMC = OS.ImmGetContext (hwnd);
- OS.ImmSetCompositionWindow (hIMC, lpCompForm);
- OS.ImmReleaseContext (hwnd, hIMC);
- }
-}
-
-void releaseChild () {
- super.releaseChild ();
- if (this == parent.getCaret ()) parent.setCaret (null);
-}
-
-void releaseWidget () {
- super.releaseWidget ();
- parent = null;
- image = null;
- font = null;
- oldFont = null;
-}
-
-void resize () {
- resized = false;
- int hwnd = parent.handle;
- OS.DestroyCaret ();
- int hBitmap = 0;
- if (image != null) hBitmap = image.handle;
- OS.CreateCaret (hwnd, hBitmap, width, height);
- OS.SetCaretPos (x, y);
- OS.ShowCaret (hwnd);
- move ();
-}
-
-void restoreIMEFont () {
- if (!OS.IsDBLocale) return;
- if (oldFont == null) return;
- int hwnd = parent.handle;
- int hIMC = OS.ImmGetContext (hwnd);
- OS.ImmSetCompositionFont (hIMC, oldFont);
- OS.ImmReleaseContext (hwnd, hIMC);
- oldFont = null;
-}
-
-void saveIMEFont () {
- if (!OS.IsDBLocale) return;
- if (oldFont != null) return;
- int hwnd = parent.handle;
- int hIMC = OS.ImmGetContext (hwnd);
- oldFont = new LOGFONT ();
- if (OS.ImmGetCompositionFont (hIMC, oldFont)) oldFont = null;
- OS.ImmReleaseContext (hwnd, hIMC);
-}
-
-/**
- * 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();
- boolean samePosition = this.x == x && this.y == y;
- boolean sameExtent = this.width == width && this.height == height;
- if (samePosition && sameExtent) return;
- this.x = x; this.y = y;
- this.width = width; this.height = height;
- if (sameExtent) {
- moved = true;
- if (isVisible && hasFocus ()) move ();
- } else {
- resized = true;
- if (isVisible && hasFocus ()) resize ();
- }
-}
-
-/**
- * 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) {
- if (rect == null) error (SWT.ERROR_NULL_ARGUMENT);
- setBounds (rect.x, rect.y, rect.width, rect.height);
-}
-
-void setFocus () {
- int hwnd = parent.handle;
- int hBitmap = 0;
- if (image != null) hBitmap = image.handle;
- OS.CreateCaret (hwnd, hBitmap, width, height);
- move ();
- if (font != null) {
- int hFont = font.handle;
- saveIMEFont ();
- setIMEFont (hFont);
- }
- if (isVisible) OS.ShowCaret (hwnd);
-}
-
-/**
- * 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;
- if (isVisible && hasFocus ()) {
- int hFont = 0;
- if (font != null) hFont = font.handle;
- if (hFont == 0) hFont = defaultFont ();
- saveIMEFont ();
- setIMEFont (hFont);
- }
-}
-
-/**
- * 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 font the new font (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 (isVisible && hasFocus ()) resize ();
-}
-
-void setIMEFont (int hFont) {
- if (!OS.IsDBLocale) return;
- LOGFONT logFont = new LOGFONT ();
- if (OS.GetObject (hFont, LOGFONT.sizeof, logFont) != 0) {
- int hwnd = parent.handle;
- int hIMC = OS.ImmGetContext (hwnd);
- OS.ImmSetCompositionFont (hIMC, logFont);
- OS.ImmReleaseContext (hwnd, hIMC);
- }
-}
-
-/**
- * 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();
- if (this.x == x && this.y == y) return;
- this.x = x; this.y = y;
- moved = true;
- if (isVisible && hasFocus ()) move ();
-}
-
-/**
- * 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();
- if (this.width == width && this.height == height) return;
- this.width = width; this.height = height;
- resized = true;
- if (isVisible && hasFocus ()) resize ();
-}
-
-/**
- * Sets the receiver's size to the point specified by the argument.
- *
- * @param size the new extent for the receiver
- * @param height the new height 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;
- int hwnd = parent.handle;
- if (OS.GetFocus () != hwnd) return;
- if (!isVisible) {
- OS.HideCaret (hwnd);
- } else {
- if (resized) {
- resize ();
- } else {
- if (moved) move ();
- }
- OS.ShowCaret (hwnd);
- }
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +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> + */ + +public class Caret extends Widget { + Canvas parent; + int x, y, width, height; + boolean moved, resized; + boolean isVisible; + Image image; + Font font; + LOGFONT oldFont; + +/** + * 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 (); +} + +void createWidget () { + isVisible = true; + if (parent.getCaret () == null) { + parent.setCaret (this); + } +} + +int defaultFont () { + int hwnd = parent.handle; + int hwndIME = OS.ImmGetDefaultIMEWnd (hwnd); + if (hwndIME == 0) return parent.defaultFont (); + int hFont = OS.SendMessage (hwndIME, OS.WM_GETFONT, 0, 0); + if (hFont == 0) return parent.defaultFont (); + return hFont; +} + +/** + * 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); + } + return new Rectangle (x, y, width, height); +} + +public Display getDisplay () { + Composite parent = this.parent; + if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED); + return parent.getDisplay (); +} + +/** + * 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) { + int hFont = defaultFont (); + return Font.win32_new (getDisplay (), hFont); + } + return font; +} + +/** + * 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); + } + 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 hasFocus () { + return parent.handle == OS.GetFocus (); +} + +boolean isFocusCaret () { + return parent.caret == this && hasFocus (); +} + +/** + * 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 () && hasFocus (); +} + +void killFocus () { + OS.DestroyCaret (); + if (font != null) restoreIMEFont (); +} + +void move () { + moved = false; + if (!OS.SetCaretPos (x, y)) return; + if (OS.IsDBLocale) { + POINT ptCurrentPos = new POINT (); + if (!OS.GetCaretPos (ptCurrentPos)) return; + COMPOSITIONFORM lpCompForm = new COMPOSITIONFORM (); + lpCompForm.dwStyle = OS.CFS_POINT; + lpCompForm.x = ptCurrentPos.x; + lpCompForm.y = ptCurrentPos.y; + int hwnd = parent.handle; + int hIMC = OS.ImmGetContext (hwnd); + OS.ImmSetCompositionWindow (hIMC, lpCompForm); + OS.ImmReleaseContext (hwnd, hIMC); + } +} + +void releaseChild () { + super.releaseChild (); + if (this == parent.getCaret ()) parent.setCaret (null); +} + +void releaseWidget () { + super.releaseWidget (); + parent = null; + image = null; + font = null; + oldFont = null; +} + +void resize () { + resized = false; + int hwnd = parent.handle; + OS.DestroyCaret (); + int hBitmap = 0; + if (image != null) hBitmap = image.handle; + OS.CreateCaret (hwnd, hBitmap, width, height); + OS.SetCaretPos (x, y); + OS.ShowCaret (hwnd); + move (); +} + +void restoreIMEFont () { + if (!OS.IsDBLocale) return; + if (oldFont == null) return; + int hwnd = parent.handle; + int hIMC = OS.ImmGetContext (hwnd); + OS.ImmSetCompositionFont (hIMC, oldFont); + OS.ImmReleaseContext (hwnd, hIMC); + oldFont = null; +} + +void saveIMEFont () { + if (!OS.IsDBLocale) return; + if (oldFont != null) return; + int hwnd = parent.handle; + int hIMC = OS.ImmGetContext (hwnd); + oldFont = new LOGFONT (); + if (OS.ImmGetCompositionFont (hIMC, oldFont)) oldFont = null; + OS.ImmReleaseContext (hwnd, hIMC); +} + +/** + * 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(); + boolean samePosition = this.x == x && this.y == y; + boolean sameExtent = this.width == width && this.height == height; + if (samePosition && sameExtent) return; + this.x = x; this.y = y; + this.width = width; this.height = height; + if (sameExtent) { + moved = true; + if (isVisible && hasFocus ()) move (); + } else { + resized = true; + if (isVisible && hasFocus ()) resize (); + } +} + +/** + * 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) { + if (rect == null) error (SWT.ERROR_NULL_ARGUMENT); + setBounds (rect.x, rect.y, rect.width, rect.height); +} + +void setFocus () { + int hwnd = parent.handle; + int hBitmap = 0; + if (image != null) hBitmap = image.handle; + OS.CreateCaret (hwnd, hBitmap, width, height); + move (); + if (font != null) { + int hFont = font.handle; + saveIMEFont (); + setIMEFont (hFont); + } + if (isVisible) OS.ShowCaret (hwnd); +} + +/** + * 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; + if (isVisible && hasFocus ()) { + int hFont = 0; + if (font != null) hFont = font.handle; + if (hFont == 0) hFont = defaultFont (); + saveIMEFont (); + setIMEFont (hFont); + } +} + +/** + * 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 font the new font (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 (isVisible && hasFocus ()) resize (); +} + +void setIMEFont (int hFont) { + if (!OS.IsDBLocale) return; + LOGFONT logFont = new LOGFONT (); + if (OS.GetObject (hFont, LOGFONT.sizeof, logFont) != 0) { + int hwnd = parent.handle; + int hIMC = OS.ImmGetContext (hwnd); + OS.ImmSetCompositionFont (hIMC, logFont); + OS.ImmReleaseContext (hwnd, hIMC); + } +} + +/** + * 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(); + if (this.x == x && this.y == y) return; + this.x = x; this.y = y; + moved = true; + if (isVisible && hasFocus ()) move (); +} + +/** + * 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(); + if (this.width == width && this.height == height) return; + this.width = width; this.height = height; + resized = true; + if (isVisible && hasFocus ()) resize (); +} + +/** + * Sets the receiver's size to the point specified by the argument. + * + * @param size the new extent for the receiver + * @param height the new height 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; + int hwnd = parent.handle; + if (OS.GetFocus () != hwnd) return; + if (!isVisible) { + OS.HideCaret (hwnd); + } else { + if (resized) { + resize (); + } else { + if (moved) move (); + } + OS.ShowCaret (hwnd); + } +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ColorDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ColorDialog.java index 6a5a3ea76e..8366153109 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ColorDialog.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ColorDialog.java @@ -1,198 +1,198 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.*;
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-
-/**
- * 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>
- */
-
-public class ColorDialog extends Dialog {
- RGB rgb;
-
-/**
- * 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 (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
- * @see Widget#checkSubclass
- * @see Widget#getStyle
- */
-public ColorDialog (Shell parent) {
- this (parent, SWT.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
- * @see Widget#checkSubclass
- * @see Widget#getStyle
- */
-public ColorDialog (Shell parent, int style) {
- super (parent, style);
- checkSubclass ();
-}
-
-int CCHookProc (int hdlg, int uiMsg, int lParam, int lpData) {
- switch (uiMsg) {
- case OS.WM_INITDIALOG:
- if (title != null && title.length () != 0) {
- /* Use the character encoding for the default locale */
- TCHAR buffer = new TCHAR (0, title, true);
- OS.SetWindowText (hdlg, buffer);
- }
- break;
- }
- return 0;
-}
-
-/**
- * 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 () {
-
- /* Get the owner HWND for the dialog */
- int hwndOwner = parent.handle;
-
- /* Create the CCHookProc */
- Callback callback = new Callback (this, "CCHookProc", 4);
- int lpfnHook = callback.getAddress ();
-
- /* Allocate the Custom Colors */
- Display display = parent.getDisplay ();
- if (display.lpCustColors == 0) {
- int hHeap = OS.GetProcessHeap ();
- display.lpCustColors = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, 16 * 4);
- }
-
- /* Open the dialog */
- CHOOSECOLOR lpcc = new CHOOSECOLOR ();
- lpcc.lStructSize = CHOOSECOLOR.sizeof;
- lpcc.Flags = OS.CC_ANYCOLOR | OS.CC_ENABLEHOOK;
- lpcc.lpfnHook = lpfnHook;
- lpcc.hwndOwner = hwndOwner;
- lpcc.lpCustColors = display.lpCustColors;
- if (rgb != null) {
- lpcc.Flags |= OS.CC_RGBINIT;
- int red = rgb.red & 0xFF;
- int green = (rgb.green << 8) & 0xFF00;
- int blue = (rgb.blue << 16) & 0xFF0000;
- lpcc.rgbResult = red | green | blue;
- }
- boolean success = OS.ChooseColor (lpcc);
- if (success) {
- int red = lpcc.rgbResult & 0xFF;
- int green = (lpcc.rgbResult >> 8) & 0xFF;
- int blue = (lpcc.rgbResult >> 16) & 0xFF;
- rgb = new RGB (red, green, blue);
- }
-
- /* Free the CCHookProc */
- callback.dispose ();
-
- /* Free the Custom Colors */
- /*
- * This code is intentionally commented. Currently,
- * there is exactly one set of custom colors per display.
- * The memory associated with these colors is released
- * when the display is disposed.
- */
-// if (lpCustColors != 0) OS.HeapFree (hHeap, 0, lpCustColors);
-
- /*
- * This code is intentionally commented. On some
- * platforms, the owner window is repainted right
- * away when a dialog window exits. This behavior
- * is currently unspecified.
- */
-// if (hwndOwner != 0) OS.UpdateWindow (hwndOwner);
-
- if (!success) return null;
- 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 to select a default when
- * open() is called
- * @see PaletteData#getRGBs
- */
-public void setRGB (RGB rgb) {
- this.rgb = rgb;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; + +/** + * 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> + */ + +public class ColorDialog extends Dialog { + RGB rgb; + +/** + * 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 (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 + * @see Widget#checkSubclass + * @see Widget#getStyle + */ +public ColorDialog (Shell parent) { + this (parent, SWT.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 + * @see Widget#checkSubclass + * @see Widget#getStyle + */ +public ColorDialog (Shell parent, int style) { + super (parent, style); + checkSubclass (); +} + +int CCHookProc (int hdlg, int uiMsg, int lParam, int lpData) { + switch (uiMsg) { + case OS.WM_INITDIALOG: + if (title != null && title.length () != 0) { + /* Use the character encoding for the default locale */ + TCHAR buffer = new TCHAR (0, title, true); + OS.SetWindowText (hdlg, buffer); + } + break; + } + return 0; +} + +/** + * 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 () { + + /* Get the owner HWND for the dialog */ + int hwndOwner = parent.handle; + + /* Create the CCHookProc */ + Callback callback = new Callback (this, "CCHookProc", 4); + int lpfnHook = callback.getAddress (); + + /* Allocate the Custom Colors */ + Display display = parent.getDisplay (); + if (display.lpCustColors == 0) { + int hHeap = OS.GetProcessHeap (); + display.lpCustColors = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, 16 * 4); + } + + /* Open the dialog */ + CHOOSECOLOR lpcc = new CHOOSECOLOR (); + lpcc.lStructSize = CHOOSECOLOR.sizeof; + lpcc.Flags = OS.CC_ANYCOLOR | OS.CC_ENABLEHOOK; + lpcc.lpfnHook = lpfnHook; + lpcc.hwndOwner = hwndOwner; + lpcc.lpCustColors = display.lpCustColors; + if (rgb != null) { + lpcc.Flags |= OS.CC_RGBINIT; + int red = rgb.red & 0xFF; + int green = (rgb.green << 8) & 0xFF00; + int blue = (rgb.blue << 16) & 0xFF0000; + lpcc.rgbResult = red | green | blue; + } + boolean success = OS.ChooseColor (lpcc); + if (success) { + int red = lpcc.rgbResult & 0xFF; + int green = (lpcc.rgbResult >> 8) & 0xFF; + int blue = (lpcc.rgbResult >> 16) & 0xFF; + rgb = new RGB (red, green, blue); + } + + /* Free the CCHookProc */ + callback.dispose (); + + /* Free the Custom Colors */ + /* + * This code is intentionally commented. Currently, + * there is exactly one set of custom colors per display. + * The memory associated with these colors is released + * when the display is disposed. + */ +// if (lpCustColors != 0) OS.HeapFree (hHeap, 0, lpCustColors); + + /* + * This code is intentionally commented. On some + * platforms, the owner window is repainted right + * away when a dialog window exits. This behavior + * is currently unspecified. + */ +// if (hwndOwner != 0) OS.UpdateWindow (hwndOwner); + + if (!success) return null; + 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 to select a default when + * open() is called + * @see PaletteData#getRGBs + */ +public void setRGB (RGB rgb) { + this.rgb = rgb; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Combo.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Combo.java index 5e1cfa4b2b..1d9ce8dcae 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Combo.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Combo.java @@ -1,1461 +1,1461 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.events.*;
-
-/**
- * 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</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
- */
-
-public class Combo extends Composite {
- boolean noSelection;
-
- /**
- * 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 = OS.IsWinNT ? 0x7FFFFFFF : 0x7FFF;
- }
-
- static final int ComboProc;
- static final TCHAR ComboClass = new TCHAR (0,"COMBOBOX", true);
- /*
- * These are the undocumented control id's for the children of
- * a combo box. Since there are no constants for these values,
- * they may change with different versions of Windows (but have
- * been the same since Windows 3.0).
- */
- static final int CBID_LIST = 1000;
- static final int CBID_EDIT = 1001;
- static {
- WNDCLASS lpWndClass = new WNDCLASS ();
- OS.GetClassInfo (0, ComboClass, lpWndClass);
- ComboProc = lpWndClass.lpfnWndProc;
- }
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure</li>
- * </ul>
- *
- * @see #add(String,int)
- */
-public void add (String string) {
- checkWidget ();
- if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
- TCHAR buffer = new TCHAR (getCodePage (), string, true);
- int result = OS.SendMessage (handle, OS.CB_ADDSTRING, 0, buffer);
- if (result == OS.CB_ERR) error (SWT.ERROR_ITEM_NOT_ADDED);
- if (result == OS.CB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED);
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure</li>
- * </ul>
- *
- * @see #add(String)
- */
-public void add (String string, int index) {
- checkWidget ();
- if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
- TCHAR buffer = new TCHAR (getCodePage (), string, true);
- int result = OS.SendMessage (handle, OS.CB_INSERTSTRING, index, buffer);
- if (result == OS.CB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED);
- if (result == OS.CB_ERR) {
- int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
- if (0 <= index && index <= count) {
- error (SWT.ERROR_ITEM_NOT_ADDED);
- } else {
- error (SWT.ERROR_INVALID_RANGE);
- }
- }
-}
-
-/**
- * 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 receiver's selection changes, by sending
- * it one of the messages defined in the <code>SelectionListener</code>
- * interface.
- * <p>
- * <code>widgetSelected</code> is called when the combo's list selection changes.
- * <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);
-}
-
-int callWindowProc (int msg, int wParam, int lParam) {
- if (handle == 0) return 0;
- return OS.CallWindowProc (ComboProc, handle, msg, wParam, lParam);
-}
-
-protected void checkSubclass () {
- if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
-}
-
-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;
-}
-
-/**
- * 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 ();
- OS.SendMessage (handle, OS.CB_SETEDITSEL, 0, -1);
-}
-
-public Point computeSize (int wHint, int hHint, boolean changed) {
- checkWidget ();
- int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
- int itemHeight = OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, 0, 0);
- int width = 0, height = 0;
- if ((style & SWT.SIMPLE) != 0) height = count * itemHeight;
- int newFont, oldFont = 0;
- int hDC = OS.GetDC (handle);
- newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
- RECT rect = new RECT ();
- int flags = OS.DT_CALCRECT | OS.DT_NOPREFIX;
- int length = OS.GetWindowTextLength (handle);
- int cp = getCodePage ();
- TCHAR buffer = new TCHAR (cp, length + 1);
- OS.GetWindowText (handle, buffer, length + 1);
- OS.DrawText (hDC, buffer, length, rect, flags);
- width = Math.max (width, rect.right - rect.left);
- for (int i=0; i<count; i++) {
- length = OS.SendMessage (handle, OS.CB_GETLBTEXTLEN, i, 0);
- if (length != OS.CB_ERR) {
- if (length + 1 > buffer.length ()) buffer = new TCHAR (cp, length + 1);
- int result = OS.SendMessage (handle, OS.CB_GETLBTEXT, i, buffer);
- if (result != OS.CB_ERR) {
- OS.DrawText (hDC, buffer, length, rect, flags);
- width = Math.max (width, rect.right - rect.left);
- }
- }
- }
- TEXTMETRIC tm = new TEXTMETRIC ();
- OS.GetTextMetrics (hDC, tm);
- if (newFont != 0) OS.SelectObject (hDC, oldFont);
- OS.ReleaseDC (handle, hDC);
- 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 = OS.GetSystemMetrics (OS.SM_CXEDGE);
- width += OS.GetSystemMetrics (OS.SM_CXVSCROLL) + (tm.tmInternalLeading + border) * 2;
- int textHeight = OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, -1, 0);
- if ((style & SWT.DROP_DOWN) != 0) {
- height = textHeight + 6;
- } else {
- height += textHeight + 10;
- }
- 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 ();
- OS.SendMessage (handle, OS.WM_COPY, 0, 0);
-}
-
-void createHandle () {
- super.createHandle ();
- state &= ~CANVAS;
-}
-
-/**
- * Cuts the selected text.
- * <p>
- * The current selection is first copied to the
- * clipboard and then deleted from the widget.
- * </p>
- *
- * @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>
- *
- * @since 2.1
- */
-public void cut () {
- checkWidget ();
- OS.SendMessage (handle, OS.WM_CUT, 0, 0);
-}
-
-int defaultBackground () {
- return OS.GetSysColor (OS.COLOR_WINDOW);
-}
-
-/**
- * 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 ();
- int selection = OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
- if (index != selection) return;
- OS.SendMessage (handle, OS.CB_SETCURSEL, -1, 0);
- sendEvent (SWT.Modify);
- // widget could be disposed at this point
-}
-
-/**
- * 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 ();
- OS.SendMessage (handle, OS.CB_SETCURSEL, -1, 0);
- sendEvent (SWT.Modify);
- // widget could be disposed at this point
-}
-
-boolean getEditable () {
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- return (bits & 0x0F) == OS.CBS_DROPDOWNLIST;
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public String getItem (int index) {
- checkWidget ();
- int length = OS.SendMessage (handle, OS.CB_GETLBTEXTLEN, index, 0);
- if (length != OS.CB_ERR) {
- TCHAR buffer = new TCHAR (getCodePage (), length + 1);
- int result = OS.SendMessage (handle, OS.CB_GETLBTEXT, index, buffer);
- if (result != OS.CB_ERR) return buffer.toString (0, length);
- }
- int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
- if (0 <= index && index < count) error (SWT.ERROR_CANNOT_GET_ITEM);
- error (SWT.ERROR_INVALID_RANGE);
- return null;
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public int getItemCount () {
- checkWidget ();
- int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
- if (count == OS.CB_ERR) error (SWT.ERROR_CANNOT_GET_COUNT);
- return count;
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_ITEM_HEIGHT - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public int getItemHeight () {
- checkWidget ();
- int result = OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, 0, 0);
- if (result == OS.CB_ERR) error (SWT.ERROR_CANNOT_GET_ITEM_HEIGHT);
- return result;
-}
-
-/**
- * Returns an 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</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;
-}
-
-String getNameText () {
- return getText ();
-}
-
-/**
- * Returns a <code>Point</code> whose x coordinate is the start
- * of the selection in the receiver's text field, and whose y
- * coordinate is the end of the selection. The returned values
- * are zero-relative. An "empty" selection as indicated by
- * the the x and y coordinates having the same value.
- *
- * @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.DROP_DOWN) != 0 && (style & SWT.READ_ONLY) != 0) {
- return new Point (0, OS.GetWindowTextLength (handle));
- }
- int [] start = new int [1], end = new int [1];
- OS.SendMessage (handle, OS.CB_GETEDITSEL, start, end);
- return new Point (start [0], end [0]);
-}
-
-/**
- * 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 (noSelection) return -1;
- return OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
-}
-
-/**
- * Returns a string containing a copy of the contents of the
- * receiver's text field.
- *
- * @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 ();
- int length = OS.GetWindowTextLength (handle);
- if (length == 0) return "";
- TCHAR buffer = new TCHAR (getCodePage (), length + 1);
- OS.GetWindowText (handle, buffer, length + 1);
- return buffer.toString (0, length);
-}
-
-String getText (int start, int stop) {
- /*
- * NOTE: The current implementation uses substring ()
- * which can reference a potentially large character
- * array.
- */
- return getText ().substring (start, stop - 1);
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_ITEM_HEIGHT - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public int getTextHeight () {
- checkWidget ();
- int result = OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, -1, 0);
- if (result == OS.CB_ERR) error (SWT.ERROR_CANNOT_GET_ITEM_HEIGHT);
- return result + 6;
-}
-
-/**
- * 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>
- */
-public int getTextLimit () {
- checkWidget ();
- int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
- if (hwndText == 0) return LIMIT;
- return OS.SendMessage (hwndText, OS.EM_GETLIMITTEXT, 0, 0);
-}
-
-boolean hasFocus () {
- int hwndFocus = OS.GetFocus ();
- if (hwndFocus == handle) return true;
- if (hwndFocus == 0) return false;
- int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
- if (hwndFocus == hwndText) return true;
- int hwndList = OS.GetDlgItem (handle, CBID_LIST);
- if (hwndFocus == hwndList) return true;
- return false;
-}
-
-/**
- * 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
- * @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);
-
- /*
- * Bug in Windows. For some reason, CB_FINDSTRINGEXACT
- * will not find empty strings even though it is legal
- * to insert an empty string into a combo. The fix is
- * to search the combo, an item at a time.
- */
- if (string.length () == 0) {
- int count = getItemCount ();
- for (int i=start; i<count; i++) {
- if (string.equals (getItem (i))) return i;
- }
- return -1;
- }
-
- /* Use CB_FINDSTRINGEXACT to search for the item */
- int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
- if (!(0 <= start && start < count)) return -1;
- int index = start - 1, last = 0;
- TCHAR buffer = new TCHAR (getCodePage (), string, true);
- do {
- index = OS.SendMessage (handle, OS.CB_FINDSTRINGEXACT, last = index, buffer);
- if (index == OS.CB_ERR || index <= last) return -1;
- } while (!string.equals (getItem (index)));
- return index;
-}
-
-/**
- * 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 ();
- OS.SendMessage (handle, OS.WM_PASTE, 0, 0);
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public void remove (int index) {
- checkWidget ();
- int length = OS.GetWindowTextLength (handle);
- int code = OS.SendMessage (handle, OS.CB_DELETESTRING, index, 0);
- if (code == OS.CB_ERR) {
- int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
- if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
- error (SWT.ERROR_INVALID_RANGE);
- }
- if (length != OS.GetWindowTextLength (handle)) {
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the modify
- * event. If this happens, just return.
- */
- sendEvent (SWT.Modify);
- if (isDisposed ()) return;
- }
- /*
- * Bug in Windows. When the combo box is read only
- * with exactly one item that is currently selected
- * and that item is removed, the combo box does not
- * redraw to clear the text area. The fix is to
- * force a redraw.
- */
- if ((style & SWT.READ_ONLY) != 0) {
- int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
- if (count == 0) OS.InvalidateRect (handle, null, false);
- }
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public void remove (int start, int end) {
- checkWidget ();
- if (start > end) return;
- int length = OS.GetWindowTextLength (handle);
- for (int i=start; i<=end; i++) {
- int result = OS.SendMessage (handle, OS.CB_DELETESTRING, start, 0);
- if (result == OS.CB_ERR) {
- int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
- if (0 <= i && i < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
- error (SWT.ERROR_INVALID_RANGE);
- }
- }
- if (length != OS.GetWindowTextLength (handle)) {
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the modify
- * event. If this happens, just return.
- */
- sendEvent (SWT.Modify);
- if (isDisposed ()) return;
- }
- /*
- * Bug in Windows. When the combo box is read only
- * with exactly one item that is currently selected
- * and that item is removed, the combo box does not
- * redraw to clear the text area. The fix is to
- * force a redraw.
- */
- if ((style & SWT.READ_ONLY) != 0) {
- int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
- if (count == 0) OS.InvalidateRect (handle, null, false);
- }
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public void remove (String string) {
- 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.
- * <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 ();
- OS.SendMessage (handle, OS.CB_RESETCONTENT, 0, 0);
- sendEvent (SWT.Modify);
- // widget could be disposed at this point
-}
-
-/**
- * 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 receiver's selection changes.
- *
- * @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 ();
- int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
- if (0 <= index && index < count) {
- int selection = OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
- int code = OS.SendMessage (handle, OS.CB_SETCURSEL, index, 0);
- if (code != OS.CB_ERR && code != selection) {
- sendEvent (SWT.Modify);
- // widget could be disposed at this point
- }
- }
-}
-
-void setBackgroundPixel (int pixel) {
- if (background == pixel) return;
- super.setBackgroundPixel (pixel);
- int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
- if (hwndText != 0) OS.InvalidateRect (hwndText, null, true);
- int hwndList = OS.GetDlgItem (handle, CBID_LIST);
- if (hwndList != 0) OS.InvalidateRect (hwndList, null, true);
-}
-
-void setBounds (int x, int y, int width, int height, int flags) {
- /*
- * Feature in Windows. If the combo box has the CBS_DROPDOWN
- * or CBS_DROPDOWNLIST style, Windows uses the height that the
- * programmer sets in SetWindowPos () to control height of the
- * drop down list. When the width is non-zero, Windows remembers
- * this value and sets the height to be the height of the text
- * field part of the combo box. If the width is zero, Windows
- * allows the height to have any value. Therefore, when the
- * programmer sets and then queries the height, the values can
- * be different depending on the width. The problem occurs when
- * the programmer uses computeSize () to determine the preferred
- * height (always the height of the text field) and then uses
- * this value to set the height of the combo box. The result
- * is a combo box with a zero size drop down list. The fix, is
- * to always set the height to show a fixed number of combo box
- * items and ignore the height value that the programmer supplies.
- */
- if ((style & SWT.DROP_DOWN) != 0) {
- int textHeight = OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, -1, 0);
- int itemHeight = OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, 0, 0);
- height = textHeight + 6 + (itemHeight * 5) + 2;
- /*
- * Feature in Windows. When a drop down combo box is resized,
- * the combo box resizes the height of the text field and uses
- * the height provided in SetWindowPos () to determine the height
- * of the drop down list. For some reason, the combo box redraws
- * the whole area, not just the text field. The fix is to set the
- * SWP_NOSIZE bits when the height of text field and the drop down
- * list is the same as the requested height.
- *
- * NOTE: Setting the width of a combo box to zero does not update
- * the width of the drop down control rect. If the width of the
- * combo box is zero, then do not set SWP_NOSIZE.
- */
- RECT rect = new RECT ();
- OS.GetWindowRect (handle, rect);
- if (rect.right - rect.left != 0) {
- if (OS.SendMessage (handle, OS.CB_GETDROPPEDCONTROLRECT, 0, rect) != 0) {
- int oldWidth = rect.right - rect.left, oldHeight = rect.bottom - rect.top;
- if (oldWidth == width && oldHeight == height) flags |= OS.SWP_NOSIZE;
- }
- }
- OS.SetWindowPos (handle, 0, x, y, width, height, flags);
- return;
- }
-
- /*
- * Bug in Windows. If the combo box has the CBS_SIMPLE style,
- * the list portion of the combo box is not redrawn when the
- * combo box is resized. The fix is to force a redraw when
- * the size has changed.
- */
- if (parent.lpwp != null || (flags & OS.SWP_NOSIZE) != 0 || !OS.IsWindowVisible (handle)) {
- super.setBounds (x, y, width, height, flags);
- return;
- }
- RECT rect = new RECT ();
- OS.GetWindowRect (handle, rect);
- super.setBounds (x, y, width, height, flags);
- int oldWidth = rect.right - rect.left, oldHeight = rect.bottom - rect.top;
- if (oldWidth != width || oldHeight != height) {
- if (OS.IsWinCE) {
- int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
- if (hwndText != 0) OS.InvalidateRect (hwndText, null, true);
- int hwndList = OS.GetDlgItem (handle, CBID_LIST);
- if (hwndList != 0) OS.InvalidateRect (hwndList, null, true);
- } else {
- int uFlags = OS.RDW_ERASE | OS.RDW_INVALIDATE | OS.RDW_ALLCHILDREN;
- OS.RedrawWindow (handle, null, 0, uFlags);
- }
- }
-}
-
-void setEditable (boolean editable) {
- error (SWT.ERROR_NOT_IMPLEMENTED);
-}
-
-void setForegroundPixel (int pixel) {
- if (foreground == pixel) return;
- super.setForegroundPixel (pixel);
- int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
- if (hwndText != 0) OS.InvalidateRect (hwndText, null, true);
- int hwndList = OS.GetDlgItem (handle, CBID_LIST);
- if (hwndList != 0) OS.InvalidateRect (hwndList, null, true);
-}
-
-/**
- * Sets the text of the item in the receiver's list at the given
- * zero-relative index to the string argument. This is equivalent
- * to <code>remove</code>'ing the old item at the index, and then
- * <code>add</code>'ing the new item at that index.
- *
- * @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>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - 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 SWTError <ul>
- * <li>ERROR_ITEM_NOT_REMOVED - if the remove operation fails because of an operating system failure</li>
- * <li>ERROR_ITEM_NOT_ADDED - if the add operation fails because of an operating system failure</li>
- * </ul>
- */
-public void setItem (int index, String string) {
- checkWidget ();
- if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
- remove (index);
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the modify
- * event that might be sent when the index is removed.
- * If this happens, just exit.
- */
- if (isDisposed ()) return;
- add (string, index);
-}
-
-/**
- * Sets the receiver's list to be the given array of items.
- *
- * @param items the array 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>
- * @exception SWTError <ul>
- * <li>ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public void setItems (String [] items) {
- checkWidget ();
- if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
- OS.SendMessage (handle, OS.CB_RESETCONTENT, 0, 0);
- int codePage = getCodePage ();
- for (int i=0; i<items.length; i++) {
- String string = items [i];
- TCHAR buffer = new TCHAR (codePage, string, true);
- int code = OS.SendMessage (handle, OS.CB_ADDSTRING, 0, buffer);
- if (code == OS.CB_ERR) error (SWT.ERROR_ITEM_NOT_ADDED);
- if (code == OS.CB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED);
- }
- // widget could be disposed at this point
- sendEvent (SWT.Modify);
-}
-
-/**
- * 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 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);
- int bits = selection.x | (selection.y << 16);
- OS.SendMessage (handle, OS.CB_SETEDITSEL, 0, bits);
-}
-
-/**
- * Sets the contents of the receiver's text field to the
- * given string.
- * <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 text 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 ((style & SWT.READ_ONLY) != 0) {
- int index = indexOf (string);
- if (index != -1) select (index);
- return;
- }
- TCHAR buffer = new TCHAR (getCodePage (), string, true);
- if (OS.SetWindowText (handle, buffer)) {
- sendEvent (SWT.Modify);
- // widget could be disposed at this point
- }
-}
-
-/**
- * Sets the maximum number of characters that the receiver's
- * text field is capable of holding to be the argument.
- *
- * @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>
- */
-public void setTextLimit (int limit) {
- checkWidget ();
- if (limit == 0) error (SWT.ERROR_CANNOT_BE_ZERO);
- OS.SendMessage (handle, OS.CB_LIMITTEXT, limit, 0);
-}
-
-boolean translateAccelerator (MSG msg) {
- if (super.translateAccelerator (msg)) return true;
-
- /*
- * In order to see key events for the text widget in a combo box,
- * filter the key events before they are dispatched to the text
- * widget and invoke the cooresponding key handler for the combo
- * box as if the key was sent directly to the combo box, not the
- * text field. The key is still dispatched to the text widget,
- * in the normal fashion. Note that we must call TranslateMessage
- * in order to process accented keys properly.
- */
- int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
- if (hwndText != 0 && msg.hwnd == hwndText) {
- switch (msg.message) {
- case OS.WM_CHAR:
- case OS.WM_SYSCHAR:
- case OS.WM_KEYDOWN: {
- Display display = getDisplay ();
- if (msg.message == OS.WM_KEYDOWN) {
- if (display.translateTraversal (msg, this)) return true;
- } else {
- if (display.translateMnemonic (msg, this)) return true;
- }
- }
- }
- OS.TranslateMessage (msg);
- switch (msg.message) {
- case OS.WM_CHAR: WM_CHAR (msg.wParam, msg.lParam); break;
- case OS.WM_IME_CHAR: WM_IME_CHAR (msg.wParam, msg.lParam); break;
- case OS.WM_KEYDOWN: WM_KEYDOWN (msg.wParam, msg.lParam); break;
- case OS.WM_KEYUP: WM_KEYUP (msg.wParam, msg.lParam); break;
- case OS.WM_SYSCHAR: WM_SYSCHAR (msg.wParam, msg.lParam); break;
- case OS.WM_SYSKEYDOWN: WM_SYSKEYDOWN (msg.wParam, msg.lParam); break;
- case OS.WM_SYSKEYUP: WM_SYSKEYUP (msg.wParam, msg.lParam); break;
- }
- OS.DispatchMessage (msg);
- return true;
- }
- return false;
-}
-
-boolean translateTraversal (MSG msg) {
- /*
- * Feature in Windows. For some reason, when the
- * user presses tab, return or escape, Windows beeps.
- * The fix is to look for these keys and not call
- * the window proc.
- */
- int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
- if (hwndText != 0 && msg.hwnd == hwndText) {
- switch (msg.wParam) {
- case OS.VK_ESCAPE:
- /* Allow the escape key to close the combo box */
- if (OS.SendMessage (handle, OS.CB_GETDROPPEDSTATE, 0, 0) != 0) {
- return false;
- }
- // FALL THROUGH
- case OS.VK_TAB:
- case OS.VK_RETURN:
- boolean translated = super.translateTraversal (msg);
- if (!translated) {
- if (sendKeyEvent (SWT.KeyDown, msg.message, msg.wParam, msg.lParam)) {
- if (msg.wParam == OS.VK_RETURN) {
- sendEvent (SWT.DefaultSelection);
- // widget could be disposed at this point
- }
- }
- }
- return true;
- }
- }
- return super.translateTraversal (msg);
-}
-
-boolean traverseEscape () {
- if (OS.SendMessage (handle, OS.CB_GETDROPPEDSTATE, 0, 0) != 0) {
- OS.SendMessage (handle, OS.CB_SHOWDROPDOWN, 0, 0);
- return true;
- }
- return super.traverseEscape ();
-}
-
-int widgetExtStyle () {
- return super.widgetExtStyle () & ~OS.WS_EX_NOINHERITLAYOUT;
-}
-
-int widgetStyle () {
- int bits = super.widgetStyle () | OS.CBS_AUTOHSCROLL | OS.CBS_NOINTEGRALHEIGHT | OS.WS_VSCROLL;
- if ((style & SWT.SIMPLE) != 0) return bits | OS.CBS_SIMPLE;
- if ((style & SWT.READ_ONLY) != 0) return bits | OS.CBS_DROPDOWNLIST;
- return bits | OS.CBS_DROPDOWN;
-}
-
-TCHAR windowClass () {
- return ComboClass;
-}
-
-int windowProc () {
- return ComboProc;
-}
-
-LRESULT WM_CHAR (int wParam, int lParam) {
- LRESULT result = super.WM_CHAR (wParam, lParam);
- if (result != null) return result;
- if (wParam == OS.VK_RETURN) {
- postEvent (SWT.DefaultSelection);
- }
- return result;
-}
-
-LRESULT WM_CTLCOLOR (int wParam, int lParam) {
- return wmColorChild (wParam, lParam);
-}
-
-LRESULT WM_GETDLGCODE (int wParam, int lParam) {
- int code = callWindowProc (OS.WM_GETDLGCODE, wParam, lParam);
- return new LRESULT (code | OS.DLGC_WANTARROWS);
-}
-
-LRESULT WM_KILLFOCUS (int wParam, int lParam) {
- /*
- * Return NULL - Focus notification is
- * done in WM_COMMAND by CBN_KILLFOCUS.
- */
- return null;
-}
-
-LRESULT WM_SETFOCUS (int wParam, int lParam) {
- /*
- * Return NULL - Focus notification is
- * done by WM_COMMAND with CBN_SETFOCUS.
- */
- return null;
-}
-
-LRESULT WM_SIZE (int wParam, int lParam) {
- /*
- * Feature in Windows. When an editable drop down combo box
- * contains text that does not correspond to an item in the
- * list, when the widget is resized, it selects the closest
- * match from the list. The fix is to remember the original
- * text and reset it after the widget is resized.
- */
- if ((style & SWT.READ_ONLY) != 0 || (style & SWT.DROP_DOWN) == 0) {
- return super.WM_SIZE (wParam, lParam);
- }
- int index = OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
- boolean redraw = false;
- TCHAR buffer = null;
- int [] start = null, end = null;
- if (index == OS.CB_ERR) {
- int length = OS.GetWindowTextLength (handle);
- if (length != 0) {
- buffer = new TCHAR (getCodePage (), length + 1);
- OS.GetWindowText (handle, buffer, length + 1);
- start = new int [1]; end = new int [1];
- OS.SendMessage (handle, OS.CB_GETEDITSEL, start, end);
- redraw = drawCount == 0 && OS.IsWindowVisible (handle);
- if (redraw) setRedraw (false);
- }
- }
- LRESULT result = super.WM_SIZE (wParam, lParam);
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the resize
- * event. If this happens, end the processing of the
- * Windows message by returning the result of the
- * WM_SIZE message.
- */
- if (isDisposed ()) return result;
- if (buffer != null) {
- OS.SetWindowText (handle, buffer);
- int bits = start [0] | (end [0] << 16);
- OS.SendMessage (handle, OS.CB_SETEDITSEL, 0, bits);
- if (redraw) setRedraw (true);
- }
- return result;
-}
-
-LRESULT wmCommandChild (int wParam, int lParam) {
- int code = wParam >> 16;
- switch (code) {
- case OS.CBN_EDITCHANGE:
- /*
- * Feature in Windows. If the combo box list selection is
- * queried using CB_GETCURSEL before the WM_COMMAND (with
- * CBM_EDITCHANGE) returns, CB_GETCURSEL returns the previous
- * selection in the list. It seems that the combo box sends
- * the WM_COMMAND before it makes the selection in the list box
- * match the entry field. The fix is remember that no selection
- * in the list should exist in this case.
- */
- noSelection = true;
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the modify
- * event. If this happens, end the processing of the
- * Windows message by returning zero as the result of
- * the window proc.
- */
- sendEvent (SWT.Modify);
- if (isDisposed ()) return LRESULT.ZERO;
- noSelection = false;
- break;
- case OS.CBN_SELCHANGE:
- /*
- * Feature in Windows. If the text in an editable combo box
- * is queried using GetWindowText () before the WM_COMMAND
- * (with CBM_SELCHANGE) returns, GetWindowText () returns is
- * the previous text in the combo box. It seems that the combo
- * box sends the WM_COMMAND before it updates the text field to
- * match the list selection. The fix is to force the text field
- * to match the list selection by re-selecting the list item.
- */
- int index = OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
- if (index != OS.CB_ERR) OS.SendMessage (handle, OS.CB_SETCURSEL, index, 0);
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the modify
- * event. If this happens, end the processing of the
- * Windows message by returning zero as the result of
- * the window proc.
- */
- sendEvent (SWT.Modify);
- if (isDisposed ()) return LRESULT.ZERO;
- postEvent (SWT.Selection);
- break;
- case OS.CBN_SETFOCUS:
- case OS.CBN_KILLFOCUS:
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the focus
- * event. If this happens, end the processing of the
- * Windows message by returning zero as the result of
- * the window proc.
- */
- sendEvent (code == OS.CBN_SETFOCUS ? SWT.FocusIn : SWT.FocusOut);
- if (isDisposed ()) return LRESULT.ZERO;
- break;
- }
- return super.wmCommandChild (wParam, lParam);
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.events.*; + +/** + * 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</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 + */ + +public class Combo extends Composite { + boolean noSelection; + + /** + * 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 = OS.IsWinNT ? 0x7FFFFFFF : 0x7FFF; + } + + static final int ComboProc; + static final TCHAR ComboClass = new TCHAR (0,"COMBOBOX", true); + /* + * These are the undocumented control id's for the children of + * a combo box. Since there are no constants for these values, + * they may change with different versions of Windows (but have + * been the same since Windows 3.0). + */ + static final int CBID_LIST = 1000; + static final int CBID_EDIT = 1001; + static { + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, ComboClass, lpWndClass); + ComboProc = lpWndClass.lpfnWndProc; + } + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure</li> + * </ul> + * + * @see #add(String,int) + */ +public void add (String string) { + checkWidget (); + if (string == null) error (SWT.ERROR_NULL_ARGUMENT); + TCHAR buffer = new TCHAR (getCodePage (), string, true); + int result = OS.SendMessage (handle, OS.CB_ADDSTRING, 0, buffer); + if (result == OS.CB_ERR) error (SWT.ERROR_ITEM_NOT_ADDED); + if (result == OS.CB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED); +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure</li> + * </ul> + * + * @see #add(String) + */ +public void add (String string, int index) { + checkWidget (); + if (string == null) error (SWT.ERROR_NULL_ARGUMENT); + TCHAR buffer = new TCHAR (getCodePage (), string, true); + int result = OS.SendMessage (handle, OS.CB_INSERTSTRING, index, buffer); + if (result == OS.CB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED); + if (result == OS.CB_ERR) { + int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0); + if (0 <= index && index <= count) { + error (SWT.ERROR_ITEM_NOT_ADDED); + } else { + error (SWT.ERROR_INVALID_RANGE); + } + } +} + +/** + * 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 receiver's selection changes, by sending + * it one of the messages defined in the <code>SelectionListener</code> + * interface. + * <p> + * <code>widgetSelected</code> is called when the combo's list selection changes. + * <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); +} + +int callWindowProc (int msg, int wParam, int lParam) { + if (handle == 0) return 0; + return OS.CallWindowProc (ComboProc, handle, msg, wParam, lParam); +} + +protected void checkSubclass () { + if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS); +} + +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; +} + +/** + * 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 (); + OS.SendMessage (handle, OS.CB_SETEDITSEL, 0, -1); +} + +public Point computeSize (int wHint, int hHint, boolean changed) { + checkWidget (); + int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0); + int itemHeight = OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, 0, 0); + int width = 0, height = 0; + if ((style & SWT.SIMPLE) != 0) height = count * itemHeight; + int newFont, oldFont = 0; + int hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); + RECT rect = new RECT (); + int flags = OS.DT_CALCRECT | OS.DT_NOPREFIX; + int length = OS.GetWindowTextLength (handle); + int cp = getCodePage (); + TCHAR buffer = new TCHAR (cp, length + 1); + OS.GetWindowText (handle, buffer, length + 1); + OS.DrawText (hDC, buffer, length, rect, flags); + width = Math.max (width, rect.right - rect.left); + for (int i=0; i<count; i++) { + length = OS.SendMessage (handle, OS.CB_GETLBTEXTLEN, i, 0); + if (length != OS.CB_ERR) { + if (length + 1 > buffer.length ()) buffer = new TCHAR (cp, length + 1); + int result = OS.SendMessage (handle, OS.CB_GETLBTEXT, i, buffer); + if (result != OS.CB_ERR) { + OS.DrawText (hDC, buffer, length, rect, flags); + width = Math.max (width, rect.right - rect.left); + } + } + } + TEXTMETRIC tm = new TEXTMETRIC (); + OS.GetTextMetrics (hDC, tm); + if (newFont != 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + 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 = OS.GetSystemMetrics (OS.SM_CXEDGE); + width += OS.GetSystemMetrics (OS.SM_CXVSCROLL) + (tm.tmInternalLeading + border) * 2; + int textHeight = OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, -1, 0); + if ((style & SWT.DROP_DOWN) != 0) { + height = textHeight + 6; + } else { + height += textHeight + 10; + } + 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 (); + OS.SendMessage (handle, OS.WM_COPY, 0, 0); +} + +void createHandle () { + super.createHandle (); + state &= ~CANVAS; +} + +/** + * Cuts the selected text. + * <p> + * The current selection is first copied to the + * clipboard and then deleted from the widget. + * </p> + * + * @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> + * + * @since 2.1 + */ +public void cut () { + checkWidget (); + OS.SendMessage (handle, OS.WM_CUT, 0, 0); +} + +int defaultBackground () { + return OS.GetSysColor (OS.COLOR_WINDOW); +} + +/** + * 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 (); + int selection = OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0); + if (index != selection) return; + OS.SendMessage (handle, OS.CB_SETCURSEL, -1, 0); + sendEvent (SWT.Modify); + // widget could be disposed at this point +} + +/** + * 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 (); + OS.SendMessage (handle, OS.CB_SETCURSEL, -1, 0); + sendEvent (SWT.Modify); + // widget could be disposed at this point +} + +boolean getEditable () { + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + return (bits & 0x0F) == OS.CBS_DROPDOWNLIST; +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</li> + * </ul> + */ +public String getItem (int index) { + checkWidget (); + int length = OS.SendMessage (handle, OS.CB_GETLBTEXTLEN, index, 0); + if (length != OS.CB_ERR) { + TCHAR buffer = new TCHAR (getCodePage (), length + 1); + int result = OS.SendMessage (handle, OS.CB_GETLBTEXT, index, buffer); + if (result != OS.CB_ERR) return buffer.toString (0, length); + } + int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0); + if (0 <= index && index < count) error (SWT.ERROR_CANNOT_GET_ITEM); + error (SWT.ERROR_INVALID_RANGE); + return null; +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure</li> + * </ul> + */ +public int getItemCount () { + checkWidget (); + int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0); + if (count == OS.CB_ERR) error (SWT.ERROR_CANNOT_GET_COUNT); + return count; +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_ITEM_HEIGHT - if the operation fails because of an operating system failure</li> + * </ul> + */ +public int getItemHeight () { + checkWidget (); + int result = OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, 0, 0); + if (result == OS.CB_ERR) error (SWT.ERROR_CANNOT_GET_ITEM_HEIGHT); + return result; +} + +/** + * Returns an 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</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; +} + +String getNameText () { + return getText (); +} + +/** + * Returns a <code>Point</code> whose x coordinate is the start + * of the selection in the receiver's text field, and whose y + * coordinate is the end of the selection. The returned values + * are zero-relative. An "empty" selection as indicated by + * the the x and y coordinates having the same value. + * + * @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.DROP_DOWN) != 0 && (style & SWT.READ_ONLY) != 0) { + return new Point (0, OS.GetWindowTextLength (handle)); + } + int [] start = new int [1], end = new int [1]; + OS.SendMessage (handle, OS.CB_GETEDITSEL, start, end); + return new Point (start [0], end [0]); +} + +/** + * 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 (noSelection) return -1; + return OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0); +} + +/** + * Returns a string containing a copy of the contents of the + * receiver's text field. + * + * @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 (); + int length = OS.GetWindowTextLength (handle); + if (length == 0) return ""; + TCHAR buffer = new TCHAR (getCodePage (), length + 1); + OS.GetWindowText (handle, buffer, length + 1); + return buffer.toString (0, length); +} + +String getText (int start, int stop) { + /* + * NOTE: The current implementation uses substring () + * which can reference a potentially large character + * array. + */ + return getText ().substring (start, stop - 1); +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_ITEM_HEIGHT - if the operation fails because of an operating system failure</li> + * </ul> + */ +public int getTextHeight () { + checkWidget (); + int result = OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, -1, 0); + if (result == OS.CB_ERR) error (SWT.ERROR_CANNOT_GET_ITEM_HEIGHT); + return result + 6; +} + +/** + * 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> + */ +public int getTextLimit () { + checkWidget (); + int hwndText = OS.GetDlgItem (handle, CBID_EDIT); + if (hwndText == 0) return LIMIT; + return OS.SendMessage (hwndText, OS.EM_GETLIMITTEXT, 0, 0); +} + +boolean hasFocus () { + int hwndFocus = OS.GetFocus (); + if (hwndFocus == handle) return true; + if (hwndFocus == 0) return false; + int hwndText = OS.GetDlgItem (handle, CBID_EDIT); + if (hwndFocus == hwndText) return true; + int hwndList = OS.GetDlgItem (handle, CBID_LIST); + if (hwndFocus == hwndList) return true; + return false; +} + +/** + * 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 + * @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); + + /* + * Bug in Windows. For some reason, CB_FINDSTRINGEXACT + * will not find empty strings even though it is legal + * to insert an empty string into a combo. The fix is + * to search the combo, an item at a time. + */ + if (string.length () == 0) { + int count = getItemCount (); + for (int i=start; i<count; i++) { + if (string.equals (getItem (i))) return i; + } + return -1; + } + + /* Use CB_FINDSTRINGEXACT to search for the item */ + int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0); + if (!(0 <= start && start < count)) return -1; + int index = start - 1, last = 0; + TCHAR buffer = new TCHAR (getCodePage (), string, true); + do { + index = OS.SendMessage (handle, OS.CB_FINDSTRINGEXACT, last = index, buffer); + if (index == OS.CB_ERR || index <= last) return -1; + } while (!string.equals (getItem (index))); + return index; +} + +/** + * 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 (); + OS.SendMessage (handle, OS.WM_PASTE, 0, 0); +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li> + * </ul> + */ +public void remove (int index) { + checkWidget (); + int length = OS.GetWindowTextLength (handle); + int code = OS.SendMessage (handle, OS.CB_DELETESTRING, index, 0); + if (code == OS.CB_ERR) { + int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0); + if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED); + error (SWT.ERROR_INVALID_RANGE); + } + if (length != OS.GetWindowTextLength (handle)) { + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the modify + * event. If this happens, just return. + */ + sendEvent (SWT.Modify); + if (isDisposed ()) return; + } + /* + * Bug in Windows. When the combo box is read only + * with exactly one item that is currently selected + * and that item is removed, the combo box does not + * redraw to clear the text area. The fix is to + * force a redraw. + */ + if ((style & SWT.READ_ONLY) != 0) { + int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0); + if (count == 0) OS.InvalidateRect (handle, null, false); + } +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li> + * </ul> + */ +public void remove (int start, int end) { + checkWidget (); + if (start > end) return; + int length = OS.GetWindowTextLength (handle); + for (int i=start; i<=end; i++) { + int result = OS.SendMessage (handle, OS.CB_DELETESTRING, start, 0); + if (result == OS.CB_ERR) { + int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0); + if (0 <= i && i < count) error (SWT.ERROR_ITEM_NOT_REMOVED); + error (SWT.ERROR_INVALID_RANGE); + } + } + if (length != OS.GetWindowTextLength (handle)) { + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the modify + * event. If this happens, just return. + */ + sendEvent (SWT.Modify); + if (isDisposed ()) return; + } + /* + * Bug in Windows. When the combo box is read only + * with exactly one item that is currently selected + * and that item is removed, the combo box does not + * redraw to clear the text area. The fix is to + * force a redraw. + */ + if ((style & SWT.READ_ONLY) != 0) { + int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0); + if (count == 0) OS.InvalidateRect (handle, null, false); + } +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li> + * </ul> + */ +public void remove (String string) { + 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. + * <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 (); + OS.SendMessage (handle, OS.CB_RESETCONTENT, 0, 0); + sendEvent (SWT.Modify); + // widget could be disposed at this point +} + +/** + * 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 receiver's selection changes. + * + * @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 (); + int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0); + if (0 <= index && index < count) { + int selection = OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0); + int code = OS.SendMessage (handle, OS.CB_SETCURSEL, index, 0); + if (code != OS.CB_ERR && code != selection) { + sendEvent (SWT.Modify); + // widget could be disposed at this point + } + } +} + +void setBackgroundPixel (int pixel) { + if (background == pixel) return; + super.setBackgroundPixel (pixel); + int hwndText = OS.GetDlgItem (handle, CBID_EDIT); + if (hwndText != 0) OS.InvalidateRect (hwndText, null, true); + int hwndList = OS.GetDlgItem (handle, CBID_LIST); + if (hwndList != 0) OS.InvalidateRect (hwndList, null, true); +} + +void setBounds (int x, int y, int width, int height, int flags) { + /* + * Feature in Windows. If the combo box has the CBS_DROPDOWN + * or CBS_DROPDOWNLIST style, Windows uses the height that the + * programmer sets in SetWindowPos () to control height of the + * drop down list. When the width is non-zero, Windows remembers + * this value and sets the height to be the height of the text + * field part of the combo box. If the width is zero, Windows + * allows the height to have any value. Therefore, when the + * programmer sets and then queries the height, the values can + * be different depending on the width. The problem occurs when + * the programmer uses computeSize () to determine the preferred + * height (always the height of the text field) and then uses + * this value to set the height of the combo box. The result + * is a combo box with a zero size drop down list. The fix, is + * to always set the height to show a fixed number of combo box + * items and ignore the height value that the programmer supplies. + */ + if ((style & SWT.DROP_DOWN) != 0) { + int textHeight = OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, -1, 0); + int itemHeight = OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, 0, 0); + height = textHeight + 6 + (itemHeight * 5) + 2; + /* + * Feature in Windows. When a drop down combo box is resized, + * the combo box resizes the height of the text field and uses + * the height provided in SetWindowPos () to determine the height + * of the drop down list. For some reason, the combo box redraws + * the whole area, not just the text field. The fix is to set the + * SWP_NOSIZE bits when the height of text field and the drop down + * list is the same as the requested height. + * + * NOTE: Setting the width of a combo box to zero does not update + * the width of the drop down control rect. If the width of the + * combo box is zero, then do not set SWP_NOSIZE. + */ + RECT rect = new RECT (); + OS.GetWindowRect (handle, rect); + if (rect.right - rect.left != 0) { + if (OS.SendMessage (handle, OS.CB_GETDROPPEDCONTROLRECT, 0, rect) != 0) { + int oldWidth = rect.right - rect.left, oldHeight = rect.bottom - rect.top; + if (oldWidth == width && oldHeight == height) flags |= OS.SWP_NOSIZE; + } + } + OS.SetWindowPos (handle, 0, x, y, width, height, flags); + return; + } + + /* + * Bug in Windows. If the combo box has the CBS_SIMPLE style, + * the list portion of the combo box is not redrawn when the + * combo box is resized. The fix is to force a redraw when + * the size has changed. + */ + if (parent.lpwp != null || (flags & OS.SWP_NOSIZE) != 0 || !OS.IsWindowVisible (handle)) { + super.setBounds (x, y, width, height, flags); + return; + } + RECT rect = new RECT (); + OS.GetWindowRect (handle, rect); + super.setBounds (x, y, width, height, flags); + int oldWidth = rect.right - rect.left, oldHeight = rect.bottom - rect.top; + if (oldWidth != width || oldHeight != height) { + if (OS.IsWinCE) { + int hwndText = OS.GetDlgItem (handle, CBID_EDIT); + if (hwndText != 0) OS.InvalidateRect (hwndText, null, true); + int hwndList = OS.GetDlgItem (handle, CBID_LIST); + if (hwndList != 0) OS.InvalidateRect (hwndList, null, true); + } else { + int uFlags = OS.RDW_ERASE | OS.RDW_INVALIDATE | OS.RDW_ALLCHILDREN; + OS.RedrawWindow (handle, null, 0, uFlags); + } + } +} + +void setEditable (boolean editable) { + error (SWT.ERROR_NOT_IMPLEMENTED); +} + +void setForegroundPixel (int pixel) { + if (foreground == pixel) return; + super.setForegroundPixel (pixel); + int hwndText = OS.GetDlgItem (handle, CBID_EDIT); + if (hwndText != 0) OS.InvalidateRect (hwndText, null, true); + int hwndList = OS.GetDlgItem (handle, CBID_LIST); + if (hwndList != 0) OS.InvalidateRect (hwndList, null, true); +} + +/** + * Sets the text of the item in the receiver's list at the given + * zero-relative index to the string argument. This is equivalent + * to <code>remove</code>'ing the old item at the index, and then + * <code>add</code>'ing the new item at that index. + * + * @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> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - 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 SWTError <ul> + * <li>ERROR_ITEM_NOT_REMOVED - if the remove operation fails because of an operating system failure</li> + * <li>ERROR_ITEM_NOT_ADDED - if the add operation fails because of an operating system failure</li> + * </ul> + */ +public void setItem (int index, String string) { + checkWidget (); + if (string == null) error (SWT.ERROR_NULL_ARGUMENT); + remove (index); + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the modify + * event that might be sent when the index is removed. + * If this happens, just exit. + */ + if (isDisposed ()) return; + add (string, index); +} + +/** + * Sets the receiver's list to be the given array of items. + * + * @param items the array 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> + * @exception SWTError <ul> + * <li>ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure</li> + * </ul> + */ +public void setItems (String [] items) { + checkWidget (); + if (items == null) error (SWT.ERROR_NULL_ARGUMENT); + OS.SendMessage (handle, OS.CB_RESETCONTENT, 0, 0); + int codePage = getCodePage (); + for (int i=0; i<items.length; i++) { + String string = items [i]; + TCHAR buffer = new TCHAR (codePage, string, true); + int code = OS.SendMessage (handle, OS.CB_ADDSTRING, 0, buffer); + if (code == OS.CB_ERR) error (SWT.ERROR_ITEM_NOT_ADDED); + if (code == OS.CB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED); + } + // widget could be disposed at this point + sendEvent (SWT.Modify); +} + +/** + * 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 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); + int bits = selection.x | (selection.y << 16); + OS.SendMessage (handle, OS.CB_SETEDITSEL, 0, bits); +} + +/** + * Sets the contents of the receiver's text field to the + * given string. + * <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 text 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 ((style & SWT.READ_ONLY) != 0) { + int index = indexOf (string); + if (index != -1) select (index); + return; + } + TCHAR buffer = new TCHAR (getCodePage (), string, true); + if (OS.SetWindowText (handle, buffer)) { + sendEvent (SWT.Modify); + // widget could be disposed at this point + } +} + +/** + * Sets the maximum number of characters that the receiver's + * text field is capable of holding to be the argument. + * + * @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> + */ +public void setTextLimit (int limit) { + checkWidget (); + if (limit == 0) error (SWT.ERROR_CANNOT_BE_ZERO); + OS.SendMessage (handle, OS.CB_LIMITTEXT, limit, 0); +} + +boolean translateAccelerator (MSG msg) { + if (super.translateAccelerator (msg)) return true; + + /* + * In order to see key events for the text widget in a combo box, + * filter the key events before they are dispatched to the text + * widget and invoke the cooresponding key handler for the combo + * box as if the key was sent directly to the combo box, not the + * text field. The key is still dispatched to the text widget, + * in the normal fashion. Note that we must call TranslateMessage + * in order to process accented keys properly. + */ + int hwndText = OS.GetDlgItem (handle, CBID_EDIT); + if (hwndText != 0 && msg.hwnd == hwndText) { + switch (msg.message) { + case OS.WM_CHAR: + case OS.WM_SYSCHAR: + case OS.WM_KEYDOWN: { + Display display = getDisplay (); + if (msg.message == OS.WM_KEYDOWN) { + if (display.translateTraversal (msg, this)) return true; + } else { + if (display.translateMnemonic (msg, this)) return true; + } + } + } + OS.TranslateMessage (msg); + switch (msg.message) { + case OS.WM_CHAR: WM_CHAR (msg.wParam, msg.lParam); break; + case OS.WM_IME_CHAR: WM_IME_CHAR (msg.wParam, msg.lParam); break; + case OS.WM_KEYDOWN: WM_KEYDOWN (msg.wParam, msg.lParam); break; + case OS.WM_KEYUP: WM_KEYUP (msg.wParam, msg.lParam); break; + case OS.WM_SYSCHAR: WM_SYSCHAR (msg.wParam, msg.lParam); break; + case OS.WM_SYSKEYDOWN: WM_SYSKEYDOWN (msg.wParam, msg.lParam); break; + case OS.WM_SYSKEYUP: WM_SYSKEYUP (msg.wParam, msg.lParam); break; + } + OS.DispatchMessage (msg); + return true; + } + return false; +} + +boolean translateTraversal (MSG msg) { + /* + * Feature in Windows. For some reason, when the + * user presses tab, return or escape, Windows beeps. + * The fix is to look for these keys and not call + * the window proc. + */ + int hwndText = OS.GetDlgItem (handle, CBID_EDIT); + if (hwndText != 0 && msg.hwnd == hwndText) { + switch (msg.wParam) { + case OS.VK_ESCAPE: + /* Allow the escape key to close the combo box */ + if (OS.SendMessage (handle, OS.CB_GETDROPPEDSTATE, 0, 0) != 0) { + return false; + } + // FALL THROUGH + case OS.VK_TAB: + case OS.VK_RETURN: + boolean translated = super.translateTraversal (msg); + if (!translated) { + if (sendKeyEvent (SWT.KeyDown, msg.message, msg.wParam, msg.lParam)) { + if (msg.wParam == OS.VK_RETURN) { + sendEvent (SWT.DefaultSelection); + // widget could be disposed at this point + } + } + } + return true; + } + } + return super.translateTraversal (msg); +} + +boolean traverseEscape () { + if (OS.SendMessage (handle, OS.CB_GETDROPPEDSTATE, 0, 0) != 0) { + OS.SendMessage (handle, OS.CB_SHOWDROPDOWN, 0, 0); + return true; + } + return super.traverseEscape (); +} + +int widgetExtStyle () { + return super.widgetExtStyle () & ~OS.WS_EX_NOINHERITLAYOUT; +} + +int widgetStyle () { + int bits = super.widgetStyle () | OS.CBS_AUTOHSCROLL | OS.CBS_NOINTEGRALHEIGHT | OS.WS_VSCROLL; + if ((style & SWT.SIMPLE) != 0) return bits | OS.CBS_SIMPLE; + if ((style & SWT.READ_ONLY) != 0) return bits | OS.CBS_DROPDOWNLIST; + return bits | OS.CBS_DROPDOWN; +} + +TCHAR windowClass () { + return ComboClass; +} + +int windowProc () { + return ComboProc; +} + +LRESULT WM_CHAR (int wParam, int lParam) { + LRESULT result = super.WM_CHAR (wParam, lParam); + if (result != null) return result; + if (wParam == OS.VK_RETURN) { + postEvent (SWT.DefaultSelection); + } + return result; +} + +LRESULT WM_CTLCOLOR (int wParam, int lParam) { + return wmColorChild (wParam, lParam); +} + +LRESULT WM_GETDLGCODE (int wParam, int lParam) { + int code = callWindowProc (OS.WM_GETDLGCODE, wParam, lParam); + return new LRESULT (code | OS.DLGC_WANTARROWS); +} + +LRESULT WM_KILLFOCUS (int wParam, int lParam) { + /* + * Return NULL - Focus notification is + * done in WM_COMMAND by CBN_KILLFOCUS. + */ + return null; +} + +LRESULT WM_SETFOCUS (int wParam, int lParam) { + /* + * Return NULL - Focus notification is + * done by WM_COMMAND with CBN_SETFOCUS. + */ + return null; +} + +LRESULT WM_SIZE (int wParam, int lParam) { + /* + * Feature in Windows. When an editable drop down combo box + * contains text that does not correspond to an item in the + * list, when the widget is resized, it selects the closest + * match from the list. The fix is to remember the original + * text and reset it after the widget is resized. + */ + if ((style & SWT.READ_ONLY) != 0 || (style & SWT.DROP_DOWN) == 0) { + return super.WM_SIZE (wParam, lParam); + } + int index = OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0); + boolean redraw = false; + TCHAR buffer = null; + int [] start = null, end = null; + if (index == OS.CB_ERR) { + int length = OS.GetWindowTextLength (handle); + if (length != 0) { + buffer = new TCHAR (getCodePage (), length + 1); + OS.GetWindowText (handle, buffer, length + 1); + start = new int [1]; end = new int [1]; + OS.SendMessage (handle, OS.CB_GETEDITSEL, start, end); + redraw = drawCount == 0 && OS.IsWindowVisible (handle); + if (redraw) setRedraw (false); + } + } + LRESULT result = super.WM_SIZE (wParam, lParam); + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the resize + * event. If this happens, end the processing of the + * Windows message by returning the result of the + * WM_SIZE message. + */ + if (isDisposed ()) return result; + if (buffer != null) { + OS.SetWindowText (handle, buffer); + int bits = start [0] | (end [0] << 16); + OS.SendMessage (handle, OS.CB_SETEDITSEL, 0, bits); + if (redraw) setRedraw (true); + } + return result; +} + +LRESULT wmCommandChild (int wParam, int lParam) { + int code = wParam >> 16; + switch (code) { + case OS.CBN_EDITCHANGE: + /* + * Feature in Windows. If the combo box list selection is + * queried using CB_GETCURSEL before the WM_COMMAND (with + * CBM_EDITCHANGE) returns, CB_GETCURSEL returns the previous + * selection in the list. It seems that the combo box sends + * the WM_COMMAND before it makes the selection in the list box + * match the entry field. The fix is remember that no selection + * in the list should exist in this case. + */ + noSelection = true; + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the modify + * event. If this happens, end the processing of the + * Windows message by returning zero as the result of + * the window proc. + */ + sendEvent (SWT.Modify); + if (isDisposed ()) return LRESULT.ZERO; + noSelection = false; + break; + case OS.CBN_SELCHANGE: + /* + * Feature in Windows. If the text in an editable combo box + * is queried using GetWindowText () before the WM_COMMAND + * (with CBM_SELCHANGE) returns, GetWindowText () returns is + * the previous text in the combo box. It seems that the combo + * box sends the WM_COMMAND before it updates the text field to + * match the list selection. The fix is to force the text field + * to match the list selection by re-selecting the list item. + */ + int index = OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0); + if (index != OS.CB_ERR) OS.SendMessage (handle, OS.CB_SETCURSEL, index, 0); + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the modify + * event. If this happens, end the processing of the + * Windows message by returning zero as the result of + * the window proc. + */ + sendEvent (SWT.Modify); + if (isDisposed ()) return LRESULT.ZERO; + postEvent (SWT.Selection); + break; + case OS.CBN_SETFOCUS: + case OS.CBN_KILLFOCUS: + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the focus + * event. If this happens, end the processing of the + * Windows message by returning zero as the result of + * the window proc. + */ + sendEvent (code == OS.CBN_SETFOCUS ? SWT.FocusIn : SWT.FocusOut); + if (isDisposed ()) return LRESULT.ZERO; + break; + } + return super.wmCommandChild (wParam, lParam); +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Composite.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Composite.java index 96548af04a..770516cbd0 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Composite.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Composite.java @@ -1,830 +1,830 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-
-/**
- * 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</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>
- * This class may be subclassed by custom control implementors
- * who are building controls that are constructed from aggregates
- * of other controls.
- * </p>
- *
- * @see Canvas
- */
-
-public class Composite extends Scrollable {
- Layout layout;
- int font;
- WINDOWPOS [] lpwp;
- Control [] tabList;
-
-/**
- * Prevents uninitialized instances from being created outside the package.
- */
-Composite () {
-}
-
-/**
- * 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 Widget#getStyle
- */
-public Composite (Composite parent, int style) {
- super (parent, style);
-}
-Control [] _getChildren () {
- int count = 0;
- int hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
- if (hwndChild == 0) return new Control [0];
- while (hwndChild != 0) {
- count++;
- hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
- }
- Control [] children = new Control [count];
- int index = 0;
- hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
- while (hwndChild != 0) {
- Control control = WidgetTable.get (hwndChild);
- if (control != null && control != this) {
- children [index++] = control;
- }
- hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
- }
- if (count == index) return children;
- Control [] newChildren = new Control [index];
- System.arraycopy (children, 0, newChildren, 0, index);
- return newChildren;
-}
-
-Control [] _getTabList () {
- if (tabList == null) return tabList;
- 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;
-}
-
-protected void checkSubclass () {
- /* Do nothing - Subclassing is allowed */
-}
-
-Control [] computeTabList () {
- Control 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];
- Control [] childList = child.computeTabList ();
- if (childList.length != 0) {
- Control [] newResult = new Control [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;
-}
-
-public Point computeSize (int wHint, int hHint, boolean changed) {
- checkWidget ();
- Point size;
- if (layout != null) {
- if (wHint == SWT.DEFAULT || hHint == SWT.DEFAULT) {
- size = layout.computeSize (this, wHint, hHint, changed);
- } else {
- size = new Point (wHint, hHint);
- }
- } else {
- size = minimumSize ();
- }
- 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);
-}
-
-void createHandle () {
- super.createHandle ();
- state |= CANVAS;
-}
-
-/**
- * Returns an array containing the receiver's children.
- * <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
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if 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 ();
-}
-
-int getChildrenCount () {
- /*
- * NOTE: The current implementation will count
- * non-registered children.
- */
- int count = 0;
- int hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
- while (hwndChild != 0) {
- count++;
- hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
- }
- return count;
-}
-
-/**
- * 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;
-}
-
-/**
- * Gets the last specified 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);
-}
-
-/**
- * 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>
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if 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 the argument is <code>true</code> the layout must not rely
- * on any cached information it is keeping about the children. If it
- * is <code>false</code> the layout may (potentially) simplify the
- * work it is doing by assuming that the state of the none of the
- * receiver's children has changed since the last layout.
- * If the receiver does not have a layout, do nothing.
- *
- * @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;
- setResizeChildren (false);
- layout.layout (this, changed);
- setResizeChildren (true);
-}
-
-Point minimumSize () {
- 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);
-}
-
-void releaseChildren () {
- Control [] children = _getChildren ();
- for (int i=0; i<children.length; i++) {
- Control child = children [i];
- if (!child.isDisposed ()) child.releaseResources ();
- }
-}
-
-void resizeChildren () {
- if (lpwp == null) return;
- do {
- WINDOWPOS [] currentLpwp = lpwp;
- lpwp = null;
- if (!resizeChildren (true, currentLpwp)) {
- resizeChildren (false, currentLpwp);
- }
- } while (lpwp != null);
-}
-
-boolean resizeChildren (boolean defer, WINDOWPOS [] pwp) {
- if (pwp == null) return true;
- int hdwp = 0;
- if (defer) {
- hdwp = OS.BeginDeferWindowPos (pwp.length);
- if (hdwp == 0) return false;
- }
- for (int i=0; i<pwp.length; i++) {
- WINDOWPOS wp = pwp [i];
- if (wp != null) {
- /*
- * This code is intentionally commented. All widgets that
- * are created by SWT have WS_CLIPSIBLINGS to ensure that
- * application code does not draw outside of the control.
- */
-// int count = parent.getChildrenCount ();
-// if (count > 1) {
-// int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
-// if ((bits & OS.WS_CLIPSIBLINGS) == 0) wp.flags |= OS.SWP_NOCOPYBITS;
-// }
- if (defer) {
- hdwp = OS.DeferWindowPos (hdwp, wp.hwnd, 0, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
- if (hdwp == 0) return false;
- } else {
- OS.SetWindowPos (wp.hwnd, 0, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
- }
- }
- }
- if (defer) return OS.EndDeferWindowPos (hdwp);
- return true;
-}
-
-void releaseWidget () {
- releaseChildren ();
- super.releaseWidget ();
- layout = null;
- tabList = null;
- lpwp = null;
-}
-
-public boolean setFocus () {
- checkWidget ();
- if ((style & SWT.NO_FOCUS) != 0) return false;
- Control [] children = _getChildren ();
- for (int i=0; i<children.length; i++) {
- Control child = children [i];
- if (child.setRadioFocus ()) return true;
- }
- for (int i=0; i<children.length; i++) {
- Control child = children [i];
- if (child.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;
-}
-
-/**
- * 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);
- /*
- * This code is intentionally commented.
- * Tab lists are currently only supported
- * for the direct children of a composite.
- */
-// Shell shell = control.getShell ();
-// while (control != shell && control != this) {
-// control = control.parent;
-// }
-// if (control != this) error (SWT.ERROR_INVALID_PARENT);
- 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;
-}
-
-void setResizeChildren (boolean resize) {
- if (resize) {
- resizeChildren ();
- } else {
- int count = getChildrenCount ();
- if (count > 1 && lpwp == null) {
- lpwp = new WINDOWPOS [count];
- }
- }
-}
-
-boolean setTabGroupFocus () {
- if (isTabItem ()) return setTabItemFocus ();
- if ((style & SWT.NO_FOCUS) == 0) {
- boolean takeFocus = true;
- 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.setRadioFocus ()) return true;
- }
- for (int i=0; i<children.length; i++) {
- Control child = children [i];
- if (child.isTabItem () && child.setTabItemFocus ()) return true;
- }
- return false;
-}
-
-boolean setTabItemFocus () {
- if ((style & SWT.NO_FOCUS) == 0) {
- boolean takeFocus = true;
- if ((state & CANVAS) != 0) takeFocus = hooksKeys ();
- if (takeFocus) {
- if (!isShowing ()) return false;
- if (forceFocus ()) return true;
- }
- }
- return super.setTabItemFocus ();
-}
-
-String toolTipText (NMTTDISPINFO hdr) {
- if ((hdr.uFlags & OS.TTF_IDISHWND) == 0) {
- return null;
- }
- int hwnd = hdr.idFrom;
- if (hwnd == 0) return null;
- Control control = WidgetTable.get (hwnd);
- if (control == null) return null;
- return control.toolTipText;
-}
-
-boolean translateMnemonic (char key) {
- if (super.translateMnemonic (key)) return true;
- Control [] children = _getChildren ();
- for (int i=0; i<children.length; i++) {
- Control child = children [i];
- if (child.translateMnemonic (key)) return true;
- }
- return false;
-}
-
-void updateFont (Font oldFont, Font newFont) {
- Control [] children = _getChildren ();
- for (int i=0; i<children.length; i++) {
- Control control = children [i];
- if (!control.isDisposed ()) {
- control.updateFont (oldFont, newFont);
- }
- }
- super.updateFont (oldFont, newFont);
- layout (true);
-}
-
-int widgetStyle () {
- /* Force clipping of children by setting WS_CLIPCHILDREN */
- return super.widgetStyle () | OS.WS_CLIPCHILDREN;
-}
-
-LRESULT WM_ERASEBKGND (int wParam, int lParam) {
- LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
- if (result != null) return result;
- if ((state & CANVAS) != 0) {
- if ((style & SWT.NO_BACKGROUND) != 0) return LRESULT.ONE;
- }
- return result;
-}
-
-LRESULT WM_GETDLGCODE (int wParam, int lParam) {
- LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
- if (result != null) return result;
- if ((state & CANVAS) != 0) {
- if ((style & SWT.NO_FOCUS) != 0) return new LRESULT (OS.DLGC_STATIC);
- if (hooksKeys ()) {
- int flags = OS.DLGC_WANTALLKEYS | OS.DLGC_WANTARROWS | OS.DLGC_WANTTAB;
- return new LRESULT (flags);
- }
- int count = getChildrenCount ();
- if (count != 0) return new LRESULT (OS.DLGC_STATIC);
- }
- return result;
-}
-
-LRESULT WM_GETFONT (int wParam, int lParam) {
- LRESULT result = super.WM_GETFONT (wParam, lParam);
- if (result != null) return result;
- int code = callWindowProc (OS.WM_GETFONT, wParam, lParam);
- if (code != 0) return new LRESULT (code);
- if (font == 0) font = defaultFont ();
- return new LRESULT (font);
-}
-
-LRESULT WM_LBUTTONDOWN (int wParam, int lParam) {
- LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam);
-
- /* Set focus for a canvas with no children */
- if ((state & CANVAS) != 0) {
- if ((style & SWT.NO_FOCUS) != 0) return result;
- if (OS.GetWindow (handle, OS.GW_CHILD) == 0) setFocus ();
- }
- return result;
-}
-
-LRESULT WM_NOTIFY (int wParam, int lParam) {
- if (!OS.IsWinCE) {
- NMHDR hdr = new NMHDR ();
- OS.MoveMemory (hdr, lParam, NMHDR.sizeof);
- switch (hdr.code) {
- /*
- * Feature in Windows. When the tool tip control is
- * created, the parent of the tool tip is the shell.
- * If SetParent () is used to reparent the tool bar
- * into a new shell, the tool tip is not reparented
- * and pops up underneath the new shell. The fix is
- * to make sure the tool tip is a topmost window.
- */
- case OS.TTN_SHOW:
- case OS.TTN_POP: {
- /*
- * Bug in Windows 98 and NT. Setting the tool tip to be the
- * top most window using HWND_TOPMOST can result in a parent
- * dialog shell being moved behind its parent if the dialog
- * has a sibling that is currently on top. The fix is to lock
- * the z-order of the active window.
- */
- Display display = getDisplay ();
- display.lockActiveWindow = true;
- int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOSIZE;
- int hwndInsertAfter = hdr.code == OS.TTN_SHOW ? OS.HWND_TOPMOST : OS.HWND_NOTOPMOST;
- OS.SetWindowPos (hdr.hwndFrom, hwndInsertAfter, 0, 0, 0, 0, flags);
- display.lockActiveWindow = false;
- break;
- }
- /*
- * Bug in Windows 98. For some reason, the tool bar control
- * sends both TTN_GETDISPINFOW and TTN_GETDISPINFOA to get
- * the tool tip text and the tab folder control sends only
- * TTN_GETDISPINFOW. The fix is to handle only TTN_GETDISPINFOW,
- * even though it should never be sent on Windows 98.
- *
- * NOTE: Because the size of NMTTDISPINFO differs between
- * Windows 98 and NT, guard against the case where the wrong
- * kind of message occurs by inlining the memory moves and
- * the UNICODE conversion code.
- */
- case OS.TTN_GETDISPINFOA:
- case OS.TTN_GETDISPINFOW: {
- NMTTDISPINFO lpnmtdi = new NMTTDISPINFO ();
- if (hdr.code == OS.TTN_GETDISPINFOA) {
- OS.MoveMemoryA (lpnmtdi, lParam, NMTTDISPINFO.sizeofA);
- } else {
- OS.MoveMemoryW (lpnmtdi, lParam, NMTTDISPINFO.sizeofW);
- }
- String string = toolTipText (lpnmtdi);
- if (string != null) {
- Shell shell = getShell ();
- string = Display.withCrLf (string);
- int length = string.length ();
- char [] chars = new char [length + 1];
- string.getChars (0, length, chars, 0);
- if (hdr.code == OS.TTN_GETDISPINFOA) {
- byte [] bytes = new byte [chars.length * 2];
- OS.WideCharToMultiByte (OS.CP_ACP, 0, chars, chars.length, bytes, bytes.length, null, null);
- shell.setToolTipText (lpnmtdi, bytes);
- OS.MoveMemoryA (lParam, lpnmtdi, NMTTDISPINFO.sizeofA);
- } else {
- shell.setToolTipText (lpnmtdi, chars);
- OS.MoveMemoryW (lParam, lpnmtdi, NMTTDISPINFO.sizeofW);
- }
- return LRESULT.ZERO;
- }
- break;
- }
- }
- }
- return super.WM_NOTIFY (wParam, lParam);
-}
-
-LRESULT WM_PAINT (int wParam, int lParam) {
- if ((state & CANVAS) == 0) {
- return super.WM_PAINT (wParam, lParam);
- }
-
- /*
- * This code is intentionally commented. Don't exit
- * early because the background must still be painted,
- * even though no application code will be painting
- * the widget.
- *
- * Do not uncomment this code.
- */
-// if (!hooks (SWT.Paint)) return null;
-
- /* Get the damage */
- int [] lpRgnData = null;
- boolean isComplex = false;
- boolean exposeRegion = false;
- if ((style & SWT.NO_MERGE_PAINTS) != 0) {
- int rgn = OS.CreateRectRgn (0, 0, 0, 0);
- isComplex = OS.GetUpdateRgn (handle, rgn, false) == OS.COMPLEXREGION;
- if (isComplex) {
- int nBytes = OS.GetRegionData (rgn, 0, null);
- lpRgnData = new int [nBytes / 4];
- exposeRegion = OS.GetRegionData (rgn, nBytes, lpRgnData) != 0;
- }
- OS.DeleteObject (rgn);
- }
-
- /* Set the clipping bits */
- int oldBits = 0;
- if (!OS.IsWinCE) {
- oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- int newBits = oldBits | OS.WS_CLIPSIBLINGS | OS.WS_CLIPCHILDREN;
- OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
- }
-
- /* Create the paint GC */
- PAINTSTRUCT ps = new PAINTSTRUCT ();
- GCData data = new GCData ();
- data.ps = ps;
- GC gc = GC.win32_new (this, data);
- int hDC = gc.handle;
-
- /* Send the paint event */
- Event event = new Event ();
- event.gc = gc;
- if (isComplex && exposeRegion) {
- RECT rect = new RECT ();
- int count = lpRgnData [2];
- for (int i=0; i<count; i++) {
- OS.SetRect (rect,
- lpRgnData [8 + (i << 2)],
- lpRgnData [8 + (i << 2) + 1],
- lpRgnData [8 + (i << 2) + 2],
- lpRgnData [8 + (i << 2) + 3]);
- if ((style & SWT.NO_BACKGROUND) == 0) {
- drawBackground (hDC, rect);
- }
- event.x = rect.left;
- event.y = rect.top;
- event.width = rect.right - rect.left;
- event.height = rect.bottom - rect.top;
- event.count = count - 1 - i;
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the paint
- * event. If this happens, attempt to give back the
- * paint GC anyways because this is a scarce Windows
- * resource.
- */
- sendEvent (SWT.Paint, event);
- if (isDisposed ()) break;
- }
- } else {
- if ((style & SWT.NO_BACKGROUND) == 0) {
- RECT rect = new RECT ();
- OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
- drawBackground (hDC, rect);
- }
- event.x = ps.left;
- event.y = ps.top;
- event.width = ps.right - ps.left;
- event.height = ps.bottom - ps.top;
- sendEvent (SWT.Paint, event);
- }
- // widget could be disposed at this point
-
- /* Dispose the paint GC */
- event.gc = null;
- gc.dispose ();
-
- if (!OS.IsWinCE) {
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the paint
- * event. If this happens, don't attempt to restore
- * the style.
- */
- if (!isDisposed ()) {
- OS.SetWindowLong (handle, OS.GWL_STYLE, oldBits);
- }
- }
- return LRESULT.ZERO;
-}
-
-LRESULT WM_SETFONT (int wParam, int lParam) {
- return super.WM_SETFONT (font = wParam, lParam);
-}
-
-LRESULT WM_SIZE (int wParam, int lParam) {
-
- /* Begin deferred window positioning */
- setResizeChildren (false);
-
- /* Resize and Layout */
- LRESULT result = super.WM_SIZE (wParam, lParam);
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the resize
- * event. If this happens, end the processing of the
- * Windows message by returning the result of the
- * WM_SIZE message.
- */
- if (isDisposed ()) return result;
- if (layout != null) layout.layout (this, false);
-
- /* End deferred window positioning */
- setResizeChildren (true);
-
- /* Damage the widget to cause a repaint */
- if ((state & CANVAS) != 0) {
- if ((style & SWT.NO_REDRAW_RESIZE) == 0) {
- if (hooks (SWT.Paint)) {
- OS.InvalidateRect (handle, null, true);
- }
- }
- }
- return result;
-}
-
-LRESULT WM_SYSCOLORCHANGE (int wParam, int lParam) {
- Control [] children = _getChildren ();
- for (int i=0; i<children.length; i++) {
- int hwndChild = children [i].handle;
- OS.SendMessage (hwndChild, OS.WM_SYSCOLORCHANGE, 0, 0);
- }
- return null;
-}
-
-LRESULT WM_SYSCOMMAND (int wParam, int lParam) {
- LRESULT result = super.WM_SYSCOMMAND (wParam, lParam);
- if (result != null) return result;
-
- /*
- * Check to see if the command is a system command or
- * a user menu item that was added to the system menu.
- */
- if ((wParam & 0xF000) == 0) return result;
-
- /*
- * Bug in Windows. When a vertical or horizontal scroll bar is
- * hidden or shown while the opposite scroll bar is being scrolled
- * by the user (with WM_HSCROLL code SB_LINEDOWN), the scroll bar
- * does not redraw properly. The fix is to detect this case and
- * redraw the non-client area.
- */
- if (!OS.IsWinCE) {
- int cmd = wParam & 0xFFF0;
- switch (cmd) {
- case OS.SC_HSCROLL:
- case OS.SC_VSCROLL:
- boolean showHBar = horizontalBar != null && horizontalBar.getVisible ();
- boolean showVBar = verticalBar != null && verticalBar.getVisible ();
- int code = callWindowProc (OS.WM_SYSCOMMAND, wParam, lParam);
- if ((showHBar != (horizontalBar != null && horizontalBar.getVisible ())) ||
- (showVBar != (verticalBar != null && verticalBar.getVisible ()))) {
- int flags = OS.RDW_FRAME | OS.RDW_INVALIDATE | OS.RDW_UPDATENOW;
- OS.RedrawWindow (handle, null, 0, flags);
- }
- if (code == 0) return LRESULT.ZERO;
- return new LRESULT (code);
- }
- }
- /* Return the result */
- return result;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; + +/** + * 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</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> + * This class may be subclassed by custom control implementors + * who are building controls that are constructed from aggregates + * of other controls. + * </p> + * + * @see Canvas + */ + +public class Composite extends Scrollable { + Layout layout; + int font; + WINDOWPOS [] lpwp; + Control [] tabList; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Composite () { +} + +/** + * 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 Widget#getStyle + */ +public Composite (Composite parent, int style) { + super (parent, style); +} +Control [] _getChildren () { + int count = 0; + int hwndChild = OS.GetWindow (handle, OS.GW_CHILD); + if (hwndChild == 0) return new Control [0]; + while (hwndChild != 0) { + count++; + hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT); + } + Control [] children = new Control [count]; + int index = 0; + hwndChild = OS.GetWindow (handle, OS.GW_CHILD); + while (hwndChild != 0) { + Control control = WidgetTable.get (hwndChild); + if (control != null && control != this) { + children [index++] = control; + } + hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT); + } + if (count == index) return children; + Control [] newChildren = new Control [index]; + System.arraycopy (children, 0, newChildren, 0, index); + return newChildren; +} + +Control [] _getTabList () { + if (tabList == null) return tabList; + 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; +} + +protected void checkSubclass () { + /* Do nothing - Subclassing is allowed */ +} + +Control [] computeTabList () { + Control 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]; + Control [] childList = child.computeTabList (); + if (childList.length != 0) { + Control [] newResult = new Control [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; +} + +public Point computeSize (int wHint, int hHint, boolean changed) { + checkWidget (); + Point size; + if (layout != null) { + if (wHint == SWT.DEFAULT || hHint == SWT.DEFAULT) { + size = layout.computeSize (this, wHint, hHint, changed); + } else { + size = new Point (wHint, hHint); + } + } else { + size = minimumSize (); + } + 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); +} + +void createHandle () { + super.createHandle (); + state |= CANVAS; +} + +/** + * Returns an array containing the receiver's children. + * <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 + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if 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 (); +} + +int getChildrenCount () { + /* + * NOTE: The current implementation will count + * non-registered children. + */ + int count = 0; + int hwndChild = OS.GetWindow (handle, OS.GW_CHILD); + while (hwndChild != 0) { + count++; + hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT); + } + return count; +} + +/** + * 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; +} + +/** + * Gets the last specified 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); +} + +/** + * 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> + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if 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 the argument is <code>true</code> the layout must not rely + * on any cached information it is keeping about the children. If it + * is <code>false</code> the layout may (potentially) simplify the + * work it is doing by assuming that the state of the none of the + * receiver's children has changed since the last layout. + * If the receiver does not have a layout, do nothing. + * + * @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; + setResizeChildren (false); + layout.layout (this, changed); + setResizeChildren (true); +} + +Point minimumSize () { + 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); +} + +void releaseChildren () { + Control [] children = _getChildren (); + for (int i=0; i<children.length; i++) { + Control child = children [i]; + if (!child.isDisposed ()) child.releaseResources (); + } +} + +void resizeChildren () { + if (lpwp == null) return; + do { + WINDOWPOS [] currentLpwp = lpwp; + lpwp = null; + if (!resizeChildren (true, currentLpwp)) { + resizeChildren (false, currentLpwp); + } + } while (lpwp != null); +} + +boolean resizeChildren (boolean defer, WINDOWPOS [] pwp) { + if (pwp == null) return true; + int hdwp = 0; + if (defer) { + hdwp = OS.BeginDeferWindowPos (pwp.length); + if (hdwp == 0) return false; + } + for (int i=0; i<pwp.length; i++) { + WINDOWPOS wp = pwp [i]; + if (wp != null) { + /* + * This code is intentionally commented. All widgets that + * are created by SWT have WS_CLIPSIBLINGS to ensure that + * application code does not draw outside of the control. + */ +// int count = parent.getChildrenCount (); +// if (count > 1) { +// int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); +// if ((bits & OS.WS_CLIPSIBLINGS) == 0) wp.flags |= OS.SWP_NOCOPYBITS; +// } + if (defer) { + hdwp = OS.DeferWindowPos (hdwp, wp.hwnd, 0, wp.x, wp.y, wp.cx, wp.cy, wp.flags); + if (hdwp == 0) return false; + } else { + OS.SetWindowPos (wp.hwnd, 0, wp.x, wp.y, wp.cx, wp.cy, wp.flags); + } + } + } + if (defer) return OS.EndDeferWindowPos (hdwp); + return true; +} + +void releaseWidget () { + releaseChildren (); + super.releaseWidget (); + layout = null; + tabList = null; + lpwp = null; +} + +public boolean setFocus () { + checkWidget (); + if ((style & SWT.NO_FOCUS) != 0) return false; + Control [] children = _getChildren (); + for (int i=0; i<children.length; i++) { + Control child = children [i]; + if (child.setRadioFocus ()) return true; + } + for (int i=0; i<children.length; i++) { + Control child = children [i]; + if (child.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; +} + +/** + * 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); + /* + * This code is intentionally commented. + * Tab lists are currently only supported + * for the direct children of a composite. + */ +// Shell shell = control.getShell (); +// while (control != shell && control != this) { +// control = control.parent; +// } +// if (control != this) error (SWT.ERROR_INVALID_PARENT); + 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; +} + +void setResizeChildren (boolean resize) { + if (resize) { + resizeChildren (); + } else { + int count = getChildrenCount (); + if (count > 1 && lpwp == null) { + lpwp = new WINDOWPOS [count]; + } + } +} + +boolean setTabGroupFocus () { + if (isTabItem ()) return setTabItemFocus (); + if ((style & SWT.NO_FOCUS) == 0) { + boolean takeFocus = true; + 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.setRadioFocus ()) return true; + } + for (int i=0; i<children.length; i++) { + Control child = children [i]; + if (child.isTabItem () && child.setTabItemFocus ()) return true; + } + return false; +} + +boolean setTabItemFocus () { + if ((style & SWT.NO_FOCUS) == 0) { + boolean takeFocus = true; + if ((state & CANVAS) != 0) takeFocus = hooksKeys (); + if (takeFocus) { + if (!isShowing ()) return false; + if (forceFocus ()) return true; + } + } + return super.setTabItemFocus (); +} + +String toolTipText (NMTTDISPINFO hdr) { + if ((hdr.uFlags & OS.TTF_IDISHWND) == 0) { + return null; + } + int hwnd = hdr.idFrom; + if (hwnd == 0) return null; + Control control = WidgetTable.get (hwnd); + if (control == null) return null; + return control.toolTipText; +} + +boolean translateMnemonic (char key) { + if (super.translateMnemonic (key)) return true; + Control [] children = _getChildren (); + for (int i=0; i<children.length; i++) { + Control child = children [i]; + if (child.translateMnemonic (key)) return true; + } + return false; +} + +void updateFont (Font oldFont, Font newFont) { + Control [] children = _getChildren (); + for (int i=0; i<children.length; i++) { + Control control = children [i]; + if (!control.isDisposed ()) { + control.updateFont (oldFont, newFont); + } + } + super.updateFont (oldFont, newFont); + layout (true); +} + +int widgetStyle () { + /* Force clipping of children by setting WS_CLIPCHILDREN */ + return super.widgetStyle () | OS.WS_CLIPCHILDREN; +} + +LRESULT WM_ERASEBKGND (int wParam, int lParam) { + LRESULT result = super.WM_ERASEBKGND (wParam, lParam); + if (result != null) return result; + if ((state & CANVAS) != 0) { + if ((style & SWT.NO_BACKGROUND) != 0) return LRESULT.ONE; + } + return result; +} + +LRESULT WM_GETDLGCODE (int wParam, int lParam) { + LRESULT result = super.WM_GETDLGCODE (wParam, lParam); + if (result != null) return result; + if ((state & CANVAS) != 0) { + if ((style & SWT.NO_FOCUS) != 0) return new LRESULT (OS.DLGC_STATIC); + if (hooksKeys ()) { + int flags = OS.DLGC_WANTALLKEYS | OS.DLGC_WANTARROWS | OS.DLGC_WANTTAB; + return new LRESULT (flags); + } + int count = getChildrenCount (); + if (count != 0) return new LRESULT (OS.DLGC_STATIC); + } + return result; +} + +LRESULT WM_GETFONT (int wParam, int lParam) { + LRESULT result = super.WM_GETFONT (wParam, lParam); + if (result != null) return result; + int code = callWindowProc (OS.WM_GETFONT, wParam, lParam); + if (code != 0) return new LRESULT (code); + if (font == 0) font = defaultFont (); + return new LRESULT (font); +} + +LRESULT WM_LBUTTONDOWN (int wParam, int lParam) { + LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam); + + /* Set focus for a canvas with no children */ + if ((state & CANVAS) != 0) { + if ((style & SWT.NO_FOCUS) != 0) return result; + if (OS.GetWindow (handle, OS.GW_CHILD) == 0) setFocus (); + } + return result; +} + +LRESULT WM_NOTIFY (int wParam, int lParam) { + if (!OS.IsWinCE) { + NMHDR hdr = new NMHDR (); + OS.MoveMemory (hdr, lParam, NMHDR.sizeof); + switch (hdr.code) { + /* + * Feature in Windows. When the tool tip control is + * created, the parent of the tool tip is the shell. + * If SetParent () is used to reparent the tool bar + * into a new shell, the tool tip is not reparented + * and pops up underneath the new shell. The fix is + * to make sure the tool tip is a topmost window. + */ + case OS.TTN_SHOW: + case OS.TTN_POP: { + /* + * Bug in Windows 98 and NT. Setting the tool tip to be the + * top most window using HWND_TOPMOST can result in a parent + * dialog shell being moved behind its parent if the dialog + * has a sibling that is currently on top. The fix is to lock + * the z-order of the active window. + */ + Display display = getDisplay (); + display.lockActiveWindow = true; + int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOSIZE; + int hwndInsertAfter = hdr.code == OS.TTN_SHOW ? OS.HWND_TOPMOST : OS.HWND_NOTOPMOST; + OS.SetWindowPos (hdr.hwndFrom, hwndInsertAfter, 0, 0, 0, 0, flags); + display.lockActiveWindow = false; + break; + } + /* + * Bug in Windows 98. For some reason, the tool bar control + * sends both TTN_GETDISPINFOW and TTN_GETDISPINFOA to get + * the tool tip text and the tab folder control sends only + * TTN_GETDISPINFOW. The fix is to handle only TTN_GETDISPINFOW, + * even though it should never be sent on Windows 98. + * + * NOTE: Because the size of NMTTDISPINFO differs between + * Windows 98 and NT, guard against the case where the wrong + * kind of message occurs by inlining the memory moves and + * the UNICODE conversion code. + */ + case OS.TTN_GETDISPINFOA: + case OS.TTN_GETDISPINFOW: { + NMTTDISPINFO lpnmtdi = new NMTTDISPINFO (); + if (hdr.code == OS.TTN_GETDISPINFOA) { + OS.MoveMemoryA (lpnmtdi, lParam, NMTTDISPINFO.sizeofA); + } else { + OS.MoveMemoryW (lpnmtdi, lParam, NMTTDISPINFO.sizeofW); + } + String string = toolTipText (lpnmtdi); + if (string != null) { + Shell shell = getShell (); + string = Display.withCrLf (string); + int length = string.length (); + char [] chars = new char [length + 1]; + string.getChars (0, length, chars, 0); + if (hdr.code == OS.TTN_GETDISPINFOA) { + byte [] bytes = new byte [chars.length * 2]; + OS.WideCharToMultiByte (OS.CP_ACP, 0, chars, chars.length, bytes, bytes.length, null, null); + shell.setToolTipText (lpnmtdi, bytes); + OS.MoveMemoryA (lParam, lpnmtdi, NMTTDISPINFO.sizeofA); + } else { + shell.setToolTipText (lpnmtdi, chars); + OS.MoveMemoryW (lParam, lpnmtdi, NMTTDISPINFO.sizeofW); + } + return LRESULT.ZERO; + } + break; + } + } + } + return super.WM_NOTIFY (wParam, lParam); +} + +LRESULT WM_PAINT (int wParam, int lParam) { + if ((state & CANVAS) == 0) { + return super.WM_PAINT (wParam, lParam); + } + + /* + * This code is intentionally commented. Don't exit + * early because the background must still be painted, + * even though no application code will be painting + * the widget. + * + * Do not uncomment this code. + */ +// if (!hooks (SWT.Paint)) return null; + + /* Get the damage */ + int [] lpRgnData = null; + boolean isComplex = false; + boolean exposeRegion = false; + if ((style & SWT.NO_MERGE_PAINTS) != 0) { + int rgn = OS.CreateRectRgn (0, 0, 0, 0); + isComplex = OS.GetUpdateRgn (handle, rgn, false) == OS.COMPLEXREGION; + if (isComplex) { + int nBytes = OS.GetRegionData (rgn, 0, null); + lpRgnData = new int [nBytes / 4]; + exposeRegion = OS.GetRegionData (rgn, nBytes, lpRgnData) != 0; + } + OS.DeleteObject (rgn); + } + + /* Set the clipping bits */ + int oldBits = 0; + if (!OS.IsWinCE) { + oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE); + int newBits = oldBits | OS.WS_CLIPSIBLINGS | OS.WS_CLIPCHILDREN; + OS.SetWindowLong (handle, OS.GWL_STYLE, newBits); + } + + /* Create the paint GC */ + PAINTSTRUCT ps = new PAINTSTRUCT (); + GCData data = new GCData (); + data.ps = ps; + GC gc = GC.win32_new (this, data); + int hDC = gc.handle; + + /* Send the paint event */ + Event event = new Event (); + event.gc = gc; + if (isComplex && exposeRegion) { + RECT rect = new RECT (); + int count = lpRgnData [2]; + for (int i=0; i<count; i++) { + OS.SetRect (rect, + lpRgnData [8 + (i << 2)], + lpRgnData [8 + (i << 2) + 1], + lpRgnData [8 + (i << 2) + 2], + lpRgnData [8 + (i << 2) + 3]); + if ((style & SWT.NO_BACKGROUND) == 0) { + drawBackground (hDC, rect); + } + event.x = rect.left; + event.y = rect.top; + event.width = rect.right - rect.left; + event.height = rect.bottom - rect.top; + event.count = count - 1 - i; + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the paint + * event. If this happens, attempt to give back the + * paint GC anyways because this is a scarce Windows + * resource. + */ + sendEvent (SWT.Paint, event); + if (isDisposed ()) break; + } + } else { + if ((style & SWT.NO_BACKGROUND) == 0) { + RECT rect = new RECT (); + OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom); + drawBackground (hDC, rect); + } + event.x = ps.left; + event.y = ps.top; + event.width = ps.right - ps.left; + event.height = ps.bottom - ps.top; + sendEvent (SWT.Paint, event); + } + // widget could be disposed at this point + + /* Dispose the paint GC */ + event.gc = null; + gc.dispose (); + + if (!OS.IsWinCE) { + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the paint + * event. If this happens, don't attempt to restore + * the style. + */ + if (!isDisposed ()) { + OS.SetWindowLong (handle, OS.GWL_STYLE, oldBits); + } + } + return LRESULT.ZERO; +} + +LRESULT WM_SETFONT (int wParam, int lParam) { + return super.WM_SETFONT (font = wParam, lParam); +} + +LRESULT WM_SIZE (int wParam, int lParam) { + + /* Begin deferred window positioning */ + setResizeChildren (false); + + /* Resize and Layout */ + LRESULT result = super.WM_SIZE (wParam, lParam); + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the resize + * event. If this happens, end the processing of the + * Windows message by returning the result of the + * WM_SIZE message. + */ + if (isDisposed ()) return result; + if (layout != null) layout.layout (this, false); + + /* End deferred window positioning */ + setResizeChildren (true); + + /* Damage the widget to cause a repaint */ + if ((state & CANVAS) != 0) { + if ((style & SWT.NO_REDRAW_RESIZE) == 0) { + if (hooks (SWT.Paint)) { + OS.InvalidateRect (handle, null, true); + } + } + } + return result; +} + +LRESULT WM_SYSCOLORCHANGE (int wParam, int lParam) { + Control [] children = _getChildren (); + for (int i=0; i<children.length; i++) { + int hwndChild = children [i].handle; + OS.SendMessage (hwndChild, OS.WM_SYSCOLORCHANGE, 0, 0); + } + return null; +} + +LRESULT WM_SYSCOMMAND (int wParam, int lParam) { + LRESULT result = super.WM_SYSCOMMAND (wParam, lParam); + if (result != null) return result; + + /* + * Check to see if the command is a system command or + * a user menu item that was added to the system menu. + */ + if ((wParam & 0xF000) == 0) return result; + + /* + * Bug in Windows. When a vertical or horizontal scroll bar is + * hidden or shown while the opposite scroll bar is being scrolled + * by the user (with WM_HSCROLL code SB_LINEDOWN), the scroll bar + * does not redraw properly. The fix is to detect this case and + * redraw the non-client area. + */ + if (!OS.IsWinCE) { + int cmd = wParam & 0xFFF0; + switch (cmd) { + case OS.SC_HSCROLL: + case OS.SC_VSCROLL: + boolean showHBar = horizontalBar != null && horizontalBar.getVisible (); + boolean showVBar = verticalBar != null && verticalBar.getVisible (); + int code = callWindowProc (OS.WM_SYSCOMMAND, wParam, lParam); + if ((showHBar != (horizontalBar != null && horizontalBar.getVisible ())) || + (showVBar != (verticalBar != null && verticalBar.getVisible ()))) { + int flags = OS.RDW_FRAME | OS.RDW_INVALIDATE | OS.RDW_UPDATENOW; + OS.RedrawWindow (handle, null, 0, flags); + } + if (code == 0) return LRESULT.ZERO; + return new LRESULT (code); + } + } + /* Return the result */ + return result; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java index 12d66dd630..c601004f37 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java @@ -1,4224 +1,4224 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.events.*;
-import org.eclipse.swt.accessibility.*;
-
-/**
- * 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>FocusIn, FocusOut, Help, KeyDown, KeyUp, MouseDoubleClick, MouseDown, MouseEnter,
- * MouseExit, MouseHover, MouseUp, MouseMove, Move, Paint, Resize</dd>
- * </dl>
- * <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>
- *
- * Note: Only one of LEFT_TO_RIGHT and RIGHT_TO_LEFT may be specified.
- */
-
-public abstract class Control extends Widget implements Drawable {
- /**
- * the handle to the OS resource
- * (Warning: This field is platform dependent)
- */
- public int handle;
-
- Composite parent;
- int drawCount, hCursor;
- int foreground, background;
- Menu menu;
- String toolTipText;
- Object layoutData;
- Accessible accessible;
-
- static final short [] ACCENTS = new short [] {'~', '`', '\'', '^', '"'};
-
-/**
- * Prevents uninitialized instances from being created outside the package.
- */
-Control () {
-}
-
-/**
- * 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 Widget#checkSubclass
- * @see Widget#getStyle
- */
-public Control (Composite parent, int style) {
- super (parent, style);
- this.parent = parent;
- createWidget ();
-}
-
-/**
- * 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 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.
- *
- * @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 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 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);
-}
-
-/**
- * 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);
-}
-
-abstract int callWindowProc (int msg, int wParam, int lParam);
-
-void checkOrientation (Widget parent) {
- super.checkOrientation (parent);
- if ((style & SWT.RIGHT_TO_LEFT) != 0) style |= SWT.MIRRORED;
-}
-
-/**
- * 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
- * @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
- * @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);
-}
-
-Control computeTabGroup () {
- if (isTabGroup ()) return this;
- return parent.computeTabGroup ();
-}
-
-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 ();
-}
-
-Control [] computeTabList () {
- if (isTabGroup ()) {
- if (getVisible () && getEnabled ()) {
- return new Control [] {this};
- }
- }
- return new Control [0];
-}
-
-void createHandle () {
- int hwndParent = 0;
- if (handle != 0) {
- hwndParent = handle;
- } else {
- if (parent != null) hwndParent = parent.handle;
- }
- handle = OS.CreateWindowEx (
- widgetExtStyle (),
- windowClass (),
- null,
- widgetStyle (),
- OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
- hwndParent,
- 0,
- OS.GetModuleHandle (null),
- null);
- if (handle == 0) error (SWT.ERROR_NO_HANDLES);
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & OS.WS_CHILD) != 0) {
- OS.SetWindowLong (handle, OS.GWL_ID, handle);
- }
- if (OS.IsDBLocale && parent != null) {
- int hIMC = OS.ImmGetContext (hwndParent);
- OS.ImmAssociateContext (handle, hIMC);
- OS.ImmReleaseContext (hwndParent, hIMC);
- }
-}
-
-void createWidget () {
- foreground = background = -1;
- checkOrientation (parent);
- createHandle ();
- register ();
- subclass ();
- setDefaultFont ();
-}
-
-int defaultBackground () {
- if (OS.IsWinCE) return OS.GetSysColor (OS.COLOR_WINDOW);
- return OS.GetSysColor (OS.COLOR_BTNFACE);
-}
-
-int defaultFont () {
- Display display = getDisplay ();
- return display.systemFont ();
-}
-
-int defaultForeground () {
- return OS.GetSysColor (OS.COLOR_WINDOWTEXT);
-}
-
-void deregister () {
- WidgetTable.remove (handle);
-}
-
-void destroyWidget () {
- int hwnd = handle;
- releaseHandle ();
- if (hwnd != 0) {
- OS.DestroyWindow (hwnd);
- }
-}
-
-void drawBackground (int hDC) {
- RECT rect = new RECT ();
- OS.GetClientRect (handle, rect);
- drawBackground (hDC, rect);
-}
-
-void drawBackground (int hDC, RECT rect) {
- Display display = getDisplay ();
- int hPalette = display.hPalette;
- if (hPalette != 0) {
- OS.SelectPalette (hDC, hPalette, false);
- OS.RealizePalette (hDC);
- }
- int pixel = getBackgroundPixel ();
- int hBrush = findBrush (pixel);
- OS.FillRect (hDC, rect, hBrush);
-}
-
-int findBrush (int pixel) {
- return parent.findBrush (pixel);
-}
-
-int findCursor () {
- if (hCursor != 0) return hCursor;
- return parent.findCursor ();
-}
-
-char findMnemonic (String string) {
- int index = 0;
- int length = string.length ();
- do {
- while (index < length && string.charAt (index) != Mnemonic) index++;
- if (++index >= length) return '\0';
- if (string.charAt (index) != Mnemonic) return string.charAt (index);
- index++;
- } while (index < length);
- return '\0';
-}
-
-void fixFocus () {
- Shell shell = getShell ();
- Control control = this;
- while ((control = control.parent) != null) {
- if (control.setFocus () || control == shell) return;
- }
- OS.SetFocus (0);
-}
-
-/**
- * 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 ();
- Decorations shell = menuShell ();
- shell.setSavedFocus (this);
- if (!isEnabled () || !isVisible () || !isActive ()) return false;
- if (isFocusControl ()) return true;
- shell.bringToTop ();
- /*
- * This code is intentionally commented.
- *
- * When setting focus to a control, it is
- * possible that application code can set
- * the focus to another control inside of
- * WM_SETFOCUS. In this case, the original
- * control will no longer have the focus
- * and the call to setFocus() will return
- * false indicating failure.
- *
- * We are still working on a solution at
- * this time.
- */
-// if (OS.GetFocus () != OS.SetFocus (handle)) return false;
- OS.SetFocus (handle);
- return isFocusControl ();
-}
-
-void forceResize () {
- if (parent == null) return;
- WINDOWPOS [] lpwp = parent.lpwp;
- if (lpwp == null) return;
- for (int i=0; i<lpwp.length; i++) {
- WINDOWPOS wp = lpwp [i];
- if (wp != null && wp.hwnd == handle) {
- /*
- * This code is intentionally commented. All widgets that
- * are created by SWT have WS_CLIPSIBLINGS to ensure that
- * application code does not draw outside of the control.
- */
-// int count = parent.getChildrenCount ();
-// if (count > 1) {
-// int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
-// if ((bits & OS.WS_CLIPSIBLINGS) == 0) wp.flags |= OS.SWP_NOCOPYBITS;
-// }
- OS.SetWindowPos (wp.hwnd, 0, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
- lpwp [i] = null;
- return;
- }
- }
-}
-
-/**
- * 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.
- *
- * @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 ();
- return Color.win32_new (getDisplay (), getBackgroundPixel ());
-}
-
-int getBackgroundPixel () {
- if (background == -1) return defaultBackground ();
- return background;
-}
-
-/**
- * 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 ();
- int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
- if ((bits & OS.WS_EX_CLIENTEDGE) != 0) return OS.GetSystemMetrics (OS.SM_CXEDGE);
- if ((bits & OS.WS_EX_STATICEDGE) != 0) return OS.GetSystemMetrics (OS.SM_CXBORDER);
- return 0;
-}
-
-/**
- * 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 ();
- forceResize ();
- RECT rect = new RECT ();
- OS.GetWindowRect (handle, rect);
- int hwndParent = parent == null ? 0 : parent.handle;
- OS.MapWindowPoints (0, hwndParent, rect, 2);
- int width = rect.right - rect.left;
- int height = rect.bottom - rect.top;
- return new Rectangle (rect.left, rect.top, width, height);
-}
-
-int getCodePage () {
- int hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- LOGFONT logFont = new LOGFONT ();
- OS.GetObject (hFont, LOGFONT.sizeof, logFont);
- int cs = logFont.lfCharSet & 0xFF;
- int [] lpCs = new int [8];
- if (OS.TranslateCharsetInfo (cs, lpCs, OS.TCI_SRCCHARSET)) {
- return lpCs [1];
- }
- return OS.GetACP ();
-}
-
-/**
- * Returns the display that the receiver was created on.
- *
- * @return the receiver's 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 Display getDisplay () {
- Composite parent = this.parent;
- if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED);
- return parent.getDisplay ();
-}
-
-/**
- * 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 OS.IsWindowEnabled (handle);
-}
-
-/**
- * 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 ();
- int hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- if (hFont == 0) hFont = defaultFont ();
- return Font.win32_new (getDisplay (), hFont);
-}
-
-/**
- * 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 Color.win32_new (getDisplay (), getForegroundPixel ());
-}
-
-int getForegroundPixel () {
- if (foreground == -1) return defaultForeground ();
- return foreground;
-}
-
-/**
- * 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).
- *
- * @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 ();
- forceResize ();
- RECT rect = new RECT ();
- OS.GetWindowRect (handle, rect);
- int hwndParent = parent == null ? 0 : parent.handle;
- OS.MapWindowPoints (0, hwndParent, rect, 2);
- return new Point (rect.left, rect.top);
-}
-
-/**
- * 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;
-}
-
-/**
- * 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;
-}
-
-/**
- * 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 ();
- forceResize ();
- RECT rect = new RECT ();
- OS.GetWindowRect (handle, rect);
- int width = rect.right - rect.left;
- int height = rect.bottom - rect.top;
- return new Point (width, height);
-}
-
-/**
- * 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 ();
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- return (bits & OS.WS_VISIBLE) != 0;
-}
-
-boolean hasCursor () {
- RECT rect = new RECT ();
- if (!OS.GetClientRect (handle, rect)) return false;
- if (OS.MapWindowPoints (handle, 0, rect, 2) == 0) return false;
- POINT pt = new POINT ();
- return (OS.GetCursorPos (pt) && OS.PtInRect (rect, pt));
-}
-
-boolean hasFocus () {
- /*
- * If a non-SWT child of the control has focus,
- * then this control is considered to have focus
- * even though it does not have focus in Windows.
- */
- int hwndFocus = OS.GetFocus ();
- while (hwndFocus != 0) {
- if (hwndFocus == handle) return true;
- if (WidgetTable.get (hwndFocus) != null) {
- return false;
- }
- hwndFocus = OS.GetParent (hwndFocus);
- }
- return false;
-}
-
-/**
- * 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
- *
- * @private
- */
-public int internal_new_GC (GCData data) {
- checkWidget();
- int hDC;
- if (data == null || data.ps == null) {
- hDC = OS.GetDC (handle);
- } else {
- hDC = OS.BeginPaint (handle, data.ps);
- }
- if (hDC == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- if (data != null) {
- data.device = getDisplay ();
- data.foreground = getForegroundPixel ();
- data.background = getBackgroundPixel ();
- data.hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- data.hwnd = handle;
- }
- return hDC;
-}
-
-/**
- * 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 handle the platform specific GC handle
- * @param data the platform specific GC data
- *
- * @private
- */
-public void internal_dispose_GC (int hDC, GCData data) {
- checkWidget ();
- if (data == null || data.ps == null) {
- OS.ReleaseDC (handle, hDC);
- } else {
- OS.EndPaint (handle, data.ps);
- }
-}
-
-boolean isActive () {
- Display display = getDisplay ();
- Shell modal = display.getModalShell ();
- if (modal != null && modal != this) {
- if ((modal.style & SWT.PRIMARY_MODAL) != 0) {
- Shell shell = getShell ();
- if (modal.parent == shell) {
- return false;
- }
- }
- int bits = SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL;
- if ((modal.style & bits) != 0) {
- Control control = this;
- while (control != null) {
- if (control == modal) break;
- control = control.parent;
- }
- if (control != modal) return false;
- }
- }
- return getShell ().getEnabled ();
-}
-
-public boolean isDisposed () {
- return handle == 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 ();
-}
-
-/**
- * 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 ();
- return hasFocus ();
-}
-
-boolean isFocusAncestor () {
- Display display = getDisplay ();
- Control control = display.getFocusControl ();
- while (control != null && control != this) {
- control = control.parent;
- }
- return control == this;
-}
-
-/**
- * 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;
- /*
- * Check to see if current damage is included.
- */
-// if (!OS.IsWindowVisible (handle)) return false;
-// int flags = OS.DCX_CACHE | OS.DCX_CLIPCHILDREN | OS.DCX_CLIPSIBLINGS;
-// int hDC = OS.GetDCEx (handle, 0, flags);
-// int result = OS.GetClipBox (hDC, new RECT ());
-// OS.ReleaseDC (handle, hDC);
-// return result != OS.NULLREGION;
-}
-
-boolean isTabGroup () {
- Control [] tabList = parent._getTabList ();
- if (tabList != null) {
- for (int i=0; i<tabList.length; i++) {
- if (tabList [i] == this) return true;
- }
- }
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- return (bits & OS.WS_TABSTOP) != 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 bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & OS.WS_TABSTOP) != 0) return false;
- int code = OS.SendMessage (handle, OS.WM_GETDLGCODE, 0, 0);
- if ((code & OS.DLGC_STATIC) != 0) return false;
- if ((code & OS.DLGC_WANTALLKEYS) != 0) return false;
- if ((code & OS.DLGC_WANTARROWS) != 0) return false;
- if ((code & OS.DLGC_WANTTAB) != 0) return false;
- return true;
-}
-
-/**
- * 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 OS.IsWindowVisible (handle);
-}
-
-Decorations menuShell () {
- return parent.menuShell ();
-}
-
-boolean mnemonicHit (char key) {
- return false;
-}
-
-boolean mnemonicMatch (char key) {
- return false;
-}
-
-/**
- * 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 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>
- */
-public void moveAbove (Control control) {
- checkWidget ();
- int hwndAbove = OS.HWND_TOP;
- if (control != null) {
- if (control.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT);
- if (parent != control.parent) return;
- int hwnd = control.handle;
- if (hwnd == 0 || hwnd == handle) return;
- hwndAbove = OS.GetWindow (hwnd, OS.GW_HWNDPREV);
- /*
- * Bug in Windows. For some reason, when GetWindow ()
- * with GW_HWNDPREV is used to query the previous window
- * in the z-order with the first child, Windows returns
- * the first child instead of NULL. The fix is to detect
- * this case and move the control to the top.
- */
- if (hwndAbove == 0 || hwndAbove == hwnd) {
- hwndAbove = OS.HWND_TOP;
- }
- }
- int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
- OS.SetWindowPos (handle, hwndAbove, 0, 0, 0, 0, flags);
-}
-
-/**
- * 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 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>
- */
-public void moveBelow (Control control) {
- checkWidget ();
- int hwndAbove = OS.HWND_BOTTOM;
- if (control != null) {
- if (control.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT);
- if (parent != control.parent) return;
- hwndAbove = control.handle;
- }
- if (hwndAbove == 0 || hwndAbove == handle) return;
- int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
- OS.SetWindowPos (handle, hwndAbove, 0, 0, 0, 0, flags);
-}
-
-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
- */
-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>
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - 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
- */
-public void pack (boolean changed) {
- checkWidget ();
- setSize (computeSize (SWT.DEFAULT, SWT.DEFAULT, changed));
-}
-
-/**
- * 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.
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - 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
- */
-public void redraw () {
- checkWidget ();
- if (!OS.IsWindowVisible (handle)) return;
- if (OS.IsWinCE) {
- OS.InvalidateRect (handle, null, true);
- } else {
- int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE;
- OS.RedrawWindow (handle, null, 0, flags);
- }
-}
-
-/**
- * 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. 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
- */
-public void redraw (int x, int y, int width, int height, boolean all) {
- checkWidget ();
- if (width <= 0 || height <= 0) return;
- if (!OS.IsWindowVisible (handle)) return;
- RECT rect = new RECT ();
- OS.SetRect (rect, x, y, x + width, y + height);
- if (OS.IsWinCE) {
- OS.InvalidateRect (handle, rect, true);
- } else {
- int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE;
- if (all) flags |= OS.RDW_ALLCHILDREN;
- OS.RedrawWindow (handle, rect, 0, flags);
- }
-}
-
-void register () {
- WidgetTable.put (handle, this);
-}
-
-void releaseHandle () {
- super.releaseHandle ();
- handle = 0;
-}
-
-void releaseWidget () {
- super.releaseWidget ();
- if (OS.IsDBLocale) {
- OS.ImmAssociateContext (handle, 0);
- }
- if (toolTipText != null) {
- Shell shell = getShell ();
- shell.setToolTipText (handle, null);
- }
- toolTipText = null;
- if (menu != null && !menu.isDisposed ()) {
- menu.dispose ();
- }
- menu = null;
- deregister ();
- unsubclass ();
- parent = null;
- layoutData = null;
- if (accessible != null) {
- accessible.internal_dispose_Accessible ();
- }
- accessible = 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 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 gains or loses focus.
- *
- * @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 #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 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 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 mouse passes or hovers over controls.
- *
- * @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 #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 mouse buttons are pressed and released.
- *
- * @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 #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 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 receiver needs to be painted.
- *
- * @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 #addPaintListener
- */
-public void removePaintListener(PaintListener listener) {
- checkWidget ();
- if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
- if (eventTable == null) return;
- eventTable.unhook(SWT.Paint, listener);
-}
-
-/**
- * Removes the listener from the collection of listeners who will
- * be notified when traversal events occur.
- *
- * @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 #addTraverseListener
- */
-public void removeTraverseListener(TraverseListener listener) {
- checkWidget ();
- if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
- if (eventTable == null) return;
- eventTable.unhook (SWT.Traverse, listener);
-}
-
-boolean sendKeyEvent (int type, int msg, int wParam, int lParam) {
- Event event = new Event ();
- if (!setKeyState (event, type)) return true;
- return sendKeyEvent (type, msg, wParam, lParam, event);
-}
-
-boolean sendKeyEvent (int type, int msg, int wParam, int lParam, Event event) {
- postEvent (type, event);
- return true;
-}
-
-boolean sendMouseEvent (int type, int button, int msg, int wParam, int lParam) {
- Event event = new Event ();
- event.button = button;
- event.x = (short) (lParam & 0xFFFF);
- event.y = (short) (lParam >> 16);
- setInputState (event, type);
- return sendMouseEvent (type, msg, wParam, lParam, event);
-}
-
-boolean sendMouseEvent (int type, int msg, int wParam, int lParam, Event event) {
- postEvent (type, event);
- return true;
-}
-
-/**
- * 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.
- *
- * @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 ();
- int pixel = -1;
- if (color != null) {
- if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- pixel = color.handle;
- }
- setBackgroundPixel (pixel);
-}
-
-void setBackgroundPixel (int pixel) {
- if (background == pixel) return;
- background = pixel;
- OS.InvalidateRect (handle, null, true);
-}
-
-/**
- * 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).
- * <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 ();
- int flags = OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE;
- setBounds (x, y, Math.max (0, width), Math.max (0, height), flags);
-}
-
-void setBounds (int x, int y, int width, int height, int flags) {
- if (parent == null) {
- OS.SetWindowPos (handle, 0, x, y, width, height, flags);
- return;
- }
- if (parent.lpwp == null) {
- /*
- * This code is intentionally commented. All widgets that
- * are created by SWT have WS_CLIPSIBLINGS to ensure that
- * application code does not draw outside of the control.
- */
-// int count = parent.getChildrenCount ();
-// if (count > 1) {
-// int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
-// if ((bits & OS.WS_CLIPSIBLINGS) == 0) flags |= OS.SWP_NOCOPYBITS;
-// }
- OS.SetWindowPos (handle, 0, x, y, width, height, flags);
- return;
- }
- forceResize ();
- WINDOWPOS [] lpwp = parent.lpwp;
- int index = 0;
- while (index < lpwp.length) {
- if (lpwp [index] == null) break;
- index ++;
- }
- if (index == lpwp.length) {
- WINDOWPOS [] newLpwp = new WINDOWPOS [lpwp.length + 4];
- System.arraycopy (lpwp, 0, newLpwp, 0, lpwp.length);
- parent.lpwp = lpwp = newLpwp;
- }
- WINDOWPOS wp = new WINDOWPOS ();
- wp.hwnd = handle;
- wp.x = x;
- wp.y = y;
- wp.cx = width;
- wp.cy = height;
- wp.flags = flags;
- lpwp [index] = wp;
-}
-
-/**
- * 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, rect.width, rect.height);
-}
-
-/**
- * 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.
- *
- * @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 ();
- if (capture) {
- OS.SetCapture (handle);
- } else {
- if (OS.GetCapture () == handle) {
- OS.ReleaseCapture ();
- }
- }
-}
-
-/**
- * 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 ();
- hCursor = 0;
- if (cursor != null) {
- if (cursor.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- hCursor = cursor.handle;
- }
- if (OS.IsWinCE) {
- OS.SetCursor (hCursor);
- return;
- }
- int hwndCursor = OS.GetCapture ();
- if (hwndCursor == 0) {
- POINT pt = new POINT ();
- if (!OS.GetCursorPos (pt)) return;
- int hwnd = hwndCursor = OS.WindowFromPoint (pt);
- while (hwnd != 0 && hwnd != handle) {
- hwnd = OS.GetParent (hwnd);
- }
- if (hwnd == 0) return;
- }
- int lParam = OS.HTCLIENT | (OS.WM_MOUSEMOVE << 16);
- OS.SendMessage (hwndCursor, OS.WM_SETCURSOR, hwndCursor, lParam);
-}
-
-void setDefaultFont () {
- Display display = getDisplay ();
- int hFont = display.systemFont ();
- OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0);
-}
-
-/**
- * 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 ();
-
- /*
- * Feature in Windows. If the receiver has focus, disabling
- * the receiver causes no window to have focus. The fix is
- * to assign focus to the first ancestor window that takes
- * focus. If no window will take focus, set focus to the
- * desktop.
- */
- boolean fixFocus = false;
- if (!enabled) fixFocus = isFocusAncestor ();
- OS.EnableWindow (handle, enabled);
- if (fixFocus) fixFocus ();
-}
-
-/**
- * Causes the receiver to have the <em>keyboard focus</em>,
- * such that all keyboard events will 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 #forceFocus
- */
-public boolean setFocus () {
- checkWidget ();
- 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 ();
- int hFont = 0;
- if (font != null) {
- if (font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- hFont = font.handle;
- }
- if (hFont == 0) hFont = defaultFont ();
- OS.SendMessage (handle, OS.WM_SETFONT, hFont, 1);
-}
-
-/**
- * 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.
- *
- * @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 ();
- int pixel = -1;
- if (color != null) {
- if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- pixel = color.handle;
- }
- setForegroundPixel (pixel);
-}
-
-void setForegroundPixel (int pixel) {
- if (foreground == pixel) return;
- foreground = pixel;
- OS.InvalidateRect (handle, null, true);
-}
-
-/**
- * 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).
- *
- * @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 ();
- int flags = OS.SWP_NOSIZE | OS.SWP_NOZORDER | OS.SWP_NOACTIVATE;
- /*
- * Feature in WinCE. The SWP_DRAWFRAME flag for SetWindowPos()
- * causes a WM_SIZE message to be sent even when the SWP_NOSIZE
- * flag is specified. The fix is to set SWP_DRAWFRAME only when
- * not running on WinCE.
- */
- if (!OS.IsWinCE) flags |= OS.SWP_DRAWFRAME;
- setBounds (x, y, 0, 0, flags);
-}
-
-/**
- * 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 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.
- *
- * @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;
-}
-
-boolean setRadioFocus () {
- return false;
-}
-
-boolean setRadioSelection (boolean value) {
- return false;
-}
-
-/**
- * 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.
- * <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
- * @see #update
- */
-public void setRedraw (boolean redraw) {
- checkWidget ();
- /*
- * This code is intentionally commented.
- *
- * Feature in Windows. When WM_SETREDRAW is used to turn
- * off drawing in a widget, it clears the WS_VISIBLE bits
- * and then sets them when redraw is turned back on. This
- * means that WM_SETREDRAW will make a widget unexpectedly
- * visible.
- *
- * There is no fix at this time.
- */
-// if (drawCount == 0) {
-// int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
-// if ((bits & OS.WS_VISIBLE) == 0) return;
-// }
-
- if (redraw) {
- if (--drawCount == 0) {
- OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
- if (OS.IsWinCE) {
- OS.InvalidateRect (handle, null, true);
- } else {
- int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE | OS.RDW_ALLCHILDREN;
- OS.RedrawWindow (handle, null, 0, flags);
- }
- }
- } else {
- if (drawCount++ == 0) {
- OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
- }
- }
-}
-
-boolean setSavedFocus () {
- return forceFocus ();
-}
-
-/**
- * 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 ();
- int flags = OS.SWP_NOMOVE | OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE;
- setBounds (0, 0, Math.max (0, width), Math.max (0, height), flags);
-}
-
-/**
- * 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
- * @param height the new height 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);
-}
-
-boolean setTabGroupFocus () {
- return setTabItemFocus ();
-}
-
-boolean setTabItemFocus () {
- if (!isShowing ()) return false;
- return setFocus ();
-}
-
-/**
- * Sets the receiver's tool tip text to the argument, which
- * may be null indicating that no tool tip text should be shown.
- *
- * @param string the new tool tip text (or null)
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if 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 ();
- Shell shell = getShell ();
- shell.setToolTipText (handle, toolTipText = string);
-}
-
-/**
- * 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 ();
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if (((bits & OS.WS_VISIBLE) != 0) == visible) return;
- 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 Windows. If the receiver has focus, hiding
- * the receiver causes no window to have focus. The fix is
- * to assign focus to the first ancestor window that takes
- * focus. If no window will take focus, set focus to the
- * desktop.
- */
- boolean fixFocus = false;
- if (!visible) fixFocus = isFocusAncestor ();
- OS.ShowWindow (handle, visible ? OS.SW_SHOW : OS.SW_HIDE);
- 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 ();
-}
-
-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;
- }
- }
- }
- }
-}
-
-void subclass () {
- int oldProc = windowProc ();
- int newProc = getDisplay ().windowProc;
- if (oldProc == newProc) return;
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, newProc);
-}
-
-/**
- * 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 ();
- POINT pt = new POINT ();
- pt.x = x; pt.y = y;
- OS.ScreenToClient (handle, pt);
- return new Point (pt.x, pt.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 ();
- POINT pt = new POINT ();
- pt.x = x; pt.y = y;
- OS.ClientToScreen (handle, pt);
- return new Point (pt.x, pt.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);
-}
-
-boolean translateAccelerator (MSG msg) {
- return menuShell ().translateAccelerator (msg);
-}
-
-boolean translateMnemonic (char key) {
- if (!isVisible () || !isEnabled ()) return false;
- Event event = new Event ();
- event.doit = mnemonicMatch (key);
- event.detail = SWT.TRAVERSE_MNEMONIC;
- Display display = getDisplay ();
- display.lastKey = 0;
- display.lastAscii = key;
- display.lastVirtual = display.lastNull = false;
- if (!setKeyState (event, SWT.Traverse)) {
- return false;
- }
- return traverse (event);
-}
-
-boolean translateMnemonic (MSG msg) {
- int hwnd = msg.hwnd;
- if (OS.GetKeyState (OS.VK_MENU) >= 0) {
- int code = OS.SendMessage (hwnd, OS.WM_GETDLGCODE, 0, 0);
- if ((code & OS.DLGC_WANTALLKEYS) != 0) return false;
- if ((code & OS.DLGC_BUTTON) == 0) return false;
- }
- Decorations shell = menuShell ();
- if (shell.isVisible () && shell.isEnabled ()) {
- char ch = mbcsToWcs ((char) msg.wParam);
- return ch != 0 && shell.translateMnemonic (ch);
- }
- return false;
-}
-
-boolean translateTraversal (MSG msg) {
- int key = msg.wParam;
- if (key == OS.VK_MENU) {
- Shell shell = getShell ();
- int hwndShell = shell.handle;
- OS.SendMessage (hwndShell, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
- return false;
- }
- int hwnd = msg.hwnd;
- int detail = SWT.TRAVERSE_NONE;
- boolean doit = true, all = false;
- boolean lastVirtual = false;
- int lastKey = key, lastAscii = 0;
- switch (key) {
- case OS.VK_ESCAPE: {
- all = true;
- lastAscii = 27;
- int code = OS.SendMessage (hwnd, OS.WM_GETDLGCODE, 0, 0);
- if ((code & OS.DLGC_WANTALLKEYS) != 0) {
- /*
- * Use DLGC_HASSETSEL to determine that the control
- * is a text widget. A text widget normally wants
- * all keys except VK_ESCAPE. If this bit is not
- * set, then assume the control wants all keys,
- * including VK_ESCAPE.
- */
- if ((code & OS.DLGC_HASSETSEL) == 0) doit = false;
- }
- detail = SWT.TRAVERSE_ESCAPE;
- break;
- }
- case OS.VK_RETURN: {
- all = true;
- lastAscii = '\r';
- int code = OS.SendMessage (hwnd, OS.WM_GETDLGCODE, 0, 0);
- if ((code & OS.DLGC_WANTALLKEYS) != 0) doit = false;
- detail = SWT.TRAVERSE_RETURN;
- break;
- }
- case OS.VK_TAB: {
- /*
- * NOTE: This code causes Shift+Tab and Ctrl+Tab to
- * always attempt traversal which is not correct.
- * The default should be the same as a plain Tab key.
- * This behavior is currently relied on by StyledText.
- *
- * The correct behavior is to give every key to a
- * control that answers DLGC_WANTALLKEYS.
- */
- lastAscii = '\t';
- boolean next = OS.GetKeyState (OS.VK_SHIFT) >= 0;
- int code = OS.SendMessage (hwnd, OS.WM_GETDLGCODE, 0, 0);
- if ((code & (OS.DLGC_WANTTAB | OS.DLGC_WANTALLKEYS)) != 0) {
- if (next && OS.GetKeyState (OS.VK_CONTROL) >= 0) doit = false;
- }
- detail = next ? SWT.TRAVERSE_TAB_NEXT : SWT.TRAVERSE_TAB_PREVIOUS;
- break;
- }
- case OS.VK_UP:
- case OS.VK_LEFT:
- case OS.VK_DOWN:
- case OS.VK_RIGHT: {
- /*
- * On WinCE SP there is no tab key. Focus is assigned
- * using only the VK_UP and VK_DOWN keys, not with VK_LEFT
- * or VK_RIGHT.
*/
- if (OS.IsSP) {
- if (key == OS.VK_LEFT || key == OS.VK_RIGHT) return false;
- }
- lastVirtual = true;
- int code = OS.SendMessage (hwnd, OS.WM_GETDLGCODE, 0, 0);
- if ((code & (OS.DLGC_WANTARROWS /*| OS.DLGC_WANTALLKEYS*/)) != 0) doit = false;
- boolean next = key == OS.VK_DOWN || key == OS.VK_RIGHT;
- detail = next ? SWT.TRAVERSE_ARROW_NEXT : SWT.TRAVERSE_ARROW_PREVIOUS;
- break;
- }
- case OS.VK_PRIOR:
- case OS.VK_NEXT: {
- all = true;
- lastVirtual = true;
- if (OS.GetKeyState (OS.VK_CONTROL) >= 0) return false;
- /*
- * The fact that this code is commented causes Ctrl+PgUp
- * and Ctrl+PgDn to always attempt traversal which is not
- * correct. This behavior is relied on by StyledText.
- *
- * The correct behavior is to give every key to a control
- * that answers DLGC_WANTALLKEYS.
- */
-// int code = OS.SendMessage (hwnd, OS., 0, 0);
-// if ((code & OS.DLGC_WANTALLKEYS) != 0) doit = false;
- detail = key == OS.VK_PRIOR ? SWT.TRAVERSE_PAGE_PREVIOUS : SWT.TRAVERSE_PAGE_NEXT;
- break;
- }
- default:
- return false;
- }
- Event event = new Event ();
- event.doit = doit;
- event.detail = detail;
- Display display = getDisplay ();
- display.lastKey = lastKey;
- display.lastAscii = lastAscii;
- display.lastVirtual = lastVirtual;
- display.lastNull = false;
- if (!setKeyState (event, SWT.Traverse)) {
- return false;
- }
- Shell shell = getShell ();
- Control control = this;
- do {
- if (control.traverse (event)) {
- int hwndShell = shell.handle;
- OS.SendMessage (hwndShell, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
- 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;
-}
-
-boolean traverse (Event event) {
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the traverse
- * event. If this happens, return true to stop further
- * event processing.
- */
- sendEvent (SWT.Traverse, event);
- if (isDisposed ()) return false;
- 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.character);
- case SWT.TRAVERSE_PAGE_NEXT: return traversePage (true);
- case SWT.TRAVERSE_PAGE_PREVIOUS: return traversePage (false);
- }
- 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 ();
- if (!isFocusControl () && !setFocus ()) return false;
- Event event = new Event ();
- event.doit = true;
- event.detail = traversal;
- return traverse (event);
-}
-
-boolean traverseEscape () {
- return false;
-}
-
-boolean traverseGroup (boolean next) {
- Control root = computeTabRoot ();
- Control group = computeTabGroup ();
- Control [] 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) {
- Control control = list [index];
- if (!control.isDisposed () && control.setTabGroupFocus ()) {
- if (!isDisposed () && !isFocusControl ()) 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.
- */
- 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 traverseMnemonic (char key) {
- return mnemonicHit (key);
-}
-
-boolean traversePage (boolean next) {
- return false;
-}
-
-boolean traverseReturn () {
- return false;
-}
-
-void unsubclass () {
- int newProc = windowProc ();
- int oldProc = getDisplay ().windowProc;
- if (oldProc == newProc) return;
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, newProc);
-}
-
-/**
- * Forces all outstanding paint requests for the widget
- * to be processed before this method returns.
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - 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
- */
-public void update () {
- checkWidget ();
- update (false);
-}
-
-void update (boolean all) {
-// checkWidget ();
- if (OS.IsWinCE) {
- OS.UpdateWindow (handle);
- } else {
- int flags = OS.RDW_UPDATENOW;
- if (all) flags |= OS.RDW_ALLCHILDREN;
- OS.RedrawWindow (handle, null, 0, flags);
- }
-}
-
-void updateFont (Font oldFont, Font newFont) {
- Font font = getFont ();
- if (font.equals (oldFont)) setFont (newFont);
-}
-
-int widgetExtStyle () {
- int bits = 0;
- if ((style & SWT.BORDER) != 0) bits |= OS.WS_EX_CLIENTEDGE;
- /*
- * Feature in Windows NT. When CreateWindowEx() is called with
- * WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT, CreateWindowEx()
- * fails to create the HWND. The fix is to not use these bits.
- */
- if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) < (4 << 16 | 10)) {
- return bits;
- }
- bits |= OS.WS_EX_NOINHERITLAYOUT;
- if ((style & SWT.RIGHT_TO_LEFT) != 0) bits |= OS.WS_EX_LAYOUTRTL;
- return bits;
-}
-
-int widgetStyle () {
- /* Force clipping of siblings by setting WS_CLIPSIBLINGS */
- return OS.WS_CHILD | OS.WS_VISIBLE | OS.WS_CLIPSIBLINGS;
-
- /*
- * This code is intentionally commented. When clipping
- * of both siblings and children is not enforced, it is
- * possible for application code to draw outside of the
- * control.
- */
-// int bits = OS.WS_CHILD | OS.WS_VISIBLE;
-// if ((style & SWT.CLIP_SIBLINGS) != 0) bits |= OS.WS_CLIPSIBLINGS;
-// if ((style & SWT.CLIP_CHILDREN) != 0) bits |= OS.WS_CLIPCHILDREN;
-// return bits;
-}
-
-/**
- * Changes the parent of the widget to be the one provided if
- * the underlying operating system supports this feature.
- * Answers <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>
- * </ul>
- * @exception SWTError <ul>
- * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
- * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</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 (OS.SetParent (handle, parent.handle) == 0) {
- return false;
- }
- this.parent = parent;
- return true;
-}
-
-abstract TCHAR windowClass ();
-
-abstract int windowProc ();
-
-int windowProc (int msg, int wParam, int lParam) {
- LRESULT result = null;
- switch (msg) {
- case OS.WM_ACTIVATE: result = WM_ACTIVATE (wParam, lParam); break;
- case OS.WM_CHAR: result = WM_CHAR (wParam, lParam); break;
- case OS.WM_CLEAR: result = WM_CLEAR (wParam, lParam); break;
- case OS.WM_CLOSE: result = WM_CLOSE (wParam, lParam); break;
- case OS.WM_COMMAND: result = WM_COMMAND (wParam, lParam); break;
- case OS.WM_CONTEXTMENU: result = WM_CONTEXTMENU (wParam, lParam); break;
- case OS.WM_CTLCOLORBTN:
- case OS.WM_CTLCOLORDLG:
- case OS.WM_CTLCOLOREDIT:
- case OS.WM_CTLCOLORLISTBOX:
- case OS.WM_CTLCOLORMSGBOX:
- case OS.WM_CTLCOLORSCROLLBAR:
- case OS.WM_CTLCOLORSTATIC: result = WM_CTLCOLOR (wParam, lParam); break;
- case OS.WM_CUT: result = WM_CUT (wParam, lParam); break;
- case OS.WM_DESTROY: result = WM_DESTROY (wParam, lParam); break;
- case OS.WM_DRAWITEM: result = WM_DRAWITEM (wParam, lParam); break;
- case OS.WM_ENDSESSION: result = WM_ENDSESSION (wParam, lParam); break;
- case OS.WM_ERASEBKGND: result = WM_ERASEBKGND (wParam, lParam); break;
- case OS.WM_GETDLGCODE: result = WM_GETDLGCODE (wParam, lParam); break;
- case OS.WM_HELP: result = WM_HELP (wParam, lParam); break;
- case OS.WM_HSCROLL: result = WM_HSCROLL (wParam, lParam); break;
- case OS.WM_IME_CHAR: result = WM_IME_CHAR (wParam, lParam); break;
- case OS.WM_IME_COMPOSITION: result = WM_IME_COMPOSITION (wParam, lParam); break;
- case OS.WM_INITMENUPOPUP: result = WM_INITMENUPOPUP (wParam, lParam); break;
- case OS.WM_GETFONT: result = WM_GETFONT (wParam, lParam); break;
- case OS.WM_GETOBJECT: result = WM_GETOBJECT (wParam, lParam); break;
- case OS.WM_HOTKEY: result = WM_HOTKEY (wParam, lParam); break;
- case OS.WM_KEYDOWN: result = WM_KEYDOWN (wParam, lParam); break;
- case OS.WM_KEYUP: result = WM_KEYUP (wParam, lParam); break;
- case OS.WM_KILLFOCUS: result = WM_KILLFOCUS (wParam, lParam); break;
- case OS.WM_LBUTTONDBLCLK: result = WM_LBUTTONDBLCLK (wParam, lParam); break;
- case OS.WM_LBUTTONDOWN: result = WM_LBUTTONDOWN (wParam, lParam); break;
- case OS.WM_LBUTTONUP: result = WM_LBUTTONUP (wParam, lParam); break;
- case OS.WM_MBUTTONDBLCLK: result = WM_MBUTTONDBLCLK (wParam, lParam); break;
- case OS.WM_MBUTTONDOWN: result = WM_MBUTTONDOWN (wParam, lParam); break;
- case OS.WM_MBUTTONUP: result = WM_MBUTTONUP (wParam, lParam); break;
- case OS.WM_MEASUREITEM: result = WM_MEASUREITEM (wParam, lParam); break;
- case OS.WM_MENUCHAR: result = WM_MENUCHAR (wParam, lParam); break;
- case OS.WM_MENUSELECT: result = WM_MENUSELECT (wParam, lParam); break;
- case OS.WM_MOUSEACTIVATE: result = WM_MOUSEACTIVATE (wParam, lParam); break;
- case OS.WM_MOUSEHOVER: result = WM_MOUSEHOVER (wParam, lParam); break;
- case OS.WM_MOUSELEAVE: result = WM_MOUSELEAVE (wParam, lParam); break;
- case OS.WM_MOUSEMOVE: result = WM_MOUSEMOVE (wParam, lParam); break;
- case OS.WM_MOUSEWHEEL: result = WM_MOUSEWHEEL (wParam, lParam); break;
- case OS.WM_MOVE: result = WM_MOVE (wParam, lParam); break;
- case OS.WM_NCACTIVATE: result = WM_NCACTIVATE (wParam, lParam); break;
- case OS.WM_NCCALCSIZE: result = WM_NCCALCSIZE (wParam, lParam); break;
- case OS.WM_NCHITTEST: result = WM_NCHITTEST (wParam, lParam); break;
- case OS.WM_NOTIFY: result = WM_NOTIFY (wParam, lParam); break;
- case OS.WM_PAINT: result = WM_PAINT (wParam, lParam); break;
- case OS.WM_PALETTECHANGED: result = WM_PALETTECHANGED (wParam, lParam); break;
- case OS.WM_PASTE: result = WM_PASTE (wParam, lParam); break;
- case OS.WM_PRINTCLIENT: result = WM_PRINTCLIENT (wParam, lParam); break;
- case OS.WM_QUERYENDSESSION: result = WM_QUERYENDSESSION (wParam, lParam); break;
- case OS.WM_QUERYNEWPALETTE: result = WM_QUERYNEWPALETTE (wParam, lParam); break;
- case OS.WM_QUERYOPEN: result = WM_QUERYOPEN (wParam, lParam); break;
- case OS.WM_RBUTTONDBLCLK: result = WM_RBUTTONDBLCLK (wParam, lParam); break;
- case OS.WM_RBUTTONDOWN: result = WM_RBUTTONDOWN (wParam, lParam); break;
- case OS.WM_RBUTTONUP: result = WM_RBUTTONUP (wParam, lParam); break;
- case OS.WM_SETCURSOR: result = WM_SETCURSOR (wParam, lParam); break;
- case OS.WM_SETFOCUS: result = WM_SETFOCUS (wParam, lParam); break;
- case OS.WM_SETFONT: result = WM_SETFONT (wParam, lParam); break;
- case OS.WM_SETTINGCHANGE: result = WM_SETTINGCHANGE (wParam, lParam); break;
- case OS.WM_SETREDRAW: result = WM_SETREDRAW (wParam, lParam); break;
- case OS.WM_SHOWWINDOW: result = WM_SHOWWINDOW (wParam, lParam); break;
- case OS.WM_SIZE: result = WM_SIZE (wParam, lParam); break;
- case OS.WM_SYSCHAR: result = WM_SYSCHAR (wParam, lParam); break;
- case OS.WM_SYSCOLORCHANGE: result = WM_SYSCOLORCHANGE (wParam, lParam); break;
- case OS.WM_SYSCOMMAND: result = WM_SYSCOMMAND (wParam, lParam); break;
- case OS.WM_SYSKEYDOWN: result = WM_SYSKEYDOWN (wParam, lParam); break;
- case OS.WM_SYSKEYUP: result = WM_SYSKEYUP (wParam, lParam); break;
- case OS.WM_TIMER: result = WM_TIMER (wParam, lParam); break;
- case OS.WM_UNDO: result = WM_UNDO (wParam, lParam); break;
- case OS.WM_VSCROLL: result = WM_VSCROLL (wParam, lParam); break;
- case OS.WM_WINDOWPOSCHANGING: result = WM_WINDOWPOSCHANGING (wParam, lParam); break;
- }
- if (result != null) return result.value;
- return callWindowProc (msg, wParam, lParam);
-}
-
-LRESULT WM_ACTIVATE (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_CHAR (int wParam, int lParam) {
-
- /*
- * Do not report a lead byte as a key pressed.
- */
- Display display = getDisplay ();
- if (!OS.IsUnicode && OS.IsDBLocale) {
- byte lead = (byte) (wParam & 0xFF);
- if (OS.IsDBCSLeadByte (lead)) return null;
- }
-
- /*
- * Use VkKeyScan () to tell us if the character is a control
- * or a numeric key pad character with Num Lock down. On
- * international keyboards, the control key may be down when
- * the character is not a control character. In this case
- * use the last key (computed in WM_KEYDOWN) instead of wParam
- * as the keycode because there is not enough information to
- * compute the keycode in WPARAM.
- */
- display.lastAscii = wParam;
- display.lastNull = false;
- if (display.lastKey == 0) {
- display.lastKey = wParam;
- display.lastVirtual = display.isVirtualKey (wParam);
- } else {
- int result = OS.IsWinCE ? 0 : OS.VkKeyScan ((short) wParam);
- if (!OS.IsWinCE && (result == -1 || (result >> 8) <= 2)) {
- if (OS.GetKeyState (OS.VK_CONTROL) < 0) {
- display.lastVirtual = display.isVirtualKey (display.lastKey);
- }
- } else {
- display.lastKey = wParam;
- display.lastVirtual = false;
- }
- }
- if (!sendKeyEvent (SWT.KeyDown, OS.WM_CHAR, wParam, lParam)) {
- return LRESULT.ZERO;
- }
- return null;
-}
-
-LRESULT WM_CLEAR (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_CLOSE (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_COMMAND (int wParam, int lParam) {
- /*
- * When the WM_COMMAND message is sent from a
- * menu, the HWND parameter in LPARAM is zero.
- */
- if (lParam == 0) {
- Decorations shell = menuShell ();
- if (shell.isEnabled ()) {
- int id = wParam & 0xFFFF;
- MenuItem item = shell.findMenuItem (id);
- if (item != null && item.isEnabled ()) {
- return item.wmCommandChild (wParam, lParam);
- }
- }
- return null;
- }
- Control control = WidgetTable.get (lParam);
- if (control == null) return null;
- return control.wmCommandChild (wParam, lParam);
-}
-
-LRESULT WM_CONTEXTMENU (int wParam, int lParam) {
- if (wParam != handle) return null;
-
- /*
- * Feature in Windows. When the user presses WM_NCRBUTTONUP,
- * a WM_CONTEXTMENU message is generated. This happens when
- * the user releases the mouse over a scroll bar. Normally,
- * window displays the default scrolling menu but applications
- * can process WM_CONTEXTMENU to display a different menu.
- * Typically, an application does not want to supply a special
- * scroll menu. The fix is to look for a WM_CONTEXTMENU that
- * originated from a mouse event and display the menu when the
- * mouse was released in the client area.
- */
- POINT pt = new POINT ();
- pt.x = (short) (lParam & 0xFFFF);
- pt.y = (short) (lParam >> 16);
- if (pt.x != -1 || pt.y != -1) {
- RECT rect = new RECT ();
- OS.GetClientRect (handle, rect);
- OS.ScreenToClient (handle, pt);
- if (!OS.PtInRect (rect, pt)) return null;
- }
-
- /*
- * Because context menus can be shared between controls
- * and the parent of all menus is the shell, the menu may
- * have been destroyed.
- */
- if (menu != null && !menu.isDisposed ()) {
-// menu.setLocation (x, y);
- menu.setVisible (true);
- return LRESULT.ZERO;
- }
- return null;
-}
-
-LRESULT WM_CTLCOLOR (int wParam, int lParam) {
- Display display = getDisplay ();
- int hPalette = display.hPalette;
- if (hPalette != 0) {
- OS.SelectPalette (wParam, hPalette, false);
- OS.RealizePalette (wParam);
- }
- Control control = WidgetTable.get (lParam);
- if (control == null) return null;
- return control.wmColorChild (wParam, lParam);
-}
-
-LRESULT WM_CUT (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_DESTROY (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_DRAWITEM (int wParam, int lParam) {
- DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT ();
- OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof);
- if (struct.CtlType == OS.ODT_MENU) {
- Decorations shell = menuShell ();
- MenuItem item = shell.findMenuItem (struct.itemID);
- if (item == null) return null;
- return item.wmDrawChild (wParam, lParam);
- }
- Control control = WidgetTable.get (struct.hwndItem);
- if (control == null) return null;
- return control.wmDrawChild (wParam, lParam);
-}
-
-LRESULT WM_ENDSESSION (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_ERASEBKGND (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_GETDLGCODE (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_GETFONT (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_GETOBJECT (int wParam, int lParam) {
- if (accessible != null) {
- int result = accessible.internal_WM_GETOBJECT (wParam, lParam);
- if (result != 0) return new LRESULT (result);
- }
- return null;
-}
-
-LRESULT WM_HOTKEY (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_HELP (int wParam, int lParam) {
- if (OS.IsWinCE) return null;
- HELPINFO lphi = new HELPINFO ();
- OS.MoveMemory (lphi, lParam, HELPINFO.sizeof);
- Decorations shell = menuShell ();
- if (!shell.isEnabled ()) return null;
- if (lphi.iContextType == OS.HELPINFO_MENUITEM) {
- MenuItem item = shell.findMenuItem (lphi.iCtrlId);
- if (item != null && item.isEnabled ()) {
- Widget widget = null;
- if (item.hooks (SWT.Help)) {
- widget = item;
- } else {
- Menu menu = item.parent;
- if (menu.hooks (SWT.Help)) widget = menu;
- }
- if (widget != null) {
- int hwndShell = shell.handle;
- OS.SendMessage (hwndShell, OS.WM_CANCELMODE, 0, 0);
- widget.postEvent (SWT.Help);
- return LRESULT.ONE;
- }
- }
- return null;
- }
- if (hooks (SWT.Help)) {
- postEvent (SWT.Help);
- return LRESULT.ONE;
- }
- return null;
-}
-
-LRESULT WM_HSCROLL (int wParam, int lParam) {
- if (lParam == 0) return null;
- Control control = WidgetTable.get (lParam);
- if (control == null) return null;
- return control.wmScrollChild (wParam, lParam);
-}
-
-LRESULT WM_IME_CHAR (int wParam, int lParam) {
- Display display = getDisplay ();
- display.lastKey = 0;
- display.lastAscii = wParam;
- display.lastVirtual = display.lastNull = false;
- sendKeyEvent (SWT.KeyDown, OS.WM_IME_CHAR, wParam, lParam);
- sendKeyEvent (SWT.KeyUp, OS.WM_IME_CHAR, wParam, lParam);
- display.lastKey = display.lastAscii = 0;
- return LRESULT.ZERO;
-}
-
-LRESULT WM_IME_COMPOSITION (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_INITMENUPOPUP (int wParam, int lParam) {
-
- /* Ignore WM_INITMENUPOPUP for an accelerator */
- Display display = getDisplay ();
- if (display.accelKeyHit) return null;
-
- /*
- * If the high order word of LPARAM is non-zero,
- * the menu is the system menu and we can ignore
- * WPARAM. Otherwise, use WPARAM to find the menu.
- */
- Shell shell = getShell ();
- Menu oldMenu = shell.activeMenu, newMenu = null;
- if ((lParam >> 16) == 0) {
- newMenu = menuShell ().findMenu (wParam);
- }
- Menu menu = newMenu;
- while (menu != null && menu != oldMenu) {
- menu = menu.getParentMenu ();
- }
- if (menu == null) {
- menu = shell.activeMenu;
- while (menu != null) {
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the hide
- * event. If this happens, stop searching up the
- * ancestor list because there is no longer a link
- * to follow.
- */
- menu.sendEvent (SWT.Hide);
- if (menu.isDisposed ()) break;
- menu = menu.getParentMenu ();
- Menu ancestor = newMenu;
- while (ancestor != null && ancestor != menu) {
- ancestor = ancestor.getParentMenu ();
- }
- if (ancestor != null) break;
- }
- }
-
- /*
- * The shell and the new menu may be disposed because of
- * sending the hide event to the ancestor menus but setting
- * a field to null in a disposed shell is not harmful.
- */
- if (newMenu != null && newMenu.isDisposed ()) newMenu = null;
- shell.activeMenu = newMenu;
-
- /*
- * Send the show event
- */
- if (newMenu != null && newMenu != oldMenu) {
- /*
- * SWT.Selection events are posted to allow stepping
- * in the VA/Java debugger. SWT.Show events are
- * sent to ensure that application event handler
- * code runs before the menu is displayed. This
- * means that SWT.Show events would normally occur
- * before SWT.Selection events. While this is not
- * strictly incorrect, applications often use the
- * SWT.Selection event to update the state of menu
- * items and would like the ordering of events to
- * be the other way around.
- *
- * The fix is to run the deferred events before
- * the menu is shown. This means that stepping
- * through a selection event that was caused by
- * a popup menu will fail in VA/Java.
- */
- display.runDeferredEvents ();
- newMenu.sendEvent (SWT.Show);
- // widget could be disposed at this point
- }
- return null;
-}
-
-LRESULT WM_KEYDOWN (int wParam, int lParam) {
-
- /* Ignore repeating modifier keys by testing key down state */
- switch (wParam) {
- case OS.VK_SHIFT:
- case OS.VK_MENU:
- case OS.VK_CONTROL:
- case OS.VK_CAPITAL:
- case OS.VK_NUMLOCK:
- case OS.VK_SCROLL:
- if ((lParam & 0x40000000) != 0) return null;
- }
-
- /* Clear last key and last ascii because a new key has been typed */
- Display display = getDisplay ();
- display.lastAscii = display.lastKey = 0;
- display.lastVirtual = display.lastNull = false;
-
- /*
- * Do not report a lead byte as a key pressed.
- */
- if (!OS.IsUnicode && OS.IsDBLocale) {
- byte lead = (byte) (wParam & 0xFF);
- if (OS.IsDBCSLeadByte (lead)) return null;
- }
-
- /* Map the virtual key */
- /*
- * Bug on WinCE. MapVirtualKey() returns incorrect values.
- * The fix is to rely on a key mappings table to determine
- * whether the key event must be sent now or if a WM_CHAR
- * event will follow.
- */
- int mapKey = OS.IsWinCE ? 0 : OS.MapVirtualKey (wParam, 2);
-
- /*
- * Bug in Windows 95 and NT. When the user types an accent key such
- * as ^ to get an accented character on a German keyboard, the accent
- * key should be ignored and the next key that the user types is the
- * accented key. On Windows 95 and NT, a call to ToAscii (), clears the
- * accented state such that the next WM_CHAR loses the accent. The fix
- * is to detect the accent key stroke (called a dead key) by testing the
- * high bit of the value returned by MapVirtualKey (). A further problem
- * is that the high bit on Windows NT is bit 32 while the high bit on
- * Windows 95 is bit 16. They should both be bit 32.
- *
- * NOTE: This code is used to avoid a call to ToAscii ().
- */
- if (OS.IsWinNT) {
- if ((mapKey & 0x80000000) != 0) return null;
- } else {
- if ((mapKey & 0x8000) != 0) return null;
- }
-
- /*
- * Bug in Windows. When the accent key is generated on an international
- * keyboard using Ctrl+Alt or the special key, MapVirtualKey () does not
- * have the high bit set indicating that this is an accent key stroke.
- * The fix is to iterate through all known accent, mapping them back to
- * their corresponding virtual key and key state. If the virtual key
- * and key state match the current key, then this is an accent that has
- * been generated using an international keyboard and calling ToAscii ()
- * will clear the accent state.
- *
- * NOTE: This code is used to avoid a call to ToAscii ().
- */
- if (!OS.IsWinCE) {
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.*; +import org.eclipse.swt.events.*; +import org.eclipse.swt.accessibility.*; + +/** + * 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>FocusIn, FocusOut, Help, KeyDown, KeyUp, MouseDoubleClick, MouseDown, MouseEnter, + * MouseExit, MouseHover, MouseUp, MouseMove, Move, Paint, Resize</dd> + * </dl> + * <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> + * + * Note: Only one of LEFT_TO_RIGHT and RIGHT_TO_LEFT may be specified. + */ + +public abstract class Control extends Widget implements Drawable { + /** + * the handle to the OS resource + * (Warning: This field is platform dependent) + */ + public int handle; + + Composite parent; + int drawCount, hCursor; + int foreground, background; + Menu menu; + String toolTipText; + Object layoutData; + Accessible accessible; + + static final short [] ACCENTS = new short [] {'~', '`', '\'', '^', '"'}; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Control () { +} + +/** + * 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 Widget#checkSubclass + * @see Widget#getStyle + */ +public Control (Composite parent, int style) { + super (parent, style); + this.parent = parent; + createWidget (); +} + +/** + * 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 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. + * + * @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 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 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); +} + +/** + * 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); +} + +abstract int callWindowProc (int msg, int wParam, int lParam); + +void checkOrientation (Widget parent) { + super.checkOrientation (parent); + if ((style & SWT.RIGHT_TO_LEFT) != 0) style |= SWT.MIRRORED; +} + +/** + * 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 + * @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 + * @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); +} + +Control computeTabGroup () { + if (isTabGroup ()) return this; + return parent.computeTabGroup (); +} + +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 (); +} + +Control [] computeTabList () { + if (isTabGroup ()) { + if (getVisible () && getEnabled ()) { + return new Control [] {this}; + } + } + return new Control [0]; +} + +void createHandle () { + int hwndParent = 0; + if (handle != 0) { + hwndParent = handle; + } else { + if (parent != null) hwndParent = parent.handle; + } + handle = OS.CreateWindowEx ( + widgetExtStyle (), + windowClass (), + null, + widgetStyle (), + OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0, + hwndParent, + 0, + OS.GetModuleHandle (null), + null); + if (handle == 0) error (SWT.ERROR_NO_HANDLES); + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & OS.WS_CHILD) != 0) { + OS.SetWindowLong (handle, OS.GWL_ID, handle); + } + if (OS.IsDBLocale && parent != null) { + int hIMC = OS.ImmGetContext (hwndParent); + OS.ImmAssociateContext (handle, hIMC); + OS.ImmReleaseContext (hwndParent, hIMC); + } +} + +void createWidget () { + foreground = background = -1; + checkOrientation (parent); + createHandle (); + register (); + subclass (); + setDefaultFont (); +} + +int defaultBackground () { + if (OS.IsWinCE) return OS.GetSysColor (OS.COLOR_WINDOW); + return OS.GetSysColor (OS.COLOR_BTNFACE); +} + +int defaultFont () { + Display display = getDisplay (); + return display.systemFont (); +} + +int defaultForeground () { + return OS.GetSysColor (OS.COLOR_WINDOWTEXT); +} + +void deregister () { + WidgetTable.remove (handle); +} + +void destroyWidget () { + int hwnd = handle; + releaseHandle (); + if (hwnd != 0) { + OS.DestroyWindow (hwnd); + } +} + +void drawBackground (int hDC) { + RECT rect = new RECT (); + OS.GetClientRect (handle, rect); + drawBackground (hDC, rect); +} + +void drawBackground (int hDC, RECT rect) { + Display display = getDisplay (); + int hPalette = display.hPalette; + if (hPalette != 0) { + OS.SelectPalette (hDC, hPalette, false); + OS.RealizePalette (hDC); + } + int pixel = getBackgroundPixel (); + int hBrush = findBrush (pixel); + OS.FillRect (hDC, rect, hBrush); +} + +int findBrush (int pixel) { + return parent.findBrush (pixel); +} + +int findCursor () { + if (hCursor != 0) return hCursor; + return parent.findCursor (); +} + +char findMnemonic (String string) { + int index = 0; + int length = string.length (); + do { + while (index < length && string.charAt (index) != Mnemonic) index++; + if (++index >= length) return '\0'; + if (string.charAt (index) != Mnemonic) return string.charAt (index); + index++; + } while (index < length); + return '\0'; +} + +void fixFocus () { + Shell shell = getShell (); + Control control = this; + while ((control = control.parent) != null) { + if (control.setFocus () || control == shell) return; + } + OS.SetFocus (0); +} + +/** + * 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 (); + Decorations shell = menuShell (); + shell.setSavedFocus (this); + if (!isEnabled () || !isVisible () || !isActive ()) return false; + if (isFocusControl ()) return true; + shell.bringToTop (); + /* + * This code is intentionally commented. + * + * When setting focus to a control, it is + * possible that application code can set + * the focus to another control inside of + * WM_SETFOCUS. In this case, the original + * control will no longer have the focus + * and the call to setFocus() will return + * false indicating failure. + * + * We are still working on a solution at + * this time. + */ +// if (OS.GetFocus () != OS.SetFocus (handle)) return false; + OS.SetFocus (handle); + return isFocusControl (); +} + +void forceResize () { + if (parent == null) return; + WINDOWPOS [] lpwp = parent.lpwp; + if (lpwp == null) return; + for (int i=0; i<lpwp.length; i++) { + WINDOWPOS wp = lpwp [i]; + if (wp != null && wp.hwnd == handle) { + /* + * This code is intentionally commented. All widgets that + * are created by SWT have WS_CLIPSIBLINGS to ensure that + * application code does not draw outside of the control. + */ +// int count = parent.getChildrenCount (); +// if (count > 1) { +// int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); +// if ((bits & OS.WS_CLIPSIBLINGS) == 0) wp.flags |= OS.SWP_NOCOPYBITS; +// } + OS.SetWindowPos (wp.hwnd, 0, wp.x, wp.y, wp.cx, wp.cy, wp.flags); + lpwp [i] = null; + return; + } + } +} + +/** + * 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. + * + * @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 (); + return Color.win32_new (getDisplay (), getBackgroundPixel ()); +} + +int getBackgroundPixel () { + if (background == -1) return defaultBackground (); + return background; +} + +/** + * 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 (); + int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE); + if ((bits & OS.WS_EX_CLIENTEDGE) != 0) return OS.GetSystemMetrics (OS.SM_CXEDGE); + if ((bits & OS.WS_EX_STATICEDGE) != 0) return OS.GetSystemMetrics (OS.SM_CXBORDER); + return 0; +} + +/** + * 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 (); + forceResize (); + RECT rect = new RECT (); + OS.GetWindowRect (handle, rect); + int hwndParent = parent == null ? 0 : parent.handle; + OS.MapWindowPoints (0, hwndParent, rect, 2); + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + return new Rectangle (rect.left, rect.top, width, height); +} + +int getCodePage () { + int hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + LOGFONT logFont = new LOGFONT (); + OS.GetObject (hFont, LOGFONT.sizeof, logFont); + int cs = logFont.lfCharSet & 0xFF; + int [] lpCs = new int [8]; + if (OS.TranslateCharsetInfo (cs, lpCs, OS.TCI_SRCCHARSET)) { + return lpCs [1]; + } + return OS.GetACP (); +} + +/** + * Returns the display that the receiver was created on. + * + * @return the receiver's 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 Display getDisplay () { + Composite parent = this.parent; + if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED); + return parent.getDisplay (); +} + +/** + * 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 OS.IsWindowEnabled (handle); +} + +/** + * 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 (); + int hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (hFont == 0) hFont = defaultFont (); + return Font.win32_new (getDisplay (), hFont); +} + +/** + * 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 Color.win32_new (getDisplay (), getForegroundPixel ()); +} + +int getForegroundPixel () { + if (foreground == -1) return defaultForeground (); + return foreground; +} + +/** + * 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). + * + * @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 (); + forceResize (); + RECT rect = new RECT (); + OS.GetWindowRect (handle, rect); + int hwndParent = parent == null ? 0 : parent.handle; + OS.MapWindowPoints (0, hwndParent, rect, 2); + return new Point (rect.left, rect.top); +} + +/** + * 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; +} + +/** + * 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; +} + +/** + * 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 (); + forceResize (); + RECT rect = new RECT (); + OS.GetWindowRect (handle, rect); + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + return new Point (width, height); +} + +/** + * 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 (); + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + return (bits & OS.WS_VISIBLE) != 0; +} + +boolean hasCursor () { + RECT rect = new RECT (); + if (!OS.GetClientRect (handle, rect)) return false; + if (OS.MapWindowPoints (handle, 0, rect, 2) == 0) return false; + POINT pt = new POINT (); + return (OS.GetCursorPos (pt) && OS.PtInRect (rect, pt)); +} + +boolean hasFocus () { + /* + * If a non-SWT child of the control has focus, + * then this control is considered to have focus + * even though it does not have focus in Windows. + */ + int hwndFocus = OS.GetFocus (); + while (hwndFocus != 0) { + if (hwndFocus == handle) return true; + if (WidgetTable.get (hwndFocus) != null) { + return false; + } + hwndFocus = OS.GetParent (hwndFocus); + } + return false; +} + +/** + * 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 + * + * @private + */ +public int internal_new_GC (GCData data) { + checkWidget(); + int hDC; + if (data == null || data.ps == null) { + hDC = OS.GetDC (handle); + } else { + hDC = OS.BeginPaint (handle, data.ps); + } + if (hDC == 0) SWT.error(SWT.ERROR_NO_HANDLES); + if (data != null) { + data.device = getDisplay (); + data.foreground = getForegroundPixel (); + data.background = getBackgroundPixel (); + data.hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + data.hwnd = handle; + } + return hDC; +} + +/** + * 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 handle the platform specific GC handle + * @param data the platform specific GC data + * + * @private + */ +public void internal_dispose_GC (int hDC, GCData data) { + checkWidget (); + if (data == null || data.ps == null) { + OS.ReleaseDC (handle, hDC); + } else { + OS.EndPaint (handle, data.ps); + } +} + +boolean isActive () { + Display display = getDisplay (); + Shell modal = display.getModalShell (); + if (modal != null && modal != this) { + if ((modal.style & SWT.PRIMARY_MODAL) != 0) { + Shell shell = getShell (); + if (modal.parent == shell) { + return false; + } + } + int bits = SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL; + if ((modal.style & bits) != 0) { + Control control = this; + while (control != null) { + if (control == modal) break; + control = control.parent; + } + if (control != modal) return false; + } + } + return getShell ().getEnabled (); +} + +public boolean isDisposed () { + return handle == 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 (); +} + +/** + * 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 (); + return hasFocus (); +} + +boolean isFocusAncestor () { + Display display = getDisplay (); + Control control = display.getFocusControl (); + while (control != null && control != this) { + control = control.parent; + } + return control == this; +} + +/** + * 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; + /* + * Check to see if current damage is included. + */ +// if (!OS.IsWindowVisible (handle)) return false; +// int flags = OS.DCX_CACHE | OS.DCX_CLIPCHILDREN | OS.DCX_CLIPSIBLINGS; +// int hDC = OS.GetDCEx (handle, 0, flags); +// int result = OS.GetClipBox (hDC, new RECT ()); +// OS.ReleaseDC (handle, hDC); +// return result != OS.NULLREGION; +} + +boolean isTabGroup () { + Control [] tabList = parent._getTabList (); + if (tabList != null) { + for (int i=0; i<tabList.length; i++) { + if (tabList [i] == this) return true; + } + } + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + return (bits & OS.WS_TABSTOP) != 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 bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & OS.WS_TABSTOP) != 0) return false; + int code = OS.SendMessage (handle, OS.WM_GETDLGCODE, 0, 0); + if ((code & OS.DLGC_STATIC) != 0) return false; + if ((code & OS.DLGC_WANTALLKEYS) != 0) return false; + if ((code & OS.DLGC_WANTARROWS) != 0) return false; + if ((code & OS.DLGC_WANTTAB) != 0) return false; + return true; +} + +/** + * 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 OS.IsWindowVisible (handle); +} + +Decorations menuShell () { + return parent.menuShell (); +} + +boolean mnemonicHit (char key) { + return false; +} + +boolean mnemonicMatch (char key) { + return false; +} + +/** + * 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 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> + */ +public void moveAbove (Control control) { + checkWidget (); + int hwndAbove = OS.HWND_TOP; + if (control != null) { + if (control.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT); + if (parent != control.parent) return; + int hwnd = control.handle; + if (hwnd == 0 || hwnd == handle) return; + hwndAbove = OS.GetWindow (hwnd, OS.GW_HWNDPREV); + /* + * Bug in Windows. For some reason, when GetWindow () + * with GW_HWNDPREV is used to query the previous window + * in the z-order with the first child, Windows returns + * the first child instead of NULL. The fix is to detect + * this case and move the control to the top. + */ + if (hwndAbove == 0 || hwndAbove == hwnd) { + hwndAbove = OS.HWND_TOP; + } + } + int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE; + OS.SetWindowPos (handle, hwndAbove, 0, 0, 0, 0, flags); +} + +/** + * 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 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> + */ +public void moveBelow (Control control) { + checkWidget (); + int hwndAbove = OS.HWND_BOTTOM; + if (control != null) { + if (control.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT); + if (parent != control.parent) return; + hwndAbove = control.handle; + } + if (hwndAbove == 0 || hwndAbove == handle) return; + int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE; + OS.SetWindowPos (handle, hwndAbove, 0, 0, 0, 0, flags); +} + +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 + */ +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> + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - 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 + */ +public void pack (boolean changed) { + checkWidget (); + setSize (computeSize (SWT.DEFAULT, SWT.DEFAULT, changed)); +} + +/** + * 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. + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - 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 + */ +public void redraw () { + checkWidget (); + if (!OS.IsWindowVisible (handle)) return; + if (OS.IsWinCE) { + OS.InvalidateRect (handle, null, true); + } else { + int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE; + OS.RedrawWindow (handle, null, 0, flags); + } +} + +/** + * 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. 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 + */ +public void redraw (int x, int y, int width, int height, boolean all) { + checkWidget (); + if (width <= 0 || height <= 0) return; + if (!OS.IsWindowVisible (handle)) return; + RECT rect = new RECT (); + OS.SetRect (rect, x, y, x + width, y + height); + if (OS.IsWinCE) { + OS.InvalidateRect (handle, rect, true); + } else { + int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE; + if (all) flags |= OS.RDW_ALLCHILDREN; + OS.RedrawWindow (handle, rect, 0, flags); + } +} + +void register () { + WidgetTable.put (handle, this); +} + +void releaseHandle () { + super.releaseHandle (); + handle = 0; +} + +void releaseWidget () { + super.releaseWidget (); + if (OS.IsDBLocale) { + OS.ImmAssociateContext (handle, 0); + } + if (toolTipText != null) { + Shell shell = getShell (); + shell.setToolTipText (handle, null); + } + toolTipText = null; + if (menu != null && !menu.isDisposed ()) { + menu.dispose (); + } + menu = null; + deregister (); + unsubclass (); + parent = null; + layoutData = null; + if (accessible != null) { + accessible.internal_dispose_Accessible (); + } + accessible = 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 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 gains or loses focus. + * + * @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 #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 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 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 mouse passes or hovers over controls. + * + * @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 #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 mouse buttons are pressed and released. + * + * @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 #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 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 receiver needs to be painted. + * + * @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 #addPaintListener + */ +public void removePaintListener(PaintListener listener) { + checkWidget (); + if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); + if (eventTable == null) return; + eventTable.unhook(SWT.Paint, listener); +} + +/** + * Removes the listener from the collection of listeners who will + * be notified when traversal events occur. + * + * @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 #addTraverseListener + */ +public void removeTraverseListener(TraverseListener listener) { + checkWidget (); + if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); + if (eventTable == null) return; + eventTable.unhook (SWT.Traverse, listener); +} + +boolean sendKeyEvent (int type, int msg, int wParam, int lParam) { + Event event = new Event (); + if (!setKeyState (event, type)) return true; + return sendKeyEvent (type, msg, wParam, lParam, event); +} + +boolean sendKeyEvent (int type, int msg, int wParam, int lParam, Event event) { + postEvent (type, event); + return true; +} + +boolean sendMouseEvent (int type, int button, int msg, int wParam, int lParam) { + Event event = new Event (); + event.button = button; + event.x = (short) (lParam & 0xFFFF); + event.y = (short) (lParam >> 16); + setInputState (event, type); + return sendMouseEvent (type, msg, wParam, lParam, event); +} + +boolean sendMouseEvent (int type, int msg, int wParam, int lParam, Event event) { + postEvent (type, event); + return true; +} + +/** + * 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. + * + * @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 (); + int pixel = -1; + if (color != null) { + if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + pixel = color.handle; + } + setBackgroundPixel (pixel); +} + +void setBackgroundPixel (int pixel) { + if (background == pixel) return; + background = pixel; + OS.InvalidateRect (handle, null, true); +} + +/** + * 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). + * <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 (); + int flags = OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE; + setBounds (x, y, Math.max (0, width), Math.max (0, height), flags); +} + +void setBounds (int x, int y, int width, int height, int flags) { + if (parent == null) { + OS.SetWindowPos (handle, 0, x, y, width, height, flags); + return; + } + if (parent.lpwp == null) { + /* + * This code is intentionally commented. All widgets that + * are created by SWT have WS_CLIPSIBLINGS to ensure that + * application code does not draw outside of the control. + */ +// int count = parent.getChildrenCount (); +// if (count > 1) { +// int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); +// if ((bits & OS.WS_CLIPSIBLINGS) == 0) flags |= OS.SWP_NOCOPYBITS; +// } + OS.SetWindowPos (handle, 0, x, y, width, height, flags); + return; + } + forceResize (); + WINDOWPOS [] lpwp = parent.lpwp; + int index = 0; + while (index < lpwp.length) { + if (lpwp [index] == null) break; + index ++; + } + if (index == lpwp.length) { + WINDOWPOS [] newLpwp = new WINDOWPOS [lpwp.length + 4]; + System.arraycopy (lpwp, 0, newLpwp, 0, lpwp.length); + parent.lpwp = lpwp = newLpwp; + } + WINDOWPOS wp = new WINDOWPOS (); + wp.hwnd = handle; + wp.x = x; + wp.y = y; + wp.cx = width; + wp.cy = height; + wp.flags = flags; + lpwp [index] = wp; +} + +/** + * 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, rect.width, rect.height); +} + +/** + * 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. + * + * @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 (); + if (capture) { + OS.SetCapture (handle); + } else { + if (OS.GetCapture () == handle) { + OS.ReleaseCapture (); + } + } +} + +/** + * 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 (); + hCursor = 0; + if (cursor != null) { + if (cursor.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + hCursor = cursor.handle; + } + if (OS.IsWinCE) { + OS.SetCursor (hCursor); + return; + } + int hwndCursor = OS.GetCapture (); + if (hwndCursor == 0) { + POINT pt = new POINT (); + if (!OS.GetCursorPos (pt)) return; + int hwnd = hwndCursor = OS.WindowFromPoint (pt); + while (hwnd != 0 && hwnd != handle) { + hwnd = OS.GetParent (hwnd); + } + if (hwnd == 0) return; + } + int lParam = OS.HTCLIENT | (OS.WM_MOUSEMOVE << 16); + OS.SendMessage (hwndCursor, OS.WM_SETCURSOR, hwndCursor, lParam); +} + +void setDefaultFont () { + Display display = getDisplay (); + int hFont = display.systemFont (); + OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0); +} + +/** + * 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 (); + + /* + * Feature in Windows. If the receiver has focus, disabling + * the receiver causes no window to have focus. The fix is + * to assign focus to the first ancestor window that takes + * focus. If no window will take focus, set focus to the + * desktop. + */ + boolean fixFocus = false; + if (!enabled) fixFocus = isFocusAncestor (); + OS.EnableWindow (handle, enabled); + if (fixFocus) fixFocus (); +} + +/** + * Causes the receiver to have the <em>keyboard focus</em>, + * such that all keyboard events will 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 #forceFocus + */ +public boolean setFocus () { + checkWidget (); + 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 (); + int hFont = 0; + if (font != null) { + if (font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + hFont = font.handle; + } + if (hFont == 0) hFont = defaultFont (); + OS.SendMessage (handle, OS.WM_SETFONT, hFont, 1); +} + +/** + * 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. + * + * @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 (); + int pixel = -1; + if (color != null) { + if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + pixel = color.handle; + } + setForegroundPixel (pixel); +} + +void setForegroundPixel (int pixel) { + if (foreground == pixel) return; + foreground = pixel; + OS.InvalidateRect (handle, null, true); +} + +/** + * 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). + * + * @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 (); + int flags = OS.SWP_NOSIZE | OS.SWP_NOZORDER | OS.SWP_NOACTIVATE; + /* + * Feature in WinCE. The SWP_DRAWFRAME flag for SetWindowPos() + * causes a WM_SIZE message to be sent even when the SWP_NOSIZE + * flag is specified. The fix is to set SWP_DRAWFRAME only when + * not running on WinCE. + */ + if (!OS.IsWinCE) flags |= OS.SWP_DRAWFRAME; + setBounds (x, y, 0, 0, flags); +} + +/** + * 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 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. + * + * @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; +} + +boolean setRadioFocus () { + return false; +} + +boolean setRadioSelection (boolean value) { + return false; +} + +/** + * 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. + * <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 + * @see #update + */ +public void setRedraw (boolean redraw) { + checkWidget (); + /* + * This code is intentionally commented. + * + * Feature in Windows. When WM_SETREDRAW is used to turn + * off drawing in a widget, it clears the WS_VISIBLE bits + * and then sets them when redraw is turned back on. This + * means that WM_SETREDRAW will make a widget unexpectedly + * visible. + * + * There is no fix at this time. + */ +// if (drawCount == 0) { +// int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); +// if ((bits & OS.WS_VISIBLE) == 0) return; +// } + + if (redraw) { + if (--drawCount == 0) { + OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0); + if (OS.IsWinCE) { + OS.InvalidateRect (handle, null, true); + } else { + int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE | OS.RDW_ALLCHILDREN; + OS.RedrawWindow (handle, null, 0, flags); + } + } + } else { + if (drawCount++ == 0) { + OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); + } + } +} + +boolean setSavedFocus () { + return forceFocus (); +} + +/** + * 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 (); + int flags = OS.SWP_NOMOVE | OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE; + setBounds (0, 0, Math.max (0, width), Math.max (0, height), flags); +} + +/** + * 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 + * @param height the new height 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); +} + +boolean setTabGroupFocus () { + return setTabItemFocus (); +} + +boolean setTabItemFocus () { + if (!isShowing ()) return false; + return setFocus (); +} + +/** + * Sets the receiver's tool tip text to the argument, which + * may be null indicating that no tool tip text should be shown. + * + * @param string the new tool tip text (or null) + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if 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 (); + Shell shell = getShell (); + shell.setToolTipText (handle, toolTipText = string); +} + +/** + * 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 (); + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if (((bits & OS.WS_VISIBLE) != 0) == visible) return; + 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 Windows. If the receiver has focus, hiding + * the receiver causes no window to have focus. The fix is + * to assign focus to the first ancestor window that takes + * focus. If no window will take focus, set focus to the + * desktop. + */ + boolean fixFocus = false; + if (!visible) fixFocus = isFocusAncestor (); + OS.ShowWindow (handle, visible ? OS.SW_SHOW : OS.SW_HIDE); + 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 (); +} + +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; + } + } + } + } +} + +void subclass () { + int oldProc = windowProc (); + int newProc = getDisplay ().windowProc; + if (oldProc == newProc) return; + OS.SetWindowLong (handle, OS.GWL_WNDPROC, newProc); +} + +/** + * 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 (); + POINT pt = new POINT (); + pt.x = x; pt.y = y; + OS.ScreenToClient (handle, pt); + return new Point (pt.x, pt.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 (); + POINT pt = new POINT (); + pt.x = x; pt.y = y; + OS.ClientToScreen (handle, pt); + return new Point (pt.x, pt.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); +} + +boolean translateAccelerator (MSG msg) { + return menuShell ().translateAccelerator (msg); +} + +boolean translateMnemonic (char key) { + if (!isVisible () || !isEnabled ()) return false; + Event event = new Event (); + event.doit = mnemonicMatch (key); + event.detail = SWT.TRAVERSE_MNEMONIC; + Display display = getDisplay (); + display.lastKey = 0; + display.lastAscii = key; + display.lastVirtual = display.lastNull = false; + if (!setKeyState (event, SWT.Traverse)) { + return false; + } + return traverse (event); +} + +boolean translateMnemonic (MSG msg) { + int hwnd = msg.hwnd; + if (OS.GetKeyState (OS.VK_MENU) >= 0) { + int code = OS.SendMessage (hwnd, OS.WM_GETDLGCODE, 0, 0); + if ((code & OS.DLGC_WANTALLKEYS) != 0) return false; + if ((code & OS.DLGC_BUTTON) == 0) return false; + } + Decorations shell = menuShell (); + if (shell.isVisible () && shell.isEnabled ()) { + char ch = mbcsToWcs ((char) msg.wParam); + return ch != 0 && shell.translateMnemonic (ch); + } + return false; +} + +boolean translateTraversal (MSG msg) { + int key = msg.wParam; + if (key == OS.VK_MENU) { + Shell shell = getShell (); + int hwndShell = shell.handle; + OS.SendMessage (hwndShell, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0); + return false; + } + int hwnd = msg.hwnd; + int detail = SWT.TRAVERSE_NONE; + boolean doit = true, all = false; + boolean lastVirtual = false; + int lastKey = key, lastAscii = 0; + switch (key) { + case OS.VK_ESCAPE: { + all = true; + lastAscii = 27; + int code = OS.SendMessage (hwnd, OS.WM_GETDLGCODE, 0, 0); + if ((code & OS.DLGC_WANTALLKEYS) != 0) { + /* + * Use DLGC_HASSETSEL to determine that the control + * is a text widget. A text widget normally wants + * all keys except VK_ESCAPE. If this bit is not + * set, then assume the control wants all keys, + * including VK_ESCAPE. + */ + if ((code & OS.DLGC_HASSETSEL) == 0) doit = false; + } + detail = SWT.TRAVERSE_ESCAPE; + break; + } + case OS.VK_RETURN: { + all = true; + lastAscii = '\r'; + int code = OS.SendMessage (hwnd, OS.WM_GETDLGCODE, 0, 0); + if ((code & OS.DLGC_WANTALLKEYS) != 0) doit = false; + detail = SWT.TRAVERSE_RETURN; + break; + } + case OS.VK_TAB: { + /* + * NOTE: This code causes Shift+Tab and Ctrl+Tab to + * always attempt traversal which is not correct. + * The default should be the same as a plain Tab key. + * This behavior is currently relied on by StyledText. + * + * The correct behavior is to give every key to a + * control that answers DLGC_WANTALLKEYS. + */ + lastAscii = '\t'; + boolean next = OS.GetKeyState (OS.VK_SHIFT) >= 0; + int code = OS.SendMessage (hwnd, OS.WM_GETDLGCODE, 0, 0); + if ((code & (OS.DLGC_WANTTAB | OS.DLGC_WANTALLKEYS)) != 0) { + if (next && OS.GetKeyState (OS.VK_CONTROL) >= 0) doit = false; + } + detail = next ? SWT.TRAVERSE_TAB_NEXT : SWT.TRAVERSE_TAB_PREVIOUS; + break; + } + case OS.VK_UP: + case OS.VK_LEFT: + case OS.VK_DOWN: + case OS.VK_RIGHT: { + /* + * On WinCE SP there is no tab key. Focus is assigned + * using only the VK_UP and VK_DOWN keys, not with VK_LEFT + * or VK_RIGHT.
*/ + if (OS.IsSP) { + if (key == OS.VK_LEFT || key == OS.VK_RIGHT) return false; + } + lastVirtual = true; + int code = OS.SendMessage (hwnd, OS.WM_GETDLGCODE, 0, 0); + if ((code & (OS.DLGC_WANTARROWS /*| OS.DLGC_WANTALLKEYS*/)) != 0) doit = false; + boolean next = key == OS.VK_DOWN || key == OS.VK_RIGHT; + detail = next ? SWT.TRAVERSE_ARROW_NEXT : SWT.TRAVERSE_ARROW_PREVIOUS; + break; + } + case OS.VK_PRIOR: + case OS.VK_NEXT: { + all = true; + lastVirtual = true; + if (OS.GetKeyState (OS.VK_CONTROL) >= 0) return false; + /* + * The fact that this code is commented causes Ctrl+PgUp + * and Ctrl+PgDn to always attempt traversal which is not + * correct. This behavior is relied on by StyledText. + * + * The correct behavior is to give every key to a control + * that answers DLGC_WANTALLKEYS. + */ +// int code = OS.SendMessage (hwnd, OS., 0, 0); +// if ((code & OS.DLGC_WANTALLKEYS) != 0) doit = false; + detail = key == OS.VK_PRIOR ? SWT.TRAVERSE_PAGE_PREVIOUS : SWT.TRAVERSE_PAGE_NEXT; + break; + } + default: + return false; + } + Event event = new Event (); + event.doit = doit; + event.detail = detail; + Display display = getDisplay (); + display.lastKey = lastKey; + display.lastAscii = lastAscii; + display.lastVirtual = lastVirtual; + display.lastNull = false; + if (!setKeyState (event, SWT.Traverse)) { + return false; + } + Shell shell = getShell (); + Control control = this; + do { + if (control.traverse (event)) { + int hwndShell = shell.handle; + OS.SendMessage (hwndShell, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0); + 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; +} + +boolean traverse (Event event) { + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the traverse + * event. If this happens, return true to stop further + * event processing. + */ + sendEvent (SWT.Traverse, event); + if (isDisposed ()) return false; + 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.character); + case SWT.TRAVERSE_PAGE_NEXT: return traversePage (true); + case SWT.TRAVERSE_PAGE_PREVIOUS: return traversePage (false); + } + 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 (); + if (!isFocusControl () && !setFocus ()) return false; + Event event = new Event (); + event.doit = true; + event.detail = traversal; + return traverse (event); +} + +boolean traverseEscape () { + return false; +} + +boolean traverseGroup (boolean next) { + Control root = computeTabRoot (); + Control group = computeTabGroup (); + Control [] 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) { + Control control = list [index]; + if (!control.isDisposed () && control.setTabGroupFocus ()) { + if (!isDisposed () && !isFocusControl ()) 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. + */ + 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 traverseMnemonic (char key) { + return mnemonicHit (key); +} + +boolean traversePage (boolean next) { + return false; +} + +boolean traverseReturn () { + return false; +} + +void unsubclass () { + int newProc = windowProc (); + int oldProc = getDisplay ().windowProc; + if (oldProc == newProc) return; + OS.SetWindowLong (handle, OS.GWL_WNDPROC, newProc); +} + +/** + * Forces all outstanding paint requests for the widget + * to be processed before this method returns. + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - 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 + */ +public void update () { + checkWidget (); + update (false); +} + +void update (boolean all) { +// checkWidget (); + if (OS.IsWinCE) { + OS.UpdateWindow (handle); + } else { + int flags = OS.RDW_UPDATENOW; + if (all) flags |= OS.RDW_ALLCHILDREN; + OS.RedrawWindow (handle, null, 0, flags); + } +} + +void updateFont (Font oldFont, Font newFont) { + Font font = getFont (); + if (font.equals (oldFont)) setFont (newFont); +} + +int widgetExtStyle () { + int bits = 0; + if ((style & SWT.BORDER) != 0) bits |= OS.WS_EX_CLIENTEDGE; + /* + * Feature in Windows NT. When CreateWindowEx() is called with + * WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT, CreateWindowEx() + * fails to create the HWND. The fix is to not use these bits. + */ + if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) < (4 << 16 | 10)) { + return bits; + } + bits |= OS.WS_EX_NOINHERITLAYOUT; + if ((style & SWT.RIGHT_TO_LEFT) != 0) bits |= OS.WS_EX_LAYOUTRTL; + return bits; +} + +int widgetStyle () { + /* Force clipping of siblings by setting WS_CLIPSIBLINGS */ + return OS.WS_CHILD | OS.WS_VISIBLE | OS.WS_CLIPSIBLINGS; + + /* + * This code is intentionally commented. When clipping + * of both siblings and children is not enforced, it is + * possible for application code to draw outside of the + * control. + */ +// int bits = OS.WS_CHILD | OS.WS_VISIBLE; +// if ((style & SWT.CLIP_SIBLINGS) != 0) bits |= OS.WS_CLIPSIBLINGS; +// if ((style & SWT.CLIP_CHILDREN) != 0) bits |= OS.WS_CLIPCHILDREN; +// return bits; +} + +/** + * Changes the parent of the widget to be the one provided if + * the underlying operating system supports this feature. + * Answers <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> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li> + * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</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 (OS.SetParent (handle, parent.handle) == 0) { + return false; + } + this.parent = parent; + return true; +} + +abstract TCHAR windowClass (); + +abstract int windowProc (); + +int windowProc (int msg, int wParam, int lParam) { + LRESULT result = null; + switch (msg) { + case OS.WM_ACTIVATE: result = WM_ACTIVATE (wParam, lParam); break; + case OS.WM_CHAR: result = WM_CHAR (wParam, lParam); break; + case OS.WM_CLEAR: result = WM_CLEAR (wParam, lParam); break; + case OS.WM_CLOSE: result = WM_CLOSE (wParam, lParam); break; + case OS.WM_COMMAND: result = WM_COMMAND (wParam, lParam); break; + case OS.WM_CONTEXTMENU: result = WM_CONTEXTMENU (wParam, lParam); break; + case OS.WM_CTLCOLORBTN: + case OS.WM_CTLCOLORDLG: + case OS.WM_CTLCOLOREDIT: + case OS.WM_CTLCOLORLISTBOX: + case OS.WM_CTLCOLORMSGBOX: + case OS.WM_CTLCOLORSCROLLBAR: + case OS.WM_CTLCOLORSTATIC: result = WM_CTLCOLOR (wParam, lParam); break; + case OS.WM_CUT: result = WM_CUT (wParam, lParam); break; + case OS.WM_DESTROY: result = WM_DESTROY (wParam, lParam); break; + case OS.WM_DRAWITEM: result = WM_DRAWITEM (wParam, lParam); break; + case OS.WM_ENDSESSION: result = WM_ENDSESSION (wParam, lParam); break; + case OS.WM_ERASEBKGND: result = WM_ERASEBKGND (wParam, lParam); break; + case OS.WM_GETDLGCODE: result = WM_GETDLGCODE (wParam, lParam); break; + case OS.WM_HELP: result = WM_HELP (wParam, lParam); break; + case OS.WM_HSCROLL: result = WM_HSCROLL (wParam, lParam); break; + case OS.WM_IME_CHAR: result = WM_IME_CHAR (wParam, lParam); break; + case OS.WM_IME_COMPOSITION: result = WM_IME_COMPOSITION (wParam, lParam); break; + case OS.WM_INITMENUPOPUP: result = WM_INITMENUPOPUP (wParam, lParam); break; + case OS.WM_GETFONT: result = WM_GETFONT (wParam, lParam); break; + case OS.WM_GETOBJECT: result = WM_GETOBJECT (wParam, lParam); break; + case OS.WM_HOTKEY: result = WM_HOTKEY (wParam, lParam); break; + case OS.WM_KEYDOWN: result = WM_KEYDOWN (wParam, lParam); break; + case OS.WM_KEYUP: result = WM_KEYUP (wParam, lParam); break; + case OS.WM_KILLFOCUS: result = WM_KILLFOCUS (wParam, lParam); break; + case OS.WM_LBUTTONDBLCLK: result = WM_LBUTTONDBLCLK (wParam, lParam); break; + case OS.WM_LBUTTONDOWN: result = WM_LBUTTONDOWN (wParam, lParam); break; + case OS.WM_LBUTTONUP: result = WM_LBUTTONUP (wParam, lParam); break; + case OS.WM_MBUTTONDBLCLK: result = WM_MBUTTONDBLCLK (wParam, lParam); break; + case OS.WM_MBUTTONDOWN: result = WM_MBUTTONDOWN (wParam, lParam); break; + case OS.WM_MBUTTONUP: result = WM_MBUTTONUP (wParam, lParam); break; + case OS.WM_MEASUREITEM: result = WM_MEASUREITEM (wParam, lParam); break; + case OS.WM_MENUCHAR: result = WM_MENUCHAR (wParam, lParam); break; + case OS.WM_MENUSELECT: result = WM_MENUSELECT (wParam, lParam); break; + case OS.WM_MOUSEACTIVATE: result = WM_MOUSEACTIVATE (wParam, lParam); break; + case OS.WM_MOUSEHOVER: result = WM_MOUSEHOVER (wParam, lParam); break; + case OS.WM_MOUSELEAVE: result = WM_MOUSELEAVE (wParam, lParam); break; + case OS.WM_MOUSEMOVE: result = WM_MOUSEMOVE (wParam, lParam); break; + case OS.WM_MOUSEWHEEL: result = WM_MOUSEWHEEL (wParam, lParam); break; + case OS.WM_MOVE: result = WM_MOVE (wParam, lParam); break; + case OS.WM_NCACTIVATE: result = WM_NCACTIVATE (wParam, lParam); break; + case OS.WM_NCCALCSIZE: result = WM_NCCALCSIZE (wParam, lParam); break; + case OS.WM_NCHITTEST: result = WM_NCHITTEST (wParam, lParam); break; + case OS.WM_NOTIFY: result = WM_NOTIFY (wParam, lParam); break; + case OS.WM_PAINT: result = WM_PAINT (wParam, lParam); break; + case OS.WM_PALETTECHANGED: result = WM_PALETTECHANGED (wParam, lParam); break; + case OS.WM_PASTE: result = WM_PASTE (wParam, lParam); break; + case OS.WM_PRINTCLIENT: result = WM_PRINTCLIENT (wParam, lParam); break; + case OS.WM_QUERYENDSESSION: result = WM_QUERYENDSESSION (wParam, lParam); break; + case OS.WM_QUERYNEWPALETTE: result = WM_QUERYNEWPALETTE (wParam, lParam); break; + case OS.WM_QUERYOPEN: result = WM_QUERYOPEN (wParam, lParam); break; + case OS.WM_RBUTTONDBLCLK: result = WM_RBUTTONDBLCLK (wParam, lParam); break; + case OS.WM_RBUTTONDOWN: result = WM_RBUTTONDOWN (wParam, lParam); break; + case OS.WM_RBUTTONUP: result = WM_RBUTTONUP (wParam, lParam); break; + case OS.WM_SETCURSOR: result = WM_SETCURSOR (wParam, lParam); break; + case OS.WM_SETFOCUS: result = WM_SETFOCUS (wParam, lParam); break; + case OS.WM_SETFONT: result = WM_SETFONT (wParam, lParam); break; + case OS.WM_SETTINGCHANGE: result = WM_SETTINGCHANGE (wParam, lParam); break; + case OS.WM_SETREDRAW: result = WM_SETREDRAW (wParam, lParam); break; + case OS.WM_SHOWWINDOW: result = WM_SHOWWINDOW (wParam, lParam); break; + case OS.WM_SIZE: result = WM_SIZE (wParam, lParam); break; + case OS.WM_SYSCHAR: result = WM_SYSCHAR (wParam, lParam); break; + case OS.WM_SYSCOLORCHANGE: result = WM_SYSCOLORCHANGE (wParam, lParam); break; + case OS.WM_SYSCOMMAND: result = WM_SYSCOMMAND (wParam, lParam); break; + case OS.WM_SYSKEYDOWN: result = WM_SYSKEYDOWN (wParam, lParam); break; + case OS.WM_SYSKEYUP: result = WM_SYSKEYUP (wParam, lParam); break; + case OS.WM_TIMER: result = WM_TIMER (wParam, lParam); break; + case OS.WM_UNDO: result = WM_UNDO (wParam, lParam); break; + case OS.WM_VSCROLL: result = WM_VSCROLL (wParam, lParam); break; + case OS.WM_WINDOWPOSCHANGING: result = WM_WINDOWPOSCHANGING (wParam, lParam); break; + } + if (result != null) return result.value; + return callWindowProc (msg, wParam, lParam); +} + +LRESULT WM_ACTIVATE (int wParam, int lParam) { + return null; +} + +LRESULT WM_CHAR (int wParam, int lParam) { + + /* + * Do not report a lead byte as a key pressed. + */ + Display display = getDisplay (); + if (!OS.IsUnicode && OS.IsDBLocale) { + byte lead = (byte) (wParam & 0xFF); + if (OS.IsDBCSLeadByte (lead)) return null; + } + + /* + * Use VkKeyScan () to tell us if the character is a control + * or a numeric key pad character with Num Lock down. On + * international keyboards, the control key may be down when + * the character is not a control character. In this case + * use the last key (computed in WM_KEYDOWN) instead of wParam + * as the keycode because there is not enough information to + * compute the keycode in WPARAM. + */ + display.lastAscii = wParam; + display.lastNull = false; + if (display.lastKey == 0) { + display.lastKey = wParam; + display.lastVirtual = display.isVirtualKey (wParam); + } else { + int result = OS.IsWinCE ? 0 : OS.VkKeyScan ((short) wParam); + if (!OS.IsWinCE && (result == -1 || (result >> 8) <= 2)) { + if (OS.GetKeyState (OS.VK_CONTROL) < 0) { + display.lastVirtual = display.isVirtualKey (display.lastKey); + } + } else { + display.lastKey = wParam; + display.lastVirtual = false; + } + } + if (!sendKeyEvent (SWT.KeyDown, OS.WM_CHAR, wParam, lParam)) { + return LRESULT.ZERO; + } + return null; +} + +LRESULT WM_CLEAR (int wParam, int lParam) { + return null; +} + +LRESULT WM_CLOSE (int wParam, int lParam) { + return null; +} + +LRESULT WM_COMMAND (int wParam, int lParam) { + /* + * When the WM_COMMAND message is sent from a + * menu, the HWND parameter in LPARAM is zero. + */ + if (lParam == 0) { + Decorations shell = menuShell (); + if (shell.isEnabled ()) { + int id = wParam & 0xFFFF; + MenuItem item = shell.findMenuItem (id); + if (item != null && item.isEnabled ()) { + return item.wmCommandChild (wParam, lParam); + } + } + return null; + } + Control control = WidgetTable.get (lParam); + if (control == null) return null; + return control.wmCommandChild (wParam, lParam); +} + +LRESULT WM_CONTEXTMENU (int wParam, int lParam) { + if (wParam != handle) return null; + + /* + * Feature in Windows. When the user presses WM_NCRBUTTONUP, + * a WM_CONTEXTMENU message is generated. This happens when + * the user releases the mouse over a scroll bar. Normally, + * window displays the default scrolling menu but applications + * can process WM_CONTEXTMENU to display a different menu. + * Typically, an application does not want to supply a special + * scroll menu. The fix is to look for a WM_CONTEXTMENU that + * originated from a mouse event and display the menu when the + * mouse was released in the client area. + */ + POINT pt = new POINT (); + pt.x = (short) (lParam & 0xFFFF); + pt.y = (short) (lParam >> 16); + if (pt.x != -1 || pt.y != -1) { + RECT rect = new RECT (); + OS.GetClientRect (handle, rect); + OS.ScreenToClient (handle, pt); + if (!OS.PtInRect (rect, pt)) return null; + } + + /* + * Because context menus can be shared between controls + * and the parent of all menus is the shell, the menu may + * have been destroyed. + */ + if (menu != null && !menu.isDisposed ()) { +// menu.setLocation (x, y); + menu.setVisible (true); + return LRESULT.ZERO; + } + return null; +} + +LRESULT WM_CTLCOLOR (int wParam, int lParam) { + Display display = getDisplay (); + int hPalette = display.hPalette; + if (hPalette != 0) { + OS.SelectPalette (wParam, hPalette, false); + OS.RealizePalette (wParam); + } + Control control = WidgetTable.get (lParam); + if (control == null) return null; + return control.wmColorChild (wParam, lParam); +} + +LRESULT WM_CUT (int wParam, int lParam) { + return null; +} + +LRESULT WM_DESTROY (int wParam, int lParam) { + return null; +} + +LRESULT WM_DRAWITEM (int wParam, int lParam) { + DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT (); + OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof); + if (struct.CtlType == OS.ODT_MENU) { + Decorations shell = menuShell (); + MenuItem item = shell.findMenuItem (struct.itemID); + if (item == null) return null; + return item.wmDrawChild (wParam, lParam); + } + Control control = WidgetTable.get (struct.hwndItem); + if (control == null) return null; + return control.wmDrawChild (wParam, lParam); +} + +LRESULT WM_ENDSESSION (int wParam, int lParam) { + return null; +} + +LRESULT WM_ERASEBKGND (int wParam, int lParam) { + return null; +} + +LRESULT WM_GETDLGCODE (int wParam, int lParam) { + return null; +} + +LRESULT WM_GETFONT (int wParam, int lParam) { + return null; +} + +LRESULT WM_GETOBJECT (int wParam, int lParam) { + if (accessible != null) { + int result = accessible.internal_WM_GETOBJECT (wParam, lParam); + if (result != 0) return new LRESULT (result); + } + return null; +} + +LRESULT WM_HOTKEY (int wParam, int lParam) { + return null; +} + +LRESULT WM_HELP (int wParam, int lParam) { + if (OS.IsWinCE) return null; + HELPINFO lphi = new HELPINFO (); + OS.MoveMemory (lphi, lParam, HELPINFO.sizeof); + Decorations shell = menuShell (); + if (!shell.isEnabled ()) return null; + if (lphi.iContextType == OS.HELPINFO_MENUITEM) { + MenuItem item = shell.findMenuItem (lphi.iCtrlId); + if (item != null && item.isEnabled ()) { + Widget widget = null; + if (item.hooks (SWT.Help)) { + widget = item; + } else { + Menu menu = item.parent; + if (menu.hooks (SWT.Help)) widget = menu; + } + if (widget != null) { + int hwndShell = shell.handle; + OS.SendMessage (hwndShell, OS.WM_CANCELMODE, 0, 0); + widget.postEvent (SWT.Help); + return LRESULT.ONE; + } + } + return null; + } + if (hooks (SWT.Help)) { + postEvent (SWT.Help); + return LRESULT.ONE; + } + return null; +} + +LRESULT WM_HSCROLL (int wParam, int lParam) { + if (lParam == 0) return null; + Control control = WidgetTable.get (lParam); + if (control == null) return null; + return control.wmScrollChild (wParam, lParam); +} + +LRESULT WM_IME_CHAR (int wParam, int lParam) { + Display display = getDisplay (); + display.lastKey = 0; + display.lastAscii = wParam; + display.lastVirtual = display.lastNull = false; + sendKeyEvent (SWT.KeyDown, OS.WM_IME_CHAR, wParam, lParam); + sendKeyEvent (SWT.KeyUp, OS.WM_IME_CHAR, wParam, lParam); + display.lastKey = display.lastAscii = 0; + return LRESULT.ZERO; +} + +LRESULT WM_IME_COMPOSITION (int wParam, int lParam) { + return null; +} + +LRESULT WM_INITMENUPOPUP (int wParam, int lParam) { + + /* Ignore WM_INITMENUPOPUP for an accelerator */ + Display display = getDisplay (); + if (display.accelKeyHit) return null; + + /* + * If the high order word of LPARAM is non-zero, + * the menu is the system menu and we can ignore + * WPARAM. Otherwise, use WPARAM to find the menu. + */ + Shell shell = getShell (); + Menu oldMenu = shell.activeMenu, newMenu = null; + if ((lParam >> 16) == 0) { + newMenu = menuShell ().findMenu (wParam); + } + Menu menu = newMenu; + while (menu != null && menu != oldMenu) { + menu = menu.getParentMenu (); + } + if (menu == null) { + menu = shell.activeMenu; + while (menu != null) { + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the hide + * event. If this happens, stop searching up the + * ancestor list because there is no longer a link + * to follow. + */ + menu.sendEvent (SWT.Hide); + if (menu.isDisposed ()) break; + menu = menu.getParentMenu (); + Menu ancestor = newMenu; + while (ancestor != null && ancestor != menu) { + ancestor = ancestor.getParentMenu (); + } + if (ancestor != null) break; + } + } + + /* + * The shell and the new menu may be disposed because of + * sending the hide event to the ancestor menus but setting + * a field to null in a disposed shell is not harmful. + */ + if (newMenu != null && newMenu.isDisposed ()) newMenu = null; + shell.activeMenu = newMenu; + + /* + * Send the show event + */ + if (newMenu != null && newMenu != oldMenu) { + /* + * SWT.Selection events are posted to allow stepping + * in the VA/Java debugger. SWT.Show events are + * sent to ensure that application event handler + * code runs before the menu is displayed. This + * means that SWT.Show events would normally occur + * before SWT.Selection events. While this is not + * strictly incorrect, applications often use the + * SWT.Selection event to update the state of menu + * items and would like the ordering of events to + * be the other way around. + * + * The fix is to run the deferred events before + * the menu is shown. This means that stepping + * through a selection event that was caused by + * a popup menu will fail in VA/Java. + */ + display.runDeferredEvents (); + newMenu.sendEvent (SWT.Show); + // widget could be disposed at this point + } + return null; +} + +LRESULT WM_KEYDOWN (int wParam, int lParam) { + + /* Ignore repeating modifier keys by testing key down state */ + switch (wParam) { + case OS.VK_SHIFT: + case OS.VK_MENU: + case OS.VK_CONTROL: + case OS.VK_CAPITAL: + case OS.VK_NUMLOCK: + case OS.VK_SCROLL: + if ((lParam & 0x40000000) != 0) return null; + } + + /* Clear last key and last ascii because a new key has been typed */ + Display display = getDisplay (); + display.lastAscii = display.lastKey = 0; + display.lastVirtual = display.lastNull = false; + + /* + * Do not report a lead byte as a key pressed. + */ + if (!OS.IsUnicode && OS.IsDBLocale) { + byte lead = (byte) (wParam & 0xFF); + if (OS.IsDBCSLeadByte (lead)) return null; + } + + /* Map the virtual key */ + /* + * Bug on WinCE. MapVirtualKey() returns incorrect values. + * The fix is to rely on a key mappings table to determine + * whether the key event must be sent now or if a WM_CHAR + * event will follow. + */ + int mapKey = OS.IsWinCE ? 0 : OS.MapVirtualKey (wParam, 2); + + /* + * Bug in Windows 95 and NT. When the user types an accent key such + * as ^ to get an accented character on a German keyboard, the accent + * key should be ignored and the next key that the user types is the + * accented key. On Windows 95 and NT, a call to ToAscii (), clears the + * accented state such that the next WM_CHAR loses the accent. The fix + * is to detect the accent key stroke (called a dead key) by testing the + * high bit of the value returned by MapVirtualKey (). A further problem + * is that the high bit on Windows NT is bit 32 while the high bit on + * Windows 95 is bit 16. They should both be bit 32. + * + * NOTE: This code is used to avoid a call to ToAscii (). + */ + if (OS.IsWinNT) { + if ((mapKey & 0x80000000) != 0) return null; + } else { + if ((mapKey & 0x8000) != 0) return null; + } + + /* + * Bug in Windows. When the accent key is generated on an international + * keyboard using Ctrl+Alt or the special key, MapVirtualKey () does not + * have the high bit set indicating that this is an accent key stroke. + * The fix is to iterate through all known accent, mapping them back to + * their corresponding virtual key and key state. If the virtual key + * and key state match the current key, then this is an accent that has + * been generated using an international keyboard and calling ToAscii () + * will clear the accent state. + * + * NOTE: This code is used to avoid a call to ToAscii (). + */ + if (!OS.IsWinCE) { for (int i=0; i<ACCENTS.length; i++) { - int value = OS.VkKeyScan (ACCENTS [i]);
- if ((value & 0xFF) == wParam && (value & 0x600) == 0x600) {
- return null;
- }
- }
- }
-
- /*
- * If we are going to get a WM_CHAR, ensure that last key has
- * the correct character value for the key down and key up
- * events. It is not sufficient to ignore the WM_KEYDOWN
- * (when we know we are going to get a WM_CHAR) and compute
- * the key in WM_CHAR because there is not enough information
- * by the time we get the WM_CHAR. For example, when the user
- * types Ctrl+Shift+6 on a US keyboard, we get a WM_CHAR with
- * wParam=30. When the user types Ctrl+Shift+6 on a German
- * keyboard, we also get a WM_CHAR with wParam=30. On the US
- * keyboard Shift+6 is ^, on the German keyboard Shift+6 is &.
- * There is no way to map wParam=30 in WM_CHAR to the correct
- * value. Also, on international keyboards, the control key
- * may be down when the user has not entered a control character.
- */
- display.lastKey = wParam;
- display.lastVirtual = (mapKey == 0);
- if (display.lastVirtual) {
- /*
- * Feature in Windows. The virtual key VK_DELETE is not
- * treated as both a virtual key and an ASCII key by Windows.
- * Therefore, we will not receive a WM_CHAR for this key.
- * The fix is to treat VK_DELETE as a special case and map
- * the ASCII value explictly (Delete is 0x7F).
- */
- if (display.lastKey == OS.VK_DELETE) display.lastAscii = 0x7F;
- /*
- * It is possible to get a WM_CHAR for a virtual key when
- * Num Lock is on. If the user types Home while Num Lock
- * is down, a WM_CHAR is issued with WPARM=55 (for the
- * character 7). If we are going to get a WM_CHAR we need
- * to ensure that the last key has the correct value. Note
- * that Ctrl+Home does not issue a WM_CHAR when Num Lock is
- * down.
- */
- if (OS.VK_NUMPAD0 <= display.lastKey && display.lastKey <= OS.VK_DIVIDE) {
- if (display.asciiKey (display.lastKey) != 0) return null;
- display.lastAscii = display.numpadKey (display.lastKey);
- }
- } else {
- /*
- * Get the shifted state or convert to lower case if necessary.
- * If the user types Ctrl+A, LastKey should be 'a', not 'A'. If
- * the user types Ctrl+Shift+A, LastKey should be 'A'. If the user
- * types Ctrl+Shift+6, the value of LastKey will depend on the
- * international keyboard.
- */
- if (OS.GetKeyState (OS.VK_SHIFT) < 0) {
- display.lastKey = display.shiftedKey (display.lastKey);
- if (display.lastKey == 0) display.lastKey = wParam;
- } else {
- display.lastKey = OS.CharLower ((short) mapKey);
- }
- /*
- * Some key combinations map to Windows ASCII keys depending
- * on the keyboard. For example, Ctrl+Alt+Q maps to @ on a
- * German keyboard. If the current key combination is special,
- * the correct character is placed in wParam for processing in
- * WM_CHAR. If this is the case, issue the key down event from
- * inside WM_CHAR.
- */
- int asciiKey = display.asciiKey (wParam);
- if (asciiKey != 0) {
- /*
- * When the user types Ctrl+Space, ToAscii () maps this to
- * Space. Normally, ToAscii () maps a key to a different
- * key if both a WM_KEYDOWN and a WM_CHAR will be issued.
- * To avoid the extra SWT.KeyDown, look for VK_SPACE and
- * issue the event from WM_CHAR.
- */
- if (asciiKey == OS.VK_SPACE) {
- display.lastVirtual = true;
- return null;
- }
- if (asciiKey != wParam) return null;
- }
-
- /*
- * If the control key is not down at this point, then
- * the key that was pressed was an accent key. In that
- * case, do not issue the key down event.
- */
- if (OS.GetKeyState (OS.VK_CONTROL) >= 0) {
- display.lastKey = 0;
- return null;
- }
-
- /*
- * Virtual keys such as VK_RETURN are both virtual and ASCII keys.
- * Normally, these are marked virtual in WM_CHAR. Since we will not
- * be getting a WM_CHAR for the key at this point, we need to test
- * LastKey to see if it is virtual. This happens when the user types
- * Ctrl+Tab.
- */
- display.lastVirtual = display.isVirtualKey (wParam);
- display.lastAscii = display.controlKey (display.lastKey);
- display.lastNull = display.lastAscii == 0 && display.lastKey == '@';
- }
- if (!sendKeyEvent (SWT.KeyDown, OS.WM_KEYDOWN, wParam, lParam)) {
- return LRESULT.ZERO;
- }
- return null;
-}
-
-LRESULT WM_KEYUP (int wParam, int lParam) {
- Display display = getDisplay ();
-
- /* Check for hardware keys */
- if (OS.IsWinCE) {
- if (OS.VK_APP1 <= wParam && wParam <= OS.VK_APP6) {
- display.lastKey = display.lastAscii = 0;
- display.lastVirtual = display.lastNull = false;
- Event event = new Event ();
- event.detail = wParam - OS.VK_APP1 + 1;
- /* Check the bit 30 to get the key state */
- int type = (lParam & 0x40000000) != 0 ? SWT.HardKeyUp : SWT.HardKeyDown;
- if (setInputState (event, type)) sendEvent (type, event);
- return null;
- }
- }
-
- /*
- * If the key up is not hooked, reset last key
- * and last ascii in case the key down is hooked.
- */
- if (!hooks (SWT.KeyUp) && !display.filters (SWT.KeyUp)) {
- display.lastKey = display.lastAscii = 0;
- display.lastVirtual = display.lastNull = false;
- return null;
- }
-
- /* Map the virtual key. */
- /*
- * Bug on WinCE. MapVirtualKey() returns incorrect values.
- * The fix is to rely on a key mappings table to determine
- * whether the key event must be sent now or if a WM_CHAR
- * event will follow.
- */
- int mapKey = OS.IsWinCE ? 0 : OS.MapVirtualKey (wParam, 2);
-
- /*
- * Bug in Windows 95 and NT. When the user types an accent key such
- * as ^ to get an accented character on a German keyboard, the accent
- * key should be ignored and the next key that the user types is the
- * accented key. On Windows 95 and NT, a call to ToAscii (), clears the
- * accented state such that the next WM_CHAR loses the accent. The fix
- * is to detect the accent key stroke (called a dead key) by testing the
- * high bit of the value returned by MapVirtualKey (). A further problem
- * is that the high bit on Windows NT is bit 32 while the high bit on
- * Windows 95 is bit 16. They should both be bit 32.
- *
- * NOTE: This code is used to avoid a call to ToAscii ().
- *
- */
- if (OS.IsWinNT) {
- if ((mapKey & 0x80000000) != 0) return null;
- } else {
- if ((mapKey & 0x8000) != 0) return null;
- }
-
- /*
- * Bug in Windows. When the accent key is generated on an international
- * keyboard using Ctrl+Alt or the special key, MapVirtualKey () does not
- * have the high bit set indicating that this is an accent key stroke.
- * The fix is to iterate through all known accent, mapping them back to
- * their corresponding virtual key and key state. If the virtual key
- * and key state match the current key, then this is an accent that has
- * been generated using an international keyboard.
- *
- * NOTE: This code is used to avoid a call to ToAscii ().
- */
- if (!OS.IsWinCE) {
- for (int i=0; i<ACCENTS.length; i++) {
- int value = OS.VkKeyScan (ACCENTS [i]);
- if ((value & 0xFF) == wParam && (value & 0x600) == 0x600) {
- display.lastKey = display.lastAscii = 0;
- display.lastVirtual = display.lastNull = false;
- return null;
- }
- }
- }
-
- display.lastVirtual = (mapKey == 0);
- if (display.lastVirtual) {
- display.lastKey = wParam;
- } else {
- if (display.lastKey == 0) {
- display.lastAscii = 0;
- display.lastNull = false;
- return null;
- }
- display.lastVirtual = display.isVirtualKey (display.lastKey);
- }
-
- LRESULT result = null;
- if (!sendKeyEvent (SWT.KeyUp, OS.WM_KEYUP, wParam, lParam)) {
- result = LRESULT.ZERO;
- }
- display.lastKey = display.lastAscii = 0;
- display.lastVirtual = display.lastNull = false;
- return result;
-}
-
-LRESULT WM_KILLFOCUS (int wParam, int lParam) {
- int code = callWindowProc (OS.WM_KILLFOCUS, wParam, lParam);
- Display display = getDisplay ();
- Shell shell = getShell ();
-
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the focus
- * out event. If this happens keep going to send
- * the deactivate events.
- */
- sendEvent (SWT.FocusOut);
- // widget could be disposed at this point
-
- /*
- * 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 ()) {
- Control control = display.findControl (wParam);
- if (control == null || shell != control.getShell ()) {
- shell.setActiveControl (null);
- }
- }
-
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the focus
- * or deactivate events. If this happens, end the
- * processing of the Windows message by returning
- * zero as the result of the window proc.
- */
- if (isDisposed ()) return LRESULT.ZERO;
- if (code == 0) return LRESULT.ZERO;
- return new LRESULT (code);
-}
-
-LRESULT WM_LBUTTONDBLCLK (int wParam, int lParam) {
- /*
- * Feature in Windows. Windows sends the following
- * messages when the user double clicks the mouse:
- *
- * WM_LBUTTONDOWN - mouse down
- * WM_LBUTTONUP - mouse up
- * WM_LBUTTONDBLCLK - double click
- * WM_LBUTTONUP - mouse up
- *
- * Applications that expect matching mouse down/up
- * pairs will not see the second mouse down. The
- * fix is to send a mouse down event.
- */
- sendMouseEvent (SWT.MouseDown, 1, OS.WM_LBUTTONDOWN, wParam, lParam);
- sendMouseEvent (SWT.MouseDoubleClick, 1, OS.WM_LBUTTONDBLCLK, wParam, lParam);
- int result = callWindowProc (OS.WM_LBUTTONDBLCLK, wParam, lParam);
- if (OS.GetCapture () != handle) OS.SetCapture (handle);
- return new LRESULT (result);
-}
-
-LRESULT WM_LBUTTONDOWN (int wParam, int lParam) {
- boolean dragging = false, mouseDown = true;
- boolean dragDetect = hooks (SWT.DragDetect);
- if (dragDetect) {
- if (!OS.IsWinCE) {
- /*
- * Feature in Windows. It's possible that the drag
- * operation will not be started while the mouse is
- * down, meaning that the mouse should be captured.
- * This can happen when the user types the ESC key
- * to cancel the drag. The fix is to query the state
- * of the mouse and capture the mouse accordingly.
- */
- POINT pt = new POINT ();
- pt.x = (short) (lParam & 0xFFFF);
- pt.y = (short) (lParam >> 16);
- OS.ClientToScreen(handle, pt);
- dragging = OS.DragDetect (handle, pt);
- mouseDown = OS.GetKeyState (OS.VK_LBUTTON) < 0;
- }
- }
- sendMouseEvent (SWT.MouseDown, 1, OS.WM_LBUTTONDOWN, wParam, lParam);
- int result = callWindowProc (OS.WM_LBUTTONDOWN, wParam, lParam);
- if (OS.IsPPC) {
- if (menu != null && !menu.isDisposed ()) {
- int x = (short) (lParam & 0xFFFF);
- int y = (short) (lParam >> 16);
- SHRGINFO shrg = new SHRGINFO ();
- shrg.cbSize = SHRGINFO.sizeof;
- shrg.hwndClient = handle;
- shrg.ptDown_x = x;
- shrg.ptDown_y = y;
- shrg.dwFlags = OS.SHRG_RETURNCMD;
- int type = OS.SHRecognizeGesture (shrg);
- if (type == OS.GN_CONTEXTMENU) {
- menu.setVisible (true);
- }
- }
- }
- if (mouseDown) {
- if (OS.GetCapture () != handle) OS.SetCapture (handle);
- }
- if (dragging) {
- postEvent (SWT.DragDetect);
- } else {
- if (dragDetect) {
- /*
- * Feature in Windows. DragDetect() captures the mouse
- * and tracks its movement until the user releases the
- * left mouse button, presses the ESC key, or moves the
- * mouse outside the drag rectangle. If the user moves
- * the mouse outside of the drag rectangle, DragDetect()
- * returns true and a drag and drop operation can be
- * started. When the left mouse button is released or
- * the ESC key is pressed, these events are consumed by
- * DragDetect() so that application code that matches
- * mouse down/up pairs or looks for the ESC key will not
- * function properly. The fix is to send these events
- * when the drag has not started.
- *
- * NOTE: For now, don't send a fake WM_KEYDOWN/WM_KEYUP
- * events for the ESC key. This would require computing
- * wParam (the key) and lParam (the repeat count, scan code,
- * extended-key flag, context code, previous key-state flag,
- * and transition-state flag) which is non-trivial.
- */
- if (OS.GetKeyState (OS.VK_ESCAPE) >= 0) {
- OS.SendMessage (handle, OS.WM_LBUTTONUP, wParam, lParam);
- }
- }
- }
- return new LRESULT (result);
-}
-
-LRESULT WM_LBUTTONUP (int wParam, int lParam) {
- sendMouseEvent (SWT.MouseUp, 1, OS.WM_LBUTTONUP, wParam, lParam);
- int result = callWindowProc (OS.WM_LBUTTONUP, wParam, lParam);
- if ((wParam & (OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON)) == 0) {
- if (OS.GetCapture () == handle) OS.ReleaseCapture ();
- }
- return new LRESULT (result);
-}
-
-LRESULT WM_MBUTTONDBLCLK (int wParam, int lParam) {
- /*
- * Feature in Windows. Windows sends the following
- * messages when the user double clicks the mouse:
- *
- * WM_MBUTTONDOWN - mouse down
- * WM_MBUTTONUP - mouse up
- * WM_MLBUTTONDBLCLK - double click
- * WM_MBUTTONUP - mouse up
- *
- * Applications that expect matching mouse down/up
- * pairs will not see the second mouse down. The
- * fix is to send a mouse down event.
- */
- sendMouseEvent (SWT.MouseDown, 2, OS.WM_MBUTTONDOWN, wParam, lParam);
- sendMouseEvent (SWT.MouseDoubleClick, 2, OS.WM_MBUTTONDBLCLK, wParam, lParam);
- int result = callWindowProc (OS.WM_MBUTTONDBLCLK, wParam, lParam);
- if (OS.GetCapture () != handle) OS.SetCapture (handle);
- return new LRESULT (result);
-}
-
-LRESULT WM_MBUTTONDOWN (int wParam, int lParam) {
- sendMouseEvent (SWT.MouseDown, 2, OS.WM_MBUTTONDOWN, wParam, lParam);
- int result = callWindowProc (OS.WM_MBUTTONDOWN, wParam, lParam);
- if (OS.GetCapture () != handle) OS.SetCapture(handle);
- return new LRESULT (result);
-}
-
-LRESULT WM_MBUTTONUP (int wParam, int lParam) {
- sendMouseEvent (SWT.MouseUp, 2, OS.WM_MBUTTONUP, wParam, lParam);
- int result = callWindowProc (OS.WM_MBUTTONUP, wParam, lParam);
- if ((wParam & (OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON)) == 0) {
- if (OS.GetCapture () == handle) OS.ReleaseCapture ();
- }
- return new LRESULT (result);
-}
-
-LRESULT WM_MEASUREITEM (int wParam, int lParam) {
- MEASUREITEMSTRUCT struct = new MEASUREITEMSTRUCT ();
- OS.MoveMemory (struct, lParam, MEASUREITEMSTRUCT.sizeof);
- if (struct.CtlType == OS.ODT_MENU) {
- Decorations shell = menuShell ();
- MenuItem item = shell.findMenuItem (struct.itemID);
- if (item == null) return null;
- return item.wmMeasureChild (wParam, lParam);
- }
- int hwnd = OS.GetDlgItem (handle, struct.CtlID);
- Control control = WidgetTable.get (hwnd);
- if (control == null) return null;
- return control.wmMeasureChild (wParam, lParam);
-}
-
-LRESULT WM_MENUCHAR (int wParam, int lParam) {
- /*
- * Feature in Windows. When the user types Alt+<key>
- * and <key> does not match a mnemonic in the System
- * menu or the menu bar, Windows beeps. This beep is
- * unexpected and unwanted by applications that look
- * for Alt+<key>. The fix is to detect the case and
- * stop Windows from beeping by closing the menu.
- */
- int type = wParam >> 16;
- if (type == 0 || type == OS.MF_SYSMENU) {
- Display display = getDisplay ();
- display.mnemonicKeyHit = false;
- return new LRESULT (OS.MNC_CLOSE << 16);
- }
- return null;
-}
-
-LRESULT WM_MENUSELECT (int wParam, int lParam) {
- int code = wParam >> 16;
- Shell shell = getShell ();
- if (code == -1 && lParam == 0) {
- Display display = getDisplay ();
- display.mnemonicKeyHit = true;
- Menu menu = shell.activeMenu;
- while (menu != null) {
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the hide
- * event. If this happens, stop searching up the
- * parent list because there is no longer a link
- * to follow.
- */
- menu.sendEvent (SWT.Hide);
- if (menu.isDisposed ()) break;
- menu = menu.getParentMenu ();
- }
- /*
- * The shell may be disposed because of sending the hide
- * event to the last active menu menu but setting a field
- * to null in a destroyed widget is not harmful.
- */
- shell.activeMenu = null;
- return null;
- }
- if ((code & OS.MF_SYSMENU) != 0) return null;
- if ((code & OS.MF_HILITE) != 0) {
- MenuItem item = null;
- Decorations menuShell = menuShell ();
- if ((code & OS.MF_POPUP) != 0) {
- int index = wParam & 0xFFFF;
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- info.fMask = OS.MIIM_SUBMENU;
- if (OS.GetMenuItemInfo (lParam, index, true, info)) {
- Menu newMenu = menuShell.findMenu (info.hSubMenu);
- if (newMenu != null) item = newMenu.cascade;
- }
- } else {
- Menu newMenu = menuShell.findMenu (lParam);
- if (newMenu != null) {
- int id = wParam & 0xFFFF;
- item = menuShell.findMenuItem (id);
- }
- Menu oldMenu = shell.activeMenu;
- if (oldMenu != null) {
- Menu ancestor = oldMenu;
- while (ancestor != null && ancestor != newMenu) {
- ancestor = ancestor.getParentMenu ();
- }
- if (ancestor == newMenu) {
- ancestor = oldMenu;
- while (ancestor != newMenu) {
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the hide
- * event or the item about to be armed. If this
- * happens, stop searching up the ancestor list
- * because there is no longer a link to follow.
- */
- ancestor.sendEvent (SWT.Hide);
- if (ancestor.isDisposed ()) break;
- ancestor = ancestor.getParentMenu ();
- }
- /*
- * The shell and/or the item could be disposed when
- * processing hide events from above. If this happens,
- * ensure that the shell is not accessed and that no
- * arm event is sent to the item.
- */
- if (!shell.isDisposed ()) {
- if (newMenu != null && newMenu.isDisposed ()) {
- newMenu = null;
- }
- shell.activeMenu = newMenu;
- }
- if (item != null && item.isDisposed ()) item = null;
- }
- }
- }
- if (item != null) item.sendEvent (SWT.Arm);
- }
- return null;
-}
-
-LRESULT WM_MOUSEACTIVATE (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_MOUSEHOVER (int wParam, int lParam) {
- sendMouseEvent (SWT.MouseHover, 0, OS.WM_MOUSEHOVER, wParam, lParam);
- return null;
-}
-
-LRESULT WM_MOUSELEAVE (int wParam, int lParam) {
- int pos = OS.GetMessagePos ();
- POINT pt = new POINT ();
- pt.x = (short) (pos & 0xFFFF);
- pt.y = (short) (pos >> 16);
- OS.ScreenToClient (handle, pt);
- lParam = pt.x | (pt.y << 16);
- sendMouseEvent (SWT.MouseExit, 0, OS.WM_MOUSELEAVE, wParam, lParam);
- return null;
-}
-
-LRESULT WM_MOUSEMOVE (int wParam, int lParam) {
- if (!OS.IsWinCE) {
- Display display = getDisplay ();
- boolean mouseEnter = hooks (SWT.MouseEnter) || display.filters (SWT.MouseEnter);
- boolean mouseExit = hooks (SWT.MouseExit) || display.filters (SWT.MouseExit);
- boolean mouseHover = hooks (SWT.MouseHover) || display.filters (SWT.MouseHover);
- if (mouseEnter || mouseExit || mouseHover) {
- TRACKMOUSEEVENT lpEventTrack = new TRACKMOUSEEVENT ();
- lpEventTrack.cbSize = TRACKMOUSEEVENT.sizeof;
- lpEventTrack.dwFlags = OS.TME_QUERY;
- lpEventTrack.hwndTrack = handle;
- OS.TrackMouseEvent (lpEventTrack);
- if (lpEventTrack.dwFlags == 0) {
- lpEventTrack.dwFlags = OS.TME_LEAVE | OS.TME_HOVER;
- lpEventTrack.hwndTrack = handle;
- OS.TrackMouseEvent (lpEventTrack);
- if (mouseEnter) {
- sendMouseEvent (SWT.MouseEnter, 0, OS.WM_MOUSEMOVE, wParam, lParam);
- }
- } else {
- lpEventTrack.dwFlags = OS.TME_HOVER;
- OS.TrackMouseEvent (lpEventTrack);
- }
- }
- }
- Display display = getDisplay ();
- int pos = OS.GetMessagePos ();
- if (pos != display.lastMouse) {
- display.lastMouse = pos;
- sendMouseEvent (SWT.MouseMove, 0, OS.WM_MOUSEMOVE, wParam, lParam);
- }
- return null;
-}
-
-LRESULT WM_MOUSEWHEEL (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_MOVE (int wParam, int lParam) {
- sendEvent (SWT.Move);
- // widget could be disposed at this point
- return null;
-}
-
-LRESULT WM_NCACTIVATE (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_NCCALCSIZE (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_NCHITTEST (int wParam, int lParam) {
- if (!OS.IsWindowEnabled (handle)) return null;
- if (!isActive ()) return new LRESULT (OS.HTTRANSPARENT);
- return null;
-}
-
-LRESULT WM_NOTIFY (int wParam, int lParam) {
- NMHDR hdr = new NMHDR ();
- OS.MoveMemory (hdr, lParam, NMHDR.sizeof);
- int hwnd = hdr.hwndFrom;
- if (hwnd == 0) return null;
- Control control = WidgetTable.get (hwnd);
- if (control == null) return null;
- return control.wmNotifyChild (wParam, lParam);
-}
-
-LRESULT WM_PAINT (int wParam, int lParam) {
-
- /* Exit early - don't draw the background */
- if (!hooks (SWT.Paint) && !filters (SWT.Paint)) {
- return null;
- }
-
- /* Get the damage */
- int result = 0;
- if (OS.IsWinCE) {
- RECT rect = new RECT ();
- OS.GetUpdateRect (handle, rect, false);
- result = callWindowProc (OS.WM_PAINT, wParam, lParam);
- OS.InvalidateRect (handle, rect, false);
- } else {
- int rgn = OS.CreateRectRgn (0, 0, 0, 0);
- OS.GetUpdateRgn (handle, rgn, false);
- result = callWindowProc (OS.WM_PAINT, wParam, lParam);
- OS.InvalidateRgn (handle, rgn, false);
- OS.DeleteObject (rgn);
- }
-
- /* Create the paint GC */
- PAINTSTRUCT ps = new PAINTSTRUCT ();
- GCData data = new GCData ();
- data.ps = ps;
- GC gc = GC.win32_new (this, data);
-
- /* Send the paint event */
- Event event = new Event ();
- event.gc = gc;
- event.x = ps.left;
- event.y = ps.top;
- event.width = ps.right - ps.left;
- event.height = ps.bottom - ps.top;
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the paint
- * event. If this happens, attempt to give back the
- * paint GC anyways because this is a scarce Windows
- * resource.
- */
- sendEvent (SWT.Paint, event);
- // widget could be disposed at this point
-
- /* Dispose the paint GC */
- event.gc = null;
- gc.dispose ();
-
- if (result == 0) return LRESULT.ZERO;
- return new LRESULT (result);
-}
-
-LRESULT WM_PALETTECHANGED (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_PASTE (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_PRINTCLIENT (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_QUERYENDSESSION (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_QUERYNEWPALETTE (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_QUERYOPEN (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_RBUTTONDBLCLK (int wParam, int lParam) {
- /*
- * Feature in Windows. Windows sends the following
- * messages when the user double clicks the mouse:
- *
- * WM_RBUTTONDOWN - mouse down
- * WM_RBUTTONUP - mouse up
- * WM_RBUTTONDBLCLK - double click
- * WM_LBUTTONUP - mouse up
- *
- * Applications that expect matching mouse down/up
- * pairs will not see the second mouse down. The
- * fix is to send a mouse down event.
- */
- sendMouseEvent (SWT.MouseDown, 3, OS.WM_RBUTTONDOWN, wParam, lParam);
- sendMouseEvent (SWT.MouseDoubleClick, 3, OS.WM_RBUTTONDBLCLK, wParam, lParam);
- int result = callWindowProc (OS.WM_RBUTTONDBLCLK, wParam, lParam);
- if (OS.GetCapture () != handle) OS.SetCapture (handle);
- return new LRESULT (result);
-}
-
-LRESULT WM_RBUTTONDOWN (int wParam, int lParam) {
- sendMouseEvent (SWT.MouseDown, 3, OS.WM_RBUTTONDOWN, wParam, lParam);
- int result = callWindowProc (OS.WM_RBUTTONDOWN, wParam, lParam);
- if (OS.GetCapture () != handle) OS.SetCapture (handle);
- return new LRESULT (result);
-}
-
-LRESULT WM_RBUTTONUP (int wParam, int lParam) {
- sendMouseEvent (SWT.MouseUp, 3, OS.WM_RBUTTONUP, wParam, lParam);
- int result = callWindowProc (OS.WM_RBUTTONUP, wParam, lParam);
- if ((wParam & (OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON)) == 0) {
- if (OS.GetCapture () == handle) OS.ReleaseCapture ();
- }
- return new LRESULT (result);
-}
-
-LRESULT WM_SETCURSOR (int wParam, int lParam) {
- int hitTest = lParam & 0xFFFF;
- if (hitTest == OS.HTCLIENT) {
- Control control = WidgetTable.get (wParam);
- if (control == null) return null;
- int hCursor = control.findCursor ();
- if (hCursor != 0) {
- OS.SetCursor (hCursor);
- return LRESULT.ONE;
- }
- }
- return null;
-}
-
-LRESULT WM_SETFOCUS (int wParam, int lParam) {
- int code = callWindowProc (OS.WM_SETFOCUS, wParam, lParam);
- Shell shell = getShell ();
-
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the focus
- * in event. If this happens keep going to send
- * the activate events.
- */
- sendEvent (SWT.FocusIn);
- // widget could be disposed at this point
-
- /*
- * 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 ()) {
- shell.setActiveControl (this);
- }
-
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the focus
- * or activate events. If this happens, end the
- * processing of the Windows message by returning
- * zero as the result of the window proc.
- */
- if (isDisposed ()) return LRESULT.ZERO;
- if (code == 0) return LRESULT.ZERO;
- return new LRESULT (code);
-}
-
-LRESULT WM_SETTINGCHANGE (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_SETFONT (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_SETREDRAW (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_SHOWWINDOW (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_SIZE (int wParam, int lParam) {
- sendEvent (SWT.Resize);
- // widget could be disposed at this point
- return null;
-}
-
-LRESULT WM_SYSCHAR (int wParam, int lParam) {
- Display display = getDisplay ();
-
- /* Set last key and last ascii because a new key has been typed */
- display.lastAscii = display.lastKey = wParam;
- display.lastVirtual = display.isVirtualKey (wParam);
- display.lastNull = false;
-
- /* Do not issue a key down if a menu bar mnemonic was invoked */
- if (!hooks (SWT.KeyDown) && !display.filters (SWT.KeyDown)) {
- return null;
- }
- display.mnemonicKeyHit = true;
- int result = callWindowProc (OS.WM_SYSCHAR, wParam, lParam);
- if (!display.mnemonicKeyHit) {
- sendKeyEvent (SWT.KeyDown, OS.WM_SYSCHAR, wParam, lParam);
- }
- display.mnemonicKeyHit = false;
- return new LRESULT (result);
-}
-
-LRESULT WM_SYSCOLORCHANGE (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_SYSCOMMAND (int wParam, int lParam) {
- /*
- * Check to see if the command is a system command or
- * a user menu item that was added to the System menu.
- * When a user item is added to the System menu,
- * WM_SYSCOMMAND must always return zero.
- */
- if ((wParam & 0xF000) == 0) {
- Decorations shell = menuShell ();
- if (shell.isEnabled ()) {
- MenuItem item = shell.findMenuItem (wParam & 0xFFFF);
- if (item != null) item.wmCommandChild (wParam, lParam);
- }
- return LRESULT.ZERO;
- }
-
- /* Process the System Command */
- int cmd = wParam & 0xFFF0;
- switch (cmd) {
- case OS.SC_CLOSE:
- int hwndShell = menuShell ().handle;
- int bits = OS.GetWindowLong (hwndShell, OS.GWL_STYLE);
- if ((bits & OS.WS_SYSMENU) == 0) return LRESULT.ZERO;
- break;
- case OS.SC_KEYMENU:
- if (hooks (SWT.KeyDown) || hooks (SWT.KeyUp)) {
- Decorations shell = menuShell ();
- Menu menu = shell.getMenuBar ();
- if (menu != null) {
- char key = mbcsToWcs (lParam);
- if (key != 0) {
- key = Character.toUpperCase (key);
- MenuItem [] items = menu.getItems ();
- for (int i=0; i<items.length; i++) {
- MenuItem item = items [i];
- String text = item.getText ();
- char mnemonic = findMnemonic (text);
- if (text.length () > 0 && mnemonic == 0) {
- char ch = text.charAt (0);
- if (Character.toUpperCase (ch) == key) {
- Display display = getDisplay ();
- display.mnemonicKeyHit = false;
- return LRESULT.ZERO;
- }
- }
- }
- }
- }
- }
- // FALL THROUGH
- case OS.SC_HSCROLL:
- case OS.SC_VSCROLL:
- /*
- * Do not allow keyboard traversal of the menu bar
- * or scrolling when the shell is not enabled.
- */
- Decorations shell = menuShell ();
- if (!shell.isEnabled () || !shell.isActive ()) {
- return LRESULT.ZERO;
- }
- break;
- case OS.SC_MINIMIZE:
- /* Save the focus widget when the shell is minimized */
- menuShell ().saveFocus ();
- break;
- }
- return null;
-}
-
-LRESULT WM_SYSKEYDOWN (int wParam, int lParam) {
- /*
- * Feature in Windows. WM_SYSKEYDOWN is sent when
- * the user presses ALT-<aKey> or F10 without the ALT key.
- * In order to issue events for F10 (without the ALT key)
- * but ignore all other key presses without the ALT key,
- * make F10 a special case.
- */
- if (wParam != OS.VK_F10) {
- /* Make sure WM_SYSKEYDOWN was sent by ALT-<aKey>. */
- if ((lParam & 0x20000000) == 0) return null;
- }
-
- /* Ignore repeating modifier keys by testing key down state */
- switch (wParam) {
- case OS.VK_SHIFT:
- case OS.VK_MENU:
- case OS.VK_CONTROL:
- case OS.VK_CAPITAL:
- case OS.VK_NUMLOCK:
- case OS.VK_SCROLL:
- if ((lParam & 0x40000000) != 0) return null;
- }
-
- /* Clear last key and last ascii because a new key has been typed */
- Display display = getDisplay ();
- display.lastAscii = display.lastKey = 0;
- display.lastVirtual = display.lastNull = false;
-
- /* If are going to get a WM_SYSCHAR, ignore this message. */
- /*
- * Bug on WinCE. MapVirtualKey() returns incorrect values.
- * The fix is to rely on a key mappings table to determine
- * whether the key event must be sent now or if a WM_SYSCHAR
- * event will follow.
- */
- if (!OS.IsWinCE) {
- if (OS.MapVirtualKey (wParam, 2) != 0) {
- /*
- * Feature in Windows. MapVirtualKey() indicates that
- * a WM_SYSCHAR message will occur for Alt+Enter but
- * this message never happens. The fix is to issue the
- * event from WM_SYSKEYDOWN and map VK_RETURN to '\r'.
- */
- if (wParam != OS.VK_RETURN) return null;
- display.lastAscii = '\r';
- }
- }
- display.lastKey = wParam;
- display.lastVirtual = true;
-
- /*
- * Feature in Windows. The virtual key VK_DELETE is not
- * treated as both a virtual key and an ASCII key by Windows.
- * Therefore, we will not receive a WM_CHAR for this key.
- * The fix is to treat VK_DELETE as a special case and map
- * the ASCII value explictly (Delete is 0x7F).
- */
- if (display.lastKey == OS.VK_DELETE) display.lastAscii = 0x7F;
-
- /*
- * It is possible to get a WM_CHAR for a virtual key when
- * Num Lock is on. If the user types Home while Num Lock
- * is down, a WM_CHAR is issued with WPARM=55 (for the
- * character 7). If we are going to get a WM_CHAR we need
- * to ensure that the last key has the correct value. Note
- * that Ctrl+Home does not issue a WM_CHAR when Num Lock is
- * down.
- */
- if (OS.VK_NUMPAD0 <= display.lastKey && display.lastKey <= OS.VK_DIVIDE) {
- if (display.asciiKey (display.lastKey) != 0) return null;
- }
-
- if (!sendKeyEvent (SWT.KeyDown, OS.WM_SYSKEYDOWN, wParam, lParam)) {
- return LRESULT.ZERO;
- }
- return null;
-}
-
-LRESULT WM_SYSKEYUP (int wParam, int lParam) {
- return WM_KEYUP (wParam, lParam);
-}
-
-LRESULT WM_TIMER (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_UNDO (int wParam, int lParam) {
- return null;
-}
-
-LRESULT WM_VSCROLL (int wParam, int lParam) {
- if (lParam == 0) return null;
- Control control = WidgetTable.get (lParam);
- if (control == null) return null;
- return control.wmScrollChild (wParam, lParam);
-}
-
-LRESULT WM_WINDOWPOSCHANGING (int wParam, int lParam) {
- return null;
-}
-
-LRESULT wmColorChild (int wParam, int lParam) {
- if (background == -1 && foreground == -1) return null;
- int forePixel = foreground, backPixel = background;
- if (forePixel == -1) forePixel = defaultForeground ();
- if (backPixel == -1) backPixel = defaultBackground ();
- OS.SetTextColor (wParam, forePixel);
- OS.SetBkColor (wParam, backPixel);
- return new LRESULT (findBrush (backPixel));
-}
-
-LRESULT wmCommandChild (int wParam, int lParam) {
- return null;
-}
-
-LRESULT wmDrawChild (int wParam, int lParam) {
- return null;
-}
-
-LRESULT wmMeasureChild (int wParam, int lParam) {
- return null;
-}
-
-LRESULT wmNotifyChild (int wParam, int lParam) {
- return null;
-}
-
-LRESULT wmScrollChild (int wParam, int lParam) {
- return null;
-}
-
-}
-
+ int value = OS.VkKeyScan (ACCENTS [i]); + if ((value & 0xFF) == wParam && (value & 0x600) == 0x600) { + return null; + } + } + } + + /* + * If we are going to get a WM_CHAR, ensure that last key has + * the correct character value for the key down and key up + * events. It is not sufficient to ignore the WM_KEYDOWN + * (when we know we are going to get a WM_CHAR) and compute + * the key in WM_CHAR because there is not enough information + * by the time we get the WM_CHAR. For example, when the user + * types Ctrl+Shift+6 on a US keyboard, we get a WM_CHAR with + * wParam=30. When the user types Ctrl+Shift+6 on a German + * keyboard, we also get a WM_CHAR with wParam=30. On the US + * keyboard Shift+6 is ^, on the German keyboard Shift+6 is &. + * There is no way to map wParam=30 in WM_CHAR to the correct + * value. Also, on international keyboards, the control key + * may be down when the user has not entered a control character. + */ + display.lastKey = wParam; + display.lastVirtual = (mapKey == 0); + if (display.lastVirtual) { + /* + * Feature in Windows. The virtual key VK_DELETE is not + * treated as both a virtual key and an ASCII key by Windows. + * Therefore, we will not receive a WM_CHAR for this key. + * The fix is to treat VK_DELETE as a special case and map + * the ASCII value explictly (Delete is 0x7F). + */ + if (display.lastKey == OS.VK_DELETE) display.lastAscii = 0x7F; + /* + * It is possible to get a WM_CHAR for a virtual key when + * Num Lock is on. If the user types Home while Num Lock + * is down, a WM_CHAR is issued with WPARM=55 (for the + * character 7). If we are going to get a WM_CHAR we need + * to ensure that the last key has the correct value. Note + * that Ctrl+Home does not issue a WM_CHAR when Num Lock is + * down. + */ + if (OS.VK_NUMPAD0 <= display.lastKey && display.lastKey <= OS.VK_DIVIDE) { + if (display.asciiKey (display.lastKey) != 0) return null; + display.lastAscii = display.numpadKey (display.lastKey); + } + } else { + /* + * Get the shifted state or convert to lower case if necessary. + * If the user types Ctrl+A, LastKey should be 'a', not 'A'. If + * the user types Ctrl+Shift+A, LastKey should be 'A'. If the user + * types Ctrl+Shift+6, the value of LastKey will depend on the + * international keyboard. + */ + if (OS.GetKeyState (OS.VK_SHIFT) < 0) { + display.lastKey = display.shiftedKey (display.lastKey); + if (display.lastKey == 0) display.lastKey = wParam; + } else { + display.lastKey = OS.CharLower ((short) mapKey); + } + /* + * Some key combinations map to Windows ASCII keys depending + * on the keyboard. For example, Ctrl+Alt+Q maps to @ on a + * German keyboard. If the current key combination is special, + * the correct character is placed in wParam for processing in + * WM_CHAR. If this is the case, issue the key down event from + * inside WM_CHAR. + */ + int asciiKey = display.asciiKey (wParam); + if (asciiKey != 0) { + /* + * When the user types Ctrl+Space, ToAscii () maps this to + * Space. Normally, ToAscii () maps a key to a different + * key if both a WM_KEYDOWN and a WM_CHAR will be issued. + * To avoid the extra SWT.KeyDown, look for VK_SPACE and + * issue the event from WM_CHAR. + */ + if (asciiKey == OS.VK_SPACE) { + display.lastVirtual = true; + return null; + } + if (asciiKey != wParam) return null; + } + + /* + * If the control key is not down at this point, then + * the key that was pressed was an accent key. In that + * case, do not issue the key down event. + */ + if (OS.GetKeyState (OS.VK_CONTROL) >= 0) { + display.lastKey = 0; + return null; + } + + /* + * Virtual keys such as VK_RETURN are both virtual and ASCII keys. + * Normally, these are marked virtual in WM_CHAR. Since we will not + * be getting a WM_CHAR for the key at this point, we need to test + * LastKey to see if it is virtual. This happens when the user types + * Ctrl+Tab. + */ + display.lastVirtual = display.isVirtualKey (wParam); + display.lastAscii = display.controlKey (display.lastKey); + display.lastNull = display.lastAscii == 0 && display.lastKey == '@'; + } + if (!sendKeyEvent (SWT.KeyDown, OS.WM_KEYDOWN, wParam, lParam)) { + return LRESULT.ZERO; + } + return null; +} + +LRESULT WM_KEYUP (int wParam, int lParam) { + Display display = getDisplay (); + + /* Check for hardware keys */ + if (OS.IsWinCE) { + if (OS.VK_APP1 <= wParam && wParam <= OS.VK_APP6) { + display.lastKey = display.lastAscii = 0; + display.lastVirtual = display.lastNull = false; + Event event = new Event (); + event.detail = wParam - OS.VK_APP1 + 1; + /* Check the bit 30 to get the key state */ + int type = (lParam & 0x40000000) != 0 ? SWT.HardKeyUp : SWT.HardKeyDown; + if (setInputState (event, type)) sendEvent (type, event); + return null; + } + } + + /* + * If the key up is not hooked, reset last key + * and last ascii in case the key down is hooked. + */ + if (!hooks (SWT.KeyUp) && !display.filters (SWT.KeyUp)) { + display.lastKey = display.lastAscii = 0; + display.lastVirtual = display.lastNull = false; + return null; + } + + /* Map the virtual key. */ + /* + * Bug on WinCE. MapVirtualKey() returns incorrect values. + * The fix is to rely on a key mappings table to determine + * whether the key event must be sent now or if a WM_CHAR + * event will follow. + */ + int mapKey = OS.IsWinCE ? 0 : OS.MapVirtualKey (wParam, 2); + + /* + * Bug in Windows 95 and NT. When the user types an accent key such + * as ^ to get an accented character on a German keyboard, the accent + * key should be ignored and the next key that the user types is the + * accented key. On Windows 95 and NT, a call to ToAscii (), clears the + * accented state such that the next WM_CHAR loses the accent. The fix + * is to detect the accent key stroke (called a dead key) by testing the + * high bit of the value returned by MapVirtualKey (). A further problem + * is that the high bit on Windows NT is bit 32 while the high bit on + * Windows 95 is bit 16. They should both be bit 32. + * + * NOTE: This code is used to avoid a call to ToAscii (). + * + */ + if (OS.IsWinNT) { + if ((mapKey & 0x80000000) != 0) return null; + } else { + if ((mapKey & 0x8000) != 0) return null; + } + + /* + * Bug in Windows. When the accent key is generated on an international + * keyboard using Ctrl+Alt or the special key, MapVirtualKey () does not + * have the high bit set indicating that this is an accent key stroke. + * The fix is to iterate through all known accent, mapping them back to + * their corresponding virtual key and key state. If the virtual key + * and key state match the current key, then this is an accent that has + * been generated using an international keyboard. + * + * NOTE: This code is used to avoid a call to ToAscii (). + */ + if (!OS.IsWinCE) { + for (int i=0; i<ACCENTS.length; i++) { + int value = OS.VkKeyScan (ACCENTS [i]); + if ((value & 0xFF) == wParam && (value & 0x600) == 0x600) { + display.lastKey = display.lastAscii = 0; + display.lastVirtual = display.lastNull = false; + return null; + } + } + } + + display.lastVirtual = (mapKey == 0); + if (display.lastVirtual) { + display.lastKey = wParam; + } else { + if (display.lastKey == 0) { + display.lastAscii = 0; + display.lastNull = false; + return null; + } + display.lastVirtual = display.isVirtualKey (display.lastKey); + } + + LRESULT result = null; + if (!sendKeyEvent (SWT.KeyUp, OS.WM_KEYUP, wParam, lParam)) { + result = LRESULT.ZERO; + } + display.lastKey = display.lastAscii = 0; + display.lastVirtual = display.lastNull = false; + return result; +} + +LRESULT WM_KILLFOCUS (int wParam, int lParam) { + int code = callWindowProc (OS.WM_KILLFOCUS, wParam, lParam); + Display display = getDisplay (); + Shell shell = getShell (); + + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the focus + * out event. If this happens keep going to send + * the deactivate events. + */ + sendEvent (SWT.FocusOut); + // widget could be disposed at this point + + /* + * 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 ()) { + Control control = display.findControl (wParam); + if (control == null || shell != control.getShell ()) { + shell.setActiveControl (null); + } + } + + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the focus + * or deactivate events. If this happens, end the + * processing of the Windows message by returning + * zero as the result of the window proc. + */ + if (isDisposed ()) return LRESULT.ZERO; + if (code == 0) return LRESULT.ZERO; + return new LRESULT (code); +} + +LRESULT WM_LBUTTONDBLCLK (int wParam, int lParam) { + /* + * Feature in Windows. Windows sends the following + * messages when the user double clicks the mouse: + * + * WM_LBUTTONDOWN - mouse down + * WM_LBUTTONUP - mouse up + * WM_LBUTTONDBLCLK - double click + * WM_LBUTTONUP - mouse up + * + * Applications that expect matching mouse down/up + * pairs will not see the second mouse down. The + * fix is to send a mouse down event. + */ + sendMouseEvent (SWT.MouseDown, 1, OS.WM_LBUTTONDOWN, wParam, lParam); + sendMouseEvent (SWT.MouseDoubleClick, 1, OS.WM_LBUTTONDBLCLK, wParam, lParam); + int result = callWindowProc (OS.WM_LBUTTONDBLCLK, wParam, lParam); + if (OS.GetCapture () != handle) OS.SetCapture (handle); + return new LRESULT (result); +} + +LRESULT WM_LBUTTONDOWN (int wParam, int lParam) { + boolean dragging = false, mouseDown = true; + boolean dragDetect = hooks (SWT.DragDetect); + if (dragDetect) { + if (!OS.IsWinCE) { + /* + * Feature in Windows. It's possible that the drag + * operation will not be started while the mouse is + * down, meaning that the mouse should be captured. + * This can happen when the user types the ESC key + * to cancel the drag. The fix is to query the state + * of the mouse and capture the mouse accordingly. + */ + POINT pt = new POINT (); + pt.x = (short) (lParam & 0xFFFF); + pt.y = (short) (lParam >> 16); + OS.ClientToScreen(handle, pt); + dragging = OS.DragDetect (handle, pt); + mouseDown = OS.GetKeyState (OS.VK_LBUTTON) < 0; + } + } + sendMouseEvent (SWT.MouseDown, 1, OS.WM_LBUTTONDOWN, wParam, lParam); + int result = callWindowProc (OS.WM_LBUTTONDOWN, wParam, lParam); + if (OS.IsPPC) { + if (menu != null && !menu.isDisposed ()) { + int x = (short) (lParam & 0xFFFF); + int y = (short) (lParam >> 16); + SHRGINFO shrg = new SHRGINFO (); + shrg.cbSize = SHRGINFO.sizeof; + shrg.hwndClient = handle; + shrg.ptDown_x = x; + shrg.ptDown_y = y; + shrg.dwFlags = OS.SHRG_RETURNCMD; + int type = OS.SHRecognizeGesture (shrg); + if (type == OS.GN_CONTEXTMENU) { + menu.setVisible (true); + } + } + } + if (mouseDown) { + if (OS.GetCapture () != handle) OS.SetCapture (handle); + } + if (dragging) { + postEvent (SWT.DragDetect); + } else { + if (dragDetect) { + /* + * Feature in Windows. DragDetect() captures the mouse + * and tracks its movement until the user releases the + * left mouse button, presses the ESC key, or moves the + * mouse outside the drag rectangle. If the user moves + * the mouse outside of the drag rectangle, DragDetect() + * returns true and a drag and drop operation can be + * started. When the left mouse button is released or + * the ESC key is pressed, these events are consumed by + * DragDetect() so that application code that matches + * mouse down/up pairs or looks for the ESC key will not + * function properly. The fix is to send these events + * when the drag has not started. + * + * NOTE: For now, don't send a fake WM_KEYDOWN/WM_KEYUP + * events for the ESC key. This would require computing + * wParam (the key) and lParam (the repeat count, scan code, + * extended-key flag, context code, previous key-state flag, + * and transition-state flag) which is non-trivial. + */ + if (OS.GetKeyState (OS.VK_ESCAPE) >= 0) { + OS.SendMessage (handle, OS.WM_LBUTTONUP, wParam, lParam); + } + } + } + return new LRESULT (result); +} + +LRESULT WM_LBUTTONUP (int wParam, int lParam) { + sendMouseEvent (SWT.MouseUp, 1, OS.WM_LBUTTONUP, wParam, lParam); + int result = callWindowProc (OS.WM_LBUTTONUP, wParam, lParam); + if ((wParam & (OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON)) == 0) { + if (OS.GetCapture () == handle) OS.ReleaseCapture (); + } + return new LRESULT (result); +} + +LRESULT WM_MBUTTONDBLCLK (int wParam, int lParam) { + /* + * Feature in Windows. Windows sends the following + * messages when the user double clicks the mouse: + * + * WM_MBUTTONDOWN - mouse down + * WM_MBUTTONUP - mouse up + * WM_MLBUTTONDBLCLK - double click + * WM_MBUTTONUP - mouse up + * + * Applications that expect matching mouse down/up + * pairs will not see the second mouse down. The + * fix is to send a mouse down event. + */ + sendMouseEvent (SWT.MouseDown, 2, OS.WM_MBUTTONDOWN, wParam, lParam); + sendMouseEvent (SWT.MouseDoubleClick, 2, OS.WM_MBUTTONDBLCLK, wParam, lParam); + int result = callWindowProc (OS.WM_MBUTTONDBLCLK, wParam, lParam); + if (OS.GetCapture () != handle) OS.SetCapture (handle); + return new LRESULT (result); +} + +LRESULT WM_MBUTTONDOWN (int wParam, int lParam) { + sendMouseEvent (SWT.MouseDown, 2, OS.WM_MBUTTONDOWN, wParam, lParam); + int result = callWindowProc (OS.WM_MBUTTONDOWN, wParam, lParam); + if (OS.GetCapture () != handle) OS.SetCapture(handle); + return new LRESULT (result); +} + +LRESULT WM_MBUTTONUP (int wParam, int lParam) { + sendMouseEvent (SWT.MouseUp, 2, OS.WM_MBUTTONUP, wParam, lParam); + int result = callWindowProc (OS.WM_MBUTTONUP, wParam, lParam); + if ((wParam & (OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON)) == 0) { + if (OS.GetCapture () == handle) OS.ReleaseCapture (); + } + return new LRESULT (result); +} + +LRESULT WM_MEASUREITEM (int wParam, int lParam) { + MEASUREITEMSTRUCT struct = new MEASUREITEMSTRUCT (); + OS.MoveMemory (struct, lParam, MEASUREITEMSTRUCT.sizeof); + if (struct.CtlType == OS.ODT_MENU) { + Decorations shell = menuShell (); + MenuItem item = shell.findMenuItem (struct.itemID); + if (item == null) return null; + return item.wmMeasureChild (wParam, lParam); + } + int hwnd = OS.GetDlgItem (handle, struct.CtlID); + Control control = WidgetTable.get (hwnd); + if (control == null) return null; + return control.wmMeasureChild (wParam, lParam); +} + +LRESULT WM_MENUCHAR (int wParam, int lParam) { + /* + * Feature in Windows. When the user types Alt+<key> + * and <key> does not match a mnemonic in the System + * menu or the menu bar, Windows beeps. This beep is + * unexpected and unwanted by applications that look + * for Alt+<key>. The fix is to detect the case and + * stop Windows from beeping by closing the menu. + */ + int type = wParam >> 16; + if (type == 0 || type == OS.MF_SYSMENU) { + Display display = getDisplay (); + display.mnemonicKeyHit = false; + return new LRESULT (OS.MNC_CLOSE << 16); + } + return null; +} + +LRESULT WM_MENUSELECT (int wParam, int lParam) { + int code = wParam >> 16; + Shell shell = getShell (); + if (code == -1 && lParam == 0) { + Display display = getDisplay (); + display.mnemonicKeyHit = true; + Menu menu = shell.activeMenu; + while (menu != null) { + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the hide + * event. If this happens, stop searching up the + * parent list because there is no longer a link + * to follow. + */ + menu.sendEvent (SWT.Hide); + if (menu.isDisposed ()) break; + menu = menu.getParentMenu (); + } + /* + * The shell may be disposed because of sending the hide + * event to the last active menu menu but setting a field + * to null in a destroyed widget is not harmful. + */ + shell.activeMenu = null; + return null; + } + if ((code & OS.MF_SYSMENU) != 0) return null; + if ((code & OS.MF_HILITE) != 0) { + MenuItem item = null; + Decorations menuShell = menuShell (); + if ((code & OS.MF_POPUP) != 0) { + int index = wParam & 0xFFFF; + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + info.fMask = OS.MIIM_SUBMENU; + if (OS.GetMenuItemInfo (lParam, index, true, info)) { + Menu newMenu = menuShell.findMenu (info.hSubMenu); + if (newMenu != null) item = newMenu.cascade; + } + } else { + Menu newMenu = menuShell.findMenu (lParam); + if (newMenu != null) { + int id = wParam & 0xFFFF; + item = menuShell.findMenuItem (id); + } + Menu oldMenu = shell.activeMenu; + if (oldMenu != null) { + Menu ancestor = oldMenu; + while (ancestor != null && ancestor != newMenu) { + ancestor = ancestor.getParentMenu (); + } + if (ancestor == newMenu) { + ancestor = oldMenu; + while (ancestor != newMenu) { + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the hide + * event or the item about to be armed. If this + * happens, stop searching up the ancestor list + * because there is no longer a link to follow. + */ + ancestor.sendEvent (SWT.Hide); + if (ancestor.isDisposed ()) break; + ancestor = ancestor.getParentMenu (); + } + /* + * The shell and/or the item could be disposed when + * processing hide events from above. If this happens, + * ensure that the shell is not accessed and that no + * arm event is sent to the item. + */ + if (!shell.isDisposed ()) { + if (newMenu != null && newMenu.isDisposed ()) { + newMenu = null; + } + shell.activeMenu = newMenu; + } + if (item != null && item.isDisposed ()) item = null; + } + } + } + if (item != null) item.sendEvent (SWT.Arm); + } + return null; +} + +LRESULT WM_MOUSEACTIVATE (int wParam, int lParam) { + return null; +} + +LRESULT WM_MOUSEHOVER (int wParam, int lParam) { + sendMouseEvent (SWT.MouseHover, 0, OS.WM_MOUSEHOVER, wParam, lParam); + return null; +} + +LRESULT WM_MOUSELEAVE (int wParam, int lParam) { + int pos = OS.GetMessagePos (); + POINT pt = new POINT (); + pt.x = (short) (pos & 0xFFFF); + pt.y = (short) (pos >> 16); + OS.ScreenToClient (handle, pt); + lParam = pt.x | (pt.y << 16); + sendMouseEvent (SWT.MouseExit, 0, OS.WM_MOUSELEAVE, wParam, lParam); + return null; +} + +LRESULT WM_MOUSEMOVE (int wParam, int lParam) { + if (!OS.IsWinCE) { + Display display = getDisplay (); + boolean mouseEnter = hooks (SWT.MouseEnter) || display.filters (SWT.MouseEnter); + boolean mouseExit = hooks (SWT.MouseExit) || display.filters (SWT.MouseExit); + boolean mouseHover = hooks (SWT.MouseHover) || display.filters (SWT.MouseHover); + if (mouseEnter || mouseExit || mouseHover) { + TRACKMOUSEEVENT lpEventTrack = new TRACKMOUSEEVENT (); + lpEventTrack.cbSize = TRACKMOUSEEVENT.sizeof; + lpEventTrack.dwFlags = OS.TME_QUERY; + lpEventTrack.hwndTrack = handle; + OS.TrackMouseEvent (lpEventTrack); + if (lpEventTrack.dwFlags == 0) { + lpEventTrack.dwFlags = OS.TME_LEAVE | OS.TME_HOVER; + lpEventTrack.hwndTrack = handle; + OS.TrackMouseEvent (lpEventTrack); + if (mouseEnter) { + sendMouseEvent (SWT.MouseEnter, 0, OS.WM_MOUSEMOVE, wParam, lParam); + } + } else { + lpEventTrack.dwFlags = OS.TME_HOVER; + OS.TrackMouseEvent (lpEventTrack); + } + } + } + Display display = getDisplay (); + int pos = OS.GetMessagePos (); + if (pos != display.lastMouse) { + display.lastMouse = pos; + sendMouseEvent (SWT.MouseMove, 0, OS.WM_MOUSEMOVE, wParam, lParam); + } + return null; +} + +LRESULT WM_MOUSEWHEEL (int wParam, int lParam) { + return null; +} + +LRESULT WM_MOVE (int wParam, int lParam) { + sendEvent (SWT.Move); + // widget could be disposed at this point + return null; +} + +LRESULT WM_NCACTIVATE (int wParam, int lParam) { + return null; +} + +LRESULT WM_NCCALCSIZE (int wParam, int lParam) { + return null; +} + +LRESULT WM_NCHITTEST (int wParam, int lParam) { + if (!OS.IsWindowEnabled (handle)) return null; + if (!isActive ()) return new LRESULT (OS.HTTRANSPARENT); + return null; +} + +LRESULT WM_NOTIFY (int wParam, int lParam) { + NMHDR hdr = new NMHDR (); + OS.MoveMemory (hdr, lParam, NMHDR.sizeof); + int hwnd = hdr.hwndFrom; + if (hwnd == 0) return null; + Control control = WidgetTable.get (hwnd); + if (control == null) return null; + return control.wmNotifyChild (wParam, lParam); +} + +LRESULT WM_PAINT (int wParam, int lParam) { + + /* Exit early - don't draw the background */ + if (!hooks (SWT.Paint) && !filters (SWT.Paint)) { + return null; + } + + /* Get the damage */ + int result = 0; + if (OS.IsWinCE) { + RECT rect = new RECT (); + OS.GetUpdateRect (handle, rect, false); + result = callWindowProc (OS.WM_PAINT, wParam, lParam); + OS.InvalidateRect (handle, rect, false); + } else { + int rgn = OS.CreateRectRgn (0, 0, 0, 0); + OS.GetUpdateRgn (handle, rgn, false); + result = callWindowProc (OS.WM_PAINT, wParam, lParam); + OS.InvalidateRgn (handle, rgn, false); + OS.DeleteObject (rgn); + } + + /* Create the paint GC */ + PAINTSTRUCT ps = new PAINTSTRUCT (); + GCData data = new GCData (); + data.ps = ps; + GC gc = GC.win32_new (this, data); + + /* Send the paint event */ + Event event = new Event (); + event.gc = gc; + event.x = ps.left; + event.y = ps.top; + event.width = ps.right - ps.left; + event.height = ps.bottom - ps.top; + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the paint + * event. If this happens, attempt to give back the + * paint GC anyways because this is a scarce Windows + * resource. + */ + sendEvent (SWT.Paint, event); + // widget could be disposed at this point + + /* Dispose the paint GC */ + event.gc = null; + gc.dispose (); + + if (result == 0) return LRESULT.ZERO; + return new LRESULT (result); +} + +LRESULT WM_PALETTECHANGED (int wParam, int lParam) { + return null; +} + +LRESULT WM_PASTE (int wParam, int lParam) { + return null; +} + +LRESULT WM_PRINTCLIENT (int wParam, int lParam) { + return null; +} + +LRESULT WM_QUERYENDSESSION (int wParam, int lParam) { + return null; +} + +LRESULT WM_QUERYNEWPALETTE (int wParam, int lParam) { + return null; +} + +LRESULT WM_QUERYOPEN (int wParam, int lParam) { + return null; +} + +LRESULT WM_RBUTTONDBLCLK (int wParam, int lParam) { + /* + * Feature in Windows. Windows sends the following + * messages when the user double clicks the mouse: + * + * WM_RBUTTONDOWN - mouse down + * WM_RBUTTONUP - mouse up + * WM_RBUTTONDBLCLK - double click + * WM_LBUTTONUP - mouse up + * + * Applications that expect matching mouse down/up + * pairs will not see the second mouse down. The + * fix is to send a mouse down event. + */ + sendMouseEvent (SWT.MouseDown, 3, OS.WM_RBUTTONDOWN, wParam, lParam); + sendMouseEvent (SWT.MouseDoubleClick, 3, OS.WM_RBUTTONDBLCLK, wParam, lParam); + int result = callWindowProc (OS.WM_RBUTTONDBLCLK, wParam, lParam); + if (OS.GetCapture () != handle) OS.SetCapture (handle); + return new LRESULT (result); +} + +LRESULT WM_RBUTTONDOWN (int wParam, int lParam) { + sendMouseEvent (SWT.MouseDown, 3, OS.WM_RBUTTONDOWN, wParam, lParam); + int result = callWindowProc (OS.WM_RBUTTONDOWN, wParam, lParam); + if (OS.GetCapture () != handle) OS.SetCapture (handle); + return new LRESULT (result); +} + +LRESULT WM_RBUTTONUP (int wParam, int lParam) { + sendMouseEvent (SWT.MouseUp, 3, OS.WM_RBUTTONUP, wParam, lParam); + int result = callWindowProc (OS.WM_RBUTTONUP, wParam, lParam); + if ((wParam & (OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON)) == 0) { + if (OS.GetCapture () == handle) OS.ReleaseCapture (); + } + return new LRESULT (result); +} + +LRESULT WM_SETCURSOR (int wParam, int lParam) { + int hitTest = lParam & 0xFFFF; + if (hitTest == OS.HTCLIENT) { + Control control = WidgetTable.get (wParam); + if (control == null) return null; + int hCursor = control.findCursor (); + if (hCursor != 0) { + OS.SetCursor (hCursor); + return LRESULT.ONE; + } + } + return null; +} + +LRESULT WM_SETFOCUS (int wParam, int lParam) { + int code = callWindowProc (OS.WM_SETFOCUS, wParam, lParam); + Shell shell = getShell (); + + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the focus + * in event. If this happens keep going to send + * the activate events. + */ + sendEvent (SWT.FocusIn); + // widget could be disposed at this point + + /* + * 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 ()) { + shell.setActiveControl (this); + } + + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the focus + * or activate events. If this happens, end the + * processing of the Windows message by returning + * zero as the result of the window proc. + */ + if (isDisposed ()) return LRESULT.ZERO; + if (code == 0) return LRESULT.ZERO; + return new LRESULT (code); +} + +LRESULT WM_SETTINGCHANGE (int wParam, int lParam) { + return null; +} + +LRESULT WM_SETFONT (int wParam, int lParam) { + return null; +} + +LRESULT WM_SETREDRAW (int wParam, int lParam) { + return null; +} + +LRESULT WM_SHOWWINDOW (int wParam, int lParam) { + return null; +} + +LRESULT WM_SIZE (int wParam, int lParam) { + sendEvent (SWT.Resize); + // widget could be disposed at this point + return null; +} + +LRESULT WM_SYSCHAR (int wParam, int lParam) { + Display display = getDisplay (); + + /* Set last key and last ascii because a new key has been typed */ + display.lastAscii = display.lastKey = wParam; + display.lastVirtual = display.isVirtualKey (wParam); + display.lastNull = false; + + /* Do not issue a key down if a menu bar mnemonic was invoked */ + if (!hooks (SWT.KeyDown) && !display.filters (SWT.KeyDown)) { + return null; + } + display.mnemonicKeyHit = true; + int result = callWindowProc (OS.WM_SYSCHAR, wParam, lParam); + if (!display.mnemonicKeyHit) { + sendKeyEvent (SWT.KeyDown, OS.WM_SYSCHAR, wParam, lParam); + } + display.mnemonicKeyHit = false; + return new LRESULT (result); +} + +LRESULT WM_SYSCOLORCHANGE (int wParam, int lParam) { + return null; +} + +LRESULT WM_SYSCOMMAND (int wParam, int lParam) { + /* + * Check to see if the command is a system command or + * a user menu item that was added to the System menu. + * When a user item is added to the System menu, + * WM_SYSCOMMAND must always return zero. + */ + if ((wParam & 0xF000) == 0) { + Decorations shell = menuShell (); + if (shell.isEnabled ()) { + MenuItem item = shell.findMenuItem (wParam & 0xFFFF); + if (item != null) item.wmCommandChild (wParam, lParam); + } + return LRESULT.ZERO; + } + + /* Process the System Command */ + int cmd = wParam & 0xFFF0; + switch (cmd) { + case OS.SC_CLOSE: + int hwndShell = menuShell ().handle; + int bits = OS.GetWindowLong (hwndShell, OS.GWL_STYLE); + if ((bits & OS.WS_SYSMENU) == 0) return LRESULT.ZERO; + break; + case OS.SC_KEYMENU: + if (hooks (SWT.KeyDown) || hooks (SWT.KeyUp)) { + Decorations shell = menuShell (); + Menu menu = shell.getMenuBar (); + if (menu != null) { + char key = mbcsToWcs (lParam); + if (key != 0) { + key = Character.toUpperCase (key); + MenuItem [] items = menu.getItems (); + for (int i=0; i<items.length; i++) { + MenuItem item = items [i]; + String text = item.getText (); + char mnemonic = findMnemonic (text); + if (text.length () > 0 && mnemonic == 0) { + char ch = text.charAt (0); + if (Character.toUpperCase (ch) == key) { + Display display = getDisplay (); + display.mnemonicKeyHit = false; + return LRESULT.ZERO; + } + } + } + } + } + } + // FALL THROUGH + case OS.SC_HSCROLL: + case OS.SC_VSCROLL: + /* + * Do not allow keyboard traversal of the menu bar + * or scrolling when the shell is not enabled. + */ + Decorations shell = menuShell (); + if (!shell.isEnabled () || !shell.isActive ()) { + return LRESULT.ZERO; + } + break; + case OS.SC_MINIMIZE: + /* Save the focus widget when the shell is minimized */ + menuShell ().saveFocus (); + break; + } + return null; +} + +LRESULT WM_SYSKEYDOWN (int wParam, int lParam) { + /* + * Feature in Windows. WM_SYSKEYDOWN is sent when + * the user presses ALT-<aKey> or F10 without the ALT key. + * In order to issue events for F10 (without the ALT key) + * but ignore all other key presses without the ALT key, + * make F10 a special case. + */ + if (wParam != OS.VK_F10) { + /* Make sure WM_SYSKEYDOWN was sent by ALT-<aKey>. */ + if ((lParam & 0x20000000) == 0) return null; + } + + /* Ignore repeating modifier keys by testing key down state */ + switch (wParam) { + case OS.VK_SHIFT: + case OS.VK_MENU: + case OS.VK_CONTROL: + case OS.VK_CAPITAL: + case OS.VK_NUMLOCK: + case OS.VK_SCROLL: + if ((lParam & 0x40000000) != 0) return null; + } + + /* Clear last key and last ascii because a new key has been typed */ + Display display = getDisplay (); + display.lastAscii = display.lastKey = 0; + display.lastVirtual = display.lastNull = false; + + /* If are going to get a WM_SYSCHAR, ignore this message. */ + /* + * Bug on WinCE. MapVirtualKey() returns incorrect values. + * The fix is to rely on a key mappings table to determine + * whether the key event must be sent now or if a WM_SYSCHAR + * event will follow. + */ + if (!OS.IsWinCE) { + if (OS.MapVirtualKey (wParam, 2) != 0) { + /* + * Feature in Windows. MapVirtualKey() indicates that + * a WM_SYSCHAR message will occur for Alt+Enter but + * this message never happens. The fix is to issue the + * event from WM_SYSKEYDOWN and map VK_RETURN to '\r'. + */ + if (wParam != OS.VK_RETURN) return null; + display.lastAscii = '\r'; + } + } + display.lastKey = wParam; + display.lastVirtual = true; + + /* + * Feature in Windows. The virtual key VK_DELETE is not + * treated as both a virtual key and an ASCII key by Windows. + * Therefore, we will not receive a WM_CHAR for this key. + * The fix is to treat VK_DELETE as a special case and map + * the ASCII value explictly (Delete is 0x7F). + */ + if (display.lastKey == OS.VK_DELETE) display.lastAscii = 0x7F; + + /* + * It is possible to get a WM_CHAR for a virtual key when + * Num Lock is on. If the user types Home while Num Lock + * is down, a WM_CHAR is issued with WPARM=55 (for the + * character 7). If we are going to get a WM_CHAR we need + * to ensure that the last key has the correct value. Note + * that Ctrl+Home does not issue a WM_CHAR when Num Lock is + * down. + */ + if (OS.VK_NUMPAD0 <= display.lastKey && display.lastKey <= OS.VK_DIVIDE) { + if (display.asciiKey (display.lastKey) != 0) return null; + } + + if (!sendKeyEvent (SWT.KeyDown, OS.WM_SYSKEYDOWN, wParam, lParam)) { + return LRESULT.ZERO; + } + return null; +} + +LRESULT WM_SYSKEYUP (int wParam, int lParam) { + return WM_KEYUP (wParam, lParam); +} + +LRESULT WM_TIMER (int wParam, int lParam) { + return null; +} + +LRESULT WM_UNDO (int wParam, int lParam) { + return null; +} + +LRESULT WM_VSCROLL (int wParam, int lParam) { + if (lParam == 0) return null; + Control control = WidgetTable.get (lParam); + if (control == null) return null; + return control.wmScrollChild (wParam, lParam); +} + +LRESULT WM_WINDOWPOSCHANGING (int wParam, int lParam) { + return null; +} + +LRESULT wmColorChild (int wParam, int lParam) { + if (background == -1 && foreground == -1) return null; + int forePixel = foreground, backPixel = background; + if (forePixel == -1) forePixel = defaultForeground (); + if (backPixel == -1) backPixel = defaultBackground (); + OS.SetTextColor (wParam, forePixel); + OS.SetBkColor (wParam, backPixel); + return new LRESULT (findBrush (backPixel)); +} + +LRESULT wmCommandChild (int wParam, int lParam) { + return null; +} + +LRESULT wmDrawChild (int wParam, int lParam) { + return null; +} + +LRESULT wmMeasureChild (int wParam, int lParam) { + return null; +} + +LRESULT wmNotifyChild (int wParam, int lParam) { + return null; +} + +LRESULT wmScrollChild (int wParam, int lParam) { + return null; +} + +} + diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoolBar.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoolBar.java index c9b8985e70..c194db22df 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoolBar.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoolBar.java @@ -1,1001 +1,1001 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-
-/**
- * Instances of this class provide an area for dynamically
- * positioning the items they contain.
- * <p>
- * The item children that may be added to instances of this class
- * must be of type <code>CoolItem</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>(none)</dd>
- * <dt><b>Events:</b></dt>
- * <dd>(none)</dd>
- * </dl>
- * <p>
- * IMPORTANT: This class is <em>not</em> intended to be subclassed.
- * </p>
- */
-
-public class CoolBar extends Composite {
- CoolItem [] items;
- CoolItem [] originalItems;
- boolean locked;
- boolean ignoreResize;
- static final int ReBarProc;
- static final TCHAR ReBarClass = new TCHAR (0, OS.REBARCLASSNAME, true);
- static {
- INITCOMMONCONTROLSEX icex = new INITCOMMONCONTROLSEX ();
- icex.dwSize = INITCOMMONCONTROLSEX.sizeof;
- icex.dwICC = OS.ICC_COOL_CLASSES;
- OS.InitCommonControlsEx (icex);
- WNDCLASS lpWndClass = new WNDCLASS ();
- OS.GetClassInfo (0, ReBarClass, lpWndClass);
- ReBarProc = lpWndClass.lpfnWndProc;
- }
- static final int MAX_WIDTH = 0x7FFF;
-
-/**
- * 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 CoolBar (Composite parent, int style) {
- super (parent, checkStyle (style));
-}
-
-int callWindowProc (int msg, int wParam, int lParam) {
- if (handle == 0) return 0;
- return OS.CallWindowProc (ReBarProc, handle, msg, wParam, lParam);
-}
-
-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 Point computeSize (int wHint, int hHint, boolean changed) {
- checkWidget ();
- int width = 0, height = 0;
- int border = getBorderWidth ();
- int newWidth = wHint == SWT.DEFAULT ? 0x3FFF : wHint + (border * 2);
- int newHeight = hHint == SWT.DEFAULT ? 0x3FFF : hHint + (border * 2);
- int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
- if (count != 0) {
- ignoreResize = true;
- boolean redraw = false;
- if (OS.IsWindowVisible (handle)) {
- if (COMCTL32_MAJOR >= 6) {
- redraw = true;
- OS.UpdateWindow (handle);
- OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
- } else {
- redraw = drawCount == 0;
- if (redraw) {
- OS.UpdateWindow (handle);
- OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
- }
- }
- }
- RECT oldRect = new RECT ();
- OS.GetWindowRect (handle, oldRect);
- int oldWidth = oldRect.right - oldRect.left;
- int oldHeight = oldRect.bottom - oldRect.top;
- int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOREDRAW | OS.SWP_NOZORDER;
- OS.SetWindowPos (handle, 0, 0, 0, newWidth, newHeight, flags);
- RECT rect = new RECT ();
- OS.SendMessage (handle, OS.RB_GETRECT, count - 1, rect);
- height = Math.max (height, rect.bottom);
- OS.SetWindowPos (handle, 0, 0, 0, oldWidth, oldHeight, flags);
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_IDEALSIZE | OS.RBBIM_STYLE;
- int rowWidth = 0;
- for (int i = 0; i < count; i++) {
- OS.SendMessage(handle, OS.RB_GETBANDINFO, i, rbBand);
- OS.SendMessage(handle, OS.RB_GETBANDBORDERS, i, rect);
- if ((rbBand.fStyle & OS.RBBS_BREAK) != 0) {
- width = Math.max(width, rowWidth);
- rowWidth = 0;
- }
- rowWidth += rbBand.cxIdeal + rect.left + rect.right + 2;
- }
- width = Math.max(width, rowWidth);
- if (redraw) {
- if (COMCTL32_MAJOR >= 6) {
- OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
- } else {
- OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
- }
- }
- ignoreResize = false;
- }
- if (width == 0) width = DEFAULT_WIDTH;
- if (height == 0) height = DEFAULT_HEIGHT;
- if (wHint != SWT.DEFAULT) width = wHint;
- if (hHint != SWT.DEFAULT) height = hHint;
- height += border * 2;
- width += border * 2;
- return new Point (width, height);
-}
-
-void createHandle () {
- super.createHandle ();
- state &= ~CANVAS;
-
- /*
- * Feature in Windows. When the control is created,
- * it does not use the default system font. A new HFONT
- * is created and destroyed when the control is destroyed.
- * This means that a program that queries the font from
- * this control, uses the font in another control and then
- * destroys this control will have the font unexpectedly
- * destroyed in the other control. The fix is to assign
- * the font ourselves each time the control is created.
- * The control will not destroy a font that it did not
- * create.
- */
- int hFont = OS.GetStockObject (OS.SYSTEM_FONT);
- OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0);
-}
-
-void createItem (CoolItem item, int index) {
- int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
- if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE);
- int id = 0;
- while (id < items.length && items [id] != null) id++;
- if (id == items.length) {
- CoolItem [] newItems = new CoolItem [items.length + 4];
- System.arraycopy (items, 0, newItems, 0, items.length);
- items = newItems;
- }
- int hHeap = OS.GetProcessHeap ();
- int lpText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, TCHAR.sizeof);
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_TEXT | OS.RBBIM_STYLE | OS.RBBIM_ID;
- rbBand.fStyle = OS.RBBS_VARIABLEHEIGHT | OS.RBBS_GRIPPERALWAYS;
- if ((item.style & SWT.DROP_DOWN) != 0) {
- rbBand.fStyle |= OS.RBBS_USECHEVRON;
- }
- rbBand.lpText = lpText;
- rbBand.wID = id;
-
- /*
- * Feature in Windows. When inserting an item at end of a row,
- * sometimes, Windows will begin to place the item on the right
- * side of the cool bar. The fix is to resize the new items to
- * the maximum size and then resize the next to last item to the
- * ideal size.
- */
- int lastIndex = getLastIndexOfRow (index - 1);
- boolean fixLast = index == lastIndex + 1;
- if (fixLast) {
- rbBand.fMask |= OS.RBBIM_SIZE;
- rbBand.cx = MAX_WIDTH;
- }
-
- /*
- * Feature in Windows. Is possible that the item at index zero
- * has the RBBS_BREAK flag set. When a new item is inserted at
- * position zero, the previous item at position zero moves to
- * a new line. The fix is to detect this case and clear the
- * RBBS_BREAK flag on the previous item before inserting the
- * new item.
- */
- if (index == 0 && count > 0) {
- getItem (0).setWrap (false);
- }
-
- /* Insert the item */
- if (OS.SendMessage (handle, OS.RB_INSERTBAND, index, rbBand) == 0) {
- error (SWT.ERROR_ITEM_NOT_ADDED);
- }
-
- /* Resize the next to last item to the ideal size */
- if (fixLast) {
- resizeToPreferredWidth (lastIndex);
- }
-
- OS.HeapFree (hHeap, 0, lpText);
- items [item.id = id] = item;
- int length = originalItems.length;
- CoolItem [] newOriginals = new CoolItem [length + 1];
- System.arraycopy (originalItems, 0, newOriginals, 0, index);
- System.arraycopy (originalItems, index, newOriginals, index + 1, length - index);
- newOriginals [index] = item;
- originalItems = newOriginals;
-}
-
-void createWidget () {
- super.createWidget ();
- items = new CoolItem [4];
- originalItems = new CoolItem [0];
-}
-
-void destroyItem (CoolItem item) {
- int index = OS.SendMessage (handle, OS.RB_IDTOINDEX, item.id, 0);
- int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
- if (count != 0) {
- int lastIndex = getLastIndexOfRow (index);
- if (index == lastIndex) {
- /*
- * Feature in Windows. If the last item in a row is
- * given its ideal size, it will be placed at the far
- * right hand edge of the coolbar. It is preferred
- * that the last item appear next to the second last
- * item. The fix is to size the last item of each row
- * so that it occupies all the available space to the
- * right in the row.
- */
- resizeToMaximumWidth (lastIndex - 1);
- }
- }
-
- /*
- * Feature in Windows. When Windows removed a rebar
- * band, it makes the band child invisible. The fix
- * is to show the child.
- */
- Control control = item.control;
- boolean wasVisible = control != null && !control.isDisposed() && control.getVisible ();
-
- /*
- * When a wrapped item is being deleted, make the next
- * item in the row wrapped in order to preserve the row.
- * In order to avoid an unnecessary layout, temporarily
- * ignore WM_SIZE. If the next item is wrapped then a
- * row will be deleted and the WM_SIZE is necessary.
- */
- CoolItem nextItem = null;
- if (item.getWrap ()) {
- if (index + 1 < count) {
- nextItem = getItem (index + 1);
- ignoreResize = !nextItem.getWrap ();
- }
- }
- if (OS.SendMessage (handle, OS.RB_DELETEBAND, index, 0) == 0) {
- error (SWT.ERROR_ITEM_NOT_REMOVED);
- }
- items [item.id] = null;
- item.id = -1;
- if (ignoreResize) {
- nextItem.setWrap (true);
- ignoreResize = false;
- }
-
- /* Restore the visible state tof the control */
- if (wasVisible) control.setVisible (true);
-
- index = 0;
- while (index < originalItems.length) {
- if (originalItems [index] == item) break;
- index++;
- }
- int length = originalItems.length - 1;
- CoolItem [] newOriginals = new CoolItem [length];
- System.arraycopy (originalItems, 0, newOriginals, 0, index);
- System.arraycopy (originalItems, index + 1, newOriginals, index, length - index);
- originalItems = newOriginals;
-}
-
-/**
- * Returns the item that is currently displayed at the given,
- * zero-relative index. Throws an exception if the index is
- * out of range.
- *
- * @param index the visual index of the item to return
- * @return the item at the given visual 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public CoolItem getItem (int index) {
- checkWidget ();
- int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
- if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE);
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_ID;
- OS.SendMessage (handle, OS.RB_GETBANDINFO, index, rbBand);
- return items [rbBand.wID];
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public int getItemCount () {
- checkWidget ();
- return OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
-}
-
-/**
- * Returns an array of zero-relative ints 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public int [] getItemOrder () {
- checkWidget ();
- int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
- int [] indices = new int [count];
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_ID;
- for (int i=0; i<count; i++) {
- OS.SendMessage (handle, OS.RB_GETBANDINFO, i, rbBand);
- CoolItem item = items [rbBand.wID];
- int index = 0;
- while (index<originalItems.length) {
- if (originalItems [index] == item) break;
- index++;
- }
- if (index == originalItems.length) error (SWT.ERROR_CANNOT_GET_ITEM);
- indices [i] = index;
- }
- return indices;
-}
-
-/**
- * Returns an array of <code>CoolItem</code>s in the order
- * in which they are currently being displayed.
- * <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 in their current visual 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public CoolItem [] getItems () {
- checkWidget ();
- int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
- CoolItem [] result = new CoolItem [count];
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_ID;
- for (int i=0; i<count; i++) {
- OS.SendMessage (handle, OS.RB_GETBANDINFO, i, rbBand);
- result [i] = items [rbBand.wID];
- }
- return result;
-}
-
-/**
- * Returns an array of points whose x and y coordinates describe
- * the widths and heights (respectively) of the items in the receiver
- * in the order in which they are currently being displayed.
- *
- * @return the receiver's item sizes in their current visual 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>
- */
-public Point [] getItemSizes () {
- checkWidget ();
- int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
- Point [] sizes = new Point [count];
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_CHILDSIZE;
- for (int i=0; i<count; i++) {
- RECT rect = new RECT ();
- OS.SendMessage (handle, OS.RB_GETRECT, i, rect);
- OS.SendMessage (handle, OS.RB_GETBANDINFO, i, rbBand);
- sizes [i] = new Point (rect.right - rect.left + 2, rbBand.cyChild);
- }
- return sizes;
-}
-
-int getLastIndexOfRow (int index) {
- int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
- if (count == 0) return -1;
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_STYLE;
- for (int i=index + 1; i<count; i++) {
- OS.SendMessage (handle, OS.RB_GETBANDINFO, i, rbBand);
- if ((rbBand.fStyle & OS.RBBS_BREAK) != 0) {
- return i - 1;
- }
- }
- return count - 1;
-}
-
-/**
- * Returns whether or not the receiver is 'locked'. When a coolbar
- * is locked, its items cannot be repositioned.
- *
- * @return true if the coolbar is locked, false 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 2.0
- */
-public boolean getLocked () {
- checkWidget ();
- return locked;
-}
-
-/**
- * Returns an array of ints that describe the zero-relative
- * indices of any item(s) in the receiver that will begin on
- * a new row. The 0th visible item always begins the first row,
- * therefore it does not count as a wrap index.
- *
- * @return an array containing the receiver's wrap indices, or an empty array if all items are in one row
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if 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 [] getWrapIndices () {
- checkWidget ();
- CoolItem [] items = getItems ();
- int [] indices = new int [items.length];
- int count = 0;
- for (int i=0; i<items.length; i++) {
- if (items [i].getWrap ()) indices [count++] = i;
- }
- int [] result = new int [count];
- System.arraycopy (indices, 0, result, 0, count);
- return result;
-}
-
-/**
- * Searches the receiver's items in the order they are currently
- * being displayed, 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 visual order index of the search item, or -1 if the item is not found
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
- * <li>ERROR_INVALID_ARGUMENT - if the item 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>
- */
-public int indexOf (CoolItem item) {
- checkWidget ();
- if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
- if (item.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
- return OS.SendMessage (handle, OS.RB_IDTOINDEX, item.id, 0);
-}
-
-void resizeToPreferredWidth (int index) {
- /*
- * Bug in Windows. When RB_GETBANDBORDERS is sent
- * with an index out of range, Windows GP's. The
- * fix is to ensure the index is in range.
- */
- int count = OS.SendMessage(handle, OS.RB_GETBANDCOUNT, 0, 0);
- if (0 <= index && index < count) {
- REBARBANDINFO rbBand = new REBARBANDINFO();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_IDEALSIZE;
- OS.SendMessage (handle, OS.RB_GETBANDINFO, index, rbBand);
- RECT rect = new RECT ();
- OS.SendMessage (handle, OS.RB_GETBANDBORDERS, index, rect);
- rbBand.cx = rbBand.cxIdeal + rect.left + rect.right;
- rbBand.fMask = OS.RBBIM_SIZE;
- OS.SendMessage (handle, OS.RB_SETBANDINFO, index, rbBand);
- }
-}
-
-void resizeToMaximumWidth (int index) {
- REBARBANDINFO rbBand = new REBARBANDINFO();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_SIZE;
- rbBand.cx = MAX_WIDTH;
- OS.SendMessage (handle, OS.RB_SETBANDINFO, index, rbBand);
-}
-
-void releaseWidget () {
- for (int i=0; i<items.length; i++) {
- CoolItem item = items [i];
- if (item != null && !item.isDisposed ()) {
- item.releaseResources ();
- }
- }
- items = null;
- super.releaseWidget();
-}
-
-void setBackgroundPixel (int pixel) {
- if (background == pixel) return;
- background = pixel;
- if (pixel == -1) pixel = defaultBackground ();
- OS.SendMessage (handle, OS.RB_SETBKCOLOR, 0, pixel);
- setItemColors (OS.SendMessage (handle, OS.RB_GETTEXTCOLOR, 0, 0), pixel);
-}
-
-void setForegroundPixel (int pixel) {
- if (foreground == pixel) return;
- foreground = pixel;
- if (pixel == -1) pixel = defaultForeground ();
- OS.SendMessage (handle, OS.RB_SETTEXTCOLOR, 0, pixel);
- setItemColors (pixel, OS.SendMessage (handle, OS.RB_GETBKCOLOR, 0, 0));
-}
-
-void setItemColors (int foreColor, int backColor) {
- int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_COLORS;
- rbBand.clrFore = foreColor;
- rbBand.clrBack = backColor;
- for (int i=0; i<count; i++) {
- OS.SendMessage (handle, OS.RB_SETBANDINFO, i, rbBand);
- }
-}
-
-/**
- * Sets the receiver's item order, wrap indices, and item sizes
- * all at once. This method is typically used to restore the
- * displayed state of the receiver to a previously stored state.
- * <p>
- * The item order is the order in which the items in the receiver
- * should be displayed, given in terms of the zero-relative ordering
- * of when the items were added.
- * </p><p>
- * The wrap indices are the indices of all item(s) in the receiver
- * that will begin on a new row. The indices are given in the order
- * specified by the item order. The 0th item always begins the first
- * row, therefore it does not count as a wrap index. If wrap indices
- * is null or empty, the items will be placed on one line.
- * </p><p>
- * The sizes are specified in an array of points whose x and y
- * coordinates describe the new widths and heights (respectively)
- * of the receiver's items in the order specified by the item order.
- * </p>
- *
- * @param itemOrder an array of indices that describe the new order to display the items in
- * @param wrapIndices an array of wrap indices, or null
- * @param sizes an array containing the new sizes for each of the receiver's items in visual 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>
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if item order or sizes is null</li>
- * <li>ERROR_INVALID_ARGUMENT - if item order or sizes is not the same length as the number of items</li>
- * </ul>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public void setItemLayout (int [] itemOrder, int [] wrapIndices, Point [] sizes) {
- checkWidget ();
- setRedraw (false);
- setItemOrder (itemOrder);
- setWrapIndices (wrapIndices);
- setItemSizes (sizes);
- setRedraw (true);
-}
-
-/*
- * 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 itemOrder the new order to display the items in
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-void setItemOrder (int [] itemOrder) {
- if (itemOrder == null) error (SWT.ERROR_NULL_ARGUMENT);
- int itemCount = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
- if (itemOrder.length != itemCount) error (SWT.ERROR_INVALID_ARGUMENT);
-
- /* Ensure that itemOrder does not contain any duplicates. */
- boolean [] set = new boolean [itemCount];
- for (int i=0; i<itemOrder.length; i++) {
- int index = itemOrder [i];
- if (index < 0 || index >= itemCount) error (SWT.ERROR_INVALID_RANGE);
- if (set [index]) error (SWT.ERROR_INVALID_ARGUMENT);
- set [index] = true;
- }
-
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- for (int i=0; i<itemOrder.length; i++) {
- int id = originalItems [itemOrder [i]].id;
- int index = OS.SendMessage (handle, OS.RB_IDTOINDEX, id, 0);
- if (index != i) {
- int lastItemSrcRow = getLastIndexOfRow (index);
- int lastItemDstRow = getLastIndexOfRow (i);
- if (index == lastItemSrcRow) {
- resizeToPreferredWidth (index);
- }
- if (i == lastItemDstRow) {
- resizeToPreferredWidth (i);
- }
-
- /* Move the item */
- OS.SendMessage (handle, OS.RB_MOVEBAND, index, i);
-
- if (index == lastItemSrcRow && index - 1 >= 0) {
- resizeToMaximumWidth (index - 1);
- }
- if (i == lastItemDstRow) {
- resizeToMaximumWidth (i);
- }
- }
- }
-}
-
-/*
- * Sets the width and height of the receiver's items to the ones
- * specified by the argument, which is an array of points whose x
- * and y coordinates describe the widths and heights (respectively)
- * in the order in which the items are currently being displayed.
- *
- * @param sizes an array containing the new sizes for each of the receiver's items in visual order
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if the array of sizes is null</li>
- * <li>ERROR_INVALID_ARGUMENT - if the array of sizes is not the same length as the number of items</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>
- */
-void setItemSizes (Point [] sizes) {
- if (sizes == null) error (SWT.ERROR_NULL_ARGUMENT);
- int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
- if (sizes.length != count) error (SWT.ERROR_INVALID_ARGUMENT);
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_ID;
- for (int i=0; i<count; i++) {
- OS.SendMessage (handle, OS.RB_GETBANDINFO, i, rbBand);
- items [rbBand.wID].setSize (sizes [i].x, sizes [i].y);
- }
-}
-
-/**
- * Sets whether or not the receiver is 'locked'. When a coolbar
- * is locked, its items cannot be repositioned.
- *
- * @param locked lock the coolbar if true, otherwise unlock the coolbar
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - 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 setLocked (boolean locked) {
- checkWidget ();
- this.locked = locked;
- int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_STYLE;
- for (int i=0; i<count; i++) {
- OS.SendMessage (handle, OS.RB_GETBANDINFO, i, rbBand);
- if (locked) {
- rbBand.fStyle |= OS.RBBS_NOGRIPPER;
- } else {
- rbBand.fStyle &= ~OS.RBBS_NOGRIPPER;
- }
- OS.SendMessage (handle, OS.RB_SETBANDINFO, i, rbBand);
- }
-}
-
-/**
- * Sets the indices of all item(s) in the receiver that will
- * begin on a new row. The indices are given in the order in
- * which they are currently being displayed. The 0th item
- * always begins the first row, therefore it does not count
- * as a wrap index. If indices is null or empty, the items
- * will be placed on one line.
- *
- * @param indices an array of wrap indices, 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 setWrapIndices (int [] indices) {
- checkWidget ();
- if (indices == null) indices = new int [0];
- int count = getItemCount ();
- for (int i=0; i<indices.length; i++) {
- if (indices [i] < 0 || indices [i] >= count) {
- error (SWT.ERROR_INVALID_RANGE);
- }
- }
- setRedraw (false);
- CoolItem [] items = getItems ();
- for (int i=0; i<items.length; i++) {
- CoolItem item = items [i];
- if (item.getWrap ()) {
- resizeToPreferredWidth (i - 1);
- item.setWrap (false);
- }
- }
- resizeToMaximumWidth (count - 1);
- for (int i=0; i<indices.length; i++) {
- int index = indices [i];
- if (0 <= index && index < items.length) {
- CoolItem item = items [index];
- item.setWrap (true);
- resizeToMaximumWidth (index - 1);
- }
- }
- setRedraw (true);
-}
-
-int widgetStyle () {
- int bits = super.widgetStyle () | OS.CCS_NODIVIDER | OS.CCS_NORESIZE;
- bits |= OS.RBS_VARHEIGHT | OS.RBS_BANDBORDERS | OS.RBS_DBLCLKTOGGLE;
- return bits;
-}
-
-TCHAR windowClass () {
- return ReBarClass;
-}
-
-int windowProc () {
- return ReBarProc;
-}
-
-LRESULT WM_COMMAND (int wParam, int lParam) {
- /*
- * Feature in Windows. When the coolbar window
- * proc processes WM_COMMAND, it forwards this
- * message to its parent. This is done so that
- * children of this control that send this message
- * type to their parent will notify not only
- * this control but also the parent of this control,
- * which is typically the application window and
- * the window that is looking for the message.
- * If the control did not forward the message,
- * applications would have to subclass the control
- * window to see the message. Because the control
- * window is subclassed by SWT, the message
- * is delivered twice, once by SWT and once when
- * the message is forwarded by the window proc.
- * The fix is to avoid calling the window proc
- * for this control.
- */
- LRESULT result = super.WM_COMMAND (wParam, lParam);
- if (result != null) return result;
- return LRESULT.ZERO;
-}
-
-LRESULT WM_ERASEBKGND (int wParam, int lParam) {
- LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
- if (result != null) return result;
-
- /*
- * Feature in Windows. For some reason, Windows
- * does not fully erase the area that the cool bar
- * occupies when the size of the cool bar is larger
- * than the space occupied by the cool bar items.
- * The fix is to erase the cool bar background.
- */
- drawBackground (wParam);
-
- /*
- * NOTE: The cool bar draws separators in WM_ERASEBKGND
- * so it is essential to run the cool bar window proc
- * after the background has been erased.
- */
- return null;
-}
-
-LRESULT WM_NOTIFY (int wParam, int lParam) {
- /*
- * Feature in Windows. When the cool bar window
- * proc processes WM_NOTIFY, it forwards this
- * message to its parent. This is done so that
- * children of this control that send this message
- * type to their parent will notify not only
- * this control but also the parent of this control,
- * which is typically the application window and
- * the window that is looking for the message.
- * If the control did not forward the message,
- * applications would have to subclass the control
- * window to see the message. Because the control
- * window is subclassed by SWT, the message
- * is delivered twice, once by SWT and once when
- * the message is forwarded by the window proc.
- * The fix is to avoid calling the window proc
- * for this control.
- */
- LRESULT result = super.WM_NOTIFY (wParam, lParam);
- if (result != null) return result;
- return LRESULT.ZERO;
-}
-
-LRESULT WM_SETREDRAW (int wParam, int lParam) {
- LRESULT result = super.WM_SETREDRAW (wParam, lParam);
- if (result != null) return result;
- /*
- * Feature in Windows. When redraw is turned off, the rebar
- * control does not call the default window proc. This means
- * that the rebar will redraw and children of the rebar will
- * also redraw. The fix is to call both the rebar window proc
- * and the default window proc.
- *
- * NOTE: The rebar control can resize itself in WM_SETREDRAW.
- * When redraw is turned off by the default window proc, this
- * can leave pixel corruption in the parent. The fix is to
- * detect the size change and damage the previous area in the
- * parent.
- *
- * NOTE: In version 6.00 of COMCTL32.DLL, when WM_SETREDRAW
- * is off, we cannot detect that the size has changed causing
- * pixel corruption. The fix is to disallow WM_SETREDRAW by
- * by not running the default window proc or the rebar window
- * proc.
- */
- if (COMCTL32_MAJOR >= 6) return LRESULT.ZERO;
- Rectangle rect = getBounds ();
- int code = callWindowProc (OS.WM_SETREDRAW, wParam, lParam);
- OS.DefWindowProc (handle, OS.WM_SETREDRAW, wParam, lParam);
- if (!rect.equals (getBounds ())) {
- parent.redraw (rect.x, rect.y, rect.width, rect.height, true);
- }
- return new LRESULT (code);
-}
-
-LRESULT WM_SIZE(int wParam, int lParam) {
- if (ignoreResize) {
- int code = callWindowProc (OS.WM_SIZE, wParam, lParam);
- if (code == 0) return LRESULT.ZERO;
- return new LRESULT (code);
- }
- return super.WM_SIZE(wParam, lParam);
-}
-
-LRESULT wmNotifyChild (int wParam, int lParam) {
- NMHDR hdr = new NMHDR ();
- OS.MoveMemory (hdr, lParam, NMHDR.sizeof);
- switch (hdr.code) {
- case OS.RBN_HEIGHTCHANGE:
- if (!ignoreResize) {
- Point size = getSize ();
- int border = getBorderWidth ();
- int height = OS.SendMessage (handle, OS.RB_GETBARHEIGHT, 0, 0);
- setSize (size.x, height + (border * 2));
- }
- break;
- case OS.RBN_CHEVRONPUSHED:
- NMREBARCHEVRON lpnm = new NMREBARCHEVRON ();
- OS.MoveMemory (lpnm, lParam, NMREBARCHEVRON.sizeof);
- CoolItem child = items [lpnm.wID];
- if (child != null) {
- Event event = new Event();
- event.detail = SWT.ARROW;
- event.x = lpnm.left;
- event.y = lpnm.bottom;
- child.postEvent (SWT.Selection, event);
- }
- break;
- }
- return super.wmNotifyChild (wParam, lParam);
-}
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; + +/** + * Instances of this class provide an area for dynamically + * positioning the items they contain. + * <p> + * The item children that may be added to instances of this class + * must be of type <code>CoolItem</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>(none)</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + */ + +public class CoolBar extends Composite { + CoolItem [] items; + CoolItem [] originalItems; + boolean locked; + boolean ignoreResize; + static final int ReBarProc; + static final TCHAR ReBarClass = new TCHAR (0, OS.REBARCLASSNAME, true); + static { + INITCOMMONCONTROLSEX icex = new INITCOMMONCONTROLSEX (); + icex.dwSize = INITCOMMONCONTROLSEX.sizeof; + icex.dwICC = OS.ICC_COOL_CLASSES; + OS.InitCommonControlsEx (icex); + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, ReBarClass, lpWndClass); + ReBarProc = lpWndClass.lpfnWndProc; + } + static final int MAX_WIDTH = 0x7FFF; + +/** + * 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 CoolBar (Composite parent, int style) { + super (parent, checkStyle (style)); +} + +int callWindowProc (int msg, int wParam, int lParam) { + if (handle == 0) return 0; + return OS.CallWindowProc (ReBarProc, handle, msg, wParam, lParam); +} + +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 Point computeSize (int wHint, int hHint, boolean changed) { + checkWidget (); + int width = 0, height = 0; + int border = getBorderWidth (); + int newWidth = wHint == SWT.DEFAULT ? 0x3FFF : wHint + (border * 2); + int newHeight = hHint == SWT.DEFAULT ? 0x3FFF : hHint + (border * 2); + int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0); + if (count != 0) { + ignoreResize = true; + boolean redraw = false; + if (OS.IsWindowVisible (handle)) { + if (COMCTL32_MAJOR >= 6) { + redraw = true; + OS.UpdateWindow (handle); + OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); + } else { + redraw = drawCount == 0; + if (redraw) { + OS.UpdateWindow (handle); + OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); + } + } + } + RECT oldRect = new RECT (); + OS.GetWindowRect (handle, oldRect); + int oldWidth = oldRect.right - oldRect.left; + int oldHeight = oldRect.bottom - oldRect.top; + int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOREDRAW | OS.SWP_NOZORDER; + OS.SetWindowPos (handle, 0, 0, 0, newWidth, newHeight, flags); + RECT rect = new RECT (); + OS.SendMessage (handle, OS.RB_GETRECT, count - 1, rect); + height = Math.max (height, rect.bottom); + OS.SetWindowPos (handle, 0, 0, 0, oldWidth, oldHeight, flags); + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_IDEALSIZE | OS.RBBIM_STYLE; + int rowWidth = 0; + for (int i = 0; i < count; i++) { + OS.SendMessage(handle, OS.RB_GETBANDINFO, i, rbBand); + OS.SendMessage(handle, OS.RB_GETBANDBORDERS, i, rect); + if ((rbBand.fStyle & OS.RBBS_BREAK) != 0) { + width = Math.max(width, rowWidth); + rowWidth = 0; + } + rowWidth += rbBand.cxIdeal + rect.left + rect.right + 2; + } + width = Math.max(width, rowWidth); + if (redraw) { + if (COMCTL32_MAJOR >= 6) { + OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); + } else { + OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0); + } + } + ignoreResize = false; + } + if (width == 0) width = DEFAULT_WIDTH; + if (height == 0) height = DEFAULT_HEIGHT; + if (wHint != SWT.DEFAULT) width = wHint; + if (hHint != SWT.DEFAULT) height = hHint; + height += border * 2; + width += border * 2; + return new Point (width, height); +} + +void createHandle () { + super.createHandle (); + state &= ~CANVAS; + + /* + * Feature in Windows. When the control is created, + * it does not use the default system font. A new HFONT + * is created and destroyed when the control is destroyed. + * This means that a program that queries the font from + * this control, uses the font in another control and then + * destroys this control will have the font unexpectedly + * destroyed in the other control. The fix is to assign + * the font ourselves each time the control is created. + * The control will not destroy a font that it did not + * create. + */ + int hFont = OS.GetStockObject (OS.SYSTEM_FONT); + OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0); +} + +void createItem (CoolItem item, int index) { + int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0); + if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE); + int id = 0; + while (id < items.length && items [id] != null) id++; + if (id == items.length) { + CoolItem [] newItems = new CoolItem [items.length + 4]; + System.arraycopy (items, 0, newItems, 0, items.length); + items = newItems; + } + int hHeap = OS.GetProcessHeap (); + int lpText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, TCHAR.sizeof); + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_TEXT | OS.RBBIM_STYLE | OS.RBBIM_ID; + rbBand.fStyle = OS.RBBS_VARIABLEHEIGHT | OS.RBBS_GRIPPERALWAYS; + if ((item.style & SWT.DROP_DOWN) != 0) { + rbBand.fStyle |= OS.RBBS_USECHEVRON; + } + rbBand.lpText = lpText; + rbBand.wID = id; + + /* + * Feature in Windows. When inserting an item at end of a row, + * sometimes, Windows will begin to place the item on the right + * side of the cool bar. The fix is to resize the new items to + * the maximum size and then resize the next to last item to the + * ideal size. + */ + int lastIndex = getLastIndexOfRow (index - 1); + boolean fixLast = index == lastIndex + 1; + if (fixLast) { + rbBand.fMask |= OS.RBBIM_SIZE; + rbBand.cx = MAX_WIDTH; + } + + /* + * Feature in Windows. Is possible that the item at index zero + * has the RBBS_BREAK flag set. When a new item is inserted at + * position zero, the previous item at position zero moves to + * a new line. The fix is to detect this case and clear the + * RBBS_BREAK flag on the previous item before inserting the + * new item. + */ + if (index == 0 && count > 0) { + getItem (0).setWrap (false); + } + + /* Insert the item */ + if (OS.SendMessage (handle, OS.RB_INSERTBAND, index, rbBand) == 0) { + error (SWT.ERROR_ITEM_NOT_ADDED); + } + + /* Resize the next to last item to the ideal size */ + if (fixLast) { + resizeToPreferredWidth (lastIndex); + } + + OS.HeapFree (hHeap, 0, lpText); + items [item.id = id] = item; + int length = originalItems.length; + CoolItem [] newOriginals = new CoolItem [length + 1]; + System.arraycopy (originalItems, 0, newOriginals, 0, index); + System.arraycopy (originalItems, index, newOriginals, index + 1, length - index); + newOriginals [index] = item; + originalItems = newOriginals; +} + +void createWidget () { + super.createWidget (); + items = new CoolItem [4]; + originalItems = new CoolItem [0]; +} + +void destroyItem (CoolItem item) { + int index = OS.SendMessage (handle, OS.RB_IDTOINDEX, item.id, 0); + int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0); + if (count != 0) { + int lastIndex = getLastIndexOfRow (index); + if (index == lastIndex) { + /* + * Feature in Windows. If the last item in a row is + * given its ideal size, it will be placed at the far + * right hand edge of the coolbar. It is preferred + * that the last item appear next to the second last + * item. The fix is to size the last item of each row + * so that it occupies all the available space to the + * right in the row. + */ + resizeToMaximumWidth (lastIndex - 1); + } + } + + /* + * Feature in Windows. When Windows removed a rebar + * band, it makes the band child invisible. The fix + * is to show the child. + */ + Control control = item.control; + boolean wasVisible = control != null && !control.isDisposed() && control.getVisible (); + + /* + * When a wrapped item is being deleted, make the next + * item in the row wrapped in order to preserve the row. + * In order to avoid an unnecessary layout, temporarily + * ignore WM_SIZE. If the next item is wrapped then a + * row will be deleted and the WM_SIZE is necessary. + */ + CoolItem nextItem = null; + if (item.getWrap ()) { + if (index + 1 < count) { + nextItem = getItem (index + 1); + ignoreResize = !nextItem.getWrap (); + } + } + if (OS.SendMessage (handle, OS.RB_DELETEBAND, index, 0) == 0) { + error (SWT.ERROR_ITEM_NOT_REMOVED); + } + items [item.id] = null; + item.id = -1; + if (ignoreResize) { + nextItem.setWrap (true); + ignoreResize = false; + } + + /* Restore the visible state tof the control */ + if (wasVisible) control.setVisible (true); + + index = 0; + while (index < originalItems.length) { + if (originalItems [index] == item) break; + index++; + } + int length = originalItems.length - 1; + CoolItem [] newOriginals = new CoolItem [length]; + System.arraycopy (originalItems, 0, newOriginals, 0, index); + System.arraycopy (originalItems, index + 1, newOriginals, index, length - index); + originalItems = newOriginals; +} + +/** + * Returns the item that is currently displayed at the given, + * zero-relative index. Throws an exception if the index is + * out of range. + * + * @param index the visual index of the item to return + * @return the item at the given visual 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</li> + * </ul> + */ +public CoolItem getItem (int index) { + checkWidget (); + int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0); + if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE); + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_ID; + OS.SendMessage (handle, OS.RB_GETBANDINFO, index, rbBand); + return items [rbBand.wID]; +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure</li> + * </ul> + */ +public int getItemCount () { + checkWidget (); + return OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0); +} + +/** + * Returns an array of zero-relative ints 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</li> + * </ul> + */ +public int [] getItemOrder () { + checkWidget (); + int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0); + int [] indices = new int [count]; + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_ID; + for (int i=0; i<count; i++) { + OS.SendMessage (handle, OS.RB_GETBANDINFO, i, rbBand); + CoolItem item = items [rbBand.wID]; + int index = 0; + while (index<originalItems.length) { + if (originalItems [index] == item) break; + index++; + } + if (index == originalItems.length) error (SWT.ERROR_CANNOT_GET_ITEM); + indices [i] = index; + } + return indices; +} + +/** + * Returns an array of <code>CoolItem</code>s in the order + * in which they are currently being displayed. + * <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 in their current visual 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</li> + * </ul> + */ +public CoolItem [] getItems () { + checkWidget (); + int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0); + CoolItem [] result = new CoolItem [count]; + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_ID; + for (int i=0; i<count; i++) { + OS.SendMessage (handle, OS.RB_GETBANDINFO, i, rbBand); + result [i] = items [rbBand.wID]; + } + return result; +} + +/** + * Returns an array of points whose x and y coordinates describe + * the widths and heights (respectively) of the items in the receiver + * in the order in which they are currently being displayed. + * + * @return the receiver's item sizes in their current visual 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> + */ +public Point [] getItemSizes () { + checkWidget (); + int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0); + Point [] sizes = new Point [count]; + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_CHILDSIZE; + for (int i=0; i<count; i++) { + RECT rect = new RECT (); + OS.SendMessage (handle, OS.RB_GETRECT, i, rect); + OS.SendMessage (handle, OS.RB_GETBANDINFO, i, rbBand); + sizes [i] = new Point (rect.right - rect.left + 2, rbBand.cyChild); + } + return sizes; +} + +int getLastIndexOfRow (int index) { + int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0); + if (count == 0) return -1; + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_STYLE; + for (int i=index + 1; i<count; i++) { + OS.SendMessage (handle, OS.RB_GETBANDINFO, i, rbBand); + if ((rbBand.fStyle & OS.RBBS_BREAK) != 0) { + return i - 1; + } + } + return count - 1; +} + +/** + * Returns whether or not the receiver is 'locked'. When a coolbar + * is locked, its items cannot be repositioned. + * + * @return true if the coolbar is locked, false 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 2.0 + */ +public boolean getLocked () { + checkWidget (); + return locked; +} + +/** + * Returns an array of ints that describe the zero-relative + * indices of any item(s) in the receiver that will begin on + * a new row. The 0th visible item always begins the first row, + * therefore it does not count as a wrap index. + * + * @return an array containing the receiver's wrap indices, or an empty array if all items are in one row + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if 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 [] getWrapIndices () { + checkWidget (); + CoolItem [] items = getItems (); + int [] indices = new int [items.length]; + int count = 0; + for (int i=0; i<items.length; i++) { + if (items [i].getWrap ()) indices [count++] = i; + } + int [] result = new int [count]; + System.arraycopy (indices, 0, result, 0, count); + return result; +} + +/** + * Searches the receiver's items in the order they are currently + * being displayed, 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 visual order index of the search item, or -1 if the item is not found + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the item is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the item 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> + */ +public int indexOf (CoolItem item) { + checkWidget (); + if (item == null) error (SWT.ERROR_NULL_ARGUMENT); + if (item.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT); + return OS.SendMessage (handle, OS.RB_IDTOINDEX, item.id, 0); +} + +void resizeToPreferredWidth (int index) { + /* + * Bug in Windows. When RB_GETBANDBORDERS is sent + * with an index out of range, Windows GP's. The + * fix is to ensure the index is in range. + */ + int count = OS.SendMessage(handle, OS.RB_GETBANDCOUNT, 0, 0); + if (0 <= index && index < count) { + REBARBANDINFO rbBand = new REBARBANDINFO(); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_IDEALSIZE; + OS.SendMessage (handle, OS.RB_GETBANDINFO, index, rbBand); + RECT rect = new RECT (); + OS.SendMessage (handle, OS.RB_GETBANDBORDERS, index, rect); + rbBand.cx = rbBand.cxIdeal + rect.left + rect.right; + rbBand.fMask = OS.RBBIM_SIZE; + OS.SendMessage (handle, OS.RB_SETBANDINFO, index, rbBand); + } +} + +void resizeToMaximumWidth (int index) { + REBARBANDINFO rbBand = new REBARBANDINFO(); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_SIZE; + rbBand.cx = MAX_WIDTH; + OS.SendMessage (handle, OS.RB_SETBANDINFO, index, rbBand); +} + +void releaseWidget () { + for (int i=0; i<items.length; i++) { + CoolItem item = items [i]; + if (item != null && !item.isDisposed ()) { + item.releaseResources (); + } + } + items = null; + super.releaseWidget(); +} + +void setBackgroundPixel (int pixel) { + if (background == pixel) return; + background = pixel; + if (pixel == -1) pixel = defaultBackground (); + OS.SendMessage (handle, OS.RB_SETBKCOLOR, 0, pixel); + setItemColors (OS.SendMessage (handle, OS.RB_GETTEXTCOLOR, 0, 0), pixel); +} + +void setForegroundPixel (int pixel) { + if (foreground == pixel) return; + foreground = pixel; + if (pixel == -1) pixel = defaultForeground (); + OS.SendMessage (handle, OS.RB_SETTEXTCOLOR, 0, pixel); + setItemColors (pixel, OS.SendMessage (handle, OS.RB_GETBKCOLOR, 0, 0)); +} + +void setItemColors (int foreColor, int backColor) { + int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0); + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_COLORS; + rbBand.clrFore = foreColor; + rbBand.clrBack = backColor; + for (int i=0; i<count; i++) { + OS.SendMessage (handle, OS.RB_SETBANDINFO, i, rbBand); + } +} + +/** + * Sets the receiver's item order, wrap indices, and item sizes + * all at once. This method is typically used to restore the + * displayed state of the receiver to a previously stored state. + * <p> + * The item order is the order in which the items in the receiver + * should be displayed, given in terms of the zero-relative ordering + * of when the items were added. + * </p><p> + * The wrap indices are the indices of all item(s) in the receiver + * that will begin on a new row. The indices are given in the order + * specified by the item order. The 0th item always begins the first + * row, therefore it does not count as a wrap index. If wrap indices + * is null or empty, the items will be placed on one line. + * </p><p> + * The sizes are specified in an array of points whose x and y + * coordinates describe the new widths and heights (respectively) + * of the receiver's items in the order specified by the item order. + * </p> + * + * @param itemOrder an array of indices that describe the new order to display the items in + * @param wrapIndices an array of wrap indices, or null + * @param sizes an array containing the new sizes for each of the receiver's items in visual 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> + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if item order or sizes is null</li> + * <li>ERROR_INVALID_ARGUMENT - if item order or sizes is not the same length as the number of items</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</li> + * </ul> + */ +public void setItemLayout (int [] itemOrder, int [] wrapIndices, Point [] sizes) { + checkWidget (); + setRedraw (false); + setItemOrder (itemOrder); + setWrapIndices (wrapIndices); + setItemSizes (sizes); + setRedraw (true); +} + +/* + * 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 itemOrder the new order to display the items in + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</li> + * </ul> + */ +void setItemOrder (int [] itemOrder) { + if (itemOrder == null) error (SWT.ERROR_NULL_ARGUMENT); + int itemCount = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0); + if (itemOrder.length != itemCount) error (SWT.ERROR_INVALID_ARGUMENT); + + /* Ensure that itemOrder does not contain any duplicates. */ + boolean [] set = new boolean [itemCount]; + for (int i=0; i<itemOrder.length; i++) { + int index = itemOrder [i]; + if (index < 0 || index >= itemCount) error (SWT.ERROR_INVALID_RANGE); + if (set [index]) error (SWT.ERROR_INVALID_ARGUMENT); + set [index] = true; + } + + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + for (int i=0; i<itemOrder.length; i++) { + int id = originalItems [itemOrder [i]].id; + int index = OS.SendMessage (handle, OS.RB_IDTOINDEX, id, 0); + if (index != i) { + int lastItemSrcRow = getLastIndexOfRow (index); + int lastItemDstRow = getLastIndexOfRow (i); + if (index == lastItemSrcRow) { + resizeToPreferredWidth (index); + } + if (i == lastItemDstRow) { + resizeToPreferredWidth (i); + } + + /* Move the item */ + OS.SendMessage (handle, OS.RB_MOVEBAND, index, i); + + if (index == lastItemSrcRow && index - 1 >= 0) { + resizeToMaximumWidth (index - 1); + } + if (i == lastItemDstRow) { + resizeToMaximumWidth (i); + } + } + } +} + +/* + * Sets the width and height of the receiver's items to the ones + * specified by the argument, which is an array of points whose x + * and y coordinates describe the widths and heights (respectively) + * in the order in which the items are currently being displayed. + * + * @param sizes an array containing the new sizes for each of the receiver's items in visual order + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of sizes is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the array of sizes is not the same length as the number of items</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> + */ +void setItemSizes (Point [] sizes) { + if (sizes == null) error (SWT.ERROR_NULL_ARGUMENT); + int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0); + if (sizes.length != count) error (SWT.ERROR_INVALID_ARGUMENT); + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_ID; + for (int i=0; i<count; i++) { + OS.SendMessage (handle, OS.RB_GETBANDINFO, i, rbBand); + items [rbBand.wID].setSize (sizes [i].x, sizes [i].y); + } +} + +/** + * Sets whether or not the receiver is 'locked'. When a coolbar + * is locked, its items cannot be repositioned. + * + * @param locked lock the coolbar if true, otherwise unlock the coolbar + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - 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 setLocked (boolean locked) { + checkWidget (); + this.locked = locked; + int count = OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0); + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_STYLE; + for (int i=0; i<count; i++) { + OS.SendMessage (handle, OS.RB_GETBANDINFO, i, rbBand); + if (locked) { + rbBand.fStyle |= OS.RBBS_NOGRIPPER; + } else { + rbBand.fStyle &= ~OS.RBBS_NOGRIPPER; + } + OS.SendMessage (handle, OS.RB_SETBANDINFO, i, rbBand); + } +} + +/** + * Sets the indices of all item(s) in the receiver that will + * begin on a new row. The indices are given in the order in + * which they are currently being displayed. The 0th item + * always begins the first row, therefore it does not count + * as a wrap index. If indices is null or empty, the items + * will be placed on one line. + * + * @param indices an array of wrap indices, 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 setWrapIndices (int [] indices) { + checkWidget (); + if (indices == null) indices = new int [0]; + int count = getItemCount (); + for (int i=0; i<indices.length; i++) { + if (indices [i] < 0 || indices [i] >= count) { + error (SWT.ERROR_INVALID_RANGE); + } + } + setRedraw (false); + CoolItem [] items = getItems (); + for (int i=0; i<items.length; i++) { + CoolItem item = items [i]; + if (item.getWrap ()) { + resizeToPreferredWidth (i - 1); + item.setWrap (false); + } + } + resizeToMaximumWidth (count - 1); + for (int i=0; i<indices.length; i++) { + int index = indices [i]; + if (0 <= index && index < items.length) { + CoolItem item = items [index]; + item.setWrap (true); + resizeToMaximumWidth (index - 1); + } + } + setRedraw (true); +} + +int widgetStyle () { + int bits = super.widgetStyle () | OS.CCS_NODIVIDER | OS.CCS_NORESIZE; + bits |= OS.RBS_VARHEIGHT | OS.RBS_BANDBORDERS | OS.RBS_DBLCLKTOGGLE; + return bits; +} + +TCHAR windowClass () { + return ReBarClass; +} + +int windowProc () { + return ReBarProc; +} + +LRESULT WM_COMMAND (int wParam, int lParam) { + /* + * Feature in Windows. When the coolbar window + * proc processes WM_COMMAND, it forwards this + * message to its parent. This is done so that + * children of this control that send this message + * type to their parent will notify not only + * this control but also the parent of this control, + * which is typically the application window and + * the window that is looking for the message. + * If the control did not forward the message, + * applications would have to subclass the control + * window to see the message. Because the control + * window is subclassed by SWT, the message + * is delivered twice, once by SWT and once when + * the message is forwarded by the window proc. + * The fix is to avoid calling the window proc + * for this control. + */ + LRESULT result = super.WM_COMMAND (wParam, lParam); + if (result != null) return result; + return LRESULT.ZERO; +} + +LRESULT WM_ERASEBKGND (int wParam, int lParam) { + LRESULT result = super.WM_ERASEBKGND (wParam, lParam); + if (result != null) return result; + + /* + * Feature in Windows. For some reason, Windows + * does not fully erase the area that the cool bar + * occupies when the size of the cool bar is larger + * than the space occupied by the cool bar items. + * The fix is to erase the cool bar background. + */ + drawBackground (wParam); + + /* + * NOTE: The cool bar draws separators in WM_ERASEBKGND + * so it is essential to run the cool bar window proc + * after the background has been erased. + */ + return null; +} + +LRESULT WM_NOTIFY (int wParam, int lParam) { + /* + * Feature in Windows. When the cool bar window + * proc processes WM_NOTIFY, it forwards this + * message to its parent. This is done so that + * children of this control that send this message + * type to their parent will notify not only + * this control but also the parent of this control, + * which is typically the application window and + * the window that is looking for the message. + * If the control did not forward the message, + * applications would have to subclass the control + * window to see the message. Because the control + * window is subclassed by SWT, the message + * is delivered twice, once by SWT and once when + * the message is forwarded by the window proc. + * The fix is to avoid calling the window proc + * for this control. + */ + LRESULT result = super.WM_NOTIFY (wParam, lParam); + if (result != null) return result; + return LRESULT.ZERO; +} + +LRESULT WM_SETREDRAW (int wParam, int lParam) { + LRESULT result = super.WM_SETREDRAW (wParam, lParam); + if (result != null) return result; + /* + * Feature in Windows. When redraw is turned off, the rebar + * control does not call the default window proc. This means + * that the rebar will redraw and children of the rebar will + * also redraw. The fix is to call both the rebar window proc + * and the default window proc. + * + * NOTE: The rebar control can resize itself in WM_SETREDRAW. + * When redraw is turned off by the default window proc, this + * can leave pixel corruption in the parent. The fix is to + * detect the size change and damage the previous area in the + * parent. + * + * NOTE: In version 6.00 of COMCTL32.DLL, when WM_SETREDRAW + * is off, we cannot detect that the size has changed causing + * pixel corruption. The fix is to disallow WM_SETREDRAW by + * by not running the default window proc or the rebar window + * proc. + */ + if (COMCTL32_MAJOR >= 6) return LRESULT.ZERO; + Rectangle rect = getBounds (); + int code = callWindowProc (OS.WM_SETREDRAW, wParam, lParam); + OS.DefWindowProc (handle, OS.WM_SETREDRAW, wParam, lParam); + if (!rect.equals (getBounds ())) { + parent.redraw (rect.x, rect.y, rect.width, rect.height, true); + } + return new LRESULT (code); +} + +LRESULT WM_SIZE(int wParam, int lParam) { + if (ignoreResize) { + int code = callWindowProc (OS.WM_SIZE, wParam, lParam); + if (code == 0) return LRESULT.ZERO; + return new LRESULT (code); + } + return super.WM_SIZE(wParam, lParam); +} + +LRESULT wmNotifyChild (int wParam, int lParam) { + NMHDR hdr = new NMHDR (); + OS.MoveMemory (hdr, lParam, NMHDR.sizeof); + switch (hdr.code) { + case OS.RBN_HEIGHTCHANGE: + if (!ignoreResize) { + Point size = getSize (); + int border = getBorderWidth (); + int height = OS.SendMessage (handle, OS.RB_GETBARHEIGHT, 0, 0); + setSize (size.x, height + (border * 2)); + } + break; + case OS.RBN_CHEVRONPUSHED: + NMREBARCHEVRON lpnm = new NMREBARCHEVRON (); + OS.MoveMemory (lpnm, lParam, NMREBARCHEVRON.sizeof); + CoolItem child = items [lpnm.wID]; + if (child != null) { + Event event = new Event(); + event.detail = SWT.ARROW; + event.x = lpnm.left; + event.y = lpnm.bottom; + child.postEvent (SWT.Selection, event); + } + break; + } + return super.wmNotifyChild (wParam, lParam); +} +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoolItem.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoolItem.java index 46445eb1bf..867f632234 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoolItem.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoolItem.java @@ -1,665 +1,665 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.events.*;
-
-/**
- * Instances of this class are selectable user interface
- * objects that represent the dynamically positionable
- * areas of a <code>CoolBar</code>.
- * <dl>
- * <dt><b>Styles:</b></dt>
- * <dd>DROP_DOWN</dd>
- * <dt><b>Events:</b></dt>
- * <dd>Selection</dd>
- * </dl>
- * <p>
- * IMPORTANT: This class is <em>not</em> intended to be subclassed.
- * </p>
- */
-
-public class CoolItem extends Item {
- CoolBar parent;
- Control control;
- int id;
- boolean ideal, minimum;
-
-/**
- * Constructs a new instance of this class given its parent
- * (which must be a <code>CoolBar</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#DROP_DOWN
- * @see Widget#checkSubclass
- * @see Widget#getStyle
- */
-public CoolItem (CoolBar 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>CoolBar</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 index at which to store the receiver in its parent
- *
- * @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 CoolItem (CoolBar parent, int style, int index) {
- super (parent, style);
- this.parent = parent;
- parent.createItem (this, index);
-}
-
-/**
- * Adds the listener to the collection of listeners that will
- * be notified when the control is selected, by sending it one
- * of the messages defined in the <code>SelectionListener</code>
- * interface.
- * <p>
- * If <code>widgetSelected</code> is called when the mouse is over
- * the drop-down arrow (or 'chevron') portion of the cool item,
- * the event object detail field contains the value <code>SWT.ARROW</code>,
- * and the x and y fields in the event object represent the point at
- * the bottom left of the chevron, where the menu should be popped up.
- * <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
- *
- * @since 2.0
- */
-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);
-}
-
-/**
- * Returns the preferred size of the receiver.
- * <p>
- * The <em>preferred size</em> of a <code>CoolItem</code> is the size that
- * it would best be displayed at. The width hint and height hint arguments
- * allow the caller to ask the instance questions such as "Given a particular
- * width, how high does it 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
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - 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 #getBounds
- * @see #getSize
- * @see CoolBar#getBorderWidth
- * @see CoolBar#computeTrim
- * @see CoolBar#getClientArea
- */
-public Point computeSize (int wHint, int hHint) {
- checkWidget ();
- int index = parent.indexOf (this);
- if (index == -1) return new Point (0, 0);
- int width = wHint, height = hHint;
- if (wHint == SWT.DEFAULT) width = 32;
- if (hHint == SWT.DEFAULT) height = 32;
- int hwnd = parent.handle;
- RECT rect = new RECT ();
- OS.SendMessage (hwnd, OS.RB_GETBANDBORDERS, index, rect);
- width += rect.left + rect.right + 2;
- return new Point (width, height);
-}
-
-/**
- * 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 ();
- int index = parent.indexOf (this);
- if (index == -1) return new Rectangle (0, 0, 0, 0);
- int hwnd = parent.handle;
- RECT rect = new RECT ();
- OS.SendMessage (hwnd, OS.RB_GETRECT, index, rect);
- int width = rect.right - rect.left + 2;
- int height = rect.bottom - rect.top;
- return new Rectangle (rect.left, rect.top, width, height);
-}
-
-/*
-* Not currently used.
-*/
-Rectangle getClientArea () {
- checkWidget ();
- int index = parent.indexOf (this);
- if (index == -1) return new Rectangle (0, 0, 0, 0);
- int hwnd = parent.handle;
- RECT insetRect = new RECT ();
- OS.SendMessage (hwnd, OS.RB_GETBANDBORDERS, index, insetRect);
- RECT rect = new RECT ();
- OS.SendMessage (hwnd, OS.RB_GETRECT, index, rect);
- int x = rect.left + insetRect.left;
- int y = rect.top + insetRect.top;
- int width = rect.right - rect.left - (insetRect.left + insetRect.right);
- int height = rect.bottom - rect.top - (insetRect.top + insetRect.bottom);
- if (index == 0) {
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_HEADERSIZE;
- OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand);
- width = width - rbBand.cxHeader + 1;
- }
- return new Rectangle (x, y, width, height);
-}
-
-/**
- * Returns the control that is associated with the receiver.
- *
- * @return the control that is contained by 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 Control getControl () {
- checkWidget ();
- return control;
-}
-
-public Display getDisplay () {
- CoolBar parent = this.parent;
- if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED);
- return parent.getDisplay ();
-}
-
-/**
- * Returns the receiver's parent, which must be a <code>CoolBar</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 CoolBar getParent () {
- checkWidget ();
- return parent;
-}
-
-void releaseChild () {
- super.releaseChild ();
- parent.destroyItem (this);
-}
-
-void releaseWidget () {
- super.releaseWidget ();
- control = null;
- parent = null;
-}
-
-/**
- * Sets the control that is associated with the receiver
- * to the argument.
- *
- * @param control the new control that will be contained by the receiver
- *
- * @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);
- }
- int index = parent.indexOf (this);
- if (index == -1) return;
- if (this.control != null && this.control.isDisposed ()) {
- this.control = null;
- }
- Control oldControl = this.control, newControl = control;
- int hwnd = parent.handle;
- int hwndChild = 0;
- if (newControl != null) hwndChild = control.handle;
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_CHILD;
- rbBand.hwndChild = hwndChild;
- this.control = newControl;
-
- /*
- * Feature in Windows. When Windows sets the rebar band child,
- * it makes the new child visible and hides the old child and
- * moves the new child to the top of the Z-order. The fix is
- * to save and restore the visibility and Z-order.
- */
- int hwndAbove = 0;
- if (newControl != null) {
- hwndAbove = OS.GetWindow (hwndChild, OS.GW_HWNDPREV);
- }
- boolean hideNew = newControl != null && !newControl.getVisible ();
- boolean showOld = oldControl != null && oldControl.getVisible ();
- OS.SendMessage (hwnd, OS.RB_SETBANDINFO, index, rbBand);
- if (hideNew) newControl.setVisible (false);
- if (showOld) oldControl.setVisible (true);
- if (hwndAbove != 0 && hwndAbove != hwndChild) {
- int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
- OS.SetWindowPos (hwndChild, hwndAbove, 0, 0, 0, 0, flags);
- }
-}
-
-/**
- * Returns a point describing the receiver's ideal size.
- * The x coordinate of the result is the ideal width of the receiver.
- * The y coordinate of the result is the ideal height of the receiver.
- *
- * @return the receiver's ideal 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 getPreferredSize () {
- checkWidget ();
- int index = parent.indexOf (this);
- if (index == -1) return new Point (0, 0);
- int hwnd = parent.handle;
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_CHILDSIZE | OS.RBBIM_IDEALSIZE;
- OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand);
- RECT rect = new RECT ();
- OS.SendMessage (hwnd, OS.RB_GETBANDBORDERS, index, rect);
- int width = rbBand.cxIdeal + rect.left + rect.right + 2;
- return new Point (width, rbBand.cyMinChild);
-}
-
-/**
- * Sets the receiver's ideal size to the point specified by the arguments.
- *
- * @param width the new ideal width for the receiver
- * @param height the new ideal 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 setPreferredSize (int width, int height) {
- checkWidget ();
- int index = parent.indexOf (this);
- if (index == -1) return;
- ideal = true;
- int hwnd = parent.handle;
- RECT rect = new RECT ();
- OS.SendMessage (hwnd, OS.RB_GETBANDBORDERS, index, rect);
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
-
- /* Get the child size fields first so we don't overwrite them. */
- rbBand.fMask = OS.RBBIM_CHILDSIZE;
- OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand);
-
- /* Set the size fields we are currently modifying. */
- rbBand.fMask = OS.RBBIM_CHILDSIZE | OS.RBBIM_IDEALSIZE;
- rbBand.cxIdeal = width - rect.left - rect.right - 2;
- rbBand.cyMaxChild = height;
- if (!minimum) rbBand.cyMinChild = height;
- OS.SendMessage (hwnd, OS.RB_SETBANDINFO, index, rbBand);
-}
-
-/**
- * Sets the receiver's ideal size to the point specified by the argument.
- *
- * @param size the new ideal size for the receiver
- * @param height the new ideal height 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 setPreferredSize (Point size) {
- checkWidget ();
- if (size == null) error(SWT.ERROR_NULL_ARGUMENT);
- setPreferredSize (size.x, size.y);
-}
-
-/**
- * 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 ();
- int index = parent.indexOf (this);
- if (index == -1) new Point (0, 0);
- int hwnd = parent.handle;
- RECT rect = new RECT ();
- OS.SendMessage (hwnd, OS.RB_GETRECT, index, rect);
- int width = rect.right - rect.left + 2;
- int height = rect.bottom - rect.top;
- return new Point (width, height);
-}
-
-/**
- * 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 ();
- int index = parent.indexOf (this);
- if (index == -1) return;
- int hwnd = parent.handle;
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
-
- /*
- * Do not set the size for the last item on the row.
- */
- int count = OS.SendMessage (hwnd, OS.RB_GETBANDCOUNT, 0, 0);
- boolean isLastItem;
- if (index + 1 == count) {
- isLastItem = true;
- } else {
- rbBand.fMask = OS.RBBIM_STYLE;
- OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index + 1, rbBand);
- isLastItem = (rbBand.fStyle & OS.RBBS_BREAK) != 0;
- rbBand.fMask = 0;
- }
-
- /* Get the child size fields first so we don't overwrite them. */
- rbBand.fMask = OS.RBBIM_CHILDSIZE | OS.RBBIM_IDEALSIZE;
- OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand);
-
- /* Set the size fields we are currently modifying. */
- rbBand.fMask = OS.RBBIM_CHILDSIZE | OS.RBBIM_IDEALSIZE;
- if (!ideal) {
- RECT rect = new RECT ();
- OS.SendMessage (hwnd, OS.RB_GETBANDBORDERS, index, rect);
- rbBand.cxIdeal = width - rect.left - rect.right - 2;
- }
- if (!minimum) rbBand.cyMinChild = height;
- rbBand.cyChild = rbBand.cyMaxChild = height;
- if (!isLastItem) {
- rbBand.cx = width - 2;
- rbBand.fMask |= OS.RBBIM_SIZE;
- }
- OS.SendMessage (hwnd, OS.RB_SETBANDINFO, index, rbBand);
-}
-
-/**
- * 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
- * @param height the new height 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) {
- if (size == null) error(SWT.ERROR_NULL_ARGUMENT);
- setSize (size.x, size.y);
-}
-
-/**
- * Returns the minimum size that the cool item can
- * be resized to using the cool item's gripper.
- *
- * @return a point containing the minimum width and height of the cool item, 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 2.0
- */
-public Point getMinimumSize () {
- checkWidget ();
- int index = parent.indexOf (this);
- if (index == -1) return new Point (0, 0);
- int hwnd = parent.handle;
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_CHILDSIZE;
- OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand);
- return new Point (rbBand.cxMinChild, rbBand.cyMinChild);
-}
-
-/**
- * Sets the minimum size that the cool item can be resized to
- * using the cool item's gripper, to the point specified by the arguments.
- *
- * @param width the minimum width of the cool item, in pixels
- * @param height the minimum height of the cool item, 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 2.0
- */
-public void setMinimumSize (int width, int height) {
- checkWidget ();
- int index = parent.indexOf (this);
- if (index == -1) return;
- minimum = true;
- int hwnd = parent.handle;
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
-
- /* Get the child size fields first so we don't overwrite them. */
- rbBand.fMask = OS.RBBIM_CHILDSIZE;
- OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand);
-
- /* Set the size fields we are currently modifying. */
- rbBand.cxMinChild = width;
- rbBand.cyMinChild = height;
- OS.SendMessage (hwnd, OS.RB_SETBANDINFO, index, rbBand);
-}
-
-/**
- * Sets the minimum size that the cool item can be resized to
- * using the cool item's gripper, to the point specified by the argument.
- *
- * @param size a point representing the minimum width and height of the cool item, in pixels
- *
- * @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.0
- */
-public void setMinimumSize (Point size) {
- checkWidget ();
- if (size == null) error (SWT.ERROR_NULL_ARGUMENT);
- setMinimumSize (size.x, size.y);
-}
-
-boolean getWrap() {
- int index = parent.indexOf (this);
- int hwnd = parent.handle;
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_STYLE;
- OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand);
- return (rbBand.fStyle & OS.RBBS_BREAK) != 0;
-}
-
-void setWrap(boolean wrap) {
- int index = parent.indexOf (this);
- int hwnd = parent.handle;
- REBARBANDINFO rbBand = new REBARBANDINFO ();
- rbBand.cbSize = REBARBANDINFO.sizeof;
- rbBand.fMask = OS.RBBIM_STYLE;
- OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand);
- if (wrap) {
- rbBand.fStyle |= OS.RBBS_BREAK;
- } else {
- rbBand.fStyle &= ~OS.RBBS_BREAK;
- }
- OS.SendMessage (hwnd, OS.RB_SETBANDINFO, index, rbBand);
-}
-
-/**
- * Removes the listener from the collection of listeners that
- * will be notified when the control is selected.
- *
- * @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 #addSelectionListener
- *
- * @since 2.0
- */
-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);
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.events.*; + +/** + * Instances of this class are selectable user interface + * objects that represent the dynamically positionable + * areas of a <code>CoolBar</code>. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>DROP_DOWN</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection</dd> + * </dl> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + */ + +public class CoolItem extends Item { + CoolBar parent; + Control control; + int id; + boolean ideal, minimum; + +/** + * Constructs a new instance of this class given its parent + * (which must be a <code>CoolBar</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#DROP_DOWN + * @see Widget#checkSubclass + * @see Widget#getStyle + */ +public CoolItem (CoolBar 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>CoolBar</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 index at which to store the receiver in its parent + * + * @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 CoolItem (CoolBar parent, int style, int index) { + super (parent, style); + this.parent = parent; + parent.createItem (this, index); +} + +/** + * Adds the listener to the collection of listeners that will + * be notified when the control is selected, by sending it one + * of the messages defined in the <code>SelectionListener</code> + * interface. + * <p> + * If <code>widgetSelected</code> is called when the mouse is over + * the drop-down arrow (or 'chevron') portion of the cool item, + * the event object detail field contains the value <code>SWT.ARROW</code>, + * and the x and y fields in the event object represent the point at + * the bottom left of the chevron, where the menu should be popped up. + * <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 + * + * @since 2.0 + */ +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); +} + +/** + * Returns the preferred size of the receiver. + * <p> + * The <em>preferred size</em> of a <code>CoolItem</code> is the size that + * it would best be displayed at. The width hint and height hint arguments + * allow the caller to ask the instance questions such as "Given a particular + * width, how high does it 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 + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - 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 #getBounds + * @see #getSize + * @see CoolBar#getBorderWidth + * @see CoolBar#computeTrim + * @see CoolBar#getClientArea + */ +public Point computeSize (int wHint, int hHint) { + checkWidget (); + int index = parent.indexOf (this); + if (index == -1) return new Point (0, 0); + int width = wHint, height = hHint; + if (wHint == SWT.DEFAULT) width = 32; + if (hHint == SWT.DEFAULT) height = 32; + int hwnd = parent.handle; + RECT rect = new RECT (); + OS.SendMessage (hwnd, OS.RB_GETBANDBORDERS, index, rect); + width += rect.left + rect.right + 2; + return new Point (width, height); +} + +/** + * 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 (); + int index = parent.indexOf (this); + if (index == -1) return new Rectangle (0, 0, 0, 0); + int hwnd = parent.handle; + RECT rect = new RECT (); + OS.SendMessage (hwnd, OS.RB_GETRECT, index, rect); + int width = rect.right - rect.left + 2; + int height = rect.bottom - rect.top; + return new Rectangle (rect.left, rect.top, width, height); +} + +/* +* Not currently used. +*/ +Rectangle getClientArea () { + checkWidget (); + int index = parent.indexOf (this); + if (index == -1) return new Rectangle (0, 0, 0, 0); + int hwnd = parent.handle; + RECT insetRect = new RECT (); + OS.SendMessage (hwnd, OS.RB_GETBANDBORDERS, index, insetRect); + RECT rect = new RECT (); + OS.SendMessage (hwnd, OS.RB_GETRECT, index, rect); + int x = rect.left + insetRect.left; + int y = rect.top + insetRect.top; + int width = rect.right - rect.left - (insetRect.left + insetRect.right); + int height = rect.bottom - rect.top - (insetRect.top + insetRect.bottom); + if (index == 0) { + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_HEADERSIZE; + OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand); + width = width - rbBand.cxHeader + 1; + } + return new Rectangle (x, y, width, height); +} + +/** + * Returns the control that is associated with the receiver. + * + * @return the control that is contained by 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 Control getControl () { + checkWidget (); + return control; +} + +public Display getDisplay () { + CoolBar parent = this.parent; + if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED); + return parent.getDisplay (); +} + +/** + * Returns the receiver's parent, which must be a <code>CoolBar</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 CoolBar getParent () { + checkWidget (); + return parent; +} + +void releaseChild () { + super.releaseChild (); + parent.destroyItem (this); +} + +void releaseWidget () { + super.releaseWidget (); + control = null; + parent = null; +} + +/** + * Sets the control that is associated with the receiver + * to the argument. + * + * @param control the new control that will be contained by the receiver + * + * @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); + } + int index = parent.indexOf (this); + if (index == -1) return; + if (this.control != null && this.control.isDisposed ()) { + this.control = null; + } + Control oldControl = this.control, newControl = control; + int hwnd = parent.handle; + int hwndChild = 0; + if (newControl != null) hwndChild = control.handle; + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_CHILD; + rbBand.hwndChild = hwndChild; + this.control = newControl; + + /* + * Feature in Windows. When Windows sets the rebar band child, + * it makes the new child visible and hides the old child and + * moves the new child to the top of the Z-order. The fix is + * to save and restore the visibility and Z-order. + */ + int hwndAbove = 0; + if (newControl != null) { + hwndAbove = OS.GetWindow (hwndChild, OS.GW_HWNDPREV); + } + boolean hideNew = newControl != null && !newControl.getVisible (); + boolean showOld = oldControl != null && oldControl.getVisible (); + OS.SendMessage (hwnd, OS.RB_SETBANDINFO, index, rbBand); + if (hideNew) newControl.setVisible (false); + if (showOld) oldControl.setVisible (true); + if (hwndAbove != 0 && hwndAbove != hwndChild) { + int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE; + OS.SetWindowPos (hwndChild, hwndAbove, 0, 0, 0, 0, flags); + } +} + +/** + * Returns a point describing the receiver's ideal size. + * The x coordinate of the result is the ideal width of the receiver. + * The y coordinate of the result is the ideal height of the receiver. + * + * @return the receiver's ideal 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 getPreferredSize () { + checkWidget (); + int index = parent.indexOf (this); + if (index == -1) return new Point (0, 0); + int hwnd = parent.handle; + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_CHILDSIZE | OS.RBBIM_IDEALSIZE; + OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand); + RECT rect = new RECT (); + OS.SendMessage (hwnd, OS.RB_GETBANDBORDERS, index, rect); + int width = rbBand.cxIdeal + rect.left + rect.right + 2; + return new Point (width, rbBand.cyMinChild); +} + +/** + * Sets the receiver's ideal size to the point specified by the arguments. + * + * @param width the new ideal width for the receiver + * @param height the new ideal 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 setPreferredSize (int width, int height) { + checkWidget (); + int index = parent.indexOf (this); + if (index == -1) return; + ideal = true; + int hwnd = parent.handle; + RECT rect = new RECT (); + OS.SendMessage (hwnd, OS.RB_GETBANDBORDERS, index, rect); + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + + /* Get the child size fields first so we don't overwrite them. */ + rbBand.fMask = OS.RBBIM_CHILDSIZE; + OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand); + + /* Set the size fields we are currently modifying. */ + rbBand.fMask = OS.RBBIM_CHILDSIZE | OS.RBBIM_IDEALSIZE; + rbBand.cxIdeal = width - rect.left - rect.right - 2; + rbBand.cyMaxChild = height; + if (!minimum) rbBand.cyMinChild = height; + OS.SendMessage (hwnd, OS.RB_SETBANDINFO, index, rbBand); +} + +/** + * Sets the receiver's ideal size to the point specified by the argument. + * + * @param size the new ideal size for the receiver + * @param height the new ideal height 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 setPreferredSize (Point size) { + checkWidget (); + if (size == null) error(SWT.ERROR_NULL_ARGUMENT); + setPreferredSize (size.x, size.y); +} + +/** + * 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 (); + int index = parent.indexOf (this); + if (index == -1) new Point (0, 0); + int hwnd = parent.handle; + RECT rect = new RECT (); + OS.SendMessage (hwnd, OS.RB_GETRECT, index, rect); + int width = rect.right - rect.left + 2; + int height = rect.bottom - rect.top; + return new Point (width, height); +} + +/** + * 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 (); + int index = parent.indexOf (this); + if (index == -1) return; + int hwnd = parent.handle; + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + + /* + * Do not set the size for the last item on the row. + */ + int count = OS.SendMessage (hwnd, OS.RB_GETBANDCOUNT, 0, 0); + boolean isLastItem; + if (index + 1 == count) { + isLastItem = true; + } else { + rbBand.fMask = OS.RBBIM_STYLE; + OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index + 1, rbBand); + isLastItem = (rbBand.fStyle & OS.RBBS_BREAK) != 0; + rbBand.fMask = 0; + } + + /* Get the child size fields first so we don't overwrite them. */ + rbBand.fMask = OS.RBBIM_CHILDSIZE | OS.RBBIM_IDEALSIZE; + OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand); + + /* Set the size fields we are currently modifying. */ + rbBand.fMask = OS.RBBIM_CHILDSIZE | OS.RBBIM_IDEALSIZE; + if (!ideal) { + RECT rect = new RECT (); + OS.SendMessage (hwnd, OS.RB_GETBANDBORDERS, index, rect); + rbBand.cxIdeal = width - rect.left - rect.right - 2; + } + if (!minimum) rbBand.cyMinChild = height; + rbBand.cyChild = rbBand.cyMaxChild = height; + if (!isLastItem) { + rbBand.cx = width - 2; + rbBand.fMask |= OS.RBBIM_SIZE; + } + OS.SendMessage (hwnd, OS.RB_SETBANDINFO, index, rbBand); +} + +/** + * 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 + * @param height the new height 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) { + if (size == null) error(SWT.ERROR_NULL_ARGUMENT); + setSize (size.x, size.y); +} + +/** + * Returns the minimum size that the cool item can + * be resized to using the cool item's gripper. + * + * @return a point containing the minimum width and height of the cool item, 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 2.0 + */ +public Point getMinimumSize () { + checkWidget (); + int index = parent.indexOf (this); + if (index == -1) return new Point (0, 0); + int hwnd = parent.handle; + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_CHILDSIZE; + OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand); + return new Point (rbBand.cxMinChild, rbBand.cyMinChild); +} + +/** + * Sets the minimum size that the cool item can be resized to + * using the cool item's gripper, to the point specified by the arguments. + * + * @param width the minimum width of the cool item, in pixels + * @param height the minimum height of the cool item, 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 2.0 + */ +public void setMinimumSize (int width, int height) { + checkWidget (); + int index = parent.indexOf (this); + if (index == -1) return; + minimum = true; + int hwnd = parent.handle; + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + + /* Get the child size fields first so we don't overwrite them. */ + rbBand.fMask = OS.RBBIM_CHILDSIZE; + OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand); + + /* Set the size fields we are currently modifying. */ + rbBand.cxMinChild = width; + rbBand.cyMinChild = height; + OS.SendMessage (hwnd, OS.RB_SETBANDINFO, index, rbBand); +} + +/** + * Sets the minimum size that the cool item can be resized to + * using the cool item's gripper, to the point specified by the argument. + * + * @param size a point representing the minimum width and height of the cool item, in pixels + * + * @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.0 + */ +public void setMinimumSize (Point size) { + checkWidget (); + if (size == null) error (SWT.ERROR_NULL_ARGUMENT); + setMinimumSize (size.x, size.y); +} + +boolean getWrap() { + int index = parent.indexOf (this); + int hwnd = parent.handle; + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_STYLE; + OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand); + return (rbBand.fStyle & OS.RBBS_BREAK) != 0; +} + +void setWrap(boolean wrap) { + int index = parent.indexOf (this); + int hwnd = parent.handle; + REBARBANDINFO rbBand = new REBARBANDINFO (); + rbBand.cbSize = REBARBANDINFO.sizeof; + rbBand.fMask = OS.RBBIM_STYLE; + OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand); + if (wrap) { + rbBand.fStyle |= OS.RBBS_BREAK; + } else { + rbBand.fStyle &= ~OS.RBBS_BREAK; + } + OS.SendMessage (hwnd, OS.RB_SETBANDINFO, index, rbBand); +} + +/** + * Removes the listener from the collection of listeners that + * will be notified when the control is selected. + * + * @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 #addSelectionListener + * + * @since 2.0 + */ +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); +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Decorations.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Decorations.java index 0e05b7bf9a..b634682a12 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Decorations.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Decorations.java @@ -1,1364 +1,1364 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-
-/**
- * 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>
- * 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
- */
-
-public class Decorations extends Canvas {
- Image image;
- Menu menuBar;
- Menu [] menus;
- MenuItem [] items;
- Control savedFocus;
- Button defaultButton, saveDefault;
- int swFlags, hAccel, nAccel, hIcon;
-
- /*
- * The start value for WM_COMMAND id's.
- * Windows reserves the values 0..100.
- *
- * The SmartPhone SWT resource file reserves
- * the values 101..107.
- */
- static final int ID_START = 108;
-
-/**
- * Prevents uninitialized instances from being created outside the package.
- */
-Decorations () {
-}
-
-/**
- * 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));
-}
-
-void add (Menu menu) {
- if (menus == null) menus = new Menu [4];
- for (int i=0; i<menus.length; i++) {
- if (menus [i] == null) {
- menus [i] = menu;
- return;
- }
- }
- Menu [] newMenus = new Menu [menus.length + 4];
- newMenus [menus.length] = menu;
- System.arraycopy (menus, 0, newMenus, 0, menus.length);
- menus = newMenus;
-}
-
-void add (MenuItem item) {
- if (items == null) items = new MenuItem [12];
- for (int i=0; i<items.length; i++) {
- if (items [i] == null) {
- item.id = i + ID_START;
- items [i] = item;
- return;
- }
- }
- item.id = items.length + ID_START;
- MenuItem [] newItems = new MenuItem [items.length + 12];
- newItems [items.length] = item;
- System.arraycopy (items, 0, newItems, 0, items.length);
- items = newItems;
-}
-
-void bringToTop () {
- /*
- * This code is intentionally commented. On some platforms,
- * the ON_TOP style creates a shell that will stay on top
- * of every other shell on the desktop. Using SetWindowPos ()
- * with HWND_TOP caused problems on Windows so this code is
- * commented out until this functionality is specified and
- * the problems are fixed.
- */
-// if ((style & SWT.ON_TOP) != 0) {
-// int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
-// OS.SetWindowPos (handle, OS.HWND_TOP, 0, 0, 0, 0, flags);
-// } else {
- OS.BringWindowToTop (handle);
-// }
-}
-
-static int checkStyle (int style) {
- if (OS.IsWinCE) {
- /*
- * Feature in WinCE PPC. WS_MINIMIZEBOX or WS_MAXIMIZEBOX
- * are not supposed to be used. If they are, the result
- * is a button which does not repaint correctly. The fix
- * is to remove this style.
- */
- if ((style & SWT.MIN) != 0) style &= ~SWT.MIN;
- if ((style & SWT.MAX) != 0) style &= ~SWT.MAX;
- return style;
- }
-
- /*
- * If either WS_MINIMIZEBOX or WS_MAXIMIZEBOX are set,
- * we must also set WS_SYSMENU or the buttons will not
- * appear.
- */
- if ((style & (SWT.MIN | SWT.MAX)) != 0) style |= SWT.CLOSE;
-
- /*
- * Both WS_SYSMENU and WS_CAPTION must be set in order
- * to for the system menu to appear.
- */
- if ((style & SWT.CLOSE) != 0) style |= SWT.TITLE;
-
- /*
- * Bug in Windows. The WS_CAPTION style must be
- * set when the window is resizable or it does not
- * draw properly.
- */
- /*
- * This code is intentionally commented. It seems
- * that this problem originally in Windows 3.11,
- * has been fixed in later versions. Because the
- * exact nature of the drawing problem is unknown,
- * keep the commented code around in case it comes
- * back.
- */
-// if ((style & SWT.RESIZE) != 0) style |= SWT.TITLE;
-
- return style;
-}
-
-protected void checkSubclass () {
- if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
-}
-
-Control computeTabGroup () {
- return this;
-}
-
-Control computeTabRoot () {
- return this;
-}
-
-public Rectangle computeTrim (int x, int y, int width, int height) {
- checkWidget ();
-
- /* Get the size of the trimmings */
- RECT rect = new RECT ();
- OS.SetRect (rect, x, y, x + width, y + height);
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- boolean hasMenu = OS.IsWinCE ? false : OS.GetMenu (handle) != 0;
- OS.AdjustWindowRectEx (rect, bits, hasMenu, OS.GetWindowLong (handle, OS.GWL_EXSTYLE));
-
- /* Get the size of the scroll bars */
- if (horizontalBar != null) rect.bottom += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
- if (verticalBar != null) rect.right += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
-
- /* Get the height of the menu bar */
- if (hasMenu) {
- RECT testRect = new RECT ();
- OS.SetRect (testRect, 0, 0, rect.right - rect.left, rect.bottom - rect.top);
- OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, testRect);
- while ((testRect.bottom - testRect.top) < height) {
- rect.top -= OS.GetSystemMetrics (OS.SM_CYMENU) - OS.GetSystemMetrics (OS.SM_CYBORDER);
- OS.SetRect(testRect, 0, 0, rect.right - rect.left, rect.bottom - rect.top);
- OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, testRect);
- }
- }
- return new Rectangle (rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
-}
-
-void createAccelerators () {
- hAccel = nAccel = 0;
- int maxAccel = 0;
- if (menuBar == null || items == null) {
- if (!OS.IsPPC) return;
- maxAccel = 1;
- } else {
- maxAccel = OS.IsPPC ? items.length + 1 : items.length;
- }
- int size = ACCEL.sizeof;
- ACCEL accel = new ACCEL ();
- byte [] buffer1 = new byte [size];
- byte [] buffer2 = new byte [maxAccel * size];
- if (menuBar != null && items != null) {
- for (int i=0; i<items.length; i++) {
- MenuItem item = items [i];
- if (item != null && item.accelerator != 0) {
- Menu parent = item.parent;
- while (parent != null && parent != menuBar) {
- parent = parent.getParentMenu ();
- }
- if (parent == menuBar) {
- item.fillAccel (accel);
- OS.MoveMemory (buffer1, accel, size);
- System.arraycopy (buffer1, 0, buffer2, nAccel * size, size);
- nAccel++;
- }
- }
- }
- }
- if (OS.IsPPC) {
- /*
- * Note on WinCE PPC. Close the shell when user taps CTRL-Q.
- * IDOK represents the "Done Button" which also closes the shell.
- */
- accel.fVirt = OS.FVIRTKEY | OS.FCONTROL;
- accel.key = 'Q';
- accel.cmd = OS.IDOK;
- OS.MoveMemory (buffer1, accel, size);
- System.arraycopy (buffer1, 0, buffer2, nAccel * size, size);
- nAccel++;
- }
- if (nAccel != 0) hAccel = OS.CreateAcceleratorTable (buffer2, nAccel);
-}
-
-void createHandle () {
- super.createHandle ();
- if (parent == null) return;
- setParent ();
- setSystemMenu ();
-}
-
-void createWidget () {
- super.createWidget ();
- swFlags = OS.IsWinCE ? OS.SW_SHOWMAXIMIZED : OS.SW_SHOWNOACTIVATE;
- hAccel = -1;
-}
-
-void destroyAccelerators () {
- if (hAccel != 0 && hAccel != -1) OS.DestroyAcceleratorTable (hAccel);
- hAccel = -1;
-}
-
-Menu findMenu (int hMenu) {
- if (menus == null) return null;
- for (int i=0; i<menus.length; i++) {
- Menu menu = menus [i];
- if (menu != null && hMenu == menu.handle) return menu;
- }
- return null;
-}
-
-MenuItem findMenuItem (int id) {
- if (items == null) return null;
- id = id - ID_START;
- if (0 <= id && id < items.length) return items [id];
- return null;
-}
-
-public Rectangle getBounds () {
- checkWidget ();
- if (!OS.IsWinCE) {
- if (OS.IsIconic (handle)) {
- WINDOWPLACEMENT lpwndpl = new WINDOWPLACEMENT ();
- lpwndpl.length = WINDOWPLACEMENT.sizeof;
- OS.GetWindowPlacement (handle, lpwndpl);
- int width = lpwndpl.right - lpwndpl.left;
- int height = lpwndpl.bottom - lpwndpl.top;
- return new Rectangle (lpwndpl.left, lpwndpl.top, width, height);
- }
- }
- return super.getBounds ();
-}
-
-public Rectangle getClientArea () {
- checkWidget ();
- /*
- * Note: The CommandBar is part of the client area,
- * not the trim. Applications don't expect this so
- * subtract the height of the CommandBar.
- */
- if (OS.IsHPC) {
- Rectangle rect = super.getClientArea ();
- if (menuBar != null) {
- int hwndCB = menuBar.hwndCB;
- int height = OS.CommandBar_Height (hwndCB);
- rect.y += height;
- rect.height -= height;
- }
- return rect;
- }
- if (!OS.IsWinCE) {
- if (OS.IsIconic (handle)) {
- RECT rect = new RECT ();
- WINDOWPLACEMENT lpwndpl = new WINDOWPLACEMENT ();
- lpwndpl.length = WINDOWPLACEMENT.sizeof;
- OS.GetWindowPlacement (handle, lpwndpl);
- int width = lpwndpl.right - lpwndpl.left;
- int height = lpwndpl.bottom - lpwndpl.top;
- OS.SetRect (rect, 0, 0, width, height);
- OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, rect);
- return new Rectangle (0, 0, rect.right, rect.bottom);
- }
- }
- return super.getClientArea ();
-}
-
-/**
- * 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
- */
-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;
-}
-
-public Point getLocation () {
- checkWidget ();
- if (!OS.IsWinCE) {
- if (OS.IsIconic (handle)) {
- WINDOWPLACEMENT lpwndpl = new WINDOWPLACEMENT ();
- lpwndpl.length = WINDOWPLACEMENT.sizeof;
- OS.GetWindowPlacement (handle, lpwndpl);
- return new Point (lpwndpl.left, lpwndpl.top);
- }
- }
- return super.getLocation ();
-}
-
-/**
- * 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 ();
- if (OS.IsWinCE) return swFlags == OS.SW_SHOWMAXIMIZED;
- if (OS.IsWindowVisible (handle)) return OS.IsZoomed (handle);
- return swFlags == OS.SW_SHOWMAXIMIZED;
-}
-
-/**
- * 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 ();
- if (OS.IsWinCE) return false;
- if (OS.IsWindowVisible (handle)) return OS.IsIconic (handle);
- return swFlags == OS.SW_SHOWMINNOACTIVE;
-}
-
-String getNameText () {
- return getText ();
-}
-
-public Point getSize () {
- checkWidget ();
- if (!OS.IsWinCE) {
- if (OS.IsIconic (handle)) {
- WINDOWPLACEMENT lpwndpl = new WINDOWPLACEMENT ();
- lpwndpl.length = WINDOWPLACEMENT.sizeof;
- OS.GetWindowPlacement (handle, lpwndpl);
- int width = lpwndpl.right - lpwndpl.left;
- int height = lpwndpl.bottom - lpwndpl.top;
- return new Point (width, height);
- }
- }
- RECT rect = new RECT ();
- OS.GetWindowRect (handle, rect);
- int width = rect.right - rect.left;
- int height = rect.bottom - rect.top;
- return new Point (width, height);
-}
-
-/**
- * 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 ();
- int length = OS.GetWindowTextLength (handle);
- if (length == 0) return "";
- /* Use the character encoding for the default locale */
- TCHAR buffer = new TCHAR (0, length + 1);
- OS.GetWindowText (handle, buffer, length + 1);
- return buffer.toString (0, length);
-}
-
-boolean isTabGroup () {
- /*
- * Can't test WS_TAB bits because they are the same as WS_MAXIMIZEBOX.
- */
- return true;
-}
-
-boolean isTabItem () {
- /*
- * Can't test WS_TAB bits because they are the same as WS_MAXIMIZEBOX.
- */
- return false;
-}
-
-Decorations menuShell () {
- return this;
-}
-
-void releaseWidget () {
- if (menuBar != null) menuBar.releaseResources ();
- menuBar = null;
- if (menus != null) {
- do {
- int index = 0;
- while (index < menus.length) {
- Menu menu = menus [index];
- if (menu != null && !menu.isDisposed ()) {
- while (menu.getParentMenu () != null) {
- menu = menu.getParentMenu ();
- }
- menu.dispose ();
- break;
- }
- index++;
- }
- if (index == menus.length) break;
- } while (true);
- }
- menus = null;
- super.releaseWidget ();
- if (hIcon != 0) OS.DestroyIcon (hIcon);
- hIcon = 0;
- items = null;
- image = null;
- savedFocus = null;
- defaultButton = saveDefault = null;
- if (hAccel != 0 && hAccel != -1) OS.DestroyAcceleratorTable (hAccel);
- hAccel = -1;
-}
-
-void remove (Menu menu) {
- if (menus == null) return;
- for (int i=0; i<menus.length; i++) {
- if (menus [i] == menu) {
- menus [i] = null;
- return;
- }
- }
-}
-
-void remove (MenuItem item) {
- if (items == null) return;
- items [item.id - ID_START] = null;
- item.id = -1;
-}
-
-boolean restoreFocus () {
- if (savedFocus != null && savedFocus.isDisposed ()) savedFocus = null;
- if (savedFocus != null && savedFocus.setSavedFocus ()) return true;
- /*
- * This code is intentionally commented. When no widget
- * has been given focus, some platforms give focus to the
- * default button. Windows doesn't do this.
- */
-// if (defaultButton != null && !defaultButton.isDisposed ()) {
-// if (defaultButton.setFocus ()) return true;
-// }
- return false;
-}
-
-void saveFocus () {
- Control control = getDisplay ().getFocusControl ();
- if (control != null) setSavedFocus (control);
-}
-
-void setBounds (int x, int y, int width, int height, int flags) {
- if (OS.IsWinCE) {
- super.setBounds (x, y, width, height, flags);
- }
- if (OS.IsIconic (handle) || OS.IsZoomed (handle)) {
- setPlacement (x, y, width, height, flags);
- return;
- }
- super.setBounds (x, y, width, height, flags);
-}
-
-/**
- * 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.
- *
- * @param the new default button
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_INVALID_ARGUMENT - if the button 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 setDefaultButton (Button button) {
- checkWidget ();
- setDefaultButton (button, true);
-}
-
-void setDefaultButton (Button button, boolean save) {
- if (button == null) {
- if (defaultButton == saveDefault) {
- if (save) saveDefault = null;
- return;
- }
- } else {
- if (button.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
- if ((button.style & SWT.PUSH) == 0) return;
- if (button == defaultButton) return;
- }
- if (defaultButton != null) {
- if (!defaultButton.isDisposed ()) defaultButton.setDefault (false);
- }
- if ((defaultButton = button) == null) defaultButton = saveDefault;
- if (defaultButton != null) {
- if (!defaultButton.isDisposed ()) defaultButton.setDefault (true);
- }
- if (save) saveDefault = defaultButton;
- if (saveDefault != null && saveDefault.isDisposed ()) saveDefault = null;
-}
-
-public boolean setFocus () {
- checkWidget ();
- if (this instanceof Shell) return super.setFocus ();
- /*
- * Bug in Windows. Setting the focus to a child of the
- * receiver interferes with moving and resizing of the
- * parent shell. The fix (for now) is to always set the
- * focus to the shell.
- */
- int hwndFocus = OS.SetFocus (getShell ().handle);
- return hwndFocus == OS.GetFocus ();
-}
-/**
- * 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);
- /*
- * Feature in WinCE. WM_SETICON and WM_GETICON set the icon
- * for the window class, not the window instance. This means
- * that it is possible to set an icon into a window and then
- * later free the icon, thus freeing the icon for every window.
- * The fix is to avoid the API.
- *
- * On WinCE PPC, icons in windows are not displayed anyways.
- */
- if (OS.IsWinCE) {
- this.image = image;
- return;
- }
- int hImage = 0;
- if (image != null) {
- if (hIcon != 0) OS.DestroyIcon (hIcon);
- hIcon = 0;
- switch (image.type) {
- case SWT.BITMAP:
- /* Copy the bitmap in case it's a DIB */
- int hBitmap = image.handle;
- BITMAP bm = new BITMAP ();
- OS.GetObject (hBitmap, BITMAP.sizeof, bm);
- byte [] lpvBits = new byte [(bm.bmWidth + 15) / 16 * 2 * bm.bmHeight];
- int hMask = OS.CreateBitmap (bm.bmWidth, bm.bmHeight, 1, 1, lpvBits);
- int hDC = OS.GetDC (handle);
- int hdcMem = OS.CreateCompatibleDC (hDC);
- int hColor = OS.CreateCompatibleBitmap (hDC, bm.bmWidth, bm.bmHeight);
- OS.SelectObject (hdcMem, hColor);
- int hdcBmp = OS.CreateCompatibleDC (hDC);
- OS.SelectObject (hdcBmp, hBitmap);
- OS.BitBlt (hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcBmp, 0, 0, OS.SRCCOPY);
- ICONINFO info = new ICONINFO ();
- info.fIcon = true;
- info.hbmMask = hMask;
- info.hbmColor = hColor;
- hImage = hIcon = OS.CreateIconIndirect (info);
- OS.DeleteObject (hMask);
- OS.DeleteObject(hColor);
- OS.DeleteDC (hdcBmp);
- OS.DeleteDC (hdcMem);
- OS.ReleaseDC (handle, hDC);
- break;
- case SWT.ICON:
- hImage = image.handle;
- break;
- default:
- return;
- }
- }
- this.image = image;
- OS.SendMessage (handle, OS.WM_SETICON, OS.ICON_BIG, hImage);
-
- /*
- * Bug in Windows. When WM_SETICON is used to remove an
- * icon from the window trimmings for a window with the
- * extended style bits WS_EX_DLGMODALFRAME, the window
- * trimmings do not redraw to hide the previous icon.
- * The fix is to force a redraw.
- */
- if (!OS.IsWinCE) {
- if (hIcon == 0 && (style & SWT.BORDER) != 0) {
- int flags = OS.RDW_FRAME | OS.RDW_INVALIDATE;
- OS.RedrawWindow (handle, null, 0, flags);
- }
- }
-}
-
-/**
- * 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 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 ();
- swFlags = maximized ? OS.SW_SHOWMAXIMIZED : OS.SW_RESTORE;
- if (OS.IsWinCE) {
- /*
- * Note: WinCE does not support SW_SHOWMAXIMIZED and SW_RESTORE. The
- * workaround is to resize the window to fit the parent client area.
- * PocketPC windows typically don't have a caption when they are
- * maximized. They usually have one when they are not occupying all the
- * space. We implement this behavior by default - it can be overriden by
- * setting SWT.TITLE or SWT.NO_TRIM.
- */
- if (maximized) {
- if ((style & SWT.TITLE) == 0) {
- /* Remove caption when maximized */
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- bits &= ~OS.WS_CAPTION;
- OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
- }
- RECT rect = new RECT ();
- OS.SystemParametersInfo (OS.SPI_GETWORKAREA, 0, rect, 0);
- int width = rect.right - rect.left, height = rect.bottom - rect.top;
- if (OS.IsPPC) {
- /* Leave space for the menu bar */
- if (menuBar != null) {
- int hwndCB = menuBar.hwndCB;
- RECT rectCB = new RECT ();
- OS.GetWindowRect (hwndCB, rectCB);
- height -= rectCB.bottom - rectCB.top;
- }
- }
- int flags = OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE;
- OS.SetWindowPos (handle, 0, rect.left, rect.top, width, height, flags);
- } else {
- if ((style & SWT.NO_TRIM) == 0) {
- /* Insert caption when no longer maximized */
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- bits |= OS.WS_CAPTION;
- OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
- int flags = OS.SWP_NOMOVE | OS.SWP_NOSIZE | OS.SWP_NOZORDER | OS.SWP_DRAWFRAME;
- OS.SetWindowPos (handle, 0, 0, 0, 0, 0, flags);
- }
- }
- } else {
- if (!OS.IsWindowVisible (handle)) return;
- if (maximized == OS.IsZoomed (handle)) return;
- OS.ShowWindow (handle, swFlags);
- OS.UpdateWindow (handle);
- }
-}
-
-/**
- * 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);
- }
- if (OS.IsWinCE) {
- if (OS.IsHPC) {
- boolean resize = menuBar != menu;
- if (menuBar != null) OS.CommandBar_Show (menuBar.hwndCB, false);
- menuBar = menu;
- if (menuBar != null) OS.CommandBar_Show (menuBar.hwndCB, true);
- if (resize) {
- sendEvent (SWT.Resize);
- layout (false);
- }
- } else {
- if (OS.IsPPC) {
- /*
- * Note in WinCE PPC. The menu bar is a separate popup window.
- * If the shell is full screen, resize its window to leave
- * space for the menu bar.
- */
- boolean resize = getMaximized () && menuBar != menu;
- if (menuBar != null) OS.ShowWindow (menuBar.hwndCB, OS.SW_HIDE);
- menuBar = menu;
- if (menuBar != null) OS.ShowWindow (menuBar.hwndCB, OS.SW_SHOW);
- if (resize) setMaximized (true);
- }
- if (OS.IsSP) {
- if (menuBar != null) OS.ShowWindow (menuBar.hwndCB, OS.SW_HIDE);
- menuBar = menu;
- if (menuBar != null) OS.ShowWindow (menuBar.hwndCB, OS.SW_SHOW);
- }
- }
- } else {
- if (menu != null) {
- Display display = getDisplay ();
- display.removeBar (menu);
- }
- menuBar = menu;
- int hMenu = menuBar != null ? menuBar.handle: 0;
- OS.SetMenu (handle, hMenu);
- }
- destroyAccelerators ();
-}
-
-/**
- * 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 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 ();
- if (OS.IsWinCE) return;
- swFlags = OS.SW_RESTORE;
- if (minimized) swFlags = OS.SW_SHOWMINNOACTIVE;
- if (!OS.IsWindowVisible (handle)) return;
- if (minimized == OS.IsIconic (handle)) return;
- OS.ShowWindow (handle, swFlags);
- OS.UpdateWindow (handle);
-}
-
-void setParent () {
- /*
- * In order for an MDI child window to support
- * a menu bar, setParent () is needed to reset
- * the parent. Otherwise, the MDI child window
- * will appear as a separate shell. This is an
- * undocumented and possibly dangerous Windows
- * feature.
- */
- Display display = getDisplay ();
- int hwndParent = parent.handle;
- display.lockActiveWindow = true;
- OS.SetParent (handle, hwndParent);
- if (!OS.IsWindowVisible (hwndParent)) {
- OS.ShowWindow (handle, OS.SW_SHOWNA);
- }
- display.lockActiveWindow = false;
-}
-
-void setPlacement (int x, int y, int width, int height, int flags) {
- WINDOWPLACEMENT lpwndpl = new WINDOWPLACEMENT ();
- lpwndpl.length = WINDOWPLACEMENT.sizeof;
- OS.GetWindowPlacement (handle, lpwndpl);
- lpwndpl.showCmd = OS.SW_SHOWNA;
- if (OS.IsIconic (handle)) {
- lpwndpl.showCmd = OS.SW_SHOWMINNOACTIVE;
- } else {
- if (OS.IsZoomed (handle)) {
- lpwndpl.showCmd = OS.SW_SHOWMAXIMIZED;
- }
- }
- if ((flags & OS.SWP_NOMOVE) == 0) {
- lpwndpl.left = x;
- lpwndpl.top = y;
- }
- if ((flags & OS.SWP_NOSIZE) == 0) {
- lpwndpl.right = x + width;
- lpwndpl.bottom = y + height;
- }
- OS.SetWindowPlacement (handle, lpwndpl);
-}
-
-void setSavedFocus (Control control) {
- if (this == control) {
- savedFocus = null;
- return;
- }
- if (this != control.menuShell ()) return;
- savedFocus = control;
-}
-
-void setSystemMenu () {
- if (OS.IsWinCE) return;
- int hMenu = OS.GetSystemMenu (handle, false);
- if (hMenu == 0) return;
- int oldCount = OS.GetMenuItemCount (hMenu);
- if ((style & SWT.RESIZE) == 0) {
- OS.DeleteMenu (hMenu, OS.SC_SIZE, OS.MF_BYCOMMAND);
- }
- if ((style & SWT.MIN) == 0) {
- OS.DeleteMenu (hMenu, OS.SC_MINIMIZE, OS.MF_BYCOMMAND);
- }
- if ((style & SWT.MAX) == 0) {
- OS.DeleteMenu (hMenu, OS.SC_MAXIMIZE, OS.MF_BYCOMMAND);
- }
- if ((style & (SWT.MIN | SWT.MAX)) == 0) {
- OS.DeleteMenu (hMenu, OS.SC_RESTORE, OS.MF_BYCOMMAND);
- }
- int newCount = OS.GetMenuItemCount (hMenu);
- if ((style & SWT.CLOSE) == 0 || newCount != oldCount) {
- OS.DeleteMenu (hMenu, OS.SC_TASKLIST, OS.MF_BYCOMMAND);
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- info.fMask = OS.MIIM_ID;
- int index = 0;
- while (index < newCount) {
- if (OS.GetMenuItemInfo (hMenu, index, true, info)) {
- if (info.wID == OS.SC_CLOSE) break;
- }
- index++;
- }
- if (index != newCount) {
- OS.DeleteMenu (hMenu, index - 1, OS.MF_BYPOSITION);
- if ((style & SWT.CLOSE) == 0) {
- OS.DeleteMenu (hMenu, OS.SC_CLOSE, OS.MF_BYCOMMAND);
- }
- }
- }
-}
-
-/**
- * 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 may not be null.
- *
- * @param text the new text
- *
- * @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>
- */
-public void setText (String string) {
- checkWidget ();
- if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
- /* Use the character encoding for the default locale */
- TCHAR buffer = new TCHAR (0, string, true);
- OS.SetWindowText (handle, buffer);
-}
-
-public void setVisible (boolean visible) {
- checkWidget ();
- if (visible == OS.IsWindowVisible (handle)) return;
- 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;
- if (OS.IsHPC) {
- if (menuBar != null) {
- int hwndCB = menuBar.hwndCB;
- OS.CommandBar_DrawMenuBar (hwndCB, 0);
- }
- }
- if (OS.IsWinCE) {
- OS.ShowWindow (handle, OS.SW_SHOW);
- } else {
- if (menuBar != null) {
- Display display = getDisplay ();
- display.removeBar (menuBar);
- OS.DrawMenuBar (handle);
- }
- OS.ShowWindow (handle, swFlags);
- }
- OS.UpdateWindow (handle);
- } else {
- if (!OS.IsWinCE) {
- if (OS.IsIconic (handle)) {
- swFlags = OS.SW_SHOWMINNOACTIVE;
- } else {
- if (OS.IsZoomed (handle)) {
- swFlags = OS.SW_SHOWMAXIMIZED;
- } else {
- if (handle == OS.GetActiveWindow ()) {
- swFlags = OS.SW_RESTORE;
- } else {
- swFlags = OS.SW_SHOWNOACTIVATE;
- }
- }
- }
- }
- OS.ShowWindow (handle, OS.SW_HIDE);
- sendEvent (SWT.Hide);
- }
-}
-
-boolean translateAccelerator (MSG msg) {
- if (!isEnabled () || !isActive ()) return false;
- if (menuBar != null && !menuBar.isEnabled ()) return false;
- if (hAccel == -1) createAccelerators ();
- if (hAccel == 0) return false;
- return OS.TranslateAccelerator (handle, hAccel, msg) != 0;
-}
-
-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;
-}
-
-int widgetExtStyle () {
- int bits = super.widgetExtStyle () & ~OS.WS_EX_CLIENTEDGE;
- if ((style & SWT.NO_TRIM) != 0) return bits;
- if (OS.IsPPC) {
- if ((style & SWT.CLOSE) != 0) bits |= OS.WS_EX_CAPTIONOKBTN;
- }
- if ((style & SWT.TOOL) != 0) bits |= OS.WS_EX_TOOLWINDOW;
- if ((style & SWT.RESIZE) != 0) return bits;
- if ((style & SWT.BORDER) != 0) bits |= OS.WS_EX_DLGMODALFRAME;
- return bits;
-}
-
-int widgetStyle () {
- /*
- * Set WS_POPUP and clear WS_VISIBLE and WS_TABSTOP.
- * NOTE: WS_TABSTOP is the same as WS_MAXIMIZEBOX so
- * it cannot be used to do tabbing with decorations.
- */
- int bits = super.widgetStyle () | OS.WS_POPUP;
- bits &= ~(OS.WS_VISIBLE | OS.WS_TABSTOP);
-
- /* Set the title bits and no-trim bits */
- bits &= ~OS.WS_BORDER;
- if ((style & SWT.NO_TRIM) != 0) return bits;
- if ((style & SWT.TITLE) != 0) bits |= OS.WS_CAPTION;
-
- /* Set the min and max button bits */
- if ((style & SWT.MIN) != 0) bits |= OS.WS_MINIMIZEBOX;
- if ((style & SWT.MAX) != 0) bits |= OS.WS_MAXIMIZEBOX;
-
- /* Set the resize, dialog border or border bits */
- if ((style & SWT.RESIZE) != 0) {
- /*
- * Note on WinCE PPC. SWT.RESIZE is used to resize
- * the Shell according to the state of the IME.
- * It does not set the WS_THICKFRAME style.
*/
- if (!OS.IsPPC) bits |= OS.WS_THICKFRAME;
- } else {
- if ((style & SWT.BORDER) == 0) bits |= OS.WS_BORDER;
- }
-
- /* Set the system menu and close box bits */
- if (!OS.IsPPC && !OS.IsSP) {
- if ((style & SWT.CLOSE) != 0) bits |= OS.WS_SYSMENU;
- }
-
- return bits;
-}
-
-int windowProc (int msg, int wParam, int lParam) {
- switch (msg) {
- case OS.WM_APP:
- case OS.WM_APP+1:
- if (hAccel == -1) createAccelerators ();
- return msg == OS.WM_APP ? nAccel : hAccel;
- }
- return super.windowProc (msg, wParam, lParam);
-}
-
-LRESULT WM_ACTIVATE (int wParam, int lParam) {
- LRESULT result = super.WM_ACTIVATE (wParam, lParam);
- if (result != null) return result;
- if ((wParam & 0xFFFF) != 0) {
- /*
- * When the high word of wParam is non-zero, the activation
- * state of the window is being changed while the window is
- * minimized. If this is the case, do not report activation
- * events or restore the focus.
- */
- if ((wParam >> 16) != 0) return result;
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the activate
- * event. If this happens, end the processing of the
- * Windows message by returning zero as the result of
- * the window proc.
- */
- sendEvent (SWT.Activate);
- if (isDisposed ()) return LRESULT.ZERO;
- if (restoreFocus ()) return LRESULT.ZERO;
- if (traverseGroup (true)) return LRESULT.ZERO;
-
- } else {
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the deactivate
- * event. If this happens, end the processing of the
- * Windows message by returning zero as the result of
- * the window proc.
- */
- Shell shell = getShell ();
- shell.setActiveControl (null);
- if (isDisposed ()) return LRESULT.ZERO;
- sendEvent (SWT.Deactivate);
- if (isDisposed ()) return LRESULT.ZERO;
- saveFocus ();
- }
- return result;
-}
-
-LRESULT WM_CLOSE (int wParam, int lParam) {
- LRESULT result = super.WM_CLOSE (wParam, lParam);
- if (result != null) return result;
- Event event = new Event ();
- sendEvent (SWT.Close, event);
- // the widget could be disposed at this point
- if (event.doit && !isDisposed ()) dispose ();
- return LRESULT.ZERO;
-}
-
-LRESULT WM_HOTKEY (int wParam, int lParam) {
- LRESULT result = super.WM_HOTKEY (wParam, lParam);
- if (result != null) return result;
- if (OS.IsSP) {
- /*
- * Feature on WinCE SP. The Back key is either used to close
- * the foreground Dialog or used as a regular Back key in an EDIT
- * control. The article 'Back Key' in MSDN for Smartphone
- * describes how an application should handle it. The
- * workaround is to override the Back key when creating
- * the menubar and handle it based on the style of the Shell.
- * If the Shell has the SWT.CLOSE style, close the Shell.
- * Otherwise, send the Back key to the window with focus.
- */
- if (((lParam >> 16) & 0xFFFF) == OS.VK_ESCAPE) {
- if ((style & SWT.CLOSE) != 0) {
- OS.PostMessage (handle, OS.WM_CLOSE, 0, 0);
- } else {
- OS.SHSendBackToFocusWindow (OS.WM_HOTKEY, wParam, lParam);
- }
- return LRESULT.ZERO;
- }
- }
- return result;
-}
-
-LRESULT WM_KILLFOCUS (int wParam, int lParam) {
- LRESULT result = super.WM_KILLFOCUS (wParam, lParam);
- saveFocus ();
- return result;
-}
-
-LRESULT WM_NCACTIVATE (int wParam, int lParam) {
- LRESULT result = super.WM_NCACTIVATE (wParam, lParam);
- if (result != null) return result;
- if (wParam == 0) {
- Display display = getDisplay ();
- if (display.lockActiveWindow) return LRESULT.ZERO;
- }
- return result;
-}
-
-LRESULT WM_QUERYOPEN (int wParam, int lParam) {
- LRESULT result = super.WM_QUERYOPEN (wParam, lParam);
- if (result != null) return result;
- sendEvent (SWT.Deiconify);
- // widget could be disposed at this point
- return result;
-}
-
-LRESULT WM_SETFOCUS (int wParam, int lParam) {
- LRESULT result = super.WM_SETFOCUS (wParam, lParam);
- if (!restoreFocus ()) traverseGroup (true);
- return result;
-}
-
-LRESULT WM_SIZE (int wParam, int lParam) {
- LRESULT result = super.WM_SIZE (wParam, lParam);
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the resize
- * event. If this happens, end the processing of the
- * Windows message by returning the result of the
- * WM_SIZE message.
- */
- if (isDisposed ()) return result;
- if (wParam == OS.SIZE_MINIMIZED) {
- sendEvent (SWT.Iconify);
- // widget could be disposed at this point
- }
- return result;
-}
-
-LRESULT WM_WINDOWPOSCHANGING (int wParam, int lParam) {
- LRESULT result = super.WM_WINDOWPOSCHANGING (wParam,lParam);
- if (result != null) return result;
- Display display = getDisplay ();
- if (display.lockActiveWindow) {
- WINDOWPOS lpwp = new WINDOWPOS ();
- OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof);
- lpwp.flags |= OS.SWP_NOZORDER;
- OS.MoveMemory (lParam, lpwp, WINDOWPOS.sizeof);
- }
- return result;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; + +/** + * 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> + * 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 + */ + +public class Decorations extends Canvas { + Image image; + Menu menuBar; + Menu [] menus; + MenuItem [] items; + Control savedFocus; + Button defaultButton, saveDefault; + int swFlags, hAccel, nAccel, hIcon; + + /* + * The start value for WM_COMMAND id's. + * Windows reserves the values 0..100. + * + * The SmartPhone SWT resource file reserves + * the values 101..107. + */ + static final int ID_START = 108; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Decorations () { +} + +/** + * 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)); +} + +void add (Menu menu) { + if (menus == null) menus = new Menu [4]; + for (int i=0; i<menus.length; i++) { + if (menus [i] == null) { + menus [i] = menu; + return; + } + } + Menu [] newMenus = new Menu [menus.length + 4]; + newMenus [menus.length] = menu; + System.arraycopy (menus, 0, newMenus, 0, menus.length); + menus = newMenus; +} + +void add (MenuItem item) { + if (items == null) items = new MenuItem [12]; + for (int i=0; i<items.length; i++) { + if (items [i] == null) { + item.id = i + ID_START; + items [i] = item; + return; + } + } + item.id = items.length + ID_START; + MenuItem [] newItems = new MenuItem [items.length + 12]; + newItems [items.length] = item; + System.arraycopy (items, 0, newItems, 0, items.length); + items = newItems; +} + +void bringToTop () { + /* + * This code is intentionally commented. On some platforms, + * the ON_TOP style creates a shell that will stay on top + * of every other shell on the desktop. Using SetWindowPos () + * with HWND_TOP caused problems on Windows so this code is + * commented out until this functionality is specified and + * the problems are fixed. + */ +// if ((style & SWT.ON_TOP) != 0) { +// int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE; +// OS.SetWindowPos (handle, OS.HWND_TOP, 0, 0, 0, 0, flags); +// } else { + OS.BringWindowToTop (handle); +// } +} + +static int checkStyle (int style) { + if (OS.IsWinCE) { + /* + * Feature in WinCE PPC. WS_MINIMIZEBOX or WS_MAXIMIZEBOX + * are not supposed to be used. If they are, the result + * is a button which does not repaint correctly. The fix + * is to remove this style. + */ + if ((style & SWT.MIN) != 0) style &= ~SWT.MIN; + if ((style & SWT.MAX) != 0) style &= ~SWT.MAX; + return style; + } + + /* + * If either WS_MINIMIZEBOX or WS_MAXIMIZEBOX are set, + * we must also set WS_SYSMENU or the buttons will not + * appear. + */ + if ((style & (SWT.MIN | SWT.MAX)) != 0) style |= SWT.CLOSE; + + /* + * Both WS_SYSMENU and WS_CAPTION must be set in order + * to for the system menu to appear. + */ + if ((style & SWT.CLOSE) != 0) style |= SWT.TITLE; + + /* + * Bug in Windows. The WS_CAPTION style must be + * set when the window is resizable or it does not + * draw properly. + */ + /* + * This code is intentionally commented. It seems + * that this problem originally in Windows 3.11, + * has been fixed in later versions. Because the + * exact nature of the drawing problem is unknown, + * keep the commented code around in case it comes + * back. + */ +// if ((style & SWT.RESIZE) != 0) style |= SWT.TITLE; + + return style; +} + +protected void checkSubclass () { + if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS); +} + +Control computeTabGroup () { + return this; +} + +Control computeTabRoot () { + return this; +} + +public Rectangle computeTrim (int x, int y, int width, int height) { + checkWidget (); + + /* Get the size of the trimmings */ + RECT rect = new RECT (); + OS.SetRect (rect, x, y, x + width, y + height); + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + boolean hasMenu = OS.IsWinCE ? false : OS.GetMenu (handle) != 0; + OS.AdjustWindowRectEx (rect, bits, hasMenu, OS.GetWindowLong (handle, OS.GWL_EXSTYLE)); + + /* Get the size of the scroll bars */ + if (horizontalBar != null) rect.bottom += OS.GetSystemMetrics (OS.SM_CYHSCROLL); + if (verticalBar != null) rect.right += OS.GetSystemMetrics (OS.SM_CXVSCROLL); + + /* Get the height of the menu bar */ + if (hasMenu) { + RECT testRect = new RECT (); + OS.SetRect (testRect, 0, 0, rect.right - rect.left, rect.bottom - rect.top); + OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, testRect); + while ((testRect.bottom - testRect.top) < height) { + rect.top -= OS.GetSystemMetrics (OS.SM_CYMENU) - OS.GetSystemMetrics (OS.SM_CYBORDER); + OS.SetRect(testRect, 0, 0, rect.right - rect.left, rect.bottom - rect.top); + OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, testRect); + } + } + return new Rectangle (rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); +} + +void createAccelerators () { + hAccel = nAccel = 0; + int maxAccel = 0; + if (menuBar == null || items == null) { + if (!OS.IsPPC) return; + maxAccel = 1; + } else { + maxAccel = OS.IsPPC ? items.length + 1 : items.length; + } + int size = ACCEL.sizeof; + ACCEL accel = new ACCEL (); + byte [] buffer1 = new byte [size]; + byte [] buffer2 = new byte [maxAccel * size]; + if (menuBar != null && items != null) { + for (int i=0; i<items.length; i++) { + MenuItem item = items [i]; + if (item != null && item.accelerator != 0) { + Menu parent = item.parent; + while (parent != null && parent != menuBar) { + parent = parent.getParentMenu (); + } + if (parent == menuBar) { + item.fillAccel (accel); + OS.MoveMemory (buffer1, accel, size); + System.arraycopy (buffer1, 0, buffer2, nAccel * size, size); + nAccel++; + } + } + } + } + if (OS.IsPPC) { + /* + * Note on WinCE PPC. Close the shell when user taps CTRL-Q. + * IDOK represents the "Done Button" which also closes the shell. + */ + accel.fVirt = OS.FVIRTKEY | OS.FCONTROL; + accel.key = 'Q'; + accel.cmd = OS.IDOK; + OS.MoveMemory (buffer1, accel, size); + System.arraycopy (buffer1, 0, buffer2, nAccel * size, size); + nAccel++; + } + if (nAccel != 0) hAccel = OS.CreateAcceleratorTable (buffer2, nAccel); +} + +void createHandle () { + super.createHandle (); + if (parent == null) return; + setParent (); + setSystemMenu (); +} + +void createWidget () { + super.createWidget (); + swFlags = OS.IsWinCE ? OS.SW_SHOWMAXIMIZED : OS.SW_SHOWNOACTIVATE; + hAccel = -1; +} + +void destroyAccelerators () { + if (hAccel != 0 && hAccel != -1) OS.DestroyAcceleratorTable (hAccel); + hAccel = -1; +} + +Menu findMenu (int hMenu) { + if (menus == null) return null; + for (int i=0; i<menus.length; i++) { + Menu menu = menus [i]; + if (menu != null && hMenu == menu.handle) return menu; + } + return null; +} + +MenuItem findMenuItem (int id) { + if (items == null) return null; + id = id - ID_START; + if (0 <= id && id < items.length) return items [id]; + return null; +} + +public Rectangle getBounds () { + checkWidget (); + if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + WINDOWPLACEMENT lpwndpl = new WINDOWPLACEMENT (); + lpwndpl.length = WINDOWPLACEMENT.sizeof; + OS.GetWindowPlacement (handle, lpwndpl); + int width = lpwndpl.right - lpwndpl.left; + int height = lpwndpl.bottom - lpwndpl.top; + return new Rectangle (lpwndpl.left, lpwndpl.top, width, height); + } + } + return super.getBounds (); +} + +public Rectangle getClientArea () { + checkWidget (); + /* + * Note: The CommandBar is part of the client area, + * not the trim. Applications don't expect this so + * subtract the height of the CommandBar. + */ + if (OS.IsHPC) { + Rectangle rect = super.getClientArea (); + if (menuBar != null) { + int hwndCB = menuBar.hwndCB; + int height = OS.CommandBar_Height (hwndCB); + rect.y += height; + rect.height -= height; + } + return rect; + } + if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + RECT rect = new RECT (); + WINDOWPLACEMENT lpwndpl = new WINDOWPLACEMENT (); + lpwndpl.length = WINDOWPLACEMENT.sizeof; + OS.GetWindowPlacement (handle, lpwndpl); + int width = lpwndpl.right - lpwndpl.left; + int height = lpwndpl.bottom - lpwndpl.top; + OS.SetRect (rect, 0, 0, width, height); + OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, rect); + return new Rectangle (0, 0, rect.right, rect.bottom); + } + } + return super.getClientArea (); +} + +/** + * 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 + */ +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; +} + +public Point getLocation () { + checkWidget (); + if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + WINDOWPLACEMENT lpwndpl = new WINDOWPLACEMENT (); + lpwndpl.length = WINDOWPLACEMENT.sizeof; + OS.GetWindowPlacement (handle, lpwndpl); + return new Point (lpwndpl.left, lpwndpl.top); + } + } + return super.getLocation (); +} + +/** + * 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 (); + if (OS.IsWinCE) return swFlags == OS.SW_SHOWMAXIMIZED; + if (OS.IsWindowVisible (handle)) return OS.IsZoomed (handle); + return swFlags == OS.SW_SHOWMAXIMIZED; +} + +/** + * 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 (); + if (OS.IsWinCE) return false; + if (OS.IsWindowVisible (handle)) return OS.IsIconic (handle); + return swFlags == OS.SW_SHOWMINNOACTIVE; +} + +String getNameText () { + return getText (); +} + +public Point getSize () { + checkWidget (); + if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + WINDOWPLACEMENT lpwndpl = new WINDOWPLACEMENT (); + lpwndpl.length = WINDOWPLACEMENT.sizeof; + OS.GetWindowPlacement (handle, lpwndpl); + int width = lpwndpl.right - lpwndpl.left; + int height = lpwndpl.bottom - lpwndpl.top; + return new Point (width, height); + } + } + RECT rect = new RECT (); + OS.GetWindowRect (handle, rect); + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + return new Point (width, height); +} + +/** + * 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 (); + int length = OS.GetWindowTextLength (handle); + if (length == 0) return ""; + /* Use the character encoding for the default locale */ + TCHAR buffer = new TCHAR (0, length + 1); + OS.GetWindowText (handle, buffer, length + 1); + return buffer.toString (0, length); +} + +boolean isTabGroup () { + /* + * Can't test WS_TAB bits because they are the same as WS_MAXIMIZEBOX. + */ + return true; +} + +boolean isTabItem () { + /* + * Can't test WS_TAB bits because they are the same as WS_MAXIMIZEBOX. + */ + return false; +} + +Decorations menuShell () { + return this; +} + +void releaseWidget () { + if (menuBar != null) menuBar.releaseResources (); + menuBar = null; + if (menus != null) { + do { + int index = 0; + while (index < menus.length) { + Menu menu = menus [index]; + if (menu != null && !menu.isDisposed ()) { + while (menu.getParentMenu () != null) { + menu = menu.getParentMenu (); + } + menu.dispose (); + break; + } + index++; + } + if (index == menus.length) break; + } while (true); + } + menus = null; + super.releaseWidget (); + if (hIcon != 0) OS.DestroyIcon (hIcon); + hIcon = 0; + items = null; + image = null; + savedFocus = null; + defaultButton = saveDefault = null; + if (hAccel != 0 && hAccel != -1) OS.DestroyAcceleratorTable (hAccel); + hAccel = -1; +} + +void remove (Menu menu) { + if (menus == null) return; + for (int i=0; i<menus.length; i++) { + if (menus [i] == menu) { + menus [i] = null; + return; + } + } +} + +void remove (MenuItem item) { + if (items == null) return; + items [item.id - ID_START] = null; + item.id = -1; +} + +boolean restoreFocus () { + if (savedFocus != null && savedFocus.isDisposed ()) savedFocus = null; + if (savedFocus != null && savedFocus.setSavedFocus ()) return true; + /* + * This code is intentionally commented. When no widget + * has been given focus, some platforms give focus to the + * default button. Windows doesn't do this. + */ +// if (defaultButton != null && !defaultButton.isDisposed ()) { +// if (defaultButton.setFocus ()) return true; +// } + return false; +} + +void saveFocus () { + Control control = getDisplay ().getFocusControl (); + if (control != null) setSavedFocus (control); +} + +void setBounds (int x, int y, int width, int height, int flags) { + if (OS.IsWinCE) { + super.setBounds (x, y, width, height, flags); + } + if (OS.IsIconic (handle) || OS.IsZoomed (handle)) { + setPlacement (x, y, width, height, flags); + return; + } + super.setBounds (x, y, width, height, flags); +} + +/** + * 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. + * + * @param the new default button + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the button 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 setDefaultButton (Button button) { + checkWidget (); + setDefaultButton (button, true); +} + +void setDefaultButton (Button button, boolean save) { + if (button == null) { + if (defaultButton == saveDefault) { + if (save) saveDefault = null; + return; + } + } else { + if (button.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); + if ((button.style & SWT.PUSH) == 0) return; + if (button == defaultButton) return; + } + if (defaultButton != null) { + if (!defaultButton.isDisposed ()) defaultButton.setDefault (false); + } + if ((defaultButton = button) == null) defaultButton = saveDefault; + if (defaultButton != null) { + if (!defaultButton.isDisposed ()) defaultButton.setDefault (true); + } + if (save) saveDefault = defaultButton; + if (saveDefault != null && saveDefault.isDisposed ()) saveDefault = null; +} + +public boolean setFocus () { + checkWidget (); + if (this instanceof Shell) return super.setFocus (); + /* + * Bug in Windows. Setting the focus to a child of the + * receiver interferes with moving and resizing of the + * parent shell. The fix (for now) is to always set the + * focus to the shell. + */ + int hwndFocus = OS.SetFocus (getShell ().handle); + return hwndFocus == OS.GetFocus (); +} +/** + * 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); + /* + * Feature in WinCE. WM_SETICON and WM_GETICON set the icon + * for the window class, not the window instance. This means + * that it is possible to set an icon into a window and then + * later free the icon, thus freeing the icon for every window. + * The fix is to avoid the API. + * + * On WinCE PPC, icons in windows are not displayed anyways. + */ + if (OS.IsWinCE) { + this.image = image; + return; + } + int hImage = 0; + if (image != null) { + if (hIcon != 0) OS.DestroyIcon (hIcon); + hIcon = 0; + switch (image.type) { + case SWT.BITMAP: + /* Copy the bitmap in case it's a DIB */ + int hBitmap = image.handle; + BITMAP bm = new BITMAP (); + OS.GetObject (hBitmap, BITMAP.sizeof, bm); + byte [] lpvBits = new byte [(bm.bmWidth + 15) / 16 * 2 * bm.bmHeight]; + int hMask = OS.CreateBitmap (bm.bmWidth, bm.bmHeight, 1, 1, lpvBits); + int hDC = OS.GetDC (handle); + int hdcMem = OS.CreateCompatibleDC (hDC); + int hColor = OS.CreateCompatibleBitmap (hDC, bm.bmWidth, bm.bmHeight); + OS.SelectObject (hdcMem, hColor); + int hdcBmp = OS.CreateCompatibleDC (hDC); + OS.SelectObject (hdcBmp, hBitmap); + OS.BitBlt (hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcBmp, 0, 0, OS.SRCCOPY); + ICONINFO info = new ICONINFO (); + info.fIcon = true; + info.hbmMask = hMask; + info.hbmColor = hColor; + hImage = hIcon = OS.CreateIconIndirect (info); + OS.DeleteObject (hMask); + OS.DeleteObject(hColor); + OS.DeleteDC (hdcBmp); + OS.DeleteDC (hdcMem); + OS.ReleaseDC (handle, hDC); + break; + case SWT.ICON: + hImage = image.handle; + break; + default: + return; + } + } + this.image = image; + OS.SendMessage (handle, OS.WM_SETICON, OS.ICON_BIG, hImage); + + /* + * Bug in Windows. When WM_SETICON is used to remove an + * icon from the window trimmings for a window with the + * extended style bits WS_EX_DLGMODALFRAME, the window + * trimmings do not redraw to hide the previous icon. + * The fix is to force a redraw. + */ + if (!OS.IsWinCE) { + if (hIcon == 0 && (style & SWT.BORDER) != 0) { + int flags = OS.RDW_FRAME | OS.RDW_INVALIDATE; + OS.RedrawWindow (handle, null, 0, flags); + } + } +} + +/** + * 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 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 (); + swFlags = maximized ? OS.SW_SHOWMAXIMIZED : OS.SW_RESTORE; + if (OS.IsWinCE) { + /* + * Note: WinCE does not support SW_SHOWMAXIMIZED and SW_RESTORE. The + * workaround is to resize the window to fit the parent client area. + * PocketPC windows typically don't have a caption when they are + * maximized. They usually have one when they are not occupying all the + * space. We implement this behavior by default - it can be overriden by + * setting SWT.TITLE or SWT.NO_TRIM. + */ + if (maximized) { + if ((style & SWT.TITLE) == 0) { + /* Remove caption when maximized */ + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + bits &= ~OS.WS_CAPTION; + OS.SetWindowLong (handle, OS.GWL_STYLE, bits); + } + RECT rect = new RECT (); + OS.SystemParametersInfo (OS.SPI_GETWORKAREA, 0, rect, 0); + int width = rect.right - rect.left, height = rect.bottom - rect.top; + if (OS.IsPPC) { + /* Leave space for the menu bar */ + if (menuBar != null) { + int hwndCB = menuBar.hwndCB; + RECT rectCB = new RECT (); + OS.GetWindowRect (hwndCB, rectCB); + height -= rectCB.bottom - rectCB.top; + } + } + int flags = OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE; + OS.SetWindowPos (handle, 0, rect.left, rect.top, width, height, flags); + } else { + if ((style & SWT.NO_TRIM) == 0) { + /* Insert caption when no longer maximized */ + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + bits |= OS.WS_CAPTION; + OS.SetWindowLong (handle, OS.GWL_STYLE, bits); + int flags = OS.SWP_NOMOVE | OS.SWP_NOSIZE | OS.SWP_NOZORDER | OS.SWP_DRAWFRAME; + OS.SetWindowPos (handle, 0, 0, 0, 0, 0, flags); + } + } + } else { + if (!OS.IsWindowVisible (handle)) return; + if (maximized == OS.IsZoomed (handle)) return; + OS.ShowWindow (handle, swFlags); + OS.UpdateWindow (handle); + } +} + +/** + * 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); + } + if (OS.IsWinCE) { + if (OS.IsHPC) { + boolean resize = menuBar != menu; + if (menuBar != null) OS.CommandBar_Show (menuBar.hwndCB, false); + menuBar = menu; + if (menuBar != null) OS.CommandBar_Show (menuBar.hwndCB, true); + if (resize) { + sendEvent (SWT.Resize); + layout (false); + } + } else { + if (OS.IsPPC) { + /* + * Note in WinCE PPC. The menu bar is a separate popup window. + * If the shell is full screen, resize its window to leave + * space for the menu bar. + */ + boolean resize = getMaximized () && menuBar != menu; + if (menuBar != null) OS.ShowWindow (menuBar.hwndCB, OS.SW_HIDE); + menuBar = menu; + if (menuBar != null) OS.ShowWindow (menuBar.hwndCB, OS.SW_SHOW); + if (resize) setMaximized (true); + } + if (OS.IsSP) { + if (menuBar != null) OS.ShowWindow (menuBar.hwndCB, OS.SW_HIDE); + menuBar = menu; + if (menuBar != null) OS.ShowWindow (menuBar.hwndCB, OS.SW_SHOW); + } + } + } else { + if (menu != null) { + Display display = getDisplay (); + display.removeBar (menu); + } + menuBar = menu; + int hMenu = menuBar != null ? menuBar.handle: 0; + OS.SetMenu (handle, hMenu); + } + destroyAccelerators (); +} + +/** + * 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 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 (); + if (OS.IsWinCE) return; + swFlags = OS.SW_RESTORE; + if (minimized) swFlags = OS.SW_SHOWMINNOACTIVE; + if (!OS.IsWindowVisible (handle)) return; + if (minimized == OS.IsIconic (handle)) return; + OS.ShowWindow (handle, swFlags); + OS.UpdateWindow (handle); +} + +void setParent () { + /* + * In order for an MDI child window to support + * a menu bar, setParent () is needed to reset + * the parent. Otherwise, the MDI child window + * will appear as a separate shell. This is an + * undocumented and possibly dangerous Windows + * feature. + */ + Display display = getDisplay (); + int hwndParent = parent.handle; + display.lockActiveWindow = true; + OS.SetParent (handle, hwndParent); + if (!OS.IsWindowVisible (hwndParent)) { + OS.ShowWindow (handle, OS.SW_SHOWNA); + } + display.lockActiveWindow = false; +} + +void setPlacement (int x, int y, int width, int height, int flags) { + WINDOWPLACEMENT lpwndpl = new WINDOWPLACEMENT (); + lpwndpl.length = WINDOWPLACEMENT.sizeof; + OS.GetWindowPlacement (handle, lpwndpl); + lpwndpl.showCmd = OS.SW_SHOWNA; + if (OS.IsIconic (handle)) { + lpwndpl.showCmd = OS.SW_SHOWMINNOACTIVE; + } else { + if (OS.IsZoomed (handle)) { + lpwndpl.showCmd = OS.SW_SHOWMAXIMIZED; + } + } + if ((flags & OS.SWP_NOMOVE) == 0) { + lpwndpl.left = x; + lpwndpl.top = y; + } + if ((flags & OS.SWP_NOSIZE) == 0) { + lpwndpl.right = x + width; + lpwndpl.bottom = y + height; + } + OS.SetWindowPlacement (handle, lpwndpl); +} + +void setSavedFocus (Control control) { + if (this == control) { + savedFocus = null; + return; + } + if (this != control.menuShell ()) return; + savedFocus = control; +} + +void setSystemMenu () { + if (OS.IsWinCE) return; + int hMenu = OS.GetSystemMenu (handle, false); + if (hMenu == 0) return; + int oldCount = OS.GetMenuItemCount (hMenu); + if ((style & SWT.RESIZE) == 0) { + OS.DeleteMenu (hMenu, OS.SC_SIZE, OS.MF_BYCOMMAND); + } + if ((style & SWT.MIN) == 0) { + OS.DeleteMenu (hMenu, OS.SC_MINIMIZE, OS.MF_BYCOMMAND); + } + if ((style & SWT.MAX) == 0) { + OS.DeleteMenu (hMenu, OS.SC_MAXIMIZE, OS.MF_BYCOMMAND); + } + if ((style & (SWT.MIN | SWT.MAX)) == 0) { + OS.DeleteMenu (hMenu, OS.SC_RESTORE, OS.MF_BYCOMMAND); + } + int newCount = OS.GetMenuItemCount (hMenu); + if ((style & SWT.CLOSE) == 0 || newCount != oldCount) { + OS.DeleteMenu (hMenu, OS.SC_TASKLIST, OS.MF_BYCOMMAND); + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + info.fMask = OS.MIIM_ID; + int index = 0; + while (index < newCount) { + if (OS.GetMenuItemInfo (hMenu, index, true, info)) { + if (info.wID == OS.SC_CLOSE) break; + } + index++; + } + if (index != newCount) { + OS.DeleteMenu (hMenu, index - 1, OS.MF_BYPOSITION); + if ((style & SWT.CLOSE) == 0) { + OS.DeleteMenu (hMenu, OS.SC_CLOSE, OS.MF_BYCOMMAND); + } + } + } +} + +/** + * 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 may not be null. + * + * @param text the new text + * + * @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> + */ +public void setText (String string) { + checkWidget (); + if (string == null) error (SWT.ERROR_NULL_ARGUMENT); + /* Use the character encoding for the default locale */ + TCHAR buffer = new TCHAR (0, string, true); + OS.SetWindowText (handle, buffer); +} + +public void setVisible (boolean visible) { + checkWidget (); + if (visible == OS.IsWindowVisible (handle)) return; + 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; + if (OS.IsHPC) { + if (menuBar != null) { + int hwndCB = menuBar.hwndCB; + OS.CommandBar_DrawMenuBar (hwndCB, 0); + } + } + if (OS.IsWinCE) { + OS.ShowWindow (handle, OS.SW_SHOW); + } else { + if (menuBar != null) { + Display display = getDisplay (); + display.removeBar (menuBar); + OS.DrawMenuBar (handle); + } + OS.ShowWindow (handle, swFlags); + } + OS.UpdateWindow (handle); + } else { + if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + swFlags = OS.SW_SHOWMINNOACTIVE; + } else { + if (OS.IsZoomed (handle)) { + swFlags = OS.SW_SHOWMAXIMIZED; + } else { + if (handle == OS.GetActiveWindow ()) { + swFlags = OS.SW_RESTORE; + } else { + swFlags = OS.SW_SHOWNOACTIVATE; + } + } + } + } + OS.ShowWindow (handle, OS.SW_HIDE); + sendEvent (SWT.Hide); + } +} + +boolean translateAccelerator (MSG msg) { + if (!isEnabled () || !isActive ()) return false; + if (menuBar != null && !menuBar.isEnabled ()) return false; + if (hAccel == -1) createAccelerators (); + if (hAccel == 0) return false; + return OS.TranslateAccelerator (handle, hAccel, msg) != 0; +} + +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; +} + +int widgetExtStyle () { + int bits = super.widgetExtStyle () & ~OS.WS_EX_CLIENTEDGE; + if ((style & SWT.NO_TRIM) != 0) return bits; + if (OS.IsPPC) { + if ((style & SWT.CLOSE) != 0) bits |= OS.WS_EX_CAPTIONOKBTN; + } + if ((style & SWT.TOOL) != 0) bits |= OS.WS_EX_TOOLWINDOW; + if ((style & SWT.RESIZE) != 0) return bits; + if ((style & SWT.BORDER) != 0) bits |= OS.WS_EX_DLGMODALFRAME; + return bits; +} + +int widgetStyle () { + /* + * Set WS_POPUP and clear WS_VISIBLE and WS_TABSTOP. + * NOTE: WS_TABSTOP is the same as WS_MAXIMIZEBOX so + * it cannot be used to do tabbing with decorations. + */ + int bits = super.widgetStyle () | OS.WS_POPUP; + bits &= ~(OS.WS_VISIBLE | OS.WS_TABSTOP); + + /* Set the title bits and no-trim bits */ + bits &= ~OS.WS_BORDER; + if ((style & SWT.NO_TRIM) != 0) return bits; + if ((style & SWT.TITLE) != 0) bits |= OS.WS_CAPTION; + + /* Set the min and max button bits */ + if ((style & SWT.MIN) != 0) bits |= OS.WS_MINIMIZEBOX; + if ((style & SWT.MAX) != 0) bits |= OS.WS_MAXIMIZEBOX; + + /* Set the resize, dialog border or border bits */ + if ((style & SWT.RESIZE) != 0) { + /* + * Note on WinCE PPC. SWT.RESIZE is used to resize + * the Shell according to the state of the IME. + * It does not set the WS_THICKFRAME style.
*/ + if (!OS.IsPPC) bits |= OS.WS_THICKFRAME; + } else { + if ((style & SWT.BORDER) == 0) bits |= OS.WS_BORDER; + } + + /* Set the system menu and close box bits */ + if (!OS.IsPPC && !OS.IsSP) { + if ((style & SWT.CLOSE) != 0) bits |= OS.WS_SYSMENU; + } + + return bits; +} + +int windowProc (int msg, int wParam, int lParam) { + switch (msg) { + case OS.WM_APP: + case OS.WM_APP+1: + if (hAccel == -1) createAccelerators (); + return msg == OS.WM_APP ? nAccel : hAccel; + } + return super.windowProc (msg, wParam, lParam); +} + +LRESULT WM_ACTIVATE (int wParam, int lParam) { + LRESULT result = super.WM_ACTIVATE (wParam, lParam); + if (result != null) return result; + if ((wParam & 0xFFFF) != 0) { + /* + * When the high word of wParam is non-zero, the activation + * state of the window is being changed while the window is + * minimized. If this is the case, do not report activation + * events or restore the focus. + */ + if ((wParam >> 16) != 0) return result; + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the activate + * event. If this happens, end the processing of the + * Windows message by returning zero as the result of + * the window proc. + */ + sendEvent (SWT.Activate); + if (isDisposed ()) return LRESULT.ZERO; + if (restoreFocus ()) return LRESULT.ZERO; + if (traverseGroup (true)) return LRESULT.ZERO; + + } else { + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the deactivate + * event. If this happens, end the processing of the + * Windows message by returning zero as the result of + * the window proc. + */ + Shell shell = getShell (); + shell.setActiveControl (null); + if (isDisposed ()) return LRESULT.ZERO; + sendEvent (SWT.Deactivate); + if (isDisposed ()) return LRESULT.ZERO; + saveFocus (); + } + return result; +} + +LRESULT WM_CLOSE (int wParam, int lParam) { + LRESULT result = super.WM_CLOSE (wParam, lParam); + if (result != null) return result; + Event event = new Event (); + sendEvent (SWT.Close, event); + // the widget could be disposed at this point + if (event.doit && !isDisposed ()) dispose (); + return LRESULT.ZERO; +} + +LRESULT WM_HOTKEY (int wParam, int lParam) { + LRESULT result = super.WM_HOTKEY (wParam, lParam); + if (result != null) return result; + if (OS.IsSP) { + /* + * Feature on WinCE SP. The Back key is either used to close + * the foreground Dialog or used as a regular Back key in an EDIT + * control. The article 'Back Key' in MSDN for Smartphone + * describes how an application should handle it. The + * workaround is to override the Back key when creating + * the menubar and handle it based on the style of the Shell. + * If the Shell has the SWT.CLOSE style, close the Shell. + * Otherwise, send the Back key to the window with focus. + */ + if (((lParam >> 16) & 0xFFFF) == OS.VK_ESCAPE) { + if ((style & SWT.CLOSE) != 0) { + OS.PostMessage (handle, OS.WM_CLOSE, 0, 0); + } else { + OS.SHSendBackToFocusWindow (OS.WM_HOTKEY, wParam, lParam); + } + return LRESULT.ZERO; + } + } + return result; +} + +LRESULT WM_KILLFOCUS (int wParam, int lParam) { + LRESULT result = super.WM_KILLFOCUS (wParam, lParam); + saveFocus (); + return result; +} + +LRESULT WM_NCACTIVATE (int wParam, int lParam) { + LRESULT result = super.WM_NCACTIVATE (wParam, lParam); + if (result != null) return result; + if (wParam == 0) { + Display display = getDisplay (); + if (display.lockActiveWindow) return LRESULT.ZERO; + } + return result; +} + +LRESULT WM_QUERYOPEN (int wParam, int lParam) { + LRESULT result = super.WM_QUERYOPEN (wParam, lParam); + if (result != null) return result; + sendEvent (SWT.Deiconify); + // widget could be disposed at this point + return result; +} + +LRESULT WM_SETFOCUS (int wParam, int lParam) { + LRESULT result = super.WM_SETFOCUS (wParam, lParam); + if (!restoreFocus ()) traverseGroup (true); + return result; +} + +LRESULT WM_SIZE (int wParam, int lParam) { + LRESULT result = super.WM_SIZE (wParam, lParam); + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the resize + * event. If this happens, end the processing of the + * Windows message by returning the result of the + * WM_SIZE message. + */ + if (isDisposed ()) return result; + if (wParam == OS.SIZE_MINIMIZED) { + sendEvent (SWT.Iconify); + // widget could be disposed at this point + } + return result; +} + +LRESULT WM_WINDOWPOSCHANGING (int wParam, int lParam) { + LRESULT result = super.WM_WINDOWPOSCHANGING (wParam,lParam); + if (result != null) return result; + Display display = getDisplay (); + if (display.lockActiveWindow) { + WINDOWPOS lpwp = new WINDOWPOS (); + OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof); + lpwp.flags |= OS.SWP_NOZORDER; + OS.MoveMemory (lParam, lpwp, WINDOWPOS.sizeof); + } + return result; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/DirectoryDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/DirectoryDialog.java index b97e76ef34..f4fdc01bf0 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/DirectoryDialog.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/DirectoryDialog.java @@ -1,242 +1,242 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.*;
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-
-/**
- * Instances of this class allow the user to navigate
- * the file system and select a directory.
- * <p>
- * IMPORTANT: This class is intended to be subclassed <em>only</em>
- * within the SWT implementation.
- * </p>
- */
-
-public class DirectoryDialog extends Dialog {
- String message = "", filterPath = "";
- String directoryPath;
-
-/**
- * Constructs a new instance of this class given only its
- * parent.
- * <p>
- * Note: Currently, null can be passed in for the parent.
- * This has the effect of creating the dialog on the currently active
- * display if there is one. If there is no current display, the
- * dialog 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_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.PRIMARY_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>
- * Note: Currently, null can be passed in for the parent.
- * This has the effect of creating the dialog on the currently active
- * display if there is one. If there is no current display, the
- * dialog 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_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, style);
- checkSubclass ();
-}
-
-int BrowseCallbackProc (int hwnd, int uMsg, int lParam, int lpData) {
- switch (uMsg) {
- case OS.BFFM_INITIALIZED:
- if (filterPath != null && filterPath.length () != 0) {
- /* Use the character encoding for the default locale */
- TCHAR buffer = new TCHAR (0, filterPath.replace ('/', '\\'), true);
- OS.SendMessage (hwnd, OS.BFFM_SETSELECTION, 1, buffer);
- }
- if (title != null && title.length () != 0) {
- /* Use the character encoding for the default locale */
- TCHAR buffer = new TCHAR (0, title, true);
- OS.SetWindowText (hwnd, buffer);
- }
- break;
- case OS.BFFM_VALIDATEFAILEDA:
- case OS.BFFM_VALIDATEFAILEDW:
- /* Use the character encoding for the default locale */
- TCHAR buffer = new TCHAR (0, 256);
- int byteCount = buffer.length () * TCHAR.sizeof;
- OS.MoveMemory (buffer, lParam, byteCount);
- directoryPath = buffer.toString (0, buffer.strlen ());
- break;
- }
- return 0;
-}
-
-/**
- * Returns the path which the dialog will use to filter
- * the directories it shows.
- *
- * @return the filter path
- */
-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 () {
- if (OS.IsWinCE) SWT.error (SWT.ERROR_NOT_IMPLEMENTED);
-
- /* Initialize OLE */
- OS.OleInitialize (0);
-
- int hHeap = OS.GetProcessHeap ();
-
- /* Get the owner HWND for the dialog */
- int hwndOwner = 0;
- if (parent != null) hwndOwner = parent.handle;
-
- /* Copy the message to OS memory */
- int lpszTitle = 0;
- if (message != null && message.length () != 0) {
- /* Use the character encoding for the default locale */
- TCHAR buffer = new TCHAR (0, message, true);
- int byteCount = buffer.length () * TCHAR.sizeof;
- lpszTitle = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- OS.MoveMemory (lpszTitle, buffer, byteCount);
- }
-
- /* Create the BrowseCallbackProc */
- Callback callback = new Callback (this, "BrowseCallbackProc", 4);
- int address = callback.getAddress ();
-
- /* Open the dialog */
- directoryPath = null;
- BROWSEINFO lpbi = new BROWSEINFO ();
- lpbi.hwndOwner = hwndOwner;
- lpbi.lpszTitle = lpszTitle;
- lpbi.ulFlags = OS.BIF_NEWDIALOGSTYLE | OS.BIF_RETURNONLYFSDIRS | OS.BIF_EDITBOX | OS.BIF_VALIDATE;
- lpbi.lpfn = address;
- int lpItemIdList = OS.SHBrowseForFolder (lpbi);
- boolean success = lpItemIdList != 0;
- if (success) {
- /* Use the character encoding for the default locale */
- TCHAR buffer = new TCHAR (0, 256);
- if (OS.SHGetPathFromIDList (lpItemIdList, buffer)) {
- directoryPath = buffer.toString (0, buffer.strlen ());
- filterPath = directoryPath;
- }
- }
-
- /* Free the BrowseCallbackProc */
- callback.dispose ();
-
- /* Free the OS memory */
- if (lpszTitle != 0) OS.HeapFree (hHeap, 0, lpszTitle);
-
- /* Free the pointer to the ITEMIDLIST */
- int [] ppMalloc = new int [1];
- if (OS.SHGetMalloc (ppMalloc) == OS.S_OK) {
- /* void Free (struct IMalloc *this, void *pv); */
- OS.VtblCall (5, ppMalloc [0], lpItemIdList);
- }
-
- /* Uninitialize OLE */
- OS.OleUninitialize ();
-
- /*
- * This code is intentionally commented. On some
- * platforms, the owner window is repainted right
- * away when a dialog window exits. This behavior
- * is currently unspecified.
- */
-// if (hwndOwner != 0) OS.UpdateWindow (hwndOwner);
-
- /* Return the directory path */
- if (!success) return null;
- return directoryPath;
-}
-
-/**
- * Sets the path which the dialog will use to filter
- * the directories it shows to the argument, which may be
- * null.
- *
- * @param string the filter path
- */
-public void setFilterPath (String string) {
- filterPath = string;
-}
-
-/**
- * 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
- */
-public void setMessage (String string) {
- message = string;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; + +/** + * Instances of this class allow the user to navigate + * the file system and select a directory. + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> + * within the SWT implementation. + * </p> + */ + +public class DirectoryDialog extends Dialog { + String message = "", filterPath = ""; + String directoryPath; + +/** + * Constructs a new instance of this class given only its + * parent. + * <p> + * Note: Currently, null can be passed in for the parent. + * This has the effect of creating the dialog on the currently active + * display if there is one. If there is no current display, the + * dialog 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_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.PRIMARY_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> + * Note: Currently, null can be passed in for the parent. + * This has the effect of creating the dialog on the currently active + * display if there is one. If there is no current display, the + * dialog 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_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, style); + checkSubclass (); +} + +int BrowseCallbackProc (int hwnd, int uMsg, int lParam, int lpData) { + switch (uMsg) { + case OS.BFFM_INITIALIZED: + if (filterPath != null && filterPath.length () != 0) { + /* Use the character encoding for the default locale */ + TCHAR buffer = new TCHAR (0, filterPath.replace ('/', '\\'), true); + OS.SendMessage (hwnd, OS.BFFM_SETSELECTION, 1, buffer); + } + if (title != null && title.length () != 0) { + /* Use the character encoding for the default locale */ + TCHAR buffer = new TCHAR (0, title, true); + OS.SetWindowText (hwnd, buffer); + } + break; + case OS.BFFM_VALIDATEFAILEDA: + case OS.BFFM_VALIDATEFAILEDW: + /* Use the character encoding for the default locale */ + TCHAR buffer = new TCHAR (0, 256); + int byteCount = buffer.length () * TCHAR.sizeof; + OS.MoveMemory (buffer, lParam, byteCount); + directoryPath = buffer.toString (0, buffer.strlen ()); + break; + } + return 0; +} + +/** + * Returns the path which the dialog will use to filter + * the directories it shows. + * + * @return the filter path + */ +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 () { + if (OS.IsWinCE) SWT.error (SWT.ERROR_NOT_IMPLEMENTED); + + /* Initialize OLE */ + OS.OleInitialize (0); + + int hHeap = OS.GetProcessHeap (); + + /* Get the owner HWND for the dialog */ + int hwndOwner = 0; + if (parent != null) hwndOwner = parent.handle; + + /* Copy the message to OS memory */ + int lpszTitle = 0; + if (message != null && message.length () != 0) { + /* Use the character encoding for the default locale */ + TCHAR buffer = new TCHAR (0, message, true); + int byteCount = buffer.length () * TCHAR.sizeof; + lpszTitle = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + OS.MoveMemory (lpszTitle, buffer, byteCount); + } + + /* Create the BrowseCallbackProc */ + Callback callback = new Callback (this, "BrowseCallbackProc", 4); + int address = callback.getAddress (); + + /* Open the dialog */ + directoryPath = null; + BROWSEINFO lpbi = new BROWSEINFO (); + lpbi.hwndOwner = hwndOwner; + lpbi.lpszTitle = lpszTitle; + lpbi.ulFlags = OS.BIF_NEWDIALOGSTYLE | OS.BIF_RETURNONLYFSDIRS | OS.BIF_EDITBOX | OS.BIF_VALIDATE; + lpbi.lpfn = address; + int lpItemIdList = OS.SHBrowseForFolder (lpbi); + boolean success = lpItemIdList != 0; + if (success) { + /* Use the character encoding for the default locale */ + TCHAR buffer = new TCHAR (0, 256); + if (OS.SHGetPathFromIDList (lpItemIdList, buffer)) { + directoryPath = buffer.toString (0, buffer.strlen ()); + filterPath = directoryPath; + } + } + + /* Free the BrowseCallbackProc */ + callback.dispose (); + + /* Free the OS memory */ + if (lpszTitle != 0) OS.HeapFree (hHeap, 0, lpszTitle); + + /* Free the pointer to the ITEMIDLIST */ + int [] ppMalloc = new int [1]; + if (OS.SHGetMalloc (ppMalloc) == OS.S_OK) { + /* void Free (struct IMalloc *this, void *pv); */ + OS.VtblCall (5, ppMalloc [0], lpItemIdList); + } + + /* Uninitialize OLE */ + OS.OleUninitialize (); + + /* + * This code is intentionally commented. On some + * platforms, the owner window is repainted right + * away when a dialog window exits. This behavior + * is currently unspecified. + */ +// if (hwndOwner != 0) OS.UpdateWindow (hwndOwner); + + /* Return the directory path */ + if (!success) return null; + return directoryPath; +} + +/** + * Sets the path which the dialog will use to filter + * the directories it shows to the argument, which may be + * null. + * + * @param string the filter path + */ +public void setFilterPath (String string) { + filterPath = string; +} + +/** + * 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 + */ +public void setMessage (String string) { + message = string; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java index 322fce35d9..37b27ba529 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java @@ -1,2333 +1,2333 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.*;
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-
-/**
- * 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</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 #dispose
- */
-
-public class Display extends Device {
-
- /**
- * the handle to the OS message queue
- * (Warning: This field is platform dependent)
- */
- public MSG msg = new MSG ();
-
- /* Windows and Events */
- Event [] eventQueue;
- Callback windowCallback;
- int windowProc, threadId, processId;
- TCHAR windowClass;
- static int WindowClassCount = 0;
- static final String WindowName = "SWT_Window";
- EventTable eventTable, filterTable;
-
- /* Message Filter */
- Callback msgFilterCallback;
- int msgFilterProc, hHook;
- MSG hookMsg = new MSG ();
-
- /* Sync/Async Widget Communication */
- Synchronizer synchronizer = new Synchronizer (this);
- Thread thread;
-
- /* Display Shutdown */
- Runnable [] disposeList;
-
- /* Timers */
- int timerCount;
- int [] timerIds;
- Runnable [] timerList;
-
- /* Keyboard and Mouse State */
- boolean lockActiveWindow;
- boolean lastVirtual, lastNull;
- int lastKey, lastAscii, lastMouse;
- byte [] keyboard = new byte [256];
- boolean accelKeyHit, mnemonicKeyHit;
-
- /* Message Only Window */
- int hwndMessage, messageProc;
- Callback messageCallback;
- int [] systemFonts;
-
- /* Image list cache */
- ImageList[] imageList, toolImageList, toolHotImageList, toolDisabledImageList;
-
- /* Custom Colors for ChooseColor */
- int lpCustColors;
-
- /* Display Data */
- Object data;
- String [] keys;
- Object [] values;
-
- /* Bar and Popup Menus */
- Menu [] bars, popups;
-
- /* Key Mappings */
- static final int [] [] KeyTable = {
-
- /* Keyboard and Mouse Masks */
- {OS.VK_MENU, SWT.ALT},
- {OS.VK_SHIFT, SWT.SHIFT},
- {OS.VK_CONTROL, SWT.CONTROL},
-
- /* NOT CURRENTLY USED */
-// {OS.VK_LBUTTON, SWT.BUTTON1},
-// {OS.VK_MBUTTON, SWT.BUTTON3},
-// {OS.VK_RBUTTON, SWT.BUTTON2},
-
- /* Non-Numeric Keypad Keys */
- {OS.VK_UP, SWT.ARROW_UP},
- {OS.VK_DOWN, SWT.ARROW_DOWN},
- {OS.VK_LEFT, SWT.ARROW_LEFT},
- {OS.VK_RIGHT, SWT.ARROW_RIGHT},
- {OS.VK_PRIOR, SWT.PAGE_UP},
- {OS.VK_NEXT, SWT.PAGE_DOWN},
- {OS.VK_HOME, SWT.HOME},
- {OS.VK_END, SWT.END},
- {OS.VK_INSERT, SWT.INSERT},
-
- /* Virtual and Ascii Keys */
- {OS.VK_BACK, SWT.BS},
- {OS.VK_RETURN, SWT.CR},
- {OS.VK_DELETE, SWT.DEL},
- {OS.VK_ESCAPE, SWT.ESC},
- {OS.VK_RETURN, SWT.LF},
- {OS.VK_TAB, SWT.TAB},
-
- /* Functions Keys */
- {OS.VK_F1, SWT.F1},
- {OS.VK_F2, SWT.F2},
- {OS.VK_F3, SWT.F3},
- {OS.VK_F4, SWT.F4},
- {OS.VK_F5, SWT.F5},
- {OS.VK_F6, SWT.F6},
- {OS.VK_F7, SWT.F7},
- {OS.VK_F8, SWT.F8},
- {OS.VK_F9, SWT.F9},
- {OS.VK_F10, SWT.F10},
- {OS.VK_F11, SWT.F11},
- {OS.VK_F12, SWT.F12},
-
- /* Numeric Keypad Keys */
-// {OS.VK_ADD, SWT.KP_PLUS},
-// {OS.VK_SUBTRACT, SWT.KP_MINUS},
-// {OS.VK_MULTIPLY, SWT.KP_TIMES},
-// {OS.VK_DIVIDE, SWT.KP_DIVIDE},
-// {OS.VK_DECIMAL, SWT.KP_DECIMAL},
-// {OS.VK_RETURN, SWT.KP_CR},
-// {OS.VK_NUMPAD0, SWT.KP_0},
-// {OS.VK_NUMPAD1, SWT.KP_1},
-// {OS.VK_NUMPAD2, SWT.KP_2},
-// {OS.VK_NUMPAD3, SWT.KP_3},
-// {OS.VK_NUMPAD4, SWT.KP_4},
-// {OS.VK_NUMPAD5, SWT.KP_5},
-// {OS.VK_NUMPAD6, SWT.KP_6},
-// {OS.VK_NUMPAD7, SWT.KP_7},
-// {OS.VK_NUMPAD8, SWT.KP_8},
-// {OS.VK_NUMPAD9, SWT.KP_9},
-
- };
-
- /* Multiple Displays */
- static Display Default;
- static Display [] Displays = new Display [4];
-
- /* Modality */
- Shell [] modalWidgets;
- static boolean TrimEnabled = false;
-
- /* Package Name */
- static final String PACKAGE_PREFIX = "org.eclipse.swt.widgets.";
- /*
- * This code is intentionally commented. In order
- * to support CLDC, .class cannot be used because
- * it does not compile on some Java compilers when
- * they are targeted for CLDC.
- */
-// static {
-// String name = Display.class.getName ();
-// int index = name.lastIndexOf ('.');
-// PACKAGE_PREFIX = name.substring (0, index + 1);
-// }
-
- /*
- * 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;
-}
-
-/**
- * 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 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 #getCurrent
- * @see #getDefault
- * @see Widget#checkSubclass
- * @see Shell
- */
-public Display () {
- this (null);
-}
-
-public Display (DeviceData data) {
- super (data);
-}
-
-int asciiKey (int key) {
- if (OS.IsWinCE) return 0;
-
- /* Get the current keyboard. */
- for (int i=0; i<keyboard.length; i++) keyboard [i] = 0;
- if (!OS.GetKeyboardState (keyboard)) return 0;
-
- /* Translate the key to ASCII or UNICODE using the virtual keyboard */
- if (OS.IsUnicode) {
- char [] result = new char [1];
- if (OS.ToUnicode (key, key, keyboard, result, 1, 0) == 1) return result [0];
- } else {
- short [] result = new short [1];
- if (OS.ToAscii (key, key, keyboard, result, 0) == 1) return result [0];
- }
- return 0;
-}
-
-/**
- * Adds the listener to the collection of listeners who will
- * be notifed when an event of the given type occurs anywhere
- * in SWT. When the event does occur, 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>
- * </ul>
- *
- * @see Listener
- * @see #removeFilter
- * @see #removeListener
- *
- * @since 2.1
- */
-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 notifed when an event of the given type occurs. 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>
- * </ul>
- *
- * @see Listener
- * @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 addBar (Menu menu) {
- if (bars == null) bars = new Menu [4];
- int length = bars.length;
- for (int i=0; i<length; i++) {
- if (bars [i] == menu) return;
- }
- int index = 0;
- while (index < length) {
- if (bars [index] == null) break;
- index++;
- }
- if (index == length) {
- Menu [] newBars = new Menu [length + 4];
- System.arraycopy (bars, 0, newBars, 0, length);
- bars = newBars;
- }
- bars [index] = menu;
-}
-
-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;
-}
-
-/**
- * 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.
- *
- * @param runnable code to run on the user-interface thread.
- *
- * @see #syncExec
- */
-public void asyncExec (Runnable runnable) {
- if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
- synchronizer.asyncExec (runnable);
-}
-
-/**
- * Causes the system hardware to emit a short sound
- * (if it supports this capability).
- */
-public void beep () {
- checkDevice ();
- OS.MessageBeep (OS.MB_OK);
-}
-
-/**
- * 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 (!isValidClass (getClass ())) error (SWT.ERROR_INVALID_SUBCLASS);
-}
-
-protected void checkDevice () {
- if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
- if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
-}
-
-static synchronized void checkDisplay (Thread thread) {
- for (int i=0; i<Displays.length; i++) {
- if (Displays [i] != null && Displays [i].thread == thread) {
- SWT.error (SWT.ERROR_THREAD_INVALID_ACCESS);
- }
- }
-}
-
-void clearModal (Shell shell) {
- if (modalWidgets == null) return;
- int index = 0, length = modalWidgets.length;
- while (index < length) {
- if (modalWidgets [index] == shell) break;
- if (modalWidgets [index] == null) return;
- index++;
- }
- if (index == length) return;
- System.arraycopy (modalWidgets, index + 1, modalWidgets, index, --length - index);
- modalWidgets [length] = null;
- if (index == 0 && modalWidgets [0] == null) modalWidgets = null;
- Shell [] shells = getShells ();
- for (int i=0; i<shells.length; i++) shells [i].updateModal ();
-}
-
-int controlKey (int key) {
- int upper = OS.CharUpper ((short) key);
- if (64 <= upper && upper <= 95) return upper & 0xBF;
- return key;
-}
-
-/**
- * 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>
- * </ul>
- *
- * @see #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 ());
- createDisplay (data);
- register (this);
- if (Default == null) Default = this;
-}
-
-void createDisplay (DeviceData data) {
-}
-
-static synchronized void deregister (Display display) {
- 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 #dispose
- * @see #release
- */
-protected void destroy () {
- if (this == Default) Default = null;
- deregister (this);
- destroyDisplay ();
-}
-
-void destroyDisplay () {
-}
-
-/**
- * Causes the <code>run()</code> method of the runnable to
- * be invoked by the user-interface thread just before the
- * receiver is disposed.
- *
- * @param runnable code to run at dispose time.
- */
-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 drawMenuBars () {
- if (bars == null) return;
- for (int i=0; i<bars.length; i++) {
- Menu menu = bars [i];
- if (menu != null && !menu.isDisposed ()) menu.update ();
- }
- bars = null;
-}
-
-/**
- * Does whatever display specific cleanup is required, and then
- * uses the code in <code>SWTError.error</code> to handle the error.
- *
- * @param code the descriptive error code
- *
- * @see SWTError#error
- */
-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);
-}
-
-boolean filterMessage (MSG msg) {
- int message = msg.message;
- if (OS.WM_KEYFIRST <= message && message <= OS.WM_KEYLAST) {
- Control control = findControl (msg.hwnd);
- if (control != null) {
- if (translateAccelerator (msg, control) || translateMnemonic (msg, control) || translateTraversal (msg, control)) {
- lastAscii = lastKey = 0;
- lastVirtual = lastNull = false;
- return true;
- }
- }
- }
- return false;
-}
-
-/**
- * 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.
- *
- * @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>
- * </ul>
- */
-public Widget findWidget (int handle) {
- checkDevice ();
- return WidgetTable.get (handle);
-}
-
-Control findControl(int handle) {
- if (handle == 0) return null;
- /*
- * This code is intentionally commented. It is possible
- * find the SWT control that is associated with a handle
- * that belongs to another process when the handle was
- * created by an in-proc OLE client. In this case, the
- * handle comes from another process, but it is a child
- * of an SWT control. For now, it is necessary to look
- * at handles that do not belong to the SWT process.
- */
-// int [] hwndProcessId = new int [1];
-// OS.GetWindowThreadProcessId (handle, hwndProcessId);
-// if (hwndProcessId [0] != processId) return null;
- do {
- Control control = WidgetTable.get (handle);
- if (control != null && control.handle == handle) {
- return control;
- }
- } while ((handle = OS.GetParent (handle)) != 0);
- 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.
- *
- * @param thread the user-interface thread
- * @return the display for the given thread
- */
-public static synchronized Display findDisplay (Thread thread) {
- 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>
- * </ul>
- */
-public Shell getActiveShell () {
- checkDevice ();
- Control control = findControl (OS.GetActiveWindow ());
- if (control instanceof Shell) return (Shell) control;
- return null;
-}
-
-/**
- * Returns a rectangle describing the receiver's size and location.
- *
- * @return the bounding rectangle
- *
- * @exception SWTException <ul>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- */
-public Rectangle getBounds () {
- checkDevice ();
- if (OS.GetSystemMetrics (OS.SM_CMONITORS) < 2) {
- int width = OS.GetSystemMetrics (OS.SM_CXSCREEN);
- int height = OS.GetSystemMetrics (OS.SM_CYSCREEN);
- return new Rectangle (0, 0, width, height);
- }
- int x = OS.GetSystemMetrics (OS.SM_XVIRTUALSCREEN);
- int y = OS.GetSystemMetrics (OS.SM_YVIRTUALSCREEN);
- int width = OS.GetSystemMetrics (OS.SM_CXVIRTUALSCREEN);
- int height = OS.GetSystemMetrics (OS.SM_CYVIRTUALSCREEN);
- return new Rectangle (x, y, width, height);
-}
-
-/**
- * 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 synchronized Display getCurrent () {
- return findDisplay (Thread.currentThread ());
-}
-
-public Rectangle getClientArea () {
- checkDevice ();
- if (OS.GetSystemMetrics (OS.SM_CMONITORS) < 2) {
- RECT rect = new RECT ();
- OS.SystemParametersInfo (OS.SPI_GETWORKAREA, 0, rect, 0);
- int width = rect.right - rect.left;
- int height = rect.bottom - rect.top;
- return new Rectangle (rect.left, rect.top, width, height);
- }
- int x = OS.GetSystemMetrics (OS.SM_XVIRTUALSCREEN);
- int y = OS.GetSystemMetrics (OS.SM_YVIRTUALSCREEN);
- int width = OS.GetSystemMetrics (OS.SM_CXVIRTUALSCREEN);
- int height = OS.GetSystemMetrics (OS.SM_CYVIRTUALSCREEN);
- return new Rectangle (x, y, width, 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>
- * </ul>
- */
-public Control getCursorControl () {
- checkDevice ();
- POINT pt = new POINT ();
- if (!OS.GetCursorPos (pt)) return null;
- return findControl (OS.WindowFromPoint (pt));
-}
-
-/**
- * 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>
- * </ul>
- */
-public Point getCursorLocation () {
- checkDevice ();
- POINT pt = new POINT ();
- OS.GetCursorPos (pt);
- return new Point (pt.x, pt.y);
-}
-
-/**
- * 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 synchronized Display getDefault () {
- if (Default == null) Default = new Display ();
- return Default;
-}
-
-static boolean isValidClass (Class clazz) {
- String name = clazz.getName ();
- int index = name.lastIndexOf ('.');
- return name.substring (0, index + 1).equals (PACKAGE_PREFIX);
-}
-
-/**
- * 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 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>
- * </ul>
- *
- * @see #setData
- * @see #disposeExec
- */
-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 provide a
- * <code>disposeExec()</code> handler which does so.
- * </p>
- *
- * @return the display specific data
- *
- * @exception SWTException <ul>
- * <li>ERROR_THREAD_INVALID_ACCESS - when called from the wrong thread</li>
- * </ul>
- *
- * @see #setData
- * @see #disposeExec
- */
-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>
- * </ul>
- *
- * @since 2.1
- */
-public int getDismissalAlignment () {
- checkDevice ();
- return SWT.LEFT;
-}
-
-
-/**
- * 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>
- * </ul>
- */
-public int getDoubleClickTime () {
- checkDevice ();
- return OS.GetDoubleClickTime ();
-}
-
-/**
- * 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>
- * </ul>
- */
-public Control getFocusControl () {
- checkDevice ();
- return findControl (OS.GetFocus ());
-}
-
-/**
- * Returns the maximum allowed depth of icons on this display.
- * 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>
- * </ul>
- */
-public int getIconDepth () {
- checkDevice ();
-
- /* Use the character encoding for the default locale */
- TCHAR buffer1 = new TCHAR (0, "Control Panel\\Desktop\\WindowMetrics", true);
-
- int [] phkResult = new int [1];
- int result = OS.RegOpenKeyEx (OS.HKEY_CURRENT_USER, buffer1, 0, OS.KEY_READ, phkResult);
- if (result != 0) return 4;
- int depth = 4;
- int [] lpcbData = {128};
-
- /* Use the character encoding for the default locale */
- TCHAR lpData = new TCHAR (0, lpcbData [0]);
- TCHAR buffer2 = new TCHAR (0, "Shell Icon BPP", true);
-
- result = OS.RegQueryValueEx (phkResult [0], buffer2, 0, null, lpData, lpcbData);
- if (result == 0) {
- try {
- depth = Integer.parseInt (lpData.toString (0, lpData.strlen ()));
- } catch (NumberFormatException e) {};
- }
- OS.RegCloseKey (phkResult [0]);
- return depth;
-}
-
-ImageList getImageList (Point size) {
- if (imageList == null) imageList = new ImageList [4];
-
- int i = 0;
- int length = imageList.length;
- while (i < length) {
- ImageList list = imageList [i];
- if (list == null) break;
- if (list.getImageSize().equals(size)) {
- list.addRef();
- return list;
- }
- i++;
- }
-
- if (i == length) {
- ImageList [] newList = new ImageList [length + 4];
- System.arraycopy (imageList, 0, newList, 0, length);
- imageList = newList;
- }
-
- ImageList list = new ImageList();
- imageList [i] = list;
- list.addRef();
- return list;
-}
-
-ImageList getToolImageList (Point size) {
- if (toolImageList == null) toolImageList = new ImageList [4];
-
- int i = 0;
- int length = toolImageList.length;
- while (i < length) {
- ImageList list = toolImageList [i];
- if (list == null) break;
- if (list.getImageSize().equals(size)) {
- list.addRef();
- return list;
- }
- i++;
- }
-
- if (i == length) {
- ImageList [] newList = new ImageList [length + 4];
- System.arraycopy (toolImageList, 0, newList, 0, length);
- toolImageList = newList;
- }
-
- ImageList list = new ImageList();
- toolImageList [i] = list;
- list.addRef();
- return list;
-}
-
-ImageList getToolHotImageList (Point size) {
- if (toolHotImageList == null) toolHotImageList = new ImageList [4];
-
- int i = 0;
- int length = toolHotImageList.length;
- while (i < length) {
- ImageList list = toolHotImageList [i];
- if (list == null) break;
- if (list.getImageSize().equals(size)) {
- list.addRef();
- return list;
- }
- i++;
- }
-
- if (i == length) {
- ImageList [] newList = new ImageList [length + 4];
- System.arraycopy (toolHotImageList, 0, newList, 0, length);
- toolHotImageList = newList;
- }
-
- ImageList list = new ImageList();
- toolHotImageList [i] = list;
- list.addRef();
- return list;
-}
-
-ImageList getToolDisabledImageList (Point size) {
- if (toolDisabledImageList == null) toolDisabledImageList = new ImageList [4];
-
- int i = 0;
- int length = toolDisabledImageList.length;
- while (i < length) {
- ImageList list = toolDisabledImageList [i];
- if (list == null) break;
- if (list.getImageSize().equals(size)) {
- list.addRef();
- return list;
- }
- i++;
- }
-
- if (i == length) {
- ImageList [] newList = new ImageList [length + 4];
- System.arraycopy (toolDisabledImageList, 0, newList, 0, length);
- toolDisabledImageList = newList;
- }
-
- ImageList list = new ImageList();
- toolDisabledImageList [i] = list;
- list.addRef();
- return list;
-}
-
-Shell getModalShell () {
- if (modalWidgets == null) return null;
- int index = modalWidgets.length;
- while (--index >= 0) {
- Shell shell = modalWidgets [index];
- if (shell != null) return shell;
- }
- return null;
-}
-
-int getLastEventTime () {
- return OS.IsWinCE ? OS.GetTickCount () : OS.GetMessageTime ();
-}
-
-/**
- * Returns an 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>
- * </ul>
- */
-public Shell [] getShells () {
- checkDevice ();
- /*
- * NOTE: Need to check that the shells that belong
- * to another display have not been disposed by the
- * other display's thread as the shells list is being
- * processed.
- */
- int count = 0;
- Shell [] shells = WidgetTable.shells ();
- for (int i=0; i<shells.length; i++) {
- Shell shell = shells [i];
- if (!shell.isDisposed () && this == shell.getDisplay ()) {
- count++;
- }
- }
- if (count == shells.length) return shells;
- int index = 0;
- Shell [] result = new Shell [count];
- for (int i=0; i<shells.length; i++) {
- Shell shell = shells [i];
- if (!shell.isDisposed () && this == shell.getDisplay ()) {
- result [index++] = shell;
- }
- }
- return result;
-}
-
-/**
- * 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
- */
-public Thread getSyncThread () {
- 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>
- * </ul>
- *
- * @see SWT
- */
-public Color getSystemColor (int id) {
- checkDevice ();
- int pixel = 0x02000000;
- switch (id) {
- case SWT.COLOR_WIDGET_DARK_SHADOW: pixel = OS.GetSysColor (OS.COLOR_3DDKSHADOW); break;
- case SWT.COLOR_WIDGET_NORMAL_SHADOW: pixel = OS.GetSysColor (OS.COLOR_3DSHADOW); break;
- case SWT.COLOR_WIDGET_LIGHT_SHADOW: pixel = OS.GetSysColor (OS.COLOR_3DLIGHT); break;
- case SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW: pixel = OS.GetSysColor (OS.COLOR_3DHIGHLIGHT); break;
- case SWT.COLOR_WIDGET_BACKGROUND: pixel = OS.GetSysColor (OS.COLOR_3DFACE); break;
- case SWT.COLOR_WIDGET_BORDER: pixel = OS.GetSysColor (OS.COLOR_WINDOWFRAME); break;
- case SWT.COLOR_WIDGET_FOREGROUND:
- case SWT.COLOR_LIST_FOREGROUND: pixel = OS.GetSysColor (OS.COLOR_WINDOWTEXT); break;
- case SWT.COLOR_LIST_BACKGROUND: pixel = OS.GetSysColor (OS.COLOR_WINDOW); break;
- case SWT.COLOR_LIST_SELECTION: pixel = OS.GetSysColor (OS.COLOR_HIGHLIGHT); break;
- case SWT.COLOR_LIST_SELECTION_TEXT: pixel = OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT);break;
- case SWT.COLOR_INFO_FOREGROUND: pixel = OS.GetSysColor (OS.COLOR_INFOTEXT); break;
- case SWT.COLOR_INFO_BACKGROUND: pixel = OS.GetSysColor (OS.COLOR_INFOBK); break;
- case SWT.COLOR_TITLE_FOREGROUND: pixel = OS.GetSysColor (OS.COLOR_CAPTIONTEXT); break;
- case SWT.COLOR_TITLE_BACKGROUND: pixel = OS.GetSysColor (OS.COLOR_ACTIVECAPTION); break;
- case SWT.COLOR_TITLE_BACKGROUND_GRADIENT:
- pixel = OS.GetSysColor (OS.COLOR_GRADIENTACTIVECAPTION);
- if (pixel == 0) pixel = OS.GetSysColor (OS.COLOR_ACTIVECAPTION);
- break;
- case SWT.COLOR_TITLE_INACTIVE_FOREGROUND: pixel = OS.GetSysColor (OS.COLOR_INACTIVECAPTIONTEXT); break;
- case SWT.COLOR_TITLE_INACTIVE_BACKGROUND: pixel = OS.GetSysColor (OS.COLOR_INACTIVECAPTION); break;
- case SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT:
- pixel = OS.GetSysColor (OS.COLOR_GRADIENTINACTIVECAPTION);
- if (pixel == 0) pixel = OS.GetSysColor (OS.COLOR_INACTIVECAPTION);
- break;
- default:
- return super.getSystemColor (id);
- }
- return Color.win32_new (this, pixel);
-}
-
-/**
- * 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 free'd 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_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- */
-public Font getSystemFont () {
- checkDevice ();
- int hFont = systemFont ();
- return Font.win32_new (this, hFont);
-}
-
-/**
- * Returns the user-interface thread for the receiver.
- *
- * @return the receiver's user-interface thread
- */
-public Thread getThread () {
- if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
- return thread;
-}
-
-/**
- * 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
- *
- * @private
- */
-public int internal_new_GC (GCData data) {
- if (isDisposed()) SWT.error(SWT.ERROR_DEVICE_DISPOSED);
- int hDC = OS.GetDC (0);
- if (hDC == 0) SWT.error (SWT.ERROR_NO_HANDLES);
- if (data != null) {
- data.device = this;
- data.hFont = systemFont ();
- }
- return hDC;
-}
-
-/**
- * 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 ();
-
- /* Create the callbacks */
- windowCallback = new Callback (this, "windowProc", 4);
- windowProc = windowCallback.getAddress ();
- if (windowProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
-
- /* Remember the current procsss and thread */
- threadId = OS.GetCurrentThreadId ();
- processId = OS.GetCurrentProcessId ();
-
- /* Use the character encoding for the default locale */
- windowClass = new TCHAR (0, WindowName + WindowClassCount++, true);
-
- /* Register the SWT window class */
- int hHeap = OS.GetProcessHeap ();
- int hInstance = OS.GetModuleHandle (null);
- WNDCLASS lpWndClass = new WNDCLASS ();
- lpWndClass.hInstance = hInstance;
- lpWndClass.lpfnWndProc = windowProc;
- lpWndClass.style = OS.CS_BYTEALIGNWINDOW | OS.CS_DBLCLKS;
- lpWndClass.hCursor = OS.LoadCursor (0, OS.IDC_ARROW);
- int byteCount = windowClass.length () * TCHAR.sizeof;
- int lpszClassName = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- lpWndClass.lpszClassName = lpszClassName;
- OS.MoveMemory (lpszClassName, windowClass, byteCount);
- OS.RegisterClass (lpWndClass);
-
- /* Initialize the system font */
- int systemFont = 0;
- if (!OS.IsWinCE) {
- NONCLIENTMETRICS info = new NONCLIENTMETRICS ();
- info.cbSize = NONCLIENTMETRICS.sizeof;
- if (OS.SystemParametersInfo (OS.SPI_GETNONCLIENTMETRICS, 0, info, 0)) {
- systemFont = OS.CreateFontIndirect (info.lfMessageFont);
- }
- }
- if (systemFont == 0) systemFont = OS.GetStockObject (OS.DEFAULT_GUI_FONT);
- if (systemFont == 0) systemFont = OS.GetStockObject (OS.SYSTEM_FONT);
- if (systemFont != 0) systemFonts = new int [] {systemFont};
-
- /* Create the message only HWND */
- hwndMessage = OS.CreateWindowEx (0,
- windowClass,
- null,
- OS.WS_OVERLAPPED,
- 0, 0, 0, 0,
- 0,
- 0,
- hInstance,
- null);
- messageCallback = new Callback (this, "messageProc", 4);
- messageProc = messageCallback.getAddress ();
- if (messageProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
- OS.SetWindowLong (hwndMessage, OS.GWL_WNDPROC, messageProc);
-
- /* Create the message filter hook */
- if (!OS.IsWinCE) {
- msgFilterCallback = new Callback (this, "msgFilterProc", 3);
- msgFilterProc = msgFilterCallback.getAddress ();
- if (msgFilterProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
- hHook = OS.SetWindowsHookEx (OS.WH_MSGFILTER, msgFilterProc, 0, threadId);
- }
-}
-
-/**
- * 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 handle the platform specific GC handle
- * @param data the platform specific GC data
- *
- * @private
- */
-public void internal_dispose_GC (int hDC, GCData data) {
- OS.ReleaseDC (0, hDC);
-}
-
-boolean isWakeMessage (MSG msg) {
- return msg.hwnd == hwndMessage && msg.message == OS.WM_NULL;
-}
-
-boolean isValidThread () {
- return thread == Thread.currentThread ();
-}
-
-boolean isVirtualKey (int key) {
- switch (key) {
- case OS.VK_TAB:
- case OS.VK_RETURN:
- case OS.VK_BACK:
- case OS.VK_ESCAPE:
-// case OS.VK_DELETE:
- case OS.VK_SPACE:
- case OS.VK_MENU:
- case OS.VK_SHIFT:
- case OS.VK_CONTROL: return true;
- }
- return false;
-}
-
-int messageProc (int hwnd, int msg, int wParam, int lParam) {
- switch (msg) {
- case OS.WM_ACTIVATEAPP:
- /*
- * Feature in Windows. When multiple shells are
- * disabled and one of the shells has an enabled
- * dialog child and the user selects a disabled
- * shell that does not have the enabled dialog
- * child using the Task bar, Windows brings the
- * disabled shell to the front. As soon as the
- * user clicks on the disabled shell, the enabled
- * dialog child comes to the front. This behavior
- * is unspecified and seems strange. Normally, a
- * disabled shell is frozen on the screen and the
- * user cannot change the z-order by clicking with
- * the mouse. The fix is to look for WM_ACTIVATEAPP
- * and force the enabled dialog child to the front.
- * This is typically what the user is expecting.
- */
- if (wParam != 0) {
- Shell shell = getModalShell ();
- if (shell != null) shell.bringToTop ();
- }
- break;
- case OS.WM_ENDSESSION:
- if (wParam != 0) dispose ();
- break;
- case OS.WM_NULL:
- runAsyncMessages ();
- break;
- case OS.WM_QUERYENDSESSION:
- Event event = new Event ();
- sendEvent (SWT.Close, event);
- if (!event.doit) return 0;
- break;
- case OS.WM_SETTINGCHANGE:
- updateFont ();
- break;
- case OS.WM_TIMER:
- runTimer (wParam);
- break;
- }
- return OS.DefWindowProc (hwnd, msg, wParam, lParam);
-}
-
-int msgFilterProc (int code, int wParam, int lParam) {
- if (code >= 0) {
- OS.MoveMemory (hookMsg, lParam, MSG.sizeof);
- if (hookMsg.message == OS.WM_NULL) runAsyncMessages ();
- }
- return OS.CallNextHookEx (hHook, code, wParam, lParam);
-}
-
-int numpadKey (int key) {
- switch (key) {
- case OS.VK_NUMPAD0: return '0';
- case OS.VK_NUMPAD1: return '1';
- case OS.VK_NUMPAD2: return '2';
- case OS.VK_NUMPAD3: return '3';
- case OS.VK_NUMPAD4: return '4';
- case OS.VK_NUMPAD5: return '5';
- case OS.VK_NUMPAD6: return '6';
- case OS.VK_NUMPAD7: return '7';
- case OS.VK_NUMPAD8: return '8';
- case OS.VK_NUMPAD9: return '9';
- case OS.VK_MULTIPLY: return '*';
- case OS.VK_ADD: return '+';
- case OS.VK_SEPARATOR: return '\0';
- case OS.VK_SUBTRACT: return '-';
- case OS.VK_DECIMAL: return '.';
- case OS.VK_DIVIDE: return '/';
- }
- return 0;
-}
-
-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;
-}
-
-/**
- * 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>
- * </ul>
- *
- * @see #sleep
- * @see #wake
- */
-public boolean readAndDispatch () {
- checkDevice ();
- drawMenuBars ();
- runPopups ();
- if (OS.PeekMessage (msg, 0, 0, 0, OS.PM_REMOVE)) {
- if (!isWakeMessage (msg)) {
- if (!filterMessage (msg)) {
- OS.TranslateMessage (msg);
- OS.DispatchMessage (msg);
- }
- runDeferredEvents ();
- return true;
- }
- }
- return runAsyncMessages ();
-}
-
-static synchronized void register (Display display) {
- 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 #dispose
- * @see #destroy
- */
-protected void release () {
- sendEvent (SWT.Dispose, new Event ());
- Shell [] shells = WidgetTable.shells ();
- for (int i=0; i<shells.length; i++) {
- Shell shell = shells [i];
- if (!shell.isDisposed ()) {
- if (this == shell.getDisplay ()) shell.dispose ();
- }
- }
- 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 () {
-
- /* Unhook the message hook */
- if (!OS.IsWinCE) {
- if (hHook != 0) OS.UnhookWindowsHookEx (hHook);
- hHook = 0;
- msgFilterCallback.dispose ();
- msgFilterCallback = null;
- msgFilterProc = 0;
- }
-
- /* Destroy the message only HWND */
- if (hwndMessage != 0) OS.DestroyWindow (hwndMessage);
- hwndMessage = 0;
- messageCallback.dispose ();
- messageCallback = null;
- messageProc = 0;
-
- /* Unregister the SWT Window class */
- int hHeap = OS.GetProcessHeap ();
- int hInstance = OS.GetModuleHandle (null);
- WNDCLASS lpWndClass = new WNDCLASS ();
- OS.GetClassInfo (0, windowClass, lpWndClass);
- OS.UnregisterClass (windowClass, hInstance);
- OS.HeapFree (hHeap, 0, lpWndClass.lpszClassName);
- windowClass = null;
- windowCallback.dispose ();
- windowCallback = null;
- windowProc = 0;
-
- /* Release the system fonts */
- if (systemFonts != null) {
- for (int i=0; i<systemFonts.length; i++) {
- if (systemFonts [i] != 0) OS.DeleteObject (systemFonts [i]);
- }
- }
- systemFonts = null;
-
- /* Release Custom Colors for ChooseColor */
- if (lpCustColors != 0) OS.HeapFree (hHeap, 0, lpCustColors);
- lpCustColors = 0;
-
- /* Release references */
- thread = null;
- msg = null;
- keyboard = null;
- modalWidgets = null;
- data = null;
- keys = null;
- values = null;
-}
-
-void releaseImageList (ImageList list) {
- int i = 0;
- int length = imageList.length;
- while (i < length) {
- if (imageList [i] == list) {
- if (list.removeRef () > 0) return;
- list.dispose ();
- System.arraycopy (imageList, i + 1, imageList, i, --length - i);
- imageList [length] = null;
- for (int j=0; j<length; j++) {
- if (imageList [j] != null) return;
- }
- imageList = null;
- return;
- }
- i++;
- }
-}
-
-void releaseToolImageList (ImageList list) {
- int i = 0;
- int length = toolImageList.length;
- while (i < length) {
- if (toolImageList [i] == list) {
- if (list.removeRef () > 0) return;
- list.dispose ();
- System.arraycopy (toolImageList, i + 1, toolImageList, i, --length - i);
- toolImageList [length] = null;
- for (int j=0; j<length; j++) {
- if (toolImageList [j] != null) return;
- }
- toolImageList = null;
- return;
- }
- i++;
- }
-}
-
-void releaseToolHotImageList (ImageList list) {
- int i = 0;
- int length = toolHotImageList.length;
- while (i < length) {
- if (toolHotImageList [i] == list) {
- if (list.removeRef () > 0) return;
- list.dispose ();
- System.arraycopy (toolHotImageList, i + 1, toolHotImageList, i, --length - i);
- toolHotImageList [length] = null;
- for (int j=0; j<length; j++) {
- if (toolHotImageList [j] != null) return;
- }
- toolHotImageList = null;
- return;
- }
- i++;
- }
-}
-
-void releaseToolDisabledImageList (ImageList list) {
- int i = 0;
- int length = toolDisabledImageList.length;
- while (i < length) {
- if (toolDisabledImageList [i] == list) {
- if (list.removeRef () > 0) return;
- list.dispose ();
- System.arraycopy (toolDisabledImageList, i + 1, toolDisabledImageList, i, --length - i);
- toolDisabledImageList [length] = null;
- for (int j=0; j<length; j++) {
- if (toolDisabledImageList [j] != null) return;
- }
- toolDisabledImageList = null;
- return;
- }
- i++;
- }
-}
-
-/**
- * Removes the listener from the collection of listeners who will
- * be notifed when an event of the given type occurs anywhere in SWT.
- *
- * @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 #addFilter
- * @see #addListener
- *
- * @since 2.1
- */
-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 notifed when an event of the given type occurs.
- *
- * @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 #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);
-}
-
-void removeBar (Menu menu) {
- if (bars == null) return;
- for (int i=0; i<bars.length; i++) {
- if (bars [i] == menu) {
- bars [i] = null;
- return;
- }
- }
-}
-
-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 () {
- return synchronizer.runAsyncMessages ();
-}
-
-boolean runDeferredEvents () {
- /*
- * Run deferred events. This code is always
- * called in the Display's thread so it must
- * be re-enterant but 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 ()) {
- widget.sendEvent (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 true;
-}
-
-boolean runPopups () {
- if (popups == null) return false;
- boolean result = false;
- while (popups != null) {
- Menu menu = popups [0];
- if (menu == null) break;
- int length = popups.length;
- System.arraycopy (popups, 1, popups, 0, --length);
- popups [length] = null;
- menu._setVisible (true);
- result = true;
- }
- popups = null;
- return result;
-}
-
-boolean runTimer (int id) {
- if (timerList != null && timerIds != null) {
- int index = 0;
- while (index <timerIds.length) {
- if (timerIds [index] == id) {
- OS.KillTimer (hwndMessage, timerIds [index]);
- timerIds [index] = 0;
- Runnable runnable = timerList [index];
- timerList [index] = null;
- if (runnable != null) runnable.run ();
- return true;
- }
- index++;
- }
- }
- return false;
-}
-
-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 ();
- if (!filterEvent (event)) {
- if (eventTable != null) eventTable.sendEvent (event);
- }
-}
-
-/**
- * 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>
- * </ul>
- *
- * @since 2.1
- */
-public void setCursorLocation (int x, int y) {
- checkDevice ();
- OS.SetCursorPos (x, y);
-}
-
-/**
- * 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
- * </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>
- * </ul>
- *
- * @see #setData
- * @see #disposeExec
- */
-public void setData (String key, Object value) {
- checkDevice ();
- if (key == null) error (SWT.ERROR_NULL_ARGUMENT);
-
- /* 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;
-}
-
-/**
- * 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 - when called from the wrong thread</li>
- * </ul>
- *
- * @see #getData
- * @see #disposeExec
- */
-public void setData (Object data) {
- checkDevice ();
- this.data = data;
-}
-
-/**
- * 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.
- *
- * @param name the new app name
- */
-public static void setAppName (String name) {
- /* Do nothing */
-}
-
-void setModalShell (Shell shell) {
- if (modalWidgets == null) modalWidgets = new Shell [4];
- int index = 0, length = modalWidgets.length;
- while (index < length) {
- if (modalWidgets [index] == shell) return;
- if (modalWidgets [index] == null) break;
- index++;
- }
- if (index == length) {
- Shell [] newModalWidgets = new Shell [length + 4];
- System.arraycopy (modalWidgets, 0, newModalWidgets, 0, length);
- modalWidgets = newModalWidgets;
- }
- modalWidgets [index] = shell;
- Shell [] shells = getShells ();
- for (int i=0; i<shells.length; i++) shells [i].updateModal ();
-}
-
-/**
- * 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>
- * </ul>
- */
-public void setSynchronizer (Synchronizer synchronizer) {
- checkDevice ();
- if (synchronizer == null) error (SWT.ERROR_NULL_ARGUMENT);
- if (this.synchronizer != null) {
- this.synchronizer.runAsyncMessages();
- }
- this.synchronizer = synchronizer;
-}
-
-int shiftedKey (int key) {
- if (OS.IsWinCE) return 0;
-
- /* Clear the virtual keyboard and press the shift key */
- for (int i=0; i<keyboard.length; i++) keyboard [i] = 0;
- keyboard [OS.VK_SHIFT] |= 0x80;
-
- /* Translate the key to ASCII or UNICODE using the virtual keyboard */
- if (OS.IsUnicode) {
- char [] result = new char [1];
- if (OS.ToUnicode (key, key, keyboard, result, 1, 0) == 1) return result [0];
- } else {
- short [] result = new short [1];
- if (OS.ToAscii (key, key, keyboard, result, 0) == 1) return result [0];
- }
- return 0;
-}
-
-/**
- * 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>
- * </ul>
- *
- * @see #wake
- */
-public boolean sleep () {
- checkDevice ();
- if (OS.IsWinCE) {
- OS.MsgWaitForMultipleObjectsEx (0, 0, OS.INFINITE, OS.QS_ALLINPUT, OS.MWMO_INPUTAVAILABLE);
- return true;
- }
- return OS.WaitMessage ();
-}
-
-/**
- * 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.
- *
- * @param runnable code to run on the user-interface thread.
- *
- * @exception SWTException <ul>
- * <li>ERROR_FAILED_EXEC - if an exception occured when executing the runnable</li>
- * </ul>
- *
- * @see #asyncExec
- */
-public void syncExec (Runnable runnable) {
- if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
- synchronizer.syncExec (runnable);
-}
-
-int systemFont () {
- int hFont = 0;
- if (systemFonts != null) {
- int length = systemFonts.length;
- if (length != 0) hFont = systemFonts [length - 1];
- }
- if (hFont == 0) hFont = OS.GetStockObject (OS.DEFAULT_GUI_FONT);
- if (hFont == 0) hFont = OS.GetStockObject (OS.SYSTEM_FONT);
- return hFont;
-}
-
-/**
- * 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.
- *
- * @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>
- * </ul>
- *
- * @see #asyncExec
- */
-public void timerExec (int milliseconds, Runnable runnable) {
- checkDevice ();
- if (runnable == null) error (SWT.ERROR_NULL_ARGUMENT);
- if (timerList == null) timerList = new Runnable [4];
- if (timerIds == null) timerIds = new int [4];
- int index = 0;
- while (index < timerList.length) {
- if (timerList [index] == runnable) break;
- index++;
- }
- int timerId = 0;
- if (index != timerList.length) {
- timerId = timerIds [index];
- if (milliseconds < 0) {
- OS.KillTimer (hwndMessage, timerId);
- timerList [index] = null;
- timerIds [index] = 0;
- return;
- }
- } else {
- if (milliseconds < 0) return;
- index = 0;
- while (index < timerList.length) {
- if (timerList [index] == null) break;
- index++;
- }
- timerCount++;
- timerId = timerCount;
- if (index == timerList.length) {
- Runnable [] newTimerList = new Runnable [timerList.length + 4];
- System.arraycopy (timerList, 0, newTimerList, 0, timerList.length);
- timerList = newTimerList;
- int [] newTimerIds = new int [timerIds.length + 4];
- System.arraycopy (timerIds, 0, newTimerIds, 0, timerIds.length);
- timerIds = newTimerIds;
- }
- }
- int newTimerID = OS.SetTimer (hwndMessage, timerId, milliseconds, 0);
- if (newTimerID != 0) {
- timerList [index] = runnable;
- timerIds [index] = newTimerID;
- }
-}
-
-boolean translateAccelerator (MSG msg, Control control) {
- accelKeyHit = true;
- boolean result = control.translateAccelerator (msg);
- accelKeyHit = false;
- return result;
-}
-
-static int translateKey (int key) {
- for (int i=0; i<KeyTable.length; i++) {
- if (KeyTable [i] [0] == key) return KeyTable [i] [1];
- }
- return 0;
-}
-
-boolean translateMnemonic (MSG msg, Control control) {
- switch (msg.message) {
- case OS.WM_CHAR:
- case OS.WM_SYSCHAR:
- return control.translateMnemonic (msg);
- }
- return false;
-}
-
-boolean translateTraversal (MSG msg, Control control) {
- switch (msg.message) {
- case OS.WM_KEYDOWN:
- switch (msg.wParam) {
- case OS.VK_RETURN:
- case OS.VK_ESCAPE:
- case OS.VK_TAB:
- case OS.VK_UP:
- case OS.VK_DOWN:
- case OS.VK_LEFT:
- case OS.VK_RIGHT:
- case OS.VK_PRIOR:
- case OS.VK_NEXT:
- return control.translateTraversal (msg);
- }
- break;
- case OS.WM_SYSKEYDOWN:
- switch (msg.wParam) {
- case OS.VK_MENU:
- return control.translateTraversal (msg);
- }
- break;
- }
- return false;
-}
-
-static int untranslateKey (int key) {
- for (int i=0; i<KeyTable.length; i++) {
- if (KeyTable [i] [1] == key) return KeyTable [i] [0];
- }
- return 0;
-}
-
-/**
- * Forces all outstanding paint requests for the display
- * to be processed before this method returns.
- *
- * @see Control#update
- */
-public void update() {
- checkDevice ();
- Shell[] shells = WidgetTable.shells ();
- for (int i=0; i<shells.length; i++) {
- Shell shell = shells [i];
- if (!shell.isDisposed () && this == shell.getDisplay ()) {
- shell.update (true);
- }
- }
-}
-
-void updateFont () {
- if (OS.IsWinCE) return;
- Font oldFont = getSystemFont ();
- int systemFont = 0;
- NONCLIENTMETRICS info = new NONCLIENTMETRICS ();
- info.cbSize = NONCLIENTMETRICS.sizeof;
- if (OS.SystemParametersInfo (OS.SPI_GETNONCLIENTMETRICS, 0, info, 0)) {
- systemFont = OS.CreateFontIndirect (info.lfMessageFont);
- }
- if (systemFont == 0) systemFont = OS.GetStockObject (OS.DEFAULT_GUI_FONT);
- if (systemFont == 0) systemFont = OS.GetStockObject (OS.SYSTEM_FONT);
- if (systemFont == 0) return;
- int length = systemFonts == null ? 0 : systemFonts.length;
- int [] newFonts = new int [length + 1];
- if (systemFonts != null) {
- System.arraycopy (systemFonts, 0, newFonts, 0, length);
- }
- newFonts [length] = systemFont;
- systemFonts = newFonts;
- Font newFont = getSystemFont ();
- Shell [] shells = getShells ();
- for (int i=0; i<shells.length; i++) {
- Shell shell = shells [i];
- if (!shell.isDisposed ()) {
- shell.updateFont (oldFont, newFont);
- }
- }
-}
-
-/**
- * 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.
- *
- * @see #sleep
- */
-public void wake () {
- if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
- if (thread == Thread.currentThread ()) return;
- if (OS.IsWinCE) {
- OS.PostMessage (hwndMessage, OS.WM_NULL, 0, 0);
- } else {
- OS.PostThreadMessage (threadId, OS.WM_NULL, 0, 0);
- }
-}
-
-int windowProc (int hwnd, int msg, int wParam, int lParam) {
- Control control = WidgetTable.get (hwnd);
- if (control != null) {
- return control.windowProc (msg, wParam, lParam);
- }
- return OS.DefWindowProc (hwnd, msg, wParam, lParam);
-}
-
-static String withCrLf (String string) {
-
- /* If the string is empty, return the string. */
- int length = string.length ();
- if (length == 0) return string;
-
- /*
- * Check for an LF or CR/LF and assume the rest of
- * the string is formated that way. This will not
- * work if the string contains mixed delimiters.
- */
- int i = string.indexOf ('\n', 0);
- if (i == -1) return string;
- if (i > 0 && string.charAt (i - 1) == '\r') {
- return string;
- }
-
- /*
- * The string is formatted with LF. Compute the
- * number of lines and the size of the buffer
- * needed to hold the result
- */
- i++;
- int count = 1;
- while (i < length) {
- if ((i = string.indexOf ('\n', i)) == -1) break;
- count++; i++;
- }
- count += length;
-
- /* Create a new string with the CR/LF line terminator. */
- i = 0;
- StringBuffer result = new StringBuffer (count);
- while (i < length) {
- int j = string.indexOf ('\n', i);
- if (j == -1) j = length;
- result.append (string.substring (i, j));
- if ((i = j) < length) {
- result.append ("\r\n");
- i++;
- }
- }
- return result.toString ();
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; + +/** + * 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</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 #dispose + */ + +public class Display extends Device { + + /** + * the handle to the OS message queue + * (Warning: This field is platform dependent) + */ + public MSG msg = new MSG (); + + /* Windows and Events */ + Event [] eventQueue; + Callback windowCallback; + int windowProc, threadId, processId; + TCHAR windowClass; + static int WindowClassCount = 0; + static final String WindowName = "SWT_Window"; + EventTable eventTable, filterTable; + + /* Message Filter */ + Callback msgFilterCallback; + int msgFilterProc, hHook; + MSG hookMsg = new MSG (); + + /* Sync/Async Widget Communication */ + Synchronizer synchronizer = new Synchronizer (this); + Thread thread; + + /* Display Shutdown */ + Runnable [] disposeList; + + /* Timers */ + int timerCount; + int [] timerIds; + Runnable [] timerList; + + /* Keyboard and Mouse State */ + boolean lockActiveWindow; + boolean lastVirtual, lastNull; + int lastKey, lastAscii, lastMouse; + byte [] keyboard = new byte [256]; + boolean accelKeyHit, mnemonicKeyHit; + + /* Message Only Window */ + int hwndMessage, messageProc; + Callback messageCallback; + int [] systemFonts; + + /* Image list cache */ + ImageList[] imageList, toolImageList, toolHotImageList, toolDisabledImageList; + + /* Custom Colors for ChooseColor */ + int lpCustColors; + + /* Display Data */ + Object data; + String [] keys; + Object [] values; + + /* Bar and Popup Menus */ + Menu [] bars, popups; + + /* Key Mappings */ + static final int [] [] KeyTable = { + + /* Keyboard and Mouse Masks */ + {OS.VK_MENU, SWT.ALT}, + {OS.VK_SHIFT, SWT.SHIFT}, + {OS.VK_CONTROL, SWT.CONTROL}, + + /* NOT CURRENTLY USED */ +// {OS.VK_LBUTTON, SWT.BUTTON1}, +// {OS.VK_MBUTTON, SWT.BUTTON3}, +// {OS.VK_RBUTTON, SWT.BUTTON2}, + + /* Non-Numeric Keypad Keys */ + {OS.VK_UP, SWT.ARROW_UP}, + {OS.VK_DOWN, SWT.ARROW_DOWN}, + {OS.VK_LEFT, SWT.ARROW_LEFT}, + {OS.VK_RIGHT, SWT.ARROW_RIGHT}, + {OS.VK_PRIOR, SWT.PAGE_UP}, + {OS.VK_NEXT, SWT.PAGE_DOWN}, + {OS.VK_HOME, SWT.HOME}, + {OS.VK_END, SWT.END}, + {OS.VK_INSERT, SWT.INSERT}, + + /* Virtual and Ascii Keys */ + {OS.VK_BACK, SWT.BS}, + {OS.VK_RETURN, SWT.CR}, + {OS.VK_DELETE, SWT.DEL}, + {OS.VK_ESCAPE, SWT.ESC}, + {OS.VK_RETURN, SWT.LF}, + {OS.VK_TAB, SWT.TAB}, + + /* Functions Keys */ + {OS.VK_F1, SWT.F1}, + {OS.VK_F2, SWT.F2}, + {OS.VK_F3, SWT.F3}, + {OS.VK_F4, SWT.F4}, + {OS.VK_F5, SWT.F5}, + {OS.VK_F6, SWT.F6}, + {OS.VK_F7, SWT.F7}, + {OS.VK_F8, SWT.F8}, + {OS.VK_F9, SWT.F9}, + {OS.VK_F10, SWT.F10}, + {OS.VK_F11, SWT.F11}, + {OS.VK_F12, SWT.F12}, + + /* Numeric Keypad Keys */ +// {OS.VK_ADD, SWT.KP_PLUS}, +// {OS.VK_SUBTRACT, SWT.KP_MINUS}, +// {OS.VK_MULTIPLY, SWT.KP_TIMES}, +// {OS.VK_DIVIDE, SWT.KP_DIVIDE}, +// {OS.VK_DECIMAL, SWT.KP_DECIMAL}, +// {OS.VK_RETURN, SWT.KP_CR}, +// {OS.VK_NUMPAD0, SWT.KP_0}, +// {OS.VK_NUMPAD1, SWT.KP_1}, +// {OS.VK_NUMPAD2, SWT.KP_2}, +// {OS.VK_NUMPAD3, SWT.KP_3}, +// {OS.VK_NUMPAD4, SWT.KP_4}, +// {OS.VK_NUMPAD5, SWT.KP_5}, +// {OS.VK_NUMPAD6, SWT.KP_6}, +// {OS.VK_NUMPAD7, SWT.KP_7}, +// {OS.VK_NUMPAD8, SWT.KP_8}, +// {OS.VK_NUMPAD9, SWT.KP_9}, + + }; + + /* Multiple Displays */ + static Display Default; + static Display [] Displays = new Display [4]; + + /* Modality */ + Shell [] modalWidgets; + static boolean TrimEnabled = false; + + /* Package Name */ + static final String PACKAGE_PREFIX = "org.eclipse.swt.widgets."; + /* + * This code is intentionally commented. In order + * to support CLDC, .class cannot be used because + * it does not compile on some Java compilers when + * they are targeted for CLDC. + */ +// static { +// String name = Display.class.getName (); +// int index = name.lastIndexOf ('.'); +// PACKAGE_PREFIX = name.substring (0, index + 1); +// } + + /* + * 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; +} + +/** + * 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 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 #getCurrent + * @see #getDefault + * @see Widget#checkSubclass + * @see Shell + */ +public Display () { + this (null); +} + +public Display (DeviceData data) { + super (data); +} + +int asciiKey (int key) { + if (OS.IsWinCE) return 0; + + /* Get the current keyboard. */ + for (int i=0; i<keyboard.length; i++) keyboard [i] = 0; + if (!OS.GetKeyboardState (keyboard)) return 0; + + /* Translate the key to ASCII or UNICODE using the virtual keyboard */ + if (OS.IsUnicode) { + char [] result = new char [1]; + if (OS.ToUnicode (key, key, keyboard, result, 1, 0) == 1) return result [0]; + } else { + short [] result = new short [1]; + if (OS.ToAscii (key, key, keyboard, result, 0) == 1) return result [0]; + } + return 0; +} + +/** + * Adds the listener to the collection of listeners who will + * be notifed when an event of the given type occurs anywhere + * in SWT. When the event does occur, 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> + * </ul> + * + * @see Listener + * @see #removeFilter + * @see #removeListener + * + * @since 2.1 + */ +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 notifed when an event of the given type occurs. 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> + * </ul> + * + * @see Listener + * @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 addBar (Menu menu) { + if (bars == null) bars = new Menu [4]; + int length = bars.length; + for (int i=0; i<length; i++) { + if (bars [i] == menu) return; + } + int index = 0; + while (index < length) { + if (bars [index] == null) break; + index++; + } + if (index == length) { + Menu [] newBars = new Menu [length + 4]; + System.arraycopy (bars, 0, newBars, 0, length); + bars = newBars; + } + bars [index] = menu; +} + +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; +} + +/** + * 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. + * + * @param runnable code to run on the user-interface thread. + * + * @see #syncExec + */ +public void asyncExec (Runnable runnable) { + if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED); + synchronizer.asyncExec (runnable); +} + +/** + * Causes the system hardware to emit a short sound + * (if it supports this capability). + */ +public void beep () { + checkDevice (); + OS.MessageBeep (OS.MB_OK); +} + +/** + * 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 (!isValidClass (getClass ())) error (SWT.ERROR_INVALID_SUBCLASS); +} + +protected void checkDevice () { + if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); + if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED); +} + +static synchronized void checkDisplay (Thread thread) { + for (int i=0; i<Displays.length; i++) { + if (Displays [i] != null && Displays [i].thread == thread) { + SWT.error (SWT.ERROR_THREAD_INVALID_ACCESS); + } + } +} + +void clearModal (Shell shell) { + if (modalWidgets == null) return; + int index = 0, length = modalWidgets.length; + while (index < length) { + if (modalWidgets [index] == shell) break; + if (modalWidgets [index] == null) return; + index++; + } + if (index == length) return; + System.arraycopy (modalWidgets, index + 1, modalWidgets, index, --length - index); + modalWidgets [length] = null; + if (index == 0 && modalWidgets [0] == null) modalWidgets = null; + Shell [] shells = getShells (); + for (int i=0; i<shells.length; i++) shells [i].updateModal (); +} + +int controlKey (int key) { + int upper = OS.CharUpper ((short) key); + if (64 <= upper && upper <= 95) return upper & 0xBF; + return key; +} + +/** + * 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> + * </ul> + * + * @see #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 ()); + createDisplay (data); + register (this); + if (Default == null) Default = this; +} + +void createDisplay (DeviceData data) { +} + +static synchronized void deregister (Display display) { + 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 #dispose + * @see #release + */ +protected void destroy () { + if (this == Default) Default = null; + deregister (this); + destroyDisplay (); +} + +void destroyDisplay () { +} + +/** + * Causes the <code>run()</code> method of the runnable to + * be invoked by the user-interface thread just before the + * receiver is disposed. + * + * @param runnable code to run at dispose time. + */ +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 drawMenuBars () { + if (bars == null) return; + for (int i=0; i<bars.length; i++) { + Menu menu = bars [i]; + if (menu != null && !menu.isDisposed ()) menu.update (); + } + bars = null; +} + +/** + * Does whatever display specific cleanup is required, and then + * uses the code in <code>SWTError.error</code> to handle the error. + * + * @param code the descriptive error code + * + * @see SWTError#error + */ +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); +} + +boolean filterMessage (MSG msg) { + int message = msg.message; + if (OS.WM_KEYFIRST <= message && message <= OS.WM_KEYLAST) { + Control control = findControl (msg.hwnd); + if (control != null) { + if (translateAccelerator (msg, control) || translateMnemonic (msg, control) || translateTraversal (msg, control)) { + lastAscii = lastKey = 0; + lastVirtual = lastNull = false; + return true; + } + } + } + return false; +} + +/** + * 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. + * + * @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> + * </ul> + */ +public Widget findWidget (int handle) { + checkDevice (); + return WidgetTable.get (handle); +} + +Control findControl(int handle) { + if (handle == 0) return null; + /* + * This code is intentionally commented. It is possible + * find the SWT control that is associated with a handle + * that belongs to another process when the handle was + * created by an in-proc OLE client. In this case, the + * handle comes from another process, but it is a child + * of an SWT control. For now, it is necessary to look + * at handles that do not belong to the SWT process. + */ +// int [] hwndProcessId = new int [1]; +// OS.GetWindowThreadProcessId (handle, hwndProcessId); +// if (hwndProcessId [0] != processId) return null; + do { + Control control = WidgetTable.get (handle); + if (control != null && control.handle == handle) { + return control; + } + } while ((handle = OS.GetParent (handle)) != 0); + 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. + * + * @param thread the user-interface thread + * @return the display for the given thread + */ +public static synchronized Display findDisplay (Thread thread) { + 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> + * </ul> + */ +public Shell getActiveShell () { + checkDevice (); + Control control = findControl (OS.GetActiveWindow ()); + if (control instanceof Shell) return (Shell) control; + return null; +} + +/** + * Returns a rectangle describing the receiver's size and location. + * + * @return the bounding rectangle + * + * @exception SWTException <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public Rectangle getBounds () { + checkDevice (); + if (OS.GetSystemMetrics (OS.SM_CMONITORS) < 2) { + int width = OS.GetSystemMetrics (OS.SM_CXSCREEN); + int height = OS.GetSystemMetrics (OS.SM_CYSCREEN); + return new Rectangle (0, 0, width, height); + } + int x = OS.GetSystemMetrics (OS.SM_XVIRTUALSCREEN); + int y = OS.GetSystemMetrics (OS.SM_YVIRTUALSCREEN); + int width = OS.GetSystemMetrics (OS.SM_CXVIRTUALSCREEN); + int height = OS.GetSystemMetrics (OS.SM_CYVIRTUALSCREEN); + return new Rectangle (x, y, width, height); +} + +/** + * 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 synchronized Display getCurrent () { + return findDisplay (Thread.currentThread ()); +} + +public Rectangle getClientArea () { + checkDevice (); + if (OS.GetSystemMetrics (OS.SM_CMONITORS) < 2) { + RECT rect = new RECT (); + OS.SystemParametersInfo (OS.SPI_GETWORKAREA, 0, rect, 0); + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + return new Rectangle (rect.left, rect.top, width, height); + } + int x = OS.GetSystemMetrics (OS.SM_XVIRTUALSCREEN); + int y = OS.GetSystemMetrics (OS.SM_YVIRTUALSCREEN); + int width = OS.GetSystemMetrics (OS.SM_CXVIRTUALSCREEN); + int height = OS.GetSystemMetrics (OS.SM_CYVIRTUALSCREEN); + return new Rectangle (x, y, width, 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> + * </ul> + */ +public Control getCursorControl () { + checkDevice (); + POINT pt = new POINT (); + if (!OS.GetCursorPos (pt)) return null; + return findControl (OS.WindowFromPoint (pt)); +} + +/** + * 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> + * </ul> + */ +public Point getCursorLocation () { + checkDevice (); + POINT pt = new POINT (); + OS.GetCursorPos (pt); + return new Point (pt.x, pt.y); +} + +/** + * 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 synchronized Display getDefault () { + if (Default == null) Default = new Display (); + return Default; +} + +static boolean isValidClass (Class clazz) { + String name = clazz.getName (); + int index = name.lastIndexOf ('.'); + return name.substring (0, index + 1).equals (PACKAGE_PREFIX); +} + +/** + * 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 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> + * </ul> + * + * @see #setData + * @see #disposeExec + */ +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 provide a + * <code>disposeExec()</code> handler which does so. + * </p> + * + * @return the display specific data + * + * @exception SWTException <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - when called from the wrong thread</li> + * </ul> + * + * @see #setData + * @see #disposeExec + */ +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> + * </ul> + * + * @since 2.1 + */ +public int getDismissalAlignment () { + checkDevice (); + return SWT.LEFT; +} + + +/** + * 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> + * </ul> + */ +public int getDoubleClickTime () { + checkDevice (); + return OS.GetDoubleClickTime (); +} + +/** + * 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> + * </ul> + */ +public Control getFocusControl () { + checkDevice (); + return findControl (OS.GetFocus ()); +} + +/** + * Returns the maximum allowed depth of icons on this display. + * 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> + * </ul> + */ +public int getIconDepth () { + checkDevice (); + + /* Use the character encoding for the default locale */ + TCHAR buffer1 = new TCHAR (0, "Control Panel\\Desktop\\WindowMetrics", true); + + int [] phkResult = new int [1]; + int result = OS.RegOpenKeyEx (OS.HKEY_CURRENT_USER, buffer1, 0, OS.KEY_READ, phkResult); + if (result != 0) return 4; + int depth = 4; + int [] lpcbData = {128}; + + /* Use the character encoding for the default locale */ + TCHAR lpData = new TCHAR (0, lpcbData [0]); + TCHAR buffer2 = new TCHAR (0, "Shell Icon BPP", true); + + result = OS.RegQueryValueEx (phkResult [0], buffer2, 0, null, lpData, lpcbData); + if (result == 0) { + try { + depth = Integer.parseInt (lpData.toString (0, lpData.strlen ())); + } catch (NumberFormatException e) {}; + } + OS.RegCloseKey (phkResult [0]); + return depth; +} + +ImageList getImageList (Point size) { + if (imageList == null) imageList = new ImageList [4]; + + int i = 0; + int length = imageList.length; + while (i < length) { + ImageList list = imageList [i]; + if (list == null) break; + if (list.getImageSize().equals(size)) { + list.addRef(); + return list; + } + i++; + } + + if (i == length) { + ImageList [] newList = new ImageList [length + 4]; + System.arraycopy (imageList, 0, newList, 0, length); + imageList = newList; + } + + ImageList list = new ImageList(); + imageList [i] = list; + list.addRef(); + return list; +} + +ImageList getToolImageList (Point size) { + if (toolImageList == null) toolImageList = new ImageList [4]; + + int i = 0; + int length = toolImageList.length; + while (i < length) { + ImageList list = toolImageList [i]; + if (list == null) break; + if (list.getImageSize().equals(size)) { + list.addRef(); + return list; + } + i++; + } + + if (i == length) { + ImageList [] newList = new ImageList [length + 4]; + System.arraycopy (toolImageList, 0, newList, 0, length); + toolImageList = newList; + } + + ImageList list = new ImageList(); + toolImageList [i] = list; + list.addRef(); + return list; +} + +ImageList getToolHotImageList (Point size) { + if (toolHotImageList == null) toolHotImageList = new ImageList [4]; + + int i = 0; + int length = toolHotImageList.length; + while (i < length) { + ImageList list = toolHotImageList [i]; + if (list == null) break; + if (list.getImageSize().equals(size)) { + list.addRef(); + return list; + } + i++; + } + + if (i == length) { + ImageList [] newList = new ImageList [length + 4]; + System.arraycopy (toolHotImageList, 0, newList, 0, length); + toolHotImageList = newList; + } + + ImageList list = new ImageList(); + toolHotImageList [i] = list; + list.addRef(); + return list; +} + +ImageList getToolDisabledImageList (Point size) { + if (toolDisabledImageList == null) toolDisabledImageList = new ImageList [4]; + + int i = 0; + int length = toolDisabledImageList.length; + while (i < length) { + ImageList list = toolDisabledImageList [i]; + if (list == null) break; + if (list.getImageSize().equals(size)) { + list.addRef(); + return list; + } + i++; + } + + if (i == length) { + ImageList [] newList = new ImageList [length + 4]; + System.arraycopy (toolDisabledImageList, 0, newList, 0, length); + toolDisabledImageList = newList; + } + + ImageList list = new ImageList(); + toolDisabledImageList [i] = list; + list.addRef(); + return list; +} + +Shell getModalShell () { + if (modalWidgets == null) return null; + int index = modalWidgets.length; + while (--index >= 0) { + Shell shell = modalWidgets [index]; + if (shell != null) return shell; + } + return null; +} + +int getLastEventTime () { + return OS.IsWinCE ? OS.GetTickCount () : OS.GetMessageTime (); +} + +/** + * Returns an 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> + * </ul> + */ +public Shell [] getShells () { + checkDevice (); + /* + * NOTE: Need to check that the shells that belong + * to another display have not been disposed by the + * other display's thread as the shells list is being + * processed. + */ + int count = 0; + Shell [] shells = WidgetTable.shells (); + for (int i=0; i<shells.length; i++) { + Shell shell = shells [i]; + if (!shell.isDisposed () && this == shell.getDisplay ()) { + count++; + } + } + if (count == shells.length) return shells; + int index = 0; + Shell [] result = new Shell [count]; + for (int i=0; i<shells.length; i++) { + Shell shell = shells [i]; + if (!shell.isDisposed () && this == shell.getDisplay ()) { + result [index++] = shell; + } + } + return result; +} + +/** + * 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 + */ +public Thread getSyncThread () { + 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> + * </ul> + * + * @see SWT + */ +public Color getSystemColor (int id) { + checkDevice (); + int pixel = 0x02000000; + switch (id) { + case SWT.COLOR_WIDGET_DARK_SHADOW: pixel = OS.GetSysColor (OS.COLOR_3DDKSHADOW); break; + case SWT.COLOR_WIDGET_NORMAL_SHADOW: pixel = OS.GetSysColor (OS.COLOR_3DSHADOW); break; + case SWT.COLOR_WIDGET_LIGHT_SHADOW: pixel = OS.GetSysColor (OS.COLOR_3DLIGHT); break; + case SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW: pixel = OS.GetSysColor (OS.COLOR_3DHIGHLIGHT); break; + case SWT.COLOR_WIDGET_BACKGROUND: pixel = OS.GetSysColor (OS.COLOR_3DFACE); break; + case SWT.COLOR_WIDGET_BORDER: pixel = OS.GetSysColor (OS.COLOR_WINDOWFRAME); break; + case SWT.COLOR_WIDGET_FOREGROUND: + case SWT.COLOR_LIST_FOREGROUND: pixel = OS.GetSysColor (OS.COLOR_WINDOWTEXT); break; + case SWT.COLOR_LIST_BACKGROUND: pixel = OS.GetSysColor (OS.COLOR_WINDOW); break; + case SWT.COLOR_LIST_SELECTION: pixel = OS.GetSysColor (OS.COLOR_HIGHLIGHT); break; + case SWT.COLOR_LIST_SELECTION_TEXT: pixel = OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT);break; + case SWT.COLOR_INFO_FOREGROUND: pixel = OS.GetSysColor (OS.COLOR_INFOTEXT); break; + case SWT.COLOR_INFO_BACKGROUND: pixel = OS.GetSysColor (OS.COLOR_INFOBK); break; + case SWT.COLOR_TITLE_FOREGROUND: pixel = OS.GetSysColor (OS.COLOR_CAPTIONTEXT); break; + case SWT.COLOR_TITLE_BACKGROUND: pixel = OS.GetSysColor (OS.COLOR_ACTIVECAPTION); break; + case SWT.COLOR_TITLE_BACKGROUND_GRADIENT: + pixel = OS.GetSysColor (OS.COLOR_GRADIENTACTIVECAPTION); + if (pixel == 0) pixel = OS.GetSysColor (OS.COLOR_ACTIVECAPTION); + break; + case SWT.COLOR_TITLE_INACTIVE_FOREGROUND: pixel = OS.GetSysColor (OS.COLOR_INACTIVECAPTIONTEXT); break; + case SWT.COLOR_TITLE_INACTIVE_BACKGROUND: pixel = OS.GetSysColor (OS.COLOR_INACTIVECAPTION); break; + case SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT: + pixel = OS.GetSysColor (OS.COLOR_GRADIENTINACTIVECAPTION); + if (pixel == 0) pixel = OS.GetSysColor (OS.COLOR_INACTIVECAPTION); + break; + default: + return super.getSystemColor (id); + } + return Color.win32_new (this, pixel); +} + +/** + * 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 free'd 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_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public Font getSystemFont () { + checkDevice (); + int hFont = systemFont (); + return Font.win32_new (this, hFont); +} + +/** + * Returns the user-interface thread for the receiver. + * + * @return the receiver's user-interface thread + */ +public Thread getThread () { + if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED); + return thread; +} + +/** + * 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 + * + * @private + */ +public int internal_new_GC (GCData data) { + if (isDisposed()) SWT.error(SWT.ERROR_DEVICE_DISPOSED); + int hDC = OS.GetDC (0); + if (hDC == 0) SWT.error (SWT.ERROR_NO_HANDLES); + if (data != null) { + data.device = this; + data.hFont = systemFont (); + } + return hDC; +} + +/** + * 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 (); + + /* Create the callbacks */ + windowCallback = new Callback (this, "windowProc", 4); + windowProc = windowCallback.getAddress (); + if (windowProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS); + + /* Remember the current procsss and thread */ + threadId = OS.GetCurrentThreadId (); + processId = OS.GetCurrentProcessId (); + + /* Use the character encoding for the default locale */ + windowClass = new TCHAR (0, WindowName + WindowClassCount++, true); + + /* Register the SWT window class */ + int hHeap = OS.GetProcessHeap (); + int hInstance = OS.GetModuleHandle (null); + WNDCLASS lpWndClass = new WNDCLASS (); + lpWndClass.hInstance = hInstance; + lpWndClass.lpfnWndProc = windowProc; + lpWndClass.style = OS.CS_BYTEALIGNWINDOW | OS.CS_DBLCLKS; + lpWndClass.hCursor = OS.LoadCursor (0, OS.IDC_ARROW); + int byteCount = windowClass.length () * TCHAR.sizeof; + int lpszClassName = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + lpWndClass.lpszClassName = lpszClassName; + OS.MoveMemory (lpszClassName, windowClass, byteCount); + OS.RegisterClass (lpWndClass); + + /* Initialize the system font */ + int systemFont = 0; + if (!OS.IsWinCE) { + NONCLIENTMETRICS info = new NONCLIENTMETRICS (); + info.cbSize = NONCLIENTMETRICS.sizeof; + if (OS.SystemParametersInfo (OS.SPI_GETNONCLIENTMETRICS, 0, info, 0)) { + systemFont = OS.CreateFontIndirect (info.lfMessageFont); + } + } + if (systemFont == 0) systemFont = OS.GetStockObject (OS.DEFAULT_GUI_FONT); + if (systemFont == 0) systemFont = OS.GetStockObject (OS.SYSTEM_FONT); + if (systemFont != 0) systemFonts = new int [] {systemFont}; + + /* Create the message only HWND */ + hwndMessage = OS.CreateWindowEx (0, + windowClass, + null, + OS.WS_OVERLAPPED, + 0, 0, 0, 0, + 0, + 0, + hInstance, + null); + messageCallback = new Callback (this, "messageProc", 4); + messageProc = messageCallback.getAddress (); + if (messageProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS); + OS.SetWindowLong (hwndMessage, OS.GWL_WNDPROC, messageProc); + + /* Create the message filter hook */ + if (!OS.IsWinCE) { + msgFilterCallback = new Callback (this, "msgFilterProc", 3); + msgFilterProc = msgFilterCallback.getAddress (); + if (msgFilterProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS); + hHook = OS.SetWindowsHookEx (OS.WH_MSGFILTER, msgFilterProc, 0, threadId); + } +} + +/** + * 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 handle the platform specific GC handle + * @param data the platform specific GC data + * + * @private + */ +public void internal_dispose_GC (int hDC, GCData data) { + OS.ReleaseDC (0, hDC); +} + +boolean isWakeMessage (MSG msg) { + return msg.hwnd == hwndMessage && msg.message == OS.WM_NULL; +} + +boolean isValidThread () { + return thread == Thread.currentThread (); +} + +boolean isVirtualKey (int key) { + switch (key) { + case OS.VK_TAB: + case OS.VK_RETURN: + case OS.VK_BACK: + case OS.VK_ESCAPE: +// case OS.VK_DELETE: + case OS.VK_SPACE: + case OS.VK_MENU: + case OS.VK_SHIFT: + case OS.VK_CONTROL: return true; + } + return false; +} + +int messageProc (int hwnd, int msg, int wParam, int lParam) { + switch (msg) { + case OS.WM_ACTIVATEAPP: + /* + * Feature in Windows. When multiple shells are + * disabled and one of the shells has an enabled + * dialog child and the user selects a disabled + * shell that does not have the enabled dialog + * child using the Task bar, Windows brings the + * disabled shell to the front. As soon as the + * user clicks on the disabled shell, the enabled + * dialog child comes to the front. This behavior + * is unspecified and seems strange. Normally, a + * disabled shell is frozen on the screen and the + * user cannot change the z-order by clicking with + * the mouse. The fix is to look for WM_ACTIVATEAPP + * and force the enabled dialog child to the front. + * This is typically what the user is expecting. + */ + if (wParam != 0) { + Shell shell = getModalShell (); + if (shell != null) shell.bringToTop (); + } + break; + case OS.WM_ENDSESSION: + if (wParam != 0) dispose (); + break; + case OS.WM_NULL: + runAsyncMessages (); + break; + case OS.WM_QUERYENDSESSION: + Event event = new Event (); + sendEvent (SWT.Close, event); + if (!event.doit) return 0; + break; + case OS.WM_SETTINGCHANGE: + updateFont (); + break; + case OS.WM_TIMER: + runTimer (wParam); + break; + } + return OS.DefWindowProc (hwnd, msg, wParam, lParam); +} + +int msgFilterProc (int code, int wParam, int lParam) { + if (code >= 0) { + OS.MoveMemory (hookMsg, lParam, MSG.sizeof); + if (hookMsg.message == OS.WM_NULL) runAsyncMessages (); + } + return OS.CallNextHookEx (hHook, code, wParam, lParam); +} + +int numpadKey (int key) { + switch (key) { + case OS.VK_NUMPAD0: return '0'; + case OS.VK_NUMPAD1: return '1'; + case OS.VK_NUMPAD2: return '2'; + case OS.VK_NUMPAD3: return '3'; + case OS.VK_NUMPAD4: return '4'; + case OS.VK_NUMPAD5: return '5'; + case OS.VK_NUMPAD6: return '6'; + case OS.VK_NUMPAD7: return '7'; + case OS.VK_NUMPAD8: return '8'; + case OS.VK_NUMPAD9: return '9'; + case OS.VK_MULTIPLY: return '*'; + case OS.VK_ADD: return '+'; + case OS.VK_SEPARATOR: return '\0'; + case OS.VK_SUBTRACT: return '-'; + case OS.VK_DECIMAL: return '.'; + case OS.VK_DIVIDE: return '/'; + } + return 0; +} + +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; +} + +/** + * 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> + * </ul> + * + * @see #sleep + * @see #wake + */ +public boolean readAndDispatch () { + checkDevice (); + drawMenuBars (); + runPopups (); + if (OS.PeekMessage (msg, 0, 0, 0, OS.PM_REMOVE)) { + if (!isWakeMessage (msg)) { + if (!filterMessage (msg)) { + OS.TranslateMessage (msg); + OS.DispatchMessage (msg); + } + runDeferredEvents (); + return true; + } + } + return runAsyncMessages (); +} + +static synchronized void register (Display display) { + 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 #dispose + * @see #destroy + */ +protected void release () { + sendEvent (SWT.Dispose, new Event ()); + Shell [] shells = WidgetTable.shells (); + for (int i=0; i<shells.length; i++) { + Shell shell = shells [i]; + if (!shell.isDisposed ()) { + if (this == shell.getDisplay ()) shell.dispose (); + } + } + 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 () { + + /* Unhook the message hook */ + if (!OS.IsWinCE) { + if (hHook != 0) OS.UnhookWindowsHookEx (hHook); + hHook = 0; + msgFilterCallback.dispose (); + msgFilterCallback = null; + msgFilterProc = 0; + } + + /* Destroy the message only HWND */ + if (hwndMessage != 0) OS.DestroyWindow (hwndMessage); + hwndMessage = 0; + messageCallback.dispose (); + messageCallback = null; + messageProc = 0; + + /* Unregister the SWT Window class */ + int hHeap = OS.GetProcessHeap (); + int hInstance = OS.GetModuleHandle (null); + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, windowClass, lpWndClass); + OS.UnregisterClass (windowClass, hInstance); + OS.HeapFree (hHeap, 0, lpWndClass.lpszClassName); + windowClass = null; + windowCallback.dispose (); + windowCallback = null; + windowProc = 0; + + /* Release the system fonts */ + if (systemFonts != null) { + for (int i=0; i<systemFonts.length; i++) { + if (systemFonts [i] != 0) OS.DeleteObject (systemFonts [i]); + } + } + systemFonts = null; + + /* Release Custom Colors for ChooseColor */ + if (lpCustColors != 0) OS.HeapFree (hHeap, 0, lpCustColors); + lpCustColors = 0; + + /* Release references */ + thread = null; + msg = null; + keyboard = null; + modalWidgets = null; + data = null; + keys = null; + values = null; +} + +void releaseImageList (ImageList list) { + int i = 0; + int length = imageList.length; + while (i < length) { + if (imageList [i] == list) { + if (list.removeRef () > 0) return; + list.dispose (); + System.arraycopy (imageList, i + 1, imageList, i, --length - i); + imageList [length] = null; + for (int j=0; j<length; j++) { + if (imageList [j] != null) return; + } + imageList = null; + return; + } + i++; + } +} + +void releaseToolImageList (ImageList list) { + int i = 0; + int length = toolImageList.length; + while (i < length) { + if (toolImageList [i] == list) { + if (list.removeRef () > 0) return; + list.dispose (); + System.arraycopy (toolImageList, i + 1, toolImageList, i, --length - i); + toolImageList [length] = null; + for (int j=0; j<length; j++) { + if (toolImageList [j] != null) return; + } + toolImageList = null; + return; + } + i++; + } +} + +void releaseToolHotImageList (ImageList list) { + int i = 0; + int length = toolHotImageList.length; + while (i < length) { + if (toolHotImageList [i] == list) { + if (list.removeRef () > 0) return; + list.dispose (); + System.arraycopy (toolHotImageList, i + 1, toolHotImageList, i, --length - i); + toolHotImageList [length] = null; + for (int j=0; j<length; j++) { + if (toolHotImageList [j] != null) return; + } + toolHotImageList = null; + return; + } + i++; + } +} + +void releaseToolDisabledImageList (ImageList list) { + int i = 0; + int length = toolDisabledImageList.length; + while (i < length) { + if (toolDisabledImageList [i] == list) { + if (list.removeRef () > 0) return; + list.dispose (); + System.arraycopy (toolDisabledImageList, i + 1, toolDisabledImageList, i, --length - i); + toolDisabledImageList [length] = null; + for (int j=0; j<length; j++) { + if (toolDisabledImageList [j] != null) return; + } + toolDisabledImageList = null; + return; + } + i++; + } +} + +/** + * Removes the listener from the collection of listeners who will + * be notifed when an event of the given type occurs anywhere in SWT. + * + * @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 #addFilter + * @see #addListener + * + * @since 2.1 + */ +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 notifed when an event of the given type occurs. + * + * @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 #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); +} + +void removeBar (Menu menu) { + if (bars == null) return; + for (int i=0; i<bars.length; i++) { + if (bars [i] == menu) { + bars [i] = null; + return; + } + } +} + +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 () { + return synchronizer.runAsyncMessages (); +} + +boolean runDeferredEvents () { + /* + * Run deferred events. This code is always + * called in the Display's thread so it must + * be re-enterant but 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 ()) { + widget.sendEvent (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 true; +} + +boolean runPopups () { + if (popups == null) return false; + boolean result = false; + while (popups != null) { + Menu menu = popups [0]; + if (menu == null) break; + int length = popups.length; + System.arraycopy (popups, 1, popups, 0, --length); + popups [length] = null; + menu._setVisible (true); + result = true; + } + popups = null; + return result; +} + +boolean runTimer (int id) { + if (timerList != null && timerIds != null) { + int index = 0; + while (index <timerIds.length) { + if (timerIds [index] == id) { + OS.KillTimer (hwndMessage, timerIds [index]); + timerIds [index] = 0; + Runnable runnable = timerList [index]; + timerList [index] = null; + if (runnable != null) runnable.run (); + return true; + } + index++; + } + } + return false; +} + +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 (); + if (!filterEvent (event)) { + if (eventTable != null) eventTable.sendEvent (event); + } +} + +/** + * 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> + * </ul> + * + * @since 2.1 + */ +public void setCursorLocation (int x, int y) { + checkDevice (); + OS.SetCursorPos (x, y); +} + +/** + * 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 + * </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> + * </ul> + * + * @see #setData + * @see #disposeExec + */ +public void setData (String key, Object value) { + checkDevice (); + if (key == null) error (SWT.ERROR_NULL_ARGUMENT); + + /* 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; +} + +/** + * 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 - when called from the wrong thread</li> + * </ul> + * + * @see #getData + * @see #disposeExec + */ +public void setData (Object data) { + checkDevice (); + this.data = data; +} + +/** + * 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. + * + * @param name the new app name + */ +public static void setAppName (String name) { + /* Do nothing */ +} + +void setModalShell (Shell shell) { + if (modalWidgets == null) modalWidgets = new Shell [4]; + int index = 0, length = modalWidgets.length; + while (index < length) { + if (modalWidgets [index] == shell) return; + if (modalWidgets [index] == null) break; + index++; + } + if (index == length) { + Shell [] newModalWidgets = new Shell [length + 4]; + System.arraycopy (modalWidgets, 0, newModalWidgets, 0, length); + modalWidgets = newModalWidgets; + } + modalWidgets [index] = shell; + Shell [] shells = getShells (); + for (int i=0; i<shells.length; i++) shells [i].updateModal (); +} + +/** + * 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> + * </ul> + */ +public void setSynchronizer (Synchronizer synchronizer) { + checkDevice (); + if (synchronizer == null) error (SWT.ERROR_NULL_ARGUMENT); + if (this.synchronizer != null) { + this.synchronizer.runAsyncMessages(); + } + this.synchronizer = synchronizer; +} + +int shiftedKey (int key) { + if (OS.IsWinCE) return 0; + + /* Clear the virtual keyboard and press the shift key */ + for (int i=0; i<keyboard.length; i++) keyboard [i] = 0; + keyboard [OS.VK_SHIFT] |= 0x80; + + /* Translate the key to ASCII or UNICODE using the virtual keyboard */ + if (OS.IsUnicode) { + char [] result = new char [1]; + if (OS.ToUnicode (key, key, keyboard, result, 1, 0) == 1) return result [0]; + } else { + short [] result = new short [1]; + if (OS.ToAscii (key, key, keyboard, result, 0) == 1) return result [0]; + } + return 0; +} + +/** + * 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> + * </ul> + * + * @see #wake + */ +public boolean sleep () { + checkDevice (); + if (OS.IsWinCE) { + OS.MsgWaitForMultipleObjectsEx (0, 0, OS.INFINITE, OS.QS_ALLINPUT, OS.MWMO_INPUTAVAILABLE); + return true; + } + return OS.WaitMessage (); +} + +/** + * 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. + * + * @param runnable code to run on the user-interface thread. + * + * @exception SWTException <ul> + * <li>ERROR_FAILED_EXEC - if an exception occured when executing the runnable</li> + * </ul> + * + * @see #asyncExec + */ +public void syncExec (Runnable runnable) { + if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED); + synchronizer.syncExec (runnable); +} + +int systemFont () { + int hFont = 0; + if (systemFonts != null) { + int length = systemFonts.length; + if (length != 0) hFont = systemFonts [length - 1]; + } + if (hFont == 0) hFont = OS.GetStockObject (OS.DEFAULT_GUI_FONT); + if (hFont == 0) hFont = OS.GetStockObject (OS.SYSTEM_FONT); + return hFont; +} + +/** + * 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. + * + * @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> + * </ul> + * + * @see #asyncExec + */ +public void timerExec (int milliseconds, Runnable runnable) { + checkDevice (); + if (runnable == null) error (SWT.ERROR_NULL_ARGUMENT); + if (timerList == null) timerList = new Runnable [4]; + if (timerIds == null) timerIds = new int [4]; + int index = 0; + while (index < timerList.length) { + if (timerList [index] == runnable) break; + index++; + } + int timerId = 0; + if (index != timerList.length) { + timerId = timerIds [index]; + if (milliseconds < 0) { + OS.KillTimer (hwndMessage, timerId); + timerList [index] = null; + timerIds [index] = 0; + return; + } + } else { + if (milliseconds < 0) return; + index = 0; + while (index < timerList.length) { + if (timerList [index] == null) break; + index++; + } + timerCount++; + timerId = timerCount; + if (index == timerList.length) { + Runnable [] newTimerList = new Runnable [timerList.length + 4]; + System.arraycopy (timerList, 0, newTimerList, 0, timerList.length); + timerList = newTimerList; + int [] newTimerIds = new int [timerIds.length + 4]; + System.arraycopy (timerIds, 0, newTimerIds, 0, timerIds.length); + timerIds = newTimerIds; + } + } + int newTimerID = OS.SetTimer (hwndMessage, timerId, milliseconds, 0); + if (newTimerID != 0) { + timerList [index] = runnable; + timerIds [index] = newTimerID; + } +} + +boolean translateAccelerator (MSG msg, Control control) { + accelKeyHit = true; + boolean result = control.translateAccelerator (msg); + accelKeyHit = false; + return result; +} + +static int translateKey (int key) { + for (int i=0; i<KeyTable.length; i++) { + if (KeyTable [i] [0] == key) return KeyTable [i] [1]; + } + return 0; +} + +boolean translateMnemonic (MSG msg, Control control) { + switch (msg.message) { + case OS.WM_CHAR: + case OS.WM_SYSCHAR: + return control.translateMnemonic (msg); + } + return false; +} + +boolean translateTraversal (MSG msg, Control control) { + switch (msg.message) { + case OS.WM_KEYDOWN: + switch (msg.wParam) { + case OS.VK_RETURN: + case OS.VK_ESCAPE: + case OS.VK_TAB: + case OS.VK_UP: + case OS.VK_DOWN: + case OS.VK_LEFT: + case OS.VK_RIGHT: + case OS.VK_PRIOR: + case OS.VK_NEXT: + return control.translateTraversal (msg); + } + break; + case OS.WM_SYSKEYDOWN: + switch (msg.wParam) { + case OS.VK_MENU: + return control.translateTraversal (msg); + } + break; + } + return false; +} + +static int untranslateKey (int key) { + for (int i=0; i<KeyTable.length; i++) { + if (KeyTable [i] [1] == key) return KeyTable [i] [0]; + } + return 0; +} + +/** + * Forces all outstanding paint requests for the display + * to be processed before this method returns. + * + * @see Control#update + */ +public void update() { + checkDevice (); + Shell[] shells = WidgetTable.shells (); + for (int i=0; i<shells.length; i++) { + Shell shell = shells [i]; + if (!shell.isDisposed () && this == shell.getDisplay ()) { + shell.update (true); + } + } +} + +void updateFont () { + if (OS.IsWinCE) return; + Font oldFont = getSystemFont (); + int systemFont = 0; + NONCLIENTMETRICS info = new NONCLIENTMETRICS (); + info.cbSize = NONCLIENTMETRICS.sizeof; + if (OS.SystemParametersInfo (OS.SPI_GETNONCLIENTMETRICS, 0, info, 0)) { + systemFont = OS.CreateFontIndirect (info.lfMessageFont); + } + if (systemFont == 0) systemFont = OS.GetStockObject (OS.DEFAULT_GUI_FONT); + if (systemFont == 0) systemFont = OS.GetStockObject (OS.SYSTEM_FONT); + if (systemFont == 0) return; + int length = systemFonts == null ? 0 : systemFonts.length; + int [] newFonts = new int [length + 1]; + if (systemFonts != null) { + System.arraycopy (systemFonts, 0, newFonts, 0, length); + } + newFonts [length] = systemFont; + systemFonts = newFonts; + Font newFont = getSystemFont (); + Shell [] shells = getShells (); + for (int i=0; i<shells.length; i++) { + Shell shell = shells [i]; + if (!shell.isDisposed ()) { + shell.updateFont (oldFont, newFont); + } + } +} + +/** + * 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. + * + * @see #sleep + */ +public void wake () { + if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED); + if (thread == Thread.currentThread ()) return; + if (OS.IsWinCE) { + OS.PostMessage (hwndMessage, OS.WM_NULL, 0, 0); + } else { + OS.PostThreadMessage (threadId, OS.WM_NULL, 0, 0); + } +} + +int windowProc (int hwnd, int msg, int wParam, int lParam) { + Control control = WidgetTable.get (hwnd); + if (control != null) { + return control.windowProc (msg, wParam, lParam); + } + return OS.DefWindowProc (hwnd, msg, wParam, lParam); +} + +static String withCrLf (String string) { + + /* If the string is empty, return the string. */ + int length = string.length (); + if (length == 0) return string; + + /* + * Check for an LF or CR/LF and assume the rest of + * the string is formated that way. This will not + * work if the string contains mixed delimiters. + */ + int i = string.indexOf ('\n', 0); + if (i == -1) return string; + if (i > 0 && string.charAt (i - 1) == '\r') { + return string; + } + + /* + * The string is formatted with LF. Compute the + * number of lines and the size of the buffer + * needed to hold the result + */ + i++; + int count = 1; + while (i < length) { + if ((i = string.indexOf ('\n', i)) == -1) break; + count++; i++; + } + count += length; + + /* Create a new string with the CR/LF line terminator. */ + i = 0; + StringBuffer result = new StringBuffer (count); + while (i < length) { + int j = string.indexOf ('\n', i); + if (j == -1) j = length; + result.append (string.substring (i, j)); + if ((i = j) < length) { + result.append ("\r\n"); + i++; + } + } + return result.toString (); +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/FileDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/FileDialog.java index 1a299ff7ca..9cb6dfa5d5 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/FileDialog.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/FileDialog.java @@ -1,411 +1,411 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-
-/**
- * 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>
- * IMPORTANT: This class is intended to be subclassed <em>only</em>
- * within the SWT implementation.
- * </p>
- */
-public class FileDialog extends Dialog {
- String [] filterNames = new String [0];
- String [] filterExtensions = new String [0];
- String [] fileNames = new String [0];
- String filterPath = "", fileName = "";
- static final String FILTER = "*.*";
- static int BUFFER_SIZE = 1024 * 10;
-
-/**
- * Constructs a new instance of this class given only its
- * parent.
- * <p>
- * Note: Currently, null can be passed in for the parent.
- * This has the effect of creating the dialog on the currently active
- * display if there is one. If there is no current display, the
- * dialog 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_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.PRIMARY_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>
- * Note: Currently, null can be passed in for the parent.
- * This has the effect of creating the dialog on the currently active
- * display if there is one. If there is no current display, the
- * dialog 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_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, int style) {
- super (parent, style);
- checkSubclass ();
-}
-
-/**
- * Returns the path of the first file that was
- * selected in the dialog relative to the filter path
- *
- * @return the relative path of the file
- */
-public String getFileName () {
- return fileName;
-}
-
-/**
- * Returns the paths of all files that were selected
- * in the dialog relative to the filter path, or null
- * if none are available.
- *
- * @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;
-}
-
-/**
- * Returns the file names which the dialog will
- * use to filter the files it shows.
- *
- * @return the file name filter
- */
-public String [] getFilterNames () {
- return filterNames;
-}
-
-/**
- * Returns the directory path that the dialog will use.
- * 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;
-}
-
-/**
- * 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 () {
- int hHeap = OS.GetProcessHeap ();
-
- /* Get the owner HWND for the dialog */
- int hwndOwner = 0;
- if (parent != null) hwndOwner = parent.handle;
-
- /* Convert the title and copy it into lpstrTitle */
- if (title == null) title = "";
- /* Use the character encoding for the default locale */
- TCHAR buffer3 = new TCHAR (0, title, true);
- int byteCount3 = buffer3.length () * TCHAR.sizeof;
- int lpstrTitle = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount3);
- OS.MoveMemory (lpstrTitle, buffer3, byteCount3);
-
- /* Compute filters and copy into lpstrFilter */
- String strFilter = "";
- if (filterNames == null) filterNames = new String [0];
- if (filterExtensions == null) filterExtensions = new String [0];
- for (int i=0; i<filterExtensions.length; i++) {
- String filterName = filterExtensions [i];
- if (i < filterNames.length) filterName = filterNames [i];
- strFilter = strFilter + filterName + '\0' + filterExtensions [i] + '\0';
- }
- if (filterExtensions.length == 0) {
- strFilter = strFilter + FILTER + '\0' + FILTER + '\0';
- }
- /* Use the character encoding for the default locale */
- TCHAR buffer4 = new TCHAR (0, strFilter, true);
- int byteCount4 = buffer4.length () * TCHAR.sizeof;
- int lpstrFilter = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount4);
- OS.MoveMemory (lpstrFilter, buffer4, byteCount4);
-
- /* Convert the fileName and filterName to C strings */
- if (fileName == null) fileName = "";
- /* Use the character encoding for the default locale */
- TCHAR name = new TCHAR (0, fileName, true);
-
- /*
- * Copy the name into lpstrFile and ensure that the
- * last byte is NULL and the buffer does not overrun.
- * Note that the longest that a single path name can
- * be on Windows is 256.
- */
- int nMaxFile = 256;
- if ((style & SWT.MULTI) != 0) nMaxFile = Math.max (nMaxFile, BUFFER_SIZE);
- int byteCount = nMaxFile * TCHAR.sizeof;
- int lpstrFile = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- int byteCountFile = Math.min (name.length () * TCHAR.sizeof, byteCount - TCHAR.sizeof);
- OS.MoveMemory (lpstrFile, name, byteCountFile);
-
- /*
- * Copy the path into lpstrInitialDir and ensure that
- * the last byte is NULL and the buffer does not overrun.
- */
- if (filterPath == null) filterPath = "";
- /* Use the character encoding for the default locale */
- TCHAR path = new TCHAR (0, filterPath.replace ('/', '\\'), true);
- int lpstrInitialDir = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- int byteCountDir = Math.min (path.length () * TCHAR.sizeof, byteCount - TCHAR.sizeof);
- OS.MoveMemory (lpstrInitialDir, path, byteCountDir);
-
- /* Create the file dialog struct */
- OPENFILENAME struct = new OPENFILENAME ();
- struct.lStructSize = OPENFILENAME.sizeof;
- struct.Flags = OS.OFN_HIDEREADONLY | OS.OFN_NOCHANGEDIR;
- if ((style & SWT.MULTI) != 0) {
- struct.Flags |= OS.OFN_ALLOWMULTISELECT | OS.OFN_EXPLORER;
- }
- struct.hwndOwner = hwndOwner;
- struct.lpstrTitle = lpstrTitle;
- struct.lpstrFile = lpstrFile;
- struct.nMaxFile = nMaxFile;
- struct.lpstrInitialDir = lpstrInitialDir;
- struct.lpstrFilter = lpstrFilter;
- struct.nFilterIndex = 0;
-
- /*
- * Feature in Windows. The focus window is not saved and
- * and restored automatically by the call to GetOpenFileName ().
- * The fix is to save and restore the focus window.
- */
- int hwndFocus = OS.GetFocus ();
-
- /*
- * Bug/Feature in Windows. When Windows opens the standard
- * file dialog, it changes the cursor to the hourglass and
- * does not put it back. The fix is to save the current
- * cursor and restore it when the dialog closes.
- */
- int hCursor = OS.GetCursor ();
-
- /*
- * Open the dialog. If the open fails due to an invalid
- * file name, use an empty file name and open it again.
- */
- boolean save = (style & SWT.SAVE) != 0;
- boolean success = (save) ? OS.GetSaveFileName (struct) : OS.GetOpenFileName (struct);
- if (OS.CommDlgExtendedError () == OS.FNERR_INVALIDFILENAME) {
- OS.MoveMemory (lpstrFile, new TCHAR (0, "", true), TCHAR.sizeof);
- success = (save) ? OS.GetSaveFileName (struct) : OS.GetOpenFileName (struct);
- }
-
- /* Set the new path, file name and filter */
- fileNames = null;
- String fullPath = null;
- if (success) {
-
- /* Use the character encoding for the default locale */
- TCHAR buffer = new TCHAR (0, struct.nMaxFile);
- int byteCount1 = buffer.length () * TCHAR.sizeof;
- OS.MoveMemory (buffer, lpstrFile, byteCount1);
-
- /*
- * Bug in WinCE. For some reason, nFileOffset and nFileExtension
- * are always zero on WinCE HPC. nFileOffset is always zero on
- * WinCE PPC when using GetSaveFileName. nFileOffset is correctly
- * set on WinCE PPC when using OpenFileName. The fix is to parse
- * lpstrFile to calculate nFileOffset.
- *
- * Note: WinCE does not support multi-select file dialogs.
- */
- int nFileOffset = struct.nFileOffset;
- if (OS.IsWinCE && nFileOffset == 0) {
- int index = 0;
- while (index < buffer.length ()) {
- int ch = buffer.tcharAt (index);
- if (ch == 0) break;
- if (ch == '\\') nFileOffset = index + 1;
- index++;
- }
- }
- if (nFileOffset > 0) {
-
- /* Use the character encoding for the default locale */
- TCHAR prefix = new TCHAR (0, nFileOffset - 1);
- int byteCount2 = prefix.length () * TCHAR.sizeof;
- OS.MoveMemory (prefix, lpstrFile, byteCount2);
- filterPath = prefix.toString (0, prefix.length ());
-
- /*
- * Get each file from the buffer. Files are delimited
- * by a NULL character with 2 NULL characters at the end.
- */
- int count = 0;
- fileNames = new String [(style & SWT.MULTI) != 0 ? 4 : 1];
- int start = nFileOffset;
- do {
- int end = start;
- while (end < buffer.length () && buffer.tcharAt (end) != 0) end++;
- String string = buffer.toString (start, end - start);
- start = end;
- if (count == fileNames.length) {
- String [] newFileNames = new String [fileNames.length + 4];
- System.arraycopy (fileNames, 0, newFileNames, 0, fileNames.length);
- fileNames = newFileNames;
- }
- fileNames [count++] = string;
- if ((style & SWT.MULTI) == 0) break;
- start++;
- } while (start < buffer.length () && buffer.tcharAt (start) != 0);
-
- if (fileNames.length > 0) fileName = fileNames [0];
- String separator = "";
- int length = filterPath.length ();
- if (length > 0 && filterPath.charAt (length - 1) != '\\') {
- separator = "\\";
- }
- fullPath = filterPath + separator + fileName;
- if (count < fileNames.length) {
- String [] newFileNames = new String [count];
- System.arraycopy (fileNames, 0, newFileNames, 0, count);
- fileNames = newFileNames;
- }
- }
- }
-
- /* Free the memory that was allocated. */
- OS.HeapFree (hHeap, 0, lpstrFile);
- OS.HeapFree (hHeap, 0, lpstrFilter);
- OS.HeapFree (hHeap, 0, lpstrInitialDir);
- OS.HeapFree (hHeap, 0, lpstrTitle);
-
- /* Restore the old cursor */
- OS.SetCursor (hCursor);
-
- /* Restore the old focus */
- OS.SetFocus (hwndFocus);
-
- /*
- * This code is intentionally commented. On some
- * platforms, the owner window is repainted right
- * away when a dialog window exits. This behavior
- * is currently unspecified.
- */
-// if (hwndOwner != 0) OS.UpdateWindow (hwndOwner);
-
- /* Answer the full path or null */
- return fullPath;
-}
-
-/**
- * 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.
- *
- * @param extensions the file extension filter
- */
-public void setFilterExtensions (String [] extensions) {
- filterExtensions = extensions;
-}
-
-/**
- * Sets the file names which the dialog will
- * use to filter the files it shows to the argument,
- * which may be null.
- *
- * @param names the file name filter
- */
-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.
- *
- * @param string the directory path
- *
- * @see #setFilterExtensions
- */
-public void setFilterPath (String string) {
- filterPath = string;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; + +/** + * 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> + * IMPORTANT: This class is intended to be subclassed <em>only</em> + * within the SWT implementation. + * </p> + */ +public class FileDialog extends Dialog { + String [] filterNames = new String [0]; + String [] filterExtensions = new String [0]; + String [] fileNames = new String [0]; + String filterPath = "", fileName = ""; + static final String FILTER = "*.*"; + static int BUFFER_SIZE = 1024 * 10; + +/** + * Constructs a new instance of this class given only its + * parent. + * <p> + * Note: Currently, null can be passed in for the parent. + * This has the effect of creating the dialog on the currently active + * display if there is one. If there is no current display, the + * dialog 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_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.PRIMARY_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> + * Note: Currently, null can be passed in for the parent. + * This has the effect of creating the dialog on the currently active + * display if there is one. If there is no current display, the + * dialog 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_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, int style) { + super (parent, style); + checkSubclass (); +} + +/** + * Returns the path of the first file that was + * selected in the dialog relative to the filter path + * + * @return the relative path of the file + */ +public String getFileName () { + return fileName; +} + +/** + * Returns the paths of all files that were selected + * in the dialog relative to the filter path, or null + * if none are available. + * + * @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; +} + +/** + * Returns the file names which the dialog will + * use to filter the files it shows. + * + * @return the file name filter + */ +public String [] getFilterNames () { + return filterNames; +} + +/** + * Returns the directory path that the dialog will use. + * 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; +} + +/** + * 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 () { + int hHeap = OS.GetProcessHeap (); + + /* Get the owner HWND for the dialog */ + int hwndOwner = 0; + if (parent != null) hwndOwner = parent.handle; + + /* Convert the title and copy it into lpstrTitle */ + if (title == null) title = ""; + /* Use the character encoding for the default locale */ + TCHAR buffer3 = new TCHAR (0, title, true); + int byteCount3 = buffer3.length () * TCHAR.sizeof; + int lpstrTitle = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount3); + OS.MoveMemory (lpstrTitle, buffer3, byteCount3); + + /* Compute filters and copy into lpstrFilter */ + String strFilter = ""; + if (filterNames == null) filterNames = new String [0]; + if (filterExtensions == null) filterExtensions = new String [0]; + for (int i=0; i<filterExtensions.length; i++) { + String filterName = filterExtensions [i]; + if (i < filterNames.length) filterName = filterNames [i]; + strFilter = strFilter + filterName + '\0' + filterExtensions [i] + '\0'; + } + if (filterExtensions.length == 0) { + strFilter = strFilter + FILTER + '\0' + FILTER + '\0'; + } + /* Use the character encoding for the default locale */ + TCHAR buffer4 = new TCHAR (0, strFilter, true); + int byteCount4 = buffer4.length () * TCHAR.sizeof; + int lpstrFilter = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount4); + OS.MoveMemory (lpstrFilter, buffer4, byteCount4); + + /* Convert the fileName and filterName to C strings */ + if (fileName == null) fileName = ""; + /* Use the character encoding for the default locale */ + TCHAR name = new TCHAR (0, fileName, true); + + /* + * Copy the name into lpstrFile and ensure that the + * last byte is NULL and the buffer does not overrun. + * Note that the longest that a single path name can + * be on Windows is 256. + */ + int nMaxFile = 256; + if ((style & SWT.MULTI) != 0) nMaxFile = Math.max (nMaxFile, BUFFER_SIZE); + int byteCount = nMaxFile * TCHAR.sizeof; + int lpstrFile = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + int byteCountFile = Math.min (name.length () * TCHAR.sizeof, byteCount - TCHAR.sizeof); + OS.MoveMemory (lpstrFile, name, byteCountFile); + + /* + * Copy the path into lpstrInitialDir and ensure that + * the last byte is NULL and the buffer does not overrun. + */ + if (filterPath == null) filterPath = ""; + /* Use the character encoding for the default locale */ + TCHAR path = new TCHAR (0, filterPath.replace ('/', '\\'), true); + int lpstrInitialDir = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + int byteCountDir = Math.min (path.length () * TCHAR.sizeof, byteCount - TCHAR.sizeof); + OS.MoveMemory (lpstrInitialDir, path, byteCountDir); + + /* Create the file dialog struct */ + OPENFILENAME struct = new OPENFILENAME (); + struct.lStructSize = OPENFILENAME.sizeof; + struct.Flags = OS.OFN_HIDEREADONLY | OS.OFN_NOCHANGEDIR; + if ((style & SWT.MULTI) != 0) { + struct.Flags |= OS.OFN_ALLOWMULTISELECT | OS.OFN_EXPLORER; + } + struct.hwndOwner = hwndOwner; + struct.lpstrTitle = lpstrTitle; + struct.lpstrFile = lpstrFile; + struct.nMaxFile = nMaxFile; + struct.lpstrInitialDir = lpstrInitialDir; + struct.lpstrFilter = lpstrFilter; + struct.nFilterIndex = 0; + + /* + * Feature in Windows. The focus window is not saved and + * and restored automatically by the call to GetOpenFileName (). + * The fix is to save and restore the focus window. + */ + int hwndFocus = OS.GetFocus (); + + /* + * Bug/Feature in Windows. When Windows opens the standard + * file dialog, it changes the cursor to the hourglass and + * does not put it back. The fix is to save the current + * cursor and restore it when the dialog closes. + */ + int hCursor = OS.GetCursor (); + + /* + * Open the dialog. If the open fails due to an invalid + * file name, use an empty file name and open it again. + */ + boolean save = (style & SWT.SAVE) != 0; + boolean success = (save) ? OS.GetSaveFileName (struct) : OS.GetOpenFileName (struct); + if (OS.CommDlgExtendedError () == OS.FNERR_INVALIDFILENAME) { + OS.MoveMemory (lpstrFile, new TCHAR (0, "", true), TCHAR.sizeof); + success = (save) ? OS.GetSaveFileName (struct) : OS.GetOpenFileName (struct); + } + + /* Set the new path, file name and filter */ + fileNames = null; + String fullPath = null; + if (success) { + + /* Use the character encoding for the default locale */ + TCHAR buffer = new TCHAR (0, struct.nMaxFile); + int byteCount1 = buffer.length () * TCHAR.sizeof; + OS.MoveMemory (buffer, lpstrFile, byteCount1); + + /* + * Bug in WinCE. For some reason, nFileOffset and nFileExtension + * are always zero on WinCE HPC. nFileOffset is always zero on + * WinCE PPC when using GetSaveFileName. nFileOffset is correctly + * set on WinCE PPC when using OpenFileName. The fix is to parse + * lpstrFile to calculate nFileOffset. + * + * Note: WinCE does not support multi-select file dialogs. + */ + int nFileOffset = struct.nFileOffset; + if (OS.IsWinCE && nFileOffset == 0) { + int index = 0; + while (index < buffer.length ()) { + int ch = buffer.tcharAt (index); + if (ch == 0) break; + if (ch == '\\') nFileOffset = index + 1; + index++; + } + } + if (nFileOffset > 0) { + + /* Use the character encoding for the default locale */ + TCHAR prefix = new TCHAR (0, nFileOffset - 1); + int byteCount2 = prefix.length () * TCHAR.sizeof; + OS.MoveMemory (prefix, lpstrFile, byteCount2); + filterPath = prefix.toString (0, prefix.length ()); + + /* + * Get each file from the buffer. Files are delimited + * by a NULL character with 2 NULL characters at the end. + */ + int count = 0; + fileNames = new String [(style & SWT.MULTI) != 0 ? 4 : 1]; + int start = nFileOffset; + do { + int end = start; + while (end < buffer.length () && buffer.tcharAt (end) != 0) end++; + String string = buffer.toString (start, end - start); + start = end; + if (count == fileNames.length) { + String [] newFileNames = new String [fileNames.length + 4]; + System.arraycopy (fileNames, 0, newFileNames, 0, fileNames.length); + fileNames = newFileNames; + } + fileNames [count++] = string; + if ((style & SWT.MULTI) == 0) break; + start++; + } while (start < buffer.length () && buffer.tcharAt (start) != 0); + + if (fileNames.length > 0) fileName = fileNames [0]; + String separator = ""; + int length = filterPath.length (); + if (length > 0 && filterPath.charAt (length - 1) != '\\') { + separator = "\\"; + } + fullPath = filterPath + separator + fileName; + if (count < fileNames.length) { + String [] newFileNames = new String [count]; + System.arraycopy (fileNames, 0, newFileNames, 0, count); + fileNames = newFileNames; + } + } + } + + /* Free the memory that was allocated. */ + OS.HeapFree (hHeap, 0, lpstrFile); + OS.HeapFree (hHeap, 0, lpstrFilter); + OS.HeapFree (hHeap, 0, lpstrInitialDir); + OS.HeapFree (hHeap, 0, lpstrTitle); + + /* Restore the old cursor */ + OS.SetCursor (hCursor); + + /* Restore the old focus */ + OS.SetFocus (hwndFocus); + + /* + * This code is intentionally commented. On some + * platforms, the owner window is repainted right + * away when a dialog window exits. This behavior + * is currently unspecified. + */ +// if (hwndOwner != 0) OS.UpdateWindow (hwndOwner); + + /* Answer the full path or null */ + return fullPath; +} + +/** + * 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. + * + * @param extensions the file extension filter + */ +public void setFilterExtensions (String [] extensions) { + filterExtensions = extensions; +} + +/** + * Sets the file names which the dialog will + * use to filter the files it shows to the argument, + * which may be null. + * + * @param names the file name filter + */ +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. + * + * @param string the directory path + * + * @see #setFilterExtensions + */ +public void setFilterPath (String string) { + filterPath = string; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/FontDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/FontDialog.java index 494dc309ee..229cb2442e 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/FontDialog.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/FontDialog.java @@ -1,237 +1,237 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.internal.Compatibility;
-
-/**
- * Instances of this class allow the user to select a font
- * from all available fonts in the system.
- * <p>
- * IMPORTANT: This class is intended to be subclassed <em>only</em>
- * within the SWT implementation.
- * </p>
- */
-public class FontDialog extends Dialog {
- FontData fontData;
- RGB rgb;
-
-/**
- * Constructs a new instance of this class given only its
- * parent.
- * <p>
- * Note: Currently, null can be passed in for the parent.
- * This has the effect of creating the dialog on the currently active
- * display if there is one. If there is no current display, the
- * dialog 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_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.PRIMARY_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>
- * Note: Currently, null can be passed in for the parent.
- * This has the effect of creating the dialog on the currently active
- * display if there is one. If there is no current display, the
- * dialog 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_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, style);
- checkSubclass ();
-}
-
-/**
- * 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
- */
-public FontData getFontData() {
- return fontData;
-}
-
-/**
- * Returns the currently selected color in the receiver.
- *
- * @return the RGB value for the selected color, may be 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 () {
- if (OS.IsWinCE) SWT.error (SWT.ERROR_NOT_IMPLEMENTED);
-
- /* Get the owner HWND for the dialog */
- int hwndOwner = 0;
- if (parent != null) hwndOwner = parent.handle;
-
- /* Open the dialog */
- int hHeap = OS.GetProcessHeap ();
- CHOOSEFONT lpcf = new CHOOSEFONT ();
- lpcf.lStructSize = CHOOSEFONT.sizeof;
- lpcf.hwndOwner = hwndOwner;
- lpcf.Flags = OS.CF_SCREENFONTS | OS.CF_EFFECTS;
- int lpLogFont = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, LOGFONT.sizeof);
- if (fontData != null && fontData.data != null) {
- LOGFONT logFont = fontData.data;
- int lfHeight = logFont.lfHeight;
- int hDC = OS.GetDC (0);
- int pixels = -Compatibility.round (fontData.height * OS.GetDeviceCaps(hDC, OS.LOGPIXELSY), 72);
- OS.ReleaseDC (0, hDC);
- logFont.lfHeight = pixels;
- lpcf.Flags |= OS.CF_INITTOLOGFONTSTRUCT;
- OS.MoveMemory (lpLogFont, logFont, LOGFONT.sizeof);
- logFont.lfHeight = lfHeight;
- }
- lpcf.lpLogFont = lpLogFont;
- if (rgb != null) {
- int red = rgb.red & 0xFF;
- int green = (rgb.green << 8) & 0xFF00;
- int blue = (rgb.blue << 16) & 0xFF0000;
- lpcf.rgbColors = red | green | blue;
- }
- boolean success = OS.ChooseFont (lpcf);
- if (success) {
- LOGFONT logFont = new LOGFONT ();
- OS.MoveMemory (logFont, lpLogFont, LOGFONT.sizeof);
-
- /*
- * This will not work on multiple screens or
- * for printing. Should use DC for the proper device.
- */
- int hDC = OS.GetDC(0);
- int logPixelsY = OS.GetDeviceCaps(hDC, OS.LOGPIXELSY);
- int pixels = 0;
- if (logFont.lfHeight > 0) {
- /*
- * Feature in Windows. If the lfHeight of the LOGFONT structure
- * is positive, the lfHeight measures the height of the entire
- * cell, including internal leading, in logical units. Since the
- * height of a font in points does not include the internal leading,
- * we must subtract the internal leading, which requires a TEXTMETRIC,
- * which in turn requires font creation.
- */
- int hFont = OS.CreateFontIndirect(logFont);
- int oldFont = OS.SelectObject(hDC, hFont);
- TEXTMETRIC lptm = new TEXTMETRIC();
- OS.GetTextMetrics(hDC, lptm);
- OS.SelectObject(hDC, oldFont);
- OS.DeleteObject(hFont);
- pixels = logFont.lfHeight - lptm.tmInternalLeading;
- } else {
- pixels = -logFont.lfHeight;
- }
- OS.ReleaseDC(0, hDC);
-
- int points = Compatibility.round(pixels * 72, logPixelsY);
- fontData = FontData.win32_new (logFont, points);
- int red = lpcf.rgbColors & 0xFF;
- int green = (lpcf.rgbColors >> 8) & 0xFF;
- int blue = (lpcf.rgbColors >> 16) & 0xFF;
- rgb = new RGB (red, green, blue);
- }
-
- /* Free the OS memory */
- if (lpLogFont != 0) OS.HeapFree (hHeap, 0, lpLogFont);
-
- /*
- * This code is intentionally commented. On some
- * platforms, the owner window is repainted right
- * away when a dialog window exits. This behavior
- * is currently unspecified.
- */
-// if (hwndOwner != 0) OS.UpdateWindow (hwndOwner);
-
- if (!success) return null;
- 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
- */
-public void setFontData (FontData fontData) {
- this.fontData = fontData;
-}
-
-/**
- * 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 to select a default when
- * open() is called
- *
- * @see PaletteData#getRGBs
- *
- * @since 2.1
- */
-public void setRGB (RGB rgb) {
- this.rgb = rgb;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.internal.Compatibility; + +/** + * Instances of this class allow the user to select a font + * from all available fonts in the system. + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> + * within the SWT implementation. + * </p> + */ +public class FontDialog extends Dialog { + FontData fontData; + RGB rgb; + +/** + * Constructs a new instance of this class given only its + * parent. + * <p> + * Note: Currently, null can be passed in for the parent. + * This has the effect of creating the dialog on the currently active + * display if there is one. If there is no current display, the + * dialog 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_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.PRIMARY_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> + * Note: Currently, null can be passed in for the parent. + * This has the effect of creating the dialog on the currently active + * display if there is one. If there is no current display, the + * dialog 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_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, style); + checkSubclass (); +} + +/** + * 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 + */ +public FontData getFontData() { + return fontData; +} + +/** + * Returns the currently selected color in the receiver. + * + * @return the RGB value for the selected color, may be 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 () { + if (OS.IsWinCE) SWT.error (SWT.ERROR_NOT_IMPLEMENTED); + + /* Get the owner HWND for the dialog */ + int hwndOwner = 0; + if (parent != null) hwndOwner = parent.handle; + + /* Open the dialog */ + int hHeap = OS.GetProcessHeap (); + CHOOSEFONT lpcf = new CHOOSEFONT (); + lpcf.lStructSize = CHOOSEFONT.sizeof; + lpcf.hwndOwner = hwndOwner; + lpcf.Flags = OS.CF_SCREENFONTS | OS.CF_EFFECTS; + int lpLogFont = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, LOGFONT.sizeof); + if (fontData != null && fontData.data != null) { + LOGFONT logFont = fontData.data; + int lfHeight = logFont.lfHeight; + int hDC = OS.GetDC (0); + int pixels = -Compatibility.round (fontData.height * OS.GetDeviceCaps(hDC, OS.LOGPIXELSY), 72); + OS.ReleaseDC (0, hDC); + logFont.lfHeight = pixels; + lpcf.Flags |= OS.CF_INITTOLOGFONTSTRUCT; + OS.MoveMemory (lpLogFont, logFont, LOGFONT.sizeof); + logFont.lfHeight = lfHeight; + } + lpcf.lpLogFont = lpLogFont; + if (rgb != null) { + int red = rgb.red & 0xFF; + int green = (rgb.green << 8) & 0xFF00; + int blue = (rgb.blue << 16) & 0xFF0000; + lpcf.rgbColors = red | green | blue; + } + boolean success = OS.ChooseFont (lpcf); + if (success) { + LOGFONT logFont = new LOGFONT (); + OS.MoveMemory (logFont, lpLogFont, LOGFONT.sizeof); + + /* + * This will not work on multiple screens or + * for printing. Should use DC for the proper device. + */ + int hDC = OS.GetDC(0); + int logPixelsY = OS.GetDeviceCaps(hDC, OS.LOGPIXELSY); + int pixels = 0; + if (logFont.lfHeight > 0) { + /* + * Feature in Windows. If the lfHeight of the LOGFONT structure + * is positive, the lfHeight measures the height of the entire + * cell, including internal leading, in logical units. Since the + * height of a font in points does not include the internal leading, + * we must subtract the internal leading, which requires a TEXTMETRIC, + * which in turn requires font creation. + */ + int hFont = OS.CreateFontIndirect(logFont); + int oldFont = OS.SelectObject(hDC, hFont); + TEXTMETRIC lptm = new TEXTMETRIC(); + OS.GetTextMetrics(hDC, lptm); + OS.SelectObject(hDC, oldFont); + OS.DeleteObject(hFont); + pixels = logFont.lfHeight - lptm.tmInternalLeading; + } else { + pixels = -logFont.lfHeight; + } + OS.ReleaseDC(0, hDC); + + int points = Compatibility.round(pixels * 72, logPixelsY); + fontData = FontData.win32_new (logFont, points); + int red = lpcf.rgbColors & 0xFF; + int green = (lpcf.rgbColors >> 8) & 0xFF; + int blue = (lpcf.rgbColors >> 16) & 0xFF; + rgb = new RGB (red, green, blue); + } + + /* Free the OS memory */ + if (lpLogFont != 0) OS.HeapFree (hHeap, 0, lpLogFont); + + /* + * This code is intentionally commented. On some + * platforms, the owner window is repainted right + * away when a dialog window exits. This behavior + * is currently unspecified. + */ +// if (hwndOwner != 0) OS.UpdateWindow (hwndOwner); + + if (!success) return null; + 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 + */ +public void setFontData (FontData fontData) { + this.fontData = fontData; +} + +/** + * 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 to select a default when + * open() is called + * + * @see PaletteData#getRGBs + * + * @since 2.1 + */ +public void setRGB (RGB rgb) { + this.rgb = rgb; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Group.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Group.java index a82ca8070c..89c1e85d23 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Group.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Group.java @@ -1,373 +1,373 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-
-/**
- * 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>
- */
-
-public class Group extends Composite {
- static final int GroupProc;
- static final TCHAR GroupClass = new TCHAR (0, OS.IsWinCE ? "BUTTON" : "SWT_GROUP", true);
- static {
- /*
- * Feature in Windows. The group box window class
- * uses the CS_HREDRAW and CS_VREDRAW style bits to
- * force a full redraw of the control and all children
- * when resized. This causes flashing. The fix is to
- * register a new window class without these bits and
- * implement special code that damages only the exposed
- * area.
- *
- * Feature in WinCE. On certain devices, defining
- * a new window class which looks like BUTTON causes
- * CreateWindowEx() to crash. The workaround is to use
- * the class Button directly.
- */
- WNDCLASS lpWndClass = new WNDCLASS ();
- if (OS.IsWinCE) {
- OS.GetClassInfo (0, GroupClass, lpWndClass);
- GroupProc = lpWndClass.lpfnWndProc;
- } else {
- TCHAR WC_BUTTON = new TCHAR (0, "BUTTON", true);
- OS.GetClassInfo (0, WC_BUTTON, lpWndClass);
- GroupProc = lpWndClass.lpfnWndProc;
- int hInstance = OS.GetModuleHandle (null);
- if (!OS.GetClassInfo (hInstance, GroupClass, lpWndClass)) {
- int hHeap = OS.GetProcessHeap ();
- lpWndClass.hInstance = hInstance;
- lpWndClass.style &= ~(OS.CS_HREDRAW | OS.CS_VREDRAW);
- int byteCount = GroupClass.length () * TCHAR.sizeof;
- int lpszClassName = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- OS.MoveMemory (lpszClassName, GroupClass, byteCount);
- lpWndClass.lpszClassName = lpszClassName;
- OS.RegisterClass (lpWndClass);
- // OS.HeapFree (hHeap, 0, lpszClassName);
- }
- }
- }
-
-/**
- * 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));
-}
-
-int callWindowProc (int msg, int wParam, int lParam) {
- if (handle == 0) return 0;
- /*
- * Feature in Windows. When the user clicks on the group
- * box label, the group box takes focus. This is unwanted.
- * The fix is to avoid calling the group box window proc.
- */
- switch (msg) {
- case OS.WM_LBUTTONDOWN:
- case OS.WM_LBUTTONDBLCLK:
- return OS.DefWindowProc (handle, msg, wParam, lParam);
- }
- return OS.CallWindowProc (GroupProc, handle, msg, wParam, lParam);
-}
-
-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 Point computeSize (int wHint, int hHint, boolean changed) {
- checkWidget ();
- int width = 0, height = 0;
- RECT rect = new RECT ();
- int newFont, oldFont = 0;
- int hDC = OS.GetDC (handle);
- newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
- int length = OS.GetWindowTextLength (handle);
- TCHAR buffer1 = new TCHAR (getCodePage (), length + 1);
- OS.GetWindowText (handle, buffer1, length + 1);
- int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE;
- OS.DrawText (hDC, buffer1, length, rect, flags);
- if (newFont != 0) OS.SelectObject (hDC, oldFont);
- OS.ReleaseDC (handle, hDC);
- Point size;
- if (layout != null) {
- size = layout.computeSize (this, wHint, hHint, changed);
- } else {
- size = minimumSize ();
- }
- width = size.x; height = size.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;
- Rectangle trim = computeTrim (0, 0, width, height);
- width = Math.max (trim.width, rect.right - rect.left + 6);
- height = trim.height;
- return new Point (width, height);
-}
-
-public Rectangle computeTrim (int x, int y, int width, int height) {
- checkWidget ();
- Rectangle trim = super.computeTrim (x, y, width, height);
- int newFont, oldFont = 0;
- int hDC = OS.GetDC (handle);
- newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
- TEXTMETRIC tm = new TEXTMETRIC ();
- OS.GetTextMetrics (hDC, tm);
- if (newFont != 0) OS.SelectObject (hDC, oldFont);
- OS.ReleaseDC (handle, hDC);
- int inset = 3;
- trim.x -= inset; trim.y -= tm.tmHeight;
- trim.width += (inset * 2); trim.height += tm.tmHeight + inset;
- return trim;
-}
-
-void createHandle () {
- super.createHandle ();
- state &= ~CANVAS;
-}
-
-public Rectangle getClientArea () {
- checkWidget ();
- forceResize ();
- RECT rect = new RECT ();
- OS.GetClientRect (handle, rect);
- int newFont, oldFont = 0;
- int hDC = OS.GetDC (handle);
- newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
- TEXTMETRIC tm = new TEXTMETRIC ();
- OS.GetTextMetrics (hDC, tm);
- if (newFont != 0) OS.SelectObject (hDC, oldFont);
- OS.ReleaseDC (handle, hDC);
- int inset = 3, x = inset, y = tm.tmHeight;
- return new Rectangle (x, y, rect.right - (inset * 2), rect.bottom - y - inset);
-}
-
-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 ();
- int length = OS.GetWindowTextLength (handle);
- if (length == 0) return "";
- TCHAR buffer = new TCHAR (getCodePage (), length + 1);
- OS.GetWindowText (handle, buffer, length + 1);
- return buffer.toString (0, length);
-}
-
-boolean mnemonicHit (char key) {
- return setFocus ();
-}
-
-boolean mnemonicMatch (char key) {
- char mnemonic = findMnemonic (getText ());
- if (mnemonic == '\0') return false;
- return Character.toUpperCase (key) == Character.toUpperCase (mnemonic);
-}
-
-/**
- * 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 '&' that causes the next
- * character to be the mnemonic. When the user presses a
- * key sequence that matches the mnemonic, focus is assgned
- * 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
- *'&' can be escaped by doubling it in the string, causing
- * a single '&' to be displayed.
- * </p>
- * @param text the new text
- *
- * @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>
- */
-public void setText (String string) {
- checkWidget ();
- if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
- TCHAR buffer = new TCHAR (getCodePage (), string, true);
- OS.SetWindowText (handle, buffer);
-}
-
-int widgetStyle () {
- /*
- * Bug in Windows. When GetDCEx () is called with DCX_INTERSECTUPDATE,
- * the HDC that is returned does not include the current update region.
- * This was confirmed under DEBUG Windows when GetDCEx () complained about
- * invalid flags. Therefore, it is not easily possible to get an HDC from
- * outside of WM_PAINT that includes the current damage and clips children.
- * Because the receiver has children and draws a frame and label, it is
- * necessary that the receiver always draw clipped, in the current damaged
- * area. The fix is to force the receiver to be fully clipped by including
- * WS_CLIPCHILDREN and WS_CLIPSIBLINGS in the default style bits.
- */
- return super.widgetStyle () | OS.BS_GROUPBOX | OS.WS_CLIPCHILDREN | OS.WS_CLIPSIBLINGS;
-}
-
-TCHAR windowClass () {
- return GroupClass;
-}
-
-int windowProc () {
- return GroupProc;
-}
-
-LRESULT WM_ERASEBKGND (int wParam, int lParam) {
- LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
- if (result != null) return result;
- /*
- * Feaure in Windows. Group boxes do not erase
- * the background before drawing. The fix is to
- * fill the background.
- */
- drawBackground (wParam);
- return LRESULT.ONE;
-}
-
-LRESULT WM_NCHITTEST (int wParam, int lParam) {
- LRESULT result = super.WM_NCHITTEST (wParam, lParam);
- if (result != null) return result;
- /*
- * Feature in Windows. The window proc for the group box
- * returns HTTRANSPARENT indicating that mouse messages
- * should not be delivered to the receiver and any children.
- * Normally, group boxes in Windows do not have children and
- * this is the correct behavior for this case. Because we
- * allow children, answer HTCLIENT to allow mouse messages
- * to be delivered to the children.
- */
- int code = callWindowProc (OS.WM_NCHITTEST, wParam, lParam);
- if (code == OS.HTTRANSPARENT) code = OS.HTCLIENT;
- return new LRESULT (code);
-}
-
-LRESULT WM_MOUSEMOVE (int wParam, int lParam) {
- LRESULT result = super.WM_MOUSEMOVE (wParam, lParam);
- if (result != null) return result;
- /*
- * Feature in Windows. In version 6.00 of COMCTL32.DLL,
- * every time the mouse moves, the group title redraws.
- * This only happens when WM_NCHITTEST returns HTCLIENT.
- * The fix is to avoid calling the group window proc.
- */
- return LRESULT.ZERO;
-}
-
-LRESULT WM_PRINTCLIENT (int wParam, int lParam) {
- LRESULT result = super.WM_PRINTCLIENT (wParam, lParam);
- if (result != null) return result;
- /*
- * Feature in Windows. In version 6.00 of COMCTL32.DLL,
- * when WM_PRINTCLIENT is sent from a child BS_GROUP
- * control to a parent BS_GROUP, the parent BS_GROUP
- * clears the font from the HDC. Normally, group boxes
- * in Windows do not have children so this behavior is
- * undefined. When the parent of a BS_GROUP is not a
- * BS_GROUP, there is no problem. The fix is to save
- * and restore the current font.
- */
- if (COMCTL32_MAJOR >= 6) {
- int hFont = OS.GetCurrentObject (wParam, OS.OBJ_FONT);
- int code = callWindowProc (OS.WM_PRINTCLIENT, wParam, lParam);
- OS.SelectObject (wParam, hFont);
- return new LRESULT (code);
- }
- return result;
-}
-
-LRESULT WM_SIZE (int wParam, int lParam) {
- LRESULT result = super.WM_SIZE (wParam, lParam);
- if (OS.IsWinCE) return result;
- OS.InvalidateRect (handle, null, true);
- return result;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; + +/** + * 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> + */ + +public class Group extends Composite { + static final int GroupProc; + static final TCHAR GroupClass = new TCHAR (0, OS.IsWinCE ? "BUTTON" : "SWT_GROUP", true); + static { + /* + * Feature in Windows. The group box window class + * uses the CS_HREDRAW and CS_VREDRAW style bits to + * force a full redraw of the control and all children + * when resized. This causes flashing. The fix is to + * register a new window class without these bits and + * implement special code that damages only the exposed + * area. + * + * Feature in WinCE. On certain devices, defining + * a new window class which looks like BUTTON causes + * CreateWindowEx() to crash. The workaround is to use + * the class Button directly. + */ + WNDCLASS lpWndClass = new WNDCLASS (); + if (OS.IsWinCE) { + OS.GetClassInfo (0, GroupClass, lpWndClass); + GroupProc = lpWndClass.lpfnWndProc; + } else { + TCHAR WC_BUTTON = new TCHAR (0, "BUTTON", true); + OS.GetClassInfo (0, WC_BUTTON, lpWndClass); + GroupProc = lpWndClass.lpfnWndProc; + int hInstance = OS.GetModuleHandle (null); + if (!OS.GetClassInfo (hInstance, GroupClass, lpWndClass)) { + int hHeap = OS.GetProcessHeap (); + lpWndClass.hInstance = hInstance; + lpWndClass.style &= ~(OS.CS_HREDRAW | OS.CS_VREDRAW); + int byteCount = GroupClass.length () * TCHAR.sizeof; + int lpszClassName = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + OS.MoveMemory (lpszClassName, GroupClass, byteCount); + lpWndClass.lpszClassName = lpszClassName; + OS.RegisterClass (lpWndClass); + // OS.HeapFree (hHeap, 0, lpszClassName); + } + } + } + +/** + * 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)); +} + +int callWindowProc (int msg, int wParam, int lParam) { + if (handle == 0) return 0; + /* + * Feature in Windows. When the user clicks on the group + * box label, the group box takes focus. This is unwanted. + * The fix is to avoid calling the group box window proc. + */ + switch (msg) { + case OS.WM_LBUTTONDOWN: + case OS.WM_LBUTTONDBLCLK: + return OS.DefWindowProc (handle, msg, wParam, lParam); + } + return OS.CallWindowProc (GroupProc, handle, msg, wParam, lParam); +} + +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 Point computeSize (int wHint, int hHint, boolean changed) { + checkWidget (); + int width = 0, height = 0; + RECT rect = new RECT (); + int newFont, oldFont = 0; + int hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); + int length = OS.GetWindowTextLength (handle); + TCHAR buffer1 = new TCHAR (getCodePage (), length + 1); + OS.GetWindowText (handle, buffer1, length + 1); + int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE; + OS.DrawText (hDC, buffer1, length, rect, flags); + if (newFont != 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + Point size; + if (layout != null) { + size = layout.computeSize (this, wHint, hHint, changed); + } else { + size = minimumSize (); + } + width = size.x; height = size.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; + Rectangle trim = computeTrim (0, 0, width, height); + width = Math.max (trim.width, rect.right - rect.left + 6); + height = trim.height; + return new Point (width, height); +} + +public Rectangle computeTrim (int x, int y, int width, int height) { + checkWidget (); + Rectangle trim = super.computeTrim (x, y, width, height); + int newFont, oldFont = 0; + int hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); + TEXTMETRIC tm = new TEXTMETRIC (); + OS.GetTextMetrics (hDC, tm); + if (newFont != 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + int inset = 3; + trim.x -= inset; trim.y -= tm.tmHeight; + trim.width += (inset * 2); trim.height += tm.tmHeight + inset; + return trim; +} + +void createHandle () { + super.createHandle (); + state &= ~CANVAS; +} + +public Rectangle getClientArea () { + checkWidget (); + forceResize (); + RECT rect = new RECT (); + OS.GetClientRect (handle, rect); + int newFont, oldFont = 0; + int hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); + TEXTMETRIC tm = new TEXTMETRIC (); + OS.GetTextMetrics (hDC, tm); + if (newFont != 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + int inset = 3, x = inset, y = tm.tmHeight; + return new Rectangle (x, y, rect.right - (inset * 2), rect.bottom - y - inset); +} + +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 (); + int length = OS.GetWindowTextLength (handle); + if (length == 0) return ""; + TCHAR buffer = new TCHAR (getCodePage (), length + 1); + OS.GetWindowText (handle, buffer, length + 1); + return buffer.toString (0, length); +} + +boolean mnemonicHit (char key) { + return setFocus (); +} + +boolean mnemonicMatch (char key) { + char mnemonic = findMnemonic (getText ()); + if (mnemonic == '\0') return false; + return Character.toUpperCase (key) == Character.toUpperCase (mnemonic); +} + +/** + * 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 '&' that causes the next + * character to be the mnemonic. When the user presses a + * key sequence that matches the mnemonic, focus is assgned + * 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 + *'&' can be escaped by doubling it in the string, causing + * a single '&' to be displayed. + * </p> + * @param text the new text + * + * @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> + */ +public void setText (String string) { + checkWidget (); + if (string == null) error (SWT.ERROR_NULL_ARGUMENT); + TCHAR buffer = new TCHAR (getCodePage (), string, true); + OS.SetWindowText (handle, buffer); +} + +int widgetStyle () { + /* + * Bug in Windows. When GetDCEx () is called with DCX_INTERSECTUPDATE, + * the HDC that is returned does not include the current update region. + * This was confirmed under DEBUG Windows when GetDCEx () complained about + * invalid flags. Therefore, it is not easily possible to get an HDC from + * outside of WM_PAINT that includes the current damage and clips children. + * Because the receiver has children and draws a frame and label, it is + * necessary that the receiver always draw clipped, in the current damaged + * area. The fix is to force the receiver to be fully clipped by including + * WS_CLIPCHILDREN and WS_CLIPSIBLINGS in the default style bits. + */ + return super.widgetStyle () | OS.BS_GROUPBOX | OS.WS_CLIPCHILDREN | OS.WS_CLIPSIBLINGS; +} + +TCHAR windowClass () { + return GroupClass; +} + +int windowProc () { + return GroupProc; +} + +LRESULT WM_ERASEBKGND (int wParam, int lParam) { + LRESULT result = super.WM_ERASEBKGND (wParam, lParam); + if (result != null) return result; + /* + * Feaure in Windows. Group boxes do not erase + * the background before drawing. The fix is to + * fill the background. + */ + drawBackground (wParam); + return LRESULT.ONE; +} + +LRESULT WM_NCHITTEST (int wParam, int lParam) { + LRESULT result = super.WM_NCHITTEST (wParam, lParam); + if (result != null) return result; + /* + * Feature in Windows. The window proc for the group box + * returns HTTRANSPARENT indicating that mouse messages + * should not be delivered to the receiver and any children. + * Normally, group boxes in Windows do not have children and + * this is the correct behavior for this case. Because we + * allow children, answer HTCLIENT to allow mouse messages + * to be delivered to the children. + */ + int code = callWindowProc (OS.WM_NCHITTEST, wParam, lParam); + if (code == OS.HTTRANSPARENT) code = OS.HTCLIENT; + return new LRESULT (code); +} + +LRESULT WM_MOUSEMOVE (int wParam, int lParam) { + LRESULT result = super.WM_MOUSEMOVE (wParam, lParam); + if (result != null) return result; + /* + * Feature in Windows. In version 6.00 of COMCTL32.DLL, + * every time the mouse moves, the group title redraws. + * This only happens when WM_NCHITTEST returns HTCLIENT. + * The fix is to avoid calling the group window proc. + */ + return LRESULT.ZERO; +} + +LRESULT WM_PRINTCLIENT (int wParam, int lParam) { + LRESULT result = super.WM_PRINTCLIENT (wParam, lParam); + if (result != null) return result; + /* + * Feature in Windows. In version 6.00 of COMCTL32.DLL, + * when WM_PRINTCLIENT is sent from a child BS_GROUP + * control to a parent BS_GROUP, the parent BS_GROUP + * clears the font from the HDC. Normally, group boxes + * in Windows do not have children so this behavior is + * undefined. When the parent of a BS_GROUP is not a + * BS_GROUP, there is no problem. The fix is to save + * and restore the current font. + */ + if (COMCTL32_MAJOR >= 6) { + int hFont = OS.GetCurrentObject (wParam, OS.OBJ_FONT); + int code = callWindowProc (OS.WM_PRINTCLIENT, wParam, lParam); + OS.SelectObject (wParam, hFont); + return new LRESULT (code); + } + return result; +} + +LRESULT WM_SIZE (int wParam, int lParam) { + LRESULT result = super.WM_SIZE (wParam, lParam); + if (OS.IsWinCE) return result; + OS.InvalidateRect (handle, null, true); + return result; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ImageList.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ImageList.java index e5c1275f7d..1cac1c7058 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ImageList.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ImageList.java @@ -1,254 +1,254 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-
-class ImageList {
- int handle, refCount;
- Image [] images;
- static final int CREATE_FLAGS;
- static {
- if (OS.IsWinCE) {
- CREATE_FLAGS = OS.ILC_MASK | OS.ILC_COLOR;
- } else {
- int flags = OS.ILC_MASK;
- int hDC = OS.GetDC (0);
- int bits = OS.GetDeviceCaps (hDC, OS.BITSPIXEL);
- int planes = OS.GetDeviceCaps (hDC, OS.PLANES);
- OS.ReleaseDC (0, hDC);
- int depth = bits * planes;
- switch (depth) {
- case 4:
- flags |= OS.ILC_COLOR4;
- break;
- case 8:
- flags |= OS.ILC_COLOR8;
- break;
- case 16:
- flags |= OS.ILC_COLOR16;
- break;
- case 24:
- flags |= OS.ILC_COLOR24;
- break;
- case 32:
- flags |= OS.ILC_COLOR32;
- break;
- default:
- flags |= OS.ILC_COLOR;
- }
- CREATE_FLAGS = flags;
- }
- }
-
-public ImageList () {
- handle = OS.ImageList_Create (32, 32, CREATE_FLAGS, 16, 16);
- images = new Image [4];
-}
-
-public int add (Image image) {
- int count = OS.ImageList_GetImageCount (handle);
- int index = 0;
- while (index < count) {
- if (images [index] != null) {
- if (images [index].isDisposed ()) images [index] = null;
- }
- if (images [index] == null) break;
- index++;
- }
- int [] cx = new int [1], cy = new int [1];
- if (count == 0) {
- Rectangle rect = image.getBounds();
- cx [0] = rect.width;
- cy [0] = rect.height;
- OS.ImageList_SetIconSize (handle, cx [0], cy [0]);
- }
- int hImage = image.handle;
- OS.ImageList_GetIconSize (handle, cx, cy);
- switch (image.type) {
- case SWT.BITMAP: {
- int hBitmap = copyBitmap (hImage, cx [0], cy [0]);
- int background = -1;
- Color color = image.getBackground ();
- if (color != null) background = color.handle;
- if (index == count) {
- if (background != -1) {
- OS.ImageList_AddMasked (handle, hBitmap, background);
- } else {
- int hMask = createMask (hBitmap, cx [0], cy [0], background);
- OS.ImageList_Add (handle, hBitmap, hMask);
- OS.DeleteObject (hMask);
- }
- } else {
- int hMask = createMask (hBitmap, cx [0], cy [0], background);
- OS.ImageList_Replace (handle, index, hBitmap, hMask);
- OS.DeleteObject (hMask);
- }
- OS.DeleteObject (hBitmap);
- break;
- }
- case SWT.ICON: {
- if (OS.IsWinCE) {
- OS.ImageList_ReplaceIcon (handle, index == count ? -1 : index, hImage);
- } else {
- int hIcon = copyIcon (hImage, cx [0], cy [0]);
- OS.ImageList_ReplaceIcon (handle, index == count ? -1 : index, hIcon);
- OS.DestroyIcon (hIcon);
- }
- break;
- }
- }
- if (index == images.length) {
- Image [] newImages = new Image [images.length + 4];
- System.arraycopy (images, 0, newImages, 0, images.length);
- images = newImages;
- }
- images [index] = image;
- return index;
-}
-
-int addRef() {
- return ++refCount;
-}
-
-int copyBitmap (int hImage, int width, int height) {
- BITMAP bm = new BITMAP ();
- OS.GetObject (hImage, BITMAP.sizeof, bm);
- int hDC = OS.GetDC (0);
- int hdc1 = OS.CreateCompatibleDC (hDC);
- OS.SelectObject (hdc1, hImage);
- int hdc2 = OS.CreateCompatibleDC (hDC);
- int hBitmap = OS.CreateCompatibleBitmap (hDC, width, height);
- OS.SelectObject (hdc2, hBitmap);
- if (!OS.IsWinCE) OS.SetStretchBltMode(hdc2, OS.COLORONCOLOR);
- OS.StretchBlt (hdc2, 0, 0, width, height, hdc1, 0, 0, bm.bmWidth, bm.bmHeight, OS.SRCCOPY);
- OS.DeleteDC (hdc1);
- OS.DeleteDC (hdc2);
- OS.ReleaseDC (0, hDC);
- return hBitmap;
-}
-
-int copyIcon (int hImage, int width, int height) {
- if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
- int hIcon = OS.CopyImage (hImage, OS.IMAGE_ICON, width, height, OS.LR_DEFAULTCOLOR);
- return hIcon != 0 ? hIcon : hImage;
-}
-
-int createMask (int hBitmap, int width, int height, int background) {
- int hMask = OS.CreateBitmap (width, height, 1, 1, null);
- int hDC = OS.GetDC (0);
- int hdc1 = OS.CreateCompatibleDC (hDC);
- if (background != -1) {
- OS.SelectObject (hdc1, hBitmap);
- int hdc2 = OS.CreateCompatibleDC (hDC);
- OS.SelectObject (hdc2, hMask);
- OS.SetBkColor (hdc1, background);
- OS.BitBlt (hdc2, 0, 0, width, height, hdc1, 0, 0, OS.SRCCOPY);
- OS.DeleteDC (hdc2);
- } else {
- int hOldBitmap = OS.SelectObject (hdc1, hMask);
- OS.PatBlt (hdc1, 0, 0, width, height, OS.BLACKNESS);
- OS.SelectObject (hdc1, hOldBitmap);
- }
- OS.ReleaseDC (0, hDC);
- OS.DeleteDC (hdc1);
- return hMask;
-}
-
-public void dispose () {
- if (handle != 0) OS.ImageList_Destroy (handle);
- handle = 0;
- images = null;
-}
-
-public Image get (int index) {
- return images [index];
-}
-
-public int getHandle () {
- return handle;
-}
-
-public Point getImageSize() {
- int [] cx = new int [1], cy = new int [1];
- OS.ImageList_GetIconSize (handle, cx, cy);
- return new Point (cx [0], cy [0]);
-}
-
-public int indexOf (Image image) {
- int count = OS.ImageList_GetImageCount (handle);
- for (int i=0; i<count; i++) {
- if (images [i] != null) {
- if (images [i].isDisposed ()) images [i] = null;
- if (images [i] != null && images [i].equals (image)) return i;
- }
- }
- return -1;
-}
-
-public void put (int index, Image image) {
- int count = OS.ImageList_GetImageCount (handle);
- if (!(0 <= index && index < count)) return;
- if (image != null) {
- int [] cx = new int [1], cy = new int [1];
- OS.ImageList_GetIconSize (handle, cx, cy);
- int hImage = image.handle;
- switch (image.type) {
- case SWT.BITMAP: {
- int background = -1;
- Color color = image.getBackground ();
- if (color != null) background = color.handle;
- int hBitmap = copyBitmap (hImage, cx [0], cy [0]);
- int hMask = createMask (hBitmap, cx [0], cy [0], background);
- OS.ImageList_Replace (handle, index, hBitmap, hMask);
- OS.DeleteObject (hBitmap);
- OS.DeleteObject (hMask);
- break;
- }
- case SWT.ICON: {
- if (OS.IsWinCE) {
- OS.ImageList_ReplaceIcon (handle, index, hImage);
- } else {
- int hIcon = copyIcon (hImage, cx [0], cy [0]);
- OS.ImageList_ReplaceIcon (handle, index, hIcon);
- OS.DestroyIcon (hIcon);
- }
- break;
- }
- }
- }
- images [index] = image;
-}
-
-public void remove (int index) {
- int count = OS.ImageList_GetImageCount (handle);
- if (!(0 <= index && index < count)) return;
- OS.ImageList_Remove (handle, index);
- System.arraycopy (images, index + 1, images, index, --count - index);
- images [index] = null;
-}
-
-int removeRef() {
- return --refCount;
-}
-
-public int size () {
- int result = 0;
- int count = OS.ImageList_GetImageCount (handle);
- for (int i=0; i<count; i++) {
- if (images [i] != null) {
- if (images [i].isDisposed ()) images [i] = null;
- if (images [i] != null) result++;
- }
- }
- return result;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; + +class ImageList { + int handle, refCount; + Image [] images; + static final int CREATE_FLAGS; + static { + if (OS.IsWinCE) { + CREATE_FLAGS = OS.ILC_MASK | OS.ILC_COLOR; + } else { + int flags = OS.ILC_MASK; + int hDC = OS.GetDC (0); + int bits = OS.GetDeviceCaps (hDC, OS.BITSPIXEL); + int planes = OS.GetDeviceCaps (hDC, OS.PLANES); + OS.ReleaseDC (0, hDC); + int depth = bits * planes; + switch (depth) { + case 4: + flags |= OS.ILC_COLOR4; + break; + case 8: + flags |= OS.ILC_COLOR8; + break; + case 16: + flags |= OS.ILC_COLOR16; + break; + case 24: + flags |= OS.ILC_COLOR24; + break; + case 32: + flags |= OS.ILC_COLOR32; + break; + default: + flags |= OS.ILC_COLOR; + } + CREATE_FLAGS = flags; + } + } + +public ImageList () { + handle = OS.ImageList_Create (32, 32, CREATE_FLAGS, 16, 16); + images = new Image [4]; +} + +public int add (Image image) { + int count = OS.ImageList_GetImageCount (handle); + int index = 0; + while (index < count) { + if (images [index] != null) { + if (images [index].isDisposed ()) images [index] = null; + } + if (images [index] == null) break; + index++; + } + int [] cx = new int [1], cy = new int [1]; + if (count == 0) { + Rectangle rect = image.getBounds(); + cx [0] = rect.width; + cy [0] = rect.height; + OS.ImageList_SetIconSize (handle, cx [0], cy [0]); + } + int hImage = image.handle; + OS.ImageList_GetIconSize (handle, cx, cy); + switch (image.type) { + case SWT.BITMAP: { + int hBitmap = copyBitmap (hImage, cx [0], cy [0]); + int background = -1; + Color color = image.getBackground (); + if (color != null) background = color.handle; + if (index == count) { + if (background != -1) { + OS.ImageList_AddMasked (handle, hBitmap, background); + } else { + int hMask = createMask (hBitmap, cx [0], cy [0], background); + OS.ImageList_Add (handle, hBitmap, hMask); + OS.DeleteObject (hMask); + } + } else { + int hMask = createMask (hBitmap, cx [0], cy [0], background); + OS.ImageList_Replace (handle, index, hBitmap, hMask); + OS.DeleteObject (hMask); + } + OS.DeleteObject (hBitmap); + break; + } + case SWT.ICON: { + if (OS.IsWinCE) { + OS.ImageList_ReplaceIcon (handle, index == count ? -1 : index, hImage); + } else { + int hIcon = copyIcon (hImage, cx [0], cy [0]); + OS.ImageList_ReplaceIcon (handle, index == count ? -1 : index, hIcon); + OS.DestroyIcon (hIcon); + } + break; + } + } + if (index == images.length) { + Image [] newImages = new Image [images.length + 4]; + System.arraycopy (images, 0, newImages, 0, images.length); + images = newImages; + } + images [index] = image; + return index; +} + +int addRef() { + return ++refCount; +} + +int copyBitmap (int hImage, int width, int height) { + BITMAP bm = new BITMAP (); + OS.GetObject (hImage, BITMAP.sizeof, bm); + int hDC = OS.GetDC (0); + int hdc1 = OS.CreateCompatibleDC (hDC); + OS.SelectObject (hdc1, hImage); + int hdc2 = OS.CreateCompatibleDC (hDC); + int hBitmap = OS.CreateCompatibleBitmap (hDC, width, height); + OS.SelectObject (hdc2, hBitmap); + if (!OS.IsWinCE) OS.SetStretchBltMode(hdc2, OS.COLORONCOLOR); + OS.StretchBlt (hdc2, 0, 0, width, height, hdc1, 0, 0, bm.bmWidth, bm.bmHeight, OS.SRCCOPY); + OS.DeleteDC (hdc1); + OS.DeleteDC (hdc2); + OS.ReleaseDC (0, hDC); + return hBitmap; +} + +int copyIcon (int hImage, int width, int height) { + if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + int hIcon = OS.CopyImage (hImage, OS.IMAGE_ICON, width, height, OS.LR_DEFAULTCOLOR); + return hIcon != 0 ? hIcon : hImage; +} + +int createMask (int hBitmap, int width, int height, int background) { + int hMask = OS.CreateBitmap (width, height, 1, 1, null); + int hDC = OS.GetDC (0); + int hdc1 = OS.CreateCompatibleDC (hDC); + if (background != -1) { + OS.SelectObject (hdc1, hBitmap); + int hdc2 = OS.CreateCompatibleDC (hDC); + OS.SelectObject (hdc2, hMask); + OS.SetBkColor (hdc1, background); + OS.BitBlt (hdc2, 0, 0, width, height, hdc1, 0, 0, OS.SRCCOPY); + OS.DeleteDC (hdc2); + } else { + int hOldBitmap = OS.SelectObject (hdc1, hMask); + OS.PatBlt (hdc1, 0, 0, width, height, OS.BLACKNESS); + OS.SelectObject (hdc1, hOldBitmap); + } + OS.ReleaseDC (0, hDC); + OS.DeleteDC (hdc1); + return hMask; +} + +public void dispose () { + if (handle != 0) OS.ImageList_Destroy (handle); + handle = 0; + images = null; +} + +public Image get (int index) { + return images [index]; +} + +public int getHandle () { + return handle; +} + +public Point getImageSize() { + int [] cx = new int [1], cy = new int [1]; + OS.ImageList_GetIconSize (handle, cx, cy); + return new Point (cx [0], cy [0]); +} + +public int indexOf (Image image) { + int count = OS.ImageList_GetImageCount (handle); + for (int i=0; i<count; i++) { + if (images [i] != null) { + if (images [i].isDisposed ()) images [i] = null; + if (images [i] != null && images [i].equals (image)) return i; + } + } + return -1; +} + +public void put (int index, Image image) { + int count = OS.ImageList_GetImageCount (handle); + if (!(0 <= index && index < count)) return; + if (image != null) { + int [] cx = new int [1], cy = new int [1]; + OS.ImageList_GetIconSize (handle, cx, cy); + int hImage = image.handle; + switch (image.type) { + case SWT.BITMAP: { + int background = -1; + Color color = image.getBackground (); + if (color != null) background = color.handle; + int hBitmap = copyBitmap (hImage, cx [0], cy [0]); + int hMask = createMask (hBitmap, cx [0], cy [0], background); + OS.ImageList_Replace (handle, index, hBitmap, hMask); + OS.DeleteObject (hBitmap); + OS.DeleteObject (hMask); + break; + } + case SWT.ICON: { + if (OS.IsWinCE) { + OS.ImageList_ReplaceIcon (handle, index, hImage); + } else { + int hIcon = copyIcon (hImage, cx [0], cy [0]); + OS.ImageList_ReplaceIcon (handle, index, hIcon); + OS.DestroyIcon (hIcon); + } + break; + } + } + } + images [index] = image; +} + +public void remove (int index) { + int count = OS.ImageList_GetImageCount (handle); + if (!(0 <= index && index < count)) return; + OS.ImageList_Remove (handle, index); + System.arraycopy (images, index + 1, images, index, --count - index); + images [index] = null; +} + +int removeRef() { + return --refCount; +} + +public int size () { + int result = 0; + int count = OS.ImageList_GetImageCount (handle); + for (int i=0; i<count; i++) { + if (images [i] != null) { + if (images [i].isDisposed ()) images [i] = null; + if (images [i] != null) result++; + } + } + return result; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Label.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Label.java index e8efcd2b0d..8be690c27c 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Label.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Label.java @@ -1,583 +1,583 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-
-/**
- * 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.
- * <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>
- */
-public class Label extends Control {
- Image image;
- int font;
- static final int LabelProc;
- static final TCHAR LabelClass = new TCHAR (0, "STATIC", true);
- static {
- WNDCLASS lpWndClass = new WNDCLASS ();
- OS.GetClassInfo (0, LabelClass, lpWndClass);
- LabelProc = lpWndClass.lpfnWndProc;
- }
-
-/**
- * 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 callWindowProc (int msg, int wParam, int lParam) {
- if (handle == 0) return 0;
- return OS.CallWindowProc (LabelProc, handle, msg, wParam, lParam);
-}
-
-static int checkStyle (int style) {
- if ((style & SWT.SEPARATOR) != 0) return style;
- return checkBits (style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0);
-}
-
-public Point computeSize (int wHint, int hHint, boolean changed) {
- checkWidget ();
- int width = 0, height = 0;
- int border = getBorderWidth ();
- if ((style & SWT.SEPARATOR) != 0) {
- int lineWidth = OS.GetSystemMetrics (OS.SM_CXBORDER);
- if ((style & SWT.HORIZONTAL) != 0) {
- width = DEFAULT_WIDTH; height = lineWidth * 2;
- } else {
- width = lineWidth * 2; height = DEFAULT_HEIGHT;
- }
- if (wHint != SWT.DEFAULT) width = wHint;
- if (hHint != SWT.DEFAULT) height = hHint;
- width += border * 2; height += border * 2;
- return new Point (width, height);
- }
- /*
- * NOTE: SS_BITMAP and SS_ICON are not single bit
- * masks so it is necessary to test for all of the
- * bits in these masks.
- */
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- boolean isBitmap = (bits & OS.SS_BITMAP) == OS.SS_BITMAP;
- boolean isIcon = (bits & OS.SS_ICON) == OS.SS_ICON;
- if (isBitmap || isIcon) {
- if (image != null) {
- Rectangle rect = image.getBounds();
- width = rect.width;
- height = rect.height;
- }
- } else {
- int hDC = OS.GetDC (handle);
- int newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- int oldFont = OS.SelectObject (hDC, newFont);
- RECT rect = new RECT ();
- int flags = OS.DT_CALCRECT | OS.DT_EDITCONTROL | OS.DT_EXPANDTABS;
- if ((style & SWT.WRAP) != 0 && wHint != SWT.DEFAULT) {
- flags |= OS.DT_WORDBREAK;
- rect.right = wHint;
- }
- int length = OS.GetWindowTextLength (handle);
- TCHAR buffer = new TCHAR (getCodePage (), length + 1);
- OS.GetWindowText (handle, buffer, length + 1);
- OS.DrawText (hDC, buffer, length, rect, flags);
- width = rect.right - rect.left;
- height = rect.bottom - rect.top;
- if (height == 0) {
- TEXTMETRIC tm = new TEXTMETRIC ();
- OS.GetTextMetrics (hDC, tm);
- height = tm.tmHeight;
- }
- if (newFont != 0) OS.SelectObject (hDC, oldFont);
- OS.ReleaseDC (handle, hDC);
- }
- if (wHint != SWT.DEFAULT) width = wHint;
- if (hHint != SWT.DEFAULT) height = hHint;
- width += border * 2; height += border * 2;
- /*
- * Feature in WinCE PPC. Text labels have a trim
- * of one pixel wide on the right and left side.
- * The fix is to increase the size.
- */
- if (OS.IsWinCE) {
- if (!isBitmap && !isIcon) width += 2;
- }
- return new Point (width, height);
-}
-
-/**
- * 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 0;
- 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 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 "";
- int length = OS.GetWindowTextLength (handle);
- if (length == 0) return "";
- TCHAR buffer = new TCHAR (getCodePage (), length + 1);
- OS.GetWindowText (handle, buffer, length + 1);
- return buffer.toString (0, length);
-}
-
-/*
-* Not currently used.
-*/
-boolean getWrap () {
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & (OS.SS_RIGHT | OS.SS_CENTER)) != 0) return true;
- if ((bits & OS.SS_LEFTNOWORDWRAP) != 0) return false;
- return true;
-}
-
-boolean mnemonicHit (char key) {
- Composite control = this.parent;
- while (control != null) {
- Control [] children = control._getChildren ();
- int index = 0;
- while (index < children.length) {
- if (children [index] == this) break;
- index++;
- }
- index++;
- if (index < children.length) {
- if (children [index].setFocus ()) return true;
- }
- control = control.parent;
- }
- return false;
-}
-
-boolean mnemonicMatch (char key) {
- char mnemonic = findMnemonic (getText ());
- if (mnemonic == '\0') return false;
- return Character.toUpperCase (key) == Character.toUpperCase (mnemonic);
-}
-
-void releaseWidget () {
- super.releaseWidget ();
- image = null;
-}
-
-/**
- * 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);
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- /*
- * Feature in Windows. The windows label does not align
- * the bitmap or icon. Any attempt to set alignment bits
- * such as SS_CENTER cause the label to display text. The
- * fix is to disallow alignment.
- *
- * NOTE: SS_BITMAP and SS_ICON are not single bit
- * masks so it is necessary to test for all of the
- * bits in these masks.
- */
- if ((bits & OS.SS_BITMAP) == OS.SS_BITMAP) return;
- if ((bits & OS.SS_ICON) == OS.SS_ICON) return;
- bits &= ~(OS.SS_LEFTNOWORDWRAP | OS.SS_CENTER | OS.SS_RIGHT);
- if ((style & SWT.LEFT) != 0 && (style & SWT.WRAP) == 0) {
- bits |= OS.SS_LEFTNOWORDWRAP;
- }
- if ((style & SWT.CENTER) != 0) bits |= OS.SS_CENTER;
- if ((style & SWT.RIGHT) != 0) bits |= OS.SS_RIGHT;
- OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
- OS.InvalidateRect (handle, null, true);
-}
-
-public boolean setFocus () {
- checkWidget();
- 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;
- int hImage = 0, imageBits = 0, fImageType = 0;
- if (image != null) {
- if (image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
- hImage = image.handle;
- switch (image.type) {
- case SWT.BITMAP:
- imageBits = OS.SS_BITMAP;
- fImageType = OS.IMAGE_BITMAP;
- break;
- case SWT.ICON:
- imageBits = OS.SS_ICON;
- fImageType = OS.IMAGE_ICON;
- break;
- default:
- return;
- }
- }
- this.image = image;
- RECT rect = new RECT ();
- OS.GetWindowRect (handle, rect);
- int newBits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- int oldBits = newBits;
- newBits &= ~(OS.SS_BITMAP | OS.SS_ICON);
- newBits |= imageBits | OS.SS_REALSIZEIMAGE | OS.SS_CENTERIMAGE;
- if (newBits != oldBits) {
- OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
- }
- OS.SendMessage (handle, OS.STM_SETIMAGE, fImageType, hImage);
- /*
- * Feature in Windows. When STM_SETIMAGE is used to set the
- * image for a static control, Windows either streches the image
- * to fit the control or shrinks the control to fit the image.
- * While not stricly wrong, neither of these is desirable.
- * The fix is to stop Windows from stretching the image by
- * using SS_REALSIZEIMAGE and SS_CENTERIMAGE, allow Windows
- * to shrink the control, and then restore the control to the
- * original size.
- */
- int flags = OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE | OS.SWP_NOMOVE;
- OS.SetWindowPos (handle, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top, flags);
- OS.InvalidateRect (handle, null, true);
-}
-
-/**
- * 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 '&' 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
- *'&' can be escaped by doubling it in the string, causing
- * a single '&' 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;
- int newBits = OS.GetWindowLong (handle, OS.GWL_STYLE), oldBits = newBits;
- newBits &= ~(OS.SS_BITMAP | OS.SS_ICON | OS.SS_REALSIZEIMAGE | OS.SS_CENTERIMAGE);
- if ((style & SWT.LEFT) != 0 && (style & SWT.WRAP) == 0) newBits |= OS.SS_LEFTNOWORDWRAP;
- if ((style & SWT.CENTER) != 0) newBits |= OS.SS_CENTER;
- if ((style & SWT.RIGHT) != 0) newBits |= OS.SS_RIGHT;
- if (newBits != oldBits) {
- /*
- * Bug in Windows. When the style of a label is SS_BITMAP
- * or SS_ICON, the label does not remember the font that is
- * set in WM_SETFONT. The fix is to remember the font and
- * return the font in WM_GETFONT and to reset the font when
- * the style is changed from SS_BITMAP or SS_ICON to a style
- * that displays text.
- */
- int hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
- if (hFont != 0) OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0);
- }
- string = Display.withCrLf (string);
- TCHAR buffer = new TCHAR (getCodePage (), string, true);
- OS.SetWindowText (handle, buffer);
-}
-
-/*
-* Not currently used.
-*/
-void setWrap (boolean wrap) {
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & (OS.SS_RIGHT | OS.SS_CENTER)) != 0) return;
- bits &= ~OS.SS_LEFTNOWORDWRAP;
- if (!wrap) bits |= OS.SS_LEFTNOWORDWRAP;
- OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
- OS.InvalidateRect (handle, null, true);
-}
-
-int widgetExtStyle () {
- int bits = super.widgetExtStyle () & ~OS.WS_EX_CLIENTEDGE;
- if ((style & SWT.BORDER) != 0) return bits | OS.WS_EX_STATICEDGE;
- return bits;
-}
-
-int widgetStyle () {
- int bits = super.widgetStyle () | OS.SS_NOTIFY;
- if ((style & SWT.SEPARATOR) != 0) return bits | OS.SS_OWNERDRAW;
- if ((style & SWT.CENTER) != 0) return bits | OS.SS_CENTER;
- if ((style & SWT.RIGHT) != 0) return bits | OS.SS_RIGHT;
- if ((style & SWT.WRAP) != 0) return bits | OS.SS_LEFT;
- return bits | OS.SS_LEFTNOWORDWRAP;
-}
-
-TCHAR windowClass () {
- return LabelClass;
-}
-
-int windowProc () {
- return LabelProc;
-}
-
-LRESULT WM_ERASEBKGND (int wParam, int lParam) {
- LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
- if (result != null) return result;
- if ((style & SWT.SEPARATOR) != 0) return LRESULT.ONE;
- /*
- * Bug in Windows. When a label has the SS_BITMAP
- * or SS_ICON style, the label does not draw the
- * background. The fix is to draw the background
- * when the label is showing a bitmap or icon.
- *
- * NOTE: SS_BITMAP and SS_ICON are not single bit
- * masks so it is necessary to test for all of the
- * bits in these masks.
- */
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- boolean isBitmap = (bits & OS.SS_BITMAP) == OS.SS_BITMAP;
- boolean isIcon = (bits & OS.SS_ICON) == OS.SS_ICON;
- if (isBitmap || isIcon) {
- drawBackground (wParam);
- return LRESULT.ONE;
- }
- return result;
-}
-
-LRESULT WM_GETFONT (int wParam, int lParam) {
- LRESULT result = super.WM_GETFONT (wParam, lParam);
- if (result != null) return result;
- /*
- * Bug in Windows. When the style of a label is SS_BITMAP
- * or SS_ICON, the label does not remember the font that is
- * set in WM_SETFONT. The fix is to remember the font and
- * return the font in WM_GETFONT.
- */
- if (font == 0) font = defaultFont ();
- return new LRESULT (font);
-}
-
-LRESULT WM_SETFONT (int wParam, int lParam) {
- /*
- * Bug in Windows. When the style of a label is SS_BITMAP
- * or SS_ICON, the label does not remember the font that is
- * set in WM_SETFONT. The fix is to remember the font and
- * return the font in WM_GETFONT.
- */
- return super.WM_SETFONT (font = wParam, lParam);
-}
-
-LRESULT WM_SIZE (int wParam, int lParam) {
- LRESULT result = super.WM_SIZE (wParam, lParam);
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the resize
- * event. If this happens, end the processing of the
- * Windows message by returning the result of the
- * WM_SIZE message.
- */
- if (isDisposed ()) return result;
- if ((style & SWT.SEPARATOR) != 0) {
- OS.InvalidateRect (handle, null, true);
- return result;
- }
-
- /*
- * Bug in Windows. For some reason, a label with
- * SS_BITMAP or SS_ICON and SS_CENTER does not redraw
- * properly when resized. Only the new area is drawn
- * and the old area is not cleared. The fix is to
- * force the redraw.
- *
- * NOTE: SS_BITMAP and SS_ICON are not single bit
- * masks so it is necessary to test for all of the
- * bits in these masks.
- */
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- boolean isBitmap = (bits & OS.SS_BITMAP) == OS.SS_BITMAP;
- boolean isIcon = (bits & OS.SS_ICON) == OS.SS_ICON;
- if (isBitmap || isIcon) {
- OS.InvalidateRect (handle, null, true);
- return result;
- }
-
- /*
- * Bug in Windows. For some reason, a label with
- * style SS_LEFT, SS_CENTER or SS_RIGHT does not
- * redraw the text in the new position when resized.
- * Note that SS_LEFTNOWORDWRAP does not have the
- * problem. The fix is to force the redraw.
- */
- if ((style & (SWT.WRAP | SWT.CENTER | SWT.RIGHT)) != 0) {
- OS.InvalidateRect (handle, null, true);
- return result;
- }
-
- return result;
-}
-
-LRESULT wmDrawChild (int wParam, int lParam) {
- DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT ();
- OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof);
- drawBackground (struct.hDC);
- if ((style & SWT.SHADOW_NONE) != 0) return null;
- RECT rect = new RECT ();
- int lineWidth = OS.GetSystemMetrics (OS.SM_CXBORDER);
- int flags = OS.EDGE_ETCHED;
- if ((style & SWT.SHADOW_IN) != 0) flags = OS.EDGE_SUNKEN;
- if ((style & SWT.HORIZONTAL) != 0) {
- int bottom = struct.top + Math.max (lineWidth * 2, (struct.bottom - struct.top) / 2);
- OS.SetRect (rect, struct.left, struct.top, struct.right, bottom);
- OS.DrawEdge (struct.hDC, rect, flags, OS.BF_BOTTOM);
- } else {
- int right = struct.left + Math.max (lineWidth * 2, (struct.right - struct.left) / 2);
- OS.SetRect (rect, struct.left, struct.top, right, struct.bottom);
- OS.DrawEdge (struct.hDC, rect, flags, OS.BF_RIGHT);
- }
- return null;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; + +/** + * 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. + * <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> + */ +public class Label extends Control { + Image image; + int font; + static final int LabelProc; + static final TCHAR LabelClass = new TCHAR (0, "STATIC", true); + static { + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, LabelClass, lpWndClass); + LabelProc = lpWndClass.lpfnWndProc; + } + +/** + * 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 callWindowProc (int msg, int wParam, int lParam) { + if (handle == 0) return 0; + return OS.CallWindowProc (LabelProc, handle, msg, wParam, lParam); +} + +static int checkStyle (int style) { + if ((style & SWT.SEPARATOR) != 0) return style; + return checkBits (style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0); +} + +public Point computeSize (int wHint, int hHint, boolean changed) { + checkWidget (); + int width = 0, height = 0; + int border = getBorderWidth (); + if ((style & SWT.SEPARATOR) != 0) { + int lineWidth = OS.GetSystemMetrics (OS.SM_CXBORDER); + if ((style & SWT.HORIZONTAL) != 0) { + width = DEFAULT_WIDTH; height = lineWidth * 2; + } else { + width = lineWidth * 2; height = DEFAULT_HEIGHT; + } + if (wHint != SWT.DEFAULT) width = wHint; + if (hHint != SWT.DEFAULT) height = hHint; + width += border * 2; height += border * 2; + return new Point (width, height); + } + /* + * NOTE: SS_BITMAP and SS_ICON are not single bit + * masks so it is necessary to test for all of the + * bits in these masks. + */ + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + boolean isBitmap = (bits & OS.SS_BITMAP) == OS.SS_BITMAP; + boolean isIcon = (bits & OS.SS_ICON) == OS.SS_ICON; + if (isBitmap || isIcon) { + if (image != null) { + Rectangle rect = image.getBounds(); + width = rect.width; + height = rect.height; + } + } else { + int hDC = OS.GetDC (handle); + int newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + int oldFont = OS.SelectObject (hDC, newFont); + RECT rect = new RECT (); + int flags = OS.DT_CALCRECT | OS.DT_EDITCONTROL | OS.DT_EXPANDTABS; + if ((style & SWT.WRAP) != 0 && wHint != SWT.DEFAULT) { + flags |= OS.DT_WORDBREAK; + rect.right = wHint; + } + int length = OS.GetWindowTextLength (handle); + TCHAR buffer = new TCHAR (getCodePage (), length + 1); + OS.GetWindowText (handle, buffer, length + 1); + OS.DrawText (hDC, buffer, length, rect, flags); + width = rect.right - rect.left; + height = rect.bottom - rect.top; + if (height == 0) { + TEXTMETRIC tm = new TEXTMETRIC (); + OS.GetTextMetrics (hDC, tm); + height = tm.tmHeight; + } + if (newFont != 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + } + if (wHint != SWT.DEFAULT) width = wHint; + if (hHint != SWT.DEFAULT) height = hHint; + width += border * 2; height += border * 2; + /* + * Feature in WinCE PPC. Text labels have a trim + * of one pixel wide on the right and left side. + * The fix is to increase the size. + */ + if (OS.IsWinCE) { + if (!isBitmap && !isIcon) width += 2; + } + return new Point (width, height); +} + +/** + * 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 0; + 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 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 ""; + int length = OS.GetWindowTextLength (handle); + if (length == 0) return ""; + TCHAR buffer = new TCHAR (getCodePage (), length + 1); + OS.GetWindowText (handle, buffer, length + 1); + return buffer.toString (0, length); +} + +/* +* Not currently used. +*/ +boolean getWrap () { + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & (OS.SS_RIGHT | OS.SS_CENTER)) != 0) return true; + if ((bits & OS.SS_LEFTNOWORDWRAP) != 0) return false; + return true; +} + +boolean mnemonicHit (char key) { + Composite control = this.parent; + while (control != null) { + Control [] children = control._getChildren (); + int index = 0; + while (index < children.length) { + if (children [index] == this) break; + index++; + } + index++; + if (index < children.length) { + if (children [index].setFocus ()) return true; + } + control = control.parent; + } + return false; +} + +boolean mnemonicMatch (char key) { + char mnemonic = findMnemonic (getText ()); + if (mnemonic == '\0') return false; + return Character.toUpperCase (key) == Character.toUpperCase (mnemonic); +} + +void releaseWidget () { + super.releaseWidget (); + image = null; +} + +/** + * 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); + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + /* + * Feature in Windows. The windows label does not align + * the bitmap or icon. Any attempt to set alignment bits + * such as SS_CENTER cause the label to display text. The + * fix is to disallow alignment. + * + * NOTE: SS_BITMAP and SS_ICON are not single bit + * masks so it is necessary to test for all of the + * bits in these masks. + */ + if ((bits & OS.SS_BITMAP) == OS.SS_BITMAP) return; + if ((bits & OS.SS_ICON) == OS.SS_ICON) return; + bits &= ~(OS.SS_LEFTNOWORDWRAP | OS.SS_CENTER | OS.SS_RIGHT); + if ((style & SWT.LEFT) != 0 && (style & SWT.WRAP) == 0) { + bits |= OS.SS_LEFTNOWORDWRAP; + } + if ((style & SWT.CENTER) != 0) bits |= OS.SS_CENTER; + if ((style & SWT.RIGHT) != 0) bits |= OS.SS_RIGHT; + OS.SetWindowLong (handle, OS.GWL_STYLE, bits); + OS.InvalidateRect (handle, null, true); +} + +public boolean setFocus () { + checkWidget(); + 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; + int hImage = 0, imageBits = 0, fImageType = 0; + if (image != null) { + if (image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); + hImage = image.handle; + switch (image.type) { + case SWT.BITMAP: + imageBits = OS.SS_BITMAP; + fImageType = OS.IMAGE_BITMAP; + break; + case SWT.ICON: + imageBits = OS.SS_ICON; + fImageType = OS.IMAGE_ICON; + break; + default: + return; + } + } + this.image = image; + RECT rect = new RECT (); + OS.GetWindowRect (handle, rect); + int newBits = OS.GetWindowLong (handle, OS.GWL_STYLE); + int oldBits = newBits; + newBits &= ~(OS.SS_BITMAP | OS.SS_ICON); + newBits |= imageBits | OS.SS_REALSIZEIMAGE | OS.SS_CENTERIMAGE; + if (newBits != oldBits) { + OS.SetWindowLong (handle, OS.GWL_STYLE, newBits); + } + OS.SendMessage (handle, OS.STM_SETIMAGE, fImageType, hImage); + /* + * Feature in Windows. When STM_SETIMAGE is used to set the + * image for a static control, Windows either streches the image + * to fit the control or shrinks the control to fit the image. + * While not stricly wrong, neither of these is desirable. + * The fix is to stop Windows from stretching the image by + * using SS_REALSIZEIMAGE and SS_CENTERIMAGE, allow Windows + * to shrink the control, and then restore the control to the + * original size. + */ + int flags = OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE | OS.SWP_NOMOVE; + OS.SetWindowPos (handle, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top, flags); + OS.InvalidateRect (handle, null, true); +} + +/** + * 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 '&' 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 + *'&' can be escaped by doubling it in the string, causing + * a single '&' 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; + int newBits = OS.GetWindowLong (handle, OS.GWL_STYLE), oldBits = newBits; + newBits &= ~(OS.SS_BITMAP | OS.SS_ICON | OS.SS_REALSIZEIMAGE | OS.SS_CENTERIMAGE); + if ((style & SWT.LEFT) != 0 && (style & SWT.WRAP) == 0) newBits |= OS.SS_LEFTNOWORDWRAP; + if ((style & SWT.CENTER) != 0) newBits |= OS.SS_CENTER; + if ((style & SWT.RIGHT) != 0) newBits |= OS.SS_RIGHT; + if (newBits != oldBits) { + /* + * Bug in Windows. When the style of a label is SS_BITMAP + * or SS_ICON, the label does not remember the font that is + * set in WM_SETFONT. The fix is to remember the font and + * return the font in WM_GETFONT and to reset the font when + * the style is changed from SS_BITMAP or SS_ICON to a style + * that displays text. + */ + int hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + OS.SetWindowLong (handle, OS.GWL_STYLE, newBits); + if (hFont != 0) OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0); + } + string = Display.withCrLf (string); + TCHAR buffer = new TCHAR (getCodePage (), string, true); + OS.SetWindowText (handle, buffer); +} + +/* +* Not currently used. +*/ +void setWrap (boolean wrap) { + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & (OS.SS_RIGHT | OS.SS_CENTER)) != 0) return; + bits &= ~OS.SS_LEFTNOWORDWRAP; + if (!wrap) bits |= OS.SS_LEFTNOWORDWRAP; + OS.SetWindowLong (handle, OS.GWL_STYLE, bits); + OS.InvalidateRect (handle, null, true); +} + +int widgetExtStyle () { + int bits = super.widgetExtStyle () & ~OS.WS_EX_CLIENTEDGE; + if ((style & SWT.BORDER) != 0) return bits | OS.WS_EX_STATICEDGE; + return bits; +} + +int widgetStyle () { + int bits = super.widgetStyle () | OS.SS_NOTIFY; + if ((style & SWT.SEPARATOR) != 0) return bits | OS.SS_OWNERDRAW; + if ((style & SWT.CENTER) != 0) return bits | OS.SS_CENTER; + if ((style & SWT.RIGHT) != 0) return bits | OS.SS_RIGHT; + if ((style & SWT.WRAP) != 0) return bits | OS.SS_LEFT; + return bits | OS.SS_LEFTNOWORDWRAP; +} + +TCHAR windowClass () { + return LabelClass; +} + +int windowProc () { + return LabelProc; +} + +LRESULT WM_ERASEBKGND (int wParam, int lParam) { + LRESULT result = super.WM_ERASEBKGND (wParam, lParam); + if (result != null) return result; + if ((style & SWT.SEPARATOR) != 0) return LRESULT.ONE; + /* + * Bug in Windows. When a label has the SS_BITMAP + * or SS_ICON style, the label does not draw the + * background. The fix is to draw the background + * when the label is showing a bitmap or icon. + * + * NOTE: SS_BITMAP and SS_ICON are not single bit + * masks so it is necessary to test for all of the + * bits in these masks. + */ + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + boolean isBitmap = (bits & OS.SS_BITMAP) == OS.SS_BITMAP; + boolean isIcon = (bits & OS.SS_ICON) == OS.SS_ICON; + if (isBitmap || isIcon) { + drawBackground (wParam); + return LRESULT.ONE; + } + return result; +} + +LRESULT WM_GETFONT (int wParam, int lParam) { + LRESULT result = super.WM_GETFONT (wParam, lParam); + if (result != null) return result; + /* + * Bug in Windows. When the style of a label is SS_BITMAP + * or SS_ICON, the label does not remember the font that is + * set in WM_SETFONT. The fix is to remember the font and + * return the font in WM_GETFONT. + */ + if (font == 0) font = defaultFont (); + return new LRESULT (font); +} + +LRESULT WM_SETFONT (int wParam, int lParam) { + /* + * Bug in Windows. When the style of a label is SS_BITMAP + * or SS_ICON, the label does not remember the font that is + * set in WM_SETFONT. The fix is to remember the font and + * return the font in WM_GETFONT. + */ + return super.WM_SETFONT (font = wParam, lParam); +} + +LRESULT WM_SIZE (int wParam, int lParam) { + LRESULT result = super.WM_SIZE (wParam, lParam); + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the resize + * event. If this happens, end the processing of the + * Windows message by returning the result of the + * WM_SIZE message. + */ + if (isDisposed ()) return result; + if ((style & SWT.SEPARATOR) != 0) { + OS.InvalidateRect (handle, null, true); + return result; + } + + /* + * Bug in Windows. For some reason, a label with + * SS_BITMAP or SS_ICON and SS_CENTER does not redraw + * properly when resized. Only the new area is drawn + * and the old area is not cleared. The fix is to + * force the redraw. + * + * NOTE: SS_BITMAP and SS_ICON are not single bit + * masks so it is necessary to test for all of the + * bits in these masks. + */ + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + boolean isBitmap = (bits & OS.SS_BITMAP) == OS.SS_BITMAP; + boolean isIcon = (bits & OS.SS_ICON) == OS.SS_ICON; + if (isBitmap || isIcon) { + OS.InvalidateRect (handle, null, true); + return result; + } + + /* + * Bug in Windows. For some reason, a label with + * style SS_LEFT, SS_CENTER or SS_RIGHT does not + * redraw the text in the new position when resized. + * Note that SS_LEFTNOWORDWRAP does not have the + * problem. The fix is to force the redraw. + */ + if ((style & (SWT.WRAP | SWT.CENTER | SWT.RIGHT)) != 0) { + OS.InvalidateRect (handle, null, true); + return result; + } + + return result; +} + +LRESULT wmDrawChild (int wParam, int lParam) { + DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT (); + OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof); + drawBackground (struct.hDC); + if ((style & SWT.SHADOW_NONE) != 0) return null; + RECT rect = new RECT (); + int lineWidth = OS.GetSystemMetrics (OS.SM_CXBORDER); + int flags = OS.EDGE_ETCHED; + if ((style & SWT.SHADOW_IN) != 0) flags = OS.EDGE_SUNKEN; + if ((style & SWT.HORIZONTAL) != 0) { + int bottom = struct.top + Math.max (lineWidth * 2, (struct.bottom - struct.top) / 2); + OS.SetRect (rect, struct.left, struct.top, struct.right, bottom); + OS.DrawEdge (struct.hDC, rect, flags, OS.BF_BOTTOM); + } else { + int right = struct.left + Math.max (lineWidth * 2, (struct.right - struct.left) / 2); + OS.SetRect (rect, struct.left, struct.top, right, struct.bottom); + OS.DrawEdge (struct.hDC, rect, flags, OS.BF_RIGHT); + } + return null; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/List.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/List.java index 7414305ee5..77b53091d6 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/List.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/List.java @@ -1,1540 +1,1540 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-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 displays a list of strings and issues notificiation
- * when a string 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>
- */
-
-public class List extends Scrollable {
- static final int ListProc;
- static final TCHAR ListClass = new TCHAR (0, "LISTBOX", true);
- static {
- WNDCLASS lpWndClass = new WNDCLASS ();
- OS.GetClassInfo (0, ListClass, lpWndClass);
- ListProc = lpWndClass.lpfnWndProc;
- }
-
-/**
- * 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));
-}
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure</li>
- * </ul>
- *
- * @see #add(String,int)
- */
-public void add (String string) {
- checkWidget ();
- if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
- TCHAR buffer = new TCHAR (getCodePage (), string, true);
- int result = OS.SendMessage (handle, OS.LB_ADDSTRING, 0, buffer);
- if (result == OS.LB_ERR) error (SWT.ERROR_ITEM_NOT_ADDED);
- if (result == OS.LB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED);
- if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, true);
-}
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure</li>
- * </ul>
- *
- * @see #add(String)
- */
-public void add (String string, int index) {
- checkWidget ();
- if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
- if (index == -1) error (SWT.ERROR_INVALID_RANGE);
- TCHAR buffer = new TCHAR (getCodePage (), string, true);
- int result = OS.SendMessage (handle, OS.LB_INSERTSTRING, index, buffer);
- if (result == OS.LB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED);
- if (result == OS.LB_ERR) {
- int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
- if (0 <= index && index <= count) {
- error (SWT.ERROR_ITEM_NOT_ADDED);
- } else {
- error (SWT.ERROR_INVALID_RANGE);
- }
- }
- if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, true);
-}
-
-/**
- * Adds the listener to the collection of listeners who will
- * be notified when the receiver's selection changes, 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
- *
- * @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);
-}
-
-int callWindowProc (int msg, int wParam, int lParam) {
- if (handle == 0) return 0;
- return OS.CallWindowProc (ListProc, handle, msg, wParam, lParam);
-}
-
-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 count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
- int itemHeight = OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0);
- int width = 0, height = count * itemHeight;
- if ((style & SWT.H_SCROLL) != 0) {
- width = OS.SendMessage (handle, OS.LB_GETHORIZONTALEXTENT, 0, 0);
- } else {
- int newFont, oldFont = 0;
- int hDC = OS.GetDC (handle);
- newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
- RECT rect = new RECT ();
- int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
- int cp = getCodePage ();
- TCHAR buffer = new TCHAR (cp, 64 + 1);
- for (int i=0; i<count; i++) {
- int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, i, 0);
- if (length != OS.LB_ERR) {
- if (length + 1 > buffer.length ()) {
- buffer = new TCHAR (cp, length + 1);
- }
- int result = OS.SendMessage (handle, OS.LB_GETTEXT, i, buffer);
- if (result != OS.LB_ERR) {
- OS.DrawText (hDC, buffer, length, rect, flags);
- width = Math.max (width, rect.right - rect.left);
- }
- }
- }
- if (newFont != 0) OS.SelectObject (hDC, oldFont);
- OS.ReleaseDC (handle, hDC);
- }
- 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 + 3;
- height += border * 2;
- if ((style & SWT.V_SCROLL) != 0) {
- width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
- }
- if ((style & SWT.H_SCROLL) != 0) {
- height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
- }
- return new Point (width, height);
-}
-
-int defaultBackground () {
- return OS.GetSysColor (OS.COLOR_WINDOW);
-}
-
-/**
- * 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 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>
- */
-public void deselect (int [] indices) {
- checkWidget ();
- if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
- if (indices.length == 0) return;
- if ((style & SWT.SINGLE) != 0) {
- int oldIndex = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
- if (oldIndex == OS.LB_ERR) return;
- for (int i=0; i<indices.length; i++) {
- if (oldIndex == indices [i]) {
- OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0);
- return;
- }
- }
- return;
- }
- for (int i=0; i<indices.length; i++) {
- int index = indices [i];
- if (index != -1) {
- OS.SendMessage (handle, OS.LB_SETSEL, 0, index);
- }
- }
-}
-
-/**
- * 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 (index == -1) return;
- if ((style & SWT.SINGLE) != 0) {
- int oldIndex = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
- if (oldIndex == OS.LB_ERR) return;
- if (oldIndex == index) OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0);
- return;
- }
- OS.SendMessage (handle, OS.LB_SETSEL, 0, index);
-}
-
-/**
- * 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 ((style & SWT.SINGLE) != 0) {
- int oldIndex = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
- if (oldIndex == OS.LB_ERR) return;
- if (start <= oldIndex && oldIndex <= end) {
- OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0);
- }
- return;
- }
- /*
- * Ensure that at least one item is contained in
- * the range from start to end. Note that when
- * start = end, LB_SELITEMRANGEEX deselects the
- * item.
- */
- int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
- if (start < 0 && end < 0) return;
- if (start >= count && end >= count) return;
- start = Math.min (count - 1, Math.max (0, start));
- end = Math.min (count - 1, Math.max (0, end));
- OS.SendMessage (handle, OS.LB_SELITEMRANGEEX, end, start);
-}
-
-/**
- * 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 ();
- if ((style & SWT.SINGLE) != 0) {
- OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0);
- } else {
- OS.SendMessage (handle, OS.LB_SETSEL, 0, -1);
- }
-}
-
-/**
- * Returns the zero-relative index of the item which is currently
- * has the focus in the receiver, or -1 if no item is 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 OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public String getItem (int index) {
- checkWidget ();
- int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0);
- if (length != OS.LB_ERR) {
- TCHAR buffer = new TCHAR (getCodePage (), length + 1);
- int result = OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer);
- if (result != OS.LB_ERR) return buffer.toString (0, length);
- }
- int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
- if (0 <= index && index < count) {
- error (SWT.ERROR_CANNOT_GET_ITEM);
- } else {
- error (SWT.ERROR_INVALID_RANGE);
- }
- 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public int getItemCount () {
- checkWidget ();
- int result = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
- if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_COUNT);
- return result;
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_ITEM_HEIGHT - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public int getItemHeight () {
- checkWidget ();
- int result = OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0);
- if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_ITEM_HEIGHT);
- return result;
-}
-
-/**
- * Returns an 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure while getting an item</li>
- * <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure while getting the item count</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 an array of <code>String</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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_SELECTION - if the operation fails because of an operating system failure while getting the selection</li>
- * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure while getting an item</li>
- * </ul>
- */
-public String [] getSelection () {
- checkWidget ();
- int [] indices = getSelectionIndices ();
- String [] result = new String [indices.length];
- for (int i=0; i<indices.length; i++) {
- result [i] = getItem (indices [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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public int getSelectionCount () {
- checkWidget ();
- if ((style & SWT.SINGLE) != 0) {
- int result = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
- if (result == OS.LB_ERR) return 0;
- return 1;
- }
- int result = OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0);
- if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_COUNT);
- return result;
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_SELECTION - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public int getSelectionIndex () {
- checkWidget ();
- if ((style & SWT.SINGLE) != 0) {
- return OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
- }
- int count = OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0);
- if (count == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_SELECTION);
- if (count == 0) return -1;
- int index = OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
- int result = OS.SendMessage (handle, OS.LB_GETSEL, index, 0);
- if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_SELECTION);
- if (result != 0) return index;
- int [] buffer = new int [1];
- result = OS.SendMessage (handle, OS.LB_GETSELITEMS, 1, buffer);
- if (result != 1) error (SWT.ERROR_CANNOT_GET_SELECTION);
- return buffer [0];
-}
-
-/**
- * Returns the zero-relative indices of the items which are currently
- * selected in the receiver. 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_SELECTION - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public int [] getSelectionIndices () {
- checkWidget ();
- if ((style & SWT.SINGLE) != 0) {
- int result = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
- if (result == OS.LB_ERR) return new int [0];
- return new int [] {result};
- }
- int length = OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0);
- if (length == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_SELECTION);
- int [] indices = new int [length];
- int result = OS.SendMessage (handle, OS.LB_GETSELITEMS, length, indices);
- if (result != length) error (SWT.ERROR_CANNOT_GET_SELECTION);
- return indices;
-}
-
-/**
- * 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 ();
- return OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
-}
-
-/**
- * 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 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
- * @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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure while getting the item count</li>
- * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure while getting an item</li>
- * </ul>
- */
-public int indexOf (String string, int start) {
- checkWidget ();
- if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
-
- /*
- * Bug in Windows. For some reason, LB_FINDSTRINGEXACT
- * will not find empty strings even though it is legal
- * to insert an empty string into a list. The fix is
- * to search the list, an item at a time.
- */
- if (string.length () == 0) {
- int count = getItemCount ();
- for (int i=start; i<count; i++) {
- if (string.equals (getItem (i))) return i;
- }
- return -1;
- }
-
- /* Use LB_FINDSTRINGEXACT to search for the item */
- int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
- if (!(0 <= start && start < count)) return -1;
- int index = start - 1, last;
- TCHAR buffer = new TCHAR (getCodePage (), string, true);
- do {
- index = OS.SendMessage (handle, OS.LB_FINDSTRINGEXACT, last = index, buffer);
- if (index == OS.LB_ERR || index <= last) return -1;
- } while (!string.equals (getItem (index)));
- return index;
-}
-
-/**
- * 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 visibility 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 ();
- int result = OS.SendMessage (handle, OS.LB_GETSEL, index, 0);
- return (result != 0) && (result != OS.LB_ERR);
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public void remove (int [] indices) {
- checkWidget ();
- if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
- int [] newIndices = new int [indices.length];
- System.arraycopy (indices, 0, newIndices, 0, indices.length);
- sort (newIndices);
- int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
- int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
- RECT rect = null;
- int hDC = 0, oldFont = 0, newFont = 0, newWidth = 0;
- if ((style & SWT.H_SCROLL) != 0) {
- rect = new RECT ();
- hDC = OS.GetDC (handle);
- newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
- }
- int cp = getCodePage ();
- int i = 0, topCount = 0, last = -1;
- while (i < newIndices.length) {
- int index = newIndices [i];
- if (index != last || i == 0) {
- TCHAR buffer = null;
- if ((style & SWT.H_SCROLL) != 0) {
- int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0);
- if (length == OS.LB_ERR) break;
- buffer = new TCHAR (cp, length + 1);
- int result = OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer);
- if (result == OS.LB_ERR) break;
- }
- int result = OS.SendMessage (handle, OS.LB_DELETESTRING, index, 0);
- if (result == OS.LB_ERR) break;
- if ((style & SWT.H_SCROLL) != 0) {
- int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
- OS.DrawText (hDC, buffer, -1, rect, flags);
- newWidth = Math.max (newWidth, rect.right - rect.left);
- }
- if (index < topIndex) topCount++;
- last = index;
- }
- i++;
- }
- if ((style & SWT.H_SCROLL) != 0) {
- if (newFont != 0) OS.SelectObject (hDC, oldFont);
- OS.ReleaseDC (handle, hDC);
- setScrollWidth (newWidth, false);
- }
- if (topCount > 0) {
- topIndex -= topCount;
- OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0);
- }
- if (i < newIndices.length) {
- int index = newIndices [i];
- if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
- error (SWT.ERROR_INVALID_RANGE);
- }
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public void remove (int index) {
- checkWidget ();
- TCHAR buffer = null;
- if ((style & SWT.H_SCROLL) != 0) {
- int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0);
- if (length == OS.LB_ERR) error (SWT.ERROR_ITEM_NOT_REMOVED);
- buffer = new TCHAR (getCodePage (), length + 1);
- int result = OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer);
- if (result == OS.LB_ERR) error (SWT.ERROR_ITEM_NOT_REMOVED);
- }
- int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
- int result = OS.SendMessage (handle, OS.LB_DELETESTRING, index, 0);
- if (result == OS.LB_ERR) {
- int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
- if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
- error (SWT.ERROR_INVALID_RANGE);
- }
- if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, false);
- if (index < topIndex) {
- OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex - 1, 0);
- }
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public void remove (int start, int end) {
- checkWidget ();
- if (start > end) return;
- int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
- int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
- RECT rect = null;
- int hDC = 0, oldFont = 0, newFont = 0, newWidth = 0;
- if ((style & SWT.H_SCROLL) != 0) {
- rect = new RECT ();
- hDC = OS.GetDC (handle);
- newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
- }
- int cp = getCodePage ();
- int index = start;
- int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
- while (index <= end) {
- TCHAR buffer = null;
- if ((style & SWT.H_SCROLL) != 0) {
- int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, start, 0);
- if (length == OS.LB_ERR) break;
- buffer = new TCHAR (cp, length + 1);
- int result = OS.SendMessage (handle, OS.LB_GETTEXT, start, buffer);
- if (result == OS.LB_ERR) break;
- }
- int result = OS.SendMessage (handle, OS.LB_DELETESTRING, start, 0);
- if (result == OS.LB_ERR) break;
- if ((style & SWT.H_SCROLL) != 0) {
- OS.DrawText (hDC, buffer, -1, rect, flags);
- newWidth = Math.max (newWidth, rect.right - rect.left);
- }
- index++;
- }
- if ((style & SWT.H_SCROLL) != 0) {
- if (newFont != 0) OS.SelectObject (hDC, oldFont);
- OS.ReleaseDC (handle, hDC);
- setScrollWidth (newWidth, false);
- }
- if (end < topIndex) {
- topIndex -= end - start + 1;
- OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0);
- }
- if (index <= end) {
- if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
- error (SWT.ERROR_INVALID_RANGE);
- }
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public void remove (String string) {
- checkWidget ();
- int index = indexOf (string, 0);
- if (index == -1) error (SWT.ERROR_INVALID_ARGUMENT);
- remove (index);
-}
-
-/**
- * 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 ();
- OS.SendMessage (handle, OS.LB_RESETCONTENT, 0, 0);
- if ((style & SWT.H_SCROLL) != 0) {
- OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, 0, 0);
- }
-}
-
-/**
- * Removes the listener from the collection of listeners who will
- * be notified when the receiver's selection changes.
- *
- * @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 items at the given zero-relative indices in the receiver.
- * If the item at the given zero-relative index in the receiver
- * is not selected, it is selected. If the item at the index
- * was selected, it remains selected. Indices that are out
- * of range and duplicate indices are ignored.
- *
- * @param indices the array of indices for the items to select
- *
- * @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>
- */
-public void select (int [] indices) {
- checkWidget ();
- if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
- select (indices, false);
-}
-
-void select (int [] indices, boolean scroll) {
- int i = 0;
- while (i < indices.length) {
- int index = indices [i];
- if (index != -1) {
- select (index, false);
- if ((style & SWT.SINGLE) != 0) {
- int count = getItemCount ();
- if (0 <= index && index < count) {
- break;
- }
- }
- }
- i++;
- }
- if (scroll) showSelection ();
-}
-
-/**
- * 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 ();
- select (index, false);
-}
-
-void select (int index, boolean scroll) {
- if (index == -1) return;
- if (scroll) {
- if ((style & SWT.SINGLE) != 0) {
- OS.SendMessage (handle, OS.LB_SETCURSEL, index, 0);
- } else {
- int focusIndex = OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
- OS.SendMessage (handle, OS.LB_SETSEL, 1, index);
- if (focusIndex != -1) {
- OS.SendMessage (handle, OS.LB_SETCARETINDEX, index, 0);
- }
- }
- return;
- }
- int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
- RECT itemRect = new RECT (), selectedRect = null;
- OS.SendMessage (handle, OS.LB_GETITEMRECT, index, itemRect);
- boolean redraw = drawCount == 0 && OS.IsWindowVisible (handle);
- if (redraw) {
- OS.UpdateWindow (handle);
- OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
- }
- int focusIndex = -1;
- if ((style & SWT.SINGLE) != 0) {
- int oldIndex = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
- if (oldIndex != -1) {
- selectedRect = new RECT ();
- OS.SendMessage (handle, OS.LB_GETITEMRECT, oldIndex, selectedRect);
- }
- OS.SendMessage (handle, OS.LB_SETCURSEL, index, 0);
- } else {
- focusIndex = OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
- OS.SendMessage (handle, OS.LB_SETSEL, 1, index);
- }
- if ((style & SWT.MULTI) != 0) {
- if (focusIndex != -1) {
- OS.SendMessage (handle, OS.LB_SETCARETINDEX, index, 0);
- }
- }
- OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0);
- if (redraw) {
- OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
- OS.ValidateRect (handle, null);
- OS.InvalidateRect (handle, itemRect, true);
- if (selectedRect != null) {
- OS.InvalidateRect (handle, selectedRect, true);
- }
- }
-}
-
-/**
- * Selects the items at the given zero-relative indices in the receiver.
- * If the item at the index was already selected, it remains
- * selected. The range of the indices is inclusive. Indices that are
- * out of range are ignored and no items will be selected if start is
- * greater than end.
- *
- * @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 select (int start, int end) {
- checkWidget ();
- select (start, end, false);
-}
-
-void select (int start, int end, boolean scroll) {
- if (start > end) return;
- if ((style & SWT.SINGLE) != 0) {
- int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
- int index = Math.min (count - 1, end);
- if (index >= start) select (index, scroll);
- return;
- }
- /*
- * Ensure that at least one item is contained in
- * the range from start to end. Note that when
- * start = end, LB_SELITEMRANGEEX deselects the
- * item.
- */
- int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
- if (start < 0 && end < 0) return;
- if (start >= count && end >= count) return;
- start = Math.min (count - 1, Math.max (0, start));
- end = Math.min (count - 1, Math.max (0, end));
- if (start == end) {
- select (start, scroll);
- return;
- }
- OS.SendMessage (handle, OS.LB_SELITEMRANGEEX, start, end);
- if (scroll) showSelection ();
-}
-
-/**
- * Selects all 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 void selectAll () {
- checkWidget ();
- if ((style & SWT.SINGLE) != 0) return;
- OS.SendMessage (handle, OS.LB_SETSEL, 1, -1);
-}
-
-void setBounds (int x, int y, int width, int height, int flags) {
- /*
- * Bug in Windows. If the receiver is scrolled horizontally
- * and is resized, the list does not redraw properly. The fix
- * is to redraw the control when resizing is not deferred and
- * the new size is different from the previous size.
- */
- if (parent.lpwp != null || (flags & OS.SWP_NOSIZE) != 0) {
- super.setBounds (x, y, width, height, flags);
- return;
- }
- RECT rect = new RECT ();
- OS.GetWindowRect (handle, rect);
- int oldWidth = rect.right - rect.left;
- int oldHeight = rect.bottom - rect.top;
- super.setBounds (x, y, width, height, flags);
- if (oldWidth == width && oldHeight == height) return;
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_POS;
- if (!OS.GetScrollInfo (handle, OS.SB_HORZ, info)) return;
- if (info.nPos != 0) OS.InvalidateRect (handle, null, true);
-}
-
-void setFocusIndex (int index) {
- OS.SendMessage (handle, OS.LB_SETCARETINDEX, index, 0);
-}
-
-public void setFont (Font font) {
- checkWidget ();
- super.setFont (font);
- if ((style & SWT.H_SCROLL) != 0) setScrollWidth ();
-}
-
-/**
- * Sets the text of the item in the receiver's list at the given
- * zero-relative index to the string argument. This is equivalent
- * to <code>remove</code>'ing the old item at the index, and then
- * <code>add</code>'ing the new item at that index.
- *
- * @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>
- * @exception SWTError <ul>
- * <li>ERROR_ITEM_NOT_REMOVED - if the remove operation fails because of an operating system failure</li>
- * <li>ERROR_ITEM_NOT_ADDED - if the add operation fails because of an operating system failure</li>
- * </ul>
- */
-public void setItem (int index, String string) {
- checkWidget ();
- if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
- int topIndex = getTopIndex ();
- boolean isSelected = isSelected (index);
- remove (index);
- add (string, index);
- if (isSelected) select (index, false);
- setTopIndex (topIndex);
-}
-
-/**
- * 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>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - 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 SWTError <ul>
- * <li>ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public void setItems (String [] items) {
- checkWidget ();
- if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
- int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC);
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, ListProc);
- boolean redraw = drawCount == 0 && OS.IsWindowVisible (handle);
- if (redraw) {
- OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
- }
- RECT rect = null;
- int hDC = 0, oldFont = 0, newFont = 0, newWidth = 0;
- if ((style & SWT.H_SCROLL) != 0) {
- rect = new RECT ();
- hDC = OS.GetDC (handle);
- newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
- OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, 0, 0);
- }
- int length = items.length;
- OS.SendMessage (handle, OS.LB_RESETCONTENT, 0, 0);
- OS.SendMessage (handle, OS.LB_INITSTORAGE, length, length * 32);
- int index = 0;
- int cp = getCodePage ();
- while (index < length) {
- String string = items [index];
- if (string == null) break;
- TCHAR buffer = new TCHAR (cp, string, true);
- int result = OS.SendMessage (handle, OS.LB_ADDSTRING, 0, buffer);
- if (result == OS.LB_ERR || result == OS.LB_ERRSPACE) break;
- if ((style & SWT.H_SCROLL) != 0) {
- int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
- OS.DrawText (hDC, buffer, buffer.length (), rect, flags);
- newWidth = Math.max (newWidth, rect.right - rect.left);
- }
- index++;
- }
- if ((style & SWT.H_SCROLL) != 0) {
- if (newFont != 0) OS.SelectObject (hDC, oldFont);
- OS.ReleaseDC (handle, hDC);
- OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, newWidth + 3, 0);
- }
- if (redraw) {
- OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
- /*
- * This code is intentionally commented. The window proc
- * for the list box implements WM_SETREDRAW to invalidate
- * and erase the widget. This is undocumented behavior.
- * The commented code below shows what is actually happening
- * and reminds us that we are relying on this undocumented
- * behavior.
- */
-// int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE;
-// OS.RedrawWindow (handle, null, 0, flags);
- }
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
- if (index < items.length) error (SWT.ERROR_ITEM_NOT_ADDED);
-}
-
-void setScrollWidth () {
- int newWidth = 0;
- RECT rect = new RECT ();
- int newFont, oldFont = 0;
- int hDC = OS.GetDC (handle);
- newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
- int cp = getCodePage ();
- int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
- int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
- for (int i=0; i<count; i++) {
- int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, i, 0);
- if (length != OS.LB_ERR) {
- TCHAR buffer = new TCHAR (cp, length + 1);
- int result = OS.SendMessage (handle, OS.LB_GETTEXT, i, buffer);
- if (result != OS.LB_ERR) {
- OS.DrawText (hDC, buffer, -1, rect, flags);
- newWidth = Math.max (newWidth, rect.right - rect.left);
- }
- }
- }
- if (newFont != 0) OS.SelectObject (hDC, oldFont);
- OS.ReleaseDC (handle, hDC);
- OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, newWidth + 3, 0);
-}
-
-void setScrollWidth (TCHAR buffer, boolean grow) {
- RECT rect = new RECT ();
- int newFont, oldFont = 0;
- int hDC = OS.GetDC (handle);
- newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
- int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
- OS.DrawText (hDC, buffer, -1, rect, flags);
- if (newFont != 0) OS.SelectObject (hDC, oldFont);
- OS.ReleaseDC (handle, hDC);
- setScrollWidth (rect.right - rect.left, grow);
-}
-
-void setScrollWidth (int newWidth, boolean grow) {
- int width = OS.SendMessage (handle, OS.LB_GETHORIZONTALEXTENT, 0, 0);
- if (grow) {
- if (newWidth <= width) return;
- OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, newWidth + 3, 0);
- } else {
- if (newWidth < width) return;
- setScrollWidth ();
- }
-}
-
-/**
- * Selects the items at the given zero-relative indices in the receiver.
- * The current selection is first cleared, then the new items are selected.
- *
- * @param indices the indices of the items to select
- *
- * @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 List#deselectAll()
- * @see List#select(int[])
- */
-public void setSelection(int [] indices) {
- checkWidget ();
- if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
- deselectAll ();
- select (indices, true);
- if ((style & SWT.MULTI) != 0) {
- if (indices.length != 0) {
- int focusIndex = indices [0];
- if (focusIndex != -1) setFocusIndex (focusIndex);
- }
- }
-}
-
-/**
- * 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 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 List#deselectAll()
- * @see List#select(int)
- */
-public void setSelection (String [] items) {
- checkWidget ();
- if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
- if ((style & SWT.MULTI) != 0) deselectAll ();
- int focusIndex = -1;
- for (int i=items.length-1; i>=0; --i) {
- String string = items [i];
- int index = 0;
- if (string != null) {
- int localFocus = -1;
- while ((index = indexOf (string, index)) != -1) {
- if (localFocus == -1) localFocus = index;
- select (index, false);
- if ((style & SWT.SINGLE) != 0 && isSelected (index)) {
- /*
- * Return and rely on the fact that select ()
- * for single-select lists clears the previous
- * selection.
- */
- showSelection ();
- return;
- }
- index++;
- }
- if (localFocus != -1) focusIndex = localFocus;
- }
- }
- if ((style & SWT.SINGLE) != 0) deselectAll ();
- if ((style & SWT.MULTI) != 0) {
- if (focusIndex != -1) setFocusIndex (focusIndex);
- }
-}
-
-/**
- * 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 selected 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>
- * @see List#deselectAll()
- * @see List#select(int)
- */
-public void setSelection (int index) {
- checkWidget ();
- if ((style & SWT.MULTI) != 0) deselectAll ();
- select (index, true);
- if ((style & SWT.MULTI) != 0) {
- if (index != -1) setFocusIndex (index);
- }
-}
-
-/**
- * Selects the items at the given zero-relative indices in the receiver.
- * The current selection is first cleared, then the new items are selected.
- * Indices that are out of range are ignored and no items will be selected
- * if start is greater than end.
- *
- * @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 ();
- if ((style & SWT.MULTI) != 0) deselectAll ();
- select (start, end, true);
- if ((style & SWT.MULTI) != 0) {
- if (start != -1) setFocusIndex (start);
- }
-}
-
-/**
- * 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 ();
- int result = OS.SendMessage (handle, OS.LB_SETTOPINDEX, index, 0);
- if (result == OS.LB_ERR) {
- int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
- index = Math.min (count - 1, Math.max (0, index));
- OS.SendMessage (handle, OS.LB_SETTOPINDEX, index, 0);
- }
-}
-
-/**
- * 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;
- if ((style & SWT.SINGLE) != 0) {
- index = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
- } else {
- int [] indices = new int [1];
- int result = OS.SendMessage (handle, OS.LB_GETSELITEMS, 1, indices);
- index = indices [0];
- if (result != 1) index = -1;
- }
- if (index == -1) return;
- int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
- if (count == 0) return;
- int height = OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0);
- RECT rect = new RECT ();
- OS.GetClientRect (handle, rect);
- int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
- int visibleCount = Math.max (rect.bottom / height, 1);
- int bottomIndex = Math.min (topIndex + visibleCount + 1, count - 1);
- if ((topIndex <= index) && (index <= bottomIndex)) return;
- int newTop = Math.min (Math.max (index - (visibleCount / 2), 0), count - 1);
- OS.SendMessage (handle, OS.LB_SETTOPINDEX, newTop, 0);
-}
-
-int widgetStyle () {
- int bits = super.widgetStyle () | OS.LBS_NOTIFY | OS.LBS_NOINTEGRALHEIGHT;
- if ((style & SWT.SINGLE) != 0) return bits;
- if ((style & SWT.MULTI) != 0) {
- if ((style & SWT.SIMPLE) != 0) return bits | OS.LBS_MULTIPLESEL;
- return bits | OS.LBS_EXTENDEDSEL;
- }
- return bits;
-}
-
-TCHAR windowClass () {
- return ListClass;
-}
-
-int windowProc () {
- return ListProc;
-}
-
-LRESULT wmCommandChild (int wParam, int lParam) {
- int code = wParam >> 16;
- switch (code) {
- case OS.LBN_SELCHANGE:
- postEvent (SWT.Selection);
- break;
- case OS.LBN_DBLCLK:
- postEvent (SWT.DefaultSelection);
- break;
- }
- return super.wmCommandChild (wParam, lParam);
-}
-
-
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +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 displays a list of strings and issues notificiation + * when a string 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> + */ + +public class List extends Scrollable { + static final int ListProc; + static final TCHAR ListClass = new TCHAR (0, "LISTBOX", true); + static { + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, ListClass, lpWndClass); + ListProc = lpWndClass.lpfnWndProc; + } + +/** + * 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)); +} +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure</li> + * </ul> + * + * @see #add(String,int) + */ +public void add (String string) { + checkWidget (); + if (string == null) error (SWT.ERROR_NULL_ARGUMENT); + TCHAR buffer = new TCHAR (getCodePage (), string, true); + int result = OS.SendMessage (handle, OS.LB_ADDSTRING, 0, buffer); + if (result == OS.LB_ERR) error (SWT.ERROR_ITEM_NOT_ADDED); + if (result == OS.LB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED); + if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, true); +} +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure</li> + * </ul> + * + * @see #add(String) + */ +public void add (String string, int index) { + checkWidget (); + if (string == null) error (SWT.ERROR_NULL_ARGUMENT); + if (index == -1) error (SWT.ERROR_INVALID_RANGE); + TCHAR buffer = new TCHAR (getCodePage (), string, true); + int result = OS.SendMessage (handle, OS.LB_INSERTSTRING, index, buffer); + if (result == OS.LB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED); + if (result == OS.LB_ERR) { + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (0 <= index && index <= count) { + error (SWT.ERROR_ITEM_NOT_ADDED); + } else { + error (SWT.ERROR_INVALID_RANGE); + } + } + if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, true); +} + +/** + * Adds the listener to the collection of listeners who will + * be notified when the receiver's selection changes, 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 + * + * @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); +} + +int callWindowProc (int msg, int wParam, int lParam) { + if (handle == 0) return 0; + return OS.CallWindowProc (ListProc, handle, msg, wParam, lParam); +} + +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 count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + int itemHeight = OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0); + int width = 0, height = count * itemHeight; + if ((style & SWT.H_SCROLL) != 0) { + width = OS.SendMessage (handle, OS.LB_GETHORIZONTALEXTENT, 0, 0); + } else { + int newFont, oldFont = 0; + int hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); + RECT rect = new RECT (); + int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX; + int cp = getCodePage (); + TCHAR buffer = new TCHAR (cp, 64 + 1); + for (int i=0; i<count; i++) { + int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, i, 0); + if (length != OS.LB_ERR) { + if (length + 1 > buffer.length ()) { + buffer = new TCHAR (cp, length + 1); + } + int result = OS.SendMessage (handle, OS.LB_GETTEXT, i, buffer); + if (result != OS.LB_ERR) { + OS.DrawText (hDC, buffer, length, rect, flags); + width = Math.max (width, rect.right - rect.left); + } + } + } + if (newFont != 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + } + 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 + 3; + height += border * 2; + if ((style & SWT.V_SCROLL) != 0) { + width += OS.GetSystemMetrics (OS.SM_CXVSCROLL); + } + if ((style & SWT.H_SCROLL) != 0) { + height += OS.GetSystemMetrics (OS.SM_CYHSCROLL); + } + return new Point (width, height); +} + +int defaultBackground () { + return OS.GetSysColor (OS.COLOR_WINDOW); +} + +/** + * 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 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> + */ +public void deselect (int [] indices) { + checkWidget (); + if (indices == null) error (SWT.ERROR_NULL_ARGUMENT); + if (indices.length == 0) return; + if ((style & SWT.SINGLE) != 0) { + int oldIndex = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0); + if (oldIndex == OS.LB_ERR) return; + for (int i=0; i<indices.length; i++) { + if (oldIndex == indices [i]) { + OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0); + return; + } + } + return; + } + for (int i=0; i<indices.length; i++) { + int index = indices [i]; + if (index != -1) { + OS.SendMessage (handle, OS.LB_SETSEL, 0, index); + } + } +} + +/** + * 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 (index == -1) return; + if ((style & SWT.SINGLE) != 0) { + int oldIndex = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0); + if (oldIndex == OS.LB_ERR) return; + if (oldIndex == index) OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0); + return; + } + OS.SendMessage (handle, OS.LB_SETSEL, 0, index); +} + +/** + * 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 ((style & SWT.SINGLE) != 0) { + int oldIndex = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0); + if (oldIndex == OS.LB_ERR) return; + if (start <= oldIndex && oldIndex <= end) { + OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0); + } + return; + } + /* + * Ensure that at least one item is contained in + * the range from start to end. Note that when + * start = end, LB_SELITEMRANGEEX deselects the + * item. + */ + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (start < 0 && end < 0) return; + if (start >= count && end >= count) return; + start = Math.min (count - 1, Math.max (0, start)); + end = Math.min (count - 1, Math.max (0, end)); + OS.SendMessage (handle, OS.LB_SELITEMRANGEEX, end, start); +} + +/** + * 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 (); + if ((style & SWT.SINGLE) != 0) { + OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0); + } else { + OS.SendMessage (handle, OS.LB_SETSEL, 0, -1); + } +} + +/** + * Returns the zero-relative index of the item which is currently + * has the focus in the receiver, or -1 if no item is 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 OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</li> + * </ul> + */ +public String getItem (int index) { + checkWidget (); + int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0); + if (length != OS.LB_ERR) { + TCHAR buffer = new TCHAR (getCodePage (), length + 1); + int result = OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer); + if (result != OS.LB_ERR) return buffer.toString (0, length); + } + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (0 <= index && index < count) { + error (SWT.ERROR_CANNOT_GET_ITEM); + } else { + error (SWT.ERROR_INVALID_RANGE); + } + 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure</li> + * </ul> + */ +public int getItemCount () { + checkWidget (); + int result = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_COUNT); + return result; +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_ITEM_HEIGHT - if the operation fails because of an operating system failure</li> + * </ul> + */ +public int getItemHeight () { + checkWidget (); + int result = OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0); + if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_ITEM_HEIGHT); + return result; +} + +/** + * Returns an 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure while getting an item</li> + * <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure while getting the item count</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 an array of <code>String</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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_SELECTION - if the operation fails because of an operating system failure while getting the selection</li> + * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure while getting an item</li> + * </ul> + */ +public String [] getSelection () { + checkWidget (); + int [] indices = getSelectionIndices (); + String [] result = new String [indices.length]; + for (int i=0; i<indices.length; i++) { + result [i] = getItem (indices [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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure</li> + * </ul> + */ +public int getSelectionCount () { + checkWidget (); + if ((style & SWT.SINGLE) != 0) { + int result = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0); + if (result == OS.LB_ERR) return 0; + return 1; + } + int result = OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0); + if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_COUNT); + return result; +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_SELECTION - if the operation fails because of an operating system failure</li> + * </ul> + */ +public int getSelectionIndex () { + checkWidget (); + if ((style & SWT.SINGLE) != 0) { + return OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0); + } + int count = OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0); + if (count == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_SELECTION); + if (count == 0) return -1; + int index = OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0); + int result = OS.SendMessage (handle, OS.LB_GETSEL, index, 0); + if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_SELECTION); + if (result != 0) return index; + int [] buffer = new int [1]; + result = OS.SendMessage (handle, OS.LB_GETSELITEMS, 1, buffer); + if (result != 1) error (SWT.ERROR_CANNOT_GET_SELECTION); + return buffer [0]; +} + +/** + * Returns the zero-relative indices of the items which are currently + * selected in the receiver. 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_SELECTION - if the operation fails because of an operating system failure</li> + * </ul> + */ +public int [] getSelectionIndices () { + checkWidget (); + if ((style & SWT.SINGLE) != 0) { + int result = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0); + if (result == OS.LB_ERR) return new int [0]; + return new int [] {result}; + } + int length = OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0); + if (length == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_SELECTION); + int [] indices = new int [length]; + int result = OS.SendMessage (handle, OS.LB_GETSELITEMS, length, indices); + if (result != length) error (SWT.ERROR_CANNOT_GET_SELECTION); + return indices; +} + +/** + * 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 (); + return OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0); +} + +/** + * 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 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 + * @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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure while getting the item count</li> + * <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure while getting an item</li> + * </ul> + */ +public int indexOf (String string, int start) { + checkWidget (); + if (string == null) error (SWT.ERROR_NULL_ARGUMENT); + + /* + * Bug in Windows. For some reason, LB_FINDSTRINGEXACT + * will not find empty strings even though it is legal + * to insert an empty string into a list. The fix is + * to search the list, an item at a time. + */ + if (string.length () == 0) { + int count = getItemCount (); + for (int i=start; i<count; i++) { + if (string.equals (getItem (i))) return i; + } + return -1; + } + + /* Use LB_FINDSTRINGEXACT to search for the item */ + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (!(0 <= start && start < count)) return -1; + int index = start - 1, last; + TCHAR buffer = new TCHAR (getCodePage (), string, true); + do { + index = OS.SendMessage (handle, OS.LB_FINDSTRINGEXACT, last = index, buffer); + if (index == OS.LB_ERR || index <= last) return -1; + } while (!string.equals (getItem (index))); + return index; +} + +/** + * 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 visibility 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 (); + int result = OS.SendMessage (handle, OS.LB_GETSEL, index, 0); + return (result != 0) && (result != OS.LB_ERR); +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li> + * </ul> + */ +public void remove (int [] indices) { + checkWidget (); + if (indices == null) error (SWT.ERROR_NULL_ARGUMENT); + int [] newIndices = new int [indices.length]; + System.arraycopy (indices, 0, newIndices, 0, indices.length); + sort (newIndices); + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0); + RECT rect = null; + int hDC = 0, oldFont = 0, newFont = 0, newWidth = 0; + if ((style & SWT.H_SCROLL) != 0) { + rect = new RECT (); + hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); + } + int cp = getCodePage (); + int i = 0, topCount = 0, last = -1; + while (i < newIndices.length) { + int index = newIndices [i]; + if (index != last || i == 0) { + TCHAR buffer = null; + if ((style & SWT.H_SCROLL) != 0) { + int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0); + if (length == OS.LB_ERR) break; + buffer = new TCHAR (cp, length + 1); + int result = OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer); + if (result == OS.LB_ERR) break; + } + int result = OS.SendMessage (handle, OS.LB_DELETESTRING, index, 0); + if (result == OS.LB_ERR) break; + if ((style & SWT.H_SCROLL) != 0) { + int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX; + OS.DrawText (hDC, buffer, -1, rect, flags); + newWidth = Math.max (newWidth, rect.right - rect.left); + } + if (index < topIndex) topCount++; + last = index; + } + i++; + } + if ((style & SWT.H_SCROLL) != 0) { + if (newFont != 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + setScrollWidth (newWidth, false); + } + if (topCount > 0) { + topIndex -= topCount; + OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0); + } + if (i < newIndices.length) { + int index = newIndices [i]; + if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED); + error (SWT.ERROR_INVALID_RANGE); + } +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li> + * </ul> + */ +public void remove (int index) { + checkWidget (); + TCHAR buffer = null; + if ((style & SWT.H_SCROLL) != 0) { + int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0); + if (length == OS.LB_ERR) error (SWT.ERROR_ITEM_NOT_REMOVED); + buffer = new TCHAR (getCodePage (), length + 1); + int result = OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer); + if (result == OS.LB_ERR) error (SWT.ERROR_ITEM_NOT_REMOVED); + } + int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0); + int result = OS.SendMessage (handle, OS.LB_DELETESTRING, index, 0); + if (result == OS.LB_ERR) { + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED); + error (SWT.ERROR_INVALID_RANGE); + } + if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, false); + if (index < topIndex) { + OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex - 1, 0); + } +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li> + * </ul> + */ +public void remove (int start, int end) { + checkWidget (); + if (start > end) return; + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0); + RECT rect = null; + int hDC = 0, oldFont = 0, newFont = 0, newWidth = 0; + if ((style & SWT.H_SCROLL) != 0) { + rect = new RECT (); + hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); + } + int cp = getCodePage (); + int index = start; + int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX; + while (index <= end) { + TCHAR buffer = null; + if ((style & SWT.H_SCROLL) != 0) { + int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, start, 0); + if (length == OS.LB_ERR) break; + buffer = new TCHAR (cp, length + 1); + int result = OS.SendMessage (handle, OS.LB_GETTEXT, start, buffer); + if (result == OS.LB_ERR) break; + } + int result = OS.SendMessage (handle, OS.LB_DELETESTRING, start, 0); + if (result == OS.LB_ERR) break; + if ((style & SWT.H_SCROLL) != 0) { + OS.DrawText (hDC, buffer, -1, rect, flags); + newWidth = Math.max (newWidth, rect.right - rect.left); + } + index++; + } + if ((style & SWT.H_SCROLL) != 0) { + if (newFont != 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + setScrollWidth (newWidth, false); + } + if (end < topIndex) { + topIndex -= end - start + 1; + OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0); + } + if (index <= end) { + if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED); + error (SWT.ERROR_INVALID_RANGE); + } +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li> + * </ul> + */ +public void remove (String string) { + checkWidget (); + int index = indexOf (string, 0); + if (index == -1) error (SWT.ERROR_INVALID_ARGUMENT); + remove (index); +} + +/** + * 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 (); + OS.SendMessage (handle, OS.LB_RESETCONTENT, 0, 0); + if ((style & SWT.H_SCROLL) != 0) { + OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, 0, 0); + } +} + +/** + * Removes the listener from the collection of listeners who will + * be notified when the receiver's selection changes. + * + * @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 items at the given zero-relative indices in the receiver. + * If the item at the given zero-relative index in the receiver + * is not selected, it is selected. If the item at the index + * was selected, it remains selected. Indices that are out + * of range and duplicate indices are ignored. + * + * @param indices the array of indices for the items to select + * + * @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> + */ +public void select (int [] indices) { + checkWidget (); + if (indices == null) error (SWT.ERROR_NULL_ARGUMENT); + select (indices, false); +} + +void select (int [] indices, boolean scroll) { + int i = 0; + while (i < indices.length) { + int index = indices [i]; + if (index != -1) { + select (index, false); + if ((style & SWT.SINGLE) != 0) { + int count = getItemCount (); + if (0 <= index && index < count) { + break; + } + } + } + i++; + } + if (scroll) showSelection (); +} + +/** + * 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 (); + select (index, false); +} + +void select (int index, boolean scroll) { + if (index == -1) return; + if (scroll) { + if ((style & SWT.SINGLE) != 0) { + OS.SendMessage (handle, OS.LB_SETCURSEL, index, 0); + } else { + int focusIndex = OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0); + OS.SendMessage (handle, OS.LB_SETSEL, 1, index); + if (focusIndex != -1) { + OS.SendMessage (handle, OS.LB_SETCARETINDEX, index, 0); + } + } + return; + } + int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0); + RECT itemRect = new RECT (), selectedRect = null; + OS.SendMessage (handle, OS.LB_GETITEMRECT, index, itemRect); + boolean redraw = drawCount == 0 && OS.IsWindowVisible (handle); + if (redraw) { + OS.UpdateWindow (handle); + OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); + } + int focusIndex = -1; + if ((style & SWT.SINGLE) != 0) { + int oldIndex = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0); + if (oldIndex != -1) { + selectedRect = new RECT (); + OS.SendMessage (handle, OS.LB_GETITEMRECT, oldIndex, selectedRect); + } + OS.SendMessage (handle, OS.LB_SETCURSEL, index, 0); + } else { + focusIndex = OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0); + OS.SendMessage (handle, OS.LB_SETSEL, 1, index); + } + if ((style & SWT.MULTI) != 0) { + if (focusIndex != -1) { + OS.SendMessage (handle, OS.LB_SETCARETINDEX, index, 0); + } + } + OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0); + if (redraw) { + OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0); + OS.ValidateRect (handle, null); + OS.InvalidateRect (handle, itemRect, true); + if (selectedRect != null) { + OS.InvalidateRect (handle, selectedRect, true); + } + } +} + +/** + * Selects the items at the given zero-relative indices in the receiver. + * If the item at the index was already selected, it remains + * selected. The range of the indices is inclusive. Indices that are + * out of range are ignored and no items will be selected if start is + * greater than end. + * + * @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 select (int start, int end) { + checkWidget (); + select (start, end, false); +} + +void select (int start, int end, boolean scroll) { + if (start > end) return; + if ((style & SWT.SINGLE) != 0) { + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + int index = Math.min (count - 1, end); + if (index >= start) select (index, scroll); + return; + } + /* + * Ensure that at least one item is contained in + * the range from start to end. Note that when + * start = end, LB_SELITEMRANGEEX deselects the + * item. + */ + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (start < 0 && end < 0) return; + if (start >= count && end >= count) return; + start = Math.min (count - 1, Math.max (0, start)); + end = Math.min (count - 1, Math.max (0, end)); + if (start == end) { + select (start, scroll); + return; + } + OS.SendMessage (handle, OS.LB_SELITEMRANGEEX, start, end); + if (scroll) showSelection (); +} + +/** + * Selects all 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 void selectAll () { + checkWidget (); + if ((style & SWT.SINGLE) != 0) return; + OS.SendMessage (handle, OS.LB_SETSEL, 1, -1); +} + +void setBounds (int x, int y, int width, int height, int flags) { + /* + * Bug in Windows. If the receiver is scrolled horizontally + * and is resized, the list does not redraw properly. The fix + * is to redraw the control when resizing is not deferred and + * the new size is different from the previous size. + */ + if (parent.lpwp != null || (flags & OS.SWP_NOSIZE) != 0) { + super.setBounds (x, y, width, height, flags); + return; + } + RECT rect = new RECT (); + OS.GetWindowRect (handle, rect); + int oldWidth = rect.right - rect.left; + int oldHeight = rect.bottom - rect.top; + super.setBounds (x, y, width, height, flags); + if (oldWidth == width && oldHeight == height) return; + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_POS; + if (!OS.GetScrollInfo (handle, OS.SB_HORZ, info)) return; + if (info.nPos != 0) OS.InvalidateRect (handle, null, true); +} + +void setFocusIndex (int index) { + OS.SendMessage (handle, OS.LB_SETCARETINDEX, index, 0); +} + +public void setFont (Font font) { + checkWidget (); + super.setFont (font); + if ((style & SWT.H_SCROLL) != 0) setScrollWidth (); +} + +/** + * Sets the text of the item in the receiver's list at the given + * zero-relative index to the string argument. This is equivalent + * to <code>remove</code>'ing the old item at the index, and then + * <code>add</code>'ing the new item at that index. + * + * @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> + * @exception SWTError <ul> + * <li>ERROR_ITEM_NOT_REMOVED - if the remove operation fails because of an operating system failure</li> + * <li>ERROR_ITEM_NOT_ADDED - if the add operation fails because of an operating system failure</li> + * </ul> + */ +public void setItem (int index, String string) { + checkWidget (); + if (string == null) error (SWT.ERROR_NULL_ARGUMENT); + int topIndex = getTopIndex (); + boolean isSelected = isSelected (index); + remove (index); + add (string, index); + if (isSelected) select (index, false); + setTopIndex (topIndex); +} + +/** + * 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> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - 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 SWTError <ul> + * <li>ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure</li> + * </ul> + */ +public void setItems (String [] items) { + checkWidget (); + if (items == null) error (SWT.ERROR_NULL_ARGUMENT); + int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC); + OS.SetWindowLong (handle, OS.GWL_WNDPROC, ListProc); + boolean redraw = drawCount == 0 && OS.IsWindowVisible (handle); + if (redraw) { + OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); + } + RECT rect = null; + int hDC = 0, oldFont = 0, newFont = 0, newWidth = 0; + if ((style & SWT.H_SCROLL) != 0) { + rect = new RECT (); + hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); + OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, 0, 0); + } + int length = items.length; + OS.SendMessage (handle, OS.LB_RESETCONTENT, 0, 0); + OS.SendMessage (handle, OS.LB_INITSTORAGE, length, length * 32); + int index = 0; + int cp = getCodePage (); + while (index < length) { + String string = items [index]; + if (string == null) break; + TCHAR buffer = new TCHAR (cp, string, true); + int result = OS.SendMessage (handle, OS.LB_ADDSTRING, 0, buffer); + if (result == OS.LB_ERR || result == OS.LB_ERRSPACE) break; + if ((style & SWT.H_SCROLL) != 0) { + int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX; + OS.DrawText (hDC, buffer, buffer.length (), rect, flags); + newWidth = Math.max (newWidth, rect.right - rect.left); + } + index++; + } + if ((style & SWT.H_SCROLL) != 0) { + if (newFont != 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, newWidth + 3, 0); + } + if (redraw) { + OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0); + /* + * This code is intentionally commented. The window proc + * for the list box implements WM_SETREDRAW to invalidate + * and erase the widget. This is undocumented behavior. + * The commented code below shows what is actually happening + * and reminds us that we are relying on this undocumented + * behavior. + */ +// int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE; +// OS.RedrawWindow (handle, null, 0, flags); + } + OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc); + if (index < items.length) error (SWT.ERROR_ITEM_NOT_ADDED); +} + +void setScrollWidth () { + int newWidth = 0; + RECT rect = new RECT (); + int newFont, oldFont = 0; + int hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); + int cp = getCodePage (); + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX; + for (int i=0; i<count; i++) { + int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, i, 0); + if (length != OS.LB_ERR) { + TCHAR buffer = new TCHAR (cp, length + 1); + int result = OS.SendMessage (handle, OS.LB_GETTEXT, i, buffer); + if (result != OS.LB_ERR) { + OS.DrawText (hDC, buffer, -1, rect, flags); + newWidth = Math.max (newWidth, rect.right - rect.left); + } + } + } + if (newFont != 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, newWidth + 3, 0); +} + +void setScrollWidth (TCHAR buffer, boolean grow) { + RECT rect = new RECT (); + int newFont, oldFont = 0; + int hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); + int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX; + OS.DrawText (hDC, buffer, -1, rect, flags); + if (newFont != 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + setScrollWidth (rect.right - rect.left, grow); +} + +void setScrollWidth (int newWidth, boolean grow) { + int width = OS.SendMessage (handle, OS.LB_GETHORIZONTALEXTENT, 0, 0); + if (grow) { + if (newWidth <= width) return; + OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, newWidth + 3, 0); + } else { + if (newWidth < width) return; + setScrollWidth (); + } +} + +/** + * Selects the items at the given zero-relative indices in the receiver. + * The current selection is first cleared, then the new items are selected. + * + * @param indices the indices of the items to select + * + * @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 List#deselectAll() + * @see List#select(int[]) + */ +public void setSelection(int [] indices) { + checkWidget (); + if (indices == null) error (SWT.ERROR_NULL_ARGUMENT); + deselectAll (); + select (indices, true); + if ((style & SWT.MULTI) != 0) { + if (indices.length != 0) { + int focusIndex = indices [0]; + if (focusIndex != -1) setFocusIndex (focusIndex); + } + } +} + +/** + * 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 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 List#deselectAll() + * @see List#select(int) + */ +public void setSelection (String [] items) { + checkWidget (); + if (items == null) error (SWT.ERROR_NULL_ARGUMENT); + if ((style & SWT.MULTI) != 0) deselectAll (); + int focusIndex = -1; + for (int i=items.length-1; i>=0; --i) { + String string = items [i]; + int index = 0; + if (string != null) { + int localFocus = -1; + while ((index = indexOf (string, index)) != -1) { + if (localFocus == -1) localFocus = index; + select (index, false); + if ((style & SWT.SINGLE) != 0 && isSelected (index)) { + /* + * Return and rely on the fact that select () + * for single-select lists clears the previous + * selection. + */ + showSelection (); + return; + } + index++; + } + if (localFocus != -1) focusIndex = localFocus; + } + } + if ((style & SWT.SINGLE) != 0) deselectAll (); + if ((style & SWT.MULTI) != 0) { + if (focusIndex != -1) setFocusIndex (focusIndex); + } +} + +/** + * 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 selected 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> + * @see List#deselectAll() + * @see List#select(int) + */ +public void setSelection (int index) { + checkWidget (); + if ((style & SWT.MULTI) != 0) deselectAll (); + select (index, true); + if ((style & SWT.MULTI) != 0) { + if (index != -1) setFocusIndex (index); + } +} + +/** + * Selects the items at the given zero-relative indices in the receiver. + * The current selection is first cleared, then the new items are selected. + * Indices that are out of range are ignored and no items will be selected + * if start is greater than end. + * + * @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 (); + if ((style & SWT.MULTI) != 0) deselectAll (); + select (start, end, true); + if ((style & SWT.MULTI) != 0) { + if (start != -1) setFocusIndex (start); + } +} + +/** + * 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 (); + int result = OS.SendMessage (handle, OS.LB_SETTOPINDEX, index, 0); + if (result == OS.LB_ERR) { + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + index = Math.min (count - 1, Math.max (0, index)); + OS.SendMessage (handle, OS.LB_SETTOPINDEX, index, 0); + } +} + +/** + * 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; + if ((style & SWT.SINGLE) != 0) { + index = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0); + } else { + int [] indices = new int [1]; + int result = OS.SendMessage (handle, OS.LB_GETSELITEMS, 1, indices); + index = indices [0]; + if (result != 1) index = -1; + } + if (index == -1) return; + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (count == 0) return; + int height = OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0); + RECT rect = new RECT (); + OS.GetClientRect (handle, rect); + int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0); + int visibleCount = Math.max (rect.bottom / height, 1); + int bottomIndex = Math.min (topIndex + visibleCount + 1, count - 1); + if ((topIndex <= index) && (index <= bottomIndex)) return; + int newTop = Math.min (Math.max (index - (visibleCount / 2), 0), count - 1); + OS.SendMessage (handle, OS.LB_SETTOPINDEX, newTop, 0); +} + +int widgetStyle () { + int bits = super.widgetStyle () | OS.LBS_NOTIFY | OS.LBS_NOINTEGRALHEIGHT; + if ((style & SWT.SINGLE) != 0) return bits; + if ((style & SWT.MULTI) != 0) { + if ((style & SWT.SIMPLE) != 0) return bits | OS.LBS_MULTIPLESEL; + return bits | OS.LBS_EXTENDEDSEL; + } + return bits; +} + +TCHAR windowClass () { + return ListClass; +} + +int windowProc () { + return ListProc; +} + +LRESULT wmCommandChild (int wParam, int lParam) { + int code = wParam >> 16; + switch (code) { + case OS.LBN_SELCHANGE: + postEvent (SWT.Selection); + break; + case OS.LBN_DBLCLK: + postEvent (SWT.DefaultSelection); + break; + } + return super.wmCommandChild (wParam, lParam); +} + + + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Menu.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Menu.java index 21339f817a..c0c411558a 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Menu.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Menu.java @@ -1,1200 +1,1200 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.events.*;
-
-/**
- * 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>
- */
-
-public class Menu extends Widget {
- /**
- * the handle to the OS resource
- * (Warning: This field is platform dependent)
- */
- public int handle;
-
- int x, y, hwndCB, id0, id1;
- boolean hasLocation;
- MenuItem cascade;
- Decorations parent;
- static final int ID_PPC = 100;
-
- /* SmartPhone SoftKeyBar resource ids */
- static final int ID_SPMM = 102;
- static final int ID_SPBM = 103;
- static final int ID_SPMB = 104;
- static final int ID_SPBB = 105;
- static final int ID_SPSOFTKEY0 = 106;
- static final int ID_SPSOFTKEY1 = 107;
-
-/**
- * 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.
- *
- * @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).getShell (), 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>
- *
- * @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 Widget#checkSubclass
- * @see Widget#getStyle
- */
-public Menu (Decorations parent, int style) {
- this (parent, checkStyle (style), 0);
-}
-
-/**
- * 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.
- *
- * @param parent 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.
- *
- * @param parent 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);
-}
-
-Menu (Decorations parent, int style, int handle) {
- super (parent, checkStyle (style));
- this.parent = parent;
- this.handle = handle;
- /*
- * Bug in IBM JVM 1.3.1. For some reason, when the checkOrientation() is
- * called from createWidget(), the JVM issues this error:
- *
- * JVM Exception 0x2 (subcode 0x0) occurred in thread "main" (TID:0x9F19D8)
- *
- * In addition, on Windows XP, a dialog appears with following error message,
- * indicating that the problem may be in the JIT:
- *
- * AppName: java.exe AppVer: 0.0.0.0 ModName: jitc.dll
- * ModVer: 0.0.0.0 Offset: 000b6912
- *
- * The fix is to call checkOrientation() from here.
- */
- checkOrientation (parent);
- createWidget ();
-}
-
-void _setVisible (boolean visible) {
- if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return;
- int hwndParent = parent.handle;
- if (!visible) {
- OS.SendMessage (hwndParent, OS.WM_CANCELMODE, 0, 0);
- return;
- }
- int flags = OS.TPM_LEFTBUTTON | OS.TPM_RIGHTBUTTON;
- if ((style & SWT.RIGHT_TO_LEFT) != 0) flags |= OS.TPM_RIGHTALIGN;
- if ((parent.style & SWT.MIRRORED) != 0) {
- flags &= ~OS.TPM_RIGHTALIGN;
- if ((style & SWT.LEFT_TO_RIGHT) != 0) flags |= OS.TPM_RIGHTALIGN;
- }
- int nX = x, nY = y;
- if (!hasLocation) {
- int pos = OS.GetMessagePos ();
- nX = (short) (pos & 0xFFFF);
- nY = (short) (pos >> 16);
- }
- /*
- * Feature in Windows. It is legal use TrackPopupMenu ()
- * to display an empty menu as long as menu items are added
- * inside of WM_INITPOPUPMENU. If no items are added, then
- * TrackPopupMenu () fails and does not send an indication
- * that the menu has been closed. This is not strictly a
- * bug but leads to unwanted behavior when application code
- * assumes that every WM_INITPOPUPMENU will eventually result
- * in a WM_MENUSELECT, wParam=0xFFFF0000, lParam=0 to indicate
- * that the menu has been closed. The fix is to detect the
- * case when TrackPopupMenu fails and the number of items in
- * the menu is zero and issue a fake WM_MENUSELECT.
- */
- boolean success = OS.TrackPopupMenu (handle, flags, nX, nY, 0, hwndParent, null);
- if (!success && GetMenuItemCount (handle) == 0) {
- OS.SendMessage (hwndParent, OS.WM_MENUSELECT, 0xFFFF0000, 0);
- }
-}
-
-/**
- * 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);
-}
-
-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 createHandle () {
- if (handle != 0) return;
- if ((style & SWT.BAR) != 0) {
- if (OS.IsPPC) {
- int hwndShell = parent.handle;
- SHMENUBARINFO mbi = new SHMENUBARINFO ();
- mbi.cbSize = SHMENUBARINFO.sizeof;
- mbi.hwndParent = hwndShell;
- mbi.dwFlags = OS.SHCMBF_HIDDEN;
- mbi.nToolBarId = ID_PPC;
- mbi.hInstRes = OS.GetLibraryHandle ();
- boolean success = OS.SHCreateMenuBar (mbi);
- hwndCB = mbi.hwndMB;
- if (!success) error (SWT.ERROR_NO_HANDLES);
- /* Remove the item from the resource file */
- OS.SendMessage (hwndCB, OS.TB_DELETEBUTTON, 0, 0);
- return;
- }
- /*
- * Note in WinCE SmartPhone. The SoftBar contains only 2 items.
- * An item can either be a menu or a button.
- * SWT.BAR: creates a SoftBar with 2 menus
- * SWT.BAR | SWT.BUTTON1: creates a SoftBar with 1 button
- * for button1, and a menu for button2
- * SWT.BAR | SWT.BUTTON1 | SWT.BUTTON2: creates a SoftBar with
- * 2 buttons
- */
- if (OS.IsSP) {
- /* Determine type of menubar */
- int nToolBarId;
- if ((style & SWT.BUTTON1) != 0) {
- nToolBarId = ((style & SWT.BUTTON2) != 0) ? ID_SPBB : ID_SPBM;
- } else {
- nToolBarId = ((style & SWT.BUTTON2) != 0) ? ID_SPMB : ID_SPMM;
- }
-
- /* Create SHMENUBAR */
- SHMENUBARINFO mbi = new SHMENUBARINFO ();
- mbi.cbSize = SHMENUBARINFO.sizeof;
- mbi.hwndParent = parent.handle;
- mbi.dwFlags = OS.SHCMBF_HIDDEN;
- mbi.nToolBarId = nToolBarId; /* as defined in .rc file */
- mbi.hInstRes = OS.GetLibraryHandle ();
- if (!OS.SHCreateMenuBar (mbi)) error (SWT.ERROR_NO_HANDLES);
- hwndCB = mbi.hwndMB;
-
- /*
- * Feature on WinCE SmartPhone. The SHCMBF_HIDDEN flag causes the
- * SHMENUBAR to not be drawn. However the keyboard events still go
- * through it. The workaround is to also hide the SHMENUBAR with
- * ShowWindow ().
- */
- OS.ShowWindow (hwndCB, OS.SW_HIDE);
-
- TBBUTTONINFO info = new TBBUTTONINFO ();
- info.cbSize = TBBUTTONINFO.sizeof;
- info.dwMask = OS.TBIF_COMMAND;
- MenuItem item;
-
- /* Set first item */
- if (nToolBarId == ID_SPMM || nToolBarId == ID_SPMB) {
- int hMenu = OS.SendMessage (hwndCB, OS.SHCMBM_GETSUBMENU, 0, ID_SPSOFTKEY0);
- /* Remove the item from the resource file */
- OS.RemoveMenu (hMenu, 0, OS.MF_BYPOSITION);
- Menu menu = new Menu (parent, SWT.DROP_DOWN, hMenu);
- item = new MenuItem (this, menu, SWT.CASCADE, 0);
- } else {
- item = new MenuItem (this, null, SWT.PUSH, 0);
- }
- info.idCommand = id0 = item.id;
- OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, ID_SPSOFTKEY0, info);
-
- /* Set second item */
- if (nToolBarId == ID_SPMM || nToolBarId == ID_SPBM) {
- int hMenu = OS.SendMessage (hwndCB, OS.SHCMBM_GETSUBMENU, 0, ID_SPSOFTKEY1);
- OS.RemoveMenu (hMenu, 0, OS.MF_BYPOSITION);
- Menu menu = new Menu (parent, SWT.DROP_DOWN, hMenu);
- item = new MenuItem (this, menu, SWT.CASCADE, 1);
- } else {
- item = new MenuItem (this, null, SWT.PUSH, 1);
- }
- info.idCommand = id1 = item.id;
- OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, ID_SPSOFTKEY1, info);
-
- /*
- * Override the Back key. For some reason, the owner of the menubar
- * must be a Dialog or it won't receive the WM_HOTKEY message. As
- * a result, Shell on WinCE SP must use the class Dialog.
- */
- int dwMask = OS.SHMBOF_NODEFAULT | OS.SHMBOF_NOTIFY;
- int lParam = dwMask << 16 | dwMask;
- OS.SendMessage (hwndCB, OS.SHCMBM_OVERRIDEKEY, OS.VK_ESCAPE, lParam);
- return;
- }
- handle = OS.CreateMenu ();
- if (handle == 0) error (SWT.ERROR_NO_HANDLES);
- if (OS.IsHPC) {
- int hwndShell = parent.handle;
- hwndCB = OS.CommandBar_Create (OS.GetModuleHandle (null), hwndShell, 1);
- if (hwndCB == 0) error (SWT.ERROR_NO_HANDLES);
- OS.CommandBar_Show (hwndCB, false);
- OS.CommandBar_InsertMenubarEx (hwndCB, 0, handle, 0);
- /*
- * The command bar hosts the 'close' button when the window does not
- * have a caption.
- */
- if ((parent.style & SWT.CLOSE) != 0 && (parent.style & SWT.TITLE) == 0) {
- OS.CommandBar_AddAdornments (hwndCB, 0, 0);
- }
- }
- } else {
- handle = OS.CreatePopupMenu ();
- if (handle == 0) error (SWT.ERROR_NO_HANDLES);
- }
-}
-
-void createItem (MenuItem item, int index) {
- int count = GetMenuItemCount (handle);
- if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE);
- parent.add (item);
- boolean success = false;
- if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
- if (OS.IsSP) return;
- TBBUTTON lpButton = new TBBUTTON ();
- lpButton.idCommand = item.id;
- lpButton.fsStyle = (byte) (OS.TBSTYLE_DROPDOWN | OS.TBSTYLE_AUTOSIZE | 0x80);
- lpButton.fsState = (byte) OS.TBSTATE_ENABLED;
- lpButton.iBitmap = OS.I_IMAGENONE;
- if ((item.style & SWT.SEPARATOR) != 0) lpButton.fsStyle = (byte) OS.BTNS_SEP;
- success = OS.SendMessage (hwndCB, OS.TB_INSERTBUTTON, index, lpButton) != 0;
- } else {
- if (OS.IsWinCE) {
- int uFlags = OS.MF_BYPOSITION;
- TCHAR lpNewItem = null;
- if ((item.style & SWT.SEPARATOR) != 0) {
- uFlags |= OS.MF_SEPARATOR;
- } else {
- lpNewItem = new TCHAR (0, "", true);
- }
- success = OS.InsertMenu (handle, index, uFlags, item.id, lpNewItem);
- if (success) {
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- info.fMask = OS.MIIM_DATA;
- info.dwItemData = item.id;
- success = OS.SetMenuItemInfo (handle, index, true, info);
- }
- } else {
- /*
- * Bug in Windows. For some reason, when InsertMenuItem ()
- * is used to insert an item without text, it is not possible
- * to use SetMenuItemInfo () to set the text at a later time.
- * The fix is to insert the item with an empty string.
- */
- int hHeap = OS.GetProcessHeap ();
- int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, TCHAR.sizeof);
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- info.fMask = OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_DATA;
- info.wID = info.dwItemData = item.id;
- info.fType = item.widgetStyle ();
- info.dwTypeData = pszText;
- success = OS.InsertMenuItem (handle, index, true, info);
- if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
- }
- }
- if (!success) {
- parent.remove (item);
- error (SWT.ERROR_ITEM_NOT_ADDED);
- }
- redraw ();
-}
-
-void createWidget () {
- /*
- * Bug in IBM JVM 1.3.1. For some reason, when the following code is called
- * from this method, the JVM issues this error:
- *
- * JVM Exception 0x2 (subcode 0x0) occurred in thread "main" (TID:0x9F19D8)
- *
- * In addition, on Windows XP, a dialog appears with following error message,
- * indicating that the problem may be in the JIT:
- *
- * AppName: java.exe AppVer: 0.0.0.0 ModName: jitc.dll
- * ModVer: 0.0.0.0 Offset: 000b6912
- *
- * The fix is to move the code to the caller of this method.
- */
-// checkOrientation (parent);
- createHandle ();
- parent.add (this);
-}
-
-/*
-* Currently not used.
-*/
-int defaultBackground () {
- return OS.GetSysColor (OS.COLOR_MENU);
-}
-
-/*
-* Currently not used.
-*/
-int defaultForeground () {
- return OS.GetSysColor (OS.COLOR_MENUTEXT);
-}
-
-void destroyAccelerators () {
- parent.destroyAccelerators ();
-}
-
-void destroyItem (MenuItem item) {
- if (OS.IsWinCE) {
- if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
- if (OS.IsSP) {
- redraw();
- return;
- }
- int index = OS.SendMessage (hwndCB, OS.TB_COMMANDTOINDEX, item.id, 0);
- if (OS.SendMessage (hwndCB, OS.TB_DELETEBUTTON, index, 0) == 0) {
- error (SWT.ERROR_ITEM_NOT_REMOVED);
- }
- } else {
- int index = 0;
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- info.fMask = OS.MIIM_DATA;
- while (OS.GetMenuItemInfo (handle, index, true, info)) {
- if (info.dwItemData == item.id) break;
- index++;
- }
- if (info.dwItemData != item.id) {
- error (SWT.ERROR_ITEM_NOT_REMOVED);
- }
- if (!OS.RemoveMenu (handle, index, OS.MF_BYPOSITION)) {
- error (SWT.ERROR_ITEM_NOT_REMOVED);
- }
- }
- } else {
- if (!OS.RemoveMenu (handle, item.id, OS.MF_BYCOMMAND)) {
- error (SWT.ERROR_ITEM_NOT_REMOVED);
- }
- }
- redraw ();
-}
-
-void destroyWidget () {
- int hMenu = handle, hCB = hwndCB;
- releaseHandle ();
- if (OS.IsWinCE && hCB != 0) {
- OS.CommandBar_Destroy (hCB);
- } else {
- if (hMenu != 0) OS.DestroyMenu (hMenu);
- }
-}
-
-/**
- * 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 ();
- if (OS.IsWinCE) return null;
- int id = OS.GetMenuDefaultItem (handle, OS.MF_BYCOMMAND, OS.GMDI_USEDISABLED);
- if (id == -1) return null;
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- info.fMask = OS.MIIM_ID;
- if (OS.GetMenuItemInfo (handle, id, false, info)) {
- return parent.findMenuItem (info.wID);
- }
- return null;
-}
-
-public Display getDisplay () {
- Decorations parent = this.parent;
- if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED);
- return parent.getDisplay ();
-}
-
-/**
- * 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 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 ();
- int id = 0;
- if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
- if (OS.IsPPC) {
- TBBUTTON lpButton = new TBBUTTON ();
- int result = OS.SendMessage (hwndCB, OS.TB_GETBUTTON, index, lpButton);
- if (result == 0) error (SWT.ERROR_CANNOT_GET_ITEM);
- id = lpButton.idCommand;
- }
- if (OS.IsSP) {
- if (!(0 <= index && index <= 1)) error (SWT.ERROR_CANNOT_GET_ITEM);
- id = index == 0 ? id0 : id1;
- }
- } else {
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- info.fMask = OS.MIIM_DATA;
- if (!OS.GetMenuItemInfo (handle, index, true, info)) {
- error (SWT.ERROR_INVALID_RANGE);
- }
- id = info.dwItemData;
- }
- return parent.findMenuItem (id);
-}
-
-/**
- * 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 GetMenuItemCount (handle);
-}
-
-/**
- * Returns an 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 ();
- if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
- if (OS.IsSP) {
- MenuItem [] result = new MenuItem [2];
- result[0] = parent.findMenuItem (id0);
- result[1] = parent.findMenuItem (id1);
- return result;
- }
- int count = OS.SendMessage (hwndCB, OS.TB_BUTTONCOUNT, 0, 0);
- TBBUTTON lpButton = new TBBUTTON ();
- MenuItem [] result = new MenuItem [count];
- for (int i=0; i<count; i++) {
- OS.SendMessage (hwndCB, OS.TB_GETBUTTON, i, lpButton);
- result [i] = parent.findMenuItem (lpButton.idCommand);
- }
- return result;
- }
- int index = 0;
- int length = OS.IsWinCE ? 4 : OS.GetMenuItemCount (handle);
- MenuItem [] items = new MenuItem [length];
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- info.fMask = OS.MIIM_DATA;
- while (OS.GetMenuItemInfo (handle, index, true, info)) {
- if (index == items.length) {
- MenuItem [] newItems = new MenuItem [index + 4];
- System.arraycopy (items, 0, newItems, 0, index);
- items = newItems;
- }
- items [index++] = parent.findMenuItem (info.dwItemData);
- }
- if (index == items.length) return items;
- MenuItem [] result = new MenuItem [index];
- System.arraycopy (items, 0, result, 0, index);
- return result;
-}
-
-int GetMenuItemCount (int handle) {
- checkWidget ();
- if (OS.IsWinCE) {
- if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
- return OS.IsSP ? 2 : OS.SendMessage (hwndCB, OS.TB_BUTTONCOUNT, 0, 0);
- }
- int count = 0;
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- while (OS.GetMenuItemInfo (handle, count, true, info)) count++;
- return count;
- }
- return OS.GetMenuItemCount (handle);
-}
-
-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) {
- Display display = getDisplay ();
- Menu [] popups = display.popups;
- if (popups == null) return false;
- for (int i=0; i<popups.length; i++) {
- if (popups [i] == this) return true;
- }
- }
- return this == getShell ().activeMenu;
-}
-
-/**
- * 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 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 (MenuItem item) {
- checkWidget ();
- if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
- if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
- if (item.parent != this) return -1;
- if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
- if (OS.IsPPC) {
- return OS.SendMessage (hwndCB, OS.TB_COMMANDTOINDEX, item.id, 0);
- }
- if (OS.IsSP) {
- if (item.id == id0) return 0;
- if (item.id == id1) return 1;
- return -1;
- }
- }
- int index = 0;
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- info.fMask = OS.MIIM_DATA;
- while (OS.GetMenuItemInfo (handle, index, true, info)) {
- if (info.dwItemData == item.id) return index;
- index++;
- }
- 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 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 ();
- Menu parentMenu = getParentMenu ();
- if (parentMenu == null) return getEnabled ();
- 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 redraw () {
- if ((style & SWT.BAR) != 0) {
- Display display = getDisplay ();
- display.addBar (this);
- } else {
- update ();
- }
-}
-
-void releaseChild () {
- super.releaseChild ();
- if (cascade != null) cascade.releaseMenu ();
- if ((style & SWT.BAR) != 0) {
- Display display = getDisplay ();
- display.removeBar (this);
- if (this == parent.menuBar) {
- parent.setMenuBar (null);
- }
- } else {
- if ((style & SWT.POP_UP) != 0) {
- Display display = getDisplay ();
- display.removePopup (this);
- }
- }
-}
-
-void releaseHandle () {
- super.releaseHandle ();
- handle = hwndCB = 0;
-}
-
-void releaseWidget () {
- MenuItem [] items = getItems ();
- for (int i=0; i<items.length; i++) {
- MenuItem item = items [i];
- if (!item.isDisposed ()) {
- if (OS.IsPPC && hwndCB != 0) {
- item.dispose ();
- } else {
- item.releaseResources ();
- }
- }
- }
- super.releaseWidget ();
- if (parent != null) parent.remove (this);
- parent = null;
- cascade = 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 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 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 ();
- int newID = -1;
- if (item != null) {
- if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
- if (item.parent != this) return;
- newID = item.id;
- }
- if (OS.IsWinCE) return;
- int oldID = OS.GetMenuDefaultItem (handle, OS.MF_BYCOMMAND, OS.GMDI_USEDISABLED);
- if (newID == oldID) return;
- OS.SetMenuDefaultItem (handle, newID, OS.MF_BYCOMMAND);
- redraw ();
-}
-
-/**
- * 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 ();
- state &= ~DISABLED;
- if (!enabled) state |= DISABLED;
-}
-
-/**
- * Sets the receiver's location to the point specified by
- * the arguments which are relative to the display.
- * <p>
- * Note: This is different from most widgets where the
- * location of the widget is relative to the parent.
- * </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 ();
- if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return;
- this.x = x;
- this.y = y;
- hasLocation = true;
-}
-
-/**
- * Sets the receiver's location to the point specified by
- * the arguments which are relative to the display.
- * <p>
- * Note: This is different from most widgets where the
- * location of the widget is relative to the parent.
- * </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) SWT.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;
- Display display = getDisplay ();
- if (visible) {
- display.addPopup (this);
- } else {
- display.removePopup (this);
- _setVisible (false);
- }
-}
-
-void update () {
- if (OS.IsPPC || OS.IsSP) return;
- if (OS.IsHPC) {
- /*
- * Each time a menu has been modified, the command menu bar
- * must be redrawn or it won't update properly. For example,
- * a submenu will not drop down.
- */
- Menu menuBar = parent.menuBar;
- if (menuBar != null) {
- Menu menu = this;
- while (menu != null && menu != menuBar) {
- menu = menu.getParentMenu ();
- }
- if (menu == menuBar) {
- OS.CommandBar_DrawMenuBar (menuBar.hwndCB, 0);
- OS.CommandBar_Show (menuBar.hwndCB, true);
- }
- }
- return;
- }
- if ((style & SWT.BAR) != 0) {
- if (this == parent.menuBar) OS.DrawMenuBar (parent.handle);
- return;
- }
- if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) < (4 << 16 | 10)) {
- return;
- }
- boolean hasCheck = false, hasImage = false;
- MenuItem [] items = getItems ();
- for (int i=0; i<items.length; i++) {
- MenuItem item = items [i];
- if (item.getImage () != null) {
- if ((hasImage = true) && hasCheck) break;
- }
- if ((item.getStyle () & (SWT.CHECK | SWT.RADIO)) != 0) {
- if ((hasCheck = true) && hasImage) break;
- }
- }
- MENUINFO lpcmi = new MENUINFO ();
- lpcmi.cbSize = MENUINFO.sizeof;
- lpcmi.fMask = OS.MIM_STYLE;
- OS.GetMenuInfo (handle, lpcmi);
- if (hasImage && !hasCheck) {
- lpcmi.dwStyle |= OS.MNS_CHECKORBMP;
- } else {
- lpcmi.dwStyle &= ~OS.MNS_CHECKORBMP;
- }
- OS.SetMenuInfo (handle, lpcmi);
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.events.*; + +/** + * 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> + */ + +public class Menu extends Widget { + /** + * the handle to the OS resource + * (Warning: This field is platform dependent) + */ + public int handle; + + int x, y, hwndCB, id0, id1; + boolean hasLocation; + MenuItem cascade; + Decorations parent; + static final int ID_PPC = 100; + + /* SmartPhone SoftKeyBar resource ids */ + static final int ID_SPMM = 102; + static final int ID_SPBM = 103; + static final int ID_SPMB = 104; + static final int ID_SPBB = 105; + static final int ID_SPSOFTKEY0 = 106; + static final int ID_SPSOFTKEY1 = 107; + +/** + * 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. + * + * @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).getShell (), 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> + * + * @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 Widget#checkSubclass + * @see Widget#getStyle + */ +public Menu (Decorations parent, int style) { + this (parent, checkStyle (style), 0); +} + +/** + * 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. + * + * @param parent 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. + * + * @param parent 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); +} + +Menu (Decorations parent, int style, int handle) { + super (parent, checkStyle (style)); + this.parent = parent; + this.handle = handle; + /* + * Bug in IBM JVM 1.3.1. For some reason, when the checkOrientation() is + * called from createWidget(), the JVM issues this error: + * + * JVM Exception 0x2 (subcode 0x0) occurred in thread "main" (TID:0x9F19D8) + * + * In addition, on Windows XP, a dialog appears with following error message, + * indicating that the problem may be in the JIT: + * + * AppName: java.exe AppVer: 0.0.0.0 ModName: jitc.dll + * ModVer: 0.0.0.0 Offset: 000b6912 + * + * The fix is to call checkOrientation() from here. + */ + checkOrientation (parent); + createWidget (); +} + +void _setVisible (boolean visible) { + if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return; + int hwndParent = parent.handle; + if (!visible) { + OS.SendMessage (hwndParent, OS.WM_CANCELMODE, 0, 0); + return; + } + int flags = OS.TPM_LEFTBUTTON | OS.TPM_RIGHTBUTTON; + if ((style & SWT.RIGHT_TO_LEFT) != 0) flags |= OS.TPM_RIGHTALIGN; + if ((parent.style & SWT.MIRRORED) != 0) { + flags &= ~OS.TPM_RIGHTALIGN; + if ((style & SWT.LEFT_TO_RIGHT) != 0) flags |= OS.TPM_RIGHTALIGN; + } + int nX = x, nY = y; + if (!hasLocation) { + int pos = OS.GetMessagePos (); + nX = (short) (pos & 0xFFFF); + nY = (short) (pos >> 16); + } + /* + * Feature in Windows. It is legal use TrackPopupMenu () + * to display an empty menu as long as menu items are added + * inside of WM_INITPOPUPMENU. If no items are added, then + * TrackPopupMenu () fails and does not send an indication + * that the menu has been closed. This is not strictly a + * bug but leads to unwanted behavior when application code + * assumes that every WM_INITPOPUPMENU will eventually result + * in a WM_MENUSELECT, wParam=0xFFFF0000, lParam=0 to indicate + * that the menu has been closed. The fix is to detect the + * case when TrackPopupMenu fails and the number of items in + * the menu is zero and issue a fake WM_MENUSELECT. + */ + boolean success = OS.TrackPopupMenu (handle, flags, nX, nY, 0, hwndParent, null); + if (!success && GetMenuItemCount (handle) == 0) { + OS.SendMessage (hwndParent, OS.WM_MENUSELECT, 0xFFFF0000, 0); + } +} + +/** + * 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); +} + +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 createHandle () { + if (handle != 0) return; + if ((style & SWT.BAR) != 0) { + if (OS.IsPPC) { + int hwndShell = parent.handle; + SHMENUBARINFO mbi = new SHMENUBARINFO (); + mbi.cbSize = SHMENUBARINFO.sizeof; + mbi.hwndParent = hwndShell; + mbi.dwFlags = OS.SHCMBF_HIDDEN; + mbi.nToolBarId = ID_PPC; + mbi.hInstRes = OS.GetLibraryHandle (); + boolean success = OS.SHCreateMenuBar (mbi); + hwndCB = mbi.hwndMB; + if (!success) error (SWT.ERROR_NO_HANDLES); + /* Remove the item from the resource file */ + OS.SendMessage (hwndCB, OS.TB_DELETEBUTTON, 0, 0); + return; + } + /* + * Note in WinCE SmartPhone. The SoftBar contains only 2 items. + * An item can either be a menu or a button. + * SWT.BAR: creates a SoftBar with 2 menus + * SWT.BAR | SWT.BUTTON1: creates a SoftBar with 1 button + * for button1, and a menu for button2 + * SWT.BAR | SWT.BUTTON1 | SWT.BUTTON2: creates a SoftBar with + * 2 buttons + */ + if (OS.IsSP) { + /* Determine type of menubar */ + int nToolBarId; + if ((style & SWT.BUTTON1) != 0) { + nToolBarId = ((style & SWT.BUTTON2) != 0) ? ID_SPBB : ID_SPBM; + } else { + nToolBarId = ((style & SWT.BUTTON2) != 0) ? ID_SPMB : ID_SPMM; + } + + /* Create SHMENUBAR */ + SHMENUBARINFO mbi = new SHMENUBARINFO (); + mbi.cbSize = SHMENUBARINFO.sizeof; + mbi.hwndParent = parent.handle; + mbi.dwFlags = OS.SHCMBF_HIDDEN; + mbi.nToolBarId = nToolBarId; /* as defined in .rc file */ + mbi.hInstRes = OS.GetLibraryHandle (); + if (!OS.SHCreateMenuBar (mbi)) error (SWT.ERROR_NO_HANDLES); + hwndCB = mbi.hwndMB; + + /* + * Feature on WinCE SmartPhone. The SHCMBF_HIDDEN flag causes the + * SHMENUBAR to not be drawn. However the keyboard events still go + * through it. The workaround is to also hide the SHMENUBAR with + * ShowWindow (). + */ + OS.ShowWindow (hwndCB, OS.SW_HIDE); + + TBBUTTONINFO info = new TBBUTTONINFO (); + info.cbSize = TBBUTTONINFO.sizeof; + info.dwMask = OS.TBIF_COMMAND; + MenuItem item; + + /* Set first item */ + if (nToolBarId == ID_SPMM || nToolBarId == ID_SPMB) { + int hMenu = OS.SendMessage (hwndCB, OS.SHCMBM_GETSUBMENU, 0, ID_SPSOFTKEY0); + /* Remove the item from the resource file */ + OS.RemoveMenu (hMenu, 0, OS.MF_BYPOSITION); + Menu menu = new Menu (parent, SWT.DROP_DOWN, hMenu); + item = new MenuItem (this, menu, SWT.CASCADE, 0); + } else { + item = new MenuItem (this, null, SWT.PUSH, 0); + } + info.idCommand = id0 = item.id; + OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, ID_SPSOFTKEY0, info); + + /* Set second item */ + if (nToolBarId == ID_SPMM || nToolBarId == ID_SPBM) { + int hMenu = OS.SendMessage (hwndCB, OS.SHCMBM_GETSUBMENU, 0, ID_SPSOFTKEY1); + OS.RemoveMenu (hMenu, 0, OS.MF_BYPOSITION); + Menu menu = new Menu (parent, SWT.DROP_DOWN, hMenu); + item = new MenuItem (this, menu, SWT.CASCADE, 1); + } else { + item = new MenuItem (this, null, SWT.PUSH, 1); + } + info.idCommand = id1 = item.id; + OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, ID_SPSOFTKEY1, info); + + /* + * Override the Back key. For some reason, the owner of the menubar + * must be a Dialog or it won't receive the WM_HOTKEY message. As + * a result, Shell on WinCE SP must use the class Dialog. + */ + int dwMask = OS.SHMBOF_NODEFAULT | OS.SHMBOF_NOTIFY; + int lParam = dwMask << 16 | dwMask; + OS.SendMessage (hwndCB, OS.SHCMBM_OVERRIDEKEY, OS.VK_ESCAPE, lParam); + return; + } + handle = OS.CreateMenu (); + if (handle == 0) error (SWT.ERROR_NO_HANDLES); + if (OS.IsHPC) { + int hwndShell = parent.handle; + hwndCB = OS.CommandBar_Create (OS.GetModuleHandle (null), hwndShell, 1); + if (hwndCB == 0) error (SWT.ERROR_NO_HANDLES); + OS.CommandBar_Show (hwndCB, false); + OS.CommandBar_InsertMenubarEx (hwndCB, 0, handle, 0); + /* + * The command bar hosts the 'close' button when the window does not + * have a caption. + */ + if ((parent.style & SWT.CLOSE) != 0 && (parent.style & SWT.TITLE) == 0) { + OS.CommandBar_AddAdornments (hwndCB, 0, 0); + } + } + } else { + handle = OS.CreatePopupMenu (); + if (handle == 0) error (SWT.ERROR_NO_HANDLES); + } +} + +void createItem (MenuItem item, int index) { + int count = GetMenuItemCount (handle); + if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE); + parent.add (item); + boolean success = false; + if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) { + if (OS.IsSP) return; + TBBUTTON lpButton = new TBBUTTON (); + lpButton.idCommand = item.id; + lpButton.fsStyle = (byte) (OS.TBSTYLE_DROPDOWN | OS.TBSTYLE_AUTOSIZE | 0x80); + lpButton.fsState = (byte) OS.TBSTATE_ENABLED; + lpButton.iBitmap = OS.I_IMAGENONE; + if ((item.style & SWT.SEPARATOR) != 0) lpButton.fsStyle = (byte) OS.BTNS_SEP; + success = OS.SendMessage (hwndCB, OS.TB_INSERTBUTTON, index, lpButton) != 0; + } else { + if (OS.IsWinCE) { + int uFlags = OS.MF_BYPOSITION; + TCHAR lpNewItem = null; + if ((item.style & SWT.SEPARATOR) != 0) { + uFlags |= OS.MF_SEPARATOR; + } else { + lpNewItem = new TCHAR (0, "", true); + } + success = OS.InsertMenu (handle, index, uFlags, item.id, lpNewItem); + if (success) { + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + info.fMask = OS.MIIM_DATA; + info.dwItemData = item.id; + success = OS.SetMenuItemInfo (handle, index, true, info); + } + } else { + /* + * Bug in Windows. For some reason, when InsertMenuItem () + * is used to insert an item without text, it is not possible + * to use SetMenuItemInfo () to set the text at a later time. + * The fix is to insert the item with an empty string. + */ + int hHeap = OS.GetProcessHeap (); + int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, TCHAR.sizeof); + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + info.fMask = OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_DATA; + info.wID = info.dwItemData = item.id; + info.fType = item.widgetStyle (); + info.dwTypeData = pszText; + success = OS.InsertMenuItem (handle, index, true, info); + if (pszText != 0) OS.HeapFree (hHeap, 0, pszText); + } + } + if (!success) { + parent.remove (item); + error (SWT.ERROR_ITEM_NOT_ADDED); + } + redraw (); +} + +void createWidget () { + /* + * Bug in IBM JVM 1.3.1. For some reason, when the following code is called + * from this method, the JVM issues this error: + * + * JVM Exception 0x2 (subcode 0x0) occurred in thread "main" (TID:0x9F19D8) + * + * In addition, on Windows XP, a dialog appears with following error message, + * indicating that the problem may be in the JIT: + * + * AppName: java.exe AppVer: 0.0.0.0 ModName: jitc.dll + * ModVer: 0.0.0.0 Offset: 000b6912 + * + * The fix is to move the code to the caller of this method. + */ +// checkOrientation (parent); + createHandle (); + parent.add (this); +} + +/* +* Currently not used. +*/ +int defaultBackground () { + return OS.GetSysColor (OS.COLOR_MENU); +} + +/* +* Currently not used. +*/ +int defaultForeground () { + return OS.GetSysColor (OS.COLOR_MENUTEXT); +} + +void destroyAccelerators () { + parent.destroyAccelerators (); +} + +void destroyItem (MenuItem item) { + if (OS.IsWinCE) { + if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) { + if (OS.IsSP) { + redraw(); + return; + } + int index = OS.SendMessage (hwndCB, OS.TB_COMMANDTOINDEX, item.id, 0); + if (OS.SendMessage (hwndCB, OS.TB_DELETEBUTTON, index, 0) == 0) { + error (SWT.ERROR_ITEM_NOT_REMOVED); + } + } else { + int index = 0; + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + info.fMask = OS.MIIM_DATA; + while (OS.GetMenuItemInfo (handle, index, true, info)) { + if (info.dwItemData == item.id) break; + index++; + } + if (info.dwItemData != item.id) { + error (SWT.ERROR_ITEM_NOT_REMOVED); + } + if (!OS.RemoveMenu (handle, index, OS.MF_BYPOSITION)) { + error (SWT.ERROR_ITEM_NOT_REMOVED); + } + } + } else { + if (!OS.RemoveMenu (handle, item.id, OS.MF_BYCOMMAND)) { + error (SWT.ERROR_ITEM_NOT_REMOVED); + } + } + redraw (); +} + +void destroyWidget () { + int hMenu = handle, hCB = hwndCB; + releaseHandle (); + if (OS.IsWinCE && hCB != 0) { + OS.CommandBar_Destroy (hCB); + } else { + if (hMenu != 0) OS.DestroyMenu (hMenu); + } +} + +/** + * 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 (); + if (OS.IsWinCE) return null; + int id = OS.GetMenuDefaultItem (handle, OS.MF_BYCOMMAND, OS.GMDI_USEDISABLED); + if (id == -1) return null; + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + info.fMask = OS.MIIM_ID; + if (OS.GetMenuItemInfo (handle, id, false, info)) { + return parent.findMenuItem (info.wID); + } + return null; +} + +public Display getDisplay () { + Decorations parent = this.parent; + if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED); + return parent.getDisplay (); +} + +/** + * 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 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 (); + int id = 0; + if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) { + if (OS.IsPPC) { + TBBUTTON lpButton = new TBBUTTON (); + int result = OS.SendMessage (hwndCB, OS.TB_GETBUTTON, index, lpButton); + if (result == 0) error (SWT.ERROR_CANNOT_GET_ITEM); + id = lpButton.idCommand; + } + if (OS.IsSP) { + if (!(0 <= index && index <= 1)) error (SWT.ERROR_CANNOT_GET_ITEM); + id = index == 0 ? id0 : id1; + } + } else { + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + info.fMask = OS.MIIM_DATA; + if (!OS.GetMenuItemInfo (handle, index, true, info)) { + error (SWT.ERROR_INVALID_RANGE); + } + id = info.dwItemData; + } + return parent.findMenuItem (id); +} + +/** + * 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 GetMenuItemCount (handle); +} + +/** + * Returns an 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 (); + if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) { + if (OS.IsSP) { + MenuItem [] result = new MenuItem [2]; + result[0] = parent.findMenuItem (id0); + result[1] = parent.findMenuItem (id1); + return result; + } + int count = OS.SendMessage (hwndCB, OS.TB_BUTTONCOUNT, 0, 0); + TBBUTTON lpButton = new TBBUTTON (); + MenuItem [] result = new MenuItem [count]; + for (int i=0; i<count; i++) { + OS.SendMessage (hwndCB, OS.TB_GETBUTTON, i, lpButton); + result [i] = parent.findMenuItem (lpButton.idCommand); + } + return result; + } + int index = 0; + int length = OS.IsWinCE ? 4 : OS.GetMenuItemCount (handle); + MenuItem [] items = new MenuItem [length]; + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + info.fMask = OS.MIIM_DATA; + while (OS.GetMenuItemInfo (handle, index, true, info)) { + if (index == items.length) { + MenuItem [] newItems = new MenuItem [index + 4]; + System.arraycopy (items, 0, newItems, 0, index); + items = newItems; + } + items [index++] = parent.findMenuItem (info.dwItemData); + } + if (index == items.length) return items; + MenuItem [] result = new MenuItem [index]; + System.arraycopy (items, 0, result, 0, index); + return result; +} + +int GetMenuItemCount (int handle) { + checkWidget (); + if (OS.IsWinCE) { + if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) { + return OS.IsSP ? 2 : OS.SendMessage (hwndCB, OS.TB_BUTTONCOUNT, 0, 0); + } + int count = 0; + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + while (OS.GetMenuItemInfo (handle, count, true, info)) count++; + return count; + } + return OS.GetMenuItemCount (handle); +} + +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) { + Display display = getDisplay (); + Menu [] popups = display.popups; + if (popups == null) return false; + for (int i=0; i<popups.length; i++) { + if (popups [i] == this) return true; + } + } + return this == getShell ().activeMenu; +} + +/** + * 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 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 (MenuItem item) { + checkWidget (); + if (item == null) error (SWT.ERROR_NULL_ARGUMENT); + if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); + if (item.parent != this) return -1; + if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) { + if (OS.IsPPC) { + return OS.SendMessage (hwndCB, OS.TB_COMMANDTOINDEX, item.id, 0); + } + if (OS.IsSP) { + if (item.id == id0) return 0; + if (item.id == id1) return 1; + return -1; + } + } + int index = 0; + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + info.fMask = OS.MIIM_DATA; + while (OS.GetMenuItemInfo (handle, index, true, info)) { + if (info.dwItemData == item.id) return index; + index++; + } + 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 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 (); + Menu parentMenu = getParentMenu (); + if (parentMenu == null) return getEnabled (); + 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 redraw () { + if ((style & SWT.BAR) != 0) { + Display display = getDisplay (); + display.addBar (this); + } else { + update (); + } +} + +void releaseChild () { + super.releaseChild (); + if (cascade != null) cascade.releaseMenu (); + if ((style & SWT.BAR) != 0) { + Display display = getDisplay (); + display.removeBar (this); + if (this == parent.menuBar) { + parent.setMenuBar (null); + } + } else { + if ((style & SWT.POP_UP) != 0) { + Display display = getDisplay (); + display.removePopup (this); + } + } +} + +void releaseHandle () { + super.releaseHandle (); + handle = hwndCB = 0; +} + +void releaseWidget () { + MenuItem [] items = getItems (); + for (int i=0; i<items.length; i++) { + MenuItem item = items [i]; + if (!item.isDisposed ()) { + if (OS.IsPPC && hwndCB != 0) { + item.dispose (); + } else { + item.releaseResources (); + } + } + } + super.releaseWidget (); + if (parent != null) parent.remove (this); + parent = null; + cascade = 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 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 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 (); + int newID = -1; + if (item != null) { + if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); + if (item.parent != this) return; + newID = item.id; + } + if (OS.IsWinCE) return; + int oldID = OS.GetMenuDefaultItem (handle, OS.MF_BYCOMMAND, OS.GMDI_USEDISABLED); + if (newID == oldID) return; + OS.SetMenuDefaultItem (handle, newID, OS.MF_BYCOMMAND); + redraw (); +} + +/** + * 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 (); + state &= ~DISABLED; + if (!enabled) state |= DISABLED; +} + +/** + * Sets the receiver's location to the point specified by + * the arguments which are relative to the display. + * <p> + * Note: This is different from most widgets where the + * location of the widget is relative to the parent. + * </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 (); + if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return; + this.x = x; + this.y = y; + hasLocation = true; +} + +/** + * Sets the receiver's location to the point specified by + * the arguments which are relative to the display. + * <p> + * Note: This is different from most widgets where the + * location of the widget is relative to the parent. + * </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) SWT.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; + Display display = getDisplay (); + if (visible) { + display.addPopup (this); + } else { + display.removePopup (this); + _setVisible (false); + } +} + +void update () { + if (OS.IsPPC || OS.IsSP) return; + if (OS.IsHPC) { + /* + * Each time a menu has been modified, the command menu bar + * must be redrawn or it won't update properly. For example, + * a submenu will not drop down. + */ + Menu menuBar = parent.menuBar; + if (menuBar != null) { + Menu menu = this; + while (menu != null && menu != menuBar) { + menu = menu.getParentMenu (); + } + if (menu == menuBar) { + OS.CommandBar_DrawMenuBar (menuBar.hwndCB, 0); + OS.CommandBar_Show (menuBar.hwndCB, true); + } + } + return; + } + if ((style & SWT.BAR) != 0) { + if (this == parent.menuBar) OS.DrawMenuBar (parent.handle); + return; + } + if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) < (4 << 16 | 10)) { + return; + } + boolean hasCheck = false, hasImage = false; + MenuItem [] items = getItems (); + for (int i=0; i<items.length; i++) { + MenuItem item = items [i]; + if (item.getImage () != null) { + if ((hasImage = true) && hasCheck) break; + } + if ((item.getStyle () & (SWT.CHECK | SWT.RADIO)) != 0) { + if ((hasCheck = true) && hasImage) break; + } + } + MENUINFO lpcmi = new MENUINFO (); + lpcmi.cbSize = MENUINFO.sizeof; + lpcmi.fMask = OS.MIM_STYLE; + OS.GetMenuInfo (handle, lpcmi); + if (hasImage && !hasCheck) { + lpcmi.dwStyle |= OS.MNS_CHECKORBMP; + } else { + lpcmi.dwStyle &= ~OS.MNS_CHECKORBMP; + } + OS.SetMenuInfo (handle, lpcmi); +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MenuItem.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MenuItem.java index 6833f5561c..5a59689728 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MenuItem.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MenuItem.java @@ -1,976 +1,976 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-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>
- */
-
-public class MenuItem extends Item {
- Menu parent, menu;
- int id, 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 index to store the receiver in its parent
- *
- * @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, int index) {
- super (parent, checkStyle (style));
- this.parent = parent;
- parent.createItem (this, index);
-}
-
-MenuItem (Menu parent, Menu menu, int style, int index) {
- super (parent, checkStyle (style));
- this.parent = parent;
- this.menu = menu;
- if (menu != null) menu.cascade = this;
- Decorations shell = parent.parent;
- shell.add (this);
-}
-
-/**
- * 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 control is selected, 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
- *
- * @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);
-}
-
-void fillAccel (ACCEL accel) {
- accel.fVirt = 0;
- accel.cmd = accel.key = 0;
- if (accelerator == 0) return;
- int fVirt = OS.FVIRTKEY;
- int key = accelerator & SWT.KEY_MASK;
- int vKey = Display.untranslateKey (key);
- if (vKey != 0) {
- key = vKey;
- } else {
- switch (key) {
- /*
- * Bug in Windows. For some reason, VkKeyScan
- * fails to map ESC to VK_ESCAPE and DEL to
- * VK_DELETE. The fix is to map these keys
- * as a special case.
- */
- case 27: key = OS.VK_ESCAPE; break;
- case 127: key = OS.VK_DELETE; break;
- default: {
- key = wcsToMbcs ((char) key);
- if (key == 0) return;
- if (OS.IsWinCE) {
- key = OS.CharUpper ((short) key);
- } else {
- vKey = OS.VkKeyScan ((short) key) & 0xFF;
- if (vKey == -1) {
- fVirt = 0;
- } else {
- key = vKey;
- }
- }
- }
- }
- }
- accel.key = (short) key;
- accel.cmd = (short) id;
- accel.fVirt = (byte) fVirt;
- if ((accelerator & SWT.ALT) != 0) accel.fVirt |= OS.FALT;
- if ((accelerator & SWT.SHIFT) != 0) accel.fVirt |= OS.FSHIFT;
- if ((accelerator & SWT.CONTROL) != 0) accel.fVirt |= OS.FCONTROL;
-}
-
-/**
- * Return 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>.
- *
- * @return the accelerator
- *
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if 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;
-}
-
-public Display getDisplay () {
- Menu parent = this.parent;
- if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED);
- return parent.getDisplay ();
-}
-
-/**
- * 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 ();
- if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) {
- int hwndCB = parent.hwndCB;
- TBBUTTONINFO info = new TBBUTTONINFO ();
- info.cbSize = TBBUTTONINFO.sizeof;
- info.dwMask = OS.TBIF_STATE;
- OS.SendMessage (hwndCB, OS.TB_GETBUTTONINFO, id, info);
- return (info.fsState & OS.TBSTATE_ENABLED) != 0;
- }
- int hMenu = parent.handle;
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- info.fMask = OS.MIIM_STATE;
- boolean success;
- if (OS.IsWinCE) {
- int index = parent.indexOf (this);
- if (index == -1) error (SWT.ERROR_CANNOT_GET_ENABLED);
- success = OS.GetMenuItemInfo (hMenu, index, true, info);
- } else {
- success = OS.GetMenuItemInfo (hMenu, id, false, info);
- }
- if (!success) error (SWT.ERROR_CANNOT_GET_ENABLED);
- return (info.fState & (OS.MFS_DISABLED | OS.MFS_GRAYED)) == 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;
- if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) return false;
- int hMenu = parent.handle;
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- info.fMask = OS.MIIM_STATE;
- boolean success = OS.GetMenuItemInfo (hMenu, id, false, info);
- if (!success) error (SWT.ERROR_CANNOT_GET_SELECTION);
- return (info.fState & OS.MFS_CHECKED) !=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 () {
- return getEnabled () && parent.isEnabled ();
-}
-
-void releaseChild () {
- super.releaseChild ();
- if (menu != null) menu.dispose ();
- menu = null;
- parent.destroyItem (this);
-}
-
-void releaseMenu () {
- if (!OS.IsSP) setMenu (null);
- menu = null;
-}
-
-void releaseWidget () {
- if (menu != null) menu.releaseResources ();
- menu = null;
- super.releaseWidget ();
- if (accelerator != 0) {
- parent.destroyAccelerators ();
- }
- accelerator = 0;
- Decorations shell = parent.parent;
- shell.remove (this);
- parent = 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 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 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.
- *
- * @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 #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);
-}
-
-/**
- * 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>.
- *
- * @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;
- parent.destroyAccelerators ();
-}
-
-/**
- * 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 ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) {
- int hwndCB = parent.hwndCB;
- TBBUTTONINFO info = new TBBUTTONINFO ();
- info.cbSize = TBBUTTONINFO.sizeof;
- info.dwMask = OS.TBIF_STATE;
- OS.SendMessage (hwndCB, OS.TB_GETBUTTONINFO, id, info);
- info.fsState &= ~OS.TBSTATE_ENABLED;
- if (enabled) info.fsState |= OS.TBSTATE_ENABLED;
- OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, id, info);
- } else {
- int hMenu = parent.handle;
- if (OS.IsWinCE) {
- int index = parent.indexOf (this);
- if (index == -1) return;
- int uEnable = OS.MF_BYPOSITION | (enabled ? OS.MF_ENABLED : OS.MF_GRAYED);
- OS.EnableMenuItem (hMenu, index, uEnable);
- } else {
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- info.fMask = OS.MIIM_STATE;
- boolean success = OS.GetMenuItemInfo (hMenu, id, false, info);
- if (!success) error (SWT.ERROR_CANNOT_SET_ENABLED);
- int bits = OS.MFS_DISABLED | OS.MFS_GRAYED;
- if (enabled) {
- if ((info.fState & bits) == 0) return;
- info.fState &= ~bits;
- } else {
- if ((info.fState & bits) == bits) return;
- info.fState |= bits;
- }
- success = OS.SetMenuItemInfo (hMenu, id, false, info);
- if (!success) error (SWT.ERROR_CANNOT_SET_ENABLED);
- }
- }
- parent.redraw ();
-}
-
-/**
- * Sets the image the receiver will display to the argument.
- * <p>
- * Note: This feature is not available on all window systems (for example, Window NT),
- * in which case, calling this method will silently do nothing.
- *
- * @param menu 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);
- if (OS.IsWinCE) return;
- if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) < (4 << 16 | 10)) {
- return;
- }
- int hMenu = parent.handle;
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- info.fMask = OS.MIIM_BITMAP;
- if (image != null) info.hbmpItem = OS.HBMMENU_CALLBACK;
- OS.SetMenuItemInfo (hMenu, id, false, info);
- parent.redraw ();
-}
-
-/**
- * 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.
- *
- * @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;
-
- /* Assign the new menu in the OS */
- if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) {
- if (OS.IsPPC) {
- int hwndCB = parent.hwndCB;
- int hMenu = menu == null ? 0 : menu.handle;
- OS.SendMessage (hwndCB, OS.SHCMBM_SETSUBMENU, id, hMenu);
- }
- if (OS.IsSP) error (SWT.ERROR_CANNOT_SET_MENU);
- } else {
- /*
- * Feature in Windows. When SetMenuItemInfo () is used to
- * set a submenu and the menu item already has a submenu,
- * Windows destroys the previous menu. This is undocumented
- * and unexpected but not necessarily wrong. The fix is to
- * remove the item with RemoveMenu () which does not destroy
- * the submenu and then insert the item with InsertMenuItem ().
- */
- int hMenu = parent.handle;
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- info.fMask = OS.MIIM_DATA;
- int index = 0;
- while (OS.GetMenuItemInfo (hMenu, index, true, info)) {
- if (info.dwItemData == id) break;
- index++;
- }
- if (info.dwItemData != id) return;
- int cch = 128;
- int hHeap = OS.GetProcessHeap ();
- int byteCount = cch * TCHAR.sizeof;
- int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- info.fMask = OS.MIIM_STATE | OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_DATA;
- info.dwTypeData = pszText;
- info.cch = cch;
- boolean success = OS.GetMenuItemInfo (hMenu, index, true, info);
- if (menu != null) {
- menu.cascade = this;
- info.fMask |= OS.MIIM_SUBMENU;
- info.hSubMenu = menu.handle;
- }
- OS.RemoveMenu (hMenu, index, OS.MF_BYPOSITION);
- if (OS.IsWinCE) {
- /*
- * On WinCE, InsertMenuItem is not available. SetMenuItemInfo
- * does not set the menu item state and submenu use InsertMenu
- * to set these fields and SetMenuItemInfo to set the menu item
- * data. NOTE: SetMenuItemInfo is also used to set the string
- * that was queried from the original menu item.
- */
- int uIDNewItem = id;
- int uFlags = OS.MF_BYPOSITION;
- if (menu != null) {
- uFlags |= OS.MF_POPUP;
- uIDNewItem = menu.handle;
- }
- TCHAR lpNewItem = new TCHAR (0, "", true);
- success = OS.InsertMenu (hMenu, index, uFlags, uIDNewItem, lpNewItem);
- if (success) {
- info.fMask = OS.MIIM_DATA | OS.MIIM_TYPE;
- success = OS.SetMenuItemInfo (hMenu, index, true, info);
- if ((info.fState & (OS.MFS_DISABLED | OS.MFS_GRAYED)) != 0) {
- OS.EnableMenuItem (hMenu, index, OS.MF_BYPOSITION | OS.MF_GRAYED);
- }
- if ((info.fState & OS.MFS_CHECKED) != 0) {
- OS.CheckMenuItem (hMenu, index, OS.MF_BYPOSITION | OS.MF_CHECKED);
- }
- }
- } else {
- success = OS.InsertMenuItem (hMenu, index, true, info);
- }
- if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
- if (!success) error (SWT.ERROR_CANNOT_SET_MENU);
- }
- parent.destroyAccelerators ();
-}
-
-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;
- if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) return;
- int hMenu = parent.handle;
- if (OS.IsWinCE) {
- int index = parent.indexOf (this);
- if (index == -1) return;
- int uCheck = OS.MF_BYPOSITION | (selected ? OS.MF_CHECKED : OS.MF_UNCHECKED);
- OS.CheckMenuItem (hMenu, index, uCheck);
- } else {
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- info.fMask = OS.MIIM_STATE;
- boolean success = OS.GetMenuItemInfo (hMenu, id, false, info);
- if (!success) error (SWT.ERROR_CANNOT_SET_SELECTION);
- info.fState &= ~OS.MFS_CHECKED;
- if (selected) info.fState |= OS.MFS_CHECKED;
- success = OS.SetMenuItemInfo (hMenu, id, false, info);
- if (!success) error (SWT.ERROR_CANNOT_SET_SELECTION);
- }
- parent.redraw ();
-}
-/**
- * Sets the receiver's text. The string may include
- * the mnemonic character and accelerator text.
- * <p>
- * Mnemonics are indicated by an '&' 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 '&' can be
- * escaped by doubling it in the string, causing a single
- *'&' 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);
- int hHeap = OS.GetProcessHeap ();
- int pszText;
- boolean success = false;
- if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) {
- /*
- * Bug in WinCE PPC. Tool items on the menubar don't resize
- * correctly when the character '&' is used (even when it
- * is a sequence '&&'). The fix is to remove all '&' from
- * the string.
- */
- if (string.indexOf ('&') != -1) {
- int length = string.length ();
- char[] text = new char [length];
- string.getChars( 0, length, text, 0);
- int i = 0, j = 0;
- for (i=0; i<length; i++) {
- if (text[i] != '&') text [j++] = text [i];
- }
- if (j < i) string = new String (text, 0, j);
- }
- /* Use the character encoding for the default locale */
- TCHAR buffer = new TCHAR (0, string, true);
- int byteCount = buffer.length () * TCHAR.sizeof;
- pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- OS.MoveMemory (pszText, buffer, byteCount);
- int hwndCB = parent.hwndCB;
- TBBUTTONINFO info2 = new TBBUTTONINFO ();
- info2.cbSize = TBBUTTONINFO.sizeof;
- info2.dwMask = OS.TBIF_TEXT;
- info2.pszText = pszText;
- success = OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, id, info2) != 0;
- } else {
- /* Use the character encoding for the default locale */
- TCHAR buffer = new TCHAR (0, string, true);
- int byteCount = buffer.length () * TCHAR.sizeof;
- pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- OS.MoveMemory (pszText, buffer, byteCount);
- int hMenu = parent.handle;
- MENUITEMINFO info = new MENUITEMINFO ();
- info.cbSize = MENUITEMINFO.sizeof;
- info.fMask = OS.MIIM_TYPE;
- info.fType = widgetStyle ();
- info.dwTypeData = pszText;
- success = OS.SetMenuItemInfo (hMenu, id, false, info);
- /*
- * Bug in Windows 2000. For some reason, when MIIM_TYPE is set
- * on a menu item that also has MIIM_BITMAP, the MIIM_TYPE clears
- * the MIIM_BITMAP style. The fix is to reset both MIIM_BITMAP.
- * Note, this does not happen on Windows 98.
- */
- if (!OS.IsWinCE) {
- if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) >= (4 << 16 | 10)) {
- if (image != null) {
- info.fMask = OS.MIIM_BITMAP;
- info.hbmpItem = OS.HBMMENU_CALLBACK;
- success = OS.SetMenuItemInfo (hMenu, id, false, info);
- }
- }
- }
- }
- if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
- if (!success) error (SWT.ERROR_CANNOT_SET_TEXT);
- parent.redraw ();
-}
-
-int widgetStyle () {
- int bits = 0;
- Decorations shell = parent.parent;
- if ((shell.style & SWT.MIRRORED) != 0) {
- if ((parent.style & SWT.LEFT_TO_RIGHT) != 0) {
- bits |= OS.MFT_RIGHTJUSTIFY | OS.MFT_RIGHTORDER;
- }
- } else {
- if ((parent.style & SWT.RIGHT_TO_LEFT) != 0) {
- bits |= OS.MFT_RIGHTJUSTIFY | OS.MFT_RIGHTORDER;
- }
- }
- if ((style & SWT.SEPARATOR) != 0) return bits | OS.MFT_SEPARATOR;
- if ((style & SWT.RADIO) != 0) return bits | OS.MFT_RADIOCHECK;
- return bits | OS.MFT_STRING;
-}
-
-LRESULT wmCommandChild (int wParam, int lParam) {
- 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 ();
- setInputState (event, SWT.Selection);
- postEvent (SWT.Selection, event);
- return null;
-}
-
-LRESULT wmDrawChild (int wParam, int lParam) {
- DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT ();
- OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof);
- if (image != null) {
- /*
- * This code intentionally commented.
- */
-// GC gc = GC.win32_new (struct.hDC, null);
-// gc.drawImage (image, struct.left, struct.top);
- int hImage = image.handle;
- switch (image.type) {
- case SWT.BITMAP:
- BITMAP bm = new BITMAP ();
- OS.GetObject (hImage, BITMAP.sizeof, bm);
- int hDC = OS.CreateCompatibleDC (struct.hDC);
- int oldBitmap = OS.SelectObject (hDC, hImage);
- OS.BitBlt (struct.hDC, struct.left, struct.top + 2, bm.bmWidth, bm.bmHeight, hDC, 0, 0, OS.SRCCOPY);
- OS.SelectObject (hDC, oldBitmap);
- OS.DeleteDC (hDC);
- break;
- case SWT.ICON:
- OS.DrawIconEx (struct.hDC, struct.left, struct.top + 2, hImage, 0, 0, 0, 0, OS.DI_NORMAL);
- break;
- }
- }
- return null;
-}
-
-LRESULT wmMeasureChild (int wParam, int lParam) {
- MEASUREITEMSTRUCT struct = new MEASUREITEMSTRUCT ();
- OS.MoveMemory (struct, lParam, MEASUREITEMSTRUCT.sizeof);
- if (image != null) {
- /*
- * Feature in Windows. On Windows 98, it is necessary
- * to add 4 pixels to the width of the image or the image
- * and text are too close. On other Windows platforms,
- * this causes the text of the longest item to touch the
- * accelerator text. The fix is to add only 2 pixels in
- * this case.
- */
- Rectangle rect = image.getBounds ();
- struct.itemWidth = rect.width + (OS.IsWin95 ? 4 : 2);
- struct.itemHeight = rect.height + 4;
- }
- OS.MoveMemory (lParam, struct, MEASUREITEMSTRUCT.sizeof);
- return null;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +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> + */ + +public class MenuItem extends Item { + Menu parent, menu; + int id, 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 index to store the receiver in its parent + * + * @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, int index) { + super (parent, checkStyle (style)); + this.parent = parent; + parent.createItem (this, index); +} + +MenuItem (Menu parent, Menu menu, int style, int index) { + super (parent, checkStyle (style)); + this.parent = parent; + this.menu = menu; + if (menu != null) menu.cascade = this; + Decorations shell = parent.parent; + shell.add (this); +} + +/** + * 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 control is selected, 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 + * + * @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); +} + +void fillAccel (ACCEL accel) { + accel.fVirt = 0; + accel.cmd = accel.key = 0; + if (accelerator == 0) return; + int fVirt = OS.FVIRTKEY; + int key = accelerator & SWT.KEY_MASK; + int vKey = Display.untranslateKey (key); + if (vKey != 0) { + key = vKey; + } else { + switch (key) { + /* + * Bug in Windows. For some reason, VkKeyScan + * fails to map ESC to VK_ESCAPE and DEL to + * VK_DELETE. The fix is to map these keys + * as a special case. + */ + case 27: key = OS.VK_ESCAPE; break; + case 127: key = OS.VK_DELETE; break; + default: { + key = wcsToMbcs ((char) key); + if (key == 0) return; + if (OS.IsWinCE) { + key = OS.CharUpper ((short) key); + } else { + vKey = OS.VkKeyScan ((short) key) & 0xFF; + if (vKey == -1) { + fVirt = 0; + } else { + key = vKey; + } + } + } + } + } + accel.key = (short) key; + accel.cmd = (short) id; + accel.fVirt = (byte) fVirt; + if ((accelerator & SWT.ALT) != 0) accel.fVirt |= OS.FALT; + if ((accelerator & SWT.SHIFT) != 0) accel.fVirt |= OS.FSHIFT; + if ((accelerator & SWT.CONTROL) != 0) accel.fVirt |= OS.FCONTROL; +} + +/** + * Return 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>. + * + * @return the accelerator + * + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if 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; +} + +public Display getDisplay () { + Menu parent = this.parent; + if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED); + return parent.getDisplay (); +} + +/** + * 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 (); + if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) { + int hwndCB = parent.hwndCB; + TBBUTTONINFO info = new TBBUTTONINFO (); + info.cbSize = TBBUTTONINFO.sizeof; + info.dwMask = OS.TBIF_STATE; + OS.SendMessage (hwndCB, OS.TB_GETBUTTONINFO, id, info); + return (info.fsState & OS.TBSTATE_ENABLED) != 0; + } + int hMenu = parent.handle; + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + info.fMask = OS.MIIM_STATE; + boolean success; + if (OS.IsWinCE) { + int index = parent.indexOf (this); + if (index == -1) error (SWT.ERROR_CANNOT_GET_ENABLED); + success = OS.GetMenuItemInfo (hMenu, index, true, info); + } else { + success = OS.GetMenuItemInfo (hMenu, id, false, info); + } + if (!success) error (SWT.ERROR_CANNOT_GET_ENABLED); + return (info.fState & (OS.MFS_DISABLED | OS.MFS_GRAYED)) == 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; + if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) return false; + int hMenu = parent.handle; + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + info.fMask = OS.MIIM_STATE; + boolean success = OS.GetMenuItemInfo (hMenu, id, false, info); + if (!success) error (SWT.ERROR_CANNOT_GET_SELECTION); + return (info.fState & OS.MFS_CHECKED) !=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 () { + return getEnabled () && parent.isEnabled (); +} + +void releaseChild () { + super.releaseChild (); + if (menu != null) menu.dispose (); + menu = null; + parent.destroyItem (this); +} + +void releaseMenu () { + if (!OS.IsSP) setMenu (null); + menu = null; +} + +void releaseWidget () { + if (menu != null) menu.releaseResources (); + menu = null; + super.releaseWidget (); + if (accelerator != 0) { + parent.destroyAccelerators (); + } + accelerator = 0; + Decorations shell = parent.parent; + shell.remove (this); + parent = 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 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 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. + * + * @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 #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); +} + +/** + * 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>. + * + * @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; + parent.destroyAccelerators (); +} + +/** + * 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 ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) { + int hwndCB = parent.hwndCB; + TBBUTTONINFO info = new TBBUTTONINFO (); + info.cbSize = TBBUTTONINFO.sizeof; + info.dwMask = OS.TBIF_STATE; + OS.SendMessage (hwndCB, OS.TB_GETBUTTONINFO, id, info); + info.fsState &= ~OS.TBSTATE_ENABLED; + if (enabled) info.fsState |= OS.TBSTATE_ENABLED; + OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, id, info); + } else { + int hMenu = parent.handle; + if (OS.IsWinCE) { + int index = parent.indexOf (this); + if (index == -1) return; + int uEnable = OS.MF_BYPOSITION | (enabled ? OS.MF_ENABLED : OS.MF_GRAYED); + OS.EnableMenuItem (hMenu, index, uEnable); + } else { + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + info.fMask = OS.MIIM_STATE; + boolean success = OS.GetMenuItemInfo (hMenu, id, false, info); + if (!success) error (SWT.ERROR_CANNOT_SET_ENABLED); + int bits = OS.MFS_DISABLED | OS.MFS_GRAYED; + if (enabled) { + if ((info.fState & bits) == 0) return; + info.fState &= ~bits; + } else { + if ((info.fState & bits) == bits) return; + info.fState |= bits; + } + success = OS.SetMenuItemInfo (hMenu, id, false, info); + if (!success) error (SWT.ERROR_CANNOT_SET_ENABLED); + } + } + parent.redraw (); +} + +/** + * Sets the image the receiver will display to the argument. + * <p> + * Note: This feature is not available on all window systems (for example, Window NT), + * in which case, calling this method will silently do nothing. + * + * @param menu 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); + if (OS.IsWinCE) return; + if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) < (4 << 16 | 10)) { + return; + } + int hMenu = parent.handle; + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + info.fMask = OS.MIIM_BITMAP; + if (image != null) info.hbmpItem = OS.HBMMENU_CALLBACK; + OS.SetMenuItemInfo (hMenu, id, false, info); + parent.redraw (); +} + +/** + * 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. + * + * @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; + + /* Assign the new menu in the OS */ + if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) { + if (OS.IsPPC) { + int hwndCB = parent.hwndCB; + int hMenu = menu == null ? 0 : menu.handle; + OS.SendMessage (hwndCB, OS.SHCMBM_SETSUBMENU, id, hMenu); + } + if (OS.IsSP) error (SWT.ERROR_CANNOT_SET_MENU); + } else { + /* + * Feature in Windows. When SetMenuItemInfo () is used to + * set a submenu and the menu item already has a submenu, + * Windows destroys the previous menu. This is undocumented + * and unexpected but not necessarily wrong. The fix is to + * remove the item with RemoveMenu () which does not destroy + * the submenu and then insert the item with InsertMenuItem (). + */ + int hMenu = parent.handle; + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + info.fMask = OS.MIIM_DATA; + int index = 0; + while (OS.GetMenuItemInfo (hMenu, index, true, info)) { + if (info.dwItemData == id) break; + index++; + } + if (info.dwItemData != id) return; + int cch = 128; + int hHeap = OS.GetProcessHeap (); + int byteCount = cch * TCHAR.sizeof; + int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + info.fMask = OS.MIIM_STATE | OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_DATA; + info.dwTypeData = pszText; + info.cch = cch; + boolean success = OS.GetMenuItemInfo (hMenu, index, true, info); + if (menu != null) { + menu.cascade = this; + info.fMask |= OS.MIIM_SUBMENU; + info.hSubMenu = menu.handle; + } + OS.RemoveMenu (hMenu, index, OS.MF_BYPOSITION); + if (OS.IsWinCE) { + /* + * On WinCE, InsertMenuItem is not available. SetMenuItemInfo + * does not set the menu item state and submenu use InsertMenu + * to set these fields and SetMenuItemInfo to set the menu item + * data. NOTE: SetMenuItemInfo is also used to set the string + * that was queried from the original menu item. + */ + int uIDNewItem = id; + int uFlags = OS.MF_BYPOSITION; + if (menu != null) { + uFlags |= OS.MF_POPUP; + uIDNewItem = menu.handle; + } + TCHAR lpNewItem = new TCHAR (0, "", true); + success = OS.InsertMenu (hMenu, index, uFlags, uIDNewItem, lpNewItem); + if (success) { + info.fMask = OS.MIIM_DATA | OS.MIIM_TYPE; + success = OS.SetMenuItemInfo (hMenu, index, true, info); + if ((info.fState & (OS.MFS_DISABLED | OS.MFS_GRAYED)) != 0) { + OS.EnableMenuItem (hMenu, index, OS.MF_BYPOSITION | OS.MF_GRAYED); + } + if ((info.fState & OS.MFS_CHECKED) != 0) { + OS.CheckMenuItem (hMenu, index, OS.MF_BYPOSITION | OS.MF_CHECKED); + } + } + } else { + success = OS.InsertMenuItem (hMenu, index, true, info); + } + if (pszText != 0) OS.HeapFree (hHeap, 0, pszText); + if (!success) error (SWT.ERROR_CANNOT_SET_MENU); + } + parent.destroyAccelerators (); +} + +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; + if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) return; + int hMenu = parent.handle; + if (OS.IsWinCE) { + int index = parent.indexOf (this); + if (index == -1) return; + int uCheck = OS.MF_BYPOSITION | (selected ? OS.MF_CHECKED : OS.MF_UNCHECKED); + OS.CheckMenuItem (hMenu, index, uCheck); + } else { + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + info.fMask = OS.MIIM_STATE; + boolean success = OS.GetMenuItemInfo (hMenu, id, false, info); + if (!success) error (SWT.ERROR_CANNOT_SET_SELECTION); + info.fState &= ~OS.MFS_CHECKED; + if (selected) info.fState |= OS.MFS_CHECKED; + success = OS.SetMenuItemInfo (hMenu, id, false, info); + if (!success) error (SWT.ERROR_CANNOT_SET_SELECTION); + } + parent.redraw (); +} +/** + * Sets the receiver's text. The string may include + * the mnemonic character and accelerator text. + * <p> + * Mnemonics are indicated by an '&' 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 '&' can be + * escaped by doubling it in the string, causing a single + *'&' 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); + int hHeap = OS.GetProcessHeap (); + int pszText; + boolean success = false; + if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) { + /* + * Bug in WinCE PPC. Tool items on the menubar don't resize + * correctly when the character '&' is used (even when it + * is a sequence '&&'). The fix is to remove all '&' from + * the string. + */ + if (string.indexOf ('&') != -1) { + int length = string.length (); + char[] text = new char [length]; + string.getChars( 0, length, text, 0); + int i = 0, j = 0; + for (i=0; i<length; i++) { + if (text[i] != '&') text [j++] = text [i]; + } + if (j < i) string = new String (text, 0, j); + } + /* Use the character encoding for the default locale */ + TCHAR buffer = new TCHAR (0, string, true); + int byteCount = buffer.length () * TCHAR.sizeof; + pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + OS.MoveMemory (pszText, buffer, byteCount); + int hwndCB = parent.hwndCB; + TBBUTTONINFO info2 = new TBBUTTONINFO (); + info2.cbSize = TBBUTTONINFO.sizeof; + info2.dwMask = OS.TBIF_TEXT; + info2.pszText = pszText; + success = OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, id, info2) != 0; + } else { + /* Use the character encoding for the default locale */ + TCHAR buffer = new TCHAR (0, string, true); + int byteCount = buffer.length () * TCHAR.sizeof; + pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + OS.MoveMemory (pszText, buffer, byteCount); + int hMenu = parent.handle; + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = MENUITEMINFO.sizeof; + info.fMask = OS.MIIM_TYPE; + info.fType = widgetStyle (); + info.dwTypeData = pszText; + success = OS.SetMenuItemInfo (hMenu, id, false, info); + /* + * Bug in Windows 2000. For some reason, when MIIM_TYPE is set + * on a menu item that also has MIIM_BITMAP, the MIIM_TYPE clears + * the MIIM_BITMAP style. The fix is to reset both MIIM_BITMAP. + * Note, this does not happen on Windows 98. + */ + if (!OS.IsWinCE) { + if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) >= (4 << 16 | 10)) { + if (image != null) { + info.fMask = OS.MIIM_BITMAP; + info.hbmpItem = OS.HBMMENU_CALLBACK; + success = OS.SetMenuItemInfo (hMenu, id, false, info); + } + } + } + } + if (pszText != 0) OS.HeapFree (hHeap, 0, pszText); + if (!success) error (SWT.ERROR_CANNOT_SET_TEXT); + parent.redraw (); +} + +int widgetStyle () { + int bits = 0; + Decorations shell = parent.parent; + if ((shell.style & SWT.MIRRORED) != 0) { + if ((parent.style & SWT.LEFT_TO_RIGHT) != 0) { + bits |= OS.MFT_RIGHTJUSTIFY | OS.MFT_RIGHTORDER; + } + } else { + if ((parent.style & SWT.RIGHT_TO_LEFT) != 0) { + bits |= OS.MFT_RIGHTJUSTIFY | OS.MFT_RIGHTORDER; + } + } + if ((style & SWT.SEPARATOR) != 0) return bits | OS.MFT_SEPARATOR; + if ((style & SWT.RADIO) != 0) return bits | OS.MFT_RADIOCHECK; + return bits | OS.MFT_STRING; +} + +LRESULT wmCommandChild (int wParam, int lParam) { + 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 (); + setInputState (event, SWT.Selection); + postEvent (SWT.Selection, event); + return null; +} + +LRESULT wmDrawChild (int wParam, int lParam) { + DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT (); + OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof); + if (image != null) { + /* + * This code intentionally commented. + */ +// GC gc = GC.win32_new (struct.hDC, null); +// gc.drawImage (image, struct.left, struct.top); + int hImage = image.handle; + switch (image.type) { + case SWT.BITMAP: + BITMAP bm = new BITMAP (); + OS.GetObject (hImage, BITMAP.sizeof, bm); + int hDC = OS.CreateCompatibleDC (struct.hDC); + int oldBitmap = OS.SelectObject (hDC, hImage); + OS.BitBlt (struct.hDC, struct.left, struct.top + 2, bm.bmWidth, bm.bmHeight, hDC, 0, 0, OS.SRCCOPY); + OS.SelectObject (hDC, oldBitmap); + OS.DeleteDC (hDC); + break; + case SWT.ICON: + OS.DrawIconEx (struct.hDC, struct.left, struct.top + 2, hImage, 0, 0, 0, 0, OS.DI_NORMAL); + break; + } + } + return null; +} + +LRESULT wmMeasureChild (int wParam, int lParam) { + MEASUREITEMSTRUCT struct = new MEASUREITEMSTRUCT (); + OS.MoveMemory (struct, lParam, MEASUREITEMSTRUCT.sizeof); + if (image != null) { + /* + * Feature in Windows. On Windows 98, it is necessary + * to add 4 pixels to the width of the image or the image + * and text are too close. On other Windows platforms, + * this causes the text of the longest item to touch the + * accelerator text. The fix is to add only 2 pixels in + * this case. + */ + Rectangle rect = image.getBounds (); + struct.itemWidth = rect.width + (OS.IsWin95 ? 4 : 2); + struct.itemHeight = rect.height + 4; + } + OS.MoveMemory (lParam, struct, MEASUREITEMSTRUCT.sizeof); + return null; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MessageBox.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MessageBox.java index e1716155e8..0b8b1e180e 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MessageBox.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MessageBox.java @@ -1,252 +1,252 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-
-/**
- * Instances of this class are used 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>
- */
-public class MessageBox extends Dialog {
- String message = "";
-
-/**
- * Constructs a new instance of this class given only its
- * parent.
- * <p>
- * Note: Currently, null can be passed in for the parent.
- * This has the effect of creating the dialog on the currently active
- * display if there is one. If there is no current display, the
- * dialog 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_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.
- * </p>
- * Note: Currently, null can be passed in for the parent.
- * This has the effect of creating the dialog on the currently active
- * display if there is one. If there is no current display, the
- * dialog 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_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, int style) {
- super (parent, checkStyle (style));
- checkSubclass ();
-}
-
-static int checkStyle (int style) {
- if ((style & (SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL)) == 0) style |= SWT.APPLICATION_MODAL;
- 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, 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 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 () {
-
- /* Compute the MessageBox style */
- int buttonBits = 0;
- if ((style & SWT.OK) == SWT.OK) buttonBits = OS.MB_OK;
- if ((style & (SWT.OK | SWT.CANCEL)) == (SWT.OK | SWT.CANCEL)) buttonBits = OS.MB_OKCANCEL;
- if ((style & (SWT.YES | SWT.NO)) == (SWT.YES | SWT.NO)) buttonBits = OS.MB_YESNO;
- if ((style & (SWT.YES | SWT.NO | SWT.CANCEL)) == (SWT.YES | SWT.NO | SWT.CANCEL)) buttonBits = OS.MB_YESNOCANCEL;
- if ((style & (SWT.RETRY | SWT.CANCEL)) == (SWT.RETRY | SWT.CANCEL)) buttonBits = OS.MB_RETRYCANCEL;
- if ((style & (SWT.ABORT | SWT.RETRY | SWT.IGNORE)) == (SWT.ABORT | SWT.RETRY | SWT.IGNORE)) buttonBits = OS.MB_ABORTRETRYIGNORE;
- if (buttonBits == 0) buttonBits = OS.MB_OK;
-
- int iconBits = 0;
- if ((style & SWT.ICON_ERROR) != 0) iconBits = OS.MB_ICONERROR;
- if ((style & SWT.ICON_INFORMATION) != 0) iconBits = OS.MB_ICONINFORMATION;
- if ((style & SWT.ICON_QUESTION) != 0) iconBits = OS.MB_ICONQUESTION;
- if ((style & SWT.ICON_WARNING) != 0) iconBits = OS.MB_ICONWARNING;
- if ((style & SWT.ICON_WORKING) != 0) iconBits = OS.MB_ICONINFORMATION;
-
- /* Only MB_APPLMODAL is supported on WinCE */
- int modalBits = 0;
- if (OS.IsWinCE) {
- if ((style & (SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL)) != 0) {
- modalBits = OS.MB_APPLMODAL;
- }
- } else {
- if ((style & SWT.PRIMARY_MODAL) != 0) modalBits = OS.MB_APPLMODAL;
- if ((style & SWT.APPLICATION_MODAL) != 0) modalBits = OS.MB_TASKMODAL;
- if ((style & SWT.SYSTEM_MODAL) != 0) modalBits = OS.MB_SYSTEMMODAL;
- }
-
- int bits = buttonBits | iconBits | modalBits;
- if ((style & SWT.RIGHT_TO_LEFT) != 0) bits |= OS.MB_RTLREADING;
- if (parent != null && (parent.style & SWT.RIGHT_TO_LEFT) != 0) {
- bits |= OS.MB_RTLREADING;
- }
-
- /*
- * Feature in Windows. System modal is not supported
- * on Windows 95 and NT. The fix is to convert system
- * modal to task modal.
- */
- if ((bits & OS.MB_SYSTEMMODAL) != 0) {
- bits |= OS.MB_TASKMODAL;
- bits &= ~OS.MB_SYSTEMMODAL;
- }
-
- /*
- * Feature in Windows. In order for MB_TASKMODAL to work,
- * the parent HWND of the MessageBox () call must be NULL.
- * If the parent is not NULL, MB_TASKMODAL behaves the
- * same as MB_APPLMODAL. The fix is to force the parent
- * to be NULL when this style is set.
- */
- int hwndOwner = 0;
- if (parent != null && (bits & OS.MB_TASKMODAL) == 0) {
- hwndOwner = parent.handle;
- }
-
- /*
- * Feature in Windows. The focus window is not saved and
- * and restored automatically by the call to MessageBox().
- * The fix is to save and restore the focus window.
- */
- int hwndFocus = OS.GetFocus ();
-
- /* Open the message box */
- /* Use the character encoding for the default locale */
- TCHAR buffer1 = new TCHAR (0, message, true);
- TCHAR buffer2 = new TCHAR (0, title, true);
- int code = OS.MessageBox (hwndOwner, buffer1, buffer2, bits);
-
- /* Restore focus */
- OS.SetFocus (hwndFocus);
-
- /*
- * This code is intentionally commented. On some
- * platforms, the owner window is repainted right
- * away when a dialog window exits. This behavior
- * is currently unspecified.
- */
-// if (hwndOwner != 0) OS.UpdateWindow (hwndOwner);
-
- /* Compute and return the result */
- if (code != 0) {
- int type = bits & 0x0F;
- if (type == OS.MB_OK) return SWT.OK;
- if (type == OS.MB_OKCANCEL) {
- return (code == OS.IDOK) ? SWT.OK : SWT.CANCEL;
- }
- if (type == OS.MB_YESNO) {
- return (code == OS.IDYES) ? SWT.YES : SWT.NO;
- }
- if (type == OS.MB_YESNOCANCEL) {
- if (code == OS.IDYES) return SWT.YES;
- if (code == OS.IDNO) return SWT.NO;
- return SWT.CANCEL;
- }
- if (type == OS.MB_RETRYCANCEL) {
- return (code == OS.IDRETRY) ? SWT.RETRY : SWT.CANCEL;
- }
- if (type == OS.MB_ABORTRETRYIGNORE) {
- if (code == OS.IDRETRY) return SWT.RETRY;
- if (code == OS.IDABORT) return SWT.ABORT;
- return SWT.IGNORE;
- }
- }
- return SWT.CANCEL;
-}
-
-/**
- * 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
- */
-public void setMessage (String string) {
- message = string;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; + +/** + * Instances of this class are used 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> + */ +public class MessageBox extends Dialog { + String message = ""; + +/** + * Constructs a new instance of this class given only its + * parent. + * <p> + * Note: Currently, null can be passed in for the parent. + * This has the effect of creating the dialog on the currently active + * display if there is one. If there is no current display, the + * dialog 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_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. + * </p> + * Note: Currently, null can be passed in for the parent. + * This has the effect of creating the dialog on the currently active + * display if there is one. If there is no current display, the + * dialog 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_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, int style) { + super (parent, checkStyle (style)); + checkSubclass (); +} + +static int checkStyle (int style) { + if ((style & (SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL)) == 0) style |= SWT.APPLICATION_MODAL; + 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, 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 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 () { + + /* Compute the MessageBox style */ + int buttonBits = 0; + if ((style & SWT.OK) == SWT.OK) buttonBits = OS.MB_OK; + if ((style & (SWT.OK | SWT.CANCEL)) == (SWT.OK | SWT.CANCEL)) buttonBits = OS.MB_OKCANCEL; + if ((style & (SWT.YES | SWT.NO)) == (SWT.YES | SWT.NO)) buttonBits = OS.MB_YESNO; + if ((style & (SWT.YES | SWT.NO | SWT.CANCEL)) == (SWT.YES | SWT.NO | SWT.CANCEL)) buttonBits = OS.MB_YESNOCANCEL; + if ((style & (SWT.RETRY | SWT.CANCEL)) == (SWT.RETRY | SWT.CANCEL)) buttonBits = OS.MB_RETRYCANCEL; + if ((style & (SWT.ABORT | SWT.RETRY | SWT.IGNORE)) == (SWT.ABORT | SWT.RETRY | SWT.IGNORE)) buttonBits = OS.MB_ABORTRETRYIGNORE; + if (buttonBits == 0) buttonBits = OS.MB_OK; + + int iconBits = 0; + if ((style & SWT.ICON_ERROR) != 0) iconBits = OS.MB_ICONERROR; + if ((style & SWT.ICON_INFORMATION) != 0) iconBits = OS.MB_ICONINFORMATION; + if ((style & SWT.ICON_QUESTION) != 0) iconBits = OS.MB_ICONQUESTION; + if ((style & SWT.ICON_WARNING) != 0) iconBits = OS.MB_ICONWARNING; + if ((style & SWT.ICON_WORKING) != 0) iconBits = OS.MB_ICONINFORMATION; + + /* Only MB_APPLMODAL is supported on WinCE */ + int modalBits = 0; + if (OS.IsWinCE) { + if ((style & (SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL)) != 0) { + modalBits = OS.MB_APPLMODAL; + } + } else { + if ((style & SWT.PRIMARY_MODAL) != 0) modalBits = OS.MB_APPLMODAL; + if ((style & SWT.APPLICATION_MODAL) != 0) modalBits = OS.MB_TASKMODAL; + if ((style & SWT.SYSTEM_MODAL) != 0) modalBits = OS.MB_SYSTEMMODAL; + } + + int bits = buttonBits | iconBits | modalBits; + if ((style & SWT.RIGHT_TO_LEFT) != 0) bits |= OS.MB_RTLREADING; + if (parent != null && (parent.style & SWT.RIGHT_TO_LEFT) != 0) { + bits |= OS.MB_RTLREADING; + } + + /* + * Feature in Windows. System modal is not supported + * on Windows 95 and NT. The fix is to convert system + * modal to task modal. + */ + if ((bits & OS.MB_SYSTEMMODAL) != 0) { + bits |= OS.MB_TASKMODAL; + bits &= ~OS.MB_SYSTEMMODAL; + } + + /* + * Feature in Windows. In order for MB_TASKMODAL to work, + * the parent HWND of the MessageBox () call must be NULL. + * If the parent is not NULL, MB_TASKMODAL behaves the + * same as MB_APPLMODAL. The fix is to force the parent + * to be NULL when this style is set. + */ + int hwndOwner = 0; + if (parent != null && (bits & OS.MB_TASKMODAL) == 0) { + hwndOwner = parent.handle; + } + + /* + * Feature in Windows. The focus window is not saved and + * and restored automatically by the call to MessageBox(). + * The fix is to save and restore the focus window. + */ + int hwndFocus = OS.GetFocus (); + + /* Open the message box */ + /* Use the character encoding for the default locale */ + TCHAR buffer1 = new TCHAR (0, message, true); + TCHAR buffer2 = new TCHAR (0, title, true); + int code = OS.MessageBox (hwndOwner, buffer1, buffer2, bits); + + /* Restore focus */ + OS.SetFocus (hwndFocus); + + /* + * This code is intentionally commented. On some + * platforms, the owner window is repainted right + * away when a dialog window exits. This behavior + * is currently unspecified. + */ +// if (hwndOwner != 0) OS.UpdateWindow (hwndOwner); + + /* Compute and return the result */ + if (code != 0) { + int type = bits & 0x0F; + if (type == OS.MB_OK) return SWT.OK; + if (type == OS.MB_OKCANCEL) { + return (code == OS.IDOK) ? SWT.OK : SWT.CANCEL; + } + if (type == OS.MB_YESNO) { + return (code == OS.IDYES) ? SWT.YES : SWT.NO; + } + if (type == OS.MB_YESNOCANCEL) { + if (code == OS.IDYES) return SWT.YES; + if (code == OS.IDNO) return SWT.NO; + return SWT.CANCEL; + } + if (type == OS.MB_RETRYCANCEL) { + return (code == OS.IDRETRY) ? SWT.RETRY : SWT.CANCEL; + } + if (type == OS.MB_ABORTRETRYIGNORE) { + if (code == OS.IDRETRY) return SWT.RETRY; + if (code == OS.IDABORT) return SWT.ABORT; + return SWT.IGNORE; + } + } + return SWT.CANCEL; +} + +/** + * 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 + */ +public void setMessage (String string) { + message = string; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ProgressBar.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ProgressBar.java index e2b5996604..14a37795ee 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ProgressBar.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ProgressBar.java @@ -1,279 +1,279 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-
-/**
- * Instances of the receiver represent is 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>
- */
-public class ProgressBar extends Control {
- static final int DELAY = 100;
- static final int TIMER_ID = 100;
- static final int ProgressBarProc;
- static final TCHAR ProgressBarClass = new TCHAR (0, OS.PROGRESS_CLASS, true);
- static {
- WNDCLASS lpWndClass = new WNDCLASS ();
- OS.GetClassInfo (0, ProgressBarClass, lpWndClass);
- ProgressBarProc = lpWndClass.lpfnWndProc;
- }
-
-/**
- * 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 Widget#checkSubclass
- * @see Widget#getStyle
- */
-public ProgressBar (Composite parent, int style) {
- super (parent, checkStyle (style));
-}
-
-int callWindowProc (int msg, int wParam, int lParam) {
- if (handle == 0) return 0;
- return OS.CallWindowProc (ProgressBarProc, handle, msg, wParam, lParam);
-}
-
-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 border = getBorderWidth ();
- int width = border * 2, height = border * 2;
- if ((style & SWT.HORIZONTAL) != 0) {
- width += OS.GetSystemMetrics (OS.SM_CXHSCROLL) * 10;
- height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
- } else {
- width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
- height += OS.GetSystemMetrics (OS.SM_CYVSCROLL) * 10;
- }
- if (wHint != SWT.DEFAULT) width = wHint + (border * 2);
- if (hHint != SWT.DEFAULT) height = hHint + (border * 2);
- return new Point (width, height);
-}
-
-void createHandle () {
- super.createHandle ();
- if ((style & SWT.INDETERMINATE) != 0) {
- OS.SetTimer (handle, TIMER_ID, DELAY, 0);
- }
-}
-
-int defaultForeground () {
- return OS.GetSysColor (OS.COLOR_HIGHLIGHT);
-}
-
-/**
- * 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 OS.SendMessage (handle, OS.PBM_GETRANGE, 0, 0);
-}
-
-/**
- * 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 OS.SendMessage (handle, OS.PBM_GETRANGE, 1, 0);
-}
-
-/**
- * Returns the single <em>selection</em> 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 OS.SendMessage (handle, OS.PBM_GETPOS, 0, 0);
-}
-
-void releaseWidget () {
- super.releaseWidget ();
- if ((style & SWT.INDETERMINATE) != 0) {
- OS.KillTimer (handle, TIMER_ID);
- }
-}
-
-void setBackgroundPixel (int pixel) {
- if (background == pixel) return;
- background = pixel;
- if (pixel == -1) pixel = OS.CLR_DEFAULT;
- OS.SendMessage (handle, OS.PBM_SETBKCOLOR, 0, pixel);
-}
-
-public boolean setFocus () {
- checkWidget();
- return false;
-}
-
-void setForegroundPixel (int pixel) {
- if (foreground == pixel) return;
- foreground = pixel;
- if (pixel == -1) pixel = OS.CLR_DEFAULT;
- OS.SendMessage (handle, OS.PBM_SETBARCOLOR, 0, pixel);
-}
-
-/**
- * Sets the maximum value which the receiver will allow
- * to be the argument which must be greater than or
- * equal to zero.
- *
- * @param value the new maximum (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 setMaximum (int value) {
- checkWidget ();
- int minimum = OS.SendMessage (handle, OS.PBM_GETRANGE, 1, 0);
- if (0 <= minimum && minimum < value) {
- OS.SendMessage (handle, OS.PBM_SETRANGE32, minimum, value);
- }
-}
-
-/**
- * Sets the minimum value which the receiver will allow
- * to be the argument which must be greater than or
- * equal to zero.
- *
- * @param value the new minimum (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 setMinimum (int value) {
- checkWidget ();
- int maximum = OS.SendMessage (handle, OS.PBM_GETRANGE, 0, 0);
- if (0 <= value && value < maximum) {
- OS.SendMessage (handle, OS.PBM_SETRANGE32, value, maximum);
- }
-}
-
-/**
- * Sets the single <em>selection</em> 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 ();
- OS.SendMessage (handle, OS.PBM_SETPOS, value, 0);
-}
-
-int widgetStyle () {
- int bits = super.widgetStyle ();
- if ((style & SWT.SMOOTH) != 0) bits |= OS.PBS_SMOOTH;
- if ((style & SWT.VERTICAL) != 0) bits |= OS.PBS_VERTICAL;
- return bits;
-}
-
-TCHAR windowClass () {
- return ProgressBarClass;
-}
-
-int windowProc () {
- return ProgressBarProc;
-}
-
-LRESULT WM_GETDLGCODE (int wParam, int lParam) {
- LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
- if (result != null) return result;
- /*
- * Feature in Windows. The progress bar does
- * not implement WM_GETDLGCODE. As a result,
- * a progress bar takes focus and takes part
- * in tab traversal. This behavior, while
- * unspecified, is unwanted. The fix is to
- * implement WM_GETDLGCODE to behave like a
- * STATIC control.
- */
- return new LRESULT (OS.DLGC_STATIC);
-}
-
-LRESULT WM_TIMER (int wParam, int lParam) {
- LRESULT result = super.WM_TIMER (wParam, lParam);
- if (result != null) return result;
- if (wParam == TIMER_ID) {
- OS.SendMessage (handle, OS.PBM_STEPIT, 0, 0);
- }
- return null;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; + +/** + * Instances of the receiver represent is 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> + */ +public class ProgressBar extends Control { + static final int DELAY = 100; + static final int TIMER_ID = 100; + static final int ProgressBarProc; + static final TCHAR ProgressBarClass = new TCHAR (0, OS.PROGRESS_CLASS, true); + static { + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, ProgressBarClass, lpWndClass); + ProgressBarProc = lpWndClass.lpfnWndProc; + } + +/** + * 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 Widget#checkSubclass + * @see Widget#getStyle + */ +public ProgressBar (Composite parent, int style) { + super (parent, checkStyle (style)); +} + +int callWindowProc (int msg, int wParam, int lParam) { + if (handle == 0) return 0; + return OS.CallWindowProc (ProgressBarProc, handle, msg, wParam, lParam); +} + +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 border = getBorderWidth (); + int width = border * 2, height = border * 2; + if ((style & SWT.HORIZONTAL) != 0) { + width += OS.GetSystemMetrics (OS.SM_CXHSCROLL) * 10; + height += OS.GetSystemMetrics (OS.SM_CYHSCROLL); + } else { + width += OS.GetSystemMetrics (OS.SM_CXVSCROLL); + height += OS.GetSystemMetrics (OS.SM_CYVSCROLL) * 10; + } + if (wHint != SWT.DEFAULT) width = wHint + (border * 2); + if (hHint != SWT.DEFAULT) height = hHint + (border * 2); + return new Point (width, height); +} + +void createHandle () { + super.createHandle (); + if ((style & SWT.INDETERMINATE) != 0) { + OS.SetTimer (handle, TIMER_ID, DELAY, 0); + } +} + +int defaultForeground () { + return OS.GetSysColor (OS.COLOR_HIGHLIGHT); +} + +/** + * 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 OS.SendMessage (handle, OS.PBM_GETRANGE, 0, 0); +} + +/** + * 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 OS.SendMessage (handle, OS.PBM_GETRANGE, 1, 0); +} + +/** + * Returns the single <em>selection</em> 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 OS.SendMessage (handle, OS.PBM_GETPOS, 0, 0); +} + +void releaseWidget () { + super.releaseWidget (); + if ((style & SWT.INDETERMINATE) != 0) { + OS.KillTimer (handle, TIMER_ID); + } +} + +void setBackgroundPixel (int pixel) { + if (background == pixel) return; + background = pixel; + if (pixel == -1) pixel = OS.CLR_DEFAULT; + OS.SendMessage (handle, OS.PBM_SETBKCOLOR, 0, pixel); +} + +public boolean setFocus () { + checkWidget(); + return false; +} + +void setForegroundPixel (int pixel) { + if (foreground == pixel) return; + foreground = pixel; + if (pixel == -1) pixel = OS.CLR_DEFAULT; + OS.SendMessage (handle, OS.PBM_SETBARCOLOR, 0, pixel); +} + +/** + * Sets the maximum value which the receiver will allow + * to be the argument which must be greater than or + * equal to zero. + * + * @param value the new maximum (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 setMaximum (int value) { + checkWidget (); + int minimum = OS.SendMessage (handle, OS.PBM_GETRANGE, 1, 0); + if (0 <= minimum && minimum < value) { + OS.SendMessage (handle, OS.PBM_SETRANGE32, minimum, value); + } +} + +/** + * Sets the minimum value which the receiver will allow + * to be the argument which must be greater than or + * equal to zero. + * + * @param value the new minimum (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 setMinimum (int value) { + checkWidget (); + int maximum = OS.SendMessage (handle, OS.PBM_GETRANGE, 0, 0); + if (0 <= value && value < maximum) { + OS.SendMessage (handle, OS.PBM_SETRANGE32, value, maximum); + } +} + +/** + * Sets the single <em>selection</em> 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 (); + OS.SendMessage (handle, OS.PBM_SETPOS, value, 0); +} + +int widgetStyle () { + int bits = super.widgetStyle (); + if ((style & SWT.SMOOTH) != 0) bits |= OS.PBS_SMOOTH; + if ((style & SWT.VERTICAL) != 0) bits |= OS.PBS_VERTICAL; + return bits; +} + +TCHAR windowClass () { + return ProgressBarClass; +} + +int windowProc () { + return ProgressBarProc; +} + +LRESULT WM_GETDLGCODE (int wParam, int lParam) { + LRESULT result = super.WM_GETDLGCODE (wParam, lParam); + if (result != null) return result; + /* + * Feature in Windows. The progress bar does + * not implement WM_GETDLGCODE. As a result, + * a progress bar takes focus and takes part + * in tab traversal. This behavior, while + * unspecified, is unwanted. The fix is to + * implement WM_GETDLGCODE to behave like a + * STATIC control. + */ + return new LRESULT (OS.DLGC_STATIC); +} + +LRESULT WM_TIMER (int wParam, int lParam) { + LRESULT result = super.WM_TIMER (wParam, lParam); + if (result != null) return result; + if (wParam == TIMER_ID) { + OS.SendMessage (handle, OS.PBM_STEPIT, 0, 0); + } + return null; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Sash.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Sash.java index 3d744daf42..ad7f3cd6c8 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Sash.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Sash.java @@ -1,404 +1,404 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.events.*;
-
-/**
- * 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</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>
- */
-public class Sash extends Control {
- boolean dragging;
- int startX, startY, lastX, lastY;
- final static int INCREMENT = 1;
- final static int PAGE_INCREMENT = 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 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 Sash (Composite parent, int style) {
- super (parent, checkStyle (style));
-}
-
-/**
- * Adds the listener to the collection of listeners who will
- * be notified when the control is selected, 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 reciever 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
- *
- * @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);
-}
-
-int callWindowProc (int msg, int wParam, int lParam) {
- if (handle == 0) return 0;
- return OS.DefWindowProc (handle, msg, wParam, lParam);
-}
-
-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 border = getBorderWidth ();
- int width = border * 2, height = border * 2;
- if ((style & SWT.HORIZONTAL) != 0) {
- width += DEFAULT_WIDTH; height += 3;
- } else {
- width += 3; height += DEFAULT_HEIGHT;
- }
- if (wHint != SWT.DEFAULT) width = wHint + (border * 2);
- if (hHint != SWT.DEFAULT) height = hHint + (border * 2);
- return new Point (width, height);
-}
-
-void drawBand (int x, int y, int width, int height) {
- int hwndTrack = parent.handle;
- byte [] bits = {-86, 0, 85, 0, -86, 0, 85, 0, -86, 0, 85, 0, -86, 0, 85, 0};
- int stippleBitmap = OS.CreateBitmap (8, 8, 1, 1, bits);
- int stippleBrush = OS.CreatePatternBrush (stippleBitmap);
- int hDC = OS.GetDCEx (hwndTrack, 0, OS.DCX_CACHE);
- int oldBrush = OS.SelectObject (hDC, stippleBrush);
- OS.PatBlt (hDC, x, y, width, height, OS.PATINVERT);
- OS.SelectObject (hDC, oldBrush);
- OS.ReleaseDC (hwndTrack, hDC);
- OS.DeleteObject (stippleBrush);
- OS.DeleteObject (stippleBitmap);
-}
-
-/**
- * Removes the listener from the collection of listeners who will
- * be notified when the control is selected.
- *
- * @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 #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);
-}
-
-TCHAR windowClass () {
- return getDisplay ().windowClass;
-}
-
-int windowProc () {
- return getDisplay ().windowProc;
-}
-
-LRESULT WM_ERASEBKGND (int wParam, int lParam) {
- LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
- if (result != null) return result;
- drawBackground (wParam);
- return LRESULT.ONE;
-}
-
-LRESULT WM_KEYDOWN (int wParam, int lParam) {
- LRESULT result = super.WM_KEYDOWN (wParam, lParam);
- if (result != null) return result;
- switch (wParam) {
- case OS.VK_LEFT:
- case OS.VK_RIGHT:
- case OS.VK_UP:
- case OS.VK_DOWN:
-
- /* Calculate the new x or y position */
- if (OS.GetKeyState (OS.VK_LBUTTON) < 0) return result;
- int step = OS.GetKeyState (OS.VK_CONTROL) < 0 ? INCREMENT : PAGE_INCREMENT;
- POINT pt = new POINT ();
- if ((style & SWT.VERTICAL) != 0) {
- if (wParam == OS.VK_UP || wParam == OS.VK_DOWN) break;
- pt.x = wParam == OS.VK_LEFT ? -step : step;
- } else {
- if (wParam == OS.VK_LEFT || wParam == OS.VK_RIGHT) break;
- pt.y = wParam == OS.VK_UP ? -step : step;
- }
- int hwndTrack = parent.handle;
- OS.MapWindowPoints (handle, hwndTrack, pt, 1);
- RECT rect = new RECT (), clientRect = new RECT ();
- OS.GetWindowRect (handle, rect);
- int width = rect.right - rect.left;
- int height = rect.bottom - rect.top;
- OS.GetClientRect (hwndTrack, clientRect);
- int clientWidth = clientRect.right - clientRect.left;
- int clientHeight = clientRect.bottom - clientRect.top;
- int newX = lastX, newY = lastY;
- if ((style & SWT.VERTICAL) != 0) {
- newX = Math.min (Math.max (0, pt.x - startX), clientWidth - width);
- } else {
- newY = Math.min (Math.max (0, pt.y - startY), clientHeight - height);
- }
- if (newX == lastX && newY == lastY) return result;
-
- /* Update the pointer position */
- POINT cursorPt = new POINT ();
- cursorPt.x = pt.x; cursorPt.y = pt.y;
- OS.ClientToScreen (parent.handle, cursorPt);
- if ((style & SWT.VERTICAL) != 0) {
- cursorPt.y += height / 2;
- }
- else {
- cursorPt.x += width / 2;
- }
- OS.SetCursorPos (cursorPt.x, cursorPt.y);
-
- /* The event must be sent because doit flag is used */
- Event event = new Event ();
- event.x = newX; event.y = newY;
- event.width = width; event.height = height;
-
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the selection
- * event. If this happens, end the processing of the
- * Windows message by returning zero as the result of
- * the window proc.
- */
- sendEvent (SWT.Selection, event);
- if (isDisposed ()) return LRESULT.ZERO;
- return result;
- }
- return result;
-}
-
-LRESULT WM_GETDLGCODE (int wParam, int lParam) {
- return new LRESULT (OS.DLGC_STATIC);
-}
-
-LRESULT WM_LBUTTONDOWN (int wParam, int lParam) {
- LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam);
-
- /* Compute the banding rectangle */
- int hwndTrack = parent.handle;
- POINT pt = new POINT ();
- pt.x = (short) (lParam & 0xFFFF);
- pt.y = (short) (lParam >> 16);
- RECT rect = new RECT ();
- OS.GetWindowRect (handle, rect);
- OS.MapWindowPoints (handle, 0, pt, 1);
- startX = pt.x - rect.left;
- startY = pt.y - rect.top;
- OS.MapWindowPoints (0, hwndTrack, rect, 2);
- lastX = rect.left;
- lastY = rect.top;
- int width = rect.right - rect.left;
- int height = rect.bottom - rect.top;
-
- /* The event must be sent because doit flag is used */
- Event event = new Event ();
- event.x = lastX;
- event.y = lastY;
- event.width = width;
- event.height = height;
- event.detail = SWT.DRAG;
-
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the selection
- * event. If this happens, end the processing of the
- * Windows message by returning zero as the result of
- * the window proc.
- */
- sendEvent (SWT.Selection, event);
- if (isDisposed ()) return LRESULT.ZERO;
-
- /* Draw the banding rectangle */
- if (event.doit) {
- dragging = true;
- menuShell ().bringToTop ();
- if (OS.IsWinCE) {
- OS.UpdateWindow (hwndTrack);
- } else {
- int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
- OS.RedrawWindow (hwndTrack, null, 0, flags);
- }
- drawBand (lastX = event.x, lastY = event.y, width, height);
- }
- return result;
-}
-
-LRESULT WM_LBUTTONUP (int wParam, int lParam) {
- LRESULT result = super.WM_LBUTTONUP (wParam, lParam);
-
- /* Compute the banding rectangle */
- if (!dragging) return result;
- dragging = false;
- RECT rect = new RECT ();
- OS.GetWindowRect (handle, rect);
- int width = rect.right - rect.left;
- int height = rect.bottom - rect.top;
-
- /* The event must be sent because doit flag is used */
- Event event = new Event ();
- event.x = lastX;
- event.y = lastY;
- event.width = width;
- event.height = height;
- drawBand (lastX, lastY, width, height);
- sendEvent (SWT.Selection, event);
- // widget could be disposed at this point
- return result;
-}
-
-LRESULT WM_MOUSEMOVE (int wParam, int lParam) {
- LRESULT result = super.WM_MOUSEMOVE (wParam, lParam);
- if (result != null) return result;
- if (!dragging || (wParam & OS.MK_LBUTTON) == 0) return result;
-
- /* Compute the banding rectangle */
- POINT pt = new POINT ();
- pt.x = (short) (lParam & 0xFFFF);
- pt.y = (short) (lParam >> 16);
- int hwndTrack = parent.handle;
- OS.MapWindowPoints (handle, hwndTrack, pt, 1);
- RECT rect = new RECT (), clientRect = new RECT ();
- OS.GetWindowRect (handle, rect);
- int width = rect.right - rect.left;
- int height = rect.bottom - rect.top;
- OS.GetClientRect (hwndTrack, clientRect);
- int newX = lastX, newY = lastY;
- if ((style & SWT.VERTICAL) != 0) {
- int clientWidth = clientRect.right - clientRect.left;
- newX = Math.min (Math.max (0, pt.x - startX), clientWidth - width);
- } else {
- int clientHeight = clientRect.bottom - clientRect.top;
- newY = Math.min (Math.max (0, pt.y - startY), clientHeight - height);
- }
- if (newX == lastX && newY == lastY) return result;
- drawBand (lastX, lastY, width, height);
-
- /* The event must be sent because doit flag is used */
- Event event = new Event ();
- event.x = newX;
- event.y = newY;
- event.width = width;
- event.height = height;
- event.detail = SWT.DRAG;
-
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the selection
- * event. If this happens, end the processing of the
- * Windows message by returning zero as the result of
- * the window proc.
- */
- sendEvent (SWT.Selection, event);
- if (isDisposed ()) return LRESULT.ZERO;
-
- /* Draw the banding rectangle */
- if (event.doit) {
- lastX = event.x; lastY = event.y;
- if (OS.IsWinCE) {
- OS.UpdateWindow (hwndTrack);
- } else {
- int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
- OS.RedrawWindow (hwndTrack, null, 0, flags);
- }
- drawBand (lastX, lastY, width, height);
- }
- return result;
-}
-
-LRESULT WM_SETCURSOR (int wParam, int lParam) {
- LRESULT result = super.WM_SETCURSOR (wParam, lParam);
- if (result != null) return result;
- int hitTest = lParam & 0xFFFF;
- if (hitTest == OS.HTCLIENT) {
- int hCursor = 0;
- if ((style & SWT.HORIZONTAL) != 0) {
- hCursor = OS.LoadCursor (0, OS.IDC_SIZENS);
- } else {
- hCursor = OS.LoadCursor (0, OS.IDC_SIZEWE);
- }
- OS.SetCursor (hCursor);
- return LRESULT.ONE;
- }
- return result;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.events.*; + +/** + * 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</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> + */ +public class Sash extends Control { + boolean dragging; + int startX, startY, lastX, lastY; + final static int INCREMENT = 1; + final static int PAGE_INCREMENT = 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 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 Sash (Composite parent, int style) { + super (parent, checkStyle (style)); +} + +/** + * Adds the listener to the collection of listeners who will + * be notified when the control is selected, 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 reciever 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 + * + * @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); +} + +int callWindowProc (int msg, int wParam, int lParam) { + if (handle == 0) return 0; + return OS.DefWindowProc (handle, msg, wParam, lParam); +} + +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 border = getBorderWidth (); + int width = border * 2, height = border * 2; + if ((style & SWT.HORIZONTAL) != 0) { + width += DEFAULT_WIDTH; height += 3; + } else { + width += 3; height += DEFAULT_HEIGHT; + } + if (wHint != SWT.DEFAULT) width = wHint + (border * 2); + if (hHint != SWT.DEFAULT) height = hHint + (border * 2); + return new Point (width, height); +} + +void drawBand (int x, int y, int width, int height) { + int hwndTrack = parent.handle; + byte [] bits = {-86, 0, 85, 0, -86, 0, 85, 0, -86, 0, 85, 0, -86, 0, 85, 0}; + int stippleBitmap = OS.CreateBitmap (8, 8, 1, 1, bits); + int stippleBrush = OS.CreatePatternBrush (stippleBitmap); + int hDC = OS.GetDCEx (hwndTrack, 0, OS.DCX_CACHE); + int oldBrush = OS.SelectObject (hDC, stippleBrush); + OS.PatBlt (hDC, x, y, width, height, OS.PATINVERT); + OS.SelectObject (hDC, oldBrush); + OS.ReleaseDC (hwndTrack, hDC); + OS.DeleteObject (stippleBrush); + OS.DeleteObject (stippleBitmap); +} + +/** + * Removes the listener from the collection of listeners who will + * be notified when the control is selected. + * + * @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 #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); +} + +TCHAR windowClass () { + return getDisplay ().windowClass; +} + +int windowProc () { + return getDisplay ().windowProc; +} + +LRESULT WM_ERASEBKGND (int wParam, int lParam) { + LRESULT result = super.WM_ERASEBKGND (wParam, lParam); + if (result != null) return result; + drawBackground (wParam); + return LRESULT.ONE; +} + +LRESULT WM_KEYDOWN (int wParam, int lParam) { + LRESULT result = super.WM_KEYDOWN (wParam, lParam); + if (result != null) return result; + switch (wParam) { + case OS.VK_LEFT: + case OS.VK_RIGHT: + case OS.VK_UP: + case OS.VK_DOWN: + + /* Calculate the new x or y position */ + if (OS.GetKeyState (OS.VK_LBUTTON) < 0) return result; + int step = OS.GetKeyState (OS.VK_CONTROL) < 0 ? INCREMENT : PAGE_INCREMENT; + POINT pt = new POINT (); + if ((style & SWT.VERTICAL) != 0) { + if (wParam == OS.VK_UP || wParam == OS.VK_DOWN) break; + pt.x = wParam == OS.VK_LEFT ? -step : step; + } else { + if (wParam == OS.VK_LEFT || wParam == OS.VK_RIGHT) break; + pt.y = wParam == OS.VK_UP ? -step : step; + } + int hwndTrack = parent.handle; + OS.MapWindowPoints (handle, hwndTrack, pt, 1); + RECT rect = new RECT (), clientRect = new RECT (); + OS.GetWindowRect (handle, rect); + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + OS.GetClientRect (hwndTrack, clientRect); + int clientWidth = clientRect.right - clientRect.left; + int clientHeight = clientRect.bottom - clientRect.top; + int newX = lastX, newY = lastY; + if ((style & SWT.VERTICAL) != 0) { + newX = Math.min (Math.max (0, pt.x - startX), clientWidth - width); + } else { + newY = Math.min (Math.max (0, pt.y - startY), clientHeight - height); + } + if (newX == lastX && newY == lastY) return result; + + /* Update the pointer position */ + POINT cursorPt = new POINT (); + cursorPt.x = pt.x; cursorPt.y = pt.y; + OS.ClientToScreen (parent.handle, cursorPt); + if ((style & SWT.VERTICAL) != 0) { + cursorPt.y += height / 2; + } + else { + cursorPt.x += width / 2; + } + OS.SetCursorPos (cursorPt.x, cursorPt.y); + + /* The event must be sent because doit flag is used */ + Event event = new Event (); + event.x = newX; event.y = newY; + event.width = width; event.height = height; + + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the selection + * event. If this happens, end the processing of the + * Windows message by returning zero as the result of + * the window proc. + */ + sendEvent (SWT.Selection, event); + if (isDisposed ()) return LRESULT.ZERO; + return result; + } + return result; +} + +LRESULT WM_GETDLGCODE (int wParam, int lParam) { + return new LRESULT (OS.DLGC_STATIC); +} + +LRESULT WM_LBUTTONDOWN (int wParam, int lParam) { + LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam); + + /* Compute the banding rectangle */ + int hwndTrack = parent.handle; + POINT pt = new POINT (); + pt.x = (short) (lParam & 0xFFFF); + pt.y = (short) (lParam >> 16); + RECT rect = new RECT (); + OS.GetWindowRect (handle, rect); + OS.MapWindowPoints (handle, 0, pt, 1); + startX = pt.x - rect.left; + startY = pt.y - rect.top; + OS.MapWindowPoints (0, hwndTrack, rect, 2); + lastX = rect.left; + lastY = rect.top; + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + + /* The event must be sent because doit flag is used */ + Event event = new Event (); + event.x = lastX; + event.y = lastY; + event.width = width; + event.height = height; + event.detail = SWT.DRAG; + + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the selection + * event. If this happens, end the processing of the + * Windows message by returning zero as the result of + * the window proc. + */ + sendEvent (SWT.Selection, event); + if (isDisposed ()) return LRESULT.ZERO; + + /* Draw the banding rectangle */ + if (event.doit) { + dragging = true; + menuShell ().bringToTop (); + if (OS.IsWinCE) { + OS.UpdateWindow (hwndTrack); + } else { + int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN; + OS.RedrawWindow (hwndTrack, null, 0, flags); + } + drawBand (lastX = event.x, lastY = event.y, width, height); + } + return result; +} + +LRESULT WM_LBUTTONUP (int wParam, int lParam) { + LRESULT result = super.WM_LBUTTONUP (wParam, lParam); + + /* Compute the banding rectangle */ + if (!dragging) return result; + dragging = false; + RECT rect = new RECT (); + OS.GetWindowRect (handle, rect); + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + + /* The event must be sent because doit flag is used */ + Event event = new Event (); + event.x = lastX; + event.y = lastY; + event.width = width; + event.height = height; + drawBand (lastX, lastY, width, height); + sendEvent (SWT.Selection, event); + // widget could be disposed at this point + return result; +} + +LRESULT WM_MOUSEMOVE (int wParam, int lParam) { + LRESULT result = super.WM_MOUSEMOVE (wParam, lParam); + if (result != null) return result; + if (!dragging || (wParam & OS.MK_LBUTTON) == 0) return result; + + /* Compute the banding rectangle */ + POINT pt = new POINT (); + pt.x = (short) (lParam & 0xFFFF); + pt.y = (short) (lParam >> 16); + int hwndTrack = parent.handle; + OS.MapWindowPoints (handle, hwndTrack, pt, 1); + RECT rect = new RECT (), clientRect = new RECT (); + OS.GetWindowRect (handle, rect); + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + OS.GetClientRect (hwndTrack, clientRect); + int newX = lastX, newY = lastY; + if ((style & SWT.VERTICAL) != 0) { + int clientWidth = clientRect.right - clientRect.left; + newX = Math.min (Math.max (0, pt.x - startX), clientWidth - width); + } else { + int clientHeight = clientRect.bottom - clientRect.top; + newY = Math.min (Math.max (0, pt.y - startY), clientHeight - height); + } + if (newX == lastX && newY == lastY) return result; + drawBand (lastX, lastY, width, height); + + /* The event must be sent because doit flag is used */ + Event event = new Event (); + event.x = newX; + event.y = newY; + event.width = width; + event.height = height; + event.detail = SWT.DRAG; + + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the selection + * event. If this happens, end the processing of the + * Windows message by returning zero as the result of + * the window proc. + */ + sendEvent (SWT.Selection, event); + if (isDisposed ()) return LRESULT.ZERO; + + /* Draw the banding rectangle */ + if (event.doit) { + lastX = event.x; lastY = event.y; + if (OS.IsWinCE) { + OS.UpdateWindow (hwndTrack); + } else { + int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN; + OS.RedrawWindow (hwndTrack, null, 0, flags); + } + drawBand (lastX, lastY, width, height); + } + return result; +} + +LRESULT WM_SETCURSOR (int wParam, int lParam) { + LRESULT result = super.WM_SETCURSOR (wParam, lParam); + if (result != null) return result; + int hitTest = lParam & 0xFFFF; + if (hitTest == OS.HTCLIENT) { + int hCursor = 0; + if ((style & SWT.HORIZONTAL) != 0) { + hCursor = OS.LoadCursor (0, OS.IDC_SIZENS); + } else { + hCursor = OS.LoadCursor (0, OS.IDC_SIZEWE); + } + OS.SetCursor (hCursor); + return LRESULT.ONE; + } + return result; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Scale.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Scale.java index 09b770cead..e3efc29250 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Scale.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Scale.java @@ -1,416 +1,416 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.events.*;
-
-/**
- * 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>
- */
-
-public class Scale extends Control {
- static final int TrackBarProc;
- static final TCHAR TrackBarClass = new TCHAR (0, OS.TRACKBAR_CLASS, true);
- static {
- WNDCLASS lpWndClass = new WNDCLASS ();
- OS.GetClassInfo (0, TrackBarClass, lpWndClass);
- TrackBarProc = lpWndClass.lpfnWndProc;
- }
-
-/**
- * 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 receiver's value changes, by sending
- * it one of the messages defined in the <code>SelectionListener</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 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);
-}
-
-int callWindowProc (int msg, int wParam, int lParam) {
- if (handle == 0) return 0;
- return OS.CallWindowProc (TrackBarProc, handle, msg, wParam, lParam);
-}
-
-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 border = getBorderWidth ();
- int width = border * 2, height = border * 2;
- RECT rect = new RECT ();
- OS.SendMessage (handle, OS.TBM_GETTHUMBRECT, 0, rect);
- if ((style & SWT.HORIZONTAL) != 0) {
- width += OS.GetSystemMetrics (OS.SM_CXHSCROLL) * 10;
- int scrollY = OS.GetSystemMetrics (OS.SM_CYHSCROLL);
- height += (rect.top * 2) + scrollY + (scrollY / 3);
- } else {
- int scrollX = OS.GetSystemMetrics (OS.SM_CXVSCROLL);
- width += (rect.left * 2) + scrollX + (scrollX / 3);
- height += OS.GetSystemMetrics (OS.SM_CYVSCROLL) * 10;
- }
- if (wHint != SWT.DEFAULT) width = wHint + (border * 2);
- if (hHint != SWT.DEFAULT) height = hHint + (border * 2);
- return new Point (width, height);
-}
-
-void createHandle () {
- super.createHandle ();
- OS.SendMessage (handle, OS.TBM_SETRANGEMAX, 0, 100);
- OS.SendMessage (handle, OS.TBM_SETPAGESIZE, 0, 10);
- OS.SendMessage (handle, OS.TBM_SETTICFREQ, 10, 0);
-}
-
-int defaultForeground () {
- return OS.GetSysColor (OS.COLOR_BTNFACE);
-}
-
-/**
- * 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 OS.SendMessage (handle, OS.TBM_GETLINESIZE, 0, 0);
-}
-
-/**
- * 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 OS.SendMessage (handle, OS.TBM_GETRANGEMAX, 0, 0);
-}
-
-/**
- * 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 OS.SendMessage (handle, OS.TBM_GETRANGEMIN, 0, 0);
-}
-
-/**
- * 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 OS.SendMessage (handle, OS.TBM_GETPAGESIZE, 0, 0);
-}
-
-/**
- * Returns the single <em>selection</em> 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 OS.SendMessage (handle, OS.TBM_GETPOS, 0, 0);
-}
-
-/**
- * Removes the listener from the collection of listeners who will
- * be notified when the receiver's value changes.
- *
- * @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 setBackgroundPixel (int pixel) {
- if (background == pixel) return;
- super.setBackgroundPixel (pixel);
- /*
- * Bug in Windows. Changing the background color of the Scale
- * widget and calling InvalidateRect still draws with the old color.
- * The fix is to post a fake WM_SETFOCUS event to cause it to redraw
- * with the new background color.
- *
- * Note. This WM_SETFOCUS message causes recursion when
- * setBackground is called from within the focus event listener.
- */
- OS.PostMessage (handle, OS.WM_SETFOCUS, 0, 0);
-}
-
-/**
- * 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 increment) {
- checkWidget ();
- if (increment < 1) return;
- int minimum = OS.SendMessage (handle, OS.TBM_GETRANGEMIN, 0, 0);
- int maximum = OS.SendMessage (handle, OS.TBM_GETRANGEMAX, 0, 0);
- if (increment > maximum - minimum) return;
- OS.SendMessage (handle, OS.TBM_SETLINESIZE, 0, increment);
-}
-
-/**
- * Sets the maximum value which the receiver will allow
- * to be the argument which must be greater than or
- * equal to zero.
- *
- * @param value the new maximum (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 setMaximum (int value) {
- checkWidget ();
- int minimum = OS.SendMessage (handle, OS.TBM_GETRANGEMIN, 0, 0);
- if (0 <= minimum && minimum < value) {
- OS.SendMessage (handle, OS.TBM_SETRANGEMAX, 1, value);
- }
-}
-
-/**
- * Sets the minimum value which the receiver will allow
- * to be the argument which must be greater than or
- * equal to zero.
- *
- * @param value the new minimum (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 setMinimum (int value) {
- checkWidget ();
- int maximum = OS.SendMessage (handle, OS.TBM_GETRANGEMAX, 0, 0);
- if (0 <= value && value < maximum) {
- OS.SendMessage (handle, OS.TBM_SETRANGEMIN, 1, 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.
- *
- * @return 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 pageIncrement) {
- checkWidget ();
- if (pageIncrement < 1) return;
- int minimum = OS.SendMessage (handle, OS.TBM_GETRANGEMIN, 0, 0);
- int maximum = OS.SendMessage (handle, OS.TBM_GETRANGEMAX, 0, 0);
- if (pageIncrement > maximum - minimum) return;
- OS.SendMessage (handle, OS.TBM_SETPAGESIZE, 0, pageIncrement);
- OS.SendMessage (handle, OS.TBM_SETTICFREQ, pageIncrement, 0);
-}
-
-/**
- * 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 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 ();
- OS.SendMessage (handle, OS.TBM_SETPOS, 1, value);
-}
-
-int widgetStyle () {
- int bits = super.widgetStyle () | OS.WS_TABSTOP | OS.TBS_BOTH | OS.TBS_AUTOTICKS;
- if ((style & SWT.HORIZONTAL) != 0) return bits | OS.TBS_HORZ;
- return bits | OS.TBS_VERT;
-}
-
-TCHAR windowClass () {
- return TrackBarClass;
-}
-
-int windowProc () {
- return TrackBarProc;
-}
-
-LRESULT wmScrollChild (int wParam, int lParam) {
-
- /* Do nothing when scrolling is ending */
- int code = wParam & 0xFFFF;
- if (code == OS.TB_ENDTRACK) return null;
-
- /*
- * This code is intentionally commented. The event
- * detail field is not currently supported on all
- * platforms.
- */
- Event event = new Event ();
-// switch (code) {
-// /*
-// * This line is intentionally commented. Do not set the detail
-// * field to DRAG to indicate that the dragging has ended when the
-// * scroll bar is finally positioned in TB_THUMBPOSITION.
-// */
-//// case OS.TB_THUMBPOSITION: break;
-// case OS.TB_THUMBTRACK: event.detail = SWT.DRAG; break;
-// case OS.TB_TOP: event.detail = SWT.HOME; break;
-// case OS.TB_BOTTOM: event.detail = SWT.END; break;
-// case OS.TB_LINEDOWN: event.detail = SWT.ARROW_DOWN; break;
-// case OS.TB_LINEUP: event.detail = SWT.ARROW_UP; break;
-// case OS.TB_PAGEDOWN: event.detail = SWT.PAGE_DOWN; break;
-// case OS.TB_PAGEUP: event.detail = SWT.PAGE_UP; break;
-// }
-
- /*
- * Send the event because WM_HSCROLL and WM_VSCROLL
- * are sent from a modal message loop in windows that
- * is active when the user is scrolling.
- */
- sendEvent (SWT.Selection, event);
- // widget could be disposed at this point
- return null;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.events.*; + +/** + * 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> + */ + +public class Scale extends Control { + static final int TrackBarProc; + static final TCHAR TrackBarClass = new TCHAR (0, OS.TRACKBAR_CLASS, true); + static { + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, TrackBarClass, lpWndClass); + TrackBarProc = lpWndClass.lpfnWndProc; + } + +/** + * 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 receiver's value changes, by sending + * it one of the messages defined in the <code>SelectionListener</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 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); +} + +int callWindowProc (int msg, int wParam, int lParam) { + if (handle == 0) return 0; + return OS.CallWindowProc (TrackBarProc, handle, msg, wParam, lParam); +} + +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 border = getBorderWidth (); + int width = border * 2, height = border * 2; + RECT rect = new RECT (); + OS.SendMessage (handle, OS.TBM_GETTHUMBRECT, 0, rect); + if ((style & SWT.HORIZONTAL) != 0) { + width += OS.GetSystemMetrics (OS.SM_CXHSCROLL) * 10; + int scrollY = OS.GetSystemMetrics (OS.SM_CYHSCROLL); + height += (rect.top * 2) + scrollY + (scrollY / 3); + } else { + int scrollX = OS.GetSystemMetrics (OS.SM_CXVSCROLL); + width += (rect.left * 2) + scrollX + (scrollX / 3); + height += OS.GetSystemMetrics (OS.SM_CYVSCROLL) * 10; + } + if (wHint != SWT.DEFAULT) width = wHint + (border * 2); + if (hHint != SWT.DEFAULT) height = hHint + (border * 2); + return new Point (width, height); +} + +void createHandle () { + super.createHandle (); + OS.SendMessage (handle, OS.TBM_SETRANGEMAX, 0, 100); + OS.SendMessage (handle, OS.TBM_SETPAGESIZE, 0, 10); + OS.SendMessage (handle, OS.TBM_SETTICFREQ, 10, 0); +} + +int defaultForeground () { + return OS.GetSysColor (OS.COLOR_BTNFACE); +} + +/** + * 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 OS.SendMessage (handle, OS.TBM_GETLINESIZE, 0, 0); +} + +/** + * 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 OS.SendMessage (handle, OS.TBM_GETRANGEMAX, 0, 0); +} + +/** + * 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 OS.SendMessage (handle, OS.TBM_GETRANGEMIN, 0, 0); +} + +/** + * 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 OS.SendMessage (handle, OS.TBM_GETPAGESIZE, 0, 0); +} + +/** + * Returns the single <em>selection</em> 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 OS.SendMessage (handle, OS.TBM_GETPOS, 0, 0); +} + +/** + * Removes the listener from the collection of listeners who will + * be notified when the receiver's value changes. + * + * @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 setBackgroundPixel (int pixel) { + if (background == pixel) return; + super.setBackgroundPixel (pixel); + /* + * Bug in Windows. Changing the background color of the Scale + * widget and calling InvalidateRect still draws with the old color. + * The fix is to post a fake WM_SETFOCUS event to cause it to redraw + * with the new background color. + * + * Note. This WM_SETFOCUS message causes recursion when + * setBackground is called from within the focus event listener. + */ + OS.PostMessage (handle, OS.WM_SETFOCUS, 0, 0); +} + +/** + * 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 increment) { + checkWidget (); + if (increment < 1) return; + int minimum = OS.SendMessage (handle, OS.TBM_GETRANGEMIN, 0, 0); + int maximum = OS.SendMessage (handle, OS.TBM_GETRANGEMAX, 0, 0); + if (increment > maximum - minimum) return; + OS.SendMessage (handle, OS.TBM_SETLINESIZE, 0, increment); +} + +/** + * Sets the maximum value which the receiver will allow + * to be the argument which must be greater than or + * equal to zero. + * + * @param value the new maximum (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 setMaximum (int value) { + checkWidget (); + int minimum = OS.SendMessage (handle, OS.TBM_GETRANGEMIN, 0, 0); + if (0 <= minimum && minimum < value) { + OS.SendMessage (handle, OS.TBM_SETRANGEMAX, 1, value); + } +} + +/** + * Sets the minimum value which the receiver will allow + * to be the argument which must be greater than or + * equal to zero. + * + * @param value the new minimum (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 setMinimum (int value) { + checkWidget (); + int maximum = OS.SendMessage (handle, OS.TBM_GETRANGEMAX, 0, 0); + if (0 <= value && value < maximum) { + OS.SendMessage (handle, OS.TBM_SETRANGEMIN, 1, 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. + * + * @return 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 pageIncrement) { + checkWidget (); + if (pageIncrement < 1) return; + int minimum = OS.SendMessage (handle, OS.TBM_GETRANGEMIN, 0, 0); + int maximum = OS.SendMessage (handle, OS.TBM_GETRANGEMAX, 0, 0); + if (pageIncrement > maximum - minimum) return; + OS.SendMessage (handle, OS.TBM_SETPAGESIZE, 0, pageIncrement); + OS.SendMessage (handle, OS.TBM_SETTICFREQ, pageIncrement, 0); +} + +/** + * 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 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 (); + OS.SendMessage (handle, OS.TBM_SETPOS, 1, value); +} + +int widgetStyle () { + int bits = super.widgetStyle () | OS.WS_TABSTOP | OS.TBS_BOTH | OS.TBS_AUTOTICKS; + if ((style & SWT.HORIZONTAL) != 0) return bits | OS.TBS_HORZ; + return bits | OS.TBS_VERT; +} + +TCHAR windowClass () { + return TrackBarClass; +} + +int windowProc () { + return TrackBarProc; +} + +LRESULT wmScrollChild (int wParam, int lParam) { + + /* Do nothing when scrolling is ending */ + int code = wParam & 0xFFFF; + if (code == OS.TB_ENDTRACK) return null; + + /* + * This code is intentionally commented. The event + * detail field is not currently supported on all + * platforms. + */ + Event event = new Event (); +// switch (code) { +// /* +// * This line is intentionally commented. Do not set the detail +// * field to DRAG to indicate that the dragging has ended when the +// * scroll bar is finally positioned in TB_THUMBPOSITION. +// */ +//// case OS.TB_THUMBPOSITION: break; +// case OS.TB_THUMBTRACK: event.detail = SWT.DRAG; break; +// case OS.TB_TOP: event.detail = SWT.HOME; break; +// case OS.TB_BOTTOM: event.detail = SWT.END; break; +// case OS.TB_LINEDOWN: event.detail = SWT.ARROW_DOWN; break; +// case OS.TB_LINEUP: event.detail = SWT.ARROW_UP; break; +// case OS.TB_PAGEDOWN: event.detail = SWT.PAGE_DOWN; break; +// case OS.TB_PAGEUP: event.detail = SWT.PAGE_UP; break; +// } + + /* + * Send the event because WM_HSCROLL and WM_VSCROLL + * are sent from a modal message loop in windows that + * is active when the user is scrolling. + */ + sendEvent (SWT.Selection, event); + // widget could be disposed at this point + return null; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ScrollBar.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ScrollBar.java index a5baa1a81b..aa6e1b0dad 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ScrollBar.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ScrollBar.java @@ -1,1004 +1,1004 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.events.*;
-
-/**
- * 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 <em>selection</em> 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
- */
-
-public class ScrollBar extends Widget {
- Scrollable parent;
- int increment, pageIncrement;
-
-/**
- * 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
- */
-ScrollBar (Scrollable parent, int style) {
- super (parent, checkStyle (style));
- this.parent = parent;
- createWidget ();
-}
-
-/**
- * Adds the listener to the collection of listeners who will
- * be notified when the receiver's value changes, 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>0</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
- *
- * @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 createWidget () {
- increment = 1;
- pageIncrement = 10;
- /*
- * Do not set the intial values of the maximum
- * or the thumb. These values normally default
- * to 100 and 10 but may have been set already
- * by the widget that owns the scroll bar. For
- * example, a scroll bar that is created for a
- * list widget, setting these defaults would
- * override the initial values provided by the
- * list widget.
- */
-}
-
-public void dispose () {
- int hwnd = hwndScrollBar (), type = scrollBarType ();
- super.dispose ();
- if (OS.IsWinCE) {
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_RANGE | OS.SIF_PAGE;
- info.nPage = 101;
- info.nMax = 100;
- info.nMin = 0;
- OS.SetScrollInfo (hwnd, type, info, true);
- } else {
- OS.ShowScrollBar (hwnd, type, false);
- }
-}
-
-/*
-* Not currently used.
-*/
-Rectangle getBounds () {
- RECT rect = new RECT ();
- OS.GetClientRect (parent.handle, rect);
- int x = 0, y = 0, width, height;
- if ((style & SWT.HORIZONTAL) != 0) {
- y = rect.bottom - rect.top;
- width = rect.right - rect.left;
- height = OS.GetSystemMetrics (OS.SM_CYHSCROLL);
- } else {
- x = rect.right - rect.left;
- width = OS.GetSystemMetrics (OS.SM_CXVSCROLL);
- height = rect.bottom - rect.top;
- }
- return new Rectangle (x, y, width, height);
-}
-
-public Display getDisplay () {
- Scrollable parent = this.parent;
- if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED);
- return parent.getDisplay ();
-}
-
-/**
- * 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();
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_RANGE;
- int hwnd = hwndScrollBar ();
- int type = scrollBarType ();
- OS.GetScrollInfo (hwnd, type, info);
- return info.nMax;
-}
-
-/**
- * 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();
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_RANGE;
- int hwnd = hwndScrollBar ();
- int type = scrollBarType ();
- OS.GetScrollInfo (hwnd, type, info);
- return info.nMin;
-}
-
-/**
- * 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 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 <em>selection</em> 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();
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_POS;
- int hwnd = hwndScrollBar ();
- int type = scrollBarType ();
- OS.GetScrollInfo (hwnd, type, info);
- return info.nPos;
-}
-
-/**
- * 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();
- RECT rect = new RECT ();
- OS.GetClientRect (parent.handle, rect);
- int width, height;
- if ((style & SWT.HORIZONTAL) != 0) {
- width = rect.right - rect.left;
- height = OS.GetSystemMetrics (OS.SM_CYHSCROLL);
- } else {
- width = OS.GetSystemMetrics (OS.SM_CXVSCROLL);
- height = rect.bottom - rect.top;
- }
- return new Point (width, height);
-}
-
-/**
- * Answers 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();
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_PAGE;
- int hwnd = hwndScrollBar ();
- int type = scrollBarType ();
- OS.GetScrollInfo (hwnd, type, info);
- if (info.nPage != 0) --info.nPage;
- return info.nPage;
-}
-
-/**
- * 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 hwndScrollBar () {
- return parent.handle;
-}
-
-/**
- * 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 ();
-}
-
-/**
- * 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 ();
-}
-
-void releaseChild () {
- super.releaseChild ();
- if (parent.horizontalBar == this) parent.horizontalBar = null;
- if (parent.verticalBar == this) parent.verticalBar = null;
-}
-
-void releaseWidget () {
- super.releaseWidget ();
- parent = null;
-}
-
-/**
- * Removes the listener from the collection of listeners who will
- * be notified when the receiver's value changes.
- *
- * @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);
-}
-
-int scrollBarType () {
- if ((style & SWT.VERTICAL) != 0) return OS.SB_VERT;
- /*
- * This line is intentionally commented. There should
- * only ever be HORIZONTAL and VERTICAL scroll bars.
- * The commented code reminds us that this is the case
- * and that the default style is HORIZONTAL.
- */
-// if ((style & SWT.HORIZONTAL) != 0) return OS.SB_HORZ;
- return OS.SB_HORZ;
-}
-
-/**
- * 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();
- /*
- * This line is intentionally commented. Currently
- * always show scrollbar as being enabled and visible.
- */
-// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED);
- if (!OS.IsWinCE) {
- int hwnd = hwndScrollBar (), type = scrollBarType ();
- int flags = enabled ? OS.ESB_ENABLE_BOTH : OS.ESB_DISABLE_BOTH;
- OS.EnableScrollBar (hwnd, type, flags);
- state &= ~DISABLED;
- if (!enabled) state |= DISABLED;
- }
-}
-
-/**
- * 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 value which the receiver will allow
- * to be the argument which must be greater than or
- * equal to zero.
- *
- * @param value the new maximum (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 setMaximum (int value) {
- checkWidget();
- if (value < 0) return;
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- int hwnd = hwndScrollBar (), type = scrollBarType ();
- info.fMask = OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
- OS.GetScrollInfo (hwnd, type, info);
- if (value - info.nMin - info.nPage < 1) return;
- info.nMax = value;
- OS.SetScrollInfo (hwnd, type, info, (state & DISABLED) == 0);
-
- /*
- * Bug in Windows. For some reason, when the widget
- * is a standard scroll bar, and SetScrollInfo () is
- * called with SIF_RANGE or SIF_PAGE, the widget is
- * incorrectly made visible so that the next time the
- * widget is resized (or another scroll bar operation
- * is performed), the scroll bar draws. The fix is
- * to hide the scroll bar (again) when already hidden.
- */
- if ((state & HIDDEN) != 0) {
- /*
- * This line is intentionally commented. Currently
- * always show scrollbar as being enabled and visible.
- */
-// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED);
- if (!OS.IsWinCE) {
- OS.ShowScrollBar (hwnd, type, false);
- }
- }
-
- /*
- * Feature in Windows. Using SIF_DISABLENOSCROLL,
- * SetScrollInfo () can change enabled and disabled
- * state of the scroll bar causing a scroll bar that
- * was disabled by the application to become enabled.
- * The fix is to disable the scroll bar (again) when
- * the application has disabled the scroll bar.
- */
- if ((state & DISABLED) != 0) {
- /*
- * This line is intentionally commented. Currently
- * always show scrollbar as being enabled and visible.
- */
-// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED);
- if (!OS.IsWinCE) {
- OS.EnableScrollBar (hwnd, type, OS.ESB_DISABLE_BOTH);
- }
- }
-}
-
-/**
- * Sets the minimum value which the receiver will allow
- * to be the argument which must be greater than or
- * equal to zero.
- *
- * @param value the new minimum (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 setMinimum (int value) {
- checkWidget();
- if (value < 0) return;
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- int hwnd = hwndScrollBar (), type = scrollBarType ();
- info.fMask = OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
- OS.GetScrollInfo (hwnd, type, info);
- if (info.nMax - value - info.nPage < 1) return;
- info.nMin = value;
- OS.SetScrollInfo (hwnd, type, info, true);
-
- /*
- * Bug in Windows. For some reason, when the widget
- * is a standard scroll bar, and SetScrollInfo () is
- * called with SIF_RANGE or SIF_PAGE, the widget is
- * incorrectly made visible so that the next time the
- * widget is resized (or another scroll bar operation
- * is performed), the scroll bar draws. The fix is
- * to hide the scroll bar (again) when already hidden.
- */
- if ((state & HIDDEN) != 0) {
- /*
- * This line is intentionally commented. Currently
- * always show scrollbar as being enabled and visible.
- */
-// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED);
- if (!OS.IsWinCE) {
- OS.ShowScrollBar (hwnd, type, false);
- }
- }
-
- /*
- * Feature in Windows. Using SIF_DISABLENOSCROLL,
- * SetScrollInfo () can change enabled and disabled
- * state of the scroll bar causing a scroll bar that
- * was disabled by the application to become enabled.
- * The fix is to disable the scroll bar (again) when
- * the application has disabled the scroll bar.
- */
- if ((state & DISABLED) != 0) {
- /*
- * This line is intentionally commented. Currently
- * always show scrollbar as being enabled and visible.
- */
-// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED);
- if (!OS.IsWinCE) {
- OS.EnableScrollBar (hwnd, type, OS.ESB_DISABLE_BOTH);
- }
- }
-}
-
-/**
- * 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.
- *
- * @return 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 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 selection) {
- checkWidget();
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- int hwnd = hwndScrollBar (), type = scrollBarType ();
- info.fMask = OS.SIF_POS;
- info.nPos = selection;
- OS.SetScrollInfo (hwnd, type, info, true);
-}
-
-/**
- * Sets the size of the receiver's thumb relative to the
- * difference between its maximum and minimum values to the
- * argument which must be at least one.
- *
- * @param value the new thumb value (must be at least 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 ScrollBar
- */
-public void setThumb (int value) {
- checkWidget();
-
- /* Position the thumb */
- if (value < 1) return;
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- int hwnd = hwndScrollBar (), type = scrollBarType ();
- info.fMask = OS.SIF_PAGE | OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
- OS.GetScrollInfo (hwnd, type, info);
- if (info.nMax - info.nMin - value < 0) return;
- info.nPage = value;
- if (info.nPage != 0) info.nPage++;
- OS.SetScrollInfo (hwnd, type, info, true);
-
- /*
- * Bug in Windows. For some reason, when the widget
- * is a standard scroll bar, and SetScrollInfo () is
- * called with SIF_RANGE or SIF_PAGE, the widget is
- * incorrectly made visible so that the next time the
- * widget is resized (or another scroll bar operation
- * is performed), the scroll bar draws. The fix is
- * to hide the scroll bar (again) when already hidden.
- */
- if ((state & HIDDEN) != 0) {
- /*
- * This line is intentionally commented. Currently
- * always show scrollbar as being enabled and visible.
- */
-// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED);
- if (!OS.IsWinCE) {
- OS.ShowScrollBar (hwnd, type, false);
- }
- }
-
- /*
- * Feature in Windows. Using SIF_DISABLENOSCROLL,
- * SetScrollInfo () can change enabled and disabled
- * state of the scroll bar causing a scroll bar that
- * was disabled by the application to become enabled.
- * The fix is to disable the scroll bar (again) when
- * the application has disabled the scroll bar.
- */
- if ((state & DISABLED) != 0) {
- /*
- * This line is intentionally commented. Currently
- * always show scrollbar as being enabled and visible.
- */
-// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED);
- if (!OS.IsWinCE) {
- OS.EnableScrollBar (hwnd, type, OS.ESB_DISABLE_BOTH);
- }
- }
-}
-
-/**
- * Sets the receiver's selection, minimum value, maximum
- * value, thumb, increment and page increment all at once.
- * <p>
- * Note: This is equivalent 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 (maximum - minimum - thumb < 0) return;
- if (increment < 1) return;
- if (pageIncrement < 1) return;
- this.increment = increment;
- this.pageIncrement = pageIncrement;
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_POS | OS.SIF_PAGE | OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
- info.nPos = selection;
- info.nMin = minimum;
- info.nMax = maximum;
- info.nPage = thumb;
- if (info.nPage != 0) info.nPage++;
- int hwnd = hwndScrollBar (), type = scrollBarType ();
- OS.SetScrollInfo (hwnd, type, info, true);
-
- /*
- * Bug in Windows. For some reason, when the widget
- * is a standard scroll bar, and SetScrollInfo () is
- * called with SIF_RANGE or SIF_PAGE, the widget is
- * incorrectly made visible so that the next time the
- * widget is resized (or another scroll bar operation
- * is performed), the scroll bar draws. The fix is
- * to hide the scroll bar (again) when already hidden.
- */
- if ((state & HIDDEN) != 0) {
- /*
- * This line is intentionally commented. Currently
- * always show scrollbar as being enabled and visible.
- */
-// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED);
- if (!OS.IsWinCE) {
- OS.ShowScrollBar (hwnd, type, false);
- }
- }
-
- /*
- * Feature in Windows. Using SIF_DISABLENOSCROLL,
- * SetScrollInfo () can change enabled and disabled
- * state of the scroll bar causing a scroll bar that
- * was disabled by the application to become enabled.
- * The fix is to disable the scroll bar (again) when
- * the application has disabled the scroll bar.
- */
- if ((state & DISABLED) != 0) {
- /*
- * This line is intentionally commented. Currently
- * always show scrollbar as being enabled and visible.
- */
-// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED);
- if (!OS.IsWinCE) {
- OS.EnableScrollBar (hwnd, type, OS.ESB_DISABLE_BOTH);
- }
- }
-}
-
-/**
- * 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 (OS.IsWinCE) {
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- int hwnd = hwndScrollBar (), type = scrollBarType ();
- info.fMask = OS.SIF_RANGE | OS.SIF_PAGE;
- if (visible) info.fMask |= OS.SIF_DISABLENOSCROLL;
- OS.GetScrollInfo (hwnd, type, info);
- if (info.nPage == info.nMax - info.nMin + 1) {
- /*
- * Bug in Windows. When the only changed flag to
- * SetScrollInfo () is OS.SIF_DISABLENOSCROLL,
- * Windows does not update the scroll bar state.
- * The fix is to increase and then decrease the
- * maximum, causing Windows to honour the flag.
- */
- int max = info.nMax;
- info.nMax++;
- OS.SetScrollInfo (hwnd, type, info, false);
- info.nMax = max;
- OS.SetScrollInfo (hwnd, type, info, true);
- } else {
- /*
- * This line is intentionally commented. Currently
- * always show scrollbar as being enabled and visible.
- */
-// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED);
- }
- return;
- }
-
- /*
- * Set the state bits before calling ShowScrollBar ()
- * because hiding and showing the scroll bar can cause
- * WM_SIZE messages when the client area is resized.
- * Setting the state before the call means that code
- * that runs during WM_SIZE that queries the visibility
- * of the scroll bar will get the correct value.
- */
- state &= ~HIDDEN;
- if (!visible) state |= HIDDEN;
- int hwnd = hwndScrollBar (), type = scrollBarType ();
- if (OS.ShowScrollBar (hwnd, type, visible)) {
- /*
- * Bug in Windows. For some reason, when the widget
- * is a standard scroll bar, and SetScrollInfo () is
- * called with SIF_RANGE or SIF_PAGE while the widget
- * is not visible, the widget is incorrectly disabled
- * even though the values for SIF_RANGE and SIF_PAGE,
- * when set for a visible scroll bar would not disable
- * the scroll bar. The fix is to enable the scroll bar
- * when not disabled by the application and the current
- * scroll bar ranges would cause the scroll bar to be
- * enabled had they been set when the scroll bar was
- * visible.
- */
- if ((state & DISABLED) == 0) {
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_RANGE | OS.SIF_PAGE;
- OS.GetScrollInfo (hwnd, type, info);
- if (info.nMax - info.nMin - info.nPage >= 0) {
- OS.EnableScrollBar (hwnd, type, OS.ESB_ENABLE_BOTH);
- }
- }
- sendEvent (visible ? SWT.Show : SWT.Hide);
- // widget could be disposed at this point
- }
-}
-
-LRESULT wmScrollChild (int wParam, int lParam) {
-
- /* Do nothing when scrolling is ending */
- int code = wParam & 0xFFFF;
- if (code == OS.SB_ENDSCROLL) return null;
-
- /*
- * Send the event because WM_HSCROLL and
- * WM_VSCROLL are sent from a modal message
- * loop in Windows that is active when the
- * user is scrolling.
- */
- Event event = new Event ();
- switch (code) {
- /*
- * This line is intentionally commented. Do not set the detail
- * field to DRAG to indicate that the dragging has ended when the
- * scroll bar is finally positioned in SB_THUMBPOSITION.
- */
-// case OS.SB_THUMBPOSITION: break;
- case OS.SB_THUMBTRACK: event.detail = SWT.DRAG; break;
- case OS.SB_TOP: event.detail = SWT.HOME; break;
- case OS.SB_BOTTOM: event.detail = SWT.END; break;
- case OS.SB_LINEDOWN: event.detail = SWT.ARROW_DOWN; break;
- case OS.SB_LINEUP: event.detail = SWT.ARROW_UP; break;
- case OS.SB_PAGEDOWN: event.detail = SWT.PAGE_DOWN; break;
- case OS.SB_PAGEUP: event.detail = SWT.PAGE_UP; break;
- }
- sendEvent (SWT.Selection, event);
- // the widget could be destroyed at this point
- return null;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.events.*; + +/** + * 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 <em>selection</em> 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 + */ + +public class ScrollBar extends Widget { + Scrollable parent; + int increment, pageIncrement; + +/** + * 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 + */ +ScrollBar (Scrollable parent, int style) { + super (parent, checkStyle (style)); + this.parent = parent; + createWidget (); +} + +/** + * Adds the listener to the collection of listeners who will + * be notified when the receiver's value changes, 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>0</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 + * + * @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 createWidget () { + increment = 1; + pageIncrement = 10; + /* + * Do not set the intial values of the maximum + * or the thumb. These values normally default + * to 100 and 10 but may have been set already + * by the widget that owns the scroll bar. For + * example, a scroll bar that is created for a + * list widget, setting these defaults would + * override the initial values provided by the + * list widget. + */ +} + +public void dispose () { + int hwnd = hwndScrollBar (), type = scrollBarType (); + super.dispose (); + if (OS.IsWinCE) { + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_RANGE | OS.SIF_PAGE; + info.nPage = 101; + info.nMax = 100; + info.nMin = 0; + OS.SetScrollInfo (hwnd, type, info, true); + } else { + OS.ShowScrollBar (hwnd, type, false); + } +} + +/* +* Not currently used. +*/ +Rectangle getBounds () { + RECT rect = new RECT (); + OS.GetClientRect (parent.handle, rect); + int x = 0, y = 0, width, height; + if ((style & SWT.HORIZONTAL) != 0) { + y = rect.bottom - rect.top; + width = rect.right - rect.left; + height = OS.GetSystemMetrics (OS.SM_CYHSCROLL); + } else { + x = rect.right - rect.left; + width = OS.GetSystemMetrics (OS.SM_CXVSCROLL); + height = rect.bottom - rect.top; + } + return new Rectangle (x, y, width, height); +} + +public Display getDisplay () { + Scrollable parent = this.parent; + if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED); + return parent.getDisplay (); +} + +/** + * 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(); + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_RANGE; + int hwnd = hwndScrollBar (); + int type = scrollBarType (); + OS.GetScrollInfo (hwnd, type, info); + return info.nMax; +} + +/** + * 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(); + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_RANGE; + int hwnd = hwndScrollBar (); + int type = scrollBarType (); + OS.GetScrollInfo (hwnd, type, info); + return info.nMin; +} + +/** + * 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 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 <em>selection</em> 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(); + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_POS; + int hwnd = hwndScrollBar (); + int type = scrollBarType (); + OS.GetScrollInfo (hwnd, type, info); + return info.nPos; +} + +/** + * 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(); + RECT rect = new RECT (); + OS.GetClientRect (parent.handle, rect); + int width, height; + if ((style & SWT.HORIZONTAL) != 0) { + width = rect.right - rect.left; + height = OS.GetSystemMetrics (OS.SM_CYHSCROLL); + } else { + width = OS.GetSystemMetrics (OS.SM_CXVSCROLL); + height = rect.bottom - rect.top; + } + return new Point (width, height); +} + +/** + * Answers 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(); + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_PAGE; + int hwnd = hwndScrollBar (); + int type = scrollBarType (); + OS.GetScrollInfo (hwnd, type, info); + if (info.nPage != 0) --info.nPage; + return info.nPage; +} + +/** + * 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 hwndScrollBar () { + return parent.handle; +} + +/** + * 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 (); +} + +/** + * 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 (); +} + +void releaseChild () { + super.releaseChild (); + if (parent.horizontalBar == this) parent.horizontalBar = null; + if (parent.verticalBar == this) parent.verticalBar = null; +} + +void releaseWidget () { + super.releaseWidget (); + parent = null; +} + +/** + * Removes the listener from the collection of listeners who will + * be notified when the receiver's value changes. + * + * @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); +} + +int scrollBarType () { + if ((style & SWT.VERTICAL) != 0) return OS.SB_VERT; + /* + * This line is intentionally commented. There should + * only ever be HORIZONTAL and VERTICAL scroll bars. + * The commented code reminds us that this is the case + * and that the default style is HORIZONTAL. + */ +// if ((style & SWT.HORIZONTAL) != 0) return OS.SB_HORZ; + return OS.SB_HORZ; +} + +/** + * 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(); + /* + * This line is intentionally commented. Currently + * always show scrollbar as being enabled and visible. + */ +// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED); + if (!OS.IsWinCE) { + int hwnd = hwndScrollBar (), type = scrollBarType (); + int flags = enabled ? OS.ESB_ENABLE_BOTH : OS.ESB_DISABLE_BOTH; + OS.EnableScrollBar (hwnd, type, flags); + state &= ~DISABLED; + if (!enabled) state |= DISABLED; + } +} + +/** + * 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 value which the receiver will allow + * to be the argument which must be greater than or + * equal to zero. + * + * @param value the new maximum (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 setMaximum (int value) { + checkWidget(); + if (value < 0) return; + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + int hwnd = hwndScrollBar (), type = scrollBarType (); + info.fMask = OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL; + OS.GetScrollInfo (hwnd, type, info); + if (value - info.nMin - info.nPage < 1) return; + info.nMax = value; + OS.SetScrollInfo (hwnd, type, info, (state & DISABLED) == 0); + + /* + * Bug in Windows. For some reason, when the widget + * is a standard scroll bar, and SetScrollInfo () is + * called with SIF_RANGE or SIF_PAGE, the widget is + * incorrectly made visible so that the next time the + * widget is resized (or another scroll bar operation + * is performed), the scroll bar draws. The fix is + * to hide the scroll bar (again) when already hidden. + */ + if ((state & HIDDEN) != 0) { + /* + * This line is intentionally commented. Currently + * always show scrollbar as being enabled and visible. + */ +// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED); + if (!OS.IsWinCE) { + OS.ShowScrollBar (hwnd, type, false); + } + } + + /* + * Feature in Windows. Using SIF_DISABLENOSCROLL, + * SetScrollInfo () can change enabled and disabled + * state of the scroll bar causing a scroll bar that + * was disabled by the application to become enabled. + * The fix is to disable the scroll bar (again) when + * the application has disabled the scroll bar. + */ + if ((state & DISABLED) != 0) { + /* + * This line is intentionally commented. Currently + * always show scrollbar as being enabled and visible. + */ +// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED); + if (!OS.IsWinCE) { + OS.EnableScrollBar (hwnd, type, OS.ESB_DISABLE_BOTH); + } + } +} + +/** + * Sets the minimum value which the receiver will allow + * to be the argument which must be greater than or + * equal to zero. + * + * @param value the new minimum (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 setMinimum (int value) { + checkWidget(); + if (value < 0) return; + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + int hwnd = hwndScrollBar (), type = scrollBarType (); + info.fMask = OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL; + OS.GetScrollInfo (hwnd, type, info); + if (info.nMax - value - info.nPage < 1) return; + info.nMin = value; + OS.SetScrollInfo (hwnd, type, info, true); + + /* + * Bug in Windows. For some reason, when the widget + * is a standard scroll bar, and SetScrollInfo () is + * called with SIF_RANGE or SIF_PAGE, the widget is + * incorrectly made visible so that the next time the + * widget is resized (or another scroll bar operation + * is performed), the scroll bar draws. The fix is + * to hide the scroll bar (again) when already hidden. + */ + if ((state & HIDDEN) != 0) { + /* + * This line is intentionally commented. Currently + * always show scrollbar as being enabled and visible. + */ +// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED); + if (!OS.IsWinCE) { + OS.ShowScrollBar (hwnd, type, false); + } + } + + /* + * Feature in Windows. Using SIF_DISABLENOSCROLL, + * SetScrollInfo () can change enabled and disabled + * state of the scroll bar causing a scroll bar that + * was disabled by the application to become enabled. + * The fix is to disable the scroll bar (again) when + * the application has disabled the scroll bar. + */ + if ((state & DISABLED) != 0) { + /* + * This line is intentionally commented. Currently + * always show scrollbar as being enabled and visible. + */ +// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED); + if (!OS.IsWinCE) { + OS.EnableScrollBar (hwnd, type, OS.ESB_DISABLE_BOTH); + } + } +} + +/** + * 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. + * + * @return 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 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 selection) { + checkWidget(); + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + int hwnd = hwndScrollBar (), type = scrollBarType (); + info.fMask = OS.SIF_POS; + info.nPos = selection; + OS.SetScrollInfo (hwnd, type, info, true); +} + +/** + * Sets the size of the receiver's thumb relative to the + * difference between its maximum and minimum values to the + * argument which must be at least one. + * + * @param value the new thumb value (must be at least 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 ScrollBar + */ +public void setThumb (int value) { + checkWidget(); + + /* Position the thumb */ + if (value < 1) return; + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + int hwnd = hwndScrollBar (), type = scrollBarType (); + info.fMask = OS.SIF_PAGE | OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL; + OS.GetScrollInfo (hwnd, type, info); + if (info.nMax - info.nMin - value < 0) return; + info.nPage = value; + if (info.nPage != 0) info.nPage++; + OS.SetScrollInfo (hwnd, type, info, true); + + /* + * Bug in Windows. For some reason, when the widget + * is a standard scroll bar, and SetScrollInfo () is + * called with SIF_RANGE or SIF_PAGE, the widget is + * incorrectly made visible so that the next time the + * widget is resized (or another scroll bar operation + * is performed), the scroll bar draws. The fix is + * to hide the scroll bar (again) when already hidden. + */ + if ((state & HIDDEN) != 0) { + /* + * This line is intentionally commented. Currently + * always show scrollbar as being enabled and visible. + */ +// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED); + if (!OS.IsWinCE) { + OS.ShowScrollBar (hwnd, type, false); + } + } + + /* + * Feature in Windows. Using SIF_DISABLENOSCROLL, + * SetScrollInfo () can change enabled and disabled + * state of the scroll bar causing a scroll bar that + * was disabled by the application to become enabled. + * The fix is to disable the scroll bar (again) when + * the application has disabled the scroll bar. + */ + if ((state & DISABLED) != 0) { + /* + * This line is intentionally commented. Currently + * always show scrollbar as being enabled and visible. + */ +// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED); + if (!OS.IsWinCE) { + OS.EnableScrollBar (hwnd, type, OS.ESB_DISABLE_BOTH); + } + } +} + +/** + * Sets the receiver's selection, minimum value, maximum + * value, thumb, increment and page increment all at once. + * <p> + * Note: This is equivalent 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 (maximum - minimum - thumb < 0) return; + if (increment < 1) return; + if (pageIncrement < 1) return; + this.increment = increment; + this.pageIncrement = pageIncrement; + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_POS | OS.SIF_PAGE | OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL; + info.nPos = selection; + info.nMin = minimum; + info.nMax = maximum; + info.nPage = thumb; + if (info.nPage != 0) info.nPage++; + int hwnd = hwndScrollBar (), type = scrollBarType (); + OS.SetScrollInfo (hwnd, type, info, true); + + /* + * Bug in Windows. For some reason, when the widget + * is a standard scroll bar, and SetScrollInfo () is + * called with SIF_RANGE or SIF_PAGE, the widget is + * incorrectly made visible so that the next time the + * widget is resized (or another scroll bar operation + * is performed), the scroll bar draws. The fix is + * to hide the scroll bar (again) when already hidden. + */ + if ((state & HIDDEN) != 0) { + /* + * This line is intentionally commented. Currently + * always show scrollbar as being enabled and visible. + */ +// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED); + if (!OS.IsWinCE) { + OS.ShowScrollBar (hwnd, type, false); + } + } + + /* + * Feature in Windows. Using SIF_DISABLENOSCROLL, + * SetScrollInfo () can change enabled and disabled + * state of the scroll bar causing a scroll bar that + * was disabled by the application to become enabled. + * The fix is to disable the scroll bar (again) when + * the application has disabled the scroll bar. + */ + if ((state & DISABLED) != 0) { + /* + * This line is intentionally commented. Currently + * always show scrollbar as being enabled and visible. + */ +// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED); + if (!OS.IsWinCE) { + OS.EnableScrollBar (hwnd, type, OS.ESB_DISABLE_BOTH); + } + } +} + +/** + * 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 (OS.IsWinCE) { + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + int hwnd = hwndScrollBar (), type = scrollBarType (); + info.fMask = OS.SIF_RANGE | OS.SIF_PAGE; + if (visible) info.fMask |= OS.SIF_DISABLENOSCROLL; + OS.GetScrollInfo (hwnd, type, info); + if (info.nPage == info.nMax - info.nMin + 1) { + /* + * Bug in Windows. When the only changed flag to + * SetScrollInfo () is OS.SIF_DISABLENOSCROLL, + * Windows does not update the scroll bar state. + * The fix is to increase and then decrease the + * maximum, causing Windows to honour the flag. + */ + int max = info.nMax; + info.nMax++; + OS.SetScrollInfo (hwnd, type, info, false); + info.nMax = max; + OS.SetScrollInfo (hwnd, type, info, true); + } else { + /* + * This line is intentionally commented. Currently + * always show scrollbar as being enabled and visible. + */ +// if (OS.IsWinCE) error (SWT.ERROR_NOT_IMPLEMENTED); + } + return; + } + + /* + * Set the state bits before calling ShowScrollBar () + * because hiding and showing the scroll bar can cause + * WM_SIZE messages when the client area is resized. + * Setting the state before the call means that code + * that runs during WM_SIZE that queries the visibility + * of the scroll bar will get the correct value. + */ + state &= ~HIDDEN; + if (!visible) state |= HIDDEN; + int hwnd = hwndScrollBar (), type = scrollBarType (); + if (OS.ShowScrollBar (hwnd, type, visible)) { + /* + * Bug in Windows. For some reason, when the widget + * is a standard scroll bar, and SetScrollInfo () is + * called with SIF_RANGE or SIF_PAGE while the widget + * is not visible, the widget is incorrectly disabled + * even though the values for SIF_RANGE and SIF_PAGE, + * when set for a visible scroll bar would not disable + * the scroll bar. The fix is to enable the scroll bar + * when not disabled by the application and the current + * scroll bar ranges would cause the scroll bar to be + * enabled had they been set when the scroll bar was + * visible. + */ + if ((state & DISABLED) == 0) { + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_RANGE | OS.SIF_PAGE; + OS.GetScrollInfo (hwnd, type, info); + if (info.nMax - info.nMin - info.nPage >= 0) { + OS.EnableScrollBar (hwnd, type, OS.ESB_ENABLE_BOTH); + } + } + sendEvent (visible ? SWT.Show : SWT.Hide); + // widget could be disposed at this point + } +} + +LRESULT wmScrollChild (int wParam, int lParam) { + + /* Do nothing when scrolling is ending */ + int code = wParam & 0xFFFF; + if (code == OS.SB_ENDSCROLL) return null; + + /* + * Send the event because WM_HSCROLL and + * WM_VSCROLL are sent from a modal message + * loop in Windows that is active when the + * user is scrolling. + */ + Event event = new Event (); + switch (code) { + /* + * This line is intentionally commented. Do not set the detail + * field to DRAG to indicate that the dragging has ended when the + * scroll bar is finally positioned in SB_THUMBPOSITION. + */ +// case OS.SB_THUMBPOSITION: break; + case OS.SB_THUMBTRACK: event.detail = SWT.DRAG; break; + case OS.SB_TOP: event.detail = SWT.HOME; break; + case OS.SB_BOTTOM: event.detail = SWT.END; break; + case OS.SB_LINEDOWN: event.detail = SWT.ARROW_DOWN; break; + case OS.SB_LINEUP: event.detail = SWT.ARROW_UP; break; + case OS.SB_PAGEDOWN: event.detail = SWT.PAGE_DOWN; break; + case OS.SB_PAGEUP: event.detail = SWT.PAGE_UP; break; + } + sendEvent (SWT.Selection, event); + // the widget could be destroyed at this point + return null; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Scrollable.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Scrollable.java index 00aff6bc5e..b6b542001a 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Scrollable.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Scrollable.java @@ -1,379 +1,379 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-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>
- */
-
-public abstract class Scrollable extends Control {
- ScrollBar horizontalBar, verticalBar;
-
-/**
- * Prevents uninitialized instances from being created outside the package.
- */
-Scrollable () {
-}
-
-/**
- * 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);
-}
-
-int callWindowProc (int msg, int wParam, int lParam) {
- if (handle == 0) return 0;
- return OS.DefWindowProc (handle, msg, wParam, lParam);
-}
-
-/**
- * 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>
- *
- * @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 ();
- RECT rect = new RECT ();
- OS.SetRect (rect, x, y, x + width, y + height);
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- OS.AdjustWindowRectEx (rect, bits, false, OS.GetWindowLong (handle, OS.GWL_EXSTYLE));
- if (horizontalBar != null) rect.bottom += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
- if (verticalBar != null) rect.right += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
- int nWidth = rect.right - rect.left, nHeight = rect.bottom - rect.top;
- return new Rectangle (rect.left, rect.top, nWidth, nHeight);
-}
-
-ScrollBar createScrollBar (int type) {
- ScrollBar bar = new ScrollBar (this, type);
- if ((state & CANVAS) != 0) {
- bar.setMaximum (100);
- bar.setThumb (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);
-}
-
-/**
- * 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 ();
- forceResize ();
- RECT rect = new RECT ();
- OS.GetClientRect (handle, rect);
- return new Rectangle (0, 0, rect.right, rect.bottom);
-}
-
-/**
- * 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;
-}
-
-void releaseWidget () {
- if (horizontalBar != null) horizontalBar.releaseResources ();
- if (verticalBar != null) verticalBar.releaseResources ();
- horizontalBar = verticalBar = null;
- super.releaseWidget ();
-}
-
-int widgetExtStyle () {
- return super.widgetExtStyle ();
- /*
- * This code is intentionally commented. In future,
- * we may wish to support different standard Windows
- * edge styles. The issue here is that not all of
- * these styles are available on the other platforms
- * this would need to be a hint.
- */
-// if ((style & SWT.BORDER) != 0) return OS.WS_EX_CLIENTEDGE;
-// if ((style & SWT.SHADOW_IN) != 0) return OS.WS_EX_STATICEDGE;
-// return super.widgetExtStyle ();
-}
-
-int widgetStyle () {
- int bits = super.widgetStyle () | OS.WS_TABSTOP;
- if ((style & SWT.H_SCROLL) != 0) bits |= OS.WS_HSCROLL;
- if ((style & SWT.V_SCROLL) != 0) bits |= OS.WS_VSCROLL;
- return bits;
-}
-
-TCHAR windowClass () {
- return getDisplay ().windowClass;
-}
-
-int windowProc () {
- return getDisplay ().windowProc;
-}
-
-LRESULT WM_HSCROLL (int wParam, int lParam) {
- LRESULT result = super.WM_HSCROLL (wParam, lParam);
- if (result != null) return result;
-
- /*
- * Bug on WinCE. lParam should be NULL when the message is not sent
- * by a scroll bar control, but it contains the handle to the window.
- * When the message is sent by a scroll bar control, it correctly
- * contains the handle to the scroll bar. The fix is to check for
- * both.
- */
- if ((lParam == 0 || lParam == handle) && horizontalBar != null) {
- return wmScroll (horizontalBar, OS.WM_HSCROLL, wParam, lParam);
- }
- return result;
-}
-
-LRESULT WM_MOUSEWHEEL (int wParam, int lParam) {
- LRESULT result = super.WM_MOUSEWHEEL (wParam, lParam);
- if (result != null) return result;
-
- /*
- * Translate WM_MOUSEWHEEL to WM_VSCROLL or WM_HSCROLL.
- */
- if ((state & CANVAS) != 0) {
- if ((wParam & (OS.MK_SHIFT | OS.MK_CONTROL)) != 0) return result;
- boolean vertical = verticalBar != null && verticalBar.getEnabled ();
- boolean horizontal = horizontalBar != null && horizontalBar.getEnabled ();
- int msg = (vertical) ? OS.WM_VSCROLL : (horizontal) ? OS.WM_HSCROLL : 0;
- if (msg == 0) return result;
- int [] value = new int [1];
- OS.SystemParametersInfo (OS.SPI_GETWHEELSCROLLLINES, 0, value, 0);
- int delta = (short) (wParam >> 16);
- int code = 0, count = 0;
- if (value [0] == OS.WHEEL_PAGESCROLL) {
- code = delta < 0 ? OS.SB_PAGEDOWN : OS.SB_PAGEUP;
- count = 1;
- } else {
- code = delta < 0 ? OS.SB_LINEDOWN : OS.SB_LINEUP;
- delta = Math.abs (delta);
- if (delta < OS.WHEEL_DELTA) return result;
- if (msg == OS.WM_VSCROLL) {
- count = value [0] * delta / OS.WHEEL_DELTA;
- } else {
- count = delta / OS.WHEEL_DELTA;
- }
- }
- for (int i=0; i<count; i++) {
- OS.SendMessage (handle, msg, code, 0);
- }
- return LRESULT.ZERO;
- }
-
- /*
- * When the native widget scrolls inside WM_MOUSEWHEEL, it
- * may or may not send a WM_VSCROLL or WM_HSCROLL to do the
- * actual scrolling. This depends on the implementation of
- * each native widget. In order to ensure that application
- * code is notified when the scroll bar moves, compare the
- * scroll bar position before and after the WM_MOUSEWHEEL.
- * If the native control sends a WM_VSCROLL or WM_HSCROLL,
- * then the application has already been notified. If not
- * explicity send the event.
- */
- int vPosition = verticalBar == null ? 0 : verticalBar.getSelection ();
- int hPosition = horizontalBar == null ? 0 : horizontalBar.getSelection ();
- int code = callWindowProc (OS.WM_MOUSEWHEEL, wParam, lParam);
- if (verticalBar != null) {
- int position = verticalBar.getSelection ();
- if (position != vPosition) {
- Event event = new Event ();
- event.detail = position < vPosition ? SWT.PAGE_UP : SWT.PAGE_DOWN;
- verticalBar.sendEvent (SWT.Selection, event);
- }
- }
- if (horizontalBar != null) {
- int position = horizontalBar.getSelection ();
- if (position != hPosition) {
- Event event = new Event ();
- event.detail = position < hPosition ? SWT.PAGE_UP : SWT.PAGE_DOWN;
- horizontalBar.sendEvent (SWT.Selection, event);
- }
- }
- return new LRESULT (code);
-}
-
-LRESULT WM_SIZE (int wParam, int lParam) {
- int code = callWindowProc (OS.WM_SIZE, wParam, lParam);
- super.WM_SIZE (wParam, lParam);
- // widget may be disposed at this point
- if (code == 0) return LRESULT.ZERO;
- return new LRESULT (code);
-}
-
-LRESULT WM_VSCROLL (int wParam, int lParam) {
- LRESULT result = super.WM_VSCROLL (wParam, lParam);
- if (result != null) return result;
-
- /*
- * Bug on WinCE. lParam should be NULL when the message is not sent
- * by a scroll bar control, but it contains the handle to the window.
- * When the message is sent by a scroll bar control, it correctly
- * contains the handle to the scroll bar. The fix is to check for
- * both.
- */
- if ((lParam == 0 || lParam == handle) && verticalBar != null) {
- return wmScroll (verticalBar, OS.WM_VSCROLL, wParam, lParam);
- }
- return result;
-}
-
-LRESULT wmScroll (ScrollBar bar, int msg, int wParam, int lParam) {
- LRESULT result = null;
- if ((state & CANVAS) != 0) {
- int type = msg == OS.WM_HSCROLL ? OS.SB_HORZ : OS.SB_VERT;
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_TRACKPOS | OS.SIF_POS | OS.SIF_RANGE;
- OS.GetScrollInfo (handle, type, info);
- info.fMask = OS.SIF_POS;
- int code = wParam & 0xFFFF;
- switch (code) {
- case OS.SB_ENDSCROLL: return null;
- case OS.SB_THUMBTRACK:
- case OS.SB_THUMBPOSITION:
- /*
- * Note: On WinCE, the value in SB_THUMBPOSITION is relative to nMin.
- * Same for SB_THUMBPOSITION 'except' for the very first thumb track
- * message which has the actual value of nMin. This is a problem when
- * nMin is not zero.
- */
- info.nPos = info.nTrackPos;
- break;
- case OS.SB_TOP:
- info.nPos = info.nMin;
- break;
- case OS.SB_BOTTOM:
- info.nPos = info.nMax;
- break;
- case OS.SB_LINEDOWN:
- info.nPos += bar.getIncrement ();
- break;
- case OS.SB_LINEUP:
- int increment = bar.getIncrement ();
- info.nPos = Math.max (info.nMin, info.nPos - increment);
- break;
- case OS.SB_PAGEDOWN:
- info.nPos += bar.getPageIncrement ();
- break;
- case OS.SB_PAGEUP:
- int pageIncrement = bar.getPageIncrement ();
- info.nPos = Math.max (info.nMin, info.nPos - pageIncrement);
- break;
- }
- OS.SetScrollInfo (handle, type, info, true);
- } else {
- int code = callWindowProc (msg, wParam, lParam);
- result = code == 0 ? LRESULT.ZERO : new LRESULT (code);
- }
- bar.wmScrollChild (wParam, lParam);
- return result;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +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> + */ + +public abstract class Scrollable extends Control { + ScrollBar horizontalBar, verticalBar; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Scrollable () { +} + +/** + * 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); +} + +int callWindowProc (int msg, int wParam, int lParam) { + if (handle == 0) return 0; + return OS.DefWindowProc (handle, msg, wParam, lParam); +} + +/** + * 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> + * + * @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 (); + RECT rect = new RECT (); + OS.SetRect (rect, x, y, x + width, y + height); + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + OS.AdjustWindowRectEx (rect, bits, false, OS.GetWindowLong (handle, OS.GWL_EXSTYLE)); + if (horizontalBar != null) rect.bottom += OS.GetSystemMetrics (OS.SM_CYHSCROLL); + if (verticalBar != null) rect.right += OS.GetSystemMetrics (OS.SM_CXVSCROLL); + int nWidth = rect.right - rect.left, nHeight = rect.bottom - rect.top; + return new Rectangle (rect.left, rect.top, nWidth, nHeight); +} + +ScrollBar createScrollBar (int type) { + ScrollBar bar = new ScrollBar (this, type); + if ((state & CANVAS) != 0) { + bar.setMaximum (100); + bar.setThumb (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); +} + +/** + * 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 (); + forceResize (); + RECT rect = new RECT (); + OS.GetClientRect (handle, rect); + return new Rectangle (0, 0, rect.right, rect.bottom); +} + +/** + * 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; +} + +void releaseWidget () { + if (horizontalBar != null) horizontalBar.releaseResources (); + if (verticalBar != null) verticalBar.releaseResources (); + horizontalBar = verticalBar = null; + super.releaseWidget (); +} + +int widgetExtStyle () { + return super.widgetExtStyle (); + /* + * This code is intentionally commented. In future, + * we may wish to support different standard Windows + * edge styles. The issue here is that not all of + * these styles are available on the other platforms + * this would need to be a hint. + */ +// if ((style & SWT.BORDER) != 0) return OS.WS_EX_CLIENTEDGE; +// if ((style & SWT.SHADOW_IN) != 0) return OS.WS_EX_STATICEDGE; +// return super.widgetExtStyle (); +} + +int widgetStyle () { + int bits = super.widgetStyle () | OS.WS_TABSTOP; + if ((style & SWT.H_SCROLL) != 0) bits |= OS.WS_HSCROLL; + if ((style & SWT.V_SCROLL) != 0) bits |= OS.WS_VSCROLL; + return bits; +} + +TCHAR windowClass () { + return getDisplay ().windowClass; +} + +int windowProc () { + return getDisplay ().windowProc; +} + +LRESULT WM_HSCROLL (int wParam, int lParam) { + LRESULT result = super.WM_HSCROLL (wParam, lParam); + if (result != null) return result; + + /* + * Bug on WinCE. lParam should be NULL when the message is not sent + * by a scroll bar control, but it contains the handle to the window. + * When the message is sent by a scroll bar control, it correctly + * contains the handle to the scroll bar. The fix is to check for + * both. + */ + if ((lParam == 0 || lParam == handle) && horizontalBar != null) { + return wmScroll (horizontalBar, OS.WM_HSCROLL, wParam, lParam); + } + return result; +} + +LRESULT WM_MOUSEWHEEL (int wParam, int lParam) { + LRESULT result = super.WM_MOUSEWHEEL (wParam, lParam); + if (result != null) return result; + + /* + * Translate WM_MOUSEWHEEL to WM_VSCROLL or WM_HSCROLL. + */ + if ((state & CANVAS) != 0) { + if ((wParam & (OS.MK_SHIFT | OS.MK_CONTROL)) != 0) return result; + boolean vertical = verticalBar != null && verticalBar.getEnabled (); + boolean horizontal = horizontalBar != null && horizontalBar.getEnabled (); + int msg = (vertical) ? OS.WM_VSCROLL : (horizontal) ? OS.WM_HSCROLL : 0; + if (msg == 0) return result; + int [] value = new int [1]; + OS.SystemParametersInfo (OS.SPI_GETWHEELSCROLLLINES, 0, value, 0); + int delta = (short) (wParam >> 16); + int code = 0, count = 0; + if (value [0] == OS.WHEEL_PAGESCROLL) { + code = delta < 0 ? OS.SB_PAGEDOWN : OS.SB_PAGEUP; + count = 1; + } else { + code = delta < 0 ? OS.SB_LINEDOWN : OS.SB_LINEUP; + delta = Math.abs (delta); + if (delta < OS.WHEEL_DELTA) return result; + if (msg == OS.WM_VSCROLL) { + count = value [0] * delta / OS.WHEEL_DELTA; + } else { + count = delta / OS.WHEEL_DELTA; + } + } + for (int i=0; i<count; i++) { + OS.SendMessage (handle, msg, code, 0); + } + return LRESULT.ZERO; + } + + /* + * When the native widget scrolls inside WM_MOUSEWHEEL, it + * may or may not send a WM_VSCROLL or WM_HSCROLL to do the + * actual scrolling. This depends on the implementation of + * each native widget. In order to ensure that application + * code is notified when the scroll bar moves, compare the + * scroll bar position before and after the WM_MOUSEWHEEL. + * If the native control sends a WM_VSCROLL or WM_HSCROLL, + * then the application has already been notified. If not + * explicity send the event. + */ + int vPosition = verticalBar == null ? 0 : verticalBar.getSelection (); + int hPosition = horizontalBar == null ? 0 : horizontalBar.getSelection (); + int code = callWindowProc (OS.WM_MOUSEWHEEL, wParam, lParam); + if (verticalBar != null) { + int position = verticalBar.getSelection (); + if (position != vPosition) { + Event event = new Event (); + event.detail = position < vPosition ? SWT.PAGE_UP : SWT.PAGE_DOWN; + verticalBar.sendEvent (SWT.Selection, event); + } + } + if (horizontalBar != null) { + int position = horizontalBar.getSelection (); + if (position != hPosition) { + Event event = new Event (); + event.detail = position < hPosition ? SWT.PAGE_UP : SWT.PAGE_DOWN; + horizontalBar.sendEvent (SWT.Selection, event); + } + } + return new LRESULT (code); +} + +LRESULT WM_SIZE (int wParam, int lParam) { + int code = callWindowProc (OS.WM_SIZE, wParam, lParam); + super.WM_SIZE (wParam, lParam); + // widget may be disposed at this point + if (code == 0) return LRESULT.ZERO; + return new LRESULT (code); +} + +LRESULT WM_VSCROLL (int wParam, int lParam) { + LRESULT result = super.WM_VSCROLL (wParam, lParam); + if (result != null) return result; + + /* + * Bug on WinCE. lParam should be NULL when the message is not sent + * by a scroll bar control, but it contains the handle to the window. + * When the message is sent by a scroll bar control, it correctly + * contains the handle to the scroll bar. The fix is to check for + * both. + */ + if ((lParam == 0 || lParam == handle) && verticalBar != null) { + return wmScroll (verticalBar, OS.WM_VSCROLL, wParam, lParam); + } + return result; +} + +LRESULT wmScroll (ScrollBar bar, int msg, int wParam, int lParam) { + LRESULT result = null; + if ((state & CANVAS) != 0) { + int type = msg == OS.WM_HSCROLL ? OS.SB_HORZ : OS.SB_VERT; + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_TRACKPOS | OS.SIF_POS | OS.SIF_RANGE; + OS.GetScrollInfo (handle, type, info); + info.fMask = OS.SIF_POS; + int code = wParam & 0xFFFF; + switch (code) { + case OS.SB_ENDSCROLL: return null; + case OS.SB_THUMBTRACK: + case OS.SB_THUMBPOSITION: + /* + * Note: On WinCE, the value in SB_THUMBPOSITION is relative to nMin. + * Same for SB_THUMBPOSITION 'except' for the very first thumb track + * message which has the actual value of nMin. This is a problem when + * nMin is not zero. + */ + info.nPos = info.nTrackPos; + break; + case OS.SB_TOP: + info.nPos = info.nMin; + break; + case OS.SB_BOTTOM: + info.nPos = info.nMax; + break; + case OS.SB_LINEDOWN: + info.nPos += bar.getIncrement (); + break; + case OS.SB_LINEUP: + int increment = bar.getIncrement (); + info.nPos = Math.max (info.nMin, info.nPos - increment); + break; + case OS.SB_PAGEDOWN: + info.nPos += bar.getPageIncrement (); + break; + case OS.SB_PAGEUP: + int pageIncrement = bar.getPageIncrement (); + info.nPos = Math.max (info.nMin, info.nPos - pageIncrement); + break; + } + OS.SetScrollInfo (handle, type, info, true); + } else { + int code = callWindowProc (msg, wParam, lParam); + result = code == 0 ? LRESULT.ZERO : new LRESULT (code); + } + bar.wmScrollChild (wParam, lParam); + return result; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Shell.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Shell.java index 358a1e033c..6341d5eeb6 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Shell.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Shell.java @@ -1,1362 +1,1362 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.events.*;
-
-/**
- * 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>
- * 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
- * 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>.
- * <dl>
- * <dt><b>Styles:</b></dt>
- * <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE</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
- */
-public class Shell extends Decorations {
- Display display;
- Menu activeMenu;
- int hIMC;
- int [] brushes;
- boolean showWithParent;
- int toolTipHandle, lpstrTip;
- Control lastActive;
- SHACTIVATEINFO psai;
- static final int DialogProc;
- static final TCHAR DialogClass = new TCHAR (0, OS.IsWinCE ? "Dialog" : "#32770", true);
- static {
- WNDCLASS lpWndClass = new WNDCLASS ();
- OS.GetClassInfo (0, DialogClass, lpWndClass);
- DialogProc = lpWndClass.lpfnWndProc;
- }
-
-/**
- * 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#NO_TRIM
- * @see SWT#SHELL_TRIM
- * @see SWT#DIALOG_TRIM
- * @see SWT#MODELESS
- * @see SWT#PRIMARY_MODAL
- * @see SWT#APPLICATION_MODAL
- * @see SWT#SYSTEM_MODAL
- */
-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, OS.IsWinCE ? SWT.NONE : 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#NO_TRIM
- * @see SWT#SHELL_TRIM
- * @see SWT#DIALOG_TRIM
- * @see SWT#MODELESS
- * @see SWT#PRIMARY_MODAL
- * @see SWT#APPLICATION_MODAL
- * @see SWT#SYSTEM_MODAL
- */
-public Shell (Display display, int style) {
- this (display, null, style, 0);
-}
-
-Shell (Display display, Shell parent, int style, int handle) {
- super ();
- checkSubclass ();
- 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.parent = parent;
- this.display = display;
- this.handle = 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_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 Shell (Shell parent) {
- this (parent, OS.IsWinCE ? SWT.NONE : 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 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#MODELESS
- * @see SWT#PRIMARY_MODAL
- * @see SWT#APPLICATION_MODAL
- * @see SWT#SYSTEM_MODAL
- */
-public Shell (Shell parent, int style) {
- this (parent != null ? parent.getDisplay () : null, parent, style, 0);
-}
-
-/**
- * Invokes platform specific functionality to allocate a new shell.
- * <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
- *
- * @private
- */
-public static Shell win32_new (Display display, int handle) {
- return new Shell (display, null, SWT.NO_TRIM, handle);
-}
-
-static int checkStyle (int style) {
- style = Decorations.checkStyle (style);
- int mask = SWT.SYSTEM_MODAL | 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;
-}
-
-/**
- * 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.Close,typedListener);
- addListener (SWT.Iconify,typedListener);
- addListener (SWT.Deiconify,typedListener);
- addListener (SWT.Activate, typedListener);
- addListener (SWT.Deactivate, typedListener);
-}
-
-int callWindowProc (int msg, int wParam, int lParam) {
- if (parent != null) {
- if (handle == 0) return 0;
- switch (msg) {
- case OS.WM_KILLFOCUS:
- case OS.WM_SETFOCUS:
- return OS.DefWindowProc (handle, msg, wParam, lParam);
- }
- return OS.CallWindowProc (DialogProc, handle, msg, wParam, lParam);
- }
- return super.callWindowProc (msg, wParam, lParam);
-}
-
-/**
- * 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 #dispose
- */
-public void close () {
- checkWidget ();
- OS.PostMessage (handle, OS.WM_CLOSE, 0, 0);
-}
-
-void createHandle () {
- boolean embedded = handle != 0;
-
- /*
- * On Windows 98 and NT, setting a window to be the
- * top most window using HWND_TOPMOST can result in a
- * parent dialog shell being moved behind its parent
- * if the dialog has a sibling that is currently on top
- * This only occurs using SetWindowPos (), not when the
- * handle is created.
- */
- /*
- * The following code is intentionally commented.
- */
-// if ((style & SWT.ON_TOP) != 0) display.lockActiveWindow = true;
- super.createHandle ();
- /*
- * The following code is intentionally commented.
- */
-// if ((style & SWT.ON_TOP) != 0) display.lockActiveWindow = false;
-
- if (!embedded) {
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- bits &= ~(OS.WS_OVERLAPPED | OS.WS_CAPTION);
- if (!OS.IsWinCE) bits |= OS.WS_POPUP;
- if ((style & SWT.TITLE) != 0) bits |= OS.WS_CAPTION;
- if ((style & SWT.NO_TRIM) == 0) {
- if ((style & (SWT.BORDER | SWT.RESIZE)) == 0) bits |= OS.WS_BORDER;
- }
- OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
- if (OS.IsWinCE) setMaximized (true);
- if (OS.IsPPC) {
- psai = new SHACTIVATEINFO ();
- psai.cbSize = SHACTIVATEINFO.sizeof;
- }
- }
- if (OS.IsDBLocale) {
- hIMC = OS.ImmCreateContext ();
- if (hIMC != 0) OS.ImmAssociateContext (handle, hIMC);
- }
-}
-
-public void dispose () {
- /*
- * This code is intentionally commented. On some
- * platforms, the owner window is repainted right
- * away when a dialog window exits. This behavior
- * is currently unspecified.
- */
-// /*
-// * Note: It is valid to attempt to dispose a widget
-// * more than once. If this happens, fail silently.
-// */
-// if (!isValidWidget ()) return;
-// if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
-// Display oldDisplay = display;
- super.dispose ();
- // widget is disposed at this point
-// if (oldDisplay != null) oldDisplay.update ();
-}
-
-int findBrush (int pixel) {
- if (pixel == OS.GetSysColor (OS.COLOR_BTNFACE)) {
- return OS.GetSysColorBrush (OS.COLOR_BTNFACE);
- }
- if (pixel == OS.GetSysColor (OS.COLOR_WINDOW)) {
- return OS.GetSysColorBrush (OS.COLOR_WINDOW);
- }
- if (brushes == null) brushes = new int [4];
- LOGBRUSH logBrush = new LOGBRUSH ();
- for (int i=0; i<brushes.length; i++) {
- int hBrush = brushes [i];
- if (hBrush == 0) break;
- OS.GetObject (hBrush, LOGBRUSH.sizeof, logBrush);
- if (logBrush.lbColor == pixel) return hBrush;
- }
- int length = brushes.length;
- int hBrush = brushes [--length];
- if (hBrush != 0) OS.DeleteObject (hBrush);
- System.arraycopy (brushes, 0, brushes, 1, length);
- brushes [0] = hBrush = OS.CreateSolidBrush (pixel);
- return hBrush;
-}
-
-int findCursor () {
- return hCursor;
-}
-
-/**
- * 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) 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
- * @see Shell#open
- * @see Shell#setActive
- */
-public void forceActive () {
- checkWidget ();
- OS.SetForegroundWindow (handle);
-}
-
-void forceResize () {
- /* Do nothing */
-}
-
-public Rectangle getBounds () {
- checkWidget ();
- if (!OS.IsWinCE) {
- if (OS.IsIconic (handle)) return super.getBounds ();
- }
- RECT rect = new RECT ();
- OS.GetWindowRect (handle, rect);
- int width = rect.right - rect.left;
- int height = rect.bottom - rect.top;
- return new Rectangle (rect.left, rect.top, width, height);
-}
-
-public Display getDisplay () {
- if (display == null) error (SWT.ERROR_WIDGET_DISPOSED);
- return display;
-}
-
-public boolean getEnabled () {
- checkWidget ();
- return (state & DISABLED) == 0;
-}
-
-/**
- * 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 ();
- if (!OS.IsDBLocale) return 0;
- int hIMC = OS.ImmGetContext (handle);
- int [] lpfdwConversion = new int [1], lpfdwSentence = new int [1];
- boolean open = OS.ImmGetOpenStatus (hIMC);
- if (open) open = OS.ImmGetConversionStatus (hIMC, lpfdwConversion, lpfdwSentence);
- OS.ImmReleaseContext (handle, hIMC);
- if (!open) return SWT.NONE;
- int result = 0;
- if ((lpfdwConversion [0] & OS.IME_CMODE_ROMAN) != 0) result |= SWT.ROMAN;
- if ((lpfdwConversion [0] & OS.IME_CMODE_FULLSHAPE) != 0) result |= SWT.DBCS;
- if ((lpfdwConversion [0] & OS.IME_CMODE_KATAKANA) != 0) return result | SWT.PHONETIC;
- if ((lpfdwConversion [0] & OS.IME_CMODE_NATIVE) != 0) return result | SWT.NATIVE;
- return result | SWT.ALPHA;
-}
-
-public Point getLocation () {
- checkWidget ();
- if (!OS.IsWinCE) {
- if (OS.IsIconic (handle)) {
- return super.getLocation ();
- }
- }
- RECT rect = new RECT ();
- OS.GetWindowRect (handle, rect);
- return new Point (rect.left, rect.top);
-}
-
-public Shell getShell () {
- checkWidget ();
- return this;
-}
-
-/**
- * Returns an array containing all shells which are
- * descendents 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 boolean isEnabled () {
- checkWidget ();
- return getEnabled ();
-}
-
-/**
- * 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,
- * and sets focus to its default button (if it has one)
- * 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
- * @see Shell#setActive
- * @see Shell#forceActive
- */
-public void open () {
- checkWidget ();
- bringToTop ();
- /*
- * Feature on WinCE PPC. A new application becomes
- * the foreground application only if it has at least
- * one visible window before the event loop is started.
- * The workaround is to explicitely force the shell to
- * be the foreground window.
- */
- if (OS.IsWinCE) OS.SetForegroundWindow (handle);
- OS.SendMessage (handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
- setVisible (true);
- /*
- * Bug in Windows XP. Despite the fact that an icon has been
- * set for a window, the task bar displays the wrong icon the
- * first time the window is made visible with ShowWindow() after
- * a call to BringToTop(), when a long time elapses between the
- * ShowWindow() and the time the event queue is read. The icon
- * in the window trimming is correct but the one in the task
- * bar does not get updated until a new icon is set into the
- * window or the window text is changed. The fix is to call
- * PeekMessage() with the flag PM_NOREMOVE to touch the event
- * queue but not dispatch events.
- */
- MSG msg = new MSG ();
- OS.PeekMessage (msg, 0, 0, 0, OS.PM_NOREMOVE);
- if (!restoreFocus ()) traverseGroup (true);
-}
-
-void releaseShells () {
- Shell [] shells = getShells ();
- for (int i=0; i<shells.length; i++) {
- Shell shell = shells [i];
- if (!shell.isDisposed ()) shell.releaseResources ();
- }
-}
-
-void releaseWidget () {
- releaseShells ();
- super.releaseWidget ();
- activeMenu = null;
- display.clearModal (this);
- display = null;
- if (lpstrTip != 0) {
- int hHeap = OS.GetProcessHeap ();
- OS.HeapFree (hHeap, 0, lpstrTip);
- }
- lpstrTip = 0;
- toolTipHandle = 0;
- if (brushes != null) {
- for (int i=0; i<brushes.length; i++) {
- int hBrush = brushes [i];
- if (hBrush != 0) OS.DeleteObject (hBrush);
- }
- }
- brushes = null;
- if (OS.IsDBLocale) {
- if (hIMC != 0) OS.ImmDestroyContext (hIMC);
- }
- lastActive = null;
-}
-
-void remove (Menu menu) {
- super.remove (menu);
- if (menu == activeMenu) activeMenu = 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.Close, listener);
- eventTable.unhook (SWT.Iconify,listener);
- eventTable.unhook (SWT.Deiconify,listener);
- eventTable.unhook (SWT.Activate, listener);
- eventTable.unhook (SWT.Deactivate, listener);
-}
-
-LRESULT selectPalette (int hPalette) {
- int hDC = OS.GetDC (handle);
- int hOld = OS.SelectPalette (hDC, hPalette, false);
- int result = OS.RealizePalette (hDC);
- if (result > 0) {
- OS.InvalidateRect (handle, null, true);
- } else {
- OS.SelectPalette (hDC, hOld, true);
- OS.RealizePalette (hDC);
- }
- OS.ReleaseDC (handle, hDC);
- return (result > 0) ? LRESULT.ONE : LRESULT.ZERO;
-}
-
-/**
- * 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) 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
- * @see Shell#open
- * @see Shell#setActive
- */
-public void setActive () {
- checkWidget ();
- bringToTop ();
-}
-
-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);
- }
- }
-}
-
-void setBounds (int x, int y, int width, int height, int flags) {
- if (OS.IsWinCE) {
- swFlags = OS.SW_RESTORE;
- if ((style & SWT.NO_TRIM) == 0) {
- /* Set the WS_CAPTION bits when no longer maximized */
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & OS.WS_CAPTION) != OS.WS_CAPTION) {
- bits |= OS.WS_CAPTION;
- OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
- }
- }
- } else {
- if (OS.IsIconic (handle) || OS.IsZoomed (handle)) {
- setPlacement (x, y, width, height, flags);
- return;
- }
- }
- OS.SetWindowPos (handle, 0, x, y, width, height, flags);
-}
-
-public void setEnabled (boolean enabled) {
- checkWidget ();
- state &= ~DISABLED;
- if (!enabled) state |= DISABLED;
- if (!Display.TrimEnabled) {
- super.setEnabled (enabled);
- } else {
- if (isActive ()) setItemEnabled (OS.SC_CLOSE, enabled);
- }
-}
-
-/**
- * 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 ();
- if (!OS.IsDBLocale) return;
- boolean imeOn = mode != SWT.NONE && mode != SWT.ROMAN;
- int hIMC = OS.ImmGetContext (handle);
- OS.ImmSetOpenStatus (hIMC, imeOn);
- if (imeOn) {
- int [] lpfdwConversion = new int [1], lpfdwSentence = new int [1];
- if (OS.ImmGetConversionStatus (hIMC, lpfdwConversion, lpfdwSentence)) {
- int newBits = 0;
- int oldBits = OS.IME_CMODE_NATIVE | OS.IME_CMODE_KATAKANA;
- if ((mode & SWT.PHONETIC) != 0) {
- newBits = OS.IME_CMODE_KATAKANA | OS.IME_CMODE_NATIVE;
- oldBits = 0;
- } else {
- if ((mode & SWT.NATIVE) != 0) {
- newBits = OS.IME_CMODE_NATIVE;
- oldBits = OS.IME_CMODE_KATAKANA;
- }
- }
- if ((mode & SWT.DBCS) != 0) {
- newBits |= OS.IME_CMODE_FULLSHAPE;
- } else {
- oldBits |= OS.IME_CMODE_FULLSHAPE;
- }
- if ((mode & SWT.ROMAN) != 0) {
- newBits |= OS.IME_CMODE_ROMAN;
- } else {
- oldBits |= OS.IME_CMODE_ROMAN;
- }
- lpfdwConversion [0] |= newBits; lpfdwConversion [0] &= ~oldBits;
- OS.ImmSetConversionStatus (hIMC, lpfdwConversion [0], lpfdwSentence [0]);
- }
- }
- OS.ImmReleaseContext (handle, hIMC);
-}
-
-void setItemEnabled (int cmd, boolean enabled) {
- int hMenu = OS.GetSystemMenu (handle, false);
- if (hMenu == 0) return;
- int flags = OS.MF_ENABLED;
- if (!enabled) flags = OS.MF_DISABLED | OS.MF_GRAYED;
- OS.EnableMenuItem (hMenu, cmd, OS.MF_BYCOMMAND | flags);
-}
-
-void setParent () {
- /* Do nothing. Not necessary for Shells */
-}
-
-void setToolTipText (int hwnd, String text) {
- if (OS.IsWinCE) return;
- if (toolTipHandle == 0) {
- toolTipHandle = OS.CreateWindowEx (
- 0,
- new TCHAR (0, OS.TOOLTIPS_CLASS, true),
- null,
- OS.TTS_ALWAYSTIP,
- OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
- handle,
- 0,
- OS.GetModuleHandle (null),
- null);
- if (toolTipHandle == 0) error (SWT.ERROR_NO_HANDLES);
- /*
- * Feature in Windows. Despite the fact that the
- * tool tip text contains \r\n, the tooltip will
- * not honour the new line unless TTM_SETMAXTIPWIDTH
- * is set. The fix is to set TTM_SETMAXTIPWIDTH to
- * a large value.
- */
- OS.SendMessage (toolTipHandle, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
- }
- TOOLINFO lpti = new TOOLINFO ();
- lpti.cbSize = TOOLINFO.sizeof;
- lpti.uId = hwnd;
- lpti.hwnd = handle;
- if (text == null) {
- OS.SendMessage (toolTipHandle, OS.TTM_DELTOOL, 0, lpti);
- } else {
- lpti.uFlags = OS.TTF_IDISHWND | OS.TTF_SUBCLASS;
- lpti.lpszText = OS.LPSTR_TEXTCALLBACK;
- OS.SendMessage (toolTipHandle, OS.TTM_ADDTOOL, 0, lpti);
- }
- OS.SendMessage (toolTipHandle, OS.TTM_UPDATE, 0, 0);
-}
-
-void setToolTipText (NMTTDISPINFO lpnmtdi, byte [] buffer) {
- /*
- * Ensure that the current position of the mouse
- * is inside the client area of the shell. This
- * prevents tool tips from popping up over the
- * shell trimmings.
- */
- if (!hasCursor ()) return;
- int hHeap = OS.GetProcessHeap ();
- if (lpstrTip != 0) OS.HeapFree (hHeap, 0, lpstrTip);
- int byteCount = buffer.length;
- lpstrTip = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- OS.MoveMemory (lpstrTip, buffer, byteCount);
- lpnmtdi.lpszText = lpstrTip;
-}
-
-void setToolTipText (NMTTDISPINFO lpnmtdi, char [] buffer) {
- /*
- * Ensure that the current position of the mouse
- * is inside the client area of the shell. This
- * prevents tool tips from popping up over the
- * shell trimmings.
- */
- if (!hasCursor ()) return;
- int hHeap = OS.GetProcessHeap ();
- if (lpstrTip != 0) OS.HeapFree (hHeap, 0, lpstrTip);
- int byteCount = buffer.length * 2;
- lpstrTip = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- OS.MoveMemory (lpstrTip, buffer, byteCount);
- lpnmtdi.lpszText = lpstrTip;
-}
-
-public void setVisible (boolean visible) {
- checkWidget ();
- super.setVisible (visible);
- if (showWithParent == visible) return;
- showWithParent = visible;
- if (!OS.IsWinCE) OS.ShowOwnedPopups (handle, visible);
- int mask = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL;
- if ((style & mask) != 0) {
- if (visible) {
- display.setModalShell (this);
- Control control = display.getFocusControl ();
- if (control != null && !control.isActive ()) bringToTop ();
- int hwndShell = OS.GetActiveWindow ();
- if (hwndShell == 0) {
- if (parent != null) hwndShell = parent.handle;
- }
- if (hwndShell != 0) {
- OS.SendMessage (hwndShell, OS.WM_CANCELMODE, 0, 0);
- }
- OS.ReleaseCapture ();
- } else {
- display.clearModal (this);
- }
- } else {
- updateModal ();
- }
-}
-
-boolean traverseEscape () {
- if (parent == null) return false;
- if (!isVisible () || !isEnabled ()) return false;
- close ();
- return true;
-}
-
-void updateModal () {
- if (!Display.TrimEnabled) {
- super.setEnabled (isActive ());
- } else {
- setItemEnabled (OS.SC_CLOSE, isActive ());
- }
-}
-
-int widgetExtStyle () {
- int bits = super.widgetExtStyle ();
- /*
- * Bug in Windows 98 and NT. Creating a window with the
- * WS_EX_TOPMOST extendes style can result in a dialog shell
- * being moved behind its parent. The exact case where this
- * happens is a shell with two dialog shell children where
- * each dialog child has another hidden dialog child with
- * the WS_EX_TOPMOST extended style. Clicking on either of
- * the visible dialog causes them to become active but move
- * to the back, behind the parent shell. The fix is to
- * disallow the WS_EX_TOPMOST extended style on Windows 98
- * and NT.
- */
- if (OS.IsWin95) return bits;
- if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) < (4 << 16 | 10)) {
- return bits;
- }
- if ((style & SWT.ON_TOP) != 0) bits |= OS.WS_EX_TOPMOST;
- return bits;
-}
-
-TCHAR windowClass () {
- if (OS.IsSP) return DialogClass;
- return parent != null ? DialogClass : super.windowClass ();
-}
-
-int windowProc () {
- if (OS.IsSP) return DialogProc;
- return parent != null ? DialogProc : super.windowProc ();
-}
-
-int widgetStyle () {
- int bits = super.widgetStyle () & ~OS.WS_POPUP;
- if (handle != 0) return bits | OS.WS_CHILD;
- bits &= ~OS.WS_CHILD;
- /*
- * Feature in WinCE. Calling CreateWindowEx () with WS_OVERLAPPED
- * and a parent window causes the new window to become a WS_CHILD of
- * the parent instead of a dialog child. The fix is to use WS_POPUP
- * for a window with a parent.
- *
- * Feature in WinCE PPC. A window without a parent with WS_POPUP
- * always shows on top of the Pocket PC 'Today Screen'. The fix
- * is to not set WS_POPUP for a window without a parent on WinCE
- * devices.
- *
- * NOTE: WS_POPUP causes CreateWindowEx () to ignore CW_USEDEFAULT
- * and causes the default window location and size to be zero.
- */
- if (OS.IsWinCE) {
- if (OS.IsSP) return bits | OS.WS_POPUP;
- return parent == null ? bits : bits | OS.WS_POPUP;
- }
-
- /*
- * Use WS_OVERLAPPED for all windows, either dialog or top level
- * so that CreateWindowEx () will respect CW_USEDEFAULT and set
- * the default window location and size.
- *
- * NOTE: When a WS_OVERLAPPED window is created, Windows gives
- * the new window WS_CAPTION style bits. These two constants are
- * as follows:
- *
- * WS_OVERLAPPED = 0
- * WS_CAPTION = WS_BORDER | WS_DLGFRAME
- *
- */
- return bits | OS.WS_OVERLAPPED | OS.WS_CAPTION;
-}
-
-LRESULT WM_ACTIVATE (int wParam, int lParam) {
- if (OS.IsPPC) {
- /*
- * Note: this does not work when we get WM_ACTIVATE prior
- * to adding a listener.
- */
- if (hooks (SWT.HardKeyDown) || hooks (SWT.HardKeyUp)) {
- int fActive = wParam & 0xFFFF;
- int hwnd = fActive != 0 ? handle : 0;
- for (int bVk=OS.VK_APP1; bVk<=OS.VK_APP6; bVk++) {
- OS.SHSetAppKeyWndAssoc ((byte) bVk, hwnd);
- }
- }
- /* Restore SIP state when window is activated */
- if ((wParam & 0xFFFF) != 0) {
- OS.SHSipPreference (handle, psai.fSipUp == 0 ? OS.SIP_DOWN : OS.SIP_UP);
- }
- }
- /*
- * Bug in Windows XP. When a Shell is deactivated, the
- * IME composition window does not go away. This causes
- * repaint issues. The fix is to close the IME ourselves
- * when the Shell is deactivated.
- *
- * Note. When the Shell is reactivated, the text in the
- * composition window has been lost.
- */
- if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) >= (5 << 16 | 1)) {
- if ((wParam & 0xFFFF) == 0 && OS.IsDBLocale && hIMC != 0) {
- OS.ImmSetOpenStatus (hIMC, false);
- }
- }
-
- LRESULT result = super.WM_ACTIVATE (wParam, lParam);
- if (parent != null) return LRESULT.ZERO;
- return result;
-}
-
-LRESULT WM_CLOSE (int wParam, int lParam) {
- if ((Display.TrimEnabled && !isEnabled ()) || !isActive ()) {
- return LRESULT.ZERO;
- }
- return super.WM_CLOSE (wParam, lParam);
-}
-
-LRESULT WM_COMMAND (int wParam, int lParam) {
- if (OS.IsPPC) {
- /*
- * Note in WinCE PPC: Close the Shell when the "Done Button" has
- * been pressed. lParam is either 0 (PocketPC 2002) or the handle
- * to the Shell (PocketPC).
- */
- int loWord = wParam & 0xFFFF;
- if (loWord == OS.IDOK && (lParam == 0 || lParam == handle)) {
- OS.PostMessage (handle, OS.WM_CLOSE, 0, 0);
- return LRESULT.ZERO;
- }
- }
- /*
- * Note in WinCE PPC. Menu events originate from the command bar.
- */
- if (OS.IsPPC || OS.IsSP) {
- if (menuBar != null) {
- int hwndCB = menuBar.hwndCB;
- if (hwndCB != 0 && lParam == hwndCB) {
- return super.WM_COMMAND (wParam, 0);
- }
- }
- }
- return super.WM_COMMAND (wParam, lParam);
-}
-
-LRESULT WM_DESTROY (int wParam, int lParam) {
- LRESULT result = super.WM_DESTROY (wParam, lParam);
- /*
- * When the shell is a WS_CHILD window of a non-SWT
- * window, the destroy code does not get called because
- * the non-SWT window does not call dispose (). Instead,
- * the destroy code is called here in WM_DESTROY.
- */
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & OS.WS_CHILD) != 0) {
- releaseChild ();
- releaseResources ();
- }
- return result;
-}
-
-LRESULT WM_MOUSEACTIVATE (int wParam, int lParam) {
- LRESULT result = super.WM_MOUSEACTIVATE (wParam, lParam);
- if (result != null) return result;
- int hittest = lParam & 0xFFFF;
- if (hittest == OS.HTMENU) return null;
- /*
- * Get the current location of the cursor,
- * not the location of the cursor when the
- * WM_MOUSEACTIVATE was generated. This is
- * strictly incorrect but is necessary in
- * order to support Activate and Deactivate
- * events for embedded widgets that have
- * their own event loop. In that case, the
- * cursor location reported by GetMessagePos
- * is the one for our event loop, not the
- * embedded widget's event loop.
- */
- POINT pt = new POINT ();
- if (!OS.GetCursorPos (pt)) {
- int pos = OS.GetMessagePos ();
- pt.x = (short) (pos & 0xFFFF);
- pt.y = (short) (pos >> 16);
- }
- int hwnd = OS.WindowFromPoint (pt);
- if (hwnd == 0) return null;
- Control control = display.findControl (hwnd);
- setActiveControl (control);
- /*
- * This code is intentionally commented. On some platforms,
- * shells that are created with SWT.NO_TRIM won't take focus
- * when the user clicks in the client area or on the border.
- * This behavior is usedful when emulating tool tip shells
- * Until this behavior is specified, this code will remain
- * commented.
- */
-// if ((style & SWT.NO_TRIM) != 0) {
-// if (hittest == OS.HTBORDER || hittest == OS.HTCLIENT) {
-// return new LRESULT (OS.MA_NOACTIVATE);
-// }
-// }
- return null;
-}
-
-LRESULT WM_NCHITTEST (int wParam, int lParam) {
- if (!OS.IsWindowEnabled (handle)) return null;
- if (!isEnabled () || !isActive ()) {
- if (!Display.TrimEnabled) return new LRESULT (OS.HTNOWHERE);
- int hittest = callWindowProc (OS.WM_NCHITTEST, wParam, lParam);
- if (hittest == OS.HTCLIENT || hittest == OS.HTMENU) hittest = OS.HTBORDER;
- return new LRESULT (hittest);
- }
- if (menuBar != null && !menuBar.getEnabled ()) {
- int hittest = callWindowProc (OS.WM_NCHITTEST, wParam, lParam);
- if (hittest == OS.HTMENU) hittest = OS.HTBORDER;
- return new LRESULT (hittest);
- }
- return null;
-}
-
-LRESULT WM_PALETTECHANGED (int wParam, int lParam) {
- if (wParam != handle) {
- int hPalette = display.hPalette;
- if (hPalette != 0) return selectPalette (hPalette);
- }
- return super.WM_PALETTECHANGED (wParam, lParam);
-}
-
-LRESULT WM_QUERYNEWPALETTE (int wParam, int lParam) {
- int hPalette = display.hPalette;
- if (hPalette != 0) return selectPalette (hPalette);
- return super.WM_QUERYNEWPALETTE (wParam, lParam);
-}
-
-LRESULT WM_SETCURSOR (int wParam, int lParam) {
- /*
- * Feature in Windows. When the shell is disabled
- * by a Windows standard dialog (like a MessageBox
- * or FileDialog), clicking in the shell does not
- * bring the shell or the dialog to the front. The
- * fix is to detect this case and bring the shell
- * forward.
- */
- int msg = lParam >> 16;
- if (msg == OS.WM_LBUTTONDOWN) {
- if (!Display.TrimEnabled) {
- Shell modalShell = display.getModalShell ();
- if (modalShell != null && !isActive ()) {
- int hwndModal = modalShell.handle;
- if (OS.IsWindowEnabled (hwndModal)) {
- OS.SetActiveWindow (hwndModal);
- }
- }
- }
- if (!OS.IsWindowEnabled (handle)) {
- if (!OS.IsWinCE) {
- int hwndPopup = OS.GetLastActivePopup (handle);
- if (hwndPopup != 0 && hwndPopup != handle) {
- if (WidgetTable.get (hwndPopup) == null) {
- if (OS.IsWindowEnabled (hwndPopup)) {
- OS.SetActiveWindow (hwndPopup);
- }
- }
- }
- }
- }
- }
- return super.WM_SETCURSOR (wParam, lParam);
-}
-
-LRESULT WM_SETTINGCHANGE (int wParam, int lParam) {
- LRESULT result = super.WM_SETTINGCHANGE (wParam, lParam);
- if (result != null) return result;
- if (OS.IsPPC) {
- if (wParam == OS.SPI_SETSIPINFO) {
- /*
- * The SIP is in a new state. Cache its new value.
* Resize the Shell if it has the style SWT.RESIZE.
- * Note that SHHandleWMSettingChange resizes the
- * Shell and also updates the cached state.
- */
- if ((style & SWT.RESIZE) != 0) {
- OS.SHHandleWMSettingChange (handle, wParam, lParam, psai);
- return LRESULT.ZERO;
- } else {
- SIPINFO pSipInfo = new SIPINFO ();
- pSipInfo.cbSize = SIPINFO.sizeof;
- OS.SipGetInfo (pSipInfo);
- psai.fSipUp = pSipInfo.fdwFlags & OS.SIPF_ON;
- }
- }
- }
- return result;
-}
-
-LRESULT WM_SHOWWINDOW (int wParam, int lParam) {
- LRESULT result = super.WM_SHOWWINDOW (wParam, lParam);
- if (result != null) return result;
- /*
- * Bug in Windows. If the shell is hidden while the parent
- * is iconic, Windows shows the shell when the parent is
- * deiconified. This does not happen if the shell is hidden
- * while the parent is not an icon. The fix is to track
- * visible state for the shell and refuse to show the shell
- * when the parent is shown.
- */
- if (lParam == OS.SW_PARENTOPENING) {
- Control control = this;
- while (control != null) {
- Shell shell = control.getShell ();
- if (!shell.showWithParent) return LRESULT.ZERO;
- control = control.parent;
- }
- }
- return result;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.events.*; + +/** + * 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> + * 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 + * 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>. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE</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 + */ +public class Shell extends Decorations { + Display display; + Menu activeMenu; + int hIMC; + int [] brushes; + boolean showWithParent; + int toolTipHandle, lpstrTip; + Control lastActive; + SHACTIVATEINFO psai; + static final int DialogProc; + static final TCHAR DialogClass = new TCHAR (0, OS.IsWinCE ? "Dialog" : "#32770", true); + static { + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, DialogClass, lpWndClass); + DialogProc = lpWndClass.lpfnWndProc; + } + +/** + * 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#NO_TRIM + * @see SWT#SHELL_TRIM + * @see SWT#DIALOG_TRIM + * @see SWT#MODELESS + * @see SWT#PRIMARY_MODAL + * @see SWT#APPLICATION_MODAL + * @see SWT#SYSTEM_MODAL + */ +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, OS.IsWinCE ? SWT.NONE : 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#NO_TRIM + * @see SWT#SHELL_TRIM + * @see SWT#DIALOG_TRIM + * @see SWT#MODELESS + * @see SWT#PRIMARY_MODAL + * @see SWT#APPLICATION_MODAL + * @see SWT#SYSTEM_MODAL + */ +public Shell (Display display, int style) { + this (display, null, style, 0); +} + +Shell (Display display, Shell parent, int style, int handle) { + super (); + checkSubclass (); + 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.parent = parent; + this.display = display; + this.handle = 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_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 Shell (Shell parent) { + this (parent, OS.IsWinCE ? SWT.NONE : 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 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#MODELESS + * @see SWT#PRIMARY_MODAL + * @see SWT#APPLICATION_MODAL + * @see SWT#SYSTEM_MODAL + */ +public Shell (Shell parent, int style) { + this (parent != null ? parent.getDisplay () : null, parent, style, 0); +} + +/** + * Invokes platform specific functionality to allocate a new shell. + * <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 + * + * @private + */ +public static Shell win32_new (Display display, int handle) { + return new Shell (display, null, SWT.NO_TRIM, handle); +} + +static int checkStyle (int style) { + style = Decorations.checkStyle (style); + int mask = SWT.SYSTEM_MODAL | 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; +} + +/** + * 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.Close,typedListener); + addListener (SWT.Iconify,typedListener); + addListener (SWT.Deiconify,typedListener); + addListener (SWT.Activate, typedListener); + addListener (SWT.Deactivate, typedListener); +} + +int callWindowProc (int msg, int wParam, int lParam) { + if (parent != null) { + if (handle == 0) return 0; + switch (msg) { + case OS.WM_KILLFOCUS: + case OS.WM_SETFOCUS: + return OS.DefWindowProc (handle, msg, wParam, lParam); + } + return OS.CallWindowProc (DialogProc, handle, msg, wParam, lParam); + } + return super.callWindowProc (msg, wParam, lParam); +} + +/** + * 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 #dispose + */ +public void close () { + checkWidget (); + OS.PostMessage (handle, OS.WM_CLOSE, 0, 0); +} + +void createHandle () { + boolean embedded = handle != 0; + + /* + * On Windows 98 and NT, setting a window to be the + * top most window using HWND_TOPMOST can result in a + * parent dialog shell being moved behind its parent + * if the dialog has a sibling that is currently on top + * This only occurs using SetWindowPos (), not when the + * handle is created. + */ + /* + * The following code is intentionally commented. + */ +// if ((style & SWT.ON_TOP) != 0) display.lockActiveWindow = true; + super.createHandle (); + /* + * The following code is intentionally commented. + */ +// if ((style & SWT.ON_TOP) != 0) display.lockActiveWindow = false; + + if (!embedded) { + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + bits &= ~(OS.WS_OVERLAPPED | OS.WS_CAPTION); + if (!OS.IsWinCE) bits |= OS.WS_POPUP; + if ((style & SWT.TITLE) != 0) bits |= OS.WS_CAPTION; + if ((style & SWT.NO_TRIM) == 0) { + if ((style & (SWT.BORDER | SWT.RESIZE)) == 0) bits |= OS.WS_BORDER; + } + OS.SetWindowLong (handle, OS.GWL_STYLE, bits); + if (OS.IsWinCE) setMaximized (true); + if (OS.IsPPC) { + psai = new SHACTIVATEINFO (); + psai.cbSize = SHACTIVATEINFO.sizeof; + } + } + if (OS.IsDBLocale) { + hIMC = OS.ImmCreateContext (); + if (hIMC != 0) OS.ImmAssociateContext (handle, hIMC); + } +} + +public void dispose () { + /* + * This code is intentionally commented. On some + * platforms, the owner window is repainted right + * away when a dialog window exits. This behavior + * is currently unspecified. + */ +// /* +// * Note: It is valid to attempt to dispose a widget +// * more than once. If this happens, fail silently. +// */ +// if (!isValidWidget ()) return; +// if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); +// Display oldDisplay = display; + super.dispose (); + // widget is disposed at this point +// if (oldDisplay != null) oldDisplay.update (); +} + +int findBrush (int pixel) { + if (pixel == OS.GetSysColor (OS.COLOR_BTNFACE)) { + return OS.GetSysColorBrush (OS.COLOR_BTNFACE); + } + if (pixel == OS.GetSysColor (OS.COLOR_WINDOW)) { + return OS.GetSysColorBrush (OS.COLOR_WINDOW); + } + if (brushes == null) brushes = new int [4]; + LOGBRUSH logBrush = new LOGBRUSH (); + for (int i=0; i<brushes.length; i++) { + int hBrush = brushes [i]; + if (hBrush == 0) break; + OS.GetObject (hBrush, LOGBRUSH.sizeof, logBrush); + if (logBrush.lbColor == pixel) return hBrush; + } + int length = brushes.length; + int hBrush = brushes [--length]; + if (hBrush != 0) OS.DeleteObject (hBrush); + System.arraycopy (brushes, 0, brushes, 1, length); + brushes [0] = hBrush = OS.CreateSolidBrush (pixel); + return hBrush; +} + +int findCursor () { + return hCursor; +} + +/** + * 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) 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 + * @see Shell#open + * @see Shell#setActive + */ +public void forceActive () { + checkWidget (); + OS.SetForegroundWindow (handle); +} + +void forceResize () { + /* Do nothing */ +} + +public Rectangle getBounds () { + checkWidget (); + if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) return super.getBounds (); + } + RECT rect = new RECT (); + OS.GetWindowRect (handle, rect); + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + return new Rectangle (rect.left, rect.top, width, height); +} + +public Display getDisplay () { + if (display == null) error (SWT.ERROR_WIDGET_DISPOSED); + return display; +} + +public boolean getEnabled () { + checkWidget (); + return (state & DISABLED) == 0; +} + +/** + * 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 (); + if (!OS.IsDBLocale) return 0; + int hIMC = OS.ImmGetContext (handle); + int [] lpfdwConversion = new int [1], lpfdwSentence = new int [1]; + boolean open = OS.ImmGetOpenStatus (hIMC); + if (open) open = OS.ImmGetConversionStatus (hIMC, lpfdwConversion, lpfdwSentence); + OS.ImmReleaseContext (handle, hIMC); + if (!open) return SWT.NONE; + int result = 0; + if ((lpfdwConversion [0] & OS.IME_CMODE_ROMAN) != 0) result |= SWT.ROMAN; + if ((lpfdwConversion [0] & OS.IME_CMODE_FULLSHAPE) != 0) result |= SWT.DBCS; + if ((lpfdwConversion [0] & OS.IME_CMODE_KATAKANA) != 0) return result | SWT.PHONETIC; + if ((lpfdwConversion [0] & OS.IME_CMODE_NATIVE) != 0) return result | SWT.NATIVE; + return result | SWT.ALPHA; +} + +public Point getLocation () { + checkWidget (); + if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + return super.getLocation (); + } + } + RECT rect = new RECT (); + OS.GetWindowRect (handle, rect); + return new Point (rect.left, rect.top); +} + +public Shell getShell () { + checkWidget (); + return this; +} + +/** + * Returns an array containing all shells which are + * descendents 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 boolean isEnabled () { + checkWidget (); + return getEnabled (); +} + +/** + * 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, + * and sets focus to its default button (if it has one) + * 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 + * @see Shell#setActive + * @see Shell#forceActive + */ +public void open () { + checkWidget (); + bringToTop (); + /* + * Feature on WinCE PPC. A new application becomes + * the foreground application only if it has at least + * one visible window before the event loop is started. + * The workaround is to explicitely force the shell to + * be the foreground window. + */ + if (OS.IsWinCE) OS.SetForegroundWindow (handle); + OS.SendMessage (handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0); + setVisible (true); + /* + * Bug in Windows XP. Despite the fact that an icon has been + * set for a window, the task bar displays the wrong icon the + * first time the window is made visible with ShowWindow() after + * a call to BringToTop(), when a long time elapses between the + * ShowWindow() and the time the event queue is read. The icon + * in the window trimming is correct but the one in the task + * bar does not get updated until a new icon is set into the + * window or the window text is changed. The fix is to call + * PeekMessage() with the flag PM_NOREMOVE to touch the event + * queue but not dispatch events. + */ + MSG msg = new MSG (); + OS.PeekMessage (msg, 0, 0, 0, OS.PM_NOREMOVE); + if (!restoreFocus ()) traverseGroup (true); +} + +void releaseShells () { + Shell [] shells = getShells (); + for (int i=0; i<shells.length; i++) { + Shell shell = shells [i]; + if (!shell.isDisposed ()) shell.releaseResources (); + } +} + +void releaseWidget () { + releaseShells (); + super.releaseWidget (); + activeMenu = null; + display.clearModal (this); + display = null; + if (lpstrTip != 0) { + int hHeap = OS.GetProcessHeap (); + OS.HeapFree (hHeap, 0, lpstrTip); + } + lpstrTip = 0; + toolTipHandle = 0; + if (brushes != null) { + for (int i=0; i<brushes.length; i++) { + int hBrush = brushes [i]; + if (hBrush != 0) OS.DeleteObject (hBrush); + } + } + brushes = null; + if (OS.IsDBLocale) { + if (hIMC != 0) OS.ImmDestroyContext (hIMC); + } + lastActive = null; +} + +void remove (Menu menu) { + super.remove (menu); + if (menu == activeMenu) activeMenu = 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.Close, listener); + eventTable.unhook (SWT.Iconify,listener); + eventTable.unhook (SWT.Deiconify,listener); + eventTable.unhook (SWT.Activate, listener); + eventTable.unhook (SWT.Deactivate, listener); +} + +LRESULT selectPalette (int hPalette) { + int hDC = OS.GetDC (handle); + int hOld = OS.SelectPalette (hDC, hPalette, false); + int result = OS.RealizePalette (hDC); + if (result > 0) { + OS.InvalidateRect (handle, null, true); + } else { + OS.SelectPalette (hDC, hOld, true); + OS.RealizePalette (hDC); + } + OS.ReleaseDC (handle, hDC); + return (result > 0) ? LRESULT.ONE : LRESULT.ZERO; +} + +/** + * 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) 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 + * @see Shell#open + * @see Shell#setActive + */ +public void setActive () { + checkWidget (); + bringToTop (); +} + +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); + } + } +} + +void setBounds (int x, int y, int width, int height, int flags) { + if (OS.IsWinCE) { + swFlags = OS.SW_RESTORE; + if ((style & SWT.NO_TRIM) == 0) { + /* Set the WS_CAPTION bits when no longer maximized */ + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & OS.WS_CAPTION) != OS.WS_CAPTION) { + bits |= OS.WS_CAPTION; + OS.SetWindowLong (handle, OS.GWL_STYLE, bits); + } + } + } else { + if (OS.IsIconic (handle) || OS.IsZoomed (handle)) { + setPlacement (x, y, width, height, flags); + return; + } + } + OS.SetWindowPos (handle, 0, x, y, width, height, flags); +} + +public void setEnabled (boolean enabled) { + checkWidget (); + state &= ~DISABLED; + if (!enabled) state |= DISABLED; + if (!Display.TrimEnabled) { + super.setEnabled (enabled); + } else { + if (isActive ()) setItemEnabled (OS.SC_CLOSE, enabled); + } +} + +/** + * 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 (); + if (!OS.IsDBLocale) return; + boolean imeOn = mode != SWT.NONE && mode != SWT.ROMAN; + int hIMC = OS.ImmGetContext (handle); + OS.ImmSetOpenStatus (hIMC, imeOn); + if (imeOn) { + int [] lpfdwConversion = new int [1], lpfdwSentence = new int [1]; + if (OS.ImmGetConversionStatus (hIMC, lpfdwConversion, lpfdwSentence)) { + int newBits = 0; + int oldBits = OS.IME_CMODE_NATIVE | OS.IME_CMODE_KATAKANA; + if ((mode & SWT.PHONETIC) != 0) { + newBits = OS.IME_CMODE_KATAKANA | OS.IME_CMODE_NATIVE; + oldBits = 0; + } else { + if ((mode & SWT.NATIVE) != 0) { + newBits = OS.IME_CMODE_NATIVE; + oldBits = OS.IME_CMODE_KATAKANA; + } + } + if ((mode & SWT.DBCS) != 0) { + newBits |= OS.IME_CMODE_FULLSHAPE; + } else { + oldBits |= OS.IME_CMODE_FULLSHAPE; + } + if ((mode & SWT.ROMAN) != 0) { + newBits |= OS.IME_CMODE_ROMAN; + } else { + oldBits |= OS.IME_CMODE_ROMAN; + } + lpfdwConversion [0] |= newBits; lpfdwConversion [0] &= ~oldBits; + OS.ImmSetConversionStatus (hIMC, lpfdwConversion [0], lpfdwSentence [0]); + } + } + OS.ImmReleaseContext (handle, hIMC); +} + +void setItemEnabled (int cmd, boolean enabled) { + int hMenu = OS.GetSystemMenu (handle, false); + if (hMenu == 0) return; + int flags = OS.MF_ENABLED; + if (!enabled) flags = OS.MF_DISABLED | OS.MF_GRAYED; + OS.EnableMenuItem (hMenu, cmd, OS.MF_BYCOMMAND | flags); +} + +void setParent () { + /* Do nothing. Not necessary for Shells */ +} + +void setToolTipText (int hwnd, String text) { + if (OS.IsWinCE) return; + if (toolTipHandle == 0) { + toolTipHandle = OS.CreateWindowEx ( + 0, + new TCHAR (0, OS.TOOLTIPS_CLASS, true), + null, + OS.TTS_ALWAYSTIP, + OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0, + handle, + 0, + OS.GetModuleHandle (null), + null); + if (toolTipHandle == 0) error (SWT.ERROR_NO_HANDLES); + /* + * Feature in Windows. Despite the fact that the + * tool tip text contains \r\n, the tooltip will + * not honour the new line unless TTM_SETMAXTIPWIDTH + * is set. The fix is to set TTM_SETMAXTIPWIDTH to + * a large value. + */ + OS.SendMessage (toolTipHandle, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF); + } + TOOLINFO lpti = new TOOLINFO (); + lpti.cbSize = TOOLINFO.sizeof; + lpti.uId = hwnd; + lpti.hwnd = handle; + if (text == null) { + OS.SendMessage (toolTipHandle, OS.TTM_DELTOOL, 0, lpti); + } else { + lpti.uFlags = OS.TTF_IDISHWND | OS.TTF_SUBCLASS; + lpti.lpszText = OS.LPSTR_TEXTCALLBACK; + OS.SendMessage (toolTipHandle, OS.TTM_ADDTOOL, 0, lpti); + } + OS.SendMessage (toolTipHandle, OS.TTM_UPDATE, 0, 0); +} + +void setToolTipText (NMTTDISPINFO lpnmtdi, byte [] buffer) { + /* + * Ensure that the current position of the mouse + * is inside the client area of the shell. This + * prevents tool tips from popping up over the + * shell trimmings. + */ + if (!hasCursor ()) return; + int hHeap = OS.GetProcessHeap (); + if (lpstrTip != 0) OS.HeapFree (hHeap, 0, lpstrTip); + int byteCount = buffer.length; + lpstrTip = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + OS.MoveMemory (lpstrTip, buffer, byteCount); + lpnmtdi.lpszText = lpstrTip; +} + +void setToolTipText (NMTTDISPINFO lpnmtdi, char [] buffer) { + /* + * Ensure that the current position of the mouse + * is inside the client area of the shell. This + * prevents tool tips from popping up over the + * shell trimmings. + */ + if (!hasCursor ()) return; + int hHeap = OS.GetProcessHeap (); + if (lpstrTip != 0) OS.HeapFree (hHeap, 0, lpstrTip); + int byteCount = buffer.length * 2; + lpstrTip = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + OS.MoveMemory (lpstrTip, buffer, byteCount); + lpnmtdi.lpszText = lpstrTip; +} + +public void setVisible (boolean visible) { + checkWidget (); + super.setVisible (visible); + if (showWithParent == visible) return; + showWithParent = visible; + if (!OS.IsWinCE) OS.ShowOwnedPopups (handle, visible); + int mask = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL; + if ((style & mask) != 0) { + if (visible) { + display.setModalShell (this); + Control control = display.getFocusControl (); + if (control != null && !control.isActive ()) bringToTop (); + int hwndShell = OS.GetActiveWindow (); + if (hwndShell == 0) { + if (parent != null) hwndShell = parent.handle; + } + if (hwndShell != 0) { + OS.SendMessage (hwndShell, OS.WM_CANCELMODE, 0, 0); + } + OS.ReleaseCapture (); + } else { + display.clearModal (this); + } + } else { + updateModal (); + } +} + +boolean traverseEscape () { + if (parent == null) return false; + if (!isVisible () || !isEnabled ()) return false; + close (); + return true; +} + +void updateModal () { + if (!Display.TrimEnabled) { + super.setEnabled (isActive ()); + } else { + setItemEnabled (OS.SC_CLOSE, isActive ()); + } +} + +int widgetExtStyle () { + int bits = super.widgetExtStyle (); + /* + * Bug in Windows 98 and NT. Creating a window with the + * WS_EX_TOPMOST extendes style can result in a dialog shell + * being moved behind its parent. The exact case where this + * happens is a shell with two dialog shell children where + * each dialog child has another hidden dialog child with + * the WS_EX_TOPMOST extended style. Clicking on either of + * the visible dialog causes them to become active but move + * to the back, behind the parent shell. The fix is to + * disallow the WS_EX_TOPMOST extended style on Windows 98 + * and NT. + */ + if (OS.IsWin95) return bits; + if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) < (4 << 16 | 10)) { + return bits; + } + if ((style & SWT.ON_TOP) != 0) bits |= OS.WS_EX_TOPMOST; + return bits; +} + +TCHAR windowClass () { + if (OS.IsSP) return DialogClass; + return parent != null ? DialogClass : super.windowClass (); +} + +int windowProc () { + if (OS.IsSP) return DialogProc; + return parent != null ? DialogProc : super.windowProc (); +} + +int widgetStyle () { + int bits = super.widgetStyle () & ~OS.WS_POPUP; + if (handle != 0) return bits | OS.WS_CHILD; + bits &= ~OS.WS_CHILD; + /* + * Feature in WinCE. Calling CreateWindowEx () with WS_OVERLAPPED + * and a parent window causes the new window to become a WS_CHILD of + * the parent instead of a dialog child. The fix is to use WS_POPUP + * for a window with a parent. + * + * Feature in WinCE PPC. A window without a parent with WS_POPUP + * always shows on top of the Pocket PC 'Today Screen'. The fix + * is to not set WS_POPUP for a window without a parent on WinCE + * devices. + * + * NOTE: WS_POPUP causes CreateWindowEx () to ignore CW_USEDEFAULT + * and causes the default window location and size to be zero. + */ + if (OS.IsWinCE) { + if (OS.IsSP) return bits | OS.WS_POPUP; + return parent == null ? bits : bits | OS.WS_POPUP; + } + + /* + * Use WS_OVERLAPPED for all windows, either dialog or top level + * so that CreateWindowEx () will respect CW_USEDEFAULT and set + * the default window location and size. + * + * NOTE: When a WS_OVERLAPPED window is created, Windows gives + * the new window WS_CAPTION style bits. These two constants are + * as follows: + * + * WS_OVERLAPPED = 0 + * WS_CAPTION = WS_BORDER | WS_DLGFRAME + * + */ + return bits | OS.WS_OVERLAPPED | OS.WS_CAPTION; +} + +LRESULT WM_ACTIVATE (int wParam, int lParam) { + if (OS.IsPPC) { + /* + * Note: this does not work when we get WM_ACTIVATE prior + * to adding a listener. + */ + if (hooks (SWT.HardKeyDown) || hooks (SWT.HardKeyUp)) { + int fActive = wParam & 0xFFFF; + int hwnd = fActive != 0 ? handle : 0; + for (int bVk=OS.VK_APP1; bVk<=OS.VK_APP6; bVk++) { + OS.SHSetAppKeyWndAssoc ((byte) bVk, hwnd); + } + } + /* Restore SIP state when window is activated */ + if ((wParam & 0xFFFF) != 0) { + OS.SHSipPreference (handle, psai.fSipUp == 0 ? OS.SIP_DOWN : OS.SIP_UP); + } + } + /* + * Bug in Windows XP. When a Shell is deactivated, the + * IME composition window does not go away. This causes + * repaint issues. The fix is to close the IME ourselves + * when the Shell is deactivated. + * + * Note. When the Shell is reactivated, the text in the + * composition window has been lost. + */ + if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) >= (5 << 16 | 1)) { + if ((wParam & 0xFFFF) == 0 && OS.IsDBLocale && hIMC != 0) { + OS.ImmSetOpenStatus (hIMC, false); + } + } + + LRESULT result = super.WM_ACTIVATE (wParam, lParam); + if (parent != null) return LRESULT.ZERO; + return result; +} + +LRESULT WM_CLOSE (int wParam, int lParam) { + if ((Display.TrimEnabled && !isEnabled ()) || !isActive ()) { + return LRESULT.ZERO; + } + return super.WM_CLOSE (wParam, lParam); +} + +LRESULT WM_COMMAND (int wParam, int lParam) { + if (OS.IsPPC) { + /* + * Note in WinCE PPC: Close the Shell when the "Done Button" has + * been pressed. lParam is either 0 (PocketPC 2002) or the handle + * to the Shell (PocketPC). + */ + int loWord = wParam & 0xFFFF; + if (loWord == OS.IDOK && (lParam == 0 || lParam == handle)) { + OS.PostMessage (handle, OS.WM_CLOSE, 0, 0); + return LRESULT.ZERO; + } + } + /* + * Note in WinCE PPC. Menu events originate from the command bar. + */ + if (OS.IsPPC || OS.IsSP) { + if (menuBar != null) { + int hwndCB = menuBar.hwndCB; + if (hwndCB != 0 && lParam == hwndCB) { + return super.WM_COMMAND (wParam, 0); + } + } + } + return super.WM_COMMAND (wParam, lParam); +} + +LRESULT WM_DESTROY (int wParam, int lParam) { + LRESULT result = super.WM_DESTROY (wParam, lParam); + /* + * When the shell is a WS_CHILD window of a non-SWT + * window, the destroy code does not get called because + * the non-SWT window does not call dispose (). Instead, + * the destroy code is called here in WM_DESTROY. + */ + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & OS.WS_CHILD) != 0) { + releaseChild (); + releaseResources (); + } + return result; +} + +LRESULT WM_MOUSEACTIVATE (int wParam, int lParam) { + LRESULT result = super.WM_MOUSEACTIVATE (wParam, lParam); + if (result != null) return result; + int hittest = lParam & 0xFFFF; + if (hittest == OS.HTMENU) return null; + /* + * Get the current location of the cursor, + * not the location of the cursor when the + * WM_MOUSEACTIVATE was generated. This is + * strictly incorrect but is necessary in + * order to support Activate and Deactivate + * events for embedded widgets that have + * their own event loop. In that case, the + * cursor location reported by GetMessagePos + * is the one for our event loop, not the + * embedded widget's event loop. + */ + POINT pt = new POINT (); + if (!OS.GetCursorPos (pt)) { + int pos = OS.GetMessagePos (); + pt.x = (short) (pos & 0xFFFF); + pt.y = (short) (pos >> 16); + } + int hwnd = OS.WindowFromPoint (pt); + if (hwnd == 0) return null; + Control control = display.findControl (hwnd); + setActiveControl (control); + /* + * This code is intentionally commented. On some platforms, + * shells that are created with SWT.NO_TRIM won't take focus + * when the user clicks in the client area or on the border. + * This behavior is usedful when emulating tool tip shells + * Until this behavior is specified, this code will remain + * commented. + */ +// if ((style & SWT.NO_TRIM) != 0) { +// if (hittest == OS.HTBORDER || hittest == OS.HTCLIENT) { +// return new LRESULT (OS.MA_NOACTIVATE); +// } +// } + return null; +} + +LRESULT WM_NCHITTEST (int wParam, int lParam) { + if (!OS.IsWindowEnabled (handle)) return null; + if (!isEnabled () || !isActive ()) { + if (!Display.TrimEnabled) return new LRESULT (OS.HTNOWHERE); + int hittest = callWindowProc (OS.WM_NCHITTEST, wParam, lParam); + if (hittest == OS.HTCLIENT || hittest == OS.HTMENU) hittest = OS.HTBORDER; + return new LRESULT (hittest); + } + if (menuBar != null && !menuBar.getEnabled ()) { + int hittest = callWindowProc (OS.WM_NCHITTEST, wParam, lParam); + if (hittest == OS.HTMENU) hittest = OS.HTBORDER; + return new LRESULT (hittest); + } + return null; +} + +LRESULT WM_PALETTECHANGED (int wParam, int lParam) { + if (wParam != handle) { + int hPalette = display.hPalette; + if (hPalette != 0) return selectPalette (hPalette); + } + return super.WM_PALETTECHANGED (wParam, lParam); +} + +LRESULT WM_QUERYNEWPALETTE (int wParam, int lParam) { + int hPalette = display.hPalette; + if (hPalette != 0) return selectPalette (hPalette); + return super.WM_QUERYNEWPALETTE (wParam, lParam); +} + +LRESULT WM_SETCURSOR (int wParam, int lParam) { + /* + * Feature in Windows. When the shell is disabled + * by a Windows standard dialog (like a MessageBox + * or FileDialog), clicking in the shell does not + * bring the shell or the dialog to the front. The + * fix is to detect this case and bring the shell + * forward. + */ + int msg = lParam >> 16; + if (msg == OS.WM_LBUTTONDOWN) { + if (!Display.TrimEnabled) { + Shell modalShell = display.getModalShell (); + if (modalShell != null && !isActive ()) { + int hwndModal = modalShell.handle; + if (OS.IsWindowEnabled (hwndModal)) { + OS.SetActiveWindow (hwndModal); + } + } + } + if (!OS.IsWindowEnabled (handle)) { + if (!OS.IsWinCE) { + int hwndPopup = OS.GetLastActivePopup (handle); + if (hwndPopup != 0 && hwndPopup != handle) { + if (WidgetTable.get (hwndPopup) == null) { + if (OS.IsWindowEnabled (hwndPopup)) { + OS.SetActiveWindow (hwndPopup); + } + } + } + } + } + } + return super.WM_SETCURSOR (wParam, lParam); +} + +LRESULT WM_SETTINGCHANGE (int wParam, int lParam) { + LRESULT result = super.WM_SETTINGCHANGE (wParam, lParam); + if (result != null) return result; + if (OS.IsPPC) { + if (wParam == OS.SPI_SETSIPINFO) { + /* + * The SIP is in a new state. Cache its new value.
* Resize the Shell if it has the style SWT.RESIZE. + * Note that SHHandleWMSettingChange resizes the + * Shell and also updates the cached state. + */ + if ((style & SWT.RESIZE) != 0) { + OS.SHHandleWMSettingChange (handle, wParam, lParam, psai); + return LRESULT.ZERO; + } else { + SIPINFO pSipInfo = new SIPINFO (); + pSipInfo.cbSize = SIPINFO.sizeof; + OS.SipGetInfo (pSipInfo); + psai.fSipUp = pSipInfo.fdwFlags & OS.SIPF_ON; + } + } + } + return result; +} + +LRESULT WM_SHOWWINDOW (int wParam, int lParam) { + LRESULT result = super.WM_SHOWWINDOW (wParam, lParam); + if (result != null) return result; + /* + * Bug in Windows. If the shell is hidden while the parent + * is iconic, Windows shows the shell when the parent is + * deiconified. This does not happen if the shell is hidden + * while the parent is not an icon. The fix is to track + * visible state for the shell and refuse to show the shell + * when the parent is shown. + */ + if (lParam == OS.SW_PARENTOPENING) { + Control control = this; + while (control != null) { + Shell shell = control.getShell (); + if (!shell.showWithParent) return LRESULT.ZERO; + control = control.parent; + } + } + return result; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Slider.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Slider.java index c1c0bf52d2..8406073f3f 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Slider.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Slider.java @@ -1,799 +1,799 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.events.*;
-
-/**
- * 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 <em>selection</em> 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
- */
-public class Slider extends Control {
- int increment, pageIncrement;
- static final int ScrollBarProc;
- static final TCHAR ScrollBarClass = new TCHAR (0, "SCROLLBAR", true);
- static {
- WNDCLASS lpWndClass = new WNDCLASS ();
- OS.GetClassInfo (0, ScrollBarClass, lpWndClass);
- ScrollBarProc = lpWndClass.lpfnWndProc;
- }
-
-/**
- * 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 receiver's value changes, 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>0</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
- *
- * @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);
-}
-
-int callWindowProc (int msg, int wParam, int lParam) {
- if (handle == 0) return 0;
- return OS.CallWindowProc (ScrollBarProc, handle, msg, wParam, lParam);
-}
-
-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 border = getBorderWidth ();
- int width = border * 2, height = border * 2;
- if ((style & SWT.HORIZONTAL) != 0) {
- width += OS.GetSystemMetrics (OS.SM_CXHSCROLL) * 10;
- height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
- } else {
- width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
- height += OS.GetSystemMetrics (OS.SM_CYVSCROLL) * 10;
- }
- if (wHint != SWT.DEFAULT) width = wHint + (border * 2);
- if (hHint != SWT.DEFAULT) height = hHint + (border * 2);
- return new Point (width, height);
-}
-
-void createWidget () {
- super.createWidget ();
- increment = 1;
- pageIncrement = 10;
- /*
- * Set the intial values of the maximum
- * to 100 and the thumb to 10. Note that
- * info.nPage needs to be 11 in order to
- * get a thumb that is 10.
- */
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_ALL;
- info.nMax = 100;
- info.nPage = 11;
- OS.SetScrollInfo (handle, OS.SB_CTL, info, true);
-}
-
-int defaultBackground () {
- return OS.GetSysColor (OS.COLOR_SCROLLBAR);
-}
-
-int defaultForeground () {
- return OS.GetSysColor (OS.COLOR_BTNFACE);
-}
-
-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 ();
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_RANGE;
- OS.GetScrollInfo (handle, OS.SB_CTL, info);
- return info.nMax;
-}
-
-/**
- * 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 ();
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_RANGE;
- OS.GetScrollInfo (handle, OS.SB_CTL, info);
- return info.nMin;
-}
-
-/**
- * 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 single <em>selection</em> 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 ();
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_POS;
- OS.GetScrollInfo (handle, OS.SB_CTL, info);
- return info.nPos;
-}
-
-/**
- * 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 ();
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_PAGE;
- OS.GetScrollInfo (handle, OS.SB_CTL, info);
- if (info.nPage != 0) --info.nPage;
- return info.nPage;
-}
-
-/**
- * Removes the listener from the collection of listeners who will
- * be notified when the receiver's value changes.
- *
- * @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 setBounds (int x, int y, int width, int height, int flags) {
- super.setBounds (x, y, width, height, flags);
- /*
- * Bug in Windows. If the scroll bar is resized when it has focus,
- * the flashing cursor that is used to show that the scroll bar has
- * focus is not moved. The fix is to post a fake WM_SETFOCUS to
- * get the scroll bar to recompute the size of the flashing cursor.
- */
- if (OS.GetFocus () == handle) {
- OS.PostMessage (handle, OS.WM_SETFOCUS, 0, 0);
- }
-}
-
-public void setEnabled (boolean enabled) {
- checkWidget ();
- if (OS.IsWinCE) {
- super.setEnabled (enabled);
- } else {
- int flags = enabled ? OS.ESB_ENABLE_BOTH : OS.ESB_DISABLE_BOTH;
- OS.EnableScrollBar (handle, OS.SB_CTL, flags);
- }
- state &= ~DISABLED;
- if (!enabled) state |= DISABLED;
-}
-
-/**
- * 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 value which the receiver will allow
- * to be the argument which must be greater than or
- * equal to zero.
- *
- * @param value the new maximum (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 setMaximum (int value) {
- checkWidget ();
- if (value < 0) return;
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
- OS.GetScrollInfo (handle, OS.SB_CTL, info);
- if (value - info.nMin - info.nPage < 1) return;
- info.nMax = value;
- OS.SetScrollInfo (handle, OS.SB_CTL, info, (state & DISABLED) == 0);
-
- /*
- * Feature in Windows. Using SIF_DISABLENOSCROLL,
- * SetScrollInfo () can change enabled and disabled
- * state of the scroll bar causing a scroll bar that
- * was disabled by the application to become enabled.
- * The fix is to disable the scroll bar (again) when
- * the application has disabled the scroll bar.
- */
- if ((state & DISABLED) != 0) {
- if (OS.IsWinCE) {
- OS.EnableWindow (handle, false);
- } else {
- OS.EnableScrollBar (handle, OS.SB_CTL, OS.ESB_DISABLE_BOTH);
- }
- }
-
- /*
- * Bug in Windows. If the thumb is resized when it has focus,
- * the flashing cursor that is used to show that the scroll bar has
- * focus is not moved. The fix is to post a fake WM_SETFOCUS to
- * get the scroll bar to recompute the size of the flashing cursor.
- */
- if (OS.GetFocus () == handle) {
- OS.PostMessage (handle, OS.WM_SETFOCUS, 0, 0);
- }
-}
-
-/**
- * Sets the minimum value which the receiver will allow
- * to be the argument which must be greater than or
- * equal to zero.
- *
- * @param value the new minimum (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 setMinimum (int value) {
- checkWidget ();
- if (value < 0) return;
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
- OS.GetScrollInfo (handle, OS.SB_CTL, info);
- if (info.nMax - value - info.nPage < 1) return;
- info.nMin = value;
- OS.SetScrollInfo (handle, OS.SB_CTL, info, true);
-
- /*
- * Feature in Windows. Using SIF_DISABLENOSCROLL,
- * SetScrollInfo () can change enabled and disabled
- * state of the scroll bar causing a scroll bar that
- * was disabled by the application to become enabled.
- * The fix is to disable the scroll bar (again) when
- * the application has disabled the scroll bar.
- */
- if ((state & DISABLED) != 0) {
- if (OS.IsWinCE) {
- OS.EnableWindow (handle, false);
- } else {
- OS.EnableScrollBar (handle, OS.SB_CTL, OS.ESB_DISABLE_BOTH);
- }
- }
-
- /*
- * Bug in Windows. If the thumb is resized when it has focus,
- * the flashing cursor that is used to show that the scroll bar has
- * focus is not moved. The fix is to post a fake WM_SETFOCUS to
- * get the scroll bar to recompute the size of the flashing cursor.
- */
- if (OS.GetFocus () == handle) {
- OS.PostMessage (handle, OS.WM_SETFOCUS, 0, 0);
- }
-}
-
-/**
- * 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.
- *
- * @return 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 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 ();
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_POS;
- info.nPos = value;
- OS.SetScrollInfo (handle, OS.SB_CTL, info, true);
-}
-
-/**
- * Sets the size of the receiver's thumb relative to the
- * difference between its maximum and minimum values to the
- * argument which must be at least one.
- *
- * @param value the new thumb value (must be at least 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 ScrollBar
- */
-public void setThumb (int value) {
- checkWidget ();
-
- /* Position the thumb */
- if (value < 1) return;
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_PAGE | OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
- OS.GetScrollInfo (handle, OS.SB_CTL, info);
- if (info.nMax - info.nMin - value < 0) return;
- info.nPage = value;
- if (info.nPage != 0) info.nPage++;
- OS.SetScrollInfo (handle, OS.SB_CTL, info, true);
-
- /*
- * Feature in Windows. Using SIF_DISABLENOSCROLL,
- * SetScrollInfo () can change enabled and disabled
- * state of the scroll bar causing a scroll bar that
- * was disabled by the application to become enabled.
- * The fix is to disable the scroll bar (again) when
- * the application has disabled the scroll bar.
- */
- if ((state & DISABLED) != 0) {
- if (OS.IsWinCE) {
- OS.EnableWindow (handle, false);
- } else {
- OS.EnableScrollBar (handle, OS.SB_CTL, OS.ESB_DISABLE_BOTH);
- }
- }
-
- /*
- * Bug in Windows. If the thumb is resized when it has focus,
- * the flashing cursor that is used to show that the scroll bar has
- * focus is not moved. The fix is to post a fake WM_SETFOCUS to
- * get the scroll bar to recompute the size of the flashing cursor.
- */
- if (OS.GetFocus () == handle) {
- OS.PostMessage (handle, OS.WM_SETFOCUS, 0, 0);
- }
-}
-
-/**
- * Sets the receiver's selection, minimum value, maximum
- * value, thumb, increment and page increment all at once.
- * <p>
- * Note: This is equivalent 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 (maximum - minimum - thumb < 0) return;
- if (increment < 1) return;
- if (pageIncrement < 1) return;
- this.increment = increment;
- this.pageIncrement = pageIncrement;
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_POS | OS.SIF_PAGE | OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
- info.nPos = selection;
- info.nMin = minimum;
- info.nMax = maximum;
- info.nPage = thumb;
- if (info.nPage != 0) info.nPage++;
- OS.SetScrollInfo (handle, OS.SB_CTL, info, true);
-
- /*
- * Feature in Windows. Using SIF_DISABLENOSCROLL,
- * SetScrollInfo () can change enabled and disabled
- * state of the scroll bar causing a scroll bar that
- * was disabled by the application to become enabled.
- * The fix is to disable the scroll bar (again) when
- * the application has disabled the scroll bar.
- */
- if ((state & DISABLED) != 0) {
- if (OS.IsWinCE) {
- OS.EnableWindow (handle, false);
- } else {
- OS.EnableScrollBar (handle, OS.SB_CTL, OS.ESB_DISABLE_BOTH);
- }
- }
-
- /*
- * Bug in Windows. If the thumb is resized when it has focus,
- * the flashing cursor that is used to show that the scroll bar has
- * focus is not moved. The fix is to post a fake WM_SETFOCUS to
- * get the scroll bar to recompute the size of the flashing cursor.
- */
- if (OS.GetFocus () == handle) {
- OS.PostMessage (handle, OS.WM_SETFOCUS, 0, 0);
- }
-}
-
-int widgetExtStyle () {
- /*
- * Bug in Windows. If a scroll bar control is given a border,
- * dragging the scroll bar thumb eats away parts of the border
- * while the thumb is dragged. The fix is to clear border for
- * all scroll bars.
- */
- int bits = super.widgetExtStyle ();
- if ((style & SWT.BORDER) != 0) bits &= ~OS.WS_EX_CLIENTEDGE;
- return bits;
-}
-
-int widgetStyle () {
- int bits = super.widgetStyle () | OS.WS_TABSTOP;
- /*
- * Bug in Windows. If a scroll bar control is given a border,
- * dragging the scroll bar thumb eats away parts of the border
- * while the thumb is dragged. The fix is to clear WS_BORDER.
- */
- if ((style & SWT.BORDER) != 0) bits &= ~OS.WS_BORDER;
- if ((style & SWT.HORIZONTAL) != 0) return bits | OS.SBS_HORZ;
- return bits | OS.SBS_VERT;
-}
-
-TCHAR windowClass () {
- return ScrollBarClass;
-}
-
-int windowProc () {
- return ScrollBarProc;
-}
-
-LRESULT WM_LBUTTONDBLCLK (int wParam, int lParam) {
-
- /*
- * Feature in Windows. For some reason, capturing
- * the mouse after processing WM_LBUTTONDBLCLK for the
- * widget interferes with the normal mouse processing
- * for the widget. The fix is to avoid the automatic
- * mouse capture.
- */
-
- /*
- * Feature in Windows. Windows uses the WS_TABSTOP
- * style for the scroll bar to decide that focus
- * should be set during WM_LBUTTONDBLCLK. This is
- * not the desired behavior. The fix is to clear
- * and restore WS_TABSTOP so that Windows will not
- * assign focus.
- */
-
- int hwndCapture = OS.GetCapture ();
- int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- int newBits = oldBits & ~OS.WS_TABSTOP;
- OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
- LRESULT result = super.WM_LBUTTONDBLCLK (wParam, lParam);
- OS.SetWindowLong (handle, OS.GWL_STYLE, oldBits);
- if (OS.GetCapture () != hwndCapture) OS.SetCapture (hwndCapture);
- return result;
-}
-
-LRESULT WM_LBUTTONDOWN (int wParam, int lParam) {
-
- /*
- * Feature in Windows. For some reason, capturing
- * the mouse after processing WM_LBUTTONDOWN for the
- * widget interferes with the normal mouse processing
- * for the widget. The fix is to avoid the automatic
- * mouse capture.
- */
-
- /*
- * Feature in Windows. Windows uses the WS_TABSTOP
- * style for the scroll bar to decide that focus
- * should be set during WM_LBUTTONDOWN. This is
- * not the desired behavior. The fix is to clear
- * and restore WS_TABSTOP so that Windows will not
- * assign focus.
- */
-
- int hwndCapture = OS.GetCapture ();
- int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- int newBits = oldBits & ~OS.WS_TABSTOP;
- OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
- LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam);
- OS.SetWindowLong (handle, OS.GWL_STYLE, oldBits);
- if (OS.GetCapture () != hwndCapture) OS.SetCapture (hwndCapture);
- return result;
-}
-
-LRESULT wmScrollChild (int wParam, int lParam) {
-
- /* Do nothing when scrolling is ending */
- int code = wParam & 0xFFFF;
- if (code == OS.SB_ENDSCROLL) return null;
-
- /* Move the thumb */
- Event event = new Event ();
- SCROLLINFO info = new SCROLLINFO ();
- info.cbSize = SCROLLINFO.sizeof;
- info.fMask = OS.SIF_TRACKPOS | OS.SIF_POS | OS.SIF_RANGE;
- OS.GetScrollInfo (handle, OS.SB_CTL, info);
- info.fMask = OS.SIF_POS;
- switch (code) {
- case OS.SB_THUMBPOSITION:
- /*
- * Do not set the detail field to DRAG to
- * indicate that the dragging has ended.
- */
- info.nPos = info.nTrackPos;
- break;
- case OS.SB_THUMBTRACK:
- event.detail = SWT.DRAG;
- info.nPos = info.nTrackPos;
- break;
- case OS.SB_TOP:
- event.detail = SWT.HOME;
- info.nPos = info.nMin;
- break;
- case OS.SB_BOTTOM:
- event.detail = SWT.END;
- info.nPos = info.nMax;
- break;
- case OS.SB_LINEDOWN:
- event.detail = SWT.ARROW_DOWN;
- info.nPos += increment;
- break;
- case OS.SB_LINEUP:
- event.detail = SWT.ARROW_UP;
- info.nPos = Math.max (info.nMin, info.nPos - increment);
- break;
- case OS.SB_PAGEDOWN:
- event.detail = SWT.PAGE_DOWN;
- info.nPos += pageIncrement;
- break;
- case OS.SB_PAGEUP:
- event.detail = SWT.PAGE_UP;
- info.nPos = Math.max (info.nMin, info.nPos - pageIncrement);
- break;
- }
- OS.SetScrollInfo (handle, OS.SB_CTL, info, true);
-
- /*
- * Send the event because WM_HSCROLL and
- * WM_VSCROLL are sent from a modal message
- * loop in Windows that is active when the
- * user is scrolling.
- */
- sendEvent (SWT.Selection, event);
- // the widget could be destroyed at this point
- return null;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.events.*; + +/** + * 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 <em>selection</em> 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 + */ +public class Slider extends Control { + int increment, pageIncrement; + static final int ScrollBarProc; + static final TCHAR ScrollBarClass = new TCHAR (0, "SCROLLBAR", true); + static { + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, ScrollBarClass, lpWndClass); + ScrollBarProc = lpWndClass.lpfnWndProc; + } + +/** + * 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 receiver's value changes, 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>0</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 + * + * @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); +} + +int callWindowProc (int msg, int wParam, int lParam) { + if (handle == 0) return 0; + return OS.CallWindowProc (ScrollBarProc, handle, msg, wParam, lParam); +} + +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 border = getBorderWidth (); + int width = border * 2, height = border * 2; + if ((style & SWT.HORIZONTAL) != 0) { + width += OS.GetSystemMetrics (OS.SM_CXHSCROLL) * 10; + height += OS.GetSystemMetrics (OS.SM_CYHSCROLL); + } else { + width += OS.GetSystemMetrics (OS.SM_CXVSCROLL); + height += OS.GetSystemMetrics (OS.SM_CYVSCROLL) * 10; + } + if (wHint != SWT.DEFAULT) width = wHint + (border * 2); + if (hHint != SWT.DEFAULT) height = hHint + (border * 2); + return new Point (width, height); +} + +void createWidget () { + super.createWidget (); + increment = 1; + pageIncrement = 10; + /* + * Set the intial values of the maximum + * to 100 and the thumb to 10. Note that + * info.nPage needs to be 11 in order to + * get a thumb that is 10. + */ + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_ALL; + info.nMax = 100; + info.nPage = 11; + OS.SetScrollInfo (handle, OS.SB_CTL, info, true); +} + +int defaultBackground () { + return OS.GetSysColor (OS.COLOR_SCROLLBAR); +} + +int defaultForeground () { + return OS.GetSysColor (OS.COLOR_BTNFACE); +} + +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 (); + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_RANGE; + OS.GetScrollInfo (handle, OS.SB_CTL, info); + return info.nMax; +} + +/** + * 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 (); + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_RANGE; + OS.GetScrollInfo (handle, OS.SB_CTL, info); + return info.nMin; +} + +/** + * 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 single <em>selection</em> 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 (); + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_POS; + OS.GetScrollInfo (handle, OS.SB_CTL, info); + return info.nPos; +} + +/** + * 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 (); + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_PAGE; + OS.GetScrollInfo (handle, OS.SB_CTL, info); + if (info.nPage != 0) --info.nPage; + return info.nPage; +} + +/** + * Removes the listener from the collection of listeners who will + * be notified when the receiver's value changes. + * + * @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 setBounds (int x, int y, int width, int height, int flags) { + super.setBounds (x, y, width, height, flags); + /* + * Bug in Windows. If the scroll bar is resized when it has focus, + * the flashing cursor that is used to show that the scroll bar has + * focus is not moved. The fix is to post a fake WM_SETFOCUS to + * get the scroll bar to recompute the size of the flashing cursor. + */ + if (OS.GetFocus () == handle) { + OS.PostMessage (handle, OS.WM_SETFOCUS, 0, 0); + } +} + +public void setEnabled (boolean enabled) { + checkWidget (); + if (OS.IsWinCE) { + super.setEnabled (enabled); + } else { + int flags = enabled ? OS.ESB_ENABLE_BOTH : OS.ESB_DISABLE_BOTH; + OS.EnableScrollBar (handle, OS.SB_CTL, flags); + } + state &= ~DISABLED; + if (!enabled) state |= DISABLED; +} + +/** + * 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 value which the receiver will allow + * to be the argument which must be greater than or + * equal to zero. + * + * @param value the new maximum (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 setMaximum (int value) { + checkWidget (); + if (value < 0) return; + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL; + OS.GetScrollInfo (handle, OS.SB_CTL, info); + if (value - info.nMin - info.nPage < 1) return; + info.nMax = value; + OS.SetScrollInfo (handle, OS.SB_CTL, info, (state & DISABLED) == 0); + + /* + * Feature in Windows. Using SIF_DISABLENOSCROLL, + * SetScrollInfo () can change enabled and disabled + * state of the scroll bar causing a scroll bar that + * was disabled by the application to become enabled. + * The fix is to disable the scroll bar (again) when + * the application has disabled the scroll bar. + */ + if ((state & DISABLED) != 0) { + if (OS.IsWinCE) { + OS.EnableWindow (handle, false); + } else { + OS.EnableScrollBar (handle, OS.SB_CTL, OS.ESB_DISABLE_BOTH); + } + } + + /* + * Bug in Windows. If the thumb is resized when it has focus, + * the flashing cursor that is used to show that the scroll bar has + * focus is not moved. The fix is to post a fake WM_SETFOCUS to + * get the scroll bar to recompute the size of the flashing cursor. + */ + if (OS.GetFocus () == handle) { + OS.PostMessage (handle, OS.WM_SETFOCUS, 0, 0); + } +} + +/** + * Sets the minimum value which the receiver will allow + * to be the argument which must be greater than or + * equal to zero. + * + * @param value the new minimum (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 setMinimum (int value) { + checkWidget (); + if (value < 0) return; + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL; + OS.GetScrollInfo (handle, OS.SB_CTL, info); + if (info.nMax - value - info.nPage < 1) return; + info.nMin = value; + OS.SetScrollInfo (handle, OS.SB_CTL, info, true); + + /* + * Feature in Windows. Using SIF_DISABLENOSCROLL, + * SetScrollInfo () can change enabled and disabled + * state of the scroll bar causing a scroll bar that + * was disabled by the application to become enabled. + * The fix is to disable the scroll bar (again) when + * the application has disabled the scroll bar. + */ + if ((state & DISABLED) != 0) { + if (OS.IsWinCE) { + OS.EnableWindow (handle, false); + } else { + OS.EnableScrollBar (handle, OS.SB_CTL, OS.ESB_DISABLE_BOTH); + } + } + + /* + * Bug in Windows. If the thumb is resized when it has focus, + * the flashing cursor that is used to show that the scroll bar has + * focus is not moved. The fix is to post a fake WM_SETFOCUS to + * get the scroll bar to recompute the size of the flashing cursor. + */ + if (OS.GetFocus () == handle) { + OS.PostMessage (handle, OS.WM_SETFOCUS, 0, 0); + } +} + +/** + * 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. + * + * @return 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 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 (); + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_POS; + info.nPos = value; + OS.SetScrollInfo (handle, OS.SB_CTL, info, true); +} + +/** + * Sets the size of the receiver's thumb relative to the + * difference between its maximum and minimum values to the + * argument which must be at least one. + * + * @param value the new thumb value (must be at least 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 ScrollBar + */ +public void setThumb (int value) { + checkWidget (); + + /* Position the thumb */ + if (value < 1) return; + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_PAGE | OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL; + OS.GetScrollInfo (handle, OS.SB_CTL, info); + if (info.nMax - info.nMin - value < 0) return; + info.nPage = value; + if (info.nPage != 0) info.nPage++; + OS.SetScrollInfo (handle, OS.SB_CTL, info, true); + + /* + * Feature in Windows. Using SIF_DISABLENOSCROLL, + * SetScrollInfo () can change enabled and disabled + * state of the scroll bar causing a scroll bar that + * was disabled by the application to become enabled. + * The fix is to disable the scroll bar (again) when + * the application has disabled the scroll bar. + */ + if ((state & DISABLED) != 0) { + if (OS.IsWinCE) { + OS.EnableWindow (handle, false); + } else { + OS.EnableScrollBar (handle, OS.SB_CTL, OS.ESB_DISABLE_BOTH); + } + } + + /* + * Bug in Windows. If the thumb is resized when it has focus, + * the flashing cursor that is used to show that the scroll bar has + * focus is not moved. The fix is to post a fake WM_SETFOCUS to + * get the scroll bar to recompute the size of the flashing cursor. + */ + if (OS.GetFocus () == handle) { + OS.PostMessage (handle, OS.WM_SETFOCUS, 0, 0); + } +} + +/** + * Sets the receiver's selection, minimum value, maximum + * value, thumb, increment and page increment all at once. + * <p> + * Note: This is equivalent 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 (maximum - minimum - thumb < 0) return; + if (increment < 1) return; + if (pageIncrement < 1) return; + this.increment = increment; + this.pageIncrement = pageIncrement; + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_POS | OS.SIF_PAGE | OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL; + info.nPos = selection; + info.nMin = minimum; + info.nMax = maximum; + info.nPage = thumb; + if (info.nPage != 0) info.nPage++; + OS.SetScrollInfo (handle, OS.SB_CTL, info, true); + + /* + * Feature in Windows. Using SIF_DISABLENOSCROLL, + * SetScrollInfo () can change enabled and disabled + * state of the scroll bar causing a scroll bar that + * was disabled by the application to become enabled. + * The fix is to disable the scroll bar (again) when + * the application has disabled the scroll bar. + */ + if ((state & DISABLED) != 0) { + if (OS.IsWinCE) { + OS.EnableWindow (handle, false); + } else { + OS.EnableScrollBar (handle, OS.SB_CTL, OS.ESB_DISABLE_BOTH); + } + } + + /* + * Bug in Windows. If the thumb is resized when it has focus, + * the flashing cursor that is used to show that the scroll bar has + * focus is not moved. The fix is to post a fake WM_SETFOCUS to + * get the scroll bar to recompute the size of the flashing cursor. + */ + if (OS.GetFocus () == handle) { + OS.PostMessage (handle, OS.WM_SETFOCUS, 0, 0); + } +} + +int widgetExtStyle () { + /* + * Bug in Windows. If a scroll bar control is given a border, + * dragging the scroll bar thumb eats away parts of the border + * while the thumb is dragged. The fix is to clear border for + * all scroll bars. + */ + int bits = super.widgetExtStyle (); + if ((style & SWT.BORDER) != 0) bits &= ~OS.WS_EX_CLIENTEDGE; + return bits; +} + +int widgetStyle () { + int bits = super.widgetStyle () | OS.WS_TABSTOP; + /* + * Bug in Windows. If a scroll bar control is given a border, + * dragging the scroll bar thumb eats away parts of the border + * while the thumb is dragged. The fix is to clear WS_BORDER. + */ + if ((style & SWT.BORDER) != 0) bits &= ~OS.WS_BORDER; + if ((style & SWT.HORIZONTAL) != 0) return bits | OS.SBS_HORZ; + return bits | OS.SBS_VERT; +} + +TCHAR windowClass () { + return ScrollBarClass; +} + +int windowProc () { + return ScrollBarProc; +} + +LRESULT WM_LBUTTONDBLCLK (int wParam, int lParam) { + + /* + * Feature in Windows. For some reason, capturing + * the mouse after processing WM_LBUTTONDBLCLK for the + * widget interferes with the normal mouse processing + * for the widget. The fix is to avoid the automatic + * mouse capture. + */ + + /* + * Feature in Windows. Windows uses the WS_TABSTOP + * style for the scroll bar to decide that focus + * should be set during WM_LBUTTONDBLCLK. This is + * not the desired behavior. The fix is to clear + * and restore WS_TABSTOP so that Windows will not + * assign focus. + */ + + int hwndCapture = OS.GetCapture (); + int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE); + int newBits = oldBits & ~OS.WS_TABSTOP; + OS.SetWindowLong (handle, OS.GWL_STYLE, newBits); + LRESULT result = super.WM_LBUTTONDBLCLK (wParam, lParam); + OS.SetWindowLong (handle, OS.GWL_STYLE, oldBits); + if (OS.GetCapture () != hwndCapture) OS.SetCapture (hwndCapture); + return result; +} + +LRESULT WM_LBUTTONDOWN (int wParam, int lParam) { + + /* + * Feature in Windows. For some reason, capturing + * the mouse after processing WM_LBUTTONDOWN for the + * widget interferes with the normal mouse processing + * for the widget. The fix is to avoid the automatic + * mouse capture. + */ + + /* + * Feature in Windows. Windows uses the WS_TABSTOP + * style for the scroll bar to decide that focus + * should be set during WM_LBUTTONDOWN. This is + * not the desired behavior. The fix is to clear + * and restore WS_TABSTOP so that Windows will not + * assign focus. + */ + + int hwndCapture = OS.GetCapture (); + int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE); + int newBits = oldBits & ~OS.WS_TABSTOP; + OS.SetWindowLong (handle, OS.GWL_STYLE, newBits); + LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam); + OS.SetWindowLong (handle, OS.GWL_STYLE, oldBits); + if (OS.GetCapture () != hwndCapture) OS.SetCapture (hwndCapture); + return result; +} + +LRESULT wmScrollChild (int wParam, int lParam) { + + /* Do nothing when scrolling is ending */ + int code = wParam & 0xFFFF; + if (code == OS.SB_ENDSCROLL) return null; + + /* Move the thumb */ + Event event = new Event (); + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_TRACKPOS | OS.SIF_POS | OS.SIF_RANGE; + OS.GetScrollInfo (handle, OS.SB_CTL, info); + info.fMask = OS.SIF_POS; + switch (code) { + case OS.SB_THUMBPOSITION: + /* + * Do not set the detail field to DRAG to + * indicate that the dragging has ended. + */ + info.nPos = info.nTrackPos; + break; + case OS.SB_THUMBTRACK: + event.detail = SWT.DRAG; + info.nPos = info.nTrackPos; + break; + case OS.SB_TOP: + event.detail = SWT.HOME; + info.nPos = info.nMin; + break; + case OS.SB_BOTTOM: + event.detail = SWT.END; + info.nPos = info.nMax; + break; + case OS.SB_LINEDOWN: + event.detail = SWT.ARROW_DOWN; + info.nPos += increment; + break; + case OS.SB_LINEUP: + event.detail = SWT.ARROW_UP; + info.nPos = Math.max (info.nMin, info.nPos - increment); + break; + case OS.SB_PAGEDOWN: + event.detail = SWT.PAGE_DOWN; + info.nPos += pageIncrement; + break; + case OS.SB_PAGEUP: + event.detail = SWT.PAGE_UP; + info.nPos = Math.max (info.nMin, info.nPos - pageIncrement); + break; + } + OS.SetScrollInfo (handle, OS.SB_CTL, info, true); + + /* + * Send the event because WM_HSCROLL and + * WM_VSCROLL are sent from a modal message + * loop in Windows that is active when the + * user is scrolling. + */ + sendEvent (SWT.Selection, event); + // the widget could be destroyed at this point + return null; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TabFolder.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TabFolder.java index 2bc870aabc..976e89f79f 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TabFolder.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TabFolder.java @@ -1,792 +1,792 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.events.*;
-
-/**
- * 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>(none)</dd>
- * <dt><b>Events:</b></dt>
- * <dd>Selection</dd>
- * </dl>
- * <p>
- * IMPORTANT: This class is <em>not</em> intended to be subclassed.
- * </p>
- */
-public class TabFolder extends Composite {
- TabItem [] items;
- ImageList imageList;
- static final int TabFolderProc;
- static final TCHAR TabFolderClass = new TCHAR (0, "SWT_" + OS.WC_TABCONTROL, true);
- static {
- /*
- * Feature in Windows. The tab control window class
- * uses the CS_HREDRAW and CS_VREDRAW style bits to
- * force a full redraw of the control and all children
- * when resized. This causes flashing. The fix is to
- * register a new window class without these bits and
- * implement special code that damages only the exposed
- * area.
- */
- WNDCLASS lpWndClass = new WNDCLASS ();
- TCHAR WC_TABCONTROL = new TCHAR (0, OS.WC_TABCONTROL, true);
- OS.GetClassInfo (0, WC_TABCONTROL, lpWndClass);
- TabFolderProc = lpWndClass.lpfnWndProc;
- int hInstance = OS.GetModuleHandle (null);
- if (!OS.GetClassInfo (hInstance, TabFolderClass, lpWndClass)) {
- int hHeap = OS.GetProcessHeap ();
- lpWndClass.hInstance = hInstance;
- lpWndClass.style &= ~(OS.CS_HREDRAW | OS.CS_VREDRAW);
- int byteCount = TabFolderClass.length () * TCHAR.sizeof;
- int lpszClassName = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- OS.MoveMemory (lpszClassName, TabFolderClass, byteCount);
- lpWndClass.lpszClassName = lpszClassName;
- OS.RegisterClass (lpWndClass);
-// OS.HeapFree (hHeap, 0, lpszClassName);
- }
- }
-
-/**
- * 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 TabFolder (Composite parent, int style) {
- super (parent, checkStyle (style));
-}
-
-/**
- * Adds the listener to the collection of listeners who will
- * be notified when the receiver's selection changes, 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
- *
- * @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);
-}
-
-int callWindowProc (int msg, int wParam, int lParam) {
- if (handle == 0) return 0;
- return OS.CallWindowProc (TabFolderProc, handle, msg, wParam, lParam);
-}
-
-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 ();
- RECT insetRect = new RECT (), itemRect = new RECT ();
- OS.SendMessage (handle, OS.TCM_ADJUSTRECT, 0, insetRect);
- int width = insetRect.left - insetRect.right, height = 0;
- int count = OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
- if (count != 0) {
- OS.SendMessage (handle, OS.TCM_GETITEMRECT, count - 1, itemRect);
- width = Math.max (width, itemRect.right - insetRect.right);
- }
- Point size = null;
- if (layout != null) {
- size = layout.computeSize (this, wHint, hHint, changed);
- } 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;
- width = Math.max (width, size.x);
- height = Math.max (height, size.y);
- 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) {
- checkWidget ();
- RECT rect = new RECT ();
- OS.SetRect (rect, x, y, x + width, y + height);
- OS.SendMessage (handle, OS.TCM_ADJUSTRECT, 1, rect);
- int border = getBorderWidth ();
- rect.left -= border; rect.right += border;
- rect.top -= border; rect.bottom += border;
- int newWidth = rect.right - rect.left;
- int newHeight = rect.bottom - rect.top;
- return new Rectangle (rect.left, rect.top, newWidth, newHeight);
-}
-
-void createItem (TabItem item, int index) {
- int count = OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
- 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;
- }
- TCITEM tcItem = new TCITEM ();
- if (OS.SendMessage (handle, OS.TCM_INSERTITEM, index, tcItem) == -1) {
- error (SWT.ERROR_ITEM_NOT_ADDED);
- }
- System.arraycopy (items, index, items, index + 1, count - index);
- items [index] = item;
-
- /*
- * Send a selection event when the item that is added becomes
- * the new selection. This only happens when the first item
- * is added.
- */
- if (count == 0) {
- Event event = new Event ();
- event.item = items [0];
- sendEvent (SWT.Selection, event);
- // the widget could be destroyed at this point
- }
-}
-
-void createHandle () {
- super.createHandle ();
- state &= ~CANVAS;
- /*
- * Feature in Windows. Despite the fact that the
- * tool tip text contains \r\n, the tooltip will
- * not honour the new line unless TTM_SETMAXTIPWIDTH
- * is set. The fix is to set TTM_SETMAXTIPWIDTH to
- * a large value.
- */
- int hwndToolTip = OS.SendMessage (handle, OS.TCM_GETTOOLTIPS, 0, 0);
- OS.SendMessage (hwndToolTip, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
-}
-
-void createWidget () {
- super.createWidget ();
- items = new TabItem [4];
-}
-
-void destroyItem (TabItem item) {
- int count = OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
- int index = 0;
- while (index < count) {
- if (items [index] == item) break;
- index++;
- }
- if (index == count) return;
- int selectionIndex = OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0);
- if (OS.SendMessage (handle, OS.TCM_DELETEITEM, index, 0) == 0) {
- error (SWT.ERROR_ITEM_NOT_REMOVED);
- }
- System.arraycopy (items, index + 1, items, index, --count - index);
- items [count] = null;
- if (count == 0) {
- if (imageList != null) {
- OS.SendMessage (handle, OS.TCM_SETIMAGELIST, 0, 0);
- Display display = getDisplay ();
- display.releaseImageList (imageList);
- }
- imageList = null;
- items = new TabItem [4];
- }
- if (count > 0 && index == selectionIndex) {
- setSelection (Math.max (0, selectionIndex - 1));
- selectionIndex = getSelectionIndex ();
- if (selectionIndex != -1) {
- Event event = new Event ();
- event.item = items [selectionIndex];
- sendEvent (SWT.Selection, event);
- // the widget could be destroyed at this point
- }
- }
-}
-
-public Rectangle getClientArea () {
- checkWidget ();
- forceResize ();
- RECT rect = new RECT ();
- OS.GetClientRect (handle, rect);
- OS.SendMessage (handle, OS.TCM_ADJUSTRECT, 0, rect);
- int width = rect.right - rect.left;
- int height = rect.bottom - rect.top;
- return new Rectangle (rect.left, rect.top, 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 = OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
- if (!(0 <= index && index < count)) 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 OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
-}
-
-/**
- * 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 = OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
- 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 = OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0);
- 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 ();
- return OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0);
-}
-
-int imageIndex (Image image) {
- if (image == null) return OS.I_IMAGENONE;
- if (imageList == null) {
- Rectangle bounds = image.getBounds ();
- imageList = getDisplay ().getImageList (new Point (bounds.width, bounds.height));
- int index = imageList.indexOf (image);
- if (index == -1) index = imageList.add (image);
- int hImageList = imageList.getHandle ();
- OS.SendMessage (handle, OS.TCM_SETIMAGELIST, 0, hImageList);
- return index;
- }
- int index = imageList.indexOf (image);
- if (index != -1) return index;
- return imageList.add (image);
-}
-
-/**
- * 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 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 (TabItem item) {
- checkWidget ();
- if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
- int count = OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
- 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 = OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
- 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);
-}
-
-boolean mnemonicHit (char key) {
- for (int i=0; i<items.length; i++) {
- TabItem item = items [i];
- if (item != null) {
- char ch = findMnemonic (item.getText ());
- if (Character.toUpperCase (key) == Character.toUpperCase (ch)) {
- if (setFocus ()) {
- setSelection (i, true);
- return true;
- }
- }
- }
- }
- return false;
-}
-
-boolean mnemonicMatch (char key) {
- for (int i=0; i<items.length; i++) {
- TabItem item = items [i];
- if (item != null) {
- char ch = findMnemonic (item.getText ());
- if (Character.toUpperCase (key) == Character.toUpperCase (ch)) {
- return true;
- }
- }
- }
- return false;
-}
-
-void releaseWidget () {
- int count = OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
- for (int i=0; i<count; i++) {
- TabItem item = items [i];
- if (!item.isDisposed ()) item.releaseResources ();
- }
- items = null;
- if (imageList != null) {
- OS.SendMessage (handle, OS.TCM_SETIMAGELIST, 0, 0);
- Display display = getDisplay ();
- display.releaseImageList (imageList);
- }
- imageList = null;
- super.releaseWidget ();
-}
-
-/**
- * Removes the listener from the collection of listeners who will
- * be notified when the receiver's selection changes.
- *
- * @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 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 SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if 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);
- return;
- }
- for (int i=items.length-1; i>=0; --i) {
- int index = indexOf (items [i]);
- if (index != -1) setSelection (index);
- }
-}
-
-/**
- * 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 selected 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 ();
- setSelection (index, false);
-}
-
-void setSelection (int index, boolean notify) {
- int oldIndex = OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0);
- if (oldIndex != -1) {
- TabItem item = items [oldIndex];
- Control control = item.control;
- if (control != null && !control.isDisposed ()) {
- control.setVisible (false);
- }
- }
- OS.SendMessage (handle, OS.TCM_SETCURSEL, index, 0);
- int newIndex = OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0);
- if (newIndex != -1) {
- TabItem item = items [newIndex];
- Control control = item.control;
- if (control != null && !control.isDisposed ()) {
- control.setBounds (getClientArea ());
- control.setVisible (true);
- }
- if (notify) {
- Event event = new Event ();
- event.item = item;
- sendEvent (SWT.Selection, event);
- }
- }
-}
-
-String toolTipText (NMTTDISPINFO hdr) {
- if ((hdr.uFlags & OS.TTF_IDISHWND) != 0) {
- return null;
- }
- int index = hdr.idFrom;
- int hwndToolTip = OS.SendMessage (handle, OS.TCM_GETTOOLTIPS, 0, 0);
- if (hwndToolTip == hdr.hwndFrom) {
- if (toolTipText != null) return "";
- if (0 <= index && index < items.length) {
- TabItem item = items [index];
- if (item != null) return item.toolTipText;
- }
- }
- return super.toolTipText (hdr);
-}
-
-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);
- return index == getSelectionIndex ();
-}
-
-int widgetStyle () {
- /*
- * Bug in Windows. Under certain circumstances,
- * when TCM_SETITEM is used to change the text
- * in a tab item, the tab folder draws on top
- * of the client area. The fix is ensure that
- * this cannot happen by setting WS_CLIPCHILDREN.
- */
- int bits = super.widgetStyle () | OS.WS_CLIPCHILDREN;
- if ((style & SWT.NO_FOCUS) != 0) bits |= OS.TCS_FOCUSNEVER;
- return bits | OS.TCS_TABS | OS.TCS_TOOLTIPS;
-}
-
-TCHAR windowClass () {
- return TabFolderClass;
-}
-
-int windowProc () {
- return TabFolderProc;
-}
-
-LRESULT WM_GETDLGCODE (int wParam, int lParam) {
- LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
- /*
- * Return DLGC_BUTTON so that mnemonics will be
- * processed without needing to press the ALT key
- * when the widget has focus.
- */
- if (result != null) return result;
- return new LRESULT (OS.DLGC_BUTTON);
-}
-
-LRESULT WM_NCHITTEST (int wParam, int lParam) {
- LRESULT result = super.WM_NCHITTEST (wParam, lParam);
- if (result != null) return result;
- /*
- * Feature in Windows. The tab control implements
- * WM_NCHITTEST to return HTCLIENT when the cursor
- * is inside the tab buttons. This causes mouse
- * events like WM_MOUSEMOVE to be delivered to the
- * parent. Also, tool tips for the tab control are
- * never invoked because tool tips rely on mouse
- * events to be delivered to the window that wants
- * to display the tool tip. The fix is to call the
- * default window proc that returns HTCLIENT when
- * the mouse is in the client area.
- */
- int hittest = OS.DefWindowProc (handle, OS.WM_NCHITTEST, wParam, lParam);
- return new LRESULT (hittest);
-}
-
-LRESULT WM_NOTIFY (int wParam, int lParam) {
- /*
- * Feature in Windows. When the tab folder window
- * proc processes WM_NOTIFY, it forwards this
- * message to its parent. This is done so that
- * children of this control that send this message
- * type to their parent will notify not only
- * this control but also the parent of this control,
- * which is typically the application window and
- * the window that is looking for the message.
- * If the control did not forward the message,
- * applications would have to subclass the control
- * window to see the message. Because the control
- * window is subclassed by SWT, the message
- * is delivered twice, once by SWT and once when
- * the message is forwarded by the window proc.
- * The fix is to avoid calling the window proc
- * for this control.
- */
- LRESULT result = super.WM_NOTIFY (wParam, lParam);
- if (result != null) return result;
- return LRESULT.ZERO;
-}
-
-LRESULT WM_SIZE (int wParam, int lParam) {
- LRESULT result = super.WM_SIZE (wParam, lParam);
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the resize
- * event. If this happens, end the processing of the
- * Windows message by returning the result of the
- * WM_SIZE message.
- */
- if (isDisposed ()) return result;
- int index = OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0);
- if (index != -1) {
- TabItem item = items [index];
- Control control = item.control;
- if (control != null && !control.isDisposed ()) {
- control.setBounds (getClientArea ());
- }
- }
- return result;
-}
-
-LRESULT WM_WINDOWPOSCHANGING (int wParam, int lParam) {
- LRESULT result = super.WM_WINDOWPOSCHANGING (wParam, lParam);
- if (result != null) return result;
- if (!OS.IsWindowVisible (handle)) return result;
- WINDOWPOS lpwp = new WINDOWPOS ();
- OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof);
- if ((lpwp.flags & (OS.SWP_NOSIZE | OS.SWP_NOREDRAW)) != 0) {
- return result;
- }
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & OS.TCS_MULTILINE) != 0) {
- OS.InvalidateRect (handle, null, true);
- return result;
- }
- RECT rect = new RECT ();
- OS.SetRect (rect, 0, 0, lpwp.cx, lpwp.cy);
- OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, rect);
- int newWidth = rect.right - rect.left;
- int newHeight = rect.bottom - rect.top;
- OS.GetClientRect (handle, rect);
- int oldWidth = rect.right - rect.left;
- int oldHeight = rect.bottom - rect.top;
- if (newWidth == oldWidth && newHeight == oldHeight) {
- return result;
- }
- RECT inset = new RECT ();
- OS.SendMessage (handle, OS.TCM_ADJUSTRECT, 0, inset);
- int marginX = -inset.right, marginY = -inset.bottom;
- if (newWidth != oldWidth) {
- int left = oldWidth;
- if (newWidth < oldWidth) left = newWidth;
- OS.SetRect (rect, left - marginX, 0, newWidth, newHeight);
- OS.InvalidateRect (handle, rect, true);
- }
- if (newHeight != oldHeight) {
- int bottom = oldHeight;
- if (newHeight < oldHeight) bottom = newHeight;
- if (newWidth < oldWidth) oldWidth -= marginX;
- OS.SetRect (rect, 0, bottom - marginY, oldWidth, newHeight);
- OS.InvalidateRect (handle, rect, true);
- }
- return result;
-}
-
-LRESULT wmNotifyChild (int wParam, int lParam) {
- NMHDR hdr = new NMHDR ();
- OS.MoveMemory (hdr, lParam, NMHDR.sizeof);
- int code = hdr.code;
- switch (code) {
- case OS.TCN_SELCHANGE:
- case OS.TCN_SELCHANGING:
- TabItem item = null;
- int index = OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0);
- if (index != -1) item = items [index];
- if (item != null) {
- Control control = item.control;
- if (control != null && !control.isDisposed ()) {
- if (code == OS.TCN_SELCHANGE) {
- control.setBounds (getClientArea ());
- }
- control.setVisible (code == OS.TCN_SELCHANGE);
- }
- }
- if (code == OS.TCN_SELCHANGE) {
- Event event = new Event ();
- event.item = item;
- postEvent (SWT.Selection, event);
- }
- }
- return super.wmNotifyChild (wParam, lParam);
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.events.*; + +/** + * 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>(none)</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection</dd> + * </dl> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + */ +public class TabFolder extends Composite { + TabItem [] items; + ImageList imageList; + static final int TabFolderProc; + static final TCHAR TabFolderClass = new TCHAR (0, "SWT_" + OS.WC_TABCONTROL, true); + static { + /* + * Feature in Windows. The tab control window class + * uses the CS_HREDRAW and CS_VREDRAW style bits to + * force a full redraw of the control and all children + * when resized. This causes flashing. The fix is to + * register a new window class without these bits and + * implement special code that damages only the exposed + * area. + */ + WNDCLASS lpWndClass = new WNDCLASS (); + TCHAR WC_TABCONTROL = new TCHAR (0, OS.WC_TABCONTROL, true); + OS.GetClassInfo (0, WC_TABCONTROL, lpWndClass); + TabFolderProc = lpWndClass.lpfnWndProc; + int hInstance = OS.GetModuleHandle (null); + if (!OS.GetClassInfo (hInstance, TabFolderClass, lpWndClass)) { + int hHeap = OS.GetProcessHeap (); + lpWndClass.hInstance = hInstance; + lpWndClass.style &= ~(OS.CS_HREDRAW | OS.CS_VREDRAW); + int byteCount = TabFolderClass.length () * TCHAR.sizeof; + int lpszClassName = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + OS.MoveMemory (lpszClassName, TabFolderClass, byteCount); + lpWndClass.lpszClassName = lpszClassName; + OS.RegisterClass (lpWndClass); +// OS.HeapFree (hHeap, 0, lpszClassName); + } + } + +/** + * 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 TabFolder (Composite parent, int style) { + super (parent, checkStyle (style)); +} + +/** + * Adds the listener to the collection of listeners who will + * be notified when the receiver's selection changes, 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 + * + * @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); +} + +int callWindowProc (int msg, int wParam, int lParam) { + if (handle == 0) return 0; + return OS.CallWindowProc (TabFolderProc, handle, msg, wParam, lParam); +} + +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 (); + RECT insetRect = new RECT (), itemRect = new RECT (); + OS.SendMessage (handle, OS.TCM_ADJUSTRECT, 0, insetRect); + int width = insetRect.left - insetRect.right, height = 0; + int count = OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0); + if (count != 0) { + OS.SendMessage (handle, OS.TCM_GETITEMRECT, count - 1, itemRect); + width = Math.max (width, itemRect.right - insetRect.right); + } + Point size = null; + if (layout != null) { + size = layout.computeSize (this, wHint, hHint, changed); + } 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; + width = Math.max (width, size.x); + height = Math.max (height, size.y); + 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) { + checkWidget (); + RECT rect = new RECT (); + OS.SetRect (rect, x, y, x + width, y + height); + OS.SendMessage (handle, OS.TCM_ADJUSTRECT, 1, rect); + int border = getBorderWidth (); + rect.left -= border; rect.right += border; + rect.top -= border; rect.bottom += border; + int newWidth = rect.right - rect.left; + int newHeight = rect.bottom - rect.top; + return new Rectangle (rect.left, rect.top, newWidth, newHeight); +} + +void createItem (TabItem item, int index) { + int count = OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0); + 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; + } + TCITEM tcItem = new TCITEM (); + if (OS.SendMessage (handle, OS.TCM_INSERTITEM, index, tcItem) == -1) { + error (SWT.ERROR_ITEM_NOT_ADDED); + } + System.arraycopy (items, index, items, index + 1, count - index); + items [index] = item; + + /* + * Send a selection event when the item that is added becomes + * the new selection. This only happens when the first item + * is added. + */ + if (count == 0) { + Event event = new Event (); + event.item = items [0]; + sendEvent (SWT.Selection, event); + // the widget could be destroyed at this point + } +} + +void createHandle () { + super.createHandle (); + state &= ~CANVAS; + /* + * Feature in Windows. Despite the fact that the + * tool tip text contains \r\n, the tooltip will + * not honour the new line unless TTM_SETMAXTIPWIDTH + * is set. The fix is to set TTM_SETMAXTIPWIDTH to + * a large value. + */ + int hwndToolTip = OS.SendMessage (handle, OS.TCM_GETTOOLTIPS, 0, 0); + OS.SendMessage (hwndToolTip, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF); +} + +void createWidget () { + super.createWidget (); + items = new TabItem [4]; +} + +void destroyItem (TabItem item) { + int count = OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0); + int index = 0; + while (index < count) { + if (items [index] == item) break; + index++; + } + if (index == count) return; + int selectionIndex = OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0); + if (OS.SendMessage (handle, OS.TCM_DELETEITEM, index, 0) == 0) { + error (SWT.ERROR_ITEM_NOT_REMOVED); + } + System.arraycopy (items, index + 1, items, index, --count - index); + items [count] = null; + if (count == 0) { + if (imageList != null) { + OS.SendMessage (handle, OS.TCM_SETIMAGELIST, 0, 0); + Display display = getDisplay (); + display.releaseImageList (imageList); + } + imageList = null; + items = new TabItem [4]; + } + if (count > 0 && index == selectionIndex) { + setSelection (Math.max (0, selectionIndex - 1)); + selectionIndex = getSelectionIndex (); + if (selectionIndex != -1) { + Event event = new Event (); + event.item = items [selectionIndex]; + sendEvent (SWT.Selection, event); + // the widget could be destroyed at this point + } + } +} + +public Rectangle getClientArea () { + checkWidget (); + forceResize (); + RECT rect = new RECT (); + OS.GetClientRect (handle, rect); + OS.SendMessage (handle, OS.TCM_ADJUSTRECT, 0, rect); + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + return new Rectangle (rect.left, rect.top, 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 = OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0); + if (!(0 <= index && index < count)) 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 OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0); +} + +/** + * 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 = OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0); + 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 = OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0); + 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 (); + return OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0); +} + +int imageIndex (Image image) { + if (image == null) return OS.I_IMAGENONE; + if (imageList == null) { + Rectangle bounds = image.getBounds (); + imageList = getDisplay ().getImageList (new Point (bounds.width, bounds.height)); + int index = imageList.indexOf (image); + if (index == -1) index = imageList.add (image); + int hImageList = imageList.getHandle (); + OS.SendMessage (handle, OS.TCM_SETIMAGELIST, 0, hImageList); + return index; + } + int index = imageList.indexOf (image); + if (index != -1) return index; + return imageList.add (image); +} + +/** + * 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 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 (TabItem item) { + checkWidget (); + if (item == null) error (SWT.ERROR_NULL_ARGUMENT); + int count = OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0); + 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 = OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0); + 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); +} + +boolean mnemonicHit (char key) { + for (int i=0; i<items.length; i++) { + TabItem item = items [i]; + if (item != null) { + char ch = findMnemonic (item.getText ()); + if (Character.toUpperCase (key) == Character.toUpperCase (ch)) { + if (setFocus ()) { + setSelection (i, true); + return true; + } + } + } + } + return false; +} + +boolean mnemonicMatch (char key) { + for (int i=0; i<items.length; i++) { + TabItem item = items [i]; + if (item != null) { + char ch = findMnemonic (item.getText ()); + if (Character.toUpperCase (key) == Character.toUpperCase (ch)) { + return true; + } + } + } + return false; +} + +void releaseWidget () { + int count = OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0); + for (int i=0; i<count; i++) { + TabItem item = items [i]; + if (!item.isDisposed ()) item.releaseResources (); + } + items = null; + if (imageList != null) { + OS.SendMessage (handle, OS.TCM_SETIMAGELIST, 0, 0); + Display display = getDisplay (); + display.releaseImageList (imageList); + } + imageList = null; + super.releaseWidget (); +} + +/** + * Removes the listener from the collection of listeners who will + * be notified when the receiver's selection changes. + * + * @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 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 SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if 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); + return; + } + for (int i=items.length-1; i>=0; --i) { + int index = indexOf (items [i]); + if (index != -1) setSelection (index); + } +} + +/** + * 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 selected 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 (); + setSelection (index, false); +} + +void setSelection (int index, boolean notify) { + int oldIndex = OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0); + if (oldIndex != -1) { + TabItem item = items [oldIndex]; + Control control = item.control; + if (control != null && !control.isDisposed ()) { + control.setVisible (false); + } + } + OS.SendMessage (handle, OS.TCM_SETCURSEL, index, 0); + int newIndex = OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0); + if (newIndex != -1) { + TabItem item = items [newIndex]; + Control control = item.control; + if (control != null && !control.isDisposed ()) { + control.setBounds (getClientArea ()); + control.setVisible (true); + } + if (notify) { + Event event = new Event (); + event.item = item; + sendEvent (SWT.Selection, event); + } + } +} + +String toolTipText (NMTTDISPINFO hdr) { + if ((hdr.uFlags & OS.TTF_IDISHWND) != 0) { + return null; + } + int index = hdr.idFrom; + int hwndToolTip = OS.SendMessage (handle, OS.TCM_GETTOOLTIPS, 0, 0); + if (hwndToolTip == hdr.hwndFrom) { + if (toolTipText != null) return ""; + if (0 <= index && index < items.length) { + TabItem item = items [index]; + if (item != null) return item.toolTipText; + } + } + return super.toolTipText (hdr); +} + +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); + return index == getSelectionIndex (); +} + +int widgetStyle () { + /* + * Bug in Windows. Under certain circumstances, + * when TCM_SETITEM is used to change the text + * in a tab item, the tab folder draws on top + * of the client area. The fix is ensure that + * this cannot happen by setting WS_CLIPCHILDREN. + */ + int bits = super.widgetStyle () | OS.WS_CLIPCHILDREN; + if ((style & SWT.NO_FOCUS) != 0) bits |= OS.TCS_FOCUSNEVER; + return bits | OS.TCS_TABS | OS.TCS_TOOLTIPS; +} + +TCHAR windowClass () { + return TabFolderClass; +} + +int windowProc () { + return TabFolderProc; +} + +LRESULT WM_GETDLGCODE (int wParam, int lParam) { + LRESULT result = super.WM_GETDLGCODE (wParam, lParam); + /* + * Return DLGC_BUTTON so that mnemonics will be + * processed without needing to press the ALT key + * when the widget has focus. + */ + if (result != null) return result; + return new LRESULT (OS.DLGC_BUTTON); +} + +LRESULT WM_NCHITTEST (int wParam, int lParam) { + LRESULT result = super.WM_NCHITTEST (wParam, lParam); + if (result != null) return result; + /* + * Feature in Windows. The tab control implements + * WM_NCHITTEST to return HTCLIENT when the cursor + * is inside the tab buttons. This causes mouse + * events like WM_MOUSEMOVE to be delivered to the + * parent. Also, tool tips for the tab control are + * never invoked because tool tips rely on mouse + * events to be delivered to the window that wants + * to display the tool tip. The fix is to call the + * default window proc that returns HTCLIENT when + * the mouse is in the client area. + */ + int hittest = OS.DefWindowProc (handle, OS.WM_NCHITTEST, wParam, lParam); + return new LRESULT (hittest); +} + +LRESULT WM_NOTIFY (int wParam, int lParam) { + /* + * Feature in Windows. When the tab folder window + * proc processes WM_NOTIFY, it forwards this + * message to its parent. This is done so that + * children of this control that send this message + * type to their parent will notify not only + * this control but also the parent of this control, + * which is typically the application window and + * the window that is looking for the message. + * If the control did not forward the message, + * applications would have to subclass the control + * window to see the message. Because the control + * window is subclassed by SWT, the message + * is delivered twice, once by SWT and once when + * the message is forwarded by the window proc. + * The fix is to avoid calling the window proc + * for this control. + */ + LRESULT result = super.WM_NOTIFY (wParam, lParam); + if (result != null) return result; + return LRESULT.ZERO; +} + +LRESULT WM_SIZE (int wParam, int lParam) { + LRESULT result = super.WM_SIZE (wParam, lParam); + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the resize + * event. If this happens, end the processing of the + * Windows message by returning the result of the + * WM_SIZE message. + */ + if (isDisposed ()) return result; + int index = OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0); + if (index != -1) { + TabItem item = items [index]; + Control control = item.control; + if (control != null && !control.isDisposed ()) { + control.setBounds (getClientArea ()); + } + } + return result; +} + +LRESULT WM_WINDOWPOSCHANGING (int wParam, int lParam) { + LRESULT result = super.WM_WINDOWPOSCHANGING (wParam, lParam); + if (result != null) return result; + if (!OS.IsWindowVisible (handle)) return result; + WINDOWPOS lpwp = new WINDOWPOS (); + OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof); + if ((lpwp.flags & (OS.SWP_NOSIZE | OS.SWP_NOREDRAW)) != 0) { + return result; + } + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & OS.TCS_MULTILINE) != 0) { + OS.InvalidateRect (handle, null, true); + return result; + } + RECT rect = new RECT (); + OS.SetRect (rect, 0, 0, lpwp.cx, lpwp.cy); + OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, rect); + int newWidth = rect.right - rect.left; + int newHeight = rect.bottom - rect.top; + OS.GetClientRect (handle, rect); + int oldWidth = rect.right - rect.left; + int oldHeight = rect.bottom - rect.top; + if (newWidth == oldWidth && newHeight == oldHeight) { + return result; + } + RECT inset = new RECT (); + OS.SendMessage (handle, OS.TCM_ADJUSTRECT, 0, inset); + int marginX = -inset.right, marginY = -inset.bottom; + if (newWidth != oldWidth) { + int left = oldWidth; + if (newWidth < oldWidth) left = newWidth; + OS.SetRect (rect, left - marginX, 0, newWidth, newHeight); + OS.InvalidateRect (handle, rect, true); + } + if (newHeight != oldHeight) { + int bottom = oldHeight; + if (newHeight < oldHeight) bottom = newHeight; + if (newWidth < oldWidth) oldWidth -= marginX; + OS.SetRect (rect, 0, bottom - marginY, oldWidth, newHeight); + OS.InvalidateRect (handle, rect, true); + } + return result; +} + +LRESULT wmNotifyChild (int wParam, int lParam) { + NMHDR hdr = new NMHDR (); + OS.MoveMemory (hdr, lParam, NMHDR.sizeof); + int code = hdr.code; + switch (code) { + case OS.TCN_SELCHANGE: + case OS.TCN_SELCHANGING: + TabItem item = null; + int index = OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0); + if (index != -1) item = items [index]; + if (item != null) { + Control control = item.control; + if (control != null && !control.isDisposed ()) { + if (code == OS.TCN_SELCHANGE) { + control.setBounds (getClientArea ()); + } + control.setVisible (code == OS.TCN_SELCHANGE); + } + } + if (code == OS.TCN_SELCHANGE) { + Event event = new Event (); + event.item = item; + postEvent (SWT.Selection, event); + } + } + return super.wmNotifyChild (wParam, lParam); +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TabItem.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TabItem.java index aed5113e03..0897a591e4 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TabItem.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TabItem.java @@ -1,317 +1,317 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-
-/**
- * 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>
- */
-
-public class TabItem extends Item {
- TabFolder parent;
- Control control;
- String toolTipText;
-
-/**
- * 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 index to store the receiver in its parent
- *
- * @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, int index) {
- super (parent, style);
- this.parent = parent;
- parent.createItem (this, index);
-}
-
-protected void checkSubclass () {
- if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
-}
-
-/**
- * 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;
-}
-
-public Display getDisplay () {
- TabFolder parent = this.parent;
- if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED);
- return parent.getDisplay ();
-}
-/**
- * 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 releaseChild () {
- super.releaseChild ();
- int index = parent.indexOf (this);
- if (index == parent.getSelectionIndex ()) {
- if (control != null) control.setVisible (false);
- }
- parent.destroyItem (this);
-}
-
-void releaseWidget () {
- super.releaseWidget ();
- control = null;
- parent = 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);
- if (index != parent.getSelectionIndex ()) {
- if (newControl != null) newControl.setVisible (false);
- return;
- }
- if (newControl != null) {
- newControl.setBounds (parent.getClientArea ());
- newControl.setVisible (true);
- }
- if (oldControl != null) oldControl.setVisible (false);
-}
-
-public void setImage (Image image) {
- checkWidget();
- int index = parent.indexOf (this);
- if (index == -1) return;
- super.setImage (image);
- /*
- * Bug in Windows. In version 6.00 of COMCTL32.DLL, tab
- * items with an image and a label that includes '&' cause
- * the tab to draw incorrectly (even when doubled '&&').
- * The image overlaps the label. The fix is to remove
- * all '&' characters from the string.
- */
- if (COMCTL32_MAJOR >= 6) {
- if (text.indexOf ('&') != -1) setText (text);
- }
- int hwnd = parent.handle;
- TCITEM tcItem = new TCITEM ();
- tcItem.mask = OS.TCIF_IMAGE;
- tcItem.iImage = parent.imageIndex (image);
- OS.SendMessage (hwnd, OS.TCM_SETITEM, index, tcItem);
-}
-/**
- * Sets the receiver's text. The string may include
- * the mnemonic character.
- * </p>
- * <p>
- * Mnemonics are indicated by an '&' 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 '&' can be
- * escaped by doubling it in the string, causing a single
- *'&' 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);
- /*
- * Bug in Windows. In version 6.00 of COMCTL32.DLL, tab
- * items with an image and a label that includes '&' cause
- * the tab to draw incorrectly (even when doubled '&&').
- * The image overlaps the label. The fix is to remove
- * all '&' characters from the string.
- */
- if (COMCTL32_MAJOR >= 6 && image != null) {
- if (text.indexOf ('&') != -1) {
- int length = string.length ();
- char[] text = new char [length];
- string.getChars ( 0, length, text, 0);
- int i = 0, j = 0;
- for (i=0; i<length; i++) {
- if (text[i] != '&') text [j++] = text [i];
- }
- if (j < i) string = new String (text, 0, j);
- }
- }
- int hwnd = parent.handle;
- int hHeap = OS.GetProcessHeap ();
- TCHAR buffer = new TCHAR (parent.getCodePage (), string, true);
- int byteCount = buffer.length () * TCHAR.sizeof;
- int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- OS.MoveMemory (pszText, buffer, byteCount);
- TCITEM tcItem = new TCITEM ();
- tcItem.mask = OS.TCIF_TEXT;
- tcItem.pszText = pszText;
- OS.SendMessage (hwnd, OS.TCM_SETITEM, index, tcItem);
- OS.HeapFree (hHeap, 0, pszText);
-}
-
-/**
- * Sets the receiver's tool tip text to the argument, which
- * may be null indicating that no tool tip text should be shown.
- *
- * @param string the new tool tip text (or null)
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if 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;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; + +/** + * 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> + */ + +public class TabItem extends Item { + TabFolder parent; + Control control; + String toolTipText; + +/** + * 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 index to store the receiver in its parent + * + * @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, int index) { + super (parent, style); + this.parent = parent; + parent.createItem (this, index); +} + +protected void checkSubclass () { + if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS); +} + +/** + * 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; +} + +public Display getDisplay () { + TabFolder parent = this.parent; + if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED); + return parent.getDisplay (); +} +/** + * 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 releaseChild () { + super.releaseChild (); + int index = parent.indexOf (this); + if (index == parent.getSelectionIndex ()) { + if (control != null) control.setVisible (false); + } + parent.destroyItem (this); +} + +void releaseWidget () { + super.releaseWidget (); + control = null; + parent = 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); + if (index != parent.getSelectionIndex ()) { + if (newControl != null) newControl.setVisible (false); + return; + } + if (newControl != null) { + newControl.setBounds (parent.getClientArea ()); + newControl.setVisible (true); + } + if (oldControl != null) oldControl.setVisible (false); +} + +public void setImage (Image image) { + checkWidget(); + int index = parent.indexOf (this); + if (index == -1) return; + super.setImage (image); + /* + * Bug in Windows. In version 6.00 of COMCTL32.DLL, tab + * items with an image and a label that includes '&' cause + * the tab to draw incorrectly (even when doubled '&&'). + * The image overlaps the label. The fix is to remove + * all '&' characters from the string. + */ + if (COMCTL32_MAJOR >= 6) { + if (text.indexOf ('&') != -1) setText (text); + } + int hwnd = parent.handle; + TCITEM tcItem = new TCITEM (); + tcItem.mask = OS.TCIF_IMAGE; + tcItem.iImage = parent.imageIndex (image); + OS.SendMessage (hwnd, OS.TCM_SETITEM, index, tcItem); +} +/** + * Sets the receiver's text. The string may include + * the mnemonic character. + * </p> + * <p> + * Mnemonics are indicated by an '&' 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 '&' can be + * escaped by doubling it in the string, causing a single + *'&' 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); + /* + * Bug in Windows. In version 6.00 of COMCTL32.DLL, tab + * items with an image and a label that includes '&' cause + * the tab to draw incorrectly (even when doubled '&&'). + * The image overlaps the label. The fix is to remove + * all '&' characters from the string. + */ + if (COMCTL32_MAJOR >= 6 && image != null) { + if (text.indexOf ('&') != -1) { + int length = string.length (); + char[] text = new char [length]; + string.getChars ( 0, length, text, 0); + int i = 0, j = 0; + for (i=0; i<length; i++) { + if (text[i] != '&') text [j++] = text [i]; + } + if (j < i) string = new String (text, 0, j); + } + } + int hwnd = parent.handle; + int hHeap = OS.GetProcessHeap (); + TCHAR buffer = new TCHAR (parent.getCodePage (), string, true); + int byteCount = buffer.length () * TCHAR.sizeof; + int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + OS.MoveMemory (pszText, buffer, byteCount); + TCITEM tcItem = new TCITEM (); + tcItem.mask = OS.TCIF_TEXT; + tcItem.pszText = pszText; + OS.SendMessage (hwnd, OS.TCM_SETITEM, index, tcItem); + OS.HeapFree (hHeap, 0, pszText); +} + +/** + * Sets the receiver's tool tip text to the argument, which + * may be null indicating that no tool tip text should be shown. + * + * @param string the new tool tip text (or null) + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if 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; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Table.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Table.java index 2d2672afb6..9107f61958 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Table.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Table.java @@ -1,2512 +1,2512 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.events.*;
-
-/**
- * Instances of this class implement a selectable user interface
- * object that displays a list of images and strings and issue
- * notificiation when selected.
- * <p>
- * The item children that may be added to instances of this class
- * must be of type <code>TableItem</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>SINGLE, MULTI, CHECK, FULL_SELECTION, HIDE_SELECTION</dd>
- * <dt><b>Events:</b></dt>
- * <dd>Selection, DefaultSelection</dd>
- * </dl>
- * <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>
- */
-
-public class Table extends Composite {
- TableItem [] items;
- TableColumn [] columns;
- ImageList imageList;
- boolean ignoreSelect, dragStarted, ignoreResize, mouseDown, customDraw;
- static final int TableProc;
- static final TCHAR TableClass = new TCHAR (0, OS.WC_LISTVIEW, true);
- static {
- WNDCLASS lpWndClass = new WNDCLASS ();
- OS.GetClassInfo (0, TableClass, lpWndClass);
- TableProc = lpWndClass.lpfnWndProc;
- }
-
-/**
- * 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 Widget#checkSubclass
- * @see Widget#getStyle
- */
-public Table (Composite parent, int style) {
- super (parent, checkStyle (style));
-}
-
-/**
- * Adds the listener to the collection of listeners who will
- * be notified when the receiver's selection changes, 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 reciever has <code>SWT.CHECK</code> style set 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
- *
- * @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);
-}
-
-int callWindowProc (int msg, int wParam, int lParam) {
- if (handle == 0) return 0;
- return OS.CallWindowProc (TableProc, handle, msg, wParam, lParam);
-}
-
-static int checkStyle (int style) {
- /*
- * Feature in Windows. It is not possible to create
- * a table that does not have scroll bars. Therefore,
- * no matter what style bits are specified, set the
- * H_SCROLL and V_SCROLL bits so that the SWT style
- * will match the widget that Windows creates.
- */
- style |= SWT.H_SCROLL | SWT.V_SCROLL;
- return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0);
-}
-
-protected void checkSubclass () {
- if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
-}
-
-public Point computeSize (int wHint, int hHint, boolean changed) {
- checkWidget ();
- int bits = 0;
- if (wHint != SWT.DEFAULT) {
- bits |= wHint & 0xFFFF;
- } else {
- int width = 0;
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
- for (int i=0; i<count; i++) {
- width += OS.SendMessage (handle, OS.LVM_GETCOLUMNWIDTH, i, 0);
- }
- bits |= width & 0xFFFF;
- }
- if (hHint != SWT.DEFAULT) bits |= hHint << 16;
- int result = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, -1, bits);
- int width = result & 0xFFFF, height = result >> 16;
- 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;
- /*
- * Feature in Windows. For some reason, LVM_APPROXIMATEVIEWRECT
- * does not include the space for the vertical scroll bar but does
- * take into account the horizontal scroll bar when calculating the
- * space needed to show the items. The fix is to add in this space.
- */
- if ((style & SWT.V_SCROLL) != 0) {
- width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
- }
- if (((style & SWT.H_SCROLL) != 0) && (hHint != SWT.DEFAULT)) {
- height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
- }
- return new Point (width, height);
-}
-
-void createHandle () {
- super.createHandle ();
- state &= ~CANVAS;
-
- /*
- * This code is intentionally commented. According to
- * the documentation, setting the default item size is
- * supposed to improve performance. By experimentation,
- * this does not seem to have much of an effect.
- */
-// OS.SendMessage (handle, OS.LVM_SETITEMCOUNT, 1024 * 2, 0);
-
- /* Set the checkbox image list */
- if ((style & SWT.CHECK) != 0) {
- int empty = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 0, 0);
- int oneItem = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 1, 0);
- int width = (oneItem >> 16) - (empty >> 16), height = width;
- setCheckboxImageList (width, height);
- }
-
- /*
- * Feature in Windows. When the control is created,
- * it does not use the default system font. A new HFONT
- * is created and destroyed when the control is destroyed.
- * This means that a program that queries the font from
- * this control, uses the font in another control and then
- * destroys this control will have the font unexpectedly
- * destroyed in the other control. The fix is to assign
- * the font ourselves each time the control is created.
- * The control will not destroy a font that it did not
- * create.
- */
- int hFont = OS.GetStockObject (OS.SYSTEM_FONT);
- OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0);
-
- /*
- * Bug in Windows. When the first column is inserted
- * without setting the header text, Windows will never
- * allow the header text for the first column to be set.
- * The fix is to set the text to an empty string when
- * the column is inserted.
- */
- LVCOLUMN lvColumn = new LVCOLUMN ();
- lvColumn.mask = OS.LVCF_TEXT;
- int hHeap = OS.GetProcessHeap ();
- int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, TCHAR.sizeof);
- lvColumn.pszText = pszText;
- OS.SendMessage (handle, OS.LVM_INSERTCOLUMN, 0, lvColumn);
- OS.HeapFree (hHeap, 0, pszText);
-
- /* Set the extended style bits */
- int bits = OS.LVS_EX_SUBITEMIMAGES | OS.LVS_EX_LABELTIP;
- if ((style & SWT.FULL_SELECTION) != 0) bits |= OS.LVS_EX_FULLROWSELECT;
- OS.SendMessage (handle, OS.LVM_SETEXTENDEDLISTVIEWSTYLE, bits, bits);
-
- /*
- * Feature in Windows. Windows does not explicitly set the orientation of
- * the header. Instead, the orientation is inherited when WS_EX_LAYOUTRTL
- * is specified for the table. This means that when both WS_EX_LAYOUTRTL
- * and WS_EX_NOINHERITLAYOUT are specified for the table, the header will
- * not be oriented correctly. The fix is to explicitly set the orientation
- * for the header.
- *
- * NOTE: WS_EX_LAYOUTRTL is not supported on Windows NT.
- */
- if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) < (4 << 16 | 10)) return;
- if ((style & SWT.RIGHT_TO_LEFT) != 0) {
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- int extStyle = OS.GetWindowLong (hwndHeader, OS.GWL_EXSTYLE);
- OS.SetWindowLong (hwndHeader, OS.GWL_EXSTYLE, extStyle | OS.WS_EX_LAYOUTRTL);
- }
-}
-
-void createItem (TableColumn column, int index) {
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
- if (count == 1 && columns [0] == null) count = 0;
- if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE);
- if (count == columns.length) {
- TableColumn [] newColumns = new TableColumn [columns.length + 4];
- System.arraycopy (columns, 0, newColumns, 0, columns.length);
- columns = newColumns;
- }
- /*
- * Insert the column into the columns array before inserting
- * it into the widget so that the column will be present when
- * any callbacks are issued as a result of LVM_INSERTCOLUMN
- * or LVM_SETCOLUMN.
- */
- System.arraycopy (columns, index, columns, index + 1, count - index);
- columns [index] = column;
- if (index == 0) {
- if (count > 0) {
- LVCOLUMN lvColumn = new LVCOLUMN ();
- lvColumn.mask = OS.LVCF_WIDTH;
- OS.SendMessage (handle, OS.LVM_INSERTCOLUMN, 1, lvColumn);
- OS.SendMessage (handle, OS.LVM_GETCOLUMN, 1, lvColumn);
- int width = lvColumn.cx;
- int cchTextMax = 1024;
- int hHeap = OS.GetProcessHeap ();
- int byteCount = cchTextMax * TCHAR.sizeof;
- int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_TEXT | OS.LVIF_IMAGE | OS.LVIF_STATE;
- int itemCount = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
- for (int i=0; i<itemCount; i++) {
- lvItem.iItem = i;
- lvItem.iSubItem = 0;
- lvItem.pszText = pszText;
- lvItem.cchTextMax = cchTextMax;
- OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem);
- lvItem.iSubItem = 1;
- OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem);
- lvItem.iSubItem = 0;
- lvItem.pszText = lvItem.cchTextMax = 0;
- lvItem.iImage = OS.I_IMAGENONE;
- OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem);
- items [i].text = "";
- items [i].image = null;
- }
- lvColumn.mask = OS.LVCF_TEXT | OS.LVCF_IMAGE | OS.LVCF_WIDTH | OS.LVCF_FMT;
- lvColumn.pszText = pszText;
- lvColumn.cchTextMax = cchTextMax;
- OS.SendMessage (handle, OS.LVM_GETCOLUMN, 0, lvColumn);
- OS.SendMessage (handle, OS.LVM_SETCOLUMN, 1, lvColumn);
- lvColumn.fmt = OS.LVCFMT_IMAGE;
- lvColumn.cx = width;
- lvColumn.iImage = OS.I_IMAGENONE;
- lvColumn.pszText = lvColumn.cchTextMax = 0;
- OS.SendMessage (handle, OS.LVM_SETCOLUMN, 0, lvColumn);
- lvColumn.mask = OS.LVCF_FMT;
- lvColumn.fmt = OS.LVCFMT_LEFT;
- OS.SendMessage (handle, OS.LVM_SETCOLUMN, 0, lvColumn);
- if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
- }
- } else {
- int fmt = OS.LVCFMT_LEFT;
- if ((column.style & SWT.CENTER) == SWT.CENTER) fmt = OS.LVCFMT_CENTER;
- if ((column.style & SWT.RIGHT) == SWT.RIGHT) fmt = OS.LVCFMT_RIGHT;
- LVCOLUMN lvColumn = new LVCOLUMN ();
- lvColumn.mask = OS.LVCF_WIDTH | OS.LVCF_FMT;
- lvColumn.fmt = fmt;
- OS.SendMessage (handle, OS.LVM_INSERTCOLUMN, index, lvColumn);
- }
-}
-
-void createItem (TableItem item, int index) {
- item.foreground = item.background = -1;
- int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
- if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE);
- if (count == items.length) {
- TableItem [] newItems = new TableItem [items.length + 4];
- System.arraycopy (items, 0, newItems, 0, items.length);
- items = newItems;
- }
- LVITEM lvItem = new LVITEM ();
- lvItem.iItem = index;
-
- /*
- * Bug in Windows. Despite the fact that the image list
- * index has never been set for the item, Windows always
- * assumes that the image index for the item is valid.
- * When an item is inserted, the image index is zero.
- * Therefore, when the first image is inserted and is
- * assigned image index zero, every item draws with this
- * image. The fix is to set the image index to none when
- * the image is created.
- */
- lvItem.iImage = OS.I_IMAGENONE;
- lvItem.mask = OS.LVIF_IMAGE;
-
- /* Set the initial unchecked state */
- if ((style & SWT.CHECK) != 0) {
- lvItem.mask = lvItem.mask | OS.TVIF_STATE;
- lvItem.state = 1 << 12;
- lvItem.stateMask = OS.LVIS_STATEIMAGEMASK;
- }
-
- /* Insert the item */
- ignoreSelect = true;
- int result = OS.SendMessage (handle, OS.LVM_INSERTITEM, 0, lvItem);
- ignoreSelect = false;
- if (result == -1) error (SWT.ERROR_ITEM_NOT_ADDED);
- System.arraycopy (items, index, items, index + 1, count - index);
- items [index] = item;
-}
-
-void createWidget () {
- super.createWidget ();
- items = new TableItem [4];
- columns = new TableColumn [4];
-}
-
-int defaultBackground () {
- return OS.GetSysColor (OS.COLOR_WINDOW);
-}
-
-/**
- * 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 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>
- */
-public void deselect (int [] indices) {
- checkWidget ();
- if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.stateMask = OS.LVIS_SELECTED;
- for (int i=0; i<indices.length; i++) {
- lvItem.iItem = indices [i];
- ignoreSelect = true;
- OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem);
- ignoreSelect = false;
- }
-}
-
-/**
- * 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 ();
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.stateMask = OS.LVIS_SELECTED;
- lvItem.iItem = index;
- ignoreSelect = true;
- OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem);
- 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 ();
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.stateMask = OS.LVIS_SELECTED;
- for (int i=start; i<=end; i++) {
- lvItem.iItem = i;
- ignoreSelect = true;
- OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem);
- 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 ();
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.stateMask = OS.LVIS_SELECTED;
- OS.SendMessage (handle, OS.LVM_SETITEMSTATE, -1, lvItem);
-}
-
-void destroyItem (TableColumn column) {
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
- int index = 0;
- while (index < count) {
- if (columns [index] == column) break;
- index++;
- }
- if (index == count) return;
- boolean first = false;
- if (index == 0) {
- first = true;
- if (count > 1) {
- index = 1;
- int cchTextMax = 1024;
- int hHeap = OS.GetProcessHeap ();
- int byteCount = cchTextMax * TCHAR.sizeof;
- int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- LVCOLUMN lvColumn = new LVCOLUMN ();
- lvColumn.mask = OS.LVCF_TEXT | OS.LVCF_WIDTH;
- lvColumn.pszText = pszText;
- lvColumn.cchTextMax = cchTextMax;
- OS.SendMessage (handle, OS.LVM_GETCOLUMN, 1, lvColumn);
- lvColumn.mask |= OS.LVCF_FMT;
- lvColumn.fmt = OS.LVCFMT_LEFT;
- OS.SendMessage (handle, OS.LVM_SETCOLUMN, 0, lvColumn);
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_TEXT | OS.LVIF_IMAGE | OS.LVIF_STATE;
- lvItem.pszText = pszText;
- lvItem.cchTextMax = cchTextMax;
- int itemCount = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
- for (int i=0; i<itemCount; i++) {
- lvItem.iItem = i;
- lvItem.iSubItem = 1;
- OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem);
- lvItem.iSubItem = 0;
- OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem);
- TCHAR buffer = new TCHAR (getCodePage (), cchTextMax);
- OS.MoveMemory (buffer, pszText, byteCount);
- items [i].text = buffer.toString (0, buffer.strlen ());
- if (imageList != null) {
- items [i].image = imageList.get (lvItem.iImage);
- }
- }
- if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
- } else {
- int hHeap = OS.GetProcessHeap ();
- int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, TCHAR.sizeof);
- LVCOLUMN lvColumn = new LVCOLUMN ();
- lvColumn.mask = OS.LVCF_TEXT;
- lvColumn.pszText = pszText;
- OS.SendMessage (handle, OS.LVM_SETCOLUMN, 0, lvColumn);
- if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
- OS.SendMessage (handle, OS.LVM_SETCOLUMNWIDTH, 0, OS.LVSCW_AUTOSIZE);
- }
- }
- if (count > 1) {
- if (OS.SendMessage (handle, OS.LVM_DELETECOLUMN, index, 0) == 0) {
- error (SWT.ERROR_ITEM_NOT_REMOVED);
- }
- }
- if (first) index = 0;
- System.arraycopy (columns, index + 1, columns, index, --count - index);
- columns [count] = null;
-}
-
-void destroyItem (TableItem item) {
- int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
- int index = 0;
- while (index < count) {
- if (items [index] == item) break;
- index++;
- }
- if (index == count) return;
- ignoreSelect = true;
- int code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0);
- ignoreSelect = false;
- if (code == 0) error (SWT.ERROR_ITEM_NOT_REMOVED);
- System.arraycopy (items, index + 1, items, index, --count - index);
- items [count] = null;
- if (count == 0) {
- if (imageList != null) {
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- int columnCount = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
- if (columnCount == 1 && columns [0] == null) columnCount = 0;
- int i = 0;
- while (i < columnCount) {
- TableColumn column = columns [i];
- if (column.getImage () != null) break;
- i++;
- }
- if (i == columnCount) {
- OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_SMALL, 0);
- Display display = getDisplay ();
- display.releaseImageList (imageList);
- imageList = null;
- }
- }
- customDraw = false;
- items = new TableItem [4];
- }
-}
-
-void fixCheckboxImageList () {
- /*
- * Bug in Windows. When the state image list is larger than the
- * image list, Windows incorrectly positions the state images. When
- * the table is scrolled, Windows draws garbage. The fix is to force
- * the state image list to be the same size as the image list.
- */
- if ((style & SWT.CHECK) == 0) return;
- int hImageList = OS.SendMessage (handle, OS.LVM_GETIMAGELIST, OS.LVSIL_SMALL, 0);
- if (hImageList == 0) return;
- int [] cx = new int [1], cy = new int [1];
- OS.ImageList_GetIconSize (hImageList, cx, cy);
- int hOldStateList = OS.SendMessage (handle, OS.LVM_GETIMAGELIST, OS.LVSIL_STATE, 0);
- if (hOldStateList == 0) return;
- int [] stateCx = new int [1], stateCy = new int [1];
- OS.ImageList_GetIconSize (hOldStateList, stateCx, stateCy);
- if (cx [0] == stateCx [0] && cy [0] == stateCy [0]) return;
- setCheckboxImageList (cx [0], cy [0]);
-}
-
-int getBackgroundPixel () {
- return OS.SendMessage (handle, OS.LVM_GETBKCOLOR, 0, 0);
-}
-
-/**
- * Returns the column at the given, zero-relative index in the
- * receiver. Throws an exception if the index is out of range.
- * 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>
- */
-public TableColumn getColumn (int index) {
- checkWidget ();
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
- if (count == 1 && columns [0] == null) count = 0;
- if (!(0 <= index && index < count)) 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 is 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public int getColumnCount () {
- checkWidget ();
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
- if (count == 1 && columns [0] == null) count = 0;
- return count;
-}
-
-/**
- * Returns an array of <code>TableColumn</code>s which are the
- * columns in the receiver. 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>
- */
-public TableColumn [] getColumns () {
- checkWidget ();
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
- if (count == 1 && columns [0] == null) count = 0;
- TableColumn [] result = new TableColumn [count];
- System.arraycopy (columns, 0, result, 0, count);
- return result;
-}
-
-int getFocusIndex () {
- return OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_FOCUSED);
-}
-
-int getForegroundPixel () {
- return OS.SendMessage (handle, OS.LVM_GETTEXTCOLOR, 0, 0);
-}
-
-/**
- * Returns the width in pixels of a grid 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 getGridLineWidth () {
- checkWidget ();
- return 1;
-}
-
-/**
- * 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 ();
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- if (hwndHeader == 0) return 0;
- RECT rect = new RECT ();
- OS.GetWindowRect (hwndHeader, rect);
- return rect.bottom - rect.top;
-}
-
-/**
- * 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 ();
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- return (bits & OS.LVS_NOCOLUMNHEADER) == 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 TableItem getItem (int index) {
- checkWidget ();
- int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
- if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE);
- return items [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.
- *
- * @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 TableItem getItem (Point point) {
- checkWidget ();
- if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
- LVHITTESTINFO pinfo = new LVHITTESTINFO ();
- pinfo.x = point.x; pinfo.y = point.y;
- OS.SendMessage (handle, OS.LVM_HITTEST, 0, pinfo);
- if (pinfo.iItem != -1) return items [pinfo.iItem];
- 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 OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
-}
-
-/**
- * Returns the height of the area which would be used to
- * display <em>one</em> of the items in the receiver's.
- *
- * @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 ();
- int empty = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 0, 0);
- int oneItem = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 1, 0);
- return (oneItem >> 16) - (empty >> 16);
-}
-
-/**
- * Returns an 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 ();
- int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
- TableItem [] result = new TableItem [count];
- System.arraycopy (items, 0, result, 0, count);
- return result;
-}
-
-/**
- * Returns <code>true</code> if the receiver's lines are 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 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 ();
- int bits = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
- return (bits & OS.LVS_EX_GRIDLINES) != 0;
-}
-
-/**
- * Returns an array of <code>TableItem</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 TableItem [] getSelection () {
- checkWidget ();
- int i = -1, j = 0, count = OS.SendMessage (handle, OS.LVM_GETSELECTEDCOUNT, 0, 0);
- TableItem [] result = new TableItem [count];
- while ((i = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, i, OS.LVNI_SELECTED)) != -1) {
- result [j++] = items [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 OS.SendMessage (handle, OS.LVM_GETSELECTEDCOUNT, 0, 0);
-}
-
-/**
- * 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 ();
- int focusIndex = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_FOCUSED);
- int selectedIndex = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_SELECTED);
- if (focusIndex == selectedIndex) return selectedIndex;
- int i = -1;
- while ((i = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, i, OS.LVNI_SELECTED)) != -1) {
- if (i == focusIndex) return i;
- }
- return selectedIndex;
-}
-
-/**
- * Returns the zero-relative indices of the items which are currently
- * selected in the receiver. 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 ();
- int i = -1, j = 0, count = OS.SendMessage (handle, OS.LVM_GETSELECTEDCOUNT, 0, 0);
- int [] result = new int [count];
- while ((i = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, i, OS.LVNI_SELECTED)) != -1) {
- result [j++] = 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 ();
- return OS.SendMessage (handle, OS.LVM_GETTOPINDEX, 0, 0);
-}
-
-int imageIndex (Image image) {
- if (image == null) return OS.I_IMAGENONE;
- if (imageList == null) {
- Rectangle bounds = image.getBounds ();
- imageList = getDisplay ().getImageList (new Point (bounds.width, bounds.height));
- int index = imageList.indexOf (image);
- if (index == -1) index = imageList.add (image);
- int hImageList = imageList.getHandle ();
- OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_SMALL, hImageList);
- return index;
- }
- int index = imageList.indexOf (image);
- if (index != -1) return index;
- return imageList.add (image);
-}
-
-/**
- * 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 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 (TableColumn column) {
- checkWidget ();
- if (column == null) error (SWT.ERROR_NULL_ARGUMENT);
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
- for (int i=0; i<count; 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 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 (TableItem item) {
- checkWidget ();
- if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
- int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
- for (int i=0; i<count; i++) {
- if (items [i] == item) 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 visibility 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 ();
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.stateMask = OS.LVIS_SELECTED;
- lvItem.iItem = index;
- int result = OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem);
- return (result != 0) && ((lvItem.state & OS.LVIS_SELECTED) != 0);
-}
-
-void releaseWidget () {
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- int columnCount = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
- if (columnCount == 1 && columns [0] == null) columnCount = 0;
- for (int i=0; i<columnCount; i++) {
- TableColumn column = columns [i];
- if (!column.isDisposed ()) column.releaseResources ();
- }
- columns = null;
- int itemCount = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
-
- /*
- * Feature in Windows. When there are a large number
- * of columns and items in a table (>1000) where each
- * of the subitems in the table has a string, it is much
- * faster to delete each item with LVM_DELETEITEM rather
- * than using LVM_DELETEALLITEMS. The fix is to detect
- * this case and delete the items, one by one.
- *
- * NOTE: LVM_DELETEALLITEMS is also sent by the table
- * when the table is destroyed.
- */
- if (columnCount > 1) {
- /* Turn off redraw and leave it off */
- OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
- for (int i=itemCount-1; i>=0; --i) {
- ignoreSelect = true;
- OS.SendMessage (handle, OS.LVM_DELETEITEM, i, 0);
- ignoreSelect = false;
- TableItem item = items [i];
- if (!item.isDisposed ()) item.releaseResources ();
- }
- } else {
- for (int i=0; i<itemCount; i++) {
- TableItem item = items [i];
- if (!item.isDisposed ()) item.releaseResources ();
- }
- }
- customDraw = false;
- items = null;
- if (imageList != null) {
- OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_SMALL, 0);
- Display display = getDisplay ();
- display.releaseImageList (imageList);
- }
- imageList = null;
- int hOldList = OS.SendMessage (handle, OS.LVM_GETIMAGELIST, OS.LVSIL_STATE, 0);
- OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_STATE, 0);
- if (hOldList != 0) OS.ImageList_Destroy (hOldList);
- super.releaseWidget ();
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public void remove (int [] indices) {
- checkWidget ();
- if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
- int [] newIndices = new int [indices.length];
- System.arraycopy (indices, 0, newIndices, 0, indices.length);
- sort (newIndices);
- int last = -1;
- int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
- for (int i=0; i<newIndices.length; i++) {
- int index = newIndices [i];
- if (index != last || i == 0) {
- ignoreSelect = true;
- int code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0);
- ignoreSelect = false;
- if (code == 0) {
- if (0 <= index && index < count) {
- error (SWT.ERROR_ITEM_NOT_REMOVED);
- } else {
- error (SWT.ERROR_INVALID_RANGE);
- }
- }
-
- // BUG - disposed callback could remove an item
- items [index].releaseResources ();
- System.arraycopy (items, index + 1, items, index, --count - index);
- items [count] = null;
- last = index;
- }
- }
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public void remove (int index) {
- checkWidget ();
- int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
- ignoreSelect = true;
- int code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0);
- ignoreSelect = false;
- if (code == 0) {
- if (0 <= index && index < count) {
- error (SWT.ERROR_ITEM_NOT_REMOVED);
- } else {
- error (SWT.ERROR_INVALID_RANGE);
- }
- }
- TableItem item = items [index];
- System.arraycopy (items, index + 1, items, index, --count - index);
- items [count] = null;
- item.releaseResources ();
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li>
- * </ul>
- */
-public void remove (int start, int end) {
- checkWidget ();
- int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
- int index = start;
- while (index <= end) {
- ignoreSelect = true;
- int code = OS.SendMessage (handle, OS.LVM_DELETEITEM, start, 0);
- ignoreSelect = false;
- if (code == 0) break;
-
- // BUG - disposed callback could remove an item
- items [index].releaseResources ();
- index++;
- }
- System.arraycopy (items, index, items, start, count - index);
- for (int i=count-(index-start); i<count; i++) items [i] = null;
- if (index <= end) {
- if (0 <= index && index < count) {
- error (SWT.ERROR_ITEM_NOT_REMOVED);
- } else {
- error (SWT.ERROR_INVALID_RANGE);
- }
- }
-}
-
-/**
- * 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 ();
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- int columnCount = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
- if (columnCount == 1 && columns [0] == null) columnCount = 0;
- int itemCount = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
-
- /*
- * Feature in Windows. When there are a large number
- * of columns and items in a table (>1000) where each
- * of the subitems in the table has a string, it is much
- * faster to delete each item with LVM_DELETEITEM rather
- * than using LVM_DELETEALLITEMS. The fix is to detect
- * this case and delete the items, one by one.
- *
- * NOTE: LVM_DELETEALLITEMS is also sent by the table
- * when the table is destroyed.
- */
- if (columnCount > 1) {
- boolean redraw = drawCount == 0 && OS.IsWindowVisible (handle);
- if (redraw) OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
- int index = itemCount - 1;
- while (index >= 0) {
- ignoreSelect = true;
- int code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0);
- ignoreSelect = false;
- if (code == 0) break;
-
- // BUG - disposed callback could remove an item
- items [index].releaseResources ();
- --index;
- }
- if (redraw) {
- OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
- /*
- * This code is intentionally commented. The window proc
- * for the table implements WM_SETREDRAW to invalidate
- * and erase the table so it is not necessary to do this
- * again.
- */
-// int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE;
-// OS.RedrawWindow (handle, null, 0, flags);
- }
- if (index != -1) error (SWT.ERROR_ITEM_NOT_REMOVED);
- } else {
- ignoreSelect = true;
- int code = OS.SendMessage (handle, OS.LVM_DELETEALLITEMS, 0, 0);
- ignoreSelect = false;
- if (code == 0) error (SWT.ERROR_ITEM_NOT_REMOVED);
- for (int i=0; i<itemCount; i++) {
- TableItem item = items [i];
- if (!item.isDisposed ()) item.releaseResources ();
- }
- }
-
- if (imageList != null) {
- int i = 0;
- while (i < columnCount) {
- TableColumn column = columns [i];
- if (column.getImage () != null) break;
- i++;
- }
- if (i == columnCount) {
- OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_SMALL, 0);
- Display display = getDisplay ();
- display.releaseImageList (imageList);
- imageList = null;
- }
- }
- customDraw = false;
- items = new TableItem [4];
-}
-
-/**
- * Removes the listener from the collection of listeners who will
- * be notified when the receiver's selection changes.
- *
- * @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 items at the given zero-relative indices in the receiver.
- * If the item at the given zero-relative index in the receiver
- * is not selected, it is selected. If the item at the index
- * was selected, it remains selected. Indices that are out
- * of range and duplicate 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>
- */
-public void select (int [] indices) {
- checkWidget ();
- if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
- int length = indices.length;
- if (length == 0) return;
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.state = OS.LVIS_SELECTED;
- lvItem.stateMask = OS.LVIS_SELECTED;
- for (int i=indices.length-1; i>=0; --i) {
- lvItem.iItem = indices [i];
- ignoreSelect = true;
- OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem);
- ignoreSelect = 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. 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 ();
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.state = OS.LVIS_SELECTED;
- lvItem.stateMask = OS.LVIS_SELECTED;
- lvItem.iItem = index;
- ignoreSelect = true;
- OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem);
- ignoreSelect = false;
-}
-
-/**
- * Selects the items at the given zero-relative indices in the receiver.
- * If the item at the index was already selected, it remains
- * selected. The range of the indices is inclusive. Indices that are
- * out of range are ignored and no items will be selected if start is
- * greater than end.
- *
- * @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 select (int start, int end) {
- checkWidget ();
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.state = OS.LVIS_SELECTED;
- lvItem.stateMask = OS.LVIS_SELECTED;
- for (int i=start; i<=end; i++) {
- lvItem.iItem = i;
- ignoreSelect = true;
- OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem);
- ignoreSelect = false;
- }
-}
-
-/**
- * Selects all 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 void selectAll () {
- checkWidget ();
- if ((style & SWT.SINGLE) != 0) return;
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.state = OS.LVIS_SELECTED;
- lvItem.stateMask = OS.LVIS_SELECTED;
- ignoreSelect = true;
- OS.SendMessage (handle, OS.LVM_SETITEMSTATE, -1, lvItem);
- ignoreSelect = false;
-}
-
-LRESULT sendMouseDownEvent (int type, int button, int msg, int wParam, int lParam) {
- /*
- * Feature in Windows. Inside WM_LBUTTONDOWN and WM_RBUTTONDOWN,
- * the widget starts a modal loop to determine if the user wants
- * to begin a drag/drop operation or marque select. Unfortunately,
- * this modal loop eats the corresponding mouse up. The fix is to
- * detect the cases when the modal loop has eaten the mouse up and
- * issue a fake mouse up.
- *
- * By observation, when the mouse is clicked anywhere but the check
- * box, the widget eats the mouse up. When the mouse is dragged,
- * the widget does not eat the mouse up.
- */
- LVHITTESTINFO pinfo = new LVHITTESTINFO ();
- pinfo.x = (short) (lParam & 0xFFFF);
- pinfo.y = (short) (lParam >> 16);
- OS.SendMessage (handle, OS.LVM_HITTEST, 0, pinfo);
- sendMouseEvent (type, button, msg, wParam, lParam);
-
- /*
- * Force the table to have focus so that when the user
- * reselects the focus item, the LVIS_FOCUSED state bits
- * for the item will be set. These bits are used when
- * the table is multi-select to issue the selection
- * event. If the user did not click on an item, then
- * set focus to the table so that it will come to the
- * front and take focus in the work around below.
- */
- OS.SetFocus (handle);
-
- /*
- * Feature in Windows. When the user selects outside of
- * a table item, Windows deselects all the items, even
- * when the table is multi-select. While not strictly
- * wrong, this is unexpected. The fix is to detect the
- * case and avoid calling the window proc.
- */
- if (pinfo.iItem == -1) {
- if (OS.GetCapture () != handle) OS.SetCapture (handle);
- return LRESULT.ZERO;
- }
-
- /*
- * Feature in Windows. When a table item is reselected,
- * the table does not issue a WM_NOTIFY when the item
- * state has not changed. This is inconsistent with
- * the list widget and other widgets in Windows. The
- * fix is to detect the case when an item is reselected
- * and issue the notification.
- */
- boolean wasSelected = false;
- int count = OS.SendMessage (handle, OS.LVM_GETSELECTEDCOUNT, 0, 0);
- if (count == 1 && pinfo.iItem != -1) {
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.stateMask = OS.LVIS_SELECTED;
- lvItem.iItem = pinfo.iItem;
- OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem);
- wasSelected = (lvItem.state & OS.LVIS_SELECTED) != 0;
- if (wasSelected) ignoreSelect = true;
- }
- dragStarted = false;
- int code = callWindowProc (msg, wParam, lParam);
- if (wasSelected) {
- ignoreSelect = false;
- Event event = new Event ();
- event.item = items [pinfo.iItem];
- postEvent (SWT.Selection, event);
- }
- if (dragStarted) {
- if (OS.GetCapture () != handle) OS.SetCapture (handle);
- } else {
- int flags = OS.LVHT_ONITEMLABEL | OS.LVHT_ONITEMICON;
- boolean fakeMouseUp = (pinfo.flags & flags) != 0;
- if (!fakeMouseUp && (style & SWT.MULTI) != 0) {
- fakeMouseUp = (pinfo.flags & OS.LVHT_ONITEMSTATEICON) == 0;
- }
- if (fakeMouseUp) {
- mouseDown = false;
- sendMouseEvent (SWT.MouseUp, button, msg, wParam, lParam);
- }
- }
- dragStarted = false;
- return new LRESULT (code);
-}
-
-void setBackgroundPixel (int pixel) {
- if (background == pixel) return;
- background = pixel;
-
- /*
- * Feature in Windows. Setting the color to be
- * the current default is not correct because the
- * widget will not change colors when the colors
- * are changed from the control panel. There is
- * no fix at this time.
- */
- if (pixel == -1) pixel = defaultBackground ();
- OS.SendMessage (handle, OS.LVM_SETBKCOLOR, 0, pixel);
- OS.SendMessage (handle, OS.LVM_SETTEXTBKCOLOR, 0, pixel);
- if ((style & SWT.CHECK) != 0) setCheckboxImageListColor ();
-
- /*
- * Feature in Windows. When the background color is
- * changed, the table does not redraw until the next
- * WM_PAINT. The fix is to force a redraw.
- */
- OS.InvalidateRect (handle, null, true);
-}
-
-void setCheckboxImageListColor () {
- if ((style & SWT.CHECK) == 0) return;
- int hOldStateList = OS.SendMessage (handle, OS.LVM_GETIMAGELIST, OS.LVSIL_STATE, 0);
- if (hOldStateList == 0) return;
- int [] cx = new int [1], cy = new int [1];
- OS.ImageList_GetIconSize (hOldStateList, cx, cy);
- setCheckboxImageList (cx [0], cy [0]);
-}
-
-void setCheckboxImageList (int width, int height) {
- if ((style & SWT.CHECK) == 0) return;
- int count = 4;
- int hStateList = OS.ImageList_Create (width, height, OS.ILC_COLOR, count, count);
- int hDC = OS.GetDC (handle);
- int memDC = OS.CreateCompatibleDC (hDC);
- int hBitmap = OS.CreateCompatibleBitmap (hDC, width * count, height);
- int hOldBitmap = OS.SelectObject (memDC, hBitmap);
- RECT rect = new RECT ();
- OS.SetRect (rect, 0, 0, width * count, height);
- int hBrush = OS.CreateSolidBrush (getBackgroundPixel ());
- OS.FillRect (memDC, rect, hBrush);
- OS.DeleteObject (hBrush);
- int oldFont = OS.SelectObject (hDC, defaultFont ());
- TEXTMETRIC tm = new TEXTMETRIC ();
- OS.GetTextMetrics (hDC, tm);
- OS.SelectObject (hDC, oldFont);
- int itemWidth = Math.min (tm.tmHeight, width);
- int itemHeight = Math.min (tm.tmHeight, height);
- int left = (width - itemWidth) / 2, top = (height - itemHeight) / 2 + 1;
- OS.SetRect (rect, left, top, left + itemWidth, top + itemHeight);
- OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_FLAT);
- rect.left += width; rect.right += width;
- OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_CHECKED | OS.DFCS_FLAT);
- rect.left += width; rect.right += width;
- OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_INACTIVE | OS.DFCS_FLAT);
- rect.left += width; rect.right += width;
- OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_CHECKED | OS.DFCS_INACTIVE | OS.DFCS_FLAT);
- OS.SelectObject (memDC, hOldBitmap);
- OS.DeleteDC (memDC);
- OS.ReleaseDC (handle, hDC);
- OS.ImageList_AddMasked (hStateList, hBitmap, 0);
- OS.DeleteObject (hBitmap);
- int hOldStateList = OS.SendMessage (handle, OS.LVM_GETIMAGELIST, OS.LVSIL_STATE, 0);
- OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_STATE, hStateList);
- if (hOldStateList != 0) OS.ImageList_Destroy (hOldStateList);
-}
-
-void setFocusIndex (int index) {
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.state = OS.LVIS_FOCUSED;
- lvItem.stateMask = OS.LVIS_FOCUSED;
- lvItem.iItem = index;
- ignoreSelect = true;
- OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem);
- ignoreSelect = false;
-}
-
-public void setFont (Font font) {
- checkWidget ();
- super.setFont (font);
- setScrollWidth ();
- /*
- * Bug in Windows. Setting the font will cause the
- * table area to be redrawn but not the column headers.
- * Fix is to force a redraw on the column headers.
- */
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- OS.InvalidateRect (hwndHeader, null, true);
- int bits = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
- if ((bits & OS.LVS_EX_GRIDLINES) == 0) return;
- bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & OS.LVS_NOCOLUMNHEADER) != 0) return;
- setRowHeight ();
-}
-
-void setForegroundPixel (int pixel) {
- if (foreground == pixel) return;
- foreground = pixel;
-
- /*
- * Feature in Windows. Setting the color to be
- * the current default is not correct because the
- * table will not change colors when the colors
- * are changed from the control panel. There is
- * no fix at this time.
- */
- if (pixel == -1) pixel = defaultForeground ();
- OS.SendMessage (handle, OS.LVM_SETTEXTCOLOR, 0, pixel);
-
- /*
- * Feature in Windows. When the foreground color is
- * changed, the table does not redraw until the next
- * WM_PAINT. The fix is to force a redraw.
- */
- OS.InvalidateRect (handle, null, 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 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 setHeaderVisible (boolean show) {
- checkWidget ();
- int newBits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- newBits &= ~OS.LVS_NOCOLUMNHEADER;
- if (!show) newBits |= OS.LVS_NOCOLUMNHEADER;
- /*
- * Feature in Windows. Setting or clearing LVS_NOCOLUMNHEADER
- * causes the table to scroll to the beginning. The fix is to
- * save and restore the top index.
- */
- int topIndex = getTopIndex ();
- OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
- if (topIndex != 0) setTopIndex (topIndex);
- if (show) {
- int bits = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
- if ((bits & OS.LVS_EX_GRIDLINES) != 0) setRowHeight ();
- }
-}
-
-/**
- * Marks the receiver's lines 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 setLinesVisible (boolean show) {
- checkWidget ();
- int newBits = 0;
- if (show) {
- newBits = OS.LVS_EX_GRIDLINES;
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & OS.LVS_NOCOLUMNHEADER) == 0) setRowHeight ();
- }
- OS.SendMessage (handle, OS.LVM_SETEXTENDEDLISTVIEWSTYLE, OS.LVS_EX_GRIDLINES, newBits);
-}
-
-public void setRedraw (boolean redraw) {
- checkWidget ();
- if (redraw) {
- if (--drawCount == 0) {
- setScrollWidth ();
- /*
- * This code is intentionally commented. When many items
- * are added to a table, it is slightly faster to temporarily
- * unsubclass the window proc so that messages are dispatched
- * directly to the table. This is optimization is dangerous
- * because any operation can occur when redraw is turned off,
- * even operations where the table must be subclassed in order
- * to have the correct behavior or work around a Windows bug.
- * For now, don't attempt it.
- */
-// subclass ();
-
- /*
- * Bug in Windows. For some reason, when WM_SETREDRAW is used
- * to turn redraw back on this may result in a WM_SIZE. If the
- * table column widths are adjusted in WM_SIZE, blank lines may
- * be inserted at the top of the widget. A call to LVM_GETTOPINDEX
- * will return a negative number (this is an impossible result).
- * The fix is to ignore any resize generated by WM_SETREDRAW and
- * defer the work until the WM_SETREDRAW has returned.
- */
- ignoreResize = true;
- OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
- if (!ignoreResize) {
- setResizeChildren (false);
- sendEvent (SWT.Resize);
- // widget may be disposed at this point
- if (isDisposed ()) return;
- if (layout != null) layout.layout (this, false);
- setResizeChildren (true);
- }
- ignoreResize = false;
-
- /*
- * This code is intentionally commented. The window proc
- * for the table implements WM_SETREDRAW to invalidate
- * and erase the table and the header. This is undocumented
- * behavior. The commented code below shows what is actually
- * happening and reminds us that we are relying on this
- * undocumented behavior.
- *
- * NOTE: The window proc for the table does not redraw the
- * non-client area (ie. the border and scroll bars). This
- * must be explicitly redrawn. This code can be removed
- * if we stop relying on the undocuemented behavior.
- */
- if (OS.IsWinCE) {
- OS.InvalidateRect (handle, null, false);
- } else {
- OS.RedrawWindow (handle, null, 0, OS.RDW_FRAME | OS.RDW_INVALIDATE);
- }
-// int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
-// if (hwndHeader != 0) OS.SendMessage (hwndHeader, OS.WM_SETREDRAW, 1, 0);
-// int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE | OS.RDW_ALLCHILDREN;
-// OS.RedrawWindow (handle, null, 0, flags);
-// if (hwndHeader != 0) OS.RedrawWindow (hwndHeader, null, 0, flags);
- }
- } else {
- if (drawCount++ == 0) {
- OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- if (hwndHeader != 0) OS.SendMessage (hwndHeader, OS.WM_SETREDRAW, 0, 0);
- /*
- * This code is intentionally commented. When many items
- * are added to a table, it is slightly faster to temporarily
- * unsubclass the window proc so that messages are dispatched
- * directly to the table. This is optimization is dangerous
- * because any operation can occur when redraw is turned off,
- * even operations where the table must be subclassed in order
- * to have the correct behavior or work around a Windows bug.
- * For now, don't attempt it.
- */
-// unsubclass ();
- }
- }
-}
-
-void setRowHeight () {
- /*
- * Bug in Windows. When both a header and grid lines are
- * displayed, the grid lines do not take into account the
- * height of the header and draw in the wrong place. The
- * fix is to set the height of the table items to be the
- * height of the header so that the lines draw in the right
- * place. The height of a table item is the maximum of the
- * height of the font or the height of image list.
- *
- * NOTE: In version 5.80 of COMCTL32.DLL, the bug is fixed.
- */
- if ((COMCTL32_MAJOR << 16 | COMCTL32_MINOR) >= (5 << 16 | 80)) return;
- int hOldList = OS.SendMessage (handle, OS.LVM_GETIMAGELIST, OS.LVSIL_SMALL, 0);
- if (hOldList != 0) return;
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- RECT rect = new RECT ();
- OS.GetWindowRect (hwndHeader, rect);
- int height = rect.bottom - rect.top - 1;
- int hImageList = OS.ImageList_Create (1, height, 0, 0, 0);
- OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_SMALL, hImageList);
- OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_SMALL, 0);
- OS.ImageList_Destroy (hImageList);
-}
-
-void setScrollWidth () {
- if (drawCount != 0) return;
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
- if (count == 1 && columns [0] == null) {
- OS.SendMessage (handle, OS.LVM_SETCOLUMNWIDTH, 0, OS.LVSCW_AUTOSIZE);
- }
-}
-
-/**
- * Selects the items at the given zero-relative indices in the receiver.
- * The current selected is first cleared, then the new items are selected.
- *
- * @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);
- deselectAll ();
- select (indices);
- if (indices.length != 0) {
- int focusIndex = indices [0];
- if (focusIndex != -1) setFocusIndex (focusIndex);
- }
- showSelection ();
-}
-
-/**
- * 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 array of items is null</li>
- * <li>ERROR_INVALID_ARGUMENT - if one of 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#deselectAll()
- * @see Table#select(int)
- */
-public void setSelection (TableItem [] items) {
- checkWidget ();
- if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
- deselectAll ();
- int length = items.length;
- if (length == 0) return;
- int focusIndex = -1;
- if ((style & SWT.SINGLE) != 0) length = 1;
- for (int i=length-1; i>=0; --i) {
- int index = indexOf (items [i]);
- if (index != -1) {
- select (focusIndex = index);
- }
- }
- if (focusIndex != -1) setFocusIndex (focusIndex);
- showSelection ();
-}
-
-/**
- * Selects the item at the given zero-relative index in the receiver.
- * The current selected 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 ();
- deselectAll ();
- select (index);
- if (index != -1) setFocusIndex (index);
- showSelection ();
-}
-
-/**
- * Selects the items at the given zero-relative indices in the receiver.
- * The current selection is first cleared, then the new items are selected.
- * Indices that are out of range are ignored and no items will be selected
- * if start is greater than end.
- *
- * @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 ();
- deselectAll ();
- select (start, end);
- /*
- * NOTE: This code relies on the select (int, int)
- * selecting the last item in the range for a single
- * selection table.
- */
- int focusIndex = (style & SWT.SINGLE) != 0 ? end : start;
- if (focusIndex != -1) setFocusIndex (focusIndex);
- showSelection ();
-}
-
-/**
- * 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 ();
- int topIndex = OS.SendMessage (handle, OS.LVM_GETTOPINDEX, 0, 0);
- if (index == topIndex) return;
-
- /*
- * Bug in Windows. For some reason, LVM_SCROLL refuses to
- * scroll a table vertically when the width and height of
- * the table is smaller than a certain size. The values
- * that the author is seeing are width=68 and height=6
- * but there is no guarantee that these values are absolute.
- * They may depend on the font and any number of other
- * factors. In fact, the author has observed that setting
- * the font to anything but the default seems to sometimes
- * fix the problem. The fix is to use LVM_GETCOUNTPERPAGE
- * to detect the case when the number of visible items is
- * zero and use LVM_ENSUREVISIBLE to scroll the table to
- * make the index visible.
- */
-
- /*
- * Bug in Windows. When the table header is visible and
- * there is not enough space to show a single table item,
- * LVM_GETCOUNTPERPAGE can return a negative number instead
- * of zero. The fix is to test for negative or zero.
- */
- if (OS.SendMessage (handle, OS.LVM_GETCOUNTPERPAGE, 0, 0) <= 0) {
-
- /*
- * Bug in Windows. For some reason, LVM_ENSUREVISIBLE can
- * scroll one item more or one item less when there is not
- * enough space to show a single table item. The fix is
- * to detect the case and call LVM_ENSUREVISIBLE again with
- * the same arguments. It seems that once LVM_ENSUREVISIBLE
- * has scrolled into the general area, it is able to scroll
- * to the exact item.
- */
- OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, index, 1);
- if (index != OS.SendMessage (handle, OS.LVM_GETTOPINDEX, 0, 0)) {
- OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, index, 1);
- }
- return;
- }
-
- /* Use LVM_SCROLL to scroll the table */
- RECT rect = new RECT ();
- rect.left = OS.LVIR_BOUNDS;
- OS.SendMessage (handle, OS.LVM_GETITEMRECT, 0, rect);
- int dy = (index - topIndex) * (rect.bottom - rect.top);
- OS.SendMessage (handle, OS.LVM_SCROLL, 0, dy);
-}
-
-void showItem (int index) {
- /*
- * Bug in Windows. For some reason, when there is insufficient space
- * to show an item, LVM_ENSUREVISIBLE causes blank lines to be
- * inserted at the top of the widget. A call to LVM_GETTOPINDEX will
- * return a negative number (this is an impossible result). The fix
- * is to use LVM_GETCOUNTPERPAGE to detect the case when the number
- * of visible items is zero and use LVM_ENSUREVISIBLE with the fPartialOK
- * flag to scroll the table.
- */
- if (OS.SendMessage (handle, OS.LVM_GETCOUNTPERPAGE, 0, 0) <= 0) {
- /*
- * Bug in Windows. For some reason, LVM_ENSUREVISIBLE can
- * scroll one item more or one item less when there is not
- * enough space to show a single table item. The fix is
- * to detect the case and call LVM_ENSUREVISIBLE again with
- * the same arguments. It seems that once LVM_ENSUREVISIBLE
- * has scrolled into the general area, it is able to scroll
- * to the exact item.
- */
- OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, index, 1);
- if (index != OS.SendMessage (handle, OS.LVM_GETTOPINDEX, 0, 0)) {
- OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, index, 1);
- }
- } else {
- OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, index, 0);
- }
-}
-
-/**
- * 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) showItem (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 = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_SELECTED);
- if (index != -1) showItem (index);
-}
-
-int widgetStyle () {
- int bits = super.widgetStyle () | OS.LVS_SHAREIMAGELISTS | OS.WS_CLIPCHILDREN;
- if ((style & SWT.HIDE_SELECTION) == 0) bits |= OS.LVS_SHOWSELALWAYS;
- if ((style & SWT.SINGLE) != 0) bits |= OS.LVS_SINGLESEL;
- /*
- * This code is intentionally commented. In the future,
- * the FLAT bit may be used to make the header flat and
- * unresponsive to mouse clicks.
- */
-// if ((style & SWT.FLAT) != 0) bits |= OS.LVS_NOSORTHEADER;
- bits |= OS.LVS_REPORT | OS.LVS_NOCOLUMNHEADER;
- return bits;
-}
-
-TCHAR windowClass () {
- return TableClass;
-}
-
-int windowProc () {
- return TableProc;
-}
-
-LRESULT WM_GETOBJECT (int wParam, int lParam) {
- /*
- * Ensure that there is an accessible object created for this
- * control because support for checked item accessibility is
- * temporarily implemented in the accessibility package.
- */
- if ((style & SWT.CHECK) != 0) {
- if (accessible == null) accessible = new_Accessible (this);
- }
- return super.WM_GETOBJECT (wParam, lParam);
-}
-
-LRESULT WM_KEYDOWN (int wParam, int lParam) {
- LRESULT result = super.WM_KEYDOWN (wParam, lParam);
- if (result != null) return result;
- if ((style & SWT.CHECK) != 0 && wParam == OS.VK_SPACE) {
- int index = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_FOCUSED);
- if (index != -1) {
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.stateMask = OS.LVIS_STATEIMAGEMASK;
- lvItem.iItem = index;
- OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem);
- int state = lvItem.state >> 12;
- if ((state & 0x1) != 0) {
- state++;
- } else {
- --state;
- }
- lvItem.state = state << 12;
- OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem);
- }
- }
- return result;
-}
-
-LRESULT WM_LBUTTONDBLCLK (int wParam, int lParam) {
- /*
- * Feature in Windows. When the user selects outside of
- * a table item, Windows deselects all the items, even
- * when the table is multi-select. While not strictly
- * wrong, this is unexpected. The fix is to detect the
- * case and avoid calling the window proc.
- */
- LVHITTESTINFO pinfo = new LVHITTESTINFO ();
- pinfo.x = (short) (lParam & 0xFFFF);
- pinfo.y = (short) (lParam >> 16);
- OS.SendMessage (handle, OS.LVM_HITTEST, 0, pinfo);
- sendMouseEvent (SWT.MouseDown, 1, OS.WM_LBUTTONDOWN, wParam, lParam);
- sendMouseEvent (SWT.MouseDoubleClick, 1, OS.WM_LBUTTONDBLCLK, wParam, lParam);
- if (pinfo.iItem != -1) callWindowProc (OS.WM_LBUTTONDBLCLK, wParam, lParam);
- if (OS.GetCapture () != handle) OS.SetCapture (handle);
- return LRESULT.ZERO;
-}
-
-LRESULT WM_LBUTTONDOWN (int wParam, int lParam) {
- mouseDown = true;
-
- /*
- * Feature in Windows. For some reason, capturing
- * the mouse after processing the mouse event for the
- * widget interferes with the normal mouse processing
- * for the widget. The fix is to avoid the automatic
- * mouse capture.
- */
- LRESULT result = sendMouseDownEvent (SWT.MouseDown, 1, OS.WM_LBUTTONDOWN, wParam, lParam);
-
- /* Look for check/uncheck */
- if ((style & SWT.CHECK) != 0) {
- LVHITTESTINFO pinfo = new LVHITTESTINFO ();
- pinfo.x = (short) (lParam & 0xFFFF);
- pinfo.y = (short) (lParam >> 16);
- /*
- * Note that when the table has LVS_EX_FULLROWSELECT and the
- * user clicks anywhere on a row except on the check box, all
- * of the bits are set. The hit test flags are LVHT_ONITEM.
- * This means that a bit test for LVHT_ONITEMSTATEICON is not
- * the correct way to determine that the user has selected
- * the check box.
- */
- int index = OS.SendMessage (handle, OS.LVM_HITTEST, 0, pinfo);
- if (index != -1 && pinfo.flags == OS.LVHT_ONITEMSTATEICON) {
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.stateMask = OS.LVIS_STATEIMAGEMASK;
- lvItem.iItem = index;
- OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem);
- int state = lvItem.state >> 12;
- if ((state & 0x1) != 0) {
- state++;
- } else {
- --state;
- }
- lvItem.state = state << 12;
- OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem);
- }
- }
-
- return result;
-}
-
-LRESULT WM_LBUTTONUP (int wParam, int lParam) {
- mouseDown = false;
- return super.WM_LBUTTONUP (wParam, lParam);
-}
-
-LRESULT WM_MOUSEHOVER (int wParam, int lParam) {
- /*
- * Feature in Windows. Despite the fact that hot
- * tracking is not enabled, the hot tracking code
- * in WM_MOUSEHOVER is executed causing the item
- * under the cursor to be selected. The fix is to
- * avoid calling the window proc.
- */
- LRESULT result = super.WM_MOUSEHOVER (wParam, lParam);
- int bits = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
- int mask = OS.LVS_EX_ONECLICKACTIVATE | OS.LVS_EX_TRACKSELECT | OS.LVS_EX_TWOCLICKACTIVATE;
- if ((bits & mask) != 0) return result;
- return LRESULT.ZERO;
-}
-
-LRESULT WM_NOTIFY (int wParam, int lParam) {
- NMHDR hdr = new NMHDR ();
- OS.MoveMemory (hdr, lParam, NMHDR.sizeof);
- int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
- if (hdr.hwndFrom == hwndHeader) {
- /*
- * Feature in Windows. On NT, the automatically created
- * header control is created as a UNICODE window, not an
- * ANSI window despite the fact that the parent is created
- * as an ANSI window. This means that it sends UNICODE
- * notification messages to the parent window on NT for
- * no good reason. The data and size in the NMHEADER and
- * HDITEM structs is identical between the platforms so no
- * different message is actually necessary. Despite this,
- * Windows sends different messages. The fix is to look
- * for both messages, despite the platform. This works
- * because only one will be sent on either platform, never
- * both.
- */
- switch (hdr.code) {
- case OS.HDN_BEGINTRACKW:
- case OS.HDN_BEGINTRACKA:
- case OS.HDN_DIVIDERDBLCLICKW:
- case OS.HDN_DIVIDERDBLCLICKA:{
- NMHEADER phdn = new NMHEADER ();
- OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
- TableColumn column = columns [phdn.iItem];
- if (column != null && !column.getResizable ()) {
- return LRESULT.ONE;
- }
- break;
- }
- case OS.HDN_ITEMCHANGEDW:
- case OS.HDN_ITEMCHANGEDA: {
- NMHEADER phdn = new NMHEADER ();
- OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
- Event event = new Event ();
- if (phdn.pitem != 0) {
- HDITEM pitem = new HDITEM ();
- OS.MoveMemory (pitem, phdn.pitem, HDITEM.sizeof);
- if ((pitem.mask & OS.HDI_WIDTH) != 0) {
- TableColumn column = columns [phdn.iItem];
- if (column != null) {
- column.sendEvent (SWT.Resize, event);
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the resize
- * event. If this happens, end the processing of the
- * Windows message by returning zero as the result of
- * the window proc.
- */
- if (isDisposed ()) return LRESULT.ZERO;
- int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
- if (count == 1 && columns [0] == null) count = 0;
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the column in the move
- * event. If this happens, process the move event
- * for those columns that have not been destroyed.
- */
- TableColumn [] newColumns = new TableColumn [count];
- System.arraycopy (columns, 0, newColumns, 0, count);
- for (int i=phdn.iItem+1; i<count; i++) {
- if (!newColumns [i].isDisposed ()) {
- newColumns [i].sendEvent (SWT.Move, event);
- }
- }
- }
- }
- }
- break;
- }
- }
- }
- return super.WM_NOTIFY (wParam, lParam);
-}
-
-LRESULT WM_RBUTTONDBLCLK (int wParam, int lParam) {
- /*
- * Feature in Windows. When the user selects outside of
- * a table item, Windows deselects all the items, even
- * when the table is multi-select. While not strictly
- * wrong, this is unexpected. The fix is to detect the
- * case and avoid calling the window proc.
- */
- LVHITTESTINFO pinfo = new LVHITTESTINFO ();
- pinfo.x = (short) (lParam & 0xFFFF);
- pinfo.y = (short) (lParam >> 16);
- OS.SendMessage (handle, OS.LVM_HITTEST, 0, pinfo);
- sendMouseEvent (SWT.MouseDown, 1, OS.WM_RBUTTONDOWN, wParam, lParam);
- sendMouseEvent (SWT.MouseDoubleClick, 1, OS.WM_RBUTTONDBLCLK, wParam, lParam);
- if (pinfo.iItem != -1) callWindowProc (OS.WM_RBUTTONDBLCLK, wParam, lParam);
- if (OS.GetCapture () != handle) OS.SetCapture (handle);
- return LRESULT.ZERO;
-}
-
-LRESULT WM_RBUTTONDOWN (int wParam, int lParam) {
- /*
- * Feature in Windows. For some reason, capturing
- * the mouse after processing the mouse event for the
- * widget interferes with the normal mouse processing
- * for the widget. The fix is to avoid the automatic
- * mouse capture.
- */
- return sendMouseDownEvent (SWT.MouseDown, 3, OS.WM_RBUTTONDOWN, wParam, lParam);
-}
-
-LRESULT WM_SETFOCUS (int wParam, int lParam) {
- LRESULT result = super.WM_SETFOCUS (wParam, lParam);
- /*
- * Bug in Windows. For some reason, the table does
- * not set the default focus rectangle to be the first
- * item in the table when it gets focus and there is
- * no selected item. The fix to make the first item
- * be the focus item.
- */
- int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
- if (count == 0) return result;
- int index = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_FOCUSED);
- if (index == -1) {
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.state = OS.LVIS_FOCUSED;
- lvItem.stateMask = OS.LVIS_FOCUSED;
- ignoreSelect = true;
- OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem);
- ignoreSelect = false;
- }
- return result;
-}
-
-LRESULT WM_SIZE (int wParam, int lParam) {
- if (ignoreResize) {
- ignoreResize = false;
- int code = callWindowProc (OS.WM_SIZE, wParam, lParam);
- return new LRESULT (code);
- }
- return super.WM_SIZE (wParam, lParam);
-}
-
-LRESULT WM_SYSCOLORCHANGE (int wParam, int lParam) {
- LRESULT result = super.WM_SYSCOLORCHANGE (wParam, lParam);
- if (result != null) return result;
- if ((style & SWT.CHECK) != 0) setCheckboxImageListColor ();
- return result;
-}
-
-LRESULT wmNotifyChild (int wParam, int lParam) {
- NMHDR hdr = new NMHDR ();
- OS.MoveMemory (hdr, lParam, NMHDR.sizeof);
- switch (hdr.code) {
- case OS.NM_CUSTOMDRAW: {
- if (!customDraw) break;
- NMLVCUSTOMDRAW nmcd = new NMLVCUSTOMDRAW ();
- OS.MoveMemory (nmcd, lParam, NMLVCUSTOMDRAW.sizeof);
- switch (nmcd.dwDrawStage) {
- case OS.CDDS_PREPAINT: return new LRESULT (OS.CDRF_NOTIFYITEMDRAW);
- case OS.CDDS_ITEMPREPAINT: return new LRESULT (OS.CDRF_NOTIFYSUBITEMDRAW);
- case OS.CDDS_ITEMPREPAINT | OS.CDDS_SUBITEM: {
- TableItem item = items [nmcd.dwItemSpec];
- int clrText = item.foreground, clrTextBk = item.background;
- if (clrText == -1 && clrTextBk == -1) break;
- nmcd.clrText = clrText == -1 ? getForegroundPixel () : clrText;
- nmcd.clrTextBk = clrTextBk == -1 ? getBackgroundPixel () : clrTextBk;
- OS.MoveMemory (lParam, nmcd, NMLVCUSTOMDRAW.sizeof);
- return new LRESULT (OS.CDRF_NEWFONT);
- }
- }
- break;
- }
- case OS.LVN_MARQUEEBEGIN: return LRESULT.ONE;
- case OS.LVN_BEGINDRAG:
- case OS.LVN_BEGINRDRAG: {
- dragStarted = true;
- if (hdr.code == OS.LVN_BEGINDRAG) {
- postEvent (SWT.DragDetect);
- }
- break;
- }
- case OS.LVN_COLUMNCLICK: {
- NMLISTVIEW pnmlv = new NMLISTVIEW ();
- OS.MoveMemory(pnmlv, lParam, NMLISTVIEW.sizeof);
- TableColumn column = columns [pnmlv.iSubItem];
- if (column != null) {
- column.postEvent (SWT.Selection);
- }
- break;
- }
- case OS.LVN_ITEMACTIVATE: {
- NMLISTVIEW pnmlv = new NMLISTVIEW ();
- OS.MoveMemory(pnmlv, lParam, NMLISTVIEW.sizeof);
- if (pnmlv.iItem != -1) {
- Event event = new Event ();
- event.item = items [pnmlv.iItem];
- postEvent (SWT.DefaultSelection, event);
- }
- break;
- }
- case OS.LVN_ITEMCHANGED: {
- if (!ignoreSelect) {
- NMLISTVIEW pnmlv = new NMLISTVIEW ();
- OS.MoveMemory (pnmlv, lParam, NMLISTVIEW.sizeof);
- if (pnmlv.iItem != -1 && (pnmlv.uChanged & OS.LVIF_STATE) != 0) {
- int oldBits = pnmlv.uOldState & OS.LVIS_STATEIMAGEMASK;
- int newBits = pnmlv.uNewState & OS.LVIS_STATEIMAGEMASK;
- if (oldBits != newBits) {
- Event event = new Event();
- event.item = items [pnmlv.iItem];
- event.detail = SWT.CHECK;
- /*
- * This code is intentionally commented.
- */
-// OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, pnmlv.iItem, 0);
- postEvent (SWT.Selection, event);
- } else {
- boolean isFocus = (pnmlv.uNewState & OS.LVIS_FOCUSED) != 0;
- int index = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_FOCUSED);
- if ((style & SWT.MULTI) != 0) {
- if (OS.GetKeyState (OS.VK_CONTROL) < 0) {
- if (!isFocus) {
- if (index == pnmlv.iItem) {
- boolean isSelected = (pnmlv.uNewState & OS.LVIS_SELECTED) != 0;
- boolean wasSelected = (pnmlv.uOldState & OS.LVIS_SELECTED) != 0;
- isFocus = isSelected != wasSelected;
- }
- } else {
- isFocus = mouseDown;
- }
- }
- }
- if (OS.GetKeyState (OS.VK_SPACE) < 0) isFocus = true;
- if (isFocus) {
- Event event = new Event();
- if (index != -1) {
- /*
- * This code is intentionally commented.
- */
-// OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, index, 0);
- event.item = items [index];
- }
- postEvent (SWT.Selection, event);
- }
- }
- }
- }
- break;
- }
- }
- return super.wmNotifyChild (wParam, lParam);
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.events.*; + +/** + * Instances of this class implement a selectable user interface + * object that displays a list of images and strings and issue + * notificiation when selected. + * <p> + * The item children that may be added to instances of this class + * must be of type <code>TableItem</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>SINGLE, MULTI, CHECK, FULL_SELECTION, HIDE_SELECTION</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection, DefaultSelection</dd> + * </dl> + * <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> + */ + +public class Table extends Composite { + TableItem [] items; + TableColumn [] columns; + ImageList imageList; + boolean ignoreSelect, dragStarted, ignoreResize, mouseDown, customDraw; + static final int TableProc; + static final TCHAR TableClass = new TCHAR (0, OS.WC_LISTVIEW, true); + static { + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, TableClass, lpWndClass); + TableProc = lpWndClass.lpfnWndProc; + } + +/** + * 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 Widget#checkSubclass + * @see Widget#getStyle + */ +public Table (Composite parent, int style) { + super (parent, checkStyle (style)); +} + +/** + * Adds the listener to the collection of listeners who will + * be notified when the receiver's selection changes, 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 reciever has <code>SWT.CHECK</code> style set 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 + * + * @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); +} + +int callWindowProc (int msg, int wParam, int lParam) { + if (handle == 0) return 0; + return OS.CallWindowProc (TableProc, handle, msg, wParam, lParam); +} + +static int checkStyle (int style) { + /* + * Feature in Windows. It is not possible to create + * a table that does not have scroll bars. Therefore, + * no matter what style bits are specified, set the + * H_SCROLL and V_SCROLL bits so that the SWT style + * will match the widget that Windows creates. + */ + style |= SWT.H_SCROLL | SWT.V_SCROLL; + return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0); +} + +protected void checkSubclass () { + if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS); +} + +public Point computeSize (int wHint, int hHint, boolean changed) { + checkWidget (); + int bits = 0; + if (wHint != SWT.DEFAULT) { + bits |= wHint & 0xFFFF; + } else { + int width = 0; + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0); + for (int i=0; i<count; i++) { + width += OS.SendMessage (handle, OS.LVM_GETCOLUMNWIDTH, i, 0); + } + bits |= width & 0xFFFF; + } + if (hHint != SWT.DEFAULT) bits |= hHint << 16; + int result = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, -1, bits); + int width = result & 0xFFFF, height = result >> 16; + 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; + /* + * Feature in Windows. For some reason, LVM_APPROXIMATEVIEWRECT + * does not include the space for the vertical scroll bar but does + * take into account the horizontal scroll bar when calculating the + * space needed to show the items. The fix is to add in this space. + */ + if ((style & SWT.V_SCROLL) != 0) { + width += OS.GetSystemMetrics (OS.SM_CXVSCROLL); + } + if (((style & SWT.H_SCROLL) != 0) && (hHint != SWT.DEFAULT)) { + height += OS.GetSystemMetrics (OS.SM_CYHSCROLL); + } + return new Point (width, height); +} + +void createHandle () { + super.createHandle (); + state &= ~CANVAS; + + /* + * This code is intentionally commented. According to + * the documentation, setting the default item size is + * supposed to improve performance. By experimentation, + * this does not seem to have much of an effect. + */ +// OS.SendMessage (handle, OS.LVM_SETITEMCOUNT, 1024 * 2, 0); + + /* Set the checkbox image list */ + if ((style & SWT.CHECK) != 0) { + int empty = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 0, 0); + int oneItem = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 1, 0); + int width = (oneItem >> 16) - (empty >> 16), height = width; + setCheckboxImageList (width, height); + } + + /* + * Feature in Windows. When the control is created, + * it does not use the default system font. A new HFONT + * is created and destroyed when the control is destroyed. + * This means that a program that queries the font from + * this control, uses the font in another control and then + * destroys this control will have the font unexpectedly + * destroyed in the other control. The fix is to assign + * the font ourselves each time the control is created. + * The control will not destroy a font that it did not + * create. + */ + int hFont = OS.GetStockObject (OS.SYSTEM_FONT); + OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0); + + /* + * Bug in Windows. When the first column is inserted + * without setting the header text, Windows will never + * allow the header text for the first column to be set. + * The fix is to set the text to an empty string when + * the column is inserted. + */ + LVCOLUMN lvColumn = new LVCOLUMN (); + lvColumn.mask = OS.LVCF_TEXT; + int hHeap = OS.GetProcessHeap (); + int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, TCHAR.sizeof); + lvColumn.pszText = pszText; + OS.SendMessage (handle, OS.LVM_INSERTCOLUMN, 0, lvColumn); + OS.HeapFree (hHeap, 0, pszText); + + /* Set the extended style bits */ + int bits = OS.LVS_EX_SUBITEMIMAGES | OS.LVS_EX_LABELTIP; + if ((style & SWT.FULL_SELECTION) != 0) bits |= OS.LVS_EX_FULLROWSELECT; + OS.SendMessage (handle, OS.LVM_SETEXTENDEDLISTVIEWSTYLE, bits, bits); + + /* + * Feature in Windows. Windows does not explicitly set the orientation of + * the header. Instead, the orientation is inherited when WS_EX_LAYOUTRTL + * is specified for the table. This means that when both WS_EX_LAYOUTRTL + * and WS_EX_NOINHERITLAYOUT are specified for the table, the header will + * not be oriented correctly. The fix is to explicitly set the orientation + * for the header. + * + * NOTE: WS_EX_LAYOUTRTL is not supported on Windows NT. + */ + if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) < (4 << 16 | 10)) return; + if ((style & SWT.RIGHT_TO_LEFT) != 0) { + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + int extStyle = OS.GetWindowLong (hwndHeader, OS.GWL_EXSTYLE); + OS.SetWindowLong (hwndHeader, OS.GWL_EXSTYLE, extStyle | OS.WS_EX_LAYOUTRTL); + } +} + +void createItem (TableColumn column, int index) { + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0); + if (count == 1 && columns [0] == null) count = 0; + if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE); + if (count == columns.length) { + TableColumn [] newColumns = new TableColumn [columns.length + 4]; + System.arraycopy (columns, 0, newColumns, 0, columns.length); + columns = newColumns; + } + /* + * Insert the column into the columns array before inserting + * it into the widget so that the column will be present when + * any callbacks are issued as a result of LVM_INSERTCOLUMN + * or LVM_SETCOLUMN. + */ + System.arraycopy (columns, index, columns, index + 1, count - index); + columns [index] = column; + if (index == 0) { + if (count > 0) { + LVCOLUMN lvColumn = new LVCOLUMN (); + lvColumn.mask = OS.LVCF_WIDTH; + OS.SendMessage (handle, OS.LVM_INSERTCOLUMN, 1, lvColumn); + OS.SendMessage (handle, OS.LVM_GETCOLUMN, 1, lvColumn); + int width = lvColumn.cx; + int cchTextMax = 1024; + int hHeap = OS.GetProcessHeap (); + int byteCount = cchTextMax * TCHAR.sizeof; + int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_TEXT | OS.LVIF_IMAGE | OS.LVIF_STATE; + int itemCount = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); + for (int i=0; i<itemCount; i++) { + lvItem.iItem = i; + lvItem.iSubItem = 0; + lvItem.pszText = pszText; + lvItem.cchTextMax = cchTextMax; + OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem); + lvItem.iSubItem = 1; + OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem); + lvItem.iSubItem = 0; + lvItem.pszText = lvItem.cchTextMax = 0; + lvItem.iImage = OS.I_IMAGENONE; + OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem); + items [i].text = ""; + items [i].image = null; + } + lvColumn.mask = OS.LVCF_TEXT | OS.LVCF_IMAGE | OS.LVCF_WIDTH | OS.LVCF_FMT; + lvColumn.pszText = pszText; + lvColumn.cchTextMax = cchTextMax; + OS.SendMessage (handle, OS.LVM_GETCOLUMN, 0, lvColumn); + OS.SendMessage (handle, OS.LVM_SETCOLUMN, 1, lvColumn); + lvColumn.fmt = OS.LVCFMT_IMAGE; + lvColumn.cx = width; + lvColumn.iImage = OS.I_IMAGENONE; + lvColumn.pszText = lvColumn.cchTextMax = 0; + OS.SendMessage (handle, OS.LVM_SETCOLUMN, 0, lvColumn); + lvColumn.mask = OS.LVCF_FMT; + lvColumn.fmt = OS.LVCFMT_LEFT; + OS.SendMessage (handle, OS.LVM_SETCOLUMN, 0, lvColumn); + if (pszText != 0) OS.HeapFree (hHeap, 0, pszText); + } + } else { + int fmt = OS.LVCFMT_LEFT; + if ((column.style & SWT.CENTER) == SWT.CENTER) fmt = OS.LVCFMT_CENTER; + if ((column.style & SWT.RIGHT) == SWT.RIGHT) fmt = OS.LVCFMT_RIGHT; + LVCOLUMN lvColumn = new LVCOLUMN (); + lvColumn.mask = OS.LVCF_WIDTH | OS.LVCF_FMT; + lvColumn.fmt = fmt; + OS.SendMessage (handle, OS.LVM_INSERTCOLUMN, index, lvColumn); + } +} + +void createItem (TableItem item, int index) { + item.foreground = item.background = -1; + int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); + if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE); + if (count == items.length) { + TableItem [] newItems = new TableItem [items.length + 4]; + System.arraycopy (items, 0, newItems, 0, items.length); + items = newItems; + } + LVITEM lvItem = new LVITEM (); + lvItem.iItem = index; + + /* + * Bug in Windows. Despite the fact that the image list + * index has never been set for the item, Windows always + * assumes that the image index for the item is valid. + * When an item is inserted, the image index is zero. + * Therefore, when the first image is inserted and is + * assigned image index zero, every item draws with this + * image. The fix is to set the image index to none when + * the image is created. + */ + lvItem.iImage = OS.I_IMAGENONE; + lvItem.mask = OS.LVIF_IMAGE; + + /* Set the initial unchecked state */ + if ((style & SWT.CHECK) != 0) { + lvItem.mask = lvItem.mask | OS.TVIF_STATE; + lvItem.state = 1 << 12; + lvItem.stateMask = OS.LVIS_STATEIMAGEMASK; + } + + /* Insert the item */ + ignoreSelect = true; + int result = OS.SendMessage (handle, OS.LVM_INSERTITEM, 0, lvItem); + ignoreSelect = false; + if (result == -1) error (SWT.ERROR_ITEM_NOT_ADDED); + System.arraycopy (items, index, items, index + 1, count - index); + items [index] = item; +} + +void createWidget () { + super.createWidget (); + items = new TableItem [4]; + columns = new TableColumn [4]; +} + +int defaultBackground () { + return OS.GetSysColor (OS.COLOR_WINDOW); +} + +/** + * 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 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> + */ +public void deselect (int [] indices) { + checkWidget (); + if (indices == null) error (SWT.ERROR_NULL_ARGUMENT); + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.stateMask = OS.LVIS_SELECTED; + for (int i=0; i<indices.length; i++) { + lvItem.iItem = indices [i]; + ignoreSelect = true; + OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem); + ignoreSelect = false; + } +} + +/** + * 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 (); + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.stateMask = OS.LVIS_SELECTED; + lvItem.iItem = index; + ignoreSelect = true; + OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem); + 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 (); + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.stateMask = OS.LVIS_SELECTED; + for (int i=start; i<=end; i++) { + lvItem.iItem = i; + ignoreSelect = true; + OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem); + 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 (); + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.stateMask = OS.LVIS_SELECTED; + OS.SendMessage (handle, OS.LVM_SETITEMSTATE, -1, lvItem); +} + +void destroyItem (TableColumn column) { + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0); + int index = 0; + while (index < count) { + if (columns [index] == column) break; + index++; + } + if (index == count) return; + boolean first = false; + if (index == 0) { + first = true; + if (count > 1) { + index = 1; + int cchTextMax = 1024; + int hHeap = OS.GetProcessHeap (); + int byteCount = cchTextMax * TCHAR.sizeof; + int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + LVCOLUMN lvColumn = new LVCOLUMN (); + lvColumn.mask = OS.LVCF_TEXT | OS.LVCF_WIDTH; + lvColumn.pszText = pszText; + lvColumn.cchTextMax = cchTextMax; + OS.SendMessage (handle, OS.LVM_GETCOLUMN, 1, lvColumn); + lvColumn.mask |= OS.LVCF_FMT; + lvColumn.fmt = OS.LVCFMT_LEFT; + OS.SendMessage (handle, OS.LVM_SETCOLUMN, 0, lvColumn); + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_TEXT | OS.LVIF_IMAGE | OS.LVIF_STATE; + lvItem.pszText = pszText; + lvItem.cchTextMax = cchTextMax; + int itemCount = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); + for (int i=0; i<itemCount; i++) { + lvItem.iItem = i; + lvItem.iSubItem = 1; + OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem); + lvItem.iSubItem = 0; + OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem); + TCHAR buffer = new TCHAR (getCodePage (), cchTextMax); + OS.MoveMemory (buffer, pszText, byteCount); + items [i].text = buffer.toString (0, buffer.strlen ()); + if (imageList != null) { + items [i].image = imageList.get (lvItem.iImage); + } + } + if (pszText != 0) OS.HeapFree (hHeap, 0, pszText); + } else { + int hHeap = OS.GetProcessHeap (); + int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, TCHAR.sizeof); + LVCOLUMN lvColumn = new LVCOLUMN (); + lvColumn.mask = OS.LVCF_TEXT; + lvColumn.pszText = pszText; + OS.SendMessage (handle, OS.LVM_SETCOLUMN, 0, lvColumn); + if (pszText != 0) OS.HeapFree (hHeap, 0, pszText); + OS.SendMessage (handle, OS.LVM_SETCOLUMNWIDTH, 0, OS.LVSCW_AUTOSIZE); + } + } + if (count > 1) { + if (OS.SendMessage (handle, OS.LVM_DELETECOLUMN, index, 0) == 0) { + error (SWT.ERROR_ITEM_NOT_REMOVED); + } + } + if (first) index = 0; + System.arraycopy (columns, index + 1, columns, index, --count - index); + columns [count] = null; +} + +void destroyItem (TableItem item) { + int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); + int index = 0; + while (index < count) { + if (items [index] == item) break; + index++; + } + if (index == count) return; + ignoreSelect = true; + int code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0); + ignoreSelect = false; + if (code == 0) error (SWT.ERROR_ITEM_NOT_REMOVED); + System.arraycopy (items, index + 1, items, index, --count - index); + items [count] = null; + if (count == 0) { + if (imageList != null) { + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + int columnCount = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0); + if (columnCount == 1 && columns [0] == null) columnCount = 0; + int i = 0; + while (i < columnCount) { + TableColumn column = columns [i]; + if (column.getImage () != null) break; + i++; + } + if (i == columnCount) { + OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_SMALL, 0); + Display display = getDisplay (); + display.releaseImageList (imageList); + imageList = null; + } + } + customDraw = false; + items = new TableItem [4]; + } +} + +void fixCheckboxImageList () { + /* + * Bug in Windows. When the state image list is larger than the + * image list, Windows incorrectly positions the state images. When + * the table is scrolled, Windows draws garbage. The fix is to force + * the state image list to be the same size as the image list. + */ + if ((style & SWT.CHECK) == 0) return; + int hImageList = OS.SendMessage (handle, OS.LVM_GETIMAGELIST, OS.LVSIL_SMALL, 0); + if (hImageList == 0) return; + int [] cx = new int [1], cy = new int [1]; + OS.ImageList_GetIconSize (hImageList, cx, cy); + int hOldStateList = OS.SendMessage (handle, OS.LVM_GETIMAGELIST, OS.LVSIL_STATE, 0); + if (hOldStateList == 0) return; + int [] stateCx = new int [1], stateCy = new int [1]; + OS.ImageList_GetIconSize (hOldStateList, stateCx, stateCy); + if (cx [0] == stateCx [0] && cy [0] == stateCy [0]) return; + setCheckboxImageList (cx [0], cy [0]); +} + +int getBackgroundPixel () { + return OS.SendMessage (handle, OS.LVM_GETBKCOLOR, 0, 0); +} + +/** + * Returns the column at the given, zero-relative index in the + * receiver. Throws an exception if the index is out of range. + * 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> + */ +public TableColumn getColumn (int index) { + checkWidget (); + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0); + if (count == 1 && columns [0] == null) count = 0; + if (!(0 <= index && index < count)) 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 is 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure</li> + * </ul> + */ +public int getColumnCount () { + checkWidget (); + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0); + if (count == 1 && columns [0] == null) count = 0; + return count; +} + +/** + * Returns an array of <code>TableColumn</code>s which are the + * columns in the receiver. 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> + */ +public TableColumn [] getColumns () { + checkWidget (); + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0); + if (count == 1 && columns [0] == null) count = 0; + TableColumn [] result = new TableColumn [count]; + System.arraycopy (columns, 0, result, 0, count); + return result; +} + +int getFocusIndex () { + return OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_FOCUSED); +} + +int getForegroundPixel () { + return OS.SendMessage (handle, OS.LVM_GETTEXTCOLOR, 0, 0); +} + +/** + * Returns the width in pixels of a grid 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 getGridLineWidth () { + checkWidget (); + return 1; +} + +/** + * 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 (); + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + if (hwndHeader == 0) return 0; + RECT rect = new RECT (); + OS.GetWindowRect (hwndHeader, rect); + return rect.bottom - rect.top; +} + +/** + * 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 (); + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + return (bits & OS.LVS_NOCOLUMNHEADER) == 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 TableItem getItem (int index) { + checkWidget (); + int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); + if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE); + return items [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. + * + * @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 TableItem getItem (Point point) { + checkWidget (); + if (point == null) error (SWT.ERROR_NULL_ARGUMENT); + LVHITTESTINFO pinfo = new LVHITTESTINFO (); + pinfo.x = point.x; pinfo.y = point.y; + OS.SendMessage (handle, OS.LVM_HITTEST, 0, pinfo); + if (pinfo.iItem != -1) return items [pinfo.iItem]; + 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 OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); +} + +/** + * Returns the height of the area which would be used to + * display <em>one</em> of the items in the receiver's. + * + * @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 (); + int empty = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 0, 0); + int oneItem = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 1, 0); + return (oneItem >> 16) - (empty >> 16); +} + +/** + * Returns an 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 (); + int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); + TableItem [] result = new TableItem [count]; + System.arraycopy (items, 0, result, 0, count); + return result; +} + +/** + * Returns <code>true</code> if the receiver's lines are 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 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 (); + int bits = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); + return (bits & OS.LVS_EX_GRIDLINES) != 0; +} + +/** + * Returns an array of <code>TableItem</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 TableItem [] getSelection () { + checkWidget (); + int i = -1, j = 0, count = OS.SendMessage (handle, OS.LVM_GETSELECTEDCOUNT, 0, 0); + TableItem [] result = new TableItem [count]; + while ((i = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, i, OS.LVNI_SELECTED)) != -1) { + result [j++] = items [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 OS.SendMessage (handle, OS.LVM_GETSELECTEDCOUNT, 0, 0); +} + +/** + * 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 (); + int focusIndex = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_FOCUSED); + int selectedIndex = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_SELECTED); + if (focusIndex == selectedIndex) return selectedIndex; + int i = -1; + while ((i = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, i, OS.LVNI_SELECTED)) != -1) { + if (i == focusIndex) return i; + } + return selectedIndex; +} + +/** + * Returns the zero-relative indices of the items which are currently + * selected in the receiver. 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 (); + int i = -1, j = 0, count = OS.SendMessage (handle, OS.LVM_GETSELECTEDCOUNT, 0, 0); + int [] result = new int [count]; + while ((i = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, i, OS.LVNI_SELECTED)) != -1) { + result [j++] = 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 (); + return OS.SendMessage (handle, OS.LVM_GETTOPINDEX, 0, 0); +} + +int imageIndex (Image image) { + if (image == null) return OS.I_IMAGENONE; + if (imageList == null) { + Rectangle bounds = image.getBounds (); + imageList = getDisplay ().getImageList (new Point (bounds.width, bounds.height)); + int index = imageList.indexOf (image); + if (index == -1) index = imageList.add (image); + int hImageList = imageList.getHandle (); + OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_SMALL, hImageList); + return index; + } + int index = imageList.indexOf (image); + if (index != -1) return index; + return imageList.add (image); +} + +/** + * 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 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 (TableColumn column) { + checkWidget (); + if (column == null) error (SWT.ERROR_NULL_ARGUMENT); + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0); + for (int i=0; i<count; 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 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 (TableItem item) { + checkWidget (); + if (item == null) error (SWT.ERROR_NULL_ARGUMENT); + int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); + for (int i=0; i<count; i++) { + if (items [i] == item) 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 visibility 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 (); + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.stateMask = OS.LVIS_SELECTED; + lvItem.iItem = index; + int result = OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem); + return (result != 0) && ((lvItem.state & OS.LVIS_SELECTED) != 0); +} + +void releaseWidget () { + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + int columnCount = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0); + if (columnCount == 1 && columns [0] == null) columnCount = 0; + for (int i=0; i<columnCount; i++) { + TableColumn column = columns [i]; + if (!column.isDisposed ()) column.releaseResources (); + } + columns = null; + int itemCount = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); + + /* + * Feature in Windows. When there are a large number + * of columns and items in a table (>1000) where each + * of the subitems in the table has a string, it is much + * faster to delete each item with LVM_DELETEITEM rather + * than using LVM_DELETEALLITEMS. The fix is to detect + * this case and delete the items, one by one. + * + * NOTE: LVM_DELETEALLITEMS is also sent by the table + * when the table is destroyed. + */ + if (columnCount > 1) { + /* Turn off redraw and leave it off */ + OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); + for (int i=itemCount-1; i>=0; --i) { + ignoreSelect = true; + OS.SendMessage (handle, OS.LVM_DELETEITEM, i, 0); + ignoreSelect = false; + TableItem item = items [i]; + if (!item.isDisposed ()) item.releaseResources (); + } + } else { + for (int i=0; i<itemCount; i++) { + TableItem item = items [i]; + if (!item.isDisposed ()) item.releaseResources (); + } + } + customDraw = false; + items = null; + if (imageList != null) { + OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_SMALL, 0); + Display display = getDisplay (); + display.releaseImageList (imageList); + } + imageList = null; + int hOldList = OS.SendMessage (handle, OS.LVM_GETIMAGELIST, OS.LVSIL_STATE, 0); + OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_STATE, 0); + if (hOldList != 0) OS.ImageList_Destroy (hOldList); + super.releaseWidget (); +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li> + * </ul> + */ +public void remove (int [] indices) { + checkWidget (); + if (indices == null) error (SWT.ERROR_NULL_ARGUMENT); + int [] newIndices = new int [indices.length]; + System.arraycopy (indices, 0, newIndices, 0, indices.length); + sort (newIndices); + int last = -1; + int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); + for (int i=0; i<newIndices.length; i++) { + int index = newIndices [i]; + if (index != last || i == 0) { + ignoreSelect = true; + int code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0); + ignoreSelect = false; + if (code == 0) { + if (0 <= index && index < count) { + error (SWT.ERROR_ITEM_NOT_REMOVED); + } else { + error (SWT.ERROR_INVALID_RANGE); + } + } + + // BUG - disposed callback could remove an item + items [index].releaseResources (); + System.arraycopy (items, index + 1, items, index, --count - index); + items [count] = null; + last = index; + } + } +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li> + * </ul> + */ +public void remove (int index) { + checkWidget (); + int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); + ignoreSelect = true; + int code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0); + ignoreSelect = false; + if (code == 0) { + if (0 <= index && index < count) { + error (SWT.ERROR_ITEM_NOT_REMOVED); + } else { + error (SWT.ERROR_INVALID_RANGE); + } + } + TableItem item = items [index]; + System.arraycopy (items, index + 1, items, index, --count - index); + items [count] = null; + item.releaseResources (); +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li> + * </ul> + */ +public void remove (int start, int end) { + checkWidget (); + int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); + int index = start; + while (index <= end) { + ignoreSelect = true; + int code = OS.SendMessage (handle, OS.LVM_DELETEITEM, start, 0); + ignoreSelect = false; + if (code == 0) break; + + // BUG - disposed callback could remove an item + items [index].releaseResources (); + index++; + } + System.arraycopy (items, index, items, start, count - index); + for (int i=count-(index-start); i<count; i++) items [i] = null; + if (index <= end) { + if (0 <= index && index < count) { + error (SWT.ERROR_ITEM_NOT_REMOVED); + } else { + error (SWT.ERROR_INVALID_RANGE); + } + } +} + +/** + * 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 (); + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + int columnCount = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0); + if (columnCount == 1 && columns [0] == null) columnCount = 0; + int itemCount = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); + + /* + * Feature in Windows. When there are a large number + * of columns and items in a table (>1000) where each + * of the subitems in the table has a string, it is much + * faster to delete each item with LVM_DELETEITEM rather + * than using LVM_DELETEALLITEMS. The fix is to detect + * this case and delete the items, one by one. + * + * NOTE: LVM_DELETEALLITEMS is also sent by the table + * when the table is destroyed. + */ + if (columnCount > 1) { + boolean redraw = drawCount == 0 && OS.IsWindowVisible (handle); + if (redraw) OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); + int index = itemCount - 1; + while (index >= 0) { + ignoreSelect = true; + int code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0); + ignoreSelect = false; + if (code == 0) break; + + // BUG - disposed callback could remove an item + items [index].releaseResources (); + --index; + } + if (redraw) { + OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0); + /* + * This code is intentionally commented. The window proc + * for the table implements WM_SETREDRAW to invalidate + * and erase the table so it is not necessary to do this + * again. + */ +// int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE; +// OS.RedrawWindow (handle, null, 0, flags); + } + if (index != -1) error (SWT.ERROR_ITEM_NOT_REMOVED); + } else { + ignoreSelect = true; + int code = OS.SendMessage (handle, OS.LVM_DELETEALLITEMS, 0, 0); + ignoreSelect = false; + if (code == 0) error (SWT.ERROR_ITEM_NOT_REMOVED); + for (int i=0; i<itemCount; i++) { + TableItem item = items [i]; + if (!item.isDisposed ()) item.releaseResources (); + } + } + + if (imageList != null) { + int i = 0; + while (i < columnCount) { + TableColumn column = columns [i]; + if (column.getImage () != null) break; + i++; + } + if (i == columnCount) { + OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_SMALL, 0); + Display display = getDisplay (); + display.releaseImageList (imageList); + imageList = null; + } + } + customDraw = false; + items = new TableItem [4]; +} + +/** + * Removes the listener from the collection of listeners who will + * be notified when the receiver's selection changes. + * + * @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 items at the given zero-relative indices in the receiver. + * If the item at the given zero-relative index in the receiver + * is not selected, it is selected. If the item at the index + * was selected, it remains selected. Indices that are out + * of range and duplicate 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> + */ +public void select (int [] indices) { + checkWidget (); + if (indices == null) error (SWT.ERROR_NULL_ARGUMENT); + int length = indices.length; + if (length == 0) return; + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.state = OS.LVIS_SELECTED; + lvItem.stateMask = OS.LVIS_SELECTED; + for (int i=indices.length-1; i>=0; --i) { + lvItem.iItem = indices [i]; + ignoreSelect = true; + OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem); + ignoreSelect = 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. 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 (); + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.state = OS.LVIS_SELECTED; + lvItem.stateMask = OS.LVIS_SELECTED; + lvItem.iItem = index; + ignoreSelect = true; + OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem); + ignoreSelect = false; +} + +/** + * Selects the items at the given zero-relative indices in the receiver. + * If the item at the index was already selected, it remains + * selected. The range of the indices is inclusive. Indices that are + * out of range are ignored and no items will be selected if start is + * greater than end. + * + * @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 select (int start, int end) { + checkWidget (); + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.state = OS.LVIS_SELECTED; + lvItem.stateMask = OS.LVIS_SELECTED; + for (int i=start; i<=end; i++) { + lvItem.iItem = i; + ignoreSelect = true; + OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem); + ignoreSelect = false; + } +} + +/** + * Selects all 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 void selectAll () { + checkWidget (); + if ((style & SWT.SINGLE) != 0) return; + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.state = OS.LVIS_SELECTED; + lvItem.stateMask = OS.LVIS_SELECTED; + ignoreSelect = true; + OS.SendMessage (handle, OS.LVM_SETITEMSTATE, -1, lvItem); + ignoreSelect = false; +} + +LRESULT sendMouseDownEvent (int type, int button, int msg, int wParam, int lParam) { + /* + * Feature in Windows. Inside WM_LBUTTONDOWN and WM_RBUTTONDOWN, + * the widget starts a modal loop to determine if the user wants + * to begin a drag/drop operation or marque select. Unfortunately, + * this modal loop eats the corresponding mouse up. The fix is to + * detect the cases when the modal loop has eaten the mouse up and + * issue a fake mouse up. + * + * By observation, when the mouse is clicked anywhere but the check + * box, the widget eats the mouse up. When the mouse is dragged, + * the widget does not eat the mouse up. + */ + LVHITTESTINFO pinfo = new LVHITTESTINFO (); + pinfo.x = (short) (lParam & 0xFFFF); + pinfo.y = (short) (lParam >> 16); + OS.SendMessage (handle, OS.LVM_HITTEST, 0, pinfo); + sendMouseEvent (type, button, msg, wParam, lParam); + + /* + * Force the table to have focus so that when the user + * reselects the focus item, the LVIS_FOCUSED state bits + * for the item will be set. These bits are used when + * the table is multi-select to issue the selection + * event. If the user did not click on an item, then + * set focus to the table so that it will come to the + * front and take focus in the work around below. + */ + OS.SetFocus (handle); + + /* + * Feature in Windows. When the user selects outside of + * a table item, Windows deselects all the items, even + * when the table is multi-select. While not strictly + * wrong, this is unexpected. The fix is to detect the + * case and avoid calling the window proc. + */ + if (pinfo.iItem == -1) { + if (OS.GetCapture () != handle) OS.SetCapture (handle); + return LRESULT.ZERO; + } + + /* + * Feature in Windows. When a table item is reselected, + * the table does not issue a WM_NOTIFY when the item + * state has not changed. This is inconsistent with + * the list widget and other widgets in Windows. The + * fix is to detect the case when an item is reselected + * and issue the notification. + */ + boolean wasSelected = false; + int count = OS.SendMessage (handle, OS.LVM_GETSELECTEDCOUNT, 0, 0); + if (count == 1 && pinfo.iItem != -1) { + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.stateMask = OS.LVIS_SELECTED; + lvItem.iItem = pinfo.iItem; + OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem); + wasSelected = (lvItem.state & OS.LVIS_SELECTED) != 0; + if (wasSelected) ignoreSelect = true; + } + dragStarted = false; + int code = callWindowProc (msg, wParam, lParam); + if (wasSelected) { + ignoreSelect = false; + Event event = new Event (); + event.item = items [pinfo.iItem]; + postEvent (SWT.Selection, event); + } + if (dragStarted) { + if (OS.GetCapture () != handle) OS.SetCapture (handle); + } else { + int flags = OS.LVHT_ONITEMLABEL | OS.LVHT_ONITEMICON; + boolean fakeMouseUp = (pinfo.flags & flags) != 0; + if (!fakeMouseUp && (style & SWT.MULTI) != 0) { + fakeMouseUp = (pinfo.flags & OS.LVHT_ONITEMSTATEICON) == 0; + } + if (fakeMouseUp) { + mouseDown = false; + sendMouseEvent (SWT.MouseUp, button, msg, wParam, lParam); + } + } + dragStarted = false; + return new LRESULT (code); +} + +void setBackgroundPixel (int pixel) { + if (background == pixel) return; + background = pixel; + + /* + * Feature in Windows. Setting the color to be + * the current default is not correct because the + * widget will not change colors when the colors + * are changed from the control panel. There is + * no fix at this time. + */ + if (pixel == -1) pixel = defaultBackground (); + OS.SendMessage (handle, OS.LVM_SETBKCOLOR, 0, pixel); + OS.SendMessage (handle, OS.LVM_SETTEXTBKCOLOR, 0, pixel); + if ((style & SWT.CHECK) != 0) setCheckboxImageListColor (); + + /* + * Feature in Windows. When the background color is + * changed, the table does not redraw until the next + * WM_PAINT. The fix is to force a redraw. + */ + OS.InvalidateRect (handle, null, true); +} + +void setCheckboxImageListColor () { + if ((style & SWT.CHECK) == 0) return; + int hOldStateList = OS.SendMessage (handle, OS.LVM_GETIMAGELIST, OS.LVSIL_STATE, 0); + if (hOldStateList == 0) return; + int [] cx = new int [1], cy = new int [1]; + OS.ImageList_GetIconSize (hOldStateList, cx, cy); + setCheckboxImageList (cx [0], cy [0]); +} + +void setCheckboxImageList (int width, int height) { + if ((style & SWT.CHECK) == 0) return; + int count = 4; + int hStateList = OS.ImageList_Create (width, height, OS.ILC_COLOR, count, count); + int hDC = OS.GetDC (handle); + int memDC = OS.CreateCompatibleDC (hDC); + int hBitmap = OS.CreateCompatibleBitmap (hDC, width * count, height); + int hOldBitmap = OS.SelectObject (memDC, hBitmap); + RECT rect = new RECT (); + OS.SetRect (rect, 0, 0, width * count, height); + int hBrush = OS.CreateSolidBrush (getBackgroundPixel ()); + OS.FillRect (memDC, rect, hBrush); + OS.DeleteObject (hBrush); + int oldFont = OS.SelectObject (hDC, defaultFont ()); + TEXTMETRIC tm = new TEXTMETRIC (); + OS.GetTextMetrics (hDC, tm); + OS.SelectObject (hDC, oldFont); + int itemWidth = Math.min (tm.tmHeight, width); + int itemHeight = Math.min (tm.tmHeight, height); + int left = (width - itemWidth) / 2, top = (height - itemHeight) / 2 + 1; + OS.SetRect (rect, left, top, left + itemWidth, top + itemHeight); + OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_FLAT); + rect.left += width; rect.right += width; + OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_CHECKED | OS.DFCS_FLAT); + rect.left += width; rect.right += width; + OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_INACTIVE | OS.DFCS_FLAT); + rect.left += width; rect.right += width; + OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_CHECKED | OS.DFCS_INACTIVE | OS.DFCS_FLAT); + OS.SelectObject (memDC, hOldBitmap); + OS.DeleteDC (memDC); + OS.ReleaseDC (handle, hDC); + OS.ImageList_AddMasked (hStateList, hBitmap, 0); + OS.DeleteObject (hBitmap); + int hOldStateList = OS.SendMessage (handle, OS.LVM_GETIMAGELIST, OS.LVSIL_STATE, 0); + OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_STATE, hStateList); + if (hOldStateList != 0) OS.ImageList_Destroy (hOldStateList); +} + +void setFocusIndex (int index) { + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.state = OS.LVIS_FOCUSED; + lvItem.stateMask = OS.LVIS_FOCUSED; + lvItem.iItem = index; + ignoreSelect = true; + OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem); + ignoreSelect = false; +} + +public void setFont (Font font) { + checkWidget (); + super.setFont (font); + setScrollWidth (); + /* + * Bug in Windows. Setting the font will cause the + * table area to be redrawn but not the column headers. + * Fix is to force a redraw on the column headers. + */ + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + OS.InvalidateRect (hwndHeader, null, true); + int bits = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); + if ((bits & OS.LVS_EX_GRIDLINES) == 0) return; + bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & OS.LVS_NOCOLUMNHEADER) != 0) return; + setRowHeight (); +} + +void setForegroundPixel (int pixel) { + if (foreground == pixel) return; + foreground = pixel; + + /* + * Feature in Windows. Setting the color to be + * the current default is not correct because the + * table will not change colors when the colors + * are changed from the control panel. There is + * no fix at this time. + */ + if (pixel == -1) pixel = defaultForeground (); + OS.SendMessage (handle, OS.LVM_SETTEXTCOLOR, 0, pixel); + + /* + * Feature in Windows. When the foreground color is + * changed, the table does not redraw until the next + * WM_PAINT. The fix is to force a redraw. + */ + OS.InvalidateRect (handle, null, 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 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 setHeaderVisible (boolean show) { + checkWidget (); + int newBits = OS.GetWindowLong (handle, OS.GWL_STYLE); + newBits &= ~OS.LVS_NOCOLUMNHEADER; + if (!show) newBits |= OS.LVS_NOCOLUMNHEADER; + /* + * Feature in Windows. Setting or clearing LVS_NOCOLUMNHEADER + * causes the table to scroll to the beginning. The fix is to + * save and restore the top index. + */ + int topIndex = getTopIndex (); + OS.SetWindowLong (handle, OS.GWL_STYLE, newBits); + if (topIndex != 0) setTopIndex (topIndex); + if (show) { + int bits = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); + if ((bits & OS.LVS_EX_GRIDLINES) != 0) setRowHeight (); + } +} + +/** + * Marks the receiver's lines 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 setLinesVisible (boolean show) { + checkWidget (); + int newBits = 0; + if (show) { + newBits = OS.LVS_EX_GRIDLINES; + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & OS.LVS_NOCOLUMNHEADER) == 0) setRowHeight (); + } + OS.SendMessage (handle, OS.LVM_SETEXTENDEDLISTVIEWSTYLE, OS.LVS_EX_GRIDLINES, newBits); +} + +public void setRedraw (boolean redraw) { + checkWidget (); + if (redraw) { + if (--drawCount == 0) { + setScrollWidth (); + /* + * This code is intentionally commented. When many items + * are added to a table, it is slightly faster to temporarily + * unsubclass the window proc so that messages are dispatched + * directly to the table. This is optimization is dangerous + * because any operation can occur when redraw is turned off, + * even operations where the table must be subclassed in order + * to have the correct behavior or work around a Windows bug. + * For now, don't attempt it. + */ +// subclass (); + + /* + * Bug in Windows. For some reason, when WM_SETREDRAW is used + * to turn redraw back on this may result in a WM_SIZE. If the + * table column widths are adjusted in WM_SIZE, blank lines may + * be inserted at the top of the widget. A call to LVM_GETTOPINDEX + * will return a negative number (this is an impossible result). + * The fix is to ignore any resize generated by WM_SETREDRAW and + * defer the work until the WM_SETREDRAW has returned. + */ + ignoreResize = true; + OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0); + if (!ignoreResize) { + setResizeChildren (false); + sendEvent (SWT.Resize); + // widget may be disposed at this point + if (isDisposed ()) return; + if (layout != null) layout.layout (this, false); + setResizeChildren (true); + } + ignoreResize = false; + + /* + * This code is intentionally commented. The window proc + * for the table implements WM_SETREDRAW to invalidate + * and erase the table and the header. This is undocumented + * behavior. The commented code below shows what is actually + * happening and reminds us that we are relying on this + * undocumented behavior. + * + * NOTE: The window proc for the table does not redraw the + * non-client area (ie. the border and scroll bars). This + * must be explicitly redrawn. This code can be removed + * if we stop relying on the undocuemented behavior. + */ + if (OS.IsWinCE) { + OS.InvalidateRect (handle, null, false); + } else { + OS.RedrawWindow (handle, null, 0, OS.RDW_FRAME | OS.RDW_INVALIDATE); + } +// int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); +// if (hwndHeader != 0) OS.SendMessage (hwndHeader, OS.WM_SETREDRAW, 1, 0); +// int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE | OS.RDW_ALLCHILDREN; +// OS.RedrawWindow (handle, null, 0, flags); +// if (hwndHeader != 0) OS.RedrawWindow (hwndHeader, null, 0, flags); + } + } else { + if (drawCount++ == 0) { + OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + if (hwndHeader != 0) OS.SendMessage (hwndHeader, OS.WM_SETREDRAW, 0, 0); + /* + * This code is intentionally commented. When many items + * are added to a table, it is slightly faster to temporarily + * unsubclass the window proc so that messages are dispatched + * directly to the table. This is optimization is dangerous + * because any operation can occur when redraw is turned off, + * even operations where the table must be subclassed in order + * to have the correct behavior or work around a Windows bug. + * For now, don't attempt it. + */ +// unsubclass (); + } + } +} + +void setRowHeight () { + /* + * Bug in Windows. When both a header and grid lines are + * displayed, the grid lines do not take into account the + * height of the header and draw in the wrong place. The + * fix is to set the height of the table items to be the + * height of the header so that the lines draw in the right + * place. The height of a table item is the maximum of the + * height of the font or the height of image list. + * + * NOTE: In version 5.80 of COMCTL32.DLL, the bug is fixed. + */ + if ((COMCTL32_MAJOR << 16 | COMCTL32_MINOR) >= (5 << 16 | 80)) return; + int hOldList = OS.SendMessage (handle, OS.LVM_GETIMAGELIST, OS.LVSIL_SMALL, 0); + if (hOldList != 0) return; + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + RECT rect = new RECT (); + OS.GetWindowRect (hwndHeader, rect); + int height = rect.bottom - rect.top - 1; + int hImageList = OS.ImageList_Create (1, height, 0, 0, 0); + OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_SMALL, hImageList); + OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_SMALL, 0); + OS.ImageList_Destroy (hImageList); +} + +void setScrollWidth () { + if (drawCount != 0) return; + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0); + if (count == 1 && columns [0] == null) { + OS.SendMessage (handle, OS.LVM_SETCOLUMNWIDTH, 0, OS.LVSCW_AUTOSIZE); + } +} + +/** + * Selects the items at the given zero-relative indices in the receiver. + * The current selected is first cleared, then the new items are selected. + * + * @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); + deselectAll (); + select (indices); + if (indices.length != 0) { + int focusIndex = indices [0]; + if (focusIndex != -1) setFocusIndex (focusIndex); + } + showSelection (); +} + +/** + * 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 array of items is null</li> + * <li>ERROR_INVALID_ARGUMENT - if one of 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#deselectAll() + * @see Table#select(int) + */ +public void setSelection (TableItem [] items) { + checkWidget (); + if (items == null) error (SWT.ERROR_NULL_ARGUMENT); + deselectAll (); + int length = items.length; + if (length == 0) return; + int focusIndex = -1; + if ((style & SWT.SINGLE) != 0) length = 1; + for (int i=length-1; i>=0; --i) { + int index = indexOf (items [i]); + if (index != -1) { + select (focusIndex = index); + } + } + if (focusIndex != -1) setFocusIndex (focusIndex); + showSelection (); +} + +/** + * Selects the item at the given zero-relative index in the receiver. + * The current selected 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 (); + deselectAll (); + select (index); + if (index != -1) setFocusIndex (index); + showSelection (); +} + +/** + * Selects the items at the given zero-relative indices in the receiver. + * The current selection is first cleared, then the new items are selected. + * Indices that are out of range are ignored and no items will be selected + * if start is greater than end. + * + * @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 (); + deselectAll (); + select (start, end); + /* + * NOTE: This code relies on the select (int, int) + * selecting the last item in the range for a single + * selection table. + */ + int focusIndex = (style & SWT.SINGLE) != 0 ? end : start; + if (focusIndex != -1) setFocusIndex (focusIndex); + showSelection (); +} + +/** + * 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 (); + int topIndex = OS.SendMessage (handle, OS.LVM_GETTOPINDEX, 0, 0); + if (index == topIndex) return; + + /* + * Bug in Windows. For some reason, LVM_SCROLL refuses to + * scroll a table vertically when the width and height of + * the table is smaller than a certain size. The values + * that the author is seeing are width=68 and height=6 + * but there is no guarantee that these values are absolute. + * They may depend on the font and any number of other + * factors. In fact, the author has observed that setting + * the font to anything but the default seems to sometimes + * fix the problem. The fix is to use LVM_GETCOUNTPERPAGE + * to detect the case when the number of visible items is + * zero and use LVM_ENSUREVISIBLE to scroll the table to + * make the index visible. + */ + + /* + * Bug in Windows. When the table header is visible and + * there is not enough space to show a single table item, + * LVM_GETCOUNTPERPAGE can return a negative number instead + * of zero. The fix is to test for negative or zero. + */ + if (OS.SendMessage (handle, OS.LVM_GETCOUNTPERPAGE, 0, 0) <= 0) { + + /* + * Bug in Windows. For some reason, LVM_ENSUREVISIBLE can + * scroll one item more or one item less when there is not + * enough space to show a single table item. The fix is + * to detect the case and call LVM_ENSUREVISIBLE again with + * the same arguments. It seems that once LVM_ENSUREVISIBLE + * has scrolled into the general area, it is able to scroll + * to the exact item. + */ + OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, index, 1); + if (index != OS.SendMessage (handle, OS.LVM_GETTOPINDEX, 0, 0)) { + OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, index, 1); + } + return; + } + + /* Use LVM_SCROLL to scroll the table */ + RECT rect = new RECT (); + rect.left = OS.LVIR_BOUNDS; + OS.SendMessage (handle, OS.LVM_GETITEMRECT, 0, rect); + int dy = (index - topIndex) * (rect.bottom - rect.top); + OS.SendMessage (handle, OS.LVM_SCROLL, 0, dy); +} + +void showItem (int index) { + /* + * Bug in Windows. For some reason, when there is insufficient space + * to show an item, LVM_ENSUREVISIBLE causes blank lines to be + * inserted at the top of the widget. A call to LVM_GETTOPINDEX will + * return a negative number (this is an impossible result). The fix + * is to use LVM_GETCOUNTPERPAGE to detect the case when the number + * of visible items is zero and use LVM_ENSUREVISIBLE with the fPartialOK + * flag to scroll the table. + */ + if (OS.SendMessage (handle, OS.LVM_GETCOUNTPERPAGE, 0, 0) <= 0) { + /* + * Bug in Windows. For some reason, LVM_ENSUREVISIBLE can + * scroll one item more or one item less when there is not + * enough space to show a single table item. The fix is + * to detect the case and call LVM_ENSUREVISIBLE again with + * the same arguments. It seems that once LVM_ENSUREVISIBLE + * has scrolled into the general area, it is able to scroll + * to the exact item. + */ + OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, index, 1); + if (index != OS.SendMessage (handle, OS.LVM_GETTOPINDEX, 0, 0)) { + OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, index, 1); + } + } else { + OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, index, 0); + } +} + +/** + * 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) showItem (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 = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_SELECTED); + if (index != -1) showItem (index); +} + +int widgetStyle () { + int bits = super.widgetStyle () | OS.LVS_SHAREIMAGELISTS | OS.WS_CLIPCHILDREN; + if ((style & SWT.HIDE_SELECTION) == 0) bits |= OS.LVS_SHOWSELALWAYS; + if ((style & SWT.SINGLE) != 0) bits |= OS.LVS_SINGLESEL; + /* + * This code is intentionally commented. In the future, + * the FLAT bit may be used to make the header flat and + * unresponsive to mouse clicks. + */ +// if ((style & SWT.FLAT) != 0) bits |= OS.LVS_NOSORTHEADER; + bits |= OS.LVS_REPORT | OS.LVS_NOCOLUMNHEADER; + return bits; +} + +TCHAR windowClass () { + return TableClass; +} + +int windowProc () { + return TableProc; +} + +LRESULT WM_GETOBJECT (int wParam, int lParam) { + /* + * Ensure that there is an accessible object created for this + * control because support for checked item accessibility is + * temporarily implemented in the accessibility package. + */ + if ((style & SWT.CHECK) != 0) { + if (accessible == null) accessible = new_Accessible (this); + } + return super.WM_GETOBJECT (wParam, lParam); +} + +LRESULT WM_KEYDOWN (int wParam, int lParam) { + LRESULT result = super.WM_KEYDOWN (wParam, lParam); + if (result != null) return result; + if ((style & SWT.CHECK) != 0 && wParam == OS.VK_SPACE) { + int index = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_FOCUSED); + if (index != -1) { + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.stateMask = OS.LVIS_STATEIMAGEMASK; + lvItem.iItem = index; + OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem); + int state = lvItem.state >> 12; + if ((state & 0x1) != 0) { + state++; + } else { + --state; + } + lvItem.state = state << 12; + OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem); + } + } + return result; +} + +LRESULT WM_LBUTTONDBLCLK (int wParam, int lParam) { + /* + * Feature in Windows. When the user selects outside of + * a table item, Windows deselects all the items, even + * when the table is multi-select. While not strictly + * wrong, this is unexpected. The fix is to detect the + * case and avoid calling the window proc. + */ + LVHITTESTINFO pinfo = new LVHITTESTINFO (); + pinfo.x = (short) (lParam & 0xFFFF); + pinfo.y = (short) (lParam >> 16); + OS.SendMessage (handle, OS.LVM_HITTEST, 0, pinfo); + sendMouseEvent (SWT.MouseDown, 1, OS.WM_LBUTTONDOWN, wParam, lParam); + sendMouseEvent (SWT.MouseDoubleClick, 1, OS.WM_LBUTTONDBLCLK, wParam, lParam); + if (pinfo.iItem != -1) callWindowProc (OS.WM_LBUTTONDBLCLK, wParam, lParam); + if (OS.GetCapture () != handle) OS.SetCapture (handle); + return LRESULT.ZERO; +} + +LRESULT WM_LBUTTONDOWN (int wParam, int lParam) { + mouseDown = true; + + /* + * Feature in Windows. For some reason, capturing + * the mouse after processing the mouse event for the + * widget interferes with the normal mouse processing + * for the widget. The fix is to avoid the automatic + * mouse capture. + */ + LRESULT result = sendMouseDownEvent (SWT.MouseDown, 1, OS.WM_LBUTTONDOWN, wParam, lParam); + + /* Look for check/uncheck */ + if ((style & SWT.CHECK) != 0) { + LVHITTESTINFO pinfo = new LVHITTESTINFO (); + pinfo.x = (short) (lParam & 0xFFFF); + pinfo.y = (short) (lParam >> 16); + /* + * Note that when the table has LVS_EX_FULLROWSELECT and the + * user clicks anywhere on a row except on the check box, all + * of the bits are set. The hit test flags are LVHT_ONITEM. + * This means that a bit test for LVHT_ONITEMSTATEICON is not + * the correct way to determine that the user has selected + * the check box. + */ + int index = OS.SendMessage (handle, OS.LVM_HITTEST, 0, pinfo); + if (index != -1 && pinfo.flags == OS.LVHT_ONITEMSTATEICON) { + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.stateMask = OS.LVIS_STATEIMAGEMASK; + lvItem.iItem = index; + OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem); + int state = lvItem.state >> 12; + if ((state & 0x1) != 0) { + state++; + } else { + --state; + } + lvItem.state = state << 12; + OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem); + } + } + + return result; +} + +LRESULT WM_LBUTTONUP (int wParam, int lParam) { + mouseDown = false; + return super.WM_LBUTTONUP (wParam, lParam); +} + +LRESULT WM_MOUSEHOVER (int wParam, int lParam) { + /* + * Feature in Windows. Despite the fact that hot + * tracking is not enabled, the hot tracking code + * in WM_MOUSEHOVER is executed causing the item + * under the cursor to be selected. The fix is to + * avoid calling the window proc. + */ + LRESULT result = super.WM_MOUSEHOVER (wParam, lParam); + int bits = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); + int mask = OS.LVS_EX_ONECLICKACTIVATE | OS.LVS_EX_TRACKSELECT | OS.LVS_EX_TWOCLICKACTIVATE; + if ((bits & mask) != 0) return result; + return LRESULT.ZERO; +} + +LRESULT WM_NOTIFY (int wParam, int lParam) { + NMHDR hdr = new NMHDR (); + OS.MoveMemory (hdr, lParam, NMHDR.sizeof); + int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + if (hdr.hwndFrom == hwndHeader) { + /* + * Feature in Windows. On NT, the automatically created + * header control is created as a UNICODE window, not an + * ANSI window despite the fact that the parent is created + * as an ANSI window. This means that it sends UNICODE + * notification messages to the parent window on NT for + * no good reason. The data and size in the NMHEADER and + * HDITEM structs is identical between the platforms so no + * different message is actually necessary. Despite this, + * Windows sends different messages. The fix is to look + * for both messages, despite the platform. This works + * because only one will be sent on either platform, never + * both. + */ + switch (hdr.code) { + case OS.HDN_BEGINTRACKW: + case OS.HDN_BEGINTRACKA: + case OS.HDN_DIVIDERDBLCLICKW: + case OS.HDN_DIVIDERDBLCLICKA:{ + NMHEADER phdn = new NMHEADER (); + OS.MoveMemory (phdn, lParam, NMHEADER.sizeof); + TableColumn column = columns [phdn.iItem]; + if (column != null && !column.getResizable ()) { + return LRESULT.ONE; + } + break; + } + case OS.HDN_ITEMCHANGEDW: + case OS.HDN_ITEMCHANGEDA: { + NMHEADER phdn = new NMHEADER (); + OS.MoveMemory (phdn, lParam, NMHEADER.sizeof); + Event event = new Event (); + if (phdn.pitem != 0) { + HDITEM pitem = new HDITEM (); + OS.MoveMemory (pitem, phdn.pitem, HDITEM.sizeof); + if ((pitem.mask & OS.HDI_WIDTH) != 0) { + TableColumn column = columns [phdn.iItem]; + if (column != null) { + column.sendEvent (SWT.Resize, event); + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the resize + * event. If this happens, end the processing of the + * Windows message by returning zero as the result of + * the window proc. + */ + if (isDisposed ()) return LRESULT.ZERO; + int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0); + if (count == 1 && columns [0] == null) count = 0; + /* + * It is possible (but unlikely), that application + * code could have disposed the column in the move + * event. If this happens, process the move event + * for those columns that have not been destroyed. + */ + TableColumn [] newColumns = new TableColumn [count]; + System.arraycopy (columns, 0, newColumns, 0, count); + for (int i=phdn.iItem+1; i<count; i++) { + if (!newColumns [i].isDisposed ()) { + newColumns [i].sendEvent (SWT.Move, event); + } + } + } + } + } + break; + } + } + } + return super.WM_NOTIFY (wParam, lParam); +} + +LRESULT WM_RBUTTONDBLCLK (int wParam, int lParam) { + /* + * Feature in Windows. When the user selects outside of + * a table item, Windows deselects all the items, even + * when the table is multi-select. While not strictly + * wrong, this is unexpected. The fix is to detect the + * case and avoid calling the window proc. + */ + LVHITTESTINFO pinfo = new LVHITTESTINFO (); + pinfo.x = (short) (lParam & 0xFFFF); + pinfo.y = (short) (lParam >> 16); + OS.SendMessage (handle, OS.LVM_HITTEST, 0, pinfo); + sendMouseEvent (SWT.MouseDown, 1, OS.WM_RBUTTONDOWN, wParam, lParam); + sendMouseEvent (SWT.MouseDoubleClick, 1, OS.WM_RBUTTONDBLCLK, wParam, lParam); + if (pinfo.iItem != -1) callWindowProc (OS.WM_RBUTTONDBLCLK, wParam, lParam); + if (OS.GetCapture () != handle) OS.SetCapture (handle); + return LRESULT.ZERO; +} + +LRESULT WM_RBUTTONDOWN (int wParam, int lParam) { + /* + * Feature in Windows. For some reason, capturing + * the mouse after processing the mouse event for the + * widget interferes with the normal mouse processing + * for the widget. The fix is to avoid the automatic + * mouse capture. + */ + return sendMouseDownEvent (SWT.MouseDown, 3, OS.WM_RBUTTONDOWN, wParam, lParam); +} + +LRESULT WM_SETFOCUS (int wParam, int lParam) { + LRESULT result = super.WM_SETFOCUS (wParam, lParam); + /* + * Bug in Windows. For some reason, the table does + * not set the default focus rectangle to be the first + * item in the table when it gets focus and there is + * no selected item. The fix to make the first item + * be the focus item. + */ + int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); + if (count == 0) return result; + int index = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_FOCUSED); + if (index == -1) { + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.state = OS.LVIS_FOCUSED; + lvItem.stateMask = OS.LVIS_FOCUSED; + ignoreSelect = true; + OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem); + ignoreSelect = false; + } + return result; +} + +LRESULT WM_SIZE (int wParam, int lParam) { + if (ignoreResize) { + ignoreResize = false; + int code = callWindowProc (OS.WM_SIZE, wParam, lParam); + return new LRESULT (code); + } + return super.WM_SIZE (wParam, lParam); +} + +LRESULT WM_SYSCOLORCHANGE (int wParam, int lParam) { + LRESULT result = super.WM_SYSCOLORCHANGE (wParam, lParam); + if (result != null) return result; + if ((style & SWT.CHECK) != 0) setCheckboxImageListColor (); + return result; +} + +LRESULT wmNotifyChild (int wParam, int lParam) { + NMHDR hdr = new NMHDR (); + OS.MoveMemory (hdr, lParam, NMHDR.sizeof); + switch (hdr.code) { + case OS.NM_CUSTOMDRAW: { + if (!customDraw) break; + NMLVCUSTOMDRAW nmcd = new NMLVCUSTOMDRAW (); + OS.MoveMemory (nmcd, lParam, NMLVCUSTOMDRAW.sizeof); + switch (nmcd.dwDrawStage) { + case OS.CDDS_PREPAINT: return new LRESULT (OS.CDRF_NOTIFYITEMDRAW); + case OS.CDDS_ITEMPREPAINT: return new LRESULT (OS.CDRF_NOTIFYSUBITEMDRAW); + case OS.CDDS_ITEMPREPAINT | OS.CDDS_SUBITEM: { + TableItem item = items [nmcd.dwItemSpec]; + int clrText = item.foreground, clrTextBk = item.background; + if (clrText == -1 && clrTextBk == -1) break; + nmcd.clrText = clrText == -1 ? getForegroundPixel () : clrText; + nmcd.clrTextBk = clrTextBk == -1 ? getBackgroundPixel () : clrTextBk; + OS.MoveMemory (lParam, nmcd, NMLVCUSTOMDRAW.sizeof); + return new LRESULT (OS.CDRF_NEWFONT); + } + } + break; + } + case OS.LVN_MARQUEEBEGIN: return LRESULT.ONE; + case OS.LVN_BEGINDRAG: + case OS.LVN_BEGINRDRAG: { + dragStarted = true; + if (hdr.code == OS.LVN_BEGINDRAG) { + postEvent (SWT.DragDetect); + } + break; + } + case OS.LVN_COLUMNCLICK: { + NMLISTVIEW pnmlv = new NMLISTVIEW (); + OS.MoveMemory(pnmlv, lParam, NMLISTVIEW.sizeof); + TableColumn column = columns [pnmlv.iSubItem]; + if (column != null) { + column.postEvent (SWT.Selection); + } + break; + } + case OS.LVN_ITEMACTIVATE: { + NMLISTVIEW pnmlv = new NMLISTVIEW (); + OS.MoveMemory(pnmlv, lParam, NMLISTVIEW.sizeof); + if (pnmlv.iItem != -1) { + Event event = new Event (); + event.item = items [pnmlv.iItem]; + postEvent (SWT.DefaultSelection, event); + } + break; + } + case OS.LVN_ITEMCHANGED: { + if (!ignoreSelect) { + NMLISTVIEW pnmlv = new NMLISTVIEW (); + OS.MoveMemory (pnmlv, lParam, NMLISTVIEW.sizeof); + if (pnmlv.iItem != -1 && (pnmlv.uChanged & OS.LVIF_STATE) != 0) { + int oldBits = pnmlv.uOldState & OS.LVIS_STATEIMAGEMASK; + int newBits = pnmlv.uNewState & OS.LVIS_STATEIMAGEMASK; + if (oldBits != newBits) { + Event event = new Event(); + event.item = items [pnmlv.iItem]; + event.detail = SWT.CHECK; + /* + * This code is intentionally commented. + */ +// OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, pnmlv.iItem, 0); + postEvent (SWT.Selection, event); + } else { + boolean isFocus = (pnmlv.uNewState & OS.LVIS_FOCUSED) != 0; + int index = OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_FOCUSED); + if ((style & SWT.MULTI) != 0) { + if (OS.GetKeyState (OS.VK_CONTROL) < 0) { + if (!isFocus) { + if (index == pnmlv.iItem) { + boolean isSelected = (pnmlv.uNewState & OS.LVIS_SELECTED) != 0; + boolean wasSelected = (pnmlv.uOldState & OS.LVIS_SELECTED) != 0; + isFocus = isSelected != wasSelected; + } + } else { + isFocus = mouseDown; + } + } + } + if (OS.GetKeyState (OS.VK_SPACE) < 0) isFocus = true; + if (isFocus) { + Event event = new Event(); + if (index != -1) { + /* + * This code is intentionally commented. + */ +// OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, index, 0); + event.item = items [index]; + } + postEvent (SWT.Selection, event); + } + } + } + } + break; + } + } + return super.wmNotifyChild (wParam, lParam); +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TableColumn.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TableColumn.java index 1d3f175d5c..f040329484 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TableColumn.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TableColumn.java @@ -1,479 +1,479 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-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.
- * <dl>
- * <dt><b>Styles:</b></dt>
- * <dd>LEFT, RIGHT, CENTER</dd>
- * <dt><b>Events:</b></dt>
- * <dd> Move, Resize, Selection</dd>
- * </dl>
- * <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>
- */
-public class TableColumn extends Item {
- Table parent;
- boolean resizable;
-
-/**
- * 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));
- resizable = true;
- this.parent = parent;
- parent.createItem (this, parent.getColumnCount ());
-}
-
-/**
- * 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 index to store the receiver in its parent
- *
- * @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, int index) {
- super (parent, checkStyle (style));
- resizable = true;
- 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 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
- *
- * @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);
-}
-
-/**
- * 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;
-}
-
-public Display getDisplay () {
- Table parent = this.parent;
- if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED);
- return parent.getDisplay ();
-}
-
-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 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 resizable;
-}
-
-/**
- * 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 index = parent.indexOf (this);
- if (index == -1) return 0;
- int hwnd = parent.handle;
- return OS.SendMessage (hwnd, OS.LVM_GETCOLUMNWIDTH, index, 0);
-}
-
-/**
- * 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 index = parent.indexOf (this);
- if (index == -1) return;
- int hwnd = parent.handle;
- TCHAR buffer = new TCHAR (parent.getCodePage (), text, true);
- int headerWidth = OS.SendMessage (hwnd, OS.LVM_GETSTRINGWIDTH, 0, buffer) + 10;
- if (image != null) {
- int margin = 0;
- if ((COMCTL32_MAJOR << 16 | COMCTL32_MINOR) >= (5 << 16 | 80)) {
- int hwndHeader = OS.SendMessage (hwnd, OS.LVM_GETHEADER, 0, 0);
- margin = OS.SendMessage (hwndHeader, OS.HDM_GETBITMAPMARGIN, 0, 0);
- } else {
- margin = OS.GetSystemMetrics (OS.SM_CXEDGE) * 3;
- }
- Rectangle rect = image.getBounds ();
- headerWidth += rect.width + margin * 2;
- }
- OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, OS.LVSCW_AUTOSIZE);
- int columnWidth = OS.SendMessage (hwnd, OS.LVM_GETCOLUMNWIDTH, index, 0);
- if (headerWidth > columnWidth) {
- if (image == null) {
- OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, OS.LVSCW_AUTOSIZE_USEHEADER);
- } else {
- OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, headerWidth);
- }
- }
-}
-
-void releaseChild () {
- super.releaseChild ();
- parent.destroyItem (this);
-}
-
-void releaseWidget () {
- super.releaseWidget ();
- parent = 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 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.
- *
- * @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 #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>.
- *
- * @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);
- int fmt = 0;
- if ((style & SWT.LEFT) == SWT.LEFT) fmt = OS.LVCFMT_LEFT;
- if ((style & SWT.CENTER) == SWT.CENTER) fmt = OS.LVCFMT_CENTER;
- if ((style & SWT.RIGHT) == SWT.RIGHT) fmt = OS.LVCFMT_RIGHT;
- int hwnd = parent.handle;
- LVCOLUMN lvColumn = new LVCOLUMN ();
- lvColumn.mask = OS.LVCF_FMT;
- lvColumn.fmt = fmt;
- OS.SendMessage (hwnd, OS.LVM_SETCOLUMN, index, lvColumn);
-}
-
-public void setImage (Image image) {
- checkWidget();
- if (image != null && image.isDisposed ()) {
- error (SWT.ERROR_INVALID_ARGUMENT);
- }
- int index = parent.indexOf (this);
- if (index == -1) return;
- super.setImage (image);
- int hwnd = parent.handle;
- LVCOLUMN lvColumn = new LVCOLUMN ();
- lvColumn.mask = OS.LVCF_FMT | OS.LVCF_IMAGE;
- lvColumn.fmt = OS.LVCFMT_IMAGE;
- lvColumn.iImage = parent.imageIndex (image);
- OS.SendMessage (hwnd, OS.LVM_SETCOLUMN, index, lvColumn);
- if (image == null) {
- lvColumn.mask = OS.LVCF_FMT;
- if ((style & SWT.LEFT) == SWT.LEFT) lvColumn.fmt = OS.LVCFMT_LEFT;
- if ((style & SWT.CENTER) == SWT.CENTER) lvColumn.fmt = OS.LVCFMT_CENTER;
- if ((style & SWT.RIGHT) == SWT.RIGHT) lvColumn.fmt = OS.LVCFMT_RIGHT;
- OS.SendMessage (hwnd, OS.LVM_SETCOLUMN, index, lvColumn);
- }
-}
-
-/**
- * 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 ();
- this.resizable = resizable;
-}
-
-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);
-
- /*
- * Bug in Windows. For some reason, when the title
- * of a column is changed after the column has been
- * created, the alignment must also be reset or the
- * text does not draw. The fix is to query and then
- * set the alignment.
- */
- int hwnd = parent.handle;
- LVCOLUMN lvColumn = new LVCOLUMN ();
- lvColumn.mask = OS.LVCF_FMT;
- OS.SendMessage (hwnd, OS.LVM_GETCOLUMN, index, lvColumn);
-
- /* Set the column title */
- int hHeap = OS.GetProcessHeap ();
- TCHAR buffer = new TCHAR (parent.getCodePage (), string, true);
- int byteCount = buffer.length () * TCHAR.sizeof;
- int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- OS.MoveMemory (pszText, buffer, byteCount);
- lvColumn.mask |= OS.LVCF_TEXT;
- lvColumn.pszText = pszText;
- int result = OS.SendMessage (hwnd, OS.LVM_SETCOLUMN, index, lvColumn);
- if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
- if (result == 0) error (SWT.ERROR_CANNOT_SET_TEXT);
-}
-
-/**
- * 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 ();
- int index = parent.indexOf (this);
- if (index == -1) return;
- int hwnd = parent.handle;
- OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, width);
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +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. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>LEFT, RIGHT, CENTER</dd> + * <dt><b>Events:</b></dt> + * <dd> Move, Resize, Selection</dd> + * </dl> + * <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> + */ +public class TableColumn extends Item { + Table parent; + boolean resizable; + +/** + * 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)); + resizable = true; + this.parent = parent; + parent.createItem (this, parent.getColumnCount ()); +} + +/** + * 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 index to store the receiver in its parent + * + * @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, int index) { + super (parent, checkStyle (style)); + resizable = true; + 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 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 + * + * @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); +} + +/** + * 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; +} + +public Display getDisplay () { + Table parent = this.parent; + if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED); + return parent.getDisplay (); +} + +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 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 resizable; +} + +/** + * 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 index = parent.indexOf (this); + if (index == -1) return 0; + int hwnd = parent.handle; + return OS.SendMessage (hwnd, OS.LVM_GETCOLUMNWIDTH, index, 0); +} + +/** + * 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 index = parent.indexOf (this); + if (index == -1) return; + int hwnd = parent.handle; + TCHAR buffer = new TCHAR (parent.getCodePage (), text, true); + int headerWidth = OS.SendMessage (hwnd, OS.LVM_GETSTRINGWIDTH, 0, buffer) + 10; + if (image != null) { + int margin = 0; + if ((COMCTL32_MAJOR << 16 | COMCTL32_MINOR) >= (5 << 16 | 80)) { + int hwndHeader = OS.SendMessage (hwnd, OS.LVM_GETHEADER, 0, 0); + margin = OS.SendMessage (hwndHeader, OS.HDM_GETBITMAPMARGIN, 0, 0); + } else { + margin = OS.GetSystemMetrics (OS.SM_CXEDGE) * 3; + } + Rectangle rect = image.getBounds (); + headerWidth += rect.width + margin * 2; + } + OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, OS.LVSCW_AUTOSIZE); + int columnWidth = OS.SendMessage (hwnd, OS.LVM_GETCOLUMNWIDTH, index, 0); + if (headerWidth > columnWidth) { + if (image == null) { + OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, OS.LVSCW_AUTOSIZE_USEHEADER); + } else { + OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, headerWidth); + } + } +} + +void releaseChild () { + super.releaseChild (); + parent.destroyItem (this); +} + +void releaseWidget () { + super.releaseWidget (); + parent = 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 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. + * + * @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 #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>. + * + * @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); + int fmt = 0; + if ((style & SWT.LEFT) == SWT.LEFT) fmt = OS.LVCFMT_LEFT; + if ((style & SWT.CENTER) == SWT.CENTER) fmt = OS.LVCFMT_CENTER; + if ((style & SWT.RIGHT) == SWT.RIGHT) fmt = OS.LVCFMT_RIGHT; + int hwnd = parent.handle; + LVCOLUMN lvColumn = new LVCOLUMN (); + lvColumn.mask = OS.LVCF_FMT; + lvColumn.fmt = fmt; + OS.SendMessage (hwnd, OS.LVM_SETCOLUMN, index, lvColumn); +} + +public void setImage (Image image) { + checkWidget(); + if (image != null && image.isDisposed ()) { + error (SWT.ERROR_INVALID_ARGUMENT); + } + int index = parent.indexOf (this); + if (index == -1) return; + super.setImage (image); + int hwnd = parent.handle; + LVCOLUMN lvColumn = new LVCOLUMN (); + lvColumn.mask = OS.LVCF_FMT | OS.LVCF_IMAGE; + lvColumn.fmt = OS.LVCFMT_IMAGE; + lvColumn.iImage = parent.imageIndex (image); + OS.SendMessage (hwnd, OS.LVM_SETCOLUMN, index, lvColumn); + if (image == null) { + lvColumn.mask = OS.LVCF_FMT; + if ((style & SWT.LEFT) == SWT.LEFT) lvColumn.fmt = OS.LVCFMT_LEFT; + if ((style & SWT.CENTER) == SWT.CENTER) lvColumn.fmt = OS.LVCFMT_CENTER; + if ((style & SWT.RIGHT) == SWT.RIGHT) lvColumn.fmt = OS.LVCFMT_RIGHT; + OS.SendMessage (hwnd, OS.LVM_SETCOLUMN, index, lvColumn); + } +} + +/** + * 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 (); + this.resizable = resizable; +} + +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); + + /* + * Bug in Windows. For some reason, when the title + * of a column is changed after the column has been + * created, the alignment must also be reset or the + * text does not draw. The fix is to query and then + * set the alignment. + */ + int hwnd = parent.handle; + LVCOLUMN lvColumn = new LVCOLUMN (); + lvColumn.mask = OS.LVCF_FMT; + OS.SendMessage (hwnd, OS.LVM_GETCOLUMN, index, lvColumn); + + /* Set the column title */ + int hHeap = OS.GetProcessHeap (); + TCHAR buffer = new TCHAR (parent.getCodePage (), string, true); + int byteCount = buffer.length () * TCHAR.sizeof; + int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + OS.MoveMemory (pszText, buffer, byteCount); + lvColumn.mask |= OS.LVCF_TEXT; + lvColumn.pszText = pszText; + int result = OS.SendMessage (hwnd, OS.LVM_SETCOLUMN, index, lvColumn); + if (pszText != 0) OS.HeapFree (hHeap, 0, pszText); + if (result == 0) error (SWT.ERROR_CANNOT_SET_TEXT); +} + +/** + * 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 (); + int index = parent.indexOf (this); + if (index == -1) return; + int hwnd = parent.handle; + OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, width); +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TableItem.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TableItem.java index 517c27465e..310f064d2a 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TableItem.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TableItem.java @@ -1,711 +1,711 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-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>
- */
-
-public class TableItem extends Item {
- Table parent;
- int background, foreground;
-
-/**
- * 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) {
- 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>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 index to store the receiver in its parent
- *
- * @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, int index) {
- super (parent, style);
- this.parent = parent;
- parent.createItem (this, index);
-}
-
-protected void checkSubclass () {
- if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
-}
-
-/**
- * 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 ();
- int pixel = (background == -1) ? parent.getBackgroundPixel() : background;
- return Color.win32_new (getDisplay (), pixel);
-}
-
-/**
- * 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();
- int itemIndex = parent.indexOf (this);
- if (itemIndex == -1) return new Rectangle (0, 0, 0, 0);
- int hwnd = parent.handle;
- int hwndHeader = OS.SendMessage (hwnd, OS.LVM_GETHEADER, 0, 0);
- int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
- if (!(0 <= index && index < count)) return new Rectangle (0, 0, 0, 0);
- int gridWidth = 0;
- if (parent.getLinesVisible ()) gridWidth = parent.getGridLineWidth ();
- RECT rect = new RECT ();
- rect.top = index;
- rect.left = OS.LVIR_LABEL;
- OS.SendMessage (hwnd, OS. LVM_GETSUBITEMRECT, itemIndex, rect);
- if (index == 0) {
- RECT iconRect = new RECT ();
- iconRect.left = OS.LVIR_ICON;
- OS.SendMessage (hwnd, OS.LVM_GETSUBITEMRECT, itemIndex, iconRect);
- rect.left = iconRect.left - gridWidth;
- }
- int width = rect.right - rect.left - gridWidth;
- int height = rect.bottom - rect.top - gridWidth;
- /*
- * Bug in Windows. In version 5.80 of COMCTL32.DLL, the top
- * of the rectangle returned by LVM_GETSUBITEMRECT is off by
- * the grid width when the grid is visible. The fix is to
- * move the top of the rectangle up by the grid width.
- */
- if ((COMCTL32_MAJOR << 16 | COMCTL32_MINOR) >= (5 << 16 | 80)) {
- rect.top -= gridWidth;
- }
- return new Rectangle (rect.left + gridWidth, rect.top + gridWidth, width, 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.
- *
- * @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.style & SWT.CHECK) == 0) return false;
- int index = parent.indexOf (this);
- if (index == -1) return false;
- int hwnd = parent.handle;
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.stateMask = OS.LVIS_STATEIMAGEMASK;
- lvItem.iItem = index;
- int result = OS.SendMessage (hwnd, OS.LVM_GETITEM, 0, lvItem);
- return (result != 0) && (((lvItem.state >> 12) & 1) == 0);
-}
-
-public Display getDisplay () {
- Table parent = this.parent;
- if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED);
- return parent.getDisplay ();
-}
-
-/**
- * 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 ();
- int pixel = (foreground == -1) ? parent.getForegroundPixel() : foreground;
- return Color.win32_new (getDisplay (), pixel);
-}
-
-/**
- * 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.style & SWT.CHECK) == 0) return false;
- int index = parent.indexOf (this);
- if (index == -1) return false;
- int hwnd = parent.handle;
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.stateMask = OS.LVIS_STATEIMAGEMASK;
- lvItem.iItem = index;
- int result = OS.SendMessage (hwnd, OS.LVM_GETITEM, 0, lvItem);
- return (result != 0) && ((lvItem.state >> 12) > 2);
-}
-
-/**
- * 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 (index == 0) return super.getImage ();
- int itemIndex = parent.indexOf (this);
- if (itemIndex == -1) return null;
- int hwnd = parent.handle;
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_IMAGE;
- lvItem.iItem = itemIndex;
- lvItem.iSubItem = index;
- if (OS.SendMessage (hwnd, OS.LVM_GETITEM, 0, lvItem) == 0) return null;
- if (lvItem.iImage >= 0) {
- ImageList imageList = parent.imageList;
- if (imageList != null) return imageList.get (lvItem.iImage);
- }
- return null;
-}
-
-/**
- * Returns a rectangle describing the size and location
- * relative to its parent of an image at a column in the
- * table.
- *
- * @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();
- int itemIndex = parent.indexOf (this);
- if (itemIndex == -1) return new Rectangle (0, 0, 0, 0);
- int hwnd = parent.handle;
- int hwndHeader = OS.SendMessage (hwnd, OS.LVM_GETHEADER, 0, 0);
- int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
- if (!(0 <= index && index < count)) return new Rectangle (0, 0, 0, 0);
- int gridWidth = 0;
- if (parent.getLinesVisible ()) gridWidth = parent.getGridLineWidth ();
- RECT rect = new RECT ();
- rect.top = index;
- rect.left = OS.LVIR_ICON;
- OS.SendMessage (hwnd, OS. LVM_GETSUBITEMRECT, itemIndex, rect);
- if (index == 0) {
- RECT iconRect = new RECT ();
- iconRect.left = OS.LVIR_ICON;
- OS.SendMessage (hwnd, OS.LVM_GETSUBITEMRECT, itemIndex, iconRect);
- rect.left = iconRect.left - gridWidth;
- }
- int width = rect.right - rect.left - gridWidth;
- int height = rect.bottom - rect.top - gridWidth;
- /*
- * Bug in Windows. In version 5.80 of COMCTL32.DLL, the top
- * of the rectangle returned by LVM_GETSUBITEMRECT is off by
- * the grid width when the grid is visible. The fix is to
- * move the top of the rectangle up by the grid width.
- */
- if ((COMCTL32_MAJOR << 16 | COMCTL32_MINOR) >= (5 << 16 | 80)) {
- rect.top -= gridWidth;
- }
- return new Rectangle (rect.left + gridWidth, rect.top + gridWidth, width, 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();
- int index = parent.indexOf (this);
- if (index == -1) return 0;
- int hwnd = parent.handle;
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_INDENT;
- lvItem.iItem = index;
- OS.SendMessage (hwnd, OS.LVM_GETITEM, 0, lvItem);
- return lvItem.iIndent;
-}
-
-/**
- * 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;
-}
-
-/**
- * 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>
- * @exception SWTError <ul>
- * <li>ERROR_CANNOT_GET_TEXT - if the column at index does not exist</li>
- * </ul>
- */
-public String getText (int index) {
- checkWidget();
- if (index == 0) return super.getText ();
- int itemIndex = parent.indexOf (this);
- if (itemIndex == -1) error (SWT.ERROR_CANNOT_GET_TEXT);
- int cchTextMax = 1024;
- int hwnd = parent.handle;
- int hHeap = OS.GetProcessHeap ();
- int byteCount = cchTextMax * TCHAR.sizeof;
- int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_TEXT;
- lvItem.iItem = itemIndex;
- lvItem.iSubItem = index;
- lvItem.pszText = pszText;
- lvItem.cchTextMax = cchTextMax;
- int result = OS.SendMessage (hwnd, OS.LVM_GETITEM, 0, lvItem);
- TCHAR buffer = new TCHAR (parent.getCodePage (), cchTextMax);
- OS.MoveMemory (buffer, pszText, byteCount);
- OS.HeapFree (hHeap, 0, pszText);
- if (result == 0) error (SWT.ERROR_CANNOT_GET_TEXT);
- return buffer.toString (0, buffer.strlen ());
-}
-
-void redraw () {
- if (parent.drawCount > 0) return;
- int hwnd = parent.handle;
- if (!OS.IsWindowVisible (hwnd)) return;
- int index = parent.indexOf (this);
- RECT rect = new RECT ();
- rect.left = OS.LVIR_BOUNDS;
- if (OS.SendMessage (hwnd, OS.LVM_GETITEMRECT, index, rect) != 0) {
- OS.InvalidateRect (hwnd, rect, true);
- }
-}
-
-void releaseChild () {
- super.releaseChild ();
- parent.destroyItem (this);
-}
-
-void releaseWidget () {
- super.releaseWidget ();
- parent = 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);
- }
- int pixel = -1;
- if (color != null) {
- parent.customDraw = true;
- pixel = color.handle;
- }
- background = pixel;
- redraw ();
-}
-
-/**
- * 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;
- int index = parent.indexOf (this);
- if (index == -1) return;
- int hwnd = parent.handle;
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.stateMask = OS.LVIS_STATEIMAGEMASK;
- lvItem.iItem = index;
- OS.SendMessage (hwnd, OS.LVM_GETITEM, 0, lvItem);
- int state = lvItem.state >> 12;
- if (checked) {
- if ((state & 0x1) != 0) state++;
- } else {
- if ((state & 0x1) == 0) --state;
- }
- lvItem.state = state << 12;
- parent.ignoreSelect = true;
- OS.SendMessage (hwnd, OS.LVM_SETITEM, 0, lvItem);
- parent.ignoreSelect = false;
-}
-
-/**
- * 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);
- }
- int pixel = -1;
- if (color != null) {
- parent.customDraw = true;
- pixel = color.handle;
- }
- foreground = pixel;
- redraw ();
-}
-
-/**
- * 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;
- int index = parent.indexOf (this);
- if (index == -1) return;
- int hwnd = parent.handle;
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_STATE;
- lvItem.stateMask = OS.LVIS_STATEIMAGEMASK;
- lvItem.iItem = index;
- OS.SendMessage (hwnd, OS.LVM_GETITEM, 0, lvItem);
- int state = lvItem.state >> 12;
- if (grayed) {
- if (state <= 2) state +=2;
- } else {
- if (state > 2) state -=2;
- }
- lvItem.state = state << 12;
- parent.ignoreSelect = true;
- OS.SendMessage (hwnd, OS.LVM_SETITEM, 0, lvItem);
- parent.ignoreSelect = false;
-}
-
-/**
- * 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 (index == 0) {
- super.setImage (image);
- }
- int hwnd = parent.handle;
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_IMAGE;
- lvItem.iItem = itemIndex;
- lvItem.iSubItem = index;
- lvItem.iImage = parent.imageIndex (image);
- if (OS.SendMessage (hwnd, OS.LVM_SETITEM, 0, lvItem) != 0) {
- if (index == 0) parent.setScrollWidth ();
- parent.fixCheckboxImageList ();
- }
-}
-
-public void setImage (Image image) {
- checkWidget ();
- setImage (0, image);
-}
-
-/**
- * Sets the image indent.
- *
- * @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>
- */
-public void setImageIndent (int indent) {
- checkWidget();
- if (indent < 0) return;
- int index = parent.indexOf (this);
- if (index == -1) return;
- int hwnd = parent.handle;
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_INDENT;
- lvItem.iItem = index;
- lvItem.iIndent = indent;
- OS.SendMessage (hwnd, OS.LVM_SETITEM, 0, lvItem);
-}
-
-/**
- * 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);
- int itemIndex = parent.indexOf (this);
- if (itemIndex == -1) return;
- if (index == 0) {
- super.setText (string);
- }
- int hwnd = parent.handle;
- int hHeap = OS.GetProcessHeap ();
- TCHAR buffer = new TCHAR (parent.getCodePage (), string, true);
- int byteCount = buffer.length () * TCHAR.sizeof;
- int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- OS.MoveMemory (pszText, buffer, byteCount);
- LVITEM lvItem = new LVITEM ();
- lvItem.mask = OS.LVIF_TEXT;
- lvItem.iItem = itemIndex;
- lvItem.pszText = pszText;
- lvItem.iSubItem = index;
- if (OS.SendMessage (hwnd, OS.LVM_SETITEM, 0, lvItem) != 0) {
- if (index == 0) parent.setScrollWidth ();
- }
- OS.HeapFree (hHeap, 0, pszText);
-}
-
-public void setText (String string) {
- checkWidget();
- setText (0, string);
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +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> + */ + +public class TableItem extends Item { + Table parent; + int background, foreground; + +/** + * 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) { + 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>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 index to store the receiver in its parent + * + * @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, int index) { + super (parent, style); + this.parent = parent; + parent.createItem (this, index); +} + +protected void checkSubclass () { + if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS); +} + +/** + * 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 (); + int pixel = (background == -1) ? parent.getBackgroundPixel() : background; + return Color.win32_new (getDisplay (), pixel); +} + +/** + * 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(); + int itemIndex = parent.indexOf (this); + if (itemIndex == -1) return new Rectangle (0, 0, 0, 0); + int hwnd = parent.handle; + int hwndHeader = OS.SendMessage (hwnd, OS.LVM_GETHEADER, 0, 0); + int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0); + if (!(0 <= index && index < count)) return new Rectangle (0, 0, 0, 0); + int gridWidth = 0; + if (parent.getLinesVisible ()) gridWidth = parent.getGridLineWidth (); + RECT rect = new RECT (); + rect.top = index; + rect.left = OS.LVIR_LABEL; + OS.SendMessage (hwnd, OS. LVM_GETSUBITEMRECT, itemIndex, rect); + if (index == 0) { + RECT iconRect = new RECT (); + iconRect.left = OS.LVIR_ICON; + OS.SendMessage (hwnd, OS.LVM_GETSUBITEMRECT, itemIndex, iconRect); + rect.left = iconRect.left - gridWidth; + } + int width = rect.right - rect.left - gridWidth; + int height = rect.bottom - rect.top - gridWidth; + /* + * Bug in Windows. In version 5.80 of COMCTL32.DLL, the top + * of the rectangle returned by LVM_GETSUBITEMRECT is off by + * the grid width when the grid is visible. The fix is to + * move the top of the rectangle up by the grid width. + */ + if ((COMCTL32_MAJOR << 16 | COMCTL32_MINOR) >= (5 << 16 | 80)) { + rect.top -= gridWidth; + } + return new Rectangle (rect.left + gridWidth, rect.top + gridWidth, width, 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. + * + * @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.style & SWT.CHECK) == 0) return false; + int index = parent.indexOf (this); + if (index == -1) return false; + int hwnd = parent.handle; + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.stateMask = OS.LVIS_STATEIMAGEMASK; + lvItem.iItem = index; + int result = OS.SendMessage (hwnd, OS.LVM_GETITEM, 0, lvItem); + return (result != 0) && (((lvItem.state >> 12) & 1) == 0); +} + +public Display getDisplay () { + Table parent = this.parent; + if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED); + return parent.getDisplay (); +} + +/** + * 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 (); + int pixel = (foreground == -1) ? parent.getForegroundPixel() : foreground; + return Color.win32_new (getDisplay (), pixel); +} + +/** + * 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.style & SWT.CHECK) == 0) return false; + int index = parent.indexOf (this); + if (index == -1) return false; + int hwnd = parent.handle; + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.stateMask = OS.LVIS_STATEIMAGEMASK; + lvItem.iItem = index; + int result = OS.SendMessage (hwnd, OS.LVM_GETITEM, 0, lvItem); + return (result != 0) && ((lvItem.state >> 12) > 2); +} + +/** + * 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 (index == 0) return super.getImage (); + int itemIndex = parent.indexOf (this); + if (itemIndex == -1) return null; + int hwnd = parent.handle; + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_IMAGE; + lvItem.iItem = itemIndex; + lvItem.iSubItem = index; + if (OS.SendMessage (hwnd, OS.LVM_GETITEM, 0, lvItem) == 0) return null; + if (lvItem.iImage >= 0) { + ImageList imageList = parent.imageList; + if (imageList != null) return imageList.get (lvItem.iImage); + } + return null; +} + +/** + * Returns a rectangle describing the size and location + * relative to its parent of an image at a column in the + * table. + * + * @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(); + int itemIndex = parent.indexOf (this); + if (itemIndex == -1) return new Rectangle (0, 0, 0, 0); + int hwnd = parent.handle; + int hwndHeader = OS.SendMessage (hwnd, OS.LVM_GETHEADER, 0, 0); + int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0); + if (!(0 <= index && index < count)) return new Rectangle (0, 0, 0, 0); + int gridWidth = 0; + if (parent.getLinesVisible ()) gridWidth = parent.getGridLineWidth (); + RECT rect = new RECT (); + rect.top = index; + rect.left = OS.LVIR_ICON; + OS.SendMessage (hwnd, OS. LVM_GETSUBITEMRECT, itemIndex, rect); + if (index == 0) { + RECT iconRect = new RECT (); + iconRect.left = OS.LVIR_ICON; + OS.SendMessage (hwnd, OS.LVM_GETSUBITEMRECT, itemIndex, iconRect); + rect.left = iconRect.left - gridWidth; + } + int width = rect.right - rect.left - gridWidth; + int height = rect.bottom - rect.top - gridWidth; + /* + * Bug in Windows. In version 5.80 of COMCTL32.DLL, the top + * of the rectangle returned by LVM_GETSUBITEMRECT is off by + * the grid width when the grid is visible. The fix is to + * move the top of the rectangle up by the grid width. + */ + if ((COMCTL32_MAJOR << 16 | COMCTL32_MINOR) >= (5 << 16 | 80)) { + rect.top -= gridWidth; + } + return new Rectangle (rect.left + gridWidth, rect.top + gridWidth, width, 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(); + int index = parent.indexOf (this); + if (index == -1) return 0; + int hwnd = parent.handle; + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_INDENT; + lvItem.iItem = index; + OS.SendMessage (hwnd, OS.LVM_GETITEM, 0, lvItem); + return lvItem.iIndent; +} + +/** + * 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; +} + +/** + * 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> + * @exception SWTError <ul> + * <li>ERROR_CANNOT_GET_TEXT - if the column at index does not exist</li> + * </ul> + */ +public String getText (int index) { + checkWidget(); + if (index == 0) return super.getText (); + int itemIndex = parent.indexOf (this); + if (itemIndex == -1) error (SWT.ERROR_CANNOT_GET_TEXT); + int cchTextMax = 1024; + int hwnd = parent.handle; + int hHeap = OS.GetProcessHeap (); + int byteCount = cchTextMax * TCHAR.sizeof; + int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_TEXT; + lvItem.iItem = itemIndex; + lvItem.iSubItem = index; + lvItem.pszText = pszText; + lvItem.cchTextMax = cchTextMax; + int result = OS.SendMessage (hwnd, OS.LVM_GETITEM, 0, lvItem); + TCHAR buffer = new TCHAR (parent.getCodePage (), cchTextMax); + OS.MoveMemory (buffer, pszText, byteCount); + OS.HeapFree (hHeap, 0, pszText); + if (result == 0) error (SWT.ERROR_CANNOT_GET_TEXT); + return buffer.toString (0, buffer.strlen ()); +} + +void redraw () { + if (parent.drawCount > 0) return; + int hwnd = parent.handle; + if (!OS.IsWindowVisible (hwnd)) return; + int index = parent.indexOf (this); + RECT rect = new RECT (); + rect.left = OS.LVIR_BOUNDS; + if (OS.SendMessage (hwnd, OS.LVM_GETITEMRECT, index, rect) != 0) { + OS.InvalidateRect (hwnd, rect, true); + } +} + +void releaseChild () { + super.releaseChild (); + parent.destroyItem (this); +} + +void releaseWidget () { + super.releaseWidget (); + parent = 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); + } + int pixel = -1; + if (color != null) { + parent.customDraw = true; + pixel = color.handle; + } + background = pixel; + redraw (); +} + +/** + * 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; + int index = parent.indexOf (this); + if (index == -1) return; + int hwnd = parent.handle; + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.stateMask = OS.LVIS_STATEIMAGEMASK; + lvItem.iItem = index; + OS.SendMessage (hwnd, OS.LVM_GETITEM, 0, lvItem); + int state = lvItem.state >> 12; + if (checked) { + if ((state & 0x1) != 0) state++; + } else { + if ((state & 0x1) == 0) --state; + } + lvItem.state = state << 12; + parent.ignoreSelect = true; + OS.SendMessage (hwnd, OS.LVM_SETITEM, 0, lvItem); + parent.ignoreSelect = false; +} + +/** + * 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); + } + int pixel = -1; + if (color != null) { + parent.customDraw = true; + pixel = color.handle; + } + foreground = pixel; + redraw (); +} + +/** + * 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; + int index = parent.indexOf (this); + if (index == -1) return; + int hwnd = parent.handle; + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_STATE; + lvItem.stateMask = OS.LVIS_STATEIMAGEMASK; + lvItem.iItem = index; + OS.SendMessage (hwnd, OS.LVM_GETITEM, 0, lvItem); + int state = lvItem.state >> 12; + if (grayed) { + if (state <= 2) state +=2; + } else { + if (state > 2) state -=2; + } + lvItem.state = state << 12; + parent.ignoreSelect = true; + OS.SendMessage (hwnd, OS.LVM_SETITEM, 0, lvItem); + parent.ignoreSelect = false; +} + +/** + * 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 (index == 0) { + super.setImage (image); + } + int hwnd = parent.handle; + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_IMAGE; + lvItem.iItem = itemIndex; + lvItem.iSubItem = index; + lvItem.iImage = parent.imageIndex (image); + if (OS.SendMessage (hwnd, OS.LVM_SETITEM, 0, lvItem) != 0) { + if (index == 0) parent.setScrollWidth (); + parent.fixCheckboxImageList (); + } +} + +public void setImage (Image image) { + checkWidget (); + setImage (0, image); +} + +/** + * Sets the image indent. + * + * @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> + */ +public void setImageIndent (int indent) { + checkWidget(); + if (indent < 0) return; + int index = parent.indexOf (this); + if (index == -1) return; + int hwnd = parent.handle; + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_INDENT; + lvItem.iItem = index; + lvItem.iIndent = indent; + OS.SendMessage (hwnd, OS.LVM_SETITEM, 0, lvItem); +} + +/** + * 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); + int itemIndex = parent.indexOf (this); + if (itemIndex == -1) return; + if (index == 0) { + super.setText (string); + } + int hwnd = parent.handle; + int hHeap = OS.GetProcessHeap (); + TCHAR buffer = new TCHAR (parent.getCodePage (), string, true); + int byteCount = buffer.length () * TCHAR.sizeof; + int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + OS.MoveMemory (pszText, buffer, byteCount); + LVITEM lvItem = new LVITEM (); + lvItem.mask = OS.LVIF_TEXT; + lvItem.iItem = itemIndex; + lvItem.pszText = pszText; + lvItem.iSubItem = index; + if (OS.SendMessage (hwnd, OS.LVM_SETITEM, 0, lvItem) != 0) { + if (index == 0) parent.setScrollWidth (); + } + OS.HeapFree (hHeap, 0, pszText); +} + +public void setText (String string) { + checkWidget(); + setText (0, string); +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Text.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Text.java index 1583861902..970e070155 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Text.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Text.java @@ -1,1755 +1,1755 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.events.*;
-
-/**
- * Instances of this class are selectable user interface
- * objects that allow the user to enter and modify text.
- * <p>
- * <dl>
- * <dt><b>Styles:</b></dt>
- * <dd>CENTER, LEFT, MULTI, 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.
- * </p><p>
- * IMPORTANT: This class is <em>not</em> intended to be subclassed.
- * </p>
- */
-public class Text extends Scrollable {
- int tabs, oldStart, oldEnd;
- boolean doubleClick, ignoreVerify, ignoreCharacter;
-
- public static final int LIMIT;
- public static final String DELIMITER;
- /*
- * These values can be different on different platforms.
- * Therefore they are not initialized in the declaration
- * to stop the compiler from inlining.
- */
- static {
- LIMIT = OS.IsWinNT ? 0x7FFFFFFF : 0x7FFF;
- DELIMITER = "\r\n";
- }
-
- static final int EditProc;
- static final TCHAR EditClass = new TCHAR (0, "EDIT", true);
- static {
- WNDCLASS lpWndClass = new WNDCLASS ();
- OS.GetClassInfo (0, EditClass, lpWndClass);
- EditProc = lpWndClass.lpfnWndProc;
- }
-
-/**
- * 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 Widget#checkSubclass
- * @see Widget#getStyle
- */
-public Text (Composite parent, int style) {
- super (parent, checkStyle (style));
-}
-
-int callWindowProc (int msg, int wParam, int lParam) {
- if (handle == 0) return 0;
- return OS.CallWindowProc (EditProc, handle, msg, wParam, lParam);
-}
-
-void createHandle () {
- super.createHandle ();
- OS.SendMessage (handle, OS.EM_LIMITTEXT, 0, 0);
-}
-
-/**
- * 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 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
- *
- * @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 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>
- */
-public void append (String string) {
- checkWidget ();
- if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
- string = Display.withCrLf (string);
- int length = OS.GetWindowTextLength (handle);
- if (hooks (SWT.Verify) || filters (SWT.Verify)) {
- string = verifyText (string, length, length);
- if (string == null) return;
- }
- OS.SendMessage (handle, OS.EM_SETSEL, length, length);
- TCHAR buffer = new TCHAR (getCodePage (), string, true);
- OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer);
- OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0);
-}
-
-static int checkStyle (int style) {
- 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;
- 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 ();
- if (OS.IsWinCE) {
- /*
- * Bug in WinCE. Calling EM_SETSEL with -1 and 0 is equivalent
- * to calling EM_SETSEL with 0 and -1. It causes the entire
- * text to be selected instead of clearing the selection. The
- * fix is to set the start of the selection to the end of the
- * current selection.
- */
- int [] end = new int [1];
- OS.SendMessage (handle, OS.EM_GETSEL, (int []) null, end);
- OS.SendMessage (handle, OS.EM_SETSEL, end [0], end [0]);
- } else {
- OS.SendMessage (handle, OS.EM_SETSEL, -1, 0);
- }
-}
-
-public Point computeSize (int wHint, int hHint, boolean changed) {
- checkWidget ();
- int newFont, oldFont = 0;
- int hDC = OS.GetDC (handle);
- newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
- TEXTMETRIC tm = new TEXTMETRIC ();
- OS.GetTextMetrics (hDC, tm);
- int count = OS.SendMessage (handle, OS.EM_GETLINECOUNT, 0, 0);
- int height = count * tm.tmHeight, width = 0;
- RECT rect = new RECT ();
- int flags = OS.DT_CALCRECT | OS.DT_EDITCONTROL | OS.DT_NOPREFIX;
- boolean wrap = (style & SWT.MULTI) != 0 && (style & SWT.WRAP) != 0;
- if (wrap && wHint != SWT.DEFAULT) {
- flags |= OS.DT_WORDBREAK;
- rect.right = wHint;
- }
- String text = getText ();
- TCHAR buffer = new TCHAR (getCodePage (), text, false);
- OS.DrawText (hDC, buffer, buffer.length (), rect, flags);
- width = rect.right - rect.left;
- if (wrap && hHint == SWT.DEFAULT) {
- int newHeight = rect.bottom - rect.top;
- if (newHeight != 0) height = newHeight;
- }
- if (newFont != 0) OS.SelectObject (hDC, oldFont);
- OS.ReleaseDC (handle, hDC);
- if (width == 0) width = DEFAULT_WIDTH;
- if (height == 0) height = DEFAULT_HEIGHT;
- if (wHint != SWT.DEFAULT) width = wHint;
- if (hHint != SWT.DEFAULT) height = hHint;
-
- /* Calculate the margin width */
- int margins = OS.SendMessage(handle, OS.EM_GETMARGINS, 0, 0);
- int marginWidth = (margins & 0xFFFF) + ((margins >> 16) & 0xFFFF);
- width += marginWidth;
-
- /*
- * The preferred height of a single-line text widget
- * has been hand-crafted to be the same height as
- * the single-line text widget in an editable combo
- * box.
- */
- if ((style & SWT.V_SCROLL) != 0) {
- width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
- }
- if ((style & SWT.H_SCROLL) != 0) {
- height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
- if ((style & SWT.BORDER) == 0) width++;
- }
- if ((style & SWT.BORDER) != 0) {
- int border = getBorderWidth ();
- width += (border * 2) + 3;
- height += (border * 2) + 3;
- }
- 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>
- */
-public void copy () {
- checkWidget ();
- OS.SendMessage (handle, OS.WM_COPY, 0, 0);
-}
-
-void createWidget () {
- super.createWidget ();
- doubleClick = true;
- setTabStops (tabs = 8);
-}
-
-/**
- * Cuts the selected text.
- * <p>
- * The current selection is first copied to the
- * clipboard and then deleted from the widget.
- * </p>
- *
- * @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>
- */
-public void cut () {
- checkWidget ();
- OS.SendMessage (handle, OS.WM_CUT, 0, 0);
-}
-
-int defaultBackground () {
- return OS.GetSysColor (OS.COLOR_WINDOW);
-}
-
-/**
- * Gets the line number of the caret.
- * <p>
- * The line number of the caret is returned.
- * </p>
- *
- * @return the line number
- *
- * @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>
- */
-public int getCaretLineNumber () {
- checkWidget ();
- return OS.SendMessage (handle, OS.EM_LINEFROMCHAR, -1, 0);
-}
-
-/**
- * Gets the location the caret.
- * <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 ();
- /*
- * Bug in Windows. For some reason, Windows is unable
- * to return the pixel coordinates of the last character
- * in the widget. The fix is to temporarily insert a
- * space, query the coordinates and delete the space.
- * The selection is always an i-beam in this case because
- * this is the only time the start of the selection can
- * be equal to the last character position in the widget.
- * If EM_POSFROMCHAR fails for any other reason, return
- * pixel coordinates (0,0).
- */
- int [] start = new int [1];
- OS.SendMessage (handle, OS.EM_GETSEL, start, (int []) null);
- int pos = OS.SendMessage (handle, OS.EM_POSFROMCHAR, start [0], 0);
- if (pos == -1) {
- pos = 0;
- if (start [0] >= OS.GetWindowTextLength (handle)) {
- int cp = getCodePage ();
- OS.SendMessage (handle, OS.EM_REPLACESEL, 0, new TCHAR (cp, " ", true));
- pos = OS.SendMessage (handle, OS.EM_POSFROMCHAR, start [0], 0);
- OS.SendMessage (handle, OS.EM_SETSEL, start [0], start [0] + 1);
- OS.SendMessage (handle, OS.EM_REPLACESEL, 0, new TCHAR (cp, "", true));
- }
- }
- return new Point ((short) (pos & 0xFFFF), (short) (pos >> 16));
-}
-
-/**
- * Gets the position of the caret.
- * <p>
- * The character position of the caret is returned.
- * </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 ();
- int [] start = new int [1], end = new int [1];
- OS.SendMessage (handle, OS.EM_GETSEL, start, end);
- int startLine = OS.SendMessage (handle, OS.EM_LINEFROMCHAR, start [0], 0);
- int caretPos = OS.SendMessage (handle, OS.EM_LINEINDEX, -1, 0);
- int caretLine = OS.SendMessage (handle, OS.EM_LINEFROMCHAR, caretPos, 0);
- int caret = end [0];
- if (caretLine == startLine) caret = start [0];
- if (OS.IsDBLocale) caret = mbcsToWcsPos (caret);
- return caret;
-}
-
-/**
- * Gets 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 ();
- int length = OS.GetWindowTextLength (handle);
- if (OS.IsDBLocale) length = mbcsToWcsPos (length);
- return length;
-}
-
-String getClipboardText () {
- String string = "";
- if (OS.OpenClipboard (0)) {
- int hMem = OS.GetClipboardData (OS.IsUnicode ? OS.CF_UNICODETEXT : OS.CF_TEXT);
- if (hMem != 0) {
- /* Ensure byteCount is a multiple of 2 bytes on UNICODE platforms */
- int byteCount = OS.GlobalSize (hMem) / TCHAR.sizeof * TCHAR.sizeof;
- int ptr = OS.GlobalLock (hMem);
- if (ptr != 0) {
- /* Use the character encoding for the default locale */
- TCHAR buffer = new TCHAR (0, byteCount / TCHAR.sizeof);
- OS.MoveMemory (buffer, ptr, byteCount);
- string = buffer.toString (0, buffer.strlen ());
- OS.GlobalUnlock (hMem);
- }
- }
- OS.CloseClipboard ();
- }
- return string;
-}
-
-/**
- * Gets 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>
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if 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;
-}
-
-/**
- * Gets 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>
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- */
-public char getEchoChar () {
- checkWidget ();
- char echo = (char) OS.SendMessage (handle, OS.EM_GETPASSWORDCHAR, 0, 0);
- if (echo != 0 && (echo = mbcsToWcs (echo, getCodePage ())) == 0) echo = '*';
- return echo;
-}
-
-/**
- * Gets the 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 boolean getEditable () {
- checkWidget ();
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- return (bits & OS.ES_READONLY) == 0;
-}
-
-/**
- * Gets 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 ();
- return OS.SendMessage (handle, OS.EM_GETLINECOUNT, 0, 0);
-}
-
-/**
- * Gets 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>
- */
-public String getLineDelimiter () {
- checkWidget ();
- return DELIMITER;
-}
-
-/**
- * Gets 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 ();
- int newFont, oldFont = 0;
- int hDC = OS.GetDC (handle);
- newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
- TEXTMETRIC tm = new TEXTMETRIC ();
- OS.GetTextMetrics (hDC, tm);
- if (newFont != 0) OS.SelectObject (hDC, oldFont);
- OS.ReleaseDC (handle, hDC);
- return tm.tmHeight;
-}
-
-/**
- * Gets the position of the selected text.
- * <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 the start and end of 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 Point getSelection () {
- checkWidget ();
- int [] start = new int [1], end = new int [1];
- OS.SendMessage (handle, OS.EM_GETSEL, start, end);
- if (OS.IsDBLocale) {
- start [0] = mbcsToWcsPos (start [0]);
- end [0] = mbcsToWcsPos (end [0]);
- }
- return new Point (start [0], end [0]);
-}
-
-/**
- * Gets 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 ();
- Point selection = getSelection ();
- return selection.y - selection.x;
-}
-
-/**
- * Gets the selected text.
- *
- * @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 ();
- /*
- * NOTE: The current implementation uses substring ()
- * which can reference a potentially large character
- * array.
- */
- Point selection = getSelection ();
- return getText ().substring (selection.x, selection.y);
-}
-
-/**
- * Gets 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;
-}
-
-int getTabWidth (int tabs) {
- int oldFont = 0;
- RECT rect = new RECT ();
- int hDC = OS.GetDC (handle);
- int newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
- if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
- int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
- TCHAR SPACE = new TCHAR (getCodePage (), " ", false);
- OS.DrawText (hDC, SPACE, SPACE.length (), rect, flags);
- if (newFont != 0) OS.SelectObject (hDC, oldFont);
- OS.ReleaseDC (handle, hDC);
- return (rect.right - rect.left) * tabs;
-}
-
-/**
- * Gets the widget text.
- * <p>
- * The text for a text widget is the characters in the widget.
- * </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 ();
- int length = OS.GetWindowTextLength (handle);
- if (length == 0) return "";
- TCHAR buffer = new TCHAR (getCodePage (), length + 1);
- OS.GetWindowText (handle, buffer, length + 1);
- return buffer.toString (0, length);
-}
-
-/**
- * Gets a range of text.
- * <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 ();
- /*
- * NOTE: The current implementation uses substring ()
- * which can reference a potentially large character
- * array.
- */
- return getText ().substring (start, end + 1);
-}
-
-/**
- * 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>
- */
-public int getTextLimit () {
- checkWidget ();
- return OS.SendMessage (handle, OS.EM_GETLIMITTEXT, 0, 0);
-}
-
-/**
- * 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 ();
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & OS.ES_MULTILINE) == 0) return 0;
- return OS.SendMessage (handle, OS.EM_GETFIRSTVISIBLELINE, 0, 0);
-}
-
-/**
- * Gets 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 ();
- /*
- * Note, EM_GETSCROLLPOS is implemented in Rich Edit 3.0
- * and greater. The plain text widget and previous versions
- * of Rich Edit return zero.
- */
- int [] buffer = new int [2];
- int code = OS.SendMessage (handle, OS.EM_GETSCROLLPOS, 0, buffer);
- if (code == 1) return buffer [1];
- return getTopIndex () * getLineHeight ();
-}
-
-/**
- * Inserts a string.
- * <p>
- * The old selection is replaced with the new text.
- * </p>
- *
- * @param string the string
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if 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);
- string = Display.withCrLf (string);
- if (hooks (SWT.Verify) || filters (SWT.Verify)) {
- int [] start = new int [1], end = new int [1];
- OS.SendMessage (handle, OS.EM_GETSEL, start, end);
- string = verifyText (string, start [0], end [0]);
- if (string == null) return;
- }
- TCHAR buffer = new TCHAR (getCodePage (), string, true);
- OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer);
-}
-
-int mbcsToWcsPos (int mbcsPos) {
- if (mbcsPos == 0) return 0;
- if (OS.IsUnicode) return mbcsPos;
- int cp = getCodePage ();
- int wcsTotal = 0, mbcsTotal = 0;
- byte [] buffer = new byte [128];
- String delimiter = getLineDelimiter();
- int delimiterSize = delimiter.length ();
- int count = OS.SendMessageA (handle, OS.EM_GETLINECOUNT, 0, 0);
- for (int line=0; line<count; line++) {
- int wcsSize = 0;
- int linePos = OS.SendMessageA (handle, OS.EM_LINEINDEX, line, 0);
- int mbcsSize = OS.SendMessageA (handle, OS.EM_LINELENGTH, linePos, 0);
- if (mbcsSize != 0) {
- if (mbcsSize + delimiterSize > buffer.length) {
- buffer = new byte [mbcsSize + delimiterSize];
- }
- buffer [0] = (byte) (mbcsSize & 0xFF);
- buffer [1] = (byte) (mbcsSize >> 8);
- mbcsSize = OS.SendMessageA (handle, OS.EM_GETLINE, line, buffer);
- wcsSize = OS.MultiByteToWideChar (cp, OS.MB_PRECOMPOSED, buffer, mbcsSize, null, 0);
- }
- if (line - 1 != count) {
- for (int i=0; i<delimiterSize; i++) {
- buffer [mbcsSize++] = (byte) delimiter.charAt (i);
- }
- wcsSize += delimiterSize;
- }
- if ((mbcsTotal + mbcsSize) >= mbcsPos) {
- int bufferSize = mbcsPos - mbcsTotal;
- wcsSize = OS.MultiByteToWideChar (cp, OS.MB_PRECOMPOSED, buffer, bufferSize, null, 0);
- return wcsTotal + wcsSize;
- }
- wcsTotal += wcsSize;
- mbcsTotal += mbcsSize;
- }
- return wcsTotal;
-}
-
-/**
- * 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 ();
- OS.SendMessage (handle, OS.WM_PASTE, 0, 0);
-}
-
-/**
- * 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.
- *
- * @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 #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
- */
-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 ();
- OS.SendMessage (handle, OS.EM_SETSEL, 0, -1);
-}
-
-boolean sendKeyEvent (int type, int msg, int wParam, int lParam, Event event) {
- if (!super.sendKeyEvent (type, msg, wParam, lParam, event)) {
- return false;
- }
- if (ignoreVerify) return true;
- if (type != SWT.KeyDown) return true;
- if (msg != OS.WM_CHAR && msg != OS.WM_KEYDOWN && msg != OS.WM_IME_CHAR) {
- return true;
- }
- if (event.character == 0) return true;
- if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return true;
- char key = event.character;
- int stateMask = event.stateMask;
-
- /* Disable all magic keys that could modify the text */
- switch (msg) {
- case OS.WM_CHAR:
- if (key != 0x08 && key != 0x7F && key != '\r' && key != '\t' && key != '\n') break;
- // FALL THROUGH
- case OS.WM_KEYDOWN:
- int modifiers = SWT.ALT | SWT.SHIFT | SWT.CONTROL;
- if ((stateMask & modifiers) != 0) return false;
- break;
- }
-
- /*
- * If the left button is down, the text widget
- * refuses the character.
- */
- if (OS.GetKeyState (OS.VK_LBUTTON) < 0) {
- return true;
- }
-
- /* Verify the character */
- String oldText = "";
- int [] start = new int [1], end = new int [1];
- OS.SendMessage (handle, OS.EM_GETSEL, start, end);
- switch (key) {
- case 0x08: /* Bs */
- if (start [0] == end [0]) {
- if (start [0] == 0) return true;
- int lineStart = OS.SendMessage (handle, OS.EM_LINEINDEX, -1, 0);
- if (start [0] == lineStart) {
- start [0] = start [0] - DELIMITER.length ();
- } else {
- start [0] = start [0] - 1;
- if (OS.IsDBLocale) {
- int [] newStart = new int [1], newEnd = new int [1];
- OS.SendMessage (handle, OS.EM_SETSEL, start [0], end [0]);
- OS.SendMessage (handle, OS.EM_GETSEL, newStart, newEnd);
- if (start [0] != newStart [0]) start [0] = start [0] - 1;
- }
- }
- start [0] = Math.max (start [0], 0);
- }
- break;
- case 0x7F: /* Del */
- if (start [0] == end [0]) {
- int length = OS.GetWindowTextLength (handle);
- if (start [0] == length) return true;
- int line = OS.SendMessage (handle, OS.EM_LINEFROMCHAR, end [0], 0);
- int lineStart = OS.SendMessage (handle, OS.EM_LINEINDEX, line + 1, 0);
- if (end [0] == lineStart - DELIMITER.length ()) {
- end [0] = end [0] + DELIMITER.length ();
- } else {
- end [0] = end [0] + 1;
- if (OS.IsDBLocale) {
- int [] newStart = new int [1], newEnd = new int [1];
- OS.SendMessage (handle, OS.EM_SETSEL, start [0], end [0]);
- OS.SendMessage (handle, OS.EM_GETSEL, newStart, newEnd);
- if (end [0] != newEnd [0]) end [0] = end [0] + 1;
- }
- }
- end [0] = Math.min (end [0], length);
- }
- break;
- case '\r': /* Return */
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & OS.ES_MULTILINE) == 0) return true;
- oldText = DELIMITER;
- break;
- default: /* Tab and other characters */
- if (key != '\t' && key < 0x20) return true;
- oldText = new String (new char [] {key});
- break;
- }
- String newText = verifyText (oldText, start [0], end [0], event);
- if (newText == null) return false;
- if (newText == oldText) return true;
- newText = Display.withCrLf (newText);
- TCHAR buffer = new TCHAR (getCodePage (), newText, true);
- OS.SendMessage (handle, OS.EM_SETSEL, start [0], end [0]);
- OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer);
- return false;
-}
-
-void setBounds (int x, int y, int width, int height, int flags) {
- /*
- * Feature in Windows. When the caret is moved,
- * the text widget scrolls to show the new location.
- * This means that the text widget may be scrolled
- * to the right in order to show the caret when the
- * widget is not large enough to show both the caret
- * location and all the text. Unfortunately, when
- * the text widget is resized such that all the text
- * and the caret could be visible, Windows does not
- * scroll the widget back. The fix is to resize the
- * text widget, set the selection to the start of the
- * text and then restore the selection. This will
- * cause the text widget compute the correct scroll
- * position.
- */
- if ((flags & OS.SWP_NOSIZE) == 0 && width != 0) {
- RECT rect = new RECT ();
- OS.GetWindowRect (handle, rect);
- if (rect.right - rect.left == 0) {
- int [] start = new int [1], end = new int [1];
- OS.SendMessage (handle, OS.EM_GETSEL, start, end);
- if (start [0] != 0 || end [0] != 0) {
- OS.SetWindowPos (handle, 0, x, y, width, height, flags);
- OS.SendMessage (handle, OS.EM_SETSEL, 0, 0);
- OS.SendMessage (handle, OS.EM_SETSEL, start [0], end [0]);
- return;
- }
- }
- }
- super.setBounds (x, y, width, height, flags);
-}
-
-/**
- * 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>
- *
- * @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,
- * 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 (echo != 0) {
- if ((echo = (char) wcsToMbcs (echo, getCodePage ())) == 0) echo = '*';
- }
- OS.SendMessage (handle, OS.EM_SETPASSWORDCHAR, echo, 0);
- /*
- * Bug in Windows. When the password character is changed,
- * Windows does not redraw to show the new password character.
- * The fix is to force a redraw when the character is set.
- */
- OS.InvalidateRect (handle, null, true);
-}
-
-/**
- * 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 ();
- style &= ~SWT.READ_ONLY;
- if (!editable) style |= SWT.READ_ONLY;
- OS.SendMessage (handle, OS.EM_SETREADONLY, editable ? 0 : 1, 0);
-}
-
-public void setFont (Font font) {
- checkWidget ();
- super.setFont (font);
- setTabStops (tabs);
-}
-
-/**
- * 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 ();
- if (OS.IsDBLocale) start = wcsToMbcsPos (start);
- OS.SendMessage (handle, OS.EM_SETSEL, start, start);
- OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0);
-}
-
-/**
- * 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
- * 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 (OS.IsDBLocale) {
- start = wcsToMbcsPos (start);
- end = wcsToMbcsPos (end);
- }
- OS.SendMessage (handle, OS.EM_SETSEL, start, end);
- OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0);
-}
-
-public void setRedraw (boolean redraw) {
- checkWidget ();
- super.setRedraw (redraw);
- /*
- * Feature in Windows. When WM_SETREDRAW is used to turn
- * redraw off, the text control is not scrolled to show the
- * i-beam. The fix is to detect that the i-beam has moved
- * while redraw is turned off and force it to be visible
- * when redraw is restored.
- */
- if (drawCount != 0) return;
- int [] start = new int [1], end = new int [1];
- OS.SendMessage (handle, OS.EM_GETSEL, start, end);
- if (!redraw) {
- oldStart = start [0]; oldEnd = end [0];
- return;
- }
- if (oldStart == start [0] && oldEnd == end [0]) return;
- OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0);
-}
-
-/**
- * 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
- * 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 (tabs < 0) return;
- setTabStops (this.tabs = tabs);
-}
-
-void setTabStops (int tabs) {
- /*
- * Feature in Windows. Windows expects the tab spacing in
- * dialog units so we must convert from space widths. Due
- * to round off error, the tab spacing may not be the exact
- * number of space widths, depending on the font.
- */
- int width = (getTabWidth (tabs) * 4) / (OS.GetDialogBaseUnits () & 0xFFFF);
- OS.SendMessage (handle, OS.EM_SETTABSTOPS, 1, new int [] {width});
-}
-
-/**
- * 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 text 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);
- string = Display.withCrLf (string);
- if (hooks (SWT.Verify) || filters (SWT.Verify)) {
- int length = OS.GetWindowTextLength (handle);
- string = verifyText (string, 0, length);
- if (string == null) return;
- }
- TCHAR buffer = new TCHAR (getCodePage (), string, true);
- OS.SetWindowText (handle, buffer);
- /*
- * Bug in Windows. When the widget is multi line
- * text widget, it does not send a WM_COMMAND with
- * control code EN_CHANGE from SetWindowText () to
- * notify the application that the text has changed.
- * The fix is to send the event.
- */
- if ((style & SWT.MULTI) != 0) {
- sendEvent (SWT.Modify);
- // widget could be disposed at this point
- }
-}
-
-/**
- * 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>.
- * </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>
- */
-public void setTextLimit (int limit) {
- checkWidget ();
- if (limit == 0) error (SWT.ERROR_CANNOT_BE_ZERO);
- OS.SendMessage (handle, OS.EM_SETLIMITTEXT, limit, 0);
-}
-
-/**
- * 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 ();
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & OS.ES_MULTILINE) == 0) return;
- int count = OS.SendMessage (handle, OS.EM_GETLINECOUNT, 0, 0);
- index = Math.min (Math.max (index, 0), count - 1);
- int topIndex = OS.SendMessage (handle, OS.EM_GETFIRSTVISIBLELINE, 0, 0);
- OS.SendMessage (handle, OS.EM_LINESCROLL, 0, index - topIndex);
-}
-
-/**
- * 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 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>
- */
-public void showSelection () {
- checkWidget ();
- OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0);
-}
-
-String verifyText (String string, int start, int end) {
- return verifyText (string, start, end, null);
-}
-
-String verifyText (String string, int start, int end, Event keyEvent) {
- if (ignoreVerify) return string;
- Event event = new Event ();
- event.text = string;
- event.start = start;
- event.end = end;
- if (keyEvent != null) {
- event.character = keyEvent.character;
- event.keyCode = keyEvent.keyCode;
- event.stateMask = keyEvent.stateMask;
- }
- if (OS.IsDBLocale) {
- event.start = mbcsToWcsPos (start);
- event.end = mbcsToWcsPos (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;
-}
-
-int wcsToMbcsPos (int wcsPos) {
- if (wcsPos == 0) return 0;
- if (OS.IsUnicode) return wcsPos;
- int cp = getCodePage ();
- int wcsTotal = 0, mbcsTotal = 0;
- byte [] buffer = new byte [128];
- String delimiter = getLineDelimiter ();
- int delimiterSize = delimiter.length ();
- int count = OS.SendMessageA (handle, OS.EM_GETLINECOUNT, 0, 0);
- for (int line=0; line<count; line++) {
- int wcsSize = 0;
- int linePos = OS.SendMessageA (handle, OS.EM_LINEINDEX, line, 0);
- int mbcsSize = OS.SendMessageA (handle, OS.EM_LINELENGTH, linePos, 0);
- if (mbcsSize != 0) {
- if (mbcsSize + delimiterSize > buffer.length) {
- buffer = new byte [mbcsSize + delimiterSize];
- }
- //ENDIAN
- buffer [0] = (byte) (mbcsSize & 0xFF);
- buffer [1] = (byte) (mbcsSize >> 8);
- mbcsSize = OS.SendMessageA (handle, OS.EM_GETLINE, line, buffer);
- wcsSize = OS.MultiByteToWideChar (cp, OS.MB_PRECOMPOSED, buffer, mbcsSize, null, 0);
- }
- if (line - 1 != count) {
- for (int i=0; i<delimiterSize; i++) {
- buffer [mbcsSize++] = (byte) delimiter.charAt (i);
- }
- wcsSize += delimiterSize;
- }
- if ((wcsTotal + wcsSize) >= wcsPos) {
- wcsSize = 0;
- int index = 0;
- while (index < mbcsSize) {
- if ((wcsTotal + wcsSize) == wcsPos) {
- return mbcsTotal + index;
- }
- if (OS.IsDBCSLeadByte (buffer [index++])) index++;
- wcsSize++;
- }
- return mbcsTotal + mbcsSize;
- }
- wcsTotal += wcsSize;
- mbcsTotal += mbcsSize;
- }
- return mbcsTotal;
-}
-
-int widgetStyle () {
- int bits = super.widgetStyle ();
- if ((style & SWT.CENTER) != 0) bits |= OS.ES_CENTER;
- if ((style & SWT.RIGHT) != 0) bits |= OS.ES_RIGHT;
- if ((style & SWT.READ_ONLY) != 0) bits |= OS.ES_READONLY;
- if ((style & SWT.SINGLE) != 0) return bits | OS.ES_AUTOHSCROLL;
- bits |= OS.ES_MULTILINE | OS.ES_AUTOHSCROLL | OS.ES_NOHIDESEL;
- if ((style & SWT.WRAP) != 0) bits &= ~(OS.WS_HSCROLL | OS.ES_AUTOHSCROLL);
- return bits;
-}
-
-TCHAR windowClass () {
- return EditClass;
-}
-
-int windowProc () {
- return EditProc;
-}
-
-LRESULT WM_CHAR (int wParam, int lParam) {
- if (ignoreCharacter) return null;
- LRESULT result = super.WM_CHAR (wParam, lParam);
- if (result != null) return result;
- /*
- * Feature in Windows. For some reason, when the
- * widget is a single line text widget, when the
- * user presses tab, return or escape, Windows beeps.
- * The fix is to look for these keys and not call
- * the window proc.
- */
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & OS.ES_MULTILINE) == 0) {
- switch (wParam) {
- case OS.VK_RETURN:
- postEvent (SWT.DefaultSelection);
- // FALL THROUGH
- case OS.VK_TAB:
- case OS.VK_ESCAPE: return LRESULT.ZERO;
- }
- }
- return result;
-}
-
-LRESULT WM_CLEAR (int wParam, int lParam) {
- LRESULT result = super.WM_CLEAR (wParam, lParam);
- if (result != null) return result;
- if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return result;
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & OS.ES_READONLY) != 0) return result;
- int [] start = new int [1], end = new int [1];
- OS.SendMessage (handle, OS.EM_GETSEL, start, end);
- if (start [0] == end [0]) return result;
- String newText = verifyText ("", start [0], end [0]);
- if (newText == null) return LRESULT.ZERO;
- if (newText.length () != 0) {
- result = new LRESULT (callWindowProc (OS.WM_CLEAR, 0, 0));
- newText = Display.withCrLf (newText);
- TCHAR buffer = new TCHAR (getCodePage (), newText, true);
- OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer);
- }
- return result;
-}
-
-LRESULT WM_CUT (int wParam, int lParam) {
- LRESULT result = super.WM_CUT (wParam, lParam);
- if (result != null) return result;
- if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return result;
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & OS.ES_READONLY) != 0) return result;
- int [] start = new int [1], end = new int [1];
- OS.SendMessage (handle, OS.EM_GETSEL, start, end);
- if (start [0] == end [0]) return result;
- String newText = verifyText ("", start [0], end [0]);
- if (newText == null) return LRESULT.ZERO;
- if (newText.length () != 0) {
- result = new LRESULT (callWindowProc (OS.WM_CUT, 0, 0));
- newText = Display.withCrLf (newText);
- TCHAR buffer = new TCHAR (getCodePage (), newText, true);
- OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer);
- }
- return result;
-}
-
-LRESULT WM_GETDLGCODE (int wParam, int lParam) {
- LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
- if (result != null) return result;
- /*
- * Feature in Windows. Despite the fact that the
- * text control is read only, it still returns a
- * dialog code indicating that it wants keys. The
- * fix is to detect this case and clear the bits.
- */
- if ((style & SWT.READ_ONLY) != 0) {
- int code = callWindowProc (OS.WM_GETDLGCODE, wParam, lParam);
- code &= ~(OS.DLGC_WANTALLKEYS | OS.DLGC_WANTTAB | OS.DLGC_WANTARROWS);
- return new LRESULT (code);
- }
- return null;
-}
-
-LRESULT WM_IME_CHAR (int wParam, int lParam) {
-
- /* Process a DBCS character */
- Display display = getDisplay ();
- display.lastKey = 0;
- display.lastAscii = wParam;
- display.lastVirtual = display.lastNull = false;
- if (!sendKeyEvent (SWT.KeyDown, OS.WM_IME_CHAR, wParam, lParam)) {
- return LRESULT.ZERO;
- }
- sendKeyEvent (SWT.KeyUp, OS.WM_IME_CHAR, wParam, lParam);
- display.lastKey = display.lastAscii = 0;
-
- /*
- * Feature in Windows. The Windows text widget uses
- * two 2 WM_CHAR's to process a DBCS key instead of
- * using WM_IME_CHAR. The fix is to allow the text
- * widget to get the WM_CHAR's but ignore sending
- * them to the application.
- */
- ignoreCharacter = true;
- int result = callWindowProc (OS.WM_IME_CHAR, wParam, lParam);
- MSG msg = new MSG ();
- while (OS.PeekMessage (msg, handle, OS.WM_CHAR, OS.WM_CHAR, OS.PM_REMOVE)) {
- OS.TranslateMessage (msg);
- OS.DispatchMessage (msg);
- }
- ignoreCharacter = false;
- return new LRESULT (result);
-}
-
-LRESULT WM_LBUTTONDBLCLK (int wParam, int lParam) {
- /*
- * Prevent Windows from processing WM_LBUTTONDBLCLK
- * when double clicking behavior is disabled by not
- * calling the window proc.
- */
- sendMouseEvent (SWT.MouseDown, 1, OS.WM_LBUTTONDOWN, wParam, lParam);
- sendMouseEvent (SWT.MouseDoubleClick, 1, OS.WM_LBUTTONDBLCLK, wParam, lParam);
- if (OS.GetCapture () != handle) OS.SetCapture (handle);
- if (!doubleClick) return LRESULT.ZERO;
-
- /*
- * Bug in Windows. When the last line of text in the
- * widget is double clicked and the line is empty, Windows
- * hides the i-beam then moves it to the first line in
- * the widget but does not scroll to show the user.
- * If the user types without clicking the mouse, invalid
- * characters are displayed at the end of each line of
- * text in the widget. The fix is to detect this case
- * and avoid calling the window proc.
- */
- int [] start = new int [1], end = new int [1];
- OS.SendMessage (handle, OS.EM_GETSEL, start, end);
- if (start [0] == end [0]) {
- int length = OS.GetWindowTextLength (handle);
- if (length == start [0]) {
- int result = OS.SendMessage (handle, OS.EM_LINELENGTH, length, 0);
- if (result == 0) return LRESULT.ZERO;
- }
- }
- return null;
-}
-
-LRESULT WM_PASTE (int wParam, int lParam) {
- LRESULT result = super.WM_PASTE (wParam, lParam);
- if (result != null) return result;
- if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return result;
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & OS.ES_READONLY) != 0) return result;
- String oldText = getClipboardText ();
- if (oldText == null) return result;
- int [] start = new int [1], end = new int [1];
- OS.SendMessage (handle, OS.EM_GETSEL, start, end);
- String newText = verifyText (oldText, start [0], end [0]);
- if (newText == null) return LRESULT.ZERO;
- if (newText != oldText) {
- newText = Display.withCrLf (newText);
- TCHAR buffer = new TCHAR (getCodePage (), newText, true);
- OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer);
- return LRESULT.ZERO;
- }
- return result;
-}
-
-LRESULT WM_UNDO (int wParam, int lParam) {
- LRESULT result = super.WM_UNDO (wParam, lParam);
- if (result != null) return result;
- if (!hooks (SWT.Verify) && !filters (SWT.Verify)) {
- return result;
- }
-
- /* Undo and then Redo to get the Undo text */
- if (OS.SendMessage (handle, OS.EM_CANUNDO, 0, 0) == 0) {
- return result;
- }
- ignoreVerify = true;
- callWindowProc (OS.WM_UNDO, wParam, lParam);
- String oldText = getSelectionText ();
- callWindowProc (OS.WM_UNDO, wParam, lParam);
- ignoreVerify = false;
-
- /* Verify the Undo operation */
- int [] start = new int [1], end = new int [1];
- OS.SendMessage (handle, OS.EM_GETSEL, start, end);
- String newText = verifyText (oldText, start [0], end [0]);
- if (newText == null) return LRESULT.ZERO;
- if (newText != oldText) {
- newText = Display.withCrLf (newText);
- TCHAR buffer = new TCHAR (getCodePage (), newText, true);
- OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer);
- return LRESULT.ZERO;
- }
-
- /* Do the original Undo */
- ignoreVerify = true;
- callWindowProc (OS.WM_UNDO, wParam, lParam);
- ignoreVerify = false;
- return LRESULT.ONE;
-}
-
-LRESULT wmCommandChild (int wParam, int lParam) {
- int code = wParam >> 16;
- switch (code) {
- case OS.EN_CHANGE:
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the modify
- * event. If this happens, end the processing of the
- * Windows message by returning zero as the result of
- * the window proc.
- */
- sendEvent (SWT.Modify);
- if (isDisposed ()) return LRESULT.ZERO;
- break;
- }
- return super.wmCommandChild (wParam, lParam);
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.events.*; + +/** + * Instances of this class are selectable user interface + * objects that allow the user to enter and modify text. + * <p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>CENTER, LEFT, MULTI, 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. + * </p><p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + */ +public class Text extends Scrollable { + int tabs, oldStart, oldEnd; + boolean doubleClick, ignoreVerify, ignoreCharacter; + + public static final int LIMIT; + public static final String DELIMITER; + /* + * These values can be different on different platforms. + * Therefore they are not initialized in the declaration + * to stop the compiler from inlining. + */ + static { + LIMIT = OS.IsWinNT ? 0x7FFFFFFF : 0x7FFF; + DELIMITER = "\r\n"; + } + + static final int EditProc; + static final TCHAR EditClass = new TCHAR (0, "EDIT", true); + static { + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, EditClass, lpWndClass); + EditProc = lpWndClass.lpfnWndProc; + } + +/** + * 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 Widget#checkSubclass + * @see Widget#getStyle + */ +public Text (Composite parent, int style) { + super (parent, checkStyle (style)); +} + +int callWindowProc (int msg, int wParam, int lParam) { + if (handle == 0) return 0; + return OS.CallWindowProc (EditProc, handle, msg, wParam, lParam); +} + +void createHandle () { + super.createHandle (); + OS.SendMessage (handle, OS.EM_LIMITTEXT, 0, 0); +} + +/** + * 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 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 + * + * @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 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> + */ +public void append (String string) { + checkWidget (); + if (string == null) error (SWT.ERROR_NULL_ARGUMENT); + string = Display.withCrLf (string); + int length = OS.GetWindowTextLength (handle); + if (hooks (SWT.Verify) || filters (SWT.Verify)) { + string = verifyText (string, length, length); + if (string == null) return; + } + OS.SendMessage (handle, OS.EM_SETSEL, length, length); + TCHAR buffer = new TCHAR (getCodePage (), string, true); + OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer); + OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0); +} + +static int checkStyle (int style) { + 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; + 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 (); + if (OS.IsWinCE) { + /* + * Bug in WinCE. Calling EM_SETSEL with -1 and 0 is equivalent + * to calling EM_SETSEL with 0 and -1. It causes the entire + * text to be selected instead of clearing the selection. The + * fix is to set the start of the selection to the end of the + * current selection. + */ + int [] end = new int [1]; + OS.SendMessage (handle, OS.EM_GETSEL, (int []) null, end); + OS.SendMessage (handle, OS.EM_SETSEL, end [0], end [0]); + } else { + OS.SendMessage (handle, OS.EM_SETSEL, -1, 0); + } +} + +public Point computeSize (int wHint, int hHint, boolean changed) { + checkWidget (); + int newFont, oldFont = 0; + int hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); + TEXTMETRIC tm = new TEXTMETRIC (); + OS.GetTextMetrics (hDC, tm); + int count = OS.SendMessage (handle, OS.EM_GETLINECOUNT, 0, 0); + int height = count * tm.tmHeight, width = 0; + RECT rect = new RECT (); + int flags = OS.DT_CALCRECT | OS.DT_EDITCONTROL | OS.DT_NOPREFIX; + boolean wrap = (style & SWT.MULTI) != 0 && (style & SWT.WRAP) != 0; + if (wrap && wHint != SWT.DEFAULT) { + flags |= OS.DT_WORDBREAK; + rect.right = wHint; + } + String text = getText (); + TCHAR buffer = new TCHAR (getCodePage (), text, false); + OS.DrawText (hDC, buffer, buffer.length (), rect, flags); + width = rect.right - rect.left; + if (wrap && hHint == SWT.DEFAULT) { + int newHeight = rect.bottom - rect.top; + if (newHeight != 0) height = newHeight; + } + if (newFont != 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + if (width == 0) width = DEFAULT_WIDTH; + if (height == 0) height = DEFAULT_HEIGHT; + if (wHint != SWT.DEFAULT) width = wHint; + if (hHint != SWT.DEFAULT) height = hHint; + + /* Calculate the margin width */ + int margins = OS.SendMessage(handle, OS.EM_GETMARGINS, 0, 0); + int marginWidth = (margins & 0xFFFF) + ((margins >> 16) & 0xFFFF); + width += marginWidth; + + /* + * The preferred height of a single-line text widget + * has been hand-crafted to be the same height as + * the single-line text widget in an editable combo + * box. + */ + if ((style & SWT.V_SCROLL) != 0) { + width += OS.GetSystemMetrics (OS.SM_CXVSCROLL); + } + if ((style & SWT.H_SCROLL) != 0) { + height += OS.GetSystemMetrics (OS.SM_CYHSCROLL); + if ((style & SWT.BORDER) == 0) width++; + } + if ((style & SWT.BORDER) != 0) { + int border = getBorderWidth (); + width += (border * 2) + 3; + height += (border * 2) + 3; + } + 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> + */ +public void copy () { + checkWidget (); + OS.SendMessage (handle, OS.WM_COPY, 0, 0); +} + +void createWidget () { + super.createWidget (); + doubleClick = true; + setTabStops (tabs = 8); +} + +/** + * Cuts the selected text. + * <p> + * The current selection is first copied to the + * clipboard and then deleted from the widget. + * </p> + * + * @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> + */ +public void cut () { + checkWidget (); + OS.SendMessage (handle, OS.WM_CUT, 0, 0); +} + +int defaultBackground () { + return OS.GetSysColor (OS.COLOR_WINDOW); +} + +/** + * Gets the line number of the caret. + * <p> + * The line number of the caret is returned. + * </p> + * + * @return the line number + * + * @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> + */ +public int getCaretLineNumber () { + checkWidget (); + return OS.SendMessage (handle, OS.EM_LINEFROMCHAR, -1, 0); +} + +/** + * Gets the location the caret. + * <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 (); + /* + * Bug in Windows. For some reason, Windows is unable + * to return the pixel coordinates of the last character + * in the widget. The fix is to temporarily insert a + * space, query the coordinates and delete the space. + * The selection is always an i-beam in this case because + * this is the only time the start of the selection can + * be equal to the last character position in the widget. + * If EM_POSFROMCHAR fails for any other reason, return + * pixel coordinates (0,0). + */ + int [] start = new int [1]; + OS.SendMessage (handle, OS.EM_GETSEL, start, (int []) null); + int pos = OS.SendMessage (handle, OS.EM_POSFROMCHAR, start [0], 0); + if (pos == -1) { + pos = 0; + if (start [0] >= OS.GetWindowTextLength (handle)) { + int cp = getCodePage (); + OS.SendMessage (handle, OS.EM_REPLACESEL, 0, new TCHAR (cp, " ", true)); + pos = OS.SendMessage (handle, OS.EM_POSFROMCHAR, start [0], 0); + OS.SendMessage (handle, OS.EM_SETSEL, start [0], start [0] + 1); + OS.SendMessage (handle, OS.EM_REPLACESEL, 0, new TCHAR (cp, "", true)); + } + } + return new Point ((short) (pos & 0xFFFF), (short) (pos >> 16)); +} + +/** + * Gets the position of the caret. + * <p> + * The character position of the caret is returned. + * </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 (); + int [] start = new int [1], end = new int [1]; + OS.SendMessage (handle, OS.EM_GETSEL, start, end); + int startLine = OS.SendMessage (handle, OS.EM_LINEFROMCHAR, start [0], 0); + int caretPos = OS.SendMessage (handle, OS.EM_LINEINDEX, -1, 0); + int caretLine = OS.SendMessage (handle, OS.EM_LINEFROMCHAR, caretPos, 0); + int caret = end [0]; + if (caretLine == startLine) caret = start [0]; + if (OS.IsDBLocale) caret = mbcsToWcsPos (caret); + return caret; +} + +/** + * Gets 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 (); + int length = OS.GetWindowTextLength (handle); + if (OS.IsDBLocale) length = mbcsToWcsPos (length); + return length; +} + +String getClipboardText () { + String string = ""; + if (OS.OpenClipboard (0)) { + int hMem = OS.GetClipboardData (OS.IsUnicode ? OS.CF_UNICODETEXT : OS.CF_TEXT); + if (hMem != 0) { + /* Ensure byteCount is a multiple of 2 bytes on UNICODE platforms */ + int byteCount = OS.GlobalSize (hMem) / TCHAR.sizeof * TCHAR.sizeof; + int ptr = OS.GlobalLock (hMem); + if (ptr != 0) { + /* Use the character encoding for the default locale */ + TCHAR buffer = new TCHAR (0, byteCount / TCHAR.sizeof); + OS.MoveMemory (buffer, ptr, byteCount); + string = buffer.toString (0, buffer.strlen ()); + OS.GlobalUnlock (hMem); + } + } + OS.CloseClipboard (); + } + return string; +} + +/** + * Gets 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> + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if 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; +} + +/** + * Gets 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> + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public char getEchoChar () { + checkWidget (); + char echo = (char) OS.SendMessage (handle, OS.EM_GETPASSWORDCHAR, 0, 0); + if (echo != 0 && (echo = mbcsToWcs (echo, getCodePage ())) == 0) echo = '*'; + return echo; +} + +/** + * Gets the 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 boolean getEditable () { + checkWidget (); + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + return (bits & OS.ES_READONLY) == 0; +} + +/** + * Gets 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 (); + return OS.SendMessage (handle, OS.EM_GETLINECOUNT, 0, 0); +} + +/** + * Gets 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> + */ +public String getLineDelimiter () { + checkWidget (); + return DELIMITER; +} + +/** + * Gets 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 (); + int newFont, oldFont = 0; + int hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); + TEXTMETRIC tm = new TEXTMETRIC (); + OS.GetTextMetrics (hDC, tm); + if (newFont != 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + return tm.tmHeight; +} + +/** + * Gets the position of the selected text. + * <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 the start and end of 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 Point getSelection () { + checkWidget (); + int [] start = new int [1], end = new int [1]; + OS.SendMessage (handle, OS.EM_GETSEL, start, end); + if (OS.IsDBLocale) { + start [0] = mbcsToWcsPos (start [0]); + end [0] = mbcsToWcsPos (end [0]); + } + return new Point (start [0], end [0]); +} + +/** + * Gets 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 (); + Point selection = getSelection (); + return selection.y - selection.x; +} + +/** + * Gets the selected text. + * + * @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 (); + /* + * NOTE: The current implementation uses substring () + * which can reference a potentially large character + * array. + */ + Point selection = getSelection (); + return getText ().substring (selection.x, selection.y); +} + +/** + * Gets 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; +} + +int getTabWidth (int tabs) { + int oldFont = 0; + RECT rect = new RECT (); + int hDC = OS.GetDC (handle); + int newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); + int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX; + TCHAR SPACE = new TCHAR (getCodePage (), " ", false); + OS.DrawText (hDC, SPACE, SPACE.length (), rect, flags); + if (newFont != 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + return (rect.right - rect.left) * tabs; +} + +/** + * Gets the widget text. + * <p> + * The text for a text widget is the characters in the widget. + * </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 (); + int length = OS.GetWindowTextLength (handle); + if (length == 0) return ""; + TCHAR buffer = new TCHAR (getCodePage (), length + 1); + OS.GetWindowText (handle, buffer, length + 1); + return buffer.toString (0, length); +} + +/** + * Gets a range of text. + * <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 (); + /* + * NOTE: The current implementation uses substring () + * which can reference a potentially large character + * array. + */ + return getText ().substring (start, end + 1); +} + +/** + * 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> + */ +public int getTextLimit () { + checkWidget (); + return OS.SendMessage (handle, OS.EM_GETLIMITTEXT, 0, 0); +} + +/** + * 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 (); + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & OS.ES_MULTILINE) == 0) return 0; + return OS.SendMessage (handle, OS.EM_GETFIRSTVISIBLELINE, 0, 0); +} + +/** + * Gets 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 (); + /* + * Note, EM_GETSCROLLPOS is implemented in Rich Edit 3.0 + * and greater. The plain text widget and previous versions + * of Rich Edit return zero. + */ + int [] buffer = new int [2]; + int code = OS.SendMessage (handle, OS.EM_GETSCROLLPOS, 0, buffer); + if (code == 1) return buffer [1]; + return getTopIndex () * getLineHeight (); +} + +/** + * Inserts a string. + * <p> + * The old selection is replaced with the new text. + * </p> + * + * @param string the string + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if 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); + string = Display.withCrLf (string); + if (hooks (SWT.Verify) || filters (SWT.Verify)) { + int [] start = new int [1], end = new int [1]; + OS.SendMessage (handle, OS.EM_GETSEL, start, end); + string = verifyText (string, start [0], end [0]); + if (string == null) return; + } + TCHAR buffer = new TCHAR (getCodePage (), string, true); + OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer); +} + +int mbcsToWcsPos (int mbcsPos) { + if (mbcsPos == 0) return 0; + if (OS.IsUnicode) return mbcsPos; + int cp = getCodePage (); + int wcsTotal = 0, mbcsTotal = 0; + byte [] buffer = new byte [128]; + String delimiter = getLineDelimiter(); + int delimiterSize = delimiter.length (); + int count = OS.SendMessageA (handle, OS.EM_GETLINECOUNT, 0, 0); + for (int line=0; line<count; line++) { + int wcsSize = 0; + int linePos = OS.SendMessageA (handle, OS.EM_LINEINDEX, line, 0); + int mbcsSize = OS.SendMessageA (handle, OS.EM_LINELENGTH, linePos, 0); + if (mbcsSize != 0) { + if (mbcsSize + delimiterSize > buffer.length) { + buffer = new byte [mbcsSize + delimiterSize]; + } + buffer [0] = (byte) (mbcsSize & 0xFF); + buffer [1] = (byte) (mbcsSize >> 8); + mbcsSize = OS.SendMessageA (handle, OS.EM_GETLINE, line, buffer); + wcsSize = OS.MultiByteToWideChar (cp, OS.MB_PRECOMPOSED, buffer, mbcsSize, null, 0); + } + if (line - 1 != count) { + for (int i=0; i<delimiterSize; i++) { + buffer [mbcsSize++] = (byte) delimiter.charAt (i); + } + wcsSize += delimiterSize; + } + if ((mbcsTotal + mbcsSize) >= mbcsPos) { + int bufferSize = mbcsPos - mbcsTotal; + wcsSize = OS.MultiByteToWideChar (cp, OS.MB_PRECOMPOSED, buffer, bufferSize, null, 0); + return wcsTotal + wcsSize; + } + wcsTotal += wcsSize; + mbcsTotal += mbcsSize; + } + return wcsTotal; +} + +/** + * 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 (); + OS.SendMessage (handle, OS.WM_PASTE, 0, 0); +} + +/** + * 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. + * + * @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 #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 + */ +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 (); + OS.SendMessage (handle, OS.EM_SETSEL, 0, -1); +} + +boolean sendKeyEvent (int type, int msg, int wParam, int lParam, Event event) { + if (!super.sendKeyEvent (type, msg, wParam, lParam, event)) { + return false; + } + if (ignoreVerify) return true; + if (type != SWT.KeyDown) return true; + if (msg != OS.WM_CHAR && msg != OS.WM_KEYDOWN && msg != OS.WM_IME_CHAR) { + return true; + } + if (event.character == 0) return true; + if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return true; + char key = event.character; + int stateMask = event.stateMask; + + /* Disable all magic keys that could modify the text */ + switch (msg) { + case OS.WM_CHAR: + if (key != 0x08 && key != 0x7F && key != '\r' && key != '\t' && key != '\n') break; + // FALL THROUGH + case OS.WM_KEYDOWN: + int modifiers = SWT.ALT | SWT.SHIFT | SWT.CONTROL; + if ((stateMask & modifiers) != 0) return false; + break; + } + + /* + * If the left button is down, the text widget + * refuses the character. + */ + if (OS.GetKeyState (OS.VK_LBUTTON) < 0) { + return true; + } + + /* Verify the character */ + String oldText = ""; + int [] start = new int [1], end = new int [1]; + OS.SendMessage (handle, OS.EM_GETSEL, start, end); + switch (key) { + case 0x08: /* Bs */ + if (start [0] == end [0]) { + if (start [0] == 0) return true; + int lineStart = OS.SendMessage (handle, OS.EM_LINEINDEX, -1, 0); + if (start [0] == lineStart) { + start [0] = start [0] - DELIMITER.length (); + } else { + start [0] = start [0] - 1; + if (OS.IsDBLocale) { + int [] newStart = new int [1], newEnd = new int [1]; + OS.SendMessage (handle, OS.EM_SETSEL, start [0], end [0]); + OS.SendMessage (handle, OS.EM_GETSEL, newStart, newEnd); + if (start [0] != newStart [0]) start [0] = start [0] - 1; + } + } + start [0] = Math.max (start [0], 0); + } + break; + case 0x7F: /* Del */ + if (start [0] == end [0]) { + int length = OS.GetWindowTextLength (handle); + if (start [0] == length) return true; + int line = OS.SendMessage (handle, OS.EM_LINEFROMCHAR, end [0], 0); + int lineStart = OS.SendMessage (handle, OS.EM_LINEINDEX, line + 1, 0); + if (end [0] == lineStart - DELIMITER.length ()) { + end [0] = end [0] + DELIMITER.length (); + } else { + end [0] = end [0] + 1; + if (OS.IsDBLocale) { + int [] newStart = new int [1], newEnd = new int [1]; + OS.SendMessage (handle, OS.EM_SETSEL, start [0], end [0]); + OS.SendMessage (handle, OS.EM_GETSEL, newStart, newEnd); + if (end [0] != newEnd [0]) end [0] = end [0] + 1; + } + } + end [0] = Math.min (end [0], length); + } + break; + case '\r': /* Return */ + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & OS.ES_MULTILINE) == 0) return true; + oldText = DELIMITER; + break; + default: /* Tab and other characters */ + if (key != '\t' && key < 0x20) return true; + oldText = new String (new char [] {key}); + break; + } + String newText = verifyText (oldText, start [0], end [0], event); + if (newText == null) return false; + if (newText == oldText) return true; + newText = Display.withCrLf (newText); + TCHAR buffer = new TCHAR (getCodePage (), newText, true); + OS.SendMessage (handle, OS.EM_SETSEL, start [0], end [0]); + OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer); + return false; +} + +void setBounds (int x, int y, int width, int height, int flags) { + /* + * Feature in Windows. When the caret is moved, + * the text widget scrolls to show the new location. + * This means that the text widget may be scrolled + * to the right in order to show the caret when the + * widget is not large enough to show both the caret + * location and all the text. Unfortunately, when + * the text widget is resized such that all the text + * and the caret could be visible, Windows does not + * scroll the widget back. The fix is to resize the + * text widget, set the selection to the start of the + * text and then restore the selection. This will + * cause the text widget compute the correct scroll + * position. + */ + if ((flags & OS.SWP_NOSIZE) == 0 && width != 0) { + RECT rect = new RECT (); + OS.GetWindowRect (handle, rect); + if (rect.right - rect.left == 0) { + int [] start = new int [1], end = new int [1]; + OS.SendMessage (handle, OS.EM_GETSEL, start, end); + if (start [0] != 0 || end [0] != 0) { + OS.SetWindowPos (handle, 0, x, y, width, height, flags); + OS.SendMessage (handle, OS.EM_SETSEL, 0, 0); + OS.SendMessage (handle, OS.EM_SETSEL, start [0], end [0]); + return; + } + } + } + super.setBounds (x, y, width, height, flags); +} + +/** + * 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> + * + * @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, + * 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 (echo != 0) { + if ((echo = (char) wcsToMbcs (echo, getCodePage ())) == 0) echo = '*'; + } + OS.SendMessage (handle, OS.EM_SETPASSWORDCHAR, echo, 0); + /* + * Bug in Windows. When the password character is changed, + * Windows does not redraw to show the new password character. + * The fix is to force a redraw when the character is set. + */ + OS.InvalidateRect (handle, null, true); +} + +/** + * 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 (); + style &= ~SWT.READ_ONLY; + if (!editable) style |= SWT.READ_ONLY; + OS.SendMessage (handle, OS.EM_SETREADONLY, editable ? 0 : 1, 0); +} + +public void setFont (Font font) { + checkWidget (); + super.setFont (font); + setTabStops (tabs); +} + +/** + * 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 (); + if (OS.IsDBLocale) start = wcsToMbcsPos (start); + OS.SendMessage (handle, OS.EM_SETSEL, start, start); + OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0); +} + +/** + * 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 + * 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 (OS.IsDBLocale) { + start = wcsToMbcsPos (start); + end = wcsToMbcsPos (end); + } + OS.SendMessage (handle, OS.EM_SETSEL, start, end); + OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0); +} + +public void setRedraw (boolean redraw) { + checkWidget (); + super.setRedraw (redraw); + /* + * Feature in Windows. When WM_SETREDRAW is used to turn + * redraw off, the text control is not scrolled to show the + * i-beam. The fix is to detect that the i-beam has moved + * while redraw is turned off and force it to be visible + * when redraw is restored. + */ + if (drawCount != 0) return; + int [] start = new int [1], end = new int [1]; + OS.SendMessage (handle, OS.EM_GETSEL, start, end); + if (!redraw) { + oldStart = start [0]; oldEnd = end [0]; + return; + } + if (oldStart == start [0] && oldEnd == end [0]) return; + OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0); +} + +/** + * 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 + * 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 (tabs < 0) return; + setTabStops (this.tabs = tabs); +} + +void setTabStops (int tabs) { + /* + * Feature in Windows. Windows expects the tab spacing in + * dialog units so we must convert from space widths. Due + * to round off error, the tab spacing may not be the exact + * number of space widths, depending on the font. + */ + int width = (getTabWidth (tabs) * 4) / (OS.GetDialogBaseUnits () & 0xFFFF); + OS.SendMessage (handle, OS.EM_SETTABSTOPS, 1, new int [] {width}); +} + +/** + * 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 text 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); + string = Display.withCrLf (string); + if (hooks (SWT.Verify) || filters (SWT.Verify)) { + int length = OS.GetWindowTextLength (handle); + string = verifyText (string, 0, length); + if (string == null) return; + } + TCHAR buffer = new TCHAR (getCodePage (), string, true); + OS.SetWindowText (handle, buffer); + /* + * Bug in Windows. When the widget is multi line + * text widget, it does not send a WM_COMMAND with + * control code EN_CHANGE from SetWindowText () to + * notify the application that the text has changed. + * The fix is to send the event. + */ + if ((style & SWT.MULTI) != 0) { + sendEvent (SWT.Modify); + // widget could be disposed at this point + } +} + +/** + * 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>. + * </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> + */ +public void setTextLimit (int limit) { + checkWidget (); + if (limit == 0) error (SWT.ERROR_CANNOT_BE_ZERO); + OS.SendMessage (handle, OS.EM_SETLIMITTEXT, limit, 0); +} + +/** + * 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 (); + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & OS.ES_MULTILINE) == 0) return; + int count = OS.SendMessage (handle, OS.EM_GETLINECOUNT, 0, 0); + index = Math.min (Math.max (index, 0), count - 1); + int topIndex = OS.SendMessage (handle, OS.EM_GETFIRSTVISIBLELINE, 0, 0); + OS.SendMessage (handle, OS.EM_LINESCROLL, 0, index - topIndex); +} + +/** + * 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 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> + */ +public void showSelection () { + checkWidget (); + OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0); +} + +String verifyText (String string, int start, int end) { + return verifyText (string, start, end, null); +} + +String verifyText (String string, int start, int end, Event keyEvent) { + if (ignoreVerify) return string; + Event event = new Event (); + event.text = string; + event.start = start; + event.end = end; + if (keyEvent != null) { + event.character = keyEvent.character; + event.keyCode = keyEvent.keyCode; + event.stateMask = keyEvent.stateMask; + } + if (OS.IsDBLocale) { + event.start = mbcsToWcsPos (start); + event.end = mbcsToWcsPos (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; +} + +int wcsToMbcsPos (int wcsPos) { + if (wcsPos == 0) return 0; + if (OS.IsUnicode) return wcsPos; + int cp = getCodePage (); + int wcsTotal = 0, mbcsTotal = 0; + byte [] buffer = new byte [128]; + String delimiter = getLineDelimiter (); + int delimiterSize = delimiter.length (); + int count = OS.SendMessageA (handle, OS.EM_GETLINECOUNT, 0, 0); + for (int line=0; line<count; line++) { + int wcsSize = 0; + int linePos = OS.SendMessageA (handle, OS.EM_LINEINDEX, line, 0); + int mbcsSize = OS.SendMessageA (handle, OS.EM_LINELENGTH, linePos, 0); + if (mbcsSize != 0) { + if (mbcsSize + delimiterSize > buffer.length) { + buffer = new byte [mbcsSize + delimiterSize]; + } + //ENDIAN + buffer [0] = (byte) (mbcsSize & 0xFF); + buffer [1] = (byte) (mbcsSize >> 8); + mbcsSize = OS.SendMessageA (handle, OS.EM_GETLINE, line, buffer); + wcsSize = OS.MultiByteToWideChar (cp, OS.MB_PRECOMPOSED, buffer, mbcsSize, null, 0); + } + if (line - 1 != count) { + for (int i=0; i<delimiterSize; i++) { + buffer [mbcsSize++] = (byte) delimiter.charAt (i); + } + wcsSize += delimiterSize; + } + if ((wcsTotal + wcsSize) >= wcsPos) { + wcsSize = 0; + int index = 0; + while (index < mbcsSize) { + if ((wcsTotal + wcsSize) == wcsPos) { + return mbcsTotal + index; + } + if (OS.IsDBCSLeadByte (buffer [index++])) index++; + wcsSize++; + } + return mbcsTotal + mbcsSize; + } + wcsTotal += wcsSize; + mbcsTotal += mbcsSize; + } + return mbcsTotal; +} + +int widgetStyle () { + int bits = super.widgetStyle (); + if ((style & SWT.CENTER) != 0) bits |= OS.ES_CENTER; + if ((style & SWT.RIGHT) != 0) bits |= OS.ES_RIGHT; + if ((style & SWT.READ_ONLY) != 0) bits |= OS.ES_READONLY; + if ((style & SWT.SINGLE) != 0) return bits | OS.ES_AUTOHSCROLL; + bits |= OS.ES_MULTILINE | OS.ES_AUTOHSCROLL | OS.ES_NOHIDESEL; + if ((style & SWT.WRAP) != 0) bits &= ~(OS.WS_HSCROLL | OS.ES_AUTOHSCROLL); + return bits; +} + +TCHAR windowClass () { + return EditClass; +} + +int windowProc () { + return EditProc; +} + +LRESULT WM_CHAR (int wParam, int lParam) { + if (ignoreCharacter) return null; + LRESULT result = super.WM_CHAR (wParam, lParam); + if (result != null) return result; + /* + * Feature in Windows. For some reason, when the + * widget is a single line text widget, when the + * user presses tab, return or escape, Windows beeps. + * The fix is to look for these keys and not call + * the window proc. + */ + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & OS.ES_MULTILINE) == 0) { + switch (wParam) { + case OS.VK_RETURN: + postEvent (SWT.DefaultSelection); + // FALL THROUGH + case OS.VK_TAB: + case OS.VK_ESCAPE: return LRESULT.ZERO; + } + } + return result; +} + +LRESULT WM_CLEAR (int wParam, int lParam) { + LRESULT result = super.WM_CLEAR (wParam, lParam); + if (result != null) return result; + if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return result; + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & OS.ES_READONLY) != 0) return result; + int [] start = new int [1], end = new int [1]; + OS.SendMessage (handle, OS.EM_GETSEL, start, end); + if (start [0] == end [0]) return result; + String newText = verifyText ("", start [0], end [0]); + if (newText == null) return LRESULT.ZERO; + if (newText.length () != 0) { + result = new LRESULT (callWindowProc (OS.WM_CLEAR, 0, 0)); + newText = Display.withCrLf (newText); + TCHAR buffer = new TCHAR (getCodePage (), newText, true); + OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer); + } + return result; +} + +LRESULT WM_CUT (int wParam, int lParam) { + LRESULT result = super.WM_CUT (wParam, lParam); + if (result != null) return result; + if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return result; + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & OS.ES_READONLY) != 0) return result; + int [] start = new int [1], end = new int [1]; + OS.SendMessage (handle, OS.EM_GETSEL, start, end); + if (start [0] == end [0]) return result; + String newText = verifyText ("", start [0], end [0]); + if (newText == null) return LRESULT.ZERO; + if (newText.length () != 0) { + result = new LRESULT (callWindowProc (OS.WM_CUT, 0, 0)); + newText = Display.withCrLf (newText); + TCHAR buffer = new TCHAR (getCodePage (), newText, true); + OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer); + } + return result; +} + +LRESULT WM_GETDLGCODE (int wParam, int lParam) { + LRESULT result = super.WM_GETDLGCODE (wParam, lParam); + if (result != null) return result; + /* + * Feature in Windows. Despite the fact that the + * text control is read only, it still returns a + * dialog code indicating that it wants keys. The + * fix is to detect this case and clear the bits. + */ + if ((style & SWT.READ_ONLY) != 0) { + int code = callWindowProc (OS.WM_GETDLGCODE, wParam, lParam); + code &= ~(OS.DLGC_WANTALLKEYS | OS.DLGC_WANTTAB | OS.DLGC_WANTARROWS); + return new LRESULT (code); + } + return null; +} + +LRESULT WM_IME_CHAR (int wParam, int lParam) { + + /* Process a DBCS character */ + Display display = getDisplay (); + display.lastKey = 0; + display.lastAscii = wParam; + display.lastVirtual = display.lastNull = false; + if (!sendKeyEvent (SWT.KeyDown, OS.WM_IME_CHAR, wParam, lParam)) { + return LRESULT.ZERO; + } + sendKeyEvent (SWT.KeyUp, OS.WM_IME_CHAR, wParam, lParam); + display.lastKey = display.lastAscii = 0; + + /* + * Feature in Windows. The Windows text widget uses + * two 2 WM_CHAR's to process a DBCS key instead of + * using WM_IME_CHAR. The fix is to allow the text + * widget to get the WM_CHAR's but ignore sending + * them to the application. + */ + ignoreCharacter = true; + int result = callWindowProc (OS.WM_IME_CHAR, wParam, lParam); + MSG msg = new MSG (); + while (OS.PeekMessage (msg, handle, OS.WM_CHAR, OS.WM_CHAR, OS.PM_REMOVE)) { + OS.TranslateMessage (msg); + OS.DispatchMessage (msg); + } + ignoreCharacter = false; + return new LRESULT (result); +} + +LRESULT WM_LBUTTONDBLCLK (int wParam, int lParam) { + /* + * Prevent Windows from processing WM_LBUTTONDBLCLK + * when double clicking behavior is disabled by not + * calling the window proc. + */ + sendMouseEvent (SWT.MouseDown, 1, OS.WM_LBUTTONDOWN, wParam, lParam); + sendMouseEvent (SWT.MouseDoubleClick, 1, OS.WM_LBUTTONDBLCLK, wParam, lParam); + if (OS.GetCapture () != handle) OS.SetCapture (handle); + if (!doubleClick) return LRESULT.ZERO; + + /* + * Bug in Windows. When the last line of text in the + * widget is double clicked and the line is empty, Windows + * hides the i-beam then moves it to the first line in + * the widget but does not scroll to show the user. + * If the user types without clicking the mouse, invalid + * characters are displayed at the end of each line of + * text in the widget. The fix is to detect this case + * and avoid calling the window proc. + */ + int [] start = new int [1], end = new int [1]; + OS.SendMessage (handle, OS.EM_GETSEL, start, end); + if (start [0] == end [0]) { + int length = OS.GetWindowTextLength (handle); + if (length == start [0]) { + int result = OS.SendMessage (handle, OS.EM_LINELENGTH, length, 0); + if (result == 0) return LRESULT.ZERO; + } + } + return null; +} + +LRESULT WM_PASTE (int wParam, int lParam) { + LRESULT result = super.WM_PASTE (wParam, lParam); + if (result != null) return result; + if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return result; + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & OS.ES_READONLY) != 0) return result; + String oldText = getClipboardText (); + if (oldText == null) return result; + int [] start = new int [1], end = new int [1]; + OS.SendMessage (handle, OS.EM_GETSEL, start, end); + String newText = verifyText (oldText, start [0], end [0]); + if (newText == null) return LRESULT.ZERO; + if (newText != oldText) { + newText = Display.withCrLf (newText); + TCHAR buffer = new TCHAR (getCodePage (), newText, true); + OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer); + return LRESULT.ZERO; + } + return result; +} + +LRESULT WM_UNDO (int wParam, int lParam) { + LRESULT result = super.WM_UNDO (wParam, lParam); + if (result != null) return result; + if (!hooks (SWT.Verify) && !filters (SWT.Verify)) { + return result; + } + + /* Undo and then Redo to get the Undo text */ + if (OS.SendMessage (handle, OS.EM_CANUNDO, 0, 0) == 0) { + return result; + } + ignoreVerify = true; + callWindowProc (OS.WM_UNDO, wParam, lParam); + String oldText = getSelectionText (); + callWindowProc (OS.WM_UNDO, wParam, lParam); + ignoreVerify = false; + + /* Verify the Undo operation */ + int [] start = new int [1], end = new int [1]; + OS.SendMessage (handle, OS.EM_GETSEL, start, end); + String newText = verifyText (oldText, start [0], end [0]); + if (newText == null) return LRESULT.ZERO; + if (newText != oldText) { + newText = Display.withCrLf (newText); + TCHAR buffer = new TCHAR (getCodePage (), newText, true); + OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer); + return LRESULT.ZERO; + } + + /* Do the original Undo */ + ignoreVerify = true; + callWindowProc (OS.WM_UNDO, wParam, lParam); + ignoreVerify = false; + return LRESULT.ONE; +} + +LRESULT wmCommandChild (int wParam, int lParam) { + int code = wParam >> 16; + switch (code) { + case OS.EN_CHANGE: + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the modify + * event. If this happens, end the processing of the + * Windows message by returning zero as the result of + * the window proc. + */ + sendEvent (SWT.Modify); + if (isDisposed ()) return LRESULT.ZERO; + break; + } + return super.wmCommandChild (wParam, lParam); +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java index 2abda90e58..5d431f6bc0 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java @@ -1,928 +1,928 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-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>
- */
-public class ToolBar extends Composite {
- int lastFocusId;
- ToolItem [] items;
- boolean ignoreResize;
- ImageList imageList, disabledImageList, hotImageList;
- static final int ToolBarProc;
- static final TCHAR ToolBarClass = new TCHAR (0, OS.TOOLBARCLASSNAME, true);
- static {
- WNDCLASS lpWndClass = new WNDCLASS ();
- OS.GetClassInfo (0, ToolBarClass, lpWndClass);
- ToolBarProc = lpWndClass.lpfnWndProc;
- }
-
- /*
- * From the Windows SDK for TB_SETBUTTONSIZE:
- *
- * "If an application does not explicitly
- * set the button size, the size defaults
- * to 24 by 22 pixels".
- */
- static final int DEFAULT_WIDTH = 24;
- static final int DEFAULT_HEIGHT = 22;
-
-/**
- * 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 callWindowProc (int msg, int wParam, int lParam) {
- if (handle == 0) return 0;
- /*
- * Bug in Windows. For some reason, during the processing
- * of WM_SYSCHAR, the tool bar window proc does not call the
- * default window proc causing mnemonics for the menu bar
- * to be ignored. The fix is to always call the default
- * window proc for WM_SYSCHAR.
- */
- if (msg == OS.WM_SYSCHAR) {
- return OS.DefWindowProc (handle, msg, wParam, lParam);
- }
- return OS.CallWindowProc (ToolBarProc, handle, msg, wParam, lParam);
-}
-
-static int checkStyle (int style) {
- /*
- * On Windows, only flat tool bars can be traversed.
- */
- if ((style & SWT.FLAT) == 0) style |= SWT.NO_FOCUS;
-
- /*
- * A vertical tool bar cannot wrap because TB_SETROWS
- * fails when the toobar has TBSTYLE_WRAPABLE.
- */
- /*
- * This code is intentionally commented.
- */
- //if ((style & SWT.VERTICAL) != 0) style &= ~SWT.WRAP;
-
- /*
- * The TB_SETROWS calls are currently commented, so force
- * the wrap style if this bar is vertical.
- */
- if ((style & SWT.VERTICAL) != 0) style |= SWT.WRAP;
-
- /*
- * 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 ();
- if (layout != null) {
- return super.computeSize (wHint, hHint, changed);
- }
- int width = 0, height = 0;
- RECT oldRect = new RECT ();
- OS.GetWindowRect (handle, oldRect);
- int oldWidth = oldRect.right - oldRect.left;
- int oldHeight = oldRect.bottom - oldRect.top;
- int border = getBorderWidth ();
- int newWidth = wHint == SWT.DEFAULT ? 0x3FFF : wHint + (border * 2);
- int newHeight = hHint == SWT.DEFAULT ? 0x3FFF : hHint + (border * 2);
- boolean redraw = drawCount == 0 && OS.IsWindowVisible (handle);
- ignoreResize = true;
- if (redraw) OS.UpdateWindow (handle);
- int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOREDRAW | OS.SWP_NOZORDER;
- OS.SetWindowPos (handle, 0, 0, 0, newWidth, newHeight, flags);
- int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
- if (count != 0) {
- RECT rect = new RECT ();
- OS.SendMessage (handle, OS.TB_GETITEMRECT, count - 1, rect);
- width = Math.max (width, rect.right);
- height = Math.max (height, rect.bottom);
- }
- OS.SetWindowPos (handle, 0, 0, 0, oldWidth, oldHeight, flags);
- if (redraw) OS.ValidateRect (handle, null);
- ignoreResize = false;
-
- /*
- * From the Windows SDK for TB_SETBUTTONSIZE:
- *
- * "If an application does not explicitly
- * set the button size, the size defaults
- * to 24 by 22 pixels".
- */
- 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) {
- checkWidget ();
- Rectangle trim = super.computeTrim (x, y, width, height);
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- if ((bits & OS.CCS_NODIVIDER) == 0) trim.height += 2;
- return trim;
-}
-
-void createHandle () {
- super.createHandle ();
- state &= ~CANVAS;
-
- /*
- * Feature in Windows. When TBSTYLE_FLAT is used to create
- * a flat toolbar, for some reason TBSTYLE_TRANSPARENT is
- * also set. This causes the toolbar to flicker when it is
- * moved or resized. The fix is to clear TBSTYLE_TRANSPARENT.
- *
- * NOTE: This work around is unnecessary on XP. There is no
- * flickering and clearing the TBSTYLE_TRANSPARENT interferes
- * with the XP theme.
- */
- if (COMCTL32_MAJOR < 6) {
- int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
- bits &= ~OS.TBSTYLE_TRANSPARENT;
- OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
- }
-
- /*
- * Feature in Windows. Despite the fact that the
- * tool tip text contains \r\n, the tooltip will
- * not honour the new line unless TTM_SETMAXTIPWIDTH
- * is set. The fix is to set TTM_SETMAXTIPWIDTH to
- * a large value.
- */
- /*
- * These lines are intentionally commented. The tool
- * bar currently sets this value to 300 so it is not
- * necessary to set TTM_SETMAXTIPWIDTH.
- */
-// int hwndToolTip = OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0);
-// OS.SendMessage (hwndToolTip, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
-
- /*
- * Feature in Windows. When the control is created,
- * it does not use the default system font. A new HFONT
- * is created and destroyed when the control is destroyed.
- * This means that a program that queries the font from
- * this control, uses the font in another control and then
- * destroys this control will have the font unexpectedly
- * destroyed in the other control. The fix is to assign
- * the font ourselves each time the control is created.
- * The control will not destroy a font that it did not
- * create.
- */
- int hFont = OS.GetStockObject (OS.SYSTEM_FONT);
- OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0);
-
- /* Set the button struct, bitmap and button sizes */
- OS.SendMessage (handle, OS.TB_BUTTONSTRUCTSIZE, TBBUTTON.sizeof, 0);
- OS.SendMessage (handle, OS.TB_SETBITMAPSIZE, 0, 0);
- OS.SendMessage (handle, OS.TB_SETBUTTONSIZE, 0, 0);
-
- /* Set the extended style bits */
- OS.SendMessage (handle, OS.TB_SETEXTENDEDSTYLE, 0, OS.TBSTYLE_EX_DRAWDDARROWS);
-}
-
-void createItem (ToolItem item, int index) {
- int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
- if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE);
- int id = 0;
- while (id < items.length && items [id] != null) id++;
- if (id == items.length) {
- ToolItem [] newItems = new ToolItem [items.length + 4];
- System.arraycopy (items, 0, newItems, 0, items.length);
- items = newItems;
- }
- int bits = item.widgetStyle ();
- TBBUTTON lpButton = new TBBUTTON ();
- lpButton.idCommand = id;
- lpButton.fsStyle = (byte) bits;
- lpButton.fsState = (byte) OS.TBSTATE_ENABLED;
-
- /*
- * Bug in Windows. Despite the fact that the image list
- * index has never been set for the item, Windows always
- * assumes that the image index for the item is valid.
- * When an item is inserted, the image index is zero.
- * Therefore, when the first image is inserted and is
- * assigned image index zero, every item draws with this
- * image. The fix is to set the image index to none
- * when the item is created. This is not necessary in
- * the case when the item has the BTNS_SEP style because
- * separators cannot show images.
- */
- if ((bits & OS.BTNS_SEP) == 0) lpButton.iBitmap = OS.I_IMAGENONE;
- if (OS.SendMessage (handle, OS.TB_INSERTBUTTON, index, lpButton) == 0) {
- error (SWT.ERROR_ITEM_NOT_ADDED);
- }
- items [item.id = id] = item;
- /*
- * This code is intentionally commented.
- */
-// if ((style & SWT.VERTICAL) != 0) {
-// OS.SendMessage (handle, OS.TB_SETROWS, count+1, 0);
-// }
- layoutItems ();
-}
-
-void createWidget () {
- super.createWidget ();
- items = new ToolItem [4];
- lastFocusId = -1;
-}
-
-int defaultBackground () {
- if (OS.IsWinCE) return OS.GetSysColor (OS.COLOR_BTNFACE);
- return super.defaultBackground ();
-}
-
-void destroyItem (ToolItem item) {
- TBBUTTONINFO info = new TBBUTTONINFO ();
- info.cbSize = TBBUTTONINFO.sizeof;
- info.dwMask = OS.TBIF_IMAGE | OS.TBIF_STYLE;
- int index = OS.SendMessage (handle, OS.TB_GETBUTTONINFO, item.id, info);
- /*
- * Feature in Windows. For some reason, a tool item that has
- * the style BTNS_SEP does not return I_IMAGENONE when queried
- * for an image index, despite the fact that no attempt has been
- * made to assign an image to the item. As a result, operations
- * on an image list that use the wrong index cause random results.
- * The fix is to ensure that the tool item is not a separator
- * before using the image index. Since separators cannot have
- * an image and one is never assigned, this is not a problem.
- */
- if ((info.fsStyle & OS.BTNS_SEP) == 0 && info.iImage != OS.I_IMAGENONE) {
- if (imageList != null) imageList.put (info.iImage, null);
- if (hotImageList != null) hotImageList.put (info.iImage, null);
- if (disabledImageList != null) disabledImageList.put (info.iImage, null);
- }
- OS.SendMessage (handle, OS.TB_DELETEBUTTON, index, 0);
- if (item.id == lastFocusId) lastFocusId = -1;
- items [item.id] = null;
- item.id = -1;
- int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
- if (count == 0) {
- Display display = getDisplay ();
- if (imageList != null) {
- OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0);
- display.releaseToolImageList (imageList);
- }
- if (hotImageList != null) {
- OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, 0);
- display.releaseToolHotImageList (hotImageList);
- }
- if (disabledImageList != null) {
- OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, 0);
- display.releaseToolDisabledImageList (disabledImageList);
- }
- imageList = hotImageList = disabledImageList = null;
- items = new ToolItem [4];
- }
- /*
- * This code is intentionally commented.
- */
-// if ((style & SWT.VERTICAL) != 0) {
-// OS.SendMessage (handle, OS.TB_SETROWS, count-1, 0);
-// }
- layoutItems ();
-}
-
-ImageList getDisabledImageList () {
- return disabledImageList;
-}
-
-ImageList getHotImageList () {
- return hotImageList;
-}
-
-ImageList getImageList () {
- return imageList;
-}
-
-/**
- * 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 ();
- int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
- if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE);
- TBBUTTON lpButton = new TBBUTTON ();
- int result = OS.SendMessage (handle, OS.TB_GETBUTTON, index, lpButton);
- if (result == 0) error (SWT.ERROR_CANNOT_GET_ITEM);
- return items [lpButton.idCommand];
-}
-
-/**
- * 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 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>
- */
-public ToolItem getItem (Point point) {
- checkWidget ();
- if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
- ToolItem [] items = getItems ();
- for (int i=0; i<items.length; i++) {
- Rectangle rect = items [i].getBounds ();
- if (rect.contains (point)) 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 OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
-}
-
-/**
- * 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 ToolItem [] getItems () {
- checkWidget ();
- int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
- TBBUTTON lpButton = new TBBUTTON ();
- ToolItem [] result = new ToolItem [count];
- for (int i=0; i<count; i++) {
- OS.SendMessage (handle, OS.TB_GETBUTTON, i, lpButton);
- result [i] = items [lpButton.idCommand];
- }
- 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 ();
- return OS.SendMessage (handle, OS.TB_GETROWS, 0, 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);
- return OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, item.id, 0);
-}
-
-void layoutItems () {
- for (int i=0; i<items.length; i++) {
- ToolItem item = items [i];
- if (item != null) item.resizeControl ();
- }
-}
-
-boolean mnemonicHit (char ch) {
- int key = wcsToMbcs (ch);
- int [] id = new int [1];
- if (OS.SendMessage (handle, OS.TB_MAPACCELERATOR, key, id) == 0) {
- return false;
- }
- if (!setTabGroupFocus ()) return false;
- int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, id [0], 0);
- if (index == -1) return false;
- OS.SendMessage (handle, OS.TB_SETHOTITEM, index, 0);
- items [id [0]].click (false);
- return true;
-}
-
-boolean mnemonicMatch (char ch) {
- int key = wcsToMbcs (ch);
- int [] id = new int [1];
- return OS.SendMessage (handle, OS.TB_MAPACCELERATOR, key, id) != 0;
-}
-
-void releaseWidget () {
- for (int i=0; i<items.length; i++) {
- ToolItem item = items [i];
- if (item != null && !item.isDisposed ()) {
- item.releaseImages ();
- item.releaseResources ();
- }
- }
- items = null;
- Display display = getDisplay ();
- if (imageList != null) {
- OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0);
- display.releaseToolImageList (imageList);
- }
- if (hotImageList != null) {
- OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, 0);
- display.releaseToolHotImageList (hotImageList);
- }
- if (disabledImageList != null) {
- OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, 0);
- display.releaseToolDisabledImageList (disabledImageList);
- }
- imageList = hotImageList = disabledImageList = null;
- super.releaseWidget ();
-}
-
-void setBounds (int x, int y, int width, int height, int flags) {
- /*
- * Feature in Windows. For some reason, when a tool bar is
- * repositioned more than once using DeferWindowPos () into
- * the same HDWP, the toolbar redraws more than once, defeating
- * the puropse of DeferWindowPos (). The fix is to end the
- * defered positioning before the next tool bar is added,
- * ensuring that only one tool bar position is deferred at
- * any given time.
- */
- if (parent.lpwp != null) {
- if (drawCount == 0 && OS.IsWindowVisible (handle)) {
- parent.setResizeChildren (false);
- parent.setResizeChildren (true);
- }
- }
- super.setBounds (x, y, width, height, flags);
-}
-
-void setDefaultFont () {
- super.setDefaultFont ();
- OS.SendMessage (handle, OS.TB_SETBITMAPSIZE, 0, 0);
- OS.SendMessage (handle, OS.TB_SETBUTTONSIZE, 0, 0);
-}
-
-void setDisabledImageList (ImageList imageList) {
- if (disabledImageList == imageList) return;
- int hImageList = 0;
- if ((disabledImageList = imageList) != null) {
- hImageList = disabledImageList.getHandle ();
- }
- OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, hImageList);
-}
-
-void setHotImageList (ImageList imageList) {
- if (hotImageList == imageList) return;
- int hImageList = 0;
- if ((hotImageList = imageList) != null) {
- hImageList = hotImageList.getHandle ();
- }
- OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, hImageList);
-}
-
-void setImageList (ImageList imageList) {
- if (this.imageList == imageList) return;
- int hImageList = 0;
- if ((this.imageList = imageList) != null) {
- hImageList = imageList.getHandle ();
- }
- OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, hImageList);
-}
-
-boolean setTabItemFocus () {
- int index = 0;
- while (index < items.length) {
- ToolItem item = items [index];
- if (item != null && (item.style & SWT.SEPARATOR) == 0) {
- if (item.getEnabled ()) break;
- }
- index++;
- }
- if (index == items.length) return false;
- return super.setTabItemFocus ();
-}
-
-String toolTipText (NMTTDISPINFO hdr) {
- if ((hdr.uFlags & OS.TTF_IDISHWND) != 0) {
- return null;
- }
- int index = hdr.idFrom;
- int hwndToolTip = OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0);
- if (hwndToolTip == hdr.hwndFrom) {
- if (toolTipText != null) return "";
- if (0 <= index && index < items.length) {
- ToolItem item = items [index];
- if (item != null) return item.toolTipText;
- }
- }
- return super.toolTipText (hdr);
-}
-
-int widgetStyle () {
- int bits = super.widgetStyle () | OS.CCS_NORESIZE | OS.TBSTYLE_TOOLTIPS;
- if ((style & SWT.SHADOW_OUT) == 0) bits |= OS.CCS_NODIVIDER;
- if ((style & SWT.WRAP) != 0) bits |= OS.TBSTYLE_WRAPABLE;
- if ((style & SWT.FLAT) != 0) bits |= OS.TBSTYLE_FLAT;
- if ((style & SWT.RIGHT) != 0) bits |= OS.TBSTYLE_LIST;
- return bits;
-}
-
-TCHAR windowClass () {
- return ToolBarClass;
-}
-
-int windowProc () {
- return ToolBarProc;
-}
-
-LRESULT WM_GETDLGCODE (int wParam, int lParam) {
- LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
- /*
- * Return DLGC_BUTTON so that mnemonics will be
- * processed without needing to press the ALT key
- * when the widget has focus.
- */
- if (result != null) return result;
- return new LRESULT (OS.DLGC_BUTTON);
-}
-
-LRESULT WM_COMMAND (int wParam, int lParam) {
- /*
- * Feature in Windows. When the toolbar window
- * proc processes WM_COMMAND, it forwards this
- * message to its parent. This is done so that
- * children of this control that send this message
- * type to their parent will notify not only
- * this control but also the parent of this control,
- * which is typically the application window and
- * the window that is looking for the message.
- * If the control did not forward the message,
- * applications would have to subclass the control
- * window to see the message. Because the control
- * window is subclassed by SWT, the message
- * is delivered twice, once by SWT and once when
- * the message is forwarded by the window proc.
- * The fix is to avoid calling the window proc
- * for this control.
- */
- LRESULT result = super.WM_COMMAND (wParam, lParam);
- if (result != null) return result;
- return LRESULT.ZERO;
-}
-
-LRESULT WM_KEYDOWN (int wParam, int lParam) {
- LRESULT result = super.WM_KEYDOWN (wParam, lParam);
- if (result != null) return result;
- switch (wParam) {
- case OS.VK_RETURN:
- case OS.VK_SPACE:
- int index = OS.SendMessage (handle, OS.TB_GETHOTITEM, 0, 0);
- if (index != -1) {
- TBBUTTON lpButton = new TBBUTTON ();
- int code = OS.SendMessage (handle, OS.TB_GETBUTTON, index, lpButton);
- if (code != 0) {
- items [lpButton.idCommand].click (wParam == OS.VK_RETURN);
- return LRESULT.ZERO;
- }
- }
- }
- return result;
-}
-
-LRESULT WM_KILLFOCUS (int wParam, int lParam) {
- int index = OS.SendMessage (handle, OS.TB_GETHOTITEM, 0, 0);
- TBBUTTON lpButton = new TBBUTTON ();
- int code = OS.SendMessage (handle, OS.TB_GETBUTTON, index, lpButton);
- if (code != 0) lastFocusId = lpButton.idCommand;
- return super.WM_KILLFOCUS (wParam, lParam);
-}
-
-LRESULT WM_NOTIFY (int wParam, int lParam) {
- /*
- * Feature in Windows. When the toolbar window
- * proc processes WM_NOTIFY, it forwards this
- * message to its parent. This is done so that
- * children of this control that send this message
- * type to their parent will notify not only
- * this control but also the parent of this control,
- * which is typically the application window and
- * the window that is looking for the message.
- * If the control did not forward the message,
- * applications would have to subclass the control
- * window to see the message. Because the control
- * window is subclassed by SWT, the message
- * is delivered twice, once by SWT and once when
- * the message is forwarded by the window proc.
- * The fix is to avoid calling the window proc
- * for this control.
- */
- LRESULT result = super.WM_NOTIFY (wParam, lParam);
- if (result != null) return result;
- return LRESULT.ZERO;
-}
-
-LRESULT WM_SETFOCUS (int wParam, int lParam) {
- LRESULT result = super.WM_SETFOCUS (wParam, lParam);
- if (lastFocusId != -1 && handle == OS.GetFocus ()) {
- int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, lastFocusId, 0);
- OS.SendMessage (handle, OS.TB_SETHOTITEM, index, 0);
- }
- return result;
-}
-
-LRESULT WM_SIZE (int wParam, int lParam) {
- if (ignoreResize) {
- int code = callWindowProc (OS.WM_SIZE, wParam, lParam);
- if (code == 0) return LRESULT.ZERO;
- return new LRESULT (code);
- }
- /*
- * Feature in Windows. When a tool bar that contains
- * separators is wrapped, under certain circumstances,
- * Windows redraws the entire tool bar unnecessarily
- * when resized no item is moves. Whether the entire
- * toolbar is damaged or not seems to depend on the
- * size of the tool bar and the position of the separators.
- * The fix is to ensure that the newly exposed areas are
- * always damaged, and avoid the redraw when no tool item
- * moves.
- */
- RECT [] rects = null;
- int rgn = 0, oldCount = 0;
- boolean fixRedraw = drawCount == 0 &&
- (style & SWT.WRAP) != 0 &&
- OS.IsWindowVisible (handle) &&
- OS.SendMessage (handle, OS.TB_GETROWS, 0, 0) != 1;
- if (fixRedraw) {
- rgn = OS.CreateRectRgn (0, 0, 0, 0);
- OS.GetUpdateRgn (handle, rgn, false);
- oldCount = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
- rects = new RECT [oldCount];
- for (int i=0; i<oldCount; i++) {
- rects [i] = new RECT ();
- OS.SendMessage (handle, OS.TB_GETITEMRECT, i, rects [i]);
- }
- }
-
- LRESULT result = super.WM_SIZE (wParam, lParam);
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the resize
- * event. If this happens, end the processing of the
- * Windows message by returning the result of the
- * WM_SIZE message.
- */
- if (isDisposed ()) return result;
-
- if (fixRedraw) {
- int newCount = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
- if (newCount == oldCount) {
- int index = 0;
- RECT rect = new RECT ();
- while (index < newCount) {
- OS.SendMessage (handle, OS.TB_GETITEMRECT, index, rect);
- if (!OS.EqualRect (rects [index], rect)) break;
- index++;
- }
- if (index == newCount) {
- OS.ValidateRect (handle, null);
- OS.InvalidateRgn (handle, rgn, false);
- }
- }
- OS.DeleteObject (rgn);
- }
-
- layoutItems ();
- return result;
-}
-
-LRESULT WM_WINDOWPOSCHANGING (int wParam, int lParam) {
- LRESULT result = super.WM_WINDOWPOSCHANGING (wParam, lParam);
- if (result != null) return result;
- /*
- * Feature in Windows. When a tool bar that contains
- * separators is wrapped, under certain circumstances,
- * Windows redraws the entire tool bar unnecessarily
- * when resized no item is moves. Whether the entire
- * toolbar is damaged or not seems to depend on the
- * size of the tool bar and the position of the separators.
- * The fix is to ensure that the newly exposed areas are
- * always damaged, and avoid the redraw when no tool item
- * moves.
- */
- if (drawCount != 0) return result;
- if ((style & SWT.WRAP) == 0) return result;
- if (!OS.IsWindowVisible (handle)) return result;
- if (OS.SendMessage (handle, OS.TB_GETROWS, 0, 0) == 1) {
- return result;
- }
- WINDOWPOS lpwp = new WINDOWPOS ();
- OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof);
- if ((lpwp.flags & (OS.SWP_NOSIZE | OS.SWP_NOREDRAW)) != 0) {
- return result;
- }
- RECT oldRect = new RECT ();
- OS.GetClientRect (handle, oldRect);
- RECT newRect = new RECT ();
- OS.SetRect (newRect, 0, 0, lpwp.cx, lpwp.cy);
- OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, newRect);
- int oldWidth = oldRect.right - oldRect.left;
- int oldHeight = oldRect.bottom - oldRect.top;
- int newWidth = newRect.right - newRect.left;
- int newHeight = newRect.bottom - newRect.top;
- if (newWidth > oldWidth) {
- /*
- * Bug in Windows. When a flat tool bar is wrapped,
- * Windows draws a horizontal separator between the
- * rows. The tool bar does not draw the first or
- * the last two pixels of this separator. When the
- * toolbar is resized to be bigger, only the new
- * area is drawn and the last two pixels, which are
- * blank are drawn over by separator. This leaves
- * garbage on the screen. The fix is to damage the
- * pixels.
- */
- RECT rect = new RECT ();
- OS.SetRect (rect, oldWidth - 2, 0, oldWidth, newHeight);
- OS.InvalidateRect (handle, rect, false);
- OS.SetRect (rect, oldRect.right, newRect.top, newRect.right, newRect.bottom);
- OS.InvalidateRect (handle, rect, true);
- }
- if (newHeight > oldHeight) {
- RECT rect = new RECT ();
- OS.SetRect (rect, newRect.left, oldRect.bottom, newRect.right, newRect.bottom);
- OS.InvalidateRect (handle, rect, true);
- }
- return result;
-}
-
-LRESULT wmCommandChild (int wParam, int lParam) {
- ToolItem child = items [wParam & 0xFFFF];
- if (child == null) return null;
- return child.wmCommandChild (wParam, lParam);
-}
-
-LRESULT wmNotifyChild (int wParam, int lParam) {
- NMHDR hdr = new NMHDR ();
- OS.MoveMemory (hdr, lParam, NMHDR.sizeof);
- switch (hdr.code) {
- case OS.TBN_DROPDOWN:
- NMTOOLBAR lpnmtb = new NMTOOLBAR ();
- OS.MoveMemory (lpnmtb, lParam, NMTOOLBAR.sizeof);
- ToolItem child = items [lpnmtb.iItem];
- if (child != null) {
- Event event = new Event ();
- event.detail = SWT.ARROW;
- int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, lpnmtb.iItem, 0);
- RECT rect = new RECT ();
- OS.SendMessage (handle, OS.TB_GETITEMRECT, index, rect);
- event.x = rect.left;
- event.y = rect.bottom;
- child.postEvent (SWT.Selection, event);
- return null;
- }
- break;
- }
- return super.wmNotifyChild (wParam, lParam);
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +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> + */ +public class ToolBar extends Composite { + int lastFocusId; + ToolItem [] items; + boolean ignoreResize; + ImageList imageList, disabledImageList, hotImageList; + static final int ToolBarProc; + static final TCHAR ToolBarClass = new TCHAR (0, OS.TOOLBARCLASSNAME, true); + static { + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, ToolBarClass, lpWndClass); + ToolBarProc = lpWndClass.lpfnWndProc; + } + + /* + * From the Windows SDK for TB_SETBUTTONSIZE: + * + * "If an application does not explicitly + * set the button size, the size defaults + * to 24 by 22 pixels". + */ + static final int DEFAULT_WIDTH = 24; + static final int DEFAULT_HEIGHT = 22; + +/** + * 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 callWindowProc (int msg, int wParam, int lParam) { + if (handle == 0) return 0; + /* + * Bug in Windows. For some reason, during the processing + * of WM_SYSCHAR, the tool bar window proc does not call the + * default window proc causing mnemonics for the menu bar + * to be ignored. The fix is to always call the default + * window proc for WM_SYSCHAR. + */ + if (msg == OS.WM_SYSCHAR) { + return OS.DefWindowProc (handle, msg, wParam, lParam); + } + return OS.CallWindowProc (ToolBarProc, handle, msg, wParam, lParam); +} + +static int checkStyle (int style) { + /* + * On Windows, only flat tool bars can be traversed. + */ + if ((style & SWT.FLAT) == 0) style |= SWT.NO_FOCUS; + + /* + * A vertical tool bar cannot wrap because TB_SETROWS + * fails when the toobar has TBSTYLE_WRAPABLE. + */ + /* + * This code is intentionally commented. + */ + //if ((style & SWT.VERTICAL) != 0) style &= ~SWT.WRAP; + + /* + * The TB_SETROWS calls are currently commented, so force + * the wrap style if this bar is vertical. + */ + if ((style & SWT.VERTICAL) != 0) style |= SWT.WRAP; + + /* + * 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 (); + if (layout != null) { + return super.computeSize (wHint, hHint, changed); + } + int width = 0, height = 0; + RECT oldRect = new RECT (); + OS.GetWindowRect (handle, oldRect); + int oldWidth = oldRect.right - oldRect.left; + int oldHeight = oldRect.bottom - oldRect.top; + int border = getBorderWidth (); + int newWidth = wHint == SWT.DEFAULT ? 0x3FFF : wHint + (border * 2); + int newHeight = hHint == SWT.DEFAULT ? 0x3FFF : hHint + (border * 2); + boolean redraw = drawCount == 0 && OS.IsWindowVisible (handle); + ignoreResize = true; + if (redraw) OS.UpdateWindow (handle); + int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOREDRAW | OS.SWP_NOZORDER; + OS.SetWindowPos (handle, 0, 0, 0, newWidth, newHeight, flags); + int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); + if (count != 0) { + RECT rect = new RECT (); + OS.SendMessage (handle, OS.TB_GETITEMRECT, count - 1, rect); + width = Math.max (width, rect.right); + height = Math.max (height, rect.bottom); + } + OS.SetWindowPos (handle, 0, 0, 0, oldWidth, oldHeight, flags); + if (redraw) OS.ValidateRect (handle, null); + ignoreResize = false; + + /* + * From the Windows SDK for TB_SETBUTTONSIZE: + * + * "If an application does not explicitly + * set the button size, the size defaults + * to 24 by 22 pixels". + */ + 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) { + checkWidget (); + Rectangle trim = super.computeTrim (x, y, width, height); + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & OS.CCS_NODIVIDER) == 0) trim.height += 2; + return trim; +} + +void createHandle () { + super.createHandle (); + state &= ~CANVAS; + + /* + * Feature in Windows. When TBSTYLE_FLAT is used to create + * a flat toolbar, for some reason TBSTYLE_TRANSPARENT is + * also set. This causes the toolbar to flicker when it is + * moved or resized. The fix is to clear TBSTYLE_TRANSPARENT. + * + * NOTE: This work around is unnecessary on XP. There is no + * flickering and clearing the TBSTYLE_TRANSPARENT interferes + * with the XP theme. + */ + if (COMCTL32_MAJOR < 6) { + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + bits &= ~OS.TBSTYLE_TRANSPARENT; + OS.SetWindowLong (handle, OS.GWL_STYLE, bits); + } + + /* + * Feature in Windows. Despite the fact that the + * tool tip text contains \r\n, the tooltip will + * not honour the new line unless TTM_SETMAXTIPWIDTH + * is set. The fix is to set TTM_SETMAXTIPWIDTH to + * a large value. + */ + /* + * These lines are intentionally commented. The tool + * bar currently sets this value to 300 so it is not + * necessary to set TTM_SETMAXTIPWIDTH. + */ +// int hwndToolTip = OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0); +// OS.SendMessage (hwndToolTip, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF); + + /* + * Feature in Windows. When the control is created, + * it does not use the default system font. A new HFONT + * is created and destroyed when the control is destroyed. + * This means that a program that queries the font from + * this control, uses the font in another control and then + * destroys this control will have the font unexpectedly + * destroyed in the other control. The fix is to assign + * the font ourselves each time the control is created. + * The control will not destroy a font that it did not + * create. + */ + int hFont = OS.GetStockObject (OS.SYSTEM_FONT); + OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0); + + /* Set the button struct, bitmap and button sizes */ + OS.SendMessage (handle, OS.TB_BUTTONSTRUCTSIZE, TBBUTTON.sizeof, 0); + OS.SendMessage (handle, OS.TB_SETBITMAPSIZE, 0, 0); + OS.SendMessage (handle, OS.TB_SETBUTTONSIZE, 0, 0); + + /* Set the extended style bits */ + OS.SendMessage (handle, OS.TB_SETEXTENDEDSTYLE, 0, OS.TBSTYLE_EX_DRAWDDARROWS); +} + +void createItem (ToolItem item, int index) { + int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); + if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE); + int id = 0; + while (id < items.length && items [id] != null) id++; + if (id == items.length) { + ToolItem [] newItems = new ToolItem [items.length + 4]; + System.arraycopy (items, 0, newItems, 0, items.length); + items = newItems; + } + int bits = item.widgetStyle (); + TBBUTTON lpButton = new TBBUTTON (); + lpButton.idCommand = id; + lpButton.fsStyle = (byte) bits; + lpButton.fsState = (byte) OS.TBSTATE_ENABLED; + + /* + * Bug in Windows. Despite the fact that the image list + * index has never been set for the item, Windows always + * assumes that the image index for the item is valid. + * When an item is inserted, the image index is zero. + * Therefore, when the first image is inserted and is + * assigned image index zero, every item draws with this + * image. The fix is to set the image index to none + * when the item is created. This is not necessary in + * the case when the item has the BTNS_SEP style because + * separators cannot show images. + */ + if ((bits & OS.BTNS_SEP) == 0) lpButton.iBitmap = OS.I_IMAGENONE; + if (OS.SendMessage (handle, OS.TB_INSERTBUTTON, index, lpButton) == 0) { + error (SWT.ERROR_ITEM_NOT_ADDED); + } + items [item.id = id] = item; + /* + * This code is intentionally commented. + */ +// if ((style & SWT.VERTICAL) != 0) { +// OS.SendMessage (handle, OS.TB_SETROWS, count+1, 0); +// } + layoutItems (); +} + +void createWidget () { + super.createWidget (); + items = new ToolItem [4]; + lastFocusId = -1; +} + +int defaultBackground () { + if (OS.IsWinCE) return OS.GetSysColor (OS.COLOR_BTNFACE); + return super.defaultBackground (); +} + +void destroyItem (ToolItem item) { + TBBUTTONINFO info = new TBBUTTONINFO (); + info.cbSize = TBBUTTONINFO.sizeof; + info.dwMask = OS.TBIF_IMAGE | OS.TBIF_STYLE; + int index = OS.SendMessage (handle, OS.TB_GETBUTTONINFO, item.id, info); + /* + * Feature in Windows. For some reason, a tool item that has + * the style BTNS_SEP does not return I_IMAGENONE when queried + * for an image index, despite the fact that no attempt has been + * made to assign an image to the item. As a result, operations + * on an image list that use the wrong index cause random results. + * The fix is to ensure that the tool item is not a separator + * before using the image index. Since separators cannot have + * an image and one is never assigned, this is not a problem. + */ + if ((info.fsStyle & OS.BTNS_SEP) == 0 && info.iImage != OS.I_IMAGENONE) { + if (imageList != null) imageList.put (info.iImage, null); + if (hotImageList != null) hotImageList.put (info.iImage, null); + if (disabledImageList != null) disabledImageList.put (info.iImage, null); + } + OS.SendMessage (handle, OS.TB_DELETEBUTTON, index, 0); + if (item.id == lastFocusId) lastFocusId = -1; + items [item.id] = null; + item.id = -1; + int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); + if (count == 0) { + Display display = getDisplay (); + if (imageList != null) { + OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0); + display.releaseToolImageList (imageList); + } + if (hotImageList != null) { + OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, 0); + display.releaseToolHotImageList (hotImageList); + } + if (disabledImageList != null) { + OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, 0); + display.releaseToolDisabledImageList (disabledImageList); + } + imageList = hotImageList = disabledImageList = null; + items = new ToolItem [4]; + } + /* + * This code is intentionally commented. + */ +// if ((style & SWT.VERTICAL) != 0) { +// OS.SendMessage (handle, OS.TB_SETROWS, count-1, 0); +// } + layoutItems (); +} + +ImageList getDisabledImageList () { + return disabledImageList; +} + +ImageList getHotImageList () { + return hotImageList; +} + +ImageList getImageList () { + return imageList; +} + +/** + * 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 (); + int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); + if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE); + TBBUTTON lpButton = new TBBUTTON (); + int result = OS.SendMessage (handle, OS.TB_GETBUTTON, index, lpButton); + if (result == 0) error (SWT.ERROR_CANNOT_GET_ITEM); + return items [lpButton.idCommand]; +} + +/** + * 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 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> + */ +public ToolItem getItem (Point point) { + checkWidget (); + if (point == null) error (SWT.ERROR_NULL_ARGUMENT); + ToolItem [] items = getItems (); + for (int i=0; i<items.length; i++) { + Rectangle rect = items [i].getBounds (); + if (rect.contains (point)) 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 OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); +} + +/** + * 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 ToolItem [] getItems () { + checkWidget (); + int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); + TBBUTTON lpButton = new TBBUTTON (); + ToolItem [] result = new ToolItem [count]; + for (int i=0; i<count; i++) { + OS.SendMessage (handle, OS.TB_GETBUTTON, i, lpButton); + result [i] = items [lpButton.idCommand]; + } + 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 (); + return OS.SendMessage (handle, OS.TB_GETROWS, 0, 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); + return OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, item.id, 0); +} + +void layoutItems () { + for (int i=0; i<items.length; i++) { + ToolItem item = items [i]; + if (item != null) item.resizeControl (); + } +} + +boolean mnemonicHit (char ch) { + int key = wcsToMbcs (ch); + int [] id = new int [1]; + if (OS.SendMessage (handle, OS.TB_MAPACCELERATOR, key, id) == 0) { + return false; + } + if (!setTabGroupFocus ()) return false; + int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, id [0], 0); + if (index == -1) return false; + OS.SendMessage (handle, OS.TB_SETHOTITEM, index, 0); + items [id [0]].click (false); + return true; +} + +boolean mnemonicMatch (char ch) { + int key = wcsToMbcs (ch); + int [] id = new int [1]; + return OS.SendMessage (handle, OS.TB_MAPACCELERATOR, key, id) != 0; +} + +void releaseWidget () { + for (int i=0; i<items.length; i++) { + ToolItem item = items [i]; + if (item != null && !item.isDisposed ()) { + item.releaseImages (); + item.releaseResources (); + } + } + items = null; + Display display = getDisplay (); + if (imageList != null) { + OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0); + display.releaseToolImageList (imageList); + } + if (hotImageList != null) { + OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, 0); + display.releaseToolHotImageList (hotImageList); + } + if (disabledImageList != null) { + OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, 0); + display.releaseToolDisabledImageList (disabledImageList); + } + imageList = hotImageList = disabledImageList = null; + super.releaseWidget (); +} + +void setBounds (int x, int y, int width, int height, int flags) { + /* + * Feature in Windows. For some reason, when a tool bar is + * repositioned more than once using DeferWindowPos () into + * the same HDWP, the toolbar redraws more than once, defeating + * the puropse of DeferWindowPos (). The fix is to end the + * defered positioning before the next tool bar is added, + * ensuring that only one tool bar position is deferred at + * any given time. + */ + if (parent.lpwp != null) { + if (drawCount == 0 && OS.IsWindowVisible (handle)) { + parent.setResizeChildren (false); + parent.setResizeChildren (true); + } + } + super.setBounds (x, y, width, height, flags); +} + +void setDefaultFont () { + super.setDefaultFont (); + OS.SendMessage (handle, OS.TB_SETBITMAPSIZE, 0, 0); + OS.SendMessage (handle, OS.TB_SETBUTTONSIZE, 0, 0); +} + +void setDisabledImageList (ImageList imageList) { + if (disabledImageList == imageList) return; + int hImageList = 0; + if ((disabledImageList = imageList) != null) { + hImageList = disabledImageList.getHandle (); + } + OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, hImageList); +} + +void setHotImageList (ImageList imageList) { + if (hotImageList == imageList) return; + int hImageList = 0; + if ((hotImageList = imageList) != null) { + hImageList = hotImageList.getHandle (); + } + OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, hImageList); +} + +void setImageList (ImageList imageList) { + if (this.imageList == imageList) return; + int hImageList = 0; + if ((this.imageList = imageList) != null) { + hImageList = imageList.getHandle (); + } + OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, hImageList); +} + +boolean setTabItemFocus () { + int index = 0; + while (index < items.length) { + ToolItem item = items [index]; + if (item != null && (item.style & SWT.SEPARATOR) == 0) { + if (item.getEnabled ()) break; + } + index++; + } + if (index == items.length) return false; + return super.setTabItemFocus (); +} + +String toolTipText (NMTTDISPINFO hdr) { + if ((hdr.uFlags & OS.TTF_IDISHWND) != 0) { + return null; + } + int index = hdr.idFrom; + int hwndToolTip = OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0); + if (hwndToolTip == hdr.hwndFrom) { + if (toolTipText != null) return ""; + if (0 <= index && index < items.length) { + ToolItem item = items [index]; + if (item != null) return item.toolTipText; + } + } + return super.toolTipText (hdr); +} + +int widgetStyle () { + int bits = super.widgetStyle () | OS.CCS_NORESIZE | OS.TBSTYLE_TOOLTIPS; + if ((style & SWT.SHADOW_OUT) == 0) bits |= OS.CCS_NODIVIDER; + if ((style & SWT.WRAP) != 0) bits |= OS.TBSTYLE_WRAPABLE; + if ((style & SWT.FLAT) != 0) bits |= OS.TBSTYLE_FLAT; + if ((style & SWT.RIGHT) != 0) bits |= OS.TBSTYLE_LIST; + return bits; +} + +TCHAR windowClass () { + return ToolBarClass; +} + +int windowProc () { + return ToolBarProc; +} + +LRESULT WM_GETDLGCODE (int wParam, int lParam) { + LRESULT result = super.WM_GETDLGCODE (wParam, lParam); + /* + * Return DLGC_BUTTON so that mnemonics will be + * processed without needing to press the ALT key + * when the widget has focus. + */ + if (result != null) return result; + return new LRESULT (OS.DLGC_BUTTON); +} + +LRESULT WM_COMMAND (int wParam, int lParam) { + /* + * Feature in Windows. When the toolbar window + * proc processes WM_COMMAND, it forwards this + * message to its parent. This is done so that + * children of this control that send this message + * type to their parent will notify not only + * this control but also the parent of this control, + * which is typically the application window and + * the window that is looking for the message. + * If the control did not forward the message, + * applications would have to subclass the control + * window to see the message. Because the control + * window is subclassed by SWT, the message + * is delivered twice, once by SWT and once when + * the message is forwarded by the window proc. + * The fix is to avoid calling the window proc + * for this control. + */ + LRESULT result = super.WM_COMMAND (wParam, lParam); + if (result != null) return result; + return LRESULT.ZERO; +} + +LRESULT WM_KEYDOWN (int wParam, int lParam) { + LRESULT result = super.WM_KEYDOWN (wParam, lParam); + if (result != null) return result; + switch (wParam) { + case OS.VK_RETURN: + case OS.VK_SPACE: + int index = OS.SendMessage (handle, OS.TB_GETHOTITEM, 0, 0); + if (index != -1) { + TBBUTTON lpButton = new TBBUTTON (); + int code = OS.SendMessage (handle, OS.TB_GETBUTTON, index, lpButton); + if (code != 0) { + items [lpButton.idCommand].click (wParam == OS.VK_RETURN); + return LRESULT.ZERO; + } + } + } + return result; +} + +LRESULT WM_KILLFOCUS (int wParam, int lParam) { + int index = OS.SendMessage (handle, OS.TB_GETHOTITEM, 0, 0); + TBBUTTON lpButton = new TBBUTTON (); + int code = OS.SendMessage (handle, OS.TB_GETBUTTON, index, lpButton); + if (code != 0) lastFocusId = lpButton.idCommand; + return super.WM_KILLFOCUS (wParam, lParam); +} + +LRESULT WM_NOTIFY (int wParam, int lParam) { + /* + * Feature in Windows. When the toolbar window + * proc processes WM_NOTIFY, it forwards this + * message to its parent. This is done so that + * children of this control that send this message + * type to their parent will notify not only + * this control but also the parent of this control, + * which is typically the application window and + * the window that is looking for the message. + * If the control did not forward the message, + * applications would have to subclass the control + * window to see the message. Because the control + * window is subclassed by SWT, the message + * is delivered twice, once by SWT and once when + * the message is forwarded by the window proc. + * The fix is to avoid calling the window proc + * for this control. + */ + LRESULT result = super.WM_NOTIFY (wParam, lParam); + if (result != null) return result; + return LRESULT.ZERO; +} + +LRESULT WM_SETFOCUS (int wParam, int lParam) { + LRESULT result = super.WM_SETFOCUS (wParam, lParam); + if (lastFocusId != -1 && handle == OS.GetFocus ()) { + int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, lastFocusId, 0); + OS.SendMessage (handle, OS.TB_SETHOTITEM, index, 0); + } + return result; +} + +LRESULT WM_SIZE (int wParam, int lParam) { + if (ignoreResize) { + int code = callWindowProc (OS.WM_SIZE, wParam, lParam); + if (code == 0) return LRESULT.ZERO; + return new LRESULT (code); + } + /* + * Feature in Windows. When a tool bar that contains + * separators is wrapped, under certain circumstances, + * Windows redraws the entire tool bar unnecessarily + * when resized no item is moves. Whether the entire + * toolbar is damaged or not seems to depend on the + * size of the tool bar and the position of the separators. + * The fix is to ensure that the newly exposed areas are + * always damaged, and avoid the redraw when no tool item + * moves. + */ + RECT [] rects = null; + int rgn = 0, oldCount = 0; + boolean fixRedraw = drawCount == 0 && + (style & SWT.WRAP) != 0 && + OS.IsWindowVisible (handle) && + OS.SendMessage (handle, OS.TB_GETROWS, 0, 0) != 1; + if (fixRedraw) { + rgn = OS.CreateRectRgn (0, 0, 0, 0); + OS.GetUpdateRgn (handle, rgn, false); + oldCount = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); + rects = new RECT [oldCount]; + for (int i=0; i<oldCount; i++) { + rects [i] = new RECT (); + OS.SendMessage (handle, OS.TB_GETITEMRECT, i, rects [i]); + } + } + + LRESULT result = super.WM_SIZE (wParam, lParam); + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the resize + * event. If this happens, end the processing of the + * Windows message by returning the result of the + * WM_SIZE message. + */ + if (isDisposed ()) return result; + + if (fixRedraw) { + int newCount = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); + if (newCount == oldCount) { + int index = 0; + RECT rect = new RECT (); + while (index < newCount) { + OS.SendMessage (handle, OS.TB_GETITEMRECT, index, rect); + if (!OS.EqualRect (rects [index], rect)) break; + index++; + } + if (index == newCount) { + OS.ValidateRect (handle, null); + OS.InvalidateRgn (handle, rgn, false); + } + } + OS.DeleteObject (rgn); + } + + layoutItems (); + return result; +} + +LRESULT WM_WINDOWPOSCHANGING (int wParam, int lParam) { + LRESULT result = super.WM_WINDOWPOSCHANGING (wParam, lParam); + if (result != null) return result; + /* + * Feature in Windows. When a tool bar that contains + * separators is wrapped, under certain circumstances, + * Windows redraws the entire tool bar unnecessarily + * when resized no item is moves. Whether the entire + * toolbar is damaged or not seems to depend on the + * size of the tool bar and the position of the separators. + * The fix is to ensure that the newly exposed areas are + * always damaged, and avoid the redraw when no tool item + * moves. + */ + if (drawCount != 0) return result; + if ((style & SWT.WRAP) == 0) return result; + if (!OS.IsWindowVisible (handle)) return result; + if (OS.SendMessage (handle, OS.TB_GETROWS, 0, 0) == 1) { + return result; + } + WINDOWPOS lpwp = new WINDOWPOS (); + OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof); + if ((lpwp.flags & (OS.SWP_NOSIZE | OS.SWP_NOREDRAW)) != 0) { + return result; + } + RECT oldRect = new RECT (); + OS.GetClientRect (handle, oldRect); + RECT newRect = new RECT (); + OS.SetRect (newRect, 0, 0, lpwp.cx, lpwp.cy); + OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, newRect); + int oldWidth = oldRect.right - oldRect.left; + int oldHeight = oldRect.bottom - oldRect.top; + int newWidth = newRect.right - newRect.left; + int newHeight = newRect.bottom - newRect.top; + if (newWidth > oldWidth) { + /* + * Bug in Windows. When a flat tool bar is wrapped, + * Windows draws a horizontal separator between the + * rows. The tool bar does not draw the first or + * the last two pixels of this separator. When the + * toolbar is resized to be bigger, only the new + * area is drawn and the last two pixels, which are + * blank are drawn over by separator. This leaves + * garbage on the screen. The fix is to damage the + * pixels. + */ + RECT rect = new RECT (); + OS.SetRect (rect, oldWidth - 2, 0, oldWidth, newHeight); + OS.InvalidateRect (handle, rect, false); + OS.SetRect (rect, oldRect.right, newRect.top, newRect.right, newRect.bottom); + OS.InvalidateRect (handle, rect, true); + } + if (newHeight > oldHeight) { + RECT rect = new RECT (); + OS.SetRect (rect, newRect.left, oldRect.bottom, newRect.right, newRect.bottom); + OS.InvalidateRect (handle, rect, true); + } + return result; +} + +LRESULT wmCommandChild (int wParam, int lParam) { + ToolItem child = items [wParam & 0xFFFF]; + if (child == null) return null; + return child.wmCommandChild (wParam, lParam); +} + +LRESULT wmNotifyChild (int wParam, int lParam) { + NMHDR hdr = new NMHDR (); + OS.MoveMemory (hdr, lParam, NMHDR.sizeof); + switch (hdr.code) { + case OS.TBN_DROPDOWN: + NMTOOLBAR lpnmtb = new NMTOOLBAR (); + OS.MoveMemory (lpnmtb, lParam, NMTOOLBAR.sizeof); + ToolItem child = items [lpnmtb.iItem]; + if (child != null) { + Event event = new Event (); + event.detail = SWT.ARROW; + int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, lpnmtb.iItem, 0); + RECT rect = new RECT (); + OS.SendMessage (handle, OS.TB_GETITEMRECT, index, rect); + event.x = rect.left; + event.y = rect.bottom; + child.postEvent (SWT.Selection, event); + return null; + } + break; + } + return super.wmNotifyChild (wParam, lParam); +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java index 38602b3a35..be3712770d 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java @@ -1,831 +1,831 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-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 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>
- */
-public class ToolItem extends Item {
- ToolBar parent;
- Control control;
- String toolTipText;
- Image disabledImage, hotImage;
- Image disabledImage2;
- int id;
-
-/**
- * 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 index to store the receiver in its parent
- *
- * @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, 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 selected, 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
- *
- * @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);
-}
-
-void click (boolean dropDown) {
- /*
- * In order to emulate all the processing that
- * happens when a mnemonic key is pressed, fake
- * a mouse press and release. This will ensure
- * that radio and pull down items are handled
- * properly.
- */
- int hwnd = parent.handle;
- if (OS.GetKeyState (OS.VK_LBUTTON) < 0) return;
- int index = OS.SendMessage (hwnd, OS.TB_COMMANDTOINDEX, id, 0);
- RECT rect = new RECT ();
- OS.SendMessage (hwnd, OS.TB_GETITEMRECT, index, rect);
- int lParam = (dropDown ? rect.right - 1 : rect.left) | (rect.top << 16);
- int hotIndex = OS.SendMessage (hwnd, OS.TB_GETHOTITEM, 0, 0);
- OS.SendMessage (hwnd, OS.WM_LBUTTONDOWN, 0, lParam);
- OS.SendMessage (hwnd, OS.WM_LBUTTONUP, 0, lParam);
- if (hotIndex != -1) {
- OS.SendMessage (hwnd, OS.TB_SETHOTITEM, hotIndex, 0);
- }
-}
-
-Image createDisabledImage (Image image, Color color) {
- Display display = getDisplay ();
- if (OS.IsWinCE) {
- return new Image (display, image, SWT.IMAGE_DISABLE);
- }
- Rectangle rect = image.getBounds ();
- Image disabled = new Image (display, rect);
- GC gc = new GC (disabled);
- gc.setBackground (color);
- gc.fillRectangle (rect);
- int hDC = gc.handle;
- int hImage = image.handle;
- int fuFlags = OS.DSS_DISABLED;
- switch (image.type) {
- case SWT.BITMAP: fuFlags |= OS.DST_BITMAP; break;
- case SWT.ICON: fuFlags |= OS.DST_ICON; break;
- }
- OS.DrawState (hDC, 0, 0, hImage, 0, 0, 0, rect.width, rect.height, fuFlags);
- gc.dispose ();
- return disabled;
-}
-
-/**
- * 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();
- int hwnd = parent.handle;
- int index = OS.SendMessage (hwnd, OS.TB_COMMANDTOINDEX, id, 0);
- RECT rect = new RECT ();
- OS.SendMessage (hwnd, OS.TB_GETITEMRECT, index, rect);
- int width = rect.right - rect.left;
- int height = rect.bottom - rect.top;
- return new Rectangle (rect.left, rect.top, width, height);
-}
-
-/**
- * Returns the control that is used to fill the bounds of
- * the item when the items 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;
-}
-
-public Display getDisplay () {
- ToolBar parent = this.parent;
- if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED);
- return parent.getDisplay ();
-}
-
-/**
- * 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();
- int hwnd = parent.handle;
- int fsState = OS.SendMessage (hwnd, OS.TB_GETSTATE, id, 0);
- return (fsState & OS.TBSTATE_ENABLED) != 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;
- int hwnd = parent.handle;
- int fsState = OS.SendMessage (hwnd, OS.TB_GETSTATE, id, 0);
- return (fsState & OS.TBSTATE_CHECKED) != 0;
-}
-
-/**
- * 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();
- int hwnd = parent.handle;
- int index = OS.SendMessage (hwnd, OS.TB_COMMANDTOINDEX, id, 0);
- RECT rect = new RECT ();
- OS.SendMessage (hwnd, OS.TB_GETITEMRECT, index, rect);
- return rect.right - rect.left;
-}
-
-/**
- * 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 ();
-}
-
-void releaseChild () {
- super.releaseChild ();
- parent.destroyItem (this);
-}
-
-void releaseWidget () {
- super.releaseWidget ();
- parent = null;
- control = null;
- toolTipText = null;
- disabledImage = hotImage = null;
- if (disabledImage2 != null) disabledImage2.dispose ();
- disabledImage2 = null;
-}
-
-void releaseImages () {
- TBBUTTONINFO info = new TBBUTTONINFO ();
- info.cbSize = TBBUTTONINFO.sizeof;
- info.dwMask = OS.TBIF_IMAGE | OS.TBIF_STYLE;
- int hwnd = parent.handle;
- OS.SendMessage (hwnd, OS.TB_GETBUTTONINFO, id, info);
- /*
- * Feature in Windows. For some reason, a tool item that has
- * the style BTNS_SEP does not return I_IMAGENONE when queried
- * for an image index, despite the fact that no attempt has been
- * made to assign an image to the item. As a result, operations
- * on an image list that use the wrong index cause random results.
- * The fix is to ensure that the tool item is not a separator
- * before using the image index. Since separators cannot have
- * an image and one is never assigned, this is not a problem.
- */
- if ((info.fsStyle & OS.BTNS_SEP) == 0 && info.iImage != OS.I_IMAGENONE) {
- ImageList imageList = parent.getImageList ();
- ImageList hotImageList = parent.getHotImageList ();
- ImageList disabledImageList = parent.getDisabledImageList();
- if (imageList != null) imageList.put (info.iImage, null);
- if (hotImageList != null) hotImageList.put (info.iImage, null);
- if (disabledImageList != null) disabledImageList.put (info.iImage, null);
- }
-}
-
-/**
- * Removes the listener from the collection of listeners who will
- * be notified when the control is selected.
- *
- * @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 #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 resizeControl () {
- if (control != null && !control.isDisposed ()) {
- /*
- * Set the size and location of the control
- * separately to minimize flashing in the
- * case where the control does not resize
- * to the size that was requested. This
- * case can occur when the control is a
- * combo box.
- */
- Rectangle itemRect = getBounds ();
- control.setSize (itemRect.width, itemRect.height);
- Rectangle rect = control.getBounds ();
- rect.x = itemRect.x + (itemRect.width - rect.width) / 2;
- rect.y = itemRect.y + (itemRect.height - rect.height) / 2;
- control.setLocation (rect.x, rect.y);
- }
-}
-
-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);
-}
-
-/**
- * Sets the control that is used to fill the bounds of
- * the item when the items 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;
- this.control = control;
- resizeControl ();
-}
-
-/**
- * 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();
- int hwnd = parent.handle;
- int fsState = OS.SendMessage (hwnd, OS.TB_GETSTATE, id, 0);
- fsState &= ~OS.TBSTATE_ENABLED;
- if (enabled) fsState |= OS.TBSTATE_ENABLED;
- OS.SendMessage (hwnd, OS.TB_SETSTATE, id, fsState);
- if (image != null) updateImages ();
-}
-
-/**
- * Sets the receiver's disabled image to the argument, which may be
- * null indicating that no disabled image should be displayed.
- * <p>
- * The disbled 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 ((style & SWT.SEPARATOR) != 0) return;
- if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
- disabledImage = image;
- updateImages ();
-}
-
-/**
- * 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 ((style & SWT.SEPARATOR) != 0) return;
- if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
- hotImage = image;
- updateImages ();
-}
-
-public void setImage (Image image) {
- checkWidget();
- if ((style & SWT.SEPARATOR) != 0) return;
- if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
- super.setImage (image);
- updateImages ();
-}
-
-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;
- int hwnd = parent.handle;
- int fsState = OS.SendMessage (hwnd, OS.TB_GETSTATE, id, 0);
- fsState &= ~OS.TBSTATE_CHECKED;
- if (selected) fsState |= OS.TBSTATE_CHECKED;
- OS.SendMessage (hwnd, OS.TB_SETSTATE, id, fsState);
-}
-/**
- * Sets the receiver's text. The string may include
- * the mnemonic character.
- * </p>
- * <p>
- * Mnemonics are indicated by an '&' 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 '&' can be
- * escaped by doubling it in the string, causing a single
- *'&' 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);
- int hwnd = parent.handle;
- int hHeap = OS.GetProcessHeap ();
- TCHAR buffer = new TCHAR (parent.getCodePage (), string, true);
- int byteCount = buffer.length () * TCHAR.sizeof;
- int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- OS.MoveMemory (pszText, buffer, byteCount);
- TBBUTTONINFO info = new TBBUTTONINFO ();
- info.cbSize = TBBUTTONINFO.sizeof;
- info.dwMask = OS.TBIF_TEXT | OS.TBIF_STYLE;
- info.pszText = pszText;
- info.fsStyle = (byte) (widgetStyle () | OS.BTNS_AUTOSIZE);
- OS.SendMessage (hwnd, OS.TB_SETBUTTONINFO, id, info);
- OS.HeapFree (hHeap, 0, pszText);
-
- /*
- * Bug in Windows. For some reason, when the font is set
- * before any tool item has text, the tool items resize to
- * a very small size. Also, a tool item will only show text
- * when text has already been set on one item and then a new
- * item is created. The fix is to use WM_SETFONT to force
- * the tool bar to redraw and layout. [1G0G7TV, 1G0FUJ5]
- */
- int hFont = OS.SendMessage (hwnd, OS.WM_GETFONT, 0, 0);
- OS.SendMessage (hwnd, OS.WM_SETFONT, hFont, 0);
-
- parent.layoutItems ();
-}
-
-/**
- * Sets the receiver's tool tip text to the argument, which
- * may be null indicating that no tool tip text should be shown.
- *
- * @param string the new tool tip text (or null)
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if 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;
-}
-
-/**
- * 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 ((style & SWT.SEPARATOR) == 0) return;
- if (width < 0) return;
- int hwnd = parent.handle;
- TBBUTTONINFO info = new TBBUTTONINFO ();
- info.cbSize = TBBUTTONINFO.sizeof;
- info.dwMask = OS.TBIF_SIZE;
- info.cx = (short) width;
- OS.SendMessage (hwnd, OS.TB_SETBUTTONINFO, id, info);
- parent.layoutItems ();
-}
-
-void updateImages () {
- int hwnd = parent.handle;
- TBBUTTONINFO info = new TBBUTTONINFO ();
- info.cbSize = TBBUTTONINFO.sizeof;
- info.dwMask = OS.TBIF_IMAGE;
- OS.SendMessage (hwnd, OS.TB_GETBUTTONINFO, id, info);
- if (info.iImage == OS.I_IMAGENONE && image == null) return;
- ImageList imageList = parent.getImageList ();
- ImageList hotImageList = parent.getHotImageList ();
- ImageList disabledImageList = parent.getDisabledImageList();
- if (info.iImage == OS.I_IMAGENONE) {
- Display display = getDisplay ();
- Rectangle bounds = image.getBounds ();
- Point size = new Point (bounds.width, bounds.height);
- if (imageList == null) imageList = display.getToolImageList (size);
- info.iImage = imageList.add (image);
- parent.setImageList (imageList);
- if (disabledImageList == null) disabledImageList = display.getToolDisabledImageList (size);
- Image disabled = disabledImage;
- if (disabledImage == null) {
- if (disabledImage2 != null) disabledImage2.dispose ();
- disabledImage2 = null;
- disabled = image;
- if (!getEnabled ()) {
- Color color = parent.getBackground ();
- disabled = disabledImage2 = createDisabledImage (image, color);
- }
- }
- disabledImageList.add (disabled);
- parent.setDisabledImageList (disabledImageList);
-// if ((parent.style & SWT.FLAT) != 0) {
- if (hotImageList == null) hotImageList = display.getToolHotImageList (size);
- hotImageList.add (hotImage != null ? hotImage : image);
- parent.setHotImageList (hotImageList);
-// }
- } else {
- if (imageList != null) imageList.put (info.iImage, image);
- if (disabledImageList != null) {
- Image disabled = null;
- if (image != null) {
- if (disabledImage2 != null) disabledImage2.dispose ();
- disabledImage2 = null;
- disabled = disabledImage;
- if (disabledImage == null) {
- disabled = image;
- if (!getEnabled ()) {
- Color color = parent.getBackground ();
- disabled = disabledImage2 = createDisabledImage (image, color);
- }
- }
- }
- disabledImageList.put (info.iImage, disabled);
- }
- if (hotImageList != null) {
- Image hot = null;
- if (image != null) hot = hotImage != null ? hotImage : image;
- hotImageList.put (info.iImage, hot);
- }
- if (image == null) info.iImage = OS.I_IMAGENONE;
- }
- OS.SendMessage (hwnd, OS.TB_SETBUTTONINFO, id, info);
-
- parent.layoutItems ();
-}
-
-int widgetStyle () {
- if ((style & SWT.DROP_DOWN) != 0) return OS.BTNS_DROPDOWN;
- if ((style & SWT.PUSH) != 0) return OS.BTNS_BUTTON;
- if ((style & SWT.CHECK) != 0) return OS.BTNS_CHECK;
- /*
- * This code is intentionally commented. In order to
- * consistently support radio tool items across platforms,
- * the platform radio behavior is not used.
- */
-// if ((style & SWT.RADIO) != 0) return OS.BTNS_CHECKGROUP;
- if ((style & SWT.RADIO) != 0) return OS.BTNS_CHECK;
- if ((style & SWT.SEPARATOR) != 0) return OS.BTNS_SEP;
- return OS.BTNS_BUTTON;
-}
-
-LRESULT wmCommandChild (int wParam, int lParam) {
- if ((style & SWT.RADIO) != 0) {
- if ((parent.getStyle () & SWT.NO_RADIO_GROUP) == 0) {
- selectRadio ();
- }
- }
- Event event = new Event ();
- setInputState (event, SWT.Selection);
- postEvent (SWT.Selection, event);
- return null;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +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 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> + */ +public class ToolItem extends Item { + ToolBar parent; + Control control; + String toolTipText; + Image disabledImage, hotImage; + Image disabledImage2; + int id; + +/** + * 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 index to store the receiver in its parent + * + * @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, 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 selected, 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 + * + * @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); +} + +void click (boolean dropDown) { + /* + * In order to emulate all the processing that + * happens when a mnemonic key is pressed, fake + * a mouse press and release. This will ensure + * that radio and pull down items are handled + * properly. + */ + int hwnd = parent.handle; + if (OS.GetKeyState (OS.VK_LBUTTON) < 0) return; + int index = OS.SendMessage (hwnd, OS.TB_COMMANDTOINDEX, id, 0); + RECT rect = new RECT (); + OS.SendMessage (hwnd, OS.TB_GETITEMRECT, index, rect); + int lParam = (dropDown ? rect.right - 1 : rect.left) | (rect.top << 16); + int hotIndex = OS.SendMessage (hwnd, OS.TB_GETHOTITEM, 0, 0); + OS.SendMessage (hwnd, OS.WM_LBUTTONDOWN, 0, lParam); + OS.SendMessage (hwnd, OS.WM_LBUTTONUP, 0, lParam); + if (hotIndex != -1) { + OS.SendMessage (hwnd, OS.TB_SETHOTITEM, hotIndex, 0); + } +} + +Image createDisabledImage (Image image, Color color) { + Display display = getDisplay (); + if (OS.IsWinCE) { + return new Image (display, image, SWT.IMAGE_DISABLE); + } + Rectangle rect = image.getBounds (); + Image disabled = new Image (display, rect); + GC gc = new GC (disabled); + gc.setBackground (color); + gc.fillRectangle (rect); + int hDC = gc.handle; + int hImage = image.handle; + int fuFlags = OS.DSS_DISABLED; + switch (image.type) { + case SWT.BITMAP: fuFlags |= OS.DST_BITMAP; break; + case SWT.ICON: fuFlags |= OS.DST_ICON; break; + } + OS.DrawState (hDC, 0, 0, hImage, 0, 0, 0, rect.width, rect.height, fuFlags); + gc.dispose (); + return disabled; +} + +/** + * 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(); + int hwnd = parent.handle; + int index = OS.SendMessage (hwnd, OS.TB_COMMANDTOINDEX, id, 0); + RECT rect = new RECT (); + OS.SendMessage (hwnd, OS.TB_GETITEMRECT, index, rect); + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + return new Rectangle (rect.left, rect.top, width, height); +} + +/** + * Returns the control that is used to fill the bounds of + * the item when the items 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; +} + +public Display getDisplay () { + ToolBar parent = this.parent; + if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED); + return parent.getDisplay (); +} + +/** + * 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(); + int hwnd = parent.handle; + int fsState = OS.SendMessage (hwnd, OS.TB_GETSTATE, id, 0); + return (fsState & OS.TBSTATE_ENABLED) != 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; + int hwnd = parent.handle; + int fsState = OS.SendMessage (hwnd, OS.TB_GETSTATE, id, 0); + return (fsState & OS.TBSTATE_CHECKED) != 0; +} + +/** + * 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(); + int hwnd = parent.handle; + int index = OS.SendMessage (hwnd, OS.TB_COMMANDTOINDEX, id, 0); + RECT rect = new RECT (); + OS.SendMessage (hwnd, OS.TB_GETITEMRECT, index, rect); + return rect.right - rect.left; +} + +/** + * 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 (); +} + +void releaseChild () { + super.releaseChild (); + parent.destroyItem (this); +} + +void releaseWidget () { + super.releaseWidget (); + parent = null; + control = null; + toolTipText = null; + disabledImage = hotImage = null; + if (disabledImage2 != null) disabledImage2.dispose (); + disabledImage2 = null; +} + +void releaseImages () { + TBBUTTONINFO info = new TBBUTTONINFO (); + info.cbSize = TBBUTTONINFO.sizeof; + info.dwMask = OS.TBIF_IMAGE | OS.TBIF_STYLE; + int hwnd = parent.handle; + OS.SendMessage (hwnd, OS.TB_GETBUTTONINFO, id, info); + /* + * Feature in Windows. For some reason, a tool item that has + * the style BTNS_SEP does not return I_IMAGENONE when queried + * for an image index, despite the fact that no attempt has been + * made to assign an image to the item. As a result, operations + * on an image list that use the wrong index cause random results. + * The fix is to ensure that the tool item is not a separator + * before using the image index. Since separators cannot have + * an image and one is never assigned, this is not a problem. + */ + if ((info.fsStyle & OS.BTNS_SEP) == 0 && info.iImage != OS.I_IMAGENONE) { + ImageList imageList = parent.getImageList (); + ImageList hotImageList = parent.getHotImageList (); + ImageList disabledImageList = parent.getDisabledImageList(); + if (imageList != null) imageList.put (info.iImage, null); + if (hotImageList != null) hotImageList.put (info.iImage, null); + if (disabledImageList != null) disabledImageList.put (info.iImage, null); + } +} + +/** + * Removes the listener from the collection of listeners who will + * be notified when the control is selected. + * + * @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 #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 resizeControl () { + if (control != null && !control.isDisposed ()) { + /* + * Set the size and location of the control + * separately to minimize flashing in the + * case where the control does not resize + * to the size that was requested. This + * case can occur when the control is a + * combo box. + */ + Rectangle itemRect = getBounds (); + control.setSize (itemRect.width, itemRect.height); + Rectangle rect = control.getBounds (); + rect.x = itemRect.x + (itemRect.width - rect.width) / 2; + rect.y = itemRect.y + (itemRect.height - rect.height) / 2; + control.setLocation (rect.x, rect.y); + } +} + +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); +} + +/** + * Sets the control that is used to fill the bounds of + * the item when the items 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; + this.control = control; + resizeControl (); +} + +/** + * 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(); + int hwnd = parent.handle; + int fsState = OS.SendMessage (hwnd, OS.TB_GETSTATE, id, 0); + fsState &= ~OS.TBSTATE_ENABLED; + if (enabled) fsState |= OS.TBSTATE_ENABLED; + OS.SendMessage (hwnd, OS.TB_SETSTATE, id, fsState); + if (image != null) updateImages (); +} + +/** + * Sets the receiver's disabled image to the argument, which may be + * null indicating that no disabled image should be displayed. + * <p> + * The disbled 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 ((style & SWT.SEPARATOR) != 0) return; + if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); + disabledImage = image; + updateImages (); +} + +/** + * 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 ((style & SWT.SEPARATOR) != 0) return; + if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); + hotImage = image; + updateImages (); +} + +public void setImage (Image image) { + checkWidget(); + if ((style & SWT.SEPARATOR) != 0) return; + if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); + super.setImage (image); + updateImages (); +} + +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; + int hwnd = parent.handle; + int fsState = OS.SendMessage (hwnd, OS.TB_GETSTATE, id, 0); + fsState &= ~OS.TBSTATE_CHECKED; + if (selected) fsState |= OS.TBSTATE_CHECKED; + OS.SendMessage (hwnd, OS.TB_SETSTATE, id, fsState); +} +/** + * Sets the receiver's text. The string may include + * the mnemonic character. + * </p> + * <p> + * Mnemonics are indicated by an '&' 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 '&' can be + * escaped by doubling it in the string, causing a single + *'&' 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); + int hwnd = parent.handle; + int hHeap = OS.GetProcessHeap (); + TCHAR buffer = new TCHAR (parent.getCodePage (), string, true); + int byteCount = buffer.length () * TCHAR.sizeof; + int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + OS.MoveMemory (pszText, buffer, byteCount); + TBBUTTONINFO info = new TBBUTTONINFO (); + info.cbSize = TBBUTTONINFO.sizeof; + info.dwMask = OS.TBIF_TEXT | OS.TBIF_STYLE; + info.pszText = pszText; + info.fsStyle = (byte) (widgetStyle () | OS.BTNS_AUTOSIZE); + OS.SendMessage (hwnd, OS.TB_SETBUTTONINFO, id, info); + OS.HeapFree (hHeap, 0, pszText); + + /* + * Bug in Windows. For some reason, when the font is set + * before any tool item has text, the tool items resize to + * a very small size. Also, a tool item will only show text + * when text has already been set on one item and then a new + * item is created. The fix is to use WM_SETFONT to force + * the tool bar to redraw and layout. [1G0G7TV, 1G0FUJ5] + */ + int hFont = OS.SendMessage (hwnd, OS.WM_GETFONT, 0, 0); + OS.SendMessage (hwnd, OS.WM_SETFONT, hFont, 0); + + parent.layoutItems (); +} + +/** + * Sets the receiver's tool tip text to the argument, which + * may be null indicating that no tool tip text should be shown. + * + * @param string the new tool tip text (or null) + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if 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; +} + +/** + * 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 ((style & SWT.SEPARATOR) == 0) return; + if (width < 0) return; + int hwnd = parent.handle; + TBBUTTONINFO info = new TBBUTTONINFO (); + info.cbSize = TBBUTTONINFO.sizeof; + info.dwMask = OS.TBIF_SIZE; + info.cx = (short) width; + OS.SendMessage (hwnd, OS.TB_SETBUTTONINFO, id, info); + parent.layoutItems (); +} + +void updateImages () { + int hwnd = parent.handle; + TBBUTTONINFO info = new TBBUTTONINFO (); + info.cbSize = TBBUTTONINFO.sizeof; + info.dwMask = OS.TBIF_IMAGE; + OS.SendMessage (hwnd, OS.TB_GETBUTTONINFO, id, info); + if (info.iImage == OS.I_IMAGENONE && image == null) return; + ImageList imageList = parent.getImageList (); + ImageList hotImageList = parent.getHotImageList (); + ImageList disabledImageList = parent.getDisabledImageList(); + if (info.iImage == OS.I_IMAGENONE) { + Display display = getDisplay (); + Rectangle bounds = image.getBounds (); + Point size = new Point (bounds.width, bounds.height); + if (imageList == null) imageList = display.getToolImageList (size); + info.iImage = imageList.add (image); + parent.setImageList (imageList); + if (disabledImageList == null) disabledImageList = display.getToolDisabledImageList (size); + Image disabled = disabledImage; + if (disabledImage == null) { + if (disabledImage2 != null) disabledImage2.dispose (); + disabledImage2 = null; + disabled = image; + if (!getEnabled ()) { + Color color = parent.getBackground (); + disabled = disabledImage2 = createDisabledImage (image, color); + } + } + disabledImageList.add (disabled); + parent.setDisabledImageList (disabledImageList); +// if ((parent.style & SWT.FLAT) != 0) { + if (hotImageList == null) hotImageList = display.getToolHotImageList (size); + hotImageList.add (hotImage != null ? hotImage : image); + parent.setHotImageList (hotImageList); +// } + } else { + if (imageList != null) imageList.put (info.iImage, image); + if (disabledImageList != null) { + Image disabled = null; + if (image != null) { + if (disabledImage2 != null) disabledImage2.dispose (); + disabledImage2 = null; + disabled = disabledImage; + if (disabledImage == null) { + disabled = image; + if (!getEnabled ()) { + Color color = parent.getBackground (); + disabled = disabledImage2 = createDisabledImage (image, color); + } + } + } + disabledImageList.put (info.iImage, disabled); + } + if (hotImageList != null) { + Image hot = null; + if (image != null) hot = hotImage != null ? hotImage : image; + hotImageList.put (info.iImage, hot); + } + if (image == null) info.iImage = OS.I_IMAGENONE; + } + OS.SendMessage (hwnd, OS.TB_SETBUTTONINFO, id, info); + + parent.layoutItems (); +} + +int widgetStyle () { + if ((style & SWT.DROP_DOWN) != 0) return OS.BTNS_DROPDOWN; + if ((style & SWT.PUSH) != 0) return OS.BTNS_BUTTON; + if ((style & SWT.CHECK) != 0) return OS.BTNS_CHECK; + /* + * This code is intentionally commented. In order to + * consistently support radio tool items across platforms, + * the platform radio behavior is not used. + */ +// if ((style & SWT.RADIO) != 0) return OS.BTNS_CHECKGROUP; + if ((style & SWT.RADIO) != 0) return OS.BTNS_CHECK; + if ((style & SWT.SEPARATOR) != 0) return OS.BTNS_SEP; + return OS.BTNS_BUTTON; +} + +LRESULT wmCommandChild (int wParam, int lParam) { + if ((style & SWT.RADIO) != 0) { + if ((parent.getStyle () & SWT.NO_RADIO_GROUP) == 0) { + selectRadio (); + } + } + Event event = new Event (); + setInputState (event, SWT.Selection); + postEvent (SWT.Selection, event); + return null; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Tracker.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Tracker.java index fec620169c..aab5fef74b 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Tracker.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Tracker.java @@ -1,726 +1,726 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.*;
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.events.*;
-
-/**
- * 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>
- */
-public class Tracker extends Widget {
- Control parent;
- Display display;
- boolean tracking, stippled;
- Rectangle [] rectangles, proportions;
- int resizeCursor, clientCursor, cursorOrientation = SWT.NONE;
- boolean inEvent = false;
-
- /*
- * 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;
- display = parent.getDisplay ();
-}
-
-/**
- * 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
- */
-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.Move,typedListener);
-}
-
-Point adjustMoveCursor () {
- Rectangle bounds = computeBounds ();
- int newX = bounds.x + bounds.width / 2;
- int newY = bounds.y;
- POINT pt = new POINT ();
- pt.x = newX; pt.y = newY;
- /*
- * Convert to screen coordinates iff needed
- */
- if (parent != null) {
- OS.ClientToScreen (parent.handle, pt);
- }
- OS.SetCursorPos (pt.x, pt.y);
- return new Point (pt.x, pt.y);
-}
-
-Point adjustResizeCursor () {
- int newX, newY;
- Rectangle bounds = computeBounds ();
-
- 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;
- }
-
- POINT pt = new POINT ();
- pt.x = newX; pt.y = newY;
- /*
- * Convert to screen coordinates iff needed
- */
- if (parent != null) {
- OS.ClientToScreen (parent.handle, pt);
- }
- OS.SetCursorPos (pt.x, pt.y);
-
- /*
- * If the client has not provided a custom cursor then determine
- * the appropriate resize cursor.
- */
- if (clientCursor == 0) {
- int newCursor = 0;
- switch (cursorOrientation) {
- case SWT.UP:
- newCursor = OS.LoadCursor (0, OS.IDC_SIZENS);
- break;
- case SWT.DOWN:
- newCursor = OS.LoadCursor (0, OS.IDC_SIZENS);
- break;
- case SWT.LEFT:
- newCursor = OS.LoadCursor (0, OS.IDC_SIZEWE);
- break;
- case SWT.RIGHT:
- newCursor = OS.LoadCursor (0, OS.IDC_SIZEWE);
- break;
- case SWT.LEFT | SWT.UP:
- newCursor = OS.LoadCursor (0, OS.IDC_SIZENWSE);
- break;
- case SWT.RIGHT | SWT.DOWN:
- newCursor = OS.LoadCursor (0, OS.IDC_SIZENWSE);
- break;
- case SWT.LEFT | SWT.DOWN:
- newCursor = OS.LoadCursor (0, OS.IDC_SIZENESW);
- break;
- case SWT.RIGHT | SWT.UP:
- newCursor = OS.LoadCursor (0, OS.IDC_SIZENESW);
- break;
- default:
- newCursor = OS.LoadCursor (0, OS.IDC_SIZEALL);
- break;
- }
- OS.SetCursor (newCursor);
- if (resizeCursor != 0) {
- OS.DestroyCursor (resizeCursor);
- }
- resizeCursor = newCursor;
- }
-
- return new Point (pt.x, pt.y);
-}
-
-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 () {
- 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];
- Rectangle bounds = computeBounds ();
- for (int i = 0; i < rects.length; i++) {
- result[i] = new Rectangle (
- (rects[i].x - bounds.x) * 100 / bounds.width,
- (rects[i].y - bounds.y) * 100 / bounds.height,
- rects[i].width * 100 / bounds.width,
- rects[i].height * 100 / bounds.height);
- }
- return result;
-}
-/**
- * Draw the rectangles displayed by the tracker.
- */
-void drawRectangles (Rectangle [] rects) {
- if (parent != null) {
- if (parent.isDisposed ()) return;
- Shell shell = parent.getShell ();
- shell.update (true);
- } else {
- display.update ();
- }
- int bandWidth = 1;
- int hwndTrack = OS.GetDesktopWindow ();
- if (parent != null) hwndTrack = parent.handle;
- int hDC = OS.GetDCEx (hwndTrack, 0, OS.DCX_CACHE);
- int hBitmap = 0, hBrush = 0, oldBrush = 0;
- if (stippled) {
- bandWidth = 3;
- byte [] bits = {-86, 0, 85, 0, -86, 0, 85, 0, -86, 0, 85, 0, -86, 0, 85, 0};
- hBitmap = OS.CreateBitmap (8, 8, 1, 1, bits);
- hBrush = OS.CreatePatternBrush (hBitmap);
- oldBrush = OS.SelectObject (hDC, hBrush);
- }
- for (int i=0; i<rects.length; i++) {
- Rectangle rect = rects [i];
- OS.PatBlt (hDC, rect.x, rect.y, rect.width, bandWidth, OS.PATINVERT);
- OS.PatBlt (hDC, rect.x, rect.y + bandWidth, bandWidth, rect.height - (bandWidth * 2), OS.PATINVERT);
- OS.PatBlt (hDC, rect.x + rect.width - bandWidth, rect.y + bandWidth, bandWidth, rect.height - (bandWidth * 2), OS.PATINVERT);
- OS.PatBlt (hDC, rect.x, rect.y + rect.height - bandWidth, rect.width, bandWidth, OS.PATINVERT);
- }
- if (stippled) {
- OS.SelectObject (hDC, oldBrush);
- OS.DeleteObject (hBrush);
- OS.DeleteObject (hBitmap);
- }
- OS.ReleaseDC (hwndTrack, hDC);
-}
-
-public Display getDisplay () {
- return display;
-}
-
-/**
- * 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 ();
- return rectangles;
-}
-
-/**
- * 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 moveRectangles (int xChange, int yChange) {
- if (xChange < 0 && ((style & SWT.LEFT) == 0)) return;
- if (xChange > 0 && ((style & SWT.RIGHT) == 0)) return;
- if (yChange < 0 && ((style & SWT.UP) == 0)) return;
- if (yChange > 0 && ((style & SWT.DOWN) == 0)) return;
- Rectangle bounds = computeBounds ();
- 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 ();
- if (rectangles == null) return false;
- boolean cancelled = false;
- tracking = true;
- Event event = new Event ();
- MSG msg = new MSG ();
- /*
- * If this tracker is being created without a mouse drag then
- * we need to create a transparent window that fills the screen
- * in order to get all mouse/keyboard events that occur
- * outside of our visible windows (ie.- over the desktop).
- */
- int hwndTransparent = 0;
- Callback newProc = null;
- boolean mouseDown = OS.GetKeyState(OS.VK_LBUTTON) < 0;
- if (!mouseDown) {
- int width = OS.GetSystemMetrics (OS.SM_CXSCREEN);
- int height = OS.GetSystemMetrics (OS.SM_CYSCREEN);
- hwndTransparent = OS.CreateWindowEx (
- OS.WS_EX_TRANSPARENT,
- display.windowClass,
- null,
- OS.WS_POPUP | OS.WS_VISIBLE,
- 0, 0,
- width, height,
- 0,
- 0,
- OS.GetModuleHandle (null),
- null);
- final int oldProc = OS.GetWindowLong (hwndTransparent, OS.GWL_WNDPROC);
- Object windowProc = new Object () {
- public int windowProc (int hwnd, int msg, int wParam, int lParam) {
- switch (msg) {
- /*
- * We typically do not want to answer that the transparent window is
- * transparent to hits since doing so negates the effect of having it
- * to grab events. However, clients of the tracker should not be aware
- * of this transparent window. Therefore if there is a hit query
- * performed as a result of client code then answer that the transparent
- * window is transparent to hits so that its existence will not impact
- * the client.
- */
- case OS.WM_NCHITTEST:
- if (inEvent) return OS.HTTRANSPARENT;
- break;
- case OS.WM_SETCURSOR:
- if (clientCursor != 0) {
- OS.SetCursor(clientCursor);
- return 1;
- }
- if (resizeCursor != 0) {
- OS.SetCursor(resizeCursor);
- return 1;
- }
- }
- return OS.CallWindowProc (oldProc, hwnd, msg, wParam, lParam);
- }
- };
- newProc = new Callback (windowProc, "windowProc", 4);
- OS.SetWindowLong (hwndTransparent, OS.GWL_WNDPROC, newProc.getAddress ());
- }
-
- drawRectangles (rectangles);
- Point cursorPos;
- if (mouseDown) {
- POINT pt = new POINT ();
- OS.GetCursorPos (pt);
- cursorPos = new Point (pt.x, pt.y);
- } else {
- if ((style & SWT.RESIZE) != 0) {
- cursorPos = adjustResizeCursor ();
- } else {
- cursorPos = adjustMoveCursor ();
- }
- }
-
- int oldX = cursorPos.x, oldY = cursorPos.y;
- /*
- * Tracker behaves like a Dialog with its own OS event loop.
- */
- while (tracking && !cancelled) {
- if (parent != null && parent.isDisposed ()) break;
- OS.GetMessage (msg, 0, 0, 0);
- int message = msg.message;
- switch (message) {
- case OS.WM_LBUTTONUP:
- case OS.WM_MOUSEMOVE:
- int newPos = OS.GetMessagePos ();
- int newX = (short) (newPos & 0xFFFF);
- int newY = (short) (newPos >> 16);
- if (newX != oldX || newY != oldY) {
- drawRectangles (rectangles);
- event.x = newX;
- event.y = newY;
- if ((style & SWT.RESIZE) != 0) {
- resizeRectangles (newX - oldX, newY - oldY);
- cursorPos = adjustResizeCursor ();
- newX = cursorPos.x; newY = cursorPos.y;
- inEvent = true;
- sendEvent (SWT.Resize, event);
- } 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 ()) return false;
- drawRectangles (rectangles);
- oldX = newX; oldY = newY;
- }
- tracking = msg.message != OS.WM_LBUTTONUP;
- break;
- case OS.WM_SYSKEYDOWN:
- cancelled = true;
- tracking = false;
- break;
- case OS.WM_KEYDOWN:
- int stepSize = OS.GetKeyState (OS.VK_CONTROL) < 0 ? STEPSIZE_SMALL : STEPSIZE_LARGE;
- int xChange = 0, yChange = 0;
- switch (msg.wParam) {
- case OS.VK_ESCAPE:
- cancelled = true;
- tracking = false;
- break;
- case OS.VK_RETURN:
- tracking = false;
- break;
- case OS.VK_LEFT:
- xChange = -stepSize;
- break;
- case OS.VK_RIGHT:
- xChange = stepSize;
- break;
- case OS.VK_UP:
- yChange = -stepSize;
- break;
- case OS.VK_DOWN:
- yChange = stepSize;
- break;
- }
- if (xChange != 0 || yChange != 0) {
- drawRectangles (rectangles);
- newX = oldX + xChange;
- newY = oldY + yChange;
- event.x = newX;
- event.y = newY;
- if ((style & SWT.RESIZE) != 0) {
- resizeRectangles (xChange, yChange);
- cursorPos = adjustResizeCursor ();
- inEvent = true;
- sendEvent (SWT.Resize, event);
- } else {
- moveRectangles (xChange, yChange);
- cursorPos = adjustMoveCursor ();
- 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 ()) return false;
- drawRectangles (rectangles);
- oldX = cursorPos.x; oldY = cursorPos.y;
- }
- break;
- }
- /*
- * Don't dispatch mouse and key events in general, EXCEPT once this
- * tracker has finished its work.
- */
- if (tracking && !cancelled) {
- if (OS.WM_KEYFIRST <= message && message <= OS.WM_KEYLAST) continue;
- if (OS.WM_MOUSEFIRST <= message && message <= OS.WM_MOUSELAST) continue;
- }
- OS.DispatchMessage (msg);
- }
- drawRectangles (rectangles);
- /*
- * Cleanup: If a transparent window was created in order to capture events then
- * destroy it and its callback object now.
- */
- if (hwndTransparent != 0) {
- OS.DestroyWindow (hwndTransparent);
- }
- if (newProc != null) {
- newProc.dispose();
- }
- /*
- * Cleanup: If this tracker was resizing then the last cursor that it created
- * needs to be destroyed.
- */
- if (resizeCursor != 0) {
- OS.DestroyCursor (resizeCursor);
- }
- tracking = false;
- return !cancelled;
-}
-
-/**
- * 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 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);
-}
-
-void resizeRectangles (int xChange, int yChange) {
- /*
- * 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)) {
- cursorOrientation |= SWT.LEFT;
- } else if (xChange > 0 && ((style & SWT.RIGHT) != 0) && ((cursorOrientation & SWT.LEFT) == 0)) {
- cursorOrientation |= SWT.RIGHT;
- } else if (yChange < 0 && ((style & SWT.UP) != 0) && ((cursorOrientation & SWT.DOWN) == 0)) {
- cursorOrientation |= SWT.UP;
- } else if (yChange > 0 && ((style & SWT.DOWN) != 0) && ((cursorOrientation & SWT.UP) == 0)) {
- cursorOrientation |= SWT.DOWN;
- }
- Rectangle bounds = computeBounds ();
- 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;
- }
- /*
- * The following are conditions under which the resize should not be applied
- */
- if (bounds.width < 0 || bounds.height < 0) return;
-
- 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;
-}
-
-/**
- * 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 = 0;
- if (newCursor != null) {
- clientCursor = newCursor.handle;
- if (inEvent) OS.SetCursor(clientCursor);
- }
-}
-/**
- * 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 SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if 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);
- this.rectangles = rectangles;
- 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;
-}
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.*; +import org.eclipse.swt.events.*; + +/** + * 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> + */ +public class Tracker extends Widget { + Control parent; + Display display; + boolean tracking, stippled; + Rectangle [] rectangles, proportions; + int resizeCursor, clientCursor, cursorOrientation = SWT.NONE; + boolean inEvent = false; + + /* + * 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; + display = parent.getDisplay (); +} + +/** + * 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 + */ +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.Move,typedListener); +} + +Point adjustMoveCursor () { + Rectangle bounds = computeBounds (); + int newX = bounds.x + bounds.width / 2; + int newY = bounds.y; + POINT pt = new POINT (); + pt.x = newX; pt.y = newY; + /* + * Convert to screen coordinates iff needed + */ + if (parent != null) { + OS.ClientToScreen (parent.handle, pt); + } + OS.SetCursorPos (pt.x, pt.y); + return new Point (pt.x, pt.y); +} + +Point adjustResizeCursor () { + int newX, newY; + Rectangle bounds = computeBounds (); + + 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; + } + + POINT pt = new POINT (); + pt.x = newX; pt.y = newY; + /* + * Convert to screen coordinates iff needed + */ + if (parent != null) { + OS.ClientToScreen (parent.handle, pt); + } + OS.SetCursorPos (pt.x, pt.y); + + /* + * If the client has not provided a custom cursor then determine + * the appropriate resize cursor. + */ + if (clientCursor == 0) { + int newCursor = 0; + switch (cursorOrientation) { + case SWT.UP: + newCursor = OS.LoadCursor (0, OS.IDC_SIZENS); + break; + case SWT.DOWN: + newCursor = OS.LoadCursor (0, OS.IDC_SIZENS); + break; + case SWT.LEFT: + newCursor = OS.LoadCursor (0, OS.IDC_SIZEWE); + break; + case SWT.RIGHT: + newCursor = OS.LoadCursor (0, OS.IDC_SIZEWE); + break; + case SWT.LEFT | SWT.UP: + newCursor = OS.LoadCursor (0, OS.IDC_SIZENWSE); + break; + case SWT.RIGHT | SWT.DOWN: + newCursor = OS.LoadCursor (0, OS.IDC_SIZENWSE); + break; + case SWT.LEFT | SWT.DOWN: + newCursor = OS.LoadCursor (0, OS.IDC_SIZENESW); + break; + case SWT.RIGHT | SWT.UP: + newCursor = OS.LoadCursor (0, OS.IDC_SIZENESW); + break; + default: + newCursor = OS.LoadCursor (0, OS.IDC_SIZEALL); + break; + } + OS.SetCursor (newCursor); + if (resizeCursor != 0) { + OS.DestroyCursor (resizeCursor); + } + resizeCursor = newCursor; + } + + return new Point (pt.x, pt.y); +} + +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 () { + 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]; + Rectangle bounds = computeBounds (); + for (int i = 0; i < rects.length; i++) { + result[i] = new Rectangle ( + (rects[i].x - bounds.x) * 100 / bounds.width, + (rects[i].y - bounds.y) * 100 / bounds.height, + rects[i].width * 100 / bounds.width, + rects[i].height * 100 / bounds.height); + } + return result; +} +/** + * Draw the rectangles displayed by the tracker. + */ +void drawRectangles (Rectangle [] rects) { + if (parent != null) { + if (parent.isDisposed ()) return; + Shell shell = parent.getShell (); + shell.update (true); + } else { + display.update (); + } + int bandWidth = 1; + int hwndTrack = OS.GetDesktopWindow (); + if (parent != null) hwndTrack = parent.handle; + int hDC = OS.GetDCEx (hwndTrack, 0, OS.DCX_CACHE); + int hBitmap = 0, hBrush = 0, oldBrush = 0; + if (stippled) { + bandWidth = 3; + byte [] bits = {-86, 0, 85, 0, -86, 0, 85, 0, -86, 0, 85, 0, -86, 0, 85, 0}; + hBitmap = OS.CreateBitmap (8, 8, 1, 1, bits); + hBrush = OS.CreatePatternBrush (hBitmap); + oldBrush = OS.SelectObject (hDC, hBrush); + } + for (int i=0; i<rects.length; i++) { + Rectangle rect = rects [i]; + OS.PatBlt (hDC, rect.x, rect.y, rect.width, bandWidth, OS.PATINVERT); + OS.PatBlt (hDC, rect.x, rect.y + bandWidth, bandWidth, rect.height - (bandWidth * 2), OS.PATINVERT); + OS.PatBlt (hDC, rect.x + rect.width - bandWidth, rect.y + bandWidth, bandWidth, rect.height - (bandWidth * 2), OS.PATINVERT); + OS.PatBlt (hDC, rect.x, rect.y + rect.height - bandWidth, rect.width, bandWidth, OS.PATINVERT); + } + if (stippled) { + OS.SelectObject (hDC, oldBrush); + OS.DeleteObject (hBrush); + OS.DeleteObject (hBitmap); + } + OS.ReleaseDC (hwndTrack, hDC); +} + +public Display getDisplay () { + return display; +} + +/** + * 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 (); + return rectangles; +} + +/** + * 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 moveRectangles (int xChange, int yChange) { + if (xChange < 0 && ((style & SWT.LEFT) == 0)) return; + if (xChange > 0 && ((style & SWT.RIGHT) == 0)) return; + if (yChange < 0 && ((style & SWT.UP) == 0)) return; + if (yChange > 0 && ((style & SWT.DOWN) == 0)) return; + Rectangle bounds = computeBounds (); + 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 (); + if (rectangles == null) return false; + boolean cancelled = false; + tracking = true; + Event event = new Event (); + MSG msg = new MSG (); + /* + * If this tracker is being created without a mouse drag then + * we need to create a transparent window that fills the screen + * in order to get all mouse/keyboard events that occur + * outside of our visible windows (ie.- over the desktop). + */ + int hwndTransparent = 0; + Callback newProc = null; + boolean mouseDown = OS.GetKeyState(OS.VK_LBUTTON) < 0; + if (!mouseDown) { + int width = OS.GetSystemMetrics (OS.SM_CXSCREEN); + int height = OS.GetSystemMetrics (OS.SM_CYSCREEN); + hwndTransparent = OS.CreateWindowEx ( + OS.WS_EX_TRANSPARENT, + display.windowClass, + null, + OS.WS_POPUP | OS.WS_VISIBLE, + 0, 0, + width, height, + 0, + 0, + OS.GetModuleHandle (null), + null); + final int oldProc = OS.GetWindowLong (hwndTransparent, OS.GWL_WNDPROC); + Object windowProc = new Object () { + public int windowProc (int hwnd, int msg, int wParam, int lParam) { + switch (msg) { + /* + * We typically do not want to answer that the transparent window is + * transparent to hits since doing so negates the effect of having it + * to grab events. However, clients of the tracker should not be aware + * of this transparent window. Therefore if there is a hit query + * performed as a result of client code then answer that the transparent + * window is transparent to hits so that its existence will not impact + * the client. + */ + case OS.WM_NCHITTEST: + if (inEvent) return OS.HTTRANSPARENT; + break; + case OS.WM_SETCURSOR: + if (clientCursor != 0) { + OS.SetCursor(clientCursor); + return 1; + } + if (resizeCursor != 0) { + OS.SetCursor(resizeCursor); + return 1; + } + } + return OS.CallWindowProc (oldProc, hwnd, msg, wParam, lParam); + } + }; + newProc = new Callback (windowProc, "windowProc", 4); + OS.SetWindowLong (hwndTransparent, OS.GWL_WNDPROC, newProc.getAddress ()); + } + + drawRectangles (rectangles); + Point cursorPos; + if (mouseDown) { + POINT pt = new POINT (); + OS.GetCursorPos (pt); + cursorPos = new Point (pt.x, pt.y); + } else { + if ((style & SWT.RESIZE) != 0) { + cursorPos = adjustResizeCursor (); + } else { + cursorPos = adjustMoveCursor (); + } + } + + int oldX = cursorPos.x, oldY = cursorPos.y; + /* + * Tracker behaves like a Dialog with its own OS event loop. + */ + while (tracking && !cancelled) { + if (parent != null && parent.isDisposed ()) break; + OS.GetMessage (msg, 0, 0, 0); + int message = msg.message; + switch (message) { + case OS.WM_LBUTTONUP: + case OS.WM_MOUSEMOVE: + int newPos = OS.GetMessagePos (); + int newX = (short) (newPos & 0xFFFF); + int newY = (short) (newPos >> 16); + if (newX != oldX || newY != oldY) { + drawRectangles (rectangles); + event.x = newX; + event.y = newY; + if ((style & SWT.RESIZE) != 0) { + resizeRectangles (newX - oldX, newY - oldY); + cursorPos = adjustResizeCursor (); + newX = cursorPos.x; newY = cursorPos.y; + inEvent = true; + sendEvent (SWT.Resize, event); + } 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 ()) return false; + drawRectangles (rectangles); + oldX = newX; oldY = newY; + } + tracking = msg.message != OS.WM_LBUTTONUP; + break; + case OS.WM_SYSKEYDOWN: + cancelled = true; + tracking = false; + break; + case OS.WM_KEYDOWN: + int stepSize = OS.GetKeyState (OS.VK_CONTROL) < 0 ? STEPSIZE_SMALL : STEPSIZE_LARGE; + int xChange = 0, yChange = 0; + switch (msg.wParam) { + case OS.VK_ESCAPE: + cancelled = true; + tracking = false; + break; + case OS.VK_RETURN: + tracking = false; + break; + case OS.VK_LEFT: + xChange = -stepSize; + break; + case OS.VK_RIGHT: + xChange = stepSize; + break; + case OS.VK_UP: + yChange = -stepSize; + break; + case OS.VK_DOWN: + yChange = stepSize; + break; + } + if (xChange != 0 || yChange != 0) { + drawRectangles (rectangles); + newX = oldX + xChange; + newY = oldY + yChange; + event.x = newX; + event.y = newY; + if ((style & SWT.RESIZE) != 0) { + resizeRectangles (xChange, yChange); + cursorPos = adjustResizeCursor (); + inEvent = true; + sendEvent (SWT.Resize, event); + } else { + moveRectangles (xChange, yChange); + cursorPos = adjustMoveCursor (); + 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 ()) return false; + drawRectangles (rectangles); + oldX = cursorPos.x; oldY = cursorPos.y; + } + break; + } + /* + * Don't dispatch mouse and key events in general, EXCEPT once this + * tracker has finished its work. + */ + if (tracking && !cancelled) { + if (OS.WM_KEYFIRST <= message && message <= OS.WM_KEYLAST) continue; + if (OS.WM_MOUSEFIRST <= message && message <= OS.WM_MOUSELAST) continue; + } + OS.DispatchMessage (msg); + } + drawRectangles (rectangles); + /* + * Cleanup: If a transparent window was created in order to capture events then + * destroy it and its callback object now. + */ + if (hwndTransparent != 0) { + OS.DestroyWindow (hwndTransparent); + } + if (newProc != null) { + newProc.dispose(); + } + /* + * Cleanup: If this tracker was resizing then the last cursor that it created + * needs to be destroyed. + */ + if (resizeCursor != 0) { + OS.DestroyCursor (resizeCursor); + } + tracking = false; + return !cancelled; +} + +/** + * 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 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); +} + +void resizeRectangles (int xChange, int yChange) { + /* + * 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)) { + cursorOrientation |= SWT.LEFT; + } else if (xChange > 0 && ((style & SWT.RIGHT) != 0) && ((cursorOrientation & SWT.LEFT) == 0)) { + cursorOrientation |= SWT.RIGHT; + } else if (yChange < 0 && ((style & SWT.UP) != 0) && ((cursorOrientation & SWT.DOWN) == 0)) { + cursorOrientation |= SWT.UP; + } else if (yChange > 0 && ((style & SWT.DOWN) != 0) && ((cursorOrientation & SWT.UP) == 0)) { + cursorOrientation |= SWT.DOWN; + } + Rectangle bounds = computeBounds (); + 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; + } + /* + * The following are conditions under which the resize should not be applied + */ + if (bounds.width < 0 || bounds.height < 0) return; + + 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; +} + +/** + * 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 = 0; + if (newCursor != null) { + clientCursor = newCursor.handle; + if (inEvent) OS.SetCursor(clientCursor); + } +} +/** + * 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 SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if 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); + this.rectangles = rectangles; + 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/win32/org/eclipse/swt/widgets/Tree.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Tree.java index c55e81d651..c08db437da 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Tree.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Tree.java @@ -1,1907 +1,1907 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.events.*;
-
-/**
- * Instances of this class provide a selectable user interface object
- * that displays a hierarchy of items and issue notificiation 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>
- * 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>SINGLE, MULTI, CHECK</dd>
- * <dt><b>Events:</b></dt>
- * <dd>Selection, DefaultSelection, Collapse, Expand</dd>
- * </dl>
- * <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>
- */
-public class Tree extends Composite {
- int hAnchor;
- TreeItem [] items;
- ImageList imageList;
- boolean dragStarted;
- boolean ignoreSelect, ignoreExpand, ignoreDeselect;
- boolean customDraw;
- static final int TreeProc;
- static final TCHAR TreeClass = new TCHAR (0, OS.WC_TREEVIEW, true);
- static {
- WNDCLASS lpWndClass = new WNDCLASS ();
- OS.GetClassInfo (0, TreeClass, lpWndClass);
- TreeProc = lpWndClass.lpfnWndProc;
- }
-
-/**
- * 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 Widget#checkSubclass
- * @see Widget#getStyle
- */
-public Tree (Composite parent, int style) {
- super (parent, checkStyle (style));
-}
-
-/**
- * Adds the listener to the collection of listeners who will
- * be notified when the receiver's selection changes, 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 reciever has <code>SWT.CHECK</code> style set 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
- *
- * @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 callWindowProc (int msg, int wParam, int lParam) {
- if (handle == 0) return 0;
- return OS.CallWindowProc (TreeProc, handle, msg, wParam, lParam);
-}
-
-static int checkStyle (int style) {
- /*
- * Feature in Windows. It is not possible to create
- * a tree that scrolls and does not have scroll bars.
- * The TVS_NOSCROLL style will remove the scroll bars
- * but the tree will never scroll. Therefore, no matter
- * what style bits are specified, set the H_SCROLL and
- * V_SCROLL bits so that the SWT style will match the
- * widget that Windows creates.
- */
- style |= SWT.H_SCROLL | SWT.V_SCROLL;
- return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0);
-}
-
-
-public Point computeSize (int wHint, int hHint, boolean changed) {
- checkWidget ();
- int width = 0, height = 0;
- RECT rect = new RECT ();
- int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
- while (hItem != 0) {
- rect.left = hItem;
- if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect) != 0) {
- width = Math.max (width, rect.right - rect.left);
- height += rect.bottom - rect.top;
- }
- hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
- }
- width = width * 2;
- 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;
- if ((style & SWT.V_SCROLL) != 0) {
- width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
- }
- if ((style & SWT.H_SCROLL) != 0) {
- height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
- }
- return new Point (width, height);
-}
-
-void createHandle () {
- super.createHandle ();
- state &= ~CANVAS;
-
- /* Set the checkbox image list */
- if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
-
- /*
- * Feature in Windows. When the control is created,
- * it does not use the default system font. A new HFONT
- * is created and destroyed when the control is destroyed.
- * This means that a program that queries the font from
- * this control, uses the font in another control and then
- * destroys this control will have the font unexpectedly
- * destroyed in the other control. The fix is to assign
- * the font ourselves each time the control is created.
- * The control will not destroy a font that it did not
- * create.
- */
- int hFont = OS.GetStockObject (OS.SYSTEM_FONT);
- OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0);
-}
-
-void createItem (TreeItem item, int hParent, int hInsertAfter) {
- item.foreground = item.background = -1;
- int id = 0;
- while (id < items.length && items [id] != null) id++;
- if (id == items.length) {
- TreeItem [] newItems = new TreeItem [items.length + 4];
- System.arraycopy (items, 0, newItems, 0, items.length);
- items = newItems;
- }
- TVINSERTSTRUCT tvInsert = new TVINSERTSTRUCT ();
- tvInsert.hParent = hParent;
- tvInsert.hInsertAfter = hInsertAfter;
- tvInsert.lParam = id;
- tvInsert.iImage = OS.I_IMAGENONE;
- tvInsert.iSelectedImage = tvInsert.iImage;
- tvInsert.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_IMAGE | OS.TVIF_SELECTEDIMAGE;
-
- /* Set the initial unchecked state */
- if ((style & SWT.CHECK) != 0) {
- tvInsert.mask = tvInsert.mask | OS.TVIF_STATE;
- tvInsert.state = 1 << 12;
- tvInsert.stateMask = OS.TVIS_STATEIMAGEMASK;
- }
-
- /* Insert the item */
- int hItem = OS.SendMessage (handle, OS.TVM_INSERTITEM, 0, tvInsert);
- if (hItem == 0) error (SWT.ERROR_ITEM_NOT_ADDED);
- item.handle = hItem;
- items [id] = item;
-
- /*
- * This code is intentionally commented.
- */
-// if (hParent != 0) {
-// int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
-// bits |= OS.TVS_LINESATROOT;
-// OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
-// }
-
- /*
- * Bug in Windows. When a child item is added to a parent item
- * that has no children outside of WM_NOTIFY with control code
- * TVN_ITEMEXPANDED, the tree widget does not redraw the +/-
- * indicator. The fix is to detect this case and force a redraw.
- */
- if (!OS.IsWindowVisible (handle) || drawCount > 0) return;
- int hChild = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hParent);
- if (hChild == 0 || OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hChild) != 0) {
- return;
- }
- RECT rect = new RECT ();
- rect.left = hParent;
- if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect) != 0) {
- OS.InvalidateRect (handle, rect, false);
- }
-}
-
-void createWidget () {
- super.createWidget ();
- items = new TreeItem [4];
-}
-
-int defaultBackground () {
- return OS.GetSysColor (OS.COLOR_WINDOW);
-}
-
-/**
- * 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 ();
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_STATE;
- tvItem.stateMask = OS.TVIS_SELECTED;
- if ((style & SWT.SINGLE) != 0) {
- int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
- if (hItem != 0) {
- tvItem.hItem = hItem;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- }
- return;
- }
- int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC);
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc);
- for (int i=0; i<items.length; i++) {
- TreeItem item = items [i];
- if (item != null) {
- tvItem.hItem = item.handle;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- }
- }
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
-}
-
-void destroyItem (TreeItem item) {
- int hItem = item.handle;
- boolean fixRedraw = false;
- if (drawCount == 0 && OS.IsWindowVisible (handle)) {
- RECT rect = new RECT ();
- rect.left = hItem;
- fixRedraw = OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect) == 0;
- }
- if (fixRedraw) {
- OS.UpdateWindow (handle);
- OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
- }
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
- releaseItems (item.getItems (), tvItem);
- releaseItem (item, tvItem);
- OS.SendMessage (handle, OS.TVM_DELETEITEM, 0, hItem);
- if (fixRedraw) {
- OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
- OS.ValidateRect (handle, null);
- }
- int count = OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
- if (count == 0) {
- if (imageList != null) {
- OS.SendMessage (handle, OS.TVM_SETIMAGELIST, 0, 0);
- Display display = getDisplay ();
- display.releaseImageList (imageList);
- }
- imageList = null;
- customDraw = false;
- items = new TreeItem [4];
- }
-}
-
-int getBackgroundPixel () {
- if (OS.IsWinCE) return OS.GetSysColor (OS.COLOR_WINDOW);
- int pixel = OS.SendMessage (handle, OS.TVM_GETBKCOLOR, 0, 0);
- if (pixel == -1) return OS.GetSysColor (OS.COLOR_WINDOW);
- return pixel;
-}
-
-int getForegroundPixel () {
- if (OS.IsWinCE) return OS.GetSysColor (OS.COLOR_WINDOWTEXT);
- int pixel = OS.SendMessage (handle, OS.TVM_GETTEXTCOLOR, 0, 0);
- if (pixel == -1) return OS.GetSysColor (OS.COLOR_WINDOWTEXT);
- return pixel;
-}
-
-/**
- * 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 TreeItem getItem (Point point) {
- checkWidget ();
- if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
- TVHITTESTINFO lpht = new TVHITTESTINFO ();
- lpht.x = point.x; lpht.y = point.y;
- OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
- if (lpht.hItem != 0 && (lpht.flags & OS.TVHT_ONITEM) != 0) {
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
- tvItem.hItem = lpht.hItem;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- return items [tvItem.lParam];
- }
- 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 ();
- int count = 0;
- int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
- while (hItem != 0) {
- hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
- count++;
- }
- return count;
-}
-
-/**
- * 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 OS.SendMessage (handle, OS.TVM_GETITEMHEIGHT, 0, 0);
-}
-
-/**
- * Returns the number 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 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 TreeItem [] getItems () {
- checkWidget ();
- int count = 0;
- int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
- while (hItem != 0) {
- hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
- count++;
- }
- int index = 0;
- TreeItem [] result = new TreeItem [count];
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
- tvItem.hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
- while (tvItem.hItem != 0) {
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- result [index++] = items [tvItem.lParam];
- tvItem.hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, tvItem.hItem);
- }
- return result;
-}
-
-/**
- * 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. 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 ();
- if ((style & SWT.SINGLE) != 0) {
- int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
- if (hItem == 0) return new TreeItem [0];
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_PARAM | OS.TVIF_STATE;
- tvItem.hItem = hItem;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- if ((tvItem.state & OS.TVIS_SELECTED) == 0) return new TreeItem [0];
- return new TreeItem [] {items [tvItem.lParam]};
- }
- int count = 0;
- TreeItem [] guess = new TreeItem [8];
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_PARAM | OS.TVIF_STATE;
- int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC);
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc);
- for (int i=0; i<items.length; i++) {
- TreeItem item = items [i];
- if (item != null) {
- tvItem.hItem = item.handle;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
- if (count < guess.length) guess [count] = item;
- count++;
- }
- }
- }
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
- if (count == 0) return new TreeItem [0];
- if (count == guess.length) return guess;
- TreeItem [] result = new TreeItem [count];
- if (count < guess.length) {
- System.arraycopy (guess, 0, result, 0, count);
- return result;
- }
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc);
- int index = 0;
- for (int i=0; i<items.length; i++) {
- TreeItem item = items [i];
- if (item != null) {
- tvItem.hItem = item.handle;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
- result [index++] = item;
- }
- }
- }
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
- 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 ();
- if ((style & SWT.SINGLE) != 0) {
- int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
- if (hItem == 0) return 0;
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_STATE;
- tvItem.hItem = hItem;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- if ((tvItem.state & OS.TVIS_SELECTED) == 0) return 0;
- return 1;
- }
- int count = 0;
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_STATE;
- int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC);
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc);
- for (int i=0; i<items.length; i++) {
- TreeItem item = items [i];
- if (item != null) {
- tvItem.hItem = item.handle;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- if ((tvItem.state & OS.TVIS_SELECTED) != 0) count++;
- }
- }
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
- return count;
-}
-
-/**
- * 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 ();
- int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
- if (hItem == 0) return null;
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_PARAM;
- tvItem.hItem = hItem;
- if (OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem) == 0) return null;
- return items [tvItem.lParam];
-}
-
-int imageIndex (Image image) {
- if (image == null) return OS.I_IMAGENONE;
- if (imageList == null) {
- int hOldList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0);
- if (hOldList != 0) OS.ImageList_Destroy (hOldList);
- Rectangle bounds = image.getBounds ();
- imageList = getDisplay ().getImageList (new Point (bounds.width, bounds.height));
- int index = imageList.indexOf (image);
- if (index == -1) index = imageList.add (image);
- int hImageList = imageList.getHandle ();
- OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, hImageList);
- return index;
- }
- int index = imageList.indexOf (image);
- if (index != -1) return index;
- return imageList.add (image);
-}
-
-boolean releaseItem (TreeItem item, TVITEM tvItem) {
- int hItem = item.handle;
- if (hItem == hAnchor) hAnchor = 0;
- if (item.isDisposed ()) return false;
- tvItem.hItem = hItem;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- items [tvItem.lParam] = null;
- return true;
-}
-
-void releaseItems (TreeItem [] nodes, TVITEM tvItem) {
- for (int i=0; i<nodes.length; i++) {
- TreeItem item = nodes [i];
- TreeItem [] sons = item.getItems ();
- if (sons.length != 0) {
- releaseItems (sons, tvItem);
- }
- if (releaseItem (item, tvItem)) {
- item.releaseResources ();
- }
- }
-}
-
-void releaseWidget () {
- for (int i=0; i<items.length; i++) {
- TreeItem item = items [i];
- if (item != null && !item.isDisposed ()) {
- item.releaseResources ();
- }
- }
- /*
- * Feature in Windows. For some reason, when
- * TVM_GETIMAGELIST or TVM_SETIMAGELIST is sent,
- * the tree issues NM_CUSTOMDRAW messages. This
- * behavior is unwanted when the tree is being
- * disposed. The fix is to ingore NM_CUSTOMDRAW
- * messages by usnig the custom draw flag.
- *
- * NOTE: This only happens on Windows XP.
- */
- customDraw = false;
- items = null;
- if (imageList != null) {
- OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, 0);
- Display display = getDisplay ();
- display.releaseImageList (imageList);
- } else {
- int hOldList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0);
- OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, 0);
- if (hOldList != 0) OS.ImageList_Destroy (hOldList);
- }
- imageList = null;
- int hOldList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_STATE, 0);
- OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_STATE, 0);
- if (hOldList != 0) OS.ImageList_Destroy (hOldList);
- super.releaseWidget ();
-}
-
-
-/**
- * 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 ();
- ignoreDeselect = ignoreSelect = true;
- if (drawCount == 0) {
- OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
- /*
- * This code is intentionally commented.
- */
-// OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
- }
- int result = OS.SendMessage (handle, OS.TVM_DELETEITEM, 0, OS.TVI_ROOT);
- if (drawCount == 0) {
- OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
- /*
- * This code is intentionally commented.
- */
-// OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
- OS.InvalidateRect (handle, null, true);
- }
- ignoreDeselect = ignoreSelect = false;
- if (result == 0) error (SWT.ERROR_ITEM_NOT_REMOVED);
- for (int i=0; i<items.length; i++) {
- TreeItem item = items [i];
- if (item != null && !item.isDisposed ()) {
- item.releaseResources ();
- }
- }
- if (imageList != null) {
- OS.SendMessage (handle, OS.TVM_SETIMAGELIST, 0, 0);
- Display display = getDisplay ();
- display.releaseImageList (imageList);
- }
- imageList = null;
- customDraw = false;
- items = new TreeItem [4];
- hAnchor = 0;
-}
-
-/**
- * Removes the listener from the collection of listeners who will
- * be notified when the receiver's selection changes.
- *
- * @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);
-}
-
-/**
- * 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 after 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 ();
- int hItem = 0;
- if (item != null) {
- if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
- hItem = item.handle;
- }
- OS.SendMessage (handle, OS.TVM_SETINSERTMARK, (before) ? 0 : 1, hItem);
-}
-
-/**
- * Selects all 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 void selectAll () {
- checkWidget ();
- if ((style & SWT.SINGLE) != 0) return;
- int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
- if (hItem == 0) {
- hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
- if (hItem != 0) {
- ignoreSelect = true;
- OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hItem);
- ignoreSelect = false;
- }
- }
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_STATE;
- tvItem.state = OS.TVIS_SELECTED;
- tvItem.stateMask = OS.TVIS_SELECTED;
- int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC);
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc);
- for (int i=0; i<items.length; i++) {
- TreeItem item = items [i];
- if (item != null) {
- tvItem.hItem = item.handle;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- }
- }
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
-}
-
-void setBackgroundPixel (int pixel) {
- if (background == pixel) return;
- background = pixel;
- /*
- * Bug in Windows. When TVM_GETBKCOLOR is used more
- * than once to set the background color of a tree,
- * the background color of the lines and the plus/minus
- * does not change to the new color. The fix is to set
- * the background color to the default before setting
- * the new color.
- */
- int oldPixel = OS.SendMessage (handle, OS.TVM_GETBKCOLOR, 0, 0);
- if (oldPixel != -1) OS.SendMessage (handle, OS.TVM_SETBKCOLOR, 0, -1);
- OS.SendMessage (handle, OS.TVM_SETBKCOLOR, 0, pixel);
- if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
-}
-
-void setBounds (int x, int y, int width, int height, int flags) {
- /*
- * Ensure that the selection is visible when the tree is resized
- * from a zero size to a size that can show the selection.
- */
- boolean fixSelection = false;
- if ((flags & OS.SWP_NOSIZE) == 0 && (width != 0 || height != 0)) {
- if (OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0) == 0) {
- fixSelection = true;
- }
- }
- super.setBounds (x, y, width, height, flags);
- if (fixSelection) {
- int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
- if (hItem != 0) showItem (hItem);
- }
-}
-
-void setCheckboxImageList () {
- if ((style & SWT.CHECK) == 0) return;
- int count = 5;
- int height = OS.SendMessage (handle, OS.TVM_GETITEMHEIGHT, 0, 0), width = height;
- int hImageList = OS.ImageList_Create (width, height, OS.ILC_COLOR, count, count);
- int hDC = OS.GetDC (handle);
- int memDC = OS.CreateCompatibleDC (hDC);
- int hBitmap = OS.CreateCompatibleBitmap (hDC, width * count, height);
- int hOldBitmap = OS.SelectObject (memDC, hBitmap);
- RECT rect = new RECT ();
- OS.SetRect (rect, 0, 0, width * count, height);
- int hBrush = OS.CreateSolidBrush (getBackgroundPixel ());
- OS.FillRect (memDC, rect, hBrush);
- OS.DeleteObject (hBrush);
- int oldFont = OS.SelectObject (hDC, defaultFont ());
- TEXTMETRIC tm = new TEXTMETRIC ();
- OS.GetTextMetrics (hDC, tm);
- OS.SelectObject (hDC, oldFont);
- int itemWidth = Math.min (tm.tmHeight, width);
- int itemHeight = Math.min (tm.tmHeight, height);
- int left = (width - itemWidth) / 2, top = (height - itemHeight) / 2 + 1;
- OS.SetRect (rect, left + width, top, left + width + itemWidth, top + itemHeight);
- OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_FLAT);
- rect.left += width; rect.right += width;
- OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_CHECKED | OS.DFCS_FLAT);
- rect.left += width; rect.right += width;
- OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_INACTIVE | OS.DFCS_FLAT);
- rect.left += width; rect.right += width;
- OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_CHECKED | OS.DFCS_INACTIVE | OS.DFCS_FLAT);
- OS.SelectObject (memDC, hOldBitmap);
- OS.DeleteDC (memDC);
- OS.ReleaseDC (handle, hDC);
- OS.ImageList_AddMasked (hImageList, hBitmap, 0);
- OS.DeleteObject (hBitmap);
- int hOldList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_STATE, 0);
- OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_STATE, hImageList);
- if (hOldList != 0) OS.ImageList_Destroy (hOldList);
-}
-
-void setForegroundPixel (int pixel) {
- if (foreground == pixel) return;
- foreground = pixel;
- OS.SendMessage (handle, OS.TVM_SETTEXTCOLOR, 0, pixel);
-}
-
-public void setRedraw (boolean redraw) {
- checkWidget ();
- /*
- * Bug in Windows. For some reason, when WM_SETREDRAW
- * is used to turn redraw on for a tree and the tree
- * contains no items, the last item in the tree does
- * not redraw properly. If the tree has only one item,
- * that item is not drawn. If another window is dragged
- * on top of the item, parts of the item are redrawn
- * and erased at random. The fix is to ensure that this
- * case doesn't happen by inserting and deleting an item
- * when redraw is turned on and there are no items in
- * the tree.
- */
- int hItem = 0;
- if (redraw) {
- int count = OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
- if (count == 0) {
- TVINSERTSTRUCT tvInsert = new TVINSERTSTRUCT ();
- tvInsert.hInsertAfter = OS.TVI_FIRST;
- hItem = OS.SendMessage (handle, OS.TVM_INSERTITEM, 0, tvInsert);
- }
- }
- super.setRedraw (redraw);
- if (hItem != 0) {
- OS.SendMessage (handle, OS.TVM_DELETEITEM, 0, hItem);
- }
-}
-
-/**
- * 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 array of items is null</li>
- * <li>ERROR_INVALID_ARGUMENT - if one of 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#deselectAll()
- */
-public void setSelection (TreeItem [] items) {
- checkWidget ();
- if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
-
- /* Select/deselect the first item */
- int hOldItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
- if (items.length == 0) {
- if (hOldItem != 0) {
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_STATE;
- tvItem.stateMask = OS.TVIS_SELECTED;
- tvItem.hItem = hOldItem;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- }
- } else {
- int hNewItem = 0;
- TreeItem item = items [0];
- if (item != null) {
- if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
- hAnchor = hNewItem = item.handle;
- }
- ignoreSelect = true;
- OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hNewItem);
- ignoreSelect = false;
- /*
- * Feature in Windows. When the old and new focused item
- * are the same, Windows does not check to make sure that
- * the item is actually selected, not just focused. The
- * fix is to force the item to draw selected by setting
- * the state mask.
- */
- if (hOldItem == hNewItem) {
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_STATE;
- tvItem.state = OS.TVIS_SELECTED;
- tvItem.stateMask = OS.TVIS_SELECTED;
- tvItem.hItem = hNewItem;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- }
- showItem (hNewItem);
- }
- if ((style & SWT.SINGLE) != 0) return;
-
- /* Select/deselect the rest of the items */
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_STATE;
- tvItem.stateMask = OS.TVIS_SELECTED;
- int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC);
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc);
- for (int i=0; i<this.items.length; i++) {
- TreeItem item = this.items [i];
- if (item != null) {
- int index = 0;
- while (index < items.length) {
- if (items [index] == item) break;
- index++;
- }
- tvItem.hItem = item.handle;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
- if (index == items.length) {
- tvItem.state = 0;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- }
- } else {
- if (index != items.length) {
- tvItem.state = OS.TVIS_SELECTED;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- }
- }
- }
- }
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
-}
-
-/**
- * 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) SWT.error (SWT.ERROR_NULL_ARGUMENT);
- if (item.isDisposed ()) SWT.error (SWT.ERROR_INVALID_ARGUMENT);
- OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, item.handle);
-}
-
-void showItem (int hItem) {
- /*
- * Bug in Windows. When TVM_ENSUREVISIBLE is used to ensure
- * that an item is visible and the client area of the tree is
- * smaller that the size of one item, TVM_ENSUREVISIBLE makes
- * the next item in the tree visible by making it the top item
- * instead of making the desired item visible. The fix is to
- * detect the case when the client area is too small and make
- * the desired visible item be the top item in the tree.
- */
- if (OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0) == 0) {
- OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, hItem);
- OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP ,0);
- } else {
- boolean scroll = true;
- RECT itemRect = new RECT ();
- itemRect.left = hItem;
- if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, itemRect) != 0) {
- RECT rect = new RECT ();
- OS.GetClientRect (handle, rect);
- POINT pt = new POINT ();
- pt.x = itemRect.left;
- pt.y = itemRect.top;
- if (OS.PtInRect (rect, pt)) {
- pt.y = itemRect.bottom;
- if (OS.PtInRect (rect, pt)) scroll = false;
- }
- }
- if (scroll) OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, hItem);
- }
-}
-
-/**
- * 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);
- showItem (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 ();
- int hItem = 0;
- if ((style & SWT.SINGLE) != 0) {
- hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
- if (hItem == 0) return;
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_STATE;
- tvItem.hItem = hItem;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- if ((tvItem.state & OS.TVIS_SELECTED) == 0) return;
- } else {
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_STATE;
- int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC);
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc);
- int index = 0;
- while (index <items.length) {
- TreeItem item = items [index];
- if (item != null) {
- tvItem.hItem = item.handle;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
- hItem = tvItem.hItem;
- break;
- }
- }
- index++;
- }
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
- }
- if (hItem != 0) showItem (hItem);
-}
-
-String toolTipText (NMTTDISPINFO hdr) {
- int hwndToolTip = OS.SendMessage (handle, OS.TVM_GETTOOLTIPS, 0, 0);
- if (hwndToolTip == hdr.hwndFrom && toolTipText != null) return "";
- return super.toolTipText (hdr);
-}
-
-int widgetStyle () {
- int bits = super.widgetStyle () | OS.TVS_SHOWSELALWAYS;
- bits |= OS.TVS_LINESATROOT | OS.TVS_HASLINES | OS.TVS_HASBUTTONS;
- /*
- * This code is intentionally commented. In future,
- * FULL_SELECTION may be implemented for trees.
- */
-// if ((style & SWT.FULL_SELECTION) != 0) {
-// bits |= OS.TVS_FULLROWSELECT;
-// } else {
-// bits |= OS.TVS_HASLINES | OS.TVS_HASBUTTONS;
-// }
-// bits |= OS.TVS_NOTOOLTIPS;
- return bits;
-}
-
-TCHAR windowClass () {
- return TreeClass;
-}
-
-int windowProc () {
- return TreeProc;
-}
-
-LRESULT WM_CHAR (int wParam, int lParam) {
- LRESULT result = super.WM_CHAR (wParam, lParam);
- if (result != null) return result;
- /*
- * Feature in Windows. The tree control beeps
- * in WM_CHAR when the search for the item that
- * matches the key stroke fails. This is the
- * standard tree behavior but is unexpected when
- * the key that was typed was ESC, CR or SPACE.
- * The fix is to avoid calling the tree window
- * proc in these cases.
- */
- switch (wParam) {
- case OS.VK_ESCAPE:
- case OS.VK_RETURN:
- case OS.VK_SPACE: return LRESULT.ZERO;
- }
- return result;
-}
-
-LRESULT WM_GETOBJECT (int wParam, int lParam) {
- /*
- * Ensure that there is an accessible object created for this
- * control because support for checked item accessibility is
- * temporarily implemented in the accessibility package.
- */
- if ((style & SWT.CHECK) != 0) {
- if (accessible == null) accessible = new_Accessible (this);
- }
- return super.WM_GETOBJECT (wParam, lParam);
-}
-
-LRESULT WM_KEYDOWN (int wParam, int lParam) {
- LRESULT result = super.WM_KEYDOWN (wParam, lParam);
- if (result != null) return result;
- switch (wParam) {
- case OS.VK_SPACE: {
- int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
- if (hItem != 0) {
- hAnchor = hItem;
- OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, hItem);
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_STATE | OS.TVIF_PARAM;
- tvItem.hItem = hItem;
- if ((style & SWT.CHECK) != 0) {
- tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- int state = tvItem.state >> 12;
- if ((state & 0x1) != 0) {
- state++;
- } else {
- --state;
- }
- tvItem.state = state << 12;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- }
- tvItem.stateMask = OS.TVIS_SELECTED;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- if ((style & SWT.MULTI) != 0 && OS.GetKeyState (OS.VK_CONTROL) < 0) {
- if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
- tvItem.state &= ~OS.TVIS_SELECTED;
- } else {
- tvItem.state |= OS.TVIS_SELECTED;
- }
- } else {
- tvItem.state |= OS.TVIS_SELECTED;
- }
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- Event event = new Event ();
- event.item = items [tvItem.lParam];
- postEvent (SWT.Selection, event);
- if ((style & SWT.CHECK) != 0) {
- event = new Event ();
- event.item = items [tvItem.lParam];
- event.detail = SWT.CHECK;
- postEvent (SWT.Selection, event);
- }
- return LRESULT.ZERO;
- }
- break;
- }
- case OS.VK_UP:
- case OS.VK_DOWN:
- case OS.VK_PRIOR:
- case OS.VK_NEXT:
- case OS.VK_HOME:
- case OS.VK_END: {
- if ((style & SWT.SINGLE) != 0) break;
- if (OS.GetKeyState (OS.VK_SHIFT) < 0) {
- int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
- if (hItem != 0) {
- if (hAnchor == 0) hAnchor = hItem;
- ignoreSelect = ignoreDeselect = true;
- int code = callWindowProc (OS.WM_KEYDOWN, wParam, lParam);
- ignoreSelect = ignoreDeselect = false;
- int hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_STATE;
- tvItem.stateMask = OS.TVIS_SELECTED;
- int hDeselectItem = hItem;
- RECT rect1 = new RECT ();
- rect1.left = hAnchor;
- OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect1);
- RECT rect2 = rect2 = new RECT ();
- rect2.left = hDeselectItem;
- OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect2);
- int flags = rect1.top < rect2.top ? OS.TVGN_PREVIOUSVISIBLE : OS.TVGN_NEXTVISIBLE;
- while (hDeselectItem != hAnchor) {
- tvItem.hItem = hDeselectItem;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- hDeselectItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, flags, hDeselectItem);
- }
- int hSelectItem = hAnchor;
- rect1.left = hNewItem;
- OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect1);
- rect2.left = hSelectItem;
- OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect2);
- tvItem.state = OS.TVIS_SELECTED;
- flags = rect1.top < rect2.top ? OS.TVGN_PREVIOUSVISIBLE : OS.TVGN_NEXTVISIBLE;
- while (hSelectItem != hNewItem) {
- tvItem.hItem = hSelectItem;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- hSelectItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, flags, hSelectItem);
- }
- tvItem.hItem = hNewItem;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- tvItem.mask = OS.TVIF_PARAM;
- tvItem.hItem = hNewItem;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- Event event = new Event ();
- event.item = items [tvItem.lParam];
- postEvent (SWT.Selection, event);
- return new LRESULT (code);
- }
- }
- if (OS.GetKeyState (OS.VK_CONTROL) < 0) {
- int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
- if (hItem != 0) {
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_STATE;
- tvItem.stateMask = OS.TVIS_SELECTED;
- tvItem.hItem = hItem;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- boolean oldSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
- int hNewItem = 0;
- switch (wParam) {
- case OS.VK_UP:
- hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUSVISIBLE, hItem);
- break;
- case OS.VK_DOWN:
- hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
- break;
- case OS.VK_HOME:
- hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
- break;
- case OS.VK_PRIOR:
- hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
- if (hNewItem == hItem) {
- OS.SendMessage (handle, OS.WM_VSCROLL, OS.SB_PAGEUP, 0);
- hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
- }
- break;
- case OS.VK_NEXT:
- RECT rect = new RECT (), clientRect = new RECT ();
- OS.GetClientRect (handle, clientRect);
- hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
- do {
- int hVisible = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hNewItem);
- if (hVisible == 0) break;
- rect.left = hVisible;
- OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect);
- if (rect.bottom > clientRect.bottom) break;
- if ((hNewItem = hVisible) == hItem) {
- OS.SendMessage (handle, OS.WM_VSCROLL, OS.SB_PAGEDOWN, 0);
- }
- } while (hNewItem != 0);
- break;
- case OS.VK_END:
- hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_LASTVISIBLE, 0);
- break;
- }
- if (hNewItem != 0) {
- OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, hNewItem);
- tvItem.hItem = hNewItem;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- boolean newSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
- if (!newSelected && drawCount == 0) {
- OS.UpdateWindow (handle);
- OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
- /*
- * This code is intentionally commented.
- */
-// OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
- }
- ignoreSelect = true;
- OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hNewItem);
- ignoreSelect = false;
- if (oldSelected) {
- tvItem.state = OS.TVIS_SELECTED;
- tvItem.hItem = hItem;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- }
- if (!newSelected) {
- tvItem.state = 0;
- tvItem.hItem = hNewItem;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- }
- if (!newSelected && drawCount == 0) {
- RECT rect1 = new RECT (), rect2 = new RECT ();
- rect1.left = hItem; rect2.left = hNewItem;
- OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect1);
- OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect2);
- /*
- * This code is intentionally commented.
- */
-// OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
- OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
- if (OS.IsWinCE) {
- OS.InvalidateRect (handle, rect1, false);
- OS.InvalidateRect (handle, rect2, false);
- OS.UpdateWindow (handle);
- } else {
- int flags = OS.RDW_UPDATENOW | OS.RDW_INVALIDATE;
- OS.RedrawWindow (handle, rect1, 0, flags);
- OS.RedrawWindow (handle, rect2, 0, flags);
- }
- }
- return LRESULT.ZERO;
- }
- }
- }
- int code = callWindowProc (OS.WM_KEYDOWN, wParam, lParam);
- hAnchor = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
- return new LRESULT (code);
- }
- }
- return result;
-}
-
-LRESULT WM_KILLFOCUS (int wParam, int lParam) {
- LRESULT result = super.WM_KILLFOCUS (wParam, lParam);
- if ((style & SWT.SINGLE) != 0) return result;
- /*
- * Feature in Windows. When multiple item have
- * the TVIS_SELECTED state, Windows redraws only
- * the focused item in the color used to show the
- * selection when the tree loses or gains focus.
- * The fix is to force Windows to redraw all the
- * visible items when focus is gained or lost.
- */
- OS.InvalidateRect (handle, null, false);
- return result;
-}
-
-LRESULT WM_LBUTTONDOWN (int wParam, int lParam) {
-
- /*
- * Feature in Windows. When a tree item is
- * reselected, Windows does not issue a WM_NOTIFY.
- * This is inconsistent with the list widget and
- * other widgets in Windows. The fix is to detect
- * the case when an item is reselected and issue
- * the notification. The first part of this work
- * around is to ensure that the user has selected
- * an item.
- */
- TVHITTESTINFO lpht = new TVHITTESTINFO ();
- lpht.x = (short) (lParam & 0xFFFF);
- lpht.y = (short) (lParam >> 16);
- OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
- if (lpht.hItem == 0 || (lpht.flags & OS.TVHT_ONITEM) == 0) {
- sendMouseEvent (SWT.MouseDown, 1, OS.WM_LBUTTONDOWN, wParam, lParam);
- int code = callWindowProc (OS.WM_LBUTTONDOWN, wParam, lParam);
- if (OS.GetCapture () != handle) OS.SetCapture (handle);
- return new LRESULT (code);
- }
-
- /* Look for check/uncheck */
- if ((style & SWT.CHECK) != 0) {
- if ((lpht.flags & OS.TVHT_ONITEMSTATEICON) != 0) {
- TVITEM tvItem = new TVITEM ();
- tvItem.hItem = lpht.hItem;
- tvItem.mask = OS.TVIF_PARAM | OS.TVIF_STATE;
- tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- int state = tvItem.state >> 12;
- if ((state & 0x1) != 0) {
- state++;
- } else {
- --state;
- }
- tvItem.state = state << 12;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- Event event = new Event ();
- event.item = items [tvItem.lParam];
- event.detail = SWT.CHECK;
- postEvent (SWT.Selection, event);
- sendMouseEvent (SWT.MouseDown, 1, OS.WM_LBUTTONDOWN, wParam, lParam);
- if (OS.GetCapture () != handle) OS.SetCapture (handle);
- return LRESULT.ZERO;
- }
- }
-
- /* Get the selected state of the item under the mouse */
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_STATE;
- tvItem.stateMask = OS.TVIS_SELECTED;
- boolean hittestSelected = false;
- if ((style & SWT.MULTI) != 0) {
- tvItem.hItem = lpht.hItem;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- hittestSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
- }
-
- /* Get the selected state of the last selected item */
- int hOldItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
- if ((style & SWT.MULTI) != 0) {
- tvItem.hItem = hOldItem;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
-
- /* Check for CONTROL or drag selection */
- if (hittestSelected || (wParam & OS.MK_CONTROL) != 0) {
- if (drawCount == 0) {
- OS.UpdateWindow (handle);
- OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
- /*
- * This code is intentionally commented.
- */
-// OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
- }
- } else {
- deselectAll ();
- }
- }
-
- /* Do the selection */
- sendMouseEvent (SWT.MouseDown, 1, OS.WM_LBUTTONDOWN, wParam, lParam);
- dragStarted = false;
- ignoreDeselect = ignoreSelect = true;
- int code = callWindowProc (OS.WM_LBUTTONDOWN, wParam, lParam);
- ignoreDeselect = ignoreSelect = false;
- if (dragStarted && OS.GetCapture () != handle) OS.SetCapture (handle);
- int hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
-
- /*
- * Feature in Windows. When the old and new focused item
- * are the same, Windows does not check to make sure that
- * the item is actually selected, not just focused. The
- * fix is to force the item to draw selected by setting
- * the state mask. This is only necessary when the tree
- * is single select.
- */
- if ((style & SWT.SINGLE) != 0) {
- if (hOldItem == hNewItem) {
- tvItem.mask = OS.TVIF_STATE;
- tvItem.state = OS.TVIS_SELECTED;
- tvItem.stateMask = OS.TVIS_SELECTED;
- tvItem.hItem = hNewItem;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- }
- }
-
- /* Reselect the last item that was unselected */
- if ((style & SWT.MULTI) != 0) {
-
- /* Check for CONTROL and reselect the last item */
- if (hittestSelected || (wParam & OS.MK_CONTROL) != 0) {
- if (hOldItem == hNewItem && hOldItem == lpht.hItem) {
- if ((wParam & OS.MK_CONTROL) != 0) {
- tvItem.state ^= OS.TVIS_SELECTED;
- if (dragStarted) tvItem.state = OS.TVIS_SELECTED;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- }
- } else {
- if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
- tvItem.state = OS.TVIS_SELECTED;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- }
- if ((wParam & OS.MK_CONTROL) != 0 && !dragStarted) {
- if (hittestSelected) {
- tvItem.state = 0;
- tvItem.hItem = lpht.hItem;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- }
- }
- }
- if (drawCount == 0) {
- RECT rect1 = new RECT (), rect2 = new RECT ();
- rect1.left = hOldItem; rect2.left = hNewItem;
- OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect1);
- OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect2);
- /*
- * This code is intentionally commented.
- */
-// OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
- OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
- if (OS.IsWinCE) {
- OS.InvalidateRect (handle, rect1, false);
- OS.InvalidateRect (handle, rect2, false);
- OS.UpdateWindow (handle);
- } else {
- int flags = OS.RDW_UPDATENOW | OS.RDW_INVALIDATE;
- OS.RedrawWindow (handle, rect1, 0, flags);
- OS.RedrawWindow (handle, rect2, 0, flags);
- }
- }
- }
-
- /* Check for SHIFT or normal select and delect/reselect items */
- if ((wParam & OS.MK_CONTROL) == 0) {
- if (!hittestSelected || !dragStarted) {
- tvItem.state = 0;
- int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC);
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc);
- for (int i=0; i<items.length; i++) {
- TreeItem item = items [i];
- if (item != null && item.handle != hNewItem) {
- tvItem.hItem = item.handle;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- }
- }
- tvItem.hItem = hNewItem;
- tvItem.state = OS.TVIS_SELECTED;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
- if ((wParam & OS.MK_SHIFT) != 0) {
- RECT rect1 = new RECT ();
- if (hAnchor == 0) hAnchor = hNewItem;
- rect1.left = hAnchor;
- if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect1) != 0) {
- RECT rect2 = rect2 = new RECT ();
- rect2.left = hNewItem;
- OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect2);
- int flags = rect1.top < rect2.top ? OS.TVGN_NEXTVISIBLE : OS.TVGN_PREVIOUSVISIBLE;
- tvItem.state = OS.TVIS_SELECTED;
- int hItem = tvItem.hItem = hAnchor;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- while (hItem != hNewItem) {
- tvItem.hItem = hItem;
- OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
- hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, flags, hItem);
- }
- }
- }
- }
- }
- }
- if ((wParam & OS.MK_SHIFT) == 0) hAnchor = hNewItem;
-
- /* Issue notification */
- tvItem.hItem = hNewItem;
- tvItem.mask = OS.TVIF_PARAM;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- Event event = new Event ();
- event.item = items [tvItem.lParam];
- postEvent (SWT.Selection, event);
-
- /*
- * Feature in Windows. Inside WM_LBUTTONDOWN and WM_RBUTTONDOWN,
- * the widget starts a modal loop to determine if the user wants
- * to begin a drag/drop operation or marque select. Unfortunately,
- * this modal loop eats the corresponding mouse up. The fix is to
- * detect the cases when the modal loop has eaten the mouse up and
- * issue a fake mouse up.
- */
- if (dragStarted) {
- postEvent (SWT.DragDetect);
- } else {
- sendMouseEvent (SWT.MouseUp, 1, OS.WM_LBUTTONUP, wParam, lParam);
- }
- dragStarted = false;
- return new LRESULT (code);
-}
-
-LRESULT WM_RBUTTONDOWN (int wParam, int lParam) {
- /*
- * Feature in Windows. The receiver uses WM_RBUTTONDOWN
- * to initiate a drag/drop operation depending on how the
- * user moves the mouse. If the user clicks the right button,
- * without moving the mouse, the tree consumes the corresponding
- * WM_RBUTTONUP. The fix is to avoid calling the window proc for
- * the tree.
- */
- sendMouseEvent (SWT.MouseDown, 3, OS.WM_RBUTTONDOWN, wParam, lParam);
- /*
- * This code is intentionally commented.
- */
-// if (OS.GetCapture () != handle) OS.SetCapture (handle);
- setFocus ();
-
- /*
- * Feature in Windows. When the user selects a tree item
- * with the right mouse button, the item remains selected
- * only as long as the user does not release or move the
- * mouse. As soon as this happens, the selection snaps
- * back to the previous selection. This behavior can be
- * observed in the Explorer but is not instantly apparent
- * because the Explorer explicity sets the selection when
- * the user chooses a menu item. If the user cancels the
- * menu, the selection snaps back. The fix is to avoid
- * calling the window proc and do the selection ourselves.
- * This behavior is consistent with the table.
- */
- TVHITTESTINFO lpht = new TVHITTESTINFO ();
- lpht.x = (short) (lParam & 0xFFFF);
- lpht.y = (short) (lParam >> 16);
- OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
- if (lpht.hItem != 0 && (lpht.flags & (OS.TVHT_ONITEMICON | OS.TVHT_ONITEMLABEL)) != 0) {
- if ((wParam & (OS.MK_CONTROL | OS.MK_SHIFT)) == 0) {
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_STATE;
- tvItem.stateMask = OS.TVIS_SELECTED;
- tvItem.hItem = lpht.hItem;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- if ((tvItem.state & OS.TVIS_SELECTED) == 0) {
- ignoreSelect = true;
- OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, 0);
- ignoreSelect = false;
- OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, lpht.hItem);
- }
- }
- }
- return LRESULT.ZERO;
-}
-
-LRESULT WM_SETFOCUS (int wParam, int lParam) {
- LRESULT result = super.WM_SETFOCUS (wParam, lParam);
- if ((style & SWT.SINGLE) != 0) return result;
- /*
- * Feature in Windows. When multiple item have
- * the TVIS_SELECTED state, Windows redraws only
- * the focused item in the color used to show the
- * selection when the tree loses or gains focus.
- * The fix is to force Windows to redraw all the
- * visible items when focus is gained or lost.
- */
- OS.InvalidateRect (handle, null, false);
- return result;
-}
-
-LRESULT WM_SYSCOLORCHANGE (int wParam, int lParam) {
- LRESULT result = super.WM_SYSCOLORCHANGE (wParam, lParam);
- if (result != null) return result;
- if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
- return result;
-}
-
-LRESULT wmNotifyChild (int wParam, int lParam) {
- NMHDR hdr = new NMHDR ();
- OS.MoveMemory (hdr, lParam, NMHDR.sizeof);
- int code = hdr.code;
- switch (code) {
- case OS.NM_CUSTOMDRAW: {
- if (!customDraw) break;
- NMTVCUSTOMDRAW nmcd = new NMTVCUSTOMDRAW ();
- OS.MoveMemory (nmcd, lParam, NMTVCUSTOMDRAW.sizeof);
- switch (nmcd.dwDrawStage) {
- case OS.CDDS_PREPAINT: return new LRESULT (OS.CDRF_NOTIFYITEMDRAW);
- case OS.CDDS_ITEMPREPAINT:
- TreeItem item = items [nmcd.lItemlParam];
- /*
- * Feature on Windows. When a new tree item is inserted
- * using TVM_INSERTITEM and the tree is using custom draw,
- * a NM_CUSTOMDRAW is sent before TVM_INSERTITEM returns
- * and before the item is added to the items array. The
- * fix is to check for null.
- *
- * NOTE: This only happens on XP with the version 6.00 of
- * COMCTL32.DLL,
- */
- if (item == null) break;
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_STATE;
- tvItem.hItem = item.handle;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- if ((tvItem.state & OS.TVIS_SELECTED) != 0) break;
- int clrText = item.foreground, clrTextBk = item.background;
- if (clrText == -1 && clrTextBk == -1) break;
- nmcd.clrText = clrText == -1 ? getForegroundPixel () : clrText;
- nmcd.clrTextBk = clrTextBk == -1 ? getBackgroundPixel () : clrTextBk;
- OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
- return new LRESULT (OS.CDRF_NEWFONT);
- }
- break;
- }
- case OS.NM_DBLCLK:
- int pos = OS.GetMessagePos ();
- TVHITTESTINFO lpht = new TVHITTESTINFO ();
- POINT pt = new POINT ();
- pt.x = (short) (pos & 0xFFFF);
- pt.y = (short) (pos >> 16);
- OS.ScreenToClient (handle, pt);
- lpht.x = pt.x; lpht.y = pt.y;
- OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
- if ((lpht.flags & OS.TVHT_ONITEM) == 0) break;
- // FALL THROUGH
- case OS.NM_RETURN:
- case OS.TVN_SELCHANGEDA:
- case OS.TVN_SELCHANGEDW:
- if (!ignoreSelect) {
- TVITEM tvItem = null;
- if (code == OS.TVN_SELCHANGED) {
- tvItem = new TVITEM ();
- int offset = NMHDR.sizeof + 4 + TVITEM.sizeof;
- OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof);
- hAnchor = tvItem.hItem;
- } else {
- int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
- if (hItem != 0) {
- tvItem = new TVITEM ();
- tvItem.hItem = hItem;
- tvItem.mask = OS.TVIF_PARAM;
- OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
- }
- }
- Event event = new Event ();
- if (tvItem != null) {
- event.item = items [tvItem.lParam];
- }
- if (code == OS.TVN_SELCHANGED) {
- postEvent (SWT.Selection, event);
- } else {
- postEvent (SWT.DefaultSelection, event);
- }
- }
- if (code == OS.NM_DBLCLK && hooks (SWT.DefaultSelection)) {
- return LRESULT.ONE;
- }
- break;
- case OS.TVN_SELCHANGINGA:
- case OS.TVN_SELCHANGINGW:
- if (!ignoreSelect && !ignoreDeselect) {
- hAnchor = 0;
- if ((style & SWT.MULTI) != 0) deselectAll ();
- }
- break;
- case OS.TVN_ITEMEXPANDINGA:
- case OS.TVN_ITEMEXPANDINGW:
- if (!ignoreExpand) {
- TVITEM tvItem = new TVITEM ();
- int offset = NMHDR.sizeof + 4 + TVITEM.sizeof;
- OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof);
- int [] action = new int [1];
- OS.MoveMemory (action, lParam + NMHDR.sizeof, 4);
- Event event = new Event ();
- event.item = items [tvItem.lParam];
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the expand
- * or collapse event. If this happens, end the
- * processing of the Windows message by returning
- * zero as the result of the window proc.
- */
- if (action [0] == OS.TVE_EXPAND) {
- sendEvent (SWT.Expand, event);
- if (isDisposed ()) return LRESULT.ZERO;
- }
- if (action [0] == OS.TVE_COLLAPSE) {
- sendEvent (SWT.Collapse, event);
- if (isDisposed ()) return LRESULT.ZERO;
- }
- }
- break;
- case OS.TVN_BEGINDRAGA:
- case OS.TVN_BEGINDRAGW:
- case OS.TVN_BEGINRDRAGA:
- case OS.TVN_BEGINRDRAGW:
- TVITEM tvItem = new TVITEM ();
- int offset = NMHDR.sizeof + 4 + TVITEM.sizeof;
- OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof);
- if (tvItem.hItem != 0 && (tvItem.state & OS.TVIS_SELECTED) == 0) {
- ignoreSelect = ignoreDeselect = true;
- OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, tvItem.hItem);
- ignoreSelect = ignoreDeselect = false;
- }
- dragStarted = true;
- break;
- }
- return super.wmNotifyChild (wParam, lParam);
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.events.*; + +/** + * Instances of this class provide a selectable user interface object + * that displays a hierarchy of items and issue notificiation 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> + * 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>SINGLE, MULTI, CHECK</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection, DefaultSelection, Collapse, Expand</dd> + * </dl> + * <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> + */ +public class Tree extends Composite { + int hAnchor; + TreeItem [] items; + ImageList imageList; + boolean dragStarted; + boolean ignoreSelect, ignoreExpand, ignoreDeselect; + boolean customDraw; + static final int TreeProc; + static final TCHAR TreeClass = new TCHAR (0, OS.WC_TREEVIEW, true); + static { + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, TreeClass, lpWndClass); + TreeProc = lpWndClass.lpfnWndProc; + } + +/** + * 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 Widget#checkSubclass + * @see Widget#getStyle + */ +public Tree (Composite parent, int style) { + super (parent, checkStyle (style)); +} + +/** + * Adds the listener to the collection of listeners who will + * be notified when the receiver's selection changes, 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 reciever has <code>SWT.CHECK</code> style set 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 + * + * @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 callWindowProc (int msg, int wParam, int lParam) { + if (handle == 0) return 0; + return OS.CallWindowProc (TreeProc, handle, msg, wParam, lParam); +} + +static int checkStyle (int style) { + /* + * Feature in Windows. It is not possible to create + * a tree that scrolls and does not have scroll bars. + * The TVS_NOSCROLL style will remove the scroll bars + * but the tree will never scroll. Therefore, no matter + * what style bits are specified, set the H_SCROLL and + * V_SCROLL bits so that the SWT style will match the + * widget that Windows creates. + */ + style |= SWT.H_SCROLL | SWT.V_SCROLL; + return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0); +} + + +public Point computeSize (int wHint, int hHint, boolean changed) { + checkWidget (); + int width = 0, height = 0; + RECT rect = new RECT (); + int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); + while (hItem != 0) { + rect.left = hItem; + if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect) != 0) { + width = Math.max (width, rect.right - rect.left); + height += rect.bottom - rect.top; + } + hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem); + } + width = width * 2; + 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; + if ((style & SWT.V_SCROLL) != 0) { + width += OS.GetSystemMetrics (OS.SM_CXVSCROLL); + } + if ((style & SWT.H_SCROLL) != 0) { + height += OS.GetSystemMetrics (OS.SM_CYHSCROLL); + } + return new Point (width, height); +} + +void createHandle () { + super.createHandle (); + state &= ~CANVAS; + + /* Set the checkbox image list */ + if ((style & SWT.CHECK) != 0) setCheckboxImageList (); + + /* + * Feature in Windows. When the control is created, + * it does not use the default system font. A new HFONT + * is created and destroyed when the control is destroyed. + * This means that a program that queries the font from + * this control, uses the font in another control and then + * destroys this control will have the font unexpectedly + * destroyed in the other control. The fix is to assign + * the font ourselves each time the control is created. + * The control will not destroy a font that it did not + * create. + */ + int hFont = OS.GetStockObject (OS.SYSTEM_FONT); + OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0); +} + +void createItem (TreeItem item, int hParent, int hInsertAfter) { + item.foreground = item.background = -1; + int id = 0; + while (id < items.length && items [id] != null) id++; + if (id == items.length) { + TreeItem [] newItems = new TreeItem [items.length + 4]; + System.arraycopy (items, 0, newItems, 0, items.length); + items = newItems; + } + TVINSERTSTRUCT tvInsert = new TVINSERTSTRUCT (); + tvInsert.hParent = hParent; + tvInsert.hInsertAfter = hInsertAfter; + tvInsert.lParam = id; + tvInsert.iImage = OS.I_IMAGENONE; + tvInsert.iSelectedImage = tvInsert.iImage; + tvInsert.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_IMAGE | OS.TVIF_SELECTEDIMAGE; + + /* Set the initial unchecked state */ + if ((style & SWT.CHECK) != 0) { + tvInsert.mask = tvInsert.mask | OS.TVIF_STATE; + tvInsert.state = 1 << 12; + tvInsert.stateMask = OS.TVIS_STATEIMAGEMASK; + } + + /* Insert the item */ + int hItem = OS.SendMessage (handle, OS.TVM_INSERTITEM, 0, tvInsert); + if (hItem == 0) error (SWT.ERROR_ITEM_NOT_ADDED); + item.handle = hItem; + items [id] = item; + + /* + * This code is intentionally commented. + */ +// if (hParent != 0) { +// int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); +// bits |= OS.TVS_LINESATROOT; +// OS.SetWindowLong (handle, OS.GWL_STYLE, bits); +// } + + /* + * Bug in Windows. When a child item is added to a parent item + * that has no children outside of WM_NOTIFY with control code + * TVN_ITEMEXPANDED, the tree widget does not redraw the +/- + * indicator. The fix is to detect this case and force a redraw. + */ + if (!OS.IsWindowVisible (handle) || drawCount > 0) return; + int hChild = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hParent); + if (hChild == 0 || OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hChild) != 0) { + return; + } + RECT rect = new RECT (); + rect.left = hParent; + if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect) != 0) { + OS.InvalidateRect (handle, rect, false); + } +} + +void createWidget () { + super.createWidget (); + items = new TreeItem [4]; +} + +int defaultBackground () { + return OS.GetSysColor (OS.COLOR_WINDOW); +} + +/** + * 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 (); + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_STATE; + tvItem.stateMask = OS.TVIS_SELECTED; + if ((style & SWT.SINGLE) != 0) { + int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + if (hItem != 0) { + tvItem.hItem = hItem; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + } + return; + } + int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC); + OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc); + for (int i=0; i<items.length; i++) { + TreeItem item = items [i]; + if (item != null) { + tvItem.hItem = item.handle; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + } + } + OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc); +} + +void destroyItem (TreeItem item) { + int hItem = item.handle; + boolean fixRedraw = false; + if (drawCount == 0 && OS.IsWindowVisible (handle)) { + RECT rect = new RECT (); + rect.left = hItem; + fixRedraw = OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect) == 0; + } + if (fixRedraw) { + OS.UpdateWindow (handle); + OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); + } + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM; + releaseItems (item.getItems (), tvItem); + releaseItem (item, tvItem); + OS.SendMessage (handle, OS.TVM_DELETEITEM, 0, hItem); + if (fixRedraw) { + OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0); + OS.ValidateRect (handle, null); + } + int count = OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0); + if (count == 0) { + if (imageList != null) { + OS.SendMessage (handle, OS.TVM_SETIMAGELIST, 0, 0); + Display display = getDisplay (); + display.releaseImageList (imageList); + } + imageList = null; + customDraw = false; + items = new TreeItem [4]; + } +} + +int getBackgroundPixel () { + if (OS.IsWinCE) return OS.GetSysColor (OS.COLOR_WINDOW); + int pixel = OS.SendMessage (handle, OS.TVM_GETBKCOLOR, 0, 0); + if (pixel == -1) return OS.GetSysColor (OS.COLOR_WINDOW); + return pixel; +} + +int getForegroundPixel () { + if (OS.IsWinCE) return OS.GetSysColor (OS.COLOR_WINDOWTEXT); + int pixel = OS.SendMessage (handle, OS.TVM_GETTEXTCOLOR, 0, 0); + if (pixel == -1) return OS.GetSysColor (OS.COLOR_WINDOWTEXT); + return pixel; +} + +/** + * 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 TreeItem getItem (Point point) { + checkWidget (); + if (point == null) error (SWT.ERROR_NULL_ARGUMENT); + TVHITTESTINFO lpht = new TVHITTESTINFO (); + lpht.x = point.x; lpht.y = point.y; + OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht); + if (lpht.hItem != 0 && (lpht.flags & OS.TVHT_ONITEM) != 0) { + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM; + tvItem.hItem = lpht.hItem; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + return items [tvItem.lParam]; + } + 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 (); + int count = 0; + int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); + while (hItem != 0) { + hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem); + count++; + } + return count; +} + +/** + * 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 OS.SendMessage (handle, OS.TVM_GETITEMHEIGHT, 0, 0); +} + +/** + * Returns the number 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 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 TreeItem [] getItems () { + checkWidget (); + int count = 0; + int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); + while (hItem != 0) { + hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem); + count++; + } + int index = 0; + TreeItem [] result = new TreeItem [count]; + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM; + tvItem.hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); + while (tvItem.hItem != 0) { + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + result [index++] = items [tvItem.lParam]; + tvItem.hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, tvItem.hItem); + } + return result; +} + +/** + * 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. 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 (); + if ((style & SWT.SINGLE) != 0) { + int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + if (hItem == 0) return new TreeItem [0]; + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_PARAM | OS.TVIF_STATE; + tvItem.hItem = hItem; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + if ((tvItem.state & OS.TVIS_SELECTED) == 0) return new TreeItem [0]; + return new TreeItem [] {items [tvItem.lParam]}; + } + int count = 0; + TreeItem [] guess = new TreeItem [8]; + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_PARAM | OS.TVIF_STATE; + int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC); + OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc); + for (int i=0; i<items.length; i++) { + TreeItem item = items [i]; + if (item != null) { + tvItem.hItem = item.handle; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + if ((tvItem.state & OS.TVIS_SELECTED) != 0) { + if (count < guess.length) guess [count] = item; + count++; + } + } + } + OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc); + if (count == 0) return new TreeItem [0]; + if (count == guess.length) return guess; + TreeItem [] result = new TreeItem [count]; + if (count < guess.length) { + System.arraycopy (guess, 0, result, 0, count); + return result; + } + OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc); + int index = 0; + for (int i=0; i<items.length; i++) { + TreeItem item = items [i]; + if (item != null) { + tvItem.hItem = item.handle; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + if ((tvItem.state & OS.TVIS_SELECTED) != 0) { + result [index++] = item; + } + } + } + OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc); + 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 (); + if ((style & SWT.SINGLE) != 0) { + int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + if (hItem == 0) return 0; + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_STATE; + tvItem.hItem = hItem; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + if ((tvItem.state & OS.TVIS_SELECTED) == 0) return 0; + return 1; + } + int count = 0; + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_STATE; + int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC); + OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc); + for (int i=0; i<items.length; i++) { + TreeItem item = items [i]; + if (item != null) { + tvItem.hItem = item.handle; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + if ((tvItem.state & OS.TVIS_SELECTED) != 0) count++; + } + } + OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc); + return count; +} + +/** + * 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 (); + int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0); + if (hItem == 0) return null; + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_PARAM; + tvItem.hItem = hItem; + if (OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem) == 0) return null; + return items [tvItem.lParam]; +} + +int imageIndex (Image image) { + if (image == null) return OS.I_IMAGENONE; + if (imageList == null) { + int hOldList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0); + if (hOldList != 0) OS.ImageList_Destroy (hOldList); + Rectangle bounds = image.getBounds (); + imageList = getDisplay ().getImageList (new Point (bounds.width, bounds.height)); + int index = imageList.indexOf (image); + if (index == -1) index = imageList.add (image); + int hImageList = imageList.getHandle (); + OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, hImageList); + return index; + } + int index = imageList.indexOf (image); + if (index != -1) return index; + return imageList.add (image); +} + +boolean releaseItem (TreeItem item, TVITEM tvItem) { + int hItem = item.handle; + if (hItem == hAnchor) hAnchor = 0; + if (item.isDisposed ()) return false; + tvItem.hItem = hItem; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + items [tvItem.lParam] = null; + return true; +} + +void releaseItems (TreeItem [] nodes, TVITEM tvItem) { + for (int i=0; i<nodes.length; i++) { + TreeItem item = nodes [i]; + TreeItem [] sons = item.getItems (); + if (sons.length != 0) { + releaseItems (sons, tvItem); + } + if (releaseItem (item, tvItem)) { + item.releaseResources (); + } + } +} + +void releaseWidget () { + for (int i=0; i<items.length; i++) { + TreeItem item = items [i]; + if (item != null && !item.isDisposed ()) { + item.releaseResources (); + } + } + /* + * Feature in Windows. For some reason, when + * TVM_GETIMAGELIST or TVM_SETIMAGELIST is sent, + * the tree issues NM_CUSTOMDRAW messages. This + * behavior is unwanted when the tree is being + * disposed. The fix is to ingore NM_CUSTOMDRAW + * messages by usnig the custom draw flag. + * + * NOTE: This only happens on Windows XP. + */ + customDraw = false; + items = null; + if (imageList != null) { + OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, 0); + Display display = getDisplay (); + display.releaseImageList (imageList); + } else { + int hOldList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0); + OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, 0); + if (hOldList != 0) OS.ImageList_Destroy (hOldList); + } + imageList = null; + int hOldList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_STATE, 0); + OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_STATE, 0); + if (hOldList != 0) OS.ImageList_Destroy (hOldList); + super.releaseWidget (); +} + + +/** + * 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 (); + ignoreDeselect = ignoreSelect = true; + if (drawCount == 0) { + OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); + /* + * This code is intentionally commented. + */ +// OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); + } + int result = OS.SendMessage (handle, OS.TVM_DELETEITEM, 0, OS.TVI_ROOT); + if (drawCount == 0) { + OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); + /* + * This code is intentionally commented. + */ +// OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0); + OS.InvalidateRect (handle, null, true); + } + ignoreDeselect = ignoreSelect = false; + if (result == 0) error (SWT.ERROR_ITEM_NOT_REMOVED); + for (int i=0; i<items.length; i++) { + TreeItem item = items [i]; + if (item != null && !item.isDisposed ()) { + item.releaseResources (); + } + } + if (imageList != null) { + OS.SendMessage (handle, OS.TVM_SETIMAGELIST, 0, 0); + Display display = getDisplay (); + display.releaseImageList (imageList); + } + imageList = null; + customDraw = false; + items = new TreeItem [4]; + hAnchor = 0; +} + +/** + * Removes the listener from the collection of listeners who will + * be notified when the receiver's selection changes. + * + * @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); +} + +/** + * 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 after 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 (); + int hItem = 0; + if (item != null) { + if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); + hItem = item.handle; + } + OS.SendMessage (handle, OS.TVM_SETINSERTMARK, (before) ? 0 : 1, hItem); +} + +/** + * Selects all 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 void selectAll () { + checkWidget (); + if ((style & SWT.SINGLE) != 0) return; + int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + if (hItem == 0) { + hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); + if (hItem != 0) { + ignoreSelect = true; + OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hItem); + ignoreSelect = false; + } + } + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_STATE; + tvItem.state = OS.TVIS_SELECTED; + tvItem.stateMask = OS.TVIS_SELECTED; + int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC); + OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc); + for (int i=0; i<items.length; i++) { + TreeItem item = items [i]; + if (item != null) { + tvItem.hItem = item.handle; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + } + } + OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc); +} + +void setBackgroundPixel (int pixel) { + if (background == pixel) return; + background = pixel; + /* + * Bug in Windows. When TVM_GETBKCOLOR is used more + * than once to set the background color of a tree, + * the background color of the lines and the plus/minus + * does not change to the new color. The fix is to set + * the background color to the default before setting + * the new color. + */ + int oldPixel = OS.SendMessage (handle, OS.TVM_GETBKCOLOR, 0, 0); + if (oldPixel != -1) OS.SendMessage (handle, OS.TVM_SETBKCOLOR, 0, -1); + OS.SendMessage (handle, OS.TVM_SETBKCOLOR, 0, pixel); + if ((style & SWT.CHECK) != 0) setCheckboxImageList (); +} + +void setBounds (int x, int y, int width, int height, int flags) { + /* + * Ensure that the selection is visible when the tree is resized + * from a zero size to a size that can show the selection. + */ + boolean fixSelection = false; + if ((flags & OS.SWP_NOSIZE) == 0 && (width != 0 || height != 0)) { + if (OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0) == 0) { + fixSelection = true; + } + } + super.setBounds (x, y, width, height, flags); + if (fixSelection) { + int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + if (hItem != 0) showItem (hItem); + } +} + +void setCheckboxImageList () { + if ((style & SWT.CHECK) == 0) return; + int count = 5; + int height = OS.SendMessage (handle, OS.TVM_GETITEMHEIGHT, 0, 0), width = height; + int hImageList = OS.ImageList_Create (width, height, OS.ILC_COLOR, count, count); + int hDC = OS.GetDC (handle); + int memDC = OS.CreateCompatibleDC (hDC); + int hBitmap = OS.CreateCompatibleBitmap (hDC, width * count, height); + int hOldBitmap = OS.SelectObject (memDC, hBitmap); + RECT rect = new RECT (); + OS.SetRect (rect, 0, 0, width * count, height); + int hBrush = OS.CreateSolidBrush (getBackgroundPixel ()); + OS.FillRect (memDC, rect, hBrush); + OS.DeleteObject (hBrush); + int oldFont = OS.SelectObject (hDC, defaultFont ()); + TEXTMETRIC tm = new TEXTMETRIC (); + OS.GetTextMetrics (hDC, tm); + OS.SelectObject (hDC, oldFont); + int itemWidth = Math.min (tm.tmHeight, width); + int itemHeight = Math.min (tm.tmHeight, height); + int left = (width - itemWidth) / 2, top = (height - itemHeight) / 2 + 1; + OS.SetRect (rect, left + width, top, left + width + itemWidth, top + itemHeight); + OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_FLAT); + rect.left += width; rect.right += width; + OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_CHECKED | OS.DFCS_FLAT); + rect.left += width; rect.right += width; + OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_INACTIVE | OS.DFCS_FLAT); + rect.left += width; rect.right += width; + OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_CHECKED | OS.DFCS_INACTIVE | OS.DFCS_FLAT); + OS.SelectObject (memDC, hOldBitmap); + OS.DeleteDC (memDC); + OS.ReleaseDC (handle, hDC); + OS.ImageList_AddMasked (hImageList, hBitmap, 0); + OS.DeleteObject (hBitmap); + int hOldList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_STATE, 0); + OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_STATE, hImageList); + if (hOldList != 0) OS.ImageList_Destroy (hOldList); +} + +void setForegroundPixel (int pixel) { + if (foreground == pixel) return; + foreground = pixel; + OS.SendMessage (handle, OS.TVM_SETTEXTCOLOR, 0, pixel); +} + +public void setRedraw (boolean redraw) { + checkWidget (); + /* + * Bug in Windows. For some reason, when WM_SETREDRAW + * is used to turn redraw on for a tree and the tree + * contains no items, the last item in the tree does + * not redraw properly. If the tree has only one item, + * that item is not drawn. If another window is dragged + * on top of the item, parts of the item are redrawn + * and erased at random. The fix is to ensure that this + * case doesn't happen by inserting and deleting an item + * when redraw is turned on and there are no items in + * the tree. + */ + int hItem = 0; + if (redraw) { + int count = OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0); + if (count == 0) { + TVINSERTSTRUCT tvInsert = new TVINSERTSTRUCT (); + tvInsert.hInsertAfter = OS.TVI_FIRST; + hItem = OS.SendMessage (handle, OS.TVM_INSERTITEM, 0, tvInsert); + } + } + super.setRedraw (redraw); + if (hItem != 0) { + OS.SendMessage (handle, OS.TVM_DELETEITEM, 0, hItem); + } +} + +/** + * 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 array of items is null</li> + * <li>ERROR_INVALID_ARGUMENT - if one of 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#deselectAll() + */ +public void setSelection (TreeItem [] items) { + checkWidget (); + if (items == null) error (SWT.ERROR_NULL_ARGUMENT); + + /* Select/deselect the first item */ + int hOldItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + if (items.length == 0) { + if (hOldItem != 0) { + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_STATE; + tvItem.stateMask = OS.TVIS_SELECTED; + tvItem.hItem = hOldItem; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + } + } else { + int hNewItem = 0; + TreeItem item = items [0]; + if (item != null) { + if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); + hAnchor = hNewItem = item.handle; + } + ignoreSelect = true; + OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hNewItem); + ignoreSelect = false; + /* + * Feature in Windows. When the old and new focused item + * are the same, Windows does not check to make sure that + * the item is actually selected, not just focused. The + * fix is to force the item to draw selected by setting + * the state mask. + */ + if (hOldItem == hNewItem) { + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_STATE; + tvItem.state = OS.TVIS_SELECTED; + tvItem.stateMask = OS.TVIS_SELECTED; + tvItem.hItem = hNewItem; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + } + showItem (hNewItem); + } + if ((style & SWT.SINGLE) != 0) return; + + /* Select/deselect the rest of the items */ + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_STATE; + tvItem.stateMask = OS.TVIS_SELECTED; + int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC); + OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc); + for (int i=0; i<this.items.length; i++) { + TreeItem item = this.items [i]; + if (item != null) { + int index = 0; + while (index < items.length) { + if (items [index] == item) break; + index++; + } + tvItem.hItem = item.handle; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + if ((tvItem.state & OS.TVIS_SELECTED) != 0) { + if (index == items.length) { + tvItem.state = 0; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + } + } else { + if (index != items.length) { + tvItem.state = OS.TVIS_SELECTED; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + } + } + } + } + OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc); +} + +/** + * 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) SWT.error (SWT.ERROR_NULL_ARGUMENT); + if (item.isDisposed ()) SWT.error (SWT.ERROR_INVALID_ARGUMENT); + OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, item.handle); +} + +void showItem (int hItem) { + /* + * Bug in Windows. When TVM_ENSUREVISIBLE is used to ensure + * that an item is visible and the client area of the tree is + * smaller that the size of one item, TVM_ENSUREVISIBLE makes + * the next item in the tree visible by making it the top item + * instead of making the desired item visible. The fix is to + * detect the case when the client area is too small and make + * the desired visible item be the top item in the tree. + */ + if (OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0) == 0) { + OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, hItem); + OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP ,0); + } else { + boolean scroll = true; + RECT itemRect = new RECT (); + itemRect.left = hItem; + if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, itemRect) != 0) { + RECT rect = new RECT (); + OS.GetClientRect (handle, rect); + POINT pt = new POINT (); + pt.x = itemRect.left; + pt.y = itemRect.top; + if (OS.PtInRect (rect, pt)) { + pt.y = itemRect.bottom; + if (OS.PtInRect (rect, pt)) scroll = false; + } + } + if (scroll) OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, hItem); + } +} + +/** + * 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); + showItem (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 (); + int hItem = 0; + if ((style & SWT.SINGLE) != 0) { + hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + if (hItem == 0) return; + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_STATE; + tvItem.hItem = hItem; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + if ((tvItem.state & OS.TVIS_SELECTED) == 0) return; + } else { + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_STATE; + int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC); + OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc); + int index = 0; + while (index <items.length) { + TreeItem item = items [index]; + if (item != null) { + tvItem.hItem = item.handle; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + if ((tvItem.state & OS.TVIS_SELECTED) != 0) { + hItem = tvItem.hItem; + break; + } + } + index++; + } + OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc); + } + if (hItem != 0) showItem (hItem); +} + +String toolTipText (NMTTDISPINFO hdr) { + int hwndToolTip = OS.SendMessage (handle, OS.TVM_GETTOOLTIPS, 0, 0); + if (hwndToolTip == hdr.hwndFrom && toolTipText != null) return ""; + return super.toolTipText (hdr); +} + +int widgetStyle () { + int bits = super.widgetStyle () | OS.TVS_SHOWSELALWAYS; + bits |= OS.TVS_LINESATROOT | OS.TVS_HASLINES | OS.TVS_HASBUTTONS; + /* + * This code is intentionally commented. In future, + * FULL_SELECTION may be implemented for trees. + */ +// if ((style & SWT.FULL_SELECTION) != 0) { +// bits |= OS.TVS_FULLROWSELECT; +// } else { +// bits |= OS.TVS_HASLINES | OS.TVS_HASBUTTONS; +// } +// bits |= OS.TVS_NOTOOLTIPS; + return bits; +} + +TCHAR windowClass () { + return TreeClass; +} + +int windowProc () { + return TreeProc; +} + +LRESULT WM_CHAR (int wParam, int lParam) { + LRESULT result = super.WM_CHAR (wParam, lParam); + if (result != null) return result; + /* + * Feature in Windows. The tree control beeps + * in WM_CHAR when the search for the item that + * matches the key stroke fails. This is the + * standard tree behavior but is unexpected when + * the key that was typed was ESC, CR or SPACE. + * The fix is to avoid calling the tree window + * proc in these cases. + */ + switch (wParam) { + case OS.VK_ESCAPE: + case OS.VK_RETURN: + case OS.VK_SPACE: return LRESULT.ZERO; + } + return result; +} + +LRESULT WM_GETOBJECT (int wParam, int lParam) { + /* + * Ensure that there is an accessible object created for this + * control because support for checked item accessibility is + * temporarily implemented in the accessibility package. + */ + if ((style & SWT.CHECK) != 0) { + if (accessible == null) accessible = new_Accessible (this); + } + return super.WM_GETOBJECT (wParam, lParam); +} + +LRESULT WM_KEYDOWN (int wParam, int lParam) { + LRESULT result = super.WM_KEYDOWN (wParam, lParam); + if (result != null) return result; + switch (wParam) { + case OS.VK_SPACE: { + int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + if (hItem != 0) { + hAnchor = hItem; + OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, hItem); + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_STATE | OS.TVIF_PARAM; + tvItem.hItem = hItem; + if ((style & SWT.CHECK) != 0) { + tvItem.stateMask = OS.TVIS_STATEIMAGEMASK; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + int state = tvItem.state >> 12; + if ((state & 0x1) != 0) { + state++; + } else { + --state; + } + tvItem.state = state << 12; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + } + tvItem.stateMask = OS.TVIS_SELECTED; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + if ((style & SWT.MULTI) != 0 && OS.GetKeyState (OS.VK_CONTROL) < 0) { + if ((tvItem.state & OS.TVIS_SELECTED) != 0) { + tvItem.state &= ~OS.TVIS_SELECTED; + } else { + tvItem.state |= OS.TVIS_SELECTED; + } + } else { + tvItem.state |= OS.TVIS_SELECTED; + } + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + Event event = new Event (); + event.item = items [tvItem.lParam]; + postEvent (SWT.Selection, event); + if ((style & SWT.CHECK) != 0) { + event = new Event (); + event.item = items [tvItem.lParam]; + event.detail = SWT.CHECK; + postEvent (SWT.Selection, event); + } + return LRESULT.ZERO; + } + break; + } + case OS.VK_UP: + case OS.VK_DOWN: + case OS.VK_PRIOR: + case OS.VK_NEXT: + case OS.VK_HOME: + case OS.VK_END: { + if ((style & SWT.SINGLE) != 0) break; + if (OS.GetKeyState (OS.VK_SHIFT) < 0) { + int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + if (hItem != 0) { + if (hAnchor == 0) hAnchor = hItem; + ignoreSelect = ignoreDeselect = true; + int code = callWindowProc (OS.WM_KEYDOWN, wParam, lParam); + ignoreSelect = ignoreDeselect = false; + int hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_STATE; + tvItem.stateMask = OS.TVIS_SELECTED; + int hDeselectItem = hItem; + RECT rect1 = new RECT (); + rect1.left = hAnchor; + OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect1); + RECT rect2 = rect2 = new RECT (); + rect2.left = hDeselectItem; + OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect2); + int flags = rect1.top < rect2.top ? OS.TVGN_PREVIOUSVISIBLE : OS.TVGN_NEXTVISIBLE; + while (hDeselectItem != hAnchor) { + tvItem.hItem = hDeselectItem; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + hDeselectItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, flags, hDeselectItem); + } + int hSelectItem = hAnchor; + rect1.left = hNewItem; + OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect1); + rect2.left = hSelectItem; + OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect2); + tvItem.state = OS.TVIS_SELECTED; + flags = rect1.top < rect2.top ? OS.TVGN_PREVIOUSVISIBLE : OS.TVGN_NEXTVISIBLE; + while (hSelectItem != hNewItem) { + tvItem.hItem = hSelectItem; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + hSelectItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, flags, hSelectItem); + } + tvItem.hItem = hNewItem; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + tvItem.mask = OS.TVIF_PARAM; + tvItem.hItem = hNewItem; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + Event event = new Event (); + event.item = items [tvItem.lParam]; + postEvent (SWT.Selection, event); + return new LRESULT (code); + } + } + if (OS.GetKeyState (OS.VK_CONTROL) < 0) { + int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + if (hItem != 0) { + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_STATE; + tvItem.stateMask = OS.TVIS_SELECTED; + tvItem.hItem = hItem; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + boolean oldSelected = (tvItem.state & OS.TVIS_SELECTED) != 0; + int hNewItem = 0; + switch (wParam) { + case OS.VK_UP: + hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUSVISIBLE, hItem); + break; + case OS.VK_DOWN: + hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem); + break; + case OS.VK_HOME: + hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); + break; + case OS.VK_PRIOR: + hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0); + if (hNewItem == hItem) { + OS.SendMessage (handle, OS.WM_VSCROLL, OS.SB_PAGEUP, 0); + hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0); + } + break; + case OS.VK_NEXT: + RECT rect = new RECT (), clientRect = new RECT (); + OS.GetClientRect (handle, clientRect); + hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0); + do { + int hVisible = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hNewItem); + if (hVisible == 0) break; + rect.left = hVisible; + OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect); + if (rect.bottom > clientRect.bottom) break; + if ((hNewItem = hVisible) == hItem) { + OS.SendMessage (handle, OS.WM_VSCROLL, OS.SB_PAGEDOWN, 0); + } + } while (hNewItem != 0); + break; + case OS.VK_END: + hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_LASTVISIBLE, 0); + break; + } + if (hNewItem != 0) { + OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, hNewItem); + tvItem.hItem = hNewItem; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + boolean newSelected = (tvItem.state & OS.TVIS_SELECTED) != 0; + if (!newSelected && drawCount == 0) { + OS.UpdateWindow (handle); + OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); + /* + * This code is intentionally commented. + */ +// OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); + } + ignoreSelect = true; + OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hNewItem); + ignoreSelect = false; + if (oldSelected) { + tvItem.state = OS.TVIS_SELECTED; + tvItem.hItem = hItem; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + } + if (!newSelected) { + tvItem.state = 0; + tvItem.hItem = hNewItem; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + } + if (!newSelected && drawCount == 0) { + RECT rect1 = new RECT (), rect2 = new RECT (); + rect1.left = hItem; rect2.left = hNewItem; + OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect1); + OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect2); + /* + * This code is intentionally commented. + */ +// OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0); + OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); + if (OS.IsWinCE) { + OS.InvalidateRect (handle, rect1, false); + OS.InvalidateRect (handle, rect2, false); + OS.UpdateWindow (handle); + } else { + int flags = OS.RDW_UPDATENOW | OS.RDW_INVALIDATE; + OS.RedrawWindow (handle, rect1, 0, flags); + OS.RedrawWindow (handle, rect2, 0, flags); + } + } + return LRESULT.ZERO; + } + } + } + int code = callWindowProc (OS.WM_KEYDOWN, wParam, lParam); + hAnchor = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + return new LRESULT (code); + } + } + return result; +} + +LRESULT WM_KILLFOCUS (int wParam, int lParam) { + LRESULT result = super.WM_KILLFOCUS (wParam, lParam); + if ((style & SWT.SINGLE) != 0) return result; + /* + * Feature in Windows. When multiple item have + * the TVIS_SELECTED state, Windows redraws only + * the focused item in the color used to show the + * selection when the tree loses or gains focus. + * The fix is to force Windows to redraw all the + * visible items when focus is gained or lost. + */ + OS.InvalidateRect (handle, null, false); + return result; +} + +LRESULT WM_LBUTTONDOWN (int wParam, int lParam) { + + /* + * Feature in Windows. When a tree item is + * reselected, Windows does not issue a WM_NOTIFY. + * This is inconsistent with the list widget and + * other widgets in Windows. The fix is to detect + * the case when an item is reselected and issue + * the notification. The first part of this work + * around is to ensure that the user has selected + * an item. + */ + TVHITTESTINFO lpht = new TVHITTESTINFO (); + lpht.x = (short) (lParam & 0xFFFF); + lpht.y = (short) (lParam >> 16); + OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht); + if (lpht.hItem == 0 || (lpht.flags & OS.TVHT_ONITEM) == 0) { + sendMouseEvent (SWT.MouseDown, 1, OS.WM_LBUTTONDOWN, wParam, lParam); + int code = callWindowProc (OS.WM_LBUTTONDOWN, wParam, lParam); + if (OS.GetCapture () != handle) OS.SetCapture (handle); + return new LRESULT (code); + } + + /* Look for check/uncheck */ + if ((style & SWT.CHECK) != 0) { + if ((lpht.flags & OS.TVHT_ONITEMSTATEICON) != 0) { + TVITEM tvItem = new TVITEM (); + tvItem.hItem = lpht.hItem; + tvItem.mask = OS.TVIF_PARAM | OS.TVIF_STATE; + tvItem.stateMask = OS.TVIS_STATEIMAGEMASK; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + int state = tvItem.state >> 12; + if ((state & 0x1) != 0) { + state++; + } else { + --state; + } + tvItem.state = state << 12; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + Event event = new Event (); + event.item = items [tvItem.lParam]; + event.detail = SWT.CHECK; + postEvent (SWT.Selection, event); + sendMouseEvent (SWT.MouseDown, 1, OS.WM_LBUTTONDOWN, wParam, lParam); + if (OS.GetCapture () != handle) OS.SetCapture (handle); + return LRESULT.ZERO; + } + } + + /* Get the selected state of the item under the mouse */ + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_STATE; + tvItem.stateMask = OS.TVIS_SELECTED; + boolean hittestSelected = false; + if ((style & SWT.MULTI) != 0) { + tvItem.hItem = lpht.hItem; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + hittestSelected = (tvItem.state & OS.TVIS_SELECTED) != 0; + } + + /* Get the selected state of the last selected item */ + int hOldItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + if ((style & SWT.MULTI) != 0) { + tvItem.hItem = hOldItem; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + + /* Check for CONTROL or drag selection */ + if (hittestSelected || (wParam & OS.MK_CONTROL) != 0) { + if (drawCount == 0) { + OS.UpdateWindow (handle); + OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); + /* + * This code is intentionally commented. + */ +// OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); + } + } else { + deselectAll (); + } + } + + /* Do the selection */ + sendMouseEvent (SWT.MouseDown, 1, OS.WM_LBUTTONDOWN, wParam, lParam); + dragStarted = false; + ignoreDeselect = ignoreSelect = true; + int code = callWindowProc (OS.WM_LBUTTONDOWN, wParam, lParam); + ignoreDeselect = ignoreSelect = false; + if (dragStarted && OS.GetCapture () != handle) OS.SetCapture (handle); + int hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + + /* + * Feature in Windows. When the old and new focused item + * are the same, Windows does not check to make sure that + * the item is actually selected, not just focused. The + * fix is to force the item to draw selected by setting + * the state mask. This is only necessary when the tree + * is single select. + */ + if ((style & SWT.SINGLE) != 0) { + if (hOldItem == hNewItem) { + tvItem.mask = OS.TVIF_STATE; + tvItem.state = OS.TVIS_SELECTED; + tvItem.stateMask = OS.TVIS_SELECTED; + tvItem.hItem = hNewItem; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + } + } + + /* Reselect the last item that was unselected */ + if ((style & SWT.MULTI) != 0) { + + /* Check for CONTROL and reselect the last item */ + if (hittestSelected || (wParam & OS.MK_CONTROL) != 0) { + if (hOldItem == hNewItem && hOldItem == lpht.hItem) { + if ((wParam & OS.MK_CONTROL) != 0) { + tvItem.state ^= OS.TVIS_SELECTED; + if (dragStarted) tvItem.state = OS.TVIS_SELECTED; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + } + } else { + if ((tvItem.state & OS.TVIS_SELECTED) != 0) { + tvItem.state = OS.TVIS_SELECTED; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + } + if ((wParam & OS.MK_CONTROL) != 0 && !dragStarted) { + if (hittestSelected) { + tvItem.state = 0; + tvItem.hItem = lpht.hItem; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + } + } + } + if (drawCount == 0) { + RECT rect1 = new RECT (), rect2 = new RECT (); + rect1.left = hOldItem; rect2.left = hNewItem; + OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect1); + OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect2); + /* + * This code is intentionally commented. + */ +// OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0); + OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); + if (OS.IsWinCE) { + OS.InvalidateRect (handle, rect1, false); + OS.InvalidateRect (handle, rect2, false); + OS.UpdateWindow (handle); + } else { + int flags = OS.RDW_UPDATENOW | OS.RDW_INVALIDATE; + OS.RedrawWindow (handle, rect1, 0, flags); + OS.RedrawWindow (handle, rect2, 0, flags); + } + } + } + + /* Check for SHIFT or normal select and delect/reselect items */ + if ((wParam & OS.MK_CONTROL) == 0) { + if (!hittestSelected || !dragStarted) { + tvItem.state = 0; + int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC); + OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc); + for (int i=0; i<items.length; i++) { + TreeItem item = items [i]; + if (item != null && item.handle != hNewItem) { + tvItem.hItem = item.handle; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + } + } + tvItem.hItem = hNewItem; + tvItem.state = OS.TVIS_SELECTED; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc); + if ((wParam & OS.MK_SHIFT) != 0) { + RECT rect1 = new RECT (); + if (hAnchor == 0) hAnchor = hNewItem; + rect1.left = hAnchor; + if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect1) != 0) { + RECT rect2 = rect2 = new RECT (); + rect2.left = hNewItem; + OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect2); + int flags = rect1.top < rect2.top ? OS.TVGN_NEXTVISIBLE : OS.TVGN_PREVIOUSVISIBLE; + tvItem.state = OS.TVIS_SELECTED; + int hItem = tvItem.hItem = hAnchor; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + while (hItem != hNewItem) { + tvItem.hItem = hItem; + OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); + hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, flags, hItem); + } + } + } + } + } + } + if ((wParam & OS.MK_SHIFT) == 0) hAnchor = hNewItem; + + /* Issue notification */ + tvItem.hItem = hNewItem; + tvItem.mask = OS.TVIF_PARAM; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + Event event = new Event (); + event.item = items [tvItem.lParam]; + postEvent (SWT.Selection, event); + + /* + * Feature in Windows. Inside WM_LBUTTONDOWN and WM_RBUTTONDOWN, + * the widget starts a modal loop to determine if the user wants + * to begin a drag/drop operation or marque select. Unfortunately, + * this modal loop eats the corresponding mouse up. The fix is to + * detect the cases when the modal loop has eaten the mouse up and + * issue a fake mouse up. + */ + if (dragStarted) { + postEvent (SWT.DragDetect); + } else { + sendMouseEvent (SWT.MouseUp, 1, OS.WM_LBUTTONUP, wParam, lParam); + } + dragStarted = false; + return new LRESULT (code); +} + +LRESULT WM_RBUTTONDOWN (int wParam, int lParam) { + /* + * Feature in Windows. The receiver uses WM_RBUTTONDOWN + * to initiate a drag/drop operation depending on how the + * user moves the mouse. If the user clicks the right button, + * without moving the mouse, the tree consumes the corresponding + * WM_RBUTTONUP. The fix is to avoid calling the window proc for + * the tree. + */ + sendMouseEvent (SWT.MouseDown, 3, OS.WM_RBUTTONDOWN, wParam, lParam); + /* + * This code is intentionally commented. + */ +// if (OS.GetCapture () != handle) OS.SetCapture (handle); + setFocus (); + + /* + * Feature in Windows. When the user selects a tree item + * with the right mouse button, the item remains selected + * only as long as the user does not release or move the + * mouse. As soon as this happens, the selection snaps + * back to the previous selection. This behavior can be + * observed in the Explorer but is not instantly apparent + * because the Explorer explicity sets the selection when + * the user chooses a menu item. If the user cancels the + * menu, the selection snaps back. The fix is to avoid + * calling the window proc and do the selection ourselves. + * This behavior is consistent with the table. + */ + TVHITTESTINFO lpht = new TVHITTESTINFO (); + lpht.x = (short) (lParam & 0xFFFF); + lpht.y = (short) (lParam >> 16); + OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht); + if (lpht.hItem != 0 && (lpht.flags & (OS.TVHT_ONITEMICON | OS.TVHT_ONITEMLABEL)) != 0) { + if ((wParam & (OS.MK_CONTROL | OS.MK_SHIFT)) == 0) { + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_STATE; + tvItem.stateMask = OS.TVIS_SELECTED; + tvItem.hItem = lpht.hItem; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + if ((tvItem.state & OS.TVIS_SELECTED) == 0) { + ignoreSelect = true; + OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, 0); + ignoreSelect = false; + OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, lpht.hItem); + } + } + } + return LRESULT.ZERO; +} + +LRESULT WM_SETFOCUS (int wParam, int lParam) { + LRESULT result = super.WM_SETFOCUS (wParam, lParam); + if ((style & SWT.SINGLE) != 0) return result; + /* + * Feature in Windows. When multiple item have + * the TVIS_SELECTED state, Windows redraws only + * the focused item in the color used to show the + * selection when the tree loses or gains focus. + * The fix is to force Windows to redraw all the + * visible items when focus is gained or lost. + */ + OS.InvalidateRect (handle, null, false); + return result; +} + +LRESULT WM_SYSCOLORCHANGE (int wParam, int lParam) { + LRESULT result = super.WM_SYSCOLORCHANGE (wParam, lParam); + if (result != null) return result; + if ((style & SWT.CHECK) != 0) setCheckboxImageList (); + return result; +} + +LRESULT wmNotifyChild (int wParam, int lParam) { + NMHDR hdr = new NMHDR (); + OS.MoveMemory (hdr, lParam, NMHDR.sizeof); + int code = hdr.code; + switch (code) { + case OS.NM_CUSTOMDRAW: { + if (!customDraw) break; + NMTVCUSTOMDRAW nmcd = new NMTVCUSTOMDRAW (); + OS.MoveMemory (nmcd, lParam, NMTVCUSTOMDRAW.sizeof); + switch (nmcd.dwDrawStage) { + case OS.CDDS_PREPAINT: return new LRESULT (OS.CDRF_NOTIFYITEMDRAW); + case OS.CDDS_ITEMPREPAINT: + TreeItem item = items [nmcd.lItemlParam]; + /* + * Feature on Windows. When a new tree item is inserted + * using TVM_INSERTITEM and the tree is using custom draw, + * a NM_CUSTOMDRAW is sent before TVM_INSERTITEM returns + * and before the item is added to the items array. The + * fix is to check for null. + * + * NOTE: This only happens on XP with the version 6.00 of + * COMCTL32.DLL, + */ + if (item == null) break; + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_STATE; + tvItem.hItem = item.handle; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + if ((tvItem.state & OS.TVIS_SELECTED) != 0) break; + int clrText = item.foreground, clrTextBk = item.background; + if (clrText == -1 && clrTextBk == -1) break; + nmcd.clrText = clrText == -1 ? getForegroundPixel () : clrText; + nmcd.clrTextBk = clrTextBk == -1 ? getBackgroundPixel () : clrTextBk; + OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof); + return new LRESULT (OS.CDRF_NEWFONT); + } + break; + } + case OS.NM_DBLCLK: + int pos = OS.GetMessagePos (); + TVHITTESTINFO lpht = new TVHITTESTINFO (); + POINT pt = new POINT (); + pt.x = (short) (pos & 0xFFFF); + pt.y = (short) (pos >> 16); + OS.ScreenToClient (handle, pt); + lpht.x = pt.x; lpht.y = pt.y; + OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht); + if ((lpht.flags & OS.TVHT_ONITEM) == 0) break; + // FALL THROUGH + case OS.NM_RETURN: + case OS.TVN_SELCHANGEDA: + case OS.TVN_SELCHANGEDW: + if (!ignoreSelect) { + TVITEM tvItem = null; + if (code == OS.TVN_SELCHANGED) { + tvItem = new TVITEM (); + int offset = NMHDR.sizeof + 4 + TVITEM.sizeof; + OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof); + hAnchor = tvItem.hItem; + } else { + int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + if (hItem != 0) { + tvItem = new TVITEM (); + tvItem.hItem = hItem; + tvItem.mask = OS.TVIF_PARAM; + OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); + } + } + Event event = new Event (); + if (tvItem != null) { + event.item = items [tvItem.lParam]; + } + if (code == OS.TVN_SELCHANGED) { + postEvent (SWT.Selection, event); + } else { + postEvent (SWT.DefaultSelection, event); + } + } + if (code == OS.NM_DBLCLK && hooks (SWT.DefaultSelection)) { + return LRESULT.ONE; + } + break; + case OS.TVN_SELCHANGINGA: + case OS.TVN_SELCHANGINGW: + if (!ignoreSelect && !ignoreDeselect) { + hAnchor = 0; + if ((style & SWT.MULTI) != 0) deselectAll (); + } + break; + case OS.TVN_ITEMEXPANDINGA: + case OS.TVN_ITEMEXPANDINGW: + if (!ignoreExpand) { + TVITEM tvItem = new TVITEM (); + int offset = NMHDR.sizeof + 4 + TVITEM.sizeof; + OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof); + int [] action = new int [1]; + OS.MoveMemory (action, lParam + NMHDR.sizeof, 4); + Event event = new Event (); + event.item = items [tvItem.lParam]; + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the expand + * or collapse event. If this happens, end the + * processing of the Windows message by returning + * zero as the result of the window proc. + */ + if (action [0] == OS.TVE_EXPAND) { + sendEvent (SWT.Expand, event); + if (isDisposed ()) return LRESULT.ZERO; + } + if (action [0] == OS.TVE_COLLAPSE) { + sendEvent (SWT.Collapse, event); + if (isDisposed ()) return LRESULT.ZERO; + } + } + break; + case OS.TVN_BEGINDRAGA: + case OS.TVN_BEGINDRAGW: + case OS.TVN_BEGINRDRAGA: + case OS.TVN_BEGINRDRAGW: + TVITEM tvItem = new TVITEM (); + int offset = NMHDR.sizeof + 4 + TVITEM.sizeof; + OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof); + if (tvItem.hItem != 0 && (tvItem.state & OS.TVIS_SELECTED) == 0) { + ignoreSelect = ignoreDeselect = true; + OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, tvItem.hItem); + ignoreSelect = ignoreDeselect = false; + } + dragStarted = true; + break; + } + return super.wmNotifyChild (wParam, lParam); +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TreeItem.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TreeItem.java index 2178d69ed8..cdcd8df0d0 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TreeItem.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TreeItem.java @@ -1,684 +1,684 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-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>
- */
-
-public class TreeItem extends Item {
- /**
- * the handle to the OS resource
- * (Warning: This field is platform dependent)
- */
- public int handle;
-
- Tree parent;
- int background, foreground;
-
-/**
- * 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 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 TreeItem (Tree parent, int style) {
- super (parent, style);
- this.parent = parent;
- parent.createItem (this, 0, OS.TVI_LAST);
-}
-
-/**
- * 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 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 index to store the receiver in its parent
- *
- * @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, int index) {
- super (parent, style);
- if (index < 0) error (SWT.ERROR_INVALID_RANGE);
- this.parent = parent;
- int hItem = OS.TVI_FIRST;
- if (index != 0) {
- int count = 1, hwnd = parent.handle;
- hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
- while (hItem != 0 && count < index) {
- hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
- count++;
- }
- if (hItem == 0) error (SWT.ERROR_INVALID_RANGE);
- };
- parent.createItem (this, 0, hItem);
-}
-
-/**
- * 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 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 TreeItem (TreeItem parentItem, int style) {
- super (checkNull (parentItem).parent, style);
- parent = parentItem.parent;
- int hItem = parentItem.handle;
- parent.createItem (this, hItem, OS.TVI_LAST);
-}
-
-/**
- * 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 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 index to store the receiver in its parent
- *
- * @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, int index) {
- super (checkNull (parentItem).parent, style);
- if (index < 0) error (SWT.ERROR_INVALID_RANGE);
- parent = parentItem.parent;
- int hItem = OS.TVI_FIRST;
- int hParent = parentItem.handle;
- if (index != 0) {
- int count = 1, hwnd = parent.handle;
- hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hParent);
- while (hItem != 0 && count < index) {
- hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
- count++;
- }
- if (hItem == 0) error (SWT.ERROR_INVALID_RANGE);
- }
- parent.createItem (this, hParent, hItem);
-}
-
-static TreeItem checkNull (TreeItem item) {
- if (item == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
- return item;
-}
-
-protected void checkSubclass () {
- if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
-}
-
-/**
- * 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 ();
- int pixel = (background == -1) ? parent.getBackgroundPixel() : background;
- return Color.win32_new (getDisplay (), pixel);
-}
-
-/**
- * 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 ();
- int hwnd = parent.handle;
- RECT rect = new RECT ();
- rect.left = handle;
- if (OS.SendMessage (hwnd, OS.TVM_GETITEMRECT, 1, rect) == 0) {
- return new Rectangle (0, 0, 0, 0);
- }
- int width = rect.right - rect.left;
- int height = rect.bottom - rect.top;
- return new Rectangle (rect.left, rect.top, width, 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.style & SWT.CHECK) == 0) return false;
- int hwnd = parent.handle;
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
- tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
- tvItem.hItem = handle;
- int result = OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem);
- return (result != 0) && (((tvItem.state >> 12) & 1) == 0);
-}
-
-public Display getDisplay () {
- Tree parent = this.parent;
- if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED);
- return parent.getDisplay ();
-}
-
-/**
- * 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 ();
- int hwnd = parent.handle;
- TVITEM tvItem = new TVITEM ();
- tvItem.hItem = handle;
- tvItem.mask = OS.TVIF_STATE;
- OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem);
- return (tvItem.state & OS.TVIS_EXPANDED) != 0;
-}
-
-/**
- * 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 ();
- int pixel = (foreground == -1) ? parent.getForegroundPixel() : foreground;
- return Color.win32_new (getDisplay (), pixel);
-}
-
-/**
- * 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
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if 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.style & SWT.CHECK) == 0) return false;
- int hwnd = parent.handle;
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
- tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
- tvItem.hItem = handle;
- int result = OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem);
- return (result != 0) && ((tvItem.state >> 12) > 2);
-}
-
-/**
- * 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 ();
- int count = 0;
- int hwnd = parent.handle;
- int hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, handle);
- while (hItem != 0) {
- hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
- count++;
- }
- return count;
-}
-
-/**
- * Returns an 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 ();
- int count = 0;
- int hwnd = parent.handle;
- int hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, handle);
- while (hItem != 0) {
- hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
- count++;
- }
- int index = 0;
- TreeItem [] result = new TreeItem [count];
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
- tvItem.hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, handle);
- while (tvItem.hItem != 0) {
- OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem);
- result [index++] = parent.items [tvItem.lParam];
- tvItem.hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, tvItem.hItem);
- }
- return result;
-}
-
-/**
- * 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 ();
- int hwnd = parent.handle;
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
- tvItem.hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, handle);
- if (tvItem.hItem == 0) return null;
- OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem);
- return parent.items [tvItem.lParam];
-}
-
-void redraw () {
- if (parent.drawCount > 0) return;
- int hwnd = parent.handle;
- if (!OS.IsWindowVisible (hwnd)) return;
- RECT rect = new RECT ();
- rect.left = handle;
- if (OS.SendMessage (hwnd, OS.TVM_GETITEMRECT, 1, rect) != 0) {
- OS.InvalidateRect (hwnd, rect, true);
- }
-}
-
-void releaseChild () {
- super.releaseChild ();
- parent.destroyItem (this);
-}
-
-void releaseHandle () {
- super.releaseHandle ();
- handle = 0;
-}
-
-void releaseWidget () {
- super.releaseWidget ();
- parent = 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);
- }
- int pixel = -1;
- if (color != null) {
- parent.customDraw = true;
- pixel = color.handle;
- }
- background = pixel;
- redraw ();
-}
-
-/**
- * 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;
- int hwnd = parent.handle;
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
- tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
- tvItem.hItem = handle;
- OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem);
- int state = tvItem.state >> 12;
- if (checked) {
- if ((state & 0x1) != 0) state++;
- } else {
- if ((state & 0x1) == 0) --state;
- }
- tvItem.state = state << 12;
- OS.SendMessage (hwnd, OS.TVM_SETITEM, 0, tvItem);
-}
-
-/**
- * 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 ();
- int hwnd = parent.handle;
- /*
- * Feature in Windows. When the user collapses the root
- * of a subtree that has the focus item, Windows moves
- * the selection to the root of the subtree and issues
- * a TVN_SELCHANGED to inform the programmer that the
- * seletion has changed. When the programmer collapses
- * the same subtree using TVM_EXPAND, Windows does not
- * send the selection changed notification. This is not
- * stricly wrong but is inconsistent. The fix is to notice
- * that the selection has changed and issue the event.
- */
- int hOldItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
- parent.ignoreExpand = true;
- OS.SendMessage (hwnd, OS.TVM_EXPAND, expanded ? OS.TVE_EXPAND : OS.TVE_COLLAPSE, handle);
- parent.ignoreExpand = false;
- int hNewItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
- if (hNewItem != hOldItem) {
- Event event = new Event ();
- if (hNewItem != 0) {
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
- tvItem.hItem = hNewItem;
- if (OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem) != 0) {
- event.item = parent.items [tvItem.lParam];
- }
- parent.hAnchor = hNewItem;
- }
- parent.sendEvent (SWT.Selection, event);
- }
-}
-
-/**
- * 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);
- }
- int pixel = -1;
- if (color != null) {
- parent.customDraw = true;
- pixel = color.handle;
- }
- foreground = pixel;
- redraw ();
-}
-
-/**
- * Sets the grayed state of the receiver.
- * <p>
- *
- * @param checked 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>
- */
-public void setGrayed (boolean grayed) {
- checkWidget ();
- if ((parent.style & SWT.CHECK) == 0) return;
- int hwnd = parent.handle;
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
- tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
- tvItem.hItem = handle;
- OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem);
- int state = tvItem.state >> 12;
- if (grayed) {
- if (state <= 2) state +=2;
- } else {
- if (state > 2) state -=2;
- }
- tvItem.state = state << 12;
- OS.SendMessage (hwnd, OS.TVM_SETITEM, 0, tvItem);
-}
-
-public void setImage (Image image) {
- checkWidget ();
- super.setImage (image);
- int hwnd = parent.handle;
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_IMAGE | OS.TVIF_SELECTEDIMAGE;
- tvItem.iImage = parent.imageIndex (image);
- tvItem.iSelectedImage = tvItem.iImage;
- tvItem.hItem = handle;
- OS.SendMessage (hwnd, OS.TVM_SETITEM, 0, tvItem);
-}
-
-public void setText (String string) {
- checkWidget ();
- if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
- super.setText (string);
- int hwnd = parent.handle;
- int hHeap = OS.GetProcessHeap ();
- TCHAR buffer = new TCHAR (parent.getCodePage (), string, true);
- int byteCount = buffer.length () * TCHAR.sizeof;
- int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
- OS.MoveMemory (pszText, buffer, byteCount);
- TVITEM tvItem = new TVITEM ();
- tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_TEXT;
- tvItem.hItem = handle;
- tvItem.pszText = pszText;
- OS.SendMessage (hwnd, OS.TVM_SETITEM, 0, tvItem);
- OS.HeapFree (hHeap, 0, pszText);
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; +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> + */ + +public class TreeItem extends Item { + /** + * the handle to the OS resource + * (Warning: This field is platform dependent) + */ + public int handle; + + Tree parent; + int background, foreground; + +/** + * 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 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 TreeItem (Tree parent, int style) { + super (parent, style); + this.parent = parent; + parent.createItem (this, 0, OS.TVI_LAST); +} + +/** + * 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 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 index to store the receiver in its parent + * + * @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, int index) { + super (parent, style); + if (index < 0) error (SWT.ERROR_INVALID_RANGE); + this.parent = parent; + int hItem = OS.TVI_FIRST; + if (index != 0) { + int count = 1, hwnd = parent.handle; + hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); + while (hItem != 0 && count < index) { + hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem); + count++; + } + if (hItem == 0) error (SWT.ERROR_INVALID_RANGE); + }; + parent.createItem (this, 0, hItem); +} + +/** + * 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 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 TreeItem (TreeItem parentItem, int style) { + super (checkNull (parentItem).parent, style); + parent = parentItem.parent; + int hItem = parentItem.handle; + parent.createItem (this, hItem, OS.TVI_LAST); +} + +/** + * 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 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 index to store the receiver in its parent + * + * @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, int index) { + super (checkNull (parentItem).parent, style); + if (index < 0) error (SWT.ERROR_INVALID_RANGE); + parent = parentItem.parent; + int hItem = OS.TVI_FIRST; + int hParent = parentItem.handle; + if (index != 0) { + int count = 1, hwnd = parent.handle; + hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hParent); + while (hItem != 0 && count < index) { + hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem); + count++; + } + if (hItem == 0) error (SWT.ERROR_INVALID_RANGE); + } + parent.createItem (this, hParent, hItem); +} + +static TreeItem checkNull (TreeItem item) { + if (item == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + return item; +} + +protected void checkSubclass () { + if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS); +} + +/** + * 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 (); + int pixel = (background == -1) ? parent.getBackgroundPixel() : background; + return Color.win32_new (getDisplay (), pixel); +} + +/** + * 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 (); + int hwnd = parent.handle; + RECT rect = new RECT (); + rect.left = handle; + if (OS.SendMessage (hwnd, OS.TVM_GETITEMRECT, 1, rect) == 0) { + return new Rectangle (0, 0, 0, 0); + } + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + return new Rectangle (rect.left, rect.top, width, 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.style & SWT.CHECK) == 0) return false; + int hwnd = parent.handle; + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE; + tvItem.stateMask = OS.TVIS_STATEIMAGEMASK; + tvItem.hItem = handle; + int result = OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem); + return (result != 0) && (((tvItem.state >> 12) & 1) == 0); +} + +public Display getDisplay () { + Tree parent = this.parent; + if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED); + return parent.getDisplay (); +} + +/** + * 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 (); + int hwnd = parent.handle; + TVITEM tvItem = new TVITEM (); + tvItem.hItem = handle; + tvItem.mask = OS.TVIF_STATE; + OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem); + return (tvItem.state & OS.TVIS_EXPANDED) != 0; +} + +/** + * 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 (); + int pixel = (foreground == -1) ? parent.getForegroundPixel() : foreground; + return Color.win32_new (getDisplay (), pixel); +} + +/** + * 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 + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if 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.style & SWT.CHECK) == 0) return false; + int hwnd = parent.handle; + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE; + tvItem.stateMask = OS.TVIS_STATEIMAGEMASK; + tvItem.hItem = handle; + int result = OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem); + return (result != 0) && ((tvItem.state >> 12) > 2); +} + +/** + * 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 (); + int count = 0; + int hwnd = parent.handle; + int hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, handle); + while (hItem != 0) { + hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem); + count++; + } + return count; +} + +/** + * Returns an 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 (); + int count = 0; + int hwnd = parent.handle; + int hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, handle); + while (hItem != 0) { + hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem); + count++; + } + int index = 0; + TreeItem [] result = new TreeItem [count]; + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM; + tvItem.hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, handle); + while (tvItem.hItem != 0) { + OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem); + result [index++] = parent.items [tvItem.lParam]; + tvItem.hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, tvItem.hItem); + } + return result; +} + +/** + * 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 (); + int hwnd = parent.handle; + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM; + tvItem.hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, handle); + if (tvItem.hItem == 0) return null; + OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem); + return parent.items [tvItem.lParam]; +} + +void redraw () { + if (parent.drawCount > 0) return; + int hwnd = parent.handle; + if (!OS.IsWindowVisible (hwnd)) return; + RECT rect = new RECT (); + rect.left = handle; + if (OS.SendMessage (hwnd, OS.TVM_GETITEMRECT, 1, rect) != 0) { + OS.InvalidateRect (hwnd, rect, true); + } +} + +void releaseChild () { + super.releaseChild (); + parent.destroyItem (this); +} + +void releaseHandle () { + super.releaseHandle (); + handle = 0; +} + +void releaseWidget () { + super.releaseWidget (); + parent = 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); + } + int pixel = -1; + if (color != null) { + parent.customDraw = true; + pixel = color.handle; + } + background = pixel; + redraw (); +} + +/** + * 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; + int hwnd = parent.handle; + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE; + tvItem.stateMask = OS.TVIS_STATEIMAGEMASK; + tvItem.hItem = handle; + OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem); + int state = tvItem.state >> 12; + if (checked) { + if ((state & 0x1) != 0) state++; + } else { + if ((state & 0x1) == 0) --state; + } + tvItem.state = state << 12; + OS.SendMessage (hwnd, OS.TVM_SETITEM, 0, tvItem); +} + +/** + * 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 (); + int hwnd = parent.handle; + /* + * Feature in Windows. When the user collapses the root + * of a subtree that has the focus item, Windows moves + * the selection to the root of the subtree and issues + * a TVN_SELCHANGED to inform the programmer that the + * seletion has changed. When the programmer collapses + * the same subtree using TVM_EXPAND, Windows does not + * send the selection changed notification. This is not + * stricly wrong but is inconsistent. The fix is to notice + * that the selection has changed and issue the event. + */ + int hOldItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + parent.ignoreExpand = true; + OS.SendMessage (hwnd, OS.TVM_EXPAND, expanded ? OS.TVE_EXPAND : OS.TVE_COLLAPSE, handle); + parent.ignoreExpand = false; + int hNewItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); + if (hNewItem != hOldItem) { + Event event = new Event (); + if (hNewItem != 0) { + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM; + tvItem.hItem = hNewItem; + if (OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem) != 0) { + event.item = parent.items [tvItem.lParam]; + } + parent.hAnchor = hNewItem; + } + parent.sendEvent (SWT.Selection, event); + } +} + +/** + * 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); + } + int pixel = -1; + if (color != null) { + parent.customDraw = true; + pixel = color.handle; + } + foreground = pixel; + redraw (); +} + +/** + * Sets the grayed state of the receiver. + * <p> + * + * @param checked 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> + */ +public void setGrayed (boolean grayed) { + checkWidget (); + if ((parent.style & SWT.CHECK) == 0) return; + int hwnd = parent.handle; + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE; + tvItem.stateMask = OS.TVIS_STATEIMAGEMASK; + tvItem.hItem = handle; + OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem); + int state = tvItem.state >> 12; + if (grayed) { + if (state <= 2) state +=2; + } else { + if (state > 2) state -=2; + } + tvItem.state = state << 12; + OS.SendMessage (hwnd, OS.TVM_SETITEM, 0, tvItem); +} + +public void setImage (Image image) { + checkWidget (); + super.setImage (image); + int hwnd = parent.handle; + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_IMAGE | OS.TVIF_SELECTEDIMAGE; + tvItem.iImage = parent.imageIndex (image); + tvItem.iSelectedImage = tvItem.iImage; + tvItem.hItem = handle; + OS.SendMessage (hwnd, OS.TVM_SETITEM, 0, tvItem); +} + +public void setText (String string) { + checkWidget (); + if (string == null) error (SWT.ERROR_NULL_ARGUMENT); + super.setText (string); + int hwnd = parent.handle; + int hHeap = OS.GetProcessHeap (); + TCHAR buffer = new TCHAR (parent.getCodePage (), string, true); + int byteCount = buffer.length () * TCHAR.sizeof; + int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + OS.MoveMemory (pszText, buffer, byteCount); + TVITEM tvItem = new TVITEM (); + tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_TEXT; + tvItem.hItem = handle; + tvItem.pszText = pszText; + OS.SendMessage (hwnd, OS.TVM_SETITEM, 0, tvItem); + OS.HeapFree (hHeap, 0, pszText); +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java index d4cc41bae2..109a3b552c 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java @@ -1,1057 +1,1057 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.*;
-import org.eclipse.swt.internal.win32.*;
-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
- */
-
-public abstract class Widget {
- int style, state;
- EventTable eventTable;
- Object data;
- String [] keys;
- Object [] values;
-
- /* Global state flags */
-// static final int AUTOMATIC = 1<<0;
-// static final int ACTIVE = 1<<1;
-// static final int GRAB = 1<<2;
-// static final int MULTIEXPOSE = 1<<3;
-// static final int RESIZEREDRAW = 1<<4;
-// static final int WRAP = 1<<5;
- static final int DISABLED = 1<<6;
- static final int HIDDEN = 1<<7;
-// static final int FOREGROUND = 1<<8;
-// static final int BACKGROUND = 1<<9;
- static final int DISPOSED = 1<<10;
-// static final int HANDLE = 1<<11;
- static final int CANVAS = 1<<12;
-
- /* Default widths for widgets */
- static final int DEFAULT_WIDTH = 64;
- static final int DEFAULT_HEIGHT = 64;
- static final char Mnemonic = '&';
-
- /* COMCTL32.DLL flags */
- static final int MAJOR = 4, MINOR = 71;
- static final int COMCTL32_MAJOR, COMCTL32_MINOR;
- static {
-
- /* Get the COMCTL32.DLL version */
- DLLVERSIONINFO dvi = new DLLVERSIONINFO ();
- dvi.cbSize = DLLVERSIONINFO.sizeof;
- dvi.dwMajorVersion = 4;
- dvi.dwMinorVersion = 0;
- TCHAR lpLibFileName = new TCHAR (0, "comctl32.dll", true);
- int hModule = OS.LoadLibrary (lpLibFileName);
- if (hModule != 0) {
- String name = "DllGetVersion\0";
- byte [] lpProcName = new byte [name.length ()];
- for (int i=0; i<lpProcName.length; i++) {
- lpProcName [i] = (byte) name.charAt (i);
- }
- int DllGetVersion = OS.GetProcAddress (hModule, lpProcName);
- if (DllGetVersion != 0) OS.Call (DllGetVersion, dvi);
- OS.FreeLibrary (hModule);
- }
- COMCTL32_MAJOR = dvi.dwMajorVersion;
- COMCTL32_MINOR = dvi.dwMinorVersion;
- if (!OS.IsWinCE) {
- if ((COMCTL32_MAJOR << 16 | COMCTL32_MINOR) < (MAJOR << 16 | MINOR)) {
- System.out.println ("***WARNING: SWT requires comctl32.dll version " + MAJOR + "." + MINOR + " or greater");
- System.out.println ("***WARNING: Detected: " + COMCTL32_MAJOR + "." + COMCTL32_MINOR);
- }
- }
-
- /* Initialize the Common Controls DLL */
- OS.InitCommonControls ();
- }
-
-/**
- * Prevents uninitialized instances from being created outside the package.
- */
-Widget () {
-}
-
-/**
- * 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
- * @see #checkSubclass
- * @see #getStyle
- */
-public Widget (Widget parent, int style) {
- checkSubclass ();
- checkParent (parent);
- this.style = style;
-}
-
-/**
- * Adds the listener to the collection of listeners who will
- * be notifed 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.
- *
- * @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 #removeListener
- */
-public void addListener (int eventType, Listener listener) {
- checkWidget();
- if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
- if (eventTable == null) eventTable = new EventTable ();
- eventTable.hook (eventType, listener);
-}
-
-/**
- * Adds the listener to the collection of listeners who will
- * be notifed 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);
-}
-
-/**
- * Returns a style with exactly one style bit set out of
- * the specified set of exclusive style bits. All other
- * possible bits are cleared when the first matching bit
- * is found. Bits that are not part of the possible set
- * are untouched.
- *
- * @param style the original style bits
- * @param int0 the 0th possible style bit
- * @param int1 the 1st possible style bit
- * @param int2 the 2nd possible style bit
- * @param int3 the 3rd possible style bit
- * @param int4 the 4th possible style bit
- * @param int5 the 5th possible style bit
- *
- * @return the new style bits
- */
-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 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);
-}
-
-/**
- * Throws an exception if the specified widget can not be
- * used as a parent for the receiver.
- *
- * @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>
- * </ul>
- */
-void checkParent (Widget parent) {
- if (parent == null) error (SWT.ERROR_NULL_ARGUMENT);
- if (!parent.isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
- if (parent.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
-}
-
-/**
- * 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 () {
- if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
- if (isDisposed ()) error (SWT.ERROR_WIDGET_DISPOSED);
-}
-
-/**
- * Destroys the widget in the operating system and releases
- * the widget's handle. If the widget does not have a handle,
- * this method may hide the widget, mark the widget as destroyed
- * or do nothing, depending on the widget.
- * <p>
- * When a widget is destroyed in the operating system, its
- * descendents are also destroyed by the operating system.
- * This means that it is only necessary to call <code>destroyWidget</code>
- * on the root of the widget tree.
- * </p><p>
- * This method is called after <code>releaseWidget</code>.
- * </p>
- * @see #dispose
- * @see #releaseChild
- * @see #releaseWidget
- * @see #releaseHandle
- */
-void destroyWidget () {
- releaseHandle ();
-}
-
-/**
- * Disposes of the operating system resources associated with
- * the receiver and all its descendents. After this method has
- * been invoked, the receiver and all descendents 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 descendents
- * 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);
- releaseChild ();
- releaseWidget ();
- destroyWidget ();
-}
-
-/**
- * Does whatever widget specific cleanup is required, and then
- * uses the code in <code>SWTError.error</code> to handle the error.
- *
- * @param code the descriptive error code
- *
- * @see SWTError#error
- */
-void error (int code) {
- SWT.error(code);
-}
-
-boolean filters (int eventType) {
- Display display = getDisplay ();
- return display.filters (eventType);
-}
-
-/**
- * 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
- */
-public Object getData () {
- checkWidget();
- return 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
- */
-public Object getData (String key) {
- checkWidget();
- 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 <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>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- */
-public abstract Display getDisplay ();
-
-/**
- * Returns the name of the widget. This is the name of
- * the class without the package name.
- *
- * @return the name of the widget
- */
-String getName () {
- String string = getClass ().getName ();
- int index = string.lastIndexOf ('.');
- if (index == -1) return string;
- return string.substring (index + 1, string.length ());
-}
-
-/*
- * Returns a short printable representation for the contents
- * of a widget. For example, a button may answer the label
- * text. This is used by <code>toString</code> to provide a
- * more meaningful description of the widget.
- *
- * @return the contents string for the widget
- *
- * @see #toString
- */
-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;
-}
-
-/*
- * Returns <code>true</code> if the specified eventType is
- * hooked, and <code>false</code> otherwise. Implementations
- * of SWT can avoid creating objects and sending events
- * when an event happens in the operating system but
- * there are no listeners hooked for the event.
- *
- * @param eventType the event to be checked
- *
- * @return <code>true</code> when the eventType is hooked and <code>false</code> otherwise
- *
- * @see #isListening
- */
-boolean hooks (int eventType) {
- if (eventTable == null) return false;
- return eventTable.hooks (eventType);
-}
-
-/**
- * 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;
-}
-
-/**
- * Returns <code>true</code> if there are any listeners
- * for the specified event type associated with the receiver,
- * and <code>false</code> otherwise.
- *
- * @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>
- */
-protected boolean isListening (int eventType) {
- checkWidget();
- return hooks (eventType);
-}
-
-/*
- * Returns <code>true</code> when subclassing is
- * allowed and <code>false</code> otherwise
- *
- * @return <code>true</code> when subclassing is allowed and <code>false</code> otherwise
- */
-boolean isValidSubclass () {
- return Display.isValidClass (getClass ());
-}
-
-/*
- * Returns <code>true</code> when the current thread is
- * the thread that created the widget and <code>false</code>
- * otherwise.
- *
- * @return <code>true</code> when the current thread is the thread that created the widget and <code>false</code> otherwise
- */
-boolean isValidThread () {
- return getDisplay ().isValidThread ();
-}
-
-/*
- * Returns a single character, converted from the default
- * multi-byte character set (MBCS) used by the operating
- * system widgets to a wide character set (WCS) used by Java.
- *
- * @param ch the MBCS character
- * @return the WCS character
- */
-char mbcsToWcs (int ch) {
- return mbcsToWcs (ch, 0);
-}
-
-/*
- * Returns a single character, converted from the specified
- * multi-byte character set (MBCS) used by the operating
- * system widgets to a wide character set (WCS) used by Java.
- *
- * @param ch the MBCS character
- * @param codePage the code page used to convert the character
- * @return the WCS character
- */
-char mbcsToWcs (int ch, int codePage) {
- if (OS.IsUnicode) return (char) ch;
- int key = ch & 0xFFFF;
- if (key <= 0x7F) return (char) ch;
- byte [] buffer;
- if (key <= 0xFF) {
- buffer = new byte [1];
- buffer [0] = (byte) key;
- } else {
- buffer = new byte [2];
- buffer [0] = (byte) ((key >> 8) & 0xFF);
- buffer [1] = (byte) (key & 0xFF);
- }
- char [] unicode = new char [1];
- int cp = codePage != 0 ? codePage : OS.CP_ACP;
- int count = OS.MultiByteToWideChar (cp, OS.MB_PRECOMPOSED, buffer, buffer.length, unicode, 1);
- if (count == 0) return 0;
- return unicode [0];
-}
-
-/**
- * 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.
- *
- * @param eventType the type of event which has occurred
- * @param event the event data
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if 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>
- */
-public void notifyListeners (int eventType, Event event) {
- checkWidget();
- if (event == null) error (SWT.ERROR_NULL_ARGUMENT);
- sendEvent (eventType, event);
-}
-
-void postEvent (int eventType) {
- sendEvent (eventType, null, false);
-}
-
-void postEvent (int eventType, Event event) {
- sendEvent (eventType, event, false);
-}
-
-/*
- * Releases the receiver, a child in a widget hierarchy,
- * from its parent.
- * <p>
- * When a widget is destroyed, it may be necessary to remove
- * it from an internal data structure of the parent. When
- * a widget has no handle, it may also be necessary for the
- * parent to hide the widget or otherwise indicate that the
- * widget has been disposed. For example, disposing a menu
- * bar requires that the menu bar first be released from the
- * shell when the menu bar is active. This could not be done
- * in <code>destroyWidget</code> for the menu bar because the
- * parent shell as well as other fields have been null'd out
- * already by <code>releaseWidget</code>.
- * </p>
- * This method is called first when a widget is disposed.
- *
- * @see #dispose
- * @see #releaseChild
- * @see #releaseWidget
- * @see #releaseHandle
- */
-void releaseChild () {
-}
-
-/*
- * Releases the widget's handle by zero'ing it out.
- * Does not destroy or release any operating system
- * resources.
- * <p>
- * This method is called after <code>releaseWidget</code>
- * or from <code>destroyWidget</code> when a widget is being
- * destroyed to ensure that the widget is marked as destroyed
- * in case the act of destroying the widget in the operating
- * system causes application code to run in callback that
- * could access the widget.
- * </p>
- *
- * @see #dispose
- * @see #releaseChild
- * @see #releaseWidget
- * @see #releaseHandle
- */
-void releaseHandle () {
- state |= DISPOSED;
-}
-
-void releaseResources () {
- releaseWidget ();
- releaseHandle ();
-}
-
-/*
- * Releases any internal resources back to the operating
- * system and clears all fields except the widget handle.
- * <p>
- * When a widget is destroyed, resources that were acquired
- * on behalf of the programmer need to be returned to the
- * operating system. For example, if the widget made a
- * copy of an icon, supplied by the programmer, this copy
- * would be freed in <code>releaseWidget</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 widget, all fields except the
- * handle are zero'd. The handle is needed by <code>destroyWidget</code>.
- * </p>
- * <p>
- * Typically, a widget with children will broadcast this
- * message to all children so that they too can release their
- * resources. The <code>releaseHandle</code> method is used
- * as part of this broadcast to zero the handle fields of the
- * children without calling <code>destroyWidget</code>. In
- * this scenario, the children are actually destroyed later,
- * when the operating system destroys the widget tree.
- * </p>
- * This method is called after <code>releaseChild</code>.
- *
- * @see #dispose
- * @see #releaseChild
- * @see #releaseWidget
- * @see #releaseHandle
- */
-void releaseWidget () {
- sendEvent (SWT.Dispose);
- eventTable = null;
- data = null;
- keys = null;
- values = null;
-}
-
-/**
- * Removes the listener from the collection of listeners who will
- * be notifed when an event of the given type occurs.
- *
- * @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_WIDGET_DISPOSED - 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
- */
-public void removeListener (int eventType, Listener listener) {
- checkWidget();
- if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
- if (eventTable == null) return;
- eventTable.unhook (eventType, listener);
-}
-
-/**
- * Removes the listener from the collection of listeners who will
- * be notifed 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 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 #addListener
- */
-protected void removeListener (int eventType, SWTEventListener listener) {
- checkWidget();
- if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
- if (eventTable == null) return;
- eventTable.unhook (eventType, listener);
-}
-
-/**
- * Removes the listener from the collection of listeners who will
- * be notifed when the widget is disposed.
- *
- * @param listener the listener which should no longer 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 #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 sendEvent (Event event) {
- Display display = event.display;
- if (!display.filterEvent (event)) {
- if (eventTable != null) eventTable.sendEvent (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) {
- Display display = getDisplay ();
- 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);
- }
-}
-
-/**
- * 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>
- */
-public void setData (Object data) {
- checkWidget();
- 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
- */
-public void setData (String key, Object value) {
- checkWidget();
- if (key == null) error (SWT.ERROR_NULL_ARGUMENT);
-
- /* 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;
-}
-
-boolean setInputState (Event event, int type) {
- if (OS.GetKeyState (OS.VK_MENU) < 0) event.stateMask |= SWT.ALT;
- if (OS.GetKeyState (OS.VK_SHIFT) < 0) event.stateMask |= SWT.SHIFT;
- if (OS.GetKeyState (OS.VK_CONTROL) < 0) event.stateMask |= SWT.CONTROL;
- if (OS.GetKeyState (OS.VK_LBUTTON) < 0) event.stateMask |= SWT.BUTTON1;
- if (OS.GetKeyState (OS.VK_MBUTTON) < 0) event.stateMask |= SWT.BUTTON2;
- if (OS.GetKeyState (OS.VK_RBUTTON) < 0) event.stateMask |= SWT.BUTTON3;
- 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;
- 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;
- 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;
- 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;
- break;
- }
- return true;
-}
-
-boolean setKeyState (Event event, int type) {
- Display display = getDisplay ();
- if (display.lastAscii != 0) {
- event.character = mbcsToWcs ((char) display.lastAscii);
- }
- if (display.lastVirtual) {
- event.keyCode = Display.translateKey (display.lastKey);
- }
- if (event.keyCode == 0 && event.character == 0) {
- if (!display.lastNull) return false;
- }
- return setInputState (event, type);
-}
-
-/**
- * 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 + "}";
-}
-
-/*
- * Returns a single character, converted from the wide
- * character set (WCS) used by Java to the specified
- * multi-byte character set used by the operating system
- * widgets.
- *
- * @param ch the WCS character
- * @param codePage the code page used to convert the character
- * @return the MBCS character
- */
-int wcsToMbcs (char ch, int codePage) {
- if (OS.IsUnicode) return ch;
- if (ch <= 0x7F) return ch;
- TCHAR buffer = new TCHAR (codePage, ch, false);
- return buffer.tcharAt (0);
-}
-
-/*
- * Returns a single character, converted from the wide
- * character set (WCS) used by Java to the default
- * multi-byte character set used by the operating system
- * widgets.
- *
- * @param ch the WCS character
- * @return the MBCS character
- */
-int wcsToMbcs (char ch) {
- return wcsToMbcs (ch, 0);
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.win32.*; +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 + */ + +public abstract class Widget { + int style, state; + EventTable eventTable; + Object data; + String [] keys; + Object [] values; + + /* Global state flags */ +// static final int AUTOMATIC = 1<<0; +// static final int ACTIVE = 1<<1; +// static final int GRAB = 1<<2; +// static final int MULTIEXPOSE = 1<<3; +// static final int RESIZEREDRAW = 1<<4; +// static final int WRAP = 1<<5; + static final int DISABLED = 1<<6; + static final int HIDDEN = 1<<7; +// static final int FOREGROUND = 1<<8; +// static final int BACKGROUND = 1<<9; + static final int DISPOSED = 1<<10; +// static final int HANDLE = 1<<11; + static final int CANVAS = 1<<12; + + /* Default widths for widgets */ + static final int DEFAULT_WIDTH = 64; + static final int DEFAULT_HEIGHT = 64; + static final char Mnemonic = '&'; + + /* COMCTL32.DLL flags */ + static final int MAJOR = 4, MINOR = 71; + static final int COMCTL32_MAJOR, COMCTL32_MINOR; + static { + + /* Get the COMCTL32.DLL version */ + DLLVERSIONINFO dvi = new DLLVERSIONINFO (); + dvi.cbSize = DLLVERSIONINFO.sizeof; + dvi.dwMajorVersion = 4; + dvi.dwMinorVersion = 0; + TCHAR lpLibFileName = new TCHAR (0, "comctl32.dll", true); + int hModule = OS.LoadLibrary (lpLibFileName); + if (hModule != 0) { + String name = "DllGetVersion\0"; + byte [] lpProcName = new byte [name.length ()]; + for (int i=0; i<lpProcName.length; i++) { + lpProcName [i] = (byte) name.charAt (i); + } + int DllGetVersion = OS.GetProcAddress (hModule, lpProcName); + if (DllGetVersion != 0) OS.Call (DllGetVersion, dvi); + OS.FreeLibrary (hModule); + } + COMCTL32_MAJOR = dvi.dwMajorVersion; + COMCTL32_MINOR = dvi.dwMinorVersion; + if (!OS.IsWinCE) { + if ((COMCTL32_MAJOR << 16 | COMCTL32_MINOR) < (MAJOR << 16 | MINOR)) { + System.out.println ("***WARNING: SWT requires comctl32.dll version " + MAJOR + "." + MINOR + " or greater"); + System.out.println ("***WARNING: Detected: " + COMCTL32_MAJOR + "." + COMCTL32_MINOR); + } + } + + /* Initialize the Common Controls DLL */ + OS.InitCommonControls (); + } + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Widget () { +} + +/** + * 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 + * @see #checkSubclass + * @see #getStyle + */ +public Widget (Widget parent, int style) { + checkSubclass (); + checkParent (parent); + this.style = style; +} + +/** + * Adds the listener to the collection of listeners who will + * be notifed 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. + * + * @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 #removeListener + */ +public void addListener (int eventType, Listener listener) { + checkWidget(); + if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); + if (eventTable == null) eventTable = new EventTable (); + eventTable.hook (eventType, listener); +} + +/** + * Adds the listener to the collection of listeners who will + * be notifed 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); +} + +/** + * Returns a style with exactly one style bit set out of + * the specified set of exclusive style bits. All other + * possible bits are cleared when the first matching bit + * is found. Bits that are not part of the possible set + * are untouched. + * + * @param style the original style bits + * @param int0 the 0th possible style bit + * @param int1 the 1st possible style bit + * @param int2 the 2nd possible style bit + * @param int3 the 3rd possible style bit + * @param int4 the 4th possible style bit + * @param int5 the 5th possible style bit + * + * @return the new style bits + */ +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 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); +} + +/** + * Throws an exception if the specified widget can not be + * used as a parent for the receiver. + * + * @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> + * </ul> + */ +void checkParent (Widget parent) { + if (parent == null) error (SWT.ERROR_NULL_ARGUMENT); + if (!parent.isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); + if (parent.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT); +} + +/** + * 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 () { + if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); + if (isDisposed ()) error (SWT.ERROR_WIDGET_DISPOSED); +} + +/** + * Destroys the widget in the operating system and releases + * the widget's handle. If the widget does not have a handle, + * this method may hide the widget, mark the widget as destroyed + * or do nothing, depending on the widget. + * <p> + * When a widget is destroyed in the operating system, its + * descendents are also destroyed by the operating system. + * This means that it is only necessary to call <code>destroyWidget</code> + * on the root of the widget tree. + * </p><p> + * This method is called after <code>releaseWidget</code>. + * </p> + * @see #dispose + * @see #releaseChild + * @see #releaseWidget + * @see #releaseHandle + */ +void destroyWidget () { + releaseHandle (); +} + +/** + * Disposes of the operating system resources associated with + * the receiver and all its descendents. After this method has + * been invoked, the receiver and all descendents 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 descendents + * 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); + releaseChild (); + releaseWidget (); + destroyWidget (); +} + +/** + * Does whatever widget specific cleanup is required, and then + * uses the code in <code>SWTError.error</code> to handle the error. + * + * @param code the descriptive error code + * + * @see SWTError#error + */ +void error (int code) { + SWT.error(code); +} + +boolean filters (int eventType) { + Display display = getDisplay (); + return display.filters (eventType); +} + +/** + * 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 + */ +public Object getData () { + checkWidget(); + return 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 + */ +public Object getData (String key) { + checkWidget(); + 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 <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> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public abstract Display getDisplay (); + +/** + * Returns the name of the widget. This is the name of + * the class without the package name. + * + * @return the name of the widget + */ +String getName () { + String string = getClass ().getName (); + int index = string.lastIndexOf ('.'); + if (index == -1) return string; + return string.substring (index + 1, string.length ()); +} + +/* + * Returns a short printable representation for the contents + * of a widget. For example, a button may answer the label + * text. This is used by <code>toString</code> to provide a + * more meaningful description of the widget. + * + * @return the contents string for the widget + * + * @see #toString + */ +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; +} + +/* + * Returns <code>true</code> if the specified eventType is + * hooked, and <code>false</code> otherwise. Implementations + * of SWT can avoid creating objects and sending events + * when an event happens in the operating system but + * there are no listeners hooked for the event. + * + * @param eventType the event to be checked + * + * @return <code>true</code> when the eventType is hooked and <code>false</code> otherwise + * + * @see #isListening + */ +boolean hooks (int eventType) { + if (eventTable == null) return false; + return eventTable.hooks (eventType); +} + +/** + * 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; +} + +/** + * Returns <code>true</code> if there are any listeners + * for the specified event type associated with the receiver, + * and <code>false</code> otherwise. + * + * @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> + */ +protected boolean isListening (int eventType) { + checkWidget(); + return hooks (eventType); +} + +/* + * Returns <code>true</code> when subclassing is + * allowed and <code>false</code> otherwise + * + * @return <code>true</code> when subclassing is allowed and <code>false</code> otherwise + */ +boolean isValidSubclass () { + return Display.isValidClass (getClass ()); +} + +/* + * Returns <code>true</code> when the current thread is + * the thread that created the widget and <code>false</code> + * otherwise. + * + * @return <code>true</code> when the current thread is the thread that created the widget and <code>false</code> otherwise + */ +boolean isValidThread () { + return getDisplay ().isValidThread (); +} + +/* + * Returns a single character, converted from the default + * multi-byte character set (MBCS) used by the operating + * system widgets to a wide character set (WCS) used by Java. + * + * @param ch the MBCS character + * @return the WCS character + */ +char mbcsToWcs (int ch) { + return mbcsToWcs (ch, 0); +} + +/* + * Returns a single character, converted from the specified + * multi-byte character set (MBCS) used by the operating + * system widgets to a wide character set (WCS) used by Java. + * + * @param ch the MBCS character + * @param codePage the code page used to convert the character + * @return the WCS character + */ +char mbcsToWcs (int ch, int codePage) { + if (OS.IsUnicode) return (char) ch; + int key = ch & 0xFFFF; + if (key <= 0x7F) return (char) ch; + byte [] buffer; + if (key <= 0xFF) { + buffer = new byte [1]; + buffer [0] = (byte) key; + } else { + buffer = new byte [2]; + buffer [0] = (byte) ((key >> 8) & 0xFF); + buffer [1] = (byte) (key & 0xFF); + } + char [] unicode = new char [1]; + int cp = codePage != 0 ? codePage : OS.CP_ACP; + int count = OS.MultiByteToWideChar (cp, OS.MB_PRECOMPOSED, buffer, buffer.length, unicode, 1); + if (count == 0) return 0; + return unicode [0]; +} + +/** + * 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. + * + * @param eventType the type of event which has occurred + * @param event the event data + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if 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> + */ +public void notifyListeners (int eventType, Event event) { + checkWidget(); + if (event == null) error (SWT.ERROR_NULL_ARGUMENT); + sendEvent (eventType, event); +} + +void postEvent (int eventType) { + sendEvent (eventType, null, false); +} + +void postEvent (int eventType, Event event) { + sendEvent (eventType, event, false); +} + +/* + * Releases the receiver, a child in a widget hierarchy, + * from its parent. + * <p> + * When a widget is destroyed, it may be necessary to remove + * it from an internal data structure of the parent. When + * a widget has no handle, it may also be necessary for the + * parent to hide the widget or otherwise indicate that the + * widget has been disposed. For example, disposing a menu + * bar requires that the menu bar first be released from the + * shell when the menu bar is active. This could not be done + * in <code>destroyWidget</code> for the menu bar because the + * parent shell as well as other fields have been null'd out + * already by <code>releaseWidget</code>. + * </p> + * This method is called first when a widget is disposed. + * + * @see #dispose + * @see #releaseChild + * @see #releaseWidget + * @see #releaseHandle + */ +void releaseChild () { +} + +/* + * Releases the widget's handle by zero'ing it out. + * Does not destroy or release any operating system + * resources. + * <p> + * This method is called after <code>releaseWidget</code> + * or from <code>destroyWidget</code> when a widget is being + * destroyed to ensure that the widget is marked as destroyed + * in case the act of destroying the widget in the operating + * system causes application code to run in callback that + * could access the widget. + * </p> + * + * @see #dispose + * @see #releaseChild + * @see #releaseWidget + * @see #releaseHandle + */ +void releaseHandle () { + state |= DISPOSED; +} + +void releaseResources () { + releaseWidget (); + releaseHandle (); +} + +/* + * Releases any internal resources back to the operating + * system and clears all fields except the widget handle. + * <p> + * When a widget is destroyed, resources that were acquired + * on behalf of the programmer need to be returned to the + * operating system. For example, if the widget made a + * copy of an icon, supplied by the programmer, this copy + * would be freed in <code>releaseWidget</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 widget, all fields except the + * handle are zero'd. The handle is needed by <code>destroyWidget</code>. + * </p> + * <p> + * Typically, a widget with children will broadcast this + * message to all children so that they too can release their + * resources. The <code>releaseHandle</code> method is used + * as part of this broadcast to zero the handle fields of the + * children without calling <code>destroyWidget</code>. In + * this scenario, the children are actually destroyed later, + * when the operating system destroys the widget tree. + * </p> + * This method is called after <code>releaseChild</code>. + * + * @see #dispose + * @see #releaseChild + * @see #releaseWidget + * @see #releaseHandle + */ +void releaseWidget () { + sendEvent (SWT.Dispose); + eventTable = null; + data = null; + keys = null; + values = null; +} + +/** + * Removes the listener from the collection of listeners who will + * be notifed when an event of the given type occurs. + * + * @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_WIDGET_DISPOSED - 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 + */ +public void removeListener (int eventType, Listener listener) { + checkWidget(); + if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); + if (eventTable == null) return; + eventTable.unhook (eventType, listener); +} + +/** + * Removes the listener from the collection of listeners who will + * be notifed 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 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 #addListener + */ +protected void removeListener (int eventType, SWTEventListener listener) { + checkWidget(); + if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); + if (eventTable == null) return; + eventTable.unhook (eventType, listener); +} + +/** + * Removes the listener from the collection of listeners who will + * be notifed when the widget is disposed. + * + * @param listener the listener which should no longer 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 #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 sendEvent (Event event) { + Display display = event.display; + if (!display.filterEvent (event)) { + if (eventTable != null) eventTable.sendEvent (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) { + Display display = getDisplay (); + 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); + } +} + +/** + * 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> + */ +public void setData (Object data) { + checkWidget(); + 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 + */ +public void setData (String key, Object value) { + checkWidget(); + if (key == null) error (SWT.ERROR_NULL_ARGUMENT); + + /* 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; +} + +boolean setInputState (Event event, int type) { + if (OS.GetKeyState (OS.VK_MENU) < 0) event.stateMask |= SWT.ALT; + if (OS.GetKeyState (OS.VK_SHIFT) < 0) event.stateMask |= SWT.SHIFT; + if (OS.GetKeyState (OS.VK_CONTROL) < 0) event.stateMask |= SWT.CONTROL; + if (OS.GetKeyState (OS.VK_LBUTTON) < 0) event.stateMask |= SWT.BUTTON1; + if (OS.GetKeyState (OS.VK_MBUTTON) < 0) event.stateMask |= SWT.BUTTON2; + if (OS.GetKeyState (OS.VK_RBUTTON) < 0) event.stateMask |= SWT.BUTTON3; + 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; + 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; + 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; + 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; + break; + } + return true; +} + +boolean setKeyState (Event event, int type) { + Display display = getDisplay (); + if (display.lastAscii != 0) { + event.character = mbcsToWcs ((char) display.lastAscii); + } + if (display.lastVirtual) { + event.keyCode = Display.translateKey (display.lastKey); + } + if (event.keyCode == 0 && event.character == 0) { + if (!display.lastNull) return false; + } + return setInputState (event, type); +} + +/** + * 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 + "}"; +} + +/* + * Returns a single character, converted from the wide + * character set (WCS) used by Java to the specified + * multi-byte character set used by the operating system + * widgets. + * + * @param ch the WCS character + * @param codePage the code page used to convert the character + * @return the MBCS character + */ +int wcsToMbcs (char ch, int codePage) { + if (OS.IsUnicode) return ch; + if (ch <= 0x7F) return ch; + TCHAR buffer = new TCHAR (codePage, ch, false); + return buffer.tcharAt (0); +} + +/* + * Returns a single character, converted from the wide + * character set (WCS) used by Java to the default + * multi-byte character set used by the operating system + * widgets. + * + * @param ch the WCS character + * @return the MBCS character + */ +int wcsToMbcs (char ch) { + return wcsToMbcs (ch, 0); +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/WidgetTable.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/WidgetTable.java index 3e4590df35..5398addd49 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/WidgetTable.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/WidgetTable.java @@ -1,115 +1,115 @@ -package org.eclipse.swt.widgets;
-
-/*
+package org.eclipse.swt.widgets; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.internal.win32.*;
-
-/**
- * This class contains static methods which provide a map from the
- * platform representation of a widget to the SWT control.
- */
-
-class WidgetTable {
- static int FreeSlot = 0;
- static int GrowSize = 1024;
- static int [] IndexTable = new int [GrowSize];
- static Control [] ControlTable = new Control [GrowSize];
- static {
- for (int i=0; i<GrowSize-1; i++) IndexTable [i] = i + 1;
- IndexTable [GrowSize - 1] = -1;
- }
-
-public static synchronized Control get (int handle) {
- if (handle == 0) return null;
- int index = OS.GetWindowLong (handle, OS.GWL_USERDATA) - 1;
- if (0 <= index && index < ControlTable.length) return ControlTable [index];
- return null;
-}
-
-public synchronized static void put (int handle, Control control) {
- if (handle == 0) return;
- if (FreeSlot == -1) {
- int length = (FreeSlot = IndexTable.length) + GrowSize;
- int [] newIndexTable = new int [length];
- Control [] newControlTable = new Control [length];
- System.arraycopy (IndexTable, 0, newIndexTable, 0, FreeSlot);
- System.arraycopy (ControlTable, 0, newControlTable, 0, FreeSlot);
- for (int i=FreeSlot; i<length-1; i++) newIndexTable [i] = i + 1;
- newIndexTable [length - 1] = -1;
- IndexTable = newIndexTable;
- ControlTable = newControlTable;
- }
- OS.SetWindowLong (handle, OS.GWL_USERDATA, FreeSlot + 1);
- int oldSlot = FreeSlot;
- FreeSlot = IndexTable [oldSlot];
- IndexTable [oldSlot] = -2;
- ControlTable [oldSlot] = control;
-}
-
-public static synchronized Control remove (int handle) {
- if (handle == 0) return null;
- Control control = null;
- int index = OS.GetWindowLong (handle, OS.GWL_USERDATA) - 1;
- if (0 <= index && index < ControlTable.length) {
- control = ControlTable [index];
- ControlTable [index] = null;
- IndexTable [index] = FreeSlot;
- FreeSlot = index;
- OS.SetWindowLong (handle, OS.GWL_USERDATA, 0);
- }
- return control;
-}
-
-public static synchronized Shell [] shells () {
- /*
- * This code is intentionally commented.
- * Bug in JVM 1.2. For some reason, when the following code
- * is inlined in this method, the JVM issues this error error:
- *
- * A nonfatal internal JIT (3.00.072b(x)) error 'GetRegisterA' has occurred in :
- * 'org/eclipse/swt/widgets/WidgetTable.shells ()[Lorg/eclipse/swt/widgets/Shell;': Interpreting method.
- * Please report this error in detail to http://java.sun.com/cgi-bin/bugreport.cgi
- *
- * The fix is to move the code that would be inlined into another method.
- */
-// int size = 0;
-// for (int i=0; i<WidgetTable.length; i++) {
-// Control control = WidgetTable [i];
-// if (control != null && control instanceof Shell) size++;
-// }
-
- int size = shellSize ();
- int index = 0;
- Shell [] result = new Shell [size];
- for (int i=0; i<ControlTable.length; i++) {
- Control control = ControlTable [i];
- if (control != null && control instanceof Shell) {
- result [index++] = (Shell) control;
- }
- }
- return result;
-}
-
-static int shellSize () {
- int length = 0;
- for (int i=0; i<ControlTable.length; i++) {
- Control control = ControlTable [i];
- if (control != null && control instanceof Shell) length++;
- }
- return length;
-}
-
-public static synchronized int size () {
- int length = 0;
- for (int i=0; i<ControlTable.length; i++) {
- if (ControlTable [i] != null) length++;
- }
- return length;
-}
-
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.internal.win32.*; + +/** + * This class contains static methods which provide a map from the + * platform representation of a widget to the SWT control. + */ + +class WidgetTable { + static int FreeSlot = 0; + static int GrowSize = 1024; + static int [] IndexTable = new int [GrowSize]; + static Control [] ControlTable = new Control [GrowSize]; + static { + for (int i=0; i<GrowSize-1; i++) IndexTable [i] = i + 1; + IndexTable [GrowSize - 1] = -1; + } + +public static synchronized Control get (int handle) { + if (handle == 0) return null; + int index = OS.GetWindowLong (handle, OS.GWL_USERDATA) - 1; + if (0 <= index && index < ControlTable.length) return ControlTable [index]; + return null; +} + +public synchronized static void put (int handle, Control control) { + if (handle == 0) return; + if (FreeSlot == -1) { + int length = (FreeSlot = IndexTable.length) + GrowSize; + int [] newIndexTable = new int [length]; + Control [] newControlTable = new Control [length]; + System.arraycopy (IndexTable, 0, newIndexTable, 0, FreeSlot); + System.arraycopy (ControlTable, 0, newControlTable, 0, FreeSlot); + for (int i=FreeSlot; i<length-1; i++) newIndexTable [i] = i + 1; + newIndexTable [length - 1] = -1; + IndexTable = newIndexTable; + ControlTable = newControlTable; + } + OS.SetWindowLong (handle, OS.GWL_USERDATA, FreeSlot + 1); + int oldSlot = FreeSlot; + FreeSlot = IndexTable [oldSlot]; + IndexTable [oldSlot] = -2; + ControlTable [oldSlot] = control; +} + +public static synchronized Control remove (int handle) { + if (handle == 0) return null; + Control control = null; + int index = OS.GetWindowLong (handle, OS.GWL_USERDATA) - 1; + if (0 <= index && index < ControlTable.length) { + control = ControlTable [index]; + ControlTable [index] = null; + IndexTable [index] = FreeSlot; + FreeSlot = index; + OS.SetWindowLong (handle, OS.GWL_USERDATA, 0); + } + return control; +} + +public static synchronized Shell [] shells () { + /* + * This code is intentionally commented. + * Bug in JVM 1.2. For some reason, when the following code + * is inlined in this method, the JVM issues this error error: + * + * A nonfatal internal JIT (3.00.072b(x)) error 'GetRegisterA' has occurred in : + * 'org/eclipse/swt/widgets/WidgetTable.shells ()[Lorg/eclipse/swt/widgets/Shell;': Interpreting method. + * Please report this error in detail to http://java.sun.com/cgi-bin/bugreport.cgi + * + * The fix is to move the code that would be inlined into another method. + */ +// int size = 0; +// for (int i=0; i<WidgetTable.length; i++) { +// Control control = WidgetTable [i]; +// if (control != null && control instanceof Shell) size++; +// } + + int size = shellSize (); + int index = 0; + Shell [] result = new Shell [size]; + for (int i=0; i<ControlTable.length; i++) { + Control control = ControlTable [i]; + if (control != null && control instanceof Shell) { + result [index++] = (Shell) control; + } + } + return result; +} + +static int shellSize () { + int length = 0; + for (int i=0; i<ControlTable.length; i++) { + Control control = ControlTable [i]; + if (control != null && control instanceof Shell) length++; + } + return length; +} + +public static synchronized int size () { + int length = 0; + for (int i=0; i<ControlTable.length; i++) { + if (ControlTable [i] != null) length++; + } + return length; +} + +} |