diff options
author | Christian Campo <ccampo> | 2010-08-09 07:57:10 +0000 |
---|---|---|
committer | Christian Campo <ccampo> | 2010-08-09 07:57:10 +0000 |
commit | c64b166eb91342ebed0e339dc0c596666896fdd4 (patch) | |
tree | 7632b0fe94ed73a77a3459d37992919a42b2a8a7 | |
parent | 2f47908a071ffd38fcd4f9b9f8edf751975f35df (diff) | |
download | eclipse.platform.swt-c64b166eb91342ebed0e339dc0c596666896fdd4.tar.gz eclipse.platform.swt-c64b166eb91342ebed0e339dc0c596666896fdd4.tar.xz eclipse.platform.swt-c64b166eb91342ebed0e339dc0c596666896fdd4.zip |
initial checkin of Qt Source code as approved in https://dev.eclipse.org/ipzilla/show_bug.cgi?id=4301
80 files changed, 54788 insertions, 0 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/qt/org/eclipse/swt/browser/QtWebkit.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/qt/org/eclipse/swt/browser/QtWebkit.java new file mode 100644 index 0000000000..b0b4cc759d --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/qt/org/eclipse/swt/browser/QtWebkit.java @@ -0,0 +1,201 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 compeople AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * compeople AG - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.browser; + +import com.trolltech.qt.core.QUrl; +import com.trolltech.qt.webkit.QWebView; + +import org.eclipse.swt.widgets.Composite; + +/** + * + */ +public class QtWebkit extends WebBrowser { + + private QWebView webView = null; + private int style; + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.swt.browser.WebBrowser#create(org.eclipse.swt.widgets.Composite + * , int) + */ + @Override + public void create(Composite parent, int style) { + this.style = style; + webView = new QWebView(parent.getQWidget()); + webView.loadProgress.connect(this, "loadProgress(int)"); //$NON-NLS-1$ + webView.loadFinished.connect(this, "loadFinished(boolean)"); //$NON-NLS-1$ + webView.titleChanged.connect(this, "titleChanged(java.lang.String)"); //$NON-NLS-1$ + + } + + public void loadProgress(int progress) { + ProgressEvent progressEvent = new ProgressEvent(browser); + progressEvent.display = browser.getDisplay(); + progressEvent.widget = browser; + progressEvent.current = progress; + for (int i = 0; i < progressListeners.length; i++) { + progressListeners[i].changed(progressEvent); + } + } + + public void loadFinished(boolean OK) { + ProgressEvent progressEvent = new ProgressEvent(browser); + progressEvent.display = browser.getDisplay(); + progressEvent.widget = browser; + for (int i = 0; i < progressListeners.length; i++) { + progressListeners[i].completed(progressEvent); + } + } + + public void titleChanged(String title) { + TitleEvent newEvent = new TitleEvent(browser); + newEvent.display = browser.getDisplay(); + newEvent.widget = browser; + newEvent.title = title; + for (int i = 0; i < titleListeners.length; i++) { + titleListeners[i].changed(newEvent); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.browser.WebBrowser#execute(java.lang.String) + */ + @Override + public boolean execute(String script) { + webView.page().mainFrame().evaluateJavaScript(script); + webView.repaint(); // TODO seems to help for SWT Snippet161 but is a repaint really necessary ? + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.browser.WebBrowser#back() + */ + @Override + public boolean back() { + webView.back(); + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.browser.WebBrowser#forward() + */ + @Override + public boolean forward() { + webView.forward(); + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.browser.WebBrowser#getBrowserType() + */ + @Override + public String getBrowserType() { + // TODO Auto-generated method stub + return "qtWebkit"; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.browser.WebBrowser#getText() + */ + @Override + public String getText() { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.browser.WebBrowser#getUrl() + */ + @Override + public String getUrl() { + return webView.url().toString(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.browser.WebBrowser#isBackEnabled() + */ + @Override + public boolean isBackEnabled() { + return webView.history().canGoBack(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.browser.WebBrowser#isForwardEnabled() + */ + @Override + public boolean isForwardEnabled() { + return webView.history().canGoForward(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.browser.WebBrowser#refresh() + */ + @Override + public void refresh() { + webView.reload(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.browser.WebBrowser#setText(java.lang.String) + */ + @Override + public boolean setText(String html) { + webView.setHtml(html); + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.browser.WebBrowser#setUrl(java.lang.String) + */ + @Override + public boolean setUrl(String url) { + webView.load(new QUrl(url)); + // TODO Auto-generated method stub + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.browser.WebBrowser#stop() + */ + @Override + public void stop() { + webView.stop(); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/ByteArrayTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/ByteArrayTransfer.java new file mode 100644 index 0000000000..e46c883f8b --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/ByteArrayTransfer.java @@ -0,0 +1,201 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.dnd; + +/** + * The class <code>ByteArrayTransfer</code> provides a platform specific + * mechanism for converting a java <code>byte[]</code> to a platform specific + * representation of the byte array and vice versa. + * + * <p> + * <code>ByteArrayTransfer</code> is never used directly but is sub-classed by + * transfer agents that convert between data in a java format such as a + * <code>String</code> and a platform specific byte array. + * + * <p> + * If the data you are converting <b>does not</b> map to a <code>byte[]</code>, + * you should sub-class <code>Transfer</code> directly and do your own mapping + * to a platform data type. + * </p> + * + * <p> + * The following snippet shows a subclass of ByteArrayTransfer that transfers + * data defined by the class <code>MyType</code>. + * </p> + * + * <pre> + * <code> + * public class MyType { + * public String fileName; + * public long fileLength; + * public long lastModified; + * } + * </code> + * </pre> + * + * <pre> + * <code> + * public class MyTypeTransfer extends ByteArrayTransfer { + * + * private static final String MYTYPENAME = "my_type_name"; + * private static final int MYTYPEID = registerType(MYTYPENAME); + * private static MyTypeTransfer _instance = new MyTypeTransfer(); + * + * private MyTypeTransfer() {} + * + * public static MyTypeTransfer getInstance () { + * return _instance; + * } + * public void javaToNative (Object object, TransferData transferData) { + * if (object == null || !(object instanceof MyType[])) return; + * + * if (isSupportedType(transferData)) { + * MyType[] myTypes = (MyType[]) object; + * try { + * // write data to a byte array and then ask super to convert to pMedium + * ByteArrayOutputStream out = new ByteArrayOutputStream(); + * DataOutputStream writeOut = new DataOutputStream(out); + * for (int i = 0, length = myTypes.length; i < length; i++){ + * byte[] buffer = myTypes[i].fileName.getBytes(); + * writeOut.writeInt(buffer.length); + * writeOut.write(buffer); + * writeOut.writeLong(myTypes[i].fileLength); + * writeOut.writeLong(myTypes[i].lastModified); + * } + * byte[] buffer = out.toByteArray(); + * writeOut.close(); + * + * super.javaToNative(buffer, transferData); + * + * } catch (IOException e) { + * } + * } + * } + * public Object nativeToJava(TransferData transferData){ + * + * if (isSupportedType(transferData)) { + * + * byte[] buffer = (byte[])super.nativeToJava(transferData); + * if (buffer == null) return null; + * + * MyType[] myData = new MyType[0]; + * try { + * ByteArrayInputStream in = new ByteArrayInputStream(buffer); + * DataInputStream readIn = new DataInputStream(in); + * while(readIn.available() > 20) { + * MyType datum = new MyType(); + * int size = readIn.readInt(); + * byte[] name = new byte[size]; + * readIn.read(name); + * datum.fileName = new String(name); + * datum.fileLength = readIn.readLong(); + * datum.lastModified = readIn.readLong(); + * MyType[] newMyData = new MyType[myData.length + 1]; + * System.arraycopy(myData, 0, newMyData, 0, myData.length); + * newMyData[myData.length] = datum; + * myData = newMyData; + * } + * readIn.close(); + * } catch (IOException ex) { + * return null; + * } + * return myData; + * } + * + * return null; + * } + * protected String[] getTypeNames(){ + * return new String[]{MYTYPENAME}; + * } + * protected int[] getTypeIds(){ + * return new int[] {MYTYPEID}; + * } + * } + * </code> + * </pre> + * + * @see Transfer + */ +public abstract class ByteArrayTransfer extends Transfer { + + @Override + public TransferData[] getSupportedTypes() { + int[] types = getTypeIds(); + String[] names = getTypeNames(); + TransferData[] data = new TransferData[types.length]; + for (int i = 0; i < types.length; i++) { + data[i] = new TransferData(); + data[i].type = types[i]; + data[i].format = names[i]; + } + return data; + } + + @Override + public boolean isSupportedType(TransferData transferData) { + if (transferData == null) { + return false; + } + int[] types = getTypeIds(); + for (int i = 0; i < types.length; i++) { + if (transferData.type == types[i]) { + return true; + } + } + return false; + } + + /** + * This implementation of <code>javaToNative</code> converts a java + * <code>byte[]</code> to a platform specific representation. + * + * @param object + * a java <code>byte[]</code> containing the data to be converted + * @param transferData + * an empty <code>TransferData</code> object that will be filled + * in on return with the platform specific format of the data + * + * @see Transfer#nativeToJava + */ + @Override + protected void javaToNative(Object object, TransferData transferData) { + if (!checkByteArray(object) || !isSupportedType(transferData)) { + DND.error(DND.ERROR_INVALID_DATA); + } + transferData.data = object; + } + + /** + * This implementation of <code>nativeToJava</code> converts a platform + * specific representation of a byte array to a java <code>byte[]</code>. + * + * @param transferData + * the platform specific representation of the data to be + * converted + * @return a java <code>byte[]</code> containing the converted data if the + * conversion was successful; otherwise null + * + * @see Transfer#javaToNative + */ + @Override + protected Object nativeToJava(TransferData transferData) { + if (!checkByteArray(transferData.data) || !isSupportedType(transferData)) { + return null; + } + return transferData.data; + } + + protected boolean checkByteArray(Object object) { + return object != null && object instanceof byte[] && ((byte[]) object).length > 0; + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/Clipboard.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/Clipboard.java new file mode 100644 index 0000000000..981acde037 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/Clipboard.java @@ -0,0 +1,410 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.dnd; + + +import org.eclipse.swt.*; +import org.eclipse.swt.widgets.*; + +/** + * The <code>Clipboard</code> provides a mechanism for transferring data from one + * application to another or within an application. + * + * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#clipboard">Clipboard snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ClipboardExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class Clipboard { + + private Display display; + +/** + * Constructs a new instance of this class. Creating an instance of a Clipboard + * may cause system resources to be allocated depending on the platform. It is therefore + * mandatory that the Clipboard instance be disposed when no longer required. + * + * @param display the display on which to allocate the clipboard + * + * @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 Clipboard#dispose + * @see Clipboard#checkSubclass + */ +public Clipboard(Display display) { + checkSubclass (); + if (display == null) { + display = Display.getCurrent(); + if (display == null) { + display = Display.getDefault(); + } + } + if (display.getThread() != Thread.currentThread()) { + DND.error(SWT.ERROR_THREAD_INVALID_ACCESS); + } + this.display = display; +} + +/** + * Checks that this class can be subclassed. + * <p> + * The SWT class library is intended to be subclassed + * only at specific, controlled points. 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 () { + String name = getClass().getName (); + String validName = Clipboard.class.getName(); + if (!validName.equals(name)) { + DND.error (SWT.ERROR_INVALID_SUBCLASS); + } +} + +/** + * Throws an <code>SWTException</code> if the receiver can not + * be accessed by the caller. This may include both checks on + * the state of the receiver and more generally on the entire + * execution context. This method <em>should</em> be called by + * widget implementors to enforce the standard SWT invariants. + * <p> + * Currently, it is an error to invoke any method (other than + * <code>isDisposed()</code>) on a widget that has had its + * <code>dispose()</code> method called. It is also an error + * to call widget methods from any thread that is different + * from the thread that created the widget. + * </p><p> + * In future releases of SWT, there may be more or fewer error + * checks and exceptions may be thrown for different reasons. + * </p> + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +protected void checkWidget () { + Display display = this.display; + if (display == null) DND.error (SWT.ERROR_WIDGET_DISPOSED); + if (display.getThread() != Thread.currentThread ()) DND.error (SWT.ERROR_THREAD_INVALID_ACCESS); + if (display.isDisposed()) DND.error(SWT.ERROR_WIDGET_DISPOSED); +} + +/** + * Disposes of the operating system resources associated with the clipboard. + * The data will still be available on the system clipboard after the dispose + * method is called. + * + * <p>NOTE: On some platforms the data will not be available once the application + * has exited or the display has been disposed.</p> + * + * @exception SWTException <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> + * </ul> + */ +public void dispose () { + if (isDisposed()) return; + if (display.getThread() != Thread.currentThread()) DND.error(SWT.ERROR_THREAD_INVALID_ACCESS); + display = null; +} + +/** + * Retrieve the data of the specified type currently available on the system + * clipboard. Refer to the specific subclass of <code>Transfer</code> to + * determine the type of object returned. + * + * <p>The following snippet shows text and RTF text being retrieved from the + * clipboard:</p> + * + * <code><pre> + * Clipboard clipboard = new Clipboard(display); + * TextTransfer textTransfer = TextTransfer.getInstance(); + * String textData = (String)clipboard.getContents(textTransfer); + * if (textData != null) System.out.println("Text is "+textData); + * RTFTransfer rtfTransfer = RTFTransfer.getInstance(); + * String rtfData = (String)clipboard.getContents(rtfTransfer); + * if (rtfData != null) System.out.println("RTF Text is "+rtfData); + * clipboard.dispose(); + * </code></pre> + * + * @param transfer the transfer agent for the type of data being requested + * @return the data obtained from the clipboard or null if no data of this type is available + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - 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 transfer is null</li> + * </ul> + * + * @see Transfer + */ +public Object getContents(Transfer transfer) { + return getContents(transfer, DND.CLIPBOARD); +} + +/** + * Retrieve the data of the specified type currently available on the specified + * clipboard. Refer to the specific subclass of <code>Transfer</code> to + * determine the type of object returned. + * + * <p>The following snippet shows text and RTF text being retrieved from the + * clipboard:</p> + * + * <code><pre> + * Clipboard clipboard = new Clipboard(display); + * TextTransfer textTransfer = TextTransfer.getInstance(); + * String textData = (String)clipboard.getContents(textTransfer); + * if (textData != null) System.out.println("Text is "+textData); + * RTFTransfer rtfTransfer = RTFTransfer.getInstance(); + * String rtfData = (String)clipboard.getContents(rtfTransfer, DND.CLIPBOARD); + * if (rtfData != null) System.out.println("RTF Text is "+rtfData); + * clipboard.dispose(); + * </code></pre> + * + * <p>The clipboards value is either one of the clipboard constants defined in + * class <code>DND</code>, 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>DND</code> clipboard constants.</p> + * + * @param transfer the transfer agent for the type of data being requested + * @param clipboards on which to look for data + * + * @return the data obtained from the clipboard or null if no data of this type is available + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - 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 transfer is null</li> + * </ul> + * + * @see Transfer + * @see DND#CLIPBOARD + * @see DND#SELECTION_CLIPBOARD + * + * @since 3.1 + */ +public Object getContents(Transfer transfer, int clipboards) { + checkWidget(); + if (transfer == null) DND.error(SWT.ERROR_NULL_ARGUMENT); + if (!(transfer instanceof TextTransfer)) return null; + return display.getData("TextTransfer"); //$NON-NLS-1$ +} + +/** + * Returns <code>true</code> if the clipboard has been disposed, + * and <code>false</code> otherwise. + * <p> + * This method gets the dispose state for the clipboard. + * When a clipboard has been disposed, it is an error to + * invoke any other method using the clipboard. + * </p> + * + * @return <code>true</code> when the widget is disposed and <code>false</code> otherwise + * + * @since 3.0 + */ +public boolean isDisposed () { + return (display == null); +} + +/** + * Place data of the specified type on the system clipboard. More than one type + * of data can be placed on the system clipboard at the same time. Setting the + * data clears any previous data from the system clipboard, regardless of type. + * + * <p>NOTE: On some platforms, the data is immediately copied to the system + * clipboard but on other platforms it is provided upon request. As a result, + * if the application modifies the data object it has set on the clipboard, that + * modification may or may not be available when the data is subsequently + * requested.</p> + * + * <p>The following snippet shows text and RTF text being set on the copy/paste + * clipboard: + * </p> + * + * <code><pre> + * Clipboard clipboard = new Clipboard(display); + * String textData = "Hello World"; + * String rtfData = "{\\rtf1\\b\\i Hello World}"; + * TextTransfer textTransfer = TextTransfer.getInstance(); + * RTFTransfer rtfTransfer = RTFTransfer.getInstance(); + * Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer}; + * Object[] data = new Object[]{textData, rtfData}; + * clipboard.setContents(data, transfers); + * clipboard.dispose(); + * </code></pre> + * + * @param data the data to be set in the clipboard + * @param dataTypes the transfer agents that will convert the data to its + * platform specific format; each entry in the data array must have a + * corresponding dataType + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null + * or the length of data is not the same as the length of dataTypes</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - 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_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li> + * </ul> + * + * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an SWTException, since it is a + * recoverable error, but can not be changed due to backward compatibility.</p> + */ +public void setContents(Object[] data, Transfer[] dataTypes) { + setContents(data, dataTypes, DND.CLIPBOARD); +} + +/** + * Place data of the specified type on the specified clipboard. More than one + * type of data can be placed on the specified clipboard at the same time. + * Setting the data clears any previous data from the specified + * clipboard, regardless of type. + * + * <p>NOTE: On some platforms, the data is immediately copied to the specified + * clipboard but on other platforms it is provided upon request. As a result, + * if the application modifies the data object it has set on the clipboard, that + * modification may or may not be available when the data is subsequently + * requested.</p> + * + * <p>The clipboards value is either one of the clipboard constants defined in + * class <code>DND</code>, 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>DND</code> clipboard constants.</p> + * + * <p>The following snippet shows text and RTF text being set on the copy/paste + * clipboard: + * </p> + * + * <code><pre> + * Clipboard clipboard = new Clipboard(display); + * String textData = "Hello World"; + * String rtfData = "{\\rtf1\\b\\i Hello World}"; + * TextTransfer textTransfer = TextTransfer.getInstance(); + * RTFTransfer rtfTransfer = RTFTransfer.getInstance(); + * Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer}; + * Object[] data = new Object[]{textData, rtfData}; + * clipboard.setContents(data, transfers, DND.CLIPBOARD); + * clipboard.dispose(); + * </code></pre> + * + * @param data the data to be set in the clipboard + * @param dataTypes the transfer agents that will convert the data to its + * platform specific format; each entry in the data array must have a + * corresponding dataType + * @param clipboards on which to set the data + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null + * or the length of data is not the same as the length of dataTypes</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - 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_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li> + * </ul> + * + * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an SWTException, since it is a + * recoverable error, but can not be changed due to backward compatibility.</p> + * + * @see DND#CLIPBOARD + * @see DND#SELECTION_CLIPBOARD + * + * @since 3.1 + */ +public void setContents(Object[] data, Transfer[] dataTypes, int clipboards) { + checkWidget(); + if (data == null || dataTypes == null || data.length != dataTypes.length) { + DND.error(SWT.ERROR_INVALID_ARGUMENT); + } + + for (int i = 0; i < dataTypes.length; i++) { + if (dataTypes[i] instanceof TextTransfer && data[i] instanceof String){ + display.setData("TextTransfer", data[i]); //$NON-NLS-1$ + return; + } + } +} + +/** + * Returns an array of the data types currently available on the system + * clipboard. Use with Transfer.isSupportedType. + * + * @return array of data types currently available on the system clipboard + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see Transfer#isSupportedType + * + * @since 3.0 + */ +public TransferData[] getAvailableTypes() { + checkWidget(); + return new TransferData[0]; +} + +/** + * Returns a platform specific list of the data types currently available on the + * system clipboard. + * + * <p>Note: <code>getAvailableTypeNames</code> is a utility for writing a Transfer + * sub-class. It should NOT be used within an application because it provides + * platform specific information.</p> + * + * @return a platform specific list of the data types currently available on the + * system clipboard + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if 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[] getAvailableTypeNames() { + checkWidget(); + return new String[0]; +} +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/DragSource.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/DragSource.java new file mode 100644 index 0000000000..fffc83ce22 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/DragSource.java @@ -0,0 +1,593 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.dnd; + +import com.trolltech.qt.core.QByteArray; +import com.trolltech.qt.core.QMimeData; +import com.trolltech.qt.core.Qt.DropAction; +import com.trolltech.qt.core.Qt.DropActions; +import com.trolltech.qt.gui.QDrag; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTError; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.Widget; + +/** + * + * <code>DragSource</code> defines the source object for a drag and drop + * transfer. + * + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * <p> + * A drag source is the object which originates a drag and drop operation. For + * the specified widget, it defines the type of data that is available for + * dragging and the set of operations that can be performed on that data. The + * operations can be any bit-wise combination of DND.MOVE, DND.COPY or DND.LINK. + * The type of data that can be transferred is specified by subclasses of + * Transfer such as TextTransfer or FileTransfer. The type of data transferred + * can be a predefined system type or it can be a type defined by the + * application. For instructions on how to define your own transfer type, refer + * to <code>ByteArrayTransfer</code>. + * </p> + * + * <p> + * You may have several DragSources in an application but you can only have one + * DragSource per Control. Data dragged from this DragSource can be dropped on a + * site within this application or it can be dropped on another application such + * as an external Text editor. + * </p> + * + * <p> + * The application supplies the content of the data being transferred by + * implementing the <code>DragSourceListener</code> and associating it with the + * DragSource via DragSource#addDragListener. + * </p> + * + * <p> + * When a successful move operation occurs, the application is required to take + * the appropriate action to remove the data from its display and remove any + * associated operating system resources or internal references. Typically in a + * move operation, the drop target makes a copy of the data and the drag source + * deletes the original. However, sometimes copying the data can take a long + * time (such as copying a large file). Therefore, on some platforms, the drop + * target may actually move the data in the operating system rather than make a + * copy. This is usually only done in file transfers. In this case, the drag + * source is informed in the DragEnd event that a DROP_TARGET_MOVE was + * performed. It is the responsibility of the drag source at this point to clean + * up its displayed information. No action needs to be taken on the operating + * system resources. + * </p> + * + * <p> + * The following example shows a Label widget that allows text to be dragged + * from it. + * </p> + * + * <code><pre> + * // Enable a label as a Drag Source + * Label label = new Label(shell, SWT.NONE); + * // This example will allow text to be dragged + * Transfer[] types = new Transfer[] {TextTransfer.getInstance()}; + * // This example will allow the text to be copied or moved to the drop target + * int operations = DND.DROP_MOVE | DND.DROP_COPY; + * + * DragSource source = new DragSource(label, operations); + * source.setTransfer(types); + * source.addDragListener(new DragSourceListener() { + * public void dragStart(DragSourceEvent e) { + * // Only start the drag if there is actually text in the + * // label - this text will be what is dropped on the target. + * if (label.getText().length() == 0) { + * event.doit = false; + * } + * }; + * public void dragSetData(DragSourceEvent event) { + * // A drop has been performed, so provide the data of the + * // requested type. + * // (Checking the type of the requested data is only + * // necessary if the drag source supports more than + * // one data type but is shown here as an example). + * if (TextTransfer.getInstance().isSupportedType(event.dataType)){ + * event.data = label.getText(); + * } + * } + * public void dragFinished(DragSourceEvent event) { + * // A Move operation has been performed so remove the data + * // from the source + * if (event.detail == DND.DROP_MOVE) + * label.setText(""); + * } + * }); + * </pre></code> + * + * + * <dl> + * <dt><b>Styles</b></dt> + * <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd> + * <dt><b>Events</b></dt> + * <dd>DND.DragStart, DND.DragSetData, DND.DragEnd</dd> + * </dl> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#dnd">Drag and Drop + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * DNDExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class DragSource extends Widget { + + // info for registering as a drag source + private Control control; + private Listener controlListener; + private Transfer[] transferAgents = new Transfer[0]; + private DragSourceEffect dragEffect; + private QDrag drag; + + private static final String DEFAULT_DRAG_SOURCE_EFFECT = "DEFAULT_DRAG_SOURCE_EFFECT"; //$NON-NLS-1$ + + /** + * Creates a new <code>DragSource</code> to handle dragging from the + * specified <code>Control</code>. Creating an instance of a DragSource may + * cause system resources to be allocated depending on the platform. It is + * therefore mandatory that the DragSource instance be disposed when no + * longer required. + * + * @param control + * the <code>Control</code> that the user clicks on to initiate + * the drag + * @param style + * the bitwise OR'ing of allowed operations; this may be a + * combination of any of DND.DROP_NONE, DND.DROP_COPY, + * DND.DROP_MOVE, DND.DROP_LINK + * + * @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> + * @exception SWTError + * <ul> + * <li>ERROR_CANNOT_INIT_DRAG - unable to initiate drag + * source; this will occur if more than one drag source is + * created for a control or if the operating system will not + * allow the creation of the drag source</li> + * </ul> + * + * <p> + * NOTE: ERROR_CANNOT_INIT_DRAG should be an SWTException, + * since it is a recoverable error, but can not be changed + * due to backward compatibility. + * </p> + * + * @see Widget#dispose + * @see DragSource#checkSubclass + * @see DND#DROP_NONE + * @see DND#DROP_COPY + * @see DND#DROP_MOVE + * @see DND#DROP_LINK + */ + public DragSource(Control control, int style) { + super(control, checkStyle(style)); + this.control = control; + if (control.getData(DND.DRAG_SOURCE_KEY) != null) { + DND.error(DND.ERROR_CANNOT_INIT_DRAG); + } + control.setDragEnabled(true); + control.setData(DND.DRAG_SOURCE_KEY, this); + + controlListener = new Listener() { + public void handleEvent(Event event) { + if (event.type == SWT.DragDetect) { + if (!DragSource.this.isDisposed()) { + DragSource.this.drag(event); + return; + } + } + if (event.type == SWT.Dispose) { + if (!DragSource.this.isDisposed()) { + DragSource.this.dispose(); + } + } + } + }; + control.addListener(SWT.Dispose, controlListener); + control.addListener(SWT.DragDetect, controlListener); + + this.addListener(SWT.Dispose, new Listener() { + public void handleEvent(Event e) { + onDispose(); + } + }); + + Object effect = control.getData(DEFAULT_DRAG_SOURCE_EFFECT); + if (effect instanceof DragSourceEffect) { + dragEffect = (DragSourceEffect) effect; + } else if (control instanceof Tree) { + dragEffect = new TreeDragSourceEffect((Tree) control); + } else if (control instanceof Table) { + dragEffect = new TableDragSourceEffect((Table) control); + } + } + + private void drag(Event dragEvent) { + if (transferAgents == null || transferAgents.length == 0) { + return; + } + System.out.println("dragging ongoing"); + + try { + if (drag == null) { + DNDEvent event = new DNDEvent(); + event.widget = this; + event.x = dragEvent.x; + event.y = dragEvent.y; + event.time = dragEvent.time; + event.doit = true; + notifyListeners(DND.DragStart, event); + + if (!event.doit) { + System.out.println("stop after DragStart event"); + return; + } + + QMimeData mimeData = createMimeData(); + if (mimeData == null) { + System.out.println("stop after DragSetData event"); + return; + } + + System.out.println("send mime: " + mimeData); + + drag = new QDrag(control.getQWidget()); + + drag.setMimeData(mimeData); + + DropActions actions = convertOps2Actions(getStyle()); + DropAction dropAction = drag.exec(actions, defaultAction(actions)); + + int operation = convertAction(dropAction); + DNDEvent endEvent = new DNDEvent(); + endEvent.widget = this; + endEvent.doit = operation != 0; + endEvent.detail = operation; + notifyListeners(DND.DragEnd, endEvent); + + control.dragEnd(); + System.out.println(dropAction); + } + } finally { + drag = null; + } + } + + /** + * @param actions + * @return + */ + private DropAction defaultAction(DropActions actions) { + if (actions.isSet(DropAction.CopyAction)) { + return DropAction.CopyAction; + } else if (actions.isSet(DropAction.MoveAction)) { + return DropAction.MoveAction; + } else if (actions.isSet(DropAction.LinkAction)) { + return DropAction.LinkAction; + } else if (actions.isSet(DropAction.TargetMoveAction)) { + return DropAction.TargetMoveAction; + } + return DropAction.IgnoreAction; + } + + /** + * @param dragEvent + * @return + */ + private QMimeData createMimeData() { + QMimeData mimeData = null; + for (Transfer transfer : transferAgents) { + if (transfer == null) { + continue; + } + for (TransferData transferData : transfer.getSupportedTypes()) { + DNDEvent setDataEvent = new DNDEvent(); + setDataEvent.widget = this; + setDataEvent.dataType = transferData; + notifyListeners(DND.DragSetData, setDataEvent); + if (setDataEvent.doit && setDataEvent.data != null) { + transfer.javaToNative(setDataEvent.data, transferData); + if (mimeData == null) { + mimeData = new QMimeData(); + } + mimeData.setData(transferData.format, new QByteArray((byte[]) transferData.data)); + } + } + } + return mimeData; + } + + static int convertAction(DropAction dropAction) { + if (dropAction == DropAction.CopyAction) { + return DND.DROP_COPY; + } + if (dropAction == DropAction.MoveAction) { + return DND.DROP_MOVE; + } + if (dropAction == DropAction.LinkAction) { + return DND.DROP_LINK; + } + if (dropAction == DropAction.TargetMoveAction) { + return DND.DROP_TARGET_MOVE; + } + return DND.DROP_NONE; + } + + static int convertActions(DropActions dropActions) { + int actions = DND.DROP_NONE; + if (dropActions.isSet(DropAction.CopyAction)) { + actions |= DND.DROP_COPY; + } + if (dropActions.isSet(DropAction.MoveAction)) { + actions |= DND.DROP_MOVE; + } + if (dropActions.isSet(DropAction.LinkAction)) { + actions |= DND.DROP_LINK; + } + if (dropActions.isSet(DropAction.TargetMoveAction)) { + actions |= DND.DROP_TARGET_MOVE; + } + return actions; + } + + static DropActions convertOps2Actions(int operations) { + int actions = 0; + if ((operations & DND.DROP_COPY) != 0) { + actions |= DropAction.CopyAction.value(); + } + if ((operations & DND.DROP_MOVE) != 0) { + actions |= DropAction.MoveAction.value(); + } + if ((operations & DND.DROP_LINK) != 0) { + actions |= DropAction.LinkAction.value(); + } + if ((operations & DND.DROP_TARGET_MOVE) != 0) { + actions |= DropAction.TargetMoveAction.value(); + } + return new DropActions(actions); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when a drag and drop operation is in progress, by sending it one of the + * messages defined in the <code>DragSourceListener</code> interface. + * + * <p> + * <ul> + * <li><code>dragStart</code> is called when the user has begun the actions + * required to drag the widget. This event gives the application the chance + * to decide if a drag should be started. + * <li><code>dragSetData</code> is called when the data is required from the + * drag source. + * <li><code>dragFinished</code> is called when the drop has successfully + * completed (mouse up over a valid target) or has been terminated (such as + * hitting the ESC key). Perform cleanup such as removing data from the + * source side on a successful move operation. + * </ul> + * </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 DragSourceListener + * @see #getDragListeners + * @see #removeDragListener + * @see DragSourceEvent + */ + public void addDragListener(DragSourceListener listener) { + if (listener == null) { + DND.error(SWT.ERROR_NULL_ARGUMENT); + } + DNDListener typedListener = new DNDListener(listener); + typedListener.dndWidget = this; + addListener(DND.DragStart, typedListener); + addListener(DND.DragSetData, typedListener); + addListener(DND.DragEnd, typedListener); + } + + static int checkStyle(int style) { + if (style == SWT.NONE) { + return DND.DROP_MOVE; + } + return style; + } + + @Override + protected void checkSubclass() { + String name = getClass().getName(); + String validName = DragSource.class.getName(); + if (!validName.equals(name)) { + DND.error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + /** + * Returns the Control which is registered for this DragSource. This is the + * control that the user clicks in to initiate dragging. + * + * @return the Control which is registered for this DragSource + */ + public Control getControl() { + return control; + } + + /** + * Returns an array of listeners who will be notified when a drag and drop + * operation is in progress, by sending it one of the messages defined in + * the <code>DragSourceListener</code> interface. + * + * @return the listeners who will be notified when a drag and drop operation + * is in progress + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see DragSourceListener + * @see #addDragListener + * @see #removeDragListener + * @see DragSourceEvent + * + * @since 3.4 + */ + public DragSourceListener[] getDragListeners() { + Listener[] listeners = getListeners(DND.DragStart); + int length = listeners.length; + DragSourceListener[] dragListeners = new DragSourceListener[length]; + int count = 0; + for (int i = 0; i < length; i++) { + Listener listener = listeners[i]; + if (listener instanceof DNDListener) { + dragListeners[count] = (DragSourceListener) ((DNDListener) listener).getEventListener(); + count++; + } + } + if (count == length) { + return dragListeners; + } + DragSourceListener[] result = new DragSourceListener[count]; + System.arraycopy(dragListeners, 0, result, 0, count); + return result; + } + + /** + * Returns the drag effect that is registered for this DragSource. This drag + * effect will be used during a drag and drop operation. + * + * @return the drag effect that is registered for this DragSource + * + * @since 3.3 + */ + public DragSourceEffect getDragSourceEffect() { + return dragEffect; + } + + /** + * Returns the list of data types that can be transferred by this + * DragSource. + * + * @return the list of data types that can be transferred by this DragSource + */ + public Transfer[] getTransfer() { + return transferAgents; + } + + private void onDispose() { + if (control == null) { + return; + } + if (controlListener != null) { + control.removeListener(SWT.Dispose, controlListener); + control.removeListener(SWT.DragDetect, controlListener); + } + controlListener = null; + control.setData(DND.DRAG_SOURCE_KEY, null); + control = null; + transferAgents = null; + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when a drag and drop operation is in progress. + * + * @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 DragSourceListener + * @see #addDragListener + * @see #getDragListeners + */ + public void removeDragListener(DragSourceListener listener) { + if (listener == null) { + DND.error(SWT.ERROR_NULL_ARGUMENT); + } + removeListener(DND.DragStart, listener); + removeListener(DND.DragSetData, listener); + removeListener(DND.DragEnd, listener); + } + + /** + * Specifies the drag effect for this DragSource. This drag effect will be + * used during a drag and drop operation. + * + * @param effect + * the drag effect that is registered for this DragSource + * + * @since 3.3 + */ + public void setDragSourceEffect(DragSourceEffect effect) { + dragEffect = effect; + } + + /** + * Specifies the list of data types that can be transferred by this + * DragSource. The application must be able to provide data to match each of + * these types when a successful drop has occurred. + * + * @param transferAgents + * a list of Transfer objects which define the types of data that + * can be dragged from this source + */ + public void setTransfer(Transfer[] transferAgents) { + this.transferAgents = transferAgents; + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/DropTarget.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/DropTarget.java new file mode 100644 index 0000000000..4bf4db6afd --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/DropTarget.java @@ -0,0 +1,638 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.dnd; + +import java.util.ArrayList; +import java.util.List; + +import com.trolltech.qt.core.QByteArray; +import com.trolltech.qt.core.QMimeData; +import com.trolltech.qt.core.QPoint; +import com.trolltech.qt.core.Qt.DropAction; +import com.trolltech.qt.core.Qt.DropActions; +import com.trolltech.qt.gui.QDragEnterEvent; +import com.trolltech.qt.gui.QDragLeaveEvent; +import com.trolltech.qt.gui.QDragMoveEvent; +import com.trolltech.qt.gui.QDropEvent; +import com.trolltech.qt.gui.QWidget; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTError; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.internal.qt.DragNDropListener; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.Widget; + +/** + * + * Class <code>DropTarget</code> defines the target object for a drag and drop + * transfer. + * + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * <p> + * This class identifies the <code>Control</code> over which the user must + * position the cursor in order to drop the data being transferred. It also + * specifies what data types can be dropped on this control and what operations + * can be performed. You may have several DropTragets in an application but + * there can only be a one to one mapping between a <code>Control</code> and a + * <code>DropTarget</code>. The DropTarget can receive data from within the same + * application or from other applications (such as text dragged from a text + * editor like Word). + * </p> + * + * <code><pre> + * int operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK; + * Transfer[] types = new Transfer[] {TextTransfer.getInstance()}; + * DropTarget target = new DropTarget(label, operations); + * target.setTransfer(types); + * </code></pre> + * + * <p> + * The application is notified of data being dragged over this control and of + * when a drop occurs by implementing the interface + * <code>DropTargetListener</code> which uses the class + * <code>DropTargetEvent</code>. The application can modify the type of drag + * being performed on this Control at any stage of the drag by modifying the + * <code>event.detail</code> field or the <code>event.currentDataType</code> + * field. When the data is dropped, it is the responsibility of the application + * to copy this data for its own purposes. + * + * <code><pre> + * target.addDropListener (new DropTargetListener() { + * public void dragEnter(DropTargetEvent event) {}; + * public void dragOver(DropTargetEvent event) {}; + * public void dragLeave(DropTargetEvent event) {}; + * public void dragOperationChanged(DropTargetEvent event) {}; + * public void dropAccept(DropTargetEvent event) {} + * public void drop(DropTargetEvent event) { + * // A drop has occurred, copy over the data + * if (event.data == null) { // no data to copy, indicate failure in event.detail + * event.detail = DND.DROP_NONE; + * return; + * } + * label.setText ((String) event.data); // data copied to label text + * } + * }); + * </pre></code> + * + * <dl> + * <dt><b>Styles</b></dt> + * <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd> + * <dt><b>Events</b></dt> + * <dd>DND.DragEnter, DND.DragLeave, DND.DragOver, DND.DragOperationChanged, + * DND.DropAccept, DND.Drop</dd> + * </dl> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#dnd">Drag and Drop + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * DNDExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class DropTarget extends Widget { + + // info for registering as a droptarget + Control control; + Listener controlListener; + Transfer[] transferAgents = new Transfer[0]; + DropTargetEffect dropEffect; + private DragNDropListener dndListener; + + static final String DEFAULT_DROP_TARGET_EFFECT = "DEFAULT_DROP_TARGET_EFFECT"; //$NON-NLS-1$ + + /** + * Creates a new <code>DropTarget</code> to allow data to be dropped on the + * specified <code>Control</code>. Creating an instance of a DropTarget may + * cause system resources to be allocated depending on the platform. It is + * therefore mandatory that the DropTarget instance be disposed when no + * longer required. + * + * @param control + * the <code>Control</code> over which the user positions the + * cursor to drop the data + * @param style + * the bitwise OR'ing of allowed operations; this may be a + * combination of any of DND.DROP_NONE, DND.DROP_COPY, + * DND.DROP_MOVE, DND.DROP_LINK + * + * @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> + * @exception SWTError + * <ul> + * <li>ERROR_CANNOT_INIT_DROP - unable to initiate drop + * target; this will occur if more than one drop target is + * created for a control or if the operating system will not + * allow the creation of the drop target</li> + * </ul> + * + * <p> + * NOTE: ERROR_CANNOT_INIT_DROP should be an SWTException, + * since it is a recoverable error, but can not be changed + * due to backward compatibility. + * </p> + * + * @see Widget#dispose + * @see DropTarget#checkSubclass + * @see DND#DROP_NONE + * @see DND#DROP_COPY + * @see DND#DROP_MOVE + * @see DND#DROP_LINK + */ + public DropTarget(Control control, int style) { + super(control, checkStyle(style)); + this.control = control; + if (control.getData(DND.DROP_TARGET_KEY) != null) { + DND.error(DND.ERROR_CANNOT_INIT_DROP); + } + control.setData(DND.DROP_TARGET_KEY, this); + control.setAcceptDrops(true); + + controlListener = new Listener() { + public void handleEvent(Event event) { + if (!DropTarget.this.isDisposed()) { + DropTarget.this.dispose(); + } + } + }; + control.addListener(SWT.Dispose, controlListener); + + this.addListener(SWT.Dispose, new Listener() { + public void handleEvent(Event event) { + onDispose(); + } + }); + + this.dndListener = new QDNDListener(); + control.setDragNDropListener(dndListener); + + Object effect = control.getData(DEFAULT_DROP_TARGET_EFFECT); + if (effect instanceof DropTargetEffect) { + dropEffect = (DropTargetEffect) effect; + } else if (control instanceof Table) { + dropEffect = new TableDropTargetEffect((Table) control); + } else if (control instanceof Tree) { + dropEffect = new TreeDropTargetEffect((Tree) control); + } + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when a drag and drop operation is in progress, by sending it one of the + * messages defined in the <code>DropTargetListener</code> interface. + * + * <p> + * <ul> + * <li><code>dragEnter</code> is called when the cursor has entered the drop + * target boundaries + * <li><code>dragLeave</code> is called when the cursor has left the drop + * target boundaries and just before the drop occurs or is cancelled. + * <li><code>dragOperationChanged</code> is called when the operation being + * performed has changed (usually due to the user changing the selected + * modifier key(s) while dragging) + * <li><code>dragOver</code> is called when the cursor is moving over the + * drop target + * <li><code>dropAccept</code> is called just before the drop is performed. + * The drop target is given the chance to change the nature of the drop or + * veto the drop by setting the <code>event.detail</code> field + * <li><code>drop</code> is called when the data is being dropped + * </ul> + * </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 DropTargetListener + * @see #getDropListeners + * @see #removeDropListener + * @see DropTargetEvent + */ + public void addDropListener(DropTargetListener listener) { + if (listener == null) { + DND.error(SWT.ERROR_NULL_ARGUMENT); + } + DNDListener typedListener = new DNDListener(listener); + typedListener.dndWidget = this; + addListener(DND.DragEnter, typedListener); + addListener(DND.DragLeave, typedListener); + addListener(DND.DragOver, typedListener); + addListener(DND.DragOperationChanged, typedListener); + addListener(DND.Drop, typedListener); + addListener(DND.DropAccept, typedListener); + } + + static int checkStyle(int style) { + if (style == SWT.NONE) { + return DND.DROP_MOVE; + } + return style; + } + + @Override + protected void checkSubclass() { + String name = getClass().getName(); + String validName = DropTarget.class.getName(); + if (!validName.equals(name)) { + DND.error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + /** + * Returns the Control which is registered for this DropTarget. This is the + * control over which the user positions the cursor to drop the data. + * + * @return the Control which is registered for this DropTarget + */ + public Control getControl() { + return control; + } + + /** + * Returns an array of listeners who will be notified when a drag and drop + * operation is in progress, by sending it one of the messages defined in + * the <code>DropTargetListener</code> interface. + * + * @return the listeners who will be notified when a drag and drop operation + * is in progress + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see DropTargetListener + * @see #addDropListener + * @see #removeDropListener + * @see DropTargetEvent + * + * @since 3.4 + */ + public DropTargetListener[] getDropListeners() { + Listener[] listeners = getListeners(DND.DragEnter); + int length = listeners.length; + DropTargetListener[] dropListeners = new DropTargetListener[length]; + int count = 0; + for (int i = 0; i < length; i++) { + Listener listener = listeners[i]; + if (listener instanceof DropTargetListener) { + dropListeners[count] = (DropTargetListener) ((DNDListener) listener).getEventListener(); + count++; + } + } + if (count == length) { + return dropListeners; + } + DropTargetListener[] result = new DropTargetListener[count]; + System.arraycopy(dropListeners, 0, result, 0, count); + return result; + } + + /** + * Returns the drop effect for this DropTarget. This drop effect will be + * used during a drag and drop to display the drag under effect on the + * target widget. + * + * @return the drop effect that is registered for this DropTarget + * + * @since 3.3 + */ + public DropTargetEffect getDropTargetEffect() { + return dropEffect; + } + + /** + * Specifies the drop effect for this DropTarget. This drop effect will be + * used during a drag and drop to display the drag under effect on the + * target widget. + * + * @param effect + * the drop effect that is registered for this DropTarget + * + * @since 3.3 + */ + public void setDropTargetEffect(DropTargetEffect effect) { + dropEffect = effect; + } + + /** + * Returns a list of the data types that can be transferred to this + * DropTarget. + * + * @return a list of the data types that can be transferred to this + * DropTarget + */ + public Transfer[] getTransfer() { + return transferAgents; + } + + void onDispose() { + if (control == null) { + return; + } + if (controlListener != null) { + control.removeListener(SWT.Dispose, controlListener); + } + controlListener = null; + control.unsetDragNDropListener(dndListener); + dndListener = null; + control.setData(DND.DROP_TARGET_KEY, null); + control.setAcceptDrops(false); + transferAgents = null; + control = null; + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when a drag and drop operation is in progress. + * + * @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 DropTargetListener + * @see #addDropListener + * @see #getDropListeners + */ + public void removeDropListener(DropTargetListener listener) { + if (listener == null) { + DND.error(SWT.ERROR_NULL_ARGUMENT); + } + removeListener(DND.DragEnter, listener); + removeListener(DND.DragLeave, listener); + removeListener(DND.DragOver, listener); + removeListener(DND.DragOperationChanged, listener); + removeListener(DND.Drop, listener); + removeListener(DND.DropAccept, listener); + } + + /** + * Specifies the data types that can be transferred to this DropTarget. If + * data is being dragged that does not match one of these types, the drop + * target will be notified of the drag and drop operation but the + * currentDataType will be null and the operation will be DND.NONE. + * + * @param transferAgents + * a list of Transfer objects which define the types of data that + * can be dropped on this target + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if transferAgents is null</li> + * </ul> + */ + public void setTransfer(Transfer[] transferAgents) { + if (transferAgents == null) { + DND.error(SWT.ERROR_NULL_ARGUMENT); + } + this.transferAgents = transferAgents; + } + + private final class QDNDListener implements DragNDropListener { + TransferData selectedDataType; + int selectedOperation = -1; + + public void dragEnter(QDragEnterEvent qEvent) { + System.out.println("DNDListener.dragEnter"); + + DNDEvent event = new DNDEvent(); + if (!initDNDEvent(event, qEvent.source(), qEvent.mimeData(), qEvent.pos(), qEvent.proposedAction(), qEvent + .possibleActions())) { + return; + } + + int operation = event.detail; + int allowedOperations = event.operations; + System.out.println("proposed op: " + operation + " from: " + event.operations); + selectedDataType = null; + selectedOperation = DND.DROP_NONE; + notifyListeners(DND.DragEnter, event); + + if (!handleEventResponse(qEvent, event, operation, allowedOperations)) { + qEvent.acceptProposedAction(); + } + } + + public void dragMove(QDragMoveEvent qEvent) { + System.out.println("DNDListener.dragMove"); + + DNDEvent event = new DNDEvent(); + if (!initDNDEvent(event, qEvent.source(), qEvent.mimeData(), qEvent.pos(), qEvent.proposedAction(), qEvent + .possibleActions())) { + return; + } + int operation = event.detail; + int allowedOperations = event.operations; + + System.out.println("proposed op: " + operation + " from: " + event.operations); + + selectedDataType = null; + if (selectedOperation != operation) { + System.out.println("op changed"); + notifyListeners(DND.DragOperationChanged, event); + } else { + notifyListeners(DND.DragOver, event); + } + handleEventResponse(qEvent, event, operation, allowedOperations); + } + + public void drop(QDropEvent event) { + System.out.println("DNDListener.drop. selected type: " + selectedDataType + " op: " + selectedOperation); + + DNDEvent swtEvent = new DNDEvent(); + if (!initDNDEvent(swtEvent, event.source(), event.mimeData(), event.pos(), event.proposedAction(), event + .possibleActions())) { + return; + } + + swtEvent.dataType = selectedDataType; + swtEvent.detail = selectedOperation; + + Transfer transfer = getTransfer(selectedDataType.format); + QByteArray ba = event.mimeData().data(selectedDataType.format); + if (ba == null || transfer == null) { + System.out.println("no data or transfer for format: " + selectedDataType.format); + return; + } + selectedDataType.data = ba.toByteArray(); + swtEvent.data = transfer.nativeToJava(selectedDataType); + + notifyListeners(DND.Drop, swtEvent); + handleEventResponse(event, swtEvent, selectedOperation, selectedOperation); + } + + public void dragLeave(QDragLeaveEvent event) { + System.out.println("DNDListener.dragLeave"); + DNDEvent swtEvent = new DNDEvent(); + + swtEvent.widget = DropTarget.this; + swtEvent.detail = DND.DROP_NONE; + notifyListeners(DND.DragLeave, swtEvent); + selectedDataType = null; + selectedOperation = -1; + } + + private boolean initDNDEvent(DNDEvent event, QWidget source, QMimeData mimeData, QPoint globalPos, + DropAction proposedAction, DropActions possibleActions) { + + event.operations = DragSource.convertActions(possibleActions) & getStyle(); + if (event.operations == DND.DROP_NONE) { + return false; + } + + TransferData[] dataTypes = getDataTypes(mimeData); + if (dataTypes.length == 0) { + System.out.println("no supported mime types found"); + return false; + } + + QPoint pos = source.mapToGlobal(globalPos); + event.widget = DropTarget.this; + event.x = pos.x(); + event.y = pos.y(); + event.time = DropTarget.this.control.getDisplay().getLastEventTime(); + event.dataType = dataTypes[0]; + event.dataTypes = dataTypes; + event.detail = DragSource.convertAction(proposedAction); + event.feedback = DND.FEEDBACK_SELECT; + event.doit = true; + if (dropEffect != null) { + event.item = dropEffect.getItem(event.x, event.y); + } + + return true; + } + + private boolean handleEventResponse(QDropEvent qEvent, DNDEvent event, int operation, int allowedOperations) { + selectedDataType = event.dataType; + System.out.println("selected type: " + selectedDataType); + System.out.println("op from event : " + event.detail); + if (event.detail == DND.DROP_DEFAULT) { + event.detail = (allowedOperations & DND.DROP_MOVE) != 0 ? DND.DROP_MOVE : DND.DROP_NONE; + } + + if (selectedDataType != null && (allowedOperations & event.detail) != 0) { + selectedOperation = event.detail; + } + System.out.println("selected op : " + selectedOperation); + + if (selectedOperation == operation) { + qEvent.acceptProposedAction(); + } else { + if (selectedOperation != DND.DROP_NONE) { + DropAction action = convertOperation(selectedOperation); + System.out.println("changed op: " + action); + qEvent.setDropAction(action); + qEvent.accept(); + } else { + return false; + } + } + return true; + } + + private Transfer getTransfer(String format) { + for (Transfer transfer : transferAgents) { + if (transfer == null) { + continue; + } + for (String typeName : transfer.getTypeNames()) { + if (format.equals(typeName)) { + return transfer; + } + } + } + return null; + } + + private TransferData[] getDataTypes(QMimeData mimeData) { + System.out.println("got mimeData " + mimeData.formats()); + + List<TransferData> dataTypes = new ArrayList<TransferData>(); + for (Transfer transfer : transferAgents) { + if (transfer == null) { + continue; + } + String[] typeNames = transfer.getTypeNames(); + int[] typeIds = transfer.getTypeIds(); + for (int i = 0; i < typeNames.length; i++) { + String typeName = typeNames[i]; + if (mimeData.hasFormat(typeName)) { + TransferData data = new TransferData(); + data.type = typeIds[i]; + data.format = typeName; + dataTypes.add(data); + } + } + } + //System.out.println("mime -> transfer types: " + dataTypes); + return dataTypes.toArray(new TransferData[dataTypes.size()]); + } + + private DropAction convertOperation(int operation) { + if (operation == DND.DROP_COPY) { + return DropAction.CopyAction; + } + if (operation == DND.DROP_MOVE) { + return DropAction.MoveAction; + } + if (operation == DND.DROP_LINK) { + return DropAction.LinkAction; + } + if (operation == DND.DROP_TARGET_MOVE) { + return DropAction.TargetMoveAction; + } + return DropAction.IgnoreAction; + } + + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/FileTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/FileTransfer.java new file mode 100644 index 0000000000..21e615d272 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/FileTransfer.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.dnd; + +/** + * The class <code>FileTransfer</code> provides a platform specific mechanism + * for converting a list of files represented as a java <code>String[]</code> to + * a platform specific representation of the data and vice versa. Each + * <code>String</code> in the array contains the absolute path for a single file + * or directory. + * + * <p> + * An example of a java <code>String[]</code> containing a list of files is + * shown below: + * </p> + * + * <code><pre> + * File file1 = new File("C:\temp\file1"); + * File file2 = new File("C:\temp\file2"); + * String[] fileData = new String[2]; + * fileData[0] = file1.getAbsolutePath(); + * fileData[1] = file2.getAbsolutePath(); + * </code></pre> + * + * @see Transfer + */ +public class FileTransfer extends ByteArrayTransfer { + /** + * + */ + private static final String SEPARATOR = "\n"; + private static final String URI_LIST = "text/uri-list"; //$NON-NLS-1$ + private static final int URI_LIST_ID = registerType(URI_LIST); + + private FileTransfer() { + } + + private static FileTransfer _instance = new FileTransfer(); + + /** + * Returns the singleton instance of the FileTransfer class. + * + * @return the singleton instance of the FileTransfer class + */ + public static FileTransfer getInstance() { + return _instance; + } + + /** + * This implementation of <code>javaToNative</code> converts a list of file + * names represented by a java <code>String[]</code> to a platform specific + * representation. Each <code>String</code> in the array contains the + * absolute path for a single file or directory. + * + * @param object + * a java <code>String[]</code> containing the file names to be + * converted + * @param transferData + * an empty <code>TransferData</code> object that will be filled + * in on return with the platform specific format of the data + * + * @see Transfer#nativeToJava + */ + @Override + public void javaToNative(Object object, TransferData transferData) { + if (!checkStringArray(object) || !isSupportedType(transferData)) { + DND.error(DND.ERROR_INVALID_DATA); + } + boolean first = true; + StringBuilder sb = new StringBuilder(); + String[] files = (String[]) object; + for (String file : files) { + if (file == null || file.length() == 0) { + continue; + } + System.out.println("dnd file: " + file); + if (first) { + first = false; + } else { + sb.append(SEPARATOR); + } + sb.append("file://"); + sb.append(file); + } + transferData.data = sb.toString().getBytes(); + transferData.format = URI_LIST; + } + + /** + * This implementation of <code>nativeToJava</code> converts a platform + * specific representation of a list of file names to a java + * <code>String[]</code>. Each String in the array contains the absolute + * path for a single file or directory. + * + * @param transferData + * the platform specific representation of the data to be + * converted + * @return a java <code>String[]</code> containing a list of file names if + * the conversion was successful; otherwise null + * + * @see Transfer#javaToNative + */ + @Override + public Object nativeToJava(TransferData transferData) { + byte[] data = (byte[]) super.nativeToJava(transferData); + if (data == null) { + return null; + } + String[] files = new String(data).split(SEPARATOR); + return files; + } + + @Override + protected int[] getTypeIds() { + return new int[] { URI_LIST_ID }; + } + + @Override + protected String[] getTypeNames() { + return new String[] { URI_LIST }; + } + + boolean checkStringArray(Object object) { + if (object == null || !(object instanceof String[]) || ((String[]) object).length == 0) { + return false; + } + String[] strings = (String[]) object; + for (int i = 0; i < strings.length; i++) { + if (strings[i] == null || strings[i].length() == 0) { + return false; + } + } + return true; + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/HTMLTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/HTMLTransfer.java new file mode 100644 index 0000000000..afdec0185a --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/HTMLTransfer.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.dnd; + +/** + * The class <code>HTMLTransfer</code> provides a platform specific mechanism + * for converting text in HTML format represented as a java <code>String</code> + * to a platform specific representation of the data and vice versa. + * + * <p>An example of a java <code>String</code> containing HTML text is shown + * below:</p> + * + * <code><pre> + * String htmlData = "<p>This is a paragraph of text.</p>"; + * </code></pre> + * + * @see Transfer + */ +public class HTMLTransfer extends ByteArrayTransfer { + + private static HTMLTransfer _instance = new HTMLTransfer(); + private static final String TYPENAME1 = "text/html\0"; + private static final int TYPEID1 = registerType(TYPENAME1); + private static final String TYPENAME2 = "TEXT/HTML\0"; + private static final int TYPEID2 = registerType(TYPENAME2); + +private HTMLTransfer() { +} +/** + * Returns the singleton instance of the HTMLTransfer class. + * + * @return the singleton instance of the HTMLTransfer class + */ +public static HTMLTransfer getInstance () { + return _instance; +} +/** + * This implementation of <code>javaToNative</code> converts HTML-formatted text + * represented by a java <code>String</code> to a platform specific representation. + * + * @param object a java <code>String</code> containing HTML text + * @param transferData an empty <code>TransferData</code> object that will + * be filled in on return with the platform specific format of the data + * + * @see Transfer#nativeToJava + */ +public void javaToNative (Object object, TransferData transferData){ +} +/** + * This implementation of <code>nativeToJava</code> converts a platform specific + * representation of HTML text to a java <code>String</code>. + * + * @param transferData the platform specific representation of the data to be converted + * @return a java <code>String</code> containing HTML text if the conversion was successful; + * otherwise null + * + * @see Transfer#javaToNative + */ +public Object nativeToJava(TransferData transferData){ + return null; +} +protected String[] getTypeNames(){ + return new String[]{TYPENAME1, TYPENAME2}; +} +protected int[] getTypeIds(){ + return new int[]{TYPEID1, TYPEID2}; +} +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/ImageTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/ImageTransfer.java new file mode 100644 index 0000000000..8e5c3a4d28 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/ImageTransfer.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.dnd; + +/** + * The class <code>ImageTransfer</code> provides a platform specific mechanism + * for converting an Image represented as a java <code>ImageData</code> to a + * platform specific representation of the data and vice versa. + * + * <p>An example of a java <code>ImageData</code> is shown below:</p> + * + * <code><pre> + * Image image = new Image(display, "C:\temp\img1.gif"); + * ImageData imgData = image.getImageData(); + * </code></pre> + * + * @see Transfer + * + * @since 3.4 + */ +public class ImageTransfer extends ByteArrayTransfer { + +private ImageTransfer() {} + +/** + * Returns the singleton instance of the ImageTransfer class. + * + * @return the singleton instance of the ImageTransfer class + */ +public static ImageTransfer getInstance () { + return null; +} + +/** + * This implementation of <code>javaToNative</code> converts an ImageData object represented + * by java <code>ImageData</code> to a platform specific representation. + * + * @param object a java <code>ImageData</code> containing the ImageData to be converted + * @param transferData an empty <code>TransferData</code> object that will + * be filled in on return with the platform specific format of the data + * + * @see Transfer#nativeToJava + */ +public void javaToNative(Object object, TransferData transferData) { +} + +/** + * This implementation of <code>nativeToJava</code> converts a platform specific + * representation of an image to java <code>ImageData</code>. + * + * @param transferData the platform specific representation of the data to be converted + * @return a java <code>ImageData</code> of the image if the conversion was successful; + * otherwise null + * + * @see Transfer#javaToNative + */ +public Object nativeToJava(TransferData transferData) { + return null; +} + +protected int[] getTypeIds(){ + return null; +} + +protected String[] getTypeNames(){ + return null; +} +}
\ No newline at end of file diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/RTFTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/RTFTransfer.java new file mode 100644 index 0000000000..11085904b3 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/RTFTransfer.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.dnd; + + +/** + * The class <code>RTFTransfer</code> provides a platform specific mechanism + * for converting text in RTF format represented as a java <code>String</code> + * to a platform specific representation of the data and vice versa. + * + * <p>An example of a java <code>String</code> containing RTF text is shown + * below:</p> + * + * <code><pre> + * String rtfData = "{\\rtf1{\\colortbl;\\red255\\green0\\blue0;}\\uc1\\b\\i Hello World}"; + * </code></pre> + * + * @see Transfer + */ +public class RTFTransfer extends ByteArrayTransfer { + + private static RTFTransfer _instance = new RTFTransfer(); + private static final String TYPENAME1 = "text/rtf\0"; + private static final int TYPEID1 = registerType(TYPENAME1); + private static final String TYPENAME2 = "TEXT/RTF\0"; + private static final int TYPEID2 = registerType(TYPENAME2); + private static final String TYPENAME3 = "application/rtf\0"; + private static final int TYPEID3 = registerType(TYPENAME3); + +private RTFTransfer() { +} +/** + * Returns the singleton instance of the RTFTransfer class. + * + * @return the singleton instance of the RTFTransfer class + */ +public static RTFTransfer getInstance () { + return _instance; +} +/** + * This implementation of <code>javaToNative</code> converts RTF-formatted text + * represented by a java <code>String</code> to a platform specific representation. + * + * @param object a java <code>String</code> containing RTF text + * @param transferData an empty <code>TransferData</code> object that will + * be filled in on return with the platform specific format of the data + * + * @see Transfer#nativeToJava + */ +public void javaToNative (Object object, TransferData transferData){ +} +/** + * This implementation of <code>nativeToJava</code> converts a platform specific + * representation of RTF text to a java <code>String</code>. + * + * @param transferData the platform specific representation of the data to be converted + * @return a java <code>String</code> containing RTF text if the conversion was successful; + * otherwise null + * + * @see Transfer#javaToNative + */ +public Object nativeToJava(TransferData transferData){ + return null; +} +protected String[] getTypeNames(){ + return new String[]{TYPENAME1, TYPENAME2, TYPENAME3}; +} +protected int[] getTypeIds(){ + return new int[]{TYPEID1, TYPEID2, TYPEID3}; +} +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TableDragSourceEffect.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TableDragSourceEffect.java new file mode 100644 index 0000000000..b7dbda53be --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TableDragSourceEffect.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.dnd; + +import org.eclipse.swt.widgets.*; + +/** + * This class provides default implementations to display a source image + * when a drag is initiated from a <code>Table</code>. + * + * <p>Classes that wish to provide their own source image for a <code>Table</code> can + * extend the <code>TableDragSourceEffect</code> class, override the + * <code>TableDragSourceEffect.dragStart</code> method and set the field + * <code>DragSourceEvent.image</code> with their own image.</p> + * + * Subclasses that override any methods of this class must call the corresponding + * <code>super</code> method to get the default drag source effect implementation. + * + * @see DragSourceEffect + * @see DragSourceEvent + * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> + * + * @since 3.3 + */ +public class TableDragSourceEffect extends DragSourceEffect { + /** + * Creates a new <code>TableDragSourceEffect</code> to handle drag effect + * from the specified <code>Table</code>. + * + * @param table the <code>Table</code> that the user clicks on to initiate the drag + */ + public TableDragSourceEffect(Table table) { + super(table); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TableDropTargetEffect.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TableDropTargetEffect.java new file mode 100644 index 0000000000..8818ec6a4b --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TableDropTargetEffect.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.dnd; + +import org.eclipse.swt.widgets.*; + +/** + * This class provides a default drag under effect (eg. select, insert and scroll) + * when a drag occurs over a <code>Table</code>. + * + * <p>Classes that wish to provide their own drag under effect for a <code>Table</code> + * can extend the <code>TableDropTargetEffect</code> and override any applicable methods + * in <code>TableDropTargetEffect</code> to display their own drag under effect.</p> + * + * Subclasses that override any methods of this class must call the corresponding + * <code>super</code> method to get the default drag under effect implementation. + * + * <p>The feedback value is either one of the FEEDBACK constants defined in + * class <code>DND</code> which is applicable to instances of this class, + * or it must be built by <em>bitwise OR</em>'ing together + * (that is, using the <code>int</code> "|" operator) two or more + * of those <code>DND</code> effect constants. + * </p> + * <p> + * <dl> + * <dt><b>Feedback:</b></dt> + * <dd>FEEDBACK_SELECT, FEEDBACK_SCROLL</dd> + * </dl> + * </p> + * + * @see DropTargetAdapter + * @see DropTargetEvent + * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> + * + * @since 3.3 + */ +public class TableDropTargetEffect extends DropTargetEffect { + /** + * Creates a new <code>TableDropTargetEffect</code> to handle the drag under effect on the specified + * <code>Table</code>. + * + * @param table the <code>Table</code> over which the user positions the cursor to drop the data + */ + public TableDropTargetEffect(Table table) { + super(table); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TextTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TextTransfer.java new file mode 100644 index 0000000000..0b83a9633b --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TextTransfer.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.dnd; + +/** + * The class <code>TextTransfer</code> provides a platform specific mechanism + * for converting plain text represented as a java <code>String</code> to a + * platform specific representation of the data and vice versa. + * + * <p> + * An example of a java <code>String</code> containing plain text is shown + * below: + * </p> + * + * <code><pre> + * String textData = "Hello World"; + * </code></pre> + * + * @see Transfer + */ +public class TextTransfer extends ByteArrayTransfer { + private static final String TYPENAME = "text/plain"; //$NON-NLS-1$ + private static final int TYPEID = registerType(TYPENAME); + private static TextTransfer _instance = new TextTransfer(); + + private TextTransfer() { + } + + /** + * Returns the singleton instance of the TextTransfer class. + * + * @return the singleton instance of the TextTransfer class + */ + public static TextTransfer getInstance() { + return _instance; + } + + /** + * This implementation of <code>javaToNative</code> converts plain text + * represented by a java <code>String</code> to a platform specific + * representation. + * + * @param object + * a java <code>String</code> containing text + * @param transferData + * an empty <code>TransferData</code> object that will be filled + * in on return with the platform specific format of the data + * + * @see Transfer#nativeToJava + */ + @Override + public void javaToNative(Object object, TransferData transferData) { + if (!checkText(object) || !isSupportedType(transferData)) { + DND.error(DND.ERROR_INVALID_DATA); + return; + } + transferData.data = ((String) object).getBytes(); + transferData.format = TYPENAME; + transferData.type = TYPEID; + } + + private boolean checkText(Object object) { + return object != null && object instanceof String && ((String) object).length() > 0; + } + + /** + * This implementation of <code>nativeToJava</code> converts a platform + * specific representation of plain text to a java <code>String</code>. + * + * @param transferData + * the platform specific representation of the data to be + * converted + * @return a java <code>String</code> containing text if the conversion was + * successful; otherwise null + * + * @see Transfer#javaToNative + */ + @Override + public Object nativeToJava(TransferData transferData) { + byte[] data = (byte[]) super.nativeToJava(transferData); + if (data == null) { + return null; + } + return new String(data); + } + + @Override + protected String[] getTypeNames() { + return new String[] { TYPENAME }; + } + + @Override + protected int[] getTypeIds() { + return new int[] { TYPEID }; + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/Transfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/Transfer.java new file mode 100644 index 0000000000..4ed963d9f0 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/Transfer.java @@ -0,0 +1,163 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.dnd; + +/** + * <code>Transfer</code> provides a mechanism for converting between a java + * representation of data and a platform specific representation of data and + * vice versa. It is used in data transfer operations such as drag and drop and + * clipboard copy/paste. + * + * <p> + * You should only need to become familiar with this class if you are + * implementing a Transfer subclass and you are unable to subclass the + * ByteArrayTransfer class. + * </p> + * + * @see ByteArrayTransfer + * @see <a href="http://www.eclipse.org/swt/snippets/#dnd">Drag and Drop + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * DNDExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + */ +public abstract class Transfer { + + /** + * Returns a list of the platform specific data types that can be converted + * using this transfer agent. + * + * <p> + * Only the data type fields of the <code>TransferData</code> objects are + * filled in. + * </p> + * + * @return a list of the data types that can be converted using this + * transfer agent + */ + abstract public TransferData[] getSupportedTypes(); + + /** + * Returns true if the <code>TransferData</code> data type can be converted + * using this transfer agent, or false otherwise (including if transferData + * is <code>null</code>). + * + * @param transferData + * a platform specific description of a data type; only the data + * type fields of the <code>TransferData</code> object need to be + * filled in + * + * @return true if the transferData data type can be converted using this + * transfer agent + */ + abstract public boolean isSupportedType(TransferData transferData); + + /** + * Returns the platform specific names of the data types that can be + * converted using this transfer agent. + * + * @return the platform specific names of the data types that can be + * converted using this transfer agent. + */ + abstract protected String[] getTypeNames(); + + /** + * Returns the platform specific ids of the data types that can be converted + * using this transfer agent. + * + * @return the platform specific ids of the data types that can be converted + * using this transfer agent + */ + abstract protected int[] getTypeIds(); + + /** + * Converts a java representation of data to a platform specific + * representation of the data. + * + * <p> + * On a successful conversion, the transferData.result field will be set as + * follows: + * <ul> + * <li>Windows: COM.S_OK + * <li>Motif: 1 + * <li>GTK: 1 + * <li>Photon: 1 + * </ul> + * </p> + * + * <p> + * If this transfer agent is unable to perform the conversion, the + * transferData.result field will be set to a failure value as follows: + * <ul> + * <li>Windows: COM.DV_E_TYMED or COM.E_FAIL + * <li>Motif: 0 + * <li>GTK: 0 + * <li>Photon: 0 + * </ul> + * </p> + * + * @param object + * a java representation of the data to be converted; the type of + * Object that is passed in is dependent on the + * <code>Transfer</code> subclass. + * + * @param transferData + * an empty TransferData object; this object will be filled in on + * return with the platform specific representation of the data + * + * @exception org.eclipse.swt.SWTException + * <ul> + * <li>ERROR_INVALID_DATA - if object does not contain data + * in a valid format or is <code>null</code></li> + * </ul> + */ + abstract protected void javaToNative(Object object, TransferData transferData); + + /** + * Converts a platform specific representation of data to a java + * representation. + * + * @param transferData + * the platform specific representation of the data to be + * converted + * + * @return a java representation of the converted data if the conversion was + * successful; otherwise null. If transferData is <code>null</code> + * then <code>null</code> is returned. The type of Object that is + * returned is dependent on the <code>Transfer</code> subclass. + */ + abstract protected Object nativeToJava(TransferData transferData); + + /** + * Registers a name for a data type and returns the associated unique + * identifier. + * + * <p> + * You may register the same type more than once, the same unique identifier + * will be returned if the type has been previously registered. + * </p> + * + * <p> + * Note: On windows, do <b>not</b> call this method with pre-defined + * Clipboard Format types such as CF_TEXT or CF_BITMAP because the + * pre-defined identifier will not be returned + * </p> + * + * @param formatName + * the name of a data type + * + * @return the unique identifier associated with this data type + */ + public static int registerType(String formatName) { + return formatName.hashCode(); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TransferData.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TransferData.java new file mode 100644 index 0000000000..cd59afd06a --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TransferData.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.dnd; + +/** + * The <code>TransferData</code> class is a platform specific data structure for + * describing the type and the contents of data being converted by a transfer + * agent. + * + * <p> + * As an application writer, you do not need to know the specifics of + * TransferData. TransferData instances are passed to a subclass of Transfer and + * the Transfer object manages the platform specific issues. You can ask a + * Transfer subclass if it can handle this data by calling + * Transfer.isSupportedType(transferData). + * </p> + * + * <p> + * You should only need to become familiar with the fields in this class if you + * are implementing a Transfer subclass and you are unable to subclass the + * ByteArrayTransfer class. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + */ +public class TransferData { + /** + * The type is a unique identifier of a system format or user defined + * format. (Warning: This field is platform dependent) + * <p> + * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT public API. + * It is marked public only so that it can be shared within the packages + * provided by SWT. It is not available on all platforms and should never be + * accessed from application code. + * </p> + */ + public int type; + + // attributes specific to set/get + Object data; + String format; + + /** + * The result field contains the result of converting a java data type into + * a platform specific value. (Warning: This field is platform dependent) + * <p> + * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT public API. + * It is marked public only so that it can be shared within the packages + * provided by SWT. It is not available on all platforms and should never be + * accessed from application code. + * </p> + * <p> + * The value of result is 1 if the conversion was successful. The value of + * result is 0 if the conversion failed. + * </p> + */ + // int result; + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder("TransferData {type: ");//$NON-NLS-1$ + sb.append(type); + sb.append(", format: ");//$NON-NLS-1$ + sb.append(format); + sb.append(", data: ");//$NON-NLS-1$ + sb.append(data); + sb.append("}"); //$NON-NLS-1$ + return sb.toString(); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TreeDragSourceEffect.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TreeDragSourceEffect.java new file mode 100644 index 0000000000..7a66bebb22 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TreeDragSourceEffect.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.dnd; + +import org.eclipse.swt.widgets.*; + +/** + * This class provides default implementations to display a source image + * when a drag is initiated from a <code>Tree</code>. + * + * <p>Classes that wish to provide their own source image for a <code>Tree</code> can + * extend <code>TreeDragSourceEffect</code> class and override the <code>TreeDragSourceEffect.dragStart</code> + * method and set the field <code>DragSourceEvent.image</code> with their own image.</p> + * + * Subclasses that override any methods of this class must call the corresponding + * <code>super</code> method to get the default drag under effect implementation. + * + * @see DragSourceEffect + * @see DragSourceEvent + * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> + * + * @since 3.3 + */ +public class TreeDragSourceEffect extends DragSourceEffect { + /** + * Creates a new <code>TreeDragSourceEffect</code> to handle drag effect + * from the specified <code>Tree</code>. + * + * @param tree the <code>Tree</code> that the user clicks on to initiate the drag + */ + public TreeDragSourceEffect(Tree tree) { + super(tree); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TreeDropTargetEffect.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TreeDropTargetEffect.java new file mode 100644 index 0000000000..d5eaaeb31a --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/TreeDropTargetEffect.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.dnd; + +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.swt.widgets.Widget; + +/** + * This class provides a default drag under effect (eg. select, insert, scroll + * and expand) when a drag occurs over a <code>Tree</code>. + * + * <p> + * Classes that wish to provide their own drag under effect for a + * <code>Tree</code> can extend the <code>TreeDropTargetEffect</code> class and + * override any applicable methods in <code>TreeDropTargetEffect</code> to + * display their own drag under effect. + * </p> + * + * Subclasses that override any methods of this class must call the + * corresponding <code>super</code> method to get the default drag under effect + * implementation. + * + * <p> + * The feedback value is either one of the FEEDBACK constants defined in class + * <code>DND</code> which is applicable to instances of this class, or it must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>DND</code> effect + * constants. + * </p> + * <p> + * <dl> + * <dt><b>Feedback:</b></dt> + * <dd>FEEDBACK_SELECT, FEEDBACK_INSERT_BEFORE, FEEDBACK_INSERT_AFTER, + * FEEDBACK_EXPAND, FEEDBACK_SCROLL</dd> + * </dl> + * </p> + * <p> + * Note: Only one of the styles FEEDBACK_SELECT, FEEDBACK_INSERT_BEFORE or + * FEEDBACK_INSERT_AFTER may be specified. + * </p> + * + * @see DropTargetAdapter + * @see DropTargetEvent + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * + * @since 3.3 + */ +public class TreeDropTargetEffect extends DropTargetEffect { + /** + * Creates a new <code>TreeDropTargetEffect</code> to handle the drag under + * effect on the specified <code>Tree</code>. + * + * @param tree + * the <code>Tree</code> over which the user positions the cursor + * to drop the data + */ + public TreeDropTargetEffect(Tree tree) { + super(tree); + } + + @Override + public void dragEnter(DropTargetEvent event) { + System.out.println("TreeDropTargetEffect.dragEnter: " + event); + super.dragEnter(event); + } + + @Override + public void dragLeave(DropTargetEvent event) { + System.out.println("TreeDropTargetEffect.dragLeave: " + event); + super.dragLeave(event); + } + + @Override + public void dragOver(DropTargetEvent event) { + System.out.println("TreeDropTargetEffect.dragOver: " + event); + Tree tree = (Tree) control; + //int effect = checkEffect(event.feedback); + + TreeItem item = tree.getItem(tree.toControl(new Point(event.x, event.y))); + + tree.highlightItem(item); + } + + @Override + public void drop(DropTargetEvent event) { + System.out.println("TreeDropTargetEffect.drop: " + event); + super.drop(event); + } + + @Override + public void dropAccept(DropTargetEvent event) { + System.out.println("TreeDropTargetEffect.dropAccept: " + event); + super.dropAccept(event); + } + + @Override + public Widget getItem(int x, int y) { + //System.out.println("TreeDropTargetEffect.getItem: " + x + " " + y); + Tree tree = (Tree) control; + TreeItem item = tree.getItem(tree.toControl(new Point(x, y))); + //System.out.println("item: " + item); + return item; + } + + private int checkEffect(int effect) { + // Some effects are mutually exclusive. Make sure that only one of the mutually exclusive effects has been specified. + if ((effect & DND.FEEDBACK_SELECT) != 0) { + effect = effect & ~DND.FEEDBACK_INSERT_AFTER & ~DND.FEEDBACK_INSERT_BEFORE; + } + if ((effect & DND.FEEDBACK_INSERT_BEFORE) != 0) { + effect = effect & ~DND.FEEDBACK_INSERT_AFTER; + } + return effect; + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/URLTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/URLTransfer.java new file mode 100644 index 0000000000..589d3ec7c1 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/qt/org/eclipse/swt/dnd/URLTransfer.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 20007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.dnd; + +/** + * The class <code>URLTransfer</code> provides a platform specific mechanism + * for converting text in URL format represented as a java <code>String</code> + * to a platform specific representation of the data and vice versa. The string + * must contain a fully specified url. + * + * <p>An example of a java <code>String</code> containing a URL is shown below:</p> + * + * <code><pre> + * String url = "http://www.eclipse.org"; + * </code></pre> + * + * @see Transfer + * @since 3.4 + */ +public class URLTransfer extends ByteArrayTransfer { + +private URLTransfer() {} + +/** + * Returns the singleton instance of the URLTransfer class. + * + * @return the singleton instance of the URLTransfer class + */ +public static URLTransfer getInstance () { + return null; +} + +/** + * This implementation of <code>javaToNative</code> converts a URL + * represented by a java <code>String</code> to a platform specific representation. + * + * @param object a java <code>String</code> containing a URL + * @param transferData an empty <code>TransferData</code> object that will + * be filled in on return with the platform specific format of the data + * + * @see Transfer#nativeToJava + */ +public void javaToNative (Object object, TransferData transferData){ +} + +/** + * This implementation of <code>nativeToJava</code> converts a platform + * specific representation of a URL to a java <code>String</code>. + * + * @param transferData the platform specific representation of the data to be converted + * @return a java <code>String</code> containing a URL if the conversion was successful; + * otherwise null + * + * @see Transfer#javaToNative + */ +public Object nativeToJava(TransferData transferData){ + return null; +} + +protected int[] getTypeIds(){ + return null; +} + +protected String[] getTypeNames(){ + return null; +} +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Color.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Color.java new file mode 100644 index 0000000000..9d39595e17 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Color.java @@ -0,0 +1,364 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * Portion Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Nokia Corporation - Qt implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import com.trolltech.qt.gui.QColor; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; + +/** + * 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 extends Resource { + + /** + * the handle to the OS color resource (Warning: This field is platform + * dependent) + * <p> + * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT public API. + * It is marked public only so that it can be shared within the packages + * provided by SWT. It is not available on all platforms and should never be + * accessed from application code. + * </p> + */ + private QColor color; + + /** + * 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) { + init(device, red, green, blue); + } + + /** + * 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 (rgb == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + init(device, rgb.red, rgb.green, rgb.blue); + } + + /** + * Disposes of the operating system resources associated with this resource. + * Applications must dispose of all resources which they allocate. + */ + @Override + public void dispose() { + if (device == null) { + return; + } + if (device.isDisposed()) { + return; + } + if (device.tracking) { + device.dispose_Object(this); + } + device = null; + color = 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 + */ + @Override + public boolean equals(Object object) { + if (object == this) { + return true; + } + if (!(object instanceof Color)) { + return false; + } + Color color = (Color) object; + if (isDisposed() || color.isDisposed()) { + return false; + } + return this.color.equals(color.color); + } + + /** + * 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 color.blue(); + } + + /** + * 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 color.green(); + } + + /** + * 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 color.red(); + } + + /** + * Returns an <code>RGB</code> representing the receiver. + * + * @return the RGB for the color + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public RGB getRGB() { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return new RGB(color.red(), color.green(), color.blue()); + } + + /** + * Returns an integer hash code for the receiver. Any two objects that + * return <code>true</code> when passed to <code>equals</code> must return + * the same value for this method. + * + * @return the receiver's hash + * + * @see #equals + */ + @Override + public int hashCode() { + if (isDisposed()) { + return 0; + } + return color.hashCode(); + } + + /** + * 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 red + * the red component + * @param green + * the green component + * @param blue + * the blue component + * + * @private + */ + + void init(Device device, int red, int green, int blue) { + + if (device == null) { + device = Device.getDevice(); + } + if (device == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + this.device = device; + + if (red > 255 || red < 0 || green > 255 || green < 0 || blue > 255 || blue < 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + // Keep this after dealing with all exceptions! + if (device.tracking) { + device.new_Object(this); + } + color = new QColor(red, green, blue); + } + + public QColor getColor() { + if (color == null) { + color = new QColor(getRed(), getGreen(), getBlue()); + } + return color; + } + + /** + * 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 + */ + @Override + public boolean isDisposed() { + return color == null; + } + + /** + * Returns a string containing a concise, human-readable description of the + * receiver. + * + * @return a string representation of the receiver + */ + @Override + public String toString() { + if (isDisposed()) { + return "Color {*DISPOSED*}"; //$NON-NLS-1$ + } + return "Color {" + getRed() + ", " + getGreen() + ", " + getBlue() + "}"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + + /** + * 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 + * @return a new color object containing the specified device and handle + */ + public static Color qt_new(Device device, int rgb) { + Color color = new Color(); + color.device = device; + color.color = new QColor(rgb); + return color; + } + + public static Color qt_new(Device device, QColor qColor) { + Color color = new Color(device, qColor.red(), qColor.green(), qColor.blue()); + color.color = qColor; + return color; + } + + public int getPixel() { + return getColor().value(); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Cursor.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Cursor.java new file mode 100644 index 0000000000..6803a4d1a8 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Cursor.java @@ -0,0 +1,445 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import com.trolltech.qt.core.Qt.CursorShape; +import com.trolltech.qt.gui.QCursor; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTError; + +/** + * Instances of this class manage operating system resources that specify the + * appearance of the on-screen pointer. To create a cursor you specify the + * device and either a simple cursor style describing one of the standard + * operating system provided cursors or the image and mask data for the desired + * appearance. + * <p> + * Application code must explicitly invoke the <code>Cursor.dispose()</code> + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + * </p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd> + * CURSOR_ARROW, CURSOR_WAIT, CURSOR_CROSS, CURSOR_APPSTARTING, CURSOR_HELP, + * CURSOR_SIZEALL, CURSOR_SIZENESW, CURSOR_SIZENS, CURSOR_SIZENWSE, + * CURSOR_SIZEWE, CURSOR_SIZEN, CURSOR_SIZES, CURSOR_SIZEE, CURSOR_SIZEW, + * CURSOR_SIZENE, CURSOR_SIZESE, CURSOR_SIZESW, CURSOR_SIZENW, CURSOR_UPARROW, + * CURSOR_IBEAM, CURSOR_NO, CURSOR_HAND</dd> + * </dl> + * <p> + * Note: Only one of the above styles may be specified. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#cursor">Cursor + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + */ + +public final class Cursor extends Resource { + + /** + * the handle to the OS cursor resource (Warning: This field is platform + * dependent) + * <p> + * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT public API. + * It is marked public only so that it can be shared within the packages + * provided by SWT. It is not available on all platforms and should never be + * accessed from application code. + * </p> + */ + public QCursor cursor; + + boolean isIcon; + + /** + * Prevents uninitialized instances from being created outside the package. + */ + Cursor(Device device) { + super(device); + } + + /** + * Constructs a new cursor given a device and a style constant describing + * the desired cursor appearance. + * <p> + * You must dispose the cursor when it is no longer required. + * </p> + * + * @param device + * the device on which to allocate the cursor + * @param style + * the style of cursor to allocate + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is + * no current device</li> + * <li>ERROR_INVALID_ARGUMENT - when an unknown style is + * specified</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES - if a handle could not be obtained + * for cursor creation</li> + * </ul> + * + * @see SWT#CURSOR_ARROW + * @see SWT#CURSOR_WAIT + * @see SWT#CURSOR_CROSS + * @see SWT#CURSOR_APPSTARTING + * @see SWT#CURSOR_HELP + * @see SWT#CURSOR_SIZEALL + * @see SWT#CURSOR_SIZENESW + * @see SWT#CURSOR_SIZENS + * @see SWT#CURSOR_SIZENWSE + * @see SWT#CURSOR_SIZEWE + * @see SWT#CURSOR_SIZEN + * @see SWT#CURSOR_SIZES + * @see SWT#CURSOR_SIZEE + * @see SWT#CURSOR_SIZEW + * @see SWT#CURSOR_SIZENE + * @see SWT#CURSOR_SIZESE + * @see SWT#CURSOR_SIZESW + * @see SWT#CURSOR_SIZENW + * @see SWT#CURSOR_UPARROW + * @see SWT#CURSOR_IBEAM + * @see SWT#CURSOR_NO + * @see SWT#CURSOR_HAND + */ + public Cursor(Device device, int style) { + super(device); + CursorShape cursorShape = null; + switch (style) { + case SWT.CURSOR_HAND: + cursorShape = CursorShape.PointingHandCursor; + break; + case SWT.CURSOR_ARROW: + cursorShape = CursorShape.ArrowCursor; + break; + case SWT.CURSOR_WAIT: + cursorShape = CursorShape.WaitCursor; + break; + case SWT.CURSOR_CROSS: + cursorShape = CursorShape.CrossCursor; + break; + case SWT.CURSOR_APPSTARTING: + cursorShape = CursorShape.BusyCursor; + break; + case SWT.CURSOR_HELP: + cursorShape = CursorShape.WhatsThisCursor; + break; + case SWT.CURSOR_SIZEALL: + cursorShape = CursorShape.SizeAllCursor; + break; + case SWT.CURSOR_SIZENESW: + cursorShape = CursorShape.SizeBDiagCursor; + break; + case SWT.CURSOR_SIZENS: + cursorShape = CursorShape.SizeVerCursor; + break; + case SWT.CURSOR_SIZENWSE: + cursorShape = CursorShape.SizeFDiagCursor; + break; + case SWT.CURSOR_SIZEWE: + cursorShape = CursorShape.SizeHorCursor; + break; + case SWT.CURSOR_SIZEN: + cursorShape = CursorShape.SizeVerCursor; + break; + case SWT.CURSOR_SIZES: + cursorShape = CursorShape.SizeVerCursor; + break; + case SWT.CURSOR_SIZEE: + cursorShape = CursorShape.SizeHorCursor; + break; + case SWT.CURSOR_SIZEW: + cursorShape = CursorShape.SizeHorCursor; + break; + case SWT.CURSOR_SIZENE: + cursorShape = CursorShape.SizeBDiagCursor; + break; + case SWT.CURSOR_SIZESE: + cursorShape = CursorShape.SizeBDiagCursor; + break; + case SWT.CURSOR_SIZESW: + cursorShape = CursorShape.SizeFDiagCursor; + break; + case SWT.CURSOR_SIZENW: + cursorShape = CursorShape.SizeFDiagCursor; + break; + case SWT.CURSOR_UPARROW: + cursorShape = CursorShape.UpArrowCursor; + break; + case SWT.CURSOR_IBEAM: + cursorShape = CursorShape.IBeamCursor; + break; + case SWT.CURSOR_NO: + cursorShape = CursorShape.ForbiddenCursor; + + break; + default: + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + cursor = new QCursor(cursorShape); + init(); + } + + /** + * Constructs a new cursor given a device, image and mask data describing + * the desired cursor appearance, and the x and y coordinates of the + * <em>hotspot</em> (that is, the point within the area covered by the + * cursor which is considered to be where the on-screen pointer is + * "pointing"). + * <p> + * The mask data is allowed to be null, but in this case the source must be + * an ImageData representing an icon that specifies both color data and mask + * data. + * <p> + * You must dispose the cursor when it is no longer required. + * </p> + * + * @param device + * the device on which to allocate the cursor + * @param source + * the color data for the cursor + * @param mask + * the mask data for the cursor (or null) + * @param hotspotX + * the x coordinate of the cursor's hotspot + * @param hotspotY + * the y coordinate of the cursor's hotspot + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is + * no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the source is null</li> + * <li>ERROR_NULL_ARGUMENT - if the mask is null and the + * source does not have a mask</li> + * <li>ERROR_INVALID_ARGUMENT - if the source and the mask + * are not the same size, or if the hotspot is outside the + * bounds of the image</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES - if a handle could not be obtained + * for cursor creation</li> + * </ul> + */ + public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int hotspotY) { + this(device, SWT.CURSOR_ARROW); + //TODO + // super(device); + // if (source == null) { + // SWT.error(SWT.ERROR_NULL_ARGUMENT); + // } + // if (mask == null) { + // if (source.getTransparencyType() != SWT.TRANSPARENCY_MASK) { + // SWT.error(SWT.ERROR_NULL_ARGUMENT); + // } + // mask = source.getTransparencyMask(); + // } + // /* Check the bounds. Mask must be the same size as source */ + // if (mask.width != source.width || mask.height != source.height) { + // SWT.error(SWT.ERROR_INVALID_ARGUMENT); + // } + // /* Check the hotspots */ + // if (hotspotX >= source.width || hotspotX < 0 || hotspotY >= source.height || hotspotY < 0) { + // SWT.error(SWT.ERROR_INVALID_ARGUMENT); + // } + // /* Convert depth to 1 */ + // mask = ImageData.convertMask(mask); + // source = ImageData.convertMask(source); + // + // /* Make sure source and mask scanline pad is 2 */ + // byte[] sourceData = ImageData.convertPad(source.data, source.width, source.height, source.depth, + // source.scanlinePad, 2); + // byte[] maskData = ImageData.convertPad(mask.data, mask.width, mask.height, mask.depth, mask.scanlinePad, 2); + + /* Create the cursor */ + // TODO + // cursor = new QCursor(mask.) + // int /* long */hInst = OS.GetModuleHandle(null); + // if (OS.IsWinCE) { + // SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + // } + // handle = OS.CreateCursor(hInst, hotspotX, hotspotY, source.width, source.height, sourceData, maskData); + // if (handle == 0) { + // SWT.error(SWT.ERROR_NO_HANDLES); + // } + //init(); + } + + /** + * Constructs a new cursor given a device, image data describing the desired + * cursor appearance, and the x and y coordinates of the <em>hotspot</em> + * (that is, the point within the area covered by the cursor which is + * considered to be where the on-screen pointer is "pointing"). + * <p> + * You must dispose the cursor when it is no longer required. + * </p> + * + * @param device + * the device on which to allocate the cursor + * @param source + * the image data for the cursor + * @param hotspotX + * the x coordinate of the cursor's hotspot + * @param hotspotY + * the y coordinate of the cursor's hotspot + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is + * no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the image is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the hotspot is outside the + * bounds of the image</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES - if a handle could not be obtained + * for cursor creation</li> + * </ul> + * + * @since 3.0 + */ + public Cursor(Device device, ImageData source, int hotspotX, int hotspotY) { + this(device, SWT.CURSOR_ARROW); + // if (source == null) { + // SWT.error(SWT.ERROR_NULL_ARGUMENT); + // } + // /* Check the hotspots */ + // if (hotspotX >= source.width || hotspotX < 0 || hotspotY >= source.height || hotspotY < 0) { + // SWT.error(SWT.ERROR_INVALID_ARGUMENT); + // } + + // ImageData mask = source.getTransparencyMask(); + // int /* long */[] result = new int[2]; // TODO = Image.init(this.device, null, source, mask); + // int /* long */hBitmap = result[0]; + // int /* long */hMask = result[1]; + // /* Create the icon */ + // ICONINFO info = new ICONINFO(); + // info.fIcon = false; + // info.hbmColor = hBitmap; + // info.hbmMask = hMask; + // info.xHotspot = hotspotX; + // info.yHotspot = hotspotY; + //TODO + // handle = OS.CreateIconIndirect(info); + // if (handle == 0) { + // SWT.error(SWT.ERROR_NO_HANDLES); + // } + // OS.DeleteObject(hBitmap); + // OS.DeleteObject(hMask); + //isIcon = true; + // init(); + } + + @Override + void destroy() { + cursor = 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 + */ + @Override + public boolean equals(Object object) { + if (object == this) { + return true; + } + if (!(object instanceof Cursor)) { + return false; + } + Cursor cursor = (Cursor) object; + return device == cursor.device && this.cursor == cursor.cursor; + } + + /** + * Returns an integer hash code for the receiver. Any two objects that + * return <code>true</code> when passed to <code>equals</code> must return + * the same value for this method. + * + * @return the receiver's hash + * + * @see #equals + */ + @Override + public int hashCode() { + return cursor.hashCode(); + } + + /** + * 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 + */ + @Override + public boolean isDisposed() { + return cursor == null; + } + + /** + * Returns a string containing a concise, human-readable description of the + * receiver. + * + * @return a string representation of the receiver + */ + @Override + public String toString() { + if (isDisposed()) { + return "Cursor {*DISPOSED*}"; //$NON-NLS-1$ + } + return "Cursor {" + cursor + "}"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * 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 + * @return a new cursor object containing the specified device and handle + */ + public static Cursor win32_new(Device device, int handle) { + Cursor cursor = new Cursor(device); + // TODO + // cursor.cursor = handle; + return cursor; + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Device.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Device.java new file mode 100644 index 0000000000..99a3dcb47a --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Device.java @@ -0,0 +1,920 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import java.util.ArrayList; +import java.util.List; + +import com.trolltech.qt.gui.QApplication; +import com.trolltech.qt.gui.QColor; +import com.trolltech.qt.gui.QFontDatabase; +import com.trolltech.qt.gui.QPaintDeviceInterface; +import com.trolltech.qt.gui.QPalette; +import com.trolltech.qt.gui.QPalette.ColorGroup; +import com.trolltech.qt.gui.QPalette.ColorRole; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; + +/** + * This class is the abstract superclass of all device objects, such as the + * Display device and the Printer device. Devices can have a graphics context + * (GC) created for them, and they can be drawn on by sending messages to the + * associated GC. + * + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + */ +public abstract class Device implements Drawable { + + /* Debugging */ + public static boolean DEBUG; + private boolean debug = DEBUG; + boolean tracking = DEBUG; + private Error[] errors; + private Object[] objects; + private Object trackingLock; + + /* System Font */ + Font systemFont; + private QColor COLOR_LIST_BACKGROUND; + private QColor COLOR_LIST_FOREGROUND; + private QColor COLOR_LIST_SELECTION; + private QColor COLOR_LIST_SELECTION_TEXT; + private QColor COLOR_TITLE_BACKGROUND; + private QColor COLOR_TITLE_BACKGROUND_GRADIENT; + private QColor COLOR_TITLE_FOREGROUND; + private QColor COLOR_TITLE_INACTIVE_BACKGROUND; + private QColor COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT; + private QColor COLOR_TITLE_INACTIVE_FOREGROUND; + private QColor COLOR_WIDGET_BACKGROUND; + private QColor COLOR_WIDGET_BORDER; + private QColor COLOR_WIDGET_DARK_SHADOW; + private QColor COLOR_WIDGET_FOREGROUND; + private QColor COLOR_WIDGET_HIGHLIGHT_SHADOW; + private QColor COLOR_WIDGET_LIGHT_SHADOW; + private QColor COLOR_WIDGET_NORMAL_SHADOW; + private QColor COLOR_INFO_FOREGROUND; + private QColor COLOR_INFO_BACKGROUND; + + private boolean disposed; + private QPaintDeviceInterface paintDevice; + + /* + * TEMPORARY CODE. When a graphics object is created and the device + * parameter is null, the current Display is used. This presents a problem + * because SWT graphics does not reference classes in SWT widgets. The + * correct fix is to remove this feature. Unfortunately, too many + * application programs rely on this feature. + */ + protected static Device CurrentDevice; + protected static Runnable DeviceFinder; + static { + try { + Class.forName("org.eclipse.swt.widgets.Display"); //$NON-NLS-1$ + } catch (ClassNotFoundException e) { + } + } + + /* + * TEMPORARY CODE. + */ + static synchronized Device getDevice() { + if (DeviceFinder != null) { + DeviceFinder.run(); + } + Device device = CurrentDevice; + CurrentDevice = null; + return device; + } + + /** + * Constructs a new instance of this class. + * <p> + * You must dispose the device when it is no longer required. + * </p> + * + * @see #create + * @see #init + * + * @since 3.1 + */ + public Device() { + this(null); + } + + /** + * Constructs a new instance of this class. + * <p> + * You must dispose the device when it is no longer required. + * </p> + * + * @param data + * the DeviceData which describes the receiver + * + * @see #create + * @see #init + * @see DeviceData + */ + public Device(DeviceData data) { + synchronized (Device.class) { + if (data != null) { + debug = data.debug; + tracking = data.tracking; + } + if (tracking) { + errors = new Error[128]; + objects = new Object[128]; + trackingLock = new Object(); + } + create(data); + init(); + } + } + + protected void setPaintDevice(QPaintDeviceInterface paintDevice) { + this.paintDevice = paintDevice; + } + + /** + * 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) { + } + + /** + * 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() { + synchronized (Device.class) { + if (isDisposed()) { + return; + } + checkDevice(); + release(); + destroy(); + disposed = true; + if (tracking) { + synchronized (trackingLock) { + printErrors(); + objects = null; + errors = null; + trackingLock = null; + } + } + } + } + + void dispose_Object(Object object) { + synchronized (trackingLock) { + for (int i = 0; i < objects.length; i++) { + if (objects[i] == object) { + objects[i] = null; + errors[i] = null; + return; + } + } + } + } + + /** + * 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(); + return new Rectangle(0, 0, paintDevice.width(), paintDevice.height()); + } + + /** + * Returns a <code>DeviceData</code> based on the receiver. Modifications + * made to this <code>DeviceData</code> will not affect the receiver. + * + * @return a <code>DeviceData</code> containing the device's data and + * attributes + * + * @exception SWTException + * <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see DeviceData + */ + public DeviceData getDeviceData() { + checkDevice(); + DeviceData data = new DeviceData(); + data.debug = debug; + data.tracking = tracking; + if (tracking) { + synchronized (trackingLock) { + int count = 0, length = objects.length; + for (int i = 0; i < length; i++) { + if (objects[i] != null) { + count++; + } + } + int index = 0; + data.objects = new Object[count]; + data.errors = new Error[count]; + for (int i = 0; i < length; i++) { + if (objects[i] != null) { + data.objects[index] = objects[i]; + data.errors[index] = errors[i]; + index++; + } + } + } + } else { + data.objects = new Object[0]; + data.errors = new Error[0]; + } + return data; + } + + /** + * Returns a rectangle which describes the area of the receiver which is + * capable of displaying data. + * + * @return the client area + * + * @exception SWTException + * <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #getBounds + */ + public Rectangle getClientArea() { + return getBounds(); + } + + /** + * Returns the bit depth of the screen, which is the number of bits it takes + * to represent the number of unique colors that the screen is currently + * capable of displaying. This number will typically be one of 1, 8, 15, 16, + * 24 or 32. + * + * @return the depth of the screen + * + * @exception SWTException + * <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public int getDepth() { + checkDevice(); + return paintDevice.depth(); + } + + /** + * Returns a point whose x coordinate is the horizontal dots per inch of the + * display, and whose y coordinate is the vertical dots per inch of the + * display. + * + * @return the horizontal and vertical DPI + * + * @exception SWTException + * <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public Point getDPI() { + checkDevice(); + return new Point(paintDevice.physicalDpiX(), paintDevice.physicalDpiY()); + } + + /** + * Returns <code>FontData</code> objects which describe the fonts that match + * the given arguments. If the <code>faceName</code> is null, all fonts will + * be returned. + * + * @param faceName + * the name of the font to look for, or null + * @param scalable + * if true only scalable fonts are returned, otherwise only + * non-scalable fonts are returned. + * @return the matching font data + * + * @exception SWTException + * <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public FontData[] getFontList(String faceName, boolean scalable) { + checkDevice(); + QFontDatabase qFontDatabase = null; + qFontDatabase = new QFontDatabase(); + String fontFamilies[] = qFontDatabase.families().toArray(new String[0]); + // for storing FontData arrays + List<FontData> fontData = new ArrayList<FontData>(); + + for (int i = 0; i < fontFamilies.length; i++) { + String family = null; + if (faceName == null) { + family = fontFamilies[i]; + } else { + if (faceName.equals(fontFamilies[i])) { + family = fontFamilies[i]; + } else { + continue; + } + } + getFontList(fontData, qFontDatabase, family, scalable); + if (faceName != null) { + break; + } + } + + qFontDatabase.dispose(); //TODO_DISPOSE (called many times) + qFontDatabase = null; + + if (fontData.size() > 0) { + FontData[] result = new FontData[fontData.size()]; + int size = fontData.size(); + for (int i = 0; i < size; ++i) { + result[i] = fontData.get(i); + } + return result; + } else { + return new FontData[0]; + } + } + + private void getFontList(List<FontData> fontData, QFontDatabase qFontDatabase, String family, boolean onlyScalable) { + String nativeStyles[] = qFontDatabase.styles(family).toArray(new String[0]); + int prevStyle = -1; + int i = 0; + // Go trough each native style of the font family, map them to SWT + // styles + // and create a new FontData for each newly found SWT style of the + // family. + // Still, it may be possible that there are no native styles for a + // family, + // in which case we add a single FontData with default SWT style: + // NORMAL. + // In addition we go trough all heights of non scalable font families, + // creating a new FontData for all heights of all native styles. + do { + String nativeStyle = nativeStyles.length > 0 ? nativeStyles[i] : null; + boolean isScalable = qFontDatabase.isScalable(family, nativeStyle); + int style = SWT.NORMAL; + if (qFontDatabase.bold(family, nativeStyle)) { + style |= SWT.BOLD; + } + if (qFontDatabase.italic(family, nativeStyle)) { + style |= SWT.ITALIC; + } + if (style != prevStyle) { + prevStyle = style; + int[] heights = null; + int j = 0; + if (onlyScalable && isScalable) { + heights = new int[1]; + heights[0] = FontData.FONT_DEF_HEIGHT; + } else if (!onlyScalable && !isScalable) { + List<Integer> pointSizes = null; + if (nativeStyle == null) { + pointSizes = qFontDatabase.pointSizes(family); + } else { + pointSizes = qFontDatabase.pointSizes(family, nativeStyle); + } + heights = new int[pointSizes.size()]; + for (int x = 0; x < pointSizes.size(); x++) { + heights[x] = pointSizes.get(x); + } + } + if (heights != null) { + do { + FontData fd = new FontData(family, heights[j], style); + fontData.add(fd); + j++; + } while (!onlyScalable && !isScalable && j < heights.length); + } + } + i++; + } while (i < nativeStyles.length); + } + + /** + * Returns the matching standard color for the given constant, which should + * be one of the color constants specified in class <code>SWT</code>. Any + * value other than one of the SWT color constants which is passed in will + * result in the color black. This color should not be freed because it was + * allocated by the system, not the application. + * + * @param id + * the color constant + * @return the matching color + * + * @exception SWTException + * <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see SWT + */ + public Color getSystemColor(int id) { + checkDevice(); + int pixel = 0x00000000; + switch (id) { + case SWT.COLOR_WHITE: + return Color.qt_new(this, QColor.white); + case SWT.COLOR_BLACK: + return Color.qt_new(this, QColor.black); + case SWT.COLOR_RED: + return Color.qt_new(this, QColor.red); + case SWT.COLOR_DARK_RED: + return Color.qt_new(this, QColor.darkRed); + case SWT.COLOR_GREEN: + return Color.qt_new(this, QColor.green); + case SWT.COLOR_DARK_GREEN: + return Color.qt_new(this, QColor.darkGreen); + case SWT.COLOR_YELLOW: + return Color.qt_new(this, QColor.yellow); + case SWT.COLOR_DARK_YELLOW: + return Color.qt_new(this, QColor.darkYellow); + case SWT.COLOR_BLUE: + return Color.qt_new(this, QColor.blue); + case SWT.COLOR_DARK_BLUE: + return Color.qt_new(this, QColor.darkBlue); + case SWT.COLOR_MAGENTA: + return Color.qt_new(this, QColor.magenta); + case SWT.COLOR_DARK_MAGENTA: + return Color.qt_new(this, QColor.magenta); + case SWT.COLOR_CYAN: + return Color.qt_new(this, QColor.cyan); + case SWT.COLOR_DARK_CYAN: + return Color.qt_new(this, QColor.darkCyan); + case SWT.COLOR_GRAY: + return Color.qt_new(this, QColor.gray); + case SWT.COLOR_DARK_GRAY: + return Color.qt_new(this, QColor.darkGray); + case SWT.COLOR_LIST_BACKGROUND: + return Color.qt_new(this, COLOR_LIST_BACKGROUND); + case SWT.COLOR_LIST_FOREGROUND: + return Color.qt_new(this, COLOR_LIST_FOREGROUND); + case SWT.COLOR_LIST_SELECTION: + return Color.qt_new(this, COLOR_LIST_SELECTION); + case SWT.COLOR_LIST_SELECTION_TEXT: + return Color.qt_new(this, COLOR_LIST_SELECTION_TEXT); + case SWT.COLOR_TITLE_BACKGROUND: + return Color.qt_new(this, COLOR_TITLE_BACKGROUND); + case SWT.COLOR_TITLE_BACKGROUND_GRADIENT: + return Color.qt_new(this, COLOR_TITLE_BACKGROUND_GRADIENT); + case SWT.COLOR_TITLE_FOREGROUND: + return Color.qt_new(this, COLOR_TITLE_FOREGROUND); + case SWT.COLOR_TITLE_INACTIVE_BACKGROUND: + return Color.qt_new(this, COLOR_TITLE_INACTIVE_BACKGROUND); + case SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT: + return Color.qt_new(this, COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT); + case SWT.COLOR_TITLE_INACTIVE_FOREGROUND: + return Color.qt_new(this, COLOR_TITLE_INACTIVE_FOREGROUND); + case SWT.COLOR_WIDGET_BACKGROUND: + return Color.qt_new(this, COLOR_WIDGET_BACKGROUND); + case SWT.COLOR_WIDGET_BORDER: + return Color.qt_new(this, COLOR_WIDGET_BORDER); + case SWT.COLOR_WIDGET_DARK_SHADOW: + return Color.qt_new(this, COLOR_WIDGET_DARK_SHADOW); + case SWT.COLOR_WIDGET_FOREGROUND: + return Color.qt_new(this, COLOR_WIDGET_FOREGROUND); + case SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW: + return Color.qt_new(this, COLOR_WIDGET_HIGHLIGHT_SHADOW); + case SWT.COLOR_WIDGET_LIGHT_SHADOW: + return Color.qt_new(this, COLOR_WIDGET_LIGHT_SHADOW); + case SWT.COLOR_WIDGET_NORMAL_SHADOW: + return Color.qt_new(this, COLOR_WIDGET_NORMAL_SHADOW); + case SWT.COLOR_INFO_FOREGROUND: + return Color.qt_new(this, COLOR_INFO_FOREGROUND); + case SWT.COLOR_INFO_BACKGROUND: + return Color.qt_new(this, COLOR_INFO_BACKGROUND); + } + return Color.qt_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 freed because it was allocated by the system, not + * the application. + * <p> + * Typically, applications which want the default look should simply not set + * the font on the widgets they create. Widgets are always created with the + * correct default font for the class of user-interface component they + * represent. + * </p> + * + * @return a font + * + * @exception SWTException + * <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public Font getSystemFont() { + checkDevice(); + return Font.qt_new(this, QApplication.font()); + } + + /** + * 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() { + /* Initialize the system font slot */ + systemFont = getSystemFont(); + QPalette palette = QApplication.style().standardPalette(); + try { + // Mapping colors from the QPalette to SWT colors. Not all + // colors are 100% right. Use snippet 235 and 235_1 to get + // all colors displayed. + + // Info + COLOR_INFO_FOREGROUND = palette.color(ColorGroup.Active, ColorRole.ToolTipText); + COLOR_INFO_BACKGROUND = palette.color(ColorGroup.Active, ColorRole.ToolTipBase); + + // List + COLOR_LIST_BACKGROUND = palette.color(ColorGroup.Active, ColorRole.Base); + COLOR_LIST_FOREGROUND = palette.color(ColorGroup.Active, ColorRole.Text); + COLOR_LIST_SELECTION = palette.color(ColorGroup.Active, ColorRole.Highlight); + COLOR_LIST_SELECTION_TEXT = palette.color(ColorGroup.Active, ColorRole.HighlightedText); + + // Title + COLOR_TITLE_BACKGROUND = new QColor(0, 84, 227); // palette.color(ColorGroup.Active, ColorRole.Highlight); + // TODO The required blue/grey does not exist in QPalette. Using grey as a substitute. + COLOR_TITLE_BACKGROUND_GRADIENT = new QColor(61, 149, 255);// palette.color(ColorGroup.Active, ColorRole.Light); + COLOR_TITLE_FOREGROUND = palette.color(ColorGroup.Active, ColorRole.HighlightedText); + + // Inactive highlight + COLOR_TITLE_INACTIVE_BACKGROUND = new QColor(122, 150, 223);// palette.color(ColorGroup.Inactive, ColorRole.Dark); + // TODO The required shade of grey does not exist in QPalette. Should be a bit lighter. + COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT = new QColor(157, 185, 235); //palette.color(ColorGroup.Inactive, ColorRole.Light); + // TODO The required shade of grey does not exist in QPalette. Should be a bit lighter. + // Even lighter still than background gradient. It's the same at the moment. + COLOR_TITLE_INACTIVE_FOREGROUND = new QColor(216, 228, 248); //palette.color(ColorGroup.Inactive, ColorRole.BrightText); + + // Window + //QApplication.style(). + COLOR_WIDGET_BACKGROUND = palette.color(ColorGroup.Active, ColorRole.Window);//new QColor(239, 235, 231); + COLOR_WIDGET_DARK_SHADOW = palette.color(ColorGroup.Active, ColorRole.Shadow); + COLOR_WIDGET_FOREGROUND = COLOR_WIDGET_BORDER = palette.color(ColorGroup.Active, ColorRole.WindowText); + COLOR_WIDGET_HIGHLIGHT_SHADOW = palette.color(ColorGroup.Active, ColorRole.Light); + + COLOR_WIDGET_LIGHT_SHADOW = new QColor(236, 233, 216); //palette.color(ColorGroup.Active, ColorRole.Button); + COLOR_WIDGET_NORMAL_SHADOW = new QColor(157, 155, 144); //palette.color(ColorGroup.Active, ColorRole.Mid); + + } finally { + palette.dispose(); + } + } + + /** + * Invokes platform specific functionality to allocate a new GC handle. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public API for + * <code>Device</code>. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms, and should never be called from application code. + * </p> + * + * @param data + * the platform specific GC data + * @return the platform specific GC handle + */ + public abstract QPaintDeviceInterface internal_new_GC(GCData data); + + /** + * Invokes platform specific functionality to dispose a GC handle. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public API for + * <code>Device</code>. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms, and should never be called from application code. + * </p> + * + * @param hDC + * the platform specific GC handle + * @param data + * the platform specific GC data + */ + public abstract void internal_dispose_GC(QPaintDeviceInterface paintDevice, GCData data); + + /** + * Returns <code>true</code> if the device has been disposed, and + * <code>false</code> otherwise. + * <p> + * This method gets the dispose state for the device. When a device has been + * disposed, it is an error to invoke any other method using the device. + * + * @return <code>true</code> when the device is disposed and + * <code>false</code> otherwise + */ + public boolean isDisposed() { + synchronized (Device.class) { + return disposed; + } + } + + /** + * Loads the font specified by a file. The font will be present in the list + * of fonts available to the application. + * + * @param path + * the font file path + * @return whether the font was successfully loaded + * + * @exception SWTException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if path is null</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see Font + * + * @since 3.3 + */ + public boolean loadFont(String path) { + checkDevice(); + if (path == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + int retCode = QFontDatabase.addApplicationFont(path); + return retCode != -1; // -1 == font load failed + } + + void new_Object(Object object) { + synchronized (trackingLock) { + for (int i = 0; i < objects.length; i++) { + if (objects[i] == null) { + objects[i] = object; + errors[i] = new Error(); + return; + } + } + Object[] newObjects = new Object[objects.length + 128]; + System.arraycopy(objects, 0, newObjects, 0, objects.length); + newObjects[objects.length] = object; + objects = newObjects; + Error[] newErrors = new Error[errors.length + 128]; + System.arraycopy(errors, 0, newErrors, 0, errors.length); + newErrors[errors.length] = new Error(); + errors = newErrors; + } + } + + void printErrors() { + if (!DEBUG) { + return; + } + if (tracking) { + synchronized (trackingLock) { + if (objects == null || errors == null) { + return; + } + int objectCount = 0; + int colors = 0, cursors = 0, fonts = 0, gcs = 0, images = 0; + int paths = 0, patterns = 0, regions = 0, textLayouts = 0, transforms = 0; + for (int i = 0; i < objects.length; i++) { + Object object = objects[i]; + if (object != null) { + objectCount++; + if (object instanceof Color) { + colors++; + } + if (object instanceof Cursor) { + cursors++; + } + if (object instanceof Font) { + fonts++; + } + if (object instanceof GC) { + gcs++; + } + if (object instanceof Image) { + images++; + } + if (object instanceof Path) { + paths++; + } + if (object instanceof Pattern) { + patterns++; + } + if (object instanceof Region) { + regions++; + } + if (object instanceof TextLayout) { + textLayouts++; + } + if (object instanceof Transform) { + transforms++; + } + } + } + if (objectCount != 0) { + String string = "Summary: "; //$NON-NLS-1$ + if (colors != 0) { + string += colors + " Color(s), ";//$NON-NLS-1$ + } + if (cursors != 0) { + string += cursors + " Cursor(s), ";//$NON-NLS-1$ + } + if (fonts != 0) { + string += fonts + " Font(s), ";//$NON-NLS-1$ + } + if (gcs != 0) { + string += gcs + " GC(s), ";//$NON-NLS-1$ + } + if (images != 0) { + string += images + " Image(s), ";//$NON-NLS-1$ + } + if (paths != 0) { + string += paths + " Path(s), ";//$NON-NLS-1$ + } + if (patterns != 0) { + string += patterns + " Pattern(s), ";//$NON-NLS-1$ + } + if (regions != 0) { + string += regions + " Region(s), ";//$NON-NLS-1$ + } + if (textLayouts != 0) { + string += textLayouts + " TextLayout(s), ";//$NON-NLS-1$ + } + if (transforms != 0) { + string += transforms + " Transforms(s), ";//$NON-NLS-1$ + } + if (string.length() != 0) { + string = string.substring(0, string.length() - 2); + System.err.println(string); + } + for (int i = 0; i < errors.length; i++) { + if (errors[i] != null) { + errors[i].printStackTrace(System.err); + } + } + } + } + } + } + + /** + * 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() { + paintDevice = null; + } + + /** + * If the underlying window system supports printing warning messages to the + * console, setting warnings to <code>false</code> prevents these messages + * from being printed. If the argument is <code>true</code> then message + * printing is not blocked. + * + * @param warnings + * <code>true</code>if warnings should be printed, and + * <code>false</code> otherwise + * + * @exception SWTException + * <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void setWarnings(boolean warnings) { + checkDevice(); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/DeviceData.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/DeviceData.java new file mode 100644 index 0000000000..8dd1012d58 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/DeviceData.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.graphics; + +public class DeviceData { + /* + * Debug fields - may not be honoured on some SWT platforms. + */ + public boolean debug; + public boolean tracking; + public Error[] errors; + public Object[] objects; +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Font.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Font.java new file mode 100644 index 0000000000..0758f4d05f --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Font.java @@ -0,0 +1,379 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import com.trolltech.qt.gui.QFont; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTError; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.internal.qt.QtSupplementaryFontData; +import org.eclipse.swt.internal.qt.SWQT; + +/** + * Instances of this class manage operating system resources that define how + * text looks when it is displayed. Fonts may be constructed by providing a + * device and either name, size and style information or a <code>FontData</code> + * object which encapsulates this data. + * <p> + * Application code must explicitly invoke the <code>Font.dispose()</code> + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + * </p> + * + * @see FontData + * @see <a href="http://www.eclipse.org/swt/snippets/#font">Font snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: + * GraphicsExample, PaintExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + */ + +public final class Font extends Resource { + + /** + * the handle to the OS font resource (Warning: This field is platform + * dependent) + * <p> + * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT public API. + * It is marked public only so that it can be shared within the packages + * provided by SWT. It is not available on all platforms and should never be + * accessed from application code. + * </p> + */ + private QFont font; + + boolean extraFontStyle; + String xlfd; + + /** + * Prevents uninitialized instances from being created outside the package. + */ + Font() { + } + + /** + * Prevents uninitialized instances from being created outside the package. + */ + Font(Device device) { + super(device); + } + + /** + * Constructs a new font given a device and font data which describes the + * desired font's appearance. + * <p> + * You must dispose the font when it is no longer required. + * </p> + * + * @param device + * the device to create the font on + * @param fd + * the FontData that describes the desired font (must not be + * null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is + * no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the fd argument is null</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES - if a font could not be created from + * the given font data</li> + * </ul> + */ + public Font(Device device, FontData fd) { + super(device); + init(fd); + init(); + } + + /** + * Constructs a new font given a device and an array of font data which + * describes the desired font's appearance. + * <p> + * You must dispose the font when it is no longer required. + * </p> + * + * @param device + * the device to create the font on + * @param fds + * the array of FontData that describes the desired font (must + * not be null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is + * no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the fds argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the length of fds is zero</li> + * <li>ERROR_NULL_ARGUMENT - if any fd in the array is null</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES - if a font could not be created from + * the given font data</li> + * </ul> + * + * @since 2.1 + */ + public Font(Device device, FontData[] fds) { + super(device); + if (fds == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (fds.length == 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + for (int i = 0; i < fds.length; i++) { + if (fds[i] == null) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + } + init(fds[0]); + init(); + } + + /** + * Constructs a new font given a device, a font name, the height of the + * desired font in points, and a font style. + * <p> + * You must dispose the font when it is no longer required. + * </p> + * + * @param device + * the device to create the font on + * @param name + * the name of the font (must not be null) + * @param height + * the font height in points + * @param style + * a bit or combination of NORMAL, BOLD, ITALIC + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is + * no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the name argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the height is negative</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES - if a font could not be created from + * the given arguments</li> + * </ul> + */ + public Font(Device device, String name, int height, int style) { + super(device); + if (name == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + init(new FontData(name, height, style)); + init(); + } + + public QFont getQFont() { + return font; + } + + // /*public*/ Font(Device device, String name, float height, int style) { + // super(device); + // if (name == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + // init(new FontData (name, height, style)); + // init(); + // } + @Override + void destroy() { + font.dispose(); // TODO_DISPOSE + font = 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 + */ + @Override + public boolean equals(Object object) { + if (object == this) { + return true; + } + if (!(object instanceof Font)) { + return false; + } + Font font = (Font) object; + return this.getQFont().equals(font.getQFont()); + } + + /** + * 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); + } + + String family = font.family(); + int pointSize = font.pointSize(); + int weight = font.weight(); + boolean italic = font.italic(); + + int style = SWT.NORMAL; + if (weight > SWQT.QT_FONTNORMAL) { + style |= SWT.BOLD; + } + if (italic) { + style |= SWT.ITALIC; + } + FontData data = new FontData(family, pointSize, style); + if (xlfd != null) { + data.xlfd = xlfd; + } else if (extraFontStyle) { + data.extraFontData = new QtSupplementaryFontData(); + QtSupplementaryFontData extraData = data.extraFontData; + extraData.underline = font.underline() ? 1 : 0; + extraData.overline = font.overline() ? 1 : 0; + extraData.strikeOut = font.strikeOut() ? 1 : 0; + extraData.stretch = font.stretch(); + extraData.fixedPitch = font.fixedPitch() ? 1 : 0; + extraData.style = font.style(); + extraData.weight = font.weight(); + extraData.styleStrategy = font.styleStrategy(); + } + return new FontData[] { data }; + } + + /** + * Returns an integer hash code for the receiver. Any two objects that + * return <code>true</code> when passed to <code>equals</code> must return + * the same value for this method. + * + * @return the receiver's hash + * + * @see #equals + */ + @Override + public int hashCode() { + if (font == null) { + return 0; + } + return font.toString().hashCode(); // TODO + } + + void init(FontData fd) { + if (fd == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + int weight = QFont.Weight.Normal.value(); + boolean italic = false; + if (fd.extraFontData != null) { + weight = fd.extraFontData.weight; + italic = fd.extraFontData.style == QFont.Style.StyleItalic; + } + + font = new QFont(fd.name, fd.getHeight(), weight, italic); + // TODO font can be BOLD AND ITALIC + if (fd.style == SWT.BOLD) { + font.setBold(true); + } + if (fd.style == SWT.ITALIC) { + font.setItalic(true); + } + // int lfHeight = fontData.lfHeight; + // fontData.lfHeight = device.computePixels(fd.height); + // handle = OS.CreateFontIndirect(logFont); + // fontData.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 + */ + @Override + public boolean isDisposed() { + return font == null; + } + + /** + * Returns a string containing a concise, human-readable description of the + * receiver. + * + * @return a string representation of the receiver + */ + @Override + public String toString() { + if (isDisposed()) { + return "Font {*DISPOSED*}"; //$NON-NLS-1$ + } + return "Font {" + font.family() + "}"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * 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 + * @return a new font object containing the specified device and handle + */ + public static Font qt_new(Device device, QFont fontParm) { + if (fontParm == null) { + return null; + } + if (device == null) { + device = Device.getDevice(); + } + if (device == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + Font font = new Font(); + font.font = fontParm; + font.device = device; + return font; + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/FontData.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/FontData.java new file mode 100644 index 0000000000..89db2b04ff --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/FontData.java @@ -0,0 +1,722 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * Portion Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Nokia Corporation - Qt implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import com.trolltech.qt.gui.QFont; +import com.trolltech.qt.gui.QFont.Style; +import com.trolltech.qt.gui.QFont.StyleStrategy; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.internal.qt.QtSupplementaryFontData; +import org.eclipse.swt.internal.qt.SWQT; + +/** + * Instances of this class describe operating system fonts. + * <p> + * For platform-independent behaviour, use the get and set methods corresponding + * to the following properties: + * <dl> + * <dt>height</dt> + * <dd>the height of the font in points</dd> + * <dt>name</dt> + * <dd>the face name of the font, which may include the foundry</dd> + * <dt>style</dt> + * <dd>A bitwise combination of NORMAL, ITALIC and BOLD</dd> + * </dl> + * If extra, platform-dependent functionality is required: + * <ul> + * <li>On <em>Windows</em>, the data member of the <code>FontData</code> + * corresponds to a Windows <code>LOGFONT</code> structure whose fields may be + * retrieved and modified.</li> + * <li>On <em>X</em>, the fields of the <code>FontData</code> correspond to the + * entries in the font's XLFD name and may be retrieved and modified. + * </ul> + * Application code does <em>not</em> need to explicitly release the resources + * managed by each instance when those instances are no longer required, and + * thus no <code>dispose()</code> method is provided. + * + * @see Font + */ +public final class FontData { + /** + * the font name + */ + String name; + + /** + * The height of the font data in points + */ + int height; + + /** + * the font style + */ + int style; + + /** + * The locales of the font + */ + String lang, country, variant; + + QtSupplementaryFontData extraFontData; + String xlfd; + + public static final int FONT_DEF_HEIGHT = 12; + + /** + * Constructs a new uninitialized font data. + */ + public FontData() { + this("", FONT_DEF_HEIGHT, SWT.NORMAL); //$NON-NLS-1$ + } + + // The characters in the string must all be decimal digits + // the value must be given with radix 10 + + /** + * 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); + } + parseFontDescriptor(string); + updateFontData(); + + } + + /** + * 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); + } + if (height < 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + setName(name); + setHeight(height); + setStyle(style); + } + + /** + * Compares the argument to the receiver, and returns true if they represent + * the <em>same</em> object using a class specific comparison. + * + * @param object + * the object to compare with this object + * @return <code>true</code> if the object is the same as this object and + * <code>false</code> otherwise + * + * @see #hashCode + */ + @Override + public boolean equals(Object object) { + if (object == this) { + return true; + } + if (!(object instanceof FontData)) { + return false; + } + + FontData data = (FontData) object; + + if (!(xlfd == null && data.xlfd == null || xlfd != null && data.xlfd != null)) { + return false; + } + + if (!(extraFontData == null && data.extraFontData == null || extraFontData != null + && data.extraFontData != null)) { + return false; + } + + if (xlfd != null) { + return xlfd.trim().equals(data.xlfd.trim()); + } + + boolean mainFontStyleEqual = name.equals(data.name) && height == data.height && style == data.style; + if (mainFontStyleEqual && extraFontData != null) { + return mainFontStyleEqual && extraFontData.underline == data.extraFontData.underline + && extraFontData.underline == data.extraFontData.underline + && extraFontData.overline == data.extraFontData.overline + && extraFontData.strikeOut == data.extraFontData.strikeOut + && extraFontData.stretch == data.extraFontData.stretch + && extraFontData.fixedPitch == data.extraFontData.fixedPitch + && extraFontData.style == data.extraFontData.style + && extraFontData.weight == data.extraFontData.weight + && extraFontData.styleStrategy == data.extraFontData.styleStrategy; + } else { + return mainFontStyleEqual; + } + } + + /** + * Returns the height of the receiver in points. + * + * @return the height of this FontData + * + * @see #setHeight(int) + */ + public int getHeight() { + return height; + } + + /** + * Returns the locale of the receiver. + * <p> + * The locale determines which platform character set this font is going to + * use. Widgets and graphics operations that use this font will convert + * UNICODE strings to the platform character set of the specified locale. + * </p> + * <p> + * On platforms where there are multiple character sets for a given + * language/country locale, the variant portion of the locale will determine + * the character set. + * </p> + * + * @return the <code>String</code> representing a Locale object + * @since 3.0 + */ + public String getLocale() { + StringBuffer buffer = new StringBuffer(); + char sep = '_'; + if (lang != null) { + buffer.append(lang); + buffer.append(sep); + } + if (country != null) { + buffer.append(country); + buffer.append(sep); + } + if (variant != null) { + buffer.append(variant); + } + + String result = buffer.toString(); + int length = result.length(); + if (length > 0) { + if (result.charAt(length - 1) == sep) { + result = result.substring(0, length - 1); + } + } + return result; + } + + /** + * Returns the name of the receiver. On platforms that support font + * foundries, the return value will be the foundry followed by a dash ("-") + * followed by the face name. + * + * @return the name of this <code>FontData</code> + * + * @see #setName + */ + public String getName() { + return name; + } + + /** + * Returns the style of the receiver which is a bitwise OR of one or more of + * the <code>SWT</code> constants NORMAL, BOLD and ITALIC. + * + * @return the style of this <code>FontData</code> + * + * @see #setStyle + */ + public int getStyle() { + return style; + } + + /** + * Returns an integer hash code for the receiver. Any two objects that + * return <code>true</code> when passed to <code>equals</code> must return + * the same value for this method. + * + * @return the receiver's hash + * + * @see #equals + */ + @Override + public int hashCode() { + return name.hashCode() ^ height ^ style; + } + + void parseFontDescriptor(String string) { + 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); + 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.trim().toUpperCase().equals("QT") && version2.equals("1")) { //$NON-NLS-1$ //$NON-NLS-2$ + try { + extraFontData = new QtSupplementaryFontData(); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) { + return; + } + extraFontData.underline = Integer.parseInt(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) { + return; + } + extraFontData.overline = Integer.parseInt(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) { + return; + } + extraFontData.strikeOut = Integer.parseInt(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) { + return; + } + int stretch = Integer.parseInt(string.substring(start, end)); + if (stretch > 0) { + if (stretch > 4000) { + stretch = 4000; + } + extraFontData.stretch = stretch; + } + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) { + extraFontData = null; + return; + } + extraFontData.fixedPitch = Integer.parseInt(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) { + return; + } + int fontStyle = Integer.parseInt(string.substring(start, end)); + if (fontStyle == SWQT.QFONT_STYLE_NORMAL) { + extraFontData.style = Style.StyleNormal; + } + if (fontStyle == SWQT.QFONT_STYLE_ITALIC) { + extraFontData.style = Style.StyleItalic; + } + if (fontStyle == SWQT.QFONT_STYLE_OBLIQUE) { + extraFontData.style = Style.StyleOblique; + } + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) { + return; + } + int weight = Integer.parseInt(string.substring(start, end)); + if (weight > -1) { + if (weight > 99) { + weight = 99; + } + extraFontData.weight = weight; + } + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) { + return; + } + int styleStrategy = Integer.parseInt(string.substring(start, end)); + int[] strategies = new int[] { SWQT.QFONT_STYLESTRATEGY_PREFERDEFALUT, + SWQT.QFONT_STYLESTRATEGY_PREFERBITMAP, SWQT.QFONT_STYLESTRATEGY_PREFERDEVICE, + SWQT.QFONT_STYLESTRATEGY_PREFEROUTLINE, SWQT.QFONT_STYLESTRATEGY_FORCEOUTLINE, + SWQT.QFONT_STYLESTRATEGY_NOANTIALIAS, SWQT.QFONT_STYLESTRATEGY_PREFERANTIALIAS, + SWQT.QFONT_STYLESTRATEGY_OPENGLCOMPATIABLE, SWQT.QFONT_STYLESTRATEGY_NOFONTMERGING }; + boolean isValidStrategy = styleStrategy == SWQT.QFONT_STYLESTRATEGY_PREFERQUALITY + || styleStrategy == SWQT.QFONT_STYLESTRATEGY_PREFERMATCH ? true : false; + for (int i = 0; i < strategies.length; i++) { + if ((styleStrategy & strategies[i]) == 0) { + continue; + } else { + if (styleStrategy == strategies[i] + || styleStrategy == (strategies[i] | SWQT.QFONT_STYLESTRATEGY_PREFERQUALITY) + || styleStrategy == (strategies[i] | SWQT.QFONT_STYLESTRATEGY_PREFERMATCH)) { + isValidStrategy = true; + } + break; + } + } + if (isValidStrategy) { + if (styleStrategy == SWQT.QFONT_STYLESTRATEGY_FORCEOUTLINE) { + extraFontData.styleStrategy = StyleStrategy.ForceOutline; + } + if (styleStrategy == SWQT.QFONT_STYLESTRATEGY_NOANTIALIAS) { + extraFontData.styleStrategy = StyleStrategy.NoAntialias; + } + if (styleStrategy == SWQT.QFONT_STYLESTRATEGY_NOFONTMERGING) { + extraFontData.styleStrategy = StyleStrategy.NoFontMerging; + } + if (styleStrategy == SWQT.QFONT_STYLESTRATEGY_OPENGLCOMPATIABLE) { + extraFontData.styleStrategy = StyleStrategy.OpenGLCompatible; + } + if (styleStrategy == SWQT.QFONT_STYLESTRATEGY_PREFERANTIALIAS) { + extraFontData.styleStrategy = StyleStrategy.PreferAntialias; + } + if (styleStrategy == SWQT.QFONT_STYLESTRATEGY_PREFERBITMAP) { + extraFontData.styleStrategy = StyleStrategy.PreferBitmap; + } + if (styleStrategy == SWQT.QFONT_STYLESTRATEGY_PREFERDEFALUT) { + extraFontData.styleStrategy = StyleStrategy.PreferDefault; + } + if (styleStrategy == SWQT.QFONT_STYLESTRATEGY_PREFERDEVICE) { + extraFontData.styleStrategy = StyleStrategy.PreferDevice; + } + if (styleStrategy == SWQT.QFONT_STYLESTRATEGY_PREFERMATCH) { + extraFontData.styleStrategy = StyleStrategy.PreferMatch; + } + if (styleStrategy == SWQT.QFONT_STYLESTRATEGY_PREFEROUTLINE) { + extraFontData.styleStrategy = StyleStrategy.PreferOutline; + } + if (styleStrategy == SWQT.QFONT_STYLESTRATEGY_PREFERQUALITY) { + extraFontData.styleStrategy = StyleStrategy.PreferQuality; + } + } + } catch (NumberFormatException e) { + extraFontData = null; + } + } + // else if (platform.trim().toUpperCase().equals("X11") + // && OS.windowServer == OS.WS_X11) { + // start = end + 1; + // end = string.indexOf('|', start); + // if (end == -1) + // return; + // xlfd = string.substring(start, end); + // if (xlfd.length() < 1) { + // xlfd = null; + // } + // } + + } + + /** + * 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 where there are multiple character sets for a given + * language/country locale, the variant portion of the locale will determine + * the character set. + * </p> + * + * @param locale + * the <code>String</code> representing a Locale object + * @see java.util.Locale#toString + */ + public void setLocale(String locale) { + lang = country = variant = null; + if (locale != null) { + char sep = '_'; + int length = locale.length(); + int firstSep, secondSep; + + firstSep = locale.indexOf(sep); + if (firstSep == -1) { + firstSep = secondSep = length; + } else { + secondSep = locale.indexOf(sep, firstSep + 1); + if (secondSep == -1) { + secondSep = length; + } + } + if (firstSep > 0) { + lang = locale.substring(0, firstSep); + } + if (secondSep > firstSep + 1) { + country = locale.substring(firstSep + 1, secondSep); + } + if (length > secondSep + 1) { + variant = locale.substring(secondSep + 1); + } + } + } + + /** + * Sets the name of the receiver. + * <p> + * Some platforms support font foundries. On these platforms, the name of + * the font specified in setName() may have one of the following forms: + * <ol> + * <li>a face name (for example, "courier")</li> + * <li>a foundry followed by a dash ("-") followed by a face name (for + * example, "adobe-courier")</li> + * </ol> + * In either case, the name returned from getName() will include the + * foundry. + * </p> + * <p> + * On platforms that do not support font foundries, only the face name (for + * example, "courier") is used in <code>setName()</code> and + * <code>getName()</code>. + * </p> + * + * @param name + * the name of the font data (must not be null) + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - when the font name is null</li> + * </ul> + * + * @see #getName + */ + public void setName(String name) { + if (name == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + this.name = name; + } + + /** + * Sets the style of the receiver to the argument which must be a bitwise OR + * of one or more of the <code>SWT</code> constants NORMAL, BOLD and ITALIC. + * All other style bits are ignored. + * + * @param style + * the new style for this <code>FontData</code> + * + * @see #getStyle + */ + public void setStyle(int style) { + this.style = style; + } + + /** + * 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 + */ + @Override + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("1|"); //$NON-NLS-1$ + buffer.append(getName()); + buffer.append("|"); //$NON-NLS-1$ + buffer.append(getHeight()); + buffer.append("|"); //$NON-NLS-1$ + buffer.append(getStyle()); + buffer.append("|"); //$NON-NLS-1$ + if (xlfd != null) { + buffer.append("X11|1|"); //$NON-NLS-1$ + buffer.append(xlfd); + buffer.append("|"); //$NON-NLS-1$ + } else if (extraFontData != null) { + buffer.append("QT|1|"); //$NON-NLS-1$ + buffer.append(extraFontData.overline); + buffer.append("|"); //$NON-NLS-1$ + buffer.append(extraFontData.underline); + buffer.append("|"); //$NON-NLS-1$ + buffer.append(extraFontData.strikeOut); + buffer.append("|"); //$NON-NLS-1$ + buffer.append(extraFontData.stretch); + buffer.append("|"); //$NON-NLS-1$ + buffer.append(extraFontData.fixedPitch); + buffer.append("|"); //$NON-NLS-1$ + buffer.append(extraFontData.style); + buffer.append("|"); //$NON-NLS-1$ + buffer.append(extraFontData.weight); + buffer.append("|"); //$NON-NLS-1$ + buffer.append(extraFontData.styleStrategy); + buffer.append("|"); //$NON-NLS-1$ + } + return buffer.toString(); + } + + void updateFontData() { + if (extraFontData == null && xlfd == null) { + return; + } + + boolean italic = (style & SWT.ITALIC) != 0; + int weight = SWQT.QT_FONTNORMAL; + if ((style & SWT.BOLD) != 0) { + weight = SWQT.QT_FONTBOLD; + } + QFont font = new QFont(name, height, weight, italic); + + if (xlfd != null) { + font.setRawName(xlfd); + + } else { + if (extraFontData.underline > -1) { + font.setUnderline(extraFontData.underline > 0 ? true : false); + } + if (extraFontData.overline > -1) { + font.setOverline(extraFontData.overline > 0 ? true : false); + } + if (extraFontData.strikeOut > -1) { + font.setStrikeOut(extraFontData.strikeOut > 0 ? true : false); + } + if (extraFontData.stretch > -1) { + font.setStretch(extraFontData.stretch); + } + if (extraFontData.fixedPitch > -1) { + font.setFixedPitch(extraFontData.fixedPitch > 0 ? true : false); + } + if (extraFontData.style != null) { + font.setStyle(extraFontData.style); + } + if (extraFontData.weight > -1) { + font.setWeight(extraFontData.weight); + } + if (extraFontData.styleStrategy != null) { + font.setStyleStrategy(extraFontData.styleStrategy); + } + } + + name = font.family(); + height = font.pointSize(); + weight = font.weight(); + italic = font.italic(); + style = SWT.NORMAL; + if (weight > SWQT.QT_FONTNORMAL) { + style |= SWT.BOLD; + } + if (italic == true) { + style |= SWT.ITALIC; + } + if (extraFontData != null) { + extraFontData.underline = font.underline() == true ? 1 : 0; + extraFontData.overline = font.overline() == true ? 1 : 0; + extraFontData.strikeOut = font.strikeOut() == true ? 1 : 0; + extraFontData.stretch = font.stretch(); + extraFontData.fixedPitch = font.fixedPitch() == true ? 1 : 0; + extraFontData.style = font.style(); + extraFontData.weight = font.weight(); + extraFontData.styleStrategy = font.styleStrategy(); + font.dispose(); + } + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/FontMetrics.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/FontMetrics.java new file mode 100644 index 0000000000..2be6f6e78e --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/FontMetrics.java @@ -0,0 +1,165 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import com.trolltech.qt.gui.QFontMetrics; + +/** + * Instances of this class provide measurement information about fonts including + * ascent, descent, height, leading space between rows, and average character + * width. <code>FontMetrics</code> are obtained from <code>GC</code>s using the + * <code>getFontMetrics()</code> method. + * + * @see GC#getFontMetrics + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + */ +public final class FontMetrics { + private final int ascent; + private final int descent; + private final int aveCharWidth; + private final int leading; + private final int height; + + private FontMetrics(int ascent, int descent, int aveCharWidth, int leading, int height) { + this.ascent = ascent; + this.descent = descent; + this.aveCharWidth = aveCharWidth; + this.leading = leading; + this.height = height; + } + + /** + * 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 + */ + @Override + public boolean equals(Object object) { + if (object == this) { + return true; + } + if (!(object instanceof FontMetrics)) { + return false; + } + FontMetrics other = (FontMetrics) object; + return ascent == other.ascent && descent == other.descent && aveCharWidth == other.aveCharWidth + && leading == other.leading && height == other.height; + } + + /** + * Returns the ascent of the font described by the receiver. A font's + * <em>ascent</em> is the distance from the baseline to the top of actual + * characters, not including any of the leading area, measured in pixels. + * + * @return the ascent of the font + */ + public int getAscent() { + return ascent; + } + + /** + * Returns the average character width, measured in pixels, of the font + * described by the receiver. + * + * @return the average character width of the font + */ + public int getAverageCharWidth() { + return aveCharWidth; + } + + /** + * Returns the descent of the font described by the receiver. A font's + * <em>descent</em> is the distance from the baseline to the bottom of + * actual characters, not including any of the leading area, measured in + * pixels. + * + * @return the descent of the font + */ + public int getDescent() { + return descent; + } + + /** + * Returns the height of the font described by the receiver, measured in + * pixels. A font's <em>height</em> is the sum of its ascent, descent and + * leading area. + * + * @return the height of the font + * + * @see #getAscent + * @see #getDescent + * @see #getLeading + */ + public int getHeight() { + return height; + } + + /** + * Returns the leading area of the font described by the receiver. A font's + * <em>leading area</em> is the space above its ascent which may include + * accents or other marks. + * + * @return the leading space of the font + */ + public int getLeading() { + return leading; + } + + /** + * Returns an integer hash code for the receiver. Any two objects that + * return <code>true</code> when passed to <code>equals</code> must return + * the same value for this method. + * + * @return the receiver's hash + * + * @see #equals + */ + @Override + public int hashCode() { + return ascent ^ descent ^ aveCharWidth ^ leading ^ height; + } + + /** + * 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 metrics + * the <code>QFontMetrics</code> containing information about a + * font + * @return a new font metrics object containing the specified + * <code>TEXTMETRIC</code> + */ + public static FontMetrics internal_new(QFontMetrics qfm) { + return new FontMetrics(qfm.ascent(), qfm.descent(), qfm.averageCharWidth(), 0, qfm.height()); + } + + public static FontMetrics internal_new(Font font) { + return internal_new(new QFontMetrics(font.getQFont())); + } + + public static FontMetrics internal_new(int ascent, int descent, int aveCharWidth, int leading, int height) { + return new FontMetrics(ascent, descent, aveCharWidth, leading, height); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/GC.java new file mode 100644 index 0000000000..026041b62b --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/GC.java @@ -0,0 +1,3555 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import com.trolltech.qt.core.QPointF; +import com.trolltech.qt.core.QRect; +import com.trolltech.qt.core.Qt.AlignmentFlag; +import com.trolltech.qt.core.Qt.BGMode; +import com.trolltech.qt.core.Qt.FillRule; +import com.trolltech.qt.core.Qt.PenStyle; +import com.trolltech.qt.core.Qt.SizeMode; +import com.trolltech.qt.core.Qt.TextFlag; +import com.trolltech.qt.gui.QApplication; +import com.trolltech.qt.gui.QBrush; +import com.trolltech.qt.gui.QColor; +import com.trolltech.qt.gui.QFontMetrics; +import com.trolltech.qt.gui.QLinearGradient; +import com.trolltech.qt.gui.QPaintDeviceInterface; +import com.trolltech.qt.gui.QPainter; +import com.trolltech.qt.gui.QPixmap; +import com.trolltech.qt.gui.QPolygon; +import com.trolltech.qt.gui.QRegion; +import com.trolltech.qt.gui.QStyleOptionFocusRect; +import com.trolltech.qt.gui.QStyle.PrimitiveElement; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTError; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.internal.qt.QtSWTConverter; + +/** + * Class <code>GC</code> is where all of the drawing capabilities that are + * supported by SWT are located. Instances are used to draw on either an + * <code>Image</code>, a <code>Control</code>, or directly on a + * <code>Display</code>. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>LEFT_TO_RIGHT, RIGHT_TO_LEFT</dd> + * </dl> + * + * <p> + * The SWT drawing coordinate system is the two-dimensional space with the + * origin (0,0) at the top left corner of the drawing area and with (x,y) values + * increasing to the right and downward respectively. + * </p> + * + * <p> + * The result of drawing on an image that was created with an indexed palette + * using a color that is not in the palette is platform specific. Some platforms + * will match to the nearest color while other will draw the color itself. This + * happens because the allocated image might use a direct palette on platforms + * that do not support indexed palette. + * </p> + * + * <p> + * Application code must explicitly invoke the <code>GC.dispose()</code> method + * to release the operating system resources managed by each instance when those + * instances are no longer required. This is <em>particularly</em> important on + * Windows95 and Windows98 where the operating system has a limited number of + * device contexts available. + * </p> + * + * <p> + * Note: Only one of LEFT_TO_RIGHT and RIGHT_TO_LEFT may be specified. + * </p> + * + * @see org.eclipse.swt.events.PaintEvent + * @see <a href="http://www.eclipse.org/swt/snippets/#gc">GC snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: + * GraphicsExample, PaintExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + */ +public final class GC extends Resource { + + /** + * the handle to the OS device context (Warning: This field is platform + * dependent) + * <p> + * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT public API. + * It is marked public only so that it can be shared within the packages + * provided by SWT. It is not available on all platforms and should never be + * accessed from application code. + * </p> + */ + private QPaintDeviceInterface paintDevice; + private QPainter activePainter; + private QRegion activeClipping; + + public int handle; + + private Drawable drawable; + private GCData data; + private FillRule fillRule; + + private int antialias = SWT.OFF; // TODO make sure this flag does not get lost, currently not interpreted + + private static final int FOREGROUND = 1 << 0; + private static final int BACKGROUND = 1 << 1; + private static final int FONT = 1 << 2; + private static final int LINE_STYLE = 1 << 3; + private static final int LINE_WIDTH = 1 << 4; + private static final int LINE_CAP = 1 << 5; + private static final int LINE_JOIN = 1 << 6; + private static final int LINE_MITERLIMIT = 1 << 7; + private static final int FOREGROUND_TEXT = 1 << 8; + private static final int BACKGROUND_TEXT = 1 << 9; + private static final int BRUSH = 1 << 10; + private static final int PEN = 1 << 11; + private static final int NULL_BRUSH = 1 << 12; + private static final int NULL_PEN = 1 << 13; + private static final int DRAW_OFFSET = 1 << 14; + + /** + * 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 color, background color + * and font in the GC to match those in the drawable. + * <p> + * You must dispose the graphics context when it is no longer required. + * </p> + * + * @param drawable + * the drawable to draw on + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the drawable is null</li> + * <li>ERROR_NULL_ARGUMENT - if there is no current device</li> + * <li>ERROR_INVALID_ARGUMENT - if the drawable is an image + * that is not a bitmap or an icon - if the drawable is an + * image or printer that is already selected into another + * graphics context</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for + * GC creation</li> + * <li>ERROR_THREAD_INVALID_ACCESS if not called from the + * thread that created the drawable</li> + * </ul> + */ + public GC(Drawable drawable) { + this(drawable, SWT.NONE); + } + + /** + * Constructs a new instance of this class which has been configured to draw + * on the specified drawable. Sets the foreground color, background color + * and font in the GC to match those in the drawable. + * <p> + * You must dispose the graphics context when it is no longer required. + * </p> + * + * @param drawable + * the drawable to draw on + * @param style + * the style of GC to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the drawable is null</li> + * <li>ERROR_NULL_ARGUMENT - if there is no current device</li> + * <li>ERROR_INVALID_ARGUMENT - if the drawable is an image + * that is not a bitmap or an icon - if the drawable is an + * image or printer that is already selected into another + * graphics context</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for + * GC creation</li> + * <li>ERROR_THREAD_INVALID_ACCESS if not called from the + * thread that created the drawable</li> + * </ul> + * + * @since 2.1.2 + */ + public GC(Drawable drawable, int style) { + if (drawable == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + + GCData data = new GCData(); + data.style = checkStyle(style); + QPaintDeviceInterface paintDevice = drawable.internal_new_GC(data); + Device device = data.device; + if (device == null) { + device = Device.getDevice(); + } + if (device == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + this.device = data.device = device; + init(drawable, data, paintDevice); + init(); + } + + private QPainter getActivePainter() { + if (activePainter == null) { + activePainter = new QPainter(); + // if (paintDevice.paintingActive()) { + //System.out.println("new painter for " + paintDevice + "active: " + paintDevice.paintingActive()); + // //paintDevice.paintEngine().end(); + // } + } + + if (!activePainter.isActive()) { + activePainter.begin(paintDevice); + } + + if (!activePainter.isActive()) { + System.out.println("inactive painter for: " + paintDevice + " painter: " //$NON-NLS-1$ //$NON-NLS-2$ + + paintDevice.paintEngine().painter()); + // RuntimeException re = new RuntimeException(); + // re.printStackTrace(); + } + + if (activeClipping != null) { + activePainter.setClipRegion(activeClipping); + } + return activePainter; + } + + static int checkStyle(int style) { + if ((style & SWT.LEFT_TO_RIGHT) != 0) { + style &= ~SWT.RIGHT_TO_LEFT; + } + return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT); + } + + void init(Drawable drawable, GCData data, QPaintDeviceInterface paintDevice) { + this.paintDevice = paintDevice; + + Color foreground = data.foregroundColor; + if (foreground != null) { + data.state &= ~(FOREGROUND | FOREGROUND_TEXT | PEN); + } else { + data.foregroundColor = data.device.getSystemColor(SWT.COLOR_BLACK); + } + Color background = data.backgroundColor; + if (background != null) { + data.state &= ~(BACKGROUND | BACKGROUND_TEXT | BRUSH); + } else { + data.backgroundColor = data.device.getSystemColor(SWT.COLOR_WHITE); + } + data.state &= ~(NULL_BRUSH | NULL_PEN); + Font font = data.font; + if (font != null) { + data.state &= ~FONT; + } else { + data.font = device.getSystemFont(); + } + Image image = data.image; + if (image != null) { + image.setMemGC(this); + } + if ((data.style & SWT.RIGHT_TO_LEFT) != 0) { + data.style |= SWT.MIRRORED; + } + this.drawable = drawable; + this.data = data; + } + + /** + * Copies a rectangular area of the receiver at the specified position into + * the image, which must be of type <code>SWT.BITMAP</code>. + * + * @param image + * the image to copy into + * @param x + * the x coordinate in the receiver of the area to be copied + * @param y + * the y coordinate in the receiver of the area to be copied + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the image is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the image is not a bitmap + * or has been disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void copyArea(Image image, int x, int y) { + // TODO + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (image == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (!image.isBitmap() || image.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + } + + /** + * Copies a rectangular area of the receiver at the source position onto the + * receiver at the destination position. + * + * @param srcX + * the x coordinate in the receiver of the area to be copied + * @param srcY + * the y coordinate in the receiver of the area to be copied + * @param width + * the width of the area to copy + * @param height + * the height of the area to copy + * @param destX + * the x coordinate in the receiver of the area to copy to + * @param destY + * the y coordinate in the receiver of the area to copy to + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY) { + copyArea(srcX, srcY, width, height, destX, destY, true); + } + + /** + * Copies a rectangular area of the receiver at the source position onto the + * receiver at the destination position. + * + * @param srcX + * the x coordinate in the receiver of the area to be copied + * @param srcY + * the y coordinate in the receiver of the area to be copied + * @param width + * the width of the area to copy + * @param height + * the height of the area to copy + * @param destX + * the x coordinate in the receiver of the area to copy to + * @param destY + * the y coordinate in the receiver of the area to copy to + * @param paint + * if <code>true</code> paint events will be generated for old + * and obscured areas + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.1 + */ + public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY, boolean paint) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + //TODO + /* + * Feature in WinCE. The function WindowFromDC is not part of the WinCE + * SDK. The fix is to remember the HWND. + */ + // int /* long */hwnd = data.hwnd; + // if (hwnd == 0) { + // OS.BitBlt(handle, destX, destY, width, height, handle, srcX, srcY, OS.SRCCOPY); + // } else { + // RECT lprcClip = null; + // int /* long */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 flags = paint ? OS.SW_INVALIDATE | OS.SW_ERASE : 0; + // int res = OS.ScrollWindowEx(hwnd, destX - srcX, destY - srcY, lprcScroll, lprcClip, 0, null, flags); + // + // /* + // * 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. + // */ + // } + } + + /** + * Disposes of the operating system resources associated with the graphics + * context. Applications must dispose of all GCs which they allocate. + * + * @exception SWTError + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS if not called from the + * thread that created the drawable</li> + * </ul> + */ + @Override + void destroy() { + if (activePainter != null) { + activePainter.end(); + //System.out.println("end painter for " + paintDevice); + activePainter = null; + } + + Image image = data.image; + if (image != null) { + image.setMemGC(null); + } + + if (drawable != null) { + drawable.internal_dispose_GC(paintDevice, data); + } + drawable = null; + data.image = null; + data = null; + paintDevice = null; + } + + /** + * Draws the outline of a circular or elliptical arc within the specified + * rectangular area. + * <p> + * The resulting arc begins at <code>startAngle</code> and extends for + * <code>arcAngle</code> degrees, using the current color. Angles are + * interpreted such that 0 degrees is at the 3 o'clock position. A positive + * value indicates a counter-clockwise rotation while a negative value + * indicates a clockwise rotation. + * </p> + * <p> + * The center of the arc is the center of the rectangle whose origin is ( + * <code>x</code>, <code>y</code>) and whose size is specified by the + * <code>width</code> and <code>height</code> arguments. + * </p> + * <p> + * The resulting arc covers an area <code>width + 1</code> pixels wide by + * <code>height + 1</code> pixels tall. + * </p> + * + * @param x + * the x coordinate of the upper-left corner of the arc to be + * drawn + * @param y + * the y coordinate of the upper-left corner of the arc to be + * drawn + * @param width + * the width of the arc to be drawn + * @param height + * the height of the arc to be drawn + * @param startAngle + * the beginning angle + * @param arcAngle + * the angular extent of the arc, relative to the start angle + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + QPainter painter = getActivePainter(); + painter.setPen(getForeground().getColor()); + painter.drawArc(x, y, width, height, startAngle, arcAngle); + } + + /** + * Draws a rectangle, based on the specified arguments, which has the + * appearance of the platform's <em>focus rectangle</em> if the platform + * supports such a notion, and otherwise draws a simple rectangle in the + * receiver's foreground color. + * + * @param x + * the x coordinate of the rectangle + * @param y + * the y coordinate of the rectangle + * @param width + * the width of the rectangle + * @param height + * the height of the rectangle + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #drawRectangle(int, int, int, int) + */ + public void drawFocus(int x, int y, int width, int height) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + QPainter painter = getActivePainter(); + painter.setPen(getForeground().getColor()); + QStyleOptionFocusRect option = new QStyleOptionFocusRect(); + option.rect().setRect(x, y, width, height); + QApplication.style().drawPrimitive(PrimitiveElement.PE_FrameFocusRect, option, painter); + } + + /** + * Draws the given image in the receiver at the specified coordinates. + * + * @param image + * the image to draw + * @param x + * the x coordinate of where to draw + * @param y + * the y coordinate of where to draw + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the image is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the image has been + * disposed</li> + * <li>ERROR_INVALID_ARGUMENT - if the given coordinates are + * outside the bounds of the image</li> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES - if no handles are available to + * perform the operation</li> + * </ul> + */ + public void drawImage(Image image, int x, int y) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (image == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (image.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + + QPainter painter = getActivePainter(); + QPixmap pic = image.getQPixmap(); + painter.drawPixmap(x, y, pic); + } + + /** + * Copies a rectangular area from the source image into a (potentially + * different sized) rectangular area in the receiver. If the source and + * destination areas are of differing sizes, then the source area will be + * stretched or shrunk to fit the destination area as it is copied. The copy + * fails if any part of the source rectangle lies outside the bounds of the + * source image, or if any of the width or height arguments are negative. + * + * @param image + * the source image + * @param srcX + * the x coordinate in the source image to copy from + * @param srcY + * the y coordinate in the source image to copy from + * @param srcWidth + * the width in pixels to copy from the source + * @param srcHeight + * the height in pixels to copy from the source + * @param destX + * the x coordinate in the destination to copy to + * @param destY + * the y coordinate in the destination to copy to + * @param destWidth + * the width in pixels of the destination rectangle + * @param destHeight + * the height in pixels of the destination rectangle + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the image is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the image has been + * disposed</li> + * <li>ERROR_INVALID_ARGUMENT - if any of the width or height + * arguments are negative. + * <li>ERROR_INVALID_ARGUMENT - if the source rectangle is + * not contained within the bounds of the source image</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES - if no handles are available to + * perform the operation</li> + * </ul> + */ + public void drawImage(Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, + int destWidth, int destHeight) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (srcWidth == 0 || srcHeight == 0 || destWidth == 0 || destHeight == 0) { + return; + } + if (srcX < 0 || srcY < 0 || srcWidth < 0 || srcHeight < 0 || destWidth < 0 || destHeight < 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (image == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (image.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + + QPainter painter = getActivePainter(); + painter.drawPixmap(new QRect(destX, destY, destWidth, destHeight), image.getQPixmap(), new QRect(srcX, srcY, + srcWidth, srcHeight)); + } + + /** + * 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 (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + QPainter painter = getActivePainter(); + painter.setPen(getForeground().getColor()); + painter.drawLine(x1, y1, x2, y2); + } + + /** + * 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 (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + QPainter painter = getActivePainter(); + painter.setPen(getForeground().getColor()); + painter.drawEllipse(x, y, width, height); + } + + /** + * Draws the path described by the parameter. + * <p> + * This operation requires the operating system's advanced graphics + * subsystem which may not be available on some platforms. + * </p> + * + * @param path + * the path to draw + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the parameter has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are + * not available</li> + * </ul> + * + * @see Path + * + * @since 3.1 + */ + public void drawPath(Path path) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (path == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (path.handle == 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + //checkGC(DRAW); + //TODO + // int /* long */gdipGraphics = data.gdipGraphics; + // Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend); + // Gdip.Graphics_DrawPath(gdipGraphics, data.gdipPen, path.handle); + // Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend); + } + } + + /** + * Draws a pixel, using the foreground color, at the specified point ( + * <code>x</code>, <code>y</code>). + * <p> + * Note that the receiver's line attributes do not affect this operation. + * </p> + * + * @param x + * the point's x coordinate + * @param y + * the point's y coordinate + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.0 + */ + public void drawPoint(int x, int y) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + QPainter painter = getActivePainter(); + painter.setPen(getForeground().getColor()); + painter.drawPoint(x, y); + } + + /** + * 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 (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + validatePointArray(pointArray); + QPainter painter = getActivePainter(); + painter.setPen(getForeground().getColor()); + painter.drawPolygon(createPolygonFromArray(pointArray)); + } + + /** + * 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 (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (pointArray == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + validatePointArray(pointArray); + QPainter painter = getActivePainter(); + painter.setPen(getForeground().getColor()); + painter.drawPolyline(createPolygonFromArray(pointArray)); + } + + /** + * 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 (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + QPainter painter = getActivePainter(); + painter.setPen(getForeground().getColor()); + painter.drawRect(x, y, width, height); + } + + /** + * 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, which are respectively the width and height of the ellipse + * used to draw the corners. + * + * @param x + * the x coordinate of the rectangle to be drawn + * @param y + * the y coordinate of the rectangle to be drawn + * @param width + * the width of the rectangle to be drawn + * @param height + * the height of the rectangle to be drawn + * @param arcWidth + * the width of the arc + * @param arcHeight + * the height of the arc + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void drawRoundRectangle(int x, int y, int width, int height, int arcWidth, int arcHeight) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + QPainter painter = getActivePainter(); + painter.setPen(getForeground().getColor()); + painter.drawRoundedRect(x, y, width, height, arcWidth, arcHeight, SizeMode.AbsoluteSize); + } + + /** + * 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 (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + QPainter painter = getActivePainter(); + if (isTransparent) { + painter.setBackgroundMode(BGMode.TransparentMode); + } else { + painter.setBackgroundMode(BGMode.OpaqueMode); + painter.setBackground(new QBrush(getBackground().getColor())); + } + painter.setFont(data.font.getQFont()); + painter.setPen(getForeground().getColor()); + //System.out.println("drawText(" + x + ", " + y + ", " + string + ")"); + + painter.drawText(x, y + getHightCorrection(painter), string); + } + + private int getHightCorrection(QPainter painter) { + QFontMetrics fm = painter.fontMetrics(); + return fm.ascent(); + } + + /** + * Draws the given string, using the receiver's current font and foreground + * color. Tab expansion and carriage return processing are performed. The + * background of the rectangular area where the text is being drawn will be + * filled with the receiver's background color. + * + * @param string + * the string to be drawn + * @param x + * the x coordinate of the top left corner of the rectangular + * area where the text is to be drawn + * @param y + * the y coordinate of the top left corner of the rectangular + * area where the text is to be drawn + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void drawText(String string, int x, int y) { + drawText(string, x, y, SWT.DRAW_DELIMITER | SWT.DRAW_TAB); + } + + /** + * Draws the given string, using the receiver's current font and foreground + * color. Tab expansion and carriage return processing are performed. If + * <code>isTransparent</code> is <code>true</code>, then the background of + * the rectangular area where the text is being drawn will not be modified, + * otherwise it will be filled with the receiver's background color. + * + * @param string + * the string to be drawn + * @param x + * the x coordinate of the top left corner of the rectangular + * area where the text is to be drawn + * @param y + * the y coordinate of the top left corner of the rectangular + * area where the text is to be drawn + * @param isTransparent + * if <code>true</code> the background will be transparent, + * otherwise it will be opaque + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void drawText(String string, int x, int y, boolean isTransparent) { + int flags = SWT.DRAW_DELIMITER | SWT.DRAW_TAB; + if (isTransparent) { + flags |= SWT.DRAW_TRANSPARENT; + } + drawText(string, x, y, flags); + } + + /** + * Draws the given string, using the receiver's current font and foreground + * color. Tab expansion, line delimiter and mnemonic processing are + * performed according to the specified flags. If <code>flags</code> + * includes <code>DRAW_TRANSPARENT</code>, then the background of the + * rectangular area where the text is being drawn will not be modified, + * otherwise it will be filled with the receiver's background color. + * <p> + * The parameter <code>flags</code> may be a combination of: + * <dl> + * <dt><b>DRAW_DELIMITER</b></dt> + * <dd>draw multiple lines</dd> + * <dt><b>DRAW_TAB</b></dt> + * <dd>expand tabs</dd> + * <dt><b>DRAW_MNEMONIC</b></dt> + * <dd>underline the mnemonic character</dd> + * <dt><b>DRAW_TRANSPARENT</b></dt> + * <dd>transparent background</dd> + * </dl> + * </p> + * + * @param string + * the string to be drawn + * @param x + * the x coordinate of the top left corner of the rectangular + * area where the text is to be drawn + * @param y + * the y coordinate of the top left corner of the rectangular + * area where the text is to be drawn + * @param flags + * the flags specifying how to process the text + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void drawText(String string, int x, int y, int flags) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + QPainter painter = getActivePainter(); + if ((flags & SWT.DRAW_TRANSPARENT) != 0) { + painter.setBackgroundMode(BGMode.TransparentMode); + painter.setBackground(new QBrush(getBackground().getColor())); + } + + int translatedFlags = translateTextFlags(flags); + + painter.setPen(getForeground().getColor()); + + QRect r = painter.boundingRect(0, 0, 0, 0, translatedFlags, string); + + //System.out.println("drawText(" + x + ", " + y + ", " + r.width() + ", " + r.height() + ", " + string + ")"); + painter.drawText(x, y, r.width(), r.height(), translatedFlags, string); + } + + /** + * @param flags + * @return + */ + private int translateTextFlags(int flags) { + int translatedFlags = AlignmentFlag.AlignTop.value() | AlignmentFlag.AlignLeft.value(); + if ((flags & SWT.DRAW_DELIMITER) == 0) { + translatedFlags |= TextFlag.TextSingleLine.value(); + } + if ((flags & SWT.DRAW_TAB) != 0) { + translatedFlags |= TextFlag.TextExpandTabs.value(); + } + if ((flags & SWT.DRAW_MNEMONIC) != 0) { + translatedFlags |= TextFlag.TextShowMnemonic.value(); + } + return translatedFlags; + } + + /** + * 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 + */ + @Override + public boolean equals(Object object) { + return object == this || object instanceof GC && paintDevice == ((GC) object).paintDevice; + } + + /** + * Fills the interior of a circular or elliptical arc within the specified + * rectangular area, with the receiver's background color. + * <p> + * The resulting arc begins at <code>startAngle</code> and extends for + * <code>arcAngle</code> degrees, using the current color. Angles are + * interpreted such that 0 degrees is at the 3 o'clock position. A positive + * value indicates a counter-clockwise rotation while a negative value + * indicates a clockwise rotation. + * </p> + * <p> + * The center of the arc is the center of the rectangle whose origin is ( + * <code>x</code>, <code>y</code>) and whose size is specified by the + * <code>width</code> and <code>height</code> arguments. + * </p> + * <p> + * The resulting arc covers an area <code>width + 1</code> pixels wide by + * <code>height + 1</code> pixels tall. + * </p> + * + * @param x + * the x coordinate of the upper-left corner of the arc to be + * filled + * @param y + * the y coordinate of the upper-left corner of the arc to be + * filled + * @param width + * the width of the arc to be filled + * @param height + * the height of the arc to be filled + * @param startAngle + * the beginning angle + * @param arcAngle + * the angular extent of the arc, relative to the start angle + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #drawArc + */ + public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + QPainter painter = getActivePainter(); + painter.setBrush(getBackground().getColor()); + //painter.setPen(getBackground().getColor()); + painter.setPen(PenStyle.NoPen); + painter.drawArc(x, y, width, height, startAngle, arcAngle); + } + + /** + * Fills the interior of the specified rectangle with a gradient sweeping + * from left to right or top to bottom progressing from the receiver's + * foreground color to its background color. + * + * @param x + * the x coordinate of the rectangle to be filled + * @param y + * the y coordinate of the rectangle to be filled + * @param width + * the width of the rectangle to be filled, may be negative + * (inverts direction of gradient if horizontal) + * @param height + * the height of the rectangle to be filled, may be negative + * (inverts direction of gradient if vertical) + * @param vertical + * if true sweeps from top to bottom, else sweeps from left to + * right + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #drawRectangle(int, int, int, int) + */ + public void fillGradientRectangle(int x, int y, int width, int height, boolean vertical) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (width == 0 || height == 0) { + return; + } + // if (true) { + // return; + // } + + QColor fromColor = getForeground().getColor(); + QColor toColor = getBackground().getColor(); + + 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) { + QColor tmp = fromColor; + fromColor = toColor; + toColor = tmp; + } + if (fromColor.equals(toColor)) { + fillRectangle(x, y, width, height); + return; + } + + QPointF p1 = new QPointF(), p2 = new QPointF(); + p1.setX(x); + p1.setY(y); + if (vertical) { + p2.setX(p1.x()); + p2.setY(p1.y() + height); + } else { + p2.setX(p1.x() + width); + p2.setY(p1.y()); + } + QPainter painter = getActivePainter(); + QLinearGradient fade = new QLinearGradient(p1, p2); + fade.setColorAt(0.0, fromColor); + fade.setColorAt(1.0, toColor); + QBrush brush = new QBrush(fade); + painter.fillRect(x, y, width, height, brush); + } + + /** + * 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 (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + QPainter painter = getActivePainter(); + painter.setBrush(getBackground().getColor()); + painter.setPen(getBackground().getColor()); + painter.drawEllipse(x, y, width, height); + } + + /** + * Fills the path described by the parameter. + * <p> + * This operation requires the operating system's advanced graphics + * subsystem which may not be available on some platforms. + * </p> + * + * @param path + * the path to fill + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the parameter has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are + * not available</li> + * </ul> + * + * @see Path + * + * @since 3.1 + */ + public void fillPath(Path path) { + //TODO + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (path == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (path.handle == 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + } + + /** + * 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 (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + validatePointArray(pointArray); + QPainter painter = getActivePainter(); + painter.setBrush(getBackground().getColor()); + painter.setPen(getBackground().getColor()); + painter.drawPolygon(createPolygonFromArray(pointArray), FillRule.WindingFill); + } + + private void validatePointArray(int[] pointArray) { + if (pointArray == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (pointArray.length % 2 != 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + + } + + public static QPolygon createPolygonFromArray(int[] pointArray) { + QPolygon polygon = new QPolygon(); + for (int i = 0; i < pointArray.length; i += 2) { + polygon.add(pointArray[i], pointArray[i + 1]); + } + return polygon; + } + + /** + * Fills the interior of the rectangle specified by the arguments, using the + * receiver's background color. + * + * @param x + * the x coordinate of the rectangle to be filled + * @param y + * the y coordinate of the rectangle to be filled + * @param width + * the width of the rectangle to be filled + * @param height + * the height of the rectangle to be filled + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #drawRectangle(int, int, int, int) + */ + public void fillRectangle(int x, int y, int width, int height) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + QPainter painter = getActivePainter(); + painter.fillRect(x, y, width, height, getBackground().getColor()); + } + + /** + * Fills the interior of the specified rectangle, using the receiver's + * background color. + * + * @param rect + * the rectangle to be filled + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #drawRectangle(int, int, int, int) + */ + public void fillRectangle(Rectangle rect) { + if (rect == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + fillRectangle(rect.x, rect.y, rect.width, rect.height); + } + + /** + * Fills the interior of the round-cornered rectangle specified by the + * arguments, using the receiver's background color. + * + * @param x + * the x coordinate of the rectangle to be filled + * @param y + * the y coordinate of the rectangle to be filled + * @param width + * the width of the rectangle to be filled + * @param height + * the height of the rectangle to be filled + * @param arcWidth + * the width of the arc + * @param arcHeight + * the height of the arc + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #drawRoundRectangle + */ + public void fillRoundRectangle(int x, int y, int width, int height, int arcWidth, int arcHeight) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + QPainter painter = getActivePainter(); + painter.setBrush(getBackground().getColor()); + painter.setPen(getBackground().getColor()); + painter.drawRoundedRect(x, y, width, height, arcWidth, arcHeight); + } + + void flush() { + } + + /** + * 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 (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + QPainter activePainter = getActivePainter(); + return activePainter.fontMetrics().width(ch); + // //checkGC(FONT); + // 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 receiver's alpha value. The alpha value is between 0 + * (transparent) and 255 (opaque). + * + * @return the alpha value + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.1 + */ + public int getAlpha() { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return data.alpha; + } + + /** + * Returns the receiver's anti-aliasing setting value, which will be one of + * <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or <code>SWT.ON</code>. + * Note that this controls anti-aliasing for all <em>non-text drawing</em> + * operations. + * + * @return the anti-aliasing setting + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #getTextAntialias + * + * @since 3.1 + */ + public int getAntialias() { + return antialias; + // if (handle == 0) { + // SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + // } + // if (data.gdipGraphics == 0) + // return SWT.DEFAULT; + // int mode = Gdip.Graphics_GetSmoothingMode(data.gdipGraphics); + // switch (mode) { + // case Gdip.SmoothingModeDefault: + // return SWT.DEFAULT; + // case Gdip.SmoothingModeHighSpeed: + // case Gdip.SmoothingModeNone: + // return SWT.OFF; + // case Gdip.SmoothingModeAntiAlias: + // case Gdip.SmoothingModeAntiAlias8x8: + // case Gdip.SmoothingModeHighQuality: + // return SWT.ON; + // } + // return SWT.DEFAULT; + } + + /** + * 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 (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return data.backgroundColor; + } + + /** + * Returns the background pattern. The default value is <code>null</code>. + * + * @return the receiver's background pattern + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see Pattern + * + * @since 3.1 + */ + public Pattern getBackgroundPattern() { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return data.backgroundPattern; + } + + /** + * 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) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + //checkGC(FONT); + // TODO + return 10; + } + + /** + * 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 (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + QPainter painter = getActivePainter(); + if (painter.hasClipping()) { + return QtSWTConverter.convert(painter.clipRegion()); + } else { + return new Rectangle(0, 0, paintDevice.width(), paintDevice.height()); + } + } + + /** + * Sets the region managed by the argument to the current clipping region of + * the receiver. + * + * @param region + * the region to fill with the clipping region + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the region is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the region is disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void getClipping(Region region) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (region == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (region.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + + QPainter painter = getActivePainter(); + Rectangle rect; + if (painter.hasClipping()) { + rect = QtSWTConverter.convert(painter.clipRegion()); + } else { + rect = new Rectangle(0, 0, paintDevice.width(), paintDevice.height()); + } + region.add(rect); + } + + /** + * Returns the receiver's fill rule, which will be one of + * <code>SWT.FILL_EVEN_ODD</code> or <code>SWT.FILL_WINDING</code>. + * + * @return the receiver's fill rule + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.1 + */ + public int getFillRule() { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (fillRule == null || fillRule.equals(FillRule.WindingFill)) { + return SWT.FILL_WINDING; + } + return SWT.FILL_EVEN_ODD; + } + + /** + * Sets the receiver's fill rule to the parameter, which must be one of + * <code>SWT.FILL_EVEN_ODD</code> or <code>SWT.FILL_WINDING</code>. + * + * @param rule + * the new fill rule + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the rule is not one of + * <code>SWT.FILL_EVEN_ODD</code> or + * <code>SWT.FILL_WINDING</code></li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.1 + */ + public void setFillRule(int rule) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + switch (rule) { + case SWT.FILL_WINDING: + fillRule = FillRule.WindingFill; + break; + case SWT.FILL_EVEN_ODD: + fillRule = FillRule.OddEvenFill; + break; + default: + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + } + + /** + * 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 (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return data.font; + } + + /** + * Returns a FontMetrics which contains information about the font currently + * being used by the receiver to draw and measure text. + * + * @return font metrics for the receiver's font + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public FontMetrics getFontMetrics() { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + //checkGC(FONT); + //if (!paintDevice.paintingActive()) { + return FontMetrics.internal_new(data.font); + // } + // QPainter painter = getActivePainter(); + // painter.setFont(data.font.getQFont()); + // try { + // return FontMetrics.internal_new(painter.fontMetrics()); + // } finally { + // painter.end(); + // } + + } + + /** + * 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 (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return data.foregroundColor; + } + + /** + * Returns the foreground pattern. The default value is <code>null</code>. + * + * @return the receiver's foreground pattern + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see Pattern + * + * @since 3.1 + */ + public Pattern getForegroundPattern() { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return data.foregroundPattern; + } + + /** + * Returns the GCData. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public API for + * <code>GC</code>. It is marked public only so that it can be shared within + * the packages provided by SWT. It is not available on all platforms, and + * should never be called from application code. + * </p> + * + * @return the receiver's GCData + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see GCData + * + * @since 3.2 + * @noreference This method is not intended to be referenced by clients. + */ + public GCData getGCData() { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return data; + } + + /** + * Returns the receiver's interpolation setting, which will be one of + * <code>SWT.DEFAULT</code>, <code>SWT.NONE</code>, <code>SWT.LOW</code> or + * <code>SWT.HIGH</code>. + * + * @return the receiver's interpolation setting + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.1 + */ + public int getInterpolation() { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return SWT.DEFAULT; + //TODO + // int mode = Gdip.Graphics_GetInterpolationMode(data.gdipGraphics); + // switch (mode) { + // case Gdip.InterpolationModeDefault: + // return SWT.DEFAULT; + // case Gdip.InterpolationModeNearestNeighbor: + // return SWT.NONE; + // case Gdip.InterpolationModeBilinear: + // case Gdip.InterpolationModeLowQuality: + // return SWT.LOW; + // case Gdip.InterpolationModeBicubic: + // case Gdip.InterpolationModeHighQualityBilinear: + // case Gdip.InterpolationModeHighQualityBicubic: + // case Gdip.InterpolationModeHighQuality: + // return SWT.HIGH; + // } + // return SWT.DEFAULT; + } + + /** + * Returns the receiver's line attributes. + * + * @return the line attributes used for drawing lines + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.3 + */ + public LineAttributes getLineAttributes() { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + float[] dashes = null; + if (data.lineDashes != null) { + dashes = new float[data.lineDashes.length]; + System.arraycopy(data.lineDashes, 0, dashes, 0, dashes.length); + } + return new LineAttributes(data.lineWidth, data.lineCap, data.lineJoin, data.lineStyle, dashes, + data.lineDashesOffset, data.lineMiterLimit); + } + + /** + * Returns the receiver's line cap style, which will be one of the constants + * <code>SWT.CAP_FLAT</code>, <code>SWT.CAP_ROUND</code>, or + * <code>SWT.CAP_SQUARE</code>. + * + * @return the cap style used for drawing lines + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.1 + */ + public int getLineCap() { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return data.lineCap; + } + + /** + * Returns the receiver's line dash style. The default value is + * <code>null</code>. + * + * @return the line dash style used for drawing lines + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.1 + */ + public int[] getLineDash() { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (data.lineDashes == null) { + return null; + } + int[] lineDashes = new int[data.lineDashes.length]; + for (int i = 0; i < lineDashes.length; i++) { + lineDashes[i] = (int) data.lineDashes[i]; + } + return lineDashes; + } + + /** + * Returns the receiver's line join style, which will be one of the + * constants <code>SWT.JOIN_MITER</code>, <code>SWT.JOIN_ROUND</code>, or + * <code>SWT.JOIN_BEVEL</code>. + * + * @return the join style used for drawing lines + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.1 + */ + public int getLineJoin() { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return data.lineJoin; + } + + /** + * Returns the receiver's line style, which will be one of the constants + * <code>SWT.LINE_SOLID</code>, <code>SWT.LINE_DASH</code>, + * <code>SWT.LINE_DOT</code>, <code>SWT.LINE_DASHDOT</code> or + * <code>SWT.LINE_DASHDOTDOT</code>. + * + * @return the style used for drawing lines + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public int getLineStyle() { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return data.lineStyle; + } + + /** + * Returns the width that will be used when drawing lines for all of the + * figure drawing operations (that is, <code>drawLine</code>, + * <code>drawRectangle</code>, <code>drawPolyline</code>, and so forth. + * + * @return the receiver's line width + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public int getLineWidth() { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return (int) data.lineWidth; + } + + /** + * Returns the receiver's style information. + * <p> + * Note that the value which is returned by this method <em>may + * not match</em> the value which was provided to the constructor when the + * receiver was created. This can occur when the underlying operating system + * does not support a particular combination of requested styles. + * </p> + * + * @return the style bits + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 2.1.2 + */ + public int getStyle() { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return data.style; + } + + /** + * Returns the receiver's text drawing anti-aliasing setting value, which + * will be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or + * <code>SWT.ON</code>. Note that this controls anti-aliasing <em>only</em> + * for text drawing operations. + * + * @return the anti-aliasing setting + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #getAntialias + * + * @since 3.1 + */ + public int getTextAntialias() { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + // if (data.gdipGraphics == 0) + return SWT.DEFAULT; + // TODO + // int mode = Gdip.Graphics_GetTextRenderingHint(data.gdipGraphics); + // switch (mode) { + // case Gdip.TextRenderingHintSystemDefault: + // return SWT.DEFAULT; + // case Gdip.TextRenderingHintSingleBitPerPixel: + // case Gdip.TextRenderingHintSingleBitPerPixelGridFit: + // return SWT.OFF; + // case Gdip.TextRenderingHintAntiAlias: + // case Gdip.TextRenderingHintAntiAliasGridFit: + // case Gdip.TextRenderingHintClearTypeGridFit: + // return SWT.ON; + // } + // return SWT.DEFAULT; + } + + /** + * Sets the parameter to the transform that is currently being used by the + * receiver. + * + * @param transform + * the destination to copy the transform into + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the parameter has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see Transform + * + * @since 3.1 + */ + public void getTransform(Transform transform) { + //TODO + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (transform == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (transform.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + // int /* long */gdipGraphics = data.gdipGraphics; + // if (gdipGraphics != 0) { + // Gdip.Graphics_GetTransform(gdipGraphics, transform.handle); + // int /* long */identity = identity(); + // Gdip.Matrix_Invert(identity); + // Gdip.Matrix_Multiply(transform.handle, identity, Gdip.MatrixOrderAppend); + // Gdip.Matrix_delete(identity); + // } else { + // transform.setElements(1, 0, 0, 1, 0, 0); + // } + } + } + + /** + * Returns <code>true</code> if this GC is drawing in the mode where the + * resulting color in the destination is the <em>exclusive or</em> of the + * color values in the source and the destination, and <code>false</code> if + * it is drawing in the mode where the destination color is being replaced + * with the source color value. + * + * @return <code>true</code> true if the receiver is in XOR mode, and false + * otherwise + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public boolean getXORMode() { + //TODO + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + // int rop2 = 0; + // rop2 = OS.GetROP2(handle); + return false; //rop2 == OS.R2_XORPEN; + } + + /** + * If the argument is <code>true</code>, puts the receiver in a drawing mode + * where the resulting color in the destination is the <em>exclusive or</em> + * of the color values in the source and the destination, and if the + * argument is <code>false</code>, puts the receiver in a drawing mode where + * the destination color is replaced with the source color value. + * <p> + * Note that this mode in fundamentally unsupportable on certain platforms, + * notably Carbon (Mac OS X). Clients that want their code to run on all + * platforms need to avoid this method. + * </p> + * + * @param xor + * if <code>true</code>, then <em>xor</em> mode is used, + * otherwise <em>source copy</em> mode is used + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @deprecated this functionality is not supported on some platforms + */ + @Deprecated + public void setXORMode(boolean xor) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + //TODO + //OS.SetROP2(handle, xor ? OS.R2_XORPEN : OS.R2_COPYPEN); + } + + /** + * Returns an integer hash code for the receiver. Any two objects that + * return <code>true</code> when passed to <code>equals</code> must return + * the same value for this method. + * + * @return the receiver's hash + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #equals + */ + @Override + public int hashCode() { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return paintDevice.hashCode(); + } + + /** + * 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 (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return activeClipping != null; + } + + /** + * Returns <code>true</code> if the GC has been disposed, and + * <code>false</code> otherwise. + * <p> + * This method gets the dispose state for the GC. When a GC has been + * disposed, it is an error to invoke any other method using the GC. + * + * @return <code>true</code> when the GC is disposed and <code>false</code> + * otherwise + */ + @Override + public boolean isDisposed() { + return paintDevice == null; + } + + /** + * Sets the receiver to always use the operating system's advanced graphics + * subsystem for all graphics operations if the argument is + * <code>true</code>. If the argument is <code>false</code>, the advanced + * graphics subsystem is no longer used, advanced graphics state is cleared + * and the normal graphics subsystem is used from now on. + * <p> + * Normally, the advanced graphics subsystem is invoked automatically when + * any one of the alpha, antialias, patterns, interpolation, paths, clipping + * or transformation operations in the receiver is requested. When the + * receiver is switched into advanced mode, the advanced graphics subsystem + * performs both advanced and normal graphics operations. Because the two + * subsystems are different, their output may differ. Switching to advanced + * graphics before any graphics operations are performed ensures that the + * output is consistent. + * </p> + * <p> + * Advanced graphics may not be installed for the operating system. In this + * case, this operation does nothing. Some operating system have only one + * graphics subsystem, so switching from normal to advanced graphics does + * nothing. However, switching from advanced to normal graphics will always + * clear the advanced graphics state, even for operating systems that have + * only one graphics subsystem. + * </p> + * + * @param advanced + * the new advanced graphics state + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #setAlpha + * @see #setAntialias + * @see #setBackgroundPattern + * @see #setClipping(Path) + * @see #setForegroundPattern + * @see #setLineAttributes + * @see #setInterpolation + * @see #setTextAntialias + * @see #setTransform + * @see #getAdvanced + * + * @since 3.1 + */ + public void setAdvanced(boolean advanced) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + } + + /** + * Returns <code>true</code> if receiver is using the operating system's + * advanced graphics subsystem. Otherwise, <code>false</code> is returned to + * indicate that normal graphics are in use. + * <p> + * Advanced graphics may not be installed for the operating system. In this + * case, <code>false</code> is always returned. Some operating system have + * only one graphics subsystem. If this subsystem supports advanced + * graphics, then <code>true</code> is always returned. If any graphics + * operation such as alpha, antialias, patterns, interpolation, paths, + * clipping or transformation has caused the receiver to switch from regular + * to advanced graphics mode, <code>true</code> is returned. If the receiver + * has been explicitly switched to advanced mode and this mode is supported, + * <code>true</code> is returned. + * </p> + * + * @return the advanced value + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #setAdvanced + * + * @since 3.1 + */ + public boolean getAdvanced() { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + // Qt is Advanced :) + return true; + } + + /** + * Sets the receiver's anti-aliasing value to the parameter, which must be + * one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or + * <code>SWT.ON</code>. Note that this controls anti-aliasing for all + * <em>non-text drawing</em> operations. + * <p> + * This operation requires the operating system's advanced graphics + * subsystem which may not be available on some platforms. + * </p> + * + * @param antialias + * the anti-aliasing setting + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the parameter is not one + * of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or + * <code>SWT.ON</code></li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are + * not available</li> + * </ul> + * + * @see #getAdvanced + * @see #setAdvanced + * @see #setTextAntialias + * + * @since 3.1 + */ + public void setAntialias(int antialias) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + this.antialias = antialias; + // if (handle == 0) { + // SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + // TODO + // if (data.gdipGraphics == 0 && antialias == SWT.DEFAULT) + // return; + // int mode = 0; + // switch (antialias) { + // case SWT.DEFAULT: + // mode = Gdip.SmoothingModeDefault; + // break; + // case SWT.OFF: + // mode = Gdip.SmoothingModeNone; + // break; + // case SWT.ON: + // mode = Gdip.SmoothingModeAntiAlias; + // break; + // default: + // SWT.error(SWT.ERROR_INVALID_ARGUMENT); + // } + // } + } + + /** + * Sets the receiver's alpha value which must be between 0 (transparent) and + * 255 (opaque). + * <p> + * This operation requires the operating system's advanced graphics + * subsystem which may not be available on some platforms. + * </p> + * + * @param alpha + * the alpha value + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are + * not available</li> + * </ul> + * + * @see #getAdvanced + * @see #setAdvanced + * + * @since 3.1 + */ + public void setAlpha(int alpha) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + //TODO + data.alpha = alpha & 0xFF; + data.state &= ~(BACKGROUND | FOREGROUND); + } + + /** + * 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 (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (color == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (color.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (data.backgroundPattern == null && data.backgroundColor.equals(color)) { + return; + } + data.backgroundPattern = null; + data.backgroundColor = color; + data.state &= ~(BACKGROUND | BACKGROUND_TEXT); + } + + /** + * Sets the background pattern. The default value is <code>null</code>. + * <p> + * This operation requires the operating system's advanced graphics + * subsystem which may not be available on some platforms. + * </p> + * + * @param pattern + * the new background pattern + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the parameter has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are + * not available</li> + * </ul> + * + * @see Pattern + * @see #getAdvanced + * @see #setAdvanced + * + * @since 3.1 + */ + public void setBackgroundPattern(Pattern pattern) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (pattern != null && pattern.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (data.backgroundPattern == pattern) { + return; + } + data.backgroundPattern = pattern; + data.state &= ~BACKGROUND; + } + + /** + * Sets the area of the receiver which can be changed by drawing operations + * to the rectangular area specified by the arguments. + * + * @param x + * the x coordinate of the clipping rectangle + * @param y + * the y coordinate of the clipping rectangle + * @param width + * the width of the clipping rectangle + * @param height + * the height of the clipping rectangle + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void setClipping(int x, int y, int width, int height) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + activeClipping = new QRegion(x, y, width, height); + } + + /** + * Sets the area of the receiver which can be changed by drawing operations + * to the path specified by the argument. + * <p> + * This operation requires the operating system's advanced graphics + * subsystem which may not be available on some platforms. + * </p> + * + * @param path + * the clipping path. + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the path has been disposed + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are + * not available</li> + * </ul> + * + * @see Path + * @see #getAdvanced + * @see #setAdvanced + * + * @since 3.1 + */ + public void setClipping(Path path) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (path != null && path.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (path == null) { + activeClipping = null; + } + //TODO + } + + /** + * Sets the area of the receiver which can be changed by drawing operations + * to the rectangular area specified by the argument. Specifying + * <code>null</code> for the rectangle reverts the receiver's clipping area + * to its original value. + * + * @param rect + * the clipping rectangle or <code>null</code> + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void setClipping(Rectangle rect) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (rect != null) { + activeClipping = new QRegion(rect.x, rect.y, rect.width, rect.height); + } else { + activeClipping = null; + } + } + + /** + * Sets the area of the receiver which can be changed by drawing operations + * to the region specified by the argument. Specifying <code>null</code> for + * the region reverts the receiver's clipping area to its original value. + * + * @param region + * the clipping region or <code>null</code> + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the region has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void setClipping(Region region) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (region != null && region.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (region != null) { + activeClipping = region.getQRegion(); + } else { + activeClipping = null; + } + } + + /** + * 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 (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (font != null && font.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + data.font = font != null ? font : data.device.getSystemFont(); + data.state &= ~FONT; + } + + /** + * Sets the foreground color. The foreground color is used for drawing + * operations including when text is drawn. + * + * @param color + * the new foreground color for the receiver + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the color is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the color has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void setForeground(Color color) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (color == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (color.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (data.foregroundPattern == null && color.equals(data.foregroundColor)) { + return; + } + data.foregroundPattern = null; + data.foregroundColor = color; + data.state &= ~(FOREGROUND | FOREGROUND_TEXT); + } + + /** + * Sets the foreground pattern. The default value is <code>null</code>. + * <p> + * This operation requires the operating system's advanced graphics + * subsystem which may not be available on some platforms. + * </p> + * + * @param pattern + * the new foreground pattern + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the parameter has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are + * not available</li> + * </ul> + * + * @see Pattern + * @see #getAdvanced + * @see #setAdvanced + * + * @since 3.1 + */ + public void setForegroundPattern(Pattern pattern) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (pattern != null && pattern.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + // if (data.gdipGraphics == 0 && pattern == null) + // return; + // initGdip(); + if (data.foregroundPattern == pattern) { + return; + } + data.foregroundPattern = pattern; + data.state &= ~FOREGROUND; + } + + /** + * Sets the receiver's interpolation setting to the parameter, which must be + * one of <code>SWT.DEFAULT</code>, <code>SWT.NONE</code>, + * <code>SWT.LOW</code> or <code>SWT.HIGH</code>. + * <p> + * This operation requires the operating system's advanced graphics + * subsystem which may not be available on some platforms. + * </p> + * + * @param interpolation + * the new interpolation setting + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the rule is not one of + * <code>SWT.DEFAULT</code>, <code>SWT.NONE</code>, + * <code>SWT.LOW</code> or <code>SWT.HIGH</code> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are + * not available</li> + * </ul> + * + * @see #getAdvanced + * @see #setAdvanced + * + * @since 3.1 + */ + public void setInterpolation(int interpolation) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + //TODO + //if (data.gdipGraphics == 0 && interpolation == SWT.DEFAULT) + // int mode = 0; + // switch (interpolation) { + // case SWT.DEFAULT: + // mode = Gdip.InterpolationModeDefault; + // break; + // case SWT.NONE: + // mode = Gdip.InterpolationModeNearestNeighbor; + // break; + // case SWT.LOW: + // mode = Gdip.InterpolationModeLowQuality; + // break; + // case SWT.HIGH: + // mode = Gdip.InterpolationModeHighQuality; + // break; + // default: + // SWT.error(SWT.ERROR_INVALID_ARGUMENT); + // } + // initGdip(); + //Gdip.Graphics_SetInterpolationMode(data.gdipGraphics, mode); + } + + /** + * Sets the receiver's line attributes. + * <p> + * This operation requires the operating system's advanced graphics + * subsystem which may not be available on some platforms. + * </p> + * + * @param attributes + * the line attributes + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the attributes is null</li> + * <li>ERROR_INVALID_ARGUMENT - if any of the line attributes + * is not valid</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are + * not available</li> + * </ul> + * + * @see LineAttributes + * @see #getAdvanced + * @see #setAdvanced + * + * @since 3.3 + */ + public void setLineAttributes(LineAttributes attributes) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (attributes == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + int mask = 0; + float lineWidth = attributes.width; + if (lineWidth != data.lineWidth) { + mask |= LINE_WIDTH | DRAW_OFFSET; + } + int lineStyle = attributes.style; + if (lineStyle != data.lineStyle) { + mask |= LINE_STYLE; + switch (lineStyle) { + case SWT.LINE_SOLID: + case SWT.LINE_DASH: + case SWT.LINE_DOT: + case SWT.LINE_DASHDOT: + case SWT.LINE_DASHDOTDOT: + break; + case SWT.LINE_CUSTOM: + if (attributes.dash == null) { + lineStyle = SWT.LINE_SOLID; + } + break; + default: + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + } + int join = attributes.join; + if (join != data.lineJoin) { + mask |= LINE_JOIN; + switch (join) { + case SWT.CAP_ROUND: + case SWT.CAP_FLAT: + case SWT.CAP_SQUARE: + break; + default: + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + } + int cap = attributes.cap; + if (cap != data.lineCap) { + mask |= LINE_CAP; + switch (cap) { + case SWT.JOIN_MITER: + case SWT.JOIN_ROUND: + case SWT.JOIN_BEVEL: + break; + default: + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + } + float[] dashes = attributes.dash; + float[] lineDashes = data.lineDashes; + if (dashes != null && dashes.length > 0) { + boolean changed = lineDashes == null || lineDashes.length != dashes.length; + for (int i = 0; i < dashes.length; i++) { + float dash = dashes[i]; + if (dash <= 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (!changed && lineDashes[i] != dash) { + changed = true; + } + } + if (changed) { + float[] newDashes = new float[dashes.length]; + System.arraycopy(dashes, 0, newDashes, 0, dashes.length); + dashes = newDashes; + mask |= LINE_STYLE; + } else { + dashes = lineDashes; + } + } else { + if (lineDashes != null && lineDashes.length > 0) { + mask |= LINE_STYLE; + } else { + dashes = lineDashes; + } + } + float dashOffset = attributes.dashOffset; + if (dashOffset != data.lineDashesOffset) { + mask |= LINE_STYLE; + } + float miterLimit = attributes.miterLimit; + if (miterLimit != data.lineMiterLimit) { + mask |= LINE_MITERLIMIT; + } + // initGdip(); + if (mask == 0) { + return; + } + data.lineWidth = lineWidth; + data.lineStyle = lineStyle; + data.lineCap = cap; + data.lineJoin = join; + data.lineDashes = dashes; + data.lineDashesOffset = dashOffset; + data.lineMiterLimit = miterLimit; + data.state &= ~mask; + } + + /** + * Sets the receiver's line cap style to the argument, which must be one of + * the constants <code>SWT.CAP_FLAT</code>, <code>SWT.CAP_ROUND</code>, or + * <code>SWT.CAP_SQUARE</code>. + * + * @param cap + * the cap style to be used for drawing lines + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.1 + */ + public void setLineCap(int cap) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + if (data.lineCap == cap) { + return; + } + switch (cap) { + case SWT.CAP_ROUND: + case SWT.CAP_FLAT: + case SWT.CAP_SQUARE: + break; + default: + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + data.lineCap = cap; + data.state &= ~LINE_CAP; + } + + /** + * Sets the receiver's line dash style to the argument. The default value is + * <code>null</code>. If the argument is not <code>null</code>, the + * receiver's line style is set to <code>SWT.LINE_CUSTOM</code>, otherwise + * it is set to <code>SWT.LINE_SOLID</code>. + * + * @param dashes + * the dash style to be used for drawing lines + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if any of the values in the + * array is less than or equal 0</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.1 + */ + public void setLineDash(int[] dashes) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + float[] lineDashes = data.lineDashes; + if (dashes != null && dashes.length > 0) { + boolean changed = data.lineStyle != SWT.LINE_CUSTOM || lineDashes == null + || lineDashes.length != dashes.length; + for (int i = 0; i < dashes.length; i++) { + int dash = dashes[i]; + if (dash <= 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (!changed && lineDashes[i] != dash) { + changed = true; + } + } + if (!changed) { + return; + } + data.lineDashes = new float[dashes.length]; + for (int i = 0; i < dashes.length; i++) { + data.lineDashes[i] = dashes[i]; + } + data.lineStyle = SWT.LINE_CUSTOM; + } else { + if (data.lineStyle == SWT.LINE_SOLID && (lineDashes == null || lineDashes.length == 0)) { + return; + } + data.lineDashes = null; + data.lineStyle = SWT.LINE_SOLID; + } + data.state &= ~LINE_STYLE; + } + + /** + * Sets the receiver's line join style to the argument, which must be one of + * the constants <code>SWT.JOIN_MITER</code>, <code>SWT.JOIN_ROUND</code>, + * or <code>SWT.JOIN_BEVEL</code>. + * + * @param join + * the join style to be used for drawing lines + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.1 + */ + public void setLineJoin(int join) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (data.lineJoin == join) { + return; + } + switch (join) { + case SWT.JOIN_MITER: + case SWT.JOIN_ROUND: + case SWT.JOIN_BEVEL: + break; + default: + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + data.lineJoin = join; + data.state &= ~LINE_JOIN; + } + + /** + * Sets the receiver's line style to the argument, which must be one of the + * constants <code>SWT.LINE_SOLID</code>, <code>SWT.LINE_DASH</code>, + * <code>SWT.LINE_DOT</code>, <code>SWT.LINE_DASHDOT</code> or + * <code>SWT.LINE_DASHDOTDOT</code>. + * + * @param lineStyle + * the style to be used for drawing lines + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void setLineStyle(int lineStyle) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (data.lineStyle == lineStyle) { + return; + } + switch (lineStyle) { + case SWT.LINE_SOLID: + case SWT.LINE_DASH: + case SWT.LINE_DOT: + case SWT.LINE_DASHDOT: + case SWT.LINE_DASHDOTDOT: + break; + case SWT.LINE_CUSTOM: + if (data.lineDashes == null) { + lineStyle = SWT.LINE_SOLID; + } + break; + default: + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + data.lineStyle = lineStyle; + data.state &= ~LINE_STYLE; + } + + /** + * Sets the width that will be used when drawing lines for all of the figure + * drawing operations (that is, <code>drawLine</code>, + * <code>drawRectangle</code>, <code>drawPolyline</code>, and so forth. + * <p> + * Note that line width of zero is used as a hint to indicate that the + * fastest possible line drawing algorithms should be used. This means that + * the output may be different from line width one. + * </p> + * + * @param lineWidth + * the width of a line + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void setLineWidth(int lineWidth) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + if (data.lineWidth == lineWidth) { + return; + } + data.lineWidth = lineWidth; + data.state &= ~(LINE_WIDTH | DRAW_OFFSET); + } + + /** + * Sets the receiver's text anti-aliasing value to the parameter, which must + * be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or + * <code>SWT.ON</code>. Note that this controls anti-aliasing only for all + * <em>text drawing</em> operations. + * <p> + * This operation requires the operating system's advanced graphics + * subsystem which may not be available on some platforms. + * </p> + * + * @param antialias + * the anti-aliasing setting + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the parameter is not one + * of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or + * <code>SWT.ON</code></li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are + * not available</li> + * </ul> + * + * @see #getAdvanced + * @see #setAdvanced + * @see #setAntialias + * + * @since 3.1 + */ + public void setTextAntialias(int antialias) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + //TODO + // if (data.gdipGraphics == 0 && antialias == SWT.DEFAULT) + // return; + // int textMode = 0; + // switch (antialias) { + // case SWT.DEFAULT: + // textMode = Gdip.TextRenderingHintSystemDefault; + // break; + // case SWT.OFF: + // textMode = Gdip.TextRenderingHintSingleBitPerPixelGridFit; + // break; + // case SWT.ON: + // int[] type = new int[1]; + // OS.SystemParametersInfo(OS.SPI_GETFONTSMOOTHINGTYPE, 0, type, 0); + // if (type[0] == OS.FE_FONTSMOOTHINGCLEARTYPE) { + // textMode = Gdip.TextRenderingHintClearTypeGridFit; + // } else { + // textMode = Gdip.TextRenderingHintAntiAliasGridFit; + // } + // break; + // default: + // SWT.error(SWT.ERROR_INVALID_ARGUMENT); + // } + // // initGdip(); + // Gdip.Graphics_SetTextRenderingHint(data.gdipGraphics, textMode); + } + + /** + * Sets the transform that is currently being used by the receiver. If the + * argument is <code>null</code>, the current transform is set to the + * identity transform. + * <p> + * This operation requires the operating system's advanced graphics + * subsystem which may not be available on some platforms. + * </p> + * + * @param transform + * the transform to set + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the parameter has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are + * not available</li> + * </ul> + * + * @see Transform + * @see #getAdvanced + * @see #setAdvanced + * + * @since 3.1 + */ + public void setTransform(Transform transform) { + //TODO + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (transform != null && transform.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + // if (data.gdipGraphics == 0 && transform == null) + // return; + // // initGdip(); + // int /* long */identity = identity(); + // if (transform != null) { + // Gdip.Matrix_Multiply(identity, transform.handle, Gdip.MatrixOrderPrepend); + // } + // Gdip.Graphics_SetTransform(data.gdipGraphics, identity); + // Gdip.Matrix_delete(identity); + // data.state &= ~DRAW_OFFSET; + } + } + + /** + * Returns the extent of the given string. No tab expansion or carriage + * return processing will be performed. + * <p> + * The <em>extent</em> of a string is the width and height of the + * rectangular area it would cover if drawn in a particular font (in this + * case, the current font in the receiver). + * </p> + * + * @param string + * the string to measure + * @return a point containing the extent of the string + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public Point stringExtent(String string) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + + return _textExtent(getActivePainter(), string, 0); + } + + /** + * Returns the extent of the given string. Tab expansion and carriage return + * processing are performed. + * <p> + * The <em>extent</em> of a string is the width and height of the + * rectangular area it would cover if drawn in a particular font (in this + * case, the current font in the receiver). + * </p> + * + * @param string + * the string to measure + * @return a point containing the extent of the string + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public Point textExtent(String string) { + return textExtent(string, SWT.DRAW_DELIMITER | SWT.DRAW_TAB); + } + + /** + * Returns the extent of the given string. Tab expansion, line delimiter and + * mnemonic processing are performed according to the specified flags, which + * can be a combination of: + * <dl> + * <dt><b>DRAW_DELIMITER</b></dt> + * <dd>draw multiple lines</dd> + * <dt><b>DRAW_TAB</b></dt> + * <dd>expand tabs</dd> + * <dt><b>DRAW_MNEMONIC</b></dt> + * <dd>underline the mnemonic character</dd> + * <dt><b>DRAW_TRANSPARENT</b></dt> + * <dd>transparent background</dd> + * </dl> + * <p> + * The <em>extent</em> of a string is the width and height of the + * rectangular area it would cover if drawn in a particular font (in this + * case, the current font in the receiver). + * </p> + * + * @param string + * the string to measure + * @param flags + * the flags specifying how to process the text + * @return a point containing the extent of the string + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public Point textExtent(String string, int flags) { + if (paintDevice == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (string == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + QPainter painter = getActivePainter(); + return _textExtent(painter, string, flags); + } + + private Point _textExtent(QPainter painter, String string, int flags) { + int qFlags = translateTextFlags(flags); + painter.setFont(data.font.getQFont()); + QRect rect = painter.boundingRect((QRect) null, qFlags, string); + //System.out.println("textExtent: " + string + " -> " + rect.width() + "x" + rect.height()); + return new Point(rect.width(), rect.height()); + } + + /** + * 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> + */ + public static GC qt_new(Drawable drawable, GCData data) { + GC gc = new GC(); + QPaintDeviceInterface paintDevice = drawable.internal_new_GC(data); + gc.device = data.device; + gc.init(drawable, data, paintDevice); + return gc; + } + + /** + * Invokes platform specific functionality to wrap a 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 hDC + * the Windows HDC. + * @param data + * the data for the receiver. + * + * @return a new <code>GC</code> + */ + public static GC qt_new(Drawable drawable, QPaintDeviceInterface paintDevice, GCData data) { + GC gc = new GC(); + gc.device = data.device; + gc.init(drawable, data, paintDevice); + return gc; + } + + /** + * Returns a string containing a concise, human-readable description of the + * receiver. + * + * @return a string representation of the receiver + */ + @Override + public String toString() { + if (isDisposed()) { + return "GC {*DISPOSED*}"; //$NON-NLS-1$ + } + return "GC {" + paintDevice + "}"; //$NON-NLS-1$ //$NON-NLS-2$ + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/GCData.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/GCData.java new file mode 100644 index 0000000000..a5050c0fdd --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/GCData.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import org.eclipse.swt.SWT; + +/** + * Instances of this class are descriptions of GCs in terms of unallocated + * platform-specific data fields. + * <p> + * <b>IMPORTANT:</b> This class is <em>not</em> part of the public API for SWT. + * It is marked public only so that it can be shared within the packages + * provided by SWT. It is not available on all platforms, and should never be + * called from application code. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noinstantiate This class is not intended to be instantiated by clients. + */ + +public final class GCData { + public Device device; + public int style, state = -1; + public Color foregroundColor = null; + public Color backgroundColor = null; + public Font font; + public Pattern foregroundPattern; + public Pattern backgroundPattern; + public int lineStyle = SWT.LINE_SOLID; + public float lineWidth; + public int lineCap = SWT.CAP_FLAT; + public int lineJoin = SWT.JOIN_MITER; + public float lineDashesOffset; + public float[] lineDashes; + public float lineMiterLimit = 10; + public int alpha = 0xFF; + public Image image; + public int layout = -1; + public int uiState = 0; + public boolean focusDrawn; + public int handle; +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Image.java new file mode 100644 index 0000000000..fe3374b526 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Image.java @@ -0,0 +1,978 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import java.io.InputStream; +import java.util.Arrays; +import java.util.List; + +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.gui.QIcon; +import com.trolltech.qt.gui.QImage; +import com.trolltech.qt.gui.QPaintDeviceInterface; +import com.trolltech.qt.gui.QPixmap; +import com.trolltech.qt.gui.QImage.Format; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTError; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.widgets.Display; + +/** + * Instances of this class are graphics which have been prepared for display on + * a specific device. That is, they are ready to paint using methods such as + * <code>GC.drawImage()</code> and display on widgets with, for example, + * <code>Button.setImage()</code>. + * <p> + * If loaded from a file format that supports it, an <code>Image</code> may have + * transparency, meaning that certain pixels are specified as being transparent + * when drawn. Examples of file formats that support transparency are GIF and + * PNG. + * </p> + * <p> + * There are two primary ways to use <code>Images</code>. The first is to load a + * graphic file from disk and create an <code>Image</code> from it. This is done + * using an <code>Image</code> constructor, for example: + * + * <pre> + * Image i = new Image(device, "C:\\graphic.bmp"); + * </pre> + * + * A graphic file may contain a color table specifying which colors the image + * was intended to possess. In the above example, these colors will be mapped to + * the closest available color in SWT. It is possible to get more control over + * the mapping of colors as the image is being created, using code of the form: + * + * <pre> + * ImageData data = new ImageData("C:\\graphic.bmp"); + * RGB[] rgbs = data.getRGBs(); + * // At this point, rgbs contains specifications of all + * // the colors contained within this image. You may + * // allocate as many of these colors as you wish by + * // using the Color constructor Color(RGB), then + * // create the image: + * Image i = new Image(device, data); + * </pre> + * <p> + * Applications which require even greater control over the image loading + * process should use the support provided in class <code>ImageLoader</code>. + * </p> + * <p> + * Application code must explicitly invoke the <code>Image.dispose()</code> + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + * </p> + * + * @see Color + * @see ImageData + * @see ImageLoader + * @see <a href="http://www.eclipse.org/swt/snippets/#image">Image snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: + * GraphicsExample, ImageAnalyzer</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + */ +public final class Image extends Resource implements Drawable { + + /** + * specifies whether the receiver is a bitmap or an icon (one of + * <code>SWT.BITMAP</code>, <code>SWT.ICON</code>) + */ + private int type = SWT.BITMAP; + + private int transparentPixel = -1; + + /** + * The GC the image is currently selected in. + */ + private GC memGC; + + /** + * The global alpha value to be used for every pixel. + */ + private int alpha = -1; + + private boolean hasMask = false; + + //private QImage image; + private QIcon icon; + private QPixmap pixmap; + + Image(Device device) { + super(device); + } + + /** + * Constructs an empty instance of this class with the specified width and + * height. The result may be drawn upon by creating a GC and using any of + * its drawing operations, as shown in the following example: + * + * <pre> + * Image i = new Image(device, width, height); + * GC gc = new GC(i); + * gc.drawRectangle(0, 0, 50, 50); + * gc.dispose(); + * </pre> + * <p> + * Note: Some platforms may have a limitation on the size of image that can + * be created (size depends on width, height, and depth). For example, + * Windows 95, 98, and ME do not allow images larger than 16M. + * </p> + * + * @param device + * the device on which to create the image + * @param width + * the width of the new image + * @param height + * the height of the new image + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is + * no current device</li> + * <li>ERROR_INVALID_ARGUMENT - if either the width or height + * is negative or zero</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for + * image creation</li> + * </ul> + */ + public Image(Device device, int width, int height) { + super(device); + init(width, height); + init(); + } + + /** + * Constructs a new instance of this class based on the provided image, with + * an appearance that varies depending on the value of the flag. The + * possible flag values are: + * <dl> + * <dt><b>{@link SWT#IMAGE_COPY}</b></dt> + * <dd>the result is an identical copy of srcImage</dd> + * <dt><b>{@link SWT#IMAGE_DISABLE}</b></dt> + * <dd>the result is a copy of srcImage which has a <em>disabled</em> look</dd> + * <dt><b>{@link SWT#IMAGE_GRAY}</b></dt> + * <dd>the result is a copy of srcImage which has a <em>gray scale</em> look + * </dd> + * </dl> + * + * @param device + * the device on which to create the image + * @param srcImage + * the image to use as the source + * @param flag + * the style, either <code>IMAGE_COPY</code>, + * <code>IMAGE_DISABLE</code> or <code>IMAGE_GRAY</code> + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is + * no current device</li> + * <li>ERROR_NULL_ARGUMENT - if srcImage is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the flag is not one of + * <code>IMAGE_COPY</code>, <code>IMAGE_DISABLE</code> or + * <code>IMAGE_GRAY</code></li> + * <li>ERROR_INVALID_ARGUMENT - if the image has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or + * an icon, or is otherwise in an invalid state</li> + * <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the image is + * not supported</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for + * image creation</li> + * </ul> + */ + public Image(Device device, Image srcImage, int flag) { + super(device); + if (srcImage == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (srcImage.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + device = this.device; + this.type = srcImage.type; + switch (flag) { + case SWT.IMAGE_COPY: + this.pixmap = new QPixmap(srcImage.pixmap); + break; + case SWT.IMAGE_DISABLE: + this.pixmap = createDisabledImage(srcImage); + break; + case SWT.IMAGE_GRAY: + this.pixmap = createGrayImage(srcImage); + break; + default: + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + init(); + } + + /** + * Constructs an empty instance of this class with the width and height of + * the specified rectangle. The result may be drawn upon by creating a GC + * and using any of its drawing operations, as shown in the following + * example: + * + * <pre> + * Image i = new Image(device, boundsRectangle); + * GC gc = new GC(i); + * gc.drawRectangle(0, 0, 50, 50); + * gc.dispose(); + * </pre> + * <p> + * Note: Some platforms may have a limitation on the size of image that can + * be created (size depends on width, height, and depth). For example, + * Windows 95, 98, and ME do not allow images larger than 16M. + * </p> + * + * @param device + * the device on which to create the image + * @param bounds + * a rectangle specifying the image's width and height (must not + * be null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is + * no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the bounds rectangle is null</li> + * <li>ERROR_INVALID_ARGUMENT - if either the rectangle's + * width or height is negative</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for + * image creation</li> + * </ul> + */ + public Image(Device device, Rectangle bounds) { + super(device); + if (bounds == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + init(bounds.width, bounds.height); + init(); + } + + /** + * Constructs an instance of this class from the given + * <code>ImageData</code>. + * + * @param device + * the device on which to create the image + * @param data + * the image data to create the image from (must not be null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is + * no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the image data is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the + * ImageData is not supported</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for + * image creation</li> + * </ul> + */ + public Image(Device device, ImageData data) { + super(device); + init(data); + init(); + } + + /** + * Constructs an instance of this class, whose type is <code>SWT.ICON</code> + * , from the two given <code>ImageData</code> objects. The two images must + * be the same size. Pixel transparency in either image will be ignored. + * <p> + * The mask image should contain white wherever the icon is to be visible, + * and black wherever the icon is to be transparent. In addition, the source + * image should contain black wherever the icon is to be transparent. + * </p> + * + * @param device + * the device on which to create the icon + * @param source + * the color data for the icon + * @param mask + * the mask data for the icon + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is + * no current device</li> + * <li>ERROR_NULL_ARGUMENT - if either the source or mask is + * null</li> + * <li>ERROR_INVALID_ARGUMENT - if source and mask are + * different sizes</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for + * image creation</li> + * </ul> + */ + public Image(Device device, ImageData source, ImageData mask) { + super(device); + if (source == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (mask == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (source.width != mask.width || source.height != mask.height) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + mask = ImageData.convertMask(mask); + ImageData image = new ImageData(source.width, source.height, source.depth, source.palette, source.scanlinePad, + source.data); + image.maskPad = mask.scanlinePad; + image.maskData = mask.data; + init(image); + } + + /** + * Constructs an instance of this class by loading its representation from + * the specified input stream. Throws an error if an error occurs while + * loading the image, or if the result is an image of an unsupported type. + * Application code is still responsible for closing the input stream. + * <p> + * This constructor is provided for convenience when loading a single image + * only. If the stream contains multiple images, only the first one will be + * loaded. To load multiple images, use <code>ImageLoader.load()</code>. + * </p> + * <p> + * This constructor may be used to load a resource as follows: + * </p> + * + * <pre> + * static Image loadImage(Display display, Class clazz, String string) { + * InputStream stream = clazz.getResourceAsStream(string); + * if (stream == null) + * return null; + * Image image = null; + * try { + * image = new Image(display, stream); + * } catch (SWTException ex) { + * } finally { + * try { + * stream.close(); + * } catch (IOException ex) { + * } + * } + * return image; + * } + * </pre> + * + * @param device + * the device on which to create the image + * @param stream + * the input stream to load the image from + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is + * no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the stream is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_IO - if an IO error occurs while reading from + * the stream</li> + * <li>ERROR_INVALID_IMAGE - if the image stream contains + * invalid data</li> + * <li>ERROR_UNSUPPORTED_DEPTH - if the image stream + * describes an image with an unsupported depth</li> + * <li>ERROR_UNSUPPORTED_FORMAT - if the image stream + * contains an unrecognized format</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for + * image creation</li> + * </ul> + */ + public Image(Device device, InputStream stream) { + super(device); + init(new ImageData(stream)); + init(); + } + + /** + * Constructs an instance of this class by loading its representation from + * the file with the specified name. Throws an error if an error occurs + * while loading the image, or if the result is an image of an unsupported + * type. + * <p> + * This constructor is provided for convenience when loading a single image + * only. If the specified file contains multiple images, only the first one + * will be used. + * + * @param device + * the device on which to create the image + * @param filename + * the name of the file to load the image from + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is + * no current device</li> <li>ERROR_NULL_ARGUMENT - if the + * file name is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_IO - if an IO error occurs while reading from + * the file</li> <li>ERROR_INVALID_IMAGE - if the image file + * contains invalid data </li> <li>ERROR_UNSUPPORTED_DEPTH - + * if the image file describes an image with an unsupported + * depth</li> <li>ERROR_UNSUPPORTED_FORMAT - if the image + * file contains an unrecognized format</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for + * image creation</li> + * </ul> + */ + public Image(Device device, String filename) { + super(device); + if (filename == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + initNative(filename); + if (this.pixmap == null) { + init(new ImageData(filename)); + } + init(); + } + + void init(int width, int height) { + if (width <= 0 || height <= 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + this.type = SWT.BITMAP; + pixmap = new QPixmap(width, height); //, Format.Format_ARGB32 + } + + void init(ImageData imageData) { + if (imageData == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + + this.type = SWT.BITMAP; + + Format format = getImageFormat(imageData); + byte[] buffer = imageData2RawData(imageData, format); + QImage image = new QImage(buffer, imageData.width, imageData.height, format); + + if (imageData.colorTable != null) { + image.setColorTable(imageData.colorTable); + } + + if (imageData.maskData != null) { + hasMask = true; + } + updateAlphaChannel(image, imageData); + + pixmap = QPixmap.fromImage(image); + + try { + this.transparentPixel = getTransparentPixel(imageData); + } catch (Error e) { + pixmap = null; + throw e; + } + } + + private Format getImageFormat(ImageData imageData) { + switch (imageData.depth) { + case 32: + return Format.Format_ARGB32; + case 24: + return Format.Format_RGB888; + case 16: + return Format.Format_RGB16; + case 8: + case 4: + return Format.Format_Indexed8; + case 1: + return Format.Format_Mono; + default: + throw new RuntimeException("invalid color depth"); //$NON-NLS-1$ + } + } + + private void updateAlphaChannel(QImage image, ImageData imageData) { + Format format = null; + byte[] data = null; + if (imageData.maskData != null) { + // Mask data is 1 bit/pixel + data = imageData.maskData; + format = Format.Format_Mono; + } else if (imageData.alpha != -1) { + data = new byte[image.width() * image.height()]; + Arrays.fill(data, (byte) alpha); + format = Format.Format_Indexed8; + } else if (imageData.alphaData != null) { + data = imageData.alphaData; + format = Format.Format_Indexed8; + } + if (data != null) { + QImage alpha = new QImage(data, imageData.width, imageData.height, format); + image.setAlphaChannel(alpha); + } + } + + private byte[] imageData2RawData(ImageData image, Format format) { + PaletteData palette = image.palette; + if (!((image.depth == 1 || image.depth == 2 || image.depth == 4 || image.depth == 8) && !palette.isDirect + || image.depth == 8 || (image.depth == 16 || image.depth == 24 || image.depth == 32) + && palette.isDirect)) { + SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); + } + + byte[] buffer = image.data; + if (format.equals(Format.Format_RGB888)) { + // swap red and blue bytes + for (int i = 0; i < buffer.length - 2; i += 3) { + byte tmp = buffer[i + 2]; + buffer[i + 2] = buffer[i]; + buffer[i] = tmp; + } + } + + return buffer; + } + + private int getTransparentPixel(ImageData image) { + if (image.transparentPixel != -1) { + PaletteData palette = image.palette; + RGB rgb = null; + if (palette.isDirect) { + rgb = palette.getRGB(image.transparentPixel); + } else { + if (image.transparentPixel < palette.colors.length) { + rgb = palette.getRGB(image.transparentPixel); + } + } + + if (rgb != null) { + return rgb.red << 24 | rgb.green << 16 | rgb.blue << 8 | 0xFF; + } + } + return -1; + } + + void initNative(String filename) { + if (filename.toLowerCase().endsWith(".ico")) { //$NON-NLS-1$ + this.type = SWT.ICON; + icon = new QIcon(filename); + } else { + this.type = SWT.BITMAP; + pixmap = new QPixmap(filename); + } + } + + private QPixmap createGrayImage(Image srcImage) { + return srcImage.getQPixmap(); //.convertToFormat(Format.Format_Indexed8, ImageConversionFlag.ThresholdDither); + } + + private QPixmap createDisabledImage(Image srcImage) { + // TODO the same as gray? + return createGrayImage(srcImage); + } + + private QImage getQImage() { + return pixmap.toImage(); + } + + public QIcon getQIcon() { + // fallback strategy if image is a bitmap + if (icon == null) { + icon = new QIcon(getQPixmap()); + } + return icon; + } + + public QPixmap getQPixmap() { + // if (pixmap == null) { + // if (image != null) { + // pixmap = QPixmap.fromImage(image); + // } else if (icon != null) { + // pixmap = icon.pixmap(getDefaultIconSize()); + // } + // } + return pixmap; + } + + public QSize getDefaultIconSize() { + List<QSize> sizes = getQIcon().availableSizes(); + if (sizes.isEmpty()) { + return new QSize(); + } + return sizes.get(0); + } + + public boolean isIcon() { + return type == SWT.ICON; + } + + public boolean isBitmap() { + return type == SWT.BITMAP; + } + + @Override + void destroy() { + if (memGC != null) { + memGC.dispose(); + memGC = null; + } + // image = null; + // icon = null; + pixmap = 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 + */ + @Override + public boolean equals(Object object) { + if (object == this) { + return true; + } + if (!(object instanceof Image)) { + return false; + } + Image other = (Image) object; + return device == other.device && pixmap == other.pixmap && transparentPixel == other.transparentPixel; + } + + /** + * Returns the color to which to map the transparent pixel, or null if the + * receiver has no transparent pixel. + * <p> + * There are certain uses of Images that do not support transparency (for + * example, setting an image into a button or label). In these cases, it may + * be desired to simulate transparency by using the background color of the + * widget to paint the transparent pixels of the image. Use this method to + * check which color will be used in these cases in place of transparency. + * This value may be set with setBackground(). + * <p> + * + * @return the background color of the image, or null if there is no + * transparency in the image + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public Color getBackground() { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (transparentPixel == -1) { + return null; + } + int red = transparentPixel >> 16 & 0xFF; + int green = transparentPixel >> 8 & 0xFF; + int blue = transparentPixel >> 0 & 0xFF; + return new Color(device, red, green, blue); + } + + /** + * 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); + } + + return new Rectangle(0, 0, pixmap.width(), pixmap.height()); + } + + /** + * 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); + } + + QImage image = getQImage(); + + PaletteData palette = new PaletteData(0x00FF0000, 0x00FF00, 0x00FF); + ImageData imageData = new ImageData(image.width(), image.height(), image.depth(), palette, 4, image + .copyOfBytes()); + imageData.bytesPerLine = image.bytesPerLine(); + imageData.transparentPixel = -1; + imageData.alpha = alpha; + imageData.alphaData = getAlphaData(image); + + if (image.numColors() > 0) { + List<Integer> colorTable = image.colorTable(); + imageData.colorTable = colorTable; + } + + return imageData; + } + + private byte[] getAlphaData(QImage image) { + if (hasMask) { + // Mask data is 1 bit/pixel + if (image.hasAlphaChannel()) { + QImage alpha = image.alphaChannel(); + alpha.convertToFormat(Format.Format_Mono); + return alpha.copyOfBytes(); + } else { + int maskSize = image.width() * image.height() / 8; + byte[] alphaData = new byte[maskSize]; + Arrays.fill(alphaData, (byte) 0xFF); + return alphaData; + //imageData.maskPad = 8; + } + } else if (alpha != -1) { + byte[] alphaData = new byte[image.width() * image.height()]; + Arrays.fill(alphaData, (byte) alpha); + return alphaData; + } else if (image.hasAlphaChannel()) { + QImage alpha = image.alphaChannel(); + return alpha.copyOfBytes(); + } + return null; + } + + public static Image qt_new(Display device, int type, QIcon qIcon) { + Image image = new Image(device); + image.type = type; + image.icon = qIcon; + return image; + } + + /** + * Returns an integer hash code for the receiver. Any two objects that + * return <code>true</code> when passed to <code>equals</code> must return + * the same value for this method. + * + * @return the receiver's hash + * + * @see #equals + */ + @Override + public int hashCode() { + return pixmap != null ? (int) pixmap.hashCode() : 0; + } + + /** + * Invokes platform specific functionality to allocate a new GC handle. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public API for + * <code>Image</code>. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms, and should never be called from application code. + * </p> + * + * @param data + * the platform specific GC data + * @return the platform specific GC handle + */ + public QPaintDeviceInterface internal_new_GC(GCData data) { + data.backgroundColor = getBackground(); + data.device = device; + return pixmap; + } + + /** + * Invokes platform specific functionality to dispose a GC handle. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public API for + * <code>Image</code>. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms, and should never be called from application code. + * </p> + * + * @param hDC + * the platform specific GC handle + * @param data + * the platform specific GC data + */ + public void internal_dispose_GC(QPaintDeviceInterface paintDevice, GCData data) { + } + + /** + * 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 + */ + @Override + public boolean isDisposed() { + return pixmap == null && icon == null; + } + + /** + * Sets the color to which to map the transparent pixel. + * <p> + * There are certain uses of <code>Images</code> that do not support + * transparency (for example, setting an image into a button or label). In + * these cases, it may be desired to simulate transparency by using the + * background color of the widget to paint the transparent pixels of the + * image. This method specifies the color that will be used in these cases. + * For example: + * + * <pre> + * Button b = new Button(); + * image.setBackground(b.getBackground()); + * b.setImage(image); + * </pre> + * + * </p> + * <p> + * The image may be modified by this operation (in effect, the transparent + * regions may be filled with the supplied color). Hence this operation is + * not reversible and it is not legal to call this function twice or with a + * null argument. + * </p> + * <p> + * This method has no effect if the receiver does not have a transparent + * pixel value. + * </p> + * + * @param color + * the color to use when a transparent pixel is specified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the color is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the color has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void setBackground(Color color) { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (color == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (color.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (transparentPixel == -1) { + return; + } + return; // TODO function disabled + // byte red = (byte) ((transparentPixel >> 16) & 0xFF); + // byte green = (byte) ((transparentPixel >> 8) & 0xFF); + // byte blue = (byte) ((transparentPixel >> 0) & 0xFF); + // byte newRed = (byte) ((int) (color.handle[0] * 255) & 0xFF); + // byte newGreen = (byte) ((int) (color.handle[1] * 255) & 0xFF); + // byte newBlue = (byte) ((int) (color.handle[2] * 255) & 0xFF); + // NSBitmapImageRep imageRep = getRepresentation(); + // long /* int */bpr = imageRep.bytesPerRow(); + // long /* int */data = imageRep.bitmapData(); + // byte[] line = new byte[(int) bpr]; + // for (int i = 0, offset = 0; i < height; i++, offset += bpr) { + // OS.memmove(line, data + offset, bpr); + // for (int j = 0; j < line.length; j += 4) { + // if (line[j + 1] == red && line[j + 2] == green + // && line[j + 3] == blue) { + // line[j + 1] = newRed; + // line[j + 2] = newGreen; + // line[j + 3] = newBlue; + // } + // } + // OS.memmove(data + offset, line, bpr); + // } + // transparentPixel = (newRed & 0xFF) << 16 | (newGreen & 0xFF) << 8 + // | (newBlue & 0xFF); + } + + /** + * Returns a string containing a concise, human-readable description of the + * receiver. + * + * @return a string representation of the receiver + */ + @Override + public String toString() { + if (isDisposed()) { + return "Image {*DISPOSED*}"; //$NON-NLS-1$ + } + return "Image {pixmap: " + pixmap + ", icon: " + icon + " }"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + public void setMemGC(GC gc) { + this.memGC = gc; + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Region.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Region.java new file mode 100644 index 0000000000..23c2ec90e0 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/graphics/Region.java @@ -0,0 +1,776 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import com.trolltech.qt.core.QPoint; +import com.trolltech.qt.core.QRect; +import com.trolltech.qt.gui.QRegion; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTError; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.internal.qt.QtSWTConverter; + +/** + * Instances of this class represent areas of an x-y coordinate system that are + * aggregates of the areas covered by a number of polygons. + * <p> + * Application code must explicitly invoke the <code>Region.dispose()</code> + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * GraphicsExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + */ + +public final class Region extends Resource { + + /** + * the OS resource for the region (Warning: This field is platform + * dependent) + * <p> + * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT public API. + * It is marked public only so that it can be shared within the packages + * provided by SWT. It is not available on all platforms and should never be + * accessed from application code. + * </p> + */ + private QRegion region; + + /** + * Constructs a new empty region. + * + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for + * region creation</li> + * </ul> + */ + public Region() { + this(null); + } + + /** + * Constructs a new empty region. + * <p> + * You must dispose the region when it is no longer required. + * </p> + * + * @param device + * the device on which to allocate the region + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is + * no current device</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for + * region creation</li> + * </ul> + * + * @see #dispose + * + * @since 3.0 + */ + public Region(Device device) { + super(device); + region = new QRegion(); + init(); + } + + /** + * Constructs a new region given a handle to the operating system resources + * that it should represent. + * + * @param handle + * the handle for the result + */ + Region(Device device, QRegion region) { + super(device); + this.region = region; + } + + QRegion getQRegion() { + return region; + } + + /** + * Adds the given polygon to the collection of polygons the receiver + * maintains to describe its area. + * + * @param pointArray + * points that describe the polygon to merge with the receiver + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.0 + * + */ + public void add(int[] pointArray) { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (pointArray == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + QRegion rg = new QRegion(GC.createPolygonFromArray(pointArray)); + region = region.united(rg); + } + + /** + * Adds the given rectangle to the collection of polygons the receiver + * maintains to describe its area. + * + * @param rect + * the rectangle to merge with the receiver + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or + * height is negative</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void add(Rectangle rect) { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (rect == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + region = region.unite(QtSWTConverter.convert(rect)); + } + + /** + * Adds the given rectangle to the collection of polygons the receiver + * maintains to describe its area. + * + * @param x + * the x coordinate of the rectangle + * @param y + * the y coordinate of the rectangle + * @param width + * the width coordinate of the rectangle + * @param height + * the height coordinate of the rectangle + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or + * height is negative</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.1 + */ + public void add(int x, int y, int width, int height) { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (width < 0 || height < 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + region = region.united(new QRect(x, y, width, height)); + } + + /** + * Adds all of the polygons which make up the area covered by the argument + * to the collection of polygons the receiver maintains to describe its + * area. + * + * @param region + * the region to merge + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void add(Region region) { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (region == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (region.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + this.region = this.region.united(region.getQRegion()); + } + + /** + * 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 region.contains(new QPoint(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 (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (pt == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + return region.contains(QtSWTConverter.convert(pt)); + } + + @Override + void destroy() { + region = 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 + */ + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (!(object instanceof Region)) { + return false; + } + return region.equals(((Region) object).getQRegion()); + } + + /** + * Returns a rectangle which represents the rectangular union of the + * collection of polygons the receiver maintains to describe its area. + * + * @return a bounding rectangle for the region + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see Rectangle#union + */ + public Rectangle getBounds() { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return QtSWTConverter.convert(region.boundingRect()); + } + + /** + * Returns an integer hash code for the receiver. Any two objects that + * return <code>true</code> when passed to <code>equals</code> must return + * the same value for this method. + * + * @return the receiver's hash + * + * @see #equals + */ + @Override + public int hashCode() { + return region.hashCode(); + } + + /** + * Intersects the given rectangle to the collection of polygons the receiver + * maintains to describe its area. + * + * @param rect + * the rectangle to intersect with the receiver + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or + * height is negative</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.0 + */ + public void intersect(Rectangle rect) { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (rect == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + intersect(rect.x, rect.y, rect.width, rect.height); + } + + /** + * Intersects the given rectangle to the collection of polygons the receiver + * maintains to describe its area. + * + * @param x + * the x coordinate of the rectangle + * @param y + * the y coordinate of the rectangle + * @param width + * the width coordinate of the rectangle + * @param height + * the height coordinate of the rectangle + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or + * height is negative</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.1 + */ + public void intersect(int x, int y, int width, int height) { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (width < 0 || height < 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + region = region.intersect(new QRect(x, y, width, height)); + } + + /** + * Intersects all of the polygons which make up the area covered by the + * argument to the collection of polygons the receiver maintains to describe + * its area. + * + * @param region + * the region to intersect + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.0 + */ + public void intersect(Region region) { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (region == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (region.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + this.region = this.region.intersected(region.getQRegion()); + } + + /** + * Returns <code>true</code> if the rectangle described by the arguments + * intersects with any of the polygons the receiver maintains to describe + * its area, and <code>false</code> otherwise. + * + * @param x + * the x coordinate of the origin of the rectangle + * @param y + * the y coordinate of the origin of the rectangle + * @param width + * the width of the rectangle + * @param height + * the height of the rectangle + * @return <code>true</code> if the rectangle intersects with the receiver, + * and <code>false</code> otherwise + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see Rectangle#intersects(Rectangle) + */ + public boolean intersects(int x, int y, int width, int height) { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + return region.intersects(new QRect(x, y, width, height)); + } + + /** + * Returns <code>true</code> if the given rectangle intersects with any of + * the polygons the receiver maintains to describe its area and + * <code>false</code> otherwise. + * + * @param rect + * the rectangle to test for intersection + * @return <code>true</code> if the rectangle intersects with the receiver, + * and <code>false</code> otherwise + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see Rectangle#intersects(Rectangle) + */ + public boolean intersects(Rectangle rect) { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + 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 + */ + @Override + public boolean isDisposed() { + return region == null; + } + + /** + * 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); + } + return region.isEmpty(); + } + + /** + * Subtracts the given polygon from the collection of polygons the receiver + * maintains to describe its area. + * + * @param pointArray + * points that describe the polygon to merge with the receiver + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.0 + */ + public void subtract(int[] pointArray) { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (pointArray == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + QRegion rg = new QRegion(GC.createPolygonFromArray(pointArray)); + region = region.subtracted(rg); + } + + /** + * Subtracts the given rectangle from the collection of polygons the + * receiver maintains to describe its area. + * + * @param rect + * the rectangle to subtract from the receiver + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or + * height is negative</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.0 + */ + public void subtract(Rectangle rect) { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (rect == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + subtract(rect.x, rect.y, rect.width, rect.height); + } + + /** + * Subtracts the given rectangle from the collection of polygons the + * receiver maintains to describe its area. + * + * @param x + * the x coordinate of the rectangle + * @param y + * the y coordinate of the rectangle + * @param width + * the width coordinate of the rectangle + * @param height + * the height coordinate of the rectangle + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or + * height is negative</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.1 + */ + public void subtract(int x, int y, int width, int height) { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (width < 0 || height < 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + region = region.subtracted(new QRegion(x, y, width, height)); + } + + /** + * Subtracts all of the polygons which make up the area covered by the + * argument from the collection of polygons the receiver maintains to + * describe its area. + * + * @param region + * the region to subtract + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.0 + */ + public void subtract(Region region) { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (region == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (region.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + this.region = this.region.subtracted(region.getQRegion()); + } + + /** + * Translate all of the polygons the receiver maintains to describe its area + * by the specified point. + * + * @param x + * the x coordinate of the point to translate + * @param y + * the y coordinate of the point to translate + * + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.1 + */ + public void translate(int x, int y) { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + region = region.translated(x, y); + } + + /** + * Translate all of the polygons the receiver maintains to describe its area + * by the specified point. + * + * @param pt + * the point to translate + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.1 + */ + public void translate(Point pt) { + if (isDisposed()) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (pt == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + translate(pt.x, pt.y); + } + + /** + * Returns a string containing a concise, human-readable description of the + * receiver. + * + * @return a string representation of the receiver + */ + @Override + public String toString() { + if (isDisposed()) { + return "Region {*DISPOSED*}"; //$NON-NLS-1$ + } + return "Region {" + region + "}"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * 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 device + * the device on which to allocate the region + * @param handle + * the handle for the region + * @return a new region object containing the specified device and handle + */ + public static Region win32_new(Device device, QRegion region) { + return new Region(device, region); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/DragNDropListener.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/DragNDropListener.java new file mode 100644 index 0000000000..2850edc6d3 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/DragNDropListener.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 compeople AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * compeople AG - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.internal.qt; + +import com.trolltech.qt.gui.QDragEnterEvent; +import com.trolltech.qt.gui.QDragLeaveEvent; +import com.trolltech.qt.gui.QDragMoveEvent; +import com.trolltech.qt.gui.QDropEvent; + +public interface DragNDropListener { + + public void dragEnter(QDragEnterEvent event); + + public void dragLeave(QDragLeaveEvent event); + + public void dragMove(QDragMoveEvent event); + + public void drop(QDropEvent event); + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/FontConverter.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/FontConverter.java new file mode 100644 index 0000000000..cd042cf785 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/FontConverter.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 compeople AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * compeople AG - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.internal.qt; + +import java.util.LinkedList; +import java.util.List; + +import com.trolltech.qt.gui.QFont; +import com.trolltech.qt.gui.QFont.Weight; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Font; + +/** + * @author kriese + * + */ +public class FontConverter { + + private List<FontNameTuple> fontNames; + private List<FontStyleTuple> fontStyles; + + public FontConverter() { + fontNames = new LinkedList<FontNameTuple>(); + fontNames.add(new FontNameTuple("Arial", "Times")); //$NON-NLS-1$ //$NON-NLS-2$ + + fontStyles = new LinkedList<FontStyleTuple>(); + fontStyles.add(new FontStyleTuple(SWT.BOLD, QFont.Weight.Bold)); + fontStyles.add(new FontStyleTuple(SWT.NORMAL, QFont.Weight.Normal)); + } + + public QFont getQtFont(Font swtFont) { + + FontNameTuple tuple = null; + for (FontNameTuple f : fontNames) { + if (f.getSwtFontName().equals(swtFont.getFontData()[0].getName())) { + tuple = f; + } + } + + // swtFont.getFontData()[0].get + + FontStyleTuple style = null; + for (FontStyleTuple s : fontStyles) { + if (s.getSwtStyle() == swtFont.getFontData()[0].getStyle()) { + style = s; + } + } + + if (null != tuple) { + + if (null != style) { + return new QFont(tuple.getQtFontName(), swtFont.getFontData()[0].getHeight(), style.getQtStyle() + .value()); + } + + return new QFont(tuple.getQtFontName(), swtFont.getFontData()[0].getHeight()); + } + + return null; + } + + private static class FontStyleTuple { + private QFont.Weight qtStyle; + private int swtStyle; + + public FontStyleTuple(int swtStyle, Weight qtStyle) { + super(); + this.qtStyle = qtStyle; + this.swtStyle = swtStyle; + } + + public QFont.Weight getQtStyle() { + return qtStyle; + } + + public int getSwtStyle() { + return swtStyle; + } + } + + private static class FontNameTuple { + private String swtFontName; + private String qtFontName; + + public FontNameTuple(String swtFontName, String qtFontName) { + this.swtFontName = swtFontName; + this.qtFontName = qtFontName; + } + + public String getSwtFontName() { + return swtFontName; + } + + public String getQtFontName() { + return qtFontName; + } + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/KeyUtil.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/KeyUtil.java new file mode 100644 index 0000000000..9d25fa7a1f --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/KeyUtil.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 compeople AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * compeople AG - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.internal.qt; + +import com.trolltech.qt.core.Qt.Key; +import com.trolltech.qt.core.Qt.KeyboardModifier; +import com.trolltech.qt.core.Qt.KeyboardModifiers; +import com.trolltech.qt.gui.QKeyEvent; + +import org.eclipse.swt.SWT; + +/** + * Helper class for Key translation SWT <-> Qt + */ +public class KeyUtil { + /* Key Mappings */ + private static final int[][] KeyTable = { + /* Keyboard and Mouse Masks */ + { Key.Key_Alt.value(), SWT.ALT }, { Key.Key_AltGr.value(), SWT.ALT }, { Key.Key_Meta.value(), SWT.ALT }, + { Key.Key_Shift.value(), SWT.SHIFT }, { Key.Key_Control.value(), SWT.CONTROL }, + /* Non-Numeric Keypad Keys */ + { Key.Key_Up.value(), SWT.ARROW_UP }, { Key.Key_Down.value(), SWT.ARROW_DOWN }, + { Key.Key_Left.value(), SWT.ARROW_LEFT }, { Key.Key_Right.value(), SWT.ARROW_RIGHT }, + { Key.Key_PageUp.value(), SWT.PAGE_UP }, { Key.Key_PageDown.value(), SWT.PAGE_DOWN }, + { Key.Key_Home.value(), SWT.HOME }, { Key.Key_End.value(), SWT.END }, + { Key.Key_Insert.value(), SWT.INSERT }, + /* Virtual and Ascii Keys */ + { Key.Key_Space.value(), ' ' }, { Key.Key_Backspace.value(), SWT.BS }, { Key.Key_Return.value(), SWT.CR }, + { Key.Key_Delete.value(), SWT.DEL }, { Key.Key_Escape.value(), SWT.ESC }, + { Key.Key_Enter.value(), SWT.CR }, { Key.Key_Tab.value(), SWT.TAB }, { Key.Key_Backtab.value(), SWT.TAB }, + /* Functions Keys */ + { Key.Key_F1.value(), SWT.F1 }, { Key.Key_F2.value(), SWT.F2 }, { Key.Key_F3.value(), SWT.F3 }, + { Key.Key_F4.value(), SWT.F4 }, { Key.Key_F5.value(), SWT.F5 }, { Key.Key_F6.value(), SWT.F6 }, + { Key.Key_F7.value(), SWT.F7 }, { Key.Key_F8.value(), SWT.F8 }, { Key.Key_F9.value(), SWT.F9 }, + { Key.Key_F10.value(), SWT.F10 }, { Key.Key_F11.value(), SWT.F11 }, { Key.Key_F12.value(), SWT.F12 }, + { Key.Key_F13.value(), SWT.F13 }, { Key.Key_F14.value(), SWT.F14 }, { Key.Key_F15.value(), SWT.F15 }, + /* Other keys */ + { Key.Key_CapsLock.value(), SWT.CAPS_LOCK }, { Key.Key_NumLock.value(), SWT.NUM_LOCK }, + { Key.Key_ScrollLock.value(), SWT.SCROLL_LOCK }, { Key.Key_Pause.value(), SWT.PAUSE }, + { Key.Key_Print.value(), SWT.PRINT_SCREEN }, { Key.Key_Help.value(), SWT.HELP }, + + }; + + private static final int[][] KeyPadKeyTable = { + /* Numeric Keypad Keys */ + { Key.Key_Asterisk.value(), SWT.KEYPAD_MULTIPLY }, { Key.Key_Plus.value(), SWT.KEYPAD_ADD }, + { Key.Key_Enter.value(), SWT.KEYPAD_CR }, { Key.Key_Minus.value(), SWT.KEYPAD_SUBTRACT }, + { Key.Key_Period.value(), SWT.KEYPAD_DECIMAL }, { Key.Key_Slash.value(), SWT.KEYPAD_DIVIDE }, + { Key.Key_0.value(), SWT.KEYPAD_0 }, { Key.Key_1.value(), SWT.KEYPAD_1 }, + { Key.Key_2.value(), SWT.KEYPAD_2 }, { Key.Key_3.value(), SWT.KEYPAD_3 }, + { Key.Key_4.value(), SWT.KEYPAD_4 }, { Key.Key_5.value(), SWT.KEYPAD_5 }, + { Key.Key_6.value(), SWT.KEYPAD_6 }, { Key.Key_7.value(), SWT.KEYPAD_7 }, + { Key.Key_8.value(), SWT.KEYPAD_8 }, { Key.Key_9.value(), SWT.KEYPAD_9 }, + { Key.Key_Equal.value(), SWT.KEYPAD_EQUAL }, }; + + private KeyUtil() { + // utility class + } + + public static int translateKey(int key) { + for (int i = 0; i < KeyTable.length; i++) { + if (KeyTable[i][0] == key) { + return KeyTable[i][1]; + } + } + return 0; + } + + public static int untranslateKey(int key) { + for (int i = 0; i < KeyTable.length; i++) { + if (KeyTable[i][1] == key) { + return KeyTable[i][0]; + } + } + return 0; + } + + // Converts keys from Qt to SWT + public static final int translateKey(QKeyEvent qEvent) { + int key = qEvent.key(); + boolean keypad = qEvent.modifiers().isSet(KeyboardModifier.KeypadModifier); + if (keypad) { + for (int i = 0; i < KeyPadKeyTable.length; i++) { + if (KeyPadKeyTable[i][0] == key) { + return KeyPadKeyTable[i][1]; + } + } + } + for (int i = 0; i < KeyTable.length; i++) { + if (KeyTable[i][0] == key) { + return KeyTable[i][1]; + } + } + return 0; + } + + // Converts modifiers from Qt to SWT + public static final int translateModifiers(KeyboardModifiers nativeModifiers) { + int modifiers = 0; + if (nativeModifiers.isSet(KeyboardModifier.AltModifier)) { + modifiers |= SWT.ALT; + } + if (nativeModifiers.isSet(KeyboardModifier.ShiftModifier)) { + modifiers |= SWT.SHIFT; + } + if (nativeModifiers.isSet(KeyboardModifier.ControlModifier)) { + modifiers |= SWT.CONTROL; + } + return modifiers; + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/QtSWTConverter.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/QtSWTConverter.java new file mode 100644 index 0000000000..e67a631c38 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/QtSWTConverter.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 compeople AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * compeople AG - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.internal.qt; + +import com.trolltech.qt.core.QPoint; +import com.trolltech.qt.core.QRect; +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.gui.QColor; +import com.trolltech.qt.gui.QRegion; + +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.graphics.Region; + +/** + * @author J�rgen Becker + * + */ +public class QtSWTConverter { + + private QtSWTConverter() { + // utility class + } + + public static Rectangle convert(QRect rect) { + if (rect == null) { + return null; + } + return new Rectangle(rect.x(), rect.y(), rect.width(), rect.height()); + } + + public static QRect convert(Rectangle rect) { + if (rect == null) { + return null; + } + return new QRect(rect.x, rect.y, rect.width, rect.height); + } + + public static Point convert(QSize size) { + if (size == null) { + return null; + } + return new Point(size.width(), size.height()); + } + + public static Point convert(QPoint point) { + if (point == null) { + return null; + } + return new Point(point.x(), point.y()); + } + + public static Point convertPosition(QRect rect) { + if (rect == null) { + return null; + } + return new Point(rect.x(), rect.y()); + } + + public static Point convertSize(QRect rect) { + if (rect == null) { + return null; + } + return new Point(rect.width(), rect.height()); + } + + public static QPoint convert(Point point) { + if (point == null) { + return null; + } + return new QPoint(point.x, point.y); + } + + public static QColor convert(Color color) { + if (color == null) { + return null; + } + return new QColor(color.getRed(), color.getGreen(), color.getBlue()); + } + + public static Color convert(QColor color) { + if (color == null) { + return null; + } + return new Color(null, color.red(), color.green(), color.blue()); + } + + public static QRegion convert(Region region) { + if (region == null) { + return null; + } + return new QRegion(convert(region.getBounds())); + } + + public static Rectangle convert(QRegion region) { + if (region == null) { + return null; + } + return convert(region.boundingRect()); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/QtSupplementaryFontData.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/QtSupplementaryFontData.java new file mode 100644 index 0000000000..b7343e54d0 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/QtSupplementaryFontData.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Nokia Corporation - initial implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ + +package org.eclipse.swt.internal.qt; + +import com.trolltech.qt.gui.QFont.Style; +import com.trolltech.qt.gui.QFont.StyleStrategy; + +public final class QtSupplementaryFontData { + public int underline = -1; + public int overline = -1; + public int strikeOut = -1; + public int stretch = -1; + public int fixedPitch = -1; + public Style style = null; + public int weight = -1; + public StyleStrategy styleStrategy = null; +}
\ No newline at end of file diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/SWQT.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/SWQT.java new file mode 100644 index 0000000000..e1761859b4 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/SWQT.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010s compeople AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * compeople AG - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.internal.qt; + +public class SWQT { + + /* Widget Event Constants */ + + /** + * The null event type (value is 0). + * + * @since 3.0 + */ + public static final int StyleSheetChange = 1024; + + /** + * + */ + public static final String STYLESHEET_KEY = "stylesheet"; //$NON-NLS-1$ + + // Qt QFont::Weight + public static final int QT_FONTNORMAL = 50; + public static final int QT_FONTBOLD = 75; + + // QFont::Style + public static final int QFONT_STYLE_NORMAL = 0; + public static final int QFONT_STYLE_ITALIC = 1; + public static final int QFONT_STYLE_OBLIQUE = 2; + + // QFont::StyleStrategy + public static final int QFONT_STYLESTRATEGY_PREFERDEFALUT = 0x0001; + public static final int QFONT_STYLESTRATEGY_PREFERBITMAP = 0x0002; + public static final int QFONT_STYLESTRATEGY_PREFERDEVICE = 0x0004; + public static final int QFONT_STYLESTRATEGY_PREFEROUTLINE = 0x0008; + public static final int QFONT_STYLESTRATEGY_FORCEOUTLINE = 0x0010; + public static final int QFONT_STYLESTRATEGY_NOANTIALIAS = 0x0100; + public static final int QFONT_STYLESTRATEGY_PREFERANTIALIAS = 0x0080; + public static final int QFONT_STYLESTRATEGY_OPENGLCOMPATIABLE = 0x0200; + public static final int QFONT_STYLESTRATEGY_NOFONTMERGING = 0x8000; + public static final int QFONT_STYLESTRATEGY_PREFERMATCH = 0x0020; + public static final int QFONT_STYLESTRATEGY_PREFERQUALITY = 0x0040; + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/SignalConnector.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/SignalConnector.java new file mode 100644 index 0000000000..08414ac5ec --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/SignalConnector.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 compeople AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * compeople AG - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.internal.qt; + +import com.trolltech.qt.QSignalEmitter.AbstractSignal; + +/** + * A {@code SignalConnector} is the representation of a certain signal, + * receiver, method tuple. This tuple allows connecting and disconnecting from + * the signal - without the need of constantly repeating (error-prone) the + * necessary parameters. + */ +public class SignalConnector { + + private final AbstractSignal signal; + private final Object receiver; + private final String method; + + /** + * Create a {@code SignalConnector} from the given parameters. + * + * @param signal + * the signal + * @param receiver + * the receiver of the signal + * @param method + * the reveiver's method + */ + public SignalConnector(final AbstractSignal signal, final Object receiver, final String method) { + this.signal = signal; + this.receiver = receiver; + this.method = method; + } + + /** + * Connect the signal. + * + * @return this object. + */ + public SignalConnector connect() { + signal.connect(receiver, method); + return this; + } + + /** + * Disconnect the signal. + */ + public void disconnect() { + signal.disconnect(receiver, method); + } + + /** + * Run the given {@code Runnable} with disconnecting before and + * re-connection afterwards. + * + * @param runnable + */ + public void runDisconnected(final Runnable runnable) { + try { + disconnect(); + runnable.run(); + } finally { + connect(); + } + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/StylableScrollArea.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/StylableScrollArea.java new file mode 100644 index 0000000000..ef6bef9263 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/StylableScrollArea.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2009, 2009 compeople AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * compeople AG - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.internal.qt; + +import com.trolltech.qt.QtPropertyResetter; +import com.trolltech.qt.gui.QColor; +import com.trolltech.qt.gui.QScrollArea; + +public class StylableScrollArea extends QScrollArea { + private QColor gradientStart = new QColor(0, 0, 255); + private QColor gradientEnd = new QColor(0, 255, 0); + private QColor text = new QColor(0, 0, 0); + private QColor border = new QColor(255, 255, 255); + + public QColor getGradientStart() { + return gradientStart; + } + + public void setGradientStart(QColor gradientStart) { + this.gradientStart = gradientStart; + } + + @QtPropertyResetter(name = "gradientStart") + public void resetGradientStart() { + gradientStart = new QColor(0, 0, 255); + } + + public QColor getGradientEnd() { + return gradientEnd; + } + + public void setGradientEnd(QColor gradientEnd) { + this.gradientEnd = gradientEnd; + } + + public QColor getText() { + return text; + } + + public void setText(QColor text) { + this.text = text; + } + + public QColor getBorder() { + return border; + } + + public void setBorder(QColor border) { + this.border = border; + } + +}
\ No newline at end of file diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/ToString.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/ToString.java new file mode 100644 index 0000000000..288a2dfe22 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/internal/qt/ToString.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 compeople AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * compeople AG - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.internal.qt; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; + +/** + * Generic .toString() that collects all Java bean properties. + */ +public final class ToString { + + private static final String SEPARATOR = ", "; //$NON-NLS-1$ + + private ToString() { + + } + + /** + * Collect all Java bean properties of the given object and return them as a + * printable string. + * + * @param object + * @return toString() + */ + public static String of(Object object) { + if (object == null) { + return "NULL"; //$NON-NLS-1$ + } + try { + return of(object, Introspector.getBeanInfo(object.getClass())); + } catch (IntrospectionException e) { + return e.toString(); + } + } + + /** + * Collect all Java bean properties of the given object but stop + * introspection at the given stop class and return them as a printable + * string. + * + * @param object + * @param stopClass + * if {@code null} stop class will be the super class of the + * given object + * @return toString() + */ + public static String of(Object object, Class<?> stopClass) { + if (object == null) { + return "NULL"; //$NON-NLS-1$ + } + if (stopClass == null) { + stopClass = object.getClass().getSuperclass(); + } + String result = object.toString() + " - "; //$NON-NLS-1$ + try { + result = result + of(object, Introspector.getBeanInfo(object.getClass(), stopClass)); + } catch (IntrospectionException e) { + result = result + e.toString(); + } + return result; + } + + @SuppressWarnings("nls") + private static String of(Object object, BeanInfo beanInfo) { + StringBuilder bob = new StringBuilder(object.getClass().getSimpleName()).append(" ("); + PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); + for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { + Method readMethod = propertyDescriptor.getReadMethod(); + try { + if (readMethod != null && !propertyDescriptor.getName().equals("class")) { + Object value = readMethod.invoke(object, (Object[]) null); + if (value != null && value.toString().startsWith(value.getClass().getName() + "@")) { + value = ".."; + } + bob.append(propertyDescriptor.getName()).append('=').append(value).append(SEPARATOR); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + if (bob.toString().endsWith(SEPARATOR)) { + bob.setLength(bob.length() - SEPARATOR.length()); + } + bob.append(" )"); + return bob.toString(); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Button.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Button.java new file mode 100644 index 0000000000..b3319910ac --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Button.java @@ -0,0 +1,801 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.Qt.CheckState; +import com.trolltech.qt.gui.QAbstractButton; +import com.trolltech.qt.gui.QApplication; +import com.trolltech.qt.gui.QCheckBox; +import com.trolltech.qt.gui.QMouseEvent; +import com.trolltech.qt.gui.QPushButton; +import com.trolltech.qt.gui.QRadioButton; +import com.trolltech.qt.gui.QSizePolicy; +import com.trolltech.qt.gui.QWidget; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; + +/** + * Instances of this class represent a selectable user interface object that + * issues notification when pressed and released. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>ARROW, CHECK, PUSH, RADIO, TOGGLE, FLAT</dd> + * <dd>UP, DOWN, LEFT, RIGHT, CENTER</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection</dd> + * </dl> + * <p> + * Note: Only one of the styles ARROW, CHECK, PUSH, RADIO, and TOGGLE may be + * specified. + * </p> + * <p> + * Note: Only one of the styles LEFT, RIGHT, and CENTER may be specified. + * </p> + * <p> + * Note: Only one of the styles UP, DOWN, LEFT, and RIGHT may be specified when + * the ARROW style is specified. + * </p> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> within the + * SWT implementation. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#button">Button + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class Button extends Control { + private Image image; + private Image image2; + private Image disabledImage; + private static/* final */boolean COMMAND_LINK = false; + + /** + * 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)); + } + + @Override + protected void connectSignals() { + getQButton().released.connect(this, "clickEvent()"); //$NON-NLS-1$ + } + + @Override + protected QWidget createQWidget(int style) { + int marginLeft = 0; + int marginTop = 0; + int marginRight = 0; + int marginBottom = 0; + QAbstractButton tb; + if ((style & SWT.CHECK) != 0) { + tb = new MyQCheckBox(); + marginTop = 0; + marginBottom = 2; + } else if ((style & SWT.RADIO) != 0) { + tb = new MyQRadioButton(); + if ((getParent().style & SWT.NO_RADIO_GROUP) != 0) { + tb.setAutoExclusive(false); + } + marginTop = 3; + marginBottom = 0; + } else { + tb = new MyQPushButton(); + if ((style & SWT.TOGGLE) != 0) { + tb.setCheckable(true); + } + if ((style & SWT.FLAT) != 0) { + ((QPushButton) tb).setFlat(true); + } + // In SWT, push buttons do not inherit color from + // their parent, not even with INHERIT_FORCE. + tb.setPalette(QApplication.palette()); + marginTop = 3; + } + tb.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum); + tb.setContentsMargins(marginLeft, marginTop, marginRight, marginBottom); + return tb; + } + + QAbstractButton getQButton() { + return (QAbstractButton) getQWidget(); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the control is selected by the user, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * <code>widgetSelected</code> is called when the control is selected by the + * user. <code>widgetDefaultSelected</code> is not called. + * </p> + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + protected void clickEvent() { + sendEvent(SWT.Selection); + } + + static int checkStyle(int style) { + style = checkBits(style, SWT.PUSH, SWT.ARROW, SWT.CHECK, SWT.RADIO, SWT.TOGGLE, COMMAND_LINK ? SWT.COMMAND : 0); + if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) { + return checkBits(style, SWT.CENTER, SWT.LEFT, SWT.RIGHT, 0, 0, 0); + } + if ((style & (SWT.CHECK | SWT.RADIO)) != 0) { + return checkBits(style, SWT.LEFT, SWT.RIGHT, SWT.CENTER, 0, 0, 0); + } + if ((style & SWT.ARROW) != 0) { + style |= SWT.NO_FOCUS; + return checkBits(style, SWT.UP, SWT.DOWN, SWT.LEFT, SWT.RIGHT, 0, 0); + } + return style; + } + + void click() { + getQButton().click(); + } + + // public Point computeSize( int wHint, int hHint, boolean changed ) { + // checkWidget(); + // Point size = super.computeSize( wHint, hHint, changed ); + // size.x += 2; + // return size; + // } + + /** + * Returns a value which describes the position of the text or image in the + * receiver. The value will be one of <code>LEFT</code>, <code>RIGHT</code> + * or <code>CENTER</code> unless the receiver is an <code>ARROW</code> + * button, in which case, the alignment will indicate the direction of the + * arrow (one of <code>LEFT</code>, <code>RIGHT</code>, <code>UP</code> or + * <code>DOWN</code>). + * + * @return the alignment + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getAlignment() { + checkWidget(); + if ((style & SWT.ARROW) != 0) { + if ((style & SWT.UP) != 0) { + return SWT.UP; + } + if ((style & SWT.DOWN) != 0) { + return SWT.DOWN; + } + if ((style & SWT.LEFT) != 0) { + return SWT.LEFT; + } + if ((style & SWT.RIGHT) != 0) { + return SWT.RIGHT; + } + return SWT.UP; + } + if ((style & SWT.LEFT) != 0) { + return SWT.LEFT; + } + if ((style & SWT.CENTER) != 0) { + return SWT.CENTER; + } + if ((style & SWT.RIGHT) != 0) { + return SWT.RIGHT; + } + return SWT.LEFT; + } + + /** + * Returns <code>true</code> if the receiver is grayed, and false otherwise. + * When the widget does not have the <code>CHECK</code> style, return false. + * + * @return the grayed state of the checkbox + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public boolean getGrayed() { + checkWidget(); + if ((style & SWT.CHECK) == 0) { + return false; + } + QCheckBox box = (QCheckBox) getQButton(); + if (box.isTristate()) { + return CheckState.PartiallyChecked.equals(box.checkState()); + } + return false; + } + + /** + * 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; + } + + /** + * Returns the widget message. When the widget is created with the style + * <code>SWT.COMMAND</code>, the message text is displayed to provide + * further information for the user. + * + * @return the widget message + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.3 + */ + /* public */String getMessage() { + checkWidget(); + return getQButton().whatsThis(); + } + + @Override + 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; + } + return getQButton().isChecked(); + } + + /** + * Returns the receiver's text, which will be an empty string if it has + * never been set or if the receiver is an <code>ARROW</code> button. + * + * @return the receiver's text + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String getText() { + checkWidget(); + if ((style & SWT.ARROW) != 0) { + return ""; //$NON-NLS-1$ + } + return getQButton().text(); + } + + @Override + boolean isTabItem() { + if ((style & SWT.PUSH) != 0) { + return isTabGroup(); + } + return super.isTabItem(); + } + + @Override + 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; + } + + @Override + boolean mnemonicMatch(char key) { + char mnemonic = findMnemonic(getText()); + if (mnemonic == '\0') { + return false; + } + return Character.toUpperCase(key) == Character.toUpperCase(mnemonic); + } + + @Override + void releaseWidget() { + super.releaseWidget(); + if (disabledImage != null) { + disabledImage.dispose(); + disabledImage = null; + } + if (image2 != null) { + image2.dispose(); + image2 = null; + } + image = null; + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is selected by the user. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + void selectRadio() { + /* + * This code is intentionally commented. When two groups of radio + * buttons with the same parent are separated by another control, the + * correct behavior should be that the two groups act independently. + * This is consistent with radio tool and menu items. The commented code + * implements this behavior. + */ + // int index = 0; + // Control [] children = parent._getChildren (); + // while (index < children.length && children [index] != this) index++; + // int i = index - 1; + // while (i >= 0 && children [i].setRadioSelection (false)) --i; + // int j = index + 1; + // while (j < children.length && children [j].setRadioSelection (false)) + // j++; + // setSelection (true); + Control[] children = parent._getChildren(); + for (int i = 0; i < children.length; i++) { + Control child = children[i]; + if (this != child) { + child.setRadioSelection(false); + } + } + setSelection(true); + } + + /** + * 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(); + // TODO how to change it for the qt control + 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); + 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); + } + + void setDefault(boolean value) { + if ((style & SWT.PUSH) == 0) { + return; + } + ((QPushButton) getQButton()).setDefault(value); + } + + @Override + boolean setFixedFocus() { + /* + * Feature in Windows. When a radio button gets focus, it selects the + * button in WM_SETFOCUS. The fix is to not assign focus to an + * unselected radio button. + */ + if ((style & SWT.RADIO) != 0 && !getSelection()) { + return false; + } + return super.setFixedFocus(); + } + + /** + * Sets the receiver's image to the argument, which may be <code>null</code> + * indicating that no image should be displayed. + * <p> + * Note that a Button can display an image and text simultaneously on + * Windows (starting with XP), GTK+ and OSX. On other platforms, a Button + * that has an image and text set into it will display the image or text + * that was set most recently. + * </p> + * + * @param image + * the image to display on the receiver (may be <code>null</code> + * ) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the image has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setImage(Image image) { + checkWidget(); + if (image != null && image.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if ((style & SWT.ARROW) != 0) { + return; + } + this.image = image; + + getQButton().setIcon(image.getQIcon()); + getQButton().setIconSize(image.getDefaultIconSize()); + } + + /** + * Sets the grayed state of the receiver. This state change only applies if + * the control was created with the SWT.CHECK style. + * + * @param grayed + * the new grayed state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public void setGrayed(boolean grayed) { + checkWidget(); + if ((style & SWT.CHECK) == 0) { + return; + } + QCheckBox box = (QCheckBox) getQButton(); + box.setTristate(true); + box.setCheckState(CheckState.PartiallyChecked); + } + + /** + * Sets the widget message. When the widget is created with the style + * <code>SWT.COMMAND</code>, the message text is displayed to provide + * further information for the user. + * + * @param message + * the new message + * + * @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> + * + * @since 3.3 + */ + /* public */void setMessage(String message) { + checkWidget(); + if (message == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + getQButton().setWhatsThis(message); + } + + @Override + boolean setRadioFocus(boolean tabbing) { + if ((style & SWT.RADIO) == 0 || !getSelection()) { + return false; + } + return tabbing ? setTabItemFocus() : setFocus(); + } + + @Override + boolean setRadioSelection(boolean value) { + if ((style & SWT.RADIO) == 0) { + return false; + } + if (getSelection() != value) { + setSelection(value); + postEvent(SWT.Selection); + } + return true; + } + + @Override + 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 not assign focus to an unselected radio button. + */ + 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; + } + getQButton().setChecked(selected); + } + + /** + * 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 emphasized 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> + * Note that a Button can display an image and text simultaneously on + * Windows (starting with XP), GTK+ and OSX. On other platforms, a Button + * that has an image and text set into it will display the image or text + * that was set most recently. + * </p> + * + * @param string + * the new text + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the text is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setText(String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if ((style & SWT.ARROW) != 0) { + return; + } + getQButton().setText(string); + } + + private final class MyQCheckBox extends QCheckBox { + + @Override + protected void mousePressEvent(QMouseEvent e) { + super.mousePressEvent(e); + e.setAccepted(false); + } + + } + + private final class MyQRadioButton extends QRadioButton { + + @Override + protected void mousePressEvent(QMouseEvent e) { + super.mousePressEvent(e); + e.setAccepted(false); + } + + } + + private final class MyQPushButton extends QPushButton { + + @Override + protected void mousePressEvent(QMouseEvent e) { + super.mousePressEvent(e); + e.setAccepted(false); + } + + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Canvas.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Canvas.java new file mode 100644 index 0000000000..4ae2a9a9ed --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Canvas.java @@ -0,0 +1,355 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.QObject; +import com.trolltech.qt.gui.QPaintEvent; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Rectangle; + +/** + * Instances of this class provide a surface for drawing arbitrary graphics. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>(none)</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * This class may be subclassed by custom control implementors who are building + * controls that are <em>not</em> constructed from aggregates of other controls. + * That is, they are either painted using SWT graphics calls or are handled by + * native methods. + * </p> + * + * @see Composite + * @see <a href="http://www.eclipse.org/swt/snippets/#canvas">Canvas + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + */ + +public class Canvas extends Composite { + Caret caret; + IME ime; + + /** + * 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> + * </ul> + * + * @see SWT + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public Canvas(Composite parent, int style) { + super(parent, style); + } + + /** + * Fills the interior of the rectangle specified by the arguments, with the + * receiver's background. + * + * @param gc + * the gc where the rectangle is to be filled + * @param x + * the x coordinate of the rectangle to be filled + * @param y + * the y coordinate of the rectangle to be filled + * @param width + * the width of the rectangle to be filled + * @param height + * the height of the rectangle to be filled + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the gc is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the gc has been disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public void drawBackground(GC gc, int x, int y, int width, int height) { + checkWidget(); + if (gc == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (gc.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + Color gcBG = gc.getBackground(); + gc.setBackground(getBackground()); + gc.fillRectangle(x, y, width, height); + gc.setBackground(gcBG); + } + + /** + * Returns the caret. + * <p> + * The caret for the control is automatically hidden and shown when the + * control is painted or resized, when focus is gained or lost and when an + * the control is scrolled. To avoid drawing on top of the caret, the + * programmer must hide and show the caret when drawing in the window any + * other time. + * </p> + * + * @return the caret for the receiver, may be null + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Caret getCaret() { + checkWidget(); + return caret; + } + + /** + * Returns the IME. + * + * @return the IME + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public IME getIME() { + checkWidget(); + return ime; + } + + @Override + void releaseChildren(boolean destroy) { + if (caret != null) { + caret.release(false); + caret = null; + } + if (ime != null) { + ime.release(false); + ime = null; + } + super.releaseChildren(destroy); + } + + /** + * Scrolls a rectangular area of the receiver by first copying the source + * area to the destination and then causing the area of the source which is + * not covered by the destination to be repainted. Children that intersect + * the rectangle are optionally moved during the operation. In addition, + * outstanding paint events are flushed before the source area is copied to + * ensure that the contents of the canvas are drawn correctly. + * + * @param destX + * the x coordinate of the destination + * @param destY + * the y coordinate of the destination + * @param x + * the x coordinate of the source + * @param y + * the y coordinate of the source + * @param width + * the width of the area + * @param height + * the height of the area + * @param all + * <code>true</code>if children should be scrolled, and + * <code>false</code> otherwise + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void scroll(int destX, int destY, int x, int y, int width, int height, boolean all) { + checkWidget(); + if (width <= 0 || height <= 0) { + return; + } + int deltaX = destX - x, deltaY = destY - y; + if (deltaX == 0 && deltaY == 0) { + return; + } + if (!isVisible()) { + return; + } + + //getQWidget().scroll(deltaX, deltaY, new QRect(x, y, width, height)); + + if (all) { + Control[] children = _getChildren(); + for (int i = 0; i < children.length; i++) { + Control child = children[i]; + Rectangle rect = child.getBounds(); + if (Math.min(x + width, rect.x + rect.width) >= Math.max(x, rect.x) + && Math.min(y + height, rect.y + rect.height) >= Math.max(y, rect.y)) { + child.setLocation(rect.x + deltaX, rect.y + deltaY); + } + } + } + getQMasterWidget().update(); + } + + /** + * Sets the receiver's caret. + * <p> + * The caret for the control is automatically hidden and shown when the + * control is painted or resized, when focus is gained or lost and when an + * the control is scrolled. To avoid drawing on top of the caret, the + * programmer must hide and show the caret when drawing in the window any + * other time. + * </p> + * + * @param caret + * the new caret for the receiver, may be null + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the caret has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setCaret(Caret caret) { + checkWidget(); + Caret newCaret = caret; + Caret oldCaret = this.caret; + this.caret = newCaret; + if (hasFocus()) { + if (oldCaret != null) { + oldCaret.killFocus(); + } + if (newCaret != null) { + if (newCaret.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + newCaret.setFocus(); + } + } + } + + @Override + public void setFont(Font font) { + checkWidget(); + if (caret != null) { + caret.setFont(font); + } + super.setFont(font); + } + + /** + * Sets the receiver's IME. + * + * @param ime + * the new IME for the receiver, may be null + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the IME has been disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public void setIME(IME ime) { + checkWidget(); + if (ime != null && ime.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + this.ime = ime; + } + + @Override + public boolean qtPaintEvent(QObject source, QPaintEvent paintEvent) { + boolean ret = super.qtPaintEvent(source, paintEvent); + if (source == getQWidget()) { + if (caret != null) { + isOngoingPaintEvent = true; + try { + caret.draw(); + } finally { + isOngoingPaintEvent = false; + } + } + } + return ret; + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Caret.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Caret.java new file mode 100644 index 0000000000..6e7d0c24f6 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Caret.java @@ -0,0 +1,590 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.GCData; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; + +/** + * Instances of this class provide an i-beam that is typically used as the + * insertion point for text. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>(none)</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> within the + * SWT implementation. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#caret">Caret snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample, Canvas tab</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class Caret extends Widget { + private static final int DEFAULT_WIDTH = 1; + private Canvas parent; + private int x, y; + private int width = DEFAULT_WIDTH; + private int height; + private boolean isVisible; + private Image image; + private Font font; + private Color carentBG; + + /** + * 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; + carentBG = new Color(display, 0, 0, 0); + if (parent.getCaret() == null) { + parent.setCaret(this); + } + } + + /** + * 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); + } + + /** + * Returns the font that the receiver will use to paint textual information. + * + * @return the receiver's font + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Font getFont() { + checkWidget(); + if (font != null) { + return font; + } + return parent.getFont(); + } + + /** + * Returns the image that the receiver will use to paint the caret. + * + * @return the receiver's image + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Image getImage() { + checkWidget(); + return image; + } + + /** + * Returns a point describing the receiver's location relative to its parent + * (or its display if its parent is null). + * + * @return the receiver's location + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Point getLocation() { + checkWidget(); + return new Point(x, y); + } + + /** + * Returns the receiver's parent, which must be a <code>Canvas</code>. + * + * @return the receiver's parent + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Canvas getParent() { + checkWidget(); + return parent; + } + + /** + * Returns a point describing the receiver's size. + * + * @return the receiver's size + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Point getSize() { + checkWidget(); + if (image != null) { + Rectangle rect = image.getBounds(); + return new Point(rect.width, rect.height); + } + 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; + } + + /** + * Returns <code>true</code> if the receiver is visible and all of the + * receiver's ancestors are visible and <code>false</code> otherwise. + * + * @return the receiver's visibility state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #getVisible + */ + public boolean isVisible() { + checkWidget(); + return isVisible && parent.isVisible() && parent.hasFocus(); + } + + /** + * 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; + } + + @Override + void releaseParent() { + super.releaseParent(); + if (this == parent.getCaret()) { + parent.setCaret(null); + } + } + + @Override + void releaseWidget() { + parent = null; + image = null; + font = null; + carentBG.dispose(); + carentBG = null; + } + + /** + * Sets the receiver's size and location to the rectangular area specified + * by the arguments. The <code>x</code> and <code>y</code> arguments are + * relative to the receiver's parent (or its display if its parent is null). + * + * @param x + * the new x coordinate for the receiver + * @param y + * the new y coordinate for the receiver + * @param width + * the new width for the receiver + * @param height + * the new height for the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setBounds(int x, int y, int width, int height) { + checkWidget(); + //System.out.println("Caret.setBounds(" + x + ", " + y + ", " + width + ", " + height + ")"); + boolean moved = this.x != x || this.y != y; + boolean resized = this.width != width || this.height != height; + if (!(moved || resized)) { + return; + } + + // invalidate old location + parent.getQWidget().update(this.x, this.y, this.width, this.height); + + this.x = x; + this.y = y; + this.width = Math.max(width, DEFAULT_WIDTH); + this.height = height; + + // invalidate new location + parent.getQWidget().update(this.x, this.y, this.width, this.height); + } + + /** + * 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 killFocus() { + //focus = false; + } + + void setFocus() { + //focus = true; + } + + /** + * Sets the font that the receiver will use to paint textual information to + * the font specified by the argument, or to the default font for that kind + * of control if the argument is null. + * + * @param font + * the new font (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the font has been disposed + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setFont(Font font) { + checkWidget(); + if (font != null && font.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + this.font = font; + } + + /** + * Sets the image that the receiver will use to paint the caret to the image + * specified by the argument, or to the default which is a filled rectangle + * if the argument is null + * + * @param image + * the new image (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the image has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setImage(Image image) { + checkWidget(); + if (image != null && image.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + this.image = image; + // resize(); + } + + /** + * 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; + } + setBounds(x, y, width, height); + } + + /** + * Sets the receiver's location to the point specified by the argument which + * is relative to the receiver's parent (or its display if its parent is + * null). + * + * @param location + * the new location for the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setLocation(Point location) { + checkWidget(); + if (location == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + setLocation(location.x, location.y); + } + + /** + * Sets the receiver's size to the point specified by the arguments. + * + * @param width + * the new width for the receiver + * @param height + * the new height for the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setSize(int width, int height) { + checkWidget(); + if (this.width == width && this.height == height) { + return; + } + setBounds(x, y, width, height); + } + + /** + * Sets the receiver's size to the point specified by the argument. + * + * @param size + * the new extent for the receiver + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setSize(Point size) { + checkWidget(); + if (size == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + setSize(size.x, size.y); + } + + void draw() { + if (!isVisible || parent == null || parent.isDisposed()) { + return; + } + //System.out.println("caret paint: " + this + " @ " + getLocation()); + GCData data = new GCData(); + data.device = display; + GC gc = GC.qt_new(parent, parent.getQWidget(), data); + // GdkColor color = new GdkColor (); + // color.red = (short) 0xffff; + // color.green = (short) 0xffff; + // color.blue = (short) 0xffff; + // int /*long*/ colormap = OS.gdk_colormap_get_system (); + // OS.gdk_colormap_alloc_color (colormap, color, true, true); + // OS.gdk_gc_set_foreground (gc, color); + // OS.gdk_gc_set_function (gc, OS.GDK_XOR); + // if (image != null && !image.isDisposed() && image.mask == 0) { + // int[] width = new int[1]; + // int[] height = new int[1]; + // OS.gdk_drawable_get_size(image.pixmap, width, height); + // int nX = x; + // if ((parent.style & SWT.MIRRORED) != 0) { + // nX = parent.getClientWidth() - width[0] - nX; + // } + // OS.gdk_draw_drawable(window, gc, image.pixmap, 0, 0, nX, y, width[0], height[0]); + // } else { + int nWidth = width, nHeight = height; + if (nWidth <= 0) { + nWidth = DEFAULT_WIDTH; + } + int nX = x; + if ((parent.style & SWT.MIRRORED) != 0) { + nX = parent.getClientWidth() - nWidth - nX; + } + data.backgroundColor = carentBG; + gc.fillRectangle(nX, y, nWidth, nHeight); + gc.dispose(); + //} + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ColorDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ColorDialog.java new file mode 100644 index 0000000000..bb98ecabfe --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ColorDialog.java @@ -0,0 +1,164 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.gui.QColor; +import com.trolltech.qt.gui.QColorDialog; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.PaletteData; +import org.eclipse.swt.graphics.RGB; + +/** + * Instances of this class allow the user to select a color from a predefined + * set of available colors. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>(none)</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> within the + * SWT implementation. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample, Dialog tab</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class ColorDialog extends Dialog { + Display display; + int width, height; + RGB initialRGB; + QColorDialog cd; + + /** + * Constructs a new instance of this class given only its parent. + * + * @param parent + * a composite control which will be the parent of the new + * instance + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public ColorDialog(Shell parent) { + this(parent, SWT.APPLICATION_MODAL); + } + + /** + * Constructs a new instance of this class given its parent and a style + * value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a composite control which will be the parent of the new + * instance (cannot be null) + * @param style + * the style of control to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public ColorDialog(Shell parent, int style) { + super(parent, checkStyle(parent, style)); + checkSubclass(); + cd = new QColorDialog(); + + } + + /** + * 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() { + QColor color = cd.currentColor(); + RGB rgb = new RGB(color.red(), color.green(), color.blue()); + 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() { + cd.exec(); + QColor color = cd.selectedColor(); + cd.disposeLater(); + return new RGB(color.red(), color.green(), color.blue()); + } + + /** + * Sets the receiver's selected color to be the argument. + * + * @param rgb + * the new RGB value for the selected color, may be null to let + * the platform select a default when open() is called + * @see PaletteData#getRGBs + */ + public void setRGB(RGB rgb) { + cd.setCurrentColor(new QColor(rgb.red, rgb.green, rgb.blue)); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Combo.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Combo.java new file mode 100644 index 0000000000..bb0ab32767 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Combo.java @@ -0,0 +1,1398 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import java.util.Arrays; + +import com.trolltech.qt.core.QObject; +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.core.Qt.LayoutDirection; +import com.trolltech.qt.gui.QComboBox; +import com.trolltech.qt.gui.QFrame; +import com.trolltech.qt.gui.QLineEdit; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QComboBox.InsertPolicy; +import com.trolltech.qt.gui.QComboBox.SizeAdjustPolicy; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.events.VerifyListener; +import org.eclipse.swt.graphics.Point; + +/** + * Instances of this class are controls that allow the user to choose an item + * from a list of items, or optionally enter a new value by typing it into an + * editable text field. Often, <code>Combo</code>s are used in the same place + * where a single selection <code>List</code> widget could be used but space is + * limited. A <code>Combo</code> takes less space than a <code>List</code> + * widget and shows similar information. + * <p> + * Note: Since <code>Combo</code>s can contain both a list and an editable text + * field, it is possible to confuse methods which access one versus the other + * (compare for example, <code>clearSelection()</code> and + * <code>deselectAll()</code>). The API documentation is careful to indicate + * either "the receiver's list" or the "the receiver's text field" to + * distinguish between the two cases. + * </p> + * <p> + * Note that although this class is a subclass of <code>Composite</code>, it + * does not make sense to add children to it, or set a layout on it. + * </p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>DROP_DOWN, READ_ONLY, SIMPLE</dd> + * <dt><b>Events:</b></dt> + * <dd>DefaultSelection, Modify, Selection, Verify</dd> + * </dl> + * <p> + * Note: Only one of the styles DROP_DOWN and SIMPLE may be specified. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see List + * @see <a href="http://www.eclipse.org/swt/snippets/#combo">Combo snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class Combo extends Composite { + /** + * 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 = new QLineEdit().maxLength(); + } + + /** + * 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)); + } + + @Override + protected QComboBox createQWidget(int style) { + QComboBox combo = new QComboBox(); + combo.setEditable(true); + combo.setSizeAdjustPolicy(SizeAdjustPolicy.AdjustToMinimumContentsLength); + // Disable the ability to add edited text at the end + combo.setInsertPolicy(InsertPolicy.NoInsert); + if ((style & SWT.READ_ONLY) != 0) { + combo.lineEdit().setReadOnly(true); + } + return combo; + } + + private QComboBox getQComboBox() { + return (QComboBox) getQWidget(); + } + + @Override + protected void connectSignals() { + getQComboBox().activatedIndex.connect(this, "qtActivatedIndexEvent(int)"); //$NON-NLS-1$ + getQComboBox().lineEdit().returnPressed.connect(this, "qtReturnPressedEvent()"); //$NON-NLS-1$ + getQComboBox().editTextChanged.connect(this, "qtEditTextChangedEvent(String)"); //$NON-NLS-1$ + } + + protected void qtActivatedIndexEvent(int index) { + setSelection(new Point(0, getQComboBox().lineEdit().text().length())); + sendEvent(SWT.Selection); + } + + protected void qtReturnPressedEvent() { + sendEvent(SWT.DefaultSelection); + } + + protected void qtEditTextChangedEvent(String text) { + sendEvent(SWT.Modify); + } + + /** + * Adds the argument to the end of the receiver's list. + * + * @param string + * the new item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #add(String,int) + */ + public void add(String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + getQComboBox().addItem(string); + } + + /** + * Adds the argument to the receiver's list at the given zero-relative + * index. + * <p> + * Note: To add an item at the end of the list, use the result of calling + * <code>getItemCount()</code> as the index or use <code>add(String)</code>. + * </p> + * + * @param string + * the new item + * @param index + * the index for the item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list (inclusive)</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #add(String) + */ + public void add(String string, int index) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + getQComboBox().insertItem(index, string); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the receiver's text is modified, by sending it one of the messages + * defined in the <code>ModifyListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ModifyListener + * @see #removeModifyListener + */ + public void addModifyListener(ModifyListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Modify, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the user changes the receiver's selection, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * <code>widgetSelected</code> is called when the user changes the combo's + * list selection. <code>widgetDefaultSelected</code> is typically called + * when ENTER is pressed the combo's text area. + * </p> + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the receiver's text is verified, by sending it one of the messages + * defined in the <code>VerifyListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see VerifyListener + * @see #removeVerifyListener + * + * @since 3.1 + */ + public void addVerifyListener(VerifyListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Verify, typedListener); + } + + @Override + 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(); + getQComboBox().lineEdit().setCursorPosition(0); + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + checkWidget(); + if (changed) { + getQWidget().updateGeometry(); + } + + // to get the maximum row length depending on the content, + // set size policy to QComboBox::AdjustToContents. but it has drawback + // that + // it doesn't allow resizing so we have to set back size policy after + // compute size + getQComboBox().setSizeAdjustPolicy(SizeAdjustPolicy.AdjustToContents); + QSize size = getQWidget().sizeHint(); + Point sizeHint = new Point(size.width(), size.height()); + + int width = DEFAULT_WIDTH; + int height = DEFAULT_HEIGHT; + if (sizeHint.x >= 0) { + width = sizeHint.x; + } + if (sizeHint.y >= 0) { + height = sizeHint.y; + } + if (wHint != SWT.DEFAULT) { + width = wHint; + } + if (hHint != SWT.DEFAULT && hHint < sizeHint.y) { + height = hHint; + } + + // sets the size policy back to default so that resizing will be allowed + getQComboBox().setSizeAdjustPolicy(SizeAdjustPolicy.AdjustToMinimumContentsLength); + 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(); + getQComboBox().lineEdit().copy(); + } + + /** + * Cuts the selected text. + * <p> + * The current selection is first copied to the clipboard and then deleted + * from the widget. + * </p> + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 2.1 + */ + public void cut() { + checkWidget(); + getQComboBox().lineEdit().cut(); + } + + /** + * Deselects the item at the given zero-relative index in the receiver's + * list. If the item at the index was already deselected, it remains + * deselected. Indices that are out of range are ignored. + * + * @param index + * the index of the item to deselect + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void deselect(int index) { + checkWidget(); + if (getSelectionIndex() == index) { + deselectAll(); + } + } + + /** + * 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(); + getQComboBox().setCurrentIndex(-1); + sendEvent(SWT.Modify); + } + + /** + * Returns the item at the given, zero-relative index in the receiver's + * list. Throws an exception if the index is out of range. + * + * @param index + * the index of the item to return + * @return the item at the given index + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list minus 1 (inclusive) + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String getItem(int index) { + checkWidget(); + return getQComboBox().itemText(index); + } + + /** + * Returns the number of items contained in the receiver's list. + * + * @return the number of items + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getItemCount() { + checkWidget(); + return getQComboBox().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> + */ + public int getItemHeight() { + checkWidget(); + return getQComboBox().view().sizeHintForRow(0); + } + + /** + * Returns a (possibly empty) array of <code>String</code>s which are the + * items in the receiver's list. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its list of items, so modifying the array will not affect the receiver. + * </p> + * + * @return the items in the receiver's list + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String[] getItems() { + checkWidget(); + int count = getItemCount(); + String[] result = new String[count]; + for (int i = 0; i < count; i++) { + result[i] = getItem(i); + } + return result; + } + + /** + * Returns <code>true</code> if the receiver's list is visible, and + * <code>false</code> otherwise. + * <p> + * If one of the receiver's ancestors is not visible or some other condition + * makes the receiver not visible, this method may still indicate that it is + * considered visible even though it may not actually be showing. + * </p> + * + * @return the receiver's list's visibility state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public boolean getListVisible() { + checkWidget(); + java.util.List<QObject> children = getQComboBox().children(); + for (QObject child : children) { + if (child.isWidgetType() && child instanceof QFrame) { + return ((QWidget) child).isVisible(); + } + } + return false; + } + + @Override + String getNameText() { + return getText(); + } + + /** + * Marks the receiver's list as visible if the argument is <code>true</code> + * , and marks it invisible otherwise. + * <p> + * If one of the receiver's ancestors is not visible or some other condition + * makes the receiver not visible, marking it visible may not actually cause + * it to be displayed. + * </p> + * + * @param visible + * the new visibility state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public void setListVisible(boolean visible) { + checkWidget(); + if (visible) { + getQComboBox().showPopup(); + } else { + getQComboBox().hidePopup(); + } + } + + /** + * Returns the orientation of the receiver. + * + * @return the orientation style + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 2.1.2 + */ + public int getOrientation() { + checkWidget(); + return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT); + } + + /** + * Returns a <code>Point</code> whose x coordinate is the character position + * representing the start of the selection in the receiver's text field, and + * whose y coordinate is the character position representing the end of the + * selection. An "empty" selection is indicated by the x and y coordinates + * having the same value. + * <p> + * Indexing is zero based. The range of a selection is from 0..N where N is + * the number of characters in the widget. + * </p> + * + * @return a point representing the selection start and end + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Point getSelection() { + checkWidget(); + int start = getQComboBox().lineEdit().selectionStart(); + int end = getQComboBox().lineEdit().cursorPosition(); + return new Point(start == -1 ? end : start, end); + } + + /** + * 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(); + return getQComboBox().currentIndex(); + } + + /** + * Returns a string containing a copy of the contents of the receiver's text + * field, or an empty string if there are no contents. + * + * @return the receiver's text + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String getText() { + checkWidget(); + return getQComboBox().currentText(); + } + + /** + * Returns the height of the receivers's text field. + * + * @return the text height + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getTextHeight() { + checkWidget(); + return getQComboBox().lineEdit().sizeHint().height(); + } + + /** + * Returns the maximum number of characters that the receiver's text field + * is capable of holding. If this has not been changed by + * <code>setTextLimit()</code>, it will be the constant + * <code>Combo.LIMIT</code>. + * + * @return the text limit + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #LIMIT + */ + public int getTextLimit() { + checkWidget(); + return getQComboBox().lineEdit().maxLength(); + } + + /** + * Gets the number of items that are visible in the drop down portion of the + * receiver's list. + * <p> + * Note: This operation is a hint and is not supported on platforms that do + * not have this concept. + * </p> + * + * @return the number of items that are visible + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ + public int getVisibleItemCount() { + checkWidget(); + return getQComboBox().maxVisibleItems(); + } + + /** + * Searches the receiver's list starting at the first item (index 0) until + * an item is found that is equal to the argument, and returns the index of + * that item. If no item is found, returns -1. + * + * @param string + * the search item + * @return the index of the item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int indexOf(String string) { + return indexOf(string, 0); + } + + /** + * Searches the receiver's list starting at the given, zero-relative index + * until an item is found that is equal to the argument, and returns the + * index of that item. If no item is found or the starting index is out of + * range, returns -1. + * + * @param string + * the search item + * @param start + * the zero-relative index at which to begin the search + * @return the index of the item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int indexOf(String string, int start) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + int index = getQComboBox().findText(string); + if (!(0 <= start && start <= index)) { + return -1; + } + 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(); + getQComboBox().lineEdit().paste(); + } + + /** + * Removes the item from the receiver's list at the given zero-relative + * index. + * + * @param index + * the index for the item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list minus 1 (inclusive) + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void remove(int index) { + checkWidget(); + int count = getItemCount(); + if (!(index < count && index >= 0)) { + error(SWT.ERROR_INVALID_RANGE); + } + getQComboBox().removeItem(index); + } + + /** + * Removes the items from the receiver's list which are between the given + * zero-relative start and end indices (inclusive). + * + * @param start + * the start of the range + * @param end + * the end of the range + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if either the start or end are + * not between 0 and the number of elements in the list minus + * 1 (inclusive)</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void remove(int start, int end) { + checkWidget(); + int count = getItemCount(); + if (!(start < count && start >= 0 && end < count)) { + error(SWT.ERROR_INVALID_RANGE); + } + if (start > end) { + return; + } + for (int i = end; i >= start; --i) { + getQComboBox().removeItem(i); + } + } + + /** + * Searches the receiver's list starting at the first item until an item is + * found that is equal to the argument, and removes that item from the list. + * + * @param string + * the item to remove + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the string is not found in + * the list</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void remove(String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + int index = indexOf(string, 0); + if (index == -1) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + remove(index); + } + + /** + * Removes all of the items from the receiver's list and clear the contents + * of receiver's text field. + * <p> + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + */ + public void removeAll() { + checkWidget(); + getQComboBox().clear(); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the receiver's text is modified. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ModifyListener + * @see #addModifyListener + */ + public void removeModifyListener(ModifyListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Modify, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the user changes the receiver's selection. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is verified. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see VerifyListener + * @see #addVerifyListener + * + * @since 3.1 + */ + public void removeVerifyListener(VerifyListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Verify, listener); + } + + /** + * Selects the item at the given zero-relative index in the receiver's list. + * If the item at the index was already selected, it remains selected. + * Indices that are out of range are ignored. + * + * @param index + * the index of the item to select + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void select(int index) { + checkWidget(); + int count = getItemCount(); + if (index < 0 || index >= count) { + return; + } + getQComboBox().setCurrentIndex(index); + } + + /** + * Sets the text of the item in the receiver's list at the given + * zero-relative index to the string argument. + * + * @param index + * the index for the item + * @param string + * the new text for the item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list minus 1 (inclusive) + * </li> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setItem(int index, String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + int selection = getSelectionIndex(); + remove(index); + if (isDisposed()) { + return; + } + add(string, index); + if (selection != -1) { + select(selection); + } + } + + /** + * Sets the receiver's list to be the given array of items. + * + * @param items + * the array of items + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the items array is null</li> + * <li>ERROR_INVALID_ARGUMENT - if an item in the items array + * is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setItems(String[] items) { + checkWidget(); + if (items == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + for (int i = 0; i < items.length; i++) { + if (items[i] == null) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + } + getQComboBox().addItems(Arrays.asList(items)); + } + + /** + * Sets the orientation of the receiver, which must be one of the constants + * <code>SWT.LEFT_TO_RIGHT</code> or <code>SWT.RIGHT_TO_LEFT</code>. + * <p> + * + * @param orientation + * new orientation style + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + * + * @since 2.1.2 + */ + public void setOrientation(int orientation) { + checkWidget(); + int flags = SWT.RIGHT_TO_LEFT | SWT.LEFT_TO_RIGHT; + if ((orientation & flags) == 0 || (orientation & flags) == flags) { + return; + } + + style &= ~flags; + style |= orientation & flags; + + getQWidget().setLayoutDirection( + orientation == SWT.LEFT_TO_RIGHT ? LayoutDirection.LeftToRight : LayoutDirection.RightToLeft); + } + + /** + * Sets the selection in the receiver's text field to the range specified by + * the argument whose x coordinate is the start of the selection and whose y + * coordinate is the end of the selection. + * + * @param selection + * a point representing the new selection start and end + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setSelection(Point selection) { + checkWidget(); + if (selection == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + int start = selection.x, end = selection.y; + getQComboBox().lineEdit().setSelection(start, (end - start)); + } + + /** + * 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 string + * the new text + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setText(String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if ((style & SWT.READ_ONLY) != 0) { + int index = indexOf(string); + if (index != -1) { + select(index); + } + return; + } + getQComboBox().setEditText(string); + sendEvent(SWT.Modify); + } + + /** + * Sets the maximum number of characters that the receiver's text field is + * capable of holding to be the argument. + * <p> + * To reset this value to the default, use + * <code>setTextLimit(Combo.LIMIT)</code>. Specifying a limit value larger + * than <code>Combo.LIMIT</code> sets the receiver's limit to + * <code>Combo.LIMIT</code>. + * </p> + * + * @param limit + * new text limit + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #LIMIT + */ + public void setTextLimit(int limit) { + checkWidget(); + if (limit <= 0) { + error(SWT.ERROR_CANNOT_BE_ZERO); + } + if (limit > LIMIT) { + limit = LIMIT; + } + getQComboBox().lineEdit().setMaxLength(limit); + } + + /** + * Sets the number of items that are visible in the drop down portion of the + * receiver's list. + * <p> + * Note: This operation is a hint and is not supported on platforms that do + * not have this concept. + * </p> + * + * @param count + * the new number of items to be visible + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ + public void setVisibleItemCount(int count) { + checkWidget(); + if (count < 0) { + return; + } + getQComboBox().setMaxVisibleItems(count); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Composite.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Composite.java new file mode 100644 index 0000000000..374d7c9f88 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Composite.java @@ -0,0 +1,1301 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import java.util.Collection; +import java.util.LinkedList; + +import com.trolltech.qt.core.QObject; +import com.trolltech.qt.core.QPoint; +import com.trolltech.qt.core.Qt.FocusReason; +import com.trolltech.qt.gui.QLabel; +import com.trolltech.qt.gui.QMouseEvent; +import com.trolltech.qt.gui.QResizeEvent; +import com.trolltech.qt.gui.QScrollArea; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QPalette.ColorRole; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; + +/** + * Instances of this class are controls which are capable of containing other + * controls. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>NO_BACKGROUND, NO_FOCUS, NO_MERGE_PAINTS, NO_REDRAW_RESIZE, + * NO_RADIO_GROUP, EMBEDDED, DOUBLE_BUFFERED</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * Note: The <code>NO_BACKGROUND</code>, <code>NO_FOCUS</code>, + * <code>NO_MERGE_PAINTS</code>, and <code>NO_REDRAW_RESIZE</code> styles are + * intended for use with <code>Canvas</code>. They can be used with + * <code>Composite</code> if you are drawing your own, but their behavior is + * undefined if they are used with subclasses of <code>Composite</code> other + * than <code>Canvas</code>. + * </p> + * <p> + * Note: The <code>CENTER</code> style, although undefined for composites, has + * the same value as <code>EMBEDDED</code> which is used to embed widgets from + * other widget toolkits into SWT. On some operating systems (GTK, Motif), this + * may cause the children of this composite to be obscured. + * </p> + * <p> + * This class may be subclassed by custom control implementors who are building + * controls that are constructed from aggregates of other controls. + * </p> + * + * @see Canvas + * @see <a href="http://www.eclipse.org/swt/snippets/#composite">Composite + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + */ +public class Composite extends Scrollable { + private Layout layout; + private Control[] tabList; + protected int layoutCount; + private int backgroundMode = SWT.INHERIT_NONE; + + /** + * 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); + } + + @Override + QWidget createQWidget(int style) { + QWidget widget = super.createQWidget(style); + state |= CANVAS; + if ((style & (SWT.H_SCROLL | SWT.V_SCROLL)) == 0) { + state |= THEME_BACKGROUND; + } + if ((style & SWT.TRANSPARENT) != 0) { + System.out.println("TODO: handle SWT.TRANSPARENT"); //$NON-NLS-1$ + } + return widget; + } + + protected void updateAutoFillBackground() { + // if ((style & SWT.NO_BACKGROUND) == 0) { + // getQMasterWidget().setAutoFillBackground(true); + // } else { + // getQMasterWidget().setAutoFillBackground(false); + // System.out.println(this + " no bg"); + // } + } + + protected boolean noBackground() { + return (style & SWT.NO_BACKGROUND) == 1; + } + + @Override + protected void updateBackground() { + if ((state & PARENT_BACKGROUND) == 0) { + updateAutoFillBackground(); + applyBackgroundColor(getDefaultBackgroundColor()); + } else { + super.updateBackground(); + } + } + + @Override + protected ColorRole[] getBackgroundColorRoles() { + if (backgroundMode == SWT.INHERIT_FORCE) { + return super.getBackgroundColorRoles(); + } else { + return new ColorRole[] { ColorRole.Window }; + } + } + + void addQChild(Control control) { + control.getQMasterWidget().setParent(getQWidget()); + } + + 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; + } + + /** + * Clears any data that has been cached by a Layout for all widgets that are + * in the parent hierarchy of the changed control up to and including the + * receiver. If an ancestor does not have a layout, it is skipped. + * + * @param changed + * an array of controls that changed state and require a + * recalculation of size + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the changed array is null + * any of its controls are null or have been disposed</li> + * <li>ERROR_INVALID_PARENT - if any control in changed is + * not in the widget tree of the receiver</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public void changed(Control[] changed) { + checkWidget(); + if (changed == null) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + for (int i = 0; i < changed.length; i++) { + Control control = changed[i]; + if (control == null) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (control.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + boolean ancestor = false; + Composite composite = control.parent; + while (composite != null) { + ancestor = composite == this; + if (ancestor) { + break; + } + composite = composite.parent; + } + if (!ancestor) { + error(SWT.ERROR_INVALID_PARENT); + } + } + for (int i = 0; i < changed.length; i++) { + Control child = changed[i]; + Composite composite = child.parent; + while (child != this) { + if (composite.layout == null || !composite.layout.flushCache(child)) { + composite.state |= LAYOUT_CHANGED; + } + child = composite; + composite = child.parent; + } + } + } + + @Override + protected void checkSubclass() { + /* Do nothing - Subclassing is allowed */ + } + + @Override + 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; + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + checkWidget(); + Point size; + if ((state & CANVAS) != 0) { + if (layout != null) { + if (wHint == SWT.DEFAULT || hHint == SWT.DEFAULT) { + changed |= (state & LAYOUT_CHANGED) != 0; + state &= ~LAYOUT_CHANGED; + size = layout.computeSize(this, wHint, hHint, changed); + } else { + size = new Point(wHint, hHint); + } + } else { + size = minimumSize(wHint, hHint, changed); + } + if (size.x < 0) { + size.x = DEFAULT_WIDTH; + } + if (size.y < 0) { + size.y = DEFAULT_HEIGHT; + } + if (wHint != SWT.DEFAULT && wHint > 0) { + size.x = wHint; + } + if (hHint != SWT.DEFAULT && hHint > 0) { + size.y = hHint; + } + Rectangle trim = computeTrim(0, 0, size.x, size.y); + return new Point(trim.width, trim.height); + } + return super.computeSize(wHint, hHint, changed); + + } + + @Override + boolean isMirrored() { + return (style & SWT.MIRRORED) != 0; + } + + /** + * Copies a rectangular area of the receiver at the specified position using + * the gc. + * + * @param gc + * the gc where the rectangle is to be filled + * @param x + * the x coordinate of the rectangle to be filled + * @param y + * the y coordinate of the rectangle to be filled + * @param width + * the width of the rectangle to be filled + * @param height + * the height of the rectangle to be filled + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the gc is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the gc has been disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + /* public */void copyArea(GC gc, int x, int y, int width, int height) { + checkWidget(); + if (gc == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (gc.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + throw new UnsupportedOperationException("not yet implemented"); //$NON-NLS-1$ + } + + protected Composite findDeferredControl() { + return layoutCount > 0 ? this : parent.findDeferredControl(); + } + + @Override + Menu[] findMenus(Control control) { + if (control == this) { + return new Menu[0]; + } + Menu result[] = super.findMenus(control); + Control[] children = _getChildren(); + for (int i = 0; i < children.length; i++) { + Control child = children[i]; + Menu[] menuList = child.findMenus(control); + if (menuList.length != 0) { + Menu[] newResult = new Menu[result.length + menuList.length]; + System.arraycopy(result, 0, newResult, 0, result.length); + System.arraycopy(menuList, 0, newResult, result.length, menuList.length); + result = newResult; + } + } + return result; + } + + @Override + void fixChildren(Shell newShell, Shell oldShell, Decorations newDecorations, Decorations oldDecorations, + Menu[] menus) { + super.fixChildren(newShell, oldShell, newDecorations, oldDecorations, menus); + Control[] children = _getChildren(); + for (int i = 0; i < children.length; i++) { + children[i].fixChildren(newShell, oldShell, newDecorations, oldDecorations, menus); + } + } + + void fixTabList(Control control) { + if (tabList == null) { + return; + } + int count = 0; + for (int i = 0; i < tabList.length; i++) { + if (tabList[i] == control) { + count++; + } + } + if (count == 0) { + return; + } + Control[] newList = null; + int length = tabList.length - count; + if (length != 0) { + newList = new Control[length]; + int index = 0; + for (int i = 0; i < tabList.length; i++) { + if (tabList[i] != control) { + newList[index++] = tabList[i]; + } + } + } + tabList = newList; + } + + /** + * Returns the receiver's background drawing mode. This will be one of the + * following constants defined in class <code>SWT</code>: + * <code>INHERIT_NONE</code>, <code>INHERIT_DEFAULT</code>, + * <code>INHERTIT_FORCE</code>. + * + * @return the background mode + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SWT + * + * @since 3.2 + */ + public int getBackgroundMode() { + checkWidget(); + return backgroundMode; + } + + /** + * Returns a (possibly empty) array containing the receiver's children. + * Children are returned in the order that they are drawn. The topmost + * control appears at the beginning of the array. Subsequent controls draw + * beneath this control and appear later in the array. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its list of children, so modifying the array will not affect the + * receiver. + * </p> + * + * @return an array of children + * + * @see Control#moveAbove + * @see Control#moveBelow + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Control[] getChildren() { + checkWidget(); + return _getChildren(); + } + + Control[] _getChildren() { + Collection<QObject> qtChildren = getQWidget().children(); + int count = qtChildren.size(); + if (count == 0) { + return new Control[0]; + } + LinkedList<Control> children = new LinkedList<Control>(); + for (QObject qObj : qtChildren) { + Widget widget = display.findControl(qObj); + if (widget != null && widget != this) { + if (widget instanceof Control && !(widget instanceof Shell)) { + children.addFirst((Control) widget); + } + } + } + return children.toArray(new Control[children.size()]); + } + + int getChildrenCount() { + return getQWidget().children().size(); + } + + /** + * 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 (possibly empty) tabbing order for the control. + * + * @return tabList the ordered list of controls representing the tab order + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #setTabList + */ + public Control[] getTabList() { + checkWidget(); + Control[] tabList = _getTabList(); + if (tabList == null) { + int count = 0; + Control[] list = _getChildren(); + for (int i = 0; i < list.length; i++) { + if (list[i].isTabGroup()) { + count++; + } + } + tabList = new Control[count]; + int index = 0; + for (int i = 0; i < list.length; i++) { + if (list[i].isTabGroup()) { + tabList[index++] = list[i]; + } + } + } + return tabList; + } + + boolean hooksKeys() { + return hooks(SWT.KeyDown) || hooks(SWT.KeyUp); + } + + /** + * Returns <code>true</code> if the receiver has deferred the performing of + * layout, and <code>false</code> otherwise. + * + * @return the receiver's deferred layout state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #setLayoutDeferred(boolean) + * @see #isLayoutDeferred() + * + * @since 3.1 + */ + public boolean getLayoutDeferred() { + checkWidget(); + return layoutCount > 0; + } + + /** + * Returns <code>true</code> if the receiver or any ancestor up to and + * including the receiver's nearest ancestor shell has deferred the + * performing of layouts. Otherwise, <code>false</code> is returned. + * + * @return the receiver's deferred layout state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #setLayoutDeferred(boolean) + * @see #getLayoutDeferred() + * + * @since 3.1 + */ + public boolean isLayoutDeferred() { + checkWidget(); + return findDeferredControl() != null; + } + + /** + * If the receiver has a layout, asks the layout to <em>lay out</em> (that + * is, set the size and location of) the receiver's children. If the + * receiver does not have a layout, do nothing. + * <p> + * This is equivalent to calling <code>layout(true)</code>. + * </p> + * <p> + * Note: Layout is different from painting. If a child is moved or resized + * such that an area in the parent is exposed, then the parent will paint. + * If no child is affected, the parent will not paint. + * </p> + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void layout() { + checkWidget(); + layout(true); + } + + @Override + protected void updateLayout() { + layout(true, true); + } + + /** + * If the receiver has a layout, asks the layout to <em>lay out</em> (that + * is, set the size and location of) the receiver's children. If the + * argument is <code>true</code> the layout must not rely on any information + * it has cached about the immediate children. If it is <code>false</code> + * the layout may (potentially) optimize the work it is doing by assuming + * that none of the receiver's children has changed state since the last + * layout. If the receiver does not have a layout, do nothing. + * <p> + * If a child is resized as a result of a call to layout, the resize event + * will invoke the layout of the child. The layout will cascade down through + * all child widgets in the receiver's widget tree until a child is + * encountered that does not resize. Note that a layout due to a resize will + * not flush any cached information (same as <code>layout(false)</code>). + * </p> + * <p> + * Note: Layout is different from painting. If a child is moved or resized + * such that an area in the parent is exposed, then the parent will paint. + * If no child is affected, the parent will not paint. + * </p> + * + * @param changed + * <code>true</code> if the layout must flush its caches, and + * <code>false</code> otherwise + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void layout(boolean changed) { + checkWidget(); + if (layout == null) { + return; + } + layout(changed, false); + } + + /** + * If the receiver has a layout, asks the layout to <em>lay out</em> (that + * is, set the size and location of) the receiver's children. If the changed + * argument is <code>true</code> the layout must not rely on any information + * it has cached about its children. If it is <code>false</code> the layout + * may (potentially) optimize the work it is doing by assuming that none of + * the receiver's children has changed state since the last layout. If the + * all argument is <code>true</code> the layout will cascade down through + * all child widgets in the receiver's widget tree, regardless of whether + * the child has changed size. The changed argument is applied to all + * layouts. If the all argument is <code>false</code>, the layout will + * <em>not</em> cascade down through all child widgets in the receiver's + * widget tree. However, if a child is resized as a result of a call to + * layout, the resize event will invoke the layout of the child. Note that a + * layout due to a resize will not flush any cached information (same as + * <code>layout(false)</code>). </p> + * <p> + * Note: Layout is different from painting. If a child is moved or resized + * such that an area in the parent is exposed, then the parent will paint. + * If no child is affected, the parent will not paint. + * </p> + * + * @param changed + * <code>true</code> if the layout must flush its caches, and + * <code>false</code> otherwise + * @param all + * <code>true</code> if all children in the receiver's widget + * tree should be laid out, and <code>false</code> otherwise + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public void layout(boolean changed, boolean all) { + checkWidget(); + if (layout == null && !all) { + return; + } + markLayout(changed, all); + updateLayout(all); + } + + /** + * Forces a lay out (that is, sets the size and location) of all widgets + * that are in the parent hierarchy of the changed control up to and + * including the receiver. The layouts in the hierarchy must not rely on any + * information cached about the changed control or any of its ancestors. The + * layout may (potentially) optimize the work it is doing by assuming that + * none of the peers of the changed control have changed state since the + * last layout. If an ancestor does not have a layout, skip it. + * <p> + * Note: Layout is different from painting. If a child is moved or resized + * such that an area in the parent is exposed, then the parent will paint. + * If no child is affected, the parent will not paint. + * </p> + * + * @param changed + * a control that has had a state change which requires a + * recalculation of its size + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the changed array is null + * any of its controls are null or have been disposed</li> + * <li>ERROR_INVALID_PARENT - if any control in changed is + * not in the widget tree of the receiver</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public void layout(Control[] changed) { + checkWidget(); + if (changed == null) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + for (int i = 0; i < changed.length; i++) { + Control control = changed[i]; + if (control == null) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (control.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + boolean ancestor = false; + Composite composite = control.parent; + while (composite != null) { + ancestor = composite == this; + if (ancestor) { + break; + } + composite = composite.parent; + } + if (!ancestor) { + error(SWT.ERROR_INVALID_PARENT); + } + } + int updateCount = 0; + Composite[] update = new Composite[16]; + for (int i = 0; i < changed.length; i++) { + Control child = changed[i]; + Composite composite = child.parent; + while (child != this) { + if (composite.layout != null) { + composite.state |= LAYOUT_NEEDED; + if (!composite.layout.flushCache(child)) { + composite.state |= LAYOUT_CHANGED; + } + } + if (updateCount == update.length) { + Composite[] newUpdate = new Composite[update.length + 16]; + System.arraycopy(update, 0, newUpdate, 0, update.length); + update = newUpdate; + } + child = update[updateCount++] = composite; + composite = child.parent; + } + } + for (int i = updateCount - 1; i >= 0; i--) { + update[i].updateLayout(false); + } + } + + @Override + void markLayout(boolean changed, boolean all) { + if (layout != null) { + state |= LAYOUT_NEEDED; + if (changed) { + state |= LAYOUT_CHANGED; + } + } + if (all) { + Control[] children = _getChildren(); + for (int i = 0; i < children.length; i++) { + children[i].markLayout(changed, all); + } + } + } + + Point minimumSize(int wHint, int hHint, boolean changed) { + Control[] children = _getChildren(); + int width = 0, height = 0; + for (int i = 0; i < children.length; i++) { + Rectangle rect = children[i].getBounds(); + width = Math.max(width, rect.x + rect.width); + height = Math.max(height, rect.y + rect.height); + } + return new Point(width, height); + } + + @Override + void redrawChildren() { + Control[] children = _getChildren(); + for (int i = 0; i < children.length; i++) { + children[i]._redraw(); + } + } + + @Override + void releaseChildren(boolean destroy) { + Control[] children = _getChildren(); + for (int i = 0; i < children.length; i++) { + Control child = children[i]; + if (child != null && !child.isDisposed()) { + child.release(false); + } + } + super.releaseChildren(destroy); + } + + @Override + void releaseWidget() { + super.releaseWidget(); + layout = null; + tabList = null; + } + + void removeControl(Control control) { + control.getQMasterWidget().setParent(null); + fixTabList(control); + resizeChildren(); + } + + private void resizeChildren() { + if (getQWidget() == null) { + return; + } + for (QObject child : getQWidget().children()) { + if (child.isWidgetType()) { + ((QWidget) child).updateGeometry(); + } + } + } + + /** + * Sets the background drawing mode to the argument which should be one of + * the following constants defined in class <code>SWT</code>: + * <code>INHERIT_NONE</code>, <code>INHERIT_DEFAULT</code>, + * <code>INHERIT_FORCE</code>. + * + * @param mode + * the new background mode + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SWT + * + * @since 3.2 + */ + public void setBackgroundMode(int mode) { + checkWidget(); + if (backgroundMode == mode) { + return; + } + backgroundMode = mode; + Control[] children = _getChildren(); + for (int i = 0; i < children.length; i++) { + children[i].updateBackgroundMode(); + } + } + + @Override + protected void setBounds(int x, int y, int width, int height, boolean move, boolean resize) { + if ((state & CANVAS) != 0) { + state &= ~(RESIZE_OCCURRED | MOVE_OCCURRED); + state |= RESIZE_DEFERRED | MOVE_DEFERRED; + } + super.setBounds(x, y, width, height, move, resize); + if ((state & CANVAS) != 0) { + boolean wasResized = (state & RESIZE_OCCURRED) != 0; + state &= ~(RESIZE_DEFERRED | MOVE_DEFERRED); + if (wasResized && layout != null) { + markLayout(false, false); + updateLayout(false); + } + } + } + + @Override + public boolean setFocus() { + checkWidget(); + return setFocus(FocusReason.OtherFocusReason); + // Control[] children = _getChildren(); + // for (int i = 0; i < children.length; i++) { + // Control child = children[i]; + // if (child.setRadioFocus(false)) + // return true; + // } + // for (int i = 0; i < children.length; i++) { + // Control child = children[i]; + // if (child.setFocus()) + // return true; + // } + // return super.setFocus(); + } + + @Override + protected boolean setFocus(FocusReason focusReason) { + Control[] children = _getChildren(); + for (int i = 0; i < children.length; i++) { + Control child = children[i]; + if (child.getVisible() && child.setFocus(focusReason)) { + return true; + } + } + return super.setFocus(focusReason); + } + + /** + * Sets the layout which is associated with the receiver to be the argument + * which may be null. + * + * @param layout + * the receiver's new layout or null + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setLayout(Layout layout) { + checkWidget(); + this.layout = layout; + } + + /** + * If the argument is <code>true</code>, causes subsequent layout operations + * in the receiver or any of its children to be ignored. No layout of any + * kind can occur in the receiver or any of its children until the flag is + * set to false. Layout operations that occurred while the flag was + * <code>true</code> are remembered and when the flag is set to + * <code>false</code>, the layout operations are performed in an optimized + * manner. Nested calls to this method are stacked. + * + * @param defer + * the new defer state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #layout(boolean) + * @see #layout(Control[]) + * + * @since 3.1 + */ + public void setLayoutDeferred(boolean defer) { + if (!defer) { + if (--layoutCount == 0) { + if ((state & LAYOUT_CHILD) != 0 || (state & LAYOUT_NEEDED) != 0) { + updateLayout(true); + } + } + } else { + layoutCount++; + } + } + + /** + * Sets the tabbing order for the specified controls to match the order that + * they occur in the argument list. + * + * @param tabList + * the ordered list of controls representing the tab order or + * null + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if a widget in the tabList is + * null or has been disposed</li> + * <li>ERROR_INVALID_PARENT - if widget in the tabList is not + * in the same widget tree</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setTabList(Control[] tabList) { + checkWidget(); + if (tabList != null) { + for (int i = 0; i < tabList.length; i++) { + Control control = tabList[i]; + if (control == null) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (control.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (control.parent != this) { + error(SWT.ERROR_INVALID_PARENT); + } + } + Control[] newList = new Control[tabList.length]; + System.arraycopy(tabList, 0, newList, 0, tabList.length); + tabList = newList; + } + this.tabList = tabList; + } + + @Override + boolean setTabGroupFocus() { + if (isTabItem()) { + return setTabItemFocus(); + } + boolean takeFocus = (style & SWT.NO_FOCUS) == 0; + if ((state & CANVAS) != 0) { + takeFocus = hooksKeys(); + if ((style & SWT.EMBEDDED) != 0) { + takeFocus = true; + } + } + 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(true)) { + return true; + } + } + for (int i = 0; i < children.length; i++) { + Control child = children[i]; + if (child.isTabItem() && !child.isTabGroup() && child.setTabItemFocus()) { + return true; + } + } + return false; + } + + @Override + boolean translateMnemonic(Event event, Control control) { + if (super.translateMnemonic(event, control)) { + return true; + } + if (control != null) { + Control[] children = _getChildren(); + for (int i = 0; i < children.length; i++) { + Control child = children[i]; + if (child.translateMnemonic(event, control)) { + return true; + } + } + } + return false; + } + + @Override + void updateBackgroundColor() { + // if (noBackground()) { + // return; + // } + super.updateBackgroundColor(); + for (Control child : _getChildren()) { + if ((child.state & PARENT_BACKGROUND) != 0) { + child.updateBackgroundColor(); + } + } + } + + @Override + void updateBackgroundImage() { + // if (noBackground()) { + // return; + // } + super.updateBackgroundImage(); + for (Control child : _getChildren()) { + if ((child.state & PARENT_BACKGROUND) != 0) { + child.updateBackgroundImage(); + } + } + } + + @Override + void updateBackgroundMode() { + super.updateBackgroundMode(); + for (Control child : _getChildren()) { + child.updateBackgroundMode(); + } + } + + @Override + void updateFont(Font oldFont, Font newFont) { + super.updateFont(oldFont, newFont); + Control[] children = _getChildren(); + for (int i = 0; i < children.length; i++) { + Control control = children[i]; + if (!control.isDisposed()) { + control.updateFont(oldFont, newFont); + } + } + } + + @Override + void updateLayout(boolean all) { + Composite parent = findDeferredControl(); + if (parent != null) { + parent.state |= LAYOUT_CHILD; + return; + } + if ((state & LAYOUT_NEEDED) != 0) { + boolean changed = (state & LAYOUT_CHANGED) != 0; + state &= ~(LAYOUT_NEEDED | LAYOUT_CHANGED); + if (layout != null) { + layout.layout(this, changed); + } + resizeChildren(); + } + if (all) { + state &= ~LAYOUT_CHILD; + Control[] children = _getChildren(); + for (int i = 0; i < children.length; i++) { + children[i].updateLayout(all); + } + } + } + + @Override + protected void _setVisible(QWidget widget, boolean visible) { + findChildren(); + boolean oldVisibility = getQMasterWidget().isVisible(); + super._setVisible(widget, visible); + if (getQMasterWidget().isVisible() != oldVisibility && layout != null) { + markLayout(true, true); + updateLayout(true); + } + } + + // TODO sma@2010-02-08 Links contain HTML escape sequences and therefore "&". + // Removing it breaks the HTML. Can Links have mnemonics? + private void findChildren() { + for (Control child : getChildren()) { + if (!(child instanceof Link) && child.getQWidget() instanceof QLabel + && ((QLabel) child.getQWidget()).text().contains("&")) { //$NON-NLS-1$ + handleMnemonic(child.getQWidget()); + } else if (child instanceof Composite) { + ((Composite) child).findChildren(); + } + } + } + + private void handleMnemonic(QWidget qwidget) { + QLabel myLabel = (QLabel) qwidget; + boolean foundBuddy = false; + java.util.List<QObject> children = myLabel.parent().children(); + for (int i = 0; i < children.size() - 1; i++) { + if (children.get(i).equals(myLabel)) { + // search for a suitable buddy + for (int k = i + 1; k < children.size(); k++) { + QObject neighbour = children.get(k); + if (neighbour != null && !(neighbour instanceof QLabel) && !(neighbour instanceof QScrollArea)) { + myLabel.setBuddy((QWidget) neighbour); + foundBuddy = true; + break; + } + } + } + + } + /* + * If there is no buddy to get the mnemonic, the "&" is removed from the + * string. In SWT/Win32 the character will remain underlined without any + * function, but in SWT/Qt this is not possible. + */ + if (!foundBuddy) { + myLabel.setText(myLabel.text().replace("&", "")); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + @Override + public boolean qtResizeEvent(QObject source, QResizeEvent resizeEvent) { + if (isDisposed()) { + return true; + } + if (isMirrored()) { + int newWidth = resizeEvent.size().width(); + int oldWidth = resizeEvent.oldSize().width(); + final int dx = newWidth - oldWidth; + if (dx != 0) { + Control[] children = _getChildren(); + for (int i = 0; i < children.length; ++i) { + Control child = children[i]; + if (!child.isDisposed()) { + QWidget qtControl = child.getQMasterWidget(); + QPoint pos = qtControl.pos(); + qtControl.move(pos.x() + dx, pos.y()); + } + } + } + } + super.qtResizeEvent(source, resizeEvent); + if (layout != null) { + markLayout(false, false); + updateLayout(false); + } + return false; + } + + @Override + public boolean qtMouseButtonPressEvent(QObject source, QMouseEvent mouseEvent) { + if (source == getQWidget()) { + boolean ret = super.qtMouseButtonPressEvent(source, mouseEvent); + if ((this.state & CANVAS) != 0) { + if ((style & SWT.NO_FOCUS) == 0 && hooksKeys()) { + Control[] children = getChildren(); + if (children == null || children.length == 0) { + setFocus(FocusReason.OtherFocusReason); + } + } + } + return ret; + } + return false; + } + + @Override + public boolean qtMouseEnterEvent(Object source) { + if (source == getQMasterWidget()) { + sendEvent(SWT.MouseEnter); + } + return false; + } + + @Override + public boolean qtMouseLeaveEvent(Object source) { + if (source == getQMasterWidget()) { + sendEvent(SWT.MouseExit); + } + return false; + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Control.java new file mode 100644 index 0000000000..ffff864e5b --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Control.java @@ -0,0 +1,4225 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import java.util.List; + +import com.trolltech.qt.core.QCoreApplication; +import com.trolltech.qt.core.QObject; +import com.trolltech.qt.core.QPoint; +import com.trolltech.qt.core.QRect; +import com.trolltech.qt.core.QEventLoop.ProcessEventsFlag; +import com.trolltech.qt.core.Qt.FocusPolicy; +import com.trolltech.qt.core.Qt.FocusReason; +import com.trolltech.qt.core.Qt.Key; +import com.trolltech.qt.core.Qt.LayoutDirection; +import com.trolltech.qt.core.Qt.MouseButton; +import com.trolltech.qt.core.Qt.MouseButtons; +import com.trolltech.qt.gui.QAbstractScrollArea; +import com.trolltech.qt.gui.QAction; +import com.trolltech.qt.gui.QApplication; +import com.trolltech.qt.gui.QBrush; +import com.trolltech.qt.gui.QColor; +import com.trolltech.qt.gui.QContextMenuEvent; +import com.trolltech.qt.gui.QDesktopWidget; +import com.trolltech.qt.gui.QDragEnterEvent; +import com.trolltech.qt.gui.QDragLeaveEvent; +import com.trolltech.qt.gui.QDragMoveEvent; +import com.trolltech.qt.gui.QDropEvent; +import com.trolltech.qt.gui.QFrame; +import com.trolltech.qt.gui.QKeyEvent; +import com.trolltech.qt.gui.QMenu; +import com.trolltech.qt.gui.QMouseEvent; +import com.trolltech.qt.gui.QMoveEvent; +import com.trolltech.qt.gui.QPaintDeviceInterface; +import com.trolltech.qt.gui.QPaintEvent; +import com.trolltech.qt.gui.QPainter; +import com.trolltech.qt.gui.QPalette; +import com.trolltech.qt.gui.QPicture; +import com.trolltech.qt.gui.QResizeEvent; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QFrame.Shadow; +import com.trolltech.qt.gui.QFrame.Shape; +import com.trolltech.qt.gui.QPalette.ColorRole; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.accessibility.Accessible; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.events.DragDetectListener; +import org.eclipse.swt.events.FocusListener; +import org.eclipse.swt.events.HelpListener; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.MenuDetectListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.MouseMoveListener; +import org.eclipse.swt.events.MouseTrackListener; +import org.eclipse.swt.events.MouseWheelListener; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.events.TraverseListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.graphics.Drawable; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.GCData; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.graphics.Region; +import org.eclipse.swt.internal.qt.DragNDropListener; +import org.eclipse.swt.internal.qt.KeyUtil; +import org.eclipse.swt.internal.qt.QtSWTConverter; + +/** + * Control is the abstract superclass of all windowed user interface classes. + * <p> + * <dl> + * <dt><b>Styles:</b> + * <dd>BORDER</dd> + * <dd>LEFT_TO_RIGHT, RIGHT_TO_LEFT</dd> + * <dt><b>Events:</b> + * <dd>DragDetect, FocusIn, FocusOut, Help, KeyDown, KeyUp, MenuDetect, + * MouseDoubleClick, MouseDown, MouseEnter, MouseExit, MouseHover, MouseUp, + * MouseMove, Move, Paint, Resize, Traverse</dd> + * </dl> + * </p> + * <p> + * Only one of LEFT_TO_RIGHT or RIGHT_TO_LEFT may be specified. + * </p> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> within the + * SWT implementation. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#control">Control + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public abstract class Control extends Widget implements Drawable { + /** + * the handle to the OS resource (Warning: This field is platform dependent) + * <p> + * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT public API. + * It is marked public only so that it can be shared within the packages + * provided by SWT. It is not available on all platforms and should never be + * accessed from application code. + * </p> + */ + public int /* long */handle; + Composite parent; + protected Cursor cursor; + private Menu menu; + private Object layoutData; + private Accessible accessible; + protected Region region; + private Font font; + protected Color foreground; + protected Color background; + protected Image backgroundImage; + private QPicture temporaryGC; + protected boolean isOngoingPaintEvent = false; + private boolean enabled = true; + private QPoint dragStartPos; + private DragNDropListener dndListener; + + /** + * 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(parent, style); + } + + protected void createWidget(Composite parent, int style) { + state |= DRAG_DETECT; + checkAndUpdateOrientation(parent); + QWidget qWidget = createQWidget(style); + if (qWidget == null) { + error(SWT.ERROR_UNSPECIFIED); + } + setQWidget(qWidget); + setParent(); + fixZOrder(); + checkAndUpdateBackground(); + connectSignals(); + registerQWidget(); + setupQWidget(); + updateLayoutDirection(); + setupStyleSheet(); + checkAndUpdateMirrored(); + checkAndUpdateBorder(); + updateFocusPolicy(); + updateBackground(); + updateSizeAndVisibility(); + } + + abstract QWidget createQWidget(int style); + + protected void setParent() { + if (parent != null) { + parent.addQChild(this); + } + } + + protected void fixZOrder() { + if (parent != null && !(parent instanceof TabFolder)) { + getQMasterWidget().lower(); + } + } + + /** + * Hook that guarantees that getQWidget() != null. Called immediately after + * {@link createQtControl()}. + */ + protected void setupQWidget() { + //nothing + } + + protected void updateSizeAndVisibility() { + if (parent != null && parent.getQWidget().isVisible() && !(parent instanceof Shell) && !(this instanceof Shell)) { + getQMasterWidget().setVisible(true); + } + } + + protected void connectSignals() { + // nothing by default + } + + boolean isQScrollArea() { + return getQWidget() instanceof QAbstractScrollArea; + } + + protected void setupStyleSheet() { + String styleSheet = getShell() != null ? getShell().getQMasterWidget().styleSheet() : null; + if (styleSheet == null) { + styleSheet = getDisplay().getStyleSheet(); + if (styleSheet != null) { + setStyleSheet(styleSheet); + } + } + } + + protected void updateLayoutDirection() { + if ((style & SWT.RIGHT_TO_LEFT) != 0) { + getQWidget().setLayoutDirection(LayoutDirection.RightToLeft); + } else { + getQWidget().setLayoutDirection(LayoutDirection.LeftToRight); + } + } + + protected void updateFocusPolicy() { + if ((style & SWT.NO_FOCUS) != 0) { + getQMasterWidget().setFocusPolicy(FocusPolicy.NoFocus); + } + } + + void registerQWidget() { + display.addControl(getQWidget(), this); + if (getQMasterWidget() != null && getQMasterWidget() != getQWidget()) { + display.addControl(getQMasterWidget(), this); + } + } + + void deregisterQWidget() { + display.removeControl(getQWidget()); + if (getQMasterWidget() != null && getQMasterWidget() != getQWidget()) { + display.removeControl(getQMasterWidget()); + } + } + + @Override + void releaseQWidget() { + super.releaseQWidget(); + parent = null; + } + + @Override + void releaseParent() { + parent.removeControl(this); + } + + @Override + void releaseWidget() { + super.releaseWidget(); + + deregisterQWidget(); + + if (menu != null && !menu.isDisposed()) { + menu.dispose(); + } + temporaryGC = null; + backgroundImage = null; + menu = null; + cursor = null; + layoutData = null; + if (accessible != null) { + // TODO + //accessible.internal_dispose_Accessible(); + } + accessible = null; + region = null; + font = null; + } + + protected void checkAndUpdateBorder() { + checkAndUpdateBorder(getQMasterWidget()); + if (getBorderWidth() == 0) { + style &= ~SWT.BORDER; + } + } + + protected void checkAndUpdateBorder(QWidget control) { + if (control != null && control instanceof QFrame) { + QFrame frame = (QFrame) control; + if ((style & SWT.BORDER) != 0) { + frame.setFrameShape(Shape.StyledPanel); + frame.setFrameShadow(Shadow.Sunken); + frame.setLineWidth(1); + } else { + frame.setFrameShape(Shape.NoFrame); + frame.setLineWidth(0); + } + } + + } + + /* used by CoolBar */ + boolean drawGripper(int x, int y, int width, int height, boolean vertical) { + return false; + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the control is moved or resized, by sending it one of the messages + * defined in the <code>ControlListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ControlListener + * @see #removeControlListener + */ + public void addControlListener(ControlListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Resize, typedListener); + addListener(SWT.Move, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when a drag gesture occurs, by sending it one of the messages defined in + * the <code>DragDetectListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see DragDetectListener + * @see #removeDragDetectListener + * + * @since 3.3 + */ + public void addDragDetectListener(DragDetectListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.DragDetect, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the control gains or loses focus, by sending it one of the messages + * defined in the <code>FocusListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see FocusListener + * @see #removeFocusListener + */ + public void addFocusListener(FocusListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.FocusIn, typedListener); + addListener(SWT.FocusOut, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when help events are generated for the control, by sending it one of the + * messages defined in the <code>HelpListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see HelpListener + * @see #removeHelpListener + */ + public void addHelpListener(HelpListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Help, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when keys are pressed and released on the system keyboard, by sending it + * one of the messages defined in the <code>KeyListener</code> interface. + * <p> + * When a key listener is added to a control, the control will take part in + * widget traversal. By default, all traversal keys (such as the tab key and + * so on) are delivered to the control. In order for a control to take part + * in traversal, it should listen for traversal events. Otherwise, the user + * can traverse into a control but not out. Note that native controls such + * as table and tree implement key traversal in the operating system. It is + * not necessary to add traversal listeners for these controls, unless you + * want to override the default traversal. + * </p> + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see KeyListener + * @see #removeKeyListener + */ + public void addKeyListener(KeyListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.KeyUp, typedListener); + addListener(SWT.KeyDown, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the platform-specific context menu trigger has occurred, by sending + * it one of the messages defined in the <code>MenuDetectListener</code> + * interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see MenuDetectListener + * @see #removeMenuDetectListener + * + * @since 3.3 + */ + public void addMenuDetectListener(MenuDetectListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.MenuDetect, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when mouse buttons are pressed and released, by sending it one of the + * messages defined in the <code>MouseListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see MouseListener + * @see #removeMouseListener + */ + public void addMouseListener(MouseListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.MouseDown, typedListener); + addListener(SWT.MouseUp, typedListener); + addListener(SWT.MouseDoubleClick, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the mouse passes or hovers over controls, by sending it one of the + * messages defined in the <code>MouseTrackListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see MouseTrackListener + * @see #removeMouseTrackListener + */ + public void addMouseTrackListener(MouseTrackListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.MouseEnter, typedListener); + addListener(SWT.MouseExit, typedListener); + addListener(SWT.MouseHover, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the mouse moves, by sending it one of the messages defined in the + * <code>MouseMoveListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see MouseMoveListener + * @see #removeMouseMoveListener + */ + public void addMouseMoveListener(MouseMoveListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.MouseMove, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the mouse wheel is scrolled, by sending it one of the messages + * defined in the <code>MouseWheelListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see MouseWheelListener + * @see #removeMouseWheelListener + * + * @since 3.3 + */ + public void addMouseWheelListener(MouseWheelListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.MouseWheel, typedListener); + } + + /** + * 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); + } + + protected void checkBuffered() { + style &= ~SWT.DOUBLE_BUFFERED; + } + + protected void checkAndUpdateMirrored() { + 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(boolean) + * @see "computeTrim, getClientArea for controls that implement them" + */ + public Point computeSize(int wHint, int hHint) { + return computeSize(wHint, hHint, true); + } + + /** + * Returns the preferred size of the receiver. + * <p> + * The <em>preferred size</em> of a control is the size that it would best + * be displayed at. The width hint and height hint arguments allow the + * caller to ask a control questions such as "Given a particular width, how + * high does the control need to be to show all of the contents?" To + * indicate that the caller does not wish to constrain a particular + * dimension, the constant <code>SWT.DEFAULT</code> is passed for the hint. + * </p> + * <p> + * If the changed flag is <code>true</code>, it indicates that the + * receiver's <em>contents</em> have changed, therefore any caches that a + * layout manager containing the control may have been keeping need to be + * flushed. When the control is resized, the changed flag will be + * <code>false</code>, so layout manager caches can be retained. + * </p> + * + * @param wHint + * the width hint (can be <code>SWT.DEFAULT</code>) + * @param hHint + * the height hint (can be <code>SWT.DEFAULT</code>) + * @param changed + * <code>true</code> if the control's contents have changed, and + * <code>false</code> otherwise + * @return the preferred size of the control. + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Layout + * @see #getBorderWidth + * @see #getBounds + * @see #getSize + * @see #pack(boolean) + * @see "computeTrim, getClientArea for controls that implement them" + */ + public Point computeSize(int wHint, int hHint, boolean changed) { + checkWidget(); + if (changed) { + getQMasterWidget().updateGeometry(); + } + Point res = QtSWTConverter.convert(getQMasterWidget().sizeHint()); + if (res.x < 0) { + res.x = DEFAULT_WIDTH; + } + if (res.y < 0) { + res.y = DEFAULT_HEIGHT; + } + + int border = getBorderWidth(); + if (wHint != SWT.DEFAULT) { + res.x = wHint + 2 * border; + } + if (hHint != SWT.DEFAULT) { + res.y = hHint + 2 * border; + } + + return res; + } + + 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]; + } + + Font defaultFont() { + return display.getSystemFont(); + } + + /** + * Detects a drag and drop gesture. This method is used to detect a drag + * gesture when called from within a mouse down listener. + * + * <p> + * By default, a drag is detected when the gesture occurs anywhere within + * the client area of a control. Some controls, such as tables and trees, + * override this behavior. In addition to the operating system specific drag + * gesture, they require the mouse to be inside an item. Custom widget + * writers can use <code>setDragDetect</code> to disable the default + * detection, listen for mouse down, and then call <code>dragDetect()</code> + * from within the listener to conditionally detect a drag. + * </p> + * + * @param event + * the mouse down event + * + * @return <code>true</code> if the gesture occurred, and <code>false</code> + * otherwise. + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT when the event is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see DragDetectListener + * @see #addDragDetectListener + * + * @see #getDragDetect + * @see #setDragDetect + * + * @since 3.3 + */ + public boolean dragDetect(Event event) { + checkWidget(); + if (event == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + return dragDetect(event.button, event.count, event.stateMask, event.x, event.y); + } + + /** + * Detects a drag and drop gesture. This method is used to detect a drag + * gesture when called from within a mouse down listener. + * + * <p> + * By default, a drag is detected when the gesture occurs anywhere within + * the client area of a control. Some controls, such as tables and trees, + * override this behavior. In addition to the operating system specific drag + * gesture, they require the mouse to be inside an item. Custom widget + * writers can use <code>setDragDetect</code> to disable the default + * detection, listen for mouse down, and then call <code>dragDetect()</code> + * from within the listener to conditionally detect a drag. + * </p> + * + * @param event + * the mouse down event + * + * @return <code>true</code> if the gesture occurred, and <code>false</code> + * otherwise. + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT when the event is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see DragDetectListener + * @see #addDragDetectListener + * + * @see #getDragDetect + * @see #setDragDetect + * + * @since 3.3 + */ + public boolean dragDetect(MouseEvent event) { + checkWidget(); + if (event == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + return dragDetect(event.button, event.count, event.stateMask, event.x, event.y); + } + + boolean dragDetect(int button, int count, int stateMask, int x, int y) { + return false; + // TODO + } + + Cursor findCursor() { + if (cursor != null) { + return cursor; + } + return parent.findCursor(); + } + + Control findImageControl() { + Control control = findBackgroundControl(); + return control != null && control.backgroundImage != null ? control : null; + } + + Control findThemeControl() { + return background == null && backgroundImage == null ? parent.findThemeControl() : null; + } + + Menu[] findMenus(Control control) { + if (menu != null && this != control) { + return new Menu[] { menu }; + } + return new Menu[0]; + } + + protected char findMnemonic(String string) { + int index = 0; + int length = string.length(); + do { + while (index < length && string.charAt(index) != '&') { + index++; + } + if (++index >= length) { + return '\0'; + } + if (string.charAt(index) != '&') { + return string.charAt(index); + } + index++; + } while (index < length); + return '\0'; + } + + void fixChildren(Shell newShell, Shell oldShell, Decorations newDecorations, Decorations oldDecorations, + Menu[] menus) { + oldShell.fixShell(newShell, this); + oldDecorations.fixDecorations(newDecorations, this, menus); + } + + private void fixFocus(Control focusControl) { + Shell shell = getShell(); + Control control = this; + while (control != shell && (control = control.parent) != null) { + if (control.setFixedFocus()) { + return; + } + } + + shell.setSavedFocus(focusControl); + + QDesktopWidget desktopWidget = QApplication.desktop(); + if (desktopWidget != null) { + desktopWidget.setFocus(FocusReason.OtherFocusReason); + } + } + + /** + * 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(); + return forceFocus(FocusReason.OtherFocusReason); + } + + protected boolean forceFocus(FocusReason focusReason) { + if (display.focusEvent == SWT.FocusOut) { + return false; + } + Decorations shell = menuShell(); + shell.setSavedFocus(this); + if (!isEnabled() || !isVisible() || !isActive()) { + return false; + } + if (isFocusControl()) { + return true; + } + shell.setSavedFocus(null); + getQWidget().setFocus(focusReason); + if (isDisposed()) { + return false; + } + shell.setSavedFocus(this); + return _isFocusControl(); + } + + /** + * 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 _getBackgroundColor(); + } + + /** + * Returns the receiver's background image. + * + * @return the background image + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public Image getBackgroundImage() { + checkWidget(); + Control control = findBackgroundControl(); + if (control == null) { + control = this; + } + return control.backgroundImage; + } + + Color _getBackgroundColor() { + Control control = findBackgroundControl(); + if (control == null) { + control = this; + } + if (control.background != null) { + return control.background; + } + return getDefaultBackgroundColor(); + } + + /** + * 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(); + if (getQMasterWidget() instanceof QFrame) { + return ((QFrame) getQMasterWidget()).frameWidth(); + } + return 0; + } + + /** + * Returns a rectangle describing the receiver's size and location relative + * to its parent (or its display if its parent is null), unless the receiver + * is a shell. In this case, the location is relative to the display. + * + * @return the receiver's bounding rectangle + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Rectangle getBounds() { + checkWidget(); + return QtSWTConverter.convert(getQMasterWidget().frameGeometry()); + } + + /** + * Returns the receiver's cursor, or null if it has not been set. + * <p> + * When the mouse pointer passes over a control its appearance is changed to + * match the control's cursor. + * </p> + * + * @return the receiver's cursor or <code>null</code> + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.3 + */ + public Cursor getCursor() { + checkWidget(); + return cursor; + } + + /** + * Returns <code>true</code> if the receiver is detecting drag gestures, and + * <code>false</code> otherwise. + * + * @return the receiver's drag detect state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.3 + */ + public boolean getDragDetect() { + checkWidget(); + return isDragDetectEnabled(); + } + + private boolean isDragDetectEnabled() { + return (state & DRAG_DETECT) != 0; + } + + /** + * Sets the receiver's drag detect state. If the argument is + * <code>true</code>, the receiver will detect drag gestures, otherwise + * these gestures will be ignored. + * + * @param dragDetect + * the new drag detect state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.3 + */ + public void setDragDetect(boolean dragDetect) { + checkWidget(); + if (dragDetect) { + state |= DRAG_DETECT; + } else { + state &= ~DRAG_DETECT; + } + } + + protected boolean isDropTargetEnabled() { + return getData(DND.DROP_TARGET_KEY) != null; // check if DropTarget is present + } + + public void setAcceptDrops(boolean accept) { + getQMasterWidget().setAcceptDrops(accept); + } + + public void setDragEnabled(boolean enabled) { + // nothing by default + } + + public void dragEnd() { + dragStartPos = null; + } + + public void setDragNDropListener(DragNDropListener listener) { + this.dndListener = listener; + } + + public void unsetDragNDropListener(DragNDropListener listener) { + if (this.dndListener == listener) { + this.dndListener = null; + } + } + + protected final void sendDropEvent(QDropEvent event) { + if (this.dndListener == null) { + return; + } + dndListener.drop(event); + } + + protected final void sendDragMoveEvent(QDragMoveEvent event) { + if (this.dndListener == null) { + return; + } + dndListener.dragMove(event); + } + + protected final void sendDragLeaveEvent(QDragLeaveEvent event) { + if (this.dndListener == null) { + return; + } + dndListener.dragLeave(event); + } + + protected final void sendDragEnterEvent(QDragEnterEvent event) { + if (this.dndListener == null) { + return; + } + dndListener.dragEnter(event); + } + + /** + * Returns the font that the receiver will use to paint textual information. + * + * @return the receiver's font + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Font getFont() { + checkWidget(); + if (font != null) { + return font; + } + return defaultFont(); + } + + /** + * Returns the foreground color that the receiver will use to draw. + * + * @return the receiver's foreground color + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Color getForeground() { + checkWidget(); + return _getForegroundColor(); + } + + Color _getForegroundColor() { + if (foreground != null) { + return foreground; + } + return getDefaultForegroundColor(); + } + + protected Color getDefaultForegroundColor() { + return Color.qt_new(display, getColorFromPalette(ColorRole.WindowText)); + } + + protected QColor getColorFromPalette(ColorRole role) { + QPalette palette = getQWidget().palette(); + return palette.color(role); + } + + /** + * Returns layout data which is associated with the receiver. + * + * @return the receiver's layout data + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Object getLayoutData() { + checkWidget(); + return layoutData; + } + + /** + * Returns a point describing the receiver's location relative to its parent + * (or its display if its parent is null), unless the receiver is a shell. + * In this case, the point is relative to the display. + * + * @return the receiver's location + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Point getLocation() { + checkWidget(); + //forceResize(); + return QtSWTConverter.convert(getQWidget().pos()); + } + + /** + * 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> + */ + @Override + public Menu getMenu() { + checkWidget(); + return menu; + } + + /** + * Returns the receiver's monitor. + * + * @return the receiver's monitor + * + * @since 3.0 + */ + public Monitor getMonitor() { + checkWidget(); + return Display.createMonitor(getQWidget()); + } + + /** + * 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 region that defines the shape of the control, or null if the + * control has the default shape. + * + * @return the region that defines the shape of the shell (or null) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public Region getRegion() { + checkWidget(); + return region; + } + + /** + * Returns the receiver's shell. For all controls other than shells, this + * simply returns the control's nearest ancestor shell. Shells return + * themselves, even if they are children of other shells. + * + * @return the receiver's shell + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #getParent + */ + public Shell getShell() { + checkWidget(); + return parent.getShell(); + } + + /** + * Returns a point describing the receiver's size. The x coordinate of the + * result is the width of the receiver. The y coordinate of the result is + * the height of the receiver. + * + * @return the receiver's size + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Point getSize() { + checkWidget(); + return QtSWTConverter.convert(getQMasterWidget().frameSize()); + } + + int getClientWidth() { + return getQMasterWidget().rect().width(); + } + + /** + * 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 getQWidget().toolTip(); + } + + boolean hasFocus() { + return getQWidget().hasFocus(); + } + + /** + * Invokes platform specific functionality to allocate a new GC handle. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public API for + * <code>Control</code>. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms, and should never be called from application code. + * </p> + * + * @param data + * the platform specific GC data + * @return the platform specific GC handle + */ + public QPaintDeviceInterface internal_new_GC(GCData data) { + checkWidget(); + initGCData(data); + // we are in a Qt paint event + if (isOngoingPaintEvent) { + return getQWidget(); + } + // if we are not in a paint event, we need to temporarily render to a + // temp GC and apply the changes in the next paint event + temporaryGC = new QPicture(); + //System.out.println("creating tmp gc for " + this + " " + temporaryGC); + return temporaryGC; + } + + void initGCData(GCData data) { + data.device = display; + data.backgroundColor = getBackground(); + data.foregroundColor = getForeground(); + data.font = getFont(); + } + + /** + * Invokes platform specific functionality to dispose a GC handle. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public API for + * <code>Control</code>. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms, and should never be called from application code. + * </p> + * + * @param hDC + * the platform specific GC handle + * @param data + * the platform specific GC data + */ + public void internal_dispose_GC(QPaintDeviceInterface paintDevice, GCData data) { + checkWidget(); + if (!isOngoingPaintEvent) { + //System.out.println("tmp gc back " + this + " " + parent + " " + Thread.currentThread()); + //new RuntimeException().printStackTrace(); + getQWidget().update(); + } + } + + boolean isActive() { + Dialog dialog = display.getModalDialog(); + if (dialog != null) { + Shell dialogShell = dialog.parent; + if (dialogShell != null && !dialogShell.isDisposed()) { + if (dialogShell != getShell()) { + return false; + } + } + } + Shell shell = null; + Shell[] modalShells = display.modalShells; + if (modalShells != null) { + int bits = SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL; + int index = modalShells.length; + while (--index >= 0) { + Shell modal = modalShells[index]; + if (modal != null) { + if ((modal.style & bits) != 0) { + Control control = this; + while (control != null) { + if (control == modal) { + break; + } + control = control.parent; + } + if (control != modal) { + return false; + } + break; + } + if ((modal.style & SWT.PRIMARY_MODAL) != 0) { + if (shell == null) { + shell = getShell(); + } + if (modal.parent == shell) { + return false; + } + } + } + } + } + if (shell == null) { + shell = getShell(); + } + return shell.getEnabled(); + } + + /** + * 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 _isFocusControl(); + } + + protected boolean _isFocusControl() { + Control focusControl = display.focusControl; + if (focusControl != null && !focusControl.isDisposed()) { + return this == focusControl; + } + return hasFocus(); + } + + boolean isFocusAncestor(Control control) { + while (control != null && control != this && !(control instanceof Shell)) { + 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() { + if (!isVisible()) { + return false; + } + Control control = this; + while (control != null) { + Point size = control.getSize(); + if (size.x == 0 || size.y == 0) { + return false; + } + control = control.parent; + } + return true; + } + + boolean isTabGroup() { + Control[] tabList = parent._getTabList(); + if (tabList != null) { + for (int i = 0; i < tabList.length; i++) { + if (tabList[i] == this) { + return true; + } + } + } + //TODO + return false; + } + + boolean isTabItem() { + Control[] tabList = parent._getTabList(); + if (tabList != null) { + for (int i = 0; i < tabList.length; i++) { + if (tabList[i] == this) { + return false; + } + } + } + return FocusPolicy.TabFocus.equals(getQWidget().focusPolicy()); + } + + /** + * Returns <code>true</code> if the receiver is visible and all ancestors up + * to and including the receiver's nearest ancestor shell are visible. + * Otherwise, <code>false</code> is returned. + * + * @return the receiver's visibility state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #getVisible + */ + public boolean isVisible() { + checkWidget(); + return getQMasterWidget().isVisible(); + } + + /** + * 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(); + // TODO hack. some layouts are distroyed if we return the visibile state instead of the real visibility + return getQMasterWidget().isVisible(); + } + + /** + * 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(final boolean visible) { + checkWidget(); + _setVisible(getQMasterWidget(), visible); + } + + protected void _setVisible(QWidget widget, final boolean visible) { + //this.visible = visible; + + boolean oldVisibility = getQMasterWidget().isVisible(); + + // we always set the visibility, this is important during initialization, when all widgets are not visible, but some are explicitly hidden + widget.setVisible(visible); + + if (oldVisibility == visible) { // bail out if state has not changed + return; + } + + // TODO hack + if (widget.parentWidget() != null) { + widget.parentWidget().update(); + } + + if (getQMasterWidget().isVisible()) { + sendEvent(SWT.Show); + if (isDisposed()) { + return; + } + } + Control control = null; + boolean fixFocus = false; + if (getQMasterWidget().isHidden()) { + if (display.focusEvent != SWT.FocusOut) { + control = display.getFocusControl(); + fixFocus = isFocusAncestor(control); + } + + sendEvent(SWT.Hide); + if (isDisposed()) { + return; + } + } + if (fixFocus) { + fixFocus(control); + } + } + + void markLayout(boolean changed, boolean all) { + /* Do nothing */ + } + + 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 control + * the sibling control (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the control has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Control#moveBelow + * @see Composite#getChildren + */ + public void moveAbove(Control control) { + checkWidget(); + if (control != null) { + if (control.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (parent != control.parent) { + return; + } + + Control controlAbove = null; + List<QObject> children = getQWidget().children(); + boolean next = false; + for (QObject child : children) { + Widget widget = display.findControl(child); + if (!next && widget == control) { + next = true; + continue; + } + if (next) { + if (widget != null && widget != this) { + if (widget instanceof Control) { + controlAbove = (Control) widget; + break; + } + } + } + } + if (controlAbove != null) { + moveBelow(controlAbove); + } else { + getQMasterWidget().raise(); + } + } else { + getQMasterWidget().raise(); + } + } + + /** + * Moves the receiver below the specified control in the drawing order. If + * the argument is null, then the receiver is moved to the bottom of the + * drawing order. The control at the bottom of the drawing order will be + * covered by all other controls which occupy intersecting areas. + * + * @param control + * the sibling control (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the control has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Control#moveAbove + * @see Composite#getChildren + */ + public void moveBelow(Control control) { + checkWidget(); + if (control != null) { + if (control.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (parent != control.parent) { + return; + } + getQMasterWidget().stackUnder(control.getQWidget()); + } else { + getQMasterWidget().lower(); + } + } + + Accessible new_Accessible(Control control) { + return Accessible.internal_new_Accessible(this); + } + + @Override + GC new_GC(GCData data) { + return GC.qt_new(this, data); + } + + /** + * Causes the receiver to be resized to its preferred size. For a composite, + * this involves computing the preferred size from its layout, if there is + * one. + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #computeSize(int, int, boolean) + */ + public void pack() { + checkWidget(); + pack(true); + } + + /** + * Causes the receiver to be resized to its preferred size. For a composite, + * this involves computing the preferred size from its layout, if there is + * one. + * <p> + * If the changed flag is <code>true</code>, it indicates that the + * receiver's <em>contents</em> have changed, therefore any caches that a + * layout manager containing the control may have been keeping need to be + * flushed. When the control is resized, the changed flag will be + * <code>false</code>, so layout manager caches can be retained. + * </p> + * + * @param changed + * whether or not the receiver's contents have changed + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #computeSize(int, int, boolean) + */ + public void pack(boolean changed) { + checkWidget(); + setSize(computeSize(SWT.DEFAULT, SWT.DEFAULT, changed)); + } + + /** + * Prints the receiver and all children. + * + * @param gc + * the gc where the drawing occurs + * @return <code>true</code> if the operation was successful and + * <code>false</code> otherwise + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the gc is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the gc has been disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public boolean print(GC gc) { + checkWidget(); + if (gc == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (gc.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + + // TODO + // QPixmap pix; + // pix.grabWidget(myMainWindowWidget); + // QImage im = pix.convertToImage(); + return false; + } + + /** + * Causes the entire bounds of the receiver to be marked as needing to be + * redrawn. The next time a paint request is processed, the control will be + * completely painted, including the background. + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #update() + * @see PaintListener + * @see SWT#Paint + * @see SWT#NO_BACKGROUND + * @see SWT#NO_REDRAW_RESIZE + * @see SWT#NO_MERGE_PAINTS + * @see SWT#DOUBLE_BUFFERED + */ + public void redraw() { + checkWidget(); + _redraw(); + } + + void _redraw() { + getQMasterWidget().update(); + if (getQMasterWidget() != getQWidget()) { + getQWidget().update(); + } + redrawChildren(); + } + + /** + * Causes the rectangular area of the receiver specified by the arguments to + * be marked as needing to be redrawn. The next time a paint request is + * processed, that area of the receiver will be painted, including the + * background. If the <code>all</code> flag is <code>true</code>, any + * children of the receiver which intersect with the specified area will + * also paint their intersecting areas. If the <code>all</code> flag is + * <code>false</code>, the children will not be painted. + * + * @param x + * the x coordinate of the area to draw + * @param y + * the y coordinate of the area to draw + * @param width + * the width of the area to draw + * @param height + * the height of the area to draw + * @param all + * <code>true</code> if children should redraw, and + * <code>false</code> otherwise + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #update() + * @see PaintListener + * @see SWT#Paint + * @see SWT#NO_BACKGROUND + * @see SWT#NO_REDRAW_RESIZE + * @see SWT#NO_MERGE_PAINTS + * @see SWT#DOUBLE_BUFFERED + */ + public void redraw(int x, int y, int width, int height, boolean all) { + checkWidget(); + getQMasterWidget().update(x, y, width, height); + if (getQMasterWidget() != getQWidget()) { + getQWidget().update(x, y, width, height); + } + + if (all) { + redrawChildren(); + } + } + + void redrawChildren() { + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is moved or resized. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ControlListener + * @see #addControlListener + */ + public void removeControlListener(ControlListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Move, listener); + eventTable.unhook(SWT.Resize, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when a drag gesture occurs. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see DragDetectListener + * @see #addDragDetectListener + * + * @since 3.3 + */ + public void removeDragDetectListener(DragDetectListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.DragDetect, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control gains or loses focus. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see FocusListener + * @see #addFocusListener + */ + public void removeFocusListener(FocusListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.FocusIn, listener); + eventTable.unhook(SWT.FocusOut, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the help events are generated for the control. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see HelpListener + * @see #addHelpListener + */ + public void removeHelpListener(HelpListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Help, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when keys are pressed and released on the system keyboard. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see KeyListener + * @see #addKeyListener + */ + public void removeKeyListener(KeyListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.KeyUp, listener); + eventTable.unhook(SWT.KeyDown, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the platform-specific context menu trigger has occurred. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see MenuDetectListener + * @see #addMenuDetectListener + * + * @since 3.3 + */ + public void removeMenuDetectListener(MenuDetectListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.MenuDetect, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the mouse passes or hovers over controls. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see MouseTrackListener + * @see #addMouseTrackListener + */ + public void removeMouseTrackListener(MouseTrackListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.MouseEnter, listener); + eventTable.unhook(SWT.MouseExit, listener); + eventTable.unhook(SWT.MouseHover, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when mouse buttons are pressed and released. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see MouseListener + * @see #addMouseListener + */ + public void removeMouseListener(MouseListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.MouseDown, listener); + eventTable.unhook(SWT.MouseUp, listener); + eventTable.unhook(SWT.MouseDoubleClick, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the mouse moves. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see MouseMoveListener + * @see #addMouseMoveListener + */ + public void removeMouseMoveListener(MouseMoveListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.MouseMove, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the mouse wheel is scrolled. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see MouseWheelListener + * @see #addMouseWheelListener + * + * @since 3.3 + */ + public void removeMouseWheelListener(MouseWheelListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.MouseWheel, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the receiver needs to be painted. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see PaintListener + * @see #addPaintListener + */ + public void removePaintListener(PaintListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Paint, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when traversal events occur. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see TraverseListener + * @see #addTraverseListener + */ + public void removeTraverseListener(TraverseListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Traverse, listener); + } + + void sendMove() { + sendEvent(SWT.Move); + } + + void sendResize() { + sendEvent(SWT.Resize); + } + + /** + * Sets the receiver's background color to the color specified by the + * argument, or to the default system color for the control if the argument + * is null. + * <p> + * Note: This operation is a hint and may be overridden by the platform. For + * example, on Windows the background of a Button cannot be changed. + * </p> + * + * @param color + * the new color (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setBackground(Color color) { + checkWidget(); + _setBackground(color); + } + + void _setBackground(Color color) { + if (color != null) { + if (color.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + } + if (color == null) { + background = getDefaultBackgroundColor(); + } else { + background = color; + } + if (backgroundImage == null) { + updateBackgroundColor(); + } + } + + protected Color getDefaultBackgroundColor() { + return display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); + } + + /* refactored: was checkBackground */ + protected void checkAndUpdateBackground() { + Shell shell = getShell(); + if (this == shell) { + return; + } + state &= ~PARENT_BACKGROUND; + Composite composite = parent; + do { + int mode = composite.getBackgroundMode(); + if (mode != 0) { + if (mode == SWT.INHERIT_DEFAULT) { + Control control = this; + do { + if ((control.state & THEME_BACKGROUND) == 0) { + return; + } + control = control.parent; + } while (control != composite); + } + state |= PARENT_BACKGROUND; + return; + } + if (composite == shell) { + break; + } + composite = composite.parent; + } while (true); + } + + protected void updateBackground() { + if ((state & PARENT_BACKGROUND) == 0) { + return; + } + Control control = findBackgroundImageControl(); + if (control == null) { + control = this; + } + if (control.backgroundImage != null) { + applyBackgroundImage(control.backgroundImage); + return; + } + + control = findBackgroundColorControl(); + if (control == null) { + control = this; + } + applyBackgroundColor(control.background != null ? control.background : control.getDefaultBackgroundColor()); + } + + Control findBackgroundControl() { + if (background != null || backgroundImage != null) { + return this; + } + return (state & PARENT_BACKGROUND) != 0 ? parent.findBackgroundControl() : null; + } + + protected void applyBackgroundColor(Color color) { + updatedPalette(color, getBackgroundColorRoles()); + } + + protected void updatedPalette(Color color, ColorRole[] colorRoles) { + QPalette palette = getQMasterWidget().palette(); + for (ColorRole role : colorRoles) { + palette.setBrush(role, new QBrush(color.getColor())); + } + getQMasterWidget().setAutoFillBackground(true); + getQMasterWidget().setPalette(palette); + } + + protected ColorRole[] getBackgroundColorRoles() { + return new ColorRole[] { ColorRole.Window, ColorRole.Base, ColorRole.Button }; + } + + protected ColorRole[] getBackgroundImageRoles() { + return new QPalette.ColorRole[] { QPalette.ColorRole.Window, QPalette.ColorRole.Base }; + } + + /** + * Sets the receiver's background image to the image specified by the + * argument, or to the default system color for the control if the argument + * is null. The background image is tiled to fill the available space. + * <p> + * Note: This operation is a hint and may be overridden by the platform. For + * example, on Windows the background of a Button cannot be changed. + * </p> + * + * @param image + * the new image (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * <li>ERROR_INVALID_ARGUMENT - if the argument is not a + * bitmap</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public void setBackgroundImage(Image image) { + checkWidget(); + if (image != null) { + if (image.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (!image.isBitmap()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + } + if (image == null) { + backgroundImage = null; + updateBackgroundColor(); + } else { + backgroundImage = image; + updateBackgroundImage(); + } + } + + void applyBackgroundImage(Image image) { + QPalette palette = getQMasterWidget().palette(); + ColorRole[] bkRoles = getBackgroundImageRoles(); + for (ColorRole bkRole : bkRoles) { + // if (bgControl != this && canInheritBackgroundImage()) { + // palette.setColor(bkRole, null); + // // If background is inherited then brush is set to null + // palette.setBrush(bkRole, null); + // } else { + palette.setBrush(bkRole, new QBrush(image.getQPixmap())); + // } + } + getQMasterWidget().setPalette(palette); + getQMasterWidget().setAutoFillBackground(true); + } + + protected boolean canInheritBackgroundImage() { + return 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), + * unless the receiver is a shell. In this case, the <code>x</code> and + * <code>y</code> arguments are relative to the display. + * <p> + * Note: Attempting to set the width or height of the receiver to a negative + * number will cause that value to be set to zero instead. + * </p> + * + * @param x + * the new x coordinate for the receiver + * @param y + * the new y coordinate for the receiver + * @param width + * the new width for the receiver + * @param height + * the new height for the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setBounds(int x, int y, int width, int height) { + checkWidget(); + setBounds(x, y, width, height, true, true); + } + + protected void setBounds(int x, int y, int width, int height, boolean move, boolean resize) { + if (resize) { + Point oldSize = QtSWTConverter.convert(getQMasterWidget().size()); + if (oldSize.x != width || oldSize.y != height) { + getQMasterWidget().resize(width, height); + state |= RESIZE_OCCURRED; + } + } + if (move) { + Point oldPos = QtSWTConverter.convert(getQMasterWidget().pos()); + if (oldPos.x != x || oldPos.y != y) { + getQMasterWidget().move(x, y); + state |= MOVE_OCCURRED; + } + } + } + + /** + * 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, true, true); + } + + /** + * If the argument is <code>true</code>, causes the receiver to have all + * mouse events delivered to it until the method is called with + * <code>false</code> as the argument. Note that on some platforms, a mouse + * button must currently be down for capture to be assigned. + * + * @param capture + * <code>true</code> to capture the mouse, and <code>false</code> + * to release it + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setCapture(boolean capture) { + checkWidget(); + if (capture) { + getQMasterWidget().grabMouse(); + } else { + getQMasterWidget().releaseMouse(); + } + } + + /** + * Sets the receiver's cursor to the cursor specified by the argument, or to + * the default cursor for that kind of control if the argument is null. + * <p> + * When the mouse pointer passes over a control its appearance is changed to + * match the control's cursor. + * </p> + * + * @param cursor + * the new cursor (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setCursor(Cursor cursor) { + checkWidget(); + if (cursor != null && cursor.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + this.cursor = cursor; + if (cursor == null) { + getQMasterWidget().setCursor(null); + } else { + getQMasterWidget().setCursor(cursor.cursor); + } + } + + /** + * Returns <code>true</code> if the receiver is enabled and all ancestors up + * to and including the receiver's nearest ancestor shell are enabled. + * Otherwise, <code>false</code> is returned. A disabled control is + * typically not selectable from the user interface and draws with an + * inactive or "grayed" look. + * + * @return the receiver's enabled state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #getEnabled + */ + public boolean isEnabled() { + checkWidget(); + return getQMasterWidget().isEnabled(); + } + + /** + * 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 enabled; + } + + /** + * 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. + */ + Control control = null; + boolean fixFocus = false; + if (!enabled) { + if (display.focusEvent != SWT.FocusOut) { + control = display.getFocusControl(); + fixFocus = isFocusAncestor(control); + } + } + enableWidget(enabled); + if (fixFocus) { + fixFocus(control); + } + } + + void enableWidget(boolean enabled) { + this.enabled = enabled; + getQMasterWidget().setEnabled(enabled); + } + + boolean setFixedFocus() { + if ((style & SWT.NO_FOCUS) != 0) { + return false; + } + return forceFocus(FocusReason.OtherFocusReason); + } + + /** + * Causes the receiver to have the <em>keyboard focus</em>, such that all + * keyboard events will be delivered to it. Focus reassignment will respect + * applicable platform constraints. + * + * @return <code>true</code> if the control got focus, and + * <code>false</code> if it was unable to. + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #forceFocus + */ + public boolean setFocus() { + checkWidget(); + return setFocus(FocusReason.OtherFocusReason); + } + + protected boolean setFocus(FocusReason focusReason) { + if ((style & SWT.NO_FOCUS) != 0) { + return false; + } + return forceFocus(focusReason); + } + + /** + * Sets the font that the receiver will use to paint textual information to + * the font specified by the argument, or to the default font for that kind + * of control if the argument is null. + * + * @param font + * the new font (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setFont(Font font) { + checkWidget(); + if (font != null && font.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + this.font = font; + if (font == null) { + getQMasterWidget().setFont(null); + } else { + getQMasterWidget().setFont(font.getQFont()); + } + } + + /** + * Sets the receiver's foreground color to the color specified by the + * argument, or to the default system color for the control if the argument + * is null. + * <p> + * Note: This operation is a hint and may be overridden by the platform. + * </p> + * + * @param color + * the new color (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setForeground(Color color) { + checkWidget(); + Color oldColor = foreground; + if (color != null) { + if (color.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + } + if (foreground == null && color == null) { + return; + } + if (color == null) { + foreground = null; + } else { + foreground = Color.qt_new(display, color.getColor()); + } + if (oldColor != null) { + oldColor.dispose(); + } + applyForegroundColor(foreground); + } + + protected void updateForeground() { + if (foreground != null) { + applyForegroundColor(foreground); + } + } + + void applyForegroundColor(Color color) { + updatedPalette(color, getForegroundColorRoles()); + } + + private ColorRole[] getForegroundColorRoles() { + return new ColorRole[] { QPalette.ColorRole.WindowText, QPalette.ColorRole.Text, QPalette.ColorRole.ButtonText }; + } + + /** + * Sets the layout data associated with the receiver to the argument. + * + * @param layoutData + * the new layout data for the receiver. + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setLayoutData(Object layoutData) { + checkWidget(); + this.layoutData = layoutData; + } + + /** + * Sets the receiver's location to the point specified by the arguments + * which are relative to the receiver's parent (or its display if its parent + * is null), unless the receiver is a shell. In this case, the point is + * relative to the display. + * + * @param x + * the new x coordinate for the receiver + * @param y + * the new y coordinate for the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setLocation(int x, int y) { + checkWidget(); + setBounds(x, y, 0, 0, true, false); + } + + /** + * Sets the receiver's location to the point specified by the arguments + * which are relative to the receiver's parent (or its display if its parent + * is null), unless the receiver is a shell. In this case, the point is + * relative to the display. + * + * @param location + * the new location for the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setLocation(Point location) { + checkWidget(); + if (location == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + 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. + * <p> + * Note: Disposing of a control that has a pop up menu will dispose of the + * menu. To avoid this behavior, set the menu to null before the control is + * disposed. + * </p> + * + * @param menu + * the new pop up menu + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_MENU_NOT_POP_UP - the menu is not a pop up menu</li> + * <li>ERROR_INVALID_PARENT - if the menu is not in the same + * widget tree</li> + * <li>ERROR_INVALID_ARGUMENT - if the menu has been disposed + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setMenu(Menu menu) { + checkWidget(); + if (menu != null) { + if (menu.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if ((menu.style & SWT.POP_UP) == 0) { + error(SWT.ERROR_MENU_NOT_POP_UP); + } + if (menu.parent != menuShell()) { + error(SWT.ERROR_INVALID_PARENT); + } + } + this.menu = menu; + } + + boolean setRadioFocus(boolean tabbing) { + 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. Nested calls to this method are stacked. + * <p> + * Note: This operation is a hint and may not be supported on some platforms + * or for some widgets. + * </p> + * + * @param redraw + * the new redraw state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #redraw(int, int, int, int, boolean) + * @see #update() + */ + public void setRedraw(boolean redraw) { + checkWidget(); + getQMasterWidget().setUpdatesEnabled(redraw); + } + + /** + * Sets the shape of the control to the region specified by the argument. + * When the argument is null, the default shape of the control is restored. + * + * @param region + * the region that defines the shape of the control (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the region has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public void setRegion(Region region) { + checkWidget(); + if (region != null && region.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + this.region = region; + getQMasterWidget().setMask(QtSWTConverter.convert(region)); + } + + 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(); + setBounds(0, 0, Math.max(0, width), Math.max(0, height), false, true); + } + + /** + * Sets the receiver's size to the point specified by the argument. + * <p> + * Note: Attempting to set the width or height of the receiver to a negative + * number will cause them to be set to zero instead. + * </p> + * + * @param size + * the new size for the receiver + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setSize(Point size) { + checkWidget(); + if (size == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + setSize(size.x, size.y); + } + + boolean setTabGroupFocus() { + return setTabItemFocus(); + } + + boolean setTabItemFocus() { + if (!isShowing()) { + return false; + } + return forceFocus(); + } + + /** + * Sets the receiver's tool tip text to the argument, which may be null + * indicating that the default tool tip for the control will be shown. For a + * control that has a default tool tip, such as the Tree control on Windows, + * setting the tool tip text to an empty string replaces the default, + * causing no tool tip text to be shown. + * <p> + * The mnemonic indicator (character '&') is not displayed in a tool + * tip. To display a single '&' in the tool tip, the character '&' + * can be escaped by doubling it in the string. + * </p> + * + * @param string + * the new tool tip text (or null) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setToolTipText(String string) { + checkWidget(); + getQMasterWidget().setToolTip(string); + } + + /** + * 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 mappedPoint = QtSWTConverter.convert(getQMasterWidget().mapFromGlobal(new QPoint(x, y))); + if (isMirrored()) { + mappedPoint.x = getClientWidth() - mappedPoint.x; + } + return mappedPoint; + } + + boolean isMirrored() { + return (style & SWT.MIRRORED) != 0; + } + + /** + * 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(); + if (isMirrored()) { + x = getClientWidth() - x; + } + return QtSWTConverter.convert(getQMasterWidget().mapToGlobal(new QPoint(x, y))); + } + + /** + * Returns a point which is the result of converting the argument, which is + * specified in coordinates relative to the receiver, to display relative + * coordinates. + * <p> + * + * @param point + * the point to be translated (must not be null) + * @return the translated coordinates + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + */ + public Point toDisplay(Point point) { + checkWidget(); + System.out.println("toDisplay:" + point); + if (point == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + return toDisplay(point.x, point.y); + } + + boolean translateMnemonic(Event event, Control control) { + if (control == this) { + return false; + } + if (!isVisible() || !isEnabled()) { + return false; + } + event.doit = mnemonicMatch(event.character); + return traverse(event); + } + + 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 true; + } + if (!event.doit) { + return false; + } + switch (event.detail) { + case SWT.TRAVERSE_NONE: + return true; + case SWT.TRAVERSE_ESCAPE: + return traverseEscape(); + case SWT.TRAVERSE_RETURN: + return traverseReturn(); + case SWT.TRAVERSE_TAB_NEXT: + return traverseGroup(true); + case SWT.TRAVERSE_TAB_PREVIOUS: + return traverseGroup(false); + case SWT.TRAVERSE_ARROW_NEXT: + return traverseItem(true); + case SWT.TRAVERSE_ARROW_PREVIOUS: + return traverseItem(false); + case SWT.TRAVERSE_MNEMONIC: + return traverseMnemonic(event.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(); + 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()) { + return true; + } + } + if (group.isDisposed()) { + return false; + } + return group.setTabGroupFocus(); + } + + boolean traverseItem(boolean next) { + Control[] children = parent._getChildren(); + int length = children.length; + int index = 0; + while (index < length) { + if (children[index] == this) { + break; + } + index++; + } + /* + * It is possible (but unlikely), that application code could have + * disposed the widget in focus in or out events. Ensure that a disposed + * widget is not accessed. + */ + if (index == length) { + return false; + } + int start = index, offset = next ? 1 : -1; + while ((index = (index + offset + length) % length) != start) { + Control child = children[index]; + if (!child.isDisposed() && child.isTabItem()) { + if (child.setTabItemFocus()) { + return true; + } + } + } + return false; + } + + boolean traverseMnemonic(char key) { + // TODO + // if (mnemonicHit(key)) { + // OS.SendMessage(handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0); + // return true; + // } + return false; + } + + boolean traversePage(boolean next) { + return false; + } + + boolean traverseReturn() { + return false; + } + + /** + * Forces all outstanding paint requests for the widget to be processed + * before this method returns. If there are no outstanding paint request, + * this method does nothing. + * <p> + * Note: This method does not cause a redraw. + * </p> + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #redraw() + * @see #redraw(int, int, int, int, boolean) + * @see PaintListener + * @see SWT#Paint + */ + public void update() { + checkWidget(); + _update(); + } + + void _update() { + QCoreApplication.processEvents(ProcessEventsFlag.ExcludeUserInputEvents); + } + + void updateBackgroundColor() { + Control control = findBackgroundColorControl(); + if (control == null) { + control = this; + } + applyBackgroundColor(control.background); + } + + Control findBackgroundColorControl() { + if (background != null) { + return this; + } + if (parent == null) { + return null; + } + return (state & PARENT_BACKGROUND) != 0 ? parent.findBackgroundColorControl() : null; + } + + void updateBackgroundImage() { + Control control = findBackgroundImageControl(); + if (control == null) { + control = this; + } + applyBackgroundImage(control.backgroundImage); + } + + Control findBackgroundImageControl() { + if (backgroundImage != null) { + return this; + } + if (parent == null) { + return null; + } + return (state & PARENT_BACKGROUND) != 0 ? parent.findBackgroundImageControl() : null; + } + + void updateBackgroundMode() { + int oldState = state & PARENT_BACKGROUND; + checkAndUpdateBackground(); + if (oldState != (state & PARENT_BACKGROUND)) { + updateBackground(); + } + } + + void updateFont(Font oldFont, Font newFont) { + if (getFont().equals(oldFont)) { + setFont(newFont); + } + } + + void updateImages() { + /* Do nothing */ + } + + void updateLayout(boolean all) { + /* Do nothing */ + } + + /** + * Changes the parent of the widget to be the one provided if the underlying + * operating system supports this feature. Returns <code>true</code> if the + * parent is successfully changed. + * + * @param parent + * the new parent for the control. + * @return <code>true</code> if the parent is changed and <code>false</code> + * otherwise. + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * <li>ERROR_NULL_ARGUMENT - if the parent is + * <code>null</code></li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public boolean setParent(Composite parent) { + checkWidget(); + if (parent == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (parent.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (this.parent == parent) { + return true; + } + if (!isReparentable()) { + return false; + } + releaseParent(); + Shell newShell = parent.getShell(), oldShell = getShell(); + Decorations newDecorations = parent.menuShell(), oldDecorations = menuShell(); + if (oldShell != newShell || oldDecorations != newDecorations) { + Menu[] menus = oldShell.findMenus(this); + fixChildren(newShell, oldShell, newDecorations, oldDecorations, menus); + } + getQMasterWidget().setParent(parent.getQWidget()); + return true; + } + + @Override + public boolean qtPaintEvent(QObject source, QPaintEvent paintEvent) { + if (source == getQWidget()) { + try { + isOngoingPaintEvent = true; + renderTemporaryGC(paintEvent.rect()); + sendPaintEvent(paintEvent); + } finally { + isOngoingPaintEvent = false; + } + } + return false; + } + + private void renderTemporaryGC(QRect rect) { + // Render the buffer created outside the paint event, if any + if (temporaryGC != null) { + //System.out.println("render tmp gc for " + this + " " + rect + " " + temporaryGC); + QPainter painter = new QPainter(getQWidget()); + //painter.setClipRect(rect); + painter.drawPicture(0, 0, temporaryGC); + painter.end(); + temporaryGC = null; + } + } + + private void sendPaintEvent(QPaintEvent paintEvent) { + if (!hooks(SWT.Paint) && !filters(SWT.Paint)) { + return; + } + + QRect rect = paintEvent.rect(); + int x = rect.x(); + int y = rect.y(); + int width = rect.width(); + int height = rect.height(); + GCData data = new GCData(); + initGCData(data); + GC gc = GC.qt_new(this, getQWidget(), data); + Event event = new Event(); + event.count = 0; + if (isMirrored()) { + event.x = getClientWidth() - x - width; + } else { + event.x = x; + } + event.y = y; + event.width = width; + event.height = height; + event.gc = gc; + try { + gc.setClipping(x, y, width, height); + sendEvent(SWT.Paint, event); + } finally { + if (!gc.isDisposed()) { + gc.dispose(); + } + } + } + + @Override + public boolean qtResizeEvent(QObject source, QResizeEvent resizeEvent) { + if (source == getQWidget()) { + sendResize(); + } + return super.qtResizeEvent(source, resizeEvent); + } + + @Override + public boolean qtMoveEvent(QObject source, QMoveEvent moveEvent) { + // if (source == getQMasterWidget()) { + // sendMove(); + // } + return true; + } + + @Override + public boolean qtKeyPressEvent(QObject source, QKeyEvent qEvent) { + // if ( ( ( state & NO_KEY_PROPAGATE ) != 0 ) ) { + // return true; + // } + if (source == getQWidget()) { + return sendKeyEvent(SWT.KeyDown, qEvent); + } + return false; + } + + @Override + public boolean qtKeyReleaseEvent(QObject source, QKeyEvent qEvent) { + if (source == getQWidget()) { + return sendKeyEvent(SWT.KeyUp, qEvent); + } + // if ( ( ( state & NO_KEY_PROPAGATE ) != 0 ) ) { + // return true; + // } + return false; + } + + boolean sendKeyEvent(int type, QKeyEvent qEvent) { + Event event = translateKeyEvent(qEvent); + sendEvent(type, event); + if (isDisposed()) { + return true; + } + return !event.doit; + } + + private final Event translateKeyEvent(QKeyEvent qEvent) { + Event event = new Event(); + switch (Key.resolve(qEvent.key())) { + case Key_Enter: + case Key_Return: + event.character = SWT.CR; + break; + case Key_Backspace: + event.character = SWT.BS; + break; + case Key_Delete: + event.character = SWT.DEL; + break; + case Key_Escape: + event.character = SWT.ESC; + break; + case Key_Tab: + event.character = SWT.TAB; + break; + default: + String text = qEvent.text(); + if (text != null && text.length() > 0) { + event.character = qEvent.text().charAt(0); + } + break; + } + event.keyCode = KeyUtil.translateKey(qEvent); + if (event.keyCode == 0) {// keyCode defaults to unicode value + String text = qEvent.text(); + if (text != null && text.length() > 0) { + event.keyCode = qEvent.text().charAt(0); + } + } + event.stateMask = KeyUtil.translateModifiers(qEvent.modifiers()); + return event; + } + + protected boolean sendMouseEvent(int type, QMouseEvent mouseEvent) { + return sendMouseEvent(type, mouseEvent, 0); + } + + protected boolean sendMouseEvent(int type, QMouseEvent mouseEvent, int count) { + Event event = translateMouseEvent(mouseEvent, count); + sendEvent(type, event); + if (isDisposed()) { + return true; + } + return !event.doit; + } + + private Event translateMouseEvent(QMouseEvent mouseEvent, int count) { + Event event = new Event(); + QPoint pos = mouseEvent.pos(); + event.x = pos.x(); + event.y = pos.y(); + event.count = count; + event.button = translateMouseButton(mouseEvent.button()); + event.stateMask = KeyUtil.translateModifiers(mouseEvent.modifiers()) + | translateMouseButtons(mouseEvent.buttons()); + event.stateMask &= ~event.button; + + return event; + } + + protected int translateMouseButton(MouseButton button) { + switch (button) { + case LeftButton: + return SWT.BUTTON1; + case MidButton: + return SWT.BUTTON2; + case RightButton: + return SWT.BUTTON1; + } + return 0; + } + + private int translateMouseButtons(MouseButtons buttons) { + int mask = 0; + if (buttons.isSet(MouseButton.LeftButton)) { + mask |= SWT.BUTTON1; + } + if (buttons.isSet(MouseButton.MidButton)) { + mask |= SWT.BUTTON2; + } + if (buttons.isSet(MouseButton.RightButton)) { + mask |= SWT.BUTTON3; + } + return mask; + } + + @Override + public boolean qtMouseMoveEvent(QObject source, QMouseEvent mouseEvent) { + if (source == getQWidget()) { + if (checkForDragging(mouseEvent)) { + System.out.println("dragging..."); + sendDragEvent(SWT.BUTTON1, mouseEvent.pos().x(), mouseEvent.pos().y()); + return true; + } else { + return sendMouseEvent(SWT.MouseMove, mouseEvent); + } + } + return false; + } + + private boolean checkForDragging(QMouseEvent event) { + return dragStartPos != null && isDragDetectEnabled() + && event.pos().subtract(dragStartPos).manhattanLength() >= QApplication.startDragDistance(); + } + + @Override + public boolean qtMouseButtonPressEvent(QObject source, QMouseEvent mouseEvent) { + if (source == getQWidget()) { + checkForDragStart(mouseEvent); + return sendMouseEvent(SWT.MouseDown, mouseEvent, 1); + } + return false; + } + + private void checkForDragStart(QMouseEvent mouseEvent) { + if (isDragDetectEnabled() && mouseEvent.buttons().isSet(MouseButton.LeftButton)) { + dragStartPos = mouseEvent.pos(); + } + } + + @Override + public boolean qtMouseButtonReleaseEvent(QObject source, QMouseEvent mouseEvent) { + if (source == getQWidget()) { + dragStartPos = null; + return sendMouseEvent(SWT.MouseUp, mouseEvent, 1); + } + return false; + } + + @Override + public boolean qtMouseButtonDblClickEvent(QObject source, QMouseEvent mouseEvent) { + if (source == getQWidget()) { + //System.out.println("mouse dbl click on: " + this); + boolean doit = sendMouseEvent(SWT.MouseDown, mouseEvent, 2); + if (doit) { + return sendMouseEvent(SWT.MouseDoubleClick, mouseEvent, 2); + } + } + return false; + } + + @Override + public void qtFocusInEvent(QObject source) { + if (source != getQMasterWidget()) { + return; + } + try { + display.focusEvent = SWT.FocusIn; + sendEvent(SWT.FocusIn); + } finally { + display.focusEvent = SWT.None; + } + } + + @Override + public void qtFocusOutEvent(QObject source) { + if (source != getQMasterWidget()) { + return; + } + try { + display.focusEvent = SWT.FocusOut; + sendEvent(SWT.FocusOut); + } finally { + display.focusEvent = SWT.None; + } + } + + protected boolean handleContextMenuEvent(QContextMenuEvent menuEvent) { + if (isDisposed()) { + return false; + } + Event event = new Event(); + event.x = menuEvent.globalX(); + event.y = menuEvent.globalY(); + sendEvent(SWT.MenuDetect, event); + + if (this.menu == null || menu.isDisposed()) { + return event.doit; + } + List<QAction> actions = getQWidget().actions(); + if ((actions == null || actions.size() == 0) && menu == null) { + return false; + } + + QMenu popUpMenu = menu.getQMenu(); + popUpMenu.exec(menuEvent.globalPos()); + return true; + } + + @Override + public boolean qtContextMenuEvent(Object source, QContextMenuEvent event) { + if (source == getQWidget()) { + return handleContextMenuEvent(event); + } + return super.qtContextMenuEvent(source, event); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/DateTime.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/DateTime.java new file mode 100644 index 0000000000..be8ea748c2 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/DateTime.java @@ -0,0 +1,806 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.QDate; +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.core.QTime; +import com.trolltech.qt.gui.QCalendarWidget; +import com.trolltech.qt.gui.QDateTimeEdit; +import com.trolltech.qt.gui.QWidget; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Point; + +/** + * Instances of this class are selectable user interface objects that allow the + * user to enter and modify date or time values. + * <p> + * Note that although this class is a subclass of <code>Composite</code>, it + * does not make sense to add children to it, or set a layout on it. + * </p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>DATE, TIME, CALENDAR, SHORT, MEDIUM, LONG, DROP_DOWN</dd> + * <dt><b>Events:</b></dt> + * <dd>DefaultSelection, Selection</dd> + * </dl> + * <p> + * Note: Only one of the styles DATE, TIME, or CALENDAR may be specified, and + * only one of the styles SHORT, MEDIUM, or LONG may be specified. The DROP_DOWN + * style is only valid with the DATE style. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#datetime">DateTime + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * + * @since 3.3 + * @noextend This class is not intended to be subclassed by clients. + */ + +public class DateTime extends Composite { + boolean doubleClick, ignoreSelection; + private QTime calendarTime; + + /** + * @return the time + */ + private QTime getCalendarTime() { + return calendarTime; + } + + /** + * @param time + * the time to set + */ + private void setCalendarTime(QTime time) { + this.calendarTime = time; + } + + static final char SINGLE_QUOTE = '\'';// short date format may include quoted text + static final char DAY_FORMAT_CONSTANT = 'd';// 1-4 lowercase 'd's represent day + static final char MONTH_FORMAT_CONSTANT = 'M';// 1-4 uppercase 'M's represent month + static final char YEAR_FORMAT_CONSTANT = 'y';// 1-5 lowercase 'y's represent year + static final char HOURS_FORMAT_CONSTANT = 'h';// 1-2 upper or lowercase 'h's represent hours + static final char MINUTES_FORMAT_CONSTANT = 'm';// 1-2 lowercase 'm's represent minutes + static final char SECONDS_FORMAT_CONSTANT = 's';// 1-2 lowercase 's's represent seconds + static final char AMPM_FORMAT_CONSTANT = 't';// 1-2 lowercase 't's represent am/pm + + /** + * Constructs a new instance of this class given its parent and a style + * value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a composite control which will be the parent of the new + * instance (cannot be null) + * @param style + * the style of control to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#DATE + * @see SWT#TIME + * @see SWT#CALENDAR + * @see SWT#SHORT + * @see SWT#MEDIUM + * @see SWT#LONG + * @see SWT#DROP_DOWN + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + + public DateTime(Composite parent, int style) { + super(parent, checkStyle(style)); + setDateToToday(); + setTimeToNow(); + } + + @Override + protected QWidget createQWidget(int style) { + state &= ~(CANVAS | THEME_BACKGROUND); + QWidget calendar = new QWidget(); + boolean isCalendarWidget = false; + boolean isTimeEdit = false; + if ((style & SWT.CALENDAR) != 0) { + calendar = new QCalendarWidget(); + isCalendarWidget = true; + ((QCalendarWidget) calendar).setSelectedDate(QDate.currentDate()); + connectSignals(calendar, isCalendarWidget); + } else if ((style & SWT.TIME) != 0) { + isTimeEdit = true; + /* Need to set time twice to get the right widget *with* time. */ + calendar = new QDateTimeEdit(QTime.currentTime()); + ((QDateTimeEdit) calendar).setDate(QDate.currentDate()); + ((QDateTimeEdit) calendar).setTime(QTime.currentTime()); + } else if ((style & SWT.ARROW) != 0 || (style & SWT.DROP_DOWN) != 0) { + calendar = new QDateTimeEdit(QDate.currentDate()); + ((QDateTimeEdit) calendar).setCalendarPopup(true); + ((QDateTimeEdit) calendar).setDate(QDate.currentDate()); + ((QDateTimeEdit) calendar).setTime(QTime.currentTime()); + } else /* default is a QDateEdit */{ + calendar = new QDateTimeEdit(QDate.currentDate()); + ((QDateTimeEdit) calendar).setTime(QTime.currentTime()); + ((QDateTimeEdit) calendar).setDate(QDate.currentDate()); + } + if (!isCalendarWidget) { + connectSignals(calendar, isCalendarWidget); + if ((style & SWT.SHORT) != 0) { + if (isTimeEdit) { + ((QDateTimeEdit) calendar).setDisplayFormat(getShortTimeFormat()); + } else { + ((QDateTimeEdit) calendar).setDisplayFormat(getShortDateFormat()); + } + /* + * when DisplayFormat is set I need to set the time *again* for + * some strange reasons + */ + ((QDateTimeEdit) calendar).setTime(QTime.currentTime()); + } else if ((style & SWT.LONG) != 0) { + ((QDateTimeEdit) calendar).setDisplayFormat(getLongDateFormat()); + ((QDateTimeEdit) calendar).setTime(QTime.currentTime()); + } + } + + return calendar; + } + + private void connectSignals(QWidget calendar, boolean isCalendarWidget) { + if (isCalendarWidget) { + ((QCalendarWidget) calendar).clicked.connect(this, "clicked()"); //$NON-NLS-1$ + ((QCalendarWidget) calendar).selectionChanged.connect(this, "clicked()"); //$NON-NLS-1$ + } else { + /* some missing events */ + //((QDateTimeEdit) calendar).dateChanged.connect(this, "dateChanged()"); //$NON-NLS-1$ + // ((QDateTimeEdit) calendar).dateTimeChanged.connect(this, "dateTimeChanged()"); //$NON-NLS-1$ + // ((QDateTimeEdit) calendar).timeChanged.connect(this, "timeChanged()"); //$NON-NLS-1$ + // ((QDateTimeEdit) calendar).editingFinished.connect(this, "editingFinished"); //$NON-NLS-1$ + + } + } + + protected void clicked() { + Event event = new Event(); + sendEvent(SWT.Selection, event); + } + + /** + * sets the date to now + */ + private void setDateToToday() { + QDate date = QDate.currentDate(); + setQtDate(date); + } + + /** + * sets the date to now + */ + private void setTimeToNow() { + setQtTime(QTime.currentTime()); + setCalendarTime(new QTime(0, 0, 0)); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the control is selected by the user, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * <code>widgetSelected</code> is called when the user changes the control's + * value. <code>widgetDefaultSelected</code> is typically called when ENTER + * is pressed. + * </p> + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + static int checkStyle(int style) { + /* + * Even though it is legal to create this widget with scroll bars, they + * serve no useful purpose because they do not automatically scroll the + * widget's client area. The fix is to clear the SWT style. + */ + style &= ~(SWT.H_SCROLL | SWT.V_SCROLL); + style = checkBits(style, SWT.DATE, SWT.TIME, SWT.CALENDAR, 0, 0, 0); + style = checkBits(style, SWT.MEDIUM, SWT.SHORT, SWT.LONG, 0, 0, 0); + if ((style & SWT.DATE) == 0) { + style &= ~SWT.DROP_DOWN; + } + return style; + } + + @Override + protected void checkSubclass() { + if (!isValidSubclass()) { + error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + QWidget calendar = getQWidget(); + QSize size = calendar.sizeHint(); + return new Point(size.width(), size.height()); + } + + String getComputeSizeString() { + // TODO: Not currently used but might need for WinCE + if ((style & SWT.DATE) != 0) { + if ((style & SWT.SHORT) != 0) { + return getCustomShortDateFormat(); + } + if ((style & SWT.MEDIUM) != 0) { + return getShortDateFormat(); + } + if ((style & SWT.LONG) != 0) { + return getLongDateFormat(); + } + } + if ((style & SWT.TIME) != 0) { + if ((style & SWT.SHORT) != 0) { + return getCustomShortTimeFormat(); + } + return getTimeFormat(); + } + return ""; //$NON-NLS-1$ + } + + String getCustomShortDateFormat() { + // TODO + return "M/yyyy"; //$NON-NLS-1$ + + } + + String getCustomShortTimeFormat() { + StringBuffer buffer = new StringBuffer(getTimeFormat()); + int length = buffer.length(); + boolean inQuotes = false; + int start = 0, end = 0; + while (start < length) { + char ch = buffer.charAt(start); + if (ch == SINGLE_QUOTE) { + inQuotes = !inQuotes; + } else if (ch == SECONDS_FORMAT_CONSTANT && !inQuotes) { + end = start + 1; + while (end < length && buffer.charAt(end) == SECONDS_FORMAT_CONSTANT) { + end++; + } + // skip the preceding separator + while (start > 0 && buffer.charAt(start) != MINUTES_FORMAT_CONSTANT) { + start--; + } + start++; + break; + } + start++; + } + if (start < end) { + buffer.delete(start, end); + } + return buffer.toString(); + } + + String getLongDateFormat() { + return "dddd, d. MMMM yyyy"; //$NON-NLS-1$ + } + + String getShortDateFormat() { + return "MMMM yyyy"; //$NON-NLS-1$ + } + + String getShortTimeFormat() { + return "hh:mm"; //$NON-NLS-1$ + } + + int getShortDateFormatOrdering() { + // TODO + return 0; + } + + String getTimeFormat() { + // TODO + return "h:mm:ss tt"; //$NON-NLS-1$ + } + + boolean is24HourTime() { + // TODO + return true; + } + + /** + * Returns the receiver's date, or day of the month. + * <p> + * The first day of the month is 1, and the last day depends on the month + * and year. + * </p> + * + * @return a positive integer beginning with 1 + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getDay() { + checkWidget(); + if (getQWidget() instanceof QCalendarWidget) { + return ((QCalendarWidget) getQWidget()).selectedDate().day(); + } + return ((QDateTimeEdit) getQWidget()).date().day(); + + } + + /** + * Returns the receiver's hours. + * <p> + * Hours is an integer between 0 and 23. + * </p> + * + * @return an integer between 0 and 23 + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getHours() { + checkWidget(); + if (getQWidget() instanceof QCalendarWidget) { + return getCalendarTime().hour(); + } + return ((QDateTimeEdit) getQWidget()).time().hour(); + + } + + /** + * Returns the receiver's minutes. + * <p> + * Minutes is an integer between 0 and 59. + * </p> + * + * @return an integer between 0 and 59 + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getMinutes() { + checkWidget(); + if (getQWidget() instanceof QCalendarWidget) { + return getCalendarTime().minute(); + } + return ((QDateTimeEdit) getQWidget()).time().minute(); + + } + + /** + * Returns the receiver's month. + * <p> + * The first month of the year is 0, and the last month is 11. + * </p> + * + * @return an integer between 0 and 11 + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getMonth() { + checkWidget(); + + QDate date = getQtDate(); + return date.month() - 1; + } + + @Override + String getNameText() { + return (style & SWT.TIME) != 0 ? getHours() + ":" + getMinutes() + ":" + getSeconds() : getMonth() + "/" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + getDay() + "/" + getYear(); //$NON-NLS-1$ + } + + /** + * Returns the receiver's seconds. + * <p> + * Seconds is an integer between 0 and 59. + * </p> + * + * @return an integer between 0 and 59 + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getSeconds() { + checkWidget(); + if (getQWidget() instanceof QCalendarWidget) { + return getCalendarTime().second(); + } + return ((QDateTimeEdit) getQWidget()).time().second(); + } + + /** + * Returns the receiver's year. + * <p> + * The first year is 1752 and the last year is 9999. + * </p> + * + * @return an integer between 1752 and 9999 + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getYear() { + checkWidget(); + if (getQWidget() instanceof QCalendarWidget) { + return ((QCalendarWidget) getQWidget()).selectedDate().year(); + } + return ((QDateTimeEdit) getQWidget()).date().year(); + } + + @Override + void releaseWidget() { + super.releaseWidget(); + // lastSystemTime = null; + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is selected by the user. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + /** + * Sets the receiver's year, month, and day in a single operation. + * <p> + * This is the recommended way to set the date, because setting the year, + * month, and day separately may result in invalid intermediate dates. + * </p> + * + * @param year + * an integer between 1752 and 9999 + * @param month + * an integer between 0 and 11 + * @param day + * a positive integer beginning with 1 + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public void setDate(int year, int month, int day) { + checkWidget(); + QDate date = new QDate(year, month + 1, day); + if (getQWidget() instanceof QCalendarWidget) { + ((QCalendarWidget) getQWidget()).setSelectedDate(date); + } else { + ((QDateTimeEdit) getQWidget()).setDate(date); + } + } + + /** + * Sets the receiver's date, or day of the month, to the specified day. + * <p> + * The first day of the month is 1, and the last day depends on the month + * and year. If the specified day is not valid for the receiver's month and + * year, then it is ignored. + * </p> + * + * @param day + * a positive integer beginning with 1 + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #setDate + */ + public void setDay(int day) { + checkWidget(); + QDate date = getQtDate(); + date.setDate(date.year(), date.month(), day); + setQtDate(date); + } + + private QDate getQtDate() { + if (getQWidget() instanceof QCalendarWidget) { + return ((QCalendarWidget) getQWidget()).selectedDate(); + } + return ((QDateTimeEdit) getQWidget()).date(); + } + + private QTime getQtTime() { + if (getQWidget() instanceof QCalendarWidget) { + return getCalendarTime(); + } + return ((QDateTimeEdit) getQWidget()).time(); + } + + private void setQtDate(final QDate date) { + if (getQWidget() instanceof QCalendarWidget) { + ((QCalendarWidget) getQWidget()).setSelectedDate(date); + } else { + ((QDateTimeEdit) getQWidget()).setDate(date); + } + } + + private void setQtTime(final QTime time) { + if (getQWidget() instanceof QCalendarWidget) { + setCalendarTime(time); + } else { + ((QDateTimeEdit) getQWidget()).setTime(time); + } + } + + /** + * Sets the receiver's hours. + * <p> + * Hours is an integer between 0 and 23. + * </p> + * + * @param hours + * an integer between 0 and 23 + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setHours(int hours) { + checkWidget(); + QTime time = new QTime(hours, getQtTime().minute(), getQtTime().second()); + setQtTime(time); + } + + /** + * Sets the receiver's minutes. + * <p> + * Minutes is an integer between 0 and 59. + * </p> + * + * @param minutes + * an integer between 0 and 59 + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setMinutes(int minutes) { + checkWidget(); + QTime time = new QTime(getQtTime().hour(), minutes, getQtTime().second()); + setQtTime(time); + } + + /** + * Sets the receiver's month. + * <p> + * The first month of the year is 0, and the last month is 11. If the + * specified month is not valid for the receiver's day and year, then it is + * ignored. + * </p> + * + * @param month + * an integer between 0 and 11 + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #setDate + */ + public void setMonth(final int month) { + checkWidget(); + + QDate date = getQtDate(); + date.setDate(date.year(), month + 1, date.day()); + setQtDate(date); + } + + /** + * Sets the receiver's seconds. + * <p> + * Seconds is an integer between 0 and 59. + * </p> + * + * @param seconds + * an integer between 0 and 59 + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setSeconds(int seconds) { + checkWidget(); + QTime time = new QTime(getQtTime().hour(), getQtTime().minute(), seconds); + setQtTime(time); + + } + + /** + * Sets the receiver's hours, minutes, and seconds in a single operation. + * + * @param hours + * an integer between 0 and 23 + * @param minutes + * an integer between 0 and 59 + * @param seconds + * an integer between 0 and 59 + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public void setTime(int hours, int minutes, int seconds) { + checkWidget(); + setQtTime(new QTime(hours, minutes, seconds)); + } + + /** + * Sets the receiver's year. + * <p> + * The first year is 1752 and the last year is 9999. If the specified year + * is not valid for the receiver's day and month, then it is ignored. + * </p> + * + * @param year + * an integer between 1752 and 9999 + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #setDate + */ + public void setYear(int year) { + checkWidget(); + QDate date = new QDate(year, getQtDate().month(), getQtDate().day()); + setQtDate(date); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Decorations.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Decorations.java new file mode 100644 index 0000000000..ecc78ea4da --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Decorations.java @@ -0,0 +1,1218 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.QObject; +import com.trolltech.qt.core.QRect; +import com.trolltech.qt.core.Qt.WindowState; +import com.trolltech.qt.core.Qt.WindowStates; +import com.trolltech.qt.gui.QLayout; +import com.trolltech.qt.gui.QMainWindow; +import com.trolltech.qt.gui.QWidget; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.internal.qt.QtSWTConverter; + +/** + * Instances of this class provide the appearance and behavior of + * <code>Shells</code>, but are not top level shells or dialogs. Class + * <code>Shell</code> shares a significant amount of code with this class, and + * is a subclass. + * <p> + * IMPORTANT: This class was intended to be abstract and should <em>never</em> + * be referenced or instantiated. Instead, the class <code>Shell</code> should + * be used. + * </p> + * <p> + * Instances are always displayed in one of the maximized, minimized or normal + * states: + * <ul> + * <li> + * When an instance is marked as <em>maximized</em>, the window manager will + * typically resize it to fill the entire visible area of the display, and the + * instance is usually put in a state where it can not be resized (even if it + * has style <code>RESIZE</code>) until it is no longer maximized.</li> + * <li> + * When an instance is in the <em>normal</em> state (neither maximized or + * minimized), its appearance is controlled by the style constants which were + * specified when it was created and the restrictions of the window manager (see + * below).</li> + * <li> + * When an instance has been marked as <em>minimized</em>, its contents (client + * area) will usually not be visible, and depending on the window manager, it + * may be "iconified" (that is, replaced on the desktop by a small simplified + * representation of itself), relocated to a distinguished area of the screen, + * or hidden. Combinations of these changes are also possible.</li> + * </ul> + * </p> + * Note: The styles supported by this class must be treated as <em>HINT</em>s, + * since the window manager for the desktop on which the instance is visible has + * ultimate control over the appearance and behavior of decorations. For + * example, some window managers only support resizable windows and will always + * assume the RESIZE style, even if it is not set. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE, ON_TOP, TOOL</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * Class <code>SWT</code> provides two "convenience constants" for the most + * commonly required style combinations: + * <dl> + * <dt><code>SHELL_TRIM</code></dt> + * <dd> + * the result of combining the constants which are required to produce a typical + * application top level shell: (that is, + * <code>CLOSE | TITLE | MIN | MAX | RESIZE</code>)</dd> + * <dt><code>DIALOG_TRIM</code></dt> + * <dd> + * the result of combining the constants which are required to produce a typical + * application dialog shell: (that is, <code>TITLE | CLOSE | BORDER</code>)</dd> + * </dl> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> within the + * SWT implementation. + * </p> + * + * @see #getMinimized + * @see #getMaximized + * @see Shell + * @see SWT + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class Decorations extends Canvas { + private static final int WIDGETSIZE_MAX = 16777215; + Image image, smallImage, largeImage; + Image[] images; + Menu menuBar; + Menu[] menus; + Control savedFocus; + Button defaultButton, saveDefault; + int swFlags, nAccel; + boolean moved, resized, opened; + private int restoreState; + private Point fixedSize; + static int topTitleFrame = -1; + static int leftTitleFrame = -1; + static int rightTitleFrame = -1; + static int bottomTitleFrame = -1; + static int topThinFrame = -1; + static int leftThinFrame = -1; + static int rightThinFrame = -1; + static int bottomThinFrame = -1; + + /** + * 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)); + } + + protected QWidget getWindowControl() { + return getQWidget(); + } + + QWidget getMenuContainer() { + return getWindowControl(); + } + + void addMenu(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 bringToTop() { + if (isDisposed()) { + return; + } + getWindowControl().activateWindow(); + getWindowControl().raise(); + } + + static int checkStyle(int style) { + if ((style & SWT.NO_TRIM) != 0) { + style &= ~(SWT.CLOSE | SWT.TITLE | SWT.MIN | SWT.MAX | SWT.RESIZE | SWT.BORDER); + } + if ((style & (SWT.MENU | SWT.MIN | SWT.MAX | SWT.CLOSE)) != 0) { + style |= SWT.TITLE; + } + + /* + * 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; + } + + @Override + protected void checkAndUpdateBorder() { + /* Do nothing */ + } + + @Override + void checkOpened() { + if (!opened) { + resized = false; + } + } + + @Override + protected void checkSubclass() { + if (!isValidSubclass()) { + error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + boolean closeWidget() { + Event event = new Event(); + event.doit = true; + sendEvent(SWT.Close, event); + if (event.doit && !isDisposed()) { + dispose(); + } + if (isDisposed()) { + return false; + } + return !event.doit; + } + + int compare(ImageData data1, ImageData data2, int width, int height, int depth) { + int value1 = Math.abs(data1.width - width), value2 = Math.abs(data2.width - width); + if (value1 == value2) { + int transparent1 = data1.getTransparencyType(); + int transparent2 = data2.getTransparencyType(); + if (transparent1 == transparent2) { + if (data1.depth == data2.depth) { + return 0; + } + return data1.depth > data2.depth && data1.depth <= depth ? -1 : 1; + } + if (transparent1 == SWT.TRANSPARENCY_ALPHA) { + return -1; + } + if (transparent2 == SWT.TRANSPARENCY_ALPHA) { + return 1; + } + if (transparent1 == SWT.TRANSPARENCY_MASK) { + return -1; + } + if (transparent2 == SWT.TRANSPARENCY_MASK) { + return 1; + } + if (transparent1 == SWT.TRANSPARENCY_PIXEL) { + return -1; + } + if (transparent2 == SWT.TRANSPARENCY_PIXEL) { + return 1; + } + return 0; + } + return value1 < value2 ? -1 : 1; + } + + @Override + Control computeTabGroup() { + return this; + } + + @Override + Control computeTabRoot() { + return this; + } + + @Override + public Rectangle computeTrim(int x, int y, int width, int height) { + checkWidget(); + + Rectangle trim = new Rectangle(x, y, width, height); + + QRect outer = getQWidget().frameGeometry(); + QRect inner = getQWidget().geometry(); + + int leftTrim, rightTrim; + leftTrim = rightTrim = outer.x() - inner.x(); + int topTrim = inner.y() - outer.y(); + int bottomTrim = outer.y() - inner.y(); + + trim.x -= leftTrim; + trim.width += leftTrim + rightTrim; + trim.y -= topTrim; + trim.height += topTrim + bottomTrim; + + return trim; + } + + @Override + public void dispose() { + if (isDisposed()) { + return; + } + if (!isValidThread()) { + error(SWT.ERROR_THREAD_INVALID_ACCESS); + } + if (!(this instanceof Shell)) { + if (!traverseDecorations(true)) { + Shell shell = getShell(); + shell.setFocus(); + } + setVisible(false); + } + super.dispose(); + } + + void fixDecorations(Decorations newDecorations, Control control, Menu[] menus) { + if (this == newDecorations) { + return; + } + if (control == savedFocus) { + savedFocus = null; + } + if (control == defaultButton) { + defaultButton = null; + } + if (control == saveDefault) { + saveDefault = null; + } + if (menus == null) { + return; + } + Menu menu = control.getMenu(); + if (menu != null) { + int index = 0; + while (index < menus.length) { + if (menus[index] == menu) { + control.setMenu(null); + return; + } + index++; + } + menu.fixMenus(newDecorations); + } + } + + /** + * Returns the receiver's default button if one had previously been set, + * otherwise returns null. + * + * @return the default button or null + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #setDefaultButton(Button) + */ + public Button getDefaultButton() { + checkWidget(); + return defaultButton; + } + + /** + * Returns the receiver's image if it had previously been set using + * <code>setImage()</code>. The image is typically displayed by the window + * manager when the instance is marked as iconified, and may also be + * displayed somewhere in the trim when the instance is in normal or + * maximized states. + * <p> + * Note: This method will return null if called before + * <code>setImage()</code> is called. It does not provide access to a window + * manager provided, "default" image even if one exists. + * </p> + * + * @return the image + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Image getImage() { + checkWidget(); + return image; + } + + /** + * Returns the receiver's images if they had previously been set using + * <code>setImages()</code>. Images are typically displayed by the window + * manager when the instance is marked as iconified, and may also be + * displayed somewhere in the trim when the instance is in normal or + * maximized states. Depending where the icon is displayed, the platform + * chooses the icon with the "best" attributes. It is expected that the + * array will contain the same icon rendered at different sizes, with + * different depth and transparency attributes. + * + * <p> + * Note: This method will return an empty array if called before + * <code>setImages()</code> is called. It does not provide access to a + * window manager provided, "default" image even if one exists. + * </p> + * + * @return the images + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ + public Image[] getImages() { + checkWidget(); + if (images == null) { + return new Image[0]; + } + Image[] result = new Image[images.length]; + System.arraycopy(images, 0, result, 0, images.length); + return result; + } + + /** + * Returns <code>true</code> if the receiver is currently maximized, and + * false otherwise. + * <p> + * + * @return the maximized state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + * + * @see #setMaximized + */ + public boolean getMaximized() { + checkWidget(); + return getWindowControl().isMaximized(); + } + + /** + * Returns the receiver's menu bar if one had previously been set, otherwise + * returns null. + * + * @return the menu bar or null + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Menu getMenuBar() { + checkWidget(); + return menuBar; + } + + /** + * Returns <code>true</code> if the receiver is currently minimized, and + * false otherwise. + * <p> + * + * @return the minimized state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + * + * @see #setMinimized + */ + public boolean getMinimized() { + checkWidget(); + return getWindowControl().isMinimized(); + } + + @Override + String getNameText() { + return getText(); + } + + /** + * Returns the receiver's text, which is the string that the window manager + * will typically display as the receiver's <em>title</em>. If the text has + * not previously been set, returns an empty string. + * + * @return the text + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String getText() { + checkWidget(); + return getWindowControl().windowTitle(); + } + + @Override + public boolean qtCloseEvent() { + if (isEnabled()) { + closeWidget(); + } + return true; + } + + @Override + public boolean isReparentable() { + checkWidget(); + /* + * Feature in Windows. Calling SetParent() for a shell causes a kind of + * fake MDI to happen. It doesn't work well on Windows and is not + * supported on the other platforms. The fix is to disallow the + * SetParent(). + */ + return false; + } + + @Override + boolean isTabGroup() { + /* + * Can't test WS_TAB bits because they are the same as WS_MAXIMIZEBOX. + */ + return true; + } + + @Override + boolean isTabItem() { + /* + * Can't test WS_TAB bits because they are the same as WS_MAXIMIZEBOX. + */ + return false; + } + + @Override + Decorations menuShell() { + return this; + } + + @Override + void releaseChildren(boolean destroy) { + if (menuBar != null) { + menuBar.release(false); + menuBar = null; + } + super.releaseChildren(destroy); + if (menus != null) { + for (int i = 0; i < menus.length; i++) { + Menu menu = menus[i]; + if (menu != null && !menu.isDisposed()) { + menu.dispose(); + } + } + menus = null; + } + } + + @Override + void releaseWidget() { + super.releaseWidget(); + if (smallImage != null) { + smallImage.dispose(); + } + if (largeImage != null) { + largeImage.dispose(); + } + smallImage = largeImage = image = null; + images = null; + savedFocus = null; + defaultButton = saveDefault = null; + } + + void removeMenu(Menu menu) { + if (menus == null) { + return; + } + for (int i = 0; i < menus.length; i++) { + if (menus[i] == menu) { + menus[i] = null; + return; + } + } + } + + boolean restoreFocus() { + if (savedFocus != null && savedFocus.isDisposed()) { + savedFocus = null; + } + return savedFocus != null && savedFocus.setSavedFocus(); + } + + void saveFocus() { + Control control = display.getFocusControl(); + if (control != null && control != this && this == control.menuShell()) { + setSavedFocus(control); + } + } + + protected void unlockSize() { + getWindowControl().setMaximumSize(WIDGETSIZE_MAX, WIDGETSIZE_MAX); + getWindowControl().setMinimumSize(0, 0); + } + + protected boolean sizeFixed() { + return getWindowControl().minimumSize().equals(getQWidget().maximumSize()); + } + + protected void setRestoreState(int state, boolean restore) { + int oldState = getWindowControl().windowState().value(); + if (restore) { + if ((oldState & state) == 0) { + return; + } + restoreState(); + } else { + setState(state); + } + } + + protected void restoreState() { + // This might not restore it from minimized if wm doesn't allow it. + // It might e.g. blink in the task bar to indicate to the user + // that the window wants to become active. + if (restoreState == WindowState.WindowMinimized.value()) { + setState(WindowState.WindowMinimized.value()); + } else if (restoreState == WindowState.WindowMaximized.value()) { + setState(WindowState.WindowMaximized.value()); + } else { + setState(WindowState.WindowNoState.value()); + } + bringToTop(); + restoreState = 0; + } + + protected void storeState(int state) { + if ((state & WindowState.WindowMinimized.value()) != 0) { + restoreState = WindowState.WindowMinimized.value(); + } else if ((state & WindowState.WindowMaximized.value()) != 0) { + restoreState = WindowState.WindowMaximized.value(); + } else { + restoreState = 0; + } + } + + protected void setState(final int state) { + final int oldState = getWindowControl().windowState().value(); + if ((oldState & state) != 0) { + return; + } + storeState(oldState); + int newState = oldState; + int statesToRemove = (WindowState.WindowFullScreen.value() | WindowState.WindowMaximized.value() | WindowState.WindowMinimized + .value()) + & ~state; + newState &= ~statesToRemove; + newState |= state; + + // Full screen and maximize won't work if size is fixed. The fixed size + // needs to be stored and then restored when going back to normal state. + if ((newState & (WindowState.WindowFullScreen.value() | WindowState.WindowMaximized.value())) != 0 + && (oldState & (WindowState.WindowFullScreen.value() | WindowState.WindowMaximized.value())) == 0) { + if (sizeFixed()) { + fixedSize = QtSWTConverter.convert(getWindowControl().minimumSize()); + style |= SWT.Resize; + unlockSize(); + } + } + + // Going directly from full screen to maximized doesn't work. Need to go + // normal first. + if ((newState & WindowState.WindowMaximized.value()) != 0 + && (oldState & WindowState.WindowFullScreen.value()) != 0) { + getWindowControl().setWindowState(WindowState.WindowNoState); + } + + getWindowControl().setWindowState(new WindowStates(newState)); + + // Restore the fixed size if back to normal + if ((newState & (WindowState.WindowFullScreen.value() | WindowState.WindowMaximized.value())) == 0) { + if (fixedSize != null) { + getWindowControl().setFixedSize(fixedSize.x, fixedSize.y); + style &= ~SWT.Resize; + fixedSize = null; + } + } + } + + /** + * If the argument is not null, sets the receiver's default button to the + * argument, and if the argument is null, sets the receiver's default button + * to the first button which was set as the receiver's default button + * (called the <em>saved default button</em>). If no default button had + * previously been set, or the saved default button was disposed, the + * receiver's default button will be set to null. + * <p> + * The default button is the button that is selected when the receiver is + * active and the user presses ENTER. + * </p> + * + * @param button + * the new default button + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the button has been + * disposed</li> + * <li>ERROR_INVALID_PARENT - if the control is not in the + * same widget tree</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setDefaultButton(Button button) { + checkWidget(); + if (button != null) { + if (button.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (button.menuShell() != this) { + error(SWT.ERROR_INVALID_PARENT); + } + } + setDefaultButton(button, true); + } + + void setDefaultButton(Button button, boolean save) { + if (button == null) { + if (defaultButton == saveDefault) { + if (save) { + saveDefault = null; + } + return; + } + } else { + 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; + } + } + + /** + * Sets the receiver's image to the argument, which may be null. The image + * is typically displayed by the window manager when the instance is marked + * as iconified, and may also be displayed somewhere in the trim when the + * instance is in normal or maximized states. + * + * @param image + * the new image (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the image has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setImage(Image image) { + checkWidget(); + if (image != null && image.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + this.image = image; + if (image != null) { + getWindowControl().setWindowIcon(image.getQIcon()); + } + } + + /** + * Sets the receiver's images to the argument, which may be an empty array. + * Images are typically displayed by the window manager when the instance is + * marked as iconified, and may also be displayed somewhere in the trim when + * the instance is in normal or maximized states. Depending where the icon + * is displayed, the platform chooses the icon with the "best" attributes. + * It is expected that the array will contain the same icon rendered at + * different sizes, with different depth and transparency attributes. + * + * @param images + * the new image array + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of images is null</li> + * <li>ERROR_INVALID_ARGUMENT - if one of the images is null + * or has been disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ + public void setImages(Image[] images) { + checkWidget(); + if (images == null) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + for (int i = 0; i < images.length; i++) { + if (images[i] == null || images[i].isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + } + this.images = images; + this.images = images; + if (parent != null) { + return; + } + if (images != null && images.length > 1) { + Image[] bestImages = new Image[images.length]; + System.arraycopy(images, 0, bestImages, 0, images.length); + sort(bestImages); + images = bestImages; + } + if (images.length > 0) { + getWindowControl().setWindowIcon(images[0].getQIcon()); + } else { + getWindowControl().setWindowIcon(null); + } + } + + /** + * Sets the maximized state of the receiver. If the argument is + * <code>true</code> causes the receiver to switch to the maximized state, + * and if the argument is <code>false</code> and the receiver was previously + * maximized, causes the receiver to switch back to either the minimized or + * normal states. + * <p> + * Note: The result of intermixing calls to <code>setMaximized(true)</code> + * and <code>setMinimized(true)</code> will vary by platform. Typically, the + * behavior will match the platform user's expectations, but not always. + * This should be avoided if possible. + * </p> + * + * @param maximized + * the new maximized state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #setMinimized + */ + public void setMaximized(boolean maximized) { + checkWidget(); + if (maximized) { + getWindowControl().showMaximized(); + + } else { + getWindowControl().showNormal(); + } + } + + /** + * 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 (menuBar != null) { + menuBar.dispose(); + } + menuBar = menu; + if (parent == null) { // window + ((QMainWindow) getMenuContainer()).setMenuBar(menu.getQMenuBar()); + } else { + QLayout layout = getWindowControl().layout(); + layout.setMenuBar(menu.getQWidget()); + } + + } + + /** + * Sets the minimized stated of the receiver. If the argument is + * <code>true</code> causes the receiver to switch to the minimized state, + * and if the argument is <code>false</code> and the receiver was previously + * minimized, causes the receiver to switch back to either the maximized or + * normal states. + * <p> + * Note: The result of intermixing calls to <code>setMaximized(true)</code> + * and <code>setMinimized(true)</code> will vary by platform. Typically, the + * behavior will match the platform user's expectations, but not always. + * This should be avoided if possible. + * </p> + * + * @param minimized + * the new maximized state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #setMaximized + */ + public void setMinimized(boolean minimized) { + checkWidget(); + if (minimized) { + getWindowControl().showMinimized(); + + } else { + getWindowControl().showNormal(); + } + } + + void setSavedFocus(Control control) { + savedFocus = control; + } + + /** + * Sets the receiver's text, which is the string that the window manager + * will typically display as the receiver's <em>title</em>, to the argument, + * which must not be null. + * + * @param title + * 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 title) { + checkWidget(); + if (title == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + // fix for emtpy title + if (title.length() == 0) { + title = " "; //$NON-NLS-1$ + } + getWindowControl().setWindowTitle(title); + getWindowControl().setWindowIconText(title); + } + + void sort(Image[] images) { + /* Shell Sort from K&R, pg 108 */ + int length = images.length; + if (length <= 1) { + return; + } + ImageData[] datas = new ImageData[length]; + for (int i = 0; i < length; i++) { + datas[i] = images[i].getImageData(); + } + for (int gap = length / 2; gap > 0; gap /= 2) { + for (int i = gap; i < length; i++) { + for (int j = i - gap; j >= 0; j -= gap) { + if (compare(datas[j], datas[j + gap]) >= 0) { + Image swap = images[j]; + images[j] = images[j + gap]; + images[j + gap] = swap; + ImageData swapData = datas[j]; + datas[j] = datas[j + gap]; + datas[j + gap] = swapData; + } + } + } + } + } + + int compare(ImageData data1, ImageData data2) { + if (data1.width == data2.width && data1.height == data2.height) { + int transparent1 = data1.getTransparencyType(); + int transparent2 = data2.getTransparencyType(); + if (transparent1 == SWT.TRANSPARENCY_ALPHA) { + return -1; + } + if (transparent2 == SWT.TRANSPARENCY_ALPHA) { + return 1; + } + if (transparent1 == SWT.TRANSPARENCY_MASK) { + return -1; + } + if (transparent2 == SWT.TRANSPARENCY_MASK) { + return 1; + } + if (transparent1 == SWT.TRANSPARENCY_PIXEL) { + return -1; + } + if (transparent2 == SWT.TRANSPARENCY_PIXEL) { + return 1; + } + return 0; + } + return data1.width > data2.width || data1.height > data2.height ? -1 : 1; + } + + boolean traverseDecorations(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 instanceof Decorations) { + if (child.setFocus()) { + return true; + } + } + } + return false; + } + + @Override + boolean traverseItem(boolean next) { + return false; + } + + @Override + boolean traverseReturn() { + if (defaultButton == null || defaultButton.isDisposed()) { + return false; + } + if (!defaultButton.isVisible() || !defaultButton.isEnabled()) { + return false; + } + defaultButton.click(); + return true; + } + + @Override + public void qtFocusInEvent(QObject source) { + if (source != getQMasterWidget()) { + return; + } + super.qtFocusInEvent(source); + if (savedFocus != this) { + restoreFocus(); + } + } + + @Override + public void qtFocusOutEvent(QObject source) { + if (source != getQMasterWidget()) { + return; + } + super.qtFocusInEvent(source); + if (savedFocus != this) { + saveFocus(); + } + } + + @Override + public boolean qtWindowActivateEvent(QObject source) { + if (source == getWindowControl()) { + sendEvent(SWT.Activate); + } + return false; + } + + @Override + public boolean qtWindowDeactivateEvent(QObject source) { + if (source == getWindowControl()) { + sendEvent(SWT.Deactivate); + saveFocus(); + } + return false; + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/DirectoryDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/DirectoryDialog.java new file mode 100644 index 0000000000..697a3c1e76 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/DirectoryDialog.java @@ -0,0 +1,202 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.QDir; +import com.trolltech.qt.gui.QFileDialog; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; + +/** + * Instances of this class allow the user to navigate the file system and select + * a directory. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>(none)</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> within the + * SWT implementation. + * </p> + * + * @see <a + * href="http://www.eclipse.org/swt/snippets/#directorydialog">DirectoryDialog + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample, Dialog tab</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class DirectoryDialog extends Dialog { + String message = "", filterPath = ""; //$NON-NLS-1$//$NON-NLS-2$ + String directoryPath = ""; //$NON-NLS-1$ + String[] dirNames = new String[0]; + QFileDialog fd; + + /** + * Constructs a new instance of this class given only its parent. + * + * @param parent + * a shell which will be the parent of the new instance + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + */ + public DirectoryDialog(Shell parent) { + this(parent, SWT.APPLICATION_MODAL); + } + + /** + * Constructs a new instance of this class given its parent and a style + * value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a shell which will be the parent of the new instance + * @param style + * the style of dialog to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + */ + public DirectoryDialog(Shell parent, int style) { + super(parent, checkStyle(parent, style)); + checkSubclass(); + fd = new QFileDialog(); + fd.setFileMode(QFileDialog.FileMode.DirectoryOnly); + } + + /** + * Returns the path which the dialog will use to filter the directories it + * shows. + * + * @return the filter path + * + * @see #setFilterPath + */ + public String getFilterPath() { + QDir dir = fd.directory(); + return dir.absolutePath(); + } + + /** + * 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() { + + java.util.List<String> dirs = null; + if (fd.exec() != 0) { + dirs = fd.selectedFiles(); + } + directoryPath = dirs.get(0); // + fd.disposeLater(); + + return directoryPath; + } + + /** + * Sets the path that the dialog will use to filter the directories it shows + * to the argument, which may be null. If the string is null, then the + * operating system's default filter path will be used. + * <p> + * Note that the path string is platform dependent. For convenience, either + * '/' or '\' can be used as a path separator. + * </p> + * + * @param string + * the filter path + */ + public void setFilterPath(String string) { + fd.setDirectory(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 + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + */ + public void setMessage(String string) { + /* + * QFileDialog has nothing like this message. There's a caption which + * will be shown in the title of the dialog window. But this has to be + * set when the dialog is initialized. There are also some labelTexts + * which can be set like setLabelText(DialogLabel.FileName, "Choose:") + * but these are only for describing buttons and textfields + */ + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + + message = string; + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Display.java new file mode 100644 index 0000000000..5d0bdf4a25 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Display.java @@ -0,0 +1,3200 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import com.trolltech.qt.core.QEvent; +import com.trolltech.qt.core.QEventLoop; +import com.trolltech.qt.core.QMessageHandler; +import com.trolltech.qt.core.QObject; +import com.trolltech.qt.core.QPoint; +import com.trolltech.qt.core.QRect; +import com.trolltech.qt.core.QTime; +import com.trolltech.qt.core.QTimer; +import com.trolltech.qt.core.QTimerEvent; +import com.trolltech.qt.core.QEvent.Type; +import com.trolltech.qt.core.QEventLoop.ProcessEventsFlags; +import com.trolltech.qt.core.Qt.Key; +import com.trolltech.qt.core.Qt.KeyboardModifier; +import com.trolltech.qt.core.Qt.KeyboardModifiers; +import com.trolltech.qt.core.Qt.MouseButton; +import com.trolltech.qt.gui.QApplication; +import com.trolltech.qt.gui.QCloseEvent; +import com.trolltech.qt.gui.QContextMenuEvent; +import com.trolltech.qt.gui.QCursor; +import com.trolltech.qt.gui.QFont; +import com.trolltech.qt.gui.QIcon; +import com.trolltech.qt.gui.QKeyEvent; +import com.trolltech.qt.gui.QMouseEvent; +import com.trolltech.qt.gui.QMoveEvent; +import com.trolltech.qt.gui.QPaintDeviceInterface; +import com.trolltech.qt.gui.QPaintEvent; +import com.trolltech.qt.gui.QPicture; +import com.trolltech.qt.gui.QPixmap; +import com.trolltech.qt.gui.QResizeEvent; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QWindowStateChangeEvent; +import com.trolltech.qt.gui.QStyle.StandardPixmap; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTError; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.graphics.Device; +import org.eclipse.swt.graphics.DeviceData; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.GCData; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.internal.qt.KeyUtil; +import org.eclipse.swt.internal.qt.QtSWTConverter; +import org.eclipse.swt.internal.qt.SWQT; + +/** + * Instances of this class are responsible for managing the connection between + * SWT and the underlying operating system. Their most important function is to + * implement the SWT event loop in terms of the platform event model. They also + * provide various methods for accessing information about the operating system, + * and have overall control over the operating system resources which SWT + * allocates. + * <p> + * Applications which are built with SWT will <em>almost always</em> require + * only a single display. In particular, some platforms which SWT supports will + * not allow more than one <em>active</em> display. In other words, some + * platforms do not support creating a new display if one already exists that + * has not been sent the <code>dispose()</code> message. + * <p> + * In SWT, the thread which creates a <code>Display</code> instance is + * distinguished as the <em>user-interface thread</em> for that display. + * </p> + * The user-interface thread for a particular display has the following special + * attributes: + * <ul> + * <li> + * The event loop for that display must be run from the thread.</li> + * <li> + * Some SWT API methods (notably, most of the public methods in + * <code>Widget</code> and its subclasses), may only be called from the thread. + * (To support multi-threaded user-interface applications, class + * <code>Display</code> provides inter-thread communication methods which allow + * threads other than the user-interface thread to request that it perform + * operations on their behalf.)</li> + * <li> + * The thread is not allowed to construct other <code>Display</code>s until that + * display has been disposed. (Note that, this is in addition to the restriction + * mentioned above concerning platform support for multiple displays. Thus, the + * only way to have multiple simultaneously active displays, even on platforms + * which support it, is to have multiple threads.)</li> + * </ul> + * Enforcing these attributes allows SWT to be implemented directly on the + * underlying operating system's event model. This has numerous benefits + * including smaller footprint, better use of resources, safer memory + * management, clearer program logic, better performance, and fewer overall + * operating system threads required. The down side however, is that care must + * be taken (only) when constructing multi-threaded applications to use the + * inter-thread communication mechanisms which this class provides when + * required. </p> + * <p> + * All SWT API methods which may only be called from the user-interface thread + * are distinguished in their documentation by indicating that they throw the " + * <code>ERROR_THREAD_INVALID_ACCESS</code>" SWT exception. + * </p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>(none)</dd> + * <dt><b>Events:</b></dt> + * <dd>Close, Dispose, Settings</dd> + * </dl> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see #syncExec + * @see #asyncExec + * @see #wake + * @see #readAndDispatch + * @see #sleep + * @see Device#dispose + * @see <a href="http://www.eclipse.org/swt/snippets/#display">Display + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class Display extends Device { + + Thread thread; + int threadId; + /* Windows and Events */ + private Event[] eventQueue; + private EventTable eventTable, filterTable; + + /* Focus */ + int focusEvent; + Control focusControl; + + /* Menus */ + private Menu[] bars; + Menu[] popups; + private MenuItem[] items; + + /* Settings */ + private static final int /* long */SETTINGS_ID = 100; + + /* + * The start value for WM_COMMAND id's. Windows reserves the values 0..100. + * + * The SmartPhone SWT resource file reserves the values 101..107. + */ + private static final int ID_START = 108; + + /* Sync/Async Widget Communication */ + private Synchronizer synchronizer = new Synchronizer(this); + + /* Display Shutdown */ + private Runnable[] disposeList; + + /* System Tray */ + private Tray tray; + + /* Timers */ + private int /* long */[] timerIds; + private Runnable[] timerList; + private int /* long */nextTimerId = SETTINGS_ID + 1; + + /* Keyboard and Mouse */ + int lastKey; + int lastAscii; + boolean lastVirtual; + boolean lastNull; + boolean xMouse; + + /* System Resources */ + private Font systemFont; + private Image errorImage, infoImage, questionImage, warningIcon; + private Cursor[] cursors = new Cursor[SWT.CURSOR_HAND + 1]; + + /* Display Data */ + private Object data; + private String[] keys; + private Object[] values; + + /* Multiple Displays */ + private static Display Default; + private static Display[] Displays = new Display[4]; + + /* Modality */ + Shell[] modalShells; + private Dialog modalDialog; + + /* Qt specific fields */ + private String styleSheet; + private Map<Object, Widget> qt2swtControlMap; + private MasterEventFilter masterEventFilter; + private int lastEventTime; + private static final ProcessEventsFlags PROCESS_EVENTS_FLAGS = new ProcessEventsFlags( + QEventLoop.ProcessEventsFlag.AllEvents); + private QTimer timer; + private final boolean ignorePaintEvents = false; + private QMessageHandler messageHandler; + + /* Package Name */ + private static final String PACKAGE_PREFIX = "org.eclipse.swt.widgets."; //$NON-NLS-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 called from a thread + * that already created an existing display</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see #getCurrent + * @see #getDefault + * @see Widget#checkSubclass + * @see Shell + */ + public Display() { + this(null); + } + + /** + * Constructs a new instance of this class using the parameter. + * + * @param data + * the device data + */ + public Display(DeviceData data) { + super(data); + } + + public String getStyleSheet() { + return styleSheet; + } + + protected void setStyleSheet(String style) { + this.styleSheet = style; + for (Shell shell : getShells()) { + shell.setStyleSheet(style); + } + Event event = new Event(); + event.text = style; + sendEvent(SWQT.StyleSheetChange, event); + } + + private Control _getFocusControl() { + Widget widget = findControl(QApplication.focusWidget()); + if (widget instanceof Control) { + return (Control) widget; + } + return null; + } + + void addControl(Object qtControl, Widget swtControl) { + if (qtControl == null || swtControl == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + qt2swtControlMap.put(qtControl, swtControl); + } + + Widget findControl(Object qtControl) { + if (qtControl == null) { + return null; + } + return qt2swtControlMap.get(qtControl); + } + + Widget removeControl(Object qtControl) { + return qt2swtControlMap.remove(qtControl); + } + + 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 releaseTray(Tray tray) { + if (this.tray == tray) { + this.tray = null; + } + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when an event of the given type occurs anywhere in a widget. The event + * type is one of the event constants defined in class <code>SWT</code>. + * When the event does occur, the listener is notified by sending it the + * <code>handleEvent()</code> message. + * <p> + * Setting the type of an event to <code>SWT.None</code> from within the + * <code>handleEvent()</code> method can be used to change the event type + * and stop subsequent Java listeners from running. Because event filters + * run before other listeners, event filters can both block other listeners + * and set arbitrary fields within an event. For this reason, event filters + * are both powerful and dangerous. They should generally be avoided for + * performance, debugging and code maintenance reasons. + * </p> + * + * @param eventType + * the type of event to listen for + * @param listener + * the listener which should be notified when the event occurs + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see Listener + * @see SWT + * @see #removeFilter + * @see #removeListener + * + * @since 3.0 + */ + public void addFilter(int eventType, Listener listener) { + checkDevice(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (filterTable == null) { + filterTable = new EventTable(); + } + filterTable.hook(eventType, listener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when an event of the given type occurs. The event type is one of the + * event constants defined in class <code>SWT</code>. When the event does + * occur in the display, the listener is notified by sending it the + * <code>handleEvent()</code> message. + * + * @param eventType + * the type of event to listen for + * @param listener + * the listener which should be notified when the event occurs + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see Listener + * @see SWT + * @see #removeListener + * + * @since 2.0 + */ + public void addListener(int eventType, Listener listener) { + checkDevice(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + eventTable = new EventTable(); + } + eventTable.hook(eventType, listener); + } + + void addMenuItem(MenuItem item) { + if (items == null) { + items = new MenuItem[64]; + } + 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 + 64]; + newItems[items.length] = item; + System.arraycopy(items, 0, newItems, 0, items.length); + items = newItems; + } + + 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. Specifying <code>null</code> as the runnable + * simply wakes the user-interface thread when run. + * <p> + * Note that at the time the runnable is invoked, widgets that have the + * receiver as their display may have been disposed. Therefore, it is + * necessary to check for this case inside the runnable before accessing the + * widget. + * </p> + * + * @param runnable + * code to run on the user-interface thread or <code>null</code> + * + * @exception SWTException + * <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #syncExec + */ + public void asyncExec(Runnable runnable) { + synchronized (Device.class) { + if (isDisposed()) { + error(SWT.ERROR_DEVICE_DISPOSED); + } + synchronizer.asyncExec(runnable); + } + } + + /** + * Causes the system hardware to emit a short sound (if it supports this + * capability). + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void beep() { + checkDevice(); + QApplication.beep(); + } + + /** + * 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); + } + } + + @Override + protected void checkDevice() { + if (thread == null) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + if (thread != Thread.currentThread()) { + /* + * Bug in IBM JVM 1.6. For some reason, under conditions that are + * yet to be full understood, Thread.currentThread() is either + * returning null or a different instance from the one that was + * saved when the Display was created. This is possibly a JIT + * problem because modifying this method to print logging + * information when the error happens seems to fix the problem. The + * fix is to use operating system calls to verify that the current + * thread is not the Display thread. + * + * NOTE: Despite the fact that Thread.currentThread() is used in + * other places, the failure has not been observed in all places + * where it is called. + */ + + if (threadId != (int) Thread.currentThread().getId()) { + error(SWT.ERROR_THREAD_INVALID_ACCESS); + } + } + if (isDisposed()) { + error(SWT.ERROR_DEVICE_DISPOSED); + } + } + + private static void checkDisplay(Thread thread, boolean multiple) { + synchronized (Device.class) { + for (int i = 0; i < Displays.length; i++) { + if (Displays[i] != null) { + if (!multiple) { + SWT.error(SWT.ERROR_NOT_IMPLEMENTED, null, " [multiple displays]"); //$NON-NLS-1$ + } + if (Displays[i].thread == thread) { + SWT.error(SWT.ERROR_THREAD_INVALID_ACCESS); + } + } + } + } + } + + void clearModal(Shell shell) { + if (modalShells == null) { + return; + } + int index = 0, length = modalShells.length; + while (index < length) { + if (modalShells[index] == shell) { + break; + } + if (modalShells[index] == null) { + return; + } + index++; + } + if (index == length) { + return; + } + System.arraycopy(modalShells, index + 1, modalShells, index, --length - index); + modalShells[length] = null; + if (index == 0 && modalShells[0] == null) { + modalShells = null; + } + Shell[] shells = getShells(); + for (int i = 0; i < shells.length; i++) { + shells[i].updateModal(); + } + } + + /** + * Requests that the connection between SWT and the underlying operating + * system be closed. + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see Device#dispose + * + * @since 2.0 + */ + public void close() { + checkDevice(); + Event event = new Event(); + sendEvent(SWT.Close, event); + if (event.doit) { + dispose(); + } + } + + /** + * Creates the device in the operating system. If the device does not have a + * handle, this method may do nothing depending on the device. + * <p> + * This method is called before <code>init</code>. + * </p> + * + * @param data + * the DeviceData which describes the receiver + * + * @see #init + */ + @Override + protected void create(DeviceData data) { + checkSubclass(); + checkDisplay(thread = Thread.currentThread(), true); + createDisplay(data); + register(this); + if (Default == null) { + Default = this; + } + } + + private void createDisplay(DeviceData data) { + qt2swtControlMap = Collections.synchronizedMap(new HashMap<Object, Widget>()); + QApplication.initialize(new String[0]); + QApplication.setQuitOnLastWindowClosed(false); + masterEventFilter = new MasterEventFilter(this); + QApplication.instance().installEventFilter(masterEventFilter); + setPaintDevice(QApplication.desktop()); + messageHandler = new SwtMessageHandler(); + QMessageHandler.installMessageHandler(messageHandler); + } + + static void deregister(Display display) { + synchronized (Device.class) { + for (int i = 0; i < Displays.length; i++) { + if (display == Displays[i]) { + Displays[i] = null; + } + } + } + } + + /** + * Destroys the device in the operating system and releases the device's + * handle. If the device does not have a handle, this method may do nothing + * depending on the device. + * <p> + * This method is called after <code>release</code>. + * </p> + * + * @see Device#dispose + * @see #release + */ + @Override + protected void destroy() { + if (this == Default) { + Default = null; + } + deregister(this); + destroyDisplay(); + } + + void destroyDisplay() { + QMessageHandler.removeMessageHandler(messageHandler); + QApplication.instance().removeEventFilter(masterEventFilter); + QApplication.instance().dispose(); + } + + /** + * Causes the <code>run()</code> method of the runnable to be invoked by the + * user-interface thread just before the receiver is disposed. Specifying a + * <code>null</code> runnable is ignored. + * + * @param runnable + * code to run at dispose time. + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public void disposeExec(Runnable runnable) { + checkDevice(); + if (disposeList == null) { + disposeList = new Runnable[4]; + } + for (int i = 0; i < disposeList.length; i++) { + if (disposeList[i] == null) { + disposeList[i] = runnable; + return; + } + } + Runnable[] newDisposeList = new Runnable[disposeList.length + 4]; + System.arraycopy(disposeList, 0, newDisposeList, 0, disposeList.length); + newDisposeList[disposeList.length] = runnable; + disposeList = newDisposeList; + } + + /** + * 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 SWT#error(int) + */ + void error(int code) { + SWT.error(code); + } + + boolean filterEvent(Event event) { + if (filterTable != null) { + filterTable.sendEvent(event); + } + return false; + } + + boolean filters(int eventType) { + if (filterTable == null) { + return false; + } + return filterTable.hooks(eventType); + } + + /** + * Given a widget and a widget-specific id, returns the instance of the + * <code>Widget</code> subclass which represents the widget/id pair in the + * currently running application, if such exists, or null if no matching + * widget can be found. + * + * @param widget + * the widget + * @param id + * the id for the subwidget (usually an item) + * @return the SWT subwidget (usually an item) that the widget/id pair + * represents + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.3 + */ + public Widget findWidget(Widget widget, int /* long */id) { + checkDevice(); + // TODO howto to it with qt ? use qObj.nativeId() ? + throw new UnsupportedOperationException("not yet implemented for qt"); //$NON-NLS-1$ + } + + // linux 64bit + public Widget findWidget(/* int */long id) { + checkDevice(); + // TODO howto to it with qt ? use qObj.nativeId() ? + throw new UnsupportedOperationException("not yet implemented for qt"); //$NON-NLS-1$ + } + + // win32 + public Widget findWidget(int /* long */hwnd, int /* long */id) { + checkDevice(); + // TODO howto to it with qt ? use qObj.nativeId() ? + throw new UnsupportedOperationException("not yet implemented for qt"); //$NON-NLS-1$ + } + + /** + * Returns the display which the given thread is the user-interface thread + * for, or null if the given thread is not a user-interface thread for any + * display. Specifying <code>null</code> as the thread will return + * <code>null</code> for the display. + * + * @param thread + * the user-interface thread + * @return the display for the given thread + */ + public static Display findDisplay(Thread thread) { + synchronized (Device.class) { + for (int i = 0; i < Displays.length; i++) { + Display display = Displays[i]; + if (display != null && display.thread == thread) { + return display; + } + } + return null; + } + } + + /** + * Returns the currently active <code>Shell</code>, or null if no shell + * belonging to the currently running application is active. + * + * @return the active shell or null + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public Shell getActiveShell() { + checkDevice(); + QWidget activeWindow = QApplication.activeWindow(); + Widget control = findControl(activeWindow); + if (!(control instanceof Control)) { + return null; + } + return control != null ? ((Control) control).getShell() : null; + } + + /** + * Returns a rectangle describing the receiver's size and location. Note + * that on multi-monitor systems the origin can be negative. + * + * @return the bounding rectangle + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + @Override + public Rectangle getBounds() { + checkDevice(); + return QtSWTConverter.convert(QApplication.desktop().screenGeometry()); + } + + /** + * Returns the display which the currently running thread is the + * user-interface thread for, or null if the currently running thread is not + * a user-interface thread for any display. + * + * @return the current display + */ + public static Display getCurrent() { + return findDisplay(Thread.currentThread()); + } + + /** + * Returns a rectangle which describes the area of the receiver which is + * capable of displaying data. + * + * @return the client area + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #getBounds + */ + @Override + public Rectangle getClientArea() { + checkDevice(); + return QtSWTConverter.convert(QApplication.desktop().childrenRect()); + } + + /** + * Returns the control which the on-screen pointer is currently over top of, + * or null if it is not currently over one of the controls built by the + * currently running application. + * + * @return the control under the cursor + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public Control getCursorControl() { + checkDevice(); + Widget widget = findControl(QApplication.widgetAt(QCursor.pos())); + if (widget instanceof Control) { + return (Control) widget; + } + return null; + } + + /** + * Returns the location of the on-screen pointer relative to the top left + * corner of the screen. + * + * @return the cursor location + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public Point getCursorLocation() { + checkDevice(); + return QtSWTConverter.convert(QCursor.pos()); + } + + /** + * Returns an array containing the recommended cursor sizes. + * + * @return the array of cursor sizes + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.0 + */ + public Point[] getCursorSizes() { + checkDevice(); + return new Point[] { new Point(32, 32) }; + } + + /** + * Returns the default display. One is created (making the thread that + * invokes this method its user-interface thread) if it did not already + * exist. + * + * @return the default display + */ + public static Display getDefault() { + synchronized (Device.class) { + if (Default == null) { + Default = new Display(); + // Hack: This is necessary to prevent a JVM crash when leaving the Eclipse IDE with Qt! + // http://eclipse.compeople.eu/wiki/index.php/Compeople:SWTQtImplementierungsdetails#ACCESS_VIOLATION_beim_Beenden_der_IDE_mit_Qt + Display.deregister(Default); + Default.destroyDisplay(); + } + 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 + * to provide a <code>disposeExec()</code> handler which does so. + * </p> + * + * @param key + * the name of the property + * @return the value of the property or null if it has not been set + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the key is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #setData(String, Object) + * @see #disposeExec(Runnable) + */ + public Object getData(String key) { + checkDevice(); + if (key == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + + if (SWQT.STYLESHEET_KEY.equals(key)) { + return styleSheet; + } + + if (keys == null) { + return null; + } + + for (int i = 0; i < keys.length; i++) { + if (keys[i].equals(key)) { + return values[i]; + } + } + return null; + } + + /** + * Returns the application defined, display specific data associated with + * the receiver, or null if it has not been set. The + * <em>display specific data</em> is a single, unnamed field that is stored + * with every display. + * <p> + * Applications may put arbitrary objects in this field. If the object + * stored in the display specific data needs to be notified when the display + * is disposed of, it is the application's responsibility to provide a + * <code>disposeExec()</code> handler which does so. + * </p> + * + * @return the display specific data + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #setData(Object) + * @see #disposeExec(Runnable) + */ + public Object getData() { + checkDevice(); + return data; + } + + /** + * Returns the button dismissal alignment, one of <code>LEFT</code> or + * <code>RIGHT</code>. The button dismissal alignment is the ordering that + * should be used when positioning the default dismissal button for a + * dialog. For example, in a dialog that contains an OK and CANCEL button, + * on platforms where the button dismissal alignment is <code>LEFT</code>, + * the button ordering should be OK/CANCEL. When button dismissal alignment + * is <code>RIGHT</code>, the button ordering should be CANCEL/OK. + * + * @return the button dismissal order + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 2.1 + */ + public int getDismissalAlignment() { + checkDevice(); + return SWT.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> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public int getDoubleClickTime() { + checkDevice(); + return QApplication.doubleClickInterval(); + } + + /** + * Returns the control which currently has keyboard focus, or null if + * keyboard events are not currently going to any of the controls built by + * the currently running application. + * + * @return the control under the cursor + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public Control getFocusControl() { + checkDevice(); + if (focusControl != null && !focusControl.isDisposed()) { + return focusControl; + } + return _getFocusControl(); + } + + /** + * Returns true when the high contrast mode is enabled. Otherwise, false is + * returned. + * <p> + * Note: This operation is a hint and is not supported on platforms that do + * not have this concept. + * </p> + * + * @return the high contrast mode + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.0 + */ + public boolean getHighContrast() { + checkDevice(); + return false; + } + + /** + * Returns the maximum allowed depth of icons on this display, in bits per + * pixel. On some platforms, this may be different than the actual depth of + * the display. + * + * @return the maximum icon depth + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see Device#getDepth + */ + public int getIconDepth() { + checkDevice(); + return QPixmap.defaultDepth(); + } + + /** + * Returns an array containing the recommended icon sizes. + * + * @return the array of icon sizes + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see Decorations#setImages(Image[]) + * + * @since 3.0 + */ + public Point[] getIconSizes() { + checkDevice(); + // TODO defaults ok? + return new Point[] { new Point(16, 16), new Point(32, 32) }; + } + + public int getLastEventTime() { + return lastEventTime; + } + + private int getMessageCount() { + return synchronizer.getMessageCount(); + } + + Shell getModalShell() { + if (modalShells == null) { + return null; + } + int index = modalShells.length; + while (--index >= 0) { + Shell shell = modalShells[index]; + if (shell != null) { + return shell; + } + } + return null; + } + + Dialog getModalDialog() { + return modalDialog; + } + + /** + * Returns an array of monitors attached to the device. + * + * @return the array of monitors + * + * @since 3.0 + */ + public Monitor[] getMonitors() { + checkDevice(); + Monitor[] monitors = new Monitor[QApplication.desktop().numScreens()]; + for (int i = 0; i < monitors.length; i++) { + monitors[i] = createMonitor(i); + } + return monitors; + } + + static Monitor createMonitor(QWidget widget) { + return createMonitor(QApplication.desktop().screenNumber(widget)); + } + + static Monitor createMonitor(int index) { + QRect screen = QApplication.desktop().screenGeometry(index); + Monitor monitor = new Monitor(); + monitor.handle = index; + monitor.width = screen.width(); + monitor.height = screen.height(); + + QRect rect = QApplication.desktop().availableGeometry(index); + monitor.clientX = rect.left(); + monitor.clientY = rect.top(); + monitor.clientWidth = rect.width(); + monitor.clientHeight = rect.height(); + return monitor; + } + + /** + * Returns the primary monitor for that device. + * + * @return the primary monitor + * + * @since 3.0 + */ + public Monitor getPrimaryMonitor() { + checkDevice(); + return createMonitor(QApplication.desktop().primaryScreen()); + } + + /** + * Returns a (possibly empty) array containing all shells which have not + * been disposed and have the receiver as their display. + * + * @return the receiver's shells + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public Shell[] getShells() { + checkDevice(); + int index = 0; + Shell[] result = new Shell[16]; + for (Widget control : qt2swtControlMap.values()) { + if (control != null && control instanceof Shell) { + int j = 0; + while (j < index) { + if (result[j] == control) { + break; + } + j++; + } + if (j == index) { + if (index == result.length) { + Shell[] newResult = new Shell[index + 16]; + System.arraycopy(result, 0, newResult, 0, index); + result = newResult; + } + result[index++] = (Shell) control; + } + } + } + if (index == result.length) { + return result; + } + Shell[] newResult = new Shell[index]; + System.arraycopy(result, 0, newResult, 0, index); + return newResult; + } + + /** + * Gets the synchronizer used by the display. + * + * @return the receiver's synchronizer + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.4 + */ + public Synchronizer getSynchronizer() { + checkDevice(); + return synchronizer; + } + + /** + * Returns the thread that has invoked <code>syncExec</code> or null if no + * such runnable is currently being invoked by the user-interface thread. + * <p> + * Note: If a runnable invoked by asyncExec is currently running, this + * method will return null. + * </p> + * + * @return the receiver's sync-interface thread + * + * @exception SWTException + * <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public Thread getSyncThread() { + synchronized (Device.class) { + if (isDisposed()) { + error(SWT.ERROR_DEVICE_DISPOSED); + } + return synchronizer.syncThread; + } + } + + /** + * Returns the matching standard platform cursor for the given constant, + * which should be one of the cursor constants specified in class + * <code>SWT</code>. This cursor should not be free'd because it was + * allocated by the system, not the application. A value of + * <code>null</code> will be returned if the supplied constant is not an SWT + * cursor constant. + * + * @param id + * the SWT cursor constant + * @return the corresponding cursor or <code>null</code> + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see SWT#CURSOR_ARROW + * @see SWT#CURSOR_WAIT + * @see SWT#CURSOR_CROSS + * @see SWT#CURSOR_APPSTARTING + * @see SWT#CURSOR_HELP + * @see SWT#CURSOR_SIZEALL + * @see SWT#CURSOR_SIZENESW + * @see SWT#CURSOR_SIZENS + * @see SWT#CURSOR_SIZENWSE + * @see SWT#CURSOR_SIZEWE + * @see SWT#CURSOR_SIZEN + * @see SWT#CURSOR_SIZES + * @see SWT#CURSOR_SIZEE + * @see SWT#CURSOR_SIZEW + * @see SWT#CURSOR_SIZENE + * @see SWT#CURSOR_SIZESE + * @see SWT#CURSOR_SIZESW + * @see SWT#CURSOR_SIZENW + * @see SWT#CURSOR_UPARROW + * @see SWT#CURSOR_IBEAM + * @see SWT#CURSOR_NO + * @see SWT#CURSOR_HAND + * + * @since 3.0 + */ + public Cursor getSystemCursor(int id) { + checkDevice(); + if (!(0 <= id && id < cursors.length)) { + return null; + } + if (cursors[id] == null) { + cursors[id] = new Cursor(this, id); + } + return cursors[id]; + } + + /** + * Returns 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> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + @Override + public Font getSystemFont() { + checkDevice(); + return systemFont = Font.qt_new(this, new QFont()); + } + + /** + * Returns the matching standard platform image for the given constant, + * which should be one of the icon constants specified in class + * <code>SWT</code>. This image should not be free'd because it was + * allocated by the system, not the application. A value of + * <code>null</code> will be returned either if the supplied constant is not + * an SWT icon constant or if the platform does not define an image that + * corresponds to the constant. + * + * @param id + * the SWT icon constant + * @return the corresponding image or <code>null</code> + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see SWT#ICON_ERROR + * @see SWT#ICON_INFORMATION + * @see SWT#ICON_QUESTION + * @see SWT#ICON_WARNING + * @see SWT#ICON_WORKING + * + * @since 3.0 + */ + public Image getSystemImage(int id) { + checkDevice(); + switch (id) { + case SWT.ICON_ERROR: { + if (errorImage != null) { + return errorImage; + } + QIcon icon = QApplication.style().standardIcon(StandardPixmap.SP_MessageBoxCritical); + return errorImage = Image.qt_new(this, SWT.ICON, icon); + } + case SWT.ICON_WORKING: + case SWT.ICON_INFORMATION: { + if (infoImage != null) { + return infoImage; + } + QIcon icon = QApplication.style().standardIcon(StandardPixmap.SP_MessageBoxInformation); + return errorImage = Image.qt_new(this, SWT.ICON, icon); + } + case SWT.ICON_QUESTION: { + if (questionImage != null) { + return questionImage; + } + QIcon icon = QApplication.style().standardIcon(StandardPixmap.SP_MessageBoxQuestion); + return errorImage = Image.qt_new(this, SWT.ICON, icon); + } + case SWT.ICON_WARNING: { + if (warningIcon != null) { + return warningIcon; + } + QIcon icon = QApplication.style().standardIcon(StandardPixmap.SP_MessageBoxWarning); + return errorImage = Image.qt_new(this, SWT.ICON, icon); + } + } + return null; + } + + /** + * Returns the single instance of the system tray or null when there is no + * system tray available for the platform. + * + * @return the system tray or <code>null</code> + * + * @exception SWTException + * <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.0 + */ + public Tray getSystemTray() { + checkDevice(); + if (tray != null) { + return tray; + } + tray = new Tray(this, SWT.NONE); + return tray; + } + + /** + * Returns the user-interface thread for the receiver. + * + * @return the receiver's user-interface thread + * + * @exception SWTException + * <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public Thread getThread() { + synchronized (Device.class) { + if (isDisposed()) { + error(SWT.ERROR_DEVICE_DISPOSED); + } + return thread; + } + } + + /** + * Invokes platform specific functionality to allocate a new GC handle. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public API for + * <code>Display</code>. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms, and should never be called from application code. + * </p> + * + * @param data + * the platform specific GC data + * @return the platform specific GC handle + * + * @exception SWTException + * <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * @exception SWTError + * <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for + * gc creation</li> + * </ul> + */ + @Override + public QPaintDeviceInterface internal_new_GC(GCData data) { + if (isDisposed()) { + SWT.error(SWT.ERROR_DEVICE_DISPOSED); + } + return new QPicture(); + } + + /** + * Invokes platform specific functionality to dispose a GC handle. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public API for + * <code>Display</code>. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms, and should never be called from application code. + * </p> + * + * @param hDC + * the platform specific GC handle + * @param data + * the platform specific GC data + */ + @Override + public void internal_dispose_GC(QPaintDeviceInterface paintDevice, GCData data) { + // nothing + } + + boolean isValidThread() { + return thread == Thread.currentThread(); + } + + /** + * Maps a point from one coordinate system to another. When the control is + * null, coordinates are mapped to the display. + * <p> + * NOTE: On right-to-left platforms where the coordinate systems are + * mirrored, special care needs to be taken when mapping coordinates from + * one control to another to ensure the result is correctly mirrored. + * + * Mapping a point that is the origin of a rectangle and then adding the + * width and height is not equivalent to mapping the rectangle. When one + * control is mirrored and the other is not, adding the width and height to + * a point that was mapped causes the rectangle to extend in the wrong + * direction. Mapping the entire rectangle instead of just one point causes + * both the origin and the corner of the rectangle to be mapped. + * </p> + * + * @param from + * the source <code>Control</code> or <code>null</code> + * @param to + * the destination <code>Control</code> or <code>null</code> + * @param point + * to be mapped + * @return point with mapped coordinates + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the Control from or the + * Control to have been disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 2.1.2 + */ + public Point map(Control from, Control to, Point point) { + checkDevice(); + if (point == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + return map(from, to, point.x, point.y); + } + + /** + * Maps a point from one coordinate system to another. When the control is + * null, coordinates are mapped to the display. + * <p> + * NOTE: On right-to-left platforms where the coordinate systems are + * mirrored, special care needs to be taken when mapping coordinates from + * one control to another to ensure the result is correctly mirrored. + * + * Mapping a point that is the origin of a rectangle and then adding the + * width and height is not equivalent to mapping the rectangle. When one + * control is mirrored and the other is not, adding the width and height to + * a point that was mapped causes the rectangle to extend in the wrong + * direction. Mapping the entire rectangle instead of just one point causes + * both the origin and the corner of the rectangle to be mapped. + * </p> + * + * @param from + * the source <code>Control</code> or <code>null</code> + * @param to + * the destination <code>Control</code> or <code>null</code> + * @param x + * coordinates to be mapped + * @param y + * coordinates to be mapped + * @return point with mapped coordinates + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the Control from or the + * Control to have been disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 2.1.2 + */ + public Point map(Control from, Control to, int x, int y) { + checkDevice(); + if (from != null && from.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (to != null && to.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (from == to) { + return new Point(x, y); + } + + Point point = null; + if (to != null && from != null) { + point = from.toDisplay(x, y); + point = to.toControl(x, y); + } else if (to != null) { + point = to.toControl(x, y); + } else if (from != null) { + point = from.toDisplay(x, y); + } else { + point = new Point(x, y); + } + return point; + } + + /** + * Maps a point from one coordinate system to another. When the control is + * null, coordinates are mapped to the display. + * <p> + * NOTE: On right-to-left platforms where the coordinate systems are + * mirrored, special care needs to be taken when mapping coordinates from + * one control to another to ensure the result is correctly mirrored. + * + * Mapping a point that is the origin of a rectangle and then adding the + * width and height is not equivalent to mapping the rectangle. When one + * control is mirrored and the other is not, adding the width and height to + * a point that was mapped causes the rectangle to extend in the wrong + * direction. Mapping the entire rectangle instead of just one point causes + * both the origin and the corner of the rectangle to be mapped. + * </p> + * + * @param from + * the source <code>Control</code> or <code>null</code> + * @param to + * the destination <code>Control</code> or <code>null</code> + * @param rectangle + * to be mapped + * @return rectangle with mapped coordinates + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the Control from or the + * Control to have been disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 2.1.2 + */ + public Rectangle map(Control from, Control to, Rectangle rectangle) { + checkDevice(); + if (rectangle == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + return map(from, to, rectangle.x, rectangle.y, rectangle.width, rectangle.height); + } + + /** + * Maps a point from one coordinate system to another. When the control is + * null, coordinates are mapped to the display. + * <p> + * NOTE: On right-to-left platforms where the coordinate systems are + * mirrored, special care needs to be taken when mapping coordinates from + * one control to another to ensure the result is correctly mirrored. + * + * Mapping a point that is the origin of a rectangle and then adding the + * width and height is not equivalent to mapping the rectangle. When one + * control is mirrored and the other is not, adding the width and height to + * a point that was mapped causes the rectangle to extend in the wrong + * direction. Mapping the entire rectangle instead of just one point causes + * both the origin and the corner of the rectangle to be mapped. + * </p> + * + * @param from + * the source <code>Control</code> or <code>null</code> + * @param to + * the destination <code>Control</code> or <code>null</code> + * @param x + * coordinates to be mapped + * @param y + * coordinates to be mapped + * @param width + * coordinates to be mapped + * @param height + * coordinates to be mapped + * @return rectangle with mapped coordinates + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the Control from or the + * Control to have been disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 2.1.2 + */ + public Rectangle map(Control from, Control to, int x, int y, int width, int height) { + checkDevice(); + if (from != null && from.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (to != null && to.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (from == to) { + return new Rectangle(x, y, width, height); + } + + Rectangle rectangle = new Rectangle(x, y, width, height); + if (to != null && from != null) { + Point topLeft = from.toDisplay(x, y); + topLeft = to.toControl(topLeft); + rectangle.x = topLeft.x; + rectangle.y = topLeft.y; + } else if (to != null) { + Point topLeft = to.toControl(x, y); + rectangle.x = topLeft.x; + rectangle.y = topLeft.y; + } else if (from != null) { + Point topLeft = from.toDisplay(x, y); + rectangle.x = topLeft.x; + rectangle.y = topLeft.y; + } + return rectangle; + } + + /** + * Generate a low level system event. + * + * <code>post</code> is used to generate low level keyboard and mouse + * events. The intent is to enable automated UI testing by simulating the + * input from the user. Most SWT applications should never need to call this + * method. + * <p> + * Note that this operation can fail when the operating system fails to + * generate the event for any reason. For example, this can happen when + * there is no such key or mouse button or when the system event queue is + * full. + * </p> + * <p> + * <b>Event Types:</b> + * <p> + * KeyDown, KeyUp + * <p> + * The following fields in the <code>Event</code> apply: + * <ul> + * <li>(in) type KeyDown or KeyUp</li> + * <p> + * Either one of: + * <li>(in) character a character that corresponds to a keyboard key</li> + * <li>(in) keyCode the key code of the key that was typed, as defined by + * the key code constants in class <code>SWT</code></li> + * </ul> + * <p> + * MouseDown, MouseUp + * </p> + * <p> + * The following fields in the <code>Event</code> apply: + * <ul> + * <li>(in) type MouseDown or MouseUp + * <li>(in) button the button that is pressed or released + * </ul> + * <p> + * MouseMove + * </p> + * <p> + * The following fields in the <code>Event</code> apply: + * <ul> + * <li>(in) type MouseMove + * <li>(in) x the x coordinate to move the mouse pointer to in screen + * coordinates + * <li>(in) y the y coordinate to move the mouse pointer to in screen + * coordinates + * </ul> + * <p> + * MouseWheel + * </p> + * <p> + * The following fields in the <code>Event</code> apply: + * <ul> + * <li>(in) type MouseWheel + * <li>(in) detail either SWT.SCROLL_LINE or SWT.SCROLL_PAGE + * <li>(in) count the number of lines or pages to scroll + * </ul> + * </dl> + * + * @param event + * the event to be generated + * + * @return true if the event was generated or false otherwise + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the event is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 3.0 + * + */ + public boolean post(Event event) { + if (isDisposed()) { + error(SWT.ERROR_DEVICE_DISPOSED); + } + if (event == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + + QWidget control = getControlForEvent(event); + if (control == null) { + return false; + } + + QEvent qtEvent = createQEvent(event, control); + if (event == null) { + return false; + } + + QApplication.postEvent(control, qtEvent); + return true; + + } + + private QWidget getControlForEvent(Event event) { + if (event.widget != null) { + return event.widget.getQWidget(); + } + return QApplication.focusWidget(); + } + + private QEvent createQEvent(Event event, QWidget focusWidget) { + KeyboardModifiers modifiers = mapSWTModifier2Qt(event.stateMask); + Type type = mapSWTEventType2Qt(event.type); + + switch (type) { + case KeyPress: + case KeyRelease: + return createQKeyEvent(event, type, modifiers); + case MouseButtonPress: + case MouseMove: + case MouseButtonRelease: + case MouseButtonDblClick: + return createQMouseEvent(event, type, modifiers, focusWidget); + } + return null; + } + + private QEvent createQMouseEvent(Event event, Type type, KeyboardModifiers modifiers, QWidget focusWidget) { + Control widget = (Control) findControl(focusWidget); + if ((widget.getStyle() & SWT.MIRRORED) != 0) { + event.x = widget.getClientWidth() - event.x; + } + + QPoint eventPoint = new QPoint(event.x, event.y); + QPoint global = focusWidget.mapToGlobal(eventPoint); + MouseButton button = mapSWTButton2Qt(event.button); + if (!type.equals(Type.MouseMove) && button.equals(MouseButton.NoButton)) { + return null; + } + return new QMouseEvent(type, eventPoint, global, button, MouseButton.createQFlags(button), modifiers); + } + + private QEvent createQKeyEvent(Event event, Type type, KeyboardModifiers modifiers) { + // If neither keyCode nor character is given then abort + if (event.keyCode == 0 && event.character == 0) { + return null; + } + + // Primarily try to map the keyCode to Qt:Key + int key = KeyUtil.untranslateKey(event.keyCode); + // If keyCode was given in the Event + if (event.keyCode != 0) { + // Given keyCode couldn't be translated, use it directly + if (key == 0) { + key = event.keyCode; + } + } + + // Secondarily if keyCode couldn't be mapped try the character + if (key == 0) { + switch (event.character) { + case SWT.BS: + key = Key.Key_Backspace.value(); + break; + case SWT.CR: + key = Key.Key_Return.value(); + break; + case SWT.DEL: + key = Key.Key_Delete.value(); + break; + case SWT.ESC: + key = Key.Key_Escape.value(); + break; + case SWT.TAB: + key = Key.Key_Tab.value(); + break; + /* + * Since there is no LF key on the keyboard, do not attempt to map + * LF to CR or attempt to post an LF key. + */ + case SWT.LF: + return null; + default: + key = Character.toUpperCase(event.character); + break; + } + } + return new QKeyEvent(type, key, modifiers, String.valueOf(event.character)); + } + + private static KeyboardModifiers mapSWTModifier2Qt(int modifiers) { + int nativeModifiers = 0; + if ((modifiers & SWT.ALT) != 0) { + nativeModifiers |= KeyboardModifier.AltModifier.value(); + } + if ((modifiers & SWT.SHIFT) != 0) { + nativeModifiers |= KeyboardModifier.ShiftModifier.value(); + } + if ((modifiers & SWT.CONTROL) != 0) { + nativeModifiers |= KeyboardModifier.ControlModifier.value(); + } + return new KeyboardModifiers(nativeModifiers); + } + + private static QEvent.Type mapSWTEventType2Qt(int type) { + switch (type) { + case SWT.KeyDown: + return Type.KeyPress; + case SWT.KeyUp: + return Type.KeyRelease; + case SWT.MouseDown: + return Type.MouseButtonPress; + case SWT.MouseMove: + return Type.MouseMove; + case SWT.MouseUp: + return Type.MouseButtonRelease; + case SWT.MouseDoubleClick: + return Type.MouseButtonDblClick; + default: + return Type.None; + } + } + + private static MouseButton mapSWTButton2Qt(int button) { + switch (button) { + case 1: + return MouseButton.LeftButton; + case 2: + return MouseButton.MidButton; + case 3: + return MouseButton.RightButton; + default: + return MouseButton.NoButton; + } + } + + 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> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_FAILED_EXEC - if an exception occurred while + * running an inter-thread message</li> + * </ul> + * + * @see #sleep + * @see #wake + */ + public boolean readAndDispatch() { + checkDevice(); + // runPopups(); + // boolean canSleep = runAsyncMessages(false); + // if (!canSleep) { + // QApplication.processEvents(); + // } + // return canSleep; + + if (QApplication.hasPendingEvents()) { + QApplication.processEvents();//ProcessEventsFlag.AllEvents + if (isDisposed()) { + return false; + } + QApplication.sendPostedEvents(); + } + if (isDisposed()) { + return false; + } + + runDeferredEvents(); + + if (isDisposed()) { + return false; + } + + runPopups(); + + if (isDisposed()) { + return false; + } + + return runAsyncMessages(false); + } + + private static void register(Display display) { + synchronized (Device.class) { + for (int i = 0; i < Displays.length; i++) { + if (Displays[i] == null) { + Displays[i] = display; + return; + } + } + Display[] newDisplays = new Display[Displays.length + 4]; + System.arraycopy(Displays, 0, newDisplays, 0, Displays.length); + newDisplays[Displays.length] = display; + Displays = newDisplays; + } + } + + /** + * Releases any internal resources back to the operating system and clears + * all fields except the device handle. + * <p> + * Disposes all shells which are currently open on the display. After this + * method has been invoked, all related related shells will answer + * <code>true</code> when sent the message <code>isDisposed()</code>. + * </p> + * <p> + * When a device is destroyed, resources that were acquired on behalf of the + * programmer need to be returned to the operating system. For example, if + * the device allocated a font to be used as the system font, this font + * would be freed in <code>release</code>. Also,to assist the garbage + * collector and minimize the amount of memory that is not reclaimed when + * the programmer keeps a reference to a disposed device, all fields except + * the handle are zero'd. The handle is needed by <code>destroy</code>. + * </p> + * This method is called before <code>destroy</code>. + * + * @see Device#dispose + * @see #destroy + */ + @Override + protected void release() { + sendEvent(SWT.Dispose, new Event()); + Shell[] shells = getShells(); + for (int i = 0; i < shells.length; i++) { + Shell shell = shells[i]; + if (!shell.isDisposed()) { + shell.dispose(); + } + } + if (tray != null) { + tray.dispose(); + } + tray = null; + while (readAndDispatch()) { + } + if (disposeList != null) { + for (int i = 0; i < disposeList.length; i++) { + if (disposeList[i] != null) { + disposeList[i].run(); + } + } + } + disposeList = null; + synchronizer.releaseSynchronizer(); + synchronizer = null; + releaseDisplay(); + super.release(); + } + + private void releaseDisplay() { + /* Release the System fonts */ + if (systemFont != null) { + systemFont.dispose(); + } + systemFont = null; + + /* Release the System Images */ + if (errorImage != null) { + errorImage.dispose(); + } + if (infoImage != null) { + infoImage.dispose(); + } + if (questionImage != null) { + questionImage.dispose(); + } + if (warningIcon != null) { + warningIcon.dispose(); + } + errorImage = infoImage = questionImage = warningIcon = null; + + /* Release the System Cursors */ + for (int i = 0; i < cursors.length; i++) { + if (cursors[i] != null) { + cursors[i].dispose(); + } + } + cursors = null; + + /* Release references */ + thread = null; + modalDialog = null; + modalShells = null; + data = null; + keys = null; + values = null; + bars = popups = null; + timerIds = null; + timerList = null; + eventTable = filterTable = null; + items = null; + + /* Release handles */ + threadId = 0; + QApplication.quit(); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when an event of the given type occurs anywhere in a widget. The + * event type is one of the event constants defined in class + * <code>SWT</code>. + * + * @param eventType + * the type of event to listen for + * @param listener + * the listener which should no longer be notified when the event + * occurs + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Listener + * @see SWT + * @see #addFilter + * @see #addListener + * + * @since 3.0 + */ + public void removeFilter(int eventType, Listener listener) { + checkDevice(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (filterTable == null) { + return; + } + filterTable.unhook(eventType, listener); + if (filterTable.size() == 0) { + filterTable = null; + } + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when an event of the given type occurs. The event type is one of + * the event constants defined in class <code>SWT</code>. + * + * @param eventType + * the type of event to listen for + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see Listener + * @see SWT + * @see #addListener + * + * @since 2.0 + */ + public void removeListener(int eventType, Listener listener) { + checkDevice(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(eventType, listener); + } + + 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 removeMenuItem(MenuItem item) { + if (items == null) { + return; + } + items[item.id - ID_START] = null; + } + + void removePopup(Menu menu) { + if (popups == null) { + return; + } + for (int i = 0; i < popups.length; i++) { + if (popups[i] == menu) { + popups[i] = null; + return; + } + } + } + + private boolean runAsyncMessages(boolean all) { + return synchronizer.runAsyncMessages(all); + } + + private boolean runDeferredEvents() { + boolean run = false; + /* + * 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()) { + run = true; + widget.sendEvent(event); + } + } + + /* + * At this point, the event queue could be null due to a recursive + * invocation when running the event. + */ + } + + /* Clear the queue */ + eventQueue = null; + return run; + } + + private 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; + if (!menu.isDisposed()) { + menu._setVisible(true); + } + result = true; + } + popups = null; + return result; + } + + private boolean runTimer(int /* long */id) { + if (timerList != null && timerIds != null) { + int index = 0; + while (index < timerIds.length) { + if (timerIds[index] == id && timerIds[index] != -1) { + timer.killTimer(timerIds[index]); + timerIds[index] = 0; + Runnable runnable = timerList[index]; + timerList[index] = null; + if (runnable != null) { + runnable.run(); + } + return true; + } + index++; + } + } + return false; + } + + private 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> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 2.1 + */ + public void setCursorLocation(int x, int y) { + checkDevice(); + QCursor.setPos(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 + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @since 2.0 + */ + public void setCursorLocation(Point point) { + checkDevice(); + if (point == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + setCursorLocation(point.x, point.y); + } + + /** + * Sets the application defined property of the receiver with the specified + * name to the given argument. + * <p> + * Applications may have associated arbitrary objects with the receiver in + * this fashion. If the objects stored in the properties need to be notified + * when the display is disposed of, it is the application's responsibility + * provide a <code>disposeExec()</code> handler which does so. + * </p> + * + * @param key + * the name of the property + * @param value + * the new value for the property + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the key is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #getData(String) + * @see #disposeExec(Runnable) + */ + public void setData(String key, Object value) { + checkDevice(); + if (key == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + + if (SWQT.STYLESHEET_KEY.equals(key)) { + setStyleSheet((String) value); + } + + /* 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 - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #getData() + * @see #disposeExec(Runnable) + */ + public void setData(Object data) { + checkDevice(); + this.data = data; + } + + /** + * On platforms which support it, sets the application name to be the + * argument. On Motif, for example, this can be used to set the name used + * for resource lookup. Specifying <code>null</code> for the name clears it. + * + * @param name + * the new app name or <code>null</code> + */ + public static void setAppName(String name) { + QApplication.setApplicationName(name); + } + + void setModalDialog(Dialog modalDailog) { + this.modalDialog = modalDailog; + Shell[] shells = getShells(); + for (int i = 0; i < shells.length; i++) { + shells[i].updateModal(); + } + } + + void setModalShell(Shell shell) { + if (modalShells == null) { + modalShells = new Shell[4]; + } + int index = 0, length = modalShells.length; + while (index < length) { + if (modalShells[index] == shell) { + return; + } + if (modalShells[index] == null) { + break; + } + index++; + } + if (index == length) { + Shell[] newModalShells = new Shell[length + 4]; + System.arraycopy(modalShells, 0, newModalShells, 0, length); + modalShells = newModalShells; + } + modalShells[index] = shell; + Shell[] shells = getShells(); + for (int i = 0; i < shells.length; i++) { + shells[i].updateModal(); + } + } + + /** + * Sets the synchronizer used by the display to be the argument, which can + * not be null. + * + * @param synchronizer + * the new synchronizer for the display (must not be null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the synchronizer is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_FAILED_EXEC - if an exception occurred while + * running an inter-thread message</li> + * </ul> + */ + public void setSynchronizer(Synchronizer synchronizer) { + checkDevice(); + if (synchronizer == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (synchronizer == this.synchronizer) { + return; + } + Synchronizer oldSynchronizer; + synchronized (Device.class) { + oldSynchronizer = this.synchronizer; + this.synchronizer = synchronizer; + } + if (oldSynchronizer != null) { + oldSynchronizer.runAsyncMessages(true); + } + } + + /** + * Causes the user-interface thread to <em>sleep</em> (that is, to be put in + * a state where it does not consume CPU cycles) until an event is received + * or it is otherwise awakened. + * + * @return <code>true</code> if an event requiring dispatching was placed on + * the queue. + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #wake + */ + public boolean sleep() { + checkDevice(); + if (getMessageCount() != 0) { + return true; + } + + try { + Thread.sleep(10); + } catch (InterruptedException e) { + // awake + } + QApplication.processEvents(PROCESS_EVENTS_FLAGS, 1000); + + if (isDisposed()) { + destroy(); + } + return true; + } + + /** + * Causes the <code>run()</code> method of the runnable to be invoked by the + * user-interface thread at the next reasonable opportunity. The thread + * which calls this method is suspended until the runnable completes. + * Specifying <code>null</code> as the runnable simply wakes the + * user-interface thread. + * <p> + * Note that at the time the runnable is invoked, widgets that have the + * receiver as their display may have been disposed. Therefore, it is + * necessary to check for this case inside the runnable before accessing the + * widget. + * </p> + * + * @param runnable + * code to run on the user-interface thread or <code>null</code> + * + * @exception SWTException + * <ul> + * <li>ERROR_FAILED_EXEC - if an exception occurred when + * executing the runnable</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #asyncExec + */ + public void syncExec(Runnable runnable) { + Synchronizer synchronizer; + synchronized (Device.class) { + if (isDisposed()) { + error(SWT.ERROR_DEVICE_DISPOSED); + } + synchronizer = this.synchronizer; + } + synchronizer.syncExec(runnable); + } + + /** + * Causes the <code>run()</code> method of the runnable to be invoked by the + * user-interface thread after the specified number of milliseconds have + * elapsed. If milliseconds is less than zero, the runnable is not executed. + * <p> + * Note that at the time the runnable is invoked, widgets that have the + * receiver as their display may have been disposed. Therefore, it is + * necessary to check for this case inside the runnable before accessing the + * widget. + * </p> + * + * @param milliseconds + * the delay before running the runnable + * @param runnable + * code to run on the user-interface thread + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the runnable is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #asyncExec + */ + + public void timerExec(int milliseconds, Runnable runnable) { + checkDevice(); + timer = new QTimer(); + + if (runnable == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (timerList == null) { + timerList = new Runnable[4]; + } + if (timerIds == null) { + timerIds = new int /* long */[4]; + } + int index = 0; + while (index < timerList.length) { + if (timerList[index] == runnable) { + break; + } + index++; + } + int /* long */timerId = 0; + if (index != timerList.length) { + timerId = timerIds[index]; + if (milliseconds < 0) { + timer.killTimer(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++; + } + timerId = nextTimerId++; + if (index == timerList.length) { + Runnable[] newTimerList = new Runnable[timerList.length + 4]; + System.arraycopy(timerList, 0, newTimerList, 0, timerList.length); + timerList = newTimerList; + int /* long */[] newTimerIds = new int /* long */[timerIds.length + 4]; + System.arraycopy(timerIds, 0, newTimerIds, 0, timerIds.length); + timerIds = newTimerIds; + } + } + + timer.setSingleShot(false); + timer.start(milliseconds); + final QTimerEvent qte = new QTimerEvent(timer.timerId()); + timer.timeout.connect(new QObject() { + private int id = qte.timerId(); + + @SuppressWarnings("unused") + protected void idTransfer() { + runTimer(id); + } + }, "idTransfer()"); //$NON-NLS-1$ + timerList[index] = runnable; + timerIds[index] = timer.timerId(); + } + + /** + * Forces all outstanding paint requests for the display to be processed + * before this method returns. + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see Control#update() + */ + public void update() { + checkDevice(); + if (QApplication.hasPendingEvents()) { + QApplication.processEvents(QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents); + } + } + + /** + * If the receiver's user-interface thread was <code>sleep</code>ing, causes + * it to be awakened and start running again. Note that this method may be + * called from any thread. + * + * @exception SWTException + * <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + * + * @see #sleep + */ + public void wake() { + synchronized (Device.class) { + if (isDisposed()) { + error(SWT.ERROR_DEVICE_DISPOSED); + } + if (thread == Thread.currentThread()) { + return; + } + wakeThread(); + } + } + + void wakeThread() { + try { + thread.notify(); + } catch (Exception e) { + // ok + } + } + + 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"); //$NON-NLS-1$ + i++; + } + } + return result.toString(); + } + + private final class MasterEventFilter extends QObject { + private final Display display; + private final boolean printEvents = Boolean.getBoolean("swtqt.printEvents"); //$NON-NLS-1$ + + public MasterEventFilter(Display display) { + this.display = display; + } + + @Override + public boolean eventFilter(QObject obj, QEvent event) { + try { + if (printEvents) { + System.out.println("QObject: " + (obj == null ? "null" : obj.toString()) + ": " + event.toString()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + lastEventTime = QTime.currentTime().elapsed(); + Widget eventSource = display.findControl(obj); + if (eventSource == null) { + // if (event.type() == Type.Paint) { + // System.out.println("paint event for qObj: " + obj + " unknown swt source"); //$NON-NLS-1$ //$NON-NLS-2$ + // } + if (printEvents) { + System.err.println("unknown event source: " + obj + " parent: " //$NON-NLS-1$ //$NON-NLS-2$ + + (obj == null ? "null" : obj.parent())); //$NON-NLS-1$ + } + return false; + } + switch (event.type()) { + case Paint: + if (printEvents) { + System.out.println("paint event for qObj: " + obj + " swt: " + eventSource); //$NON-NLS-1$ //$NON-NLS-2$ + } + if (ignorePaintEvents) { + return false; + } + return eventSource.qtPaintEvent(obj, (QPaintEvent) event); + case Resize: + return eventSource.qtResizeEvent(obj, (QResizeEvent) event); + case Move: + return eventSource.qtMoveEvent(obj, (QMoveEvent) event); + case FocusIn: + eventSource.qtFocusInEvent(obj); + return false; + case FocusOut: + eventSource.qtFocusOutEvent(obj); + return false; + case ContextMenu: { + QContextMenuEvent contextEvent = (QContextMenuEvent) event; + boolean accepted = eventSource.qtContextMenuEvent(obj, contextEvent); + if (accepted) { + contextEvent.setAccepted(true); + } + return accepted; + } + case Close: + QCloseEvent closeEvent = (QCloseEvent) event; + boolean accepted = eventSource.qtCloseEvent(); + if (accepted) { + closeEvent.ignore(); + } + return accepted; + case Enter: + return eventSource.qtMouseEnterEvent(obj); + case Leave: + return eventSource.qtMouseLeaveEvent(obj); + case Show: + return eventSource.qtShowEvent(obj); + case Hide: + return eventSource.qtHideEvent(obj); + case MouseMove: + return eventSource.qtMouseMoveEvent(obj, (QMouseEvent) event); + case MouseButtonPress: + QMouseEvent mouseEvent = (QMouseEvent) event; + // for debug + // QWidget widget = QApplication.widgetAt(mouseEvent.globalX(), mouseEvent.globalY()); + // System.out.println("mouse click on: " + widget); + // System.out.println("mouse click on swt widget: " + display.findControl(widget)); + return eventSource.qtMouseButtonPressEvent(obj, mouseEvent); + case MouseButtonRelease: + return eventSource.qtMouseButtonReleaseEvent(obj, (QMouseEvent) event); + case MouseButtonDblClick: + return eventSource.qtMouseButtonDblClickEvent(obj, (QMouseEvent) event); + case KeyPress: + return eventSource.qtKeyPressEvent(obj, (QKeyEvent) event); + case KeyRelease: + return eventSource.qtKeyReleaseEvent(obj, (QKeyEvent) event); + case WindowActivate: + return eventSource.qtWindowActivateEvent(obj); + case WindowDeactivate: + return eventSource.qtWindowDeactivateEvent(obj); + case WindowStateChange: + return eventSource.qtWindowStateChangeEvent(obj, (QWindowStateChangeEvent) event); + case WinEventAct: + return false; + case Timer: + return false; + default: + if (printEvents) { + System.err.println("unhandled event: " + event); //$NON-NLS-1$ + } + } + } catch (Exception e) { + System.err.println("error during event processing:"); //$NON-NLS-1$ + e.printStackTrace(); + } + return false; + } + + } + + private final static class SwtMessageHandler extends QMessageHandler { + + @Override + public void warning(String msg) { + System.err.println("Qt-Warning: " + msg); //$NON-NLS-1$ + } + + @Override + public void fatal(String msg) { + System.err.println("Qt-Fatal: " + msg); //$NON-NLS-1$ + } + + @Override + public void debug(String msg) { + System.err.println("Qt-Debug: " + msg); //$NON-NLS-1$ + } + + @Override + public void critical(String msg) { + System.err.println("Qt-Critical: " + msg); //$NON-NLS-1$ + } + }; + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/FileDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/FileDialog.java new file mode 100644 index 0000000000..f199d3626e --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/FileDialog.java @@ -0,0 +1,443 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import java.util.ArrayList; +import java.util.List; + +import com.trolltech.qt.gui.QFileDialog; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; + +/** + * Instances of this class allow the user to navigate the file system and select + * or enter a file name. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>SAVE, OPEN, MULTI</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * Note: Only one of the styles SAVE and OPEN may be specified. + * </p> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> within the + * SWT implementation. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#filedialog">FileDialog + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample, Dialog tab</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class FileDialog extends Dialog { + String[] filterNames = new String[0]; + String[] filterExtensions = new String[0]; + String[] fileNames = new String[0]; + String filterPath = "", fileName = "";//$NON-NLS-1$ //$NON-NLS-2$ + int filterIndex = 0; + boolean overwrite = false; + static final String FILTER = "*.*";//$NON-NLS-1$ + QFileDialog fd; + + /** + * Constructs a new instance of this class given only its parent. + * + * @param parent + * a shell which will be the parent of the new instance + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + */ + public FileDialog(Shell parent) { + this(parent, SWT.APPLICATION_MODAL); + } + + /** + * Constructs a new instance of this class given its parent and a style + * value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a shell which will be the parent of the new instance + * @param style + * the style of dialog to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + */ + public FileDialog(Shell parent, int style) { + super(parent, checkStyle(parent, style)); + checkSubclass(); + fd = new QFileDialog(); + if ((style & SWT.SAVE) != 0) { + fd.setFileMode(QFileDialog.FileMode.AnyFile); + } else if ((style & SWT.MULTI) != 0) { + fd.setFileMode(QFileDialog.FileMode.ExistingFiles); + } else { + fd.setFileMode(QFileDialog.FileMode.ExistingFile); + } + } + + /** + * Returns the path of the first file that was selected in the dialog + * relative to the filter path, or an empty string if no such file has been + * selected. + * + * @return the relative path of the file + */ + public String getFileName() { + String[] files = getSplittedFileNames(); + if (files.length == 1) { + return files[0]; + } else { + return ""; //$NON-NLS-1$ + } + } + + /** + * Returns a (possibly empty) array with the paths of all files that were + * selected in the dialog relative to the filter path. + * + * @return the relative paths of the files + */ + public String[] getFileNames() { + return getSplittedFileNames(); + } + + private String[] getSplittedFileNames() { + String[] split = { null, null }; + List<String> files = fd.selectedFiles(); + + if (!files.isEmpty()) { + for (int i = 0; i < files.size(); i++) { + String file = files.get(i); + split = file.split("/"); //$NON-NLS-1$ + + if (split != null) { + files.set(i, split[split.length - 1]); + } + } + } + return files.toArray(new String[] {}); + } + + /** + * Returns the file extensions which the dialog will use to filter the files + * it shows. + * + * @return the file extensions filter + */ + @SuppressWarnings("nls") + public String[] getFilterExtensions() { + List<String> filters = fd.nameFilters(); + ArrayList<String> result = new ArrayList<String>(); + String[] split1 = null; + String[] split2 = null; + /* + * just get the extensions out of the nameFilters, not the names (split + * between "(" and ")" + */ + for (String filter : filters) { + split1 = filter.split("\\("); + split2 = split1[1].split("\\)"); + result.add(split2[0]); + } + + /* + * replace all " " by ";" because that's the way swt returns the + * extensions + */ + for (String r : result) { + r = r.replaceAll(" ", ";"); + } + + return result.toArray(new String[] {}); + } + + /** + * Get the 0-based index of the file extension filter which was selected by + * the user, or -1 if no filter was selected. + * <p> + * This is an index into the FilterExtensions array and the FilterNames + * array. + * </p> + * + * @return index the file extension filter index + * + * @see #getFilterExtensions + * @see #getFilterNames + * + * @since 3.4 + */ + public int getFilterIndex() { + //TODO see Bug 166 + return filterIndex; + } + + /** + * Returns the names that describe the filter extensions which the dialog + * will use to filter the files it shows. + * + * @return the list of filter names + */ + @SuppressWarnings("nls") + public String[] getFilterNames() { + List<String> filters = fd.nameFilters(); + ArrayList<String> result = new ArrayList<String>(); + String[] name = null; + + /* + * just get the names out of the nameFilters, not the extensions(split + * between "(" + */ + for (String filter : filters) { + name = filter.split("\\("); + result.add(name[0]); + } + + return result.toArray(new String[] {}); + } + + /** + * Returns the directory path that the dialog will use, or an empty string + * if this is not set. File names in this path will appear in the dialog, + * filtered according to the filter extensions. + * + * @return the directory path string + * + * @see #setFilterExtensions + */ + public String getFilterPath() { + return fd.directory().path(); + } + + /** + * Returns the flag that the dialog will use to determine whether to prompt + * the user for file overwrite if the selected file already exists. + * + * @return true if the dialog will prompt for file overwrite, false + * otherwise + * + * @since 3.4 + */ + public boolean getOverwrite() { + return fd.confirmOverwrite(); + } + + /** + * 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() { + fd.exec(); + java.util.List<String> files = fd.selectedFiles(); + fileName = null; + fileNames = new String[files.size()]; + if (files.size() > 0) { + fileNames[0] = fileName = files.get(0); + } + for (int i = 1; i < files.size(); i++) { + fileNames[i] = files.get(i); + } + fd.disposeLater(); + return fileName; + } + + /** + * 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) { + fd.selectFile(string); + } + + /** + * Set the file extensions which the dialog will use to filter the files it + * shows to the argument, which may be null. + * <p> + * The strings are platform specific. For example, on some platforms, an + * extension filter string is typically of the form "*.extension", where + * "*.*" matches all files. For filters with multiple extensions, use + * semicolon as a separator, e.g. "*.jpg;*.png". + * </p> + * + * @param extensions + * the file extension filter + * + * @see #setFilterNames to specify the user-friendly names corresponding to + * the extensions + */ + public void setFilterExtensions(String[] extensions) { + filterExtensions = extensions; + makeFilter(); + + } + + /** + * Set the 0-based index of the file extension filter which the dialog will + * use initially to filter the files it shows to the argument. + * <p> + * This is an index into the FilterExtensions array and the FilterNames + * array. + * </p> + * + * @param index + * the file extension filter index + * + * @see #setFilterExtensions + * @see #setFilterNames + * + * @since 3.4 + */ + public void setFilterIndex(int index) { + //TODO see Bug 166 + filterIndex = index; + } + + /** + * Sets the names that describe the filter extensions which the dialog will + * use to filter the files it shows to the argument, which may be null. + * <p> + * Each name is a user-friendly short description shown for its + * corresponding filter. The <code>names</code> array must be the same + * length as the <code>extensions</code> array. + * </p> + * + * @param names + * the list of filter names, or null for no filter names + * + * @see #setFilterExtensions + */ + public void setFilterNames(String[] names) { + filterNames = names; + makeFilter(); + } + + /** + * constructs a filter for the fileDialog like this: + * "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)" + * + * @param names + * @return + */ + private void makeFilter() { + java.util.ArrayList<String> filters = new java.util.ArrayList<String>(); + + if (filterNames.length == 0 && filterExtensions.length == 0) { + // nothing to do + } else { + /* + * If there are more filterNames than filterExtensions, just use as + * much filterNames as FilterExtensions.length. Ignore the rest. + */ + for (int i = 0; i < filterExtensions.length; i++) { + if (filterNames.length >= i + 1) { + /* + * If there's a matching filterName for the + * filterExtension-Field, the filterExtension-Field has to + * get rid of the ";". The ";" are only allowed, when the + * filterExtension hasn't a matching name. + */ + String ex = filterExtensions[i].replace(";", " "); //$NON-NLS-1$ //$NON-NLS-2$ + filters.add(filterNames[i] + "(" + ex + ")"); //$NON-NLS-1$//$NON-NLS-2$ + + } else { + /* + * just a filterExtension without a name + */ + filters.add(filterExtensions[i]); + } + } + + fd.setNameFilters(filters); + } + } + + /** + * Sets the directory path that the dialog will use to the argument, which + * may be null. File names in this path will appear in the dialog, filtered + * according to the filter extensions. If the string is null, then the + * operating system's default filter path will be used. + * <p> + * Note that the path string is platform dependent. For convenience, either + * '/' or '\' can be used as a path separator. + * </p> + * + * @param string + * the directory path + * + * @see #setFilterExtensions + */ + public void setFilterPath(String string) { + fd.setDirectory(string); + } + + /** + * Sets the flag that the dialog will use to determine whether to prompt the + * user for file overwrite if the selected file already exists. + * + * @param overwrite + * true if the dialog will prompt for file overwrite, false + * otherwise + * + * @since 3.4 + */ + public void setOverwrite(boolean overwrite) { + fd.setConfirmOverwrite(overwrite); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/FontDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/FontDialog.java new file mode 100644 index 0000000000..43563ebb4f --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/FontDialog.java @@ -0,0 +1,246 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.gui.QDialog; +import com.trolltech.qt.gui.QFont; +import com.trolltech.qt.gui.QFontDialog; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.PaletteData; +import org.eclipse.swt.graphics.RGB; + +/** + * Instances of this class allow the user to select a font from all available + * fonts in the system. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>(none)</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> within the + * SWT implementation. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample, Dialog tab</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class FontDialog extends Dialog { + FontData fontData; + RGB rgb; + QFontDialog fd; + + /** + * Constructs a new instance of this class given only its parent. + * + * @param parent + * a shell which will be the parent of the new instance + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + */ + public FontDialog(Shell parent) { + this(parent, SWT.APPLICATION_MODAL); + } + + /** + * Constructs a new instance of this class given its parent and a style + * value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a shell which will be the parent of the new instance + * @param style + * the style of dialog to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + */ + public FontDialog(Shell parent, int style) { + super(parent, checkStyle(parent, style)); + checkSubclass(); + } + + protected QFontDialog createFontDialog(Shell parent, int style) { + return new QFontDialog(); + } + + /** + * Returns a FontData object describing the font that was selected in the + * dialog, or null if none is available. + * + * @return the FontData for the selected font, or null + * @deprecated use #getFontList () + */ + @Deprecated + public FontData getFontData() { + return getFontList()[0]; + } + + /** + * Returns a FontData set describing the font that was selected in the + * dialog, or null if none is available. + * + * @return the FontData for the selected font, or null + * @since 2.1.1 + */ + public FontData[] getFontList() { + QFont font = fd.selectedFont(); + if (font == null) { + return null; + } + FontData[] result = new FontData[1]; + result[0] = qFontToFontData(font); + return result; + } + + private FontData qFontToFontData(QFont qFont) { + int style = SWT.NORMAL; + if (qFont.italic()) { + style += SWT.ITALIC; + } + if (qFont.bold()) { + style += SWT.BOLD; + } + FontData fontData = new FontData(qFont.rawName(), qFont.pointSize(), style); + return fontData; + } + + /** + * Returns an RGB describing the color that was selected in the dialog, or + * null if none is available. + * + * @return the RGB value for the selected color, or null + * + * @see PaletteData#getRGBs + * + * @since 2.1 + */ + public RGB getRGB() { + // QFontDialog doesn't support setting a font color, see Bug 167 + return null; + } + + /** + * 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() { + fd = new QFontDialog(); + if (fd.exec() == QDialog.DialogCode.Rejected.value()) { + return null; + } + QFont font = fd.selectedFont(); + + FontData fontData = qFontToFontData(font); + font.dispose(); + fd.disposeLater(); + return fontData; + } + + /** + * Sets a FontData object describing the font to be selected by default in + * the dialog, or null to let the platform choose one. + * + * @param fontData + * the FontData to use initially, or null + * @deprecated use #setFontList (FontData []) + */ + @Deprecated + public void setFontData(FontData fontData) { + // QFontDialog doesn't support setting the default font + this.fontData = fontData; + } + + /** + * Sets the set of FontData objects describing the font to be selected by + * default in the dialog, or null to let the platform choose one. + * + * @param fontData + * the set of FontData objects to use initially, or null to let + * the platform select a default when open() is called + * + * @see Font#getFontData + * + * @since 2.1.1 + */ + public void setFontList(FontData[] fontData) { + // QFontDialog doesn't support setting the default font, see Bug 168 + if (fontData != null && fontData.length > 0) { + this.fontData = fontData[0]; + } else { + this.fontData = null; + } + } + + /** + * Sets the RGB describing the color to be selected by default in the + * dialog, or null to let the platform choose one. + * + * @param rgb + * the RGB value to use initially, or null to let the platform + * select a default when open() is called + * + * @see PaletteData#getRGBs + * + * @since 2.1 + */ + public void setRGB(RGB rgb) { + // QFontDialog doesn't support setting a font color, see Bug 167 + this.rgb = rgb; + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Group.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Group.java new file mode 100644 index 0000000000..9af907e13e --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Group.java @@ -0,0 +1,293 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.gui.QContentsMargins; +import com.trolltech.qt.gui.QGroupBox; +import com.trolltech.qt.gui.QWidget; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.internal.qt.QtSWTConverter; + +/** + * Instances of this class provide an etched border with an optional title. + * <p> + * Shadow styles are hints and may not be honoured by the platform. To create a + * group with the default shadow style for the platform, do not specify a shadow + * style. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>SHADOW_ETCHED_IN, SHADOW_ETCHED_OUT, SHADOW_IN, SHADOW_OUT, SHADOW_NONE</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * Note: Only one of the above styles may be specified. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class Group extends Composite { + + /** + * 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)); + } + + @Override + protected QWidget createQWidget(int style) { + state |= DRAW_BACKGROUND; + state |= CANVAS; + //TODO apply SWT.SHADOW_* styles + return new QGroupBox(); + } + + QGroupBox getQGroupBox() { + return (QGroupBox) getQWidget(); + } + + 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); + } + + @Override + protected void checkSubclass() { + if (!isValidSubclass()) { + error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + @Override + public Rectangle getClientArea() { + checkWidget(); + if (!isVisible()) { + updateQLayouts(); + } + + Rectangle clientArea = QtSWTConverter.convert(getQWidget().contentsRect()); + if (clientArea.width < 0) { + clientArea.width = 0; + } + if (clientArea.height < 0) { + clientArea.height = 0; + } + + return clientArea; + } + + @Override + public Rectangle computeTrim(int x, int y, int width, int height) { + QContentsMargins margins = getQGroupBox().getContentsMargins(); + return new Rectangle(x - margins.left, y - margins.top, width + margins.left + margins.right, height + + margins.top + margins.bottom); + } + + @Override + String getNameText() { + return getText(); + } + + /** + * Returns the receiver's text, which is the string that the is used as the + * <em>title</em>. If the text has not previously been set, returns an empty + * string. + * + * @return the text + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String getText() { + checkWidget(); + return getQGroupBox().title(); + } + + @Override + boolean mnemonicHit(char key) { + return setFocus(); + } + + @Override + boolean mnemonicMatch(char key) { + char mnemonic = findMnemonic(getText()); + if (mnemonic == '\0') { + return false; + } + return Character.toUpperCase(key) == Character.toUpperCase(mnemonic); + } + + void printWidget(int /* long */hwnd, int /* long */hdc, GC gc) { + // TODO + throw new UnsupportedOperationException("not yet implemented");//$NON-NLS-1$ + // /* + // * Bug in Windows. For some reason, PrintWindow() returns success but + // * does nothing when it is called on a printer. The fix is to just go + // * directly to WM_PRINT in this case. + // */ + // boolean success = false; + // if ( !( OS.GetDeviceCaps( gc.handle, OS.TECHNOLOGY ) == + // OS.DT_RASPRINTER ) ) { + // success = OS.PrintWindow( hwnd, hdc, 0 ); + // } + // + // /* + // * Bug in Windows. For some reason, PrintWindow() fails when it is + // * called on a push button. The fix is to detect the failure and use + // * WM_PRINT instead. Note that WM_PRINT cannot be used all the time + // * because it fails for browser controls when the browser has focus. + // */ + // if ( !success ) { + // /* + // * Bug in Windows. For some reason, WM_PRINT when called with + // * PRF_CHILDREN will not draw the tool bar divider for tool bar + // * children that do not have CCS_NODIVIDER. The fix is to draw the + // * group box and iterate through the children, drawing each one. + // */ + // int flags = OS.PRF_CLIENT | OS.PRF_NONCLIENT | OS.PRF_ERASEBKGND; + // OS.SendMessage( hwnd, OS.WM_PRINT, hdc, flags ); + // int nSavedDC = OS.SaveDC( hdc ); + // Control[] children = _getChildren(); + // Rectangle rect = getBounds(); + // OS.IntersectClipRect( hdc, 0, 0, rect.width, rect.height ); + // for ( int i = children.length - 1; i >= 0; --i ) { + // Point location = children[i].getLocation(); + // int graphicsMode = OS.GetGraphicsMode( hdc ); + // if ( graphicsMode == OS.GM_ADVANCED ) { + // float[] lpXform = { 1, 0, 0, 1, location.x, location.y }; + // OS.ModifyWorldTransform( hdc, lpXform, OS.MWT_LEFTMULTIPLY ); + // } else { + // OS.SetWindowOrgEx( hdc, -location.x, -location.y, null ); + // } + // int /* long */topHandle = children[i].topHandle(); + // int bits = OS.GetWindowLong( topHandle, OS.GWL_STYLE ); + // if ( ( bits & OS.WS_VISIBLE ) == 0 ) { + // OS.DefWindowProc( topHandle, OS.WM_SETREDRAW, 1, 0 ); + // } + // children[i].printWidget( topHandle, hdc, gc ); + // if ( ( bits & OS.WS_VISIBLE ) == 0 ) { + // OS.DefWindowProc( topHandle, OS.WM_SETREDRAW, 0, 0 ); + // } + // if ( graphicsMode == OS.GM_ADVANCED ) { + // float[] lpXform = { 1, 0, 0, 1, -location.x, -location.y }; + // OS.ModifyWorldTransform( hdc, lpXform, OS.MWT_LEFTMULTIPLY ); + // } + // } + // OS.RestoreDC( hdc, nSavedDC ); + // } + } + + @Override + public void setFont(Font font) { + checkWidget(); + Rectangle oldRect = getClientArea(); + super.setFont(font); + Rectangle newRect = getClientArea(); + if (!oldRect.equals(newRect)) { + sendResize(); + } + } + + /** + * 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 assigned to the first child of the group. On most platforms, the + * mnemonic appears underlined but may be emphasised in a platform specific + * manner. The mnemonic indicator character '&' 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); + } + getQGroupBox().setTitle(string); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Label.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Label.java new file mode 100644 index 0000000000..1274dabea4 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Label.java @@ -0,0 +1,456 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.Qt.AlignmentFlag; +import com.trolltech.qt.gui.QDragEnterEvent; +import com.trolltech.qt.gui.QDragLeaveEvent; +import com.trolltech.qt.gui.QDragMoveEvent; +import com.trolltech.qt.gui.QDropEvent; +import com.trolltech.qt.gui.QFrame; +import com.trolltech.qt.gui.QLabel; +import com.trolltech.qt.gui.QMouseEvent; +import com.trolltech.qt.gui.QWidget; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; + +/** + * Instances of this class represent a non-selectable user interface object that + * displays a string or image. When SEPARATOR is specified, displays a single + * vertical or horizontal line. + * <p> + * Shadow styles are hints and may not be honored by the platform. To create a + * separator label with the default shadow style for the platform, do not + * specify a shadow style. + * </p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>SEPARATOR, HORIZONTAL, VERTICAL</dd> + * <dd>SHADOW_IN, SHADOW_OUT, SHADOW_NONE</dd> + * <dd>CENTER, LEFT, RIGHT, WRAP</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * Note: Only one of SHADOW_IN, SHADOW_OUT and SHADOW_NONE may be specified. + * SHADOW_NONE is a HINT. Only one of HORIZONTAL and VERTICAL may be specified. + * Only one of CENTER, LEFT and RIGHT may be specified. + * </p> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> within the + * SWT implementation. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#label">Label snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class Label extends Control { + private String text = ""; //$NON-NLS-1$ + private Image image; + + /** + * 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)); + } + + @Override + protected QWidget createQWidget(int style) { + state |= THEME_BACKGROUND; + QLabel label = new MyQLabel(); + if ((style & SWT.SEPARATOR) != 0) { + setSeparatorType(label, style); + } + label.setContentsMargins(0, 0, 0, 0); + setAlignment(label, style); + label.setMargin(0); + // TODO make this work with the right size. + //label.setWordWrap((style & SWT.WRAP) != 0); + return label; + } + + @Override + protected void checkAndUpdateBorder() { + // nothing on purpose + } + + private void setSeparatorType(QLabel label, int style) { + int frameStyle = 0; + if ((style & SWT.VERTICAL) != 0) { + frameStyle |= QFrame.Shape.VLine.value(); + label.setFixedWidth(2); + } else { + frameStyle |= QFrame.Shape.HLine.value(); + label.setMaximumHeight(2); + } + if ((style & SWT.SHADOW_IN) != 0) { + frameStyle |= QFrame.Shadow.Raised.value(); + } else if ((style & SWT.SHADOW_OUT) != 0) { + frameStyle |= QFrame.Shadow.Sunken.value(); + } else if ((style & SWT.SHADOW_NONE) != 0) { + frameStyle |= QFrame.Shadow.Plain.value(); + } + label.setFrameStyle(frameStyle); + } + + private QLabel getQLabel() { + return (QLabel) getQWidget(); + } + + static int checkStyle(int style) { + style |= SWT.NO_FOCUS; + if ((style & SWT.SEPARATOR) != 0) { + style = checkBits(style, SWT.VERTICAL, SWT.HORIZONTAL, 0, 0, 0, 0); + return checkBits(style, SWT.SHADOW_OUT, SWT.SHADOW_IN, SWT.SHADOW_NONE, 0, 0, 0); + } + return checkBits(style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0); + } + + @Override + public boolean qtMouseEnterEvent(Object source) { + if (source == getQWidget()) { + sendEvent(SWT.MouseEnter); + } + return false; + } + + @Override + public boolean qtMouseLeaveEvent(Object source) { + if (source == getQWidget()) { + sendEvent(SWT.MouseExit); + } + return false; + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + Point p = super.computeSize(wHint, hHint, changed); + if ((style & SWT.SEPARATOR) != 0) { + int width = p.x; + int height = p.y; + if ((style & SWT.VERTICAL) != 0) { + width = 2; + } else { + height = Math.min(height, 3); + } + p.x = width; + p.y = height; + } + return p; + } + + @Override + 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 "";//$NON-NLS-1$ + } + return text; + } + + /** + * 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; + } + if (string.equals(text)) { + return; + } + text = string; + string = Display.withCrLf(string); + getQLabel().setText(string); + } + + @Override + 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; + } + + @Override + boolean mnemonicMatch(char key) { + char mnemonic = findMnemonic(getText()); + if (mnemonic == '\0') { + return false; + } + return Character.toUpperCase(key) == Character.toUpperCase(mnemonic); + } + + @Override + void releaseWidget() { + super.releaseWidget(); + text = null; + image = null; + } + + /** + * 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; + } + + /** + * 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(); + setAlignment(getQLabel(), alignment); + } + + void setAlignment(QLabel label, int alignment) { + if ((getStyle() & SWT.SEPARATOR) != 0) { + return; + } + if ((alignment & SWT.RIGHT) != 0) { + label.setAlignment(AlignmentFlag.AlignRight); + } else if ((alignment & SWT.CENTER) != 0) { + label.setAlignment(AlignmentFlag.AlignCenter); + } + } + + /** + * 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; + } + + /** + * 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(); + // dont crash if the image is null + if (image == null) { + return; + } + this.image = image; + getQLabel().setPixmap(image.getQPixmap()); + } + + private final class MyQLabel extends QLabel { + @Override + protected void mousePressEvent(QMouseEvent e) { + super.mousePressEvent(e); + e.setAccepted(false); + } + + @Override + protected void dropEvent(QDropEvent event) { + sendDropEvent(event); + } + + @Override + protected void dragMoveEvent(QDragMoveEvent event) { + sendDragMoveEvent(event); + } + + @Override + protected void dragEnterEvent(QDragEnterEvent event) { + sendDragEnterEvent(event); + } + + @Override + protected void dragLeaveEvent(QDragLeaveEvent event) { + sendDragLeaveEvent(event); + } + + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Link.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Link.java new file mode 100644 index 0000000000..844a4371f5 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Link.java @@ -0,0 +1,552 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.Qt.TextInteractionFlag; +import com.trolltech.qt.gui.QLabel; +import com.trolltech.qt.gui.QWidget; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.accessibility.ACC; +import org.eclipse.swt.accessibility.Accessible; +import org.eclipse.swt.accessibility.AccessibleAdapter; +import org.eclipse.swt.accessibility.AccessibleControlAdapter; +import org.eclipse.swt.accessibility.AccessibleControlEvent; +import org.eclipse.swt.accessibility.AccessibleEvent; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; + +/** + * Instances of this class represent a selectable user interface object that + * displays a text with links. + * <p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>(none)</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection</dd> + * </dl> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#link">Link snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * + * @since 3.1 + * @noextend This class is not intended to be subclassed by clients. + */ +public class Link extends Control { + private Point[] offsets; + private String[] ids; + private int[] mnemonics; + + private static final String LINK_START = "<a>";//$NON-NLS-1$ + private static final String LINK_END = "</a>";//$NON-NLS-1$ + + /** + * Constructs a new instance of this class given its parent and a style + * value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a composite control which will be the parent of the new + * instance (cannot be null) + * @param style + * the style of control to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public Link(Composite parent, int style) { + super(parent, checkBits(style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0)); + } + + @Override + protected QWidget createQWidget(int style) { + state |= THEME_BACKGROUND; + QLabel link = new QLabel(); + link.setTextInteractionFlags(TextInteractionFlag.TextBrowserInteraction); + link.setOpenExternalLinks(false); + return link; + } + + protected QLabel getQLabel() { + return (QLabel) getQWidget(); + } + + @Override + protected void connectSignals() { + getQLabel().linkActivated.connect(this, "linkActivated(java.lang.String)");//$NON-NLS-1$ + } + + protected void linkActivated(String link) { + Event event = new Event(); + event.text = link; + sendEvent(SWT.Selection, event); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the control is selected by the user, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * <code>widgetSelected</code> is called when the control is selected by the + * user. <code>widgetDefaultSelected</code> is not called. + * </p> + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + void initAccessible() { + Accessible accessible = getAccessible(); + accessible.addAccessibleListener(new AccessibleAdapter() { + @Override + public void getName(AccessibleEvent e) { + e.result = parse(_getText()); + } + }); + + accessible.addAccessibleControlListener(new AccessibleControlAdapter() { + @Override + public void getChildAtPoint(AccessibleControlEvent e) { + e.childID = ACC.CHILDID_SELF; + } + + @Override + public void getLocation(AccessibleControlEvent e) { + Rectangle rect = display.map(getParent(), null, getBounds()); + e.x = rect.x; + e.y = rect.y; + e.width = rect.width; + e.height = rect.height; + } + + @Override + public void getChildCount(AccessibleControlEvent e) { + e.detail = 0; + } + + @Override + public void getRole(AccessibleControlEvent e) { + e.detail = ACC.ROLE_LINK; + } + + @Override + public void getState(AccessibleControlEvent e) { + e.detail = ACC.STATE_FOCUSABLE; + if (hasFocus()) { + e.detail |= ACC.STATE_FOCUSED; + } + } + + @Override + public void getDefaultAction(AccessibleControlEvent e) { + e.result = SWT.getMessage("SWT_Press"); //$NON-NLS-1$ + } + + @Override + public void getSelection(AccessibleControlEvent e) { + if (hasFocus()) { + e.childID = ACC.CHILDID_SELF; + } + } + + @Override + public void getFocus(AccessibleControlEvent e) { + if (hasFocus()) { + e.childID = ACC.CHILDID_SELF; + } + } + }); + } + + @Override + String getNameText() { + return getText(); + } + + /** + * Returns the receiver's text, which will be an empty string if it has + * never been set. + * + * @return the receiver's text + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String getText() { + checkWidget(); + return _getText(); + } + + private String _getText() { + return getQLabel().text(); + } + + private String parse(String string) { + int length = string.length(); + offsets = new Point[length / 4]; + ids = new String[length / 4]; + mnemonics = new int[length / 4 + 1]; + StringBuffer result = new StringBuffer(); + char[] buffer = new char[length]; + string.getChars(0, string.length(), buffer, 0); + int index = 0, state = 0, linkIndex = 0; + int start = 0, tagStart = 0, linkStart = 0, endtagStart = 0, refStart = 0; + while (index < length) { + char c = Character.toLowerCase(buffer[index]); + switch (state) { + case 0: + if (c == '<') { + tagStart = index; + state++; + } + break; + case 1: + if (c == 'a') { + state++; + } + break; + case 2: + switch (c) { + case 'h': + state = 7; + break; + case '>': + linkStart = index + 1; + state++; + break; + default: + if (Character.isWhitespace(c)) { + break; + } + state = 13; + } + break; + case 3: + if (c == '<') { + endtagStart = index; + state++; + } + break; + case 4: + state = c == '/' ? state + 1 : 3; + break; + case 5: + state = c == 'a' ? state + 1 : 3; + break; + case 6: + if (c == '>') { + mnemonics[linkIndex] = parseMnemonics(buffer, start, tagStart, result); + int offset = result.length(); + parseMnemonics(buffer, linkStart, endtagStart, result); + offsets[linkIndex] = new Point(offset, result.length() - 1); + if (ids[linkIndex] == null) { + ids[linkIndex] = new String(buffer, linkStart, endtagStart - linkStart); + } + linkIndex++; + start = tagStart = linkStart = endtagStart = refStart = index + 1; + state = 0; + } else { + state = 3; + } + break; + case 7: + state = c == 'r' ? state + 1 : 0; + break; + case 8: + state = c == 'e' ? state + 1 : 0; + break; + case 9: + state = c == 'f' ? state + 1 : 0; + break; + case 10: + state = c == '=' ? state + 1 : 0; + break; + case 11: + if (c == '"') { + state++; + refStart = index + 1; + } else { + state = 0; + } + break; + case 12: + if (c == '"') { + ids[linkIndex] = new String(buffer, refStart, index - refStart); + state = 2; + } + break; + case 13: + if (Character.isWhitespace(c)) { + state = 0; + } else if (c == '=') { + state++; + } + break; + case 14: + state = c == '"' ? state + 1 : 0; + break; + case 15: + if (c == '"') { + state = 2; + } + break; + default: + state = 0; + break; + } + index++; + } + if (start < length) { + int tmp = parseMnemonics(buffer, start, tagStart, result); + int mnemonic = parseMnemonics(buffer, Math.max(tagStart, linkStart), length, result); + if (mnemonic == -1) { + mnemonic = tmp; + } + mnemonics[linkIndex] = mnemonic; + } else { + mnemonics[linkIndex] = -1; + } + if (offsets.length != linkIndex) { + Point[] newOffsets = new Point[linkIndex]; + System.arraycopy(offsets, 0, newOffsets, 0, linkIndex); + offsets = newOffsets; + String[] newIDs = new String[linkIndex]; + System.arraycopy(ids, 0, newIDs, 0, linkIndex); + ids = newIDs; + int[] newMnemonics = new int[linkIndex + 1]; + System.arraycopy(mnemonics, 0, newMnemonics, 0, linkIndex + 1); + mnemonics = newMnemonics; + } + return result.toString(); + } + + private int parseMnemonics(char[] buffer, int start, int end, StringBuffer result) { + int mnemonic = -1, index = start; + while (index < end) { + if (buffer[index] == '&') { + if (index + 1 < end && buffer[index + 1] == '&') { + result.append(buffer[index]); + index++; + } else { + mnemonic = result.length(); + } + } else { + result.append(buffer[index]); + } + index++; + } + return mnemonic; + } + + @Override + void releaseWidget() { + super.releaseWidget(); + offsets = null; + ids = null; + mnemonics = null; + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is selected by the user. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + /** + * Sets the receiver's text. + * <p> + * The string can contain both regular text and hyperlinks. A hyperlink is + * delimited by an anchor tag, <A> and </A>. Within an anchor, a + * single HREF attribute is supported. When a hyperlink is selected, the + * text field of the selection event contains either the text of the + * hyperlink or the value of its HREF, if one was specified. In the rare + * case of identical hyperlinks within the same string, the HREF tag can be + * used to distinguish between them. The string may include the mnemonic + * character and line delimiters. + * </p> + * + * @param string + * the new text + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the text is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setText(String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (string.equals(_getText())) { + return; + } + String text = string.replace("<A>", "<a>");//$NON-NLS-1$ //$NON-NLS-2$ + text = text.replace("</A>", "</a>");//$NON-NLS-1$ //$NON-NLS-2$ + getQLabel().setText(adjustTags(text)); + } + + /* + * QLabel does not render a link as a link if it is created like this: Text + * and <a>link</a> and another <a>link</a> QLabel requires the href part to + * be there also. This function changes the string above to this: Text and + * <a href="link">link</a> and another <a href="link">link</a> + */ + static String adjustTags(String str) { + int pos = str.indexOf(LINK_START); + + if (pos == -1) { + return str; + } + + int start = 0; + int endPos = pos; + StringBuffer sb = new StringBuffer(); + String clean = "";//$NON-NLS-1$ + + while (pos != -1) { + sb.append(str.substring(start, pos)).append("<a href=\"");//$NON-NLS-1$ + start = pos + LINK_START.length(); + endPos = str.indexOf(LINK_END, start); + if (endPos != -1) { + clean = clean(str.substring(start, endPos)); + sb.append(clean); + } else { + // If the link format is invalid in any way, just use + // original string and try not to be too clever. + return str; + } + + sb.append("\">" + clean + LINK_END);//$NON-NLS-1$ + start = endPos + LINK_END.length(); + pos = str.indexOf(LINK_START, start); + } + + return sb.toString(); + } + + static String clean(String strToClean) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < strToClean.length(); i++) { + char charAt = strToClean.charAt(i); + if (charAt == '"') { + sb.append("""); //$NON-NLS-1$ + } else { + if (charAt == '<') { + sb.append("<"); //$NON-NLS-1$ + } else { + if (charAt == '>') { + sb.append(">"); //$NON-NLS-1$ + } else { + sb.append(charAt); + } + } + } + } + return sb.toString(); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/List.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/List.java new file mode 100644 index 0000000000..db2dfc0a7b --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/List.java @@ -0,0 +1,1380 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import java.util.Arrays; + +import com.trolltech.qt.core.QModelIndex; +import com.trolltech.qt.core.QPoint; +import com.trolltech.qt.core.Qt.DropActions; +import com.trolltech.qt.gui.QDragEnterEvent; +import com.trolltech.qt.gui.QDragLeaveEvent; +import com.trolltech.qt.gui.QDragMoveEvent; +import com.trolltech.qt.gui.QDropEvent; +import com.trolltech.qt.gui.QItemSelection; +import com.trolltech.qt.gui.QListWidget; +import com.trolltech.qt.gui.QListWidgetItem; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QAbstractItemView.DragDropMode; +import com.trolltech.qt.gui.QAbstractItemView.ScrollHint; +import com.trolltech.qt.gui.QAbstractItemView.SelectionMode; +import com.trolltech.qt.gui.QItemSelectionModel.SelectionFlag; +import com.trolltech.qt.gui.QItemSelectionModel.SelectionFlags; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; + +/** + * Instances of this class represent a selectable user interface object that + * displays a list of strings and issues notification when a string is selected. + * A list may be single or multi select. + * <p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>SINGLE, MULTI</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection, DefaultSelection</dd> + * </dl> + * <p> + * Note: Only one of SINGLE and MULTI may be specified. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#list">List snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class List extends Scrollable { + /** + * 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)); + } + + @Override + protected QWidget createQWidget(int style) { + QListWidget listWidget = new MyListWidget(); + if ((style & SWT.MULTI) != 0) { + listWidget.setSelectionMode(SelectionMode.MultiSelection); + } else { + listWidget.setSelectionMode(SelectionMode.SingleSelection); + } + return listWidget; + } + + @Override + protected void connectSignals() { + getQListWidget().selectionModel().selectionChanged.connect(this, "selectionEvent()");//$NON-NLS-1$ + getQListWidget().itemActivated.connect(this, "itemActivationEvent(QListWidgetItem)");//$NON-NLS-1$ + } + + private QListWidget getQListWidget() { + return (QListWidget) getQWidget(); + } + + protected void selectionEvent() { + sendEvent(SWT.Selection); + } + + protected void itemActivationEvent(QListWidgetItem item) { + sendEvent(SWT.DefaultSelection); + } + + @Override + public void setDragEnabled(boolean enabled) { + getQListWidget().setDragEnabled(enabled); + } + + @Override + public void setAcceptDrops(boolean accept) { + super.setAcceptDrops(accept); + getQListWidget().setDragDropMode(DragDropMode.DragDrop); + getQListWidget().setDropIndicatorShown(true); + } + + /** + * Adds the argument to the end of the receiver's list. + * + * @param string + * the new item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #add(String,int) + */ + public void add(String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + getQListWidget().addItem(string); + } + + /** + * Adds the argument to the receiver's list at the given zero-relative + * index. + * <p> + * Note: To add an item at the end of the list, use the result of calling + * <code>getItemCount()</code> as the index or use <code>add(String)</code>. + * </p> + * + * @param string + * the new item + * @param index + * the index for the item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list (inclusive)</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #add(String) + */ + public void add(String string, int index) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + validateIndex(index); + getQListWidget().insertItem(index, string); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the user changes the receiver's selection, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * <code>widgetSelected</code> is called when the selection changes. + * <code>widgetDefaultSelected</code> is typically called when an item is + * double-clicked. + * </p> + * + * @param listener + * the listener which should be notified when the user changes + * the receiver's selection + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + static int checkStyle(int style) { + return checkBits(style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0); + } + + /** + * Deselects the items at the given zero-relative indices in the receiver. + * If the item at the given zero-relative index in the receiver is selected, + * it is deselected. If the item at the index was not selected, it remains + * deselected. Indices that are out of range and duplicate indices are + * ignored. + * + * @param indices + * the array of indices for the items to deselect + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the set of indices is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void deselect(int[] indices) { + checkWidget(); + if (indices == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + + updateSelection(indices, new SelectionFlags(SelectionFlag.Deselect)); + } + + private void updateSelection(int[] indices, SelectionFlags selectionFlags) { + int count = getQListWidget().count(); + for (int i = 0; i < indices.length; i++) { + if (indices[i] >= 0 && indices[i] < count) { + updateSelectionRange(indices[i], indices[i], selectionFlags); + } + } + } + + /** + * 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(); + validateIndex(index); + updateSelectionRange(index, index, new SelectionFlags(SelectionFlag.Deselect)); + } + + void validateIndex(int index) { + if (index < 0 || index > getQListWidget().count()) { + SWT.error(SWT.ERROR_INVALID_RANGE); + } + } + + /** + * 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 || end < 0) { + return; + } + int count = getQListWidget().count(); + if (start > count - 1) { + return; + } + start = Math.max(0, start); + end = Math.min(end, count - 1); + updateSelectionRange(start, end, new SelectionFlags(SelectionFlag.Deselect)); + } + + void updateSelectionRange(int start, int end, SelectionFlags flags) { + QModelIndex startIndex = getQListWidget().model().index(start, 0); + QModelIndex endIndex = getQListWidget().model().index(end, 0); + QItemSelection itemSelection = new QItemSelection(startIndex, endIndex); + getQListWidget().selectionModel().select(itemSelection, flags); + } + + /** + * 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(); + getQListWidget().clearSelection(); + } + + /** + * Returns the zero-relative index of the item which currently has the focus + * in the receiver, or -1 if no item has focus. + * + * @return the index of the selected item + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getFocusIndex() { + checkWidget(); + return getQListWidget().currentRow(); + } + + /** + * Returns the item at the given, zero-relative index in the receiver. + * Throws an exception if the index is out of range. + * + * @param index + * the index of the item to return + * @return the item at the given index + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list minus 1 (inclusive) + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String getItem(int index) { + checkWidget(); + validateIndex(index); + return getQListWidget().item(index).text(); + } + + /** + * 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 getQListWidget().count(); + } + + /** + * Returns the height of the area which would be used to display + * <em>one</em> of the items in the list. + * + * @return the height of one item + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getItemHeight() { + checkWidget(); + int itemHeight = 0; + if (getQListWidget().count() > 0) { + itemHeight = getQListWidget().sizeHintForRow(0); + } else { + // we add a dummy item to get the height + getQListWidget().addItem("");//$NON-NLS-1$ + itemHeight = getQListWidget().sizeHintForRow(0); + _remove(0); + } + return itemHeight; + } + + /** + * Returns a (possibly empty) array of <code>String</code>s which are the + * items in the receiver. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its list of items, so modifying the array will not affect the receiver. + * </p> + * + * @return the items in the receiver's list + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String[] getItems() { + checkWidget(); + 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. The order of the items is unspecified. An empty array + * indicates that no items are selected. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its selection, so modifying the array will not affect the receiver. + * </p> + * + * @return an array representing the selection + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String[] getSelection() { + checkWidget(); + QListWidget listWidget = getQListWidget(); + java.util.List<QModelIndex> selectedIndices = listWidget.selectionModel().selectedRows(); + String[] sel = new String[selectedIndices.size()]; + int i = 0; + for (QModelIndex index : selectedIndices) { + sel[i] = listWidget.item(index.row()).text(); + i++; + } + return sel; + } + + /** + * 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 getQListWidget().selectionModel().selectedRows().size(); + } + + /** + * Returns the zero-relative index of the item which is currently selected + * in the receiver, or -1 if no item is selected. + * + * @return the index of the selected item or -1 + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getSelectionIndex() { + checkWidget(); + java.util.List<QModelIndex> selectedIndices = getQListWidget().selectionModel().selectedRows(); + if (selectedIndices != null && selectedIndices.size() > 0) { + return selectedIndices.get(0).row(); + } + return 0; + } + + /** + * Returns the zero-relative indices of the items which are currently + * selected in the receiver. The order of the indices is unspecified. The + * array is empty if no items are selected. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its selection, so modifying the array will not affect the receiver. + * </p> + * + * @return the array of indices of the selected items + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int[] getSelectionIndices() { + checkWidget(); + java.util.List<QModelIndex> selection = getQListWidget().selectionModel().selectedRows(); + int[] selIndex = new int[selection.size()]; + int i = 0; + for (QModelIndex index : selection) { + selIndex[i] = index.row(); + i++; + } + return selIndex; + } + + /** + * 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(); + QModelIndex modellIndex = getQListWidget().indexAt(new QPoint(1, 1)); + return modellIndex == null ? -1 : modellIndex.row(); + } + + /** + * 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) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + + return indexOf(string, 0); + } + + /** + * Searches the receiver's list starting at the given, zero-relative index + * until an item is found that is equal to the argument, and returns the + * index of that item. If no item is found or the starting index is out of + * range, returns -1. + * + * @param string + * the search item + * @param start + * the zero-relative index at which to start the search + * @return the index of the item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int indexOf(String string, int start) { + checkWidget(); + if (string == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + QListWidget listWidget = getQListWidget(); + int count = listWidget.count(); + if (start < 0 || start > count - 1) { + return -1; + } + for (int i = start; i < count; i++) { + if (listWidget.item(i).equals(string)) { + return i; + } + } + return -1; + } + + /** + * Returns <code>true</code> if the item is selected, and <code>false</code> + * otherwise. Indices out of range are ignored. + * + * @param index + * the index of the item + * @return the selection state of the item at the index + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public boolean isSelected(int index) { + checkWidget(); + validateIndex(index); + QListWidgetItem item = getQListWidget().item(index); + if (item != null) { + return item.isSelected(); + } + return false; + } + + /** + * Removes the items from the receiver at the given zero-relative indices. + * + * @param indices + * the array of indices of the items + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list minus 1 (inclusive) + * </li> + * <li>ERROR_NULL_ARGUMENT - if the indices array is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void remove(int[] indices) { + checkWidget(); + if (indices == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + for (int index : indices) { + _remove(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> + */ + public void remove(int index) { + checkWidget(); + _remove(index); + } + + void _remove(int index) { + validateIndex(index); + getQListWidget().takeItem(index).dispose(); + } + + /** + * Removes the items from the receiver which are between the given + * zero-relative start and end indices (inclusive). + * + * @param start + * the start of the range + * @param end + * the end of the range + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if either the start or end are + * not between 0 and the number of elements in the list minus + * 1 (inclusive)</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void remove(int start, int end) { + checkWidget(); + if (end < 0 || start > end || (style & SWT.SINGLE) != 0 && start != end) { + error(SWT.ERROR_INVALID_RANGE); + } + QListWidget listWidget = getQListWidget(); + int count = listWidget.count(); + if (count == 0 || start >= count) { + error(SWT.ERROR_INVALID_RANGE); + } + start = Math.max(0, start); + end = Math.min(end, count - 1); + for (int i = end; i >= start; --i) { + listWidget.takeItem(i).dispose(); + } + } + + /** + * Searches the receiver's list starting at the first item until an item is + * found that is equal to the argument, and removes that item from the list. + * + * @param string + * the item to remove + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the string is not found in + * the list</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void remove(String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + int index = indexOf(string, 0); + if (index == -1) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + remove(index); + } + + /** + * Removes all of the items from the receiver. + * <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(); + getQListWidget().clear(); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the user changes the receiver's selection. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + /** + * Selects the items at the given zero-relative indices in the receiver. The + * current selection is not cleared before the new items are selected. + * <p> + * If the item at a given index is not selected, it is selected. If the item + * at a given index was already selected, it remains selected. Indices that + * are out of range and duplicate indices are ignored. If the receiver is + * single-select and multiple indices are specified, then all indices are + * ignored. + * + * @param indices + * the array of indices for the items to select + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of indices is null + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + * + * @see List#setSelection(int[]) + */ + public void select(int[] indices) { + checkWidget(); + if (indices == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + int length = indices.length; + if (length == 0 || (style & SWT.SINGLE) != 0 && length > 1) { + return; + } + select(indices, false); + } + + void select(int[] indices, boolean scroll) { + updateSelection(indices, new SelectionFlags(SelectionFlag.Select)); + } + + /** + * 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 < 0) { + return; + } + int count = getQListWidget().count(); + if (index >= count) { + return; + } + updateSelectionRange(index, index, new SelectionFlags(SelectionFlag.Select)); + } + + /** + * Selects the items in the range specified by the given zero-relative + * indices in the receiver. The range of indices is inclusive. The current + * selection is not cleared before the new items are selected. + * <p> + * If an item in the given range is not selected, it is selected. If an item + * in the given range was already selected, it remains selected. Indices + * that are out of range are ignored and no items will be selected if start + * is greater than end. If the receiver is single-select and there is more + * than one item in the given range, then all indices are ignored. + * + * @param start + * the start of the range + * @param end + * the end of the range + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + * + * @see List#setSelection(int,int) + */ + public void select(int start, int end) { + checkWidget(); + if (end < 0 || start > end || (style & SWT.SINGLE) != 0 && start != end) { + return; + } + int count = getQListWidget().count(); + if (count == 0 || start >= count) { + return; + } + start = Math.max(0, start); + end = Math.min(end, count - 1); + if ((style & SWT.SINGLE) != 0) { + select(start, false); + } else { + select(start, end, false); + } + } + + void select(int start, int end, boolean scroll) { + updateSelectionRange(start, end, new SelectionFlags(SelectionFlag.Select)); + } + + /** + * Selects all of the items in the receiver. + * <p> + * If the receiver is single-select, do nothing. + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + */ + public void selectAll() { + checkWidget(); + int count = getQListWidget().count(); + if ((style & SWT.MULTI) != 0 && count > 0) { + updateSelectionRange(0, count - 1, new SelectionFlags(SelectionFlag.Select)); + } + } + + void setFocusIndex(int index) { + QModelIndex modelIndex = getQListWidget().model().index(index, 0); + getQListWidget().selectionModel().setCurrentIndex(modelIndex, SelectionFlag.Current); + } + + /** + * Sets the text of the item in the receiver's list at the given + * zero-relative index to the string argument. + * + * @param index + * the index for the item + * @param string + * the new text for the item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list minus 1 (inclusive) + * </li> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setItem(int index, String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + validateIndex(index); + 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> + * <li>ERROR_INVALID_ARGUMENT - if an item in the items array + * is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setItems(String[] items) { + checkWidget(); + if (items == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + for (String item : items) { + if (item == null) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + } + getQListWidget().clear(); + getQListWidget().addItems(Arrays.asList(items)); + } + + /** + * Selects the items at the given zero-relative indices in the receiver. The + * current selection is cleared before the new items are selected. + * <p> + * Indices that are out of range and duplicate indices are ignored. If the + * receiver is single-select and multiple indices are specified, then all + * indices are ignored. + * + * @param indices + * the indices of the items to select + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of indices is null + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + * + * @see List#deselectAll() + * @see List#select(int[]) + */ + public void setSelection(int[] indices) { + checkWidget(); + if (indices == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + deselectAll(); + int length = indices.length; + if (length == 0 || (style & SWT.SINGLE) != 0 && length > 1) { + return; + } + select(indices, true); + if ((style & SWT.MULTI) != 0) { + int focusIndex = indices[0]; + if (focusIndex >= 0) { + setFocusIndex(focusIndex); + } + } + } + + /** + * Sets the receiver's selection to be the given array of items. The current + * selection is cleared before the new items are selected. + * <p> + * Items that are not in the receiver are ignored. If the receiver is + * single-select and multiple items are specified, then all items are + * ignored. + * + * @param items + * the array of items + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of items is null + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + * + * @see List#deselectAll() + * @see List#select(int[]) + * @see List#setSelection(int[]) + */ + public void setSelection(String[] items) { + checkWidget(); + if (items == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + deselectAll(); + int length = items.length; + if (length == 0 || (style & SWT.SINGLE) != 0 && length > 1) { + return; + } + int focusIndex = -1; + for (int i = 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)) { + showSelection(); + return; + } + index++; + } + if (localFocus != -1) { + focusIndex = localFocus; + } + } + } + if ((style & SWT.MULTI) != 0) { + if (focusIndex >= 0) { + 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 + * selection is first cleared, then the new item is selected. Indices that + * are out of range are ignored. + * + * @param index + * the index of the item to select + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * @see List#deselectAll() + * @see List#select(int) + */ + public void setSelection(int index) { + checkWidget(); + deselectAll(); + select(index, true); + if ((style & SWT.MULTI) != 0) { + if (index >= 0 && index < getQListWidget().count()) { + setFocusIndex(index); + } + } + } + + /** + * Selects the items in the range specified by the given zero-relative + * indices in the receiver. The range of indices is inclusive. The current + * selection is cleared before the new items are selected. + * <p> + * Indices that are out of range are ignored and no items will be selected + * if start is greater than end. If the receiver is single-select and there + * is more than one item in the given range, then all indices are ignored. + * + * @param start + * the start index of the items to select + * @param end + * the end index of the items to select + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + * + * @see List#deselectAll() + * @see List#select(int,int) + */ + public void setSelection(int start, int end) { + checkWidget(); + deselectAll(); + if (end < 0 || start > end || (style & SWT.SINGLE) != 0 && start != end) { + return; + } + int count = getQListWidget().count(); + if (count == 0 || start >= count) { + return; + } + start = Math.max(0, start); + end = Math.min(end, count - 1); + updateSelectionRange(start, end, new SelectionFlags(SelectionFlag.Select)); + } + + /** + * 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(); + validateIndex(index); + getQListWidget().scrollToItem(getQListWidget().item(index), ScrollHint.PositionAtTop); + } + + /** + * 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(); + getQListWidget().scrollToItem(getQListWidget().currentItem(), ScrollHint.PositionAtTop); + } + + private final class MyListWidget extends QListWidget { + + @Override + protected void startDrag(DropActions supportedActions) { + // System.out.println("MyQTreeWidget.startDrag: " + supportedActions); + } + + @Override + protected void dropEvent(QDropEvent event) { + sendDropEvent(event); + } + + @Override + protected void dragMoveEvent(QDragMoveEvent event) { + sendDragMoveEvent(event); + } + + @Override + protected void dragEnterEvent(QDragEnterEvent event) { + sendDragEnterEvent(event); + } + + @Override + protected void dragLeaveEvent(QDragLeaveEvent event) { + sendDragLeaveEvent(event); + } + + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Menu.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Menu.java new file mode 100644 index 0000000000..14e057d36c --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Menu.java @@ -0,0 +1,1423 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import java.util.List; + +import com.trolltech.qt.core.QObject; +import com.trolltech.qt.core.Qt.LayoutDirection; +import com.trolltech.qt.gui.QAction; +import com.trolltech.qt.gui.QActionGroup; +import com.trolltech.qt.gui.QApplication; +import com.trolltech.qt.gui.QBrush; +import com.trolltech.qt.gui.QColor; +import com.trolltech.qt.gui.QMenu; +import com.trolltech.qt.gui.QMenuBar; +import com.trolltech.qt.gui.QPalette; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QPalette.ColorRole; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.HelpListener; +import org.eclipse.swt.events.MenuListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.internal.qt.QtSWTConverter; + +/** + * Instances of this class are user interface objects that contain menu items. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>BAR, DROP_DOWN, POP_UP, NO_RADIO_GROUP</dd> + * <dd>LEFT_TO_RIGHT, RIGHT_TO_LEFT</dd> + * <dt><b>Events:</b></dt> + * <dd>Help, Hide, Show</dd> + * </dl> + * <p> + * Note: Only one of BAR, DROP_DOWN and POP_UP may be specified. Only one of + * LEFT_TO_RIGHT or RIGHT_TO_LEFT may be specified. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#menu">Menu snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class Menu extends Widget { + private int x, y; + private boolean hasLocation; + private Color foreground = null; + private Color background = null; + private Image backgroundImage; + MenuItem cascade; + Decorations parent; + private QActionGroup actionGroup; + + /** + * Constructs a new instance of this class given its parent, and sets the + * style for the instance so that the instance will be a popup menu on the + * given parent's shell. + * <p> + * After constructing a menu, it can be set into its parent using + * <code>parent.setMenu(menu)</code>. In this case, the parent may be any + * control in the same widget tree as the parent. + * </p> + * + * @param parent + * a control which will be the parent of the new instance (cannot + * be null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#POP_UP + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public Menu(Control parent) { + this(checkNull(parent).menuShell(), null, SWT.POP_UP); + } + + /** + * Constructs a new instance of this class given its parent (which must be a + * <code>Decorations</code>) and a style value describing its behavior and + * appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * <p> + * After constructing a menu or menuBar, it can be set into its parent using + * <code>parent.setMenu(menu)</code> or + * <code>parent.setMenuBar(menuBar)</code>. + * </p> + * + * @param parent + * a decorations control which will be the parent of the new + * instance (cannot be null) + * @param style + * the style of menu to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#BAR + * @see SWT#DROP_DOWN + * @see SWT#POP_UP + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public Menu(Decorations parent, int style) { + this(parent, null, checkStyle(style)); + } + + /** + * Constructs a new instance of this class given its parent (which must be a + * <code>Menu</code>) and sets the style for the instance so that the + * instance will be a drop-down menu on the given parent's parent. + * <p> + * After constructing a drop-down menu, it can be set into its parentMenu + * using <code>parentMenu.setMenu(menu)</code>. + * </p> + * + * @param parentMenu + * a menu which will be the parent of the new instance (cannot be + * null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#DROP_DOWN + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public Menu(Menu parentMenu) { + this(checkNull(parentMenu).parent, parentMenu.getQWidget(), SWT.DROP_DOWN); + } + + /** + * Constructs a new instance of this class given its parent (which must be a + * <code>MenuItem</code>) and sets the style for the instance so that the + * instance will be a drop-down menu on the given parent's parent menu. + * <p> + * After constructing a drop-down menu, it can be set into its parentItem + * using <code>parentItem.setMenu(menu)</code>. + * </p> + * + * @param parentItem + * a menu item which will be the parent of the new instance + * (cannot be null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#DROP_DOWN + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public Menu(MenuItem parentItem) { + this(checkNull(parentItem).parent); + } + + Menu(Decorations parent, QWidget qParent, int style) { + super(parent, checkStyle(style)); + display = parent.display; + createWidget(parent, qParent, style); + } + + protected void createWidget(Decorations parent, QWidget qParent, int style) { + state |= DRAG_DETECT; + this.parent = parent; + checkAndUpdateOrientation(parent); + QWidget qtControl = createQtControl(qParent != null ? qParent : parent.getQWidget()); + if (qtControl == null) { + error(SWT.ERROR_UNSPECIFIED); + } + setQWidget(qtControl); + if ((style & SWT.RIGHT_TO_LEFT) != 0) { + qtControl.setLayoutDirection(LayoutDirection.RightToLeft); + } + register(); + if ((state & PARENT_BACKGROUND) != 0) { + updateBackground(); + } + parent.addMenu(this); + } + + protected QWidget createQtControl(QWidget parent) { + state &= ~CANVAS; + if (isMenuBar()) { + return new QMenuBar(parent); + } + return new QMenu(parent); + } + + QMenuBar getQMenuBar() { + return (QMenuBar) getQWidget(); + } + + QMenu getQMenu() { + return (QMenu) getQWidget(); + } + + void addToActionGroup(QAction action) { + initActionGroup(); + actionGroup.addAction(action); + } + + void removeFromActionGroup(QAction action) { + if (hasActionGroup()) { + actionGroup.removeAction(action); + } + } + + private boolean hasActionGroup() { + return actionGroup != null; + } + + private void initActionGroup() { + if (actionGroup == null) { + actionGroup = new QActionGroup(getQWidget()); + if ((parent.style & SWT.NO_RADIO_GROUP) != 0) { + actionGroup.setExclusive(false); + } + } + } + + void register() { + display.addControl(getQWidget(), this); + } + + void deregister() { + display.removeControl(getQWidget()); + } + + void _setVisible(boolean visible) { + if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) { + return; + } + getQWidget().setHidden(!visible); + } + + /** + * 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 addAction(QAction action, int index) { + QWidget menu = getQWidget(); + int itemCount = _getItemCount(); + if (index >= 0 && index < itemCount) { + MenuItem[] items = getItems(); + QAction before = items[index].getQAction(); + menu.insertAction(before, action); + } else { + menu.addAction(action); + } + } + + void removeAction(QAction action) { + if (isMenuBar()) { + getQMenuBar().removeAction(action); + } else { + getQMenu().removeAction(action); + } + } + + boolean isMenuBar() { + return (style & SWT.BAR) != 0; + } + + Color defaultBackground() { + return display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); + } + + Color defaultForeground() { + return display.getSystemColor(SWT.COLOR_WIDGET_FOREGROUND); + } + + void fixMenus(Decorations newParent) { + MenuItem[] items = getItems(); + for (int i = 0; i < items.length; i++) { + items[i].fixMenus(newParent); + } + parent.removeMenu(this); + newParent.addMenu(this); + this.parent = newParent; + } + + /** + * 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 3.3 + */ + /* public */Color getBackground() { + checkWidget(); + return background != null ? Color.qt_new(display, background.getColor()) : defaultBackground(); + } + + /** + * Returns the receiver's background image. + * + * @return the background image + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.3 + */ + /* public */Image getBackgroundImage() { + checkWidget(); + return backgroundImage; + } + + /** + * Returns a rectangle describing the receiver's size and location relative + * to its parent (or its display if its parent is null), unless the receiver + * is a menu or a shell. In this case, the location is relative to the + * display. + * <p> + * Note that the bounds of a menu or menu item are undefined when the menu + * is not visible. This is because most platforms compute the bounds of a + * menu dynamically just before it is displayed. + * </p> + * + * @return the receiver's bounding rectangle + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + /* public */Rectangle getBounds() { + checkWidget(); + return QtSWTConverter.convert(getQWidget().frameGeometry()); + } + + /** + * 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 display.getMenuItem( info.wID ); + // } + return null; + } + + /** + * Returns <code>true</code> if the receiver is enabled, and + * <code>false</code> otherwise. A disabled menu is typically not selectable + * from the user interface and draws with an inactive or "grayed" look. + * + * @return the receiver's enabled state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #isEnabled + */ + public boolean getEnabled() { + checkWidget(); + return getQMenuBar().isEnabled(); + } + + /** + * 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 foreground != null ? Color.qt_new(display, foreground.getColor()) : defaultForeground(); + } + + /** + * 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(); + List<QAction> list = getQWidget().actions(); + int count = list.size(); + if (!(0 <= index && index < count)) { + error(SWT.ERROR_INVALID_RANGE); + } + Widget widget = display.findControl(list.get(index)); + if (widget == null || !MenuItem.class.isInstance(widget)) { + error(SWT.ERROR_CANNOT_GET_ITEM); + } + return (MenuItem) widget; + } + + /** + * 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 _getItemCount(); + } + + /** + * Returns a (possibly empty) array of <code>MenuItem</code>s which are the + * items in the receiver. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its list of items, so modifying the array will not affect the receiver. + * </p> + * + * @return the items in the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public MenuItem[] getItems() { + checkWidget(); + List<QAction> list = getQWidget().actions(); + int count = list.size(); + if (count == 0) { + return new MenuItem[0]; + } + MenuItem[] children = new MenuItem[count]; + int items = 0; + for (QAction action : list) { + if (action != null) { + Widget widget = display.findControl(action); + if (widget != null && widget != this) { + if (widget instanceof MenuItem) { + children[items++] = (MenuItem) widget; + } + } + } + } + if (items == count) { + return children; + } + MenuItem[] newChildren = new MenuItem[items]; + System.arraycopy(children, 0, newChildren, 0, items); + return newChildren; + } + + int _getItemCount() { + return getQWidget().actions().size(); + } + + @Override + String getNameText() { + String result = "";//$NON-NLS-1$ + MenuItem[] items = getItems(); + int length = items.length; + if (length > 0) { + for (int i = 0; i < length - 1; i++) { + result = result + items[i].getNameText() + ", ";//$NON-NLS-1$ + } + result = result + items[length - 1].getNameText(); + } + return result; + } + + /** + * Returns the receiver's parent, which must be a <code>Decorations</code>. + * + * @return the receiver's parent + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Decorations getParent() { + checkWidget(); + return parent; + } + + /** + * Returns the receiver's parent item, which must be a <code>MenuItem</code> + * or null when the receiver is a root. + * + * @return the receiver's parent item + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public MenuItem getParentItem() { + checkWidget(); + return cascade; + } + + /** + * Returns the receiver's parent item, which must be a <code>Menu</code> or + * null when the receiver is a root. + * + * @return the receiver's parent item + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Menu getParentMenu() { + checkWidget(); + if (cascade != null) { + return cascade.parent; + } + return null; + } + + /** + * Returns the receiver's shell. For all controls other than shells, this + * simply returns the control's nearest ancestor shell. Shells return + * themselves, even if they are children of other shells. + * + * @return the receiver's shell + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #getParent + */ + public Shell getShell() { + checkWidget(); + return parent.getShell(); + } + + /** + * Returns <code>true</code> if the receiver is visible, and + * <code>false</code> otherwise. + * <p> + * If one of the receiver's ancestors is not visible or some other condition + * makes the receiver not visible, this method may still indicate that it is + * considered visible even though it may not actually be showing. + * </p> + * + * @return the receiver's visibility state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public boolean getVisible() { + checkWidget(); + if ((style & SWT.BAR) != 0) { + return this == parent.menuShell().menuBar; + } + if ((style & SWT.POP_UP) != 0) { + Menu[] popups = display.popups; + if (popups == null) { + return false; + } + for (int i = 0; i < popups.length; i++) { + if (popups[i] == this) { + return true; + } + } + } + Shell shell = getShell(); + Menu menu = shell.activeMenu; + while (menu != null && menu != this) { + menu = menu.getParentMenu(); + } + return this == menu; + } + + /** + * Searches the receiver's list starting at the first item (index 0) until + * an item is found that is equal to the argument, and returns the index of + * that item. If no item is found, returns -1. + * + * @param item + * the search item + * @return the index of the item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the item is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int indexOf(MenuItem item) { + checkWidget(); + if (item == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (item.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (item.parent != this) { + return -1; + } + List<QAction> actions = getQWidget().actions(); + for (int i = 0; i < actions.size(); i++) { + if (actions.get(i) == item.getQAction()) { + return i; + } + } + return -1; + } + + /** + * Returns <code>true</code> if the receiver is enabled and all of the + * receiver's ancestors are enabled, and <code>false</code> otherwise. A + * disabled menu is typically not selectable from the user interface and + * draws with an inactive or "grayed" look. + * + * @return the receiver's enabled state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #getEnabled + */ + public boolean isEnabled() { + checkWidget(); + Menu parentMenu = getParentMenu(); + if (parentMenu == null) { + return getEnabled() && parent.isEnabled(); + } + return getEnabled() && parentMenu.isEnabled(); + } + + /** + * Returns <code>true</code> if the receiver is visible and all of the + * receiver's ancestors are visible and <code>false</code> otherwise. + * + * @return the receiver's visibility state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #getVisible + */ + public boolean isVisible() { + checkWidget(); + return getVisible(); + } + + void redraw() { + if (!isVisible()) { + return; + } + if ((style & SWT.BAR) != 0) { + display.addBar(this); + } + } + + @Override + void releaseQWidget() { + super.releaseQWidget(); + cascade = null; + } + + @Override + void releaseChildren(boolean destroy) { + MenuItem[] items = getItems(); + for (int i = 0; i < items.length; i++) { + MenuItem item = items[i]; + if (item != null && !item.isDisposed()) { + item.release(false); + } + } + super.releaseChildren(destroy); + } + + @Override + void releaseParent() { + super.releaseParent(); + if ((style & SWT.BAR) != 0) { + display.removeBar(this); + if (this == parent.menuBar) { + parent.setMenuBar(null); + } + } else { + if ((style & SWT.POP_UP) != 0) { + display.removePopup(this); + } + } + } + + @Override + void releaseWidget() { + super.releaseWidget(); + backgroundImage = null; + if (parent != null) { + parent.removeMenu(this); + } + parent = null; + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the help events are generated for the control. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see HelpListener + * @see #addHelpListener + */ + public void removeHelpListener(HelpListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Help, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the menu events are generated for the control. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see MenuListener + * @see #addMenuListener + */ + public void removeMenuListener(MenuListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Hide, listener); + eventTable.unhook(SWT.Show, listener); + } + + /** + * Sets the 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> + * + * @since 3.3 + */ + /* public */void setBackground(Color color) { + checkWidget(); + if (color != null) { + if (color.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + } + Color oldColor = background; + if (color == null) { + background = null; + } else { + if (color.equals(background)) { + return; + } + background = color; + } + if (oldColor != null) { + oldColor.dispose(); + } + updateBackground(); + } + + /** + * Sets the receiver's background image to the image specified by the + * argument, or to the default system color for the control if the argument + * is null. The background image is tiled to fill the available space. + * + * @param image + * the new image (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * <li>ERROR_INVALID_ARGUMENT - if the argument is not a + * bitmap</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.3 + */ + /* public */void setBackgroundImage(Image image) { + checkWidget(); + if (image != null) { + if (image.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (!image.isBitmap()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + } + if (backgroundImage == image) { + return; + } + backgroundImage = image; + updateBackground(); + } + + /** + * 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> + * + * @since 3.3 + */ + /* public */void setForeground(Color color) { + checkWidget(); + if (color != null) { + if (color.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + } + Color oldColor = foreground; + if (color == null) { + foreground = null; + } else { + if (color.equals(foreground)) { + return; + } + foreground = color; + } + if (oldColor != null) { + oldColor.dispose(); + } + applyForegroundColor(foreground); + } + + /** + * Sets the default menu item to the argument or removes the default + * emphasis when the argument is <code>null</code>. + * + * @param item + * the default menu item or null + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the menu item has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setDefaultItem(MenuItem item) { + checkWidget(); + if (item != null) { + if (item.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (item.parent != this) { + return; + } + if (!isMenuBar()) { + getQMenu().setDefaultAction(item.getQAction()); + } + } else { + if (!isMenuBar()) { + getQMenu().setDefaultAction(null); + } + } + } + + /** + * Enables the receiver if the argument is <code>true</code>, and disables + * it otherwise. A disabled menu is typically not selectable from the user + * interface and draws with an inactive or "grayed" look. + * + * @param enabled + * the new enabled state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setEnabled(boolean enabled) { + checkWidget(); + getQWidget().setEnabled(enabled); + getQWidget().update(); + } + + /** + * Sets the location of the receiver, which must be a popup, to the point + * specified by the arguments which are relative to the display. + * <p> + * Note that this is different from most widgets where the location of the + * widget is relative to the parent. + * </p> + * <p> + * Note that the platform window manager ultimately has control over the + * location of popup menus. + * </p> + * + * @param x + * the new x coordinate for the receiver + * @param y + * the new y coordinate for the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setLocation(int x, int y) { + checkWidget(); + if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) { + return; + } + this.x = x; + this.y = y; + hasLocation = true; + } + + /** + * Sets the location of the receiver, which must be a popup, to the point + * specified by the argument which is relative to the display. + * <p> + * Note that this is different from most widgets where the location of the + * widget is relative to the parent. + * </p> + * <p> + * Note that the platform window manager ultimately has control over the + * location of popup menus. + * </p> + * + * @param location + * the new location for the receiver + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 2.1 + */ + public void setLocation(Point location) { + checkWidget(); + if (location == null) { + 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; + } + if (visible) { + display.addPopup(this); + if (hasLocation) { + getQMenu().move(x, y); + } + getQMenu().setVisible(true); + } else { + display.removePopup(this); + _setVisible(false); + } + } + + @Override + public boolean qtHideEvent(QObject source) { + if (source == getQWidget()) { + if (!isDisposed()) { + sendEvent(SWT.Hide); + } + } + return super.qtHideEvent(source); + } + + @Override + public boolean qtShowEvent(QObject source) { + if (source == getQWidget()) { + if (!isDisposed()) { + sendEvent(SWT.Show); + } + } + return super.qtShowEvent(source); + } + + void updateBackground() { + if (backgroundImage != null) { + applyBackgroundImage(backgroundImage); + return; + } + if (background != null) { + applyBackgroundColor(background); + return; + } + } + + private void applyBackgroundColor(Color color) { + updatedPalette(color, getBackgroundColorRoles()); + updateAutoFillBackground(); + } + + private void updatedPalette(Color color, ColorRole[] colorRoles) { + QPalette palette = getQWidget().palette(); + if (color != null) { + QColor qColor = new QColor(color.getColor()); + for (ColorRole role : colorRoles) { + palette.setColor(role, qColor); + } + } else { + QPalette defaultPalette = QApplication.palette(); + for (ColorRole role : colorRoles) { + QBrush brush = defaultPalette.brush(role); + palette.setBrush(role, brush); + } + } + getQWidget().setPalette(palette); + } + + private QPalette.ColorRole[] getBackgroundColorRoles() { + return new QPalette.ColorRole[] { QPalette.ColorRole.Window, QPalette.ColorRole.Base, QPalette.ColorRole.Button }; + } + + private void updateAutoFillBackground() { + if (background != null || backgroundImage != null) { + getQWidget().setAutoFillBackground(true); + } + } + + private void applyBackgroundImage(Image image) { + QPalette palette = getQWidget().palette().clone(); + try { + setPaletteBgImage(palette, image); + getQWidget().setPalette(palette); + } finally { + palette.dispose(); + } + updateAutoFillBackground(); + } + + private void setPaletteBgImage(QPalette palette, Image image) { + ColorRole[] bkRoles = getBackgroundImageRoles(); + if (image != null) { + for (ColorRole bkRole : bkRoles) { + palette.setBrush(bkRole, new QBrush(image.getQPixmap())); + } + } else { + QPalette defaultPalette = QApplication.palette(); + for (ColorRole role : bkRoles) { + QBrush brush = defaultPalette.brush(role); + palette.setBrush(role, brush.clone()); + } + } + } + + private ColorRole[] getBackgroundImageRoles() { + return new QPalette.ColorRole[] { QPalette.ColorRole.Window, QPalette.ColorRole.Base }; + } + + private void applyForegroundColor(Color color) { + updatedPalette(color, getForegroundColorRoles()); + } + + private ColorRole[] getForegroundColorRoles() { + return new ColorRole[] { QPalette.ColorRole.WindowText, QPalette.ColorRole.Text, QPalette.ColorRole.ButtonText }; + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/MenuItem.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/MenuItem.java new file mode 100644 index 0000000000..479993bdec --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/MenuItem.java @@ -0,0 +1,1011 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import java.util.HashMap; + +import com.trolltech.qt.core.Qt; +import com.trolltech.qt.gui.QAction; +import com.trolltech.qt.gui.QIcon; +import com.trolltech.qt.gui.QKeySequence; +import com.trolltech.qt.gui.QMenu; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.ArmListener; +import org.eclipse.swt.events.HelpListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.internal.qt.QtSWTConverter; + +/** + * Instances of this class represent a selectable user interface object that + * issues notification when pressed and released. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>CHECK, CASCADE, PUSH, RADIO, SEPARATOR</dd> + * <dt><b>Events:</b></dt> + * <dd>Arm, Help, Selection</dd> + * </dl> + * <p> + * Note: Only one of the styles CHECK, CASCADE, PUSH, RADIO and SEPARATOR may be + * specified. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class MenuItem extends Item { + private QAction action; + Menu parent, menu; + int id, accelerator; + + private HashMap<Integer, Integer> modifiers = new HashMap<Integer, Integer>(); + private HashMap<Integer, Integer> accelerators = new HashMap<Integer, Integer>(); + + /** + * 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; + createAction(parent, style, -1); + initializeKeys(); + } + + /** + * Constructs a new instance of this class given its parent (which must be a + * <code>Menu</code>), a style value describing its behavior and appearance, + * and the index at which to place it in the items maintained by its parent. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a menu control which will be the parent of the new instance + * (cannot be null) + * @param style + * the style of control to construct + * @param index + * the zero-relative index to store the receiver in its parent + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the parent (inclusive)</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#CHECK + * @see SWT#CASCADE + * @see SWT#PUSH + * @see SWT#RADIO + * @see SWT#SEPARATOR + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public MenuItem(Menu parent, int style, int index) { + super(parent, checkStyle(style)); + this.parent = parent; + createAction(parent, style, index); + initializeKeys(); + } + + 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; + } + display.addMenuItem(this); + initializeKeys(); + } + + protected void createAction(Menu parent, int style, int index) { + action = new QAction(parent.getQWidget()); + + parent.addAction(action, index); + int bits = SWT.CHECK | SWT.RADIO | SWT.PUSH | SWT.SEPARATOR; + switch (style & bits) { + case SWT.SEPARATOR: + action.setSeparator(true); + break; + case SWT.RADIO: + action.setCheckable(true); + parent.addToActionGroup(action); + break; + case SWT.CHECK: + action.setCheckable(true); + break; + case SWT.PUSH: + default: + break; + } + connectSignals(); + display.addControl(action, this); + } + + QAction getQAction() { + return action; + } + + protected void connectSignals() { + if ((style & SWT.CASCADE) == 0) { + getQAction().triggered.connect(this, "triggerEvent(boolean)");//$NON-NLS-1$ + } + getQAction().hovered.connect(this, "hoverEvent()");//$NON-NLS-1$ + } + + protected void triggerEvent(boolean triggered) { + Event event = new Event(); + sendEvent(SWT.Selection, event); + } + + protected void hoverEvent() { + sendEvent(SWT.Arm); + } + + /** + * Initialize the hashmaps with the SWT keys mapping to QT keys. This is + * needed for the accelerator. + */ + private void initializeKeys() { + + modifiers.put(SWT.CTRL, Qt.Modifier.CTRL.value()); // 262144, 67108864 + modifiers.put(SWT.MOD1, Qt.Modifier.CTRL.value()); // 262144, 67108864 + modifiers.put(SWT.SHIFT, Qt.Modifier.SHIFT.value()); + modifiers.put(SWT.MOD2, Qt.Modifier.SHIFT.value()); + modifiers.put(SWT.ALT, Qt.Modifier.ALT.value()); + + accelerators.put(SWT.ARROW_DOWN, Qt.Key.Key_Down.value()); // 16777218 + accelerators.put(SWT.ARROW_LEFT, Qt.Key.Key_Left.value()); // 16777219 + accelerators.put(SWT.ARROW_RIGHT, Qt.Key.Key_Right.value()); // 16777220 + accelerators.put(SWT.ARROW_UP, Qt.Key.Key_Up.value()); // 16777217 + accelerators.put(SWT.F1, Qt.Key.Key_F1.value()); // 16777226 + accelerators.put(SWT.F2, Qt.Key.Key_F2.value()); + accelerators.put(SWT.F3, Qt.Key.Key_F3.value()); + accelerators.put(SWT.F4, Qt.Key.Key_F4.value()); + accelerators.put(SWT.F5, Qt.Key.Key_F5.value()); + accelerators.put(SWT.F6, Qt.Key.Key_F6.value()); + accelerators.put(SWT.F7, Qt.Key.Key_F7.value()); + accelerators.put(SWT.F8, Qt.Key.Key_F8.value()); + accelerators.put(SWT.F9, Qt.Key.Key_F9.value()); + accelerators.put(SWT.F10, Qt.Key.Key_F10.value()); + accelerators.put(SWT.F11, Qt.Key.Key_F11.value()); + accelerators.put(SWT.F12, Qt.Key.Key_F12.value()); + accelerators.put(SWT.F13, Qt.Key.Key_F13.value()); + accelerators.put(SWT.F14, Qt.Key.Key_F14.value()); + accelerators.put(SWT.F15, Qt.Key.Key_F15.value()); + accelerators.put(SWT.PAGE_UP, Qt.Key.Key_PageUp.value()); + accelerators.put(SWT.PAGE_DOWN, Qt.Key.Key_PageDown.value()); + accelerators.put(SWT.HOME, Qt.Key.Key_Home.value()); + accelerators.put(SWT.END, Qt.Key.Key_End.value()); + accelerators.put(SWT.INSERT, Qt.Key.Key_Insert.value()); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the arm events are generated for the control, by sending it one of + * the messages defined in the <code>ArmListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ArmListener + * @see #removeArmListener + */ + public void addArmListener(ArmListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Arm, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the help events are generated for the control, by sending it one of + * the messages defined in the <code>HelpListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see HelpListener + * @see #removeHelpListener + */ + public void addHelpListener(HelpListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Help, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the menu item is selected by the user, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * When <code>widgetSelected</code> is called, the stateMask field of the + * event object is valid. <code>widgetDefaultSelected</code> is not called. + * </p> + * + * @param listener + * the listener which should be notified when the menu item is + * selected by the user + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + @Override + 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); + } + + @Override + void destroyWidget() { + parent.removeAction(getQAction()); + super.destroyWidget(); + } + + void fixMenus(Decorations newParent) { + if (menu != null) { + menu.fixMenus(newParent); + } + } + + /** + * Returns the widget accelerator. An accelerator is the bit-wise OR of zero + * or more modifier masks and a key. Examples: + * <code>SWT.CONTROL | SWT.SHIFT | 'T', SWT.ALT | SWT.F2</code>. The default + * value is zero, indicating that the menu item does not have an + * accelerator. + * + * @return the accelerator or 0 + * + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getAccelerator() { + checkWidget(); + return accelerator; + } + + /** + * Returns 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> + * + * @since 3.1 + */ + /* public */Rectangle getBounds() { + checkWidget(); + return QtSWTConverter.convert(getQWidget().frameGeometry()); + } + + /** + * Returns <code>true</code> if the receiver is enabled, and + * <code>false</code> otherwise. A disabled menu item is typically not + * selectable from the user interface and draws with an inactive or "grayed" + * look. + * + * @return the receiver's enabled state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #isEnabled + */ + public boolean getEnabled() { + checkWidget(); + return getQAction().isEnabled(); + } + + /** + * 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> + */ + @Override + public Menu getMenu() { + checkWidget(); + return menu; + } + + @Override + String getNameText() { + if ((style & SWT.SEPARATOR) != 0) { + return "|";//$NON-NLS-1$ + } + 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(); + return getQAction().isChecked(); + } + + /** + * Returns <code>true</code> if the receiver is enabled and all of the + * receiver's ancestors are enabled, and <code>false</code> otherwise. A + * disabled menu item is typically not selectable from the user interface + * and draws with an inactive or "grayed" look. + * + * @return the receiver's enabled state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #getEnabled + */ + public boolean isEnabled() { + return getEnabled() && parent.isEnabled(); + } + + @Override + void releaseChildren(boolean destroy) { + if (menu != null) { + menu.release(false); + menu = null; + } + super.releaseChildren(destroy); + } + + @Override + void releaseQWidget() { + if ((style & SWT.RADIO) != 0) { + parent.removeFromActionGroup(action); + } + parent.removeAction(action); + display.removeControl(action); + parent = null; + action = null; + id = -1; + super.releaseQWidget(); + } + + @Override + void releaseParent() { + super.releaseParent(); + if (menu != null) { + menu.dispose(); + } + menu = null; + } + + @Override + void releaseWidget() { + super.releaseWidget(); + accelerator = 0; + display.removeMenuItem(this); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the arm events are generated for the control. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ArmListener + * @see #addArmListener + */ + public void removeArmListener(ArmListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Arm, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the help events are generated for the control. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see HelpListener + * @see #addHelpListener + */ + public void removeHelpListener(HelpListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Help, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is selected by the user. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + void selectRadio() { + int index = 0; + MenuItem[] items = parent.getItems(); + while (index < items.length && items[index] != this) { + index++; + } + int i = index - 1; + while (i >= 0 && items[i].setRadioSelection(false)) { + --i; + } + int j = index + 1; + while (j < items.length && items[j].setRadioSelection(false)) { + j++; + } + setSelection(true); + } + + /** + * Sets the widget accelerator. An accelerator is the bit-wise OR of zero or + * more modifier masks and a key. Examples: + * <code>SWT.MOD1 | SWT.MOD2 | 'T', SWT.MOD3 | SWT.F2</code>. + * <code>SWT.CONTROL | SWT.SHIFT | 'T', SWT.ALT | SWT.F2</code>. The default + * value is zero, indicating that the menu item does not have an + * accelerator. + * + * @param accelerator + * an integer that is the bit-wise OR of masks and a key + * + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setAccelerator(int accelerator) { + checkWidget(); + int seq = 0; + if (this.accelerator == accelerator) { + return; + } + this.accelerator = accelerator; + /* + * fetch the modifiers of the accelerator (something like + * CTRL+SHIFT...). There can be more than one modifier. + */ + for (Integer modifier : modifiers.keySet()) { + if ((accelerator & modifier) != 0) { + accelerator -= modifier; + seq += modifiers.get(modifier); + } + } + + /* + * Fetch uppercase characters and other ascii characters (+, =, ?...). + * Only one of this chars is allowed. + */ + if (accelerator >= 32 && accelerator <= 96 || accelerator >= 123 && accelerator <= 127) { + seq += accelerator; + accelerator -= accelerator; + } + /* + * Transform lowercase characters to uppercase characters, because QT + * can only handle uppercase characters and there is no difference + * between CTRL+m and CTRL+M. Only one of this chars is allowed. + */ + if (accelerator >= 97 && accelerator <= 122) { + seq += accelerator - 32; // make a uppercase character out of a lowercase character + accelerator -= accelerator; + } + + /* fetch characters like F1, arrow keys or Page Up. Only one is allowed */ + if (accelerator != 0) { + for (Integer acc : accelerators.keySet()) { + if (accelerator == acc) { + accelerator -= acc; + seq += accelerators.get(acc); + } + } + } + + if (accelerator != 0) { // something went wrong here. Not every character could be fetched. + return; + } + getQAction().setShortcut(new QKeySequence(seq)); + + } + + /* + * private QKeySequence acceleratorToString(int accelerator) { int seq = 0; + * if ((accelerator & SWT.MOD1) != 0 || (accelerator & SWT.CTRL) != 0) { // + * on Windows systems SWT.MOD1 is the ctrl key accelerator -= SWT.MOD1; seq + * += Qt.Modifier.CTRL.value(); } if ((accelerator & SWT.MOD2) != 0 || + * (accelerator & SWT.SHIFT) != 0) { // on Windows systems SWT.MOD2 is the + * shift key accelerator -= SWT.MOD2; seq += Qt.Modifier.SHIFT.value(); } if + * ((accelerator & SWT.MOD3) != 0 || (accelerator & SWT.ALT) != 0) { + * accelerator -= SWT.MOD3; seq += Qt.Modifier.ALT.value(); } if + * (accelerator >= 65 && accelerator <= 90) { seq += accelerator; } else if + * (accelerator >= 97 && accelerator <= 122) { seq += accelerator - 32; // + * this takes care of lowercase characters. CTRL+m should be the same as + * CTRL+M } else if ((accelerator & SWT.ARROW_DOWN) != 0) { seq += + * Qt.Key.Key_Down.value(); } else if ((accelerator & SWT.ARROW_LEFT) != 0) + * { seq += Qt.Key.Key_Left.value(); } else if ((accelerator & + * SWT.ARROW_RIGHT) != 0) { seq += Qt.Key.Key_Right.value(); } else if + * ((accelerator & SWT.ARROW_UP) != 0) { seq += Qt.Key.Key_Up.value(); } + * else if ((accelerator & SWT.F1) != 0) { seq += Qt.Key.Key_F1.value(); } + * return new QKeySequence(seq); } + */ + /** + * Enables the receiver if the argument is <code>true</code>, and disables + * it otherwise. A disabled menu item is typically not selectable from the + * user interface and draws with an inactive or "grayed" look. + * + * @param enabled + * the new enabled state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setEnabled(boolean enabled) { + checkWidget(); + getQAction().setEnabled(enabled); + } + + /** + * Sets the image the receiver will display to the argument. + * <p> + * Note: This operation is a hint and is not supported on platforms that do + * not have this concept (for example, Windows NT). Furthermore, some + * platforms (such as GTK), cannot display both a check box and an image at + * the same time. Instead, they hide the image and display the check box. + * </p> + * + * @param image + * the image to display + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + @Override + public void setImage(Image image) { + checkWidget(); + if ((style & SWT.SEPARATOR) != 0) { + return; + } + super.setImage(image); + if (image != null) { + getQAction().setIcon(image.getQIcon()); + } else { + getQAction().setIcon((QIcon) null); + } + } + + /** + * Sets the receiver's pull down menu to the argument. Only + * <code>CASCADE</code> menu items can have a pull down menu. The sequence + * of key strokes, button presses and/or button releases that are used to + * request a pull down menu is platform specific. + * <p> + * Note: Disposing of a menu item that has a pull down menu will dispose of + * the menu. To avoid this behavior, set the menu to null before the menu + * item is disposed. + * </p> + * + * @param menu + * the new pull down menu + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_MENU_NOT_DROP_DOWN - if the menu is not a drop + * down menu</li> + * <li>ERROR_MENUITEM_NOT_CASCADE - if the menu item is not a + * <code>CASCADE</code></li> + * <li>ERROR_INVALID_ARGUMENT - if the menu has been disposed + * </li> + * <li>ERROR_INVALID_PARENT - if the menu is not in the same + * widget tree</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setMenu(Menu menu) { + checkWidget(); + + /* Check to make sure the new menu is valid */ + if ((style & SWT.CASCADE) == 0) { + error(SWT.ERROR_MENUITEM_NOT_CASCADE); + } + if (menu != null) { + if (menu.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if ((menu.style & SWT.DROP_DOWN) == 0) { + error(SWT.ERROR_MENU_NOT_DROP_DOWN); + } + if (menu.parent != parent.parent) { + error(SWT.ERROR_INVALID_PARENT); + } + } + setMenu(menu, false); + } + + void setMenu(Menu menu, boolean dispose) { + if ((style & SWT.CASCADE) == 0) { + error(SWT.ERROR_MENUITEM_NOT_CASCADE); + } + QMenu qMenu = null; + if (menu != null) { + if ((menu.style & SWT.DROP_DOWN) == 0) { + error(SWT.ERROR_MENU_NOT_DROP_DOWN); + } + if (menu.parent != parent.parent) { + error(SWT.ERROR_INVALID_PARENT); + } + qMenu = menu.getQMenu(); + } + Menu oldMenu = this.menu; + if (oldMenu == menu) { + return; + } + if (oldMenu != null) { + oldMenu.cascade = null; + } + this.menu = menu; + getQAction().setMenu(qMenu); + if (this.menu != null) { + this.menu.cascade = this; + } + } + + 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; + } + getQAction().setChecked(selected); + } + + /** + * 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 + */ + @Override + 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); + getQAction().setText(string); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/MessageBox.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/MessageBox.java new file mode 100644 index 0000000000..297dd3161f --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/MessageBox.java @@ -0,0 +1,312 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; + +/** + * Instances of this class are used to inform or warn the user. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>ICON_ERROR, ICON_INFORMATION, ICON_QUESTION, ICON_WARNING, ICON_WORKING</dd> + * <dd>OK, OK | CANCEL</dd> + * <dd>YES | NO, YES | NO | CANCEL</dd> + * <dd>RETRY | CANCEL</dd> + * <dd>ABORT | RETRY | IGNORE</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * Note: Only one of the styles ICON_ERROR, ICON_INFORMATION, ICON_QUESTION, + * ICON_WARNING and ICON_WORKING may be specified. + * </p> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> within the + * SWT implementation. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample, Dialog tab</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class MessageBox extends Dialog { + String message = ""; //$NON-NLS-1$ + + /** + * Constructs a new instance of this class given only its parent. + * + * @param parent + * a shell which will be the parent of the new instance + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + */ + public MessageBox(Shell parent) { + this(parent, SWT.OK | SWT.ICON_INFORMATION | SWT.APPLICATION_MODAL); + } + + /** + * Constructs a new instance of this class given its parent and a style + * value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * + * @param parent + * a shell which will be the parent of the new instance + * @param style + * the style of dialog to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> <li> + * ERROR_INVALID_SUBCLASS - if this class is not an allowed + * subclass</li> + * </ul> + */ + public MessageBox(Shell parent, int style) { + super(parent, checkStyle(parent, checkStyle(style))); + checkSubclass(); + } + + static int checkStyle(int style) { + int mask = SWT.YES | SWT.NO | SWT.OK | SWT.CANCEL | SWT.ABORT | SWT.RETRY | SWT.IGNORE; + int bits = style & mask; + if (bits == SWT.OK || bits == SWT.CANCEL || bits == (SWT.OK | SWT.CANCEL)) { + return style; + } + if (bits == SWT.YES || bits == SWT.NO || bits == (SWT.YES | SWT.NO) || bits == (SWT.YES | SWT.NO | SWT.CANCEL)) { + return style; + } + if (bits == (SWT.RETRY | SWT.CANCEL) || bits == (SWT.ABORT | SWT.RETRY | SWT.IGNORE)) { + return style; + } + style = style & ~mask | SWT.OK; + return style; + } + + /** + * Returns the dialog's message, or an empty string if it does not have one. + * The message is a description of the purpose for which the dialog was + * opened. This message will be visible in the dialog while it is open. + * + * @return the message + */ + public String getMessage() { + return message; + } + + /** + * Makes the dialog visible and brings it to the front of the display. + * + * @return the ID of the button that was selected to dismiss the message box + * (e.g. SWT.OK, SWT.CANCEL, etc.) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the dialog has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the dialog</li> + * </ul> + */ + public int open() { + + /* 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 ((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 | OS.MB_RIGHT; + // } + // if ((style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT)) == 0) { + // if (parent != null && (parent.style & SWT.MIRRORED) != 0) { + // bits |= OS.MB_RTLREADING | OS.MB_RIGHT; + // } + // } + // + // /* + // * 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; + // /* Force a system modal message box to the front */ + // bits |= OS.MB_TOPMOST; + // } + // + // /* + // * 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 to set + // * the parent HWND anyway and not rely on MB_MODAL to work by making the + // * parent be temporarily modal. + // */ + // int /* long */hwndOwner = 0; //parent != null ? parent.handle : 0; + // Dialog oldModal = null; + // Display display = null; + // if ((bits & OS.MB_TASKMODAL) != 0) { + // display = parent.getDisplay(); + // oldModal = display.getModalDialog(); + // display.setModalDialog(this); + // } + // + // /* 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); + // + // /* Clear the temporarily dialog modal parent */ + // if ((bits & OS.MB_TASKMODAL) != 0) { + // display.setModalDialog(oldModal); + // } + // + // /* + // * 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 + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + */ + public void setMessage(String string) { + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + message = string; + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ProgressBar.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ProgressBar.java new file mode 100644 index 0000000000..dc80139bfa --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ProgressBar.java @@ -0,0 +1,318 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.gui.QProgressBar; +import com.trolltech.qt.gui.QWidget; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Point; + +/** + * Instances of the receiver represent an unselectable user interface object + * that is used to display progress, typically in the form of a bar. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>SMOOTH, HORIZONTAL, VERTICAL, INDETERMINATE</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified. + * </p> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> within the + * SWT implementation. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#progressbar">ProgressBar + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class ProgressBar extends Control { + static final int DELAY = 100; + int foreground = -1, background = -1; + private int timerID = -1; + + /** + * Constructs a new instance of this class given its parent and a style + * value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a composite control which will be the parent of the new + * instance (cannot be null) + * @param style + * the style of control to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#SMOOTH + * @see SWT#HORIZONTAL + * @see SWT#VERTICAL + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public ProgressBar(Composite parent, int style) { + super(parent, checkStyle(style)); + } + + @Override + protected QWidget createQWidget(int style) { + QProgressBar progressBar = new QProgressBar(); + return progressBar; + } + + @Override + protected void setupQWidget() { + if ((style & SWT.INDETERMINATE) != 0) { + getQProgressBar().setRange(0, 0); + // Funny: this avoids a JVM crash: EXCEPTION_INT_DIVIDE_BY_ZERO (0xc0000094) + // http://eclipse.compeople.eu/wiki/index.php/Compeople:SWTQtImplementierungsdetails#DIVISION_BY_ZERO + getQProgressBar().setTextVisible(false); + } + // this causes a lot of events, commented for debugging + //startTimer(getQProgressBar()); + super.setupQWidget(); + } + + private QProgressBar getQProgressBar() { + return (QProgressBar) getQWidget(); + } + + static int checkStyle(int style) { + style |= SWT.NO_FOCUS; + return checkBits(style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0); + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + checkWidget(); + QSize size = getQProgressBar().sizeHint(); + return new Point(size.width(), size.height()); + } + + /** + * 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 getQProgressBar().maximum(); + } + + /** + * Returns the minimum value which the receiver will allow. + * + * @return the minimum + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getMinimum() { + checkWidget(); + return getQProgressBar().minimum(); + } + + /** + * Returns the single 'selection' that is the receiver's position. + * + * @return the selection + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getSelection() { + checkWidget(); + return getQProgressBar().value(); + } + + /** + * Returns the state of the receiver. The value will be one of: + * <ul> + * <li>{@link SWT#NORMAL}</li> + * <li>{@link SWT#ERROR}</li> + * <li>{@link SWT#PAUSED}</li> + * </ul> + * + * @return the state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public int getState() { + checkWidget(); + return SWT.NORMAL; + } + + @Override + void releaseWidget() { + stopTimer(); + super.releaseWidget(); + } + + void startTimer(QProgressBar progressBar) { + stopTimer(); + // TODO dynamic interval for startTimer + timerID = progressBar.startTimer(DELAY); + } + + void stopTimer() { + if (timerID != -1) { + getQProgressBar().killTimer(timerID); + } + } + + /** + * Sets the maximum value that the receiver will allow. This new value will + * be ignored if it is not greater than the receiver's current minimum + * value. If the new maximum is applied then the receiver's selection value + * will be adjusted if necessary to fall within its new range. + * + * @param value + * the new maximum, which must be greater than the current + * minimum + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + + public void setMaximum(int value) { + checkWidget(); + getQProgressBar().setMaximum(value); + } + + /** + * Sets the minimum value that the receiver will allow. This new value will + * be ignored if it is negative or is not less than the receiver's current + * maximum value. If the new minimum is applied then the receiver's + * selection value will be adjusted if necessary to fall within its new + * range. + * + * @param value + * the new minimum, which must be nonnegative and less than the + * current maximum + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setMinimum(int value) { + checkWidget(); + getQProgressBar().setMinimum(value); + } + + /** + * Sets the single 'selection' that is the receiver's position to the + * argument which must be greater than or equal to zero. + * + * @param value + * the new selection (must be zero or greater) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setSelection(int value) { + checkWidget(); + getQProgressBar().setValue(value); + } + + /** + * Sets the state of the receiver. The state must be one of these values: + * <ul> + * <li>{@link SWT#NORMAL}</li> + * <li>{@link SWT#ERROR}</li> + * <li>{@link SWT#PAUSED}</li> + * </ul> + * + * @param state + * the new state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public void setState(int state) { + checkWidget(); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Sash.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Sash.java new file mode 100644 index 0000000000..399d863b45 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Sash.java @@ -0,0 +1,387 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.QObject; +import com.trolltech.qt.core.QPoint; +import com.trolltech.qt.core.QRect; +import com.trolltech.qt.core.Qt.CursorShape; +import com.trolltech.qt.core.Qt.MouseButton; +import com.trolltech.qt.gui.QCursor; +import com.trolltech.qt.gui.QFrame; +import com.trolltech.qt.gui.QMouseEvent; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QFrame.Shadow; +import com.trolltech.qt.gui.QFrame.Shape; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Point; + +/** + * 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.sw + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>HORIZONTAL, VERTICAL, SMOOTH</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection</dd> + * </dl> + * <p> + * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified. + * </p> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> within the + * SWT implementation. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#sash">Sash snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class Sash extends Control { + private boolean dragging; + private int startX, startY, lastX, lastY; + + /** + * 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)); + } + + @Override + protected QWidget createQWidget(int style) { + state |= THEME_BACKGROUND; + return new QFrame(); + } + + protected QFrame getQFrame() { + return (QFrame) getQWidget(); + } + + @Override + protected void checkAndUpdateBorder() { + if ((style & SWT.BORDER) != 0) { + getQFrame().setFrameShape(Shape.Panel); + getQFrame().setFrameShadow(Shadow.Sunken); + } else { + getQFrame().setFrameShape(Shape.NoFrame); + } + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the control is selected by the user, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * When <code>widgetSelected</code> is called, the x, y, width, and height + * fields of the event object are valid. If the receiver is being dragged, + * the event object detail field contains the value <code>SWT.DRAG</code>. + * <code>widgetDefaultSelected</code> is not called. + * </p> + * + * @param listener + * the listener which should be notified when the control is + * selected by the user + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + static int checkStyle(int style) { + return checkBits(style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0); + } + + @Override + 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); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is selected by the user. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + @Override + public boolean qtMouseMoveEvent(QObject source, QMouseEvent mouseEvent) { + if (source == getQWidget()) { + return handleMouseMove(mouseEvent); + } + return super.qtMouseMoveEvent(source, mouseEvent); + } + + @Override + public boolean qtMouseButtonPressEvent(QObject source, QMouseEvent mouseEvent) { + if (super.qtMouseButtonPressEvent(source, mouseEvent)) { + return true; // cancel; + } + return handleMousePress(mouseEvent); + } + + @Override + public boolean qtMouseButtonReleaseEvent(QObject source, QMouseEvent mouseEvent) { + if (super.qtMouseButtonReleaseEvent(source, mouseEvent)) { + return true; // cancel + } + return handleMouseRelease(mouseEvent); + } + + private boolean handleMousePress(QMouseEvent mouseEvent) { + if (!isLeftMouseButton(mouseEvent)) { + return false; + } + QPoint pt = mouseEvent.globalPos(); + QRect rect = getQWidget().frameGeometry(); + startX = pt.x() - rect.left(); + startY = pt.y() - rect.top(); + lastX = rect.left(); + lastY = rect.top(); + int width = rect.width(); + int height = rect.height(); + + Event event = new Event(); + event.x = lastX; + event.y = lastY; + event.width = width; + event.height = height; + if ((style & SWT.SMOOTH) == 0) { + event.detail = SWT.DRAG; + } + sendEvent(SWT.Selection, event); + if (isDisposed()) { + return true; + } + + /* Draw the banding rectangle */ + if (event.doit) { + dragging = true; + lastX = event.x; + lastY = event.y; + menuShell().bringToTop(); + if (isDisposed()) { + return true; + } + if ((style & SWT.SMOOTH) != 0) { + setBounds(event.x, event.y, width, height, true, true); + // widget could be disposed at this point + } + } + return false; + } + + private boolean isLeftMouseButton(QMouseEvent mouseEvent) { + return MouseButton.LeftButton.equals(mouseEvent.button()) || mouseEvent.buttons().isSet(MouseButton.LeftButton); + } + + private boolean handleMouseRelease(QMouseEvent mouseEvent) { + if (!(dragging && isLeftMouseButton(mouseEvent))) { + return false; + } + + dragging = false; + QRect rect = getQWidget().frameGeometry(); + int width = rect.width(); + int height = rect.height(); + + Event event = new Event(); + event.x = lastX; + event.y = lastY; + event.width = width; + event.height = height; + sendEvent(SWT.Selection, event); + if (isDisposed()) { + return true; + } + if (event.doit) { + if ((style & SWT.SMOOTH) != 0) { + setBounds(event.x, event.y, width, height, true, true); + // widget could be disposed at this point + } + } + return false; + } + + private boolean handleMouseMove(QMouseEvent mouseEvent) { + if (!(dragging && isLeftMouseButton(mouseEvent))) { + return false; + } + + QPoint pt = mouseEvent.globalPos(); + QRect rect = getQWidget().frameGeometry(); + int width = rect.width(); + int height = rect.height(); + QRect clientRect = getQWidget().parentWidget().frameGeometry(); + + int newX = lastX, newY = lastY; + if ((style & SWT.VERTICAL) != 0) { + int clientWidth = clientRect.width(); + newX = Math.min(Math.max(0, pt.x() - startX), clientWidth - width); + } else { + int clientHeight = clientRect.height(); + newY = Math.min(Math.max(0, pt.y() - startY), clientHeight - height); + } + if (newX == lastX && newY == lastY) { + return false; + } + + /* 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; + if ((style & SWT.SMOOTH) == 0) { + event.detail = SWT.DRAG; + } + sendEvent(SWT.Selection, event); + if (isDisposed()) { + return true; + } + + if (event.doit) { + lastX = event.x; + lastY = event.y; + } + if ((style & SWT.SMOOTH) != 0) { + setBounds(lastX, lastY, width, height, true, true); + // widget could be disposed at this point + } + return false; + } + + @Override + public boolean qtMouseEnterEvent(Object source) { + if (source == getQWidget()) { + if ((style & SWT.HORIZONTAL) != 0) { + getQWidget().setCursor(new QCursor(CursorShape.SizeVerCursor)); + } else { + getQWidget().setCursor(new QCursor(CursorShape.SizeHorCursor)); + } + } + return super.qtMouseEnterEvent(source); + } + + @Override + public boolean qtMouseLeaveEvent(Object source) { + if (source == getQWidget()) { + getQWidget().setCursor(new QCursor(CursorShape.ArrowCursor)); + } + return super.qtMouseLeaveEvent(source); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Scale.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Scale.java new file mode 100644 index 0000000000..b7ee6cb7c0 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Scale.java @@ -0,0 +1,494 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.Qt.Orientation; +import com.trolltech.qt.gui.QAbstractSlider; +import com.trolltech.qt.gui.QSlider; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QSlider.TickPosition; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Point; + +/** + * Instances of the receiver represent a selectable user interface object that + * present a range of continuous numeric values. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>HORIZONTAL, VERTICAL</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection</dd> + * </dl> + * <p> + * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified. + * </p> + * <p> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> within the + * SWT implementation. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#scale">Scale snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class Scale extends Control { + + /** + * 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)); + } + + @Override + protected QWidget createQWidget(int style) { + final Orientation orientation = (style & SWT.HORIZONTAL) != 0 ? Orientation.Horizontal : Orientation.Vertical; + return new QSlider(orientation); + } + + @Override + protected void setupQWidget() { + super.setupQWidget(); + setMinimum(0); + setMaximum(100); + setIncrement(1); + setPageIncrement(10); + getQSlider().setTickPosition(TickPosition.TicksBothSides); + } + + QSlider getQSlider() { + return (QSlider) getQWidget(); + } + + @Override + protected void connectSignals() { + getQSlider().actionTriggered.connect(this, "actionTriggered(int)"); //$NON-NLS-1$ + getQSlider().rangeChanged.connect(this, "rangeChanged(int,int)"); //$NON-NLS-1$ + getQSlider().sliderMoved.connect(this, "sliderMoved(int)"); //$NON-NLS-1$ + getQSlider().sliderPressed.connect(this, "sliderPressed()"); //$NON-NLS-1$ + getQSlider().sliderReleased.connect(this, "sliderReleased()"); //$NON-NLS-1$ + getQSlider().valueChanged.connect(this, "valueChanged(int)"); //$NON-NLS-1$ + } + + protected void actionTriggered(int action) { + System.out.println("actionTriggered :" + action + " " + getQSlider().value()); //$NON-NLS-1$//$NON-NLS-2$ + Event event = new Event(); + if (action == QAbstractSlider.SliderAction.SliderToMinimum.value()) { + event.detail = SWT.HOME; + } else if (action == QAbstractSlider.SliderAction.SliderToMaximum.value()) { + event.detail = SWT.END; + } else if (action == QAbstractSlider.SliderAction.SliderSingleStepAdd.value()) { + event.detail = SWT.ARROW_DOWN; + } else if (action == QAbstractSlider.SliderAction.SliderSingleStepSub.value()) { + event.detail = SWT.ARROW_UP; + } else if (action == QAbstractSlider.SliderAction.SliderPageStepAdd.value()) { + event.detail = SWT.PAGE_UP; + } else if (action == QAbstractSlider.SliderAction.SliderPageStepSub.value()) { + event.detail = SWT.PAGE_DOWN; + } else if (action == QAbstractSlider.SliderAction.SliderMove.value()) { + event.detail = SWT.DRAG; + } else { + return; + } + // see actionTrigger signal + getQSlider().setValue(getQSlider().sliderPosition()); + sendEvent(SWT.Selection, event); + } + + // TODO: implement the events + protected void rangeChanged(int min, int max) { + System.out.println("rangeChanged :" + min + ", " + max); //$NON-NLS-1$//$NON-NLS-2$ + } + + protected void sliderMoved(int pos) { + System.out.println("sliderMoved :" + pos); //$NON-NLS-1$ + } + + protected void sliderPressed() { + System.out.println("sliderPressed"); //$NON-NLS-1$ + } + + protected void sliderReleased() { + System.out.println("sliderReleased"); //$NON-NLS-1$ + Event event = new Event(); + event.detail = SWT.NONE; + sendEvent(SWT.Selection, event); + } + + protected void valueChanged(int value) { + System.out.println("valueChanged :" + value); //$NON-NLS-1$ + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the user changes the receiver's value, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * <code>widgetSelected</code> is called when the user changes the + * receiver's value. <code>widgetDefaultSelected</code> is not called. + * </p> + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + static int checkStyle(int style) { + return checkBits(style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0); + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + checkWidget(); + int border = getBorderWidth(); + int width = border * 2; + int height = border * 2; + // default size: this is just the two arrows + thumb + Point defaultSize = super.computeSize(wHint, hHint, changed); + if ((style & SWT.HORIZONTAL) != 0) { + width += defaultSize.y * 6; + height += defaultSize.y; + } else { + width += defaultSize.x; + height += defaultSize.x * 6; + } + if (wHint != SWT.DEFAULT) { + width = wHint + border * 2; + } + if (hHint != SWT.DEFAULT) { + height = hHint + border * 2; + } + return new Point(width, height); + } + + // TODO What should happen here? + // int defaultForeground() { + // return display.getSystemColor(SWT.COLOR_LIST_FOREGROUND); + // } + + /** + * 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 getQSlider().singleStep(); + } + + /** + * 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 getQSlider().maximum(); + } + + /** + * Returns the minimum value which the receiver will allow. + * + * @return the minimum + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getMinimum() { + checkWidget(); + return getQSlider().minimum(); + } + + /** + * Returns the amount that the receiver's value will be modified by when the + * page increment/decrement areas are selected. + * + * @return the page increment + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getPageIncrement() { + checkWidget(); + return getQSlider().pageStep(); + } + + /** + * Returns the 'selection', which is the receiver's position. + * + * @return the selection + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getSelection() { + checkWidget(); + return getQSlider().value(); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the user changes the receiver's value. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + /** + * Sets the amount that the receiver's value will be modified by when the + * up/down (or right/left) arrows are pressed to the argument, which must be + * at least one. + * + * @param increment + * the new increment (must be greater than zero) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setIncrement(int increment) { + checkWidget(); + if (increment < 1) { + return; + } + if (increment > getMaximum() - getMinimum()) { + return; + } + getQSlider().setSingleStep(increment); + } + + /** + * Sets the maximum value that the receiver will allow. This new value will + * be ignored if it is not greater than the receiver's current minimum + * value. If the new maximum is applied then the receiver's selection value + * will be adjusted if necessary to fall within its new range. + * + * @param value + * the new maximum, which must be greater than the current + * minimum + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setMaximum(int value) { + checkWidget(); + if (0 <= getMinimum() && getMinimum() < value) { + getQSlider().setMaximum(value); + } + } + + /** + * Sets the minimum value that the receiver will allow. This new value will + * be ignored if it is negative or is not less than the receiver's current + * maximum value. If the new minimum is applied then the receiver's + * selection value will be adjusted if necessary to fall within its new + * range. + * + * @param value + * the new minimum, which must be nonnegative and less than the + * current maximum + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setMinimum(int value) { + checkWidget(); + if (0 <= value && value < getMaximum()) { + getQSlider().setMinimum(value); + } + } + + /** + * Sets the amount that the receiver's value will be modified by when the + * page increment/decrement areas are selected to the argument, which must + * be at least one. + * + * @param pageIncrement + * the page increment (must be greater than zero) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setPageIncrement(int pageIncrement) { + checkWidget(); + if (pageIncrement < 1) { + return; + } + if (pageIncrement > getMaximum() - getMinimum()) { + return; + } + getQSlider().setPageStep(pageIncrement); + getQSlider().setTickInterval(pageIncrement); + } + + /** + * Sets the 'selection', which is the receiver's value, to the argument + * which must be greater than or equal to zero. + * + * @param value + * the new selection (must be zero or greater) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setSelection(int value) { + checkWidget(); + getQSlider().setValue(value); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ScrollBar.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ScrollBar.java new file mode 100644 index 0000000000..1b839a5fab --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ScrollBar.java @@ -0,0 +1,876 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.gui.QScrollBar; +import com.trolltech.qt.gui.QAbstractSlider.SliderAction; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.internal.qt.QtSWTConverter; + +/** + * Instances of this class are selectable user interface objects that represent + * a range of positive, numeric values. + * <p> + * At any given moment, a given scroll bar will have a single 'selection' that + * is considered to be its value, which is constrained to be within the range of + * values the scroll bar represents (that is, between its <em>minimum</em> and + * <em>maximum</em> values). + * </p> + * <p> + * Typically, scroll bars will be made up of five areas: + * <ol> + * <li>an arrow button for decrementing the value</li> + * <li>a page decrement area for decrementing the value by a larger amount</li> + * <li>a <em>thumb</em> for modifying the value by mouse dragging</li> + * <li>a page increment area for incrementing the value by a larger amount</li> + * <li>an arrow button for incrementing the value</li> + * </ol> + * Based on their style, scroll bars are either <code>HORIZONTAL</code> (which + * have a left facing button for decrementing the value and a right facing + * button for incrementing it) or <code>VERTICAL</code> (which have an upward + * facing button for decrementing the value and a downward facing buttons for + * incrementing it). + * </p> + * <p> + * On some platforms, the size of the scroll bar's thumb can be varied relative + * to the magnitude of the range of values it represents (that is, relative to + * the difference between its maximum and minimum values). Typically, this is + * used to indicate some proportional value such as the ratio of the visible + * area of a document to the total amount of space that it would take to display + * it. SWT supports setting the thumb size even if the underlying platform does + * not, but in this case the appearance of the scroll bar will not change. + * </p> + * <p> + * Scroll bars are created by specifying either <code>H_SCROLL</code>, + * <code>V_SCROLL</code> or both when creating a <code>Scrollable</code>. They + * are accessed from the <code>Scrollable</code> using + * <code>getHorizontalBar</code> and <code>getVerticalBar</code>. + * </p> + * <p> + * Note: Scroll bars are not Controls. On some platforms, scroll bars that + * appear as part of some standard controls such as a text or list have no + * operating system resources and are not children of the control. For this + * reason, scroll bars are treated specially. To create a control that looks + * like a scroll bar but has operating system resources, use <code>Slider</code> + * . + * </p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>HORIZONTAL, VERTICAL</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection</dd> + * </dl> + * <p> + * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see Slider + * @see Scrollable + * @see Scrollable#getHorizontalBar + * @see Scrollable#getVerticalBar + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class ScrollBar extends Widget { + private Scrollable parent; + private boolean visible = true; + private boolean enabled = true; + + /** + * 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(style); + connectSignals(); + } + + static int checkStyle(int style) { + return checkBits(style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0); + } + + private void createWidget(int style) { + if (!parent.isQScrollArea()) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + + QScrollBar scrollBar = null; + if ((style & SWT.HORIZONTAL) != 0) { + scrollBar = parent.getQScrollArea().horizontalScrollBar(); + } else { + scrollBar = parent.getQScrollArea().verticalScrollBar(); + } + if (scrollBar == null) { + SWT.error(SWT.ERROR_UNSPECIFIED); + } + setQWidget(scrollBar); + scrollBar.setMinimum(0); + scrollBar.setSliderPosition(0); + scrollBar.setTracking(false); + } + + private void connectSignals() { + QScrollBar sb = getQScrollBar(); + sb.sliderMoved.connect(this, "dragging()"); //$NON-NLS-1$ + sb.sliderReleased.connect(this, "dragEnd()"); //$NON-NLS-1$ + sb.actionTriggered.connect(this, "actionTriggered(int)"); //$NON-NLS-1$ + } + + void dragging() { + postSliderEvent(SWT.DRAG); + } + + void dragEnd() { + postSliderEvent(SWT.NONE); + } + + void actionTriggered(int code) { + SliderAction action = SliderAction.resolve(code); + switch (action) { + case SliderSingleStepSub: // button up + postSliderEvent(SWT.ARROW_UP); + break; + case SliderSingleStepAdd: // button down + postSliderEvent(SWT.ARROW_DOWN); + break; + case SliderPageStepSub: // page up + postSliderEvent(SWT.PAGE_UP); + break; + case SliderPageStepAdd: // page down + postSliderEvent(SWT.PAGE_DOWN); + break; + case SliderToMinimum: // at start + postSliderEvent(SWT.HOME); + break; + case SliderToMaximum: // at end + postSliderEvent(SWT.END); + break; + case SliderMove: // at end + postSliderEvent(SWT.DRAG); + break; + default: + System.err.println("unknown action: " + action); //$NON-NLS-1$ + } + } + + QScrollBar getQScrollBar() { + return (QScrollBar) getQWidget(); + } + + private void postSliderEvent(int subType) { + Event event = new Event(); + event.detail = subType; + postEvent(SWT.Selection, event); + } + + @Override + void releaseQWidget() { + super.releaseQWidget(); + parent = null; + } + + @Override + void releaseParent() { + super.releaseParent(); + parent.releaseBar(this); + } + + @Override + void destroyWidget() { + parent.destroyScrollBar(style); + } + + /** + * Returns the receiver's parent, which must be a Scrollable. + * + * @return the receiver's parent + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Scrollable getParent() { + checkWidget(); + return parent; + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the user changes the receiver's value, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * When <code>widgetSelected</code> is called, the event object detail field + * contains one of the following values: <code>SWT.NONE</code> - for the end + * of a drag. <code>SWT.DRAG</code>. <code>SWT.HOME</code>. + * <code>SWT.END</code>. <code>SWT.ARROW_DOWN</code>. + * <code>SWT.ARROW_UP</code>. <code>SWT.PAGE_DOWN</code>. + * <code>SWT.PAGE_UP</code>. <code>widgetDefaultSelected</code> is not + * called. + * </p> + * + * @param listener + * the listener which should be notified when the user changes + * the receiver's value + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the user changes the receiver's value. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + /** + * 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 getQScrollBar().singleStep(); + } + + /** + * 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; + } + getQScrollBar().setSingleStep(value); + } + + /** + * 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 getQScrollBar().maximum(); // + getQScrollBar().pageStep(); + } + + /** + * Sets the maximum. If this value is negative or less than or equal to the + * minimum, the value is ignored. If necessary, first the thumb and then the + * selection are adjusted to fit within the new range. + * + * @param value + * the new maximum + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setMaximum(int value) { + checkWidget(); + if (value < 0) { + return; + } + QScrollBar scrollBar = getQScrollBar(); + int min = scrollBar.minimum(); + if (value <= min) { + return; + } + + // int maxValue = value - scrollBar.pageStep(); + // if (maxValue < min) { + // scrollBar.setPageStep(value - min); + // maxValue = min; + // } + // + // if (scrollBar.value() > maxValue) { + // scrollBar.setValue(maxValue); + // } + scrollBar.setMaximum(value); + } + + /** + * 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 getQScrollBar().minimum(); + } + + /** + * Sets the minimum value. If this value is negative or greater than or + * equal to the maximum, the value is ignored. If necessary, first the thumb + * and then the selection are adjusted to fit within the new range. + * + * @param value + * the new minimum + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setMinimum(int value) { + checkWidget(); + if (value < 0) { + return; + } + QScrollBar scrollBar = getQScrollBar(); + int max = scrollBar.maximum(); + if (value >= max) { + return; + } + // + // if (max + pageStep - value < pageStep) { + // scrollBar.setPageStep(max + pageStep - value); + // scrollBar.setMaximum(value); + // } + // + // if (scrollBar.value() < value) { + // scrollBar.setValue(value); + // } + scrollBar.setMinimum(value); + } + + /** + * 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 getQScrollBar().pageStep(); + } + + /** + * Sets the amount that the receiver's value will be modified by when the + * page increment/decrement areas are selected to the argument, which must + * be at least one. + * + * @param value + * the page increment (must be greater than zero) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setPageIncrement(int value) { + checkWidget(); + if (value < 1) { + return; + } + getQScrollBar().setPageStep(value); + } + + /** + * Returns the single 'selection' that is the receiver's value. + * + * @return the selection + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getSelection() { + checkWidget(); + return getQScrollBar().sliderPosition(); + } + + /** + * Sets the single <em>selection</em> that is the receiver's value to the + * argument which must be greater than or equal to zero. + * + * @param selection + * the new selection (must be zero or greater) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setSelection(int selection) { + checkWidget(); + int min = getQScrollBar().minimum(); + if (selection < min) { + selection = min; + } else { + int max = getQScrollBar().maximum(); + if (selection > max) { + selection = max; + } + } + int value = getQScrollBar().value(); + if (value != selection) { + getQScrollBar().setSliderPosition(selection); + } + //System.out.println(this); + } + + /** + * 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(); + if (!isVisible()) { + parent.updateQLayouts(); + } + return QtSWTConverter.convert(getQWidget().size()); + } + + /** + * Returns the size of the receiver's thumb relative to the difference + * between its maximum and minimum values. + * + * @return the thumb value + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ScrollBar + */ + public int getThumb() { + checkWidget(); + return getQScrollBar().pageStep(); + } + + /** + * Sets the size of the receiver's thumb relative to the difference between + * its maximum and minimum values. This new value will be ignored if it is + * less than one, and will be clamped if it exceeds the receiver's current + * range. + * + * @param value + * the new thumb value, which must be at least one and not larger + * than the size of the current range + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setThumb(int value) { + checkWidget(); + if (value < 1) { + return; + } + if (value < 1) { + return; + } + int pageStep = getQScrollBar().pageStep(); + if (value == pageStep) { + return; + } + + int qMax = getQScrollBar().maximum(); + int range = qMax + pageStep - getQScrollBar().minimum(); + if (value > range) { + value = range; + } + int newQMaximum = qMax - (value - pageStep); + if (getQScrollBar().value() > newQMaximum) { + getQScrollBar().setValue(newQMaximum); + } + + getQScrollBar().setPageStep(value); + + getQScrollBar().setMaximum(newQMaximum); + } + + /** + * Sets the receiver's selection, minimum value, maximum value, thumb, + * increment and page increment all at once. + * <p> + * Note: This is similar to setting the values individually using the + * appropriate methods, but may be implemented in a more efficient fashion + * on some platforms. + * </p> + * + * @param selection + * the new selection value + * @param minimum + * the new minimum value + * @param maximum + * the new maximum value + * @param thumb + * the new thumb value + * @param increment + * the new increment value + * @param pageIncrement + * the new pageIncrement value + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setValues(int selection, int minimum, int maximum, int thumb, int increment, int pageIncrement) { + checkWidget(); + setSelection(selection); + setMinimum(minimum); + setMaximum(maximum); + setThumb(thumb); + setIncrement(increment); + setPageIncrement(pageIncrement); + } + + /** + * 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 this.visible; + } + + /** + * 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 getQWidget().isVisible() && parent.isVisible(); + } + + /** + * 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 == getVisible()) { + return; + } + this.visible = visible; + getQWidget().setVisible(visible); + } + + /** + * 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 enabled; + } + + /** + * 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 getQWidget().isEnabled() && parent.isEnabled(); + } + + /** + * 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.enabled = enabled; + getQWidget().setEnabled(enabled); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("ScrollBar{"); //$NON-NLS-1$ + sb.append("orient: "); //$NON-NLS-1$ + sb.append(((style & SWT.HORIZONTAL) != 0 ? "HORI" : "VERT")); //$NON-NLS-1$ //$NON-NLS-2$ + sb.append(", selection: "); //$NON-NLS-1$ + sb.append(getSelection()); + sb.append(", minimum: "); //$NON-NLS-1$ + sb.append(getMinimum()); + sb.append(", maximum: "); //$NON-NLS-1$ + sb.append(getMaximum()); + sb.append(", thumb: "); //$NON-NLS-1$ + sb.append(getThumb()); + sb.append(", increment: "); //$NON-NLS-1$ + sb.append(getIncrement()); + sb.append(", pageIncrement: "); //$NON-NLS-1$ + sb.append(getPageIncrement()); + sb.append("}"); //$NON-NLS-1$ + return sb.toString(); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Scrollable.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Scrollable.java new file mode 100644 index 0000000000..a9b7b8738a --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Scrollable.java @@ -0,0 +1,430 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.core.Qt.FocusPolicy; +import com.trolltech.qt.core.Qt.ScrollBarPolicy; +import com.trolltech.qt.gui.QAbstractScrollArea; +import com.trolltech.qt.gui.QLayout; +import com.trolltech.qt.gui.QScrollArea; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QFrame.Shape; +import com.trolltech.qt.gui.QSizePolicy.Policy; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.internal.qt.QtSWTConverter; +import org.eclipse.swt.internal.qt.StylableScrollArea; + +/** + * This class is the abstract superclass of all classes which represent controls + * that have standard scroll bars. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>H_SCROLL, V_SCROLL</dd> + * <dt><b>Events:</b> + * <dd>(none)</dd> + * </dl> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> within the + * SWT implementation. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public abstract class Scrollable extends Control { + private ScrollBar horizontalBar; + private ScrollBar verticalBar; + private QWidget masterWidget; + private QWidget contentWidget; + + /** + * 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); + createScrollBars(style); + } + + @Override + QWidget createQWidget(int style) { + QScrollArea scrollArea = new StylableScrollArea(); + scrollArea.setFrameShape(Shape.NoFrame); + scrollArea.setFocusPolicy(FocusPolicy.TabFocus); + scrollArea.setWidgetResizable(!isScrollingEnabled()); + setQMasterWidget(scrollArea); + + contentWidget = new QWidget(); + contentWidget.setSizePolicy(Policy.MinimumExpanding, Policy.MinimumExpanding); + contentWidget.setProperty("widgetType", "scrollareaContent"); //$NON-NLS-1$//$NON-NLS-2$ + contentWidget.setContentsMargins(0, 0, 0, 0); + contentWidget.resize(0, 0); + + scrollArea.setWidget(contentWidget); + scrollArea.resize(0, 0); + + return contentWidget; + } + + @Override + boolean isQScrollArea() { + return getQMasterWidget() instanceof QAbstractScrollArea; + } + + protected void setQMasterWidget(QWidget masterWidget) { + this.masterWidget = masterWidget; + } + + @Override + protected QWidget getQMasterWidget() { + if (masterWidget != null) { + return masterWidget; + } + return super.getQMasterWidget(); + } + + @Override + protected void updateFocusPolicy() { + super.updateFocusPolicy(); + if ((style & SWT.NO_FOCUS) != 0) { + if (isQScrollArea()) { + getQMasterWidget().setFocusPolicy(FocusPolicy.NoFocus); + } + } + } + + QAbstractScrollArea getQScrollArea() { + return (QAbstractScrollArea) getQMasterWidget(); + } + + private StylableScrollArea getStylableScrollArea() { + return (StylableScrollArea) getQMasterWidget(); + } + + private void createScrollBars(int style) { + if (isQScrollArea()) { + if ((style & SWT.H_SCROLL) != 0) { + setHBarPolicy(true); + if (horizontalBar == null) { + horizontalBar = createScrollBar(SWT.HORIZONTAL); + } + } else { + setHBarPolicy(false); + } + + if ((style & SWT.V_SCROLL) != 0) { + setVBarPolicy(true); + if (verticalBar == null) { + verticalBar = createScrollBar(SWT.VERTICAL); + } + } else { + setVBarPolicy(false); + } + } + } + + protected boolean isScrollingEnabled() { + return (style & SWT.V_SCROLL) != 0 || (style & SWT.H_SCROLL) != 0; + } + + protected void setHBarPolicy(boolean enableScrollbar) { + getQScrollArea().setHorizontalScrollBarPolicy( + enableScrollbar ? ScrollBarPolicy.ScrollBarAsNeeded : ScrollBarPolicy.ScrollBarAlwaysOff); + } + + protected void setVBarPolicy(boolean enableScrollbar) { + getQScrollArea().setVerticalScrollBarPolicy( + enableScrollbar ? ScrollBarPolicy.ScrollBarAsNeeded : ScrollBarPolicy.ScrollBarAlwaysOff); + } + + void destroyScrollBar(int type) { + if ((type & SWT.HORIZONTAL) != 0) { + style &= ~SWT.H_SCROLL; + horizontalBar.dispose(); + horizontalBar = null; + } + if ((type & SWT.VERTICAL) != 0) { + style &= ~SWT.V_SCROLL; + verticalBar.dispose(); + verticalBar = null; + } + } + + @Override + protected void setBounds(int x, int y, int width, int height, boolean move, boolean resize) { + super.setBounds(x, y, width, height, move, resize); + if (resize && contentWidget != null && isScrollingEnabled()) { // + Point prefSize = computeSize(SWT.DEFAULT, SWT.DEFAULT); + int newWidth = Math.max(width - getVerticalBarWidth(), prefSize.x); + int newHeight = Math.max(height - getHorizontalBarHeight(), prefSize.y); + QSize sizeHint = contentWidget.sizeHint(); + if (sizeHint.isValid()) { + newWidth = Math.max(newWidth, sizeHint.width()); + newHeight = Math.max(newHeight, sizeHint.height()); + } + contentWidget.resize(newWidth, newHeight); + } + } + + @Override + public Object getData(String key) { + checkWidget(); + if (key == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + + if ("__Qt_gradientStart".equals(key)) { //$NON-NLS-1$ + return Color.qt_new(display, getStylableScrollArea().getGradientStart()); + } else if ("__Qt_gradientEnd".equals(key)) { //$NON-NLS-1$ + return Color.qt_new(display, getStylableScrollArea().getGradientEnd()); + } else if ("__Qt_text".equals(key)) { //$NON-NLS-1$ + return Color.qt_new(display, getStylableScrollArea().getText()); + } else if ("__Qt_border".equals(key)) { //$NON-NLS-1$ + return Color.qt_new(display, getStylableScrollArea().getBorder()); + } + + return super.getData(key); + } + + /** + * Given a desired <em>client area</em> for the receiver (as described by + * the arguments), returns the bounding rectangle which would be required to + * produce that client area. + * <p> + * In other words, it returns a rectangle such that, if the receiver's + * bounds were set to that rectangle, the area of the receiver which is + * capable of displaying data (that is, not covered by the "trimmings") + * would be the rectangle described by the arguments (relative to the + * receiver's parent). + * </p> + * + * @param x + * the desired x coordinate of the client area + * @param y + * the desired y coordinate of the client area + * @param width + * the desired width of the client area + * @param height + * the desired height of the client area + * @return the required bounds to produce the given client area + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #getClientArea + */ + public Rectangle computeTrim(int x, int y, int width, int height) { + checkWidget(); + int border = getBorderWidth(); + int xn = x - border; + int yn = y - border; + int widthNew = width + 2 * border; + int heightNew = height + 2 * border; + + widthNew += getVerticalBarWidth(); + + heightNew += getHorizontalBarHeight(); + + return new Rectangle(xn, yn, widthNew, heightNew); + } + + private int getVerticalBarWidth() { + ScrollBar bar = getVerticalBar(); + if (bar != null) { + return bar.getSize().x; + } + return 0; + } + + private int getHorizontalBarHeight() { + ScrollBar bar = getHorizontalBar(); + if (bar != null) { + return bar.getSize().y; + } + return 0; + } + + ScrollBar createScrollBar(int type) { + ScrollBar bar = new ScrollBar(this, type); + if ((state & CANVAS) != 0) { + bar.setMaximum(100); + bar.setThumb(10); + } + return bar; + } + + /** + * Returns a rectangle which describes the area of the receiver which is + * capable of displaying data (that is, not covered by the "trimmings"). + * + * @return the client area + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #computeTrim + */ + public Rectangle getClientArea() { + checkWidget(); + if (!isVisible()) { + updateQLayouts(); + } + + Rectangle clientArea = QtSWTConverter.convert(getQWidget().geometry()); + if (clientArea.width < 0) { + clientArea.width = DEFAULT_WIDTH; + } + if (clientArea.height < 0) { + clientArea.height = DEFAULT_HEIGHT; + } + + return clientArea; + } + + void updateQLayouts() { + if (parent != null) { + parent.updateQLayouts(); + } + updateLayoutOfQWidget(); + } + + void updateLayoutOfQWidget() { + QLayout layout = getQWidget().layout(); + if (layout != null) { + layout.activate(); + layout.update(); + } + } + + /** + * 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; + } + + @Override + void releaseQWidget() { + masterWidget = null; + contentWidget = null; + super.releaseQWidget(); + } + + void releaseBar(ScrollBar bar) { + if (horizontalBar == bar) { + horizontalBar = null; + } + if (verticalBar == bar) { + verticalBar = null; + } + } + + @Override + void releaseChildren(boolean destroy) { + if (horizontalBar != null) { + horizontalBar.release(false); + horizontalBar = null; + } + if (verticalBar != null) { + verticalBar.release(false); + verticalBar = null; + } + super.releaseChildren(destroy); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Shell.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Shell.java new file mode 100644 index 0000000000..662756b606 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Shell.java @@ -0,0 +1,1490 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.QObject; +import com.trolltech.qt.core.QPoint; +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.core.Qt.FocusPolicy; +import com.trolltech.qt.core.Qt.FocusReason; +import com.trolltech.qt.core.Qt.WindowFlags; +import com.trolltech.qt.core.Qt.WindowModality; +import com.trolltech.qt.core.Qt.WindowState; +import com.trolltech.qt.core.Qt.WindowStates; +import com.trolltech.qt.core.Qt.WindowType; +import com.trolltech.qt.gui.QDialog; +import com.trolltech.qt.gui.QMainWindow; +import com.trolltech.qt.gui.QMouseEvent; +import com.trolltech.qt.gui.QScrollArea; +import com.trolltech.qt.gui.QStyle; +import com.trolltech.qt.gui.QVBoxLayout; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QWindowStateChangeEvent; +import com.trolltech.qt.gui.QFrame.Shape; +import com.trolltech.qt.gui.QSizePolicy.Policy; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.ShellListener; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.graphics.Region; +import org.eclipse.swt.internal.qt.QtSWTConverter; + +/** + * Instances of this class represent the "windows" which the desktop or + * "window manager" is managing. Instances that do not have a parent (that is, + * they are built using the constructor, which takes a <code>Display</code> as + * the argument) are described as <em>top level</em> shells. Instances that do + * have a parent are described as <em>secondary</em> or <em>dialog</em> shells. + * <p> + * Instances are always displayed in one of the maximized, minimized or normal + * states: + * <ul> + * <li> + * When an instance is marked as <em>maximized</em>, the window manager will + * typically resize it to fill the entire visible area of the display, and the + * instance is usually put in a state where it can not be resized (even if it + * has style <code>RESIZE</code>) until it is no longer maximized.</li> + * <li> + * When an instance is in the <em>normal</em> state (neither maximized or + * minimized), its appearance is controlled by the style constants which were + * specified when it was created and the restrictions of the window manager (see + * below).</li> + * <li> + * When an instance has been marked as <em>minimized</em>, its contents (client + * area) will usually not be visible, and depending on the window manager, it + * may be "iconified" (that is, replaced on the desktop by a small simplified + * representation of itself), relocated to a distinguished area of the screen, + * or hidden. Combinations of these changes are also possible.</li> + * </ul> + * </p> + * <p> + * The <em>modality</em> of an instance may be specified using style bits. The + * modality style bits are used to determine whether input is blocked for other + * shells on the display. The <code>PRIMARY_MODAL</code> style allows an + * instance to block input to its parent. The <code>APPLICATION_MODAL</code> + * style allows an instance to block input to every other shell in the display. + * The <code>SYSTEM_MODAL</code> style allows an instance to block input to all + * shells, including shells belonging to different applications. + * </p> + * <p> + * Note: The styles supported by this class are treated as <em>HINT</em>s, since + * the window manager for the desktop on which the instance is visible has + * ultimate control over the appearance and behavior of decorations and + * modality. For example, some window managers only support resizable windows + * and will always assume the RESIZE style, even if it is not set. In addition, + * if a modality style is not supported, it is "upgraded" to a more restrictive + * modality style that is supported. For example, if <code>PRIMARY_MODAL</code> + * is not supported, it would be upgraded to <code>APPLICATION_MODAL</code>. A + * modality style may also be "downgraded" to a less restrictive style. For + * example, most operating systems no longer support <code>SYSTEM_MODAL</code> + * because it can freeze up the desktop, so this is typically downgraded to + * <code>APPLICATION_MODAL</code>. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE, ON_TOP, TOOL</dd> + * <dd>APPLICATION_MODAL, MODELESS, PRIMARY_MODAL, SYSTEM_MODAL</dd> + * <dt><b>Events:</b></dt> + * <dd>Activate, Close, Deactivate, Deiconify, Iconify</dd> + * </dl> + * Class <code>SWT</code> provides two "convenience constants" for the most + * commonly required style combinations: + * <dl> + * <dt><code>SHELL_TRIM</code></dt> + * <dd> + * the result of combining the constants which are required to produce a typical + * application top level shell: (that is, + * <code>CLOSE | TITLE | MIN | MAX | RESIZE</code>)</dd> + * <dt><code>DIALOG_TRIM</code></dt> + * <dd> + * the result of combining the constants which are required to produce a typical + * application dialog shell: (that is, <code>TITLE | CLOSE | BORDER</code>)</dd> + * </dl> + * </p> + * <p> + * Note: Only one of the styles APPLICATION_MODAL, MODELESS, PRIMARY_MODAL and + * SYSTEM_MODAL may be specified. + * </p> + * <p> + * IMPORTANT: This class is not intended to be subclassed. + * </p> + * + * @see Decorations + * @see SWT + * @see <a href="http://www.eclipse.org/swt/snippets/#shell">Shell snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + */ +public class Shell extends Decorations { + Menu activeMenu; + boolean fullScreen, wasMaximized, modified; + Control lastActive; + private QMainWindow mainWindow; + private QDialog dialogWindow; + private QStyle oldStyle; + + /** + * Constructs a new instance of this class. This is equivalent to calling + * <code>Shell((Display) null)</code>. + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + */ + public Shell() { + this((Display) null); + } + + /** + * Constructs a new instance of this class given only the style value + * describing its behavior and appearance. This is equivalent to calling + * <code>Shell((Display) null, style)</code>. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param style + * the style of control to construct + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#BORDER + * @see SWT#CLOSE + * @see SWT#MIN + * @see SWT#MAX + * @see SWT#RESIZE + * @see SWT#TITLE + * @see SWT#TOOL + * @see SWT#NO_TRIM + * @see SWT#SHELL_TRIM + * @see SWT#DIALOG_TRIM + * @see SWT#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, SWT.SHELL_TRIM); + } + + /** + * Constructs a new instance of this class given the display to create it on + * and a style value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * <p> + * Note: Currently, null can be passed in for the display argument. This has + * the effect of creating the shell on the currently active display if there + * is one. If there is no current display, the shell is created on a + * "default" display. <b>Passing in null as the display argument is not + * considered to be good coding style, and may not be supported in a future + * release of SWT.</b> + * </p> + * + * @param display + * the display to create the shell on + * @param style + * the style of control to construct + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#BORDER + * @see SWT#CLOSE + * @see SWT#MIN + * @see SWT#MAX + * @see SWT#RESIZE + * @see SWT#TITLE + * @see SWT#TOOL + * @see SWT#NO_TRIM + * @see SWT#SHELL_TRIM + * @see SWT#DIALOG_TRIM + * @see SWT#MODELESS + * @see SWT#PRIMARY_MODAL + * @see SWT#APPLICATION_MODAL + * @see SWT#SYSTEM_MODAL + */ + public Shell(Display display, int style) { + this(display, null, style, false); + } + + Shell(Display display, Shell parent, int style, boolean embedded) { + super(); + checkSubclass(); + if (display == null) { + display = Display.getCurrent(); + } + if (display == null) { + display = Display.getDefault(); + } + if (!display.isValidThread()) { + error(SWT.ERROR_THREAD_INVALID_ACCESS); + } + if (parent != null && parent.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + this.style = checkStyle(style); + this.parent = parent; + this.display = display; + // if (handle != 0 && !embedded) { + // state |= FOREIGN_HANDLE; + // } + createWidget(parent, style); + } + + /** + * Constructs a new instance of this class given only its parent. It is + * created with style <code>SWT.DIALOG_TRIM</code>. + * <p> + * Note: Currently, null can be passed in for the parent. This has the + * effect of creating the shell on the currently active display if there is + * one. If there is no current display, the shell is created on a "default" + * display. <b>Passing in null as the parent is not considered to be good + * coding style, and may not be supported in a future release of SWT.</b> + * </p> + * + * @param parent + * a shell which will be the parent of the new instance + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + */ + public Shell(Shell parent) { + this(parent, SWT.DIALOG_TRIM); + } + + /** + * Constructs a new instance of this class given its parent and a style + * value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * <p> + * Note: Currently, null can be passed in for the parent. This has the + * effect of creating the shell on the currently active display if there is + * one. If there is no current display, the shell is created on a "default" + * display. <b>Passing in null as the parent is not considered to be good + * coding style, and may not be supported in a future release of SWT.</b> + * </p> + * + * @param parent + * a shell which will be the parent of the new instance + * @param style + * the style of control to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#BORDER + * @see SWT#CLOSE + * @see SWT#MIN + * @see SWT#MAX + * @see SWT#RESIZE + * @see SWT#TITLE + * @see SWT#NO_TRIM + * @see SWT#SHELL_TRIM + * @see SWT#DIALOG_TRIM + * @see SWT#ON_TOP + * @see SWT#TOOL + * @see SWT#MODELESS + * @see SWT#PRIMARY_MODAL + * @see SWT#APPLICATION_MODAL + * @see SWT#SYSTEM_MODAL + */ + public Shell(Shell parent, int style) { + this(parent != null ? parent.display : null, parent, style, false); + } + + @Override + QWidget createQWidget(int style) { + QScrollArea scrollArea; + if (parent == null) { + // new window + mainWindow = new QMainWindow(null, createWindowFlags(style)); + scrollArea = new QScrollArea(mainWindow); + mainWindow.setCentralWidget(scrollArea); + } else { + // new dialog + dialogWindow = new QDialog(parent.getQWidget(), createWindowFlags(style)); + scrollArea = new QScrollArea(dialogWindow); + + QVBoxLayout layout = new QVBoxLayout(dialogWindow); + layout.addWidget(scrollArea); + layout.setContentsMargins(0, 0, 0, 0); + } + + scrollArea.setFrameShape(Shape.NoFrame); + scrollArea.setContentsMargins(0, 0, 0, 0); + scrollArea.setWidgetResizable(true); + setQMasterWidget(scrollArea); + + QWidget contentWidget = new QWidget(); + contentWidget.setProperty("widgetType", "scrollareaContent"); //$NON-NLS-1$ //$NON-NLS-2$ + contentWidget.setSizePolicy(Policy.MinimumExpanding, Policy.MinimumExpanding); + contentWidget.setContentsMargins(0, 0, 0, 0); + contentWidget.resize(0, 0); + scrollArea.setWidget(contentWidget); + + scrollArea.resize(0, 0); + + int policy = getWindowControl().focusPolicy().value() & ~FocusPolicy.ClickFocus.value(); + getWindowControl().setFocusPolicy(FocusPolicy.resolve(policy)); + + state |= CANVAS; + + return scrollArea.widget(); + } + + private WindowFlags createWindowFlags(int style) { + int flags = parent == null ? WindowType.Window.value() : WindowType.Dialog.value() + | WindowModality.WindowModal.value(); + flags |= WindowType.CustomizeWindowHint.value(); + if ((style & SWT.CLOSE) != 0) { + flags |= WindowType.WindowSystemMenuHint.value() | WindowType.WindowCloseButtonHint.value(); + } + if ((style & SWT.MIN) != 0) { + flags |= WindowType.WindowMinimizeButtonHint.value(); + } + if ((style & SWT.MAX) != 0) { + flags |= WindowType.WindowMaximizeButtonHint.value(); + } + if ((style & SWT.NO_TRIM) != 0) { + flags |= WindowType.FramelessWindowHint.value(); + } + if ((style & SWT.TITLE) != 0) { + flags |= WindowType.WindowTitleHint.value(); + } + if ((style & SWT.ON_TOP) != 0) { + flags |= WindowType.WindowStaysOnTopHint.value(); + } + return new WindowFlags(flags); + } + + @Override + protected void setupQWidget() { + getWindowControl().adjustSize(); + // no setup + } + + @Override + void registerQWidget() { + super.registerQWidget(); + display.addControl(getWindowControl(), this); + } + + @Override + void deregisterQWidget() { + display.removeControl(getWindowControl()); + super.deregisterQWidget(); + } + + @Override + protected QWidget getQMasterWidget() { + return getWindowControl(); + } + + @Override + QWidget getMenuContainer() { + return getWindowControl(); + } + + QDialog getQDialog() { + return dialogWindow; + } + + boolean isDialog() { + return dialogWindow != null; + } + + @Override + public void setStyleSheet(String style) { + if (style == null || style.trim().length() == 0) { + getWindowControl().setStyleSheet(null); + if (oldStyle != null) { + getWindowControl().setStyle(oldStyle); + oldStyle = null; + } + } else { + oldStyle = getWindowControl().style(); + getWindowControl().setStyleSheet(style); + } + updateLayout(); + } + + @Override + public void updateStyleSheet() { + if (null != getWindowControl().style()) { + getWindowControl().setStyle(getWindowControl().style()); + updateLayout(); + } + } + + @Override + protected QWidget getWindowControl() { + return mainWindow != null ? mainWindow : dialogWindow; + } + + /** + * Invokes platform specific functionality to allocate a new shell that is + * embedded. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public API for + * <code>Shell</code>. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms, and should never be called from application code. + * </p> + * + * @param display + * the display for the shell + * @param qMetrics + * the handle for the shell + * @return a new shell object containing the specified display and handle + */ + public static Shell qt_new(Display display) { + return new Shell(display, null, SWT.NO_TRIM, true); + } + + static int checkStyle(int style) { + style = Decorations.checkStyle(style); + style &= ~SWT.TRANSPARENT; + 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); + } + + /** + * Requests that the window manager close the receiver in the same way it + * would be closed when the user clicks on the "close box" or performs some + * other platform specific key or mouse combination that indicates the + * window should be removed. + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SWT#Close + * @see #dispose + */ + public void close() { + checkWidget(); + closeWidget(); + } + + @Override + void enableWidget(boolean enabled) { + Control oldFocus = display.getFocusControl(); + super.enableWidget(enabled); + if (enabled) { + _update(); + } else { + + // All children were looped through and disabled by QWidget unless + // they + // were explicitly disabled. SWT behavior is not to disable the + // dialog + // Shells so we have to restore their states. + Shell shells[] = getShells(); + for (int i = 0; i < shells.length; ++i) { + if (shells[i].parent == this) { + if (shells[i].getEnabled()) { + shells[i].getQWidget().setEnabled(true); + } + } + } + // Because dialog Shell might have been temporarily disabled the + // focus might + // have been lost and must be restored. + if (oldFocus != null) { + oldFocus.menuShell().restoreFocus(); + } + } + } + + @Override + Control findBackgroundControl() { + return background != null || backgroundImage != null ? this : null; + } + + @Override + Cursor findCursor() { + return cursor; + } + + @Override + Control findThemeControl() { + return null; + } + + void fixShell(Shell newShell, Control control) { + if (this == newShell) { + return; + } + if (control == lastActive) { + setActiveControl(null); + } + } + + /** + * If the receiver is visible, moves it to the top of the drawing order for + * the display on which it was created (so that all other shells on that + * display, which are not the receiver's children will be drawn behind it) + * and forces the window manager to make the shell active. + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 2.0 + * @see Control#moveAbove + * @see Control#setFocus + * @see Control#setVisible + * @see Display#getActiveShell + * @see Decorations#setDefaultButton(Button) + * @see Shell#open + * @see Shell#setActive + */ + public void forceActive() { + checkWidget(); + if (!isVisible()) { + return; + } + bringToTop(); + } + + void forceResize() { + /* Do nothing */ + } + + /** + * Returns the receiver's alpha value. The alpha value is between 0 + * (transparent) and 255 (opaque). + * + * @return the alpha value + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public int getAlpha() { + checkWidget(); + double opacity = getQWidget().windowOpacity(); + return (int) (255 * opacity); + } + + @Override + public Rectangle getBounds() { + checkWidget(); + QPoint pos = getWindowControl().pos(); + QSize size = getWindowControl().size(); + return new Rectangle(pos.x(), pos.y(), size.width(), size.height()); + } + + @Override + public Rectangle getClientArea() { + checkWidget(); + if (!isVisible()) { + updateQLayouts(); + } + + Rectangle clientArea = QtSWTConverter.convert(getQWidget().rect()); + if (clientArea.width < 0) { + clientArea.width = 0; + } + if (clientArea.height < 0) { + clientArea.height = 0; + } + + return clientArea; + } + + /** + * Returns <code>true</code> if the receiver is currently in fullscreen + * state, and false otherwise. + * <p> + * + * @return the fullscreen state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public boolean getFullScreen() { + checkWidget(); + return fullScreen; + } + + /** + * Returns the receiver's input method editor mode. This will be the result + * of bitwise OR'ing together one or more of the following constants defined + * in class <code>SWT</code>: <code>NONE</code>, <code>ROMAN</code>, + * <code>DBCS</code>, <code>PHONETIC</code>, <code>NATIVE</code>, + * <code>ALPHA</code>. + * + * @return the IME mode + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SWT + */ + public int getImeInputMode() { + checkWidget(); + // TODO how to do it with Qt? + return SWT.NONE; + } + + @Override + public Point getLocation() { + checkWidget(); + if (getWindowControl().isMinimized()) { + return super.getLocation(); + } + return QtSWTConverter.convert(getWindowControl().pos()); + } + + @Override + public boolean getMaximized() { + checkWidget(); + return !fullScreen && super.getMaximized(); + } + + /** + * Returns a point describing the minimum receiver's size. The x coordinate + * of the result is the minimum width of the receiver. The y coordinate of + * the result is the minimum height of the receiver. + * + * @return the receiver's size + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public Point getMinimumSize() { + checkWidget(); + return QtSWTConverter.convert(getWindowControl().minimumSize()); + } + + /** + * Gets the receiver's modified state. + * + * </ul> + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.5 + */ + public boolean getModified() { + checkWidget(); + return modified; + } + + /** + * Returns the region that defines the shape of the shell, or null if the + * shell has the default shape. + * + * @return the region that defines the shape of the shell (or null) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + * + */ + @Override + public Region getRegion() { + /* This method is needed for the @since 3.0 Javadoc */ + checkWidget(); + return region; + } + + @Override + public Shell getShell() { + checkWidget(); + return this; + } + + @Override + public Point getSize() { + checkWidget(); + return QtSWTConverter.convert(getWindowControl().size()); + } + + /** + * Returns an array containing all shells which are descendants of the + * receiver. + * <p> + * + * @return the dialog shells + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + */ + public Shell[] getShells() { + checkWidget(); + int count = 0; + Shell[] shells = display.getShells(); + for (int i = 0; i < shells.length; i++) { + Control shell = shells[i]; + do { + shell = shell.parent; + } while (shell != null && shell != this); + if (shell == this) { + count++; + } + } + int index = 0; + Shell[] result = new Shell[count]; + for (int i = 0; i < shells.length; i++) { + Control shell = shells[i]; + do { + shell = shell.parent; + } while (shell != null && shell != this); + if (shell == this) { + result[index++] = shells[i]; + } + } + return result; + } + + @Override + protected Composite findDeferredControl() { + return layoutCount > 0 ? this : null; + } + + // @Override + // 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, + * sets the focus and asks the window manager to make the shell active. + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Control#moveAbove + * @see Control#setFocus + * @see Control#setVisible + * @see Display#getActiveShell + * @see Decorations#setDefaultButton(Button) + * @see Shell#setActive + * @see Shell#forceActive + */ + public void open() { + checkWidget(); + updateLayout(); + setVisible(true); + bringToTop(); + if (isDisposed()) { + return; + } + if (!restoreFocus() && !traverseGroup(true)) { + setFocus(FocusReason.OtherFocusReason); + } + } + + @Override + public boolean print(GC gc) { + checkWidget(); + if (gc == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (gc.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + //TODO + return false; + } + + @Override + void releaseChildren(boolean destroy) { + Shell[] shells = getShells(); + for (int i = 0; i < shells.length; i++) { + Shell shell = shells[i]; + if (shell != null && !shell.isDisposed()) { + shell.release(false); + } + } + super.releaseChildren(destroy); + } + + @Override + void releaseParent() { + /* Do nothing */ + } + + @Override + void releaseQWidget() { + getWindowControl().close(); + super.releaseQWidget(); + mainWindow = null; + dialogWindow = null; + } + + @Override + void releaseWidget() { + super.releaseWidget(); + lastActive = null; + } + + @Override + void removeMenu(Menu menu) { + super.removeMenu(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); + } + + /** + * If the receiver is visible, moves it to the top of the drawing order for + * the display on which it was created (so that all other shells on that + * display, which are not the receiver's children will be drawn behind it) + * and asks the window manager to make the shell active + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 2.0 + * @see Control#moveAbove + * @see Control#setFocus + * @see Control#setVisible + * @see Display#getActiveShell + * @see Decorations#setDefaultButton(Button) + * @see Shell#open + * @see Shell#setActive + */ + public void setActive() { + checkWidget(); + if (!isVisible()) { + return; + } + bringToTop(); + // widget could be disposed at this point + } + + void setActiveControl(Control control) { + if (control != null && control.isDisposed()) { + control = null; + } + if (lastActive != null && lastActive.isDisposed()) { + lastActive = null; + } + if (lastActive == control) { + return; + } + + /* + * Compute the list of controls to be activated and deactivated by + * finding the first common parent control. + */ + Control[] activate = control == null ? new Control[0] : control.getPath(); + Control[] deactivate = lastActive == null ? new Control[0] : lastActive.getPath(); + lastActive = control; + int index = 0, length = Math.min(activate.length, deactivate.length); + while (index < length) { + if (activate[index] != deactivate[index]) { + break; + } + index++; + } + + /* + * It is possible (but unlikely), that application code could have + * destroyed some of the widgets. If this happens, keep processing those + * widgets that are not disposed. + */ + for (int i = deactivate.length - 1; i >= index; --i) { + if (!deactivate[i].isDisposed()) { + deactivate[i].sendEvent(SWT.Deactivate); + } + } + for (int i = activate.length - 1; i >= index; --i) { + if (!activate[i].isDisposed()) { + activate[i].sendEvent(SWT.Activate); + } + } + } + + /** + * Sets the receiver's alpha value which must be between 0 (transparent) and + * 255 (opaque). + * <p> + * This operation requires the operating system's advanced widgets subsystem + * which may not be available on some platforms. + * </p> + * + * @param alpha + * the alpha value + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public void setAlpha(int alpha) { + checkWidget(); + if (alpha < 0 || alpha > 255) { + return; + } + getQWidget().setWindowOpacity((double) alpha / 255); + } + + @Override + protected void setBounds(int x, int y, int width, int height, boolean move, boolean resize) { + if (fullScreen) { + setFullScreen(false); + } + + Rectangle geometry = QtSWTConverter.convert(getWindowControl().frameGeometry()); + if (move) { + int oldX = geometry.x; + int oldY = geometry.y; + boolean moved = oldX != x || oldY != y; + if (moved) { + getWindowControl().move(x, y); + } + } + + if (resize) { + int oldW = geometry.width; + int oldH = geometry.height; + boolean resized = oldW != width || oldH != height; + + if (resized) { + if ((style & SWT.RESIZE) == 0) { + unlockSize(); + } + + getWindowControl().resize(width, height); + + if ((style & SWT.RESIZE) == 0) { + getWindowControl().setFixedSize(Math.max(0, width), Math.max(0, height)); + } + } + } + } + + @Override + public void setEnabled(boolean enabled) { + checkWidget(); + if (super.getEnabled() == enabled) { + return; + } + super.setEnabled(enabled); + if (enabled && getWindowControl().isActiveWindow()) { + if (!restoreFocus()) { + traverseGroup(true); + } + } + } + + /** + * Sets the full screen state of the receiver. If the argument is + * <code>true</code> causes the receiver to switch to the full screen state, + * and if the argument is <code>false</code> and the receiver was previously + * switched into full screen state, causes the receiver to switch back to + * either the maximmized or normal states. + * <p> + * Note: The result of intermixing calls to <code>setFullScreen(true)</code>, <code>setMaximized(true)</code> and <code>setMinimized(true)</code> + * will vary by platform. Typically, the behavior will match the platform + * user's expectations, but not always. This should be avoided if possible. + * </p> + * + * @param fullScreen + * the new fullscreen state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public void setFullScreen(boolean fullScreen) { + checkWidget(); + if (this.fullScreen == fullScreen) { + return; + } + this.fullScreen = fullScreen; + if (fullScreen) { + getWindowControl().showFullScreen(); + } else { + getWindowControl().showNormal(); + } + } + + /** + * 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(); + // TODO + } + + /** + * Sets the receiver's minimum size to the size specified by the arguments. + * If the new minimum size is larger than the current size of the receiver, + * the receiver is resized to the new minimum size. + * + * @param width + * the new minimum width for the receiver + * @param height + * the new minimum height for the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public void setMinimumSize(int width, int height) { + checkWidget(); + getQWidget().setMinimumSize(width, height); + } + + /** + * Sets the receiver's minimum size to the size specified by the argument. + * If the new minimum size is larger than the current size of the receiver, + * the receiver is resized to the new minimum size. + * + * @param size + * the new minimum size for the receiver + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public void setMinimumSize(Point size) { + checkWidget(); + if (size == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + setMinimumSize(size.x, size.y); + } + + /** + * Sets the receiver's modified state as specified by the argument. + * + * @param modified + * the new modified state for the receiver + * + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.5 + */ + public void setModified(boolean modified) { + checkWidget(); + this.modified = modified; + } + + /** + * Sets the shape of the shell to the region specified by the argument. When + * the argument is null, the default shape of the shell is restored. The + * shell must be created with the style SWT.NO_TRIM in order to specify a + * region. + * + * @param region + * the region that defines the shape of the shell (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the region has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + * + */ + @Override + public void setRegion(Region region) { + checkWidget(); + if ((style & SWT.NO_TRIM) == 0) { + return; + } + super.setRegion(region); + } + + @Override + public void setVisible(boolean visible) { + checkWidget(); + int mask = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL; + if ((style & mask) != 0) { + if (visible) { + display.setModalShell(this); + if ((style & (SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL)) != 0) { + display.setModalDialog(null); + } + Control control = display.getFocusControl(); + if (control != null && !control.isActive()) { + bringToTop(); + if (isDisposed()) { + return; + } + } + getWindowControl().setWindowModality(getModalityFromStyle()); + QWidget mouseGrabber = QWidget.mouseGrabber(); + if (mouseGrabber != null) { + mouseGrabber.releaseMouse(); + } + } else { + display.clearModal(this); + } + } else { + updateModal(); + } + + _setVisible(getWindowControl(), visible); + } + + private WindowModality getModalityFromStyle() { + if ((style & SWT.SYSTEM_MODAL) != 0) { + return WindowModality.ApplicationModal; + } + if ((style & SWT.APPLICATION_MODAL) != 0) { + return WindowModality.ApplicationModal; + } + if ((style & SWT.PRIMARY_MODAL) != 0) { + return WindowModality.ApplicationModal; + } + return WindowModality.NonModal; + } + + @Override + boolean traverseEscape() { + if (parent == null) { + return false; + } + if (!isVisible() || !isEnabled()) { + return false; + } + close(); + return true; + } + + void updateModal() { + } + + @Override + public boolean qtCloseEvent() { + return closeWidget(); + } + + @Override + public boolean qtWindowStateChangeEvent(QObject source, QWindowStateChangeEvent event) { + if (source != getWindowControl()) { + return false; + } + WindowStates oldState = event.oldState(); + WindowStates newState = getWindowControl().windowState(); + if (oldState.isSet(WindowState.WindowMinimized) && !newState.isSet(WindowState.WindowMinimized)) { + sendEvent(SWT.Deiconify); + return false; + } + if (!oldState.isSet(WindowState.WindowMinimized) && newState.isSet(WindowState.WindowMinimized)) { + sendEvent(SWT.Iconify); + menuShell().saveFocus(); + return false; + } + return false; + } + + @Override + public boolean qtMouseButtonPressEvent(QObject source, QMouseEvent mouseEvent) { + if (source == getQWidget()) { + QWidget clickTarget = getQWidget().childAt(mouseEvent.x(), mouseEvent.y()); + if (clickTarget != null && clickTarget != getQWidget()) { + Widget swtControl = display.findControl(clickTarget); + if (swtControl instanceof Control) { + setActiveControl((Control) swtControl); + } + } + } + return false; + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Slider.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Slider.java new file mode 100644 index 0000000000..b85060a66c --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Slider.java @@ -0,0 +1,632 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.Qt.FocusPolicy; +import com.trolltech.qt.core.Qt.Orientation; +import com.trolltech.qt.gui.QAbstractSlider; +import com.trolltech.qt.gui.QScrollBar; +import com.trolltech.qt.gui.QWidget; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Point; + +/** + * Instances of this class are selectable user interface objects that represent + * a range of positive, numeric values. + * <p> + * At any given moment, a given slider will have a single 'selection' that is + * considered to be its value, which is constrained to be within the range of + * values the slider represents (that is, between its <em>minimum</em> and + * <em>maximum</em> values). + * </p> + * <p> + * Typically, sliders will be made up of five areas: + * <ol> + * <li>an arrow button for decrementing the value</li> + * <li>a page decrement area for decrementing the value by a larger amount</li> + * <li>a <em>thumb</em> for modifying the value by mouse dragging</li> + * <li>a page increment area for incrementing the value by a larger amount</li> + * <li>an arrow button for incrementing the value</li> + * </ol> + * Based on their style, sliders are either <code>HORIZONTAL</code> (which have + * a left facing button for decrementing the value and a right facing button for + * incrementing it) or <code>VERTICAL</code> (which have an upward facing button + * for decrementing the value and a downward facing buttons for incrementing + * it). + * </p> + * <p> + * On some platforms, the size of the slider's thumb can be varied relative to + * the magnitude of the range of values it represents (that is, relative to the + * difference between its maximum and minimum values). Typically, this is used + * to indicate some proportional value such as the ratio of the visible area of + * a document to the total amount of space that it would take to display it. SWT + * supports setting the thumb size even if the underlying platform does not, but + * in this case the appearance of the slider will not change. + * </p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>HORIZONTAL, VERTICAL</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection</dd> + * </dl> + * <p> + * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see ScrollBar + * @see <a href="http://www.eclipse.org/swt/snippets/#slider">Slider + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class Slider extends Control { + + private int thumb; // TODO Not supported by Qt? + private int maximum; + + /** + * 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)); + } + + @Override + protected void connectSignals() { + getQScrollBar().actionTriggered.connect(this, "actionTriggered(int)"); //$NON-NLS-1$ + getQScrollBar().rangeChanged.connect(this, "rangeChanged(int,int)"); //$NON-NLS-1$ + getQScrollBar().sliderMoved.connect(this, "sliderMoved(int)"); //$NON-NLS-1$ + getQScrollBar().sliderPressed.connect(this, "sliderPressed()"); //$NON-NLS-1$ + getQScrollBar().sliderReleased.connect(this, "sliderReleased()"); //$NON-NLS-1$ + getQScrollBar().valueChanged.connect(this, "valueChanged(int)"); //$NON-NLS-1$ + } + + protected void actionTriggered(int action) { + System.out.println("actionTriggered :" + action + " " + getQScrollBar().value()); //$NON-NLS-1$//$NON-NLS-2$ + Event event = new Event(); + if (action == QAbstractSlider.SliderAction.SliderToMinimum.value()) { + event.detail = SWT.HOME; + } else if (action == QAbstractSlider.SliderAction.SliderToMaximum.value()) { + event.detail = SWT.END; + } else if (action == QAbstractSlider.SliderAction.SliderSingleStepAdd.value()) { + event.detail = SWT.ARROW_DOWN; + } else if (action == QAbstractSlider.SliderAction.SliderSingleStepSub.value()) { + event.detail = SWT.ARROW_UP; + } else if (action == QAbstractSlider.SliderAction.SliderPageStepAdd.value()) { + event.detail = SWT.PAGE_UP; + } else if (action == QAbstractSlider.SliderAction.SliderPageStepSub.value()) { + event.detail = SWT.PAGE_DOWN; + } else if (action == QAbstractSlider.SliderAction.SliderMove.value()) { + event.detail = SWT.DRAG; + } else { + return; + } + // see actionTrigger signal + getQScrollBar().setValue(getQScrollBar().sliderPosition()); + sendEvent(SWT.Selection, event); + } + + protected void rangeChanged(int min, int max) { + System.out.println("rangeChanged :" + min + ", " + max); //$NON-NLS-1$ //$NON-NLS-2$ + } + + protected void sliderMoved(int pos) { + System.out.println("sliderMoved :" + pos); //$NON-NLS-1$ + } + + protected void sliderPressed() { + System.out.println("sliderPressed"); //$NON-NLS-1$ + } + + protected void sliderReleased() { + System.out.println("sliderReleased"); //$NON-NLS-1$ + Event event = new Event(); + event.detail = SWT.NONE; + sendEvent(SWT.Selection, event); + } + + protected void valueChanged(int value) { + System.out.println("valueChanged :" + value); //$NON-NLS-1$ + } + + @Override + protected QWidget createQWidget(int style) { + final Orientation orientation = (style & SWT.HORIZONTAL) != 0 ? Orientation.Horizontal : Orientation.Vertical; + return new QScrollBar(orientation); + } + + @Override + protected void setupQWidget() { + super.setupQWidget(); + getQScrollBar().setFocusPolicy(FocusPolicy.WheelFocus); + setThumb(10); + setMinimum(0); + setMaximum(100); + setIncrement(1); + setPageIncrement(10); + } + + QAbstractSlider getQScrollBar() { + return (QAbstractSlider) getQWidget(); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the user changes the receiver's value, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * When <code>widgetSelected</code> is called, the event object detail field + * contains one of the following values: <code>SWT.NONE</code> - for the end + * of a drag. <code>SWT.DRAG</code>. <code>SWT.HOME</code>. + * <code>SWT.END</code>. <code>SWT.ARROW_DOWN</code>. + * <code>SWT.ARROW_UP</code>. <code>SWT.PAGE_DOWN</code>. + * <code>SWT.PAGE_UP</code>. <code>widgetDefaultSelected</code> is not + * called. + * </p> + * + * @param listener + * the listener which should be notified when the user changes + * the receiver's value + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + static int checkStyle(int style) { + return checkBits(style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0); + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + checkWidget(); + int border = getBorderWidth(); + int width = border * 2; + int height = border * 2; + // default size: this is just the two arrows + thumb + Point defaultSize = super.computeSize(wHint, hHint, changed); + if ((style & SWT.HORIZONTAL) != 0) { + width += defaultSize.y * 10; + height += defaultSize.y; + } else { + width += defaultSize.x; + height += defaultSize.x * 10; + } + if (wHint != SWT.DEFAULT) { + width = wHint + border * 2; + } + if (hHint != SWT.DEFAULT) { + height = hHint + border * 2; + } + return new Point(width, height); + } + + // TODO Is this ok? + + // int defaultBackground() { + // return OS.GetSysColor(OS.COLOR_SCROLLBAR); + // } + // + // 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 getQScrollBar().singleStep(); + } + + /** + * Returns the maximum value which the receiver will allow. + * + * @return the maximum + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getMaximum() { + checkWidget(); + return maximum; + } + + /** + * Returns the minimum value which the receiver will allow. + * + * @return the minimum + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getMinimum() { + checkWidget(); + return getQScrollBar().minimum(); + } + + /** + * Returns the amount that the receiver's value will be modified by when the + * page increment/decrement areas are selected. + * + * @return the page increment + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getPageIncrement() { + checkWidget(); + return getQScrollBar().pageStep(); + } + + /** + * Returns the 'selection', which is the receiver's value. + * + * @return the selection + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getSelection() { + checkWidget(); + return getQScrollBar().value(); + } + + /** + * Returns the size of the receiver's thumb relative to the difference + * between its maximum and minimum values. + * + * @return the thumb value + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getThumb() { + checkWidget(); + return thumb; + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the user changes the receiver's value. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + /** + * 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; + } + getQScrollBar().setSingleStep(value); + } + + /** + * Sets the maximum. If this value is negative or less than or equal to the + * minimum, the value is ignored. If necessary, first the thumb and then the + * selection are adjusted to fit within the new range. + * + * @param value + * the new maximum, which must be greater than the current + * minimum + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setMaximum(int value) { + checkWidget(); + if (value < 0 || value <= getQScrollBar().minimum()) { + return; + } + maximum = value; + getQScrollBar().setMaximum(maximum - thumb); + } + + /** + * Sets the minimum value. If this value is negative or greater than or + * equal to the maximum, the value is ignored. If necessary, first the thumb + * and then the selection are adjusted to fit within the new range. + * + * @param value + * the new minimum + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setMinimum(int value) { + checkWidget(); + if (value < 0 || value >= getQScrollBar().maximum()) { + return; + } + getQScrollBar().setMinimum(value); + } + + /** + * Sets the amount that the receiver's value will be modified by when the + * page increment/decrement areas are selected to the argument, which must + * be at least one. + * + * @param value + * the page increment (must be greater than zero) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setPageIncrement(int value) { + checkWidget(); + if (value < 1) { + return; + } + getQScrollBar().setPageStep(value); + } + + /** + * Sets the 'selection', which is the receiver's value, to the argument + * which must be greater than or equal to zero. + * + * @param value + * the new selection (must be zero or greater) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setSelection(int value) { + checkWidget(); + getQScrollBar().setValue(value); + } + + /** + * Sets the size of the receiver's thumb relative to the difference between + * its maximum and minimum values. This new value will be ignored if it is + * less than one, and will be clamped if it exceeds the receiver's current + * range. + * + * @param value + * the new thumb value, which must be at least one and not larger + * than the size of the current range + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setThumb(int value) { + checkWidget(); + if (value < 1) { + return; + } + this.thumb = value; + setMaximum(maximum); // adjust the maximum which depends on the thumb + } + + /** + * Sets the receiver's selection, minimum value, maximum value, thumb, + * increment and page increment all at once. + * <p> + * Note: This is similar to setting the values individually using the + * appropriate methods, but may be implemented in a more efficient fashion + * on some platforms. + * </p> + * + * @param selection + * the new selection value + * @param minimum + * the new minimum value + * @param maximum + * the new maximum value + * @param thumb + * the new thumb value + * @param increment + * the new increment value + * @param pageIncrement + * the new pageIncrement value + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setValues(int selection, int minimum, int maximum, int thumb, int increment, int pageIncrement) { + checkWidget(); + if (minimum < 0) { + return; + } + if (maximum < 0) { + return; + } + if (thumb < 1) { + return; + } + if (increment < 1) { + return; + } + if (pageIncrement < 1) { + return; + } + setMinimum(minimum); + setMaximum(maximum); + setThumb(thumb); + setSelection(selection); + setIncrement(increment); + setPageIncrement(pageIncrement); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Spinner.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Spinner.java new file mode 100644 index 0000000000..19c26a6a6e --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Spinner.java @@ -0,0 +1,948 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.gui.QApplication; +import com.trolltech.qt.gui.QDoubleSpinBox; +import com.trolltech.qt.gui.QWidget; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.events.VerifyListener; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; + +/** + * Instances of this class are selectable user interface objects that allow the + * user to enter and modify numeric values. + * <p> + * Note that although this class is a subclass of <code>Composite</code>, it + * does not make sense to add children to it, or set a layout on it. + * </p> + * <p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>READ_ONLY, WRAP</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection, Modify, Verify</dd> + * </dl> + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#spinner">Spinner + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * + * @since 3.1 + * @noextend This class is not intended to be subclassed by clients. + */ +public class Spinner extends Composite { + boolean ignoreModify; + int pageIncrement, digits; + int selection = 0; + + /** + * the operating system limit for the number of characters that the text + * field in an instance of this class can hold + * + * @since 3.4 + */ + public static final int LIMIT; + + /* + * These values can be different on different platforms. Therefore they are + * not initialized in the declaration to stop the compiler from inlining. + */ + static { + //TODO: 3 is just an imaginary value. see bug 161 + LIMIT = 3; + } + + /** + * Constructs a new instance of this class given its parent and a style + * value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a composite control which will be the parent of the new + * instance (cannot be null) + * @param style + * the style of control to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#READ_ONLY + * @see SWT#WRAP + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public Spinner(Composite parent, int style) { + super(parent, checkStyle(style)); + + // setting default values of the SWT widget: + ((QDoubleSpinBox) getQWidget()).setDecimals(0); + ((QDoubleSpinBox) getQWidget()).setMaximum(100); + + ((QDoubleSpinBox) getQWidget()).setSingleStep(getIncrement() / Math.pow(10, this.digits)); + } + + @Override + protected QWidget createQWidget(int style) { + state &= ~(CANVAS | THEME_BACKGROUND); + QWidget spinner = new QDoubleSpinBox(); + connectSignals(spinner); + return spinner; + } + + 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); + } + + @Override + protected void checkSubclass() { + if (!isValidSubclass()) { + error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + private void connectSignals(QWidget spinner) { + ((QDoubleSpinBox) spinner).valueChanged.connect(this, "valueChanged()"); //$NON-NLS-1$ + //TODO: connection for selection and verify event is missing, but there's not suitable event in QDoubleSpinBox (bug 159) + } + + protected void valueChanged() { + Event event = new Event(); + sendEvent(SWT.Modify, event); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the receiver's text is modified, by sending it one of the messages + * defined in the <code>ModifyListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ModifyListener + * @see #removeModifyListener + */ + public void addModifyListener(ModifyListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Modify, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the control is selected by the user, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * <code>widgetSelected</code> is not called for texts. + * <code>widgetDefaultSelected</code> is typically called when ENTER is + * pressed in a single-line text. + * </p> + * + * @param listener + * the listener which should be notified when the control is + * selected by the user + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the receiver's text is verified, by sending it one of the messages + * defined in the <code>VerifyListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see VerifyListener + * @see #removeVerifyListener + */ + void addVerifyListener(VerifyListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Verify, typedListener); + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + checkWidget(); + QSize size = ((QDoubleSpinBox) getQWidget()).sizeHint(); + return new Point(size.width(), size.height()); + } + + @Override + public Rectangle computeTrim(int x, int y, int width, int height) { + checkWidget(); + return super.computeTrim(x, y, 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(); + QApplication.clipboard().setText(((QDoubleSpinBox) getQWidget()).text()); + } + + /** + * Cuts the selected text. + * <p> + * The current selection is first copied to the clipboard and then deleted + * from the widget. + * </p> + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void cut() { + checkWidget(); + if ((style & SWT.READ_ONLY) != 0) { + return; + } + QApplication.clipboard().setText(((QDoubleSpinBox) getQWidget()).text()); + ((QDoubleSpinBox) getQWidget()).setValue(0); + this.selection = 0; + } + + @Override + void enableWidget(boolean enabled) { + super.enableWidget(enabled); + } + + @Override + void deregisterQWidget() { + super.deregisterQWidget(); + } + + @Override + boolean hasFocus() { + return getQWidget().hasFocus(); + } + + /** + * Returns the number of decimal places used by the receiver. + * + * @return the digits + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getDigits() { + checkWidget(); + return digits; + } + + String getDecimalSeparator() { + // TODO check locale + return "."; //$NON-NLS-1$ + } + + /** + * Returns the amount that the receiver's value will be modified by when the + * up/down arrows are pressed. + * + * @return the increment + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getIncrement() { + checkWidget(); + double step = ((QDoubleSpinBox) getQWidget()).singleStep(); + int qstep = (int) (step * Math.pow(10, this.digits)); + return qstep; + } + + /** + * Returns the maximum value which the receiver will allow. + * + * @return the maximum + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getMaximum() { + checkWidget(); + return (int) (((QDoubleSpinBox) getQWidget()).maximum() * Math.pow(10, this.digits)); + } + + /** + * Returns the minimum value which the receiver will allow. + * + * @return the minimum + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getMinimum() { + checkWidget(); + return (int) (((QDoubleSpinBox) getQWidget()).minimum() * Math.pow(10, this.digits)); + } + + /** + * Returns the amount that the receiver's position will be modified by when + * the page up/down keys are pressed. + * + * @return the page increment + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getPageIncrement() { + checkWidget(); + return (int) ((QDoubleSpinBox) getQWidget()).singleStep(); + } + + /** + * Returns the <em>selection</em>, which is the receiver's position. + * + * @return the selection + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getSelection() { + checkWidget(); + int qselection = (int) (((QDoubleSpinBox) getQWidget()).value() * Math.pow(10, this.digits)); + this.selection = qselection; + return qselection; + } + + int getSelectionText(boolean[] parseFail) { + // TODO + return -1; + } + + /** + * Returns a string containing a copy of the contents of the receiver's text + * field, or an empty string if there are no contents. + * + * @return the receiver's text + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public String getText() { + checkWidget(); + return ((QDoubleSpinBox) getQWidget()).text(); + } + + /** + * Returns the maximum number of characters that the receiver's text field + * is capable of holding. If this has not been changed by + * <code>setTextLimit()</code>, it will be the constant + * <code>Spinner.LIMIT</code>. + * + * @return the text limit + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #LIMIT + * + * @since 3.4 + */ + public int getTextLimit() { + checkWidget(); + //TODO: not sure about this... + int maxChars = String.valueOf(getMaximum()).trim().length(); + int minChars = String.valueOf(getMinimum()).trim().length(); + return maxChars > minChars ? maxChars : minChars; + } + + /** + * 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() { + boolean isNumber = true; + double pasteNumber; + + checkWidget(); + if ((style & SWT.READ_ONLY) != 0) { + return; + } + String pasteText = QApplication.clipboard().text(); + + try { + pasteNumber = Double.parseDouble(pasteText); + } catch (NumberFormatException e) { + isNumber = false; + return; // it's not a valid number, so just return and don't paste anything + } + if (isNumber && pasteNumber <= getMaximum() && pasteNumber >= getMinimum()) { + this.selection = Integer.valueOf(QApplication.clipboard().text()); + ((QDoubleSpinBox) getQWidget()).setValue(pasteNumber); + } + } + + @Override + void registerQWidget() { + super.registerQWidget(); + } + + @Override + void releaseQWidget() { + super.releaseQWidget(); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the receiver's text is modified. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ModifyListener + * @see #addModifyListener + */ + public void removeModifyListener(ModifyListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Modify, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is selected by the user. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is verified. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see VerifyListener + * @see #addVerifyListener + */ + void removeVerifyListener(VerifyListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Verify, listener); + } + + /** + * Sets the number of decimal places used by the receiver. + * <p> + * The digit setting is used to allow for floating point values in the + * receiver. For example, to set the selection to a floating point value of + * 1.37 call setDigits() with a value of 2 and setSelection() with a value + * of 137. Similarly, if getDigits() has a value of 2 and getSelection() + * returns 137 this should be interpreted as 1.37. This applies to all + * numeric APIs. + * </p> + * + * @param value + * the new digits (must be greater than or equal to zero) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the value is less than + * zero</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setDigits(int value) { + checkWidget(); + if (value < 0) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (value == this.digits) { + return; + } + + this.digits = value; + ((QDoubleSpinBox) getQWidget()).setDecimals(value); + ((QDoubleSpinBox) getQWidget()).setValue(selection / Math.pow(10, value)); + } + + /** + * Sets the amount that the receiver's value will be modified by when the + * up/down arrows are pressed to the argument, which must be at least one. + * + * @param value + * the new increment (must be greater than zero) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setIncrement(int value) { + checkWidget(); + if (value < 1) { + return; + } + ((QDoubleSpinBox) getQWidget()).setSingleStep(value / Math.pow(10, this.digits)); + } + + /** + * Sets the maximum value that the receiver will allow. This new value will + * be ignored if it is not greater than the receiver's current minimum + * value. If the new maximum is applied then the receiver's selection value + * will be adjusted if necessary to fall within its new range. + * + * @param value + * the new maximum, which must be greater than the current + * minimum + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setMaximum(int value) { + checkWidget(); + ((QDoubleSpinBox) getQWidget()).setMaximum(value / Math.pow(10, this.digits)); + } + + /** + * Sets the minimum value that the receiver will allow. This new value will + * be ignored if it is not less than the receiver's current maximum value. + * If the new minimum is applied then the receiver's selection value will be + * adjusted if necessary to fall within its new range. + * + * @param value + * the new minimum, which must be less than the current maximum + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setMinimum(int value) { + checkWidget(); + ((QDoubleSpinBox) getQWidget()).setMinimum(value / Math.pow(10, this.digits)); + } + + /** + * Sets the amount that the receiver's position will be modified by when the + * page up/down keys are pressed to the argument, which must be at least + * one. + * + * @param value + * the page increment (must be greater than zero) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setPageIncrement(int value) { + checkWidget(); + if (value < 1) { + return; + } + pageIncrement = value; // TODO: see bug 160 + } + + /** + * Sets the <em>selection</em>, which is the receiver's position, to the + * argument. If the argument is not within the range specified by minimum + * and maximum, it will be adjusted to fall within this range. + * + * @param value + * the new selection (must be zero or greater) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setSelection(int value) { + checkWidget(); + this.selection = value; + ((QDoubleSpinBox) getQWidget()).setDecimals(this.digits); + ((QDoubleSpinBox) getQWidget()).setValue(value / Math.pow(10, digits)); + + } + + /** + * Sets the maximum number of characters that the receiver's text field is + * capable of holding to be the argument. + * <p> + * To reset this value to the default, use + * <code>setTextLimit(Spinner.LIMIT)</code>. Specifying a limit value larger + * than <code>Spinner.LIMIT</code> sets the receiver's limit to + * <code>Spinner.LIMIT</code>. + * </p> + * + * @param limit + * new text limit + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #LIMIT + * + * @since 3.4 + */ + public void setTextLimit(int limit) { + checkWidget(); + if (limit == 0) { + error(SWT.ERROR_CANNOT_BE_ZERO); + } + + if (limit < 0 || limit > LIMIT) { + limit = LIMIT; + } + + //TODO setting the text limit to the QDoubleSpinBox + } + + /** + * Sets the receiver's selection, minimum value, maximum value, digits, + * increment and page increment all at once. + * <p> + * Note: This is similar to setting the values individually using the + * appropriate methods, but may be implemented in a more efficient fashion + * on some platforms. + * </p> + * + * @param selection + * the new selection value + * @param minimum + * the new minimum value + * @param maximum + * the new maximum value + * @param digits + * the new digits value + * @param increment + * the new increment value + * @param pageIncrement + * the new pageIncrement value + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public void setValues(int selection, int minimum, int maximum, int digits, int increment, int pageIncrement) { + checkWidget(); + if (maximum <= minimum) { + return; + } + if (digits < 0) { + return; + } + if (increment < 1) { + return; + } + if (pageIncrement < 1) { + return; + } + this.selection = Math.min(Math.max(minimum, selection), maximum); + ((QDoubleSpinBox) getQWidget()).setValue(this.selection); + setIncrement(increment); + this.pageIncrement = pageIncrement; + this.digits = digits; + } + + String verifyText(String string, int start, int end, Event keyEvent) { + // 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; + // } + // int index = 0; + // if (digits > 0) { + // String decimalSeparator = getDecimalSeparator(); + // index = string.indexOf(decimalSeparator); + // if (index != -1) { + // string = string.substring(0, index) + string.substring(index + 1); + // } + // index = 0; + // } + // if (string.length() > 0) { + // int[] min = new int[1]; + // OS.SendMessage(hwndUpDown, OS.UDM_GETRANGE32, min, null); + // if (min[0] < 0 && string.charAt(0) == '-') + // index++; + // } + // while (index < string.length()) { + // if (!Character.isDigit(string.charAt(index))) + // break; + // index++; + // } + // event.doit = index == string.length(); + // if ( !OS.IsUnicode && OS.IsDBLocale ) { + // event.start = mbcsToWcsPos( start ); + // event.end = mbcsToWcsPos( end ); + // } + // sendEvent(SWT.Verify, event); + // if (!event.doit || isDisposed()) + return null; + // return event.text; + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TabFolder.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TabFolder.java new file mode 100644 index 0000000000..90fd790cba --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TabFolder.java @@ -0,0 +1,755 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import java.util.ArrayList; + +import com.trolltech.qt.gui.QTabWidget; +import com.trolltech.qt.gui.QVBoxLayout; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QSizePolicy.Policy; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.internal.qt.QtSWTConverter; + +/** + * Instances of this class implement the notebook user interface metaphor. It + * allows the user to select a notebook page from set of pages. + * <p> + * The item children that may be added to instances of this class must be of + * type <code>TabItem</code>. <code>Control</code> children are created and then + * set into a tab item using <code>TabItem#setControl</code>. + * </p> + * <p> + * Note that although this class is a subclass of <code>Composite</code>, it + * does not make sense to set a layout on it. + * </p> + * <p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>TOP, BOTTOM</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection</dd> + * </dl> + * <p> + * Note: Only one of the styles TOP and BOTTOM may be specified. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#tabfolder">TabFolder, + * TabItem snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class TabFolder extends Composite { + private java.util.List<TabItem> items; + private java.util.List<QWidget> tabWidgets; + + /** + * 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)); + } + + @Override + protected QWidget createQWidget(int style) { + state &= ~(CANVAS | THEME_BACKGROUND); + items = new ArrayList<TabItem>(4); + tabWidgets = new ArrayList<QWidget>(4); + return new QTabWidget(); + } + + @Override + protected void connectSignals() { + getQTabWidget().currentChanged.connect(this, "selectionEvent(int)");//$NON-NLS-1$ + } + + QTabWidget getQTabWidget() { + return (QTabWidget) getQWidget(); + } + + protected void selectionEvent(int index) { + if (index != -1 && items != null) { + TabItem item = getItem(index); + Event event = new Event(); + event.item = item; + sendEvent(SWT.Selection, event); + } + } + + protected void addQChild() { + // do nothing + } + + static int checkStyle(int style) { + style = checkBits(style, SWT.TOP, SWT.BOTTOM, 0, 0, 0, 0); + + /* + * Even though it is legal to create this widget with scroll bars, they + * serve no useful purpose because they do not automatically scroll the + * widget's client area. The fix is to clear the SWT style. + */ + return style & ~(SWT.H_SCROLL | SWT.V_SCROLL); + } + + @Override + protected void checkSubclass() { + if (!isValidSubclass()) { + error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + void createItem(TabItem item, int index) { + int count = getQTabWidget().count(); + if (!(0 <= index && index <= count)) { + error(SWT.ERROR_INVALID_RANGE); + } + + items.add(index, item); + + QWidget widget = new QWidget(); + widget.setSizePolicy(Policy.Expanding, Policy.Expanding); + widget.setContentsMargins(0, 0, 0, 0); + QVBoxLayout layout = new QVBoxLayout(); + layout.setContentsMargins(0, 0, 0, 0); + widget.setLayout(layout); + + tabWidgets.add(index, widget); + + getQTabWidget().insertTab(index, widget, item.getText()); + + /* + * Send a selection event when the item that is added becomes the new + * selection. This only happens when the first item is added. + */ + if (index == 0) { + Event event = new Event(); + event.item = item; + sendEvent(SWT.Selection, event); + } + } + + void updateItem(TabItem item, Control oldControl) { + int index = indexOf(item); + QWidget container = tabWidgets.get(index); + + if (oldControl != null) { + QWidget widget = oldControl.getQMasterWidget(); + if (widget != null) { + container.layout().removeWidget(widget); + } + } + + Control control = item.getControl(); + QWidget widget = null; + if (control != null) { + widget = control.getQMasterWidget(); + } + if (widget == null) { + return; + } + container.layout().addWidget(widget); + } + + void destroyItem(TabItem item) { + int count = getQTabWidget().count(); + int index = 0; + while (index < count) { + if (items.get(index) == item) { + break; + } + index++; + } + if (index == count) { + return; + } + int selectionIndex = getQTabWidget().currentIndex(); + items.remove(count); + if (count > 0 && index == selectionIndex) { + setSelection(Math.max(0, selectionIndex - 1), true); + } + } + + @Override + Control findThemeControl() { + /* It is not possible to change the background of this control */ + return this; + } + + @Override + public Rectangle getClientArea() { + checkWidget(); + return QtSWTConverter.convert(getQTabWidget().contentsRect()); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the user changes the receiver's selection, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * When <code>widgetSelected</code> is called, the item field of the event + * object is valid. <code>widgetDefaultSelected</code> is not called. + * </p> + * + * @param listener + * the listener which should be notified when the user changes + * the receiver's selection + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + /** + * 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 = getQTabWidget().count(); + if (!(0 <= index && index < count)) { + error(SWT.ERROR_INVALID_RANGE); + } + return items.get(index); + } + + /** + * Returns the tab item at the given point in the receiver or null if no + * such item exists. The point is in the coordinate system of the receiver. + * + * @param point + * the point used to locate the item + * @return the tab item at the given point, or null if the point is not in a + * tab item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public TabItem getItem(Point point) { + checkWidget(); + if (point == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + QWidget widget = getQTabWidget().childAt(point.x, point.y); + if (widget == null) { + return null; + } + int index = getQTabWidget().indexOf(widget); + if (index < 0 || index >= items.size()) { + return null; + } + return items.get(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 getQTabWidget().count(); + } + + /** + * 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 = getQTabWidget().count(); + 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 = getQTabWidget().currentIndex(); + if (index == -1) { + return new TabItem[0]; + } + return new TabItem[] { items.get(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 getQTabWidget().currentIndex(); + } + + /** + * Searches the receiver's list starting at the first item (index 0) until + * an item is found that is equal to the argument, and returns the index of + * that item. If no item is found, returns -1. + * + * @param item + * the search item + * @return the index of the item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the item is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int indexOf(TabItem item) { + checkWidget(); + if (item == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + int count = getQTabWidget().count(); + for (int i = 0; i < count; i++) { + if (items.get(i) == item) { + return i; + } + } + return -1; + } + + @Override + 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 = getChildrenCount(); + while (index < count) { + if (items.get(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); + } + + @Override + boolean mnemonicHit(char key) { + for (int i = 0; i < items.size(); i++) { + TabItem item = items.get(i); + if (item != null) { + char ch = findMnemonic(item.getText()); + if (Character.toUpperCase(key) == Character.toUpperCase(ch)) { + if (forceFocus()) { + if (i != getSelectionIndex()) { + setSelection(i, true); + } + return true; + } + } + } + } + return false; + } + + @Override + boolean mnemonicMatch(char key) { + for (int i = 0; i < items.size(); i++) { + TabItem item = items.get(i); + if (item != null) { + char ch = findMnemonic(item.getText()); + if (Character.toUpperCase(key) == Character.toUpperCase(ch)) { + return true; + } + } + } + return false; + } + + @Override + void releaseChildren(boolean destroy) { + if (items != null) { + int count = getQTabWidget().count(); + for (int i = 0; i < count; i++) { + TabItem item = items.get(i); + if (item != null && !item.isDisposed()) { + item.release(false); + } + } + items = null; + } + super.releaseChildren(destroy); + } + + @Override + void removeControl(Control control) { + super.removeControl(control); + int count = getQTabWidget().count(); + for (int i = 0; i < count; i++) { + TabItem item = items.get(i); + if (item.control == control) { + getQTabWidget().removeTab(i); + item.setControl(null); + } + } + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the user changes the receiver's selection. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + /** + * Sets the receiver's selection to the given item. The current selected is + * first cleared, then the new item is selected. + * + * @param item + * the item to select + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the item is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public void setSelection(TabItem item) { + checkWidget(); + if (item == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + setSelection(new TabItem[] { item }); + } + + /** + * Sets the receiver's selection to be the given array of items. The current + * selected is first cleared, then the new items are selected. + * + * @param items + * the array of items + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the items array is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setSelection(TabItem[] items) { + checkWidget(); + if (items == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (items.length == 0) { + setSelection(-1, false); + } else { + for (int i = items.length - 1; i >= 0; --i) { + int index = indexOf(items[i]); + if (index != -1) { + setSelection(index, false); + } + } + } + } + + @Override + public void setFont(Font font) { + checkWidget(); + Rectangle oldRect = getClientArea(); + super.setFont(font); + Rectangle newRect = getClientArea(); + if (!oldRect.equals(newRect)) { + //sendResize(); + int index = getQTabWidget().currentIndex(); + if (index != -1) { + TabItem item = items.get(index); + Control control = item.control; + if (control != null && !control.isDisposed()) { + control.setBounds(getClientArea()); + } + } + } + } + + /** + * Selects the item at the given zero-relative index in the receiver. If the + * item at the index was already selected, it remains selected. The current + * selection is first cleared, then the new items are selected. Indices that + * are out of range are ignored. + * + * @param index + * the index of the item to select + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setSelection(int index) { + checkWidget(); + int count = getQTabWidget().count(); + if (!(0 <= index && index < count)) { + return; + } + setSelection(index, false); + } + + void setSelection(int index, boolean notify) { + int oldIndex = getQTabWidget().currentIndex(); + if (oldIndex == index) { + return; + } + if (oldIndex != -1) { + TabItem item = items.get(oldIndex); + Control control = item.control; + if (control != null && !control.isDisposed()) { + control.setVisible(false); + } + } + getQTabWidget().setCurrentIndex(index); + int newIndex = getQTabWidget().currentIndex(); + if (newIndex != -1) { + TabItem item = items.get(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); + } + } + } + + @Override + boolean traversePage(boolean next) { + int count = getItemCount(); + if (count <= 1) { + return false; + } + int index = getSelectionIndex(); + if (index == -1) { + index = 0; + } else { + int offset = next ? 1 : -1; + index = (index + offset + count) % count; + } + setSelection(index, true); + if (index == getSelectionIndex()) { + // TODO + //OS.SendMessage(handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0); + return true; + } + return false; + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TabItem.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TabItem.java new file mode 100644 index 0000000000..e6a3286797 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TabItem.java @@ -0,0 +1,389 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Rectangle; + +/** + * Instances of this class represent a selectable user interface object + * corresponding to a tab for a page in a tab folder. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>(none)</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#tabfolder">TabFolder, + * TabItem snippets</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class TabItem extends Item { + TabFolder parent; + Control control; + private 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 zero-relative index to store the receiver in its parent + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the parent (inclusive)</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public TabItem(TabFolder parent, int style, int index) { + super(parent, style); + this.parent = parent; + parent.createItem(this, index); + } + + void _setText(int index, String string) { + parent.getQTabWidget().setTabText(index, string); + } + + @Override + protected void checkSubclass() { + if (!isValidSubclass()) { + error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + @Override + void destroyWidget() { + parent.destroyItem(this); + releaseQWidget(); + } + + /** + * Returns the control that is used to fill the client area of the tab + * folder when the user selects the tab item. If no control has been set, + * return <code>null</code>. + * <p> + * + * @return the control + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + */ + public Control getControl() { + checkWidget(); + return control; + } + + /** + * Returns a rectangle describing the receiver's size and location relative + * to its parent. + * + * @return the receiver's bounding rectangle + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public Rectangle getBounds() { + checkWidget(); + int index = parent.indexOf(this); + if (index == -1 || control == null) { + return new Rectangle(0, 0, 0, 0); + } + return control.getBounds(); + } + + /** + * 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; + } + + @Override + void releaseQWidget() { + super.releaseQWidget(); + parent = null; + } + + @Override + void releaseParent() { + super.releaseParent(); + int index = parent.indexOf(this); + if (index == parent.getSelectionIndex()) { + if (control != null) { + control.setVisible(false); + } + } + } + + @Override + void releaseWidget() { + super.releaseWidget(); + control = null; + } + + /** + * Sets the control that is used to fill the client area of the tab folder + * when the user selects the tab item. + * <p> + * + * @param control + * the new control (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the control has been + * disposed</li> <li>ERROR_INVALID_PARENT - if the control is + * not in the same widget tree</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + */ + public void setControl(Control control) { + checkWidget(); + if (control != null) { + if (control.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (control.parent != parent) { + error(SWT.ERROR_INVALID_PARENT); + } + } + if (this.control != null && this.control.isDisposed()) { + this.control = null; + } + Control oldControl = this.control, newControl = control; + this.control = control; + parent.updateItem(this, oldControl); + int index = parent.indexOf(this), selectionIndex = parent.getSelectionIndex(); + if (index != selectionIndex) { + if (newControl != null) { + if (selectionIndex != -1) { + Control selectedControl = parent.getItem(selectionIndex).getControl(); + if (selectedControl == newControl) { + return; + } + } + return; + } + } + } + + @Override + public void setImage(Image image) { + checkWidget(); + int index = parent.indexOf(this); + if (index == -1) { + return; + } + super.setImage(image); + // TODO + } + + /** + * 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> + * + */ + @Override + public void setText(String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (string.equals(text)) { + return; + } + int index = parent.indexOf(this); + if (index == -1) { + return; + } + super.setText(string); + _setText(index, string); + } + + /** + * Sets the receiver's tool tip text to the argument, which may be null + * indicating that the default tool tip for the control will be shown. For a + * control that has a default tool tip, such as the Tree control on Windows, + * setting the tool tip text to an empty string replaces the default, + * causing no tool tip text to be shown. + * <p> + * The mnemonic indicator (character '&') is not displayed in a tool + * tip. To display a single '&' in the tool tip, the character '&' + * can be escaped by doubling it in the string. + * </p> + * + * @param string + * the new tool tip text (or null) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setToolTipText(String string) { + checkWidget(); + toolTipText = string; + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Table.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Table.java new file mode 100644 index 0000000000..4783422fed --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Table.java @@ -0,0 +1,2561 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import static com.trolltech.qt.core.Qt.ItemDataRole.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import com.trolltech.qt.core.QModelIndex; +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.core.Qt; +import com.trolltech.qt.core.Qt.AlignmentFlag; +import com.trolltech.qt.core.Qt.DropActions; +import com.trolltech.qt.core.Qt.ItemFlag; +import com.trolltech.qt.core.Qt.ItemFlags; +import com.trolltech.qt.core.Qt.Orientation; +import com.trolltech.qt.core.Qt.ScrollBarPolicy; +import com.trolltech.qt.core.Qt.SortOrder; +import com.trolltech.qt.gui.QAbstractTableModel; +import com.trolltech.qt.gui.QBrush; +import com.trolltech.qt.gui.QDragEnterEvent; +import com.trolltech.qt.gui.QDragLeaveEvent; +import com.trolltech.qt.gui.QDragMoveEvent; +import com.trolltech.qt.gui.QDropEvent; +import com.trolltech.qt.gui.QHeaderView; +import com.trolltech.qt.gui.QItemSelection; +import com.trolltech.qt.gui.QTableView; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QAbstractItemView.DragDropMode; +import com.trolltech.qt.gui.QAbstractItemView.EditTrigger; +import com.trolltech.qt.gui.QAbstractItemView.SelectionBehavior; +import com.trolltech.qt.gui.QAbstractItemView.SelectionMode; +import com.trolltech.qt.gui.QHeaderView.ResizeMode; +import com.trolltech.qt.gui.QItemSelectionModel.SelectionFlag; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.internal.qt.QtSWTConverter; +import org.eclipse.swt.internal.qt.SignalConnector; + +/** + * Instances of this class implement a selectable user interface object that + * displays a list of images and strings and issues notification when selected. + * <p> + * The item children that may be added to instances of this class must be of + * type <code>TableItem</code>. + * </p> + * <p> + * Style <code>VIRTUAL</code> is used to create a <code>Table</code> whose + * <code>TableItem</code>s are to be populated by the client on an on-demand + * basis instead of up-front. This can provide significant performance + * improvements for tables that are very large or for which + * <code>TableItem</code> population is expensive (for example, retrieving + * values from an external source). + * </p> + * <p> + * Here is an example of using a <code>Table</code> with style + * <code>VIRTUAL</code>: <code><pre> + * final Table table = new Table (parent, SWT.VIRTUAL | SWT.BORDER); + * table.setItemCount (1000000); + * table.addListener (SWT.SetData, new Listener () { + * public void handleEvent (Event event) { + * TableItem item = (TableItem) event.item; + * int index = table.indexOf (item); + * item.setText ("Item " + index); + * System.out.println (item.getText ()); + * } + * }); + * </pre></code> + * </p> + * <p> + * Note that although this class is a subclass of <code>Composite</code>, it + * does not normally make sense to add <code>Control</code> children to it, or + * set a layout on it, unless implementing something like a cell editor. + * </p> + * <p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>SINGLE, MULTI, CHECK, FULL_SELECTION, HIDE_SELECTION, VIRTUAL, NO_SCROLL</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection, DefaultSelection, SetData, MeasureItem, EraseItem, PaintItem</dd> + * </dl> + * </p> + * <p> + * Note: Only one of the styles SINGLE, and MULTI may be specified. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#table">Table, TableItem, + * TableColumn snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class Table extends Composite { + // aka rows, contains the cells/data + TableColumn sortColumn; + private int sortDirection; + private TableModel model; + + private SignalConnector itemSelectionChanged; + private static final int DEFAULT_ITEMHIGHT = 14; + private int itemHeight = DEFAULT_ITEMHIGHT; + + /** + * Constructs a new instance of this class given its parent and a style + * value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a composite control which will be the parent of the new + * instance (cannot be null) + * @param style + * the style of control to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#SINGLE + * @see SWT#MULTI + * @see SWT#CHECK + * @see SWT#FULL_SELECTION + * @see SWT#HIDE_SELECTION + * @see SWT#VIRTUAL + * @see SWT#NO_SCROLL + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public Table(Composite parent, int style) { + super(parent, checkStyle(style)); + } + + @Override + protected QWidget createQWidget(int style) { + state &= ~(CANVAS | THEME_BACKGROUND); + + QTableView table = new MyQTableWidget(); + model = new TableModel(isVirtual()); + table.setModel(model); + + table.verticalHeader().hide(); + table.horizontalHeader().hide(); + table.setEditTriggers(EditTrigger.NoEditTriggers); + table.setShowGrid(false); + table.setWordWrap(false); + table.setHorizontalScrollBarPolicy(ScrollBarPolicy.ScrollBarAsNeeded); + table.setVerticalScrollBarPolicy(ScrollBarPolicy.ScrollBarAsNeeded); + table.horizontalHeader().setResizeMode(ResizeMode.Interactive); + table.horizontalHeader().setStretchLastSection(true); + table.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft); + table.horizontalHeader().setContentsMargins(0, 0, 0, 0); + if ((style & SWT.MULTI) != 0) { + table.setSelectionMode(SelectionMode.ExtendedSelection); + } else { + table.setSelectionMode(SelectionMode.SingleSelection); + } + table.setSelectionBehavior(SelectionBehavior.SelectRows); + setQMasterWidget(table); + return table.viewport(); + } + + @Override + protected void connectSignals() { + itemSelectionChanged = new SignalConnector(getQTableWidget().selectionModel().selectionChanged, this, + "qtItemSelectionChangedEvent()").connect(); //$NON-NLS-1$ + } + + protected void qtItemSelectionChangedEvent() { + int selectionIndex = getSelectionIndex(); + Event event = new Event(); + event.type = SWT.Selection; + if (selectionIndex != -1) { + event.item = getItem(selectionIndex); + } + sendEvent(SWT.Selection, event, true); + } + + protected void selectionEvent(QItemSelection selected, QItemSelection deselected) { + sendEvent(SWT.Selection); + } + + public QTableView getQTableWidget() { + return (QTableView) getQMasterWidget(); + } + + static int checkStyle(int style) { + if ((style & SWT.NO_SCROLL) == 0) { + style |= SWT.H_SCROLL | SWT.V_SCROLL; + } + return checkBits(style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0); + } + + @Override + protected void updateAutoFillBackground() { + // nothing + } + + @Override + protected void updateBackground() { + super.updateBackground(); + } + + @Override + void updateBackgroundImage() { + //super.updateBackgroundImage(); + } + + @Override + protected Color getDefaultBackgroundColor() { + return display.getSystemColor(SWT.COLOR_LIST_BACKGROUND); + } + + @Override + public void setDragEnabled(boolean enabled) { + getQTableWidget().setDragEnabled(enabled); + } + + @Override + public void setAcceptDrops(boolean accept) { + super.setAcceptDrops(accept); + getQTableWidget().setDragDropMode(DragDropMode.DragDrop); + getQTableWidget().setDropIndicatorShown(true); + } + + void addItem(TableItem item, int row) { + model.addItem(item, row, false); + } + + void removeRow(TableItem row) { + model.removeRow(row); + } + + void addColumn(TableColumn column, int index) { + model.addColumn(column, index); + } + + void removeColumn(TableColumn column) { + model.removeColumn(column); + } + + void rowChanged(TableItem row) { + model.rowChanged(row); + } + + void cellChanged(TableItem row, int column) { + model.cellChanged(row, column); + } + + void columnChanged(TableColumn column) { + model.columnChanged(column); + } + + Rectangle visualRect(TableItem row, int column) { + return QtSWTConverter.convert(getQTableWidget().visualRect(model.index(indexOf(row), column))); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the user changes the receiver's selection, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * When <code>widgetSelected</code> is called, the item field of the event + * object is valid. If the receiver has the <code>SWT.CHECK</code> style and + * the check selection changes, the event object detail field contains the + * value <code>SWT.CHECK</code>. <code>widgetDefaultSelected</code> is + * typically called when an item is double-clicked. The item field of the + * event object is valid for default selection, but the detail field is not + * used. + * </p> + * + * @param listener + * the listener which should be notified when the user changes + * the receiver's selection + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + boolean checkData(TableItem item, boolean redraw) { + if ((style & SWT.VIRTUAL) == 0) { + return true; + } + + if (!item.cached) { + item.cached = true; + Event event = new Event(); + event.item = item; + event.index = indexOf(item); + sendEvent(SWT.SetData, event); + // widget could be disposed at this point + if (isDisposed() || item.isDisposed()) { + return false; + } + } + return true; + } + + @Override + protected void checkSubclass() { + if (!isValidSubclass()) { + error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + /** + * Clears the item at the given zero-relative index in the receiver. The + * text, icon and other attributes of the item are set to the default value. + * If the table was created with the <code>SWT.VIRTUAL</code> style, these + * attributes are requested again as needed. + * + * @param index + * the index of the item to clear + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list minus 1 (inclusive) + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SWT#VIRTUAL + * @see SWT#SetData + * + * @since 3.0 + */ + public void clear(int index) { + checkWidget(); + validateItemIndex(index); + model.getRow(index).clear(); + } + + /** + * Removes the items from the receiver which are between the given + * zero-relative start and end indices (inclusive). The text, icon and other + * attributes of the items are set to their default values. If the table was + * created with the <code>SWT.VIRTUAL</code> style, these attributes are + * requested again as needed. + * + * @param start + * the start index of the item to clear + * @param end + * the end index of the item to clear + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if either the start or end are + * not between 0 and the number of elements in the list minus + * 1 (inclusive)</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SWT#VIRTUAL + * @see SWT#SetData + * + * @since 3.0 + */ + public void clear(int start, int end) { + checkWidget(); + if (start > end) { + return; + } + int count = model.rowCount(); + if (!(0 <= start && start <= end && end < count)) { + error(SWT.ERROR_INVALID_RANGE); + } + if (start == 0 && end == count - 1) { + clearAll(); + } + for (int index = start; index < end; index++) { + model.getRow(index).clear(); + } + } + + /** + * Clears the items at the given zero-relative indices in the receiver. The + * text, icon and other attributes of the items are set to their default + * values. If the table was created with the <code>SWT.VIRTUAL</code> style, + * these attributes are requested again as needed. + * + * @param indices + * the array of indices of the items + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list minus 1 (inclusive) + * </li> + * <li>ERROR_NULL_ARGUMENT - if the indices array is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SWT#VIRTUAL + * @see SWT#SetData + * + * @since 3.0 + */ + public void clear(int[] indices) { + checkWidget(); + if (indices == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (indices.length == 0) { + return; + } + int count = model.rowCount(); + for (int i = 0; i < indices.length; i++) { + if (!(0 <= indices[i] && indices[i] < count)) { + error(SWT.ERROR_INVALID_RANGE); + } + } + for (int index : indices) { + model.getRow(index).clear(); + } + } + + /** + * Clears all the items in the receiver. The text, icon and other attributes + * of the items are set to their default values. If the table was created + * with the <code>SWT.VIRTUAL</code> style, these attributes are requested + * again as needed. + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SWT#VIRTUAL + * @see SWT#SetData + * + * @since 3.0 + */ + public void clearAll() { + checkWidget(); + model.clearAllItems(); + //getQTableWidget().clearContents(); + } + + @Override + public void pack() { + // getQTableWidget().resizeColumnsToContents(); + // getQTableWidget().resizeRowsToContents(); + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + checkWidget(); + QSize size = getQTableWidget().sizeHint(); + + if (getItemCount() > 0) { + int width = 0; + int height = 0; + + // Checkbox column + if ((style & SWT.CHECK) != 0 || (style & SWT.RADIO) != 0) { + width += getQTableWidget().columnWidth(0); + } + + if (getColumnCount() > 0) { + for (int i = 0; i < getColumnCount(); i++) { + // if ( getColumn( i ).useFixedWidth ) { + // width += getQTableWidget().columnWidth( i ); + // } else { + width += getColumn(i).getPreferredColumnWidth(i); + // } + } + } else { // list mode width += + getQTableWidget().sizeHintForColumn(1); + } + + int borderWidth = getBorderWidth(); + width += 2 * borderWidth; + height += 2 * borderWidth; + height += getHeaderHeight(); + int items = getItemCount(); + height += items * _getItemHeight(); + size.setWidth(width); + size.setHeight(height); + } + + return QtSWTConverter.convert(size); + } + + /** + * Deselects the items at the given zero-relative indices in the receiver. + * If the item at the given zero-relative index in the receiver is selected, + * it is deselected. If the item at the index was not selected, it remains + * deselected. Indices that are out of range and duplicate indices are + * ignored. + * + * @param indices + * the array of indices for the items to deselect + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the set of indices is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void deselect(int[] indices) { + checkWidget(); + if (indices == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (indices.length == 0) { + return; + } + for (int index : indices) { + _select(index, 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(); + _select(index, 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(); + _select(start, end, 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(); + itemSelectionChanged.runDisconnected(new Runnable() { + public void run() { + getQTableWidget().clearSelection(); + } + }); + } + + /** + * Returns the column at the given, zero-relative index in the receiver. + * Throws an exception if the index is out of range. Columns are returned in + * the order that they were created. If no <code>TableColumn</code>s were + * created by the programmer, this method will throw + * <code>ERROR_INVALID_RANGE</code> despite the fact that a single column of + * data may be visible in the table. This occurs when the programmer uses + * the table like a list, adding items but never creating a column. + * + * @param index + * the index of the column to return + * @return the column at the given index + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list minus 1 (inclusive) + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Table#getColumnOrder() + * @see Table#setColumnOrder(int[]) + * @see TableColumn#getMoveable() + * @see TableColumn#setMoveable(boolean) + * @see SWT#Move + */ + public TableColumn getColumn(int index) { + checkWidget(); + return model.getColumn(index); + } + + /** + * Returns the number of columns contained in the receiver. If no + * <code>TableColumn</code>s were created by the programmer, this value is + * zero, despite the fact that visually, one column of items may be visible. + * This occurs when the programmer uses the table like a list, adding items + * but never creating a column. + * + * @return the number of columns + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getColumnCount() { + checkWidget(); + return model.columnCount(); + } + + /** + * Returns an array of zero-relative integers that map the creation order of + * the receiver's items to the order in which they are currently being + * displayed. + * <p> + * Specifically, the indices of the returned array represent the current + * visual order of the items, and the contents of the array represent the + * creation order of the items. + * </p> + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its list of items, so modifying the array will not affect the receiver. + * </p> + * + * @return the current visual order of the receiver's items + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Table#setColumnOrder(int[]) + * @see TableColumn#getMoveable() + * @see TableColumn#setMoveable(boolean) + * @see SWT#Move + * + * @since 3.1 + */ + public int[] getColumnOrder() { + checkWidget(); + if (model.columnCount() == 0) { + return new int[0]; + } + return _getColumnOrder(); + } + + private int[] _getColumnOrder() { + int columnCount = model.columnCount(); + int[] order = new int[columnCount]; + QHeaderView header = getQTableWidget().horizontalHeader(); + for (int i = 0; i < columnCount; i++) { + order[i] = header.visualIndex(i); + } + return order; + } + + /** + * Returns an array of <code>TableColumn</code>s which are the columns in + * the receiver. Columns are returned in the order that they were created. + * If no <code>TableColumn</code>s were created by the programmer, the array + * is empty, despite the fact that visually, one column of items may be + * visible. This occurs when the programmer uses the table like a list, + * adding items but never creating a column. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its list of items, so modifying the array will not affect the receiver. + * </p> + * + * @return the items in the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Table#getColumnOrder() + * @see Table#setColumnOrder(int[]) + * @see TableColumn#getMoveable() + * @see TableColumn#setMoveable(boolean) + * @see SWT#Move + */ + public TableColumn[] getColumns() { + checkWidget(); + return model.getColumns(); + } + + /** + * Returns the width in pixels of a grid line. + * + * @return the width of a grid line in pixels + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getGridLineWidth() { + checkWidget(); + return getQTableWidget().showGrid() ? 1 : 0; + } + + /** + * Returns the height of the receiver's header + * + * @return the height of the header or zero if the header is not visible + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 2.0 + */ + public int getHeaderHeight() { + checkWidget(); + if (getQTableWidget().horizontalHeader().isVisible()) { + return getQTableWidget().horizontalHeader().height(); + } + return 0; + } + + /** + * Returns <code>true</code> if the receiver's header is visible, and + * <code>false</code> otherwise. + * <p> + * If one of the receiver's ancestors is not visible or some other condition + * makes the receiver not visible, this method may still indicate that it is + * considered visible even though it may not actually be showing. + * </p> + * + * @return the receiver's header's visibility state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public boolean getHeaderVisible() { + checkWidget(); + return !getQTableWidget().horizontalHeader().isHidden(); + } + + /** + * 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(); + validateItemIndex(index); + return model.getRow(index); + } + + void validateItemIndex(int index) { + if (!(0 <= index && index < model.rowCount())) { + error(SWT.ERROR_INVALID_RANGE); + } + } + + /** + * Returns the item at the given point in the receiver or null if no such + * item exists. The point is in the coordinate system of the receiver. + * <p> + * The item that is returned represents an item that could be selected by + * the user. For example, if selection only occurs in items in the first + * column, then null is returned if the point is outside of the item. Note + * that the SWT.FULL_SELECTION style hint, which specifies the selection + * policy, determines the extent of the selection. + * </p> + * + * @param point + * the point used to locate the item + * @return the item at the given point, or null if the point is not in a + * selectable item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public TableItem getItem(Point point) { + checkWidget(); + if (point == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + int row = getQTableWidget().rowAt(point.y); + if (row < 0) { + return null; + } + return model.getRow(row); + } + + /** + * Returns the number of items contained in the receiver. + * + * @return the number of items + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getItemCount() { + checkWidget(); + return model.rowCount(); + } + + /** + * Returns the height of the area which would be used to display + * <em>one</em> of the items in the receiver. + * + * @return the height of one item + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getItemHeight() { + checkWidget(); + return _getItemHeight(); + } + + int _getItemHeight() { + int itemHeight = 0; + if (model.rowCount() > 0) { + itemHeight = getQTableWidget().rowHeight(0); + } else { + // getQTableWidget().insertRow(0); + // itemHeight = getQTableWidget().rowHeight(0); + // getQTableWidget().removeRow(0); + } + return itemHeight; + } + + /** + * Returns a (possibly empty) array of <code>TableItem</code>s which are the + * items in the receiver. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its list of items, so modifying the array will not affect the receiver. + * </p> + * + * @return the items in the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public TableItem[] getItems() { + checkWidget(); + return model.getRows(); + } + + /** + * Returns <code>true</code> if the receiver's lines are visible, and + * <code>false</code> otherwise. Note that some platforms draw grid lines + * while others may draw alternating row colors. + * <p> + * If one of the receiver's ancestors is not visible or some other condition + * makes the receiver not visible, this method may still indicate that it is + * considered visible even though it may not actually be showing. + * </p> + * + * @return the visibility state of the lines + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public boolean getLinesVisible() { + checkWidget(); + return getQTableWidget().showGrid(); + } + + /** + * Returns an array of <code>TableItem</code>s that are currently selected + * in the receiver. The order of the items is unspecified. An empty array + * indicates that no items are selected. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its selection, so modifying the array will not affect the receiver. + * </p> + * + * @return an array representing the selection + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public TableItem[] getSelection() { + checkWidget(); + List<QModelIndex> selection = getQTableWidget().selectionModel().selectedRows(); + + /* + * This is an insert sort for sorting items according to their rows. In + * SWT/Win32 the selection is returned sorted that way. + */ + for (int i = 0; i < selection.size(); i++) { + QModelIndex selectedItem = selection.get(i); + int j = i; + while (j > 0 && selection.get(j - 1).row() > selectedItem.row()) { + selection.set(j, selection.get(j - 1)); + j = j - 1; + } + selection.set(j, selectedItem); + } + + TableItem items[] = new TableItem[selection.size()]; + int i = 0; + for (QModelIndex index : selection) { + items[i++] = model.getRow(index.row()); + } + return items; + } + + /** + * 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 getQTableWidget().selectionModel().selectedRows().size(); + } + + /** + * 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(); + if (model.rowCount() == 0) { + return -1; + } + // if (getQTableWidget().selectionModel().hasSelection()) { + List<QModelIndex> selectedRows = getQTableWidget().selectionModel().selectedRows(); + if (selectedRows.size() > 0) { + return selectedRows.get(0).row(); + } + // } + return -1; + } + + /** + * Returns the zero-relative indices of the items which are currently + * selected in the receiver. The order of the indices is unspecified. The + * array is empty if no items are selected. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its selection, so modifying the array will not affect the receiver. + * </p> + * + * @return the array of indices of the selected items + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int[] getSelectionIndices() { + checkWidget(); + List<QModelIndex> selectedIndices = getQTableWidget().selectionModel().selectedRows(); + int[] result = new int[selectedIndices.size()]; + int i = 0; + for (QModelIndex index : selectedIndices) { + result[i++] = index.row(); + } + return result; + } + + /** + * Returns the column which shows the sort indicator for the receiver. The + * value may be null if no column shows the sort indicator. + * + * @return the sort indicator + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #setSortColumn(TableColumn) + * + * @since 3.2 + */ + public TableColumn getSortColumn() { + checkWidget(); + return sortColumn; + } + + /** + * Returns the direction of the sort indicator for the receiver. The value + * will be one of <code>UP</code>, <code>DOWN</code> or <code>NONE</code>. + * + * @return the sort direction + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #setSortDirection(int) + * + * @since 3.2 + */ + public int getSortDirection() { + checkWidget(); + return sortDirection; + } + + /** + * Returns the zero-relative index of the item which is currently at the top + * of the receiver. This index can change when items are scrolled or new + * items are added or removed. + * + * @return the index of the top item + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getTopIndex() { + checkWidget(); + return getQTableWidget().rowAt(1); + } + + /** + * Searches the receiver's list starting at the first column (index 0) until + * a column is found that is equal to the argument, and returns the index of + * that column. If no column is found, returns -1. + * + * @param column + * the search column + * @return the index of the column + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the column is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int indexOf(TableColumn column) { + checkWidget(); + if (column == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + return model.indexOf(column); + } + + /** + * Searches the receiver's list starting at the first item (index 0) until + * an item is found that is equal to the argument, and returns the index of + * that item. If no item is found, returns -1. + * + * @param item + * the search item + * @return the index of the item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the item is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int indexOf(TableItem item) { + checkWidget(); + if (item == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + return model.indexOf(item); + } + + boolean isCustomToolTip() { + return hooks(SWT.MeasureItem); + } + + /** + * Returns <code>true</code> if the item is selected, and <code>false</code> + * otherwise. Indices out of range are ignored. + * + * @param index + * the index of the item + * @return the selection state of the item at the index + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public boolean isSelected(int index) { + checkWidget(); + validateItemIndex(index); + return model.getRow(index).isSelected(); + } + + @Override + void releaseChildren(boolean destroy) { + model.release(); + super.releaseChildren(destroy); + } + + /** + * Removes the items from the receiver's list at the given zero-relative + * indices. + * + * @param indices + * the array of indices of the items + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list minus 1 (inclusive) + * </li> + * <li>ERROR_NULL_ARGUMENT - if the indices array is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void remove(int[] indices) { + checkWidget(); + if (indices == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (indices.length == 0) { + return; + } + model.removeItems(indices); + } + + /** + * Removes the item from the receiver at the given zero-relative index. + * + * @param index + * the index for the item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list minus 1 (inclusive) + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void remove(int index) { + checkWidget(); + validateItemIndex(index); + model.removeRowItem(index); + } + + /** + * Removes the items from the receiver which are between the given + * zero-relative start and end indices (inclusive). + * + * @param start + * the start of the range + * @param end + * the end of the range + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if either the start or end are + * not between 0 and the number of elements in the list minus + * 1 (inclusive)</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void remove(int start, int end) { + checkWidget(); + if (start > end) { + return; + } + int count = model.rowCount(); + if (!(0 <= start && start <= end && end < count)) { + error(SWT.ERROR_INVALID_RANGE); + } + if (start == 0 && end == count - 1) { + removeAll(); + } else { + for (int index = end; index >= start; index--) { + model.removeRowItem(index); + } + } + } + + /** + * Removes all of the items from the receiver. + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void removeAll() { + checkWidget(); + model.releaseItems(); + // getQTableWidget().clearContents(); + // getQTableWidget().setRowCount(0); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the user changes the receiver's selection. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener(SelectionListener) + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + /** + * Selects the items at the given zero-relative indices in the receiver. The + * current selection is not cleared before the new items are selected. + * <p> + * If the item at a given index is not selected, it is selected. If the item + * at a given index was already selected, it remains selected. Indices that + * are out of range and duplicate indices are ignored. If the receiver is + * single-select and multiple indices are specified, then all indices are + * ignored. + * </p> + * + * @param indices + * the array of indices for the items to select + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Table#setSelection(int[]) + */ + public void select(int[] indices) { + checkWidget(); + if (indices == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + int length = indices.length; + if (length == 0 || (style & SWT.SINGLE) != 0 && length > 1) { + return; + } + for (int index : indices) { + _select(index, true); + } + } + + /** + * Selects the item at the given zero-relative index in the receiver. If the + * item at the index was already selected, it remains selected. 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, true); + } + + void _select(int index, boolean selected) { + if (index < 0 || index >= model.rowCount()) { + return; + } + getQTableWidget().selectionModel().select(model.index(index, 0), + SelectionFlag.createQFlags(SelectionFlag.Select, SelectionFlag.Rows)); + model.getRow(index).setSelected(selected); + } + + /** + * Selects the items in the range specified by the given zero-relative + * indices in the receiver. The range of indices is inclusive. The current + * selection is not cleared before the new items are selected. + * <p> + * If an item in the given range is not selected, it is selected. If an item + * in the given range was already selected, it remains selected. Indices + * that are out of range are ignored and no items will be selected if start + * is greater than end. If the receiver is single-select and there is more + * than one item in the given range, then all indices are ignored. + * </p> + * + * @param start + * the start of the range + * @param end + * the end of the range + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Table#setSelection(int,int) + */ + public void select(int start, int end) { + checkWidget(); + _select(start, end, true); + } + + void _select(int start, int end, boolean selected) { + if (end < 0 || start > end || (style & SWT.SINGLE) != 0 && start != end) { + return; + } + int count = model.rowCount(); + if (count == 0 || start >= count) { + return; + } + start = Math.max(0, start); + end = Math.min(end, count - 1); + if (start == 0 && end == count - 1) { + if (selected) { + selectAll(); + } else { + deselectAll(); + } + } else { + for (int index = start; index < end; index++) { + _select(index, selected); + } + } + } + + /** + * Selects all of the items in the receiver. + * <p> + * If the receiver is single-select, do nothing. + * </p> + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void selectAll() { + checkWidget(); + if ((style & SWT.SINGLE) != 0) { + return; + } + getQTableWidget().selectAll(); + } + + /** + * Sets the order that the items in the receiver should be displayed in to + * the given argument which is described in terms of the zero-relative + * ordering of when the items were added. + * + * @param order + * the new order to display the items + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the item order is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the item order is not the + * same length as the number of items</li> + * </ul> + * + * @see Table#getColumnOrder() + * @see TableColumn#getMoveable() + * @see TableColumn#setMoveable(boolean) + * @see SWT#Move + * + * @since 3.1 + */ + public void setColumnOrder(int[] order) { + checkWidget(); + if (validateColumnOrder(order)) { + int columnCount = getColumnCount(); + QHeaderView header = getQTableWidget().horizontalHeader(); + for (int i = 0; i < columnCount; i++) { + int visualIndex = header.visualIndex(i); + header.moveSection(visualIndex, order[i]); + } + } + } + + private boolean validateColumnOrder(int[] order) { + if (order == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + int columnCount = model.columnCount(); + if (columnCount == 0) { + if (order.length != 0) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + return false; + } + if (order.length != columnCount) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + int[] oldOrder = _getColumnOrder(); + + boolean reorder = false; + boolean[] seen = new boolean[columnCount]; + for (int i = 0; i < order.length; i++) { + int index = order[i]; + if (index < 0 || index >= columnCount) { + error(SWT.ERROR_INVALID_RANGE); + } + if (seen[index]) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + seen[index] = true; + if (index != oldOrder[i]) { + reorder = true; + } + } + return reorder; + } + + /** + * Marks the receiver's header as visible if the argument is + * <code>true</code>, and marks it invisible otherwise. + * <p> + * If one of the receiver's ancestors is not visible or some other condition + * makes the receiver not visible, marking it visible may not actually cause + * it to be displayed. + * </p> + * + * @param show + * the new visibility state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setHeaderVisible(boolean show) { + checkWidget(); + if (show) { + getQTableWidget().horizontalHeader().show(); + } else { + getQTableWidget().horizontalHeader().hide(); + } + } + + /** + * Sets the number of items contained in the receiver. + * + * @param count + * the number of items + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ + public void setItemCount(int count) { + checkWidget(); + model.setItemCount(count); + } + + /** + * @return true if Table was created with SWT.VIRTUAL style + */ + boolean isVirtual() { + return (style & SWT.VIRTUAL) != 0; + } + + /** + * Sets the height of the area which would be used to display <em>one</em> + * of the items in the table. + * + * @param itemHeight + * 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> + * + * @since 3.2 + */ + /* public */void setItemHeight(int itemHeight) { + checkWidget(); + if (itemHeight < -1) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + this.itemHeight = itemHeight; + int rows = model.rowCount(); + for (int row = 0; row < rows; row++) { + getQTableWidget().setRowHeight(row, itemHeight); + } + } + + /** + * Marks the receiver's lines as visible if the argument is + * <code>true</code>, and marks it invisible otherwise. Note that some + * platforms draw grid lines while others may draw alternating row colors. + * <p> + * If one of the receiver's ancestors is not visible or some other condition + * makes the receiver not visible, marking it visible may not actually cause + * it to be displayed. + * </p> + * + * @param show + * the new visibility state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setLinesVisible(boolean show) { + checkWidget(); + getQTableWidget().setShowGrid(show); + } + + /** + * Selects the items at the given zero-relative indices in the receiver. The + * current selection is cleared before the new items are selected. + * <p> + * Indices that are out of range and duplicate indices are ignored. If the + * receiver is single-select and multiple indices are specified, then all + * indices are ignored. + * </p> + * + * @param indices + * the indices of the items to select + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Table#deselectAll() + * @see Table#select(int[]) + */ + public void setSelection(int[] indices) { + checkWidget(); + if (indices == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + deselectAll(); + int length = indices.length; + if (length == 0 || (style & SWT.SINGLE) != 0 && length > 1) { + return; + } + select(indices); + showSelection(); + } + + /** + * Sets the receiver's selection to the given item. The current selection is + * cleared before the new item is selected. + * <p> + * If the item is not in the receiver, then it is ignored. + * </p> + * + * @param item + * the item to select + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the item is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public void setSelection(TableItem item) { + checkWidget(); + if (item == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + setSelection(new TableItem[] { item }); + } + + /** + * Sets the receiver's selection to be the given array of items. The current + * selection is cleared before the new items are selected. + * <p> + * Items that are not in the receiver are ignored. If the receiver is + * single-select and multiple items are specified, then all items are + * ignored. + * </p> + * + * @param items + * the array of items + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of items is null</li> + * <li>ERROR_INVALID_ARGUMENT - if one of the items has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Table#deselectAll() + * @see Table#select(int[]) + * @see Table#setSelection(int[]) + */ + public void setSelection(TableItem[] items) { + checkWidget(); + if (items == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + deselectAll(); + int length = items.length; + if (length == 0 || (style & SWT.SINGLE) != 0 && length > 1) { + return; + } + for (int i = length - 1; i >= 0; --i) { + int index = indexOf(items[i]); + if (index != -1) { + select(index); + } + } + showSelection(); + } + + /** + * Selects the item at the given zero-relative index in the receiver. The + * current selection is first cleared, then the new item is selected. + * + * @param index + * the index of the item to select + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Table#deselectAll() + * @see Table#select(int) + */ + public void setSelection(int index) { + checkWidget(); + deselectAll(); + select(index); + showSelection(); + } + + /** + * Selects the items in the range specified by the given zero-relative + * indices in the receiver. The range of indices is inclusive. The current + * selection is cleared before the new items are selected. + * <p> + * Indices that are out of range are ignored and no items will be selected + * if start is greater than end. If the receiver is single-select and there + * is more than one item in the given range, then all indices are ignored. + * </p> + * + * @param start + * the start index of the items to select + * @param end + * the end index of the items to select + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Table#deselectAll() + * @see Table#select(int,int) + */ + public void setSelection(int start, int end) { + checkWidget(); + deselectAll(); + if (end < 0 || start > end || (style & SWT.SINGLE) != 0 && start != end) { + return; + } + int count = model.rowCount(); + if (count == 0 || start >= count) { + return; + } + start = Math.max(0, start); + end = Math.min(end, count - 1); + select(start, end); + showSelection(); + } + + /** + * Sets the column used by the sort indicator for the receiver. A null value + * will clear the sort indicator. The current sort column is cleared before + * the new column is set. + * + * @param column + * the column used by the sort indicator or <code>null</code> + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the column is disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public void setSortColumn(TableColumn column) { + checkWidget(); + if (column != null && column.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + sortColumn = column; + if (sortColumn != null && sortDirection != SWT.NONE) { + getQTableWidget().sortByColumn(column.getColumn(), getSortOrder()); + } + } + + private SortOrder getSortOrder() { + if ((sortDirection & SWT.UP) != 0) { + return SortOrder.AscendingOrder; + } + return SortOrder.DescendingOrder; + } + + /** + * Sets the direction of the sort indicator for the receiver. The value can + * be one of <code>UP</code>, <code>DOWN</code> or <code>NONE</code>. + * + * @param direction + * the direction of the sort indicator + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public void setSortDirection(int direction) { + checkWidget(); + if ((direction & (SWT.UP | SWT.DOWN)) == 0 && direction != SWT.NONE) { + return; + } + sortDirection = direction; + if (sortColumn != null && !sortColumn.isDisposed()) { + getQTableWidget().sortByColumn(sortColumn.getColumn(), getSortOrder()); + } + } + + /** + * 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(); + if (!(0 <= index && index < model.rowCount())) { + return; + } + // int currentColumn = getQTableWidget().currentColumn(); + // QTableWidgetItem item = model.getItem(index).getCellItem(currentColumn); + // getQTableWidget().scrollToItem(item, ScrollHint.PositionAtTop); + } + + /** + * Shows the column. If the column is already showing in the receiver, this + * method simply returns. Otherwise, the columns are scrolled until the + * column is visible. + * + * @param column + * the column to be shown + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the column is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the column has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ + public void showColumn(TableColumn column) { + checkWidget(); + if (column == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (column.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (column.getParent() != this) { + return; + } + if (model.rowCount() == 0) { + return; + } + QModelIndex index = getQTableWidget().currentIndex(); + getQTableWidget().scrollTo(model.index(index.row(), model.indexOf(column))); + } + + /** + * 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, 0); + } + } + + void showItem(int row, int col) { + getQTableWidget().scrollTo(model.index(row, col)); + } + + /** + * 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(); + getQTableWidget().scrollTo(getQTableWidget().selectionModel().currentIndex()); + } + + void update(boolean all) { + getQTableWidget().update(); + } + + private final class MyQTableWidget extends QTableView { + + @Override + protected void startDrag(DropActions supportedActions) { + // System.out.println("MyQTreeWidget.startDrag: " + supportedActions); + } + + @Override + protected void dropEvent(QDropEvent event) { + sendDropEvent(event); + } + + @Override + protected void dragMoveEvent(QDragMoveEvent event) { + sendDragMoveEvent(event); + } + + @Override + protected void dragEnterEvent(QDragEnterEvent event) { + sendDragEnterEvent(event); + } + + @Override + protected void dragLeaveEvent(QDragLeaveEvent event) { + sendDragLeaveEvent(event); + } + + } + + final class TableModel extends QAbstractTableModel { + private ArrayList<TableItem> rows; + private List<TableColumn> columns; + private final boolean virtual; + + TableModel(boolean virtual) { + this.virtual = virtual; + init(); + } + + public void init() { + rows = new ArrayList<TableItem>(4); + columns = new ArrayList<TableColumn>(4); + } + + @Override + public Object data(QModelIndex index, int role) { + int row = index.row(); + int column = index.column(); + TableItem rowItem = getRow(row); + switch (role) { + case DisplayRole: + return rowItem.getText(column); + case CheckStateRole: + if ((style & SWT.CHECK) != 0 && column == 0) { + return rowItem.getChecked(); + } + break; + case DecorationRole: + Image img = rowItem.getImage(column); + if (img != null) { + return img.getQPixmap(); + } + break; + case BackgroundRole: { + Color color = rowItem.getBackground(column); + if (color != null) { + return new QBrush(color.getColor()); + } + break; + } + case ForegroundRole: { + Color color = rowItem.getForeground(column); + if (color != null) { + return new QBrush(color.getColor()); + } + break; + } + } + return null; + } + + @Override + public boolean setData(QModelIndex index, Object value, int role) { + if (role == CheckStateRole) { + getRow(index.row()).setChecked(((Boolean) value).booleanValue()); + dataChanged.emit(index, index); + return true; + } + return super.setData(index, value, role); + } + + @Override + public ItemFlags flags(QModelIndex index) { + int column = index.column(); + if ((style & SWT.CHECK) != 0 && column == 0) { + return new ItemFlags(new ItemFlag[] { ItemFlag.ItemIsSelectable, ItemFlag.ItemIsEditable, + ItemFlag.ItemIsEnabled, ItemFlag.ItemIsUserCheckable }); + } + return super.flags(index); + } + + @Override + public int rowCount(QModelIndex index) { + return rows.size(); + } + + void setItemCount(int count) { + count = Math.max(0, count); + if (count < rows.size()) { + beginRemoveRows(null, rows.size(), count - 1); + for (int i = rows.size() - 1; i >= count; i--) { + TableItem row = rows.remove(i); + row.release(false); + } + endRemoveRows(); + } else { + beginInsertRows(null, rows.size(), count - 1); + rows.ensureCapacity(count); + boolean virtual = isVirtual(); + for (int i = rows.size(); i < count; i++) { + if (virtual) { + rows.add(null); + } else { + rows.add(new TableItem(Table.this, SWT.NONE, i)); + } + } + endInsertRows(); + } + } + + TableItem getRow(int index) { + TableItem item = rows.get(index); + if (item != null) { + return item; + } + if (!virtual) { + return null; + } + item = new TableItem(Table.this, SWT.NONE, index, false); + addItem(item, index, true); + return item; + } + + public TableItem[] getRows() { + TableItem[] out = new TableItem[rows.size()]; + if (virtual) { + int count = out.length; + for (int i = 0; i < count; i++) { + out[i] = getRow(i); + } + } else { + rows.toArray(out); + } + return out; + } + + int indexOf(TableItem row) { + return rows.indexOf(row); + } + + void addItem(TableItem rowItem, int row, boolean update) { + beginInsertRows(null, row, row); + // if we add items then we need an first column to hold them + if (columns.size() == 0) { + new TableColumn(Table.this, SWT.NONE); + } + if (update) { + rows.set(row, rowItem); + } else { + if (row == rows.size()) { + rows.add(rowItem); + } else { + rows.add(row, rowItem); + } + } + endInsertRows(); + getQTableWidget().setRowHeight(row, itemHeight); + } + + void cellChanged(TableItem rowItem, int column) { + int row = indexOf(rowItem); + QModelIndex index = index(row, column); + dataChanged.emit(index, index); + } + + void rowChanged(TableItem rowItem) { + int row = indexOf(rowItem); + dataChanged.emit(index(row, 0), index(row, columns.size() - 1)); + } + + void removeRow(TableItem row) { + removeRowItem(rows.indexOf(row)); + } + + void removeRowItem(int index) { + if (index != -1) { + beginRemoveRows(null, index, index); + TableItem item = rows.remove(index); + if (item != null && !item.isDisposed()) { + item.release(false); + } + endRemoveRows(); + } + } + + void removeItems(int[] indices) { + int[] newIndices = new int[indices.length]; + System.arraycopy(indices, 0, newIndices, 0, indices.length); + Arrays.sort(newIndices); + for (int i = indices.length - 1; i >= 0; i--) { + validateItemIndex(indices[i]); + removeRowItem(indices[i]); + } + } + + void clearAllItems() { + for (TableItem item : rows) { + if (item != null) { + item.clear(); + } + } + } + + @Override + public int columnCount(QModelIndex index) { + return columns.size(); + } + + TableColumn getColumn(int index) { + validateColumnIndex(index); + return columns.get(index); + } + + int indexOf(TableColumn column) { + return columns.indexOf(column); + } + + private void validateColumnIndex(int index) { + if (!(0 <= index && index < columnCount())) { + error(SWT.ERROR_INVALID_RANGE); + } + } + + void addColumn(TableColumn column, int index) { + if (!(0 <= index && index <= columnCount())) { + error(SWT.ERROR_INVALID_RANGE); + } + beginInsertColumns(null, index, index); + if (index == columns.size()) { + columns.add(column); + } else { + columns.add(index, column); + } + int columnCount = columns.size(); + for (TableItem item : rows) { + if (item != null) { + item.addColumn(index, columnCount); + } + } + endInsertColumns(); + } + + void removeColumn(TableColumn column) { + int index = columns.indexOf(column); + if (index == -1) { + return; + } + beginRemoveColumns(null, index, index); + int columnCount = columnCount(); + columns.remove(column); + for (TableItem item : rows) { + if (item != null) { + item.removeColumn(index, columnCount); + } + } + endRemoveColumns(); + } + + TableColumn[] getColumns() { + TableColumn[] out = new TableColumn[columns.size()]; + return columns.toArray(out); + } + + void release() { + releaseItems(); + releaseColumns(); + } + + private void releaseItems() { + beginRemoveRows(null, 0, rows.size() - 1); + for (TableItem item : rows) { + if (item != null && !item.isDisposed()) { + item.release(false); + } + } + rows.clear(); + endRemoveRows(); + } + + private void releaseColumns() { + beginRemoveColumns(null, 0, columns.size() - 1); + for (TableColumn column : columns) { + if (!column.isDisposed()) { + column.release(false); + } + } + columns.clear(); + endRemoveColumns(); + } + + @Override + public Object headerData(int index, Orientation orientation, int role) { + if (index >= columns.size()) { + return null; + } + switch (role) { + case DisplayRole: + return columnText(index); + case ToolTipRole: + return columnTooltip(index); + case TextAlignmentRole: + return columnAlignment(index); + } + return null; + } + + private Object columnAlignment(int index) { + int alignment = columns.get(index).getAlignment(); + switch (alignment) { + case SWT.LEFT: + return AlignmentFlag.AlignLeft; + case SWT.CENTER: + return AlignmentFlag.AlignCenter; + case SWT.RIGHT: + return AlignmentFlag.AlignRight; + } + return null; + } + + private Object columnText(int index) { + return columns.get(index).getText(); + } + + private Object columnTooltip(int index) { + return columns.get(index).getToolTipText(); + } + + void columnChanged(TableColumn column) { + int index = indexOf(column); + columnChanged(index, index); + } + + void columnChanged(int from, int to) { + headerDataChanged.emit(Orientation.Horizontal, from, to); + } + + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TableColumn.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TableColumn.java new file mode 100644 index 0000000000..84e2e3da83 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TableColumn.java @@ -0,0 +1,664 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.gui.QTableView; +import com.trolltech.qt.gui.QHeaderView.ResizeMode; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; + +/** + * Instances of this class represent a column in a table widget. + * <p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>LEFT, RIGHT, CENTER</dd> + * <dt><b>Events:</b></dt> + * <dd>Move, Resize, Selection</dd> + * </dl> + * </p> + * <p> + * Note: Only one of the styles LEFT, RIGHT and CENTER may be specified. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#table">Table, TableItem, + * TableColumn snippets</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class TableColumn extends Item { + private Table parent; + private boolean resizable, moveable; + private String tooltip; + + /** + * 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) { + this(parent, style, 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> + * <p> + * Note that due to a restriction on some platforms, the first column is + * always left aligned. + * </p> + * + * @param parent + * a composite control which will be the parent of the new + * instance (cannot be null) + * @param style + * the style of control to construct + * @param index + * the zero-relative index to store the receiver in its parent + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the parent (inclusive)</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#LEFT + * @see SWT#RIGHT + * @see SWT#CENTER + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public TableColumn(Table parent, int style, int index) { + super(parent, checkStyle(style)); + resizable = true; + this.parent = parent; + parent.addColumn(this, index); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the control is moved or resized, by sending it one of the messages + * defined in the <code>ControlListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ControlListener + * @see #removeControlListener + */ + public void addControlListener(ControlListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Resize, typedListener); + addListener(SWT.Move, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the control is selected by the user, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * <code>widgetSelected</code> is called when the column header is selected. + * <code>widgetDefaultSelected</code> is not called. + * </p> + * + * @param listener + * the listener which should be notified when the control is + * selected by the user + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + static int checkStyle(int style) { + return checkBits(style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0); + } + + @Override + protected void checkSubclass() { + if (!isValidSubclass()) { + error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + QTableView getQTableView() { + return parent.getQTableWidget(); + } + + int getColumn() { + return parent.indexOf(this); + } + + @Override + void destroyWidget() { + parent.removeColumn(this); + releaseQWidget(); + } + + /** + * 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; + } + + @Override + String getNameText() { + return getText(); + } + + /** + * Returns the receiver's parent, which must be a <code>Table</code>. + * + * @return the receiver's parent + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Table getParent() { + checkWidget(); + return parent; + } + + /** + * Gets the moveable attribute. A column that is not moveable cannot be + * reordered by the user by dragging the header but may be reordered by the + * programmer. + * + * @return the moveable attribute + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Table#getColumnOrder() + * @see Table#setColumnOrder(int[]) + * @see TableColumn#setMoveable(boolean) + * @see SWT#Move + * + * @since 3.1 + */ + public boolean getMoveable() { + checkWidget(); + return moveable; + } + + /** + * 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; + } + + protected int getPreferredColumnWidth(int index) { + if (index != -1) { + int width = getQTableView().sizeHintForColumn(index); + if (parent.getHeaderVisible()) { + width = Math.max(width, getQTableView().horizontalHeader().sectionSizeHint(index)); + } + return width; + } + return 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> + * + * @since 3.2 + */ + public String getToolTipText() { + checkWidget(); + return this.tooltip; + } + + /** + * 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 = getColumn(); + if (index == -1) { + return 0; + } + return getQTableView().columnWidth(index); + } + + /** + * 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(); + getQTableView().resizeColumnToContents(getColumn()); + } + + @Override + void releaseQWidget() { + super.releaseQWidget(); + parent = null; + } + + @Override + void releaseParent() { + super.releaseParent(); + if (parent.sortColumn == this) { + parent.sortColumn = null; + } + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is moved or resized. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ControlListener + * @see #addControlListener + */ + public void removeControlListener(ControlListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Move, listener); + eventTable.unhook(SWT.Resize, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is selected by the user. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + /** + * Controls how text and images will be displayed in the receiver. The + * argument should be one of <code>LEFT</code>, <code>RIGHT</code> or + * <code>CENTER</code>. + * <p> + * Note that due to a restriction on some platforms, the first column is + * always left aligned. + * </p> + * + * @param alignment + * the new alignment + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setAlignment(int alignment) { + checkWidget(); + if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) == 0) { + return; + } + style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER); + style |= alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER); + parent.columnChanged(this); + } + + @Override + public void setImage(Image image) { + checkWidget(); + if (image != null && image.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + super.setImage(image); + parent.columnChanged(this); + } + + /** + * Sets the moveable attribute. A column that is moveable can be reordered + * by the user by dragging the header. A column that is not moveable cannot + * be dragged by the user but may be reordered by the programmer. + * + * @param moveable + * the moveable attribute + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Table#setColumnOrder(int[]) + * @see Table#getColumnOrder() + * @see TableColumn#getMoveable() + * @see SWT#Move + * + * @since 3.1 + */ + public void setMoveable(boolean moveable) { + checkWidget(); + this.moveable = moveable; + // TODO how to it for single column? + getQTableView().horizontalHeader().setMovable(moveable); + } + + /** + * Sets the resizable attribute. A column that is resizable can be resized + * by the user dragging the edge of the header. A column that is not + * resizable cannot be dragged by the user but may be resized by the + * programmer. + * + * @param resizable + * the resize attribute + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setResizable(boolean resizable) { + checkWidget(); + this.resizable = resizable; + ResizeMode resizeMode = resizable ? ResizeMode.Interactive : ResizeMode.Fixed; + int col = getColumn(); + if (col != -1) { + getQTableView().horizontalHeader().setResizeMode(col, resizeMode); + } + } + + @Override + public void setText(String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (string.equals(text)) { + return; + } + super.setText(string); + parent.columnChanged(this); + } + + /** + * Sets the receiver's tool tip text to the argument, which may be null + * indicating that the default tool tip for the control will be shown. For a + * control that has a default tool tip, such as the Tree control on Windows, + * setting the tool tip text to an empty string replaces the default, + * causing no tool tip text to be shown. + * <p> + * The mnemonic indicator (character '&') is not displayed in a tool + * tip. To display a single '&' in the tool tip, the character '&' + * can be escaped by doubling it in the string. + * </p> + * + * @param string + * the new tool tip text (or null) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public void setToolTipText(String string) { + checkWidget(); + this.tooltip = string; + parent.columnChanged(this); + } + + /** + * Sets the width of the receiver. + * + * @param width + * the new width + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setWidth(int width) { + checkWidget(); + if (width < 0) { + return; + } + int index = getColumn(); + if (index == -1) { + return; + } + getQTableView().setColumnWidth(index, width); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TableItem.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TableItem.java new file mode 100644 index 0000000000..fc27cd11a4 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TableItem.java @@ -0,0 +1,1441 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.Qt.FocusPolicy; +import com.trolltech.qt.gui.QRadioButton; +import com.trolltech.qt.gui.QTableView; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Rectangle; + +/** + * Instances of this class represent a selectable user interface object that + * represents an item in a table. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>(none)</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#table">Table, TableItem, + * TableColumn snippets</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class TableItem extends Item { + Table parent; + String[] strings; + Image[] images; + Font font; + Font[] cellFont; + boolean checked, grayed, cached; + int imageIndent; + Color background; + Color foreground; + int[] cellBackground, cellForeground; + private QRadioButton radioButton; + private boolean selected; + + /** + * Constructs a new instance of this class given its parent (which must be a + * <code>Table</code>) and a style value describing its behavior and + * appearance. The item is added to the end of the items maintained by its + * parent. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a composite control which will be the parent of the new + * instance (cannot be null) + * @param style + * the style of control to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public TableItem(Table parent, int style) { + this(parent, style, checkNull(parent).getItemCount(), true); + } + + /** + * Constructs a new instance of this class given its parent (which must be a + * <code>Table</code>), a style value describing its behavior and + * appearance, and the index at which to place it in the items maintained by + * its parent. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a composite control which will be the parent of the new + * instance (cannot be null) + * @param style + * the style of control to construct + * @param index + * the zero-relative index to store the receiver in its parent + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the parent (inclusive)</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public TableItem(Table parent, int style, int index) { + this(parent, style, index, true); + } + + TableItem(Table parent, int style, int index, boolean create) { + super(parent, style); + this.parent = parent; + if (create) { + parent.addItem(this, index); + updateCheckAndRadioPropertyForRow(index); + } + setText(index, "");//$NON-NLS-1$ + } + + private void updateCheckAndRadioPropertyForRow(int row) { + if (radioButton == null && (parent.style & SWT.RADIO) != 0 && (parent.style & SWT.SINGLE) != 0) { + //TODO + radioButton = new QRadioButton(); + radioButton.released.connect(this, "radioButtonClickEvent()");//$NON-NLS-1$ + radioButton.setFocusPolicy(FocusPolicy.NoFocus); + //getQTableWidget().setCellWidget(row, 0, radioButton); + } + } + + protected void radioButtonClickEvent() { + sendEvent(SWT.Selection); + } + + static Table checkNull(Table control) { + if (control == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + return control; + } + + @Override + protected void checkSubclass() { + if (!isValidSubclass()) { + error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + QTableView getQTableWidget() { + return parent.getQTableWidget(); + } + + // int getRow() { + // return parent.indexOf(this); + // } + + void clear() { + text = "";//$NON-NLS-1$ + image = null; + font = null; + strings = null; + images = null; + imageIndent = 0; + checked = grayed = false; + if (background != null) { + background.dispose(); + background = null; + } + if (foreground != null) { + foreground.dispose(); + foreground = null; + } + cellFont = null; + cellBackground = cellForeground = null; + if (parent.isVirtual()) { + cached = false; + } + } + + @Override + void destroyWidget() { + parent.removeRow(this); + releaseQWidget(); + } + + /** + * Returns the receiver's background color. + * + * @return the background color + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 2.0 + */ + public Color getBackground() { + checkWidget(); + if (!parent.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + if (background == null) { + return parent.getBackground(); + } + return background; + } + + /** + * Returns the background color at the given column index in the receiver. + * + * @param index + * the column index + * @return the background color + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ + public Color getBackground(int index) { + checkWidget(); + if (!parent.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + int count = Math.max(1, parent.getColumnCount()); + if (0 > index || index > count - 1) { + return getBackground(); + } + int pixel = cellBackground != null ? cellBackground[index] : -1; + return pixel == -1 ? getBackground() : Color.qt_new(display, 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> + * + * @since 3.2 + */ + public Rectangle getBounds() { + checkWidget(); + if (!parent.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + return getBounds(0); + } + + /** + * Returns a rectangle describing the receiver's size and location relative + * to its parent at a column in the table. + * + * @param column + * 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 column) { + checkWidget(); + if (!parent.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + + if (column < 0 || column >= parent.getItemCount()) { + return new Rectangle(0, 0, 0, 0); + } + return parent.visualRect(this, column); + } + + /** + * Returns <code>true</code> if the receiver is checked, and false + * otherwise. When the parent does not have the <code>CHECK</code> style, + * return false. + * + * @return the checked state of the checkbox + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public boolean getChecked() { + checkWidget(); + if (!parent.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + if ((parent.style & SWT.CHECK) == 0) { + return false; + } + return checked; + } + + /** + * Returns the font that the receiver will use to paint textual information + * for this item. + * + * @return the receiver's font + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ + public Font getFont() { + checkWidget(); + if (!parent.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + return font != null ? font : parent.getFont(); + } + + /** + * Returns the font that the receiver will use to paint textual information + * for the specified cell in this item. + * + * @param index + * the column index + * @return the receiver's font + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ + public Font getFont(int index) { + checkWidget(); + if (!parent.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + int count = Math.max(1, parent.getColumnCount()); + if (0 > index || index > count - 1) { + return getFont(); + } + if (cellFont == null || cellFont[index] == null) { + return getFont(); + } + return cellFont[index]; + } + + /** + * Returns the foreground color that the receiver will use to draw. + * + * @return the receiver's foreground color + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 2.0 + */ + public Color getForeground() { + checkWidget(); + if (!parent.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + if (foreground == null) { + return parent.getForeground(); + } + return foreground; + } + + /** + * + * Returns the foreground color at the given column index in the receiver. + * + * @param index + * the column index + * @return the foreground color + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ + public Color getForeground(int index) { + checkWidget(); + if (!parent.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + int count = Math.max(1, parent.getColumnCount()); + if (0 > index || index > count - 1) { + return getForeground(); + } + int pixel = cellForeground != null ? cellForeground[index] : -1; + return pixel == -1 ? getForeground() : Color.qt_new(display, 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.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + if ((parent.style & SWT.CHECK) == 0) { + return false; + } + return grayed; + } + + @Override + public Image getImage() { + checkWidget(); + if (!parent.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + return super.getImage(); + } + + /** + * Returns the image stored at the given column index in the receiver, or + * null if the image has not been set or if the column does not exist. + * + * @param index + * the column index + * @return the image stored at the given column index in the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Image getImage(int index) { + checkWidget(); + if (!parent.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + if (index == 0) { + return getImage(); + } + if (images != null) { + if (0 <= index && index < images.length) { + return images[index]; + } + } + return null; + } + + /** + * Returns a rectangle describing the size and location relative to its + * parent of an image at a column in the table. An empty rectangle is + * returned if index exceeds the index of the table's last column. + * + * @param index + * the index that specifies the column + * @return the receiver's bounding image rectangle + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Rectangle getImageBounds(int index) { + checkWidget(); + if (!parent.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + //TODO + return getBounds(index); + } + + /** + * Gets the image indent. + * + * @return the indent + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getImageIndent() { + checkWidget(); + if (!parent.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + return imageIndent; + } + + @Override + String getNameText() { + if ((parent.style & SWT.VIRTUAL) != 0) { + if (!cached) { + return "*virtual*"; //$NON-NLS-1$ + } + } + return super.getNameText(); + } + + /** + * Returns the receiver's parent, which must be a <code>Table</code>. + * + * @return the receiver's parent + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Table getParent() { + checkWidget(); + return parent; + } + + @Override + public String getText() { + checkWidget(); + if (!parent.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + return super.getText(); + } + + /** + * Returns the text stored at the given column index in the receiver, or + * empty string if the text has not been set. + * + * @param index + * the column index + * @return the text stored at the given column index in the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String getText(int index) { + checkWidget(); + if (!parent.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + if (index == 0) { + return getText(); + } + if (strings != null) { + if (0 <= index && index < strings.length) { + String string = strings[index]; + return string != null ? string : "";//$NON-NLS-1$ + } + } + return "";//$NON-NLS-1$ + } + + /** + * Returns a rectangle describing the size and location relative to its + * parent of the text at a column in the table. An empty rectangle is + * returned if index exceeds the index of the table's last column. + * + * @param index + * the index that specifies the column + * @return the receiver's bounding text rectangle + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.3 + */ + public Rectangle getTextBounds(int index) { + checkWidget(); + if (!parent.checkData(this, true)) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + //TODO + return getBounds(index); + } + + @Override + void releaseQWidget() { + super.releaseQWidget(); + radioButton = null; + parent = null; + } + + @Override + void releaseWidget() { + super.releaseWidget(); + strings = null; + images = null; + cellFont = null; + cellBackground = cellForeground = null; + } + + /** + * Sets the receiver's background color to the color specified by the + * argument, or to the default system color for the item if the argument is + * null. + * + * @param color + * the new color (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 2.0 + */ + public void setBackground(Color color) { + checkWidget(); + if (color != null && color.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + Color oldColor = background; + if (color == null) { + background = null; + } else { + if (color.equals(background)) { + return; + } + background = color; + } + if (oldColor != null) { + oldColor.dispose(); + } + if ((parent.style & SWT.VIRTUAL) != 0) { + cached = true; + } + + parent.rowChanged(this); + } + + /** + * Sets the background color at the given column index in the receiver to + * the color specified by the argument, or to the default system color for + * the item if the argument is null. + * + * @param index + * the column index + * @param color + * the new color (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ + public void setBackground(int index, Color color) { + checkWidget(); + if (color != null && color.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + int count = Math.max(1, parent.getColumnCount()); + if (0 > index || index > count - 1) { + return; + } + int pixel = -1; + if (color != null) { + pixel = color.getPixel(); + } + if (cellBackground == null) { + cellBackground = new int[count]; + for (int i = 0; i < count; i++) { + cellBackground[i] = -1; + } + } + if (cellBackground[index] == pixel) { + return; + } + cellBackground[index] = pixel; + if ((parent.style & SWT.VIRTUAL) != 0) { + cached = true; + } + parent.cellChanged(this, index); + // QBrush brush = new QBrush(QtSWTConverter.convert(color)); + // getCellItem(index).setBackground(brush); + } + + /** + * Sets the checked state of the checkbox for this item. This state change + * only applies if the Table was created with the SWT.CHECK style. + * + * @param checked + * the new checked state of the checkbox + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setChecked(boolean checked) { + checkWidget(); + if ((parent.style & SWT.CHECK) == 0) { + return; + } + if (this.checked == checked) { + return; + } + setChecked(checked, false); + } + + void setChecked(boolean checked, boolean notify) { + this.checked = checked; + if ((parent.style & SWT.VIRTUAL) != 0) { + cached = true; + } + if (notify) { + Event event = new Event(); + event.item = this; + event.detail = SWT.CHECK; + parent.postEvent(SWT.Selection, event); + } + parent.cellChanged(this, 0); + // CheckState state = checked ? CheckState.Checked : CheckState.Unchecked; + // getCellItem(0).setData(ItemDataRole.CheckStateRole, state); + } + + /** + * Sets the font that the receiver will use to paint textual information for + * this item to the font specified by the argument, or to the default font + * for that kind of control if the argument is null. + * + * @param font + * the new font (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ + public void setFont(Font font) { + checkWidget(); + if (font != null && font.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + Font oldFont = this.font; + if (oldFont == font) { + return; + } + this.font = font; + if (oldFont != null && oldFont.equals(font)) { + return; + } + if (font != null) { + if ((parent.style & SWT.VIRTUAL) != 0) { + cached = true; + } + } + parent.rowChanged(this); + // int row = getRow(); + // int columnCount = parent.getColumnCount(); + // for (int col = 0; col < columnCount; col++) { + // getCellItem(row, col).setFont(font.getQFont()); + // } + } + + /** + * Sets the font that the receiver will use to paint textual information for + * the specified cell in this item to the font specified by the argument, or + * to the default font for that kind of control if the argument is null. + * + * @param index + * the column index + * @param font + * the new font (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ + public void setFont(int index, Font font) { + checkWidget(); + if (font != null && font.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + int count = Math.max(1, parent.getColumnCount()); + if (0 > index || index > count - 1) { + return; + } + if (cellFont == null) { + if (font == null) { + return; + } + cellFont = new Font[count]; + } + Font oldFont = cellFont[index]; + if (oldFont == font) { + return; + } + cellFont[index] = font; + if (oldFont != null && oldFont.equals(font)) { + return; + } + if ((parent.style & SWT.VIRTUAL) != 0) { + cached = true; + } + parent.cellChanged(this, index); + //getCellItem(index).setFont(font.getQFont()); + } + + /** + * Sets the receiver's foreground color to the color specified by the + * argument, or to the default system color for the item if the argument is + * null. + * + * @param color + * the new color (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 2.0 + */ + public void setForeground(Color color) { + checkWidget(); + if (color != null && color.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + Color oldColor = foreground; + if (color == null) { + foreground = null; + } else { + if (color.equals(foreground)) { + return; + } + foreground = color; + } + if (oldColor != null) { + oldColor.dispose(); + } + if ((parent.style & SWT.VIRTUAL) != 0) { + cached = true; + } + parent.rowChanged(this); + // int row = getRow(); + // int columnCount = parent.getColumnCount(); + // QBrush brush = null; + // if (foreground != null) { + // brush = new QBrush(foreground.getColor()); + // } + // for (int col = 0; col < columnCount; col++) { + // getCellItem(row, col).setForeground(brush); + // } + } + + /** + * Sets the foreground color at the given column index in the receiver to + * the color specified by the argument, or to the default system color for + * the item if the argument is null. + * + * @param index + * the column index + * @param color + * the new color (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ + public void setForeground(int index, Color color) { + checkWidget(); + if (color != null && color.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + int count = Math.max(1, parent.getColumnCount()); + if (0 > index || index > count - 1) { + return; + } + int pixel = -1; + if (color != null) { + pixel = color.getPixel(); + } + if (cellForeground == null) { + cellForeground = new int[count]; + for (int i = 0; i < count; i++) { + cellForeground[i] = -1; + } + } + if (cellForeground[index] == pixel) { + return; + } + cellForeground[index] = pixel; + if (parent.isVirtual()) { + cached = true; + } + parent.cellChanged(this, index); + //getCellItem(index).setForeground(new QBrush(QtSWTConverter.convert(color))); + } + + /** + * Sets the grayed state of the checkbox for this item. This state change + * only applies if the Table was created with the SWT.CHECK style. + * + * @param grayed + * the new grayed state of the checkbox; + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setGrayed(boolean grayed) { + checkWidget(); + if ((parent.style & SWT.CHECK) == 0) { + return; + } + if (this.grayed == grayed) { + return; + } + this.grayed = grayed; + if ((parent.style & SWT.VIRTUAL) != 0) { + cached = true; + } + parent.cellChanged(this, 0); + //getCellItem(0).setCheckState(CheckState.PartiallyChecked); + } + + /** + * 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); + } + if (index == 0) { + if (image != null && image.isIcon()) { + if (image.equals(this.image)) { + return; + } + } + super.setImage(image); + } + int count = Math.max(1, parent.getColumnCount()); + if (0 > index || index > count - 1) { + return; + } + if (images == null && index != 0) { + images = new Image[count]; + images[0] = image; + } + if (images != null) { + if (image != null && image.isIcon()) { + if (image.equals(images[index])) { + return; + } + } + images[index] = image; + } + if ((parent.style & SWT.VIRTUAL) != 0) { + cached = true; + } + parent.cellChanged(this, index); + //getCellItem(index).setIcon(image.getQIcon()); + } + + @Override + public void setImage(Image image) { + checkWidget(); + setImage(0, image); + } + + /** + * Sets the indent of the first column's image, expressed in terms of the + * image's width. + * + * @param indent + * the new indent + * + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @deprecated this functionality is not supported on most platforms + */ + @Deprecated + public void setImageIndent(int indent) { + checkWidget(); + //TODO + // if ( indent < 0 ) + // return; + // if ( imageIndent == indent ) + // return; + // imageIndent = indent; + // if ( ( parent.style & SWT.VIRTUAL ) != 0 ) { + // cached = true; + // } else { + // } + } + + /** + * Sets the text for multiple columns in the table. + * + * @param strings + * the array of new strings + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the text is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setText(String[] strings) { + checkWidget(); + if (strings == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + for (int i = 0; i < strings.length; i++) { + String string = strings[i]; + if (string != null) { + setText(i, string); + } + } + } + + /** + * Sets the receiver's text at a column + * + * @param index + * the column index + * @param string + * the new text + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the text is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setText(int index, String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (index == 0) { + if (string.equals(text)) { + return; + } + super.setText(string); + } + int count = Math.max(1, parent.getColumnCount()); + if (0 > index || index > count - 1) { + return; + } + if (strings == null && index != 0) { + strings = new String[count]; + strings[0] = text; + } + if (strings != null) { + if (string.equals(strings[index])) { + return; + } + strings[index] = string; + } + if (parent.isVirtual()) { + cached = true; + } + parent.cellChanged(this, index); + //getCellItem(index).setText(string); + } + + @Override + public void setText(String string) { + checkWidget(); + setText(0, string); + } + + void addColumn(int index, int columnCount) { + String[] strings = this.strings; + if (strings != null) { + String[] temp = new String[columnCount + 1]; + System.arraycopy(strings, 0, temp, 0, index); + System.arraycopy(strings, index, temp, index + 1, columnCount - index); + strings = temp; + } + Image[] images = this.images; + if (images != null) { + Image[] temp = new Image[columnCount + 1]; + System.arraycopy(images, 0, temp, 0, index); + System.arraycopy(images, index, temp, index + 1, columnCount - index); + this.images = temp; + } + if (index == 0) { + if (columnCount != 0) { + if (strings == null) { + this.strings = new String[columnCount + 1]; + this.strings[1] = text; + } + text = ""; //$NON-NLS-1$ + if (images == null) { + images = new Image[columnCount + 1]; + images[1] = image; + } + image = null; + } + } + if (cellBackground != null) { + int[] cellBackground = this.cellBackground; + int[] temp = new int[columnCount + 1]; + System.arraycopy(cellBackground, 0, temp, 0, index); + System.arraycopy(cellBackground, index, temp, index + 1, columnCount - index); + temp[index] = -1; + this.cellBackground = temp; + } + if (cellForeground != null) { + int[] cellForeground = this.cellForeground; + int[] temp = new int[columnCount + 1]; + System.arraycopy(cellForeground, 0, temp, 0, index); + System.arraycopy(cellForeground, index, temp, index + 1, columnCount - index); + temp[index] = -1; + this.cellForeground = temp; + } + if (cellFont != null) { + Font[] cellFont = this.cellFont; + Font[] temp = new Font[columnCount + 1]; + System.arraycopy(cellFont, 0, temp, 0, index); + System.arraycopy(cellFont, index, temp, index + 1, columnCount - index); + this.cellFont = temp; + } + } + + void removeColumn(int index, int columnCount) { + if (columnCount == 0) { + strings = null; + images = null; + cellBackground = null; + cellForeground = null; + cellFont = null; + } else { + if (strings != null) { + String[] strings = this.strings; + if (index == 0) { + text = strings[1] != null ? strings[1] : ""; //$NON-NLS-1$ + } + String[] temp = new String[columnCount]; + System.arraycopy(strings, 0, temp, 0, index); + System.arraycopy(strings, index + 1, temp, index, columnCount - index); + this.strings = temp; + } else { + if (index == 0) { + text = ""; //$NON-NLS-1$ + } + } + if (images != null) { + Image[] images = this.images; + if (index == 0) { + image = images[1]; + } + Image[] temp = new Image[columnCount]; + System.arraycopy(images, 0, temp, 0, index); + System.arraycopy(images, index + 1, temp, index, columnCount - index); + this.images = temp; + } else { + if (index == 0) { + image = null; + } + } + if (cellBackground != null) { + int[] cellBackground = this.cellBackground; + int[] temp = new int[columnCount]; + System.arraycopy(cellBackground, 0, temp, 0, index); + System.arraycopy(cellBackground, index + 1, temp, index, columnCount - index); + this.cellBackground = temp; + } + if (cellForeground != null) { + int[] cellForeground = this.cellForeground; + int[] temp = new int[columnCount]; + System.arraycopy(cellForeground, 0, temp, 0, index); + System.arraycopy(cellForeground, index + 1, temp, index, columnCount - index); + this.cellForeground = temp; + } + if (cellFont != null) { + Font[] cellFont = this.cellFont; + Font[] temp = new Font[columnCount]; + System.arraycopy(cellFont, 0, temp, 0, index); + System.arraycopy(cellFont, index + 1, temp, index, columnCount - index); + this.cellFont = temp; + } + } + + } + + void setSelected(boolean selected) { + this.selected = selected; + // int columns = parent.getColumnCount(); + parent.cellChanged(this, 0); + // int row = getRow(); + // for (int col = 0; col < columns; col++) { + // //getCellItem(row, col).setSelected(selected); + // } + if ((parent.style & SWT.SINGLE) != 0 && (parent.style & SWT.RADIO) != 0) { + radioButton.setChecked(selected); + } + } + + public boolean isSelected() { + return selected; + + // int columns = parent.getColumnCount(); + // int row = getRow(); + // for (int col = 0; col < columns; col++) { + // //TODO + // // if (getCellItem(row, col).isSelected()) { + // // return true; + // // } + // } + // return false; + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Text.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Text.java new file mode 100644 index 0000000000..c456792f05 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Text.java @@ -0,0 +1,1875 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.QPoint; +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.core.Qt.LayoutDirection; +import com.trolltech.qt.gui.QAbstractScrollArea; +import com.trolltech.qt.gui.QContentsMargins; +import com.trolltech.qt.gui.QFontMetrics; +import com.trolltech.qt.gui.QLineEdit; +import com.trolltech.qt.gui.QMouseEvent; +import com.trolltech.qt.gui.QScrollBar; +import com.trolltech.qt.gui.QSizePolicy; +import com.trolltech.qt.gui.QStyle; +import com.trolltech.qt.gui.QTextBlock; +import com.trolltech.qt.gui.QTextCursor; +import com.trolltech.qt.gui.QTextDocument; +import com.trolltech.qt.gui.QTextEdit; +import com.trolltech.qt.gui.QTextLayout; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QFrame.Shape; +import com.trolltech.qt.gui.QLineEdit.EchoMode; +import com.trolltech.qt.gui.QTextCursor.MoveMode; +import com.trolltech.qt.gui.QTextCursor.MoveOperation; +import com.trolltech.qt.gui.QTextEdit.LineWrapMode; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.events.VerifyListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.internal.qt.QtSWTConverter; + +/** + * Instances of this class are selectable user interface objects that allow the + * user to enter and modify text. Text controls can be either single or + * multi-line. When a text control is created with a border, the operating + * system includes a platform specific inset around the contents of the control. + * When created without a border, an effort is made to remove the inset such + * that the preferred size of the control is the same size as the contents. + * <p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>CENTER, ICON_CANCEL, ICON_SEARCH, LEFT, MULTI, PASSWORD, SEARCH, SINGLE, + * RIGHT, READ_ONLY, WRAP</dd> + * <dt><b>Events:</b></dt> + * <dd>DefaultSelection, Modify, Verify</dd> + * </dl> + * <p> + * Note: Only one of the styles MULTI and SINGLE may be specified, and only one + * of the styles LEFT, CENTER, and RIGHT may be specified. + * </p> + * <p> + * Note: The styles ICON_CANCEL and ICON_SEARCH are hints used in combination + * with SEARCH. When the platform supports the hint, the text control shows + * these icons. When an icon is selected, a default selection event is sent with + * the detail field set to one of ICON_CANCEL or ICON_SEARCH. Normally, + * application code does not need to check the detail. In the case of + * ICON_CANCEL, the text is cleared before the default selection event is sent + * causing the application to search for an empty string. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#text">Text snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class Text extends Scrollable { + private static final int minimumLineSpacing = 14; + private static final int verticalMargin = 1; + private static final int horizontalMargin = 2; + + int tabs = 8; + int oldStart, oldEnd; + boolean doubleClick, ignoreModify, ignoreVerify, ignoreCharacter; + private int textLimit; + /** + * The maximum number of characters that can be entered into a text widget. + * <p> + * Note that this value is platform dependent, based upon the native widget + * implementation. + * </p> + */ + public static final int LIMIT; + + /** + * The delimiter used by multi-line text widgets. When text is queried and + * from the widget, it will be delimited using this delimiter. + */ + public static final String DELIMITER; + + /* + * These values can be different on different platforms. Therefore they are + * not initialized in the declaration to stop the compiler from inlining. + */ + static { + // LIMIT is the default maxlength of the QLineEdit + LIMIT = new QLineEdit().maxLength(); + DELIMITER = "\n";//$NON-NLS-1$ + } + + /** + * Constructs a new instance of this class given its parent and a style + * value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a composite control which will be the parent of the new + * instance (cannot be null) + * @param style + * the style of control to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#SINGLE + * @see SWT#MULTI + * @see SWT#READ_ONLY + * @see SWT#WRAP + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public Text(Composite parent, int style) { + super(parent, checkStyle(style)); + setTabStops(tabs); + } + + boolean isSingleLineEdit() { + return (style & SWT.MULTI) == 0; + } + + @Override + protected QWidget createQWidget(int style) { + doubleClick = true; + if (isSingleLineEdit()) { + return createQLineEdit(style); + } + return createQTextEdit(style); + } + + QLineEdit createQLineEdit(int style) { + QLineEdit lineEdit = new QLineEdit(); + if ((style & SWT.READ_ONLY) != 0) { + lineEdit.setReadOnly(true); + } + if ((style & SWT.PASSWORD) != 0) { + lineEdit.setEchoMode(EchoMode.Password); + } + lineEdit.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum); + lineEdit.setContentsMargins(0, 0, 0, 0); + + connectQLineEditSignals(lineEdit); + + lineEdit.setFrame(false); + + return lineEdit; + } + + QWidget createQTextEdit(int style) { + QTextEdit textEdit = new MyQTextEdit(); + if ((style & SWT.READ_ONLY) != 0) { + textEdit.setReadOnly(true); + } + if ((style & SWT.WRAP) != 0) { + textEdit.setLineWrapMode(LineWrapMode.WidgetWidth); + } else { + textEdit.setLineWrapMode(LineWrapMode.NoWrap); + } + connectQTextEditSignals(textEdit); + + textEdit.setFrameShape(Shape.NoFrame); + textEdit.setLineWidth(0); + + return textEdit; + } + + @Override + protected void checkAndUpdateBorder(QWidget control) { + if (isSingleLineEdit()) { + if ((style & SWT.BORDER) != 0) { + getQLineEdit().setFrame(true); + } + } else { + super.checkAndUpdateBorder(control); + } + } + + protected void connectQLineEditSignals(QLineEdit lineEdit) { + lineEdit.textChanged.connect(this, "textChangeEvent(String)"); //$NON-NLS-1$ + } + + protected void connectQTextEditSignals(QTextEdit textEdit) { + textEdit.textChanged.connect(this, "textChangeEvent()"); //$NON-NLS-1$ + } + + protected void textChangeEvent() { + textChangeEvent(null); + } + + protected void textChangeEvent(String text) { + Event event = new Event(); + event.data = text; + sendEvent(SWT.Modify, event); + } + + @Override + void registerQWidget() { + super.registerQWidget(); + if (!isSingleLineEdit()) { + display.addControl(getQTextEdit().viewport(), this); + } + } + + @Override + void deregisterQWidget() { + if (!isSingleLineEdit()) { + display.removeControl(getQTextEdit().viewport()); + } + super.deregisterQWidget(); + } + + private QLineEdit getQLineEdit() { + return (QLineEdit) getQWidget(); + } + + private QTextEdit getQTextEdit() { + return (QTextEdit) getQWidget(); + } + + @Override + QAbstractScrollArea getQScrollArea() { + if (!isSingleLineEdit()) { + return getQTextEdit(); + } + return null; + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the receiver's text is modified, by sending it one of the messages + * defined in the <code>ModifyListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ModifyListener + * @see #removeModifyListener + */ + public void addModifyListener(ModifyListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Modify, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the control is selected by the user, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * <code>widgetSelected</code> is not called for texts. + * <code>widgetDefaultSelected</code> is typically called when ENTER is + * pressed in a single-line text, or when ENTER is pressed in a search text. + * If the receiver has the <code>SWT.SEARCH | SWT.CANCEL</code> style and + * the user cancels the search, the event object detail field contains the + * value <code>SWT.CANCEL</code>. + * </p> + * + * @param listener + * the listener which should be notified when the control is + * selected by the user + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the receiver's text is verified, by sending it one of the messages + * defined in the <code>VerifyListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see VerifyListener + * @see #removeVerifyListener + */ + public void addVerifyListener(VerifyListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Verify, typedListener); + } + + /** + * Appends a string. + * <p> + * The new text is appended to the text at the end of the widget. + * </p> + * + * @param string + * the string to be appended + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void append(String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + string = Display.withCrLf(string); + if (isSingleLineEdit()) { + getQLineEdit().setText(getQLineEdit().text() + string); + } else { + getQTextEdit().append(string); + } + } + + static int checkStyle(int style) { + if ((style & SWT.SEARCH) != 0) { + style |= SWT.SINGLE | SWT.BORDER; + style &= ~SWT.PASSWORD; + style &= ~SWT.ICON_CANCEL; + /* + * NOTE: ICON_CANCEL has the same value as H_SCROLL and ICON_SEARCH + * has the same value as V_SCROLL so they are cleared because + * SWT.SINGLE is set. + */ + } + if ((style & SWT.SINGLE) != 0 && (style & SWT.MULTI) != 0) { + style &= ~SWT.MULTI; + } + style = checkBits(style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0); + if ((style & SWT.SINGLE) != 0) { + style &= ~(SWT.H_SCROLL | SWT.V_SCROLL | SWT.WRAP); + } + if ((style & SWT.WRAP) != 0) { + style |= SWT.MULTI; + style &= ~SWT.H_SCROLL; + } + if ((style & SWT.MULTI) != 0) { + style &= ~SWT.PASSWORD; + } + if ((style & (SWT.SINGLE | SWT.MULTI)) != 0) { + return style; + } + if ((style & (SWT.H_SCROLL | SWT.V_SCROLL)) != 0) { + return style | SWT.MULTI; + } + return style | SWT.SINGLE; + } + + /** + * Clears the selection. + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void clearSelection() { + checkWidget(); + if (isSingleLineEdit()) { + getQLineEdit().setCursorPosition(getQLineEdit().cursorPosition()); + } else { + getQTextEdit().textCursor().clearSelection(); + } + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + checkWidget(); + + if (wHint != SWT.DEFAULT && wHint < 0) { + wHint = SWT.DEFAULT; + } + if (hHint != SWT.DEFAULT && hHint < 0) { + hHint = SWT.DEFAULT; + } + + Point preferredSize; + if (wHint != SWT.DEFAULT && hHint != SWT.DEFAULT) { + preferredSize = new Point(wHint, hHint); + } else if (isSingleLineEdit()) { + if (wHint == SWT.DEFAULT && hHint == SWT.DEFAULT) { + preferredSize = getPreferredSingleLineClientAreaSize(); + } else if (hHint == SWT.DEFAULT) { + preferredSize = new Point(wHint, getPreferredSingleLineClientAreaSize().y); + } else { + preferredSize = new Point(getPreferredSingleLineClientAreaSize().x, hHint); + } + } else { + if (wHint == SWT.DEFAULT && hHint == SWT.DEFAULT) { + preferredSize = getPreferredClientAreaSize(-1); + } else if (hHint == SWT.DEFAULT) { + preferredSize = new Point(wHint, getPreferredClientAreaSize(wHint).y); + } else { + preferredSize = new Point(getPreferredClientAreaSize(hHint).y, hHint); + } + } + + Rectangle trim = computeTrim(0, 0, preferredSize.x, preferredSize.y); + + return new Point(trim.width, trim.height); + } + + private Point getPreferredSingleLineClientAreaSize() { + QFontMetrics fm = new QFontMetrics(getQLineEdit().font()); + QContentsMargins margins = getQLineEdit().getContentsMargins(); + int left = margins.left; + int top = margins.top; + int right = margins.right; + int bottom = margins.bottom; + int h = Math.max(fm.lineSpacing(), minimumLineSpacing) + 2 * verticalMargin + top + bottom; + int w = fm.width(getQLineEdit().text()) + 2 * horizontalMargin + left + right; + Point size = new Point(w, h); + if (size == null) { + return new Point(DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + if (size.x < 0) { + size.x = DEFAULT_WIDTH; + } + if (size.y < 0) { + size.y = DEFAULT_HEIGHT; + } + return size; + } + + private Point getPreferredClientAreaSize(int wHint) { + QTextDocument doc = getQTextEdit().document(); + Point size = null; + if (doc != null) { + double oldTextWidth = doc.textWidth(); + if (wHint >= 0) { + doc.setTextWidth(wHint); + } else { + doc.adjustSize(); + } + QSize preferredSize = doc.size().toSize(); + doc.setTextWidth(oldTextWidth); + size = new Point(preferredSize.width(), preferredSize.height()); + } + + if (size == null) { + return new Point(DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + if (size.x < 0) { + size.x = DEFAULT_WIDTH; + } + if (size.y < 0) { + size.y = DEFAULT_HEIGHT; + } + return size; + } + + @Override + public Rectangle computeTrim(int x, int y, int width, int height) { + checkWidget(); + if (isSingleLineEdit()) { + if ((style & SWT.BORDER) != 0) { + int border = 0; + QStyle style = getQWidget().style(); + if (style != null) { + border = style.pixelMetric(QStyle.PixelMetric.PM_DefaultFrameWidth); + } + x -= border; + y -= border; + width += 2 * border; + height += 2 * border; + } + return new Rectangle(x, y, width, height); + } + return super.computeTrim(x, y, 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(); + if (isSingleLineEdit()) { + getQLineEdit().copy(); + } else { + getQTextEdit().copy(); + } + } + + /** + * Cuts the selected text. + * <p> + * The current selection is first copied to the clipboard and then deleted + * from the widget. + * </p> + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void cut() { + checkWidget(); + if (isSingleLineEdit()) { + getQLineEdit().cut(); + } else { + getQTextEdit().cut(); + } + } + + /** + * Returns the line number of the caret. + * <p> + * The line number of the caret is returned. + * </p> + * + * @return the line number + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getCaretLineNumber() { + checkWidget(); + if (!isSingleLineEdit()) { + int lineNumber = 0; + QTextCursor textCursor = getQTextEdit().textCursor(); + QTextBlock textBlock = textCursor.block(); + QTextLayout textLayout = textBlock.layout(); + if (textLayout != null) { + lineNumber = textLayout.lineForTextPosition(textCursor.position() - textBlock.position()).lineNumber(); + } + lineNumber += getNumberOfPrecedingTextLines(textBlock); + return lineNumber; + } + return 0; + } + + private int getNumberOfPrecedingTextLines(QTextBlock textBlock) { + int lineCount = 0; + while (textBlock.isValid()) { + QTextLayout textLayout = textBlock.layout(); + if (textLayout != null) { + int lines = textLayout.lineCount(); + lineCount += lines > 0 ? lines : 1; + } + textBlock = textBlock.previous(); + } + return lineCount; + } + + /** + * Returns a point describing the receiver's location relative to its parent + * (or its display if its parent is null). + * <p> + * The location of the caret is returned. + * </p> + * + * @return a point, the location of the caret + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Point getCaretLocation() { + checkWidget(); + if (isSingleLineEdit()) { + return new Point(0, 0); + } + return QtSWTConverter.convertPosition(getQTextEdit().cursorRect()); + } + + /** + * Returns the character position of the caret. + * <p> + * Indexing is zero based. + * </p> + * + * @return the position of the caret + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getCaretPosition() { + checkWidget(); + if (isSingleLineEdit()) { + return getQLineEdit().cursorPosition(); + } + return getQTextEdit().textCursor().position(); + } + + /** + * Returns the number of characters. + * + * @return number of characters in the widget + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getCharCount() { + checkWidget(); + if (isSingleLineEdit()) { + return getText().length(); + + } + QTextCursor cursor = getQTextEdit().textCursor(); + int oldPosition = cursor.position(); + cursor.movePosition(MoveOperation.End); + int count = cursor.position(); + cursor.setPosition(oldPosition); + return count; + } + + /** + * Returns the double click enabled flag. + * <p> + * The double click flag enables or disables the default action of the text + * widget when the user double clicks. + * </p> + * + * @return whether or not double click is enabled + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public boolean getDoubleClickEnabled() { + checkWidget(); + return doubleClick; + } + + /** + * Returns the echo character. + * <p> + * The echo character is the character that is displayed when the user + * enters text or the text is changed by the programmer. + * </p> + * + * @return the echo character + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #setEchoChar + */ + public char getEchoChar() { + checkWidget(); + if (isSingleLineEdit()) { + if ((style & SWT.PASSWORD) != 0) { + return '*'; + } + } + return '\0'; + } + + /** + * Returns the editable state. + * + * @return whether or not the receiver is editable + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public boolean getEditable() { + checkWidget(); + if (isSingleLineEdit()) { + return !getQLineEdit().isReadOnly(); + } + return !getQTextEdit().isReadOnly(); + } + + /** + * Returns the number of lines. + * + * @return the number of lines in the widget + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getLineCount() { + checkWidget(); + if (isSingleLineEdit()) { + return 1; + } + QTextDocument textDocument = getQTextEdit().document(); + if (textDocument != null) { + return getNumberOfPrecedingTextLines(textDocument.end()); + } + return 0; + } + + /** + * Returns the line delimiter. + * + * @return a string that is the line delimiter + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #DELIMITER + */ + public String getLineDelimiter() { + checkWidget(); + return DELIMITER; + } + + /** + * Returns the height of a line. + * + * @return the height of a row of text + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getLineHeight() { + checkWidget(); + if (isSingleLineEdit()) { + return getQLineEdit().fontMetrics().lineSpacing(); + } + QTextLayout textLayout = getQTextEdit().textCursor().block().layout(); + if (textLayout != null) { + return (int) Math.round(textLayout.lineAt(0).height()); + } + return 0; + } + + /** + * Returns the orientation of the receiver, which will be one of the + * constants <code>SWT.LEFT_TO_RIGHT</code> or + * <code>SWT.RIGHT_TO_LEFT</code>. + * + * @return the orientation style + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 2.1.2 + */ + public int getOrientation() { + checkWidget(); + return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT); + } + + /** + * Returns the widget message. The message text is displayed as a hint for + * the user, indicating the purpose of the field. + * <p> + * Typically this is used in conjunction with <code>SWT.SEARCH</code>. + * </p> + * + * @return the widget message + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.3 + */ + public String getMessage() { + checkWidget(); + return getQWidget().whatsThis(); + } + + /** + * Returns the character position at the given point in the receiver or -1 + * if no such position exists. The point is in the coordinate system of the + * receiver. + * <p> + * Indexing is zero based. + * </p> + * + * @return the position of the caret + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.3 + */ + // TODO - Javadoc + // /* public */int getPosition( Point point ) { + // checkWidget(); + // if ( point == null ) + // error( SWT.ERROR_NULL_ARGUMENT ); + // int /* long */lParam = OS.MAKELPARAM( point.x, point.y ); + // int position = OS.LOWORD( OS.SendMessage( handle, OS.EM_CHARFROMPOS, 0, + // lParam ) ); + // if ( !OS.IsUnicode && OS.IsDBLocale ) + // position = mbcsToWcsPos( position ); + // return position; + // } + + /** + * Returns a <code>Point</code> whose x coordinate is the character position + * representing the start of the selected text, and whose y coordinate is + * the character position representing the end of the selection. An "empty" + * selection is indicated by the x and y coordinates having the same value. + * <p> + * Indexing is zero based. The range of a selection is from 0..N where N is + * the number of characters in the widget. + * </p> + * + * @return a point representing the selection start and end + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Point getSelection() { + checkWidget(); + if (isSingleLineEdit()) { + int selectionStart = getQLineEdit().selectionStart(); + if (selectionStart == -1) { + int cursorPos = getQLineEdit().cursorPosition(); + return new Point(cursorPos, cursorPos); + } + return new Point(selectionStart, selectionStart + getQLineEdit().selectedText().length()); + } + int start = getQTextEdit().textCursor().selectionStart(); + int end = getQTextEdit().textCursor().selectionStart(); + return new Point(Math.min(start, end), Math.max(start, end)); + } + + /** + * Returns the number of selected characters. + * + * @return the number of selected characters. + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getSelectionCount() { + checkWidget(); + Point selection = getSelection(); + return Math.abs(selection.y - selection.x); + } + + /** + * Gets the selected text, or an empty string if there is no current + * selection. + * + * @return the selected text + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String getSelectionText() { + checkWidget(); + if (isSingleLineEdit()) { + return getQLineEdit().selectedText(); + } + return getQTextEdit().textCursor().selectedText(); + } + + /** + * Returns the number of tabs. + * <p> + * Tab stop spacing is specified in terms of the space (' ') character. The + * width of a single tab stop is the pixel width of the spaces. + * </p> + * + * @return the number of tab characters + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getTabs() { + checkWidget(); + return tabs; + } + + /** + * Returns the widget text. + * <p> + * The text for a text widget is the characters in the widget, or an empty + * string if this has never been set. + * </p> + * + * @return the widget text + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String getText() { + checkWidget(); + if (isSingleLineEdit()) { + return getQLineEdit().text(); + } + return getQTextEdit().toPlainText(); + } + + /** + * Returns a range of text. Returns an empty string if the start of the + * range is greater than the end. + * <p> + * Indexing is zero based. The range of a selection is from 0..N-1 where N + * is the number of characters in the widget. + * </p> + * + * @param start + * the start of the range + * @param end + * the end of the range + * @return the range of text + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String getText(int start, int end) { + checkWidget(); + if (start > end || end < 0) { + return "";//$NON-NLS-1$ + } + + String text = getText(); + if (text != null) { + if (start >= text.length()) { + text = "";//$NON-NLS-1$ + } else { + start = Math.max(0, start); + end = Math.min(end, text.length() - 1); + text = text.substring(start, end + 1); + } + } + return text; + } + + /** + * Returns the maximum number of characters that the receiver is capable of + * holding. + * <p> + * If this has not been changed by <code>setTextLimit()</code>, it will be + * the constant <code>Text.LIMIT</code>. + * </p> + * + * @return the text limit + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #LIMIT + */ + public int getTextLimit() { + checkWidget(); + if (isSingleLineEdit()) { + return getQLineEdit().maxLength(); + } + return textLimit > 0 ? textLimit : LIMIT; + } + + /** + * Returns the zero-relative index of the line which is currently at the top + * of the receiver. + * <p> + * This index can change when lines are scrolled or new lines are added or + * removed. + * </p> + * + * @return the index of the top line + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getTopIndex() { + checkWidget(); + if (isSingleLineEdit()) { + return 0; + } + QScrollBar scrollBar = getQTextEdit().verticalScrollBar(); + int index = 0; + if (scrollBar != null) { + int top = scrollBar.value(); + QTextCursor textCursor = getQTextEdit().cursorForPosition(new QPoint(0, 0)); + QTextBlock topBlock = textCursor.block(); + QTextLayout layout = topBlock.layout(); + if (layout != null && layout.position().y() < top) { + int layoutPos = (int) Math.round(layout.position().y()); + for (int i = 0; i < layout.lineCount() + && layoutPos + layout.lineAt(i).rect().bottom() <= top + layout.lineAt(i).rect().height() / 2; ++i) { + ++index; + } + } + index += getNumberOfPrecedingTextLines(topBlock); + } + return 0; + } + + /** + * Returns the top pixel. + * <p> + * The top pixel is the pixel position of the line that is currently at the + * top of the widget. On some platforms, a text widget can be scrolled by + * pixels instead of lines so that a partial line is displayed at the top of + * the widget. + * </p> + * <p> + * The top pixel changes when the widget is scrolled. The top pixel does not + * include the widget trimming. + * </p> + * + * @return the pixel position of the top line + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getTopPixel() { + checkWidget(); + if (isSingleLineEdit()) { + return 0; + } + return getQTextEdit().verticalScrollBar().value(); + } + + /** + * Inserts a string. + * <p> + * The old selection is replaced with the new text. + * </p> + * + * @param string + * the string + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is + * <code>null</code></li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void insert(String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + string = Display.withCrLf(string); + getQLineEdit().insert(string); + } + + /** + * Pastes text from clipboard. + * <p> + * The selected text is deleted from the widget and new text inserted from + * the clipboard. + * </p> + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void paste() { + checkWidget(); + if (isSingleLineEdit()) { + getQLineEdit().paste(); + } else { + getQTextEdit().paste(); + } + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the receiver's text is modified. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ModifyListener + * @see #addModifyListener + */ + public void removeModifyListener(ModifyListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Modify, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is selected by the user. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is verified. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see VerifyListener + * @see #addVerifyListener + */ + public void removeVerifyListener(VerifyListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Verify, listener); + } + + /** + * Selects all the text in the receiver. + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void selectAll() { + checkWidget(); + if (isSingleLineEdit()) { + getQLineEdit().selectAll(); + } else { + QTextCursor textCursor = getQTextEdit().textCursor(); + textCursor.select(QTextCursor.SelectionType.Document); + getQTextEdit().setTextCursor(textCursor); + } + } + + /** + * Sets the double click enabled flag. + * <p> + * The double click flag enables or disables the default action of the text + * widget when the user double clicks. + * </p> + * <p> + * Note: This operation is a hint and is not supported on platforms that do + * not have this concept. + * </p> + * + * @param doubleClick + * the new double click flag + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setDoubleClickEnabled(boolean doubleClick) { + checkWidget(); + this.doubleClick = doubleClick; + } + + /** + * Sets the echo character. + * <p> + * The echo character is the character that is displayed when the user + * enters text or the text is changed by the programmer. Setting the echo + * character to '\0' clears the echo character and redraws the original + * text. If for any reason the echo character is invalid, or if the platform + * does not allow modification of the echo character, the default echo + * character for the platform is used. + * </p> + * + * @param echo + * the new echo character + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setEchoChar(char echo) { + checkWidget(); + if (isSingleLineEdit()) { + if (echo == '\0') { + getQLineEdit().setEchoMode(EchoMode.Normal); + } else { + getQLineEdit().setEchoMode(EchoMode.Password); + } + } + } + + /** + * Sets the editable state. + * + * @param editable + * the new editable state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setEditable(boolean editable) { + checkWidget(); + if (isSingleLineEdit()) { + getQLineEdit().setReadOnly(!editable); + } else { + getQTextEdit().setReadOnly(!editable); + } + } + + @Override + public void setFont(Font font) { + checkWidget(); + super.setFont(font); + setTabStops(tabs); + } + + /** + * Sets the widget message. The message text is displayed as a hint for the + * user, indicating the purpose of the field. + * <p> + * Typically this is used in conjunction with <code>SWT.SEARCH</code>. + * </p> + * + * @param message + * the new message + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the message is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.3 + */ + public void setMessage(String message) { + checkWidget(); + getQWidget().setWhatsThis(message); + } + + /** + * Sets the orientation of the receiver, which must be one of the constants + * <code>SWT.LEFT_TO_RIGHT</code> or <code>SWT.RIGHT_TO_LEFT</code>. + * <p> + * Note: This operation is a hint and is not supported on platforms that do + * not have this concept. + * </p> + * + * @param orientation + * new orientation style + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 2.1.2 + */ + public void setOrientation(int orientation) { + checkWidget(); + int flags = SWT.RIGHT_TO_LEFT | SWT.LEFT_TO_RIGHT; + if ((orientation & flags) == 0 || (orientation & flags) == flags) { + return; + } + + style &= ~flags; + style |= orientation & flags; + + LayoutDirection direction = LayoutDirection.LeftToRight; + if (orientation == SWT.RIGHT_TO_LEFT) { + direction = LayoutDirection.RightToLeft; + } + getQWidget().setLayoutDirection(direction); + } + + /** + * Sets the selection. + * <p> + * Indexing is zero based. The range of a selection is from 0..N where N is + * the number of characters in the widget. + * </p> + * <p> + * Text selections are specified in terms of caret positions. In a text + * widget that contains N characters, there are N+1 caret positions, ranging + * from 0..N. This differs from other functions that address character + * position such as getText () that use the regular array indexing rules. + * </p> + * + * @param start + * new caret position + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setSelection(int start) { + checkWidget(); + setSelection(start, start); + } + + /** + * Sets the selection to the range specified by the given start and end + * indices. + * <p> + * Indexing is zero based. The range of a selection is from 0..N where N is + * the number of characters in the widget. + * </p> + * <p> + * Text selections are specified in terms of caret positions. In a text + * widget that contains N characters, there are N+1 caret positions, ranging + * from 0..N. This differs from other functions that address character + * position such as getText () that use the usual array indexing rules. + * </p> + * + * @param start + * the start of the range + * @param end + * the end of the range + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setSelection(int start, int end) { + checkWidget(); + int length = getCharCount(); + start = Math.min(Math.max(0, start), length); + end = Math.min(Math.max(0, end), length); + + if (isSingleLineEdit()) { + getQLineEdit().setSelection(start, end - start); + } else { + setCursorPosition(start, true); + setCursorPosition(end, false); + } + + } + + private void setCursorPosition(int pos, boolean moveAnchor) { + QTextCursor textCursor = getQTextEdit().textCursor(); + textCursor.setPosition(pos, moveAnchor ? MoveMode.MoveAnchor : MoveMode.KeepAnchor); + getQTextEdit().setTextCursor(textCursor); + } + + /** + * Sets the selection to the range specified by the given point, where the x + * coordinate represents the start index and the y coordinate represents the + * end index. + * <p> + * Indexing is zero based. The range of a selection is from 0..N where N is + * the number of characters in the widget. + * </p> + * <p> + * Text selections are specified in terms of caret positions. In a text + * widget that contains N characters, there are N+1 caret positions, ranging + * from 0..N. This differs from other functions that address character + * position such as getText () that use the usual array indexing rules. + * </p> + * + * @param selection + * the point + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setSelection(Point selection) { + checkWidget(); + if (selection == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + setSelection(selection.x, selection.y); + } + + /** + * Sets the number of tabs. + * <p> + * Tab stop spacing is specified in terms of the space (' ') character. The + * width of a single tab stop is the pixel width of the spaces. + * </p> + * + * @param tabs + * the number of tabs + * + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setTabs(int tabs) { + checkWidget(); + if (tabs < 0) { + return; + } + this.tabs = tabs; + setTabStops(this.tabs); + } + + void setTabStops(int tabs) { + if (!isSingleLineEdit()) { + getQTextEdit().setTabStopWidth(getQTextEdit().fontMetrics().width(" ") * tabs);//$NON-NLS-1$ + } + } + + /** + * Sets the contents of the receiver to the given string. If the receiver + * has style SINGLE and the argument contains multiple lines of text, the + * result of this operation is undefined and may vary from platform to + * platform. + * + * @param string + * the new text + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setText(String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + string = Display.withCrLf(string); + if (isSingleLineEdit()) { + getQLineEdit().setText(string); + } else { + getQTextEdit().setText(string); + } + } + + /** + * Sets the maximum number of characters that the receiver is capable of + * holding to be the argument. + * <p> + * Instead of trying to set the text limit to zero, consider creating a + * read-only text widget. + * </p> + * <p> + * To reset this value to the default, use + * <code>setTextLimit(Text.LIMIT)</code>. Specifying a limit value larger + * than <code>Text.LIMIT</code> sets the receiver's limit to + * <code>Text.LIMIT</code>. + * </p> + * + * @param limit + * new text limit + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #LIMIT + */ + public void setTextLimit(int limit) { + checkWidget(); + if (limit == 0) { + error(SWT.ERROR_CANNOT_BE_ZERO); + } + + if (limit < 0 || limit > LIMIT) { + limit = LIMIT; + } + + if (isSingleLineEdit()) { + getQLineEdit().setMaxLength(limit); + } else { + textLimit = limit; + if (getCharCount() > limit) { + getQTextEdit().setPlainText(getText().substring(0, limit)); + } + } + } + + /** + * Sets the zero-relative index of the line which is currently at the top of + * the receiver. This index can change when lines are scrolled or new lines + * are added and removed. + * + * @param index + * the index of the top item + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setTopIndex(int index) { + checkWidget(); + if (!isSingleLineEdit()) { + index = Math.min(Math.max(index, 0), getLineCount() - 1); + QScrollBar scrollBar = getQTextEdit().verticalScrollBar(); + QTextDocument textDocument = getQTextEdit().document(); + if (scrollBar != null && textDocument != null) { + if (index == 0) { + scrollBar.setValue(0); + } else { + QTextBlock textBlock = textDocument.begin(); + int lineCount = 0; + while (textBlock.isValid()) { + QTextLayout layout = textBlock.layout(); + if (layout != null) { + int oldLineCount = lineCount; + int lines = layout.lineCount(); + lineCount += lines > 0 ? lines : 1; + if (index < lineCount) { + int linePosition = (int) Math.round(layout.position().y() + + layout.lineAt(index - oldLineCount).y()); + scrollBar.setValue(linePosition); + break; + } + } + textBlock = textBlock.next(); + } + } + } + } + } + + /** + * Shows the selection. + * <p> + * If the selection is already showing in the receiver, this method simply + * returns. Otherwise, lines are scrolled until the selection is visible. + * </p> + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void showSelection() { + checkWidget(); + if (!isSingleLineEdit()) { + getQTextEdit().ensureCursorVisible(); + } + } + + private final class MyQTextEdit extends QTextEdit { + + @Override + protected void mousePressEvent(QMouseEvent e) { + super.mousePressEvent(e); + e.setAccepted(false); + } + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ToolBar.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ToolBar.java new file mode 100644 index 0000000000..3e7a1a152a --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ToolBar.java @@ -0,0 +1,530 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import java.util.List; + +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.core.Qt.ContextMenuPolicy; +import com.trolltech.qt.core.Qt.Orientation; +import com.trolltech.qt.core.Qt.ToolButtonStyle; +import com.trolltech.qt.gui.QAction; +import com.trolltech.qt.gui.QToolBar; +import com.trolltech.qt.gui.QWidget; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; + +/** + * Instances of this class support the layout of selectable tool bar items. + * <p> + * The item children that may be added to instances of this class must be of + * type <code>ToolItem</code>. + * </p> + * <p> + * Note that although this class is a subclass of <code>Composite</code>, it + * does not make sense to add <code>Control</code> children to it, or set a + * layout on it. + * </p> + * <p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>FLAT, WRAP, RIGHT, HORIZONTAL, VERTICAL, SHADOW_OUT</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#toolbar">ToolBar, ToolItem + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class ToolBar extends Composite { + /* + * 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". + */ + private static final int DEFAULT_WIDTH = 24; + private 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)); + } + + @Override + protected QWidget createQWidget(int style) { + state &= ~CANVAS; + QToolBar toolbar = new QToolBar(); + initOrientation(toolbar, style); + toolbar.setStyleSheet("QToolBar { border: 0px; margin: 0px;}"); //$NON-NLS-1$ // background-color: #234; + toolbar.setContentsMargins(0, 0, 0, 0); + toolbar.setIconSize(new QSize(16, 16)); + toolbar.setToolButtonStyle(ToolButtonStyle.ToolButtonTextBesideIcon); + toolbar.setContextMenuPolicy(ContextMenuPolicy.CustomContextMenu); + toolbar.setMovable(false); + toolbar.setFloatable(false); + toolbar.resize(0, 0); + // TODO if ( ( style & SWT.RIGHT ) != 0 ) { + // TODO if ( ( style & SWT.SHADOW_OUT ) != 0 ) { + // Visually, the tool bar is often separated from the menu bar by a separator. + // SWT.SHADOW_OUT style was defined for ToolBar. This style causes tool bars to draw the appropriate separator. + // On the Macintosh and platforms that do not support this look, the separator is not drawn. + + // if ( ( style & SWT.WRAP ) != 0 ) + // qt does not support wrapped mode! :( + + return toolbar; + } + + private void initOrientation(QToolBar toolbar, int style) { + if ((style & SWT.VERTICAL) != 0) { + toolbar.setOrientation(Orientation.Vertical); + this.style |= SWT.VERTICAL; + } else { + this.style |= SWT.HORIZONTAL; + toolbar.setOrientation(Orientation.Horizontal); + } + } + + QToolBar getQToolBar() { + return (QToolBar) getQWidget(); + } + + void addAction(QAction action, int index) { + int itemCount = _getItemCount(); + if (index >= 0 && index < itemCount) { + QAction before = getItems()[index].getQAction(); + getQToolBar().insertAction(before, action); + } else { + getQToolBar().addAction(action); + } + } + + QAction addWidget(QWidget widget, int index) { + int itemCount = _getItemCount(); + QAction action; + if (index >= 0 && index < itemCount) { + QAction before = getItems()[index].getQAction(); + action = getQToolBar().insertWidget(before, widget); + } else { + action = getQToolBar().addWidget(widget); + } + return action; + } + + QWidget removeAction(QAction action) { + QWidget widget = null; + if (getQToolBar() != null) { + widget = getQToolBar().widgetForAction(action); + getQToolBar().removeAction(action); + } + return widget; + } + + 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 + * toolbar has TBSTYLE_WRAPABLE. + */ + if ((style & SWT.VERTICAL) != 0) { + style &= ~SWT.WRAP; + } + + return style; + } + + @Override + protected void checkSubclass() { + if (!isValidSubclass()) { + error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + checkWidget(); + Point size = super.computeSize(wHint, hHint, changed); + int width = size.x; + int 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 = trim.width; + height = trim.height; + return new Point(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 ToolItem getItem(int index) { + checkWidget(); + List<QAction> list = getQWidget().actions(); + int count = list.size(); + if (!(0 <= index && index < count)) { + error(SWT.ERROR_INVALID_RANGE); + } + Widget widget = display.findControl(list.get(index)); + if (widget == null || !ToolItem.class.isInstance(widget)) { + error(SWT.ERROR_CANNOT_GET_ITEM); + } + return (ToolItem) widget; + } + + /** + * Returns the item at the given point in the receiver or null if no such + * item exists. The point is in the coordinate system of the receiver. + * + * @param point + * the point used to locate the item + * @return the item at the given point + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public ToolItem getItem(Point 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 _getItemCount(); + } + + int _getItemCount() { + return getQWidget().actions().size(); + } + + /** + * Returns an array of <code>ToolItem</code>s which are the items in the + * receiver. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its list of items, so modifying the array will not affect the receiver. + * </p> + * + * @return the items in the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public ToolItem[] getItems() { + checkWidget(); + List<QAction> list = getQWidget().actions(); + int count = list.size(); + if (count == 0) { + return new ToolItem[0]; + } + ToolItem[] children = new ToolItem[count]; + int items = 0; + for (QAction action : list) { + if (action != null) { + Widget widget = display.findControl(action); + if (widget != null && widget != this) { + if (widget instanceof ToolItem) { + children[items++] = (ToolItem) widget; + } + } + } + } + if (items == count) { + return children; + } + ToolItem[] newChildren = new ToolItem[items]; + System.arraycopy(children, 0, newChildren, 0, items); + return newChildren; + } + + /** + * 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(); + if ((style & SWT.VERTICAL) != 0) { + return _getItemCount(); + } + 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 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 getQToolBar().actions().indexOf(item.getQAction()); + } + + @Override + boolean mnemonicHit(char ch) { + //TODO + // int key = Display.wcsToMbcs(ch); + // int[] id = new int[1]; + // if (OS.SendMessage(handle, OS.TB_MAPACCELERATOR, key, id) == 0) { + // return false; + // } + // if ((style & SWT.FLAT) != 0 && !setTabGroupFocus()) + // return false; + // int index = (int) /* 64 */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; + } + + @Override + boolean mnemonicMatch(char ch) { + //TODO + // int key = Display.wcsToMbcs(ch); + // int[] id = new int[1]; + // if (OS.SendMessage(handle, OS.TB_MAPACCELERATOR, key, id) == 0) { + // return false; + // } + // /* + // * Feature in Windows. TB_MAPACCELERATOR matches either the mnemonic + // * character or the first character in a tool item. This behavior is + // * undocumented and unwanted. The fix is to ensure that the tool item + // * contains a mnemonic when TB_MAPACCELERATOR returns true. + // */ + // int index = (int) /* 64 */OS.SendMessage(handle, OS.TB_COMMANDTOINDEX, id[0], 0); + // if (index == -1) + // return false; + // return findMnemonic(items[id[0]].text) != '\0'; + return true; + } + + @Override + void releaseChildren(boolean destroy) { + ToolItem[] items = getItems(); + for (int i = 0; i < items.length; i++) { + ToolItem item = items[i]; + if (item != null && !item.isDisposed()) { + item.release(false); + } + } + super.releaseChildren(destroy); + } + + @Override + void removeControl(Control control) { + super.removeControl(control); + for (ToolItem item : getItems()) { + if (item != null && item.hasControl(control)) { + item.setControl(null); + } + } + } + + @Override + public boolean setParent(Composite parent) { + checkWidget(); + if (!super.setParent(parent)) { + return false; + } + getQToolBar().setParent(parent.getQWidget()); + return true; + } + + @Override + boolean setTabItemFocus() { + int index = 0; + ToolItem[] items = getItems(); + 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(); + } + + @Override + public String toString() { + String s = getName() + "{items: #" + getItemCount() + ":"; //$NON-NLS-1$ //$NON-NLS-2$ + for (ToolItem item : getItems()) { + s += item + " " + getQToolBar().widgetForAction(item.getQAction()) + ", "; //$NON-NLS-1$ //$NON-NLS-2$ + } + return s + "}"; //$NON-NLS-1$ + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ToolItem.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ToolItem.java new file mode 100644 index 0000000000..64f62f9676 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ToolItem.java @@ -0,0 +1,981 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.QRect; +import com.trolltech.qt.core.Qt.ContextMenuPolicy; +import com.trolltech.qt.core.Qt.MouseButton; +import com.trolltech.qt.gui.QAction; +import com.trolltech.qt.gui.QIcon; +import com.trolltech.qt.gui.QMouseEvent; +import com.trolltech.qt.gui.QStyle; +import com.trolltech.qt.gui.QStyleOptionToolButton; +import com.trolltech.qt.gui.QToolBar; +import com.trolltech.qt.gui.QToolButton; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QIcon.Mode; +import com.trolltech.qt.gui.QStyle.ComplexControl; +import com.trolltech.qt.gui.QToolButton.ToolButtonPopupMode; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.internal.qt.QtSWTConverter; + +/** + * Instances of this class represent a selectable user interface object that + * represents a button in a tool bar. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>PUSH, CHECK, RADIO, SEPARATOR, DROP_DOWN</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection</dd> + * </dl> + * <p> + * Note: Only one of the styles CHECK, PUSH, RADIO, SEPARATOR and DROP_DOWN may + * be specified. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#toolbar">ToolBar, ToolItem + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class ToolItem extends Item { + private ToolBar parent; + private Control control; + private Image disabledImage, hotImage; + private QAction action; + + /** + * 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) { + this(parent, style, -1); + } + + /** + * Constructs a new instance of this class given its parent (which must be a + * <code>ToolBar</code>), a style value describing its behavior and + * appearance, and the index at which to place it in the items maintained by + * its parent. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a composite control which will be the parent of the new + * instance (cannot be null) + * @param style + * the style of control to construct + * @param index + * the zero-relative index to store the receiver in its parent + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the parent (inclusive)</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#PUSH + * @see SWT#CHECK + * @see SWT#RADIO + * @see SWT#SEPARATOR + * @see SWT#DROP_DOWN + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public ToolItem(ToolBar parent, int style, int index) { + super(parent, checkStyle(style)); + this.parent = parent; + action = createAndAddAction(style, index); + connectSignals(action); + } + + protected QAction createAndAddAction(int style, int index) { + QAction action; + int bits = SWT.CHECK | SWT.RADIO | SWT.PUSH | SWT.SEPARATOR | SWT.DROP_DOWN; + switch (style & bits) { + case SWT.SEPARATOR: + action = createAndAddSeparator(index); + break; + case SWT.DROP_DOWN: + action = createAndAddDropdownButton(index); + break; + case SWT.RADIO: + // if ( parent.actionGroup == null ) { + // parent.actionGroup = new QActionGroup( parent.getQtControl() + // ); + // if ( ( parent.style & SWT.NO_RADIO_GROUP ) != 0 ) { + // parent.actionGroup.setExclusive( false ); + // } + // } + // parent.actionGroup.addAction( action ); + case SWT.CHECK: + action = createAndAddCheckableAction(index); + break; + case SWT.PUSH: + default: + action = createAndAddAction(index); + break; + } + + display.addControl(action, this); + + QWidget toolWidget = getQToolBar().widgetForAction(action); + toolWidget.setContextMenuPolicy(ContextMenuPolicy.NoContextMenu); + display.addControl(toolWidget, this); + + return action; + } + + private QAction createAndAddSeparator(int index) { + QAction action = createAction(); + action.setSeparator(true); + addToToolbar(action, index); + return action; + } + + private void addToToolbar(QAction action, int index) { + parent.addAction(action, index); + } + + private QAction createAction() { + return new QAction(parent.getQWidget()); + } + + private QAction createAndAddAction(int index) { + QAction action = createAction(); + addToToolbar(action, index); + return action; + } + + private QAction createAndAddCheckableAction(int index) { + QAction action = createAction(); + action.setCheckable(true); + addToToolbar(action, index); + return action; + } + + private QAction createAndAddDropdownButton(int index) { + MyToolButton button = new MyToolButton(parent.getQWidget()); + button.setPopupMode(ToolButtonPopupMode.MenuButtonPopup); + QAction action = parent.addWidget(button, index); + button.setDefaultAction(action); + return action; + } + + QAction getQAction() { + return action; + } + + QWidget getToolbarWidget() { + return getQToolBar().widgetForAction(action); + } + + QToolBar getQToolBar() { + return parent.getQToolBar(); + } + + protected void connectSignals(QAction action) { + action.triggered.connect(this, "sendTriggeredEvent()"); //$NON-NLS-1$ + action.hovered.connect(this, "sendHoveredEvent()"); //$NON-NLS-1$ + } + + protected void sendTriggeredEvent() { + Event event = new Event(); + sendEvent(SWT.Selection, event); + } + + protected void sendHoveredEvent() { + Event event = new Event(); + sendEvent(SWT.Arm, event); + } + + protected void sendShowDropDownEvent() { + Event event = new Event(); + event.detail = SWT.ARROW; + + Rectangle rect = getBounds(); + event.x = rect.x; + event.y = rect.y + rect.height; + + sendEvent(SWT.Selection, event); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the control is selected by the user, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * When <code>widgetSelected</code> is called when the mouse is over the + * arrow portion of a drop-down tool, the event object detail field contains + * the value <code>SWT.ARROW</code>. <code>widgetDefaultSelected</code> is + * not called. + * </p> + * + * @param listener + * the listener which should be notified when the control is + * selected by the user, + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + static int checkStyle(int style) { + return checkBits(style, SWT.PUSH, SWT.CHECK, SWT.RADIO, SWT.SEPARATOR, SWT.DROP_DOWN, 0); + } + + @Override + protected void checkSubclass() { + if (!isValidSubclass()) { + error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + void click(boolean dropDown) { + if (dropDown) { + sendShowDropDownEvent(); + } else { + getQAction().trigger(); + } + } + + @Override + void destroyWidget() { + QWidget toolWidget = parent.removeAction(action); + if (toolWidget != null) { + toolWidget.disconnect(); + display.removeControl(toolWidget); + } + super.destroyWidget(); + } + + /** + * 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(); + return QtSWTConverter.convert(getQToolBar().actionGeometry(getQAction())); + } + + /** + * Returns the control that is used to fill the bounds of the item when the + * item is a <code>SEPARATOR</code>. + * + * @return the control + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Control getControl() { + checkWidget(); + return control; + } + + boolean hasControl(Control control) { + return this.control == 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; + } + + /** + * 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(); + return getQAction().isChecked(); + } + + /** + * 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 getQAction().toolTip(); + } + + /** + * Gets the width of the receiver. + * + * @return the width + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getWidth() { + checkWidget(); + return getQToolBar().actionGeometry(getQAction()).width(); + } + + /** + * Returns <code>true</code> if the receiver is enabled and all of the + * receiver's ancestors are enabled, and <code>false</code> otherwise. A + * disabled control is typically not selectable from the user interface and + * draws with an inactive or "grayed" look. + * + * @return the receiver's enabled state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #getEnabled + */ + public boolean isEnabled() { + checkWidget(); + return getEnabled() && parent.isEnabled(); + } + + @Override + void releaseWidget() { + super.releaseWidget(); + control = null; + disabledImage = null; + hotImage = null; + } + + @Override + void releaseQWidget() { + super.releaseQWidget(); + parent.removeAction(action); + action = null; + parent = null; + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is selected by the user. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + void 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 + * item is a <code>SEPARATOR</code>. + * + * @param control + * the new control + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the control has been + * disposed</li> + * <li>ERROR_INVALID_PARENT - if the control is not in the + * same widget tree</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setControl(Control control) { + checkWidget(); + if (control != null) { + if (control.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (control.parent != parent) { + error(SWT.ERROR_INVALID_PARENT); + } + } + if ((style & SWT.SEPARATOR) == 0) { + return; + } + this.control = control; + QAction newAction = getQToolBar().insertWidget(getQAction(), control.getQWidget()); + getQToolBar().removeAction(getQAction()); + newAction.setEnabled(action.isEnabled()); + newAction.setText(action.text()); + newAction.setToolTip(action.toolTip()); + newAction.setChecked(action.isChecked()); + updateImages(); + action = newAction; + resizeControl(); + } + + /** + * 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 getQAction().isEnabled(); + } + + /** + * 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(); + getQAction().setEnabled(enabled); + } + + /** + * Sets the receiver's disabled image to the argument, which may be null + * indicating that no disabled image should be displayed. + * <p> + * The disabled image is displayed when the receiver is disabled. + * </p> + * + * @param image + * the disabled image to display on the receiver (may be null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the image has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setDisabledImage(Image image) { + checkWidget(); + if ((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(); + } + + @Override + 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(); + } + + private void updateImages() { + if ((style & SWT.SEPARATOR) != 0) { + return; + } + + if (image == null && disabledImage == null && hotImage == null) { + getQAction().setIcon((QIcon) null); + return; + } + + QIcon icon = new QIcon(); + if (image != null) { + icon.addPixmap(image.getQPixmap()); + } + + if (disabledImage != null) { + icon.addPixmap(disabledImage.getQPixmap(), Mode.Disabled); + } + + if (hotImage != null) { + icon.addPixmap(hotImage.getQPixmap(), Mode.Selected); + } + getQAction().setIcon(icon); + } + + 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; + } + getQAction().setChecked(selected); + } + + /** + * 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> + */ + @Override + public void setText(String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if ((style & SWT.SEPARATOR) != 0) { + return; + } + if (string.equals(text)) { + return; + } + super.setText(string); + getQAction().setText(string); + } + + /** + * Sets the receiver's tool tip text to the argument, which may be null + * indicating that the default tool tip for the control will be shown. For a + * control that has a default tool tip, such as the Tree control on Windows, + * setting the tool tip text to an empty string replaces the default, + * causing no tool tip text to be shown. + * <p> + * The mnemonic indicator (character '&') is not displayed in a tool + * tip. To display a single '&' in the tool tip, the character '&' + * can be escaped by doubling it in the string. + * </p> + * + * @param string + * the new tool tip text (or null) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setToolTipText(String string) { + checkWidget(); + getQAction().setToolTip(string); + } + + /** + * Sets the width of the receiver, for <code>SEPARATOR</code> ToolItems. + * + * @param width + * the new width + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setWidth(int width) { + checkWidget(); + if ((style & SWT.SEPARATOR) == 0) { + return; + } + if (width < 0) { + return; + } + QWidget widget = getQToolBar().widgetForAction(getQAction()); + widget.resize(width, widget.height()); + } + + @Override + public String toString() { + return getName() + "{text: " + getQAction().text() + ", tooltip: " + getQAction().toolTip() + "}"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /** + * Subclassed QToolButton, to override drop down handling. We check for + * clicks on the arrow an the right side of the button and show our own + * drop-down menu, ignoring the default menu. + */ + private final class MyToolButton extends QToolButton { + public MyToolButton(QWidget parent) { + super(parent); + } + + @Override + protected void mousePressEvent(QMouseEvent e) { + if (MouseButton.LeftButton.equals(e.button()) && ToolButtonPopupMode.MenuButtonPopup.equals(popupMode())) { + QStyleOptionToolButton opt = new QStyleOptionToolButton(); + initStyleOption(opt); + QRect popupr = style().subControlRect(ComplexControl.CC_ToolButton, opt, + QStyle.SubControl.SC_ToolButtonMenu, this); + if (popupr.isValid() && popupr.contains(e.pos())) { + sendShowDropDownEvent(); + return; + } + } + super.mousePressEvent(e); + } + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ToolTip.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ToolTip.java new file mode 100644 index 0000000000..f79ffbbad4 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/ToolTip.java @@ -0,0 +1,512 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Point; + +/** + * Instances of this class represent popup windows that are used to inform or + * warn the user. + * <p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>BALLOON, ICON_ERROR, ICON_INFORMATION, ICON_WARNING</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection</dd> + * </dl> + * </p> + * <p> + * Note: Only one of the styles ICON_ERROR, ICON_INFORMATION, and ICON_WARNING + * may be specified. + * </p> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> within the + * SWT implementation. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#tooltips">Tool Tips + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * + * @since 3.2 + * @noextend This class is not intended to be subclassed by clients. + */ + +public class ToolTip extends Widget { + Shell parent; + TrayItem item; + String text = ""; //$NON-NLS-1$ + String message = ""; //$NON-NLS-1$ + int id, x, y; + boolean autoHide = true, hasLocation, visible; + static final int TIMER_ID = 100; + + /** + * 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#ICON_ERROR + * @see SWT#ICON_INFORMATION + * @see SWT#ICON_WARNING + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public ToolTip(Shell parent, int style) { + super(parent, checkStyle(style)); + this.parent = parent; + checkAndUpdateOrientation(parent); + // parent.createToolTip(this); + } + + static int checkStyle(int style) { + int mask = SWT.ICON_ERROR | SWT.ICON_INFORMATION | SWT.ICON_WARNING; + if ((style & mask) == 0) { + return style; + } + return checkBits(style, SWT.ICON_INFORMATION, SWT.ICON_WARNING, SWT.ICON_ERROR, 0, 0, 0); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the receiver is selected by the user, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * <code>widgetSelected</code> is called when the receiver is selected. + * <code>widgetDefaultSelected</code> is not called. + * </p> + * + * @param listener + * the listener which should be notified when the receiver is + * selected by the user + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + @Override + void destroyWidget() { + if (parent != null) { + // parent.destroyToolTip( this ); + } + releaseQWidget(); + } + + /** + * Returns <code>true</code> if the receiver is automatically hidden by the + * platform, and <code>false</code> otherwise. + * + * @return the receiver's auto hide 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 getAutoHide() { + checkWidget(); + return autoHide; + } + + /** + * Returns the receiver's message, which will be an empty string if it has + * never been set. + * + * @return the receiver's message + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String getMessage() { + checkWidget(); + return message; + } + + /** + * Returns the receiver's parent, which must be a <code>Shell</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 Shell getParent() { + checkWidget(); + return parent; + } + + /** + * Returns the receiver's text, which will be an empty string if it has + * never been set. + * + * @return the receiver's text + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String getText() { + checkWidget(); + return text; + } + + /** + * 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 (item != null) { + return visible; + } + return false; + } + + /** + * 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(); + if (item != null) { + return getVisible() && item.getVisible(); + } + return getVisible(); + } + + @Override + void releaseQWidget() { + super.releaseQWidget(); + parent = null; + item = null; + id = -1; + } + + @Override + void releaseWidget() { + super.releaseWidget(); + if (item == null) { + if (autoHide) { + // TODO + } + } + if (item != null && item.toolTip == this) { + item.toolTip = null; + } + item = null; + text = message = null; + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the receiver is selected by the user. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + /** + * Makes the receiver hide automatically when <code>true</code>, and remain + * visible when <code>false</code>. + * + * @param autoHide + * the auto hide 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 + * @see #setVisible + */ + public void setAutoHide(boolean autoHide) { + checkWidget(); + this.autoHide = autoHide; + // TODO - update when visible + } + + /** + * Sets the location of the receiver, which must be a tooltip, to the point + * specified by the arguments which are relative to the display. + * <p> + * Note that this is different from most widgets where the location of the + * widget is relative to the parent. + * </p> + * + * @param x + * the new x coordinate for the receiver + * @param y + * the new y coordinate for the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setLocation(int x, int y) { + checkWidget(); + this.x = x; + this.y = y; + hasLocation = true; + // TODO - update when visible + } + + /** + * Sets the location of the receiver, which must be a tooltip, to the point + * specified by the argument which is relative to the display. + * <p> + * Note that this is different from most widgets where the location of the + * widget is relative to the parent. + * </p> + * <p> + * Note that the platform window manager ultimately has control over the + * location of tooltips. + * </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> + */ + public void setLocation(Point location) { + checkWidget(); + if (location == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + setLocation(location.x, location.y); + } + + /** + * Sets the receiver's message. + * + * @param string + * the new message + * + * @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 setMessage(String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + message = string; + // TODO - update when visible + } + + /** + * Sets the receiver's text. + * + * @param string + * the new text + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the text is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setText(String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + text = string; + // TODO - update when visible + } + + /** + * 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 == getVisible()) { + return; + // TODO + } + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Tracker.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Tracker.java new file mode 100644 index 0000000000..a055510abe --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Tracker.java @@ -0,0 +1,859 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; + +/** + * Instances of this class implement rubber banding rectangles that are drawn + * onto a parent <code>Composite</code> or <code>Display</code>. These + * rectangles can be specified to respond to mouse and key events by either + * moving or resizing themselves accordingly. Trackers are typically used to + * represent window geometries in a lightweight manner. + * + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>LEFT, RIGHT, UP, DOWN, RESIZE</dd> + * <dt><b>Events:</b></dt> + * <dd>Move, Resize</dd> + * </dl> + * <p> + * Note: Rectangle move behavior is assumed unless RESIZE is specified. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#tracker">Tracker + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class Tracker extends Widget { + Control parent; + boolean tracking, cancelled, stippled; + Rectangle[] rectangles = new Rectangle[0], proportions = rectangles; + Rectangle bounds; + int /* long */resizeCursor; + Cursor clientCursor; + int cursorOrientation = SWT.NONE; + boolean inEvent = false; + int /* long */hwndTransparent, hwndOpaque, oldTransparentProc, oldOpaqueProc; + int oldX, oldY; + + /* + * The following values mirror step sizes on Windows + */ + final static int STEPSIZE_SMALL = 1; + final static int STEPSIZE_LARGE = 9; + + /** + * Constructs a new instance of this class given its parent and a style + * value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a widget which will be the parent of the new instance (cannot + * be null) + * @param style + * the style of widget to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#LEFT + * @see SWT#RIGHT + * @see SWT#UP + * @see SWT#DOWN + * @see SWT#RESIZE + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public Tracker(Composite parent, int style) { + super(parent, checkStyle(style)); + this.parent = parent; + } + + /** + * Constructs a new instance of this class given the display to create it on + * and a style value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * <p> + * Note: Currently, null can be passed in for the display argument. This has + * the effect of creating the tracker on the currently active display if + * there is one. If there is no current display, the tracker is created on a + * "default" display. <b>Passing in null as the display argument is not + * considered to be good coding style, and may not be supported in a future + * release of SWT.</b> + * </p> + * + * @param display + * the display to create the tracker on + * @param style + * the style of control to construct + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#LEFT + * @see SWT#RIGHT + * @see SWT#UP + * @see SWT#DOWN + */ + public Tracker(Display display, int style) { + if (display == null) { + display = Display.getCurrent(); + } + if (display == null) { + display = Display.getDefault(); + } + if (!display.isValidThread()) { + error(SWT.ERROR_THREAD_INVALID_ACCESS); + } + this.style = checkStyle(style); + this.display = display; + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the control is moved or resized, by sending it one of the messages + * defined in the <code>ControlListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ControlListener + * @see #removeControlListener + */ + public void addControlListener(ControlListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Resize, typedListener); + addListener(SWT.Move, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when keys are pressed and released on the system keyboard, by sending it + * one of the messages defined in the <code>KeyListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see KeyListener + * @see #removeKeyListener + */ + public void addKeyListener(KeyListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.KeyUp, typedListener); + addListener(SWT.KeyDown, typedListener); + } + + Point adjustMoveCursor() { + if (bounds == null) { + return null; + } + int newX = bounds.x + bounds.width / 2; + int newY = bounds.y; + // 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); + //TODO + return new Point(newX, newY); + } + + Point adjustResizeCursor() { + if (bounds == null) { + return null; + } + int newX, newY; + + if ((cursorOrientation & SWT.LEFT) != 0) { + newX = bounds.x; + } else if ((cursorOrientation & SWT.RIGHT) != 0) { + newX = bounds.x + bounds.width; + } else { + newX = bounds.x + bounds.width / 2; + } + + if ((cursorOrientation & SWT.UP) != 0) { + newY = bounds.y; + } else if ((cursorOrientation & SWT.DOWN) != 0) { + newY = bounds.y + bounds.height; + } else { + newY = bounds.y + bounds.height / 2; + } + + // 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 == null) { + // int /* long */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; + // } + //TODO + return new Point(newX, newY); + } + + static int checkStyle(int style) { + if ((style & (SWT.LEFT | SWT.RIGHT | SWT.UP | SWT.DOWN)) == 0) { + style |= SWT.LEFT | SWT.RIGHT | SWT.UP | SWT.DOWN; + } + return style; + } + + /** + * Stops displaying the tracker rectangles. Note that this is not considered + * to be a cancelation by the user. + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void close() { + checkWidget(); + tracking = false; + } + + Rectangle computeBounds() { + if (rectangles.length == 0) { + return null; + } + int xMin = rectangles[0].x; + int yMin = rectangles[0].y; + int xMax = rectangles[0].x + rectangles[0].width; + int yMax = rectangles[0].y + rectangles[0].height; + + for (int i = 1; i < rectangles.length; i++) { + if (rectangles[i].x < xMin) { + xMin = rectangles[i].x; + } + if (rectangles[i].y < yMin) { + yMin = rectangles[i].y; + } + int rectRight = rectangles[i].x + rectangles[i].width; + if (rectRight > xMax) { + xMax = rectRight; + } + int rectBottom = rectangles[i].y + rectangles[i].height; + if (rectBottom > yMax) { + yMax = rectBottom; + } + } + + return new Rectangle(xMin, yMin, xMax - xMin, yMax - yMin); + } + + Rectangle[] computeProportions(Rectangle[] rects) { + Rectangle[] result = new Rectangle[rects.length]; + bounds = computeBounds(); + if (bounds != null) { + for (int i = 0; i < rects.length; i++) { + int x = 0, y = 0, width = 0, height = 0; + if (bounds.width != 0) { + x = (rects[i].x - bounds.x) * 100 / bounds.width; + width = rects[i].width * 100 / bounds.width; + } else { + width = 100; + } + if (bounds.height != 0) { + y = (rects[i].y - bounds.y) * 100 / bounds.height; + height = rects[i].height * 100 / bounds.height; + } else { + height = 100; + } + result[i] = new Rectangle(x, y, width, height); + } + } + return result; + } + + /** + * Draw the rectangles displayed by the tracker. + */ + void drawRectangles(Rectangle[] rects, boolean stippled) { + // if (parent == null && OS.WIN32_VERSION >= OS.VERSION(6, 0)) { + // RECT rect1 = new RECT(); + // int bandWidth = stippled ? 3 : 1; + // for (int i = 0; i < rects.length; i++) { + // Rectangle rect = rects[i]; + // rect1.left = rect.x - bandWidth; + // rect1.top = rect.y - bandWidth; + // rect1.right = rect.x + rect.width + bandWidth * 2; + // rect1.bottom = rect.y + rect.height + bandWidth * 2; + // OS.RedrawWindow(hwndOpaque, rect1, 0, OS.RDW_INVALIDATE); + // } + // return; + // } + // int bandWidth = 1; + // int /* long */hwndTrack = OS.GetDesktopWindow(); + // if (parent != null) { + // //hwndTrack = parent.handle; + // } + // int /* long */hDC = OS.GetDCEx(hwndTrack, 0, OS.DCX_CACHE); + // int /* long */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); + } + + /** + * Returns the bounds that are being drawn, expressed relative to the parent + * widget. If the parent is a <code>Display</code> then these are screen + * coordinates. + * + * @return the bounds of the Rectangles being drawn + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Rectangle[] getRectangles() { + checkWidget(); + Rectangle[] result = new Rectangle[rectangles.length]; + for (int i = 0; i < rectangles.length; i++) { + Rectangle current = rectangles[i]; + result[i] = new Rectangle(current.x, current.y, current.width, current.height); + } + return result; + } + + /** + * Returns <code>true</code> if the rectangles are drawn with a stippled + * line, <code>false</code> otherwise. + * + * @return the stippled effect of the rectangles + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public boolean getStippled() { + checkWidget(); + return stippled; + } + + void moveRectangles(int xChange, int yChange) { + if (bounds == null) { + return; + } + if (xChange < 0 && (style & SWT.LEFT) == 0) { + xChange = 0; + } + if (xChange > 0 && (style & SWT.RIGHT) == 0) { + xChange = 0; + } + if (yChange < 0 && (style & SWT.UP) == 0) { + yChange = 0; + } + if (yChange > 0 && (style & SWT.DOWN) == 0) { + yChange = 0; + } + if (xChange == 0 && yChange == 0) { + return; + } + bounds.x += xChange; + bounds.y += yChange; + for (int i = 0; i < rectangles.length; i++) { + rectangles[i].x += xChange; + rectangles[i].y += yChange; + } + } + + /** + * Displays the Tracker rectangles for manipulation by the user. Returns + * when the user has either finished manipulating the rectangles or has + * cancelled the Tracker. + * + * @return <code>true</code> if the user did not cancel the Tracker, + * <code>false</code> otherwise + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public boolean open() { + checkWidget(); + cancelled = false; + tracking = true; + + /* + * If exactly one of UP/DOWN is specified as a style then set the cursor + * orientation accordingly (the same is done for LEFT/RIGHT styles + * below). + */ + int vStyle = style & (SWT.UP | SWT.DOWN); + if (vStyle == SWT.UP || vStyle == SWT.DOWN) { + cursorOrientation |= vStyle; + } + int hStyle = style & (SWT.LEFT | SWT.RIGHT); + if (hStyle == SWT.LEFT || hStyle == SWT.RIGHT) { + cursorOrientation |= hStyle; + } + + /* + * 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). + */ + // TODO + tracking = false; + return !cancelled; + } + + @Override + void releaseWidget() { + super.releaseWidget(); + parent = null; + rectangles = proportions = null; + bounds = null; + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is moved or resized. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ControlListener + * @see #addControlListener + */ + public void removeControlListener(ControlListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Resize, listener); + eventTable.unhook(SWT.Move, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when keys are pressed and released on the system keyboard. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see KeyListener + * @see #addKeyListener + */ + public void removeKeyListener(KeyListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.KeyUp, listener); + eventTable.unhook(SWT.KeyDown, listener); + } + + void resizeRectangles(int xChange, int yChange) { + if (bounds == null) { + return; + } + /* + * 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; + } + if (xChange > 0 && (style & SWT.RIGHT) != 0 && (cursorOrientation & SWT.LEFT) == 0) { + cursorOrientation |= SWT.RIGHT; + } + if (yChange < 0 && (style & SWT.UP) != 0 && (cursorOrientation & SWT.DOWN) == 0) { + cursorOrientation |= SWT.UP; + } + if (yChange > 0 && (style & SWT.DOWN) != 0 && (cursorOrientation & SWT.UP) == 0) { + cursorOrientation |= SWT.DOWN; + } + + /* + * If the bounds will flip about the x or y axis then apply the + * adjustment up to the axis (ie.- where bounds width/height becomes 0), + * change the cursor's orientation accordingly, and flip each + * Rectangle's origin (only necessary for > 1 Rectangles) + */ + if ((cursorOrientation & SWT.LEFT) != 0) { + if (xChange > bounds.width) { + if ((style & SWT.RIGHT) == 0) { + return; + } + cursorOrientation |= SWT.RIGHT; + cursorOrientation &= ~SWT.LEFT; + bounds.x += bounds.width; + xChange -= bounds.width; + bounds.width = 0; + if (proportions.length > 1) { + for (int i = 0; i < proportions.length; i++) { + Rectangle proportion = proportions[i]; + proportion.x = 100 - proportion.x - proportion.width; + } + } + } + } else if ((cursorOrientation & SWT.RIGHT) != 0) { + if (bounds.width < -xChange) { + if ((style & SWT.LEFT) == 0) { + return; + } + cursorOrientation |= SWT.LEFT; + cursorOrientation &= ~SWT.RIGHT; + xChange += bounds.width; + bounds.width = 0; + if (proportions.length > 1) { + for (int i = 0; i < proportions.length; i++) { + Rectangle proportion = proportions[i]; + proportion.x = 100 - proportion.x - proportion.width; + } + } + } + } + if ((cursorOrientation & SWT.UP) != 0) { + if (yChange > bounds.height) { + if ((style & SWT.DOWN) == 0) { + return; + } + cursorOrientation |= SWT.DOWN; + cursorOrientation &= ~SWT.UP; + bounds.y += bounds.height; + yChange -= bounds.height; + bounds.height = 0; + if (proportions.length > 1) { + for (int i = 0; i < proportions.length; i++) { + Rectangle proportion = proportions[i]; + proportion.y = 100 - proportion.y - proportion.height; + } + } + } + } else if ((cursorOrientation & SWT.DOWN) != 0) { + if (bounds.height < -yChange) { + if ((style & SWT.UP) == 0) { + return; + } + cursorOrientation |= SWT.UP; + cursorOrientation &= ~SWT.DOWN; + yChange += bounds.height; + bounds.height = 0; + if (proportions.length > 1) { + for (int i = 0; i < proportions.length; i++) { + Rectangle proportion = proportions[i]; + proportion.y = 100 - proportion.y - proportion.height; + } + } + } + } + + // apply the bounds adjustment + if ((cursorOrientation & SWT.LEFT) != 0) { + bounds.x += xChange; + bounds.width -= xChange; + } else if ((cursorOrientation & SWT.RIGHT) != 0) { + bounds.width += xChange; + } + if ((cursorOrientation & SWT.UP) != 0) { + bounds.y += yChange; + bounds.height -= yChange; + } else if ((cursorOrientation & SWT.DOWN) != 0) { + bounds.height += yChange; + } + + Rectangle[] newRects = new Rectangle[rectangles.length]; + for (int i = 0; i < rectangles.length; i++) { + Rectangle proportion = proportions[i]; + newRects[i] = new Rectangle(proportion.x * bounds.width / 100 + bounds.x, proportion.y * bounds.height + / 100 + bounds.y, proportion.width * bounds.width / 100, proportion.height * bounds.height / 100); + } + rectangles = newRects; + } + + /** + * Sets the <code>Cursor</code> of the Tracker. If this cursor is + * <code>null</code> then the cursor reverts to the default. + * + * @param newCursor + * the new <code>Cursor</code> to display + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setCursor(Cursor newCursor) { + checkWidget(); + clientCursor = newCursor; + // TODO + // if (newCursor != null) { + // if (inEvent) { + // OS.SetCursor(clientCursor.handle); + // } + // } + } + + /** + * Specifies the rectangles that should be drawn, expressed relative to the + * parent widget. If the parent is a Display then these are screen + * coordinates. + * + * @param rectangles + * the bounds of the rectangles to be drawn + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the set of rectangles is null + * or contains a null rectangle</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setRectangles(Rectangle[] rectangles) { + checkWidget(); + if (rectangles == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + this.rectangles = new Rectangle[rectangles.length]; + for (int i = 0; i < rectangles.length; i++) { + Rectangle current = rectangles[i]; + if (current == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + this.rectangles[i] = new Rectangle(current.x, current.y, current.width, current.height); + } + proportions = computeProportions(rectangles); + } + + /** + * Changes the appearance of the line used to draw the rectangles. + * + * @param stippled + * <code>true</code> if rectangle should appear stippled + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setStippled(boolean stippled) { + checkWidget(); + this.stippled = stippled; + } + + void update() { + if (parent == null) { + return; + } + if (parent != null) { + if (parent.isDisposed()) { + return; + } + Shell shell = parent.getShell(); + shell._update(); + } else { + display.update(); + } + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TrayItem.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TrayItem.java new file mode 100644 index 0000000000..cdee0a48fe --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TrayItem.java @@ -0,0 +1,536 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.MenuDetectListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; + +/** + * Instances of this class represent icons that can be placed on the system tray + * or task bar status area. + * <p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>(none)</dd> + * <dt><b>Events:</b></dt> + * <dd>DefaultSelection, MenuDetect, Selection</dd> + * </dl> + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#tray">Tray, TrayItem + * snippets</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * + * @since 3.0 + * @noextend This class is not intended to be subclassed by clients. + */ +public class TrayItem extends Item { + Tray parent; + int id; + Image image2; + ToolTip toolTip; + String toolTipText; + boolean visible = true; + + /** + * Constructs a new instance of this class given its parent (which must be a + * <code>Tray</code>) and a style value describing its behavior and + * appearance. The item is added to the end of the items maintained by its + * parent. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a composite control which will be the parent of the new + * instance (cannot be null) + * @param style + * the style of control to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public TrayItem(Tray parent, int style) { + super(parent, style); + this.parent = parent; + parent.createItem(this, parent.getItemCount()); + createWidget(); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the receiver is selected by the user, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * <code>widgetSelected</code> is called when the receiver is selected + * <code>widgetDefaultSelected</code> is called when the receiver is + * double-clicked + * </p> + * + * @param listener + * the listener which should be notified when the receiver is + * selected by the user + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the platform-specific context menu trigger has occurred, by sending + * it one of the messages defined in the <code>MenuDetectListener</code> + * interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see MenuDetectListener + * @see #removeMenuDetectListener + * + * @since 3.3 + */ + public void addMenuDetectListener(MenuDetectListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.MenuDetect, typedListener); + } + + @Override + protected void checkSubclass() { + if (!isValidSubclass()) { + error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + void createWidget() { + // TODO + } + + @Override + void destroyWidget() { + parent.destroyItem(this); + releaseQWidget(); + } + + /** + * Returns the receiver's parent, which must be a <code>Tray</code>. + * + * @return the receiver's parent + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public Tray getParent() { + checkWidget(); + return parent; + } + + /** + * Returns the receiver's tool tip, or null if it has not been set. + * + * @return the receiver's tool tip text + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public ToolTip getToolTip() { + checkWidget(); + return toolTip; + } + + /** + * Returns the receiver's tool tip text, or null if it has not been set. + * + * @return the receiver's tool tip text + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public String getToolTipText() { + checkWidget(); + return toolTipText; + } + + /** + * Returns <code>true</code> if the receiver is visible and + * <code>false</code> otherwise. + * + * @return the receiver's visibility + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public boolean getVisible() { + checkWidget(); + return visible; + } + + void recreate() { + createWidget(); + if (!visible) { + setVisible(false); + } + if (text.length() != 0) { + setText(text); + } + if (image != null) { + setImage(image); + } + if (toolTipText != null) { + setToolTipText(toolTipText); + } + } + + @Override + void releaseQWidget() { + super.releaseQWidget(); + parent = null; + } + + @Override + void releaseWidget() { + super.releaseWidget(); + if (toolTip != null) { + toolTip.item = null; + } + toolTip = null; + if (image2 != null) { + image2.dispose(); + } + image2 = null; + toolTipText = null; + // NOTIFYICONDATA iconData = OS.IsUnicode ? (NOTIFYICONDATA) new NOTIFYICONDATAW() : new NOTIFYICONDATAA(); + // iconData.cbSize = NOTIFYICONDATA.sizeof; + // iconData.uID = id; + // iconData.hWnd = display.hwndMessage; + // OS.Shell_NotifyIcon(OS.NIM_DELETE, iconData); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the receiver is selected by the user. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the platform-specific context menu trigger has occurred. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see MenuDetectListener + * @see #addMenuDetectListener + * + * @since 3.3 + */ + public void removeMenuDetectListener(MenuDetectListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.MenuDetect, listener); + } + + /** + * Sets the receiver's image. + * + * @param image + * the new image + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the image has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + @Override + public void setImage(Image image) { + checkWidget(); + if (image != null && image.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + super.setImage(image); + // if (image2 != null) + // image2.dispose(); + // image2 = null; + // QImage hIcon = null; + // Image icon = image; + // if (icon != null) { + // switch (icon.type) { + // case SWT.BITMAP: + // image2 = Display.createIcon(image); + // hIcon = image2.getQImage(); + // break; + // case SWT.ICON: + // hIcon = icon.getQImage(); + // break; + // } + // } + //getQTray().setIcon( image.getQIcon() ); + } + + /** + * Sets the receiver's tool tip to the argument, which may be null + * indicating that no tool tip should be shown. + * + * @param toolTip + * the new tool tip (or null) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public void setToolTip(ToolTip toolTip) { + checkWidget(); + ToolTip oldTip = this.toolTip, newTip = toolTip; + if (oldTip != null) { + oldTip.item = null; + } + this.toolTip = newTip; + if (newTip != null) { + newTip.item = this; + } + } + + /** + * Sets the receiver's tool tip text to the argument, which may be null + * indicating that the default tool tip for the control will be shown. For a + * control that has a default tool tip, such as the Tree control on Windows, + * setting the tool tip text to an empty string replaces the default, + * causing no tool tip text to be shown. + * <p> + * The mnemonic indicator (character '&') is not displayed in a tool + * tip. To display a single '&' in the tool tip, the character '&' + * can be escaped by doubling it in the string. + * </p> + * + * @param string + * the new tool tip text (or null) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setToolTipText(String string) { + checkWidget(); + toolTipText = string; + // NOTIFYICONDATA iconData = OS.IsUnicode ? (NOTIFYICONDATA) new NOTIFYICONDATAW() : new NOTIFYICONDATAA(); + // TCHAR buffer = new TCHAR(0, toolTipText == null ? "" : toolTipText, true); + // /* + // * Note that the size of the szTip field is different in version 5.0 of + // * shell32.dll. + // */ + // int length = 64; //OS.SHELL32_MAJOR < 5 ? 64 : 128; + // if (OS.IsUnicode) { + // char[] szTip = ((NOTIFYICONDATAW) iconData).szTip; + // length = Math.min(length - 1, buffer.length()); + // System.arraycopy(buffer.chars, 0, szTip, 0, length); + // } else { + // byte[] szTip = ((NOTIFYICONDATAA) iconData).szTip; + // length = Math.min(length - 1, buffer.length()); + // System.arraycopy(buffer.bytes, 0, szTip, 0, length); + // } + // iconData.cbSize = NOTIFYICONDATA.sizeof; + // iconData.uID = id; + // // iconData.hWnd = display.hwndMessage; + // // iconData.uFlags = OS.NIF_TIP; + // // OS.Shell_NotifyIcon(OS.NIM_MODIFY, iconData); + } + + /** + * Makes the receiver visible if the argument is <code>true</code>, and + * makes it invisible otherwise. + * + * @param visible + * the new visibility state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setVisible(boolean visible) { + checkWidget(); + if (this.visible == visible) { + return; + } + if (visible) { + /* + * 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; + } + } + this.visible = visible; + // TODO + if (!visible) { + sendEvent(SWT.Hide); + } + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Tree.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Tree.java new file mode 100644 index 0000000000..c9a145b5a6 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Tree.java @@ -0,0 +1,1913 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import java.util.ArrayList; +import java.util.List; + +import com.trolltech.qt.core.QModelIndex; +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.core.Qt.DropActions; +import com.trolltech.qt.core.Qt.ScrollBarPolicy; +import com.trolltech.qt.core.Qt.SortOrder; +import com.trolltech.qt.gui.QAbstractItemDelegate; +import com.trolltech.qt.gui.QDragEnterEvent; +import com.trolltech.qt.gui.QDragLeaveEvent; +import com.trolltech.qt.gui.QDragMoveEvent; +import com.trolltech.qt.gui.QDropEvent; +import com.trolltech.qt.gui.QHeaderView; +import com.trolltech.qt.gui.QPainter; +import com.trolltech.qt.gui.QStyleOptionViewItem; +import com.trolltech.qt.gui.QTreeWidget; +import com.trolltech.qt.gui.QTreeWidgetItem; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QAbstractItemView.DragDropMode; +import com.trolltech.qt.gui.QAbstractItemView.ScrollHint; +import com.trolltech.qt.gui.QAbstractItemView.SelectionBehavior; +import com.trolltech.qt.gui.QAbstractItemView.SelectionMode; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.events.TreeListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Point; + +/** + * Instances of this class provide a selectable user interface object that + * displays a hierarchy of items and issues notification when an item in the + * hierarchy is selected. + * <p> + * The item children that may be added to instances of this class must be of + * type <code>TreeItem</code>. + * </p> + * <p> + * Style <code>VIRTUAL</code> is used to create a <code>Tree</code> whose + * <code>TreeItem</code>s are to be populated by the client on an on-demand + * basis instead of up-front. This can provide significant performance + * improvements for trees that are very large or for which <code>TreeItem</code> + * population is expensive (for example, retrieving values from an external + * source). + * </p> + * <p> + * Here is an example of using a <code>Tree</code> with style + * <code>VIRTUAL</code>: <code><pre> + * final Tree tree = new Tree(parent, SWT.VIRTUAL | SWT.BORDER); + * tree.setItemCount(20); + * tree.addListener(SWT.SetData, new Listener() { + * public void handleEvent(Event event) { + * TreeItem item = (TreeItem)event.item; + * TreeItem parentItem = item.getParentItem(); + * String text = null; + * if (parentItem == null) { + * text = "node " + tree.indexOf(item); + * } else { + * text = parentItem.getText() + " - " + parentItem.indexOf(item); + * } + * item.setText(text); + * System.out.println(text); + * item.setItemCount(10); + * } + * }); + * </pre></code> + * </p> + * <p> + * Note that although this class is a subclass of <code>Composite</code>, it + * does not normally make sense to add <code>Control</code> children to it, or + * set a layout on it, unless implementing something like a cell editor. + * </p> + * <p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>SINGLE, MULTI, CHECK, FULL_SELECTION, VIRTUAL, NO_SCROLL</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection, DefaultSelection, Collapse, Expand, SetData, MeasureItem, + * EraseItem, PaintItem</dd> + * </dl> + * </p> + * <p> + * Note: Only one of the styles SINGLE and MULTI may be specified. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#tree">Tree, TreeItem, + * TreeColumn snippets</a> + * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: + * ControlExample</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ +public class Tree extends Composite { + private List<TreeItem> items; + private List<TreeColumn> columns; + TreeColumn sortColumn; + int sortDirection; + boolean customDraw; + private boolean linesVisible; + private static final int GRID_WIDTH = 1; + private TreeItemDelegate itemDelegate; + + /** + * Constructs a new instance of this class given its parent and a style + * value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a composite control which will be the parent of the new + * instance (cannot be null) + * @param style + * the style of control to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#SINGLE + * @see SWT#MULTI + * @see SWT#CHECK + * @see SWT#FULL_SELECTION + * @see SWT#VIRTUAL + * @see SWT#NO_SCROLL + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public Tree(Composite parent, int style) { + super(parent, checkStyle(style)); + } + + @Override + protected void connectSignals() { + QTreeWidget tree = getQTreeWidget(); + + tree.itemExpanded.connect(this, "qtTreeItemExpandedEvent(QTreeWidgetItem)"); //$NON-NLS-1$ + tree.itemCollapsed.connect(this, "qtTreeItemCollapsedEvent(QTreeWidgetItem)"); //$NON-NLS-1$ + tree.itemDoubleClicked.connect(this, "qtTreeItemDoubleClickedEvent(QTreeWidgetItem,Integer)"); //$NON-NLS-1$ + tree.itemSelectionChanged.connect(this, "qtTreeSelectionChanged()"); //$NON-NLS-1$ + } + + @Override + QWidget createQWidget(int style) { + state &= ~(CANVAS | THEME_BACKGROUND); + items = new ArrayList<TreeItem>(4); + columns = new ArrayList<TreeColumn>(4); + + QTreeWidget tree = new MyQTreeWidget(); + tree.setHeaderHidden(true); + + if ((style & SWT.NO_SCROLL) != 0) { + tree.setHorizontalScrollBarPolicy(ScrollBarPolicy.ScrollBarAlwaysOff); + tree.setVerticalScrollBarPolicy(ScrollBarPolicy.ScrollBarAlwaysOff); + } + + // default value is singleSelection + if ((style & SWT.MULTI) != 0) { + tree.setSelectionMode(SelectionMode.ExtendedSelection); + } else { + tree.setSelectionMode(SelectionMode.SingleSelection); + } + + if ((style & SWT.FULL_SELECTION) != 0) { + tree.setSelectionBehavior(SelectionBehavior.SelectRows); + } else { + tree.setSelectionBehavior(SelectionBehavior.SelectItems); + } + + QAbstractItemDelegate originalItemDelegate = tree.itemDelegate(); + itemDelegate = new TreeItemDelegate(originalItemDelegate); + tree.setItemDelegate(itemDelegate); + + setQMasterWidget(tree); + return tree.viewport(); + } + + QTreeWidget getQTreeWidget() { + return (QTreeWidget) getQMasterWidget(); + } + + @Override + protected void checkAndUpdateBorder() { + checkAndUpdateBorder(getQMasterWidget()); + super.checkAndUpdateBorder(); + } + + @Override + protected Color getDefaultBackgroundColor() { + return display.getSystemColor(SWT.COLOR_LIST_BACKGROUND); + } + + static int checkStyle(int style) { + /* + * Feature in Windows. Even when WS_HSCROLL or WS_VSCROLL is not + * specified, Windows creates trees and tables with scroll bars. The fix + * is to set H_SCROLL and V_SCROLL. + * + * NOTE: This code appears on all platforms so that applications have + * consistent scroll bar behavior. + */ + if ((style & SWT.NO_SCROLL) == 0) { + style |= SWT.H_SCROLL | SWT.V_SCROLL; + } + /* + * Note: Windows only supports TVS_NOSCROLL and TVS_NOHSCROLL. + */ + if ((style & SWT.H_SCROLL) != 0 && (style & SWT.V_SCROLL) == 0) { + style |= SWT.V_SCROLL; + } + return checkBits(style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0); + } + + @Override + public void setDragEnabled(boolean enabled) { + getQTreeWidget().setDragEnabled(enabled); + } + + @Override + public void setAcceptDrops(boolean accept) { + super.setAcceptDrops(accept); + getQTreeWidget().setDragDropMode(DragDropMode.DragDrop); + getQTreeWidget().setDropIndicatorShown(true); + } + + public void highlightItem(TreeItem item) { + System.out.println("highlightItem: " + item); + if (item != null) { + getQTreeWidget().setCurrentItem(item.getQItem()); + } else { + getQTreeWidget().setCurrentItem(null); + } + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the user changes the receiver's selection, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * When <code>widgetSelected</code> is called, the item field of the event + * object is valid. If the receiver has the <code>SWT.CHECK</code> style and + * the check selection changes, the event object detail field contains the + * value <code>SWT.CHECK</code>. <code>widgetDefaultSelected</code> is + * typically called when an item is double-clicked. The item field of the + * event object is valid for default selection, but the detail field is not + * used. + * </p> + * + * @param listener + * the listener which should be notified when the user changes + * the receiver's selection + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when an item in the receiver is expanded or collapsed by sending it one + * of the messages defined in the <code>TreeListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see TreeListener + * @see #removeTreeListener + */ + public void addTreeListener(TreeListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Expand, typedListener); + addListener(SWT.Collapse, typedListener); + } + + @Override + protected void checkSubclass() { + if (!isValidSubclass()) { + error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + /** + * Clears the item at the given zero-relative index in the receiver. The + * text, icon and other attributes of the item are set to the default value. + * If the tree was created with the <code>SWT.VIRTUAL</code> style, these + * attributes are requested again as needed. + * + * @param index + * the index of the item to clear + * @param all + * <code>true</code> if all child items of the indexed item + * should be cleared recursively, and <code>false</code> + * otherwise + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list minus 1 (inclusive) + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SWT#VIRTUAL + * @see SWT#SetData + * + * @since 3.2 + */ + public void clear(int index, boolean all) { + checkWidget(); + if (_getItemCount() == 0) { + return; + } + validateItemIndex(index); + items.get(index).clear(0, all); + } + + private void validateItemIndex(int index) { + if (index < 0 || index >= _getItemCount()) { + error(SWT.ERROR_INVALID_RANGE); + } + } + + /** + * Clears all the items in the receiver. The text, icon and other attributes + * of the items are set to their default values. If the tree was created + * with the <code>SWT.VIRTUAL</code> style, these attributes are requested + * again as needed. + * + * @param all + * <code>true</code> if all child items should be cleared + * recursively, and <code>false</code> otherwise + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SWT#VIRTUAL + * @see SWT#SetData + * + * @since 3.2 + */ + public void clearAll(boolean all) { + checkWidget(); + for (TreeItem item : items) { + item.clear(0, all); + } + } + + void addColumn(TreeColumn column, int index) { + int columnCount = columns.size(); + if (!(0 <= index && index <= columnCount)) { + error(SWT.ERROR_INVALID_RANGE); + } + + if (index == columnCount) { + columns.add(column); + } else { + columns.add(index, column); + } + // QHeaderView header = getQTreeWidget().header(); + // if (index >= columnCount) { + // header.addAction(column.getQAction()); + // } else { + // QAction before = header.actions().get(index); + // header.insertAction(before, column.getQAction()); + // } + } + + void removeColumn(TreeColumn treeColumn) { + columns.remove(treeColumn); + //getQTreeWidget().headerItem().removeAction(treeColumn.getQAction()); + } + + void addItem(TreeItem item, int index) { + if (index >= 0 && index < _getItemCount()) { + items.add(index, item); + getQTreeWidget().insertTopLevelItem(index, item.getQItem()); + } else { + items.add(item); + getQTreeWidget().addTopLevelItem(item.getQItem()); + } + } + + void removeItem(TreeItem item) { + items.remove(item); + getQTreeWidget().invisibleRootItem().removeChild(item.getQItem()); + } + + /** + * Deselects an item in the receiver. If the item was already deselected, it + * remains deselected. + * + * @param item + * the item to be deselected + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the item is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public void deselect(TreeItem item) { + checkWidget(); + if (item == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (item.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + + item.getQItem().setSelected(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(); + getQTreeWidget().clearSelection(); + } + + /** + * Returns the width in pixels of a grid line. + * + * @return the width of a grid line in pixels + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public int getGridLineWidth() { + checkWidget(); + return GRID_WIDTH; + } + + /** + * Returns the height of the receiver's header + * + * @return the height of the header or zero if the header is not visible + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public int getHeaderHeight() { + checkWidget(); + return getQTreeWidget().header().height(); + } + + /** + * Returns <code>true</code> if the receiver's header is visible, and + * <code>false</code> otherwise. + * <p> + * If one of the receiver's ancestors is not visible or some other condition + * makes the receiver not visible, this method may still indicate that it is + * considered visible even though it may not actually be showing. + * </p> + * + * @return the receiver's header's visibility state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public boolean getHeaderVisible() { + checkWidget(); + return !getQTreeWidget().isHeaderHidden(); + } + + /** + * Returns the column at the given, zero-relative index in the receiver. + * Throws an exception if the index is out of range. Columns are returned in + * the order that they were created. If no <code>TreeColumn</code>s were + * created by the programmer, this method will throw + * <code>ERROR_INVALID_RANGE</code> despite the fact that a single column of + * data may be visible in the tree. This occurs when the programmer uses the + * tree like a list, adding items but never creating a column. + * + * @param index + * the index of the column to return + * @return the column at the given index + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list minus 1 (inclusive) + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Tree#getColumnOrder() + * @see Tree#setColumnOrder(int[]) + * @see TreeColumn#getMoveable() + * @see TreeColumn#setMoveable(boolean) + * @see SWT#Move + * + * @since 3.1 + */ + public TreeColumn getColumn(int index) { + checkWidget(); + if (!(0 <= index && index < columns.size())) { + error(SWT.ERROR_INVALID_RANGE); + } + return columns.get(index); + } + + /** + * Returns the number of columns contained in the receiver. If no + * <code>TreeColumn</code>s were created by the programmer, this value is + * zero, despite the fact that visually, one column of items may be visible. + * This occurs when the programmer uses the tree like a list, adding items + * but never creating a column. + * + * @return the number of columns + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public int getColumnCount() { + checkWidget(); + return _getColumnCount(); + } + + int _getColumnCount() { + return columns.size(); + } + + /** + * Returns an array of zero-relative integers that map the creation order of + * the receiver's items to the order in which they are currently being + * displayed. + * <p> + * Specifically, the indices of the returned array represent the current + * visual order of the items, and the contents of the array represent the + * creation order of the items. + * </p> + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its list of items, so modifying the array will not affect the receiver. + * </p> + * + * @return the current visual order of the receiver's items + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Tree#setColumnOrder(int[]) + * @see TreeColumn#getMoveable() + * @see TreeColumn#setMoveable(boolean) + * @see SWT#Move + * + * @since 3.2 + */ + public int[] getColumnOrder() { + checkWidget(); + if (_getColumnCount() == 0) { + return new int[0]; + } + int[] order = new int[_getColumnCount()]; + QHeaderView header = getQTreeWidget().header(); + for (int i = 0; i < order.length; i++) { + order[i] = header.visualIndex(i); + } + return order; + } + + /** + * Returns an array of <code>TreeColumn</code>s which are the columns in the + * receiver. Columns are returned in the order that they were created. If no + * <code>TreeColumn</code>s were created by the programmer, the array is + * empty, despite the fact that visually, one column of items may be + * visible. This occurs when the programmer uses the tree like a list, + * adding items but never creating a column. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its list of items, so modifying the array will not affect the receiver. + * </p> + * + * @return the items in the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Tree#getColumnOrder() + * @see Tree#setColumnOrder(int[]) + * @see TreeColumn#getMoveable() + * @see TreeColumn#setMoveable(boolean) + * @see SWT#Move + * + * @since 3.1 + */ + public TreeColumn[] getColumns() { + checkWidget(); + TreeColumn[] result = new TreeColumn[_getColumnCount()]; + int i = 0; + for (TreeColumn col : columns) { + result[i] = col; + i++; + } + return result; + } + + /** + * Returns the item at the given, zero-relative index in the receiver. + * Throws an exception if the index is out of range. + * + * @param index + * the index of the item to return + * @return the item at the given index + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list minus 1 (inclusive) + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public TreeItem getItem(int index) { + checkWidget(); + if (index < 0 || index >= items.size()) { + error(SWT.ERROR_INVALID_RANGE); + } + return items.get(index); + } + + /** + * Returns the item at the given point in the receiver or null if no such + * item exists. The point is in the coordinate system of the receiver. + * <p> + * The item that is returned represents an item that could be selected by + * the user. For example, if selection only occurs in items in the first + * column, then null is returned if the point is outside of the item. Note + * that the SWT.FULL_SELECTION style hint, which specifies the selection + * policy, determines the extent of the selection. + * </p> + * + * @param point + * the point used to locate the item + * @return the item at the given point, or null if the point is not in a + * selectable item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public TreeItem getItem(Point point) { + checkWidget(); + if (point == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + return _getItem(point); + } + + private TreeItem _getItem(Point point) { + QTreeWidgetItem qItem = getQTreeWidget().itemAt(point.x, point.y); + for (TreeItem item : items) { + if (item.getQItem() == qItem) { + return item; + } + TreeItem ti = item.getItem(qItem); + if (ti != null) { + return ti; + } + } + return null; + + } + + /** + * Returns the number of items contained in the receiver that are direct + * item children of the receiver. The number that is returned is the number + * of roots in the tree. + * + * @return the number of items + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public int getItemCount() { + checkWidget(); + return items.size(); + } + + int _getItemCount() { + return items.size(); + } + + /** + * 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(); + int itemHeight = 0; + if (items.size() > 0) { + itemHeight = getQTreeWidget().sizeHintForRow(0); + } else { + // add dummy node and get the height + getQTreeWidget().addTopLevelItem(new QTreeWidgetItem()); + itemHeight = getQTreeWidget().sizeHintForRow(0); + getQTreeWidget().clear(); + } + return itemHeight; + } + + /** + * Returns a (possibly empty) array of items contained in the receiver that + * are direct item children of the receiver. These are the roots of the + * tree. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its list of items, so modifying the array will not affect the receiver. + * </p> + * + * @return the items + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public TreeItem[] getItems() { + checkWidget(); + TreeItem[] arr = new TreeItem[_getItemCount()]; + int i = 0; + for (TreeItem item : items) { + arr[i] = item; + i++; + } + return arr; + } + + /** + * Returns <code>true</code> if the receiver's lines are visible, and + * <code>false</code> otherwise. Note that some platforms draw grid lines + * while others may draw alternating row colors. + * <p> + * If one of the receiver's ancestors is not visible or some other condition + * makes the receiver not visible, this method may still indicate that it is + * considered visible even though it may not actually be showing. + * </p> + * + * @return the visibility state of the lines + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public boolean getLinesVisible() { + checkWidget(); + return linesVisible; + } + + /** + * Returns the receiver's parent item, which must be a <code>TreeItem</code> + * or null when the receiver is a root. + * + * @return the receiver's parent item + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public TreeItem getParentItem() { + checkWidget(); + return null; + } + + /** + * Returns an array of <code>TreeItem</code>s that are currently selected in + * the receiver. The order of the items is unspecified. An empty array + * indicates that no items are selected. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its selection, so modifying the array will not affect the receiver. + * </p> + * + * @return an array representing the selection + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public TreeItem[] getSelection() { + checkWidget(); + List<QTreeWidgetItem> selectedQItems = getQTreeWidget().selectedItems(); + if (selectedQItems.isEmpty()) { + return new TreeItem[0]; + } + + TreeItem[] items = new TreeItem[selectedQItems.size()]; + int i = 0; + for (QTreeWidgetItem item : selectedQItems) { + Widget widget = display.findControl(item); + if (widget instanceof TreeItem) { + items[i] = (TreeItem) widget; + } + i++; + } + return items; + } + + /** + * 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 getQTreeWidget().selectedItems().size(); + } + + /** + * Returns the column which shows the sort indicator for the receiver. The + * value may be null if no column shows the sort indicator. + * + * @return the sort indicator + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #setSortColumn(TreeColumn) + * + * @since 3.2 + */ + public TreeColumn getSortColumn() { + checkWidget(); + return sortColumn; + } + + /** + * Returns the direction of the sort indicator for the receiver. The value + * will be one of <code>UP</code>, <code>DOWN</code> or <code>NONE</code>. + * + * @return the sort direction + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #setSortDirection(int) + * + * @since 3.2 + */ + public int getSortDirection() { + checkWidget(); + return sortDirection; + } + + /** + * Returns the item which is currently at the top of the receiver. This item + * can change when items are expanded, collapsed, scrolled or new items are + * added or removed. + * + * @return the item at the top of the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 2.1 + */ + public TreeItem getTopItem() { + checkWidget(); + return _getItem(new Point(1, 1)); + } + + /** + * Searches the receiver's list starting at the first column (index 0) until + * a column is found that is equal to the argument, and returns the index of + * that column. If no column is found, returns -1. + * + * @param column + * the search column + * @return the index of the column + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the column is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public int indexOf(TreeColumn column) { + checkWidget(); + if (column == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (column.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + return columns.indexOf(column); + } + + /** + * Searches the receiver's list starting at the first item (index 0) until + * an item is found that is equal to the argument, and returns the index of + * that item. If no item is found, returns -1. + * + * @param item + * the search item + * @return the index of the item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the item is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public int indexOf(TreeItem item) { + checkWidget(); + if (item == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (item.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + return items.indexOf(item); + } + + @Override + void releaseChildren(boolean destroy) { + if (items != null) { + for (TreeItem item : items) { + if (item != null && !item.isDisposed()) { + item.release(false); + } + } + items = null; + } + if (columns != null) { + for (TreeColumn column : columns) { + if (column != null && !column.isDisposed()) { + column.release(false); + } + } + columns = null; + } + super.releaseChildren(destroy); + } + + @Override + void releaseWidget() { + super.releaseWidget(); + customDraw = false; + } + + /** + * Removes all of the items from the receiver. + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void removeAll() { + checkWidget(); + List<TreeItem> copyOfItems = new ArrayList<TreeItem>(items); + for (TreeItem item : copyOfItems) { + item.dispose(); + } + items.clear(); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the user changes the receiver's selection. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when items in the receiver are expanded or collapsed. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see TreeListener + * @see #addTreeListener + */ + public void removeTreeListener(TreeListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Expand, listener); + eventTable.unhook(SWT.Collapse, listener); + } + + /** + * Display a mark indicating the point at which an item will be inserted. + * The drop insert item has a visual hint to show where a dragged item will + * be inserted when dropped on the tree. + * + * @param item + * the insert item. Null will clear the insertion mark. + * @param before + * true places the insert mark above 'item'. false places the + * insert mark below 'item'. + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setInsertMark(TreeItem item, boolean before) { + checkWidget(); + //TODO d'n'd + } + + /** + * Sets the number of root-level items contained in the receiver. + * + * @param count + * the number of items + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public void setItemCount(int count) { + checkWidget(); + count = Math.max(0, count); + int itemCount = _getItemCount(); + if (count == itemCount) { + return; + } + boolean isVirtual = (style & SWT.VIRTUAL) != 0; + if (!isVirtual) { + setRedraw(false); + } + + if (count < itemCount) { + for (int i = itemCount - 1; i >= count; i--) { + removeItem(items.get(i)); + } + return; + } + if (isVirtual) { + //TODO + } else { + for (int i = itemCount; i < count; i++) { + new TreeItem(this, SWT.NONE, i); + } + } + if (!isVirtual) { + setRedraw(true); + } + } + + /** + * Sets the height of the area which would be used to display <em>one</em> + * of the items in the tree. + * + * @param itemHeight + * 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> + * + * @since 3.2 + */ + /* public */void setItemHeight(int itemHeight) { + checkWidget(); + if (itemHeight < -1) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + itemDelegate.setHeight(itemHeight); + update(); + } + + /** + * Marks the receiver's lines as visible if the argument is + * <code>true</code>, and marks it invisible otherwise. Note that some + * platforms draw grid lines while others may draw alternating row colors. + * <p> + * If one of the receiver's ancestors is not visible or some other condition + * makes the receiver not visible, marking it visible may not actually cause + * it to be displayed. + * </p> + * + * @param show + * the new visibility state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public void setLinesVisible(boolean show) { + checkWidget(); + if (linesVisible == show) { + return; + } + linesVisible = show; + getQTreeWidget().setAlternatingRowColors(show); + } + + /** + * Selects an item in the receiver. If the item was already selected, it + * remains selected. + * + * @param item + * the item to be selected + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the item is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.4 + */ + public void select(TreeItem item) { + checkWidget(); + if (item == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (item.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + item.getQItem().setSelected(true); + } + + /** + * Selects all of the items in the receiver. + * <p> + * If the receiver is single-select, do nothing. + * </p> + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void selectAll() { + checkWidget(); + getQTreeWidget().selectAll(); + } + + /** + * Sets the order that the items in the receiver should be displayed in to + * the given argument which is described in terms of the zero-relative + * ordering of when the items were added. + * + * @param order + * the new order to display the items + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the item order is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the item order is not the + * same length as the number of items</li> + * </ul> + * + * @see Tree#getColumnOrder() + * @see TreeColumn#getMoveable() + * @see TreeColumn#setMoveable(boolean) + * @see SWT#Move + * + * @since 3.2 + */ + public void setColumnOrder(int[] order) { + checkWidget(); + if (order == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + int columnCount = _getColumnCount(); + if (columnCount == 0) { + if (order.length != 0) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + return; + } + if (order.length != columnCount) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + QHeaderView header = getQTreeWidget().header(); + for (int i = 0; i < columnCount; i++) { + int visualIndex = header.visualIndex(i); + header.moveSection(visualIndex, order[i]); + } + } + + /** + * Marks the receiver's header as visible if the argument is + * <code>true</code>, and marks it invisible otherwise. + * <p> + * If one of the receiver's ancestors is not visible or some other condition + * makes the receiver not visible, marking it visible may not actually cause + * it to be displayed. + * </p> + * + * @param show + * the new visibility state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public void setHeaderVisible(boolean show) { + checkWidget(); + getQTreeWidget().setHeaderHidden(!show); + } + + /** + * Sets the receiver's selection to the given item. The current selection is + * cleared before the new item is selected. + * <p> + * If the item is not in the receiver, then it is ignored. + * </p> + * + * @param item + * the item to select + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the item is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public void setSelection(TreeItem item) { + checkWidget(); + if (item == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + setSelection(new TreeItem[] { item }); + } + + /** + * Sets the receiver's selection to be the given array of items. The current + * selection is cleared before the new items are selected. + * <p> + * Items that are not in the receiver are ignored. If the receiver is + * single-select and multiple items are specified, then all items are + * ignored. + * </p> + * + * @param items + * the array of items + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of items is null</li> + * <li>ERROR_INVALID_ARGUMENT - if one of the items has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Tree#deselectAll() + */ + public void setSelection(TreeItem[] items) { + checkWidget(); + if (items == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + int length = items.length; + if (length == 0 || (style & SWT.SINGLE) != 0 && length > 1) { + deselectAll(); + return; + } + getQTreeWidget().clearSelection(); + for (TreeItem item : items) { + QTreeWidgetItem treeWidgetItem = item.getQItem(); + showItem(treeWidgetItem); + treeWidgetItem.setSelected(true); + } + } + + private void showItem(QTreeWidgetItem item) { + if (item.parent() != null) { + if (!item.parent().isExpanded()) { + item.parent().setExpanded(true); + } + showItem(item.parent()); + } + } + + /** + * Sets the column used by the sort indicator for the receiver. A null value + * will clear the sort indicator. The current sort column is cleared before + * the new column is set. + * + * @param column + * the column used by the sort indicator or <code>null</code> + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the column is disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public void setSortColumn(TreeColumn column) { + checkWidget(); + if (column != null && column.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + sortColumn = column; + getQTreeWidget().sortByColumn(indexOf(column), getQSortOrder()); + } + + /** + * Sets the direction of the sort indicator for the receiver. The value can + * be one of <code>UP</code>, <code>DOWN</code> or <code>NONE</code>. + * + * @param direction + * the direction of the sort indicator + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public void setSortDirection(int direction) { + checkWidget(); + if ((direction & (SWT.UP | SWT.DOWN)) == 0 && direction != SWT.NONE) { + return; + } + sortDirection = direction; + if (sortColumn != null && !sortColumn.isDisposed()) { + getQTreeWidget().sortByColumn(indexOf(sortColumn), getQSortOrder()); + } + } + + /** + * @return + */ + private SortOrder getQSortOrder() { + if ((sortDirection & SWT.UP) != 0) { + return SortOrder.AscendingOrder; + } + return SortOrder.DescendingOrder; + } + + /** + * 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); + } + _showItem(item, ScrollHint.PositionAtTop); + } + + /** + * Shows the column. If the column is already showing in the receiver, this + * method simply returns. Otherwise, the columns are scrolled until the + * column is visible. + * + * @param column + * the column to be shown + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the item is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public void showColumn(TreeColumn column) { + checkWidget(); + if (column == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (column.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (column.parent != this) { + return; + } + int index = indexOf(column); + if (index == -1) { + return; + } + getQTreeWidget().scrollToItem(getQTreeWidget().headerItem().child(index), ScrollHint.EnsureVisible); + } + + /** + * 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, ScrollHint.EnsureVisible); + } + + private void _showItem(TreeItem item, ScrollHint hint) { + getQTreeWidget().scrollToItem(item.getQItem(), hint); + } + + /** + * 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(); + List<QTreeWidgetItem> selection = getQTreeWidget().selectedItems(); + if (selection != null && selection.size() > 0) { + getQTreeWidget().scrollToItem(selection.get(0), ScrollHint.EnsureVisible); + } + } + + boolean sendTreeEvent(int eventType, QTreeWidgetItem item) { + Event event = new Event(); + event.item = display.findControl(item); + sendEvent(eventType, event, true); + return !event.doit; + } + + public boolean qtTreeItemCollapsedEvent(QTreeWidgetItem item) { + return sendTreeEvent(SWT.Collapse, item); + } + + public boolean qtTreeItemExpandedEvent(QTreeWidgetItem item) { + return sendTreeEvent(SWT.Expand, item); + } + + public void qtTreeItemDoubleClickedEvent(QTreeWidgetItem item, Integer column) { + sendEvent(SWT.DefaultSelection); + } + + private final class TreeItemDelegate extends QAbstractItemDelegate { + private final QAbstractItemDelegate wrappedDelegate; + private int height = -1; + + TreeItemDelegate(QAbstractItemDelegate wrappedDelegate) { + this.wrappedDelegate = wrappedDelegate; + + } + + public void setHeight(int height) { + this.height = height; + } + + @Override + public void paint(QPainter painter, QStyleOptionViewItem item, QModelIndex index) { + wrappedDelegate.paint(painter, item, index); + } + + @Override + public QSize sizeHint(QStyleOptionViewItem item, QModelIndex index) { + QSize size = wrappedDelegate.sizeHint(item, index); + if (height != -1) { + size.setHeight(height); + } + return size; + } + + } + + public boolean qtTreeSelectionChanged() { + List<QTreeWidgetItem> selectedItems = getQTreeWidget().selectedItems(); + if (selectedItems.size() > 1) { + System.out.println("more than one item selected in tree, selecting first"); //$NON-NLS-1$ + } + if (selectedItems.size() == 0) { + return sendTreeEvent(SWT.Selection, null); + } else { + // TODO what if more than one element is selected + return sendTreeEvent(SWT.Selection, selectedItems.get(0)); + } + } + + private final class MyQTreeWidget extends QTreeWidget { + + @Override + protected void startDrag(DropActions supportedActions) { + // System.out.println("MyQTreeWidget.startDrag: " + supportedActions); + } + + @Override + protected void dropEvent(QDropEvent event) { + sendDropEvent(event); + } + + @Override + protected void dragMoveEvent(QDragMoveEvent event) { + sendDragMoveEvent(event); + } + + @Override + protected void dragEnterEvent(QDragEnterEvent event) { + sendDragEnterEvent(event); + } + + @Override + protected void dragLeaveEvent(QDragLeaveEvent event) { + sendDragLeaveEvent(event); + } + + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TreeColumn.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TreeColumn.java new file mode 100644 index 0000000000..1693962077 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TreeColumn.java @@ -0,0 +1,714 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import com.trolltech.qt.core.Qt.AlignmentFlag; +import com.trolltech.qt.gui.QHeaderView; +import com.trolltech.qt.gui.QIcon; +import com.trolltech.qt.gui.QTreeWidget; +import com.trolltech.qt.gui.QTreeWidgetItem; +import com.trolltech.qt.gui.QHeaderView.ResizeMode; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; + +/** + * Instances of this class represent a column in a tree widget. + * <p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>LEFT, RIGHT, CENTER</dd> + * <dt><b>Events:</b></dt> + * <dd>Move, Resize, Selection</dd> + * </dl> + * </p> + * <p> + * Note: Only one of the styles LEFT, RIGHT and CENTER may be specified. + * </p> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#tree">Tree, TreeItem, + * TreeColumn snippets</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * + * @since 3.1 + * @noextend This class is not intended to be subclassed by clients. + */ +public class TreeColumn extends Item { + Tree parent; + private boolean resizable, moveable; + + /** + * Constructs a new instance of this class given its parent (which must be a + * <code>Tree</code>) and a style value describing its behavior and + * appearance. The item is added to the end of the items maintained by its + * parent. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a composite control which will be the parent of the new + * instance (cannot be null) + * @param style + * the style of control to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#LEFT + * @see SWT#RIGHT + * @see SWT#CENTER + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public TreeColumn(Tree parent, int style) { + super(parent, checkStyle(style)); + resizable = true; + this.parent = parent; + createQAction(parent, style, parent.getColumnCount()); + } + + /** + * Constructs a new instance of this class given its parent (which must be a + * <code>Tree</code>), a style value describing its behavior and appearance, + * and the index at which to place it in the items maintained by its parent. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * <p> + * Note that due to a restriction on some platforms, the first column is + * always left aligned. + * </p> + * + * @param parent + * a composite control which will be the parent of the new + * instance (cannot be null) + * @param style + * the style of control to construct + * @param index + * the zero-relative index to store the receiver in its parent + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the parent (inclusive)</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT#LEFT + * @see SWT#RIGHT + * @see SWT#CENTER + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public TreeColumn(Tree parent, int style, int index) { + super(parent, checkStyle(style)); + resizable = true; + this.parent = parent; + createQAction(parent, style, index); + } + + private void adjustColumnCount() { + int columnCount = parent.getColumnCount(); + if (getQTreeWidget().columnCount() <= columnCount) { + getQTreeWidget().setColumnCount(columnCount + 1); + } + } + + protected void createQAction(Tree parent, int style, int index) { + adjustColumnCount(); + parent.addColumn(this, index); + getQHeaderItem().setText(index, ""); //$NON-NLS-1$ + } + + @Override + void releaseQWidget() { + //display.removeControl(action); + super.releaseQWidget(); + } + + QTreeWidget getQTreeWidget() { + return parent.getQTreeWidget(); + } + + QTreeWidgetItem getQHeaderItem() { + return getQTreeWidget().headerItem(); + } + + QHeaderView getQHeaderView() { + return getQTreeWidget().header(); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the control is moved or resized, by sending it one of the messages + * defined in the <code>ControlListener</code> interface. + * + * @param listener + * the listener which should be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ControlListener + * @see #removeControlListener + */ + public void addControlListener(ControlListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Resize, typedListener); + addListener(SWT.Move, typedListener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the control is selected by the user, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * <p> + * <code>widgetSelected</code> is called when the column header is selected. + * <code>widgetDefaultSelected</code> is not called. + * </p> + * + * @param listener + * the listener which should be notified when the control is + * selected by the user + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); + } + + static int checkStyle(int style) { + return checkBits(style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0); + } + + @Override + protected void checkSubclass() { + if (!isValidSubclass()) { + error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + @Override + void destroyWidget() { + parent.removeColumn(this); + super.destroyWidget(); + } + + /** + * 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; + } + + /** + * Gets the moveable attribute. A column that is not moveable cannot be + * reordered by the user by dragging the header but may be reordered by the + * programmer. + * + * @return the moveable attribute + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Tree#getColumnOrder() + * @see Tree#setColumnOrder(int[]) + * @see TreeColumn#setMoveable(boolean) + * @see SWT#Move + * + * @since 3.2 + */ + public boolean getMoveable() { + checkWidget(); + return moveable; + } + + @Override + String getNameText() { + return getText(); + } + + /** + * Returns the receiver's parent, which must be a <code>Tree</code>. + * + * @return the receiver's parent + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Tree getParent() { + checkWidget(); + return parent; + } + + /** + * Gets the 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; + } + + /** + * Returns the receiver's tool tip text, or null if it has not been set. + * + * @return the receiver's tool tip text + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public String getToolTipText() { + checkWidget(); + int index = parent.indexOf(this); + if (index == -1) { + return ""; //$NON-NLS-1$ + } + return getQHeaderItem().toolTip(index); + } + + /** + * 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; + } + return getQTreeWidget().header().sectionSize(index); + } + + /** + * 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; + } + getQTreeWidget().resizeColumnToContents(index); + } + + @Override + void releaseParent() { + super.releaseParent(); + if (parent.sortColumn == this) { + parent.sortColumn = null; + } + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is moved or resized. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see ControlListener + * @see #addControlListener + */ + public void removeControlListener(ControlListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Move, listener); + eventTable.unhook(SWT.Resize, listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is selected by the user. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Selection, listener); + eventTable.unhook(SWT.DefaultSelection, listener); + } + + /** + * Controls how text and images will be displayed in the receiver. The + * argument should be one of <code>LEFT</code>, <code>RIGHT</code> or + * <code>CENTER</code>. + * <p> + * Note that due to a restriction on some platforms, the first column is + * always left aligned. + * </p> + * + * @param alignment + * the new alignment + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setAlignment(int alignment) { + checkWidget(); + if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) == 0) { + return; + } + int index = parent.indexOf(this); + if (index == -1 || index == 0) { + return; + } + style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER); + style |= alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER); + + getQTreeWidget().headerItem().setTextAlignment(index, convertAlignment(style)); + } + + private int convertAlignment(int style) { + if ((style & SWT.CENTER) != 0) { + return AlignmentFlag.AlignCenter.value(); + } else if ((style & SWT.RIGHT) != 0) { + return AlignmentFlag.AlignRight.value(); + } + return AlignmentFlag.AlignLeft.value(); + } + + @Override + public void setImage(Image image) { + checkWidget(); + if (image != null && image.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + super.setImage(image); + if (parent.sortColumn != this || parent.sortDirection != SWT.NONE) { + setImage(image, false, false); + } + } + + void setImage(Image image, boolean sort, boolean right) { + int index = parent.indexOf(this); + if (index == -1) { + return; + } + if (image != null) { + QIcon icon = new QIcon(); + icon.addPixmap(image.getQPixmap()); + getQHeaderItem().setIcon(index, icon); + } else { + getQHeaderItem().setIcon(index, (QIcon) null); + } + } + + /** + * Sets the moveable attribute. A column that is moveable can be reordered + * by the user by dragging the header. A column that is not moveable cannot + * be dragged by the user but may be reordered by the programmer. + * + * @param moveable + * the moveable attribute + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Tree#setColumnOrder(int[]) + * @see Tree#getColumnOrder() + * @see TreeColumn#getMoveable() + * @see SWT#Move + * + * @since 3.2 + */ + public void setMoveable(boolean moveable) { + checkWidget(); + this.moveable = moveable; + } + + /** + * Sets the resizable attribute. A column that is not resizable cannot be + * dragged by the user but may be resized by the programmer. + * + * @param resizable + * the resize attribute + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setResizable(boolean resizable) { + checkWidget(); + this.resizable = resizable; + getQHeaderView().setResizeMode(parent.indexOf(this), resizable ? ResizeMode.Interactive : ResizeMode.Fixed); + } + + @Override + public void setText(String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (string.equals(text)) { + return; + } + int index = parent.indexOf(this); + if (index == -1) { + return; + } + super.setText(string); + getQHeaderItem().setText(index, string); + } + + /** + * Sets the receiver's tool tip text to the argument, which may be null + * indicating that the default tool tip for the control will be shown. For a + * control that has a default tool tip, such as the Tree control on Windows, + * setting the tool tip text to an empty string replaces the default, + * causing no tool tip text to be shown. + * <p> + * The mnemonic indicator (character '&') is not displayed in a tool + * tip. To display a single '&' in the tool tip, the character '&' + * can be escaped by doubling it in the string. + * </p> + * + * @param string + * the new tool tip text (or null) + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public void setToolTipText(String string) { + checkWidget(); + int index = parent.indexOf(this); + if (index == -1) { + return; + } + getQHeaderItem().setToolTip(index, 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 (width < 0) { + return; + } + int index = parent.indexOf(this); + if (index == -1) { + return; + } + getQTreeWidget().setColumnWidth(index, width); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TreeItem.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TreeItem.java new file mode 100644 index 0000000000..7ecd774bf9 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/TreeItem.java @@ -0,0 +1,1573 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import java.util.ArrayList; +import java.util.List; + +import com.trolltech.qt.gui.QBrush; +import com.trolltech.qt.gui.QIcon; +import com.trolltech.qt.gui.QTreeWidget; +import com.trolltech.qt.gui.QTreeWidgetItem; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.internal.qt.QtSWTConverter; + +/** + * Instances of this class represent a selectable user interface object that + * represents a hierarchy of tree items in a tree widget. + * + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>(none)</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + * + * @see <a href="http://www.eclipse.org/swt/snippets/#tree">Tree, TreeItem, + * TreeColumn snippets</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + * @noextend This class is not intended to be subclassed by clients. + */ + +public class TreeItem extends Item { + private QTreeWidgetItem item; + private List<TreeItem> items; + private Tree parent; + private TreeItem parentItem; + private String[] strings; + private Image[] images; + private Font font; + private Font[] cellFont; + boolean cached; + private Color background; + private Color foreground; + private int[] cellBackground, cellForeground; + private boolean grayed; + + /** + * Constructs a new instance of this class given its parent (which must be a + * <code>Tree</code> or a <code>TreeItem</code>) and a style value + * describing its behavior and appearance. The item is added to the end of + * the items maintained by its parent. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a tree control which will be the parent of the new instance + * (cannot be null) + * @param style + * the style of control to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public TreeItem(Tree parent, int style) { + this(parent, null, style, -1); + } + + /** + * Constructs a new instance of this class given its parent (which must be a + * <code>Tree</code> or a <code>TreeItem</code>), a style value describing + * its behavior and appearance, and the index at which to place it in the + * items maintained by its parent. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parent + * a tree control which will be the parent of the new instance + * (cannot be null) + * @param style + * the style of control to construct + * @param index + * the zero-relative index to store the receiver in its parent + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the parent (inclusive)</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public TreeItem(Tree parent, int style, int index) { + this(parent, null, style, index); + } + + /** + * Constructs a new instance of this class given its parent (which must be a + * <code>Tree</code> or a <code>TreeItem</code>) and a style value + * describing its behavior and appearance. The item is added to the end of + * the items maintained by its parent. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parentItem + * a tree control which will be the parent of the new instance + * (cannot be null) + * @param style + * the style of control to construct + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public TreeItem(TreeItem parentItem, int style) { + this(checkNull(parentItem).parent, parentItem, style, -1); + } + + /** + * Constructs a new instance of this class given its parent (which must be a + * <code>Tree</code> or a <code>TreeItem</code>), a style value describing + * its behavior and appearance, and the index at which to place it in the + * items maintained by its parent. + * <p> + * The style value is either one of the style constants defined in class + * <code>SWT</code> which is applicable to instances of this class, or must + * be built by <em>bitwise OR</em>'ing together (that is, using the + * <code>int</code> "|" operator) two or more of those <code>SWT</code> + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + * </p> + * + * @param parentItem + * a tree control which will be the parent of the new instance + * (cannot be null) + * @param style + * the style of control to construct + * @param index + * the zero-relative index to store the receiver in its parent + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the parent (inclusive)</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT + * @see Widget#checkSubclass + * @see Widget#getStyle + */ + public TreeItem(TreeItem parentItem, int style, int index) { + this(checkNull(parentItem).parent, parentItem, style, index); + } + + TreeItem(Tree parent, TreeItem parentItem, int style, int index) { + super(parent, style); + this.parent = parent; + item = new QTreeWidgetItem(); + items = new ArrayList<TreeItem>(4); + if (parentItem != null) { + this.parentItem = parentItem; + parentItem.addItem(this, index); + } else { + parent.addItem(this, index); + } + display.addControl(item, this); + } + + void addItem(TreeItem item, int index) { + if (index >= 0 && index < items.size()) { + items.add(index, item); + this.item.insertChild(index, item.getQItem()); + } else { + items.add(item); + this.item.addChild(item.getQItem()); + } + } + + void removeItem(TreeItem item) { + items.remove(item); + getQItem().removeChild(item.getQItem()); + } + + TreeItem getItem(QTreeWidgetItem qItem) { + for (TreeItem item : items) { + if (item.item == qItem) { + return item; + } + TreeItem ti = item.getItem(qItem); + if (ti != null) { + return ti; + } + } + return null; + } + + @Override + void releaseQWidget() { + super.releaseQWidget(); + item = null; + } + + QTreeWidgetItem getQItem() { + return item; + } + + QTreeWidget getQTreeWidget() { + return parent.getQTreeWidget(); + } + + static TreeItem checkNull(TreeItem item) { + if (item == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + return item; + } + + @Override + protected void checkSubclass() { + if (!isValidSubclass()) { + error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + void clear() { + for (int i = 0; i < parent.getColumnCount(); i++) { + item.setText(i, null); + item.setIcon(i, (QIcon) null); + item.setWhatsThis(i, null); + item.setFont(i, null); + } + text = ""; //$NON-NLS-1$ + image = null; + strings = null; + images = null; + if ((parent.style & SWT.CHECK) != 0) { + // + } + background = foreground = null; + font = null; + cellBackground = cellForeground = null; + cellFont = null; + if ((parent.style & SWT.VIRTUAL) != 0) { + cached = false; + } + } + + /** + * Clears the item at the given zero-relative index in the receiver. The + * text, icon and other attributes of the item are set to the default value. + * If the tree was created with the <code>SWT.VIRTUAL</code> style, these + * attributes are requested again as needed. + * + * @param index + * the index of the item to clear + * @param all + * <code>true</code> if all child items of the indexed item + * should be cleared recursively, and <code>false</code> + * otherwise + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list minus 1 (inclusive) + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SWT#VIRTUAL + * @see SWT#SetData + * + * @since 3.2 + */ + public void clear(int index, boolean all) { + checkWidget(); + validateItemIndex(index); + if (index == 0) { + clear(); + return; + } + TreeItem item = items.get(index); + item.clear(0, all); + } + + private void validateItemIndex(int index) { + if (index < 0 || index >= items.size()) { + error(SWT.ERROR_INVALID_RANGE); + } + } + + /** + * Clears all the items in the receiver. The text, icon and other attributes + * of the items are set to their default values. If the tree was created + * with the <code>SWT.VIRTUAL</code> style, these attributes are requested + * again as needed. + * + * @param all + * <code>true</code> if all child items should be cleared + * recursively, and <code>false</code> otherwise + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SWT#VIRTUAL + * @see SWT#SetData + * + * @since 3.2 + */ + public void clearAll(boolean all) { + checkWidget(); + clear(); + for (TreeItem item : items) { + item.clearAll(all); + } + } + + @Override + void destroyWidget() { + if (parentItem != null) { + parentItem.removeItem(this); + } else { + parent.removeItem(this); + } + super.destroyWidget(); + item = null; + } + + /** + * Returns the receiver's background color. + * + * @return the background color + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 2.0 + * + */ + public Color getBackground() { + checkWidget(); + if (background == null) { + return parent.getBackground(); + } + return background; + } + + /** + * Returns the background color at the given column index in the receiver. + * + * @param index + * the column index + * @return the background color + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public Color getBackground(int index) { + checkWidget(); + int count = Math.max(1, parent.getColumnCount()); + if (0 > index || index > count - 1) { + return getBackground(); + } + int pixel = cellBackground != null ? cellBackground[index] : -1; + return pixel == -1 ? getBackground() : Color.qt_new(display, 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(); + return QtSWTConverter.convert(getQTreeWidget().visualItemRect(item)); + } + + /** + * Returns a rectangle describing the receiver's size and location relative + * to its parent at a column in the tree. + * + * @param index + * the index that specifies the column + * @return the receiver's bounding column rectangle + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public Rectangle getBounds(int index) { + checkWidget(); + int count = Math.max(1, item.columnCount()); + if (0 > index || index > count - 1) { + return new Rectangle(0, 0, 0, 0); + } + + return QtSWTConverter.convert(getQTreeWidget().visualItemRect(item.child(index))); + } + + /** + * 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; + } + return item.isSelected(); + } + + /** + * Returns <code>true</code> if the receiver is expanded, and false + * otherwise. + * <p> + * + * @return the expanded state + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + */ + public boolean getExpanded() { + checkWidget(); + return item.isExpanded(); + } + + /** + * Returns the font that the receiver will use to paint textual information + * for this item. + * + * @return the receiver's font + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ + public Font getFont() { + checkWidget(); + return font != null ? font : parent.getFont(); + } + + /** + * Returns the font that the receiver will use to paint textual information + * for the specified cell in this item. + * + * @param index + * the column index + * @return the receiver's font + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public Font getFont(int index) { + checkWidget(); + int count = Math.max(1, parent.getColumnCount()); + if (0 > index || index > count - 1) { + return getFont(); + } + if (cellFont == null || cellFont[index] == null) { + return getFont(); + } + return cellFont[index]; + } + + /** + * Returns the foreground color that the receiver will use to draw. + * + * @return the receiver's foreground color + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 2.0 + * + */ + public Color getForeground() { + checkWidget(); + if (foreground == null) { + return parent.getForeground(); + } + return foreground; + } + + /** + * + * Returns the foreground color at the given column index in the receiver. + * + * @param index + * the column index + * @return the foreground color + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public Color getForeground(int index) { + checkWidget(); + int count = Math.max(1, parent.getColumnCount()); + if (0 > index || index > count - 1) { + return getForeground(); + } + int pixel = cellForeground != null ? cellForeground[index] : -1; + return pixel == -1 ? getForeground() : Color.qt_new(display, 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 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; + } + return grayed; + } + + /** + * Returns the item at the given, zero-relative index in the receiver. + * Throws an exception if the index is out of range. + * + * @param index + * the index of the item to return + * @return the item at the given index + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list minus 1 (inclusive) + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public TreeItem getItem(int index) { + checkWidget(); + if (index < 0 || index >= items.size()) { + error(SWT.ERROR_INVALID_RANGE); + } + return items.get(index); + } + + /** + * 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(); + return items.size(); + } + + /** + * Returns a (possibly empty) array of <code>TreeItem</code>s which are the + * direct item children of the receiver. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its list of items, so modifying the array will not affect the receiver. + * </p> + * + * @return the receiver's items + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public TreeItem[] getItems() { + checkWidget(); + return items.toArray(new TreeItem[items.size()]); + } + + @Override + public Image getImage() { + checkWidget(); + return super.getImage(); + } + + /** + * Returns the image stored at the given column index in the receiver, or + * null if the image has not been set or if the column does not exist. + * + * @param index + * the column index + * @return the image stored at the given column index in the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public Image getImage(int index) { + checkWidget(); + if (index == 0) { + return getImage(); + } + if (images != null) { + if (0 <= index && index < images.length) { + return images[index]; + } + } + return null; + } + + /** + * Returns a rectangle describing the size and location relative to its + * parent of an image at a column in the tree. + * + * @param index + * the index that specifies the column + * @return the receiver's bounding image rectangle + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public Rectangle getImageBounds(int index) { + checkWidget(); + //TODO image only ? + return QtSWTConverter.convert(getQTreeWidget().visualItemRect(getQItem().child(index))); + } + + /** + * Returns the receiver's parent, which must be a <code>Tree</code>. + * + * @return the receiver's parent + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public Tree getParent() { + checkWidget(); + return parent; + } + + /** + * Returns the receiver's parent item, which must be a <code>TreeItem</code> + * or null when the receiver is a root. + * + * @return the receiver's parent item + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public TreeItem getParentItem() { + checkWidget(); + return parentItem; + } + + /** + * Returns the text stored at the given column index in the receiver, or + * empty string if the text has not been set. + * + * @param index + * the column index + * @return the text stored at the given column index in the receiver + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public String getText(int index) { + checkWidget(); + if (index == 0) { + return getText(); + } + if (strings != null) { + if (0 <= index && index < strings.length) { + String string = strings[index]; + return string != null ? string : ""; //$NON-NLS-1$ + } + } + return ""; //$NON-NLS-1$ + } + + /** + * Returns a rectangle describing the size and location relative to its + * parent of the text at a column in the tree. + * + * @param index + * the index that specifies the column + * @return the receiver's bounding text rectangle + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.3 + */ + public Rectangle getTextBounds(int index) { + checkWidget(); + //TODO text only ? + return QtSWTConverter.convert(getQTreeWidget().visualItemRect(getQItem().child(index))); + } + + /** + * Searches the receiver's list starting at the first item (index 0) until + * an item is found that is equal to the argument, and returns the index of + * that item. If no item is found, returns -1. + * + * @param item + * the search item + * @return the index of the item + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the item is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed + * </li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public int indexOf(TreeItem item) { + checkWidget(); + if (item == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (item.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + return items.indexOf(item); + } + + @Override + void releaseChildren(boolean destroy) { + if (destroy) { + for (int i = items.size() - 1; i > -1; i--) { + items.get(i).dispose(); + } + items.clear(); + } + super.releaseChildren(destroy); + } + + @Override + void releaseWidget() { + super.releaseWidget(); + strings = null; + images = null; + cellBackground = cellForeground = null; + cellFont = null; + display.removeControl(item); + } + + /** + * Removes all of the items from the receiver. + * <p> + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not + * called from the thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public void removeAll() { + checkWidget(); + QTreeWidgetItem qItem = getQItem(); + for (TreeItem item : items) { + qItem.removeChild(item.getQItem()); + } + items.clear(); + } + + /** + * Sets the receiver's background color to the color specified by the + * argument, or to the default system color for the item if the argument is + * null. + * + * @param color + * the new color (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 2.0 + * + */ + public void setBackground(Color color) { + checkWidget(); + if (color != null && color.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + Color pixel = null; + if (color != null) { + parent.customDraw = true; + pixel = color; + } + if (background == pixel) { + return; + } + background = pixel; + if ((parent.style & SWT.VIRTUAL) != 0) { + cached = true; + } + } + + /** + * Sets the background color at the given column index in the receiver to + * the color specified by the argument, or to the default system color for + * the item if the argument is null. + * + * @param index + * the column index + * @param color + * the new color (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + * + */ + public void setBackground(int index, Color color) { + checkWidget(); + if (color != null && color.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + int count = Math.max(1, parent.getColumnCount()); + if (0 > index || index > count - 1) { + return; + } + int pixel = -1; + if (color != null) { + parent.customDraw = true; + pixel = color.getPixel(); + } + if (cellBackground == null) { + cellBackground = new int[count]; + for (int i = 0; i < count; i++) { + cellBackground[i] = -1; + } + } + if (cellBackground[index] == pixel) { + return; + } + cellBackground[index] = pixel; + if ((parent.style & SWT.VIRTUAL) != 0) { + cached = true; + } + } + + /** + * 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; + } + getQItem().setSelected(checked); + } + + /** + * 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(); + getQItem().setExpanded(expanded); + } + + /** + * Sets the font that the receiver will use to paint textual information for + * this item to the font specified by the argument, or to the default font + * for that kind of control if the argument is null. + * + * @param font + * the new font (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ + public void setFont(Font font) { + checkWidget(); + if (font != null && font.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + Font oldFont = this.font; + if (oldFont == font) { + return; + } + this.font = font; + if (oldFont != null && oldFont.equals(font)) { + return; + } + if (font != null) { + parent.customDraw = true; + } + if ((parent.style & SWT.VIRTUAL) != 0) { + cached = true; + } + item.setFont(0, font.getQFont()); + } + + /** + * Sets the font that the receiver will use to paint textual information for + * the specified cell in this item to the font specified by the argument, or + * to the default font for that kind of control if the argument is null. + * + * @param index + * the column index + * @param font + * the new font (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public void setFont(int index, Font font) { + checkWidget(); + if (font != null && font.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + int count = Math.max(1, parent.getColumnCount()); + if (0 > index || index > count - 1) { + return; + } + if (cellFont == null) { + if (font == null) { + return; + } + cellFont = new Font[count]; + } + Font oldFont = cellFont[index]; + if (oldFont == font) { + return; + } + cellFont[index] = font; + if (oldFont != null && oldFont.equals(font)) { + return; + } + if (font != null) { + parent.customDraw = true; + } + if ((parent.style & SWT.VIRTUAL) != 0) { + cached = true; + } + if (font == null) { + item.setFont(index, null); + } else { + item.setFont(index, font.getQFont()); + } + } + + /** + * 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); + } + this.foreground = color; + item.setForeground(0, new QBrush(color.getColor())); + } + + /** + * Sets the foreground color at the given column index in the receiver to + * the color specified by the argument, or to the default system color for + * the item if the argument is null. + * + * @param index + * the column index + * @param color + * the new color (or null) + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + * + */ + public void setForeground(int index, Color color) { + checkWidget(); + if (color != null && color.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + int count = Math.max(1, parent.getColumnCount()); + if (0 > index || index > count - 1) { + return; + } + int pixel = -1; + if (color != null) { + parent.customDraw = true; + pixel = color.getPixel(); + } + if (cellForeground == null) { + cellForeground = new int[count]; + for (int i = 0; i < count; i++) { + cellForeground[i] = -1; + } + } + if (cellForeground[index] == pixel) { + return; + } + cellForeground[index] = pixel; + if ((parent.style & SWT.VIRTUAL) != 0) { + cached = true; + } + } + + /** + * Sets the grayed state of the checkbox for this item. This state change + * only applies if the Tree was created with the SWT.CHECK style. + * + * @param grayed + * the new grayed state of the checkbox + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + public void setGrayed(boolean grayed) { + checkWidget(); + if ((parent.style & SWT.CHECK) == 0) { + return; + } + this.grayed = grayed; + } + + /** + * Sets the image for multiple columns in the tree. + * + * @param images + * the array of new images + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of images is null</li> + * <li>ERROR_INVALID_ARGUMENT - if one of the images has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public void setImage(Image[] images) { + checkWidget(); + if (images == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + for (int i = 0; i < images.length; i++) { + setImage(i, images[i]); + } + } + + /** + * Sets the receiver's image at a column. + * + * @param index + * the column index + * @param image + * the new image + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_ARGUMENT - if the image has been + * disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public void setImage(int index, Image image) { + checkWidget(); + if (image != null && image.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + if (index == 0) { + if (image != null && image.isIcon()) { + if (image.equals(this.image)) { + return; + } + } + super.setImage(image); + } + int count = Math.max(1, parent.getColumnCount()); + if (0 > index || index > count - 1) { + return; + } + if (images == null && index != 0) { + images = new Image[count]; + images[0] = image; + } + if (images != null) { + if (image != null && image.isIcon()) { + if (image.equals(images[index])) { + return; + } + } + images[index] = image; + } + if ((parent.style & SWT.VIRTUAL) != 0) { + cached = true; + } + item.setIcon(index, image != null ? image.getQIcon() : null); + } + + @Override + public void setImage(Image image) { + checkWidget(); + setImage(0, image); + } + + /** + * Sets the number of child items contained in the receiver. + * + * @param count + * the number of items + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ + public void setItemCount(int count) { + checkWidget(); + count = Math.max(0, count); + int itemCount = items.size(); + if (count == itemCount) { + return; + } + + if (count < itemCount) { + for (int i = itemCount - 1; i >= count; i--) { + removeItem(items.get(i)); + } + return; + } + // if (isVirtual) { + // //TODO + // } else { + for (int i = itemCount; i < count; i++) { + new TreeItem(this, SWT.NONE, i); + } + } + + /** + * Sets the text for multiple columns in the tree. + * + * @param strings + * the array of new strings + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the text is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public void setText(String[] strings) { + checkWidget(); + if (strings == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + for (int i = 0; i < strings.length; i++) { + String string = strings[i]; + if (string != null) { + setText(i, string); + } + } + } + + /** + * Sets the receiver's text at a column + * + * @param index + * the column index + * @param string + * the new text + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the text is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ + public void setText(int index, String string) { + checkWidget(); + if (string == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (index == 0) { + if (string.equals(text)) { + return; + } + super.setText(string); + } + int count = Math.max(1, parent.getColumnCount()); + if (0 > index || index > count - 1) { + return; + } + if (strings == null && index != 0) { + strings = new String[count]; + strings[0] = text; + } + if (strings != null) { + if (string.equals(strings[index])) { + return; + } + strings[index] = string; + } + if ((parent.style & SWT.VIRTUAL) != 0) { + cached = true; + } + getQItem().setText(index, string); + } + + @Override + public void setText(String string) { + checkWidget(); + setText(0, string); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Widget.java new file mode 100644 index 0000000000..cf693513e6 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Widget.java @@ -0,0 +1,1358 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * Portion Copyright (c) 2009-2010 compeople AG (http://www.compeople.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Compeople AG - QtJambi/Qt based implementation for Windows/Mac OS X/Linux + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import java.util.HashMap; +import java.util.Map; + +import com.trolltech.qt.core.QObject; +import com.trolltech.qt.gui.QContextMenuEvent; +import com.trolltech.qt.gui.QKeyEvent; +import com.trolltech.qt.gui.QMouseEvent; +import com.trolltech.qt.gui.QMoveEvent; +import com.trolltech.qt.gui.QPaintEvent; +import com.trolltech.qt.gui.QResizeEvent; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QWindowStateChangeEvent; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.GCData; +import org.eclipse.swt.internal.SWTEventListener; + +/** + * This class is the abstract superclass of all user interface objects. Widgets + * are created, disposed and issue notification to listeners when events occur + * which affect them. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>(none)</dd> + * <dt><b>Events:</b></dt> + * <dd>Dispose</dd> + * </dl> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> within the + * SWT implementation. However, it has not been marked final to allow those + * outside of the SWT development team to implement patched versions of the + * class in order to get around specific limitations in advance of when those + * limitations can be addressed by the team. Any class built using subclassing + * to access the internals of this class will likely fail to compile or run + * between releases and may be strongly platform specific. Subclassing should + * not be attempted without an intimate and detailed understanding of the + * workings of the hierarchy. No support is provided for user-written classes + * which are implemented as subclasses of this class. + * </p> + * + * @see #checkSubclass + * @see <a href="http://www.eclipse.org/swt/">Sample code and further + * information</a> + */ + +public abstract class Widget { + public static final String QT_SWT_CONTROL_PROPERTY = "__SWT_CONTROL";//$NON-NLS-1$ + int style, state; + Display display; + EventTable eventTable; + private Map<String, Object> data; + private Object mainData; + + /* Global state flags */ + static final int DISPOSED = 1 << 0; + static final int CANVAS = 1 << 1; + static final int KEYED_DATA = 1 << 2; + static final int HIDDEN = 1 << 4; + + /* A layout was requested on this widget */ + static final int LAYOUT_NEEDED = 1 << 5; + + /* The preferred size of a child has changed */ + static final int LAYOUT_CHANGED = 1 << 6; + + /* A layout was requested in this widget hierarchy */ + static final int LAYOUT_CHILD = 1 << 7; + + /* Background flags */ + static final int THEME_BACKGROUND = 1 << 8; + static final int DRAW_BACKGROUND = 1 << 9; + static final int PARENT_BACKGROUND = 1 << 10; + + /* Dispose and release flags */ + static final int RELEASED = 1 << 11; + static final int DISPOSE_SENT = 1 << 12; + + /* More global widget state flags */ + static final int TRACK_MOUSE = 1 << 13; + static final int FOREIGN_HANDLE = 1 << 14; + static final int DRAG_DETECT = 1 << 15; + + /* Move and resize state flags */ + static final int MOVE_OCCURRED = 1 << 16; + static final int MOVE_DEFERRED = 1 << 17; + static final int RESIZE_OCCURRED = 1 << 18; + static final int RESIZE_DEFERRED = 1 << 19; + + /* Ignore WM_CHANGEUISTATE */ + static final int IGNORE_WM_CHANGEUISTATE = 1 << 20; + + /* Default size for widgets */ + static final int DEFAULT_WIDTH = 64; + static final int DEFAULT_HEIGHT = 64; + + /* Check and initialize the Common Controls DLL */ + static final int MAJOR = 5, MINOR = 80; + private QWidget qWidget; + + /** + * 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> + * <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + * + * @see SWT + * @see #checkSubclass + * @see #getStyle + */ + public Widget(Widget parent, int style) { + checkSubclass(); + checkParent(parent); + this.style = style; + display = parent.display; + } + + void setQWidget(QWidget qWidget) { + this.qWidget = qWidget; + } + + public QWidget getQWidget() { + return qWidget; + } + + protected QWidget getQMasterWidget() { + return getQWidget(); + } + + protected void setStyleSheet(String style) { + getQMasterWidget().setStyleSheet(style); + updateLayout(); + } + + protected void updateStyleSheet() { + if (null != getQMasterWidget().style()) { + getQMasterWidget().setStyle(getQMasterWidget().style()); + updateLayout(); + } + } + + protected void updateLayout() { + // nothing by default + } + + void _addListener(int eventType, Listener listener) { + if (eventTable == null) { + eventTable = new EventTable(); + } + if (eventType == SWT.DragDetect && this instanceof CTabFolder) { + System.out.println("adding dnd drag listener"); + } + eventTable.hook(eventType, listener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when an event of the given type occurs. When the event does occur in the + * widget, the listener is notified by sending it the + * <code>handleEvent()</code> message. The event type is one of the event + * constants defined in class <code>SWT</code>. + * + * @param eventType + * the type of event to listen for + * @param listener + * the listener which should be notified when the event occurs + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Listener + * @see SWT + * @see #getListeners(int) + * @see #removeListener(int, Listener) + * @see #notifyListeners + */ + public void addListener(int eventType, Listener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + _addListener(eventType, listener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the widget is disposed. When the widget is disposed, the listener is + * notified by sending it the <code>widgetDisposed()</code> message. + * + * @param listener + * the listener which should be notified when the receiver is + * disposed + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see DisposeListener + * @see #removeDisposeListener + */ + public void addDisposeListener(DisposeListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Dispose, typedListener); + } + + /** + * 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 + * + * refactored: was checkBits + */ + 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; + } + + /* refactored: was checkOrientation */ + void checkAndUpdateOrientation(Widget parent) { + style &= ~SWT.MIRRORED; + if ((style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT)) == 0) { + if (parent != null) { + if ((parent.style & SWT.LEFT_TO_RIGHT) != 0) { + style |= SWT.LEFT_TO_RIGHT; + } + if ((parent.style & SWT.RIGHT_TO_LEFT) != 0) { + style |= SWT.RIGHT_TO_LEFT; + } + } + } + style = checkBits(style, SWT.LEFT_TO_RIGHT, SWT.RIGHT_TO_LEFT, 0, 0, 0, 0); + } + + void checkOpened() { + /* Do nothing */ + } + + /** + * 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.isDisposed()) { + error(SWT.ERROR_INVALID_ARGUMENT); + } + parent.checkWidget(); + parent.checkOpened(); + } + + /** + * Checks that this class can be subclassed. + * <p> + * The SWT class library is intended to be subclassed only at specific, + * controlled points (most notably, <code>Composite</code> and + * <code>Canvas</code> when implementing new widgets). This method enforces + * this rule unless it is overridden. + * </p> + * <p> + * <em>IMPORTANT:</em> By providing an implementation of this method that + * allows a subclass of a class which does not normally allow subclassing to + * be created, the implementer agrees to be fully responsible for the fact + * that any such subclass will likely fail between SWT releases and will be + * strongly platform specific. No support is provided for user-written + * classes which are implemented in this fashion. + * </p> + * <p> + * The ability to subclass outside of the allowed SWT classes is intended + * purely to enable those not on the SWT development team to implement + * patches in order to get around specific limitations in advance of when + * those limitations can be addressed by the team. Subclassing should not be + * attempted without an intimate and detailed understanding of the + * hierarchy. + * </p> + * + * @exception SWTException + * <ul> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an + * allowed subclass</li> + * </ul> + */ + protected void checkSubclass() { + if (!isValidSubclass()) { + error(SWT.ERROR_INVALID_SUBCLASS); + } + } + + /** + * Throws an <code>SWTException</code> if the receiver can not be accessed + * by the caller. This may include both checks on the state of the receiver + * and more generally on the entire execution context. This method + * <em>should</em> be called by widget implementors to enforce the standard + * SWT invariants. + * <p> + * Currently, it is an error to invoke any method (other than + * <code>isDisposed()</code>) on a widget that has had its + * <code>dispose()</code> method called. It is also an error to call widget + * methods from any thread that is different from the thread that created + * the widget. + * </p> + * <p> + * In future releases of SWT, there may be more or fewer error checks and + * exceptions may be thrown for different reasons. + * </p> + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + */ + protected void checkWidget() { + Display display = this.display; + if (display == null) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + if (display.thread != Thread.currentThread()) { + error(SWT.ERROR_THREAD_INVALID_ACCESS); + } + if ((state & DISPOSED) != 0) { + 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 descendants 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> + * <p> + * See also <code>releaseChild()</code>, <code>releaseWidget()</code> and + * <code>releaseHandle()</code>. + * </p> + * + * @see #dispose + */ + void destroyWidget() { + releaseQWidget(); + } + + /** + * Disposes of the operating system resources associated with the receiver + * and all its descendants. After this method has been invoked, the receiver + * and all descendants will answer <code>true</code> when sent the message + * <code>isDisposed()</code>. Any internal connections between the widgets + * in the tree will have been removed to facilitate garbage collection. + * <p> + * NOTE: This method is not called recursively on the descendants of the + * receiver. This means that, widget implementers can not detect when a + * widget is being disposed of by re-implementing this method, but should + * instead listen for the <code>Dispose</code> event. + * </p> + * + * @exception SWTException + * <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #addDisposeListener + * @see #removeDisposeListener + * @see #checkWidget + */ + public void dispose() { + /* + * Note: It is valid to attempt to dispose a widget more than once. If + * this happens, fail silently. + */ + if (isDisposed()) { + return; + } + + if (!isValidThread()) { + error(SWT.ERROR_THREAD_INVALID_ACCESS); + } + release(true); + } + + /** + * 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 SWT#error(int) + */ + void error(int code) { + SWT.error(code); + } + + boolean filters(int eventType) { + return display.filters(eventType); + } + + char[] fixMnemonic(String string) { + return fixMnemonic(string, false); + } + + char[] fixMnemonic(String string, boolean spaces) { + char[] buffer = new char[string.length() + 1]; + string.getChars(0, string.length(), buffer, 0); + int i = 0, j = 0; + while (i < buffer.length) { + if (buffer[i] == '&') { + if (i + 1 < buffer.length && buffer[i + 1] == '&') { + if (spaces) { + buffer[j] = ' '; + } + j++; + i++; + } + i++; + } else { + buffer[j++] = buffer[i++]; + } + } + while (j < buffer.length) { + buffer[j++] = 0; + } + return buffer; + } + + /** + * Returns the <code>Display</code> that is associated with the receiver. + * <p> + * A widget's display is either provided when it is created (for example, + * top level <code>Shell</code>s) or is the same as its parent's display. + * </p> + * + * @return the receiver's display + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * </ul> + */ + public Display getDisplay() { + Display display = this.display; + if (display == null) { + error(SWT.ERROR_WIDGET_DISPOSED); + } + return display; + } + + /** + * Returns an array of listeners who will be notified when an event of the + * given type occurs. The event type is one of the event constants defined + * in class <code>SWT</code>. + * + * @param eventType + * the type of event to listen for + * @return an array of listeners that will be notified when the event occurs + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Listener + * @see SWT + * @see #addListener(int, Listener) + * @see #removeListener(int, Listener) + * @see #notifyListeners + * + * @since 3.4 + */ + public Listener[] getListeners(int eventType) { + checkWidget(); + if (eventTable == null) { + return new Listener[0]; + } + return eventTable.getListeners(eventType); + } + + Menu getMenu() { + return null; + } + + /** + * 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 ""; //$NON-NLS-1$ + } + + /** + * 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. The event type is one of the event constants defined in class + * <code>SWT</code>. + * + * @param eventType + * the type of event + * @return true if the event is hooked + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SWT + */ + public boolean isListening(int eventType) { + checkWidget(); + return hooks(eventType); + } + + /* + * 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(); + } + + GC new_GC(GCData data) { + return null; + } + + /** + * Notifies all of the receiver's listeners for events of the given type + * that one such event has occurred by invoking their + * <code>handleEvent()</code> method. The event type is one of the event + * constants defined in class <code>SWT</code>. + * + * @param eventType + * the type of event which has occurred + * @param event + * the event data + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see SWT + * @see #addListener + * @see #getListeners(int) + * @see #removeListener(int, Listener) + */ + public void notifyListeners(int eventType, Event event) { + checkWidget(); + if (event == null) { + event = new Event(); + } + sendEvent(eventType, event); + } + + void postEvent(int eventType) { + sendEvent(eventType, null, false); + } + + void postEvent(int eventType, Event event) { + sendEvent(eventType, event, false); + } + + /* + * Releases the widget hierarchy and optionally destroys the receiver. <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> + * + * @param destroy indicates that the receiver should be destroyed + * + * @see #dispose + * + * @see #releaseParent + * + * @see #releaseWidget + */ + void release(boolean destroy) { + if ((state & DISPOSE_SENT) == 0) { + state |= DISPOSE_SENT; + sendEvent(SWT.Dispose); + } + if ((state & DISPOSED) == 0) { + releaseChildren(destroy); + } + if ((state & RELEASED) == 0) { + state |= RELEASED; + if (destroy) { + releaseParent(); + releaseWidget(); + destroyWidget(); + } else { + releaseWidget(); + releaseQWidget(); + } + } + } + + void releaseChildren(boolean destroy) { + } + + /* + * 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 #releaseChildren + * + * @see #releaseParent + * + * @see #releaseWidget + */ + void releaseQWidget() { + state |= DISPOSED; + display = null; + qWidget = null; + } + + /* + * 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. </p> + * + * @see #dispose + * + * @see #releaseChildren + * + * @see #releaseWidget + * + * @see #releaseHandle + */ + void releaseParent() { + } + + /* + * 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> + * + * @see #dispose + * + * @see #releaseChildren + * + * @see #releaseHandle + * + * @see #releaseParent + */ + void releaseWidget() { + eventTable = null; + data = null; + mainData = null; + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when an event of the given type occurs. The event type is one of + * the event constants defined in class <code>SWT</code>. + * + * @param eventType + * the type of event to listen for + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Listener + * @see SWT + * @see #addListener + * @see #getListeners(int) + * @see #notifyListeners + */ + public void removeListener(int eventType, Listener 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 + * notified when an event of the given type occurs. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the SWT public API. + * It is marked public only so that it can be shared within the packages + * provided by SWT. It should never be referenced from application code. + * </p> + * + * @param eventType + * the type of event to listen for + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see Listener + * @see #addListener + */ + protected void removeListener(int eventType, SWTEventListener 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 + * notified when the widget is disposed. + * + * @param listener + * the listener which should no longer be notified + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see DisposeListener + * @see #addDisposeListener + */ + public void removeDisposeListener(DisposeListener listener) { + checkWidget(); + if (listener == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if (eventTable == null) { + return; + } + eventTable.unhook(SWT.Dispose, listener); + } + + boolean sendDragEvent(int button, int x, int y) { + Event event = new Event(); + event.button = button; + event.x = x; + event.y = y; + //setInputState(event, SWT.DragDetect); + sendEvent(SWT.DragDetect, event); + if (isDisposed()) { + return false; + } + return event.doit; + } + + void sendEvent(Event event) { + event.display = 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) { + 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); + } + } + + /** + * Returns the application defined widget data associated with the receiver, + * or null if it has not been set. The <em>widget data</em> is a single, + * unnamed field that is stored with every widget. + * <p> + * Applications may put arbitrary objects in this field. If the object + * stored in the widget data needs to be notified when the widget is + * disposed of, it is the application's responsibility to hook the Dispose + * event on the widget and do so. + * </p> + * + * @return the widget data + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - when the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - when called from the + * wrong thread</li> + * </ul> + * + * @see #setData(Object) + */ + public Object getData() { + checkWidget(); + return mainData; + } + + /** + * Returns the application defined property of the receiver with the + * specified name, or null if it has not been set. + * <p> + * Applications may have associated arbitrary objects with the receiver in + * this fashion. If the objects stored in the properties need to be notified + * when the widget is disposed of, it is the application's responsibility to + * hook the Dispose event on the widget and do so. + * </p> + * + * @param key + * the name of the property + * @return the value of the property or null if it has not been set + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the key is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #setData(String, Object) + */ + public Object getData(String key) { + checkWidget(); + if (key == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + + Object value = getDataMap().get(key); + if (value == null) { + if (getQMasterWidget() != null) { + value = getQMasterWidget().property(key); + } + } + return value; + } + + private Map<String, Object> getDataMap() { + if (data == null) { + data = new HashMap<String, Object>(4); + } + return data; + } + + /** + * Sets the application defined widget data associated with the receiver to + * be the argument. The <em>widget + * data</em> is a single, unnamed field that is stored with every widget. + * <p> + * Applications may put arbitrary objects in this field. If the object + * stored in the widget data needs to be notified when the widget is + * disposed of, it is the application's responsibility to hook the Dispose + * event on the widget and do so. + * </p> + * + * @param data + * the widget data + * + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - when the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - when called from the + * wrong thread</li> + * </ul> + * + * @see #getData() + */ + public void setData(Object data) { + checkWidget(); + this.mainData = data; + } + + /** + * Sets the application defined property of the receiver with the specified + * name to the given value. + * <p> + * Applications may associate arbitrary objects with the receiver in this + * fashion. If the objects stored in the properties need to be notified when + * the widget is disposed of, it is the application's responsibility to hook + * the Dispose event on the widget and do so. + * </p> + * + * @param key + * the name of the property + * @param value + * the new value for the property + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the key is null</li> + * </ul> + * @exception SWTException + * <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver</li> + * </ul> + * + * @see #getData(String) + */ + public void setData(String key, Object value) { + checkWidget(); + if (key == null) { + error(SWT.ERROR_NULL_ARGUMENT); + } + if ("stylesheet".equals(key)) { //$NON-NLS-1$ + setStyleSheet((String) value); + return; + } + + if (value == null) { + if (getDataMap().containsKey(key)) { + getDataMap().remove(key); + } else { + if (getQMasterWidget() != null) { + getQMasterWidget().setProperty(key, null); + updateStyleSheet(); // we have to update the style, cause the property can be referenced in the style + } + } + } else { + // we store Strings/Booleans adin the Qt Control, everything + // else in the local map + if (getQMasterWidget() != null && (value instanceof String || value instanceof Boolean)) { + getQMasterWidget().setProperty(key, value); + updateStyleSheet(); // we have to update the style, cause the property can be referenced in the style + } else { + getDataMap().put(key, value); + } + } + } + + boolean showMenu(int x, int y) { + Event event = new Event(); + event.x = x; + event.y = y; + sendEvent(SWT.MenuDetect, event); + if (!event.doit) { + return true; + } + Menu menu = getMenu(); + if (menu != null && !menu.isDisposed()) { + if (x != event.x || y != event.y) { + menu.setLocation(event.x, event.y); + } + menu.setVisible(true); + return true; + } + return false; + } + + /** + * Returns a string containing a concise, human-readable description of the + * receiver. + * + * @return a string representation of the receiver + */ + @Override + public String toString() { + return getName() + " {" + getDescription() + "}"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + private String getDescription() { + if (isDisposed()) { + return "*Disposed*"; //$NON-NLS-1$ + } + if (!isValidThread()) { + return "*Wrong Thread*"; //$NON-NLS-1$ + } + return getNameText(); + } + + /* Qt Events */ + public boolean qtCloseEvent() { + return false; + } + + public boolean qtResizeEvent(QObject source, QResizeEvent resizeEvent) { + return false; + } + + public boolean qtMoveEvent(QObject source, QMoveEvent moveEvent) { + return false; + } + + public boolean qtPaintEvent(QObject source, QPaintEvent paintEvent) { + return false; + } + + public boolean qtKeyPressEvent(QObject source, QKeyEvent qEvent) { + return false; + } + + public boolean qtKeyReleaseEvent(QObject source, QKeyEvent qEvent) { + return false; + } + + public boolean qtMouseMoveEvent(QObject source, QMouseEvent mouseEvent) { + return false; + } + + public boolean qtMouseButtonPressEvent(QObject source, QMouseEvent mouseEvent) { + return false; + } + + public boolean qtMouseButtonReleaseEvent(QObject source, QMouseEvent mouseEvent) { + return false; + } + + public boolean qtMouseButtonDblClickEvent(QObject source, QMouseEvent mouseEvent) { + return false; + } + + public boolean qtMouseEnterEvent(Object source) { + return false; + } + + public boolean qtMouseLeaveEvent(Object source) { + return false; + } + + public boolean qtContextMenuEvent(Object source, QContextMenuEvent event) { + return false; + } + + public boolean qtShowEvent(QObject source) { + return false; + } + + public boolean qtHideEvent(QObject source) { + return false; + } + + public void qtFocusInEvent(QObject source) { + // nothing + } + + public void qtFocusOutEvent(QObject source) { + // nothing + } + + public boolean qtWindowActivateEvent(QObject source) { + return false; + } + + public boolean qtWindowDeactivateEvent(QObject obj) { + return false; + } + + public boolean qtWindowStateChangeEvent(QObject obj, QWindowStateChangeEvent event) { + return false; + } + +} |