# HG changeset patch # User Frank Benoit # Date 1211413006 -7200 # Node ID 46a6e0e6ccd404942a3ae601023a2d44138e2de6 # Parent 07b9d96fd764896a2f4d753e24f26d1ed8f96342 Merge with d-fied sources of 3.4M7 diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/commands/AbstractHandler.d --- a/dwtx/core/commands/AbstractHandler.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/commands/AbstractHandler.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2006 IBM Corporation and others. + * Copyright (c) 2004, 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 @@ -13,7 +13,7 @@ module dwtx.core.commands.AbstractHandler; import dwtx.core.commands.common.EventManager; -import dwtx.core.commands.IHandler; +import dwtx.core.commands.IHandler2; import dwtx.core.commands.IHandlerListener; import dwtx.core.commands.HandlerEvent; @@ -32,7 +32,14 @@ * * @since 3.1 */ -public abstract class AbstractHandler : EventManager, IHandler { +public abstract class AbstractHandler : EventManager, IHandler2 { + + /** + * Track this base class enabled state. + * + * @since 3.4 + */ + private bool baseEnabled = true; /** * @see IHandler#addHandlerListener(IHandlerListener) @@ -81,12 +88,48 @@ /** * Whether this handler is capable of executing at this time. Subclasses may - * override this method. + * override this method. If clients override this method they should also + * consider overriding {@link #setEnabled(Object)} so they can be notified + * about framework execution contexts. * * @return true + * @see #setEnabled(Object) + * @see #setBaseEnabled(bool) */ public bool isEnabled() { - return true; + return baseEnabled; + } + + /** + * Allow the default {@link #isEnabled()} to answer our enabled state. It + * will fire a HandlerEvent if necessary. If clients use this method they + * should also consider overriding {@link #setEnabled(Object)} so they can + * be notified about framework execution contexts. + * + * @param state + * the enabled state + * @since 3.4 + */ + protected void setBaseEnabled(bool state) { + if (baseEnabled is state) { + return; + } + baseEnabled = state; + fireHandlerChanged(new HandlerEvent(this, true, false)); + } + + /** + * Called by the framework to allow the handler to update its enabled state + * by extracting the same information available at execution time. Clients + * may override if they need to extract information from the application + * context. + * + * @param evaluationContext + * the application context. May be null + * @since 3.4 + * @see #setBaseEnabled(bool) + */ + public void setEnabled(Object evaluationContext) { } /** diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/commands/Command.d --- a/dwtx/core/commands/Command.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/commands/Command.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2007 IBM Corporation and others. + * Copyright (c) 2004, 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 @@ -499,6 +499,7 @@ // Perform the execution, if there is a handler. if ((handler !is null) && (handler.isHandled())) { + setEnabled(event.getApplicationContext()); if (!isEnabled()) { NotEnabledException exception = new NotEnabledException( "Trying to execute the disabled command " ~ getId()); //$NON-NLS-1$ @@ -735,7 +736,7 @@ /** * Returns the help context identifier associated with this command. This * method should not be called by clients. Clients should use - * {@link CommandManager#getHelpContextId(String)} instead. + * {@link CommandManager#getHelpContextId(Command)} instead. * * @return The help context identifier for this command; may be * null if there is none. @@ -862,6 +863,21 @@ return handler.isEnabled(); } + + /** + * Called be the framework to allow the handler to update its enabled state. + * + * @param evaluationContext + * the state to evaluate against. May be null + * which indicates that the handler can query whatever model that + * is necessary. This context must not be cached. + * @since 3.4 + */ + public void setEnabled(Object evaluationContext) { + if (handler instanceof IHandler2) { + ((IHandler2) handler).setEnabled(evaluationContext); + } + } /** * Returns whether this command has a handler, and whether this handler is @@ -1004,7 +1020,7 @@ } /** - * @return + * @return the handler listener */ private IHandlerListener getHandlerListener() { if (handlerListener is null) { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/commands/CommandManager.d --- a/dwtx/core/commands/CommandManager.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/commands/CommandManager.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2006 IBM Corporation and others. + * Copyright (c) 2004, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -206,11 +206,14 @@ /** * Unescapes special characters in the command id, parameter ids and - * parameter values for {@link #deserialize()}. The special characters + * parameter values for {@link #deserialize(String)}. The special characters * {@link #PARAMETER_START_CHAR}, {@link #PARAMETER_END_CHAR}, * {@link #ID_VALUE_CHAR}, {@link #PARAMETER_SEPARATOR_CHAR} and * {@link #ESCAPE_CHAR} are escaped by prepending an {@link #ESCAPE_CHAR} * character. + *

+ * See also ParameterizedCommand.escape(String) + *

* * @param escapedText * a String that may contain escaped special @@ -220,7 +223,6 @@ * @throws SerializationException * if escapedText contains an invalid escape * sequence - * @see ParameterizedCommand#escape(String) * @since 3.2 */ private static final String unescape(String escapedText) { @@ -296,7 +298,7 @@ * events from commands controlled by this manager to listeners on this * manager. */ - private IExecutionListener executionListener = null; + private IExecutionListenerWithChecks executionListener = null; /** * The collection of execution listeners. This collection is @@ -729,8 +731,6 @@ * array of parameters of the command being deserialized; may be * null. * @return an array of parameterizations; may be null. - * @throws NotDefinedException - * if the command is not defined * @throws SerializationException * if there is an error deserializing the parameters * @since 3.2 @@ -987,4 +987,109 @@ return pos; } + /** + * Fires the notEnabled event for + * executionListeners. + *

+ * Note: This supports bridging actions to the command framework, + * and should not be used outside the framework. + *

+ * + * @param commandId + * The command id of the command about to execute, never + * null. + * @param exception + * The exception, never null. + * @since 3.4 + */ + public void fireNotEnabled(String commandId, NotEnabledException exception) { + if (executionListener !is null) { + executionListener.notEnabled(commandId, exception); + } + } + + /** + * Fires the notDefined event for + * executionListeners. + *

+ * Note: This supports bridging actions to the command framework, + * and should not be used outside the framework. + *

+ * + * @param commandId + * The command id of the command about to execute, never + * null. + * @param exception + * The exception, never null. + * @since 3.4 + */ + public void fireNotDefined(String commandId, NotDefinedException exception) { + if (executionListener !is null) { + executionListener.notDefined(commandId, exception); + } + } + + /** + * Fires the preExecute event for + * executionListeners. + *

+ * Note: This supports bridging actions to the command framework, + * and should not be used outside the framework. + *

+ * + * @param commandId + * The command id of the command about to execute, never + * null. + * @param event + * The event that triggered the command, may be null. + * @since 3.4 + */ + public void firePreExecute(String commandId, ExecutionEvent event) { + if (executionListener !is null) { + executionListener.preExecute(commandId, event); + } + } + + /** + * Fires the postExecuteSuccess event for + * executionListeners. + *

+ * Note: This supports bridging actions to the command framework, + * and should not be used outside the framework. + *

+ * + * @param commandId + * The command id of the command executed, never + * null. + * @param returnValue + * The value returned from the command, may be null. + * @since 3.4 + */ + public void firePostExecuteSuccess(String commandId, Object returnValue) { + if (executionListener !is null) { + executionListener.postExecuteSuccess(commandId, returnValue); + } + } + + /** + * Fires the postExecuteFailure event for + * executionListeners. + *

+ * Note: This supports bridging actions to the command framework, + * and should not be used outside the framework. + *

+ * + * @param commandId + * The command id of the command executed, never + * null. + * @param exception + * The exception, never null. + * @since 3.4 + */ + public void firePostExecuteFailure(String commandId, + ExecutionException exception) { + if (executionListener !is null) { + executionListener.postExecuteFailure(commandId, exception); + } + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/commands/IHandler.d --- a/dwtx/core/commands/IHandler.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/commands/IHandler.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2005 IBM Corporation and others. + * Copyright (c) 2004, 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 @@ -15,7 +15,6 @@ import dwtx.core.commands.IHandlerListener; import dwtx.core.commands.ExecutionEvent; - /** * A handler is the pluggable piece of a command that handles execution. Each * command can have zero or more handlers associated with it (in general), of @@ -61,10 +60,13 @@ /** * Returns whether this handler is capable of executing at this moment in - * time. + * time. If the enabled state is other than true clients should also + * consider implementing IHandler2 so they can be notified about framework + * execution contexts. * * @return true if the command is enabled; false * otherwise. + * @see IHandler2#setEnabled(Object) */ public bool isEnabled(); diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/commands/IHandler2.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/core/commands/IHandler2.d Thu May 22 01:36:46 2008 +0200 @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 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 + * Port to the D programming language: + * Frank Benoit + ******************************************************************************/ + +module dwtx.core.commands.IHandler2; + +/** + * Extend the IHandler interface to provide some context for isEnabled() + * requests. Clients should use {@link AbstractHandler} unless they need to + * provide their own listener mechanism. + * + * @since 3.4 + * @see AbstractHandler + */ +public interface IHandler2 extends IHandler { + /** + * Called by the framework to allow the handler to update its enabled state. + * + * @param evaluationContext + * the state to evaluate against. May be null + * which indicates that the handler can query whatever model that + * is necessary. This context must not be cached. + */ + public void setEnabled(Object evaluationContext); +} diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/commands/ParameterizedCommand.d --- a/dwtx/core/commands/ParameterizedCommand.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/commands/ParameterizedCommand.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 IBM Corporation and others. + * Copyright (c) 2005, 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Benjamin Muskalla - bug 222861 [Commands] ParameterizedCommand#equals broken * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -121,7 +122,6 @@ * serialization. * @return a String representing rawText with * special serialization characters escaped - * @see CommandManager#unescape(String) * @since 3.2 */ private static final String escape(String rawText) { @@ -318,6 +318,69 @@ } /** + * Take a command and a map of parameter IDs to values, and generate the + * appropriate parameterized command. + * + * @param command + * The command object. Must not be null. + * @param parameters + * A map of String parameter ids to objects. May be + * null. + * @return the parameterized command, or null if it could not + * be generated + * @since 3.4 + */ + public static final ParameterizedCommand generateCommand(Command command, + Map parameters) { + // no parameters + if (parameters is null || parameters.isEmpty()) { + return new ParameterizedCommand(command, null); + } + + try { + ArrayList parms = new ArrayList(); + Iterator i = parameters.keySet().iterator(); + + // iterate over given parameters + while (i.hasNext()) { + String key = (String) i.next(); + IParameter parameter = null; + // get the parameter from the command + parameter = command.getParameter(key); + + // if the parameter is defined add it to the parameter list + if (parameter is null) { + return null; + } + ParameterType parameterType = command.getParameterType(key); + if (parameterType is null) { + parms.add(new Parameterization(parameter, + (String) parameters.get(key))); + } else { + AbstractParameterValueConverter valueConverter = parameterType + .getValueConverter(); + if (valueConverter !is null) { + String val = valueConverter.convertToString(parameters + .get(key)); + parms.add(new Parameterization(parameter, val)); + } else { + parms.add(new Parameterization(parameter, + (String) parameters.get(key))); + } + } + } + + // convert the parameters to an Parameterization array and create + // the command + return new ParameterizedCommand(command, (Parameterization[]) parms + .toArray(new Parameterization[parms.size()])); + } catch (NotDefinedException e) { + } catch (ParameterValueConversionException e) { + } + return null; + } + + /** * The base command which is being parameterized. This value is never * null. */ @@ -346,10 +409,7 @@ * null. * @param parameterizations * An array of parameterizations binding parameters to values for - * the command. This value may be null. This - * argument is not copied; if you need to make changes to it - * after constructing this parameterized command, then make a - * copy yourself. + * the command. This value may be null. */ public this(Command command, Parameterization[] parameterizations) { @@ -359,8 +419,27 @@ } this.command = command; - this.parameterizations = (parameterizations is null || parameterizations.length is 0) ? null - : parameterizations; + IParameter[] parms = null; + try { + parms = command.getParameters(); + } catch (NotDefinedException e) { + // This should not happen. + } + if (parameterizations !is null && parameterizations.length>0 && parms !is null) { + int parmIndex = 0; + Parameterization[] params = new Parameterization[parameterizations.length]; + for (int j = 0; j < parms.length; j++) { + for (int i = 0; i < parameterizations.length; i++) { + Parameterization pm = parameterizations[i]; + if (parms[j].equals(pm.getParameter())) { + params[parmIndex++] = pm; + } + } + } + this.parameterizations = params; + } else { + this.parameterizations = null; + } } /* @@ -548,7 +627,9 @@ return parameterMap; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see java.lang.Object#hashCode() */ public override final hash_t toHash() { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/commands/common/CommandException.d --- a/dwtx/core/commands/common/CommandException.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/commands/common/CommandException.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2005 IBM Corporation and others. + * Copyright (c) 2004, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -21,10 +21,18 @@ *

* * @since 3.1 + * @noextend This class is not intended to be subclassed by clients. */ public abstract class CommandException : Exception { /** + * Generated serial version UID for this class. + * + * @since 3.4 + */ + private static final long serialVersionUID = 5389763628699257234L; + + /** * This member variable is required here to allow us to compile against JCL * foundation libraries. The value may be null. */ diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/commands/common/IIdentifiable.d --- a/dwtx/core/commands/common/IIdentifiable.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/commands/common/IIdentifiable.d Thu May 22 01:36:46 2008 +0200 @@ -1,1 +1,32 @@ -/******************************************************************************* * Copyright (c) 2006 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 * Port to the D programming language: * Frank Benoit ******************************************************************************/ module dwtx.core.commands.common.IIdentifiable; import dwt.dwthelper.utils; /** *

* An object that is unique identifiable based on the combination of its class * and its identifier. *

* * @see HandleObject * @since 3.2 */ public interface IIdentifiable { /** * Returns the identifier for this object. * * @return The identifier; never null. */ String getId(); } \ No newline at end of file +/******************************************************************************* + * Copyright (c) 2006, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Port to the D programming language: + * Frank Benoit + *******************************************************************************/ +module dwtx.core.commands.common.IIdentifiable; +import dwt.dwthelper.utils; +/** + *

+ * An object that is unique identifiable based on the combination of its class + * and its identifier. + *

+ * + * @see HandleObject + * @since 3.2 + */ +public interface IIdentifiable { + + /** + * Returns the identifier for this object. + * + * @return The identifier; never null. + */ + String getId(); +} diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/commands/common/NamedHandleObjectComparator.d --- a/dwtx/core/commands/common/NamedHandleObjectComparator.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/commands/common/NamedHandleObjectComparator.d Thu May 22 01:36:46 2008 +0200 @@ -1,1 +1,61 @@ -/******************************************************************************* * Copyright (c) 2005 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 * Port to the D programming language: * Frank Benoit ******************************************************************************/ module dwtx.core.commands.common.NamedHandleObjectComparator; // import java.util.Comparator; import dwtx.core.commands.common.NotDefinedException; import dwtx.core.commands.common.NamedHandleObject; import dwtx.core.internal.commands.util.Util; import dwt.dwthelper.utils; /** * Comparator for instances of NamedHandleObject for display to * an end user. The comparison is based on the name of the instances. * * @since 3.2 */ public class NamedHandleObjectComparator /+: Comparator+/ { /** * Compares to instances of NamedHandleObject based on their names. This is * useful is they are display to an end user. * * @param left * The first obect to compare; may be null. * @param right * The second object to compare; may be null. * @return -1 if left is null * and right is not null; * 0 if they are both null; * 1 if left is not null * and right is null. Otherwise, the * result of left.compareTo(right). */ public final int compare(Object left, Object right) { NamedHandleObject a = cast(NamedHandleObject) left; NamedHandleObject b = cast(NamedHandleObject) right; String aName = null; try { aName = a.getName(); } catch (NotDefinedException e) { // Leave aName as null. } String bName = null; try { bName = b.getName(); } catch (NotDefinedException e) { // Leave bName as null. } return Util.compare(aName, bName); } } \ No newline at end of file +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Port to the D programming language: + * Frank Benoit + *******************************************************************************/ +module dwtx.core.commands.common.NamedHandleObjectComparator; + +import dwtx.core.commands.common.NotDefinedException; +import dwtx.core.commands.common.NamedHandleObject; +import dwtx.core.internal.commands.util.Util; +import dwt.dwthelper.utils; +/** + * Comparator for instances of NamedHandleObject for display to + * an end user. The comparison is based on the name of the instances. + * + * @since 3.2 + */ +public class NamedHandleObjectComparator /+: Comparator+/ { + + /** + * Compares to instances of NamedHandleObject based on their names. This is + * useful is they are display to an end user. + * + * @param left + * The first obect to compare; may be null. + * @param right + * The second object to compare; may be null. + * @return -1 if left is null + * and right is not null; + * 0 if they are both null; + * 1 if left is not null + * and right is null. Otherwise, the + * result of left.compareTo(right). + */ + public final int compare(Object left, Object right) { + NamedHandleObject a = cast(NamedHandleObject) left; + NamedHandleObject b = cast(NamedHandleObject) right; + + String aName = null; + try { + aName = a.getName(); + } catch (NotDefinedException e) { + // Leave aName as null. + } + String bName = null; + try { + bName = b.getName(); + } catch (NotDefinedException e) { + // Leave bName as null. + } + + return Util.compare(aName, bName); + } +} diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/commands/operations/AbstractOperation.d --- a/dwtx/core/commands/operations/AbstractOperation.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/commands/operations/AbstractOperation.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2006 IBM Corporation and others. + * Copyright (c) 2005, 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 @@ -51,9 +51,11 @@ * Construct an operation that has the specified label. * * @param label - * the label to be used for the operation. + * the label to be used for the operation. Should never be + * null. */ public this(String label) { + Assert.isNotNull(label); this.label = label; contexts = new ArraySeq!(IUndoContext); } @@ -143,7 +145,8 @@ * Set the label of the operation to the specified name. * * @param name - * the string to be used for the label. + * the string to be used for the label. Should never be + * null. */ public void setLabel(String name) { label = name; diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/commands/operations/IUndoableOperation.d --- a/dwtx/core/commands/operations/IUndoableOperation.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/commands/operations/IUndoableOperation.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005 IBM Corporation and others. + * Copyright (c) 2005, 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 @@ -158,9 +158,9 @@ /** * Return the label that should be used to show the name of the operation to * the user. This label is typically combined with the command strings shown - * to the user in "Undo" and "Redo" user interfaces. + * to the user in "Undo" and "Redo" user interfaces. * - * @return the label + * @return the String label. Should never be null. */ String getLabel(); diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/internal/runtime/LocalizationUtils.d --- a/dwtx/core/internal/runtime/LocalizationUtils.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/internal/runtime/LocalizationUtils.d Thu May 22 01:36:46 2008 +0200 @@ -25,9 +25,9 @@ * use the NLS-based translation routine. If it falls, the method returns the original * non-translated key. * - * @param key case-sensetive name of the filed in the translation file representing + * @param key case-sensitive name of the filed in the translation file representing * the string to be translated - * @return + * @return The localized message or the non-translated key */ static public String safeLocalize(String key) { //TODO: LocalizationUtils tries to load module CommonMessages. How to handle this? diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/internal/runtime/PrintStackUtil.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/core/internal/runtime/PrintStackUtil.d Thu May 22 01:36:46 2008 +0200 @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 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 + * Port to the D programming language: + * Frank Benoit + *******************************************************************************/ +module dwtx.core.internal.runtime.PrintStackUtil; + +import java.io.PrintStream; +import java.io.PrintWriter; + +import dwtx.core.runtime.IStatus; + +public class PrintStackUtil { + + static public void printChildren(IStatus status, PrintStream output) { + IStatus[] children = status.getChildren(); + if (children is null || children.length is 0) + return; + for (int i = 0; i < children.length; i++) { + output.println("Contains: " + children[i].getMessage()); //$NON-NLS-1$ + Throwable exception = children[i].getException(); + if (exception !is null) + exception.printStackTrace(); + printChildren(children[i], output); + } + } + + static public void printChildren(IStatus status, PrintWriter output) { + IStatus[] children = status.getChildren(); + if (children is null || children.length is 0) + return; + for (int i = 0; i < children.length; i++) { + output.println("Contains: " + children[i].getMessage()); //$NON-NLS-1$ + output.flush(); // call to synchronize output + Throwable exception = children[i].getException(); + if (exception !is null) + exception.printStackTrace(); + printChildren(children[i], output); + } + } + +} diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/internal/runtime/messages.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/core/internal/runtime/messages.properties Thu May 22 01:36:46 2008 +0200 @@ -0,0 +1,79 @@ +############################################################################### +# Copyright (c) 2000, 2006 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 +############################################################################### +### Runtime plugin messages + +### Authorization +auth_notAvailable = Authorization infrastructure (org.eclipse.core.runtime.compatibility.auth) not installed. + +### metadata +meta_appNotInit = The application has not been initialized. +meta_exceptionParsingLog = An exception occurred while parsing the log file: {0} + +### plugins +plugin_deactivatedLoad = Attempt to load class \"{0}\" from de-activated plug-in \"{1}\". +plugin_shutdownProblems = Problems encountered shutting down plug-in: \"{0}\". +plugin_startupProblems = Problems encountered starting up plug-in: \"{0}\". + +### Preferences +preferences_saveProblems = Problems saving preferences. + +### Line Separator Platforms +line_separator_platform_mac_os_9 = Mac OS 9 +line_separator_platform_unix = Unix +line_separator_platform_windows = Windows + +### Product +provider_invalid_general = Errors while processing the product providers. +provider_invalid = Problem creating the provider registered by {0}. +product_notFound = Product {0} could not be found. + +### Compatibility - parsing/resolving +parse_badPrereqOnFrag = Fragment \"{0}\" requires non-existent plug-in \"{1}\". Fragment ignored. +parse_duplicateFragment = Duplicate fragment found with id \"{0}\" and version \"{1}\". +parse_duplicateLib = Fragment \"{0}\" for plug-in \"{1}\", has added duplicate library entry \"{2}\" . +parse_duplicatePlugin = Two plug-ins found with the same id: \"{0}\". Ignoring duplicate at \"{1}\". +parse_error = Parsing error: \"{0}\". +parse_errorNameLineColumn = Parsing error in \"{0}\" [line {1}, column {2}]: \"{3}\". +parse_errorProcessing = Error while processing \"{0}\". +parse_extPointDisabled = Extension point \"{0}\" specified in plug-in \"{1}\" is disabled. +parse_extPointUnknown = Unknown extension point \"{0}\" specified in plug-in \"{1}\". +parse_fragmentMissingAttr = Fragment \"{0}\" ignored due to missing attributes. +parse_fragmentMissingIdName = Fragment ignored due to missing attributes (including name and id). +parse_internalStack = Element/end element mismatch for element \"{0}\". +parse_missingFPName = Plug-in name attribute missing from fragment at \"{0}\". +parse_missingFPVersion = Plug-in version attribute missing from fragment at \"{0}\". +parse_missingFragmentPd = Plug-in descriptor \"{0}\" not found for fragment \"{1}\". Fragment ignored. +parse_missingPluginId = Id attribute missing from plug-in or fragment at \"{0}\". +parse_missingPluginName = Name attribute missing from plug-in or fragment at \"{0}\". +parse_missingPluginVersion = Version attribute missing from plug-in or fragment at \"{0}\". +parse_nullFragmentIdentifier = Fragment not loaded due to missing id or version number: \"{0}\". +parse_nullPluginIdentifier = Plug-in not loaded due to missing id or version number: \"{0}\". +parse_pluginMissingAttr = Plug-in \"{0}\" disabled due to missing attributes. +parse_pluginMissingIdName = Plug-in disabled due to missing attributes (including name and id). +parse_prereqDisabled = Plug-in \"{0}\" was disabled due to missing or disabled prerequisite plug-in \"{1}\". +parse_prereqLoop = Detected prerequisite loop from \"{0}\" to \"{1}\". +parse_prereqOptLoop = Optional prerequisite from \"{0}\" to \"{1}\" produced loop. Prerequisite ignored. +parse_unknownAttribute = Unknown attribute \"{1}\" for element \"{0}\" ignored. +parse_unknownElement = Unknown element \"{1}\", found within a \"{0}\", ignored. +parse_unknownEntry = Unknown element parsed by plug-in registry: \"{0}\". +parse_unknownLibraryType = Unknown library type \"{0}\" for library \"{1}\". +parse_unknownTopElement = Unknown element \"{0}\", found at the top level, ignored. +parse_unsatisfiedOptPrereq = Optional prerequisite constraint from \"{0}\" to\" {1}\" ignored. +parse_unsatisfiedPrereq = Unable to satisfy prerequisite constraint from \"{0}\" to \"{1}\". +parse_validExport = \"{0}\" is not a valid value for the attribute \"export\". Use \"true\" or \"false\". +parse_validMatch = \"{0}\" is not a valid value for the attribute \"match\". Use \"perfect\", \"equivalent\", \"compatible\" or \"greaterOrEqual\". + +### Compatibility - plugins +plugin_notPluginClass = Supplied runtime class \"{0}\" does not extend class Plugin. +plugin_unableToResolve = Unable to resolve plug-in registry. +plugin_pluginDisabled = Attempt to activate a disabled plug-in: \"{0}\". +plugin_instantiateClassError = Plug-in \"{0}\" was unable to instantiate class \"{1}\". +plugin_loadClassError = Plug-in {0} was unable to load class {1}. diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/runtime/Assert.d --- a/dwtx/core/runtime/Assert.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/runtime/Assert.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -32,6 +32,8 @@ * This class is not intended to be instantiated or sub-classed by clients. *

* @since dwtx.equinox.common 3.2 + * @noextend This class is not intended to be subclassed by clients. + * @noinstantiate This class is not intended to be instantiated by clients. */ public final class Assert { /* This class is not intended to be instantiated. */ diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/runtime/AssertionFailedException.d --- a/dwtx/core/runtime/AssertionFailedException.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/runtime/AssertionFailedException.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -24,6 +24,8 @@ *

* @see Assert * @since dwtx.equinox.common 3.2 + * @noextend This class is not intended to be subclassed by clients. + * @noinstantiate This class is not intended to be instantiated by clients. */ public class AssertionFailedException : RuntimeException { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/runtime/IAdapterManager.d --- a/dwtx/core/runtime/IAdapterManager.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/runtime/IAdapterManager.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -65,6 +65,8 @@ *

* @see IAdaptable * @see IAdapterFactory + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. */ public interface IAdapterManager { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/runtime/ILogListener.d --- a/dwtx/core/runtime/ILogListener.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/runtime/ILogListener.d Thu May 22 01:36:46 2008 +0200 @@ -15,7 +15,6 @@ import dwtx.core.runtime.IStatus; import dwt.dwthelper.utils; - /** * A log listener is notified of entries added to a plug-in's log. *

@@ -23,8 +22,6 @@ *

* Clients may implement this interface. *

- * @see ILog#addLogListener(ILogListener) - * @see Platform#addLogListener(ILogListener) */ public interface ILogListener : EventListener { /** diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/runtime/IPath.d --- a/dwtx/core/runtime/IPath.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/runtime/IPath.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -40,6 +40,8 @@ * This interface is not intended to be implemented by clients. *

* @see Path + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. */ public interface IPath : Cloneable { @@ -248,7 +250,7 @@ * When the platform location is a file system with no meaningful device * separator, the entire string is treated as the path proper. * The device id is not checked for validity; the path proper is correct - * if each of the segments in its canonicalized form is valid. + * if each of the segments in its canonicalized form is valid. * * @param path the path to check * @return true if the given string is a valid path, diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/runtime/IProgressMonitorWithBlocking.d --- a/dwtx/core/runtime/IProgressMonitorWithBlocking.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/runtime/IProgressMonitorWithBlocking.d Thu May 22 01:36:46 2008 +0200 @@ -53,7 +53,6 @@ * reason why this operation is blocked, or null if this * information is not available. * @see #clearBlocked() - * @see dwtx.core.runtime.jobs.IJobStatus */ public void setBlocked(IStatus reason); diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/runtime/ISafeRunnable.d --- a/dwtx/core/runtime/ISafeRunnable.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/runtime/ISafeRunnable.d Thu May 22 01:36:46 2008 +0200 @@ -14,7 +14,6 @@ // import dwt.internal.Platform; import dwt.dwthelper.utils; - /** * Safe runnables represent blocks of code and associated exception * handlers. They are typically used when a plug-in needs to call some @@ -25,7 +24,7 @@ *

* Clients may implement this interface. *

- * @see Platform#run(ISafeRunnable) + * @see SafeRunner#run(ISafeRunnable) */ public interface ISafeRunnable { /** @@ -37,7 +36,7 @@ * * @param exception an exception which occurred during processing * the body of this runnable (i.e., in run()) - * @see Platform#run(ISafeRunnable) + * @see SafeRunner#run(ISafeRunnable) */ public void handleException(Exception exception); @@ -48,7 +47,7 @@ * * @exception Exception if a problem occurred while running this method. * The exception will be processed by handleException - * @see Platform#run(ISafeRunnable) + * @see SafeRunner#run(ISafeRunnable) */ public void run(); } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/runtime/OperationCanceledException.d --- a/dwtx/core/runtime/OperationCanceledException.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/runtime/OperationCanceledException.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -23,6 +23,7 @@ * This class is not intended to be subclassed by clients but * may be instantiated. *

+ * @noextend This class is not intended to be subclassed by clients. */ public final class OperationCanceledException : RuntimeException { /** diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/runtime/Path.d --- a/dwtx/core/runtime/Path.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/runtime/Path.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -38,6 +38,7 @@ * may be instantiated. *

* @see IPath + * @noextend This class is not intended to be subclassed by clients. */ public class Path : IPath, Cloneable { /** masks for separator values */ @@ -59,7 +60,6 @@ /** Mask for all bits that are involved in the hash code */ private static const int HASH_MASK = ~HAS_TRAILING; - /** Constant root path string ("/"). */ private static const String ROOT_STRING = "/"; //$NON-NLS-1$ @@ -120,7 +120,7 @@ * @since 3.1 */ public static IPath fromPortableString(String pathString) { - int firstMatch = pathString.indexOf(DEVICE_SEPARATOR) +1; + int firstMatch = pathString.indexOf(DEVICE_SEPARATOR) + 1; //no extra work required if no device characters if (firstMatch <= 0) return (new Path()).initialize(null, pathString); @@ -507,6 +507,7 @@ } return newSegments; } + /** * Returns the platform-neutral encoding of the given segment onto * the given string buffer. This escapes literal colon characters with double colons. @@ -947,7 +948,7 @@ encodeSegment(segments_[i], result); else result.append(segments_[i]); - if (i < len-1 || (separators & HAS_TRAILING) !is 0) + if (i < len - 1 || (separators & HAS_TRAILING) !is 0) result.append(SEPARATOR); } return result.toString(); diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/runtime/QualifiedName.d --- a/dwtx/core/runtime/QualifiedName.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/runtime/QualifiedName.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -27,6 +27,7 @@ *

* This class is not intended to be subclassed by clients. *

+ * @noextend This class is not intended to be subclassed by clients. */ public final class QualifiedName { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/core/runtime/SubMonitor.d --- a/dwtx/core/runtime/SubMonitor.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/core/runtime/SubMonitor.d Thu May 22 01:36:46 2008 +0200 @@ -9,6 +9,7 @@ * Stefan Xenos - initial API and implementation * Stefan Xenos - bug 174539 - add a 1-argument convert(...) method * Stefan Xenos - bug 174040 - SubMonitor#convert doesn't always set task name + * Stefan Xenos - bug 206942 - updated javadoc to recommend better constants for infinite progress * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -204,14 +205,14 @@ * *
  *      void doSomething(IProgressMonitor monitor, LinkedListNode node) {
- *          SubMonitor progress = SubMonitor.convert(monitor, 100);
+ *          SubMonitor progress = SubMonitor.convert(monitor);
  *
  *          while (node !is null) {
  *              // Regardless of the amount of progress reported so far,
- *              // use 5% of the space remaining in the monitor to process the next node.
- *              progress.setWorkRemaining(100);
+ *              // use 0.01% of the space remaining in the monitor to process the next node.
+ *              progress.setWorkRemaining(10000);
  *
- *              doWorkOnElement(node, progress.newChild(5));
+ *              doWorkOnElement(node, progress.newChild(1));
  *
  *              node = node.next;
  *          }
@@ -570,6 +571,8 @@
      * @see dwtx.core.runtime.IProgressMonitor#internalWorked(double)
      */
     public void internalWorked(double work) {
+        cleanupActiveChild();
+
         int delta = consume((work > 0.0) ? work : 0.0);
         if (delta !is 0)
             root.worked(delta);
diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/action/Action.d
--- a/dwtx/jface/action/Action.d	Mon May 19 13:41:06 2008 +0200
+++ b/dwtx/jface/action/Action.d	Thu May 22 01:36:46 2008 +0200
@@ -272,7 +272,7 @@
 
     /**
      * Holds the action's menu creator (an IMenuCreator) or checked state (a
-     * bool for toggle button, or an Integer for radio button), or
+     * Boolean for toggle button, or an Integer for radio button), or
      * null if neither have been set.
      * 

* The value of this field affects the value of getStyle(). @@ -495,9 +495,9 @@ * @since 3.0 */ public final void notifyResult(bool success) { - // avoid bool.valueOf(bool) to allow compilation against JCL + // avoid Boolean.valueOf(bool) to allow compilation against JCL // Foundation (bug 80059) - firePropertyChange(RESULT, null, new ValueWrapperBool(success)); + firePropertyChange(RESULT, null, success ? Boolean.TRUE : Boolean.FALSE); } /** @@ -559,9 +559,9 @@ if (newValue !is value) { value = newValue; if (checked) { - firePropertyChange(CHECKED, new ValueWrapperBool(false), new ValueWrapperBool(true)); + firePropertyChange(CHECKED, Boolean.FALSE, Boolean.TRUE); } else { - firePropertyChange(CHECKED, new ValueWrapperBool(true), new ValueWrapperBool(false)); + firePropertyChange(CHECKED, Boolean.TRUE, Boolean.FALSE); } } } @@ -597,8 +597,10 @@ */ public void setEnabled(bool enabled) { if (enabled !is this.enabled) { + Boolean oldVal = this.enabled ? Boolean.TRUE : Boolean.FALSE; + Boolean newVal = enabled ? Boolean.TRUE : Boolean.FALSE; this.enabled = enabled; - firePropertyChange(ENABLED, new ValueWrapperBool(this.enabled), new ValueWrapperBool(enabled)); + firePropertyChange(ENABLED, oldVal, newVal); } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/action/ActionContributionItem.d --- a/dwtx/jface/action/ActionContributionItem.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/action/ActionContributionItem.d Thu May 22 01:36:46 2008 +0200 @@ -22,7 +22,6 @@ import dwt.DWT; import dwt.graphics.GC; import dwt.graphics.Point; -import dwt.graphics.Rectangle; import dwt.widgets.Button; import dwt.widgets.Composite; import dwt.widgets.Display; @@ -35,6 +34,8 @@ import dwt.widgets.ToolItem; import dwt.widgets.Widget; import dwtx.jface.action.ExternalActionManager; +import dwtx.core.commands.ExecutionException; +import dwtx.core.commands.NotEnabledException; import dwtx.jface.bindings.Trigger; import dwtx.jface.bindings.TriggerSequence; import dwtx.jface.bindings.keys.IKeyLookup; @@ -61,11 +62,11 @@ */ public class ActionContributionItem : ContributionItem { alias ContributionItem.fill fill; - + /** - * Mode bit: Show text on tool items, even if an image is present. If this - * mode bit is not set, text is only shown on tool items if there is no - * image present. + * Mode bit: Show text on tool items or buttons, even if an image is + * present. If this mode bit is not set, text is only shown on tool items if + * there is no image present. * * @since 3.0 */ @@ -74,6 +75,11 @@ /** a string inserted in the middle of text that has been shortened */ private static const String ellipsis = "..."; //$NON-NLS-1$ + /** + * Stores the result of the action. False when the action returned failure. + */ + private Boolean result = null; + private static bool USE_COLOR_ICONS = true; /** @@ -144,6 +150,8 @@ */ private Widget widget = null; + private Listener menuCreatorListener; + /** * Creates a new contribution item from the given action. The id of the * action is used as the id of the item. @@ -262,7 +270,6 @@ */ public override void fill(Menu parent, int index) { if (widget is null && parent !is null) { - Menu subMenu = null; int flags = DWT.PUSH; if (action !is null) { int style = action.getStyle(); @@ -271,11 +278,7 @@ } else if (style is IAction.AS_RADIO_BUTTON) { flags = DWT.RADIO; } else if (style is IAction.AS_DROP_DOWN_MENU) { - IMenuCreator mc = action.getMenuCreator(); - if (mc !is null) { - subMenu = mc.getMenu(parent); - flags = DWT.CASCADE; - } + flags = DWT.CASCADE; } } @@ -294,7 +297,12 @@ mi.addHelpListener(action.getHelpListener()); } - if (subMenu !is null) { + if (flags is DWT.CASCADE) { + // just create a proxy for now, if the user shows it then + // fill it in + Menu subMenu = new Menu(parent); + subMenu.addListener(DWT.Show, getMenuCreatorListener()); + subMenu.addListener(DWT.Hide, getMenuCreatorListener()); mi.setMenu(subMenu); } @@ -477,7 +485,8 @@ // Check if our widget is the one being disposed. if (e.widget is widget) { // Dispose of the menu creator. - if (action.getStyle() is IAction.AS_DROP_DOWN_MENU) { + if (action.getStyle() is IAction.AS_DROP_DOWN_MENU + && menuCreatorCalled) { IMenuCreator mc = action.getMenuCreator(); if (mc !is null) { mc.dispose(); @@ -525,6 +534,7 @@ if (e.detail is 4) { // on drop-down button if (action.getStyle() is IAction.AS_DROP_DOWN_MENU) { IMenuCreator mc = action.getMenuCreator(); + menuCreatorCalled = true; ToolItem ti = cast(ToolItem) item; // we create the menu as a sub-menu of "dummy" so that // we can use @@ -538,11 +548,11 @@ Menu m = mc.getMenu(ti.getParent()); if (m !is null) { // position the menu below the drop down item - Rectangle b = ti.getBounds(); - Point p = ti.getParent().toDisplay( - new Point(b.x, b.y + b.height)); - m.setLocation(p.x, p.y); // waiting for DWT - // 0.42 + Point point = ti.getParent().toDisplay( + new Point(e.x, e.y)); + m.setLocation(point.x, point.y); // waiting + // for DWT + // 0.42 m.setVisible(true); return; // we don't fire the action } @@ -551,6 +561,16 @@ } } + ExternalActionManager.IExecuteCallback callback = null; + String actionDefinitionId = action.getActionDefinitionId(); + if (actionDefinitionId !is null) { + Object obj = ExternalActionManager.getInstance() + .getCallback(); + if (obj instanceof ExternalActionManager.IExecuteCallback) { + callback = (ExternalActionManager.IExecuteCallback) obj; + } + } + // Ensure action is enabled first. // See 1GAN3M6: ITPUI:WINNT - Any IAction in the workbench can be // executed while disabled. @@ -561,13 +581,49 @@ if (trace) { ms = System.currentTimeMillis(); Stdout.formatln("Running action: {}", action.getText()); //$NON-NLS-1$ + } + + IPropertyChangeListener resultListener = null; + if (callback !is null) { + resultListener = new IPropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) { + // Check on result + if (event.getProperty().equals(IAction.RESULT)) { + if (event.getNewValue() instanceof Boolean) { + result = (Boolean) event.getNewValue(); + } + } + } + }; + action.addPropertyChangeListener(resultListener); + callback.preExecute(action, e); } action.runWithEvent(e); + if (callback !is null) { + if (result is null || result.equals(Boolean.TRUE)) { + callback.postExecuteSuccess(action, Boolean.TRUE); + } else { + callback.postExecuteFailure(action, + new ExecutionException(action.getText() + + " returned failure.")); //$NON-NLS-1$ + } + } + + if (resultListener!isnull) { + result = null; + action.removePropertyChangeListener(resultListener); + } if (trace) { Stdout.formatln("{} ms to run action: {}",(System.currentTimeMillis() - ms), action.getText()); //$NON-NLS-1$ } + } else { + if (callback !is null) { + callback.notEnabled(action, new NotEnabledException(action + .getText() + + " is not enabled.")); //$NON-NLS-1$ + } } } } @@ -753,9 +809,12 @@ ExternalActionManager.ICallback callback = ExternalActionManager .getInstance().getCallback(); String commandId = action.getActionDefinitionId(); - if ((callback !is null) && (commandId !is null) && (toolTip !is null)) { - String acceleratorText = callback.getAcceleratorText(commandId); - if (acceleratorText !is null && acceleratorText.length !is 0) { + if ((callback !is null) && (commandId !is null) + && (toolTip !is null)) { + String acceleratorText = callback + .getAcceleratorText(commandId); + if (acceleratorText !is null + && acceleratorText.length !is 0) { toolTip = JFaceResources.format( "Toolbar_Tooltip_Accelerator", //$NON-NLS-1$ [ toolTip, acceleratorText ]); @@ -872,10 +931,14 @@ } if (text !is null && acceleratorText is null) { - // use extracted accelerator text in case accelerator cannot be fully represented in one int (e.g. multi-stroke keys) - acceleratorText = LegacyActionTools.extractAcceleratorText(text); + // use extracted accelerator text in case accelerator + // cannot be fully represented in one int (e.g. + // multi-stroke keys) + acceleratorText = LegacyActionTools + .extractAcceleratorText(text); if (acceleratorText is null && accelerator !is 0) { - acceleratorText= Action.convertAccelerator(accelerator); + acceleratorText = Action + .convertAccelerator(accelerator); } } @@ -919,19 +982,19 @@ if (cast(Button)widget ) { Button button = cast(Button) widget; - if (imageChanged && updateImages(false)) { - textChanged = false; // don't update text if it has an - // image + if (imageChanged) { + updateImages(false); } if (textChanged) { String text = action.getText(); - if (text is null) { - text = ""; //$NON-NLS-1$ - } else { + bool showText = text !is null && ((getMode() & MODE_FORCE_TEXT) !is 0 || !hasImages(action)); + // only do the trimming if the text will be used + if (showText) { text = Action.removeAcceleratorText(text); } - button.setText(text); + String textToSet = showText ? text : ""; //$NON-NLS-1$ + button.setText(textToSet); } if (tooltipTextChanged) { @@ -1134,4 +1197,187 @@ // If for some reason we fall through abort return textValue; } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.action.ContributionItem#dispose() + */ + public void dispose() { + if (widget !is null) { + widget.dispose(); + widget = null; + } + holdMenu = null; + } + + /** + * Handle show and hide on the proxy menu for IAction.AS_DROP_DOWN_MENU + * actions. + * + * @return the appropriate listener + * @since 3.4 + */ + private Listener getMenuCreatorListener() { + if (menuCreatorListener is null) { + menuCreatorListener = new Listener() { + public void handleEvent(Event event) { + switch (event.type) { + case DWT.Show: + handleShowProxy((Menu) event.widget); + break; + case DWT.Hide: + handleHideProxy((Menu) event.widget); + break; + } + } + }; + } + return menuCreatorListener; + } + + /** + * This is the easiest way to hold the menu until we can swap it in to the + * proxy. + */ + private Menu holdMenu = null; + + private bool menuCreatorCalled = false; + + /** + * The proxy menu is being shown, we better get the real menu. + * + * @param proxy + * the proxy menu + * @since 3.4 + */ + private void handleShowProxy(Menu proxy) { + proxy.removeListener(DWT.Show, getMenuCreatorListener()); + IMenuCreator mc = action.getMenuCreator(); + menuCreatorCalled = true; + if (mc is null) { + return; + } + holdMenu = mc.getMenu(proxy.getParentMenu()); + if (holdMenu is null) { + return; + } + copyMenu(holdMenu, proxy); + } + + /** + * Create MenuItems in the proxy menu that can execute the real menu items + * if selected. Create proxy menus for any real item submenus. + * + * @param realMenu + * the real menu to copy from + * @param proxy + * the proxy menu to populate + * @since 3.4 + */ + private void copyMenu(Menu realMenu, Menu proxy) { + if (realMenu.isDisposed() || proxy.isDisposed()) { + return; + } + + // we notify the real menu so it can populate itself if it was + // listening for DWT.Show + realMenu.notifyListeners(DWT.Show, null); + + final Listener passThrough = new Listener() { + public void handleEvent(Event event) { + if (!event.widget.isDisposed()) { + Widget realItem = (Widget) event.widget.getData(); + if (!realItem.isDisposed()) { + int style = event.widget.getStyle(); + if (event.type is DWT.Selection + && ((style & (DWT.TOGGLE | DWT.CHECK)) !is 0) + && realItem instanceof MenuItem) { + ((MenuItem) realItem) + .setSelection(((MenuItem) event.widget) + .getSelection()); + } + event.widget = realItem; + realItem.notifyListeners(event.type, event); + } + } + } + }; + + MenuItem[] items = realMenu.getItems(); + for (int i = 0; i < items.length; i++) { + final MenuItem realItem = items[i]; + final MenuItem proxyItem = new MenuItem(proxy, realItem.getStyle()); + proxyItem.setData(realItem); + proxyItem.setAccelerator(realItem.getAccelerator()); + proxyItem.setEnabled(realItem.getEnabled()); + proxyItem.setImage(realItem.getImage()); + proxyItem.setSelection(realItem.getSelection()); + proxyItem.setText(realItem.getText()); + + // pass through any events + proxyItem.addListener(DWT.Selection, passThrough); + proxyItem.addListener(DWT.Arm, passThrough); + proxyItem.addListener(DWT.Help, passThrough); + + final Menu itemMenu = realItem.getMenu(); + if (itemMenu !is null) { + // create a proxy for any sub menu items + final Menu subMenu = new Menu(proxy); + subMenu.setData(itemMenu); + proxyItem.setMenu(subMenu); + subMenu.addListener(DWT.Show, new Listener() { + public void handleEvent(Event event) { + event.widget.removeListener(DWT.Show, this); + if (event.type is DWT.Show) { + copyMenu(itemMenu, subMenu); + } + } + }); + subMenu.addListener(DWT.Help, passThrough); + subMenu.addListener(DWT.Hide, passThrough); + } + } + } + + /** + * The proxy menu is being hidden, so we need to make it go away. + * + * @param proxy + * the proxy menu + * @since 3.4 + */ + private void handleHideProxy(final Menu proxy) { + proxy.removeListener(DWT.Hide, getMenuCreatorListener()); + proxy.getDisplay().asyncExec(new Runnable() { + public void run() { + if (!proxy.isDisposed()) { + MenuItem parentItem = proxy.getParentItem(); + proxy.dispose(); + parentItem.setMenu(holdMenu); + } + if (holdMenu !is null && !holdMenu.isDisposed()) { + holdMenu.notifyListeners(DWT.Hide, null); + } + holdMenu = null; + } + }); + } + + /** + * Return the widget associated with this contribution item. It should not + * be cached, as it can be disposed and re-created by its containing + * ContributionManager, which controls all of the widgets lifecycle methods. + *

+ * This can be used to set layout data on the widget if appropriate. The + * actual type of the widget can be any valid control for this + * ContributionItem's current ContributionManager. + *

+ * + * @return the widget, or null depending on the lifecycle. + * @since 3.4 + */ + public Widget getWidget() { + return widget; + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/action/ContributionItem.d --- a/dwtx/jface/action/ContributionItem.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/action/ContributionItem.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2005 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -215,4 +215,16 @@ */ public void update(String id) { } + + /** + * The ID for this contribution item. It should be set once either in the + * constructor or using this method. + * + * @param itemId + * @since 3.4 + * @see #getId() + */ + public void setId(String itemId) { + id = itemId; + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/action/ContributionManager.d --- a/dwtx/jface/action/ContributionManager.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/action/ContributionManager.d Thu May 22 01:36:46 2008 +0200 @@ -22,6 +22,7 @@ import tango.util.collection.ArraySeq; import tango.util.collection.model.Seq; +import dwtx.core.runtime.Assert; import dwtx.jface.util.Policy; import dwt.dwthelper.utils; @@ -85,6 +86,7 @@ * (non-Javadoc) Method declared on IContributionManager. */ public void add(IAction action) { + Assert.isNotNull(action, "Action must not be null"); //$NON-NLS-1$ add(new ActionContributionItem(action)); } @@ -92,6 +94,7 @@ * (non-Javadoc) Method declared on IContributionManager. */ public void add(IContributionItem item) { + Assert.isNotNull(item, "Item must not be null"); //$NON-NLS-1$ if (allowItem(item)) { contributions.append(item); itemAdded(item); @@ -240,7 +243,7 @@ public IContributionManagerOverrides getOverrides() { if (overrides is null) { overrides = new class IContributionManagerOverrides { - public ValueWrapperBool getEnabled(IContributionItem item) { + public Boolean getEnabled(IContributionItem item) { return null; } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/action/CoolBarManager.d --- a/dwtx/jface/action/CoolBarManager.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/action/CoolBarManager.d Thu May 22 01:36:46 2008 +0200 @@ -308,17 +308,17 @@ */ public void dispose() { if (coolBarExist()) { - IContributionItem[] items = getItems(); - for (int i = 0; i < items.length; i++) { - // Disposes of the contribution item. - // If Contribution Item is a toolbar then it will dispose of - // all the nested - // contribution items. - items[i].dispose(); - } coolBar.dispose(); coolBar = null; } + IContributionItem[] items = getItems(); + for (int i = 0; i < items.length; i++) { + // Disposes of the contribution item. + // If Contribution Item is a toolbar then it will dispose of + // all the nested + // contribution items. + items[i].dispose(); + } // If a context menu existed then dispose of it. if (contextMenuManager !is null) { contextMenuManager.dispose(); diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/action/ExternalActionManager.d --- a/dwtx/jface/action/ExternalActionManager.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/action/ExternalActionManager.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -20,12 +20,18 @@ import tango.util.collection.model.Map; import tango.util.collection.model.Set; +import dwt.widgets.Event; import dwtx.core.commands.Command; import dwtx.core.commands.CommandEvent; import dwtx.core.commands.CommandManager; +import dwtx.core.commands.ExecutionEvent; +import dwtx.core.commands.ExecutionException; import dwtx.core.commands.ICommandListener; +import dwtx.core.commands.NotEnabledException; import dwtx.core.commands.ParameterizedCommand; +import dwtx.core.commands.common.NotDefinedException; import dwtx.core.runtime.IStatus; +import dwtx.core.runtime.ListenerList; import dwtx.core.runtime.Status; import dwtx.jface.bindings.BindingManager; import dwtx.jface.bindings.BindingManagerEvent; @@ -71,11 +77,14 @@ * A simple implementation of the ICallback mechanism that * simply takes a BindingManager and a * CommandManager. + *

+ * Note: this class is not intended to be subclassed by clients. + *

* * @since 3.1 */ - public static final class CommandCallback : - IBindingManagerListener, IBindingManagerCallback { + public static class CommandCallback : + IBindingManagerListener, IBindingManagerCallback, IExecuteCallback { /** * The internationalization bundle for text produced by this class. @@ -86,6 +95,11 @@ * The callback capable of responding to whether a command is active. */ private const IActiveChecker activeChecker; + + /** + * Check the applicability of firing an execution event for an action. + */ + private final IExecuteApplicable applicabilityChecker; /** * The binding manager for your application. Must not be @@ -116,7 +130,8 @@ /** * The list of listeners that have registered for property change * notification. This is a map of command identifiers (String) - * to listeners (IPropertyChangeListener). + * to listeners (IPropertyChangeListener or + * ListenerList of IPropertyChangeListener). */ private const Map!(String,IPropertyChangeListener) registeredListeners; @@ -144,9 +159,12 @@ return true; } + }, new IExecuteApplicable() { + public bool isApplicable(IAction action) { + return true; + } }); } - /** * Constructs a new instance of CommandCallback with the * workbench it should be using. @@ -166,6 +184,36 @@ public this(BindingManager bindingManager, CommandManager commandManager, IActiveChecker activeChecker) { + this(bindingManager, commandManager, activeChecker, + new IExecuteApplicable() { + public bool isApplicable(IAction action) { + return true; + } + }); + } + /** + * Constructs a new instance of CommandCallback with the + * workbench it should be using. + * + * @param bindingManager + * The binding manager which will provide the callback; must + * not be null. + * @param commandManager + * The command manager which will provide the callback; must + * not be null. + * @param activeChecker + * The callback mechanism for checking whether a command is + * active; must not be null. + * @param checker + * The callback to check if an IAction should fire execution + * events. + * + * @since 3.4 + */ + public CommandCallback(final BindingManager bindingManager, + final CommandManager commandManager, + final IActiveChecker activeChecker, + final IExecuteApplicable checker) { loggedCommandIds = new HashSet!(String); registeredListeners = new HashMap!(String,IPropertyChangeListener); if (bindingManager is null) { @@ -182,10 +230,15 @@ throw new NullPointerException( "The callback needs an active callback"); //$NON-NLS-1$ } + if (checker is null) { + throw new NullPointerException( + "The callback needs an applicable callback"); //$NON-NLS-1$ + } this.activeChecker = activeChecker; this.bindingManager = bindingManager; this.commandManager = commandManager; + this.applicabilityChecker = checker; } /** @@ -194,7 +247,16 @@ */ public final void addPropertyChangeListener(String commandId, IPropertyChangeListener listener) { - registeredListeners.add(commandId, listener); + Object existing = registeredListeners.get(commandId); + if (existing instanceof ListenerList) { + ((ListenerList) existing).add(listener); + } else if (existing !is null) { + ListenerList listeners = new ListenerList(ListenerList.IDENTITY); + listeners.add(existing); + listeners.add(listener); + } else { + registeredListeners.put(commandId, listener); + } if (!bindingManagerListenerAttached) { bindingManager.addBindingManagerListener(this); bindingManagerListenerAttached = true; @@ -213,9 +275,19 @@ ParameterizedCommand parameterizedCommand = new ParameterizedCommand( command, null); if (event.isActiveBindingsChangedFor(parameterizedCommand)) { - IPropertyChangeListener listener = cast(IPropertyChangeListener) v; - listener.propertyChange(new PropertyChangeEvent(event - .getManager(), IAction.TEXT, null, null)); + Object value = entry.getValue(); + PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(event + .getManager(), IAction.TEXT, null, null); + if (value instanceof ListenerList) { + Object[] listeners= ((ListenerList) value).getListeners(); + for (int i = 0; i < listeners.length; i++) { + final IPropertyChangeListener listener = (IPropertyChangeListener) listeners[i]; + listener.propertyChange(propertyChangeEvent); + } + } else { + final IPropertyChangeListener listener = (IPropertyChangeListener) value; + listener.propertyChange(propertyChangeEvent); + } } } } @@ -343,16 +415,71 @@ */ public final void removePropertyChangeListener(String commandId, IPropertyChangeListener listener) { - IPropertyChangeListener existingListener = cast(IPropertyChangeListener) registeredListeners - .get(commandId); - if (existingListener is listener) { + Object existing= registeredListeners.get(commandId); + if (existing is listener) { registeredListeners.removeKey(commandId); if (registeredListeners.drained()) { bindingManager.removeBindingManagerListener(this); bindingManagerListenerAttached = false; } + } else if (existing instanceof ListenerList) { + ListenerList existingList = (ListenerList) existing; + existingList.remove(listener); + if (existingList.size() is 1) { + registeredListeners.put(commandId, existingList.getListeners()[0]); + } } } + + public void preExecute(IAction action, Event event) { + String actionDefinitionId = action.getActionDefinitionId(); + if (actionDefinitionIdisnull + || !applicabilityChecker.isApplicable(action)) { + return; + } + Command command = commandManager.getCommand(actionDefinitionId); + ExecutionEvent executionEvent = new ExecutionEvent(command, + Collections.EMPTY_MAP, event, null); + + commandManager.firePreExecute(actionDefinitionId, executionEvent); + } + + public void postExecuteSuccess(IAction action, Object returnValue) { + String actionDefinitionId = action.getActionDefinitionId(); + if (actionDefinitionIdisnull + || !applicabilityChecker.isApplicable(action)) { + return; + } + commandManager.firePostExecuteSuccess(actionDefinitionId, returnValue); + } + + public void postExecuteFailure(IAction action, + ExecutionException exception) { + String actionDefinitionId = action.getActionDefinitionId(); + if (actionDefinitionIdisnull + || !applicabilityChecker.isApplicable(action)) { + return; + } + commandManager.firePostExecuteFailure(actionDefinitionId, exception); + } + + public void notDefined(IAction action, NotDefinedException exception) { + String actionDefinitionId = action.getActionDefinitionId(); + if (actionDefinitionIdisnull + || !applicabilityChecker.isApplicable(action)) { + return; + } + commandManager.fireNotDefined(actionDefinitionId, exception); + } + + public void notEnabled(IAction action, NotEnabledException exception) { + String actionDefinitionId = action.getActionDefinitionId(); + if (actionDefinitionIdisnull + || !applicabilityChecker.isApplicable(action)) { + return; + } + commandManager.fireNotEnabled(actionDefinitionId, exception); + } } /** @@ -406,6 +533,102 @@ */ public TriggerSequence[] getActiveBindingsFor(String commandId); } + + /** + * An overridable mechanism to filter certain IActions from the execution + * bridge. + * + * @since 3.4 + */ + public static interface IExecuteApplicable { + /** + * Allow the callback to filter out actions that should not fire + * execution events. + * + * @param action + * The action with an actionDefinitionId + * @return true if this action should be considered. + */ + public bool isApplicable(IAction action); + } + + /** + *

+ * A callback for executing execution events. Allows + * ActionContributionItems to fire useful events. + *

+ *

+ * Clients must not implement this interface and must not extend. + *

+ * + * @since 3.4 + * + */ + public static interface IExecuteCallback { + + /** + * Fires a NotEnabledException because the action was not + * enabled. + * + * @param action + * The action contribution that caused the exception, + * never null. + * @param exception + * The NotEnabledException, never null. + */ + public void notEnabled(IAction action, NotEnabledException exception); + + /** + * Fires a NotDefinedException because the action was not + * defined. + * + * @param action + * The action contribution that caused the exception, + * never null. + * @param exception + * The NotDefinedException, never null. + */ + public void notDefined(IAction action, NotDefinedException exception); + + /** + * Fires an execution event before an action is run. + * + * @param action + * The action contribution that requires an + * execution event to be fired. Cannot be null. + * @param e + * The DWT Event, may be null. + * + */ + public void preExecute(IAction action, + Event e); + + /** + * Fires an execution event when the action returned a success. + * + * @param action + * The action contribution that requires an + * execution event to be fired. Cannot be null. + * @param returnValue + * The command's result, may be null. + * + */ + public void postExecuteSuccess(IAction action, + Object returnValue); + + /** + * Creates an ExecutionException when the action returned + * a failure. + * + * @param action + * The action contribution that caused the exception, + * never null. + * @param exception + * The ExecutionException, never null. + */ + public void postExecuteFailure(IAction action, + ExecutionException exception); + } /** * A callback mechanism for some external tool to communicate extra @@ -423,9 +646,8 @@ * case of the Eclipse workbench, this is the command identifier. *

*

- * A single instance of the listener may only ever be associated with - * one identifier. Attempts to add the listener twice (without a removal - * in between) has undefined behaviour. + * Has no effect if an identical listener has already been added for + * the identifier. *

* * @param identifier @@ -505,6 +727,7 @@ */ public void removePropertyChangeListener(String identifier, IPropertyChangeListener listener); + } /** diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/action/ExternalActionManager.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/action/ExternalActionManager.properties Thu May 22 01:36:46 2008 +0200 @@ -0,0 +1,12 @@ +############################################################################### +# Copyright (c) 2005 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 +############################################################################### + +undefinedCommand.WarningMessage = The command ("{0}") is undefined diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/action/IAction.d --- a/dwtx/jface/action/IAction.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/action/IAction.d Thu May 22 01:36:46 2008 +0200 @@ -122,8 +122,8 @@ /** * Property name of an action's success/fail result * (value "result"). The values are - * bool.TRUE if running the action succeeded and - * bool.FALSE if running the action failed or did not + * Boolean.TRUE if running the action succeeded and + * Boolean.FALSE if running the action failed or did not * complete. *

* Not all actions report whether they succeed or fail. This property diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/action/IContributionManager.d --- a/dwtx/jface/action/IContributionManager.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/action/IContributionManager.d Thu May 22 01:36:46 2008 +0200 @@ -47,14 +47,14 @@ * Adds an action as a contribution item to this manager. * Equivalent to add(new ActionContributionItem(action)). * - * @param action the action + * @param action the action, this cannot be null */ public void add(IAction action); /** * Adds a contribution item to this manager. * - * @param item the contribution item + * @param item the contribution item, this cannot be null */ public void add(IContributionItem item); diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/action/IContributionManagerOverrides.d --- a/dwtx/jface/action/IContributionManagerOverrides.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/action/IContributionManagerOverrides.d Thu May 22 01:36:46 2008 +0200 @@ -40,13 +40,13 @@ * @param item the contribution item for which the enable override value is * determined * @return

    - *
  • bool.TRUE if the given contribution item should be enabled
  • - *
  • bool.FALSE if the item should be disabled
  • + *
  • Boolean.TRUE if the given contribution item should be enabled
  • + *
  • Boolean.FALSE if the item should be disabled
  • *
  • null if the item may determine its own enablement
  • *
* @since 2.0 */ - public ValueWrapperBool getEnabled(IContributionItem item); + public Boolean getEnabled(IContributionItem item); /** * This is not intended to be called outside of the workbench. This method diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/action/MenuManager.d --- a/dwtx/jface/action/MenuManager.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/action/MenuManager.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Remy Chi Jian Suen - Bug 12116 [Contributions] widgets: MenuManager.setImageDescriptor() method needed * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -33,14 +34,19 @@ import dwt.widgets.Control; import dwt.widgets.CoolBar; import dwt.widgets.Decorations; +import dwt.widgets.Item; import dwt.widgets.Menu; import dwt.widgets.MenuItem; import dwt.widgets.Shell; import dwt.widgets.ToolBar; import dwtx.core.runtime.ListenerList; +import dwtx.jface.resource.ImageDescriptor; +import dwtx.jface.resource.JFaceResources; +import dwtx.jface.resource.LocalResourceManager; import dwt.dwthelper.utils; + /** * A menu manager is a contribution manager which realizes itself and its items * in a menu control; either as a menu bar, a sub-menu, or a context menu. @@ -81,6 +87,16 @@ * The text for a sub-menu. */ private String menuText; + + /** + * The image for a sub-menu. + */ + private ImageDescriptor image; + + /** + * A resource manager to remember all of the images that have been used by this menu. + */ + private LocalResourceManager imageManager; /** * The overrides for items of this manager @@ -106,11 +122,17 @@ protected bool visible = true; /** + * allows a submenu to display a shortcut key. This is often used with the + * QuickMenu command or action which can pop up a menu using the shortcut. + */ + private String definitionId = null; + + /** * Creates a menu manager. The text and id are null. * Typically used for creating a context menu, where it doesn't need to be referred to by id. */ public this() { - this(null, null); + this(null, null, null); } /** @@ -121,7 +143,7 @@ * @param text the text for the menu, or null if none */ public this(String text) { - this(text, null); + this(text, null, null); } /** @@ -132,8 +154,22 @@ * @param id the menu id, or null if it is to have no id */ public this(String text, String id) { + this(text, null, id); + } + + /** + * Creates a menu manager with the given text, image, and id. + * Typically used for creating a sub-menu, where it needs to be referred to by id. + * + * @param text the text for the menu, or null if none + * @param image the image for the menu, or null if none + * @param id the menu id, or null if it is to have no id + * @since 3.4 + */ + public MenuManager(String text, ImageDescriptor image, String id) { listeners = new ListenerList(); this.menuText = text; + this.image = image; this.id = id; } @@ -211,10 +247,14 @@ menuItem = null; } + disposeOldImages(); + IContributionItem[] items = getItems(); for (int i = 0; i < items.length; i++) { items[i].dispose(); } + + markDirty(); } /* (non-Javadoc) @@ -242,6 +282,14 @@ menuItem.setText(getMenuText()); + if (image !is null) { + LocalResourceManager localManager = new LocalResourceManager( + JFaceResources.getResources()); + menuItem.setImage(localManager.createImage(image)); + disposeOldImages(); + imageManager = localManager; + } + if (!menuExist()) { menu = new Menu(parent); } @@ -250,9 +298,7 @@ initializeMenu(); - // populate the submenu, in order to enable accelerators - // and to set enabled state on the menuItem properly - update(true); + setDirty(true); } } @@ -346,13 +392,36 @@ } /** - * Returns the text shown in the menu. + * Returns the text shown in the menu, potentially with a shortcut + * appended. * * @return the menu text */ public String getMenuText() { + if (definitionId is null) { + return menuText; + } + ExternalActionManager.ICallback callback = ExternalActionManager + .getInstance().getCallback(); + if (callback !is null) { + String shortCut = callback.getAcceleratorText(definitionId); + if (shortCut is null) { + return menuText; + } + return menuText + "\t" + shortCut; //$NON-NLS-1$ + } return menuText; } + + /** + * Returns the image for this menu as an image descriptor. + * + * @return the image, or null if this menu has no image + * @since 3.4 + */ + public ImageDescriptor getImageDescriptor() { + return image; + } /* (non-Javadoc) * @see dwtx.jface.action.IContributionManager#getOverrides() @@ -369,7 +438,7 @@ return null; } - public ValueWrapperBool getEnabled(IContributionItem item) { + public Boolean getEnabled(IContributionItem item) { return null; } @@ -410,7 +479,7 @@ removeAll(); } fireAboutToShow(this); - update(false, true); + update(false, false); } /** @@ -491,10 +560,15 @@ */ public bool isVisible() { if (!visible) { - return false; // short circut calculations in this case + return false; // short circuit calculations in this case } - // menus arent visible if all of its children are invisible (or only contains visible separators). + if (removeAllWhenShown) { + // we have no way of knowing if the menu has children + return true; + } + + // menus aren't visible if all of its children are invisible (or only contains visible separators). IContributionItem[] childItems = getItems(); bool visibleChildren = false; for (int j = 0; j < childItems.length; j++) { @@ -536,7 +610,7 @@ * @return true if the control is created * and not disposed, false otherwise */ - private bool menuExist() { + protected bool menuExist() { return menu !is null && !menu.isDisposed(); } @@ -584,6 +658,19 @@ public void setVisible(bool visible) { this.visible = visible; } + + /** + * Sets the action definition id of this action. This simply allows the menu + * item text to include a short cut if available. It can be used to + * notify a user of a key combination that will open a quick menu. + * + * @param definitionId + * the command definition id + * @since 3.4 + */ + public void setActionDefinitionId(String definitionId) { + this.definitionId = definitionId; + } /* (non-Javadoc) * @see dwtx.jface.action.IContributionItem#update() @@ -603,6 +690,65 @@ } /** + * Get all the items from the implementation's widget. + * + * @return the menu items + * @since 3.4 + */ + protected Item[] getMenuItems() { + if (menu !is null) { + return menu.getItems(); + } + return null; + } + + /** + * Get an item from the implementation's widget. + * + * @param index + * of the item + * @return the menu item + * @since 3.4 + */ + protected Item getMenuItem(int index) { + if (menu !isnull) { + return menu.getItem(index); + } + return null; + } + + /** + * Get the menu item count for the implementation's widget. + * + * @return the number of items + * @since 3.4 + */ + protected int getMenuItemCount() { + if (menu !is null) { + return menu.getItemCount(); + } + return 0; + } + + /** + * Call an IContributionItem's fill method with the + * implementation's widget. The default is to use the Menu + * widget.
+ * fill(Menu menu, int index) + * + * @param ci + * An IContributionItem whose fill() + * method should be called. + * @param index + * The position the fill() method should start + * inserting at. + * @since 3.4 + */ + protected void doItemFill(IContributionItem ci, int index) { + ci.fill(menu, index); + } + + /** * Incrementally builds the menu from the contribution items. * This method leaves out double separators and separators in the first * or last position. @@ -641,7 +787,7 @@ } // remove obsolete (removed or non active) - MenuItem[] mi = menu.getItems(); + Item[] mi = getMenuItems(); for (int i = 0; i < mi.length; i++) { Object data = mi[i].getData(); @@ -660,7 +806,7 @@ } // add new - mi = menu.getItems(); + mi = getMenuItems(); int srcIx = 0; int destIx = 0; @@ -683,11 +829,11 @@ srcIx++; destIx++; } else { - int start = menu.getItemCount(); - src.fill(menu, destIx); - int newItems = menu.getItemCount() - start; + int start = getMenuItemCount(); + doItemFill(src, destIx); + int newItems = getMenuItemCount() - start; for (int i = 0; i < newItems; i++) { - MenuItem item = menu.getItem(destIx++); + Item item = getMenuItem(destIx++); item.setData(cast(Object)src); } } @@ -743,42 +889,59 @@ for (int i = 0; i < items.length; i++) { items[i].update(property); } - - if (menu !is null && !menu.isDisposed() && menu.getParentItem() !is null - && IAction.TEXT.equals(property)) { - String text = getOverrides().getText(this); + + if (menu !is null && !menu.isDisposed() && menu.getParentItem() !is null) { + if (IAction.TEXT.equals(property)) { + String text = getOverrides().getText(this); - if (text is null) { - text = getMenuText(); - } + if (text is null) { + text = getMenuText(); + } - if (text !is null) { - ExternalActionManager.ICallback callback = ExternalActionManager - .getInstance().getCallback(); + if (text !is null) { + ExternalActionManager.ICallback callback = ExternalActionManager + .getInstance().getCallback(); - if (callback !is null) { - int index = dwt.dwthelper.utils.indexOf( text, '&' ); + if (callback !is null) { + int index = dwt.dwthelper.utils.indexOf( text, '&' ); - if (index >= 0 && index < text.length - 1) { - char character = CharacterToUpper(text - .charAt(index + 1)); + if (index >= 0 && index < text.length - 1) { + char character = CharacterToUpper(text + .charAt(index + 1)); - if (callback.isAcceleratorInUse(DWT.ALT | character)) { - if (index is 0) { - text = text.substring(1); - } else { - text = text.substring(0, index) + if (callback.isAcceleratorInUse(DWT.ALT | character)) { + if (index is 0) { + text = text.substring(1); + } else { + text = text.substring(0, index) ~ text.substring(index + 1); + } } } } - } - menu.getParentItem().setText(text); + menu.getParentItem().setText(text); + } + } else if (IAction.IMAGE.equals(property) && image !is null) { + LocalResourceManager localManager = new LocalResourceManager(JFaceResources + .getResources()); + menu.getParentItem().setImage(localManager.createImage(image)); + disposeOldImages(); + imageManager = localManager; } } } + /** + * Dispose any images allocated for this menu + */ + private void disposeOldImages() { + if (imageManager !is null) { + imageManager.dispose(); + imageManager = null; + } + } + /* (non-Javadoc) * @see dwtx.jface.action.IMenuManager#updateAll(bool) */ @@ -813,7 +976,7 @@ // Partial fix for bug #34969 - diable the menu item if no // items in sub-menu (for context menus). if (menuItem !is null && !menuItem.isDisposed() && menuExist()) { - bool enabled = menu.getItemCount() > 0; + bool enabled = removeAllWhenShown || menu.getItemCount() > 0; // Workaround for 1GDDCN2: DWT:Linux - MenuItem.setEnabled() always causes a redraw if (menuItem.getEnabled() !is enabled) { // We only do this for context menus (for bug #34969) diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/action/StatusLine.d --- a/dwtx/jface/action/StatusLine.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/action/StatusLine.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -39,20 +39,22 @@ import dwtx.jface.resource.ImageDescriptor; import dwtx.jface.resource.JFaceColors; import dwtx.jface.resource.JFaceResources; +import dwtx.jface.util.Util; import dwt.dwthelper.utils; import dwt.dwthelper.Runnable; /** * A StatusLine control is a DWT Composite with a horizontal layout which hosts - * a number of status indication controls. - * Typically it is situated below the content area of the window. + * a number of status indication controls. Typically it is situated below the + * content area of the window. *

- * By default a StatusLine has two predefined status controls: a MessageLine and a - * ProgressIndicator and it provides API for easy access. + * By default a StatusLine has two predefined status controls: a MessageLine and + * a ProgressIndicator and it provides API for easy access. *

*

- * This is an internal class, not intended to be used outside the JFace framework. + * This is an internal class, not intended to be used outside the JFace + * framework. *

*/ /* package */class StatusLine : Composite, IProgressMonitor { @@ -183,7 +185,8 @@ // in its update method. There is thus a dependency // between the layout of the standard widgets and the update method. - // Make sure cancel button and progress bar are before contributions. + // Make sure cancel button and progress bar are before + // contributions. fMessageLabel.moveAbove(null); fToolBar.moveBelow(fMessageLabel); fProgressBarComposite.moveBelow(fToolBar); @@ -238,14 +241,12 @@ for (int i = 0; i < count; i++) { Control w = children[i]; /* - * Workaround for Linux Motif: - * Even if the progress bar and cancel button are - * not set to be visible ad of width 0, they still - * draw over the first pixel of the editor - * contributions. + * Workaround for Linux Motif: Even if the progress bar and + * cancel button are not set to be visible ad of width 0, they + * still draw over the first pixel of the editor contributions. * - * The fix here is to draw the progress bar and - * cancel button off screen if they are not visible. + * The fix here is to draw the progress bar and cancel button + * off screen if they are not visible. */ if (w is fProgressBarComposite && !fProgressIsVisible || w is fToolBar && !fCancelButtonIsVisible) { @@ -263,8 +264,10 @@ /** * Create a new StatusLine as a child of the given parent. * - * @param parent the parent for this Composite - * @param style the style used to create this widget + * @param parent + * the parent for this Composite + * @param style + * the style used to create this widget */ public this(Composite parent, int style) { super(parent, style); @@ -282,12 +285,13 @@ setLayout(new StatusLineLayout()); - fMessageLabel = new CLabel(this, DWT.NONE);//DWT.SHADOW_IN); - // Color[] colors = new Color[2]; - // colors[0] = parent.getDisplay().getSystemColor(DWT.COLOR_WIDGET_LIGHT_SHADOW); - // colors[1] = fMessageLabel.getBackground(); - // int[] gradient = new int[] {JFaceColors.STATUS_PERCENT}; - // fMessageLabel.setBackground(colors, gradient); + fMessageLabel = new CLabel(this, DWT.NONE);// DWT.SHADOW_IN); + // Color[] colors = new Color[2]; + // colors[0] = + // parent.getDisplay().getSystemColor(DWT.COLOR_WIDGET_LIGHT_SHADOW); + // colors[1] = fMessageLabel.getBackground(); + // int[] gradient = new int[] {JFaceColors.STATUS_PERCENT}; + // fMessageLabel.setBackground(colors, gradient); fProgressIsVisible = false; fCancelEnabled = false; @@ -330,13 +334,15 @@ /** * Notifies that the main task is beginning. * - * @param name the name (or description) of the main task - * @param totalWork the total number of work units into which - * the main task is been subdivided. If the value is 0 or UNKNOWN the - * implemenation is free to indicate progress in a way which doesn't - * require the total number of work units in advance. In general users - * should use the UNKNOWN value if they don't know the total amount of - * work units. + * @param name + * the name (or description) of the main task + * @param totalWork + * the total number of work units into which the main task is + * been subdivided. If the value is 0 or UNKNOWN the + * implemenation is free to indicate progress in a way which + * doesn't require the total number of work units in advance. In + * general users should use the UNKNOWN value if they don't know + * the total amount of work units. */ public void beginTask(String name, int totalWork) { long timestamp = System.currentTimeMillis(); @@ -364,7 +370,7 @@ fProgressBar.beginTask(totalWork); } if (name is null) { - fTaskName = "";//$NON-NLS-1$ + fTaskName = Util.ZERO_LENGTH_STRING; } else { fTaskName = name; } @@ -372,10 +378,9 @@ } /** - * Notifies that the work is done; that is, either the main task is completed or the - * user cancelled it. - * Done() can be called more than once; an implementation should be prepared to handle - * this case. + * Notifies that the work is done; that is, either the main task is + * completed or the user cancelled it. Done() can be called more than once; + * an implementation should be prepared to handle this case. */ public void done() { @@ -392,6 +397,7 @@ /** * Returns the status line's progress monitor + * * @return {@link IProgressMonitor} the progress monitor */ public IProgressMonitor getProgressMonitor() { @@ -414,7 +420,7 @@ /** * Hides the Cancel button and ProgressIndicator. - * @private + * */ protected void hideProgress() { @@ -450,15 +456,16 @@ /** * Returns true if the user does some UI action to cancel this operation. - * (like hitting the Cancel button on the progress dialog). - * The long running operation typically polls isCanceled(). + * (like hitting the Cancel button on the progress dialog). The long running + * operation typically polls isCanceled(). */ public bool isCanceled() { return fIsCanceled; } /** - * Returns true if the ProgressIndication provides UI for canceling + * Returns + * true if the ProgressIndication provides UI for canceling * a long running operation. * @return true if the ProgressIndication provides UI for canceling */ @@ -467,8 +474,8 @@ } /** - * Sets the cancel status. This method is usually called with the - * argument false if a client wants to abort a cancel action. + * Sets the cancel status. This method is usually called with the argument + * false if a client wants to abort a cancel action. */ public void setCanceled(bool b) { fIsCanceled = b; @@ -478,12 +485,13 @@ } /** - * Controls whether the ProgressIndication provides UI for canceling - * a long running operation. - * If the ProgressIndication is currently visible calling this method may have - * a direct effect on the layout because it will make a cancel button visible. - * - * @param enabled true if cancel should be enabled + * Controls whether the ProgressIndication provides UI for canceling a long + * running operation. If the ProgressIndication is currently visible calling + * this method may have a direct effect on the layout because it will make a + * cancel button visible. + * + * @param enabled + * true if cancel should be enabled */ public void setCancelEnabled(bool enabled) { fCancelEnabled = enabled; @@ -497,10 +505,11 @@ } /** - * Sets the error message text to be displayed on the status line. - * The image on the status line is cleared. + * Sets the error message text to be displayed on the status line. The image + * on the status line is cleared. * - * @param message the error message, or null for no error message + * @param message + * the error message, or null for no error message */ public void setErrorMessage(String message) { setErrorMessage(null, message); @@ -509,8 +518,10 @@ /** * Sets an image and error message text to be displayed on the status line. * - * @param image the image to use, or null for no image - * @param message the error message, or null for no error message + * @param image + * the image to use, or null for no image + * @param message + * the error message, or null for no error message */ public void setErrorMessage(Image image, String message) { fErrorText = trim(message); @@ -530,10 +541,11 @@ } /** - * Sets the message text to be displayed on the status line. - * The image on the status line is cleared. + * Sets the message text to be displayed on the status line. The image on + * the status line is cleared. * - * @param message the error message, or null for no error message + * @param message + * the error message, or null for no error message */ public void setMessage(String message) { setMessage(null, message); @@ -542,8 +554,10 @@ /** * Sets an image and a message text to be displayed on the status line. * - * @param image the image to use, or null for no image - * @param message the message, or null for no message + * @param image + * the image to use, or null for no image + * @param message + * the message, or null for no message */ public void setMessage(Image image, String message) { fMessageText = trim(message); @@ -555,12 +569,15 @@ * @see IProgressMonitor#setTaskName(java.lang.String) */ public void setTaskName(String name) { - fTaskName = name; + if (name is null) + fTaskName = Util.ZERO_LENGTH_STRING; + else + fTaskName = name; } /** * Makes the Cancel button visible. - * @private + * */ protected void showButton() { if (fToolBar !is null && !fToolBar.isDisposed()) { @@ -573,7 +590,7 @@ /** * Shows the Cancel button and ProgressIndicator. - * @private + * */ protected void showProgress() { if (!fProgressIsVisible && !isDisposed()) { @@ -604,31 +621,40 @@ } /** - * Notifies that a subtask of the main task is beginning. - * Subtasks are optional; the main task might not have subtasks. - * @param name the name (or description) of the subtask + * Notifies that a subtask of the main task is beginning. Subtasks are + * optional; the main task might not have subtasks. + * + * @param name + * the name (or description) of the subtask * @see IProgressMonitor#subTask(String) */ public void subTask(String name) { + + String newName; + if (name is null) + newName = Util.ZERO_LENGTH_STRING; + else + newName = name; + String text; if (fTaskName.length is 0) { - text = name; + text = newName; } else { text = JFaceResources.format( - "Set_SubTask", [ fTaskName, name ]);//$NON-NLS-1$ + "Set_SubTask", [ fTaskName, newName ]);//$NON-NLS-1$ } setMessage(text); } /** - * Trims the message to be displayable in the status line. - * This just pulls out the first line of the message. - * Allows null. + * Trims the message to be displayable in the status line. This just pulls + * out the first line of the message. Allows null. */ String trim(String message) { if (message is null) { return null; } + message = Util.replaceAll(message, "&", "&&"); //$NON-NLS-1$//$NON-NLS-2$ int cr = message.indexOf('\r'); int lf = message.indexOf('\n'); if (cr is -1 && lf is -1) { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/action/StatusLineContributionItem.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/action/StatusLineContributionItem.d Thu May 22 01:36:46 2008 +0200 @@ -0,0 +1,171 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Port to the D programming language: + * Frank Benoit + *******************************************************************************/ + +module dwtx.jface.action.StatusLineContributionItem; + + +import dwt.DWT; +import dwt.custom.CLabel; +import dwt.graphics.FontMetrics; +import dwt.graphics.GC; +import dwt.graphics.Point; +import dwt.widgets.Composite; +import dwt.widgets.Label; +import dwtx.core.runtime.Assert; +import dwtx.jface.util.Util; + +/** + * A contribution item to be used with status line managers. + *

+ * This class may be instantiated; it is not intended to be subclassed. + *

+ * + * @since 3.4 + */ +public class StatusLineContributionItem extends ContributionItem { + + private final static int DEFAULT_CHAR_WIDTH = 40; + + private int charWidth; + + private CLabel label; + + /** + * The composite into which this contribution item has been placed. This + * will be null if this instance has not yet been + * initialized. + */ + private Composite statusLine = null; + + private String text = Util.ZERO_LENGTH_STRING; + + private int widthHint = -1; + + private int heightHint = -1; + + /** + * Creates a status line contribution item with the given id. + * + * @param id + * the contribution item's id, or null if it is to + * have no id + */ + public StatusLineContributionItem(String id) { + this(id, DEFAULT_CHAR_WIDTH); + } + + /** + * Creates a status line contribution item with the given id that displays + * the given number of characters. + * + * @param id + * the contribution item's id, or null if it is to + * have no id + * @param charWidth + * the number of characters to display + */ + public StatusLineContributionItem(String id, int charWidth) { + super(id); + this.charWidth = charWidth; + setVisible(false); // no text to start with + } + + public void fill(Composite parent) { + statusLine = parent; + + Label sep = new Label(parent, DWT.SEPARATOR); + label = new CLabel(statusLine, DWT.SHADOW_NONE); + + if (widthHint < 0) { + GC gc = new GC(statusLine); + gc.setFont(statusLine.getFont()); + FontMetrics fm = gc.getFontMetrics(); + widthHint = fm.getAverageCharWidth() * charWidth; + heightHint = fm.getHeight(); + gc.dispose(); + } + + StatusLineLayoutData data = new StatusLineLayoutData(); + data.widthHint = widthHint; + label.setLayoutData(data); + label.setText(text); + + data = new StatusLineLayoutData(); + data.heightHint = heightHint; + sep.setLayoutData(data); + } + + /** + * An accessor for the current location of this status line contribution + * item -- relative to the display. + * + * @return The current location of this status line; null if + * not yet initialized. + */ + public Point getDisplayLocation() { + if ((label !is null) && (statusLine !is null)) { + return statusLine.toDisplay(label.getLocation()); + } + + return null; + } + + /** + * Retrieves the text that is being displayed in the status line. + * + * @return the text that is currently being displayed + */ + public String getText() { + return text; + } + + /** + * Sets the text to be displayed in the status line. + * + * @param text + * the text to be displayed, must not be null + */ + public void setText(String text) { + Assert.isNotNull(text); + + this.text = escape(text); + + if (label !is null && !label.isDisposed()) { + label.setText(this.text); + } + + if (this.text.length() is 0) { + if (isVisible()) { + setVisible(false); + IContributionManager contributionManager = getParent(); + + if (contributionManager !is null) { + contributionManager.update(true); + } + } + } else { + if (!isVisible()) { + setVisible(true); + IContributionManager contributionManager = getParent(); + + if (contributionManager !is null) { + contributionManager.update(true); + } + } + } + } + + private String escape(String text) { + return Util.replaceAll(text, "&", "&&"); //$NON-NLS-1$//$NON-NLS-2$ + } +} diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/action/SubMenuManager.d --- a/dwtx/jface/action/SubMenuManager.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/action/SubMenuManager.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -114,7 +114,7 @@ if (menuListener !is null) { getParentMenuManager().removeMenuListener(menuListener); menuListener = null; - clearListenerList(menuListeners); + menuListeners.clear(); } // Dispose wrapped menus in addition to removing them. // See bugs 64024 and 73715 for details. @@ -132,20 +132,6 @@ super.disposeManager(); } - /** - * Clears all of the listeners in a listener list. TODO Bug 117519 Remove - * this method when fixed. - * - * @param list - * The list to be clear; must not be null. - */ - private final void clearListenerList(ListenerList list) { - Object[] listeners = list.getListeners(); - for (int i = 0; i < listeners.length; i++) { - list.remove(cast(Object)listeners[i]); - } - } - /* (non-Javadoc) * @see dwtx.jface.action.IContributionItem#fill(dwt.widgets.Composite) */ diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/action/ToolBarManager.d --- a/dwtx/jface/action/ToolBarManager.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/action/ToolBarManager.d Thu May 22 01:36:46 2008 +0200 @@ -25,8 +25,11 @@ import dwt.accessibility.AccessibleAdapter; import dwt.accessibility.AccessibleEvent; import dwt.accessibility.AccessibleListener; +import dwt.graphics.Point; import dwt.widgets.Composite; import dwt.widgets.Control; +import dwt.widgets.CoolBar; +import dwt.widgets.CoolItem; import dwt.widgets.Menu; import dwt.widgets.ToolBar; import dwt.widgets.ToolItem; @@ -184,8 +187,7 @@ * Re-lays out the tool bar. *

* The default implementation of this framework method re-lays out the - * parent when the number of items crosses the zero threshold. Subclasses - * should override this method to implement their own re-layout strategy + * parent when the number of items are different and the new count !is 0 * * @param layoutBar * the tool bar control @@ -195,8 +197,31 @@ * the new number of items */ protected void relayout(ToolBar layoutBar, int oldCount, int newCount) { - if ((oldCount is 0) !is (newCount is 0)) { + if ((oldCount !is newCount) && (newCount!is0)) { + Point beforePack = layoutBar.getSize(); + layoutBar.pack(true); + Point afterPack = layoutBar.getSize(); + + // If the TB didn't change size then we're done + if (beforePack.equals(afterPack)) + return; + + // OK, we need to re-layout the TB layoutBar.getParent().layout(); + + // Now, if we're in a CoolBar then change the CoolItem size as well + if (layoutBar.getParent() instanceof CoolBar) { + CoolBar cb = (CoolBar) layoutBar.getParent(); + CoolItem[] items = cb.getItems(); + for (int i = 0; i < items.length; i++) { + if (items[i].getControl() is layoutBar) { + Point curSize = items[i].getSize(); + items[i].setSize(curSize.x+ (afterPack.x - beforePack.x), + curSize.y+ (afterPack.y - beforePack.y)); + return; + } + } + } } } @@ -362,6 +387,11 @@ } int newCount = toolBar.getItemCount(); + + // If we're forcing a change then ensure that we re-layout everything + if (force) + oldCount = newCount+1; + relayout(toolBar, oldCount, newCount); } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/action/images/stop.gif Binary file dwtx/jface/action/images/stop.gif has changed diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/bindings/Binding.d --- a/dwtx/jface/bindings/Binding.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/bindings/Binding.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2007 IBM Corporation and others. + * Copyright (c) 2004, 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 @@ -270,7 +270,7 @@ if (!Util.opEquals(getSchemeId(), binding.getSchemeId())) { return false; } - return (getType() !is binding.getType()); + return (getType() is binding.getType()); } /** diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/bindings/BindingManager.d --- a/dwtx/jface/bindings/BindingManager.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/bindings/BindingManager.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2007 IBM Corporation and others. + * Copyright (c) 2004, 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 @@ -1204,13 +1204,7 @@ public final TriggerSequence[] getActiveBindingsFor(String commandId) { ParameterizedCommand parameterizedCommand = new ParameterizedCommand( commandManager.getCommand(commandId), null); - Object object = getActiveBindingsByParameterizedCommand().get( - parameterizedCommand); - if ( auto collection = cast(Seq!(Object))object ) { - return arraycast!(TriggerSequence)(collection.toArray()); - } - - return EMPTY_TRIGGER_SEQUENCE; + return getActiveBindingsFor(parameterizedCommand); } /** @@ -1225,8 +1219,8 @@ * null if there are no active bindings. * @since 3.2 */ - private final Binding[] getActiveBindingsFor1(String commandId) { - TriggerSequence[] triggers = getActiveBindingsFor(commandId); + private final Binding[] getActiveBindingsFor1(final ParameterizedCommand command) { + TriggerSequence[] triggers = getActiveBindingsFor(command); if (triggers.length is 0) { return null; } @@ -1281,7 +1275,16 @@ * @since 3.2 */ public final TriggerSequence getBestActiveBindingFor(String commandId) { - Binding[] bindings = getActiveBindingsFor1(commandId); + return getBestActiveBindingFor(new ParameterizedCommand(commandManager.getCommand(commandId), null)); + } + + /** + * @param command + * @return + * blah + */ + public final TriggerSequence getBestActiveBindingFor(final ParameterizedCommand command) { + final Binding[] bindings = getActiveBindingsFor1(command); if ((bindings is null) || (bindings.length is 0)) { return null; } @@ -1397,7 +1400,6 @@ return null; } - /** *

* Returns the set of all bindings managed by this class. diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/bindings/keys/KeySequenceText.d --- a/dwtx/jface/bindings/keys/KeySequenceText.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/bindings/keys/KeySequenceText.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2007 IBM Corporation and others. + * Copyright (c) 2004, 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 @@ -84,6 +84,8 @@ * The key strokes from which to delete. This list must not * be null, and must represent a valid key * sequence. + * @return An array of keystrokes minus the keystrokes that were + * deleted. */ private final KeyStroke[] deleteKeyStroke(KeyStroke[] keyStrokes) { clearInsertionIndex(); @@ -152,7 +154,7 @@ */ private KeyStroke[] handleKeyDown(Event event, KeyStroke[] keyStrokes) { // Is it an unmodified backspace character? - if ((event.character is DWT.BS) && (event.stateMask is 0)) { + if ((event.character is DWT.BS || event.character is DWT.DEL) && (event.stateMask is 0)) { return deleteKeyStroke(keyStrokes); } @@ -638,6 +640,10 @@ * @param allowIncomplete * Whether incomplete strokes should be allowed to exist in the * list after the deletion. + * @param deletedKeyStrokes + * The list of keystrokes that were deleted by this operation. + * Declared as final since it will hold a reference to the new + * keyStroke array that has deleted the selected keystrokes. * @return The index at which a subsequent insert should occur. This index * only has meaning to the insertStrokeAt method. */ @@ -684,6 +690,8 @@ */ int endStrokeIndex; if (start is end) { + // return the current keystrokes, nothing has to be deleted + deletedKeyStrokes[0] = keyStrokes; return startStrokeIndex; } @@ -700,10 +708,15 @@ * Remove the strokes that are touched by the selection. Keep track of * the first stroke removed. */ - int newLength = endStrokeIndex - startStrokeIndex + 1; + int newLength = keyStrokesLength + - (endStrokeIndex - startStrokeIndex + 1); deletedKeyStrokes[0] = new KeyStroke[newLength]; KeyStroke startStroke = keyStrokes[startStrokeIndex]; - System.arraycopy(keyStrokes, 0, keyStrokes, 0, newLength); + KeyStroke keyStrokeResult[] = new KeyStroke[newLength]; + System.arraycopy(keyStrokes, 0, keyStrokeResult, 0, startStrokeIndex); + System.arraycopy(keyStrokes, endStrokeIndex + 1, keyStrokeResult, + startStrokeIndex, keyStrokesLength - endStrokeIndex - 1); + System.arraycopy(keyStrokeResult, 0, deletedKeyStrokes[0], 0, newLength); /* * Allow the first stroke removed to be replaced by an incomplete @@ -720,7 +733,7 @@ startStrokeIndex); added[startStrokeIndex] = incompleteStroke; System.arraycopy(deletedKeyStrokes[0], startStrokeIndex, added, - startStrokeIndex + 1, newLength); + startStrokeIndex + 1, newLength - startStrokeIndex); deletedKeyStrokes[0] = added; } } @@ -904,8 +917,13 @@ */ public void setKeySequence(KeySequence newKeySequence) { KeySequence oldKeySequence = keySequence; - keySequence = newKeySequence; + if (newKeySequence is null) { + text.setText(""); //$NON-NLS-1$ + } else { + keySequence = newKeySequence; + } + // Trim any extra strokes. if (maxStrokes !is INFINITE) { KeyStroke[] oldKeyStrokes = keySequence.getKeyStrokes(); diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/commands/RadioState.d --- a/dwtx/jface/commands/RadioState.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/commands/RadioState.d Thu May 22 01:36:46 2008 +0200 @@ -29,8 +29,8 @@ /** *

* A piece of bool state grouped with other bool states. Of these states, - * only one may have a value of {@link bool#TRUE} at any given point in time. - * The values of all other states must be {@link bool#FALSE}. + * only one may have a value of {@link Boolean#TRUE} at any given point in time. + * The values of all other states must be {@link Boolean#FALSE}. *

*

* If this state is registered using {@link IMenuStateIds#STYLE}, then it will @@ -79,7 +79,7 @@ */ private final void activateMember(RadioState state) { if (active !is null && active !is state) { - active.setValue( new ValueWrapperBool( false )); + active.setValue(Boolean.FALSE); } active = state; } @@ -101,8 +101,8 @@ state.addListener(this); Object value = state.getValue(); - if ( auto v = cast(ValueWrapperBool)value ) { - if (v.value) { + if ( auto v = cast(Boolean)value ) { + if (v.booleanValue()) { activateMember(state); } } @@ -111,8 +111,8 @@ public final void handleStateChange(State state, Object oldValue) { Object newValue = state.getValue(); - if ( auto v = cast(ValueWrapperBool)newValue) { - if (v.value) { + if ( auto v = cast(Boolean)newValue) { + if (v.booleanValue()) { activateMember(cast(RadioState) state); } } @@ -254,15 +254,15 @@ * the change. * * @param value - * The new value; should be a bool. + * The new value; should be a Boolean. */ public override void setValue(Object value) { - if (!( cast(ValueWrapperBool)value )) { + if (!( cast(Boolean)value )) { throw new IllegalArgumentException( - "RadioState takes a bool as a value"); //$NON-NLS-1$ + "RadioState takes a Boolean as a value"); //$NON-NLS-1$ } - if (( cast(ValueWrapperBool)value ).value && (radioGroupIdentifier !is null)) { + if (( cast(Boolean)value ).booleanValue() && (radioGroupIdentifier !is null)) { RadioStateManager.activateGroup(radioGroupIdentifier, this); } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/commands/ToggleState.d --- a/dwtx/jface/commands/ToggleState.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/commands/ToggleState.d Thu May 22 01:36:46 2008 +0200 @@ -22,7 +22,7 @@ /** *

- * A piece of state storing a {@link bool}. + * A piece of state storing a {@link Boolean}. *

*

* If this state is registered using {@link IMenuStateIds#STYLE}, then it will @@ -42,16 +42,16 @@ * off (e.g., false). */ public this() { - setValue(new ValueWrapperBool(false)); + setValue(Boolean.FALSE); } public override final void load(IPreferenceStore store, String preferenceKey) { - bool currentValue = (cast(ValueWrapperBool) getValue()).value; + bool currentValue = (cast(Boolean) getValue()).booleanValue(); store.setDefault(preferenceKey, currentValue); if (shouldPersist() && (store.contains(preferenceKey))) { bool value = store.getBoolean(preferenceKey); - setValue( new ValueWrapperBool( value )); + setValue(value ? Boolean.TRUE : Boolean.FALSE); } } @@ -59,16 +59,16 @@ String preferenceKey) { if (shouldPersist()) { Object value = getValue(); - if ( auto v = cast(ValueWrapperBool)value ) { - store.setValue(preferenceKey, v.value); + if ( auto v = cast(Boolean)value ) { + store.setValue(preferenceKey, v.booleanValue()); } } } public override void setValue(Object value) { - if (!(cast(ValueWrapperBool)value)) { + if (!(cast(Boolean)value)) { throw new IllegalArgumentException( - "ToggleState takes a bool as a value"); //$NON-NLS-1$ + "ToggleState takes a Boolean as a value"); //$NON-NLS-1$ } super.setValue(value); diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/dialogs/Dialog.d --- a/dwtx/jface/dialogs/Dialog.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/dialogs/Dialog.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Remy Chi Jian Suen - Bug 218553 [JFace] mis-spelling of their in applyDialogFont(...) * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -450,8 +451,13 @@ */ protected this(IShellProvider parentShell) { super(parentShell); - setShellStyle(DWT.DIALOG_TRIM | DWT.APPLICATION_MODAL - | getDefaultOrientation()); + if (isResizable()) { + setShellStyle(DWT.DIALOG_TRIM | DWT.APPLICATION_MODAL | DWT.MAX | DWT.RESIZE + | getDefaultOrientation()); + } else { + setShellStyle(DWT.DIALOG_TRIM | DWT.APPLICATION_MODAL + | getDefaultOrientation()); + } setBlockOnOpen(true); } @@ -1009,7 +1015,7 @@ } /** - * Sets the dialog font on the control and any of its children if thier font + * Sets the dialog font on the control and any of its children if their font * is not otherwise set. * * @param control @@ -1283,5 +1289,31 @@ // constraining behavior in Window will be used. return result; } - + + /** + * Returns a bool indicating whether the dialog should be + * considered resizable when the shell style is initially + * set. + * + * This method is used to ensure that all style + * bits appropriate for resizable dialogs are added to the + * shell style. Individual dialogs may always set the shell + * style to ensure that a dialog is resizable, but using this + * method ensures that resizable dialogs will be created with + * the same set of style bits. + * + * Style bits will never be removed based on the return value + * of this method. For example, if a dialog returns + * false, but also sets a style bit for a + * DWT.RESIZE border, the style bit will be honored. + * + * @return a bool indicating whether the dialog is + * resizable and should have the default style bits for + * resizable dialogs + * + * @since 3.4 + */ + protected bool isResizable() { + return false; + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/dialogs/ErrorDialog.d --- a/dwtx/jface/dialogs/ErrorDialog.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/dialogs/ErrorDialog.d Thu May 22 01:36:46 2008 +0200 @@ -146,7 +146,6 @@ "Reason", [ message, status.getMessage() ]); //$NON-NLS-1$ this.status = status; this.displayMask = displayMask; - setShellStyle(getShellStyle() | DWT.RESIZE); } /* @@ -201,7 +200,7 @@ provider.createSupportArea(supportArea, status); GridData supportData = new GridData(DWT.FILL, DWT.FILL, true, true); - supportData.verticalSpan = 3; + supportData.verticalSpan = 4; supportArea.setLayoutData(supportData); if (supportArea.getLayout() is null){ GridLayout layout = new GridLayout(); @@ -232,6 +231,11 @@ * and lays out a composite. Subclasses that require a different dialog area * may either override this method, or call the super * implementation and add controls to the created composite. + * + * Note: Since 3.4, the created composite no longer grabs excess vertical space. + * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=72489. + * If the old behavior is desired by subclasses, get the returned composite's + * layout data and set grabExcessVerticalSpace to true. */ protected override Control createDialogArea(Composite parent) { createMessageArea(parent); @@ -247,6 +251,7 @@ composite.setLayout(layout); GridData childData = new GridData(GridData.FILL_BOTH); childData.horizontalSpan = 2; + childData.grabExcessVerticalSpace = false; composite.setLayoutData(childData); composite.setFont(parent.getFont()); @@ -535,6 +540,7 @@ } else { list = createDropDownList(cast(Composite) getContents()); detailsButton.setText(IDialogConstants.HIDE_DETAILS_LABEL); + getContents().getShell().layout(); } Point newSize = getShell().computeSize(DWT.DEFAULT, DWT.DEFAULT); getShell() @@ -681,4 +687,13 @@ return 2; return 3; } + + /* + * (non-Javadoc) + * @see dwtx.jface.dialogs.Dialog#isResizable() + */ + protected bool isResizable() { + return true; + } + } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/dialogs/IconAndMessageDialog.d --- a/dwtx/jface/dialogs/IconAndMessageDialog.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/dialogs/IconAndMessageDialog.d Thu May 22 01:36:46 2008 +0200 @@ -74,6 +74,7 @@ * since the parent is typically the composite created in * {@link Dialog#createDialogArea}. *

+ * * @param composite * The composite to parent from. * @return Control @@ -165,11 +166,11 @@ protected override Control createButtonBar(Composite parent) { Composite composite = new Composite(parent, DWT.NONE); GridLayoutFactory.fillDefaults().numColumns(0) // this is incremented - // by createButton + // by createButton .equalWidth(true).applyTo(composite); - GridDataFactory.fillDefaults().align_(DWT.END, DWT.CENTER).span( - 2, 1).applyTo(composite); + GridDataFactory.fillDefaults().align_(DWT.END, DWT.CENTER).span(2, 1) + .applyTo(composite); composite.setFont(parent.getFont()); // Add the buttons to the button bar. createButtonsForButtonBar(composite); @@ -193,12 +194,10 @@ protected override Control createContents(Composite parent) { // initialize the dialog units initializeDialogUnits(parent); - Point defaultMargins = LayoutConstants.getMargins(); Point defaultSpacing = LayoutConstants.getSpacing(); - GridLayoutFactory.fillDefaults().margins(defaultMargins.x, - defaultMargins.y * 3 / 2).spacing(defaultSpacing.x * 2, - defaultSpacing.y).numColumns(getColumnCount()).applyTo( - parent); + GridLayoutFactory.fillDefaults().margins(LayoutConstants.getMargins()) + .spacing(defaultSpacing.x * 2, + defaultSpacing.y).numColumns(getColumnCount()).applyTo(parent); GridDataFactory.fillDefaults().grab(true, true).applyTo(parent); createDialogAndButtonArea(parent); diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/dialogs/InputDialog.d --- a/dwtx/jface/dialogs/InputDialog.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/dialogs/InputDialog.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -172,7 +172,7 @@ label.setLayoutData(data); label.setFont(parent.getFont()); } - text = new Text(composite, DWT.SINGLE | DWT.BORDER); + text = new Text(composite, getInputTextStyle()); text.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); text.addModifyListener(new class ModifyListener { @@ -286,4 +286,17 @@ } } } + + /** + * Returns the style bits that should be used for the input text field. + * Defaults to a single line entry. Subclasses may override. + * + * @return the integer style bits that should be used when creating the + * input text + * + * @since 3.4 + */ + protected int getInputTextStyle() { + return DWT.SINGLE | DWT.BORDER; + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/dialogs/MessageDialogWithToggle.d --- a/dwtx/jface/dialogs/MessageDialogWithToggle.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/dialogs/MessageDialogWithToggle.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -701,9 +701,16 @@ return IDialogConstants.NO_TO_ALL_ID; } + if (IDialogConstants.SHOW_DETAILS_LABEL.equals(buttonLabel)) { + return IDialogConstants.DETAILS_ID; + } + + if (IDialogConstants.HIDE_DETAILS_LABEL.equals(buttonLabel)) { + return IDialogConstants.DETAILS_ID; + } + // No XXX_LABEL in IDialogConstants for these. Unlikely // they would be used in a message dialog though. - // public int DETAILS_ID = 13; // public int SELECT_ALL_ID = 18; // public int DESELECT_ALL_ID = 19; // public int SELECT_TYPES_ID = 20; diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/dialogs/PopupDialog.d --- a/dwtx/jface/dialogs/PopupDialog.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/dialogs/PopupDialog.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 IBM Corporation and others. + * Copyright (c) 2005, 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 @@ -31,12 +31,10 @@ import dwt.graphics.Color; import dwt.graphics.Font; import dwt.graphics.FontData; -import dwt.graphics.Image; import dwt.graphics.Point; import dwt.graphics.Rectangle; import dwt.widgets.Composite; import dwt.widgets.Control; -import dwt.widgets.Display; import dwt.widgets.Event; import dwt.widgets.Label; import dwt.widgets.Listener; @@ -53,7 +51,6 @@ import dwtx.jface.action.Separator; import dwtx.jface.layout.GridDataFactory; import dwtx.jface.layout.GridLayoutFactory; -import dwtx.jface.resource.ImageDescriptor; import dwtx.jface.resource.JFaceResources; import dwtx.jface.window.Window; @@ -109,8 +106,32 @@ /** * The dialog settings key name for remembering if the persisted bounds * should be accessed. + * + * @deprecated Since 3.4, this is retained only for backward compatibility. */ - private static const String DIALOG_USE_PERSISTED_BOUNDS = "DIALOG_USE_PERSISTED_BOUNDS"; //$NON-NLS-1$ + private static final String DIALOG_USE_PERSISTED_BOUNDS = "DIALOG_USE_PERSISTED_BOUNDS"; //$NON-NLS-1$ + + /** + * The dialog settings key name for remembering if the bounds persisted + * prior to 3.4 have been migrated to the 3.4 settings. + * + * @since 3.4 + * @deprecated This is marked deprecated at its introduction to discourage + * future dependency + */ + private static final String DIALOG_VALUE_MIGRATED_TO_34 = "hasBeenMigratedTo34"; //$NON-NLS-1$ + + /** + * The dialog settings key name for remembering if the persisted size should + * be accessed. + */ + private static final String DIALOG_USE_PERSISTED_SIZE = "DIALOG_USE_PERSISTED_SIZE"; //$NON-NLS-1$ + + /** + * The dialog settings key name for remembering if the persisted location + * should be accessed. + */ + private static final String DIALOG_USE_PERSISTED_LOCATION = "DIALOG_USE_PERSISTED_LOCATION"; //$NON-NLS-1$ /** * Move action for the dialog. @@ -160,7 +181,7 @@ this() { super(JFaceResources.getString("PopupDialog.persistBounds"), //$NON-NLS-1$ IAction.AS_CHECK_BOX); - setChecked(persistBounds); + setChecked(persistLocation && persistSize); } /* @@ -169,20 +190,66 @@ * @see dwtx.jface.action.IAction#run() */ public override void run() { - persistBounds = isChecked(); + persistSize = isChecked(); + persistLocation = persistSize; + } + } + + /** + * + * Remember bounds action for the dialog. + */ + private class PersistSizeAction extends Action { + + PersistSizeAction() { + super(JFaceResources.getString("PopupDialog.persistSize"), //$NON-NLS-1$ + IAction.AS_CHECK_BOX); + setChecked(persistSize); + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.action.IAction#run() + */ + public void run() { + persistSize = isChecked(); + } + } + + /** + * + * Remember location action for the dialog. + */ + private class PersistLocationAction extends Action { + + PersistLocationAction() { + super(JFaceResources.getString("PopupDialog.persistLocation"), //$NON-NLS-1$ + IAction.AS_CHECK_BOX); + setChecked(persistLocation); + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.action.IAction#run() + */ + public void run() { + persistLocation = isChecked(); } } /** * Shell style appropriate for a simple hover popup that cannot get focus. + * */ public const static int HOVER_SHELLSTYLE = DWT.NO_FOCUS | DWT.ON_TOP - | DWT.NO_TRIM; + | DWT.TOOL; /** * Shell style appropriate for an info popup that can get focus. */ - public const static int INFOPOPUP_SHELLSTYLE = DWT.NO_TRIM; + public const static int INFOPOPUP_SHELLSTYLE = DWT.TOOL; /** * Shell style appropriate for a resizable info popup that can get focus. @@ -214,9 +281,23 @@ public const static int POPUP_HORIZONTALSPACING = 1; /** - * + * Image registry key for menu image. + * + * @since 3.3 */ - private static const GridLayoutFactory POPUP_LAYOUT_FACTORY; + public static final String POPUP_IMG_MENU = "popup_menu_image"; //$NON-NLS-1$ + + /** + * Image registry key for disabled menu image. + * + * @since 3.3 + */ + public static final String POPUP_IMG_MENU_DISABLED = "popup_menu_image_diabled"; //$NON-NLS-1$ + + /** + * + */ + private static final GridLayoutFactory POPUP_LAYOUT_FACTORY; static this(){ LAYOUTDATA_GRAB_BOTH = GridDataFactory.fillDefaults().grab(true,true); @@ -224,10 +305,6 @@ .fillDefaults().margins(POPUP_MARGINWIDTH, POPUP_MARGINHEIGHT) .spacing(POPUP_HORIZONTALSPACING, POPUP_VERTICALSPACING); } - /** - * Border thickness in pixels. - */ - private static const int BORDER_THICKNESS = 1; /** * The dialog's toolbar for the move and resize capabilities. @@ -256,11 +333,6 @@ private Control titleSeparator, infoSeparator; /** - * The images for the dialog menu. - */ - private Image menuImage, disabledMenuImage = null; - - /** * Font to be used for the info area text. Computed based on the dialog's * font. */ @@ -295,16 +367,29 @@ private bool showDialogMenu_ = false; /** - * Flag specifying whether a menu action allowing the user to choose whether - * the dialog bounds should be persisted is to be shown. + * Flag specifying whether menu actions allowing the user to choose whether + * the dialog bounds and location should be persisted are to be shown. */ - private bool showPersistAction = false; + private bool showPersistActions = false; + + /** + * Flag specifying whether the size of the popup should be persisted. This + * flag is used as initial default and updated by the menu if it is shown. + */ + private bool persistSize = false; /** - * Flag specifying whether the bounds of the popup should be persisted. This - * flag is updated by a menu if the menu is shown. + * Flag specifying whether the location of the popup should be persisted. + * This flag is used as initial default and updated by the menu if it is + * shown. */ - private bool persistBounds = false; + private bool persistLocation = false; + /** + * Flag specifying whether to use new 3.4 API instead of the old one. + * + * @since 3.4 + */ + private bool isUsing34API = true; /** * Text to be shown in an optional title area (on top). @@ -327,19 +412,20 @@ * A bool indicating whether focus should be taken by this * popup when it opens. * @param persistBounds - * A bool indicating whether the bounds should be persisted - * upon close of the dialog. The bounds can only be persisted if - * the dialog settings for persisting the bounds are also - * specified. If a menu action will be provided that allows the - * user to control this feature, then the last known value of the - * user's setting will be used instead of this flag. + * A bool indicating whether the bounds (size and location) of + * the dialog should be persisted upon close of the dialog. The + * bounds can only be persisted if the dialog settings for + * persisting the bounds are also specified. If a menu action + * will be provided that allows the user to control this feature, + * then the last known value of the user's setting will be used + * instead of this flag. * @param showDialogMenu * A bool indicating whether a menu for moving and resizing * the popup should be provided. - * @param showPersistAction - * A bool indicating whether an action allowing the user to - * control the persisting of the dialog bounds should be shown in - * the dialog menu. This parameter has no effect if + * @param showPersistActions + * A bool indicating whether actions allowing the user to + * control the persisting of the dialog size and location should + * be shown in the dialog menu. This parameter has no effect if * showDialogMenu is false. * @param titleText * Text to be shown in an upper title area, or null @@ -347,23 +433,149 @@ * @param infoText * Text to be shown in a lower info area, or null * if there is no info area. - * + * * @see PopupDialog#getDialogSettings() + * @deprecated As of 3.4, replaced by + * {@link #PopupDialog(Shell, int, bool, bool, bool, bool, bool, String, String)} + */ + public PopupDialog(Shell parent, int shellStyle, bool takeFocusOnOpen, + bool persistBounds, bool showDialogMenu, + bool showPersistActions, String titleText, String infoText) { + this(parent, shellStyle, takeFocusOnOpen, persistBounds, persistBounds, + showDialogMenu, showPersistActions, titleText, infoText, false); + } + + /** + * Constructs a new instance of PopupDialog. + * + * @param parent + * The parent shell. + * @param shellStyle + * The shell style. + * @param takeFocusOnOpen + * A bool indicating whether focus should be taken by this + * popup when it opens. + * @param persistSize + * A bool indicating whether the size should be persisted upon + * close of the dialog. The size can only be persisted if the + * dialog settings for persisting the bounds are also specified. + * If a menu action will be provided that allows the user to + * control this feature and the user hasn't changed that setting, + * then this flag is used as initial default for the menu. + * @param persistLocation + * A bool indicating whether the location should be persisted + * upon close of the dialog. The location can only be persisted + * if the dialog settings for persisting the bounds are also + * specified. If a menu action will be provided that allows the + * user to control this feature and the user hasn't changed that + * setting, then this flag is used as initial default for the + * menu. default for the menu until the user changed it. + * @param showDialogMenu + * A bool indicating whether a menu for moving and resizing + * the popup should be provided. + * @param showPersistActions + * A bool indicating whether actions allowing the user to + * control the persisting of the dialog bounds and location + * should be shown in the dialog menu. This parameter has no + * effect if showDialogMenu is false. + * @param titleText + * Text to be shown in an upper title area, or null + * if there is no title. + * @param infoText + * Text to be shown in a lower info area, or null + * if there is no info area. + * + * @see PopupDialog#getDialogSettings() + * + * @since 3.4 */ - public this(Shell parent, int shellStyle, bool takeFocusOnOpen, - bool persistBounds, bool showDialogMenu_, - bool showPersistAction, String titleText, String infoText) { + public PopupDialog(Shell parent, int shellStyle, bool takeFocusOnOpen, + bool persistSize, bool persistLocation, + bool showDialogMenu, bool showPersistActions, + String titleText, String infoText) { + this(parent, shellStyle, takeFocusOnOpen, persistSize, persistLocation, + showDialogMenu, showPersistActions, titleText, infoText, true); + + } + + /** + * Constructs a new instance of PopupDialog. + * + * @param parent + * The parent shell. + * @param shellStyle + * The shell style. + * @param takeFocusOnOpen + * A bool indicating whether focus should be taken by this + * popup when it opens. + * @param persistSize + * A bool indicating whether the size should be persisted upon + * close of the dialog. The size can only be persisted if the + * dialog settings for persisting the bounds are also specified. + * If a menu action will be provided that allows the user to + * control this feature and the user hasn't changed that setting, + * then this flag is used as initial default for the menu. + * @param persistLocation + * A bool indicating whether the location should be persisted + * upon close of the dialog. The location can only be persisted + * if the dialog settings for persisting the bounds are also + * specified. If a menu action will be provided that allows the + * user to control this feature and the user hasn't changed that + * setting, then this flag is used as initial default for the + * menu. default for the menu until the user changed it. + * @param showDialogMenu + * A bool indicating whether a menu for moving and resizing + * the popup should be provided. + * @param showPersistActions + * A bool indicating whether actions allowing the user to + * control the persisting of the dialog bounds and location + * should be shown in the dialog menu. This parameter has no + * effect if showDialogMenu is false. + * @param titleText + * Text to be shown in an upper title area, or null + * if there is no title. + * @param infoText + * Text to be shown in a lower info area, or null + * if there is no info area. + * @param use34API + * true if 3.4 API should be used + * + * @see PopupDialog#getDialogSettings() + * + * @since 3.4 + */ + private PopupDialog(Shell parent, int shellStyle, bool takeFocusOnOpen, + bool persistSize, bool persistLocation, + bool showDialogMenu, bool showPersistActions, + String titleText, String infoText, bool use34API) { super(parent); + // Prior to 3.4, we encouraged use of DWT.NO_TRIM and provided a + // border using a black composite background and margin. Now we + // use DWT.TOOL to get the border for some cases and this conflicts + // with DWT.NO_TRIM. Clients who previously have used DWT.NO_TRIM + // and still had a border drawn for them would find their border go + // away unless we do the following: + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=219743 + if ((shellStyle & DWT.NO_TRIM) !is 0) { + shellStyle &= ~(DWT.NO_TRIM | DWT.SHELL_TRIM); + } + setShellStyle(shellStyle); this.takeFocusOnOpen = takeFocusOnOpen; this.showDialogMenu_ = showDialogMenu_; - this.showPersistAction = showPersistAction; + this.showPersistActions = showPersistActions; this.titleText = titleText; this.infoText = infoText; setBlockOnOpen(false); - this.persistBounds = persistBounds; + this.isUsing34API = use34API; + + this.persistSize = persistSize; + this.persistLocation = persistLocation; + + migrateBoundsSetting(); + initializeWidgetState(); } @@ -373,12 +585,8 @@ * @see dwtx.jface.window.Window#configureShell(Shell) */ protected override void configureShell(Shell shell) { - Display display = shell.getDisplay(); - shell.setBackground(display.getSystemColor(DWT.COLOR_BLACK)); - - int border = ((getShellStyle() & DWT.NO_TRIM) is 0) ? 0 - : BORDER_THICKNESS; - GridLayoutFactory.fillDefaults().margins(border, border).spacing(5,5).applyTo(shell); + GridLayoutFactory.fillDefaults().margins(0, 0).spacing(5, 5).applyTo( + shell); shell.addListener(DWT.Deactivate, new class Listener { public void handleEvent(Event event) { @@ -391,11 +599,13 @@ */ if (listenToDeactivate && event.widget is getShell() && getShell().getShells().length is 0) { - close(); + asyncClose(); } else { - /* We typically ignore deactivates to work around platform-specific - * event ordering. Now that we've ignored whatever we were supposed to, - * start listening to deactivates. Example issues can be found in + /* + * We typically ignore deactivates to work around + * platform-specific event ordering. Now that we've ignored + * whatever we were supposed to, start listening to + * deactivates. Example issues can be found in * https://bugs.eclipse.org/bugs/show_bug.cgi?id=123392 */ listenToDeactivate = true; @@ -420,17 +630,18 @@ }); if ((getShellStyle() & DWT.ON_TOP) !is 0 && shell.getParent() !is null) { - parentDeactivateListener= new class Listener { + parentDeactivateListener = new class Listener { public void handleEvent(Event event) { if (listenToParentDeactivate) { - close(); + asyncClose(); } else { // Our first deactivate, now start listening on the Mac. listenToParentDeactivate = listenToDeactivate; } } }; - shell.getParent().addListener(DWT.Deactivate, parentDeactivateListener); + shell.getParent().addListener(DWT.Deactivate, + parentDeactivateListener); } shell.addDisposeListener(new class DisposeListener { @@ -440,6 +651,15 @@ }); } + private void asyncClose() { + // workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=152010 + getShell().getDisplay().asyncExec(new Runnable() { + public void run() { + close(); + } + }); + } + /** * The PopupDialog implementation of this Window * method creates and lays out the top level composite for the dialog. It @@ -585,9 +805,8 @@ Composite titleAreaComposite = new Composite(parent, DWT.NONE); POPUP_LAYOUT_FACTORY.copy().numColumns(2).applyTo(titleAreaComposite); - GridDataFactory.fillDefaults() - .align_(DWT.FILL, DWT.CENTER).grab(true, false) - .applyTo(titleAreaComposite); + GridDataFactory.fillDefaults().align_(DWT.FILL, DWT.CENTER).grab(true, + false).applyTo(titleAreaComposite); createTitleControl(titleAreaComposite); @@ -615,19 +834,8 @@ protected Control createTitleControl(Composite parent) { titleLabel = new Label(parent, DWT.NONE); - GridDataFactory.fillDefaults() - .align_(DWT.FILL, DWT.CENTER) - .grab(true, false) - .span(showDialogMenu_ ? 1 : 2, 1) - .applyTo(titleLabel); - - Font font = titleLabel.getFont(); - FontData[] fontDatas = font.getFontData(); - for (int i = 0; i < fontDatas.length; i++) { - fontDatas[i].setStyle(DWT.BOLD); - } - titleFont = new Font(titleLabel.getDisplay(), fontDatas); - titleLabel.setFont(titleFont); + GridDataFactory.fillDefaults().align_(DWT.FILL, DWT.CENTER).grab(true, + false).span(showDialogMenu ? 1 : 2, 1).applyTo(titleLabel); if (titleText !is null) { titleLabel.setText(titleText); @@ -657,15 +865,9 @@ // Status label infoLabel = new Label(parent, DWT.RIGHT); infoLabel.setText(infoText); - Font font = infoLabel.getFont(); - FontData[] fontDatas = font.getFontData(); - for (int i = 0; i < fontDatas.length; i++) { - fontDatas[i].setHeight(fontDatas[i].getHeight() * 9 / 10); - } - infoFont = new Font(infoLabel.getDisplay(), fontDatas); - infoLabel.setFont(infoFont); - GridDataFactory.fillDefaults().grab(true, false).align_(DWT.FILL, DWT.BEGINNING) - .applyTo(infoLabel); + + GridDataFactory.fillDefaults().grab(true, false).align(DWT.FILL, + DWT.BEGINNING).applyTo(infoLabel); infoLabel.setForeground(parent.getDisplay().getSystemColor( DWT.COLOR_WIDGET_DARK_SHADOW)); return infoLabel; @@ -681,7 +883,8 @@ private Control createHorizontalSeparator(Composite parent) { Label separator = new Label(parent, DWT.SEPARATOR | DWT.HORIZONTAL | DWT.LINE_DOT); - GridDataFactory.fillDefaults().align_(DWT.FILL, DWT.CENTER).grab(true, false).applyTo(separator); + GridDataFactory.fillDefaults().align_(DWT.FILL, DWT.CENTER).grab(true, + false).applyTo(separator); return separator; } @@ -696,14 +899,11 @@ toolBar = new ToolBar(parent, DWT.FLAT); ToolItem viewMenuButton = new ToolItem(toolBar, DWT.PUSH, 0); - GridDataFactory.fillDefaults().align_(DWT.END, DWT.CENTER).applyTo(toolBar); - - menuImage = ImageDescriptor.createFromFile( - getImportData!("dwtx.jface.dialogs.images.popup_menu.gif")).createImage();//$NON-NLS-1$ - disabledMenuImage = ImageDescriptor.createFromFile( - getImportData!("dwtx.jface.dialogs.images.popup_menu_disabled.gif")).createImage();//$NON-NLS-1$ - viewMenuButton.setImage(menuImage); - viewMenuButton.setDisabledImage(disabledMenuImage); + GridDataFactory.fillDefaults().align_(DWT.END, DWT.CENTER).applyTo( + toolBar); + viewMenuButton.setImage(JFaceResources.getImage(POPUP_IMG_MENU)); + viewMenuButton.setDisabledImage(JFaceResources + .getImage(POPUP_IMG_MENU_DISABLED)); viewMenuButton.setToolTipText(JFaceResources .getString("PopupDialog.menuTooltip")); //$NON-NLS-1$ viewMenuButton.addSelectionListener(new class SelectionAdapter { @@ -711,14 +911,6 @@ showDialogMenu(); } }); - viewMenuButton.addDisposeListener(new class DisposeListener { - public void widgetDisposed(DisposeEvent e) { - menuImage.dispose(); - menuImage = null; - disabledMenuImage.dispose(); - disabledMenuImage = null; - } - }); // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=177183 toolBar.addMouseListener(new class MouseAdapter { public void mouseDown(MouseEvent e) { @@ -737,8 +929,13 @@ dialogMenu.add(new GroupMarker("SystemMenuStart")); //$NON-NLS-1$ dialogMenu.add(new MoveAction()); dialogMenu.add(new ResizeAction()); - if (showPersistAction) { - dialogMenu.add(new PersistBoundsAction()); + if (showPersistActions) { + if (isUsing34API) { + dialogMenu.add(new PersistLocationAction()); + dialogMenu.add(new PersistSizeAction()); + } else { + dialogMenu.add(new PersistBoundsAction()); + } } dialogMenu.add(new Separator("SystemMenuEnd")); //$NON-NLS-1$ } @@ -837,11 +1034,47 @@ * modified if the persist bounds action is shown on the menu and the user * has changed its value. Subclasses may override this method. * - * @return if the dialogs bounds will be persisted, false if it will - * not. + * @return true if the dialog's bounds will be persisted, + * false if it will not. + * + * @deprecated As of 3.4, please use {@link #getPersistLocation()} or + * {@link #getPersistSize()} to determine separately whether + * size or location should be persisted. */ protected bool getPersistBounds() { - return persistBounds; + return persistLocation && persistSize; + } + + /** + * Return a bool indicating whether this dialog will persist its + * location. This value is initially set in the dialog's constructor, but + * can be modified if the persist location action is shown on the menu and + * the user has changed its value. Subclasses may override this method. + * + * @return true if the dialog's location will be persisted, + * false if it will not. + * + * @see #getPersistSize() + * @since 3.4 + */ + protected bool getPersistLocation() { + return persistLocation; + } + + /** + * Return a bool indicating whether this dialog will persist its size. + * This value is initially set in the dialog's constructor, but can be + * modified if the persist size action is shown on the menu and the user has + * changed its value. Subclasses may override this method. + * + * @return true if the dialog's size will be persisted, + * false if it will not. + * + * @see #getPersistLocation() + * @since 3.4 + */ + protected bool getPersistSize() { + return persistSize; } /** @@ -922,7 +1155,8 @@ initializeWidgetState(); if (parentDeactivateListener !is null) { - getShell().getParent().removeListener(DWT.Deactivate, parentDeactivateListener); + getShell().getParent().removeListener(DWT.Deactivate, + parentDeactivateListener); parentDeactivateListener = null; } @@ -965,17 +1199,21 @@ shellLocation.x -= parentLocation.x; shellLocation.y -= parentLocation.y; } - if (persistBounds) { - String prefix = this.classinfo.name; - settings.put(prefix ~ DIALOG_ORIGIN_X, shellLocation.x); - settings.put(prefix ~ DIALOG_ORIGIN_Y, shellLocation.y); + String prefix = this.classinfo.name; + if (persistSize) { settings.put(prefix ~ DIALOG_WIDTH, shellSize.x); settings.put(prefix ~ DIALOG_HEIGHT, shellSize.y); } - if (showPersistAction && showDialogMenu_) { - settings.put( - this.classinfo.name ~ DIALOG_USE_PERSISTED_BOUNDS, - persistBounds); + if (persistLocation) { + settings.put(prefix ~ DIALOG_ORIGIN_X, shellLocation.x); + settings.put(prefix ~ DIALOG_ORIGIN_Y, shellLocation.y); + } + if (showPersistActions && showDialogMenu) { + settings.put(getClass().getName() + DIALOG_USE_PERSISTED_SIZE, + persistSize); + settings.put(getClass().getName() + + DIALOG_USE_PERSISTED_LOCATION, persistLocation); + } } } @@ -986,8 +1224,8 @@ * @see dwtx.jface.window.Window#getInitialSize() */ protected override Point getInitialSize() { - Point result = super.getInitialSize(); - if (persistBounds) { + Point result = getDefaultSize(); + if (persistSize) { IDialogSettings settings = getDialogSettings(); if (settings !is null) { try { @@ -1007,6 +1245,42 @@ } /** + * Return the default size to use for the shell. This default size is used + * if the dialog does not have any persisted size to restore. The default + * implementation returns the preferred size of the shell. Subclasses should + * override this method when an alternate default size is desired, rather + * than overriding {@link #getInitialSize()}. + * + * @return the initial size of the shell + * + * @see #getPersistSize() + * @since 3.4 + */ + protected Point getDefaultSize() { + return super.getInitialSize(); + } + + /** + * Returns the default location to use for the shell. This default location + * is used if the dialog does not have any persisted location to restore. + * The default implementation uses the location computed by + * {@link dwtx.jface.window.Window#getInitialLocation(Point)}. + * Subclasses should override this method when an alternate default location + * is desired, rather than overriding {@link #getInitialLocation(Point)}. + * + * @param initialSize + * the initial size of the shell, as returned by + * getInitialSize. + * @return the initial location of the shell + * + * @see #getPersistLocation() + * @since 3.4 + */ + protected Point getDefaultLocation(Point initialSize) { + return super.getInitialLocation(initialSize); + } + + /** * Adjust the bounds of the popup as necessary prior to opening the dialog. * Default is to do nothing, which honors any bounds set directly by clients * or those that have been saved in the dialog settings. Subclasses should @@ -1022,8 +1296,8 @@ * @see dwtx.jface.window.Window#getInitialLocation(dwt.graphics.Point) */ protected override Point getInitialLocation(Point initialSize) { - Point result = super.getInitialLocation(initialSize); - if (persistBounds) { + Point result = getDefaultLocation(initialSize); + if (persistLocation) { IDialogSettings settings = getDialogSettings(); if (settings !is null) { try { @@ -1056,12 +1330,66 @@ * the contents composite */ private void applyColors(Composite composite) { - applyForegroundColor(getShell().getDisplay().getSystemColor( - DWT.COLOR_INFO_FOREGROUND), composite, - getForegroundColorExclusions()); - applyBackgroundColor(getShell().getDisplay().getSystemColor( - DWT.COLOR_INFO_BACKGROUND), composite, - getBackgroundColorExclusions()); + // The getForeground() and getBackground() methods + // should not answer null, but IColorProvider clients + // are accustomed to null meaning use the default, so we guard + // against this assumption. + Color color = getForeground(); + if (color is null) + color = getDefaultForeground(); + applyForegroundColor(color, composite, getForegroundColorExclusions()); + color = getBackground(); + if (color is null) + color = getDefaultBackground(); + applyBackgroundColor(color, composite, getBackgroundColorExclusions()); + } + + /** + * Get the foreground color that should be used for this popup. Subclasses + * may override. + * + * @return the foreground color to be used. Should not be null. + * + * @since 3.4 + * + * @see #getForegroundColorExclusions() + */ + protected Color getForeground() { + return getDefaultForeground(); + } + + /** + * Get the background color that should be used for this popup. Subclasses + * may override. + * + * @return the background color to be used. Should not be null. + * + * @since 3.4 + * + * @see #getBackgroundColorExclusions() + */ + protected Color getBackground() { + return getDefaultBackground(); + } + + /** + * Return the default foreground color used for popup dialogs. + * + * @return the default foreground color. + */ + private Color getDefaultForeground() { + return getShell().getDisplay() + .getSystemColor(DWT.COLOR_INFO_FOREGROUND); + } + + /** + * Return the default background color used for popup dialogs. + * + * @return the default background color + */ + private Color getDefaultBackground() { + return getShell().getDisplay() + .getSystemColor(DWT.COLOR_INFO_BACKGROUND); } /** @@ -1073,6 +1401,25 @@ private void applyFonts(Composite composite) { Dialog.applyDialogFont(composite); + if (titleLabel !is null) { + Font font = titleLabel.getFont(); + FontData[] fontDatas = font.getFontData(); + for (int i = 0; i < fontDatas.length; i++) { + fontDatas[i].setStyle(DWT.BOLD); + } + titleFont = new Font(titleLabel.getDisplay(), fontDatas); + titleLabel.setFont(titleFont); + } + + if (infoLabel !is null) { + Font font = infoLabel.getFont(); + FontData[] fontDatas = font.getFontData(); + for (int i = 0; i < fontDatas.length; i++) { + fontDatas[i].setHeight(fontDatas[i].getHeight() * 9 / 10); + } + infoFont = new Font(infoLabel.getDisplay(), fontDatas); + infoLabel.setFont(infoFont); + } } /** @@ -1102,7 +1449,7 @@ /** * Set the specified background color for the specified control and all of - * its children. + * its children, except for those specified in the list of exclusions. * * @param color * the color to use as the background color @@ -1130,13 +1477,13 @@ * its children. Subclasses may override this method, but typically do not. * If a subclass wishes to exclude a particular control in its contents from * getting the specified foreground color, it may instead override - * PopupDialog.getForegroundColorExclusions. + * {@link #getForegroundColorExclusions()}. * * @param color - * the color to use as the background color + * the color to use as the foreground color * @param control * the control whose color is to be changed - * @see PopupDialog#getBackgroundColorExclusions() + * @see PopupDialog#getForegroundColorExclusions() */ protected void applyForegroundColor(Color color, Control control) { applyForegroundColor(color, control, getForegroundColorExclusions()); @@ -1147,7 +1494,7 @@ * its children. Subclasses may override this method, but typically do not. * If a subclass wishes to exclude a particular control in its contents from * getting the specified background color, it may instead override - * PopupDialog.getBackgroundColorExclusions. + * {@link #getBackgroundColorExclusions()} * * @param color * the color to use as the background color @@ -1161,7 +1508,7 @@ /** * Return a list of controls which should never have their foreground color - * reset. Subclasses may extend this method (should always call + * reset. Subclasses may extend this method, but should always call * super.getForegroundColorExclusions to aggregate the list. * * @@ -1184,7 +1531,7 @@ /** * Return a list of controls which should never have their background color - * reset. Subclasses may extend this method (should always call + * reset. Subclasses may extend this method, but should always call * super.getBackgroundColorExclusions to aggregate the list. * * @return the List of controls @@ -1217,19 +1564,40 @@ // If the menu item for persisting bounds is displayed, use the stored // value to determine whether any persisted bounds should be honored at // all. - if (showDialogMenu_ && showPersistAction) { + if (showDialogMenu_ && showPersistActions) { IDialogSettings settings = getDialogSettings(); if (settings !is null) { - persistBounds = settings.getBoolean(this.classinfo.name - ~ DIALOG_USE_PERSISTED_BOUNDS); + String key = this.classinfo.name ~ DIALOG_USE_PERSISTED_SIZE; + if (settings.get(key) !is null || !isUsing34API) + persistSize = settings.getBoolean(key); + key = this.classinfo.name ~ DIALOG_USE_PERSISTED_LOCATION; + if (settings.get(key) !is null || !isUsing34API) + persistLocation = settings.getBoolean(key); } } + } + private void migrateBoundsSetting() { + IDialogSettings settings = getDialogSettings(); + if (settings is null) + return; + + final String className = getClass().getName(); + + String key = className + DIALOG_USE_PERSISTED_BOUNDS; + String value = settings.get(key); + if (value is null || DIALOG_VALUE_MIGRATED_TO_34.equals(value)) + return; + + bool storeBounds = settings.getBoolean(key); + settings.put(className + DIALOG_USE_PERSISTED_LOCATION, storeBounds); + settings.put(className + DIALOG_USE_PERSISTED_SIZE, storeBounds); + settings.put(key, DIALOG_VALUE_MIGRATED_TO_34); } /** - * The dialog is being disposed. Dispose of any resources allocated. - * + * The dialog is being disposed. Dispose of any resources allocated. + * */ private void handleDispose() { if (infoFont !is null && !infoFont.isDisposed()) { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/dialogs/ProgressIndicator.d --- a/dwtx/jface/dialogs/ProgressIndicator.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/dialogs/ProgressIndicator.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,6 +7,8 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Mark Siegel - Fix for Bug 184533 + * [Progress] ProgressIndicator uses hardcoded style for ProgressBar * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -50,9 +52,27 @@ * The widgets parent */ public this(Composite parent) { + this(parent, DWT.NONE); + } + + /** + * Create a ProgressIndicator as a child under the given parent. + * + * @param parent + * The widgets parent + * @param style the DWT style constants for progress monitors created + * by the receiver. + * @since 3.4 + */ + public ProgressIndicator(Composite parent, int style) { super(parent, DWT.NULL); - determinateProgressBar = new ProgressBar(this, DWT.HORIZONTAL); - indeterminateProgressBar = new ProgressBar(this, DWT.HORIZONTAL + + // Enforce horizontal only if vertical isn't set + if ((style & DWT.VERTICAL) is 0) + style |= DWT.HORIZONTAL; + + determinateProgressBar = new ProgressBar(this, style); + indeterminateProgressBar = new ProgressBar(this, style | DWT.INDETERMINATE); layout_ = new StackLayout(); setLayout(layout_); @@ -126,4 +146,32 @@ determinateProgressBar.setSelection(value); } } + + /** + * Show the receiver as showing an error. + * @since 3.4 + */ + public void showError() { + determinateProgressBar.setState(DWT.ERROR); + indeterminateProgressBar.setState(DWT.ERROR); + } + + /** + * Show the receiver as being paused. + * @since 3.4 + */ + public void showPaused() { + determinateProgressBar.setState(DWT.PAUSED); + indeterminateProgressBar.setState(DWT.PAUSED); + } + + /** + * Reset the progress bar to it's normal style. + * @since 3.4 + */ + public void showNormal() { + determinateProgressBar.setState(DWT.NORMAL); + indeterminateProgressBar.setState(DWT.NORMAL); + + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/dialogs/ProgressMonitorDialog.d --- a/dwtx/jface/dialogs/ProgressMonitorDialog.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/dialogs/ProgressMonitorDialog.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -265,6 +265,8 @@ * @see dwtx.core.runtime.IProgressMonitorWithBlocking#clearBlocked() */ public void clearBlocked() { + if (getShell().isDisposed()) + return; locked = false; updateForClearBlocked(); } @@ -275,6 +277,8 @@ * @see dwtx.core.runtime.IProgressMonitorWithBlocking#setBlocked(dwtx.core.runtime.IStatus) */ public void setBlocked(IStatus reason) { + if (getShell().isDisposed()) + return; locked = true; updateForSetBlocked(reason); } @@ -284,8 +288,10 @@ * Clear blocked state from the receiver. */ protected void updateForClearBlocked() { + progressIndicator.showNormal(); setMessage(task, true); imageLabel.setImage(getImage()); + } /** @@ -295,8 +301,10 @@ * IStatus that gives the details */ protected void updateForSetBlocked(IStatus reason) { + progressIndicator.showPaused(); setMessage(reason.getMessage(), true); imageLabel.setImage(getImage()); + } /** @@ -310,10 +318,14 @@ public this(Shell parent) { progressMonitor = new ProgressMonitor(); super(parent); - setShellStyle(getDefaultOrientation() | DWT.BORDER | DWT.TITLE - | DWT.APPLICATION_MODAL); // no - // close - // button + // no close button on the shell style + if (isResizable()) { + setShellStyle(getDefaultOrientation() | DWT.BORDER | DWT.TITLE + | DWT.APPLICATION_MODAL | DWT.RESIZE | DWT.MAX); + } else { + setShellStyle(getDefaultOrientation() | DWT.BORDER | DWT.TITLE + | DWT.APPLICATION_MODAL); + } setBlockOnOpen(false); } @@ -678,7 +690,8 @@ } } int result = super.open(); - // update message label just in case beginTask() has been invoked already + // update message label just in case beginTask() has been invoked + // already if (task is null || task.length is 0) setMessage(DEFAULT_TASKNAME, true); else diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/dialogs/TrayDialog.d --- a/dwtx/jface/dialogs/TrayDialog.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/dialogs/TrayDialog.d Thu May 22 01:36:46 2008 +0200 @@ -254,7 +254,7 @@ GridLayout grid = cast(GridLayout)layout; return !grid.makeColumnsEqualWidth && (grid.horizontalSpacing is 0) && (grid.marginWidth is 0) && (grid.marginHeight is 0) && - (grid.horizontalSpacing is 0) && (grid.numColumns is 5); + (grid.numColumns is 5); } return false; } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/fieldassist/ComboContentAdapter.d --- a/dwtx/jface/fieldassist/ComboContentAdapter.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/fieldassist/ComboContentAdapter.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2006 IBM Corporation and others. + * Copyright (c) 2005, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -12,6 +12,7 @@ *******************************************************************************/ module dwtx.jface.fieldassist.ComboContentAdapter; +import dwt.DWT; import dwtx.jface.fieldassist.IControlContentAdapter; import dwt.graphics.GC; @@ -30,7 +31,18 @@ * * @since 3.2 */ -public class ComboContentAdapter : IControlContentAdapter { +public class ComboContentAdapter : IControlContentAdapter, + IControlContentAdapter2 { + + /* + * Set to true if we should compute the text + * vertical bounds rather than just use the field size. + * Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=164748 + * The corresponding DWT bug is + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=44072 + */ + private static final bool COMPUTE_TEXT_USING_CLIENTAREA = !"carbon".equals(DWT.getPlatform()); //$NON-NLS-1$ + /* * (non-Javadoc) @@ -92,6 +104,8 @@ * @see dwtx.jface.fieldassist.IControlContentAdapter#getInsertionBounds(dwt.widgets.Control) */ public Rectangle getInsertionBounds(Control control) { + // This doesn't take horizontal scrolling into affect. + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=204599 Combo combo = cast(Combo) control; int position = combo.getSelection().y; String contents = combo.getText(); @@ -100,8 +114,11 @@ Point extent = gc.textExtent(contents.substring(0, Math.min(position, contents.length))); gc.dispose(); - return new Rectangle(combo.getClientArea().x + extent.x, combo + if (COMPUTE_TEXT_USING_CLIENTAREA) { + return new Rectangle(combo.getClientArea().x + extent.x, combo .getClientArea().y, 1, combo.getClientArea().height); + } + return new Rectangle(extent.x, 0, 1, combo.getSize().y); } /* @@ -114,4 +131,27 @@ (cast(Combo) control).setSelection(new Point(index, index)); } + /* + * (non-Javadoc) + * + * @see dwtx.jface.fieldassist.IControlContentAdapter2#getSelection(dwt.widgets.Control) + * + * @since 3.4 + */ + public Point getSelection(Control control) { + return ((Combo) control).getSelection(); + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.fieldassist.IControlContentAdapter2#setSelection(dwt.widgets.Control, + * dwt.graphics.Point) + * + * @since 3.4 + */ + public void setSelection(Control control, Point range) { + ((Combo) control).setSelection(range); + } + } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/fieldassist/ContentProposalAdapter.d --- a/dwtx/jface/fieldassist/ContentProposalAdapter.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/fieldassist/ContentProposalAdapter.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 IBM Corporation and others. + * Copyright (c) 2005, 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 @@ -27,6 +27,7 @@ import dwt.events.FocusEvent; import dwt.events.SelectionEvent; import dwt.events.SelectionListener; +import dwt.graphics.Color; import dwt.graphics.Image; import dwt.graphics.Point; import dwt.graphics.Rectangle; @@ -44,6 +45,8 @@ import dwtx.core.runtime.ListenerList; import dwtx.jface.bindings.keys.KeyStroke; import dwtx.jface.dialogs.PopupDialog; +import dwtx.jface.preference.JFacePreferences; +import dwtx.jface.resource.JFaceResources; import dwtx.jface.viewers.ILabelProvider; import dwt.dwthelper.utils; @@ -104,10 +107,7 @@ this(Event e__){ e_=e__; } public void run() { if (isValid()) { - if (scrollbarClicked - || hasFocus() - || (infoPopup !is null && infoPopup - .hasFocus())) { + if (scrollbarClicked || hasFocus()) { return; } // Workaround a problem on X and Mac, whereby at @@ -318,10 +318,9 @@ String contents = getControlContentAdapter() .getControlContents(getControl()); // If there are no contents, changes in cursor - // position - // have no effect. Note also that we do not affect - // the filter - // text on ARROW_LEFT as we would with BS. + // position have no effect. Note also that we do + // not affect the filter text on ARROW_LEFT as + // we would with BS. if (contents.length > 0) { asyncRecomputeProposals(filterText); } @@ -512,6 +511,24 @@ } getShell().setBounds(proposedBounds); } + + /* + * (non-Javadoc) + * @see dwtx.jface.dialogs.PopupDialog#getForeground() + */ + protected Color getForeground() { + return control.getDisplay(). + getSystemColor(DWT.COLOR_INFO_FOREGROUND); + } + + /* + * (non-Javadoc) + * @see dwtx.jface.dialogs.PopupDialog#getBackground() + */ + protected Color getBackground() { + return control.getDisplay(). + getSystemColor(DWT.COLOR_INFO_BACKGROUND); + } /* * Set the text contents of the popup. @@ -598,25 +615,21 @@ } /* - * Overridden to force change of colors. See - * https://bugs.eclipse.org/bugs/show_bug.cgi?id=136244 (non-Javadoc) - * - * @see dwtx.jface.dialogs.PopupDialog#createContents(dwt.widgets.Composite) + * (non-Javadoc) + * @see dwtx.jface.dialogs.PopupDialog#getForeground() */ - protected override Control createContents(Composite parent) { - Control contents = super.createContents(parent); - changeDefaultColors(parent); - return contents; + protected Color getForeground() { + return JFaceResources.getColorRegistry().get( + JFacePreferences.CONTENT_ASSIST_FOREGROUND_COLOR); } - + /* - * Set the colors of the popup. The contents have already been created. + * (non-Javadoc) + * @see dwtx.jface.dialogs.PopupDialog#getBackground() */ - private void changeDefaultColors(Control control) { - applyForegroundColor(getShell().getDisplay().getSystemColor( - DWT.COLOR_LIST_FOREGROUND), control); - applyBackgroundColor(getShell().getDisplay().getSystemColor( - DWT.COLOR_LIST_BACKGROUND), control); + protected Color getBackground() { + return JFaceResources.getColorRegistry().get( + JFacePreferences.CONTENT_ASSIST_BACKGROUND_COLOR); } /* @@ -821,14 +834,20 @@ } /* - * Return whether the receiver has focus. + * Return whether the receiver has focus. Since 3.4, this includes a + * check for whether the info popup has focus. */ private bool hasFocus() { if (!isValid()) { return false; } - return getShell().isFocusControl() - || proposalTable.isFocusControl(); + if (getShell().isFocusControl() || proposalTable.isFocusControl()) { + return true; + } + if (infoPopup !is null && infoPopup.hasFocus()) { + return true; + } + return false; } /* @@ -968,10 +987,9 @@ * Accept the current proposal. */ private void acceptCurrentProposal() { - // Close before accepting the proposal. - // This is important so that the cursor position can be - // properly restored at acceptance, which does not work without - // focus on some controls. + // Close before accepting the proposal. This is important + // so that the cursor position can be properly restored at + // acceptance, which does not work without focus on some controls. // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=127108 IContentProposal proposal = getSelectedProposal(); close(); @@ -1090,6 +1108,11 @@ /** * Indicates that a cumulative filter applies as keys are typed in the * popup. That is, each character typed will be added to the filter. + * + * @deprecated As of 3.4, filtering that is sensitive to changes in the + * control content should be performed by the supplied + * {@link IContentProposalProvider}, such as that performed by + * {@link SimpleContentProposalProvider} */ public static const int FILTER_CUMULATIVE = 3; @@ -1230,10 +1253,16 @@ private int insertionPos = -1; /* - * A flag that indicates that a pending modify event was caused by - * the adapter rather than the user. + * The remembered selection range. Not all controls will restore the + * selection position if the proposal popup gets focus, so we need to + * remember it. */ - private bool modifyingControlContent = false; + private Point selectionRange = new Point(-1, -1); + + /* + * A flag that indicates that we are watching modify events + */ + private bool watchModify = false; /** * Construct a content proposal adapter that can assist the user with @@ -1453,12 +1482,13 @@ * @return a constant indicating how keystrokes in the proposal popup affect * filtering of the proposals shown. FILTER_NONE * specifies that no filtering will occur in the content proposal - * list as keys are typed. FILTER_CUMULATIVE - * specifies that the content of the popup will be filtered by a - * string containing all the characters typed since the popup has - * been open. FILTER_CHARACTER specifies the content - * of the popup will be filtered by the most recently typed - * character. The default is FILTER_NONE. + * list as keys are typed. FILTER_CHARACTER specifies + * the content of the popup will be filtered by the most recently + * typed character. FILTER_CUMULATIVE is deprecated + * and no longer recommended. It specifies that the content of the + * popup will be filtered by a string containing all the characters + * typed since the popup has been open. The default is + * FILTER_NONE. */ public int getFilterStyle() { return filterStyle; @@ -1479,12 +1509,12 @@ * popup affect filtering of the proposals shown. * FILTER_NONE specifies that no automatic * filtering of the content proposal list will occur as keys are - * typed in the popup. FILTER_CUMULATIVE specifies - * that the content of the popup will be filtered by a string - * containing all the characters typed since the popup has been - * open. FILTER_CHARACTER specifies that the - * content of the popup will be filtered by the most recently - * typed character. + * typed in the popup. FILTER_CHARACTER specifies + * that the content of the popup will be filtered by the most + * recently typed character. FILTER_CUMULATIVE is + * deprecated and no longer recommended. It specifies that the + * content of the popup will be filtered by a string containing + * all the characters typed since the popup has been open. */ public void setFilterStyle(int filterStyle) { this.filterStyle = filterStyle; @@ -1719,45 +1749,52 @@ } } /* - * The triggering keystroke was not invoked. Check for - * autoactivation characters. + * The triggering keystroke was not invoked. If a character + * was typed, compare it to the autoactivation characters. */ if (e.character !is 0) { - // Auto-activation characters were specified. Check - // them. if (autoActivateString !is null) { if (autoActivateString.indexOf(e.character) >= 0) { - e.doit = propagateKeys; autoActivate(); + } else { + // No autoactivation occurred, so record the key + // down as a means to interrupt any + // autoactivation + // that is pending due to autoactivation delay. + receivedKeyDown = true; } } else { - // No autoactivation occurred, so record the key - // down - // as a means to interrupt any autoactivation that - // is - // pending. - receivedKeyDown = true; + // The autoactivate string is null. If the trigger + // is also null, we want to act on any modification + // to the content. Set a flag so we'll catch this + // in the modify event. + if (triggerKeyStroke is null) { + watchModify = true; + } } } break; // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=147377 // Given that we will close the popup when there are no valid - // proposals, we must reopen it when there are. Normally, the - // keydown event handling will catch all the cases where it - // should reopen. But when autoactivation should occur on all - // content changes, we check it here after keys have been - // processed. + // proposals, we must reopen it when there are. This means + // we should check modifications in those cases. // See also https://bugs.eclipse.org/bugs/show_bug.cgi?id=183650 - // We should not autoactivate if the content change was caused - // by the popup itself. + // The watchModify flag ensures that we don't autoactivate if + // the content change was caused by something other than typing. case DWT.Modify: if (triggerKeyStroke is null && autoActivateString is null - && !modifyingControlContent) { + && watchModify) { if (DEBUG) { dump("Modify event triggers autoactivation", e); //$NON-NLS-1$ } - autoActivate(); + watchModify = false; + // We don't autoactivate if the net change is no + // content. In other words, backspacing to empty + // should never cause a popup to open. + if (!isControlContentEmpty()) { + autoActivate(); + } } break; default: @@ -1892,13 +1929,10 @@ */ private void setControlContent(String text, int cursorPosition) { if (isValid()) { - // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=183650 - modifyingControlContent = true; - + // should already be false, but just in case. + watchModify = false; controlContentAdapter.setControlContents(control, text, cursorPosition); - - modifyingControlContent = false; } } @@ -1908,18 +1942,22 @@ */ private void insertControlContent(String text, int cursorPosition) { if (isValid()) { - // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=183650 - modifyingControlContent = true; + // should already be false, but just in case. + watchModify = false; // Not all controls preserve their selection index when they lose // focus, so we must set it explicitly here to what it was before // the popup opened. // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=127108 - if (insertionPos !is -1) { + // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=139063 + if (controlContentAdapter instanceof IControlContentAdapter2 + && selectionRange.x !is -1) { + ((IControlContentAdapter2) controlContentAdapter).setSelection( + control, selectionRange); + } else if (insertionPos !is -1) { controlContentAdapter.setCursorPosition(control, insertionPos); } controlContentAdapter.insertControlContents(control, text, cursorPosition); - modifyingControlContent = false; } } @@ -1936,8 +1974,13 @@ */ private void recordCursorPosition() { if (isValid()) { - insertionPos = getControlContentAdapter() - .getCursorPosition(control); + IControlContentAdapter adapter = getControlContentAdapter(); + insertionPos = adapter.getCursorPosition(control); + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=139063 + if (adapter instanceof IControlContentAdapter2) { + selectionRange = ((IControlContentAdapter2) adapter) + .getSelection(control); + } } } @@ -2048,4 +2091,24 @@ .proposalPopupClosed(this); } } + + /** + * Returns whether the content proposal popup has the focus. This includes + * both the primary popup and any secondary info popup that may have focus. + * + * @return true if the proposal popup or its secondary info + * popup has the focus + * @since 3.4 + */ + public bool hasProposalPopupFocus() { + return popup !is null && popup.hasFocus(); + } + + /* + * Return whether the control content is empty + */ + private bool isControlContentEmpty() { + return getControlContentAdapter().getControlContents(getControl()) + .length() is 0; + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/fieldassist/ControlDecoration.d --- a/dwtx/jface/fieldassist/ControlDecoration.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/fieldassist/ControlDecoration.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 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 @@ -121,13 +121,13 @@ private bool visible = true; /** - * bool indicating whether the decoration should only be shown when the + * Boolean indicating whether the decoration should only be shown when the * control has focus */ private bool showOnlyOnFocus = false; /** - * bool indicating whether the decoration should show its description + * Boolean indicating whether the decoration should show its description * text in a hover when the user hovers over the decoration. */ private bool showHover = true; @@ -249,7 +249,7 @@ Region region; /** - * bool indicating whether the last computed polygon location had an + * Boolean indicating whether the last computed polygon location had an * arrow on left. (true if left, false if right). */ bool arrowOnLeft = true; @@ -260,7 +260,7 @@ this(Shell parent) { Display display = parent.getDisplay(); hoverShell = new Shell(parent, DWT.NO_TRIM | DWT.ON_TOP - | DWT.NO_FOCUS); + | DWT.NO_FOCUS | DWT.TOOL); hoverShell.setBackground(display .getSystemColor(DWT.COLOR_INFO_BACKGROUND)); hoverShell.setForeground(display @@ -824,7 +824,8 @@ * an info hover over the field's control whenever the mouse hovers over the * decoration. This method can be used to show a decoration's description * text at other times (such as when the control receives focus), or to show - * other text associated with the field. + * other text associated with the field. The hover will not be shown if the + * decoration is hidden. * * @param text * the text to be shown in the info hover, or null @@ -870,12 +871,13 @@ } /** - * Hide the control decoration. This message has no effect if the decoration - * is already hidden. + * Hide the control decoration and any associated hovers. This message has + * no effect if the decoration is already hidden. */ public void hide() { if (visible) { visible = false; + hideHover(); update(); } } @@ -919,7 +921,8 @@ * decoration. * * @param image - * the image to be shown adjacent to the control + * the image to be shown adjacent to the control. Should never be + * null. */ public void setImage(Image image) { this.image = image; @@ -1045,6 +1048,11 @@ if (!showHover) { return; } + + // If we are not visible, don't show the hover. + if (!visible) { + return; + } // If there is no text, don't do anything. if (text is null) { hideHover(); diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/fieldassist/DecoratedField.d --- a/dwtx/jface/fieldassist/DecoratedField.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/fieldassist/DecoratedField.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 IBM Corporation and others. + * Copyright (c) 2005, 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 @@ -202,7 +202,7 @@ Region region; /** - * bool indicating whether the last computed polygon location had an + * Boolean indicating whether the last computed polygon location had an * arrow on left. (true if left, false if right). */ bool arrowOnLeft = true; @@ -213,7 +213,7 @@ this(Shell parent) { final Display display = parent.getDisplay(); hoverShell = new Shell(parent, DWT.NO_TRIM | DWT.ON_TOP - | DWT.NO_FOCUS); + | DWT.NO_FOCUS | DWT.TOOL); hoverShell.setBackground(display .getSystemColor(DWT.COLOR_INFO_BACKGROUND)); hoverShell.setForeground(display diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/fieldassist/IControlContentAdapter2.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/fieldassist/IControlContentAdapter2.d Thu May 22 01:36:46 2008 +0200 @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Port to the D programming language: + * Frank Benoit + *******************************************************************************/ +module dwtx.jface.fieldassist.IControlContentAdapter2; + +import dwt.graphics.Point; +import dwt.widgets.Control; + +/** + * This interface is used by a {@link ContentProposalAdapter} in order to + * retrieve and set the selection range in a control. + * + * @since 3.4 + */ +public interface IControlContentAdapter2 { + /** + * Get the current selection range in the control. The x coordinate of the + * returned point is the position of the first selected character and the y + * coordinate of the returned point is the position of the last selected + * character. The positions are specified as a zero-based index into the + * string. Valid ranges are from 0 to N, where N is the size of the contents + * string. A value of N indicates that the last character is in the + * selection. + * + * @param control + * the control whose position is to be retrieved. + * @return a point representing the selection start and end + */ + public Point getSelection(Control control); + + /** + * Set the current selection range in the control. The x coordinate of the + * provided point is the position of the first selected character and the y + * coordinate of the point is the position of the last selected character. + * The positions are specified as a zero-based index into the string. Valid + * ranges are from 0 to N, where N is the size of the contents string. A + * value of N indicates that the last character is in the selection. If the + * x and y coordinates are the same, then there is no selection. + * + * @param control + * the control whose position is to be retrieved. + * @param range + * a point representing the selection start and end + */ + public void setSelection(Control control, Point range); + +} diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/fieldassist/SimpleContentProposalProvider.d --- a/dwtx/jface/fieldassist/SimpleContentProposalProvider.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/fieldassist/SimpleContentProposalProvider.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2006 IBM Corporation and others. + * Copyright (c) 2005, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Amir Kouchekinia - bug 200762 * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -41,7 +42,7 @@ private IContentProposal[] contentProposals; /* - * bool that tracks whether filtering is used. + * Boolean that tracks whether filtering is used. */ private bool filterProposals = false; @@ -60,7 +61,7 @@ /** * Return an array of Objects representing the valid content proposals for a - * field. Ignore the current contents of the field. + * field. * * @param contents * the current contents of the field (only consulted if filtering @@ -74,7 +75,7 @@ if (filterProposals) { auto list = new ArraySeq!(IContentProposal); for (int i = 0; i < proposals.length; i++) { - if (proposals[i].length > contents.length + if (proposals[i].length >= contents.length && proposals[i].substring(0, contents.length) .equalsIgnoreCase(contents)) { list.append(makeContentProposal(proposals[i])); diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/fieldassist/TextContentAdapter.d --- a/dwtx/jface/fieldassist/TextContentAdapter.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/fieldassist/TextContentAdapter.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2006 IBM Corporation and others. + * Copyright (c) 2005, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -28,7 +28,8 @@ * * @since 3.2 */ -public class TextContentAdapter : IControlContentAdapter { +public class TextContentAdapter : IControlContentAdapter, + IControlContentAdapter2 { /* * (non-Javadoc) @@ -86,8 +87,10 @@ public Rectangle getInsertionBounds(Control control) { Text text = cast(Text) control; Point caretOrigin = text.getCaretLocation(); - return new Rectangle(caretOrigin.x, caretOrigin.y, 1, text - .getLineHeight()); + // We fudge the y pixels due to problems with getCaretLocation + // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=52520 + return new Rectangle(caretOrigin.x + text.getClientArea().x, + caretOrigin.y + text.getClientArea().y + 3, 1, text.getLineHeight()); } /* @@ -99,4 +102,27 @@ public void setCursorPosition(Control control, int position) { (cast(Text) control).setSelection(new Point(position, position)); } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.fieldassist.IControlContentAdapter2#getSelection(dwt.widgets.Control) + * + * @since 3.4 + */ + public Point getSelection(Control control) { + return ((Text) control).getSelection(); + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.fieldassist.IControlContentAdapter2#setSelection(dwt.widgets.Control, + * dwt.graphics.Point) + * + * @since 3.4 + */ + public void setSelection(Control control, Point range) { + ((Text) control).setSelection(range); + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/internal/ConfigureColumnsDialog.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/internal/ConfigureColumnsDialog.d Thu May 22 01:36:46 2008 +0200 @@ -0,0 +1,400 @@ +/******************************************************************************* + * Copyright (c) 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 + * Port to the D programming language: + * Frank Benoit + ******************************************************************************/ + +module dwtx.jface.internal.ConfigureColumnsDialog; + + +import dwt.DWT; +import dwt.graphics.Image; +import dwt.widgets.Button; +import dwt.widgets.Composite; +import dwt.widgets.Control; +import dwt.widgets.Event; +import dwt.widgets.Item; +import dwt.widgets.Label; +import dwt.widgets.Listener; +import dwt.widgets.Table; +import dwt.widgets.TableColumn; +import dwt.widgets.TableItem; +import dwt.widgets.Text; +import dwt.widgets.Tree; +import dwt.widgets.TreeColumn; +import dwtx.jface.dialogs.Dialog; +import dwtx.jface.layout.GridDataFactory; +import dwtx.jface.layout.GridLayoutFactory; +import dwtx.jface.resource.JFaceResources; +import dwtx.jface.window.IShellProvider; + +/** + * NON-API - This class is internal and will be moved to another package in 3.5. + * + */ +public class ConfigureColumnsDialog extends Dialog { + + private Control targetControl; + private ColumnObject[] columnObjects; + private Table table; + private Button upButton; + private Button downButton; + private Text text; + private bool moveableColumnsFound; + + class ColumnObject { + Item column; + int index; + String name; + Image image; + bool visible; + int width; + bool moveable; + bool resizable; + + ColumnObject(Item column, int index, String text, Image image, + int width, bool moveable, bool resizable, bool visible) { + this.column = column; + this.index = index; + this.name = text; + this.image = image; + this.width = width; + this.moveable = moveable; + this.resizable = resizable; + this.visible = visible; + } + } + + /** + * NON-API - This class is internal and will be moved to another package in + * 3.5. Creates a new dialog for configuring columns of the given column + * viewer. The column viewer must have an underlying {@link Tree} or {@link + * Table}, other controls are not supported. + * + * @param shellProvider + * @param table + */ + public ConfigureColumnsDialog(IShellProvider shellProvider, Table table) { + this(shellProvider, (Control) table); + } + + /** + * NON-API - This class is internal and will be moved to another package in + * 3.5. Creates a new dialog for configuring columns of the given column + * viewer. The column viewer must have an underlying {@link Tree} or {@link + * Table}, other controls are not supported. + * + * @param shellProvider + * @param tree + */ + public ConfigureColumnsDialog(IShellProvider shellProvider, Tree tree) { + this(shellProvider, (Control) tree); + } + + /** + * @param shellProvider + * @param control + */ + private ConfigureColumnsDialog(IShellProvider shellProvider, Control control) { + super(shellProvider); + this.targetControl = control; + this.moveableColumnsFound = createColumnObjects(); + } + + protected bool isResizable() { + return true; + } + + public void create() { + super.create(); + getShell().setText( + JFaceResources.getString("ConfigureColumnsDialog_Title")); //$NON-NLS-1$ + } + + protected void initializeBounds() { + super.initializeBounds(); + table.setSelection(0); + handleSelectionChanged(0); + } + + /** + * Returns true if any of the columns is moveable (can be reordered). + */ + private bool createColumnObjects() { + bool result = true; + Item[] columns = getViewerColumns(); + ColumnObject[] cObjects = new ColumnObject[columns.length]; + for (int i = 0; i < columns.length; i++) { + Item c = columns[i]; + bool moveable = getMoveable(c); + result = result && moveable; + cObjects[i] = new ColumnObject(c, i, getColumnName(c), + getColumnImage(c), getColumnWidth(c), moveable, + getResizable(c), true); + } + int[] columnOrder = getColumnOrder(); + columnObjects = new ColumnObject[columns.length]; + for (int i = 0; i < columnOrder.length; i++) { + columnObjects[i] = cObjects[columnOrder[i]]; + } + return result; + } + + /** + * @param c + * @return + */ + private Image getColumnImage(Item item) { + if (item instanceof TableColumn) { + return ((TableColumn) item).getImage(); + } else if (item instanceof TreeColumn) { + return ((TreeColumn) item).getImage(); + } + return null; + } + + /** + * @return + */ + private int[] getColumnOrder() { + if (targetControl instanceof Table) { + return ((Table) targetControl).getColumnOrder(); + } else if (targetControl instanceof Tree) { + return ((Tree) targetControl).getColumnOrder(); + } + return new int[0]; + } + + /** + * @param c + * @return + */ + private bool getMoveable(Item item) { + if (item instanceof TableColumn) { + return ((TableColumn) item).getMoveable(); + } else if (item instanceof TreeColumn) { + return ((TreeColumn) item).getMoveable(); + } + return false; + } + + /** + * @param c + * @return + */ + private bool getResizable(Item item) { + if (item instanceof TableColumn) { + return ((TableColumn) item).getResizable(); + } else if (item instanceof TreeColumn) { + return ((TreeColumn) item).getResizable(); + } + return false; + } + + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + + table = new Table(composite, DWT.BORDER | DWT.SINGLE | DWT.V_SCROLL + | DWT.H_SCROLL | DWT.FULL_SELECTION /* + * | DWT.CHECK + */); + for (int i = 0; i < columnObjects.length; i++) { + TableItem tableItem = new TableItem(table, DWT.NONE); + tableItem.setText(columnObjects[i].name); + tableItem.setImage(columnObjects[i].image); + tableItem.setData(columnObjects[i]); + } + + GridDataFactory.defaultsFor(table) + .span(1, moveableColumnsFound ? 3 : 1).applyTo(table); + + if (moveableColumnsFound) { + upButton = new Button(composite, DWT.PUSH); + upButton.setText(JFaceResources + .getString("ConfigureColumnsDialog_up")); //$NON-NLS-1$ + upButton.addListener(DWT.Selection, new Listener() { + public void handleEvent(Event event) { + handleMove(table, true); + } + }); + setButtonLayoutData(upButton); + downButton = new Button(composite, DWT.PUSH); + downButton.setText(JFaceResources + .getString("ConfigureColumnsDialog_down")); //$NON-NLS-1$ + downButton.addListener(DWT.Selection, new Listener() { + public void handleEvent(Event event) { + handleMove(table, false); + } + }); + setButtonLayoutData(downButton); + + // filler label + createLabel(composite, ""); //$NON-NLS-1$ + } + + Composite widthComposite = new Composite(composite, DWT.NONE); + createLabel(widthComposite, JFaceResources + .getString("ConfigureColumnsDialog_WidthOfSelectedColumn")); //$NON-NLS-1$ + + text = new Text(widthComposite, DWT.SINGLE | DWT.BORDER); + // see #initializeBounds + text.setText(Integer.toString(1000)); + + GridLayoutFactory.fillDefaults().numColumns(2).applyTo(widthComposite); + + int numColumns = moveableColumnsFound ? 2 : 1; + + GridDataFactory.defaultsFor(widthComposite).grab(false, false).span( + numColumns, 1).applyTo(widthComposite); + + GridLayoutFactory.swtDefaults().numColumns(numColumns).applyTo( + composite); + + table.addListener(DWT.Selection, new Listener() { + public void handleEvent(Event event) { + handleSelectionChanged(table.indexOf((TableItem) event.item)); + } + }); + text.addListener(DWT.Modify, new Listener() { + public void handleEvent(Event event) { + ColumnObject columnObject = columnObjects[table + .getSelectionIndex()]; + if (!columnObject.resizable) { + return; + } + try { + int width = Integer.parseInt(text.getText()); + columnObject.width = width; + } catch (NumberFormatException ex) { + // ignore for now + } + } + }); + + return composite; + } + + /** + * @param table + * @param up + */ + protected void handleMove(Table table, bool up) { + int index = table.getSelectionIndex(); + int newIndex = index + (up ? -1 : 1); + if (index < 0 || index >= table.getItemCount()) { + return; + } + ColumnObject columnObject = columnObjects[index]; + columnObjects[index] = columnObjects[newIndex]; + columnObjects[newIndex] = columnObject; + table.getItem(index).dispose(); + TableItem newItem = new TableItem(table, DWT.NONE, newIndex); + newItem.setText(columnObject.name); + newItem.setImage(columnObject.image); + newItem.setData(columnObject); + table.setSelection(newIndex); + handleSelectionChanged(newIndex); + } + + private void createLabel(final Composite composite, String string) { + Label label = new Label(composite, DWT.NONE); + label.setText(string); + } + + /** + * @param item + * @return + */ + private String getColumnName(Item item) { + String result = ""; //$NON-NLS-1$ + if (item instanceof TableColumn) { + result = ((TableColumn) item).getText(); + if (result.trim().equals("")) { //$NON-NLS-1$ + result = ((TableColumn) item).getToolTipText(); + } + } else if (item instanceof TreeColumn) { + result = ((TreeColumn) item).getText(); + if (result.trim().equals("")) { //$NON-NLS-1$ + result = ((TreeColumn) item).getToolTipText(); + } + } + return result; + } + + /** + * @param item + * @return + */ + private int getColumnWidth(Item item) { + if (item instanceof TableColumn) { + return ((TableColumn) item).getWidth(); + } else if (item instanceof TreeColumn) { + return ((TreeColumn) item).getWidth(); + } + return 0; + } + + /** + * @return + */ + private Item[] getViewerColumns() { + if (targetControl instanceof Table) { + return ((Table) targetControl).getColumns(); + } else if (targetControl instanceof Tree) { + return ((Tree) targetControl).getColumns(); + } + return new Item[0]; + } + + private void handleSelectionChanged(int index) { + ColumnObject c = columnObjects[index]; + text.setText(Integer.toString(c.width)); + text.setEnabled(c.resizable); + if (moveableColumnsFound) { + upButton.setEnabled(c.moveable && index > 0); + downButton.setEnabled(c.moveable + && index + 1 < table.getItemCount()); + } + } + + protected void okPressed() { + int[] columnOrder = new int[columnObjects.length]; + for (int i = 0; i < columnObjects.length; i++) { + ColumnObject columnObject = columnObjects[i]; + columnOrder[i] = columnObject.index; + setColumnWidth(columnObject.column, columnObject.width); + } + setColumnOrder(columnOrder); + super.okPressed(); + } + + /** + * @param column + * @param width + */ + private void setColumnWidth(Item item, int width) { + if (item instanceof TableColumn) { + ((TableColumn) item).setWidth(width); + } else if (item instanceof TreeColumn) { + ((TreeColumn) item).setWidth(width); + } + } + + /** + * @param columnOrder + */ + private void setColumnOrder(int[] order) { + if (targetControl instanceof Table) { + ((Table) targetControl).setColumnOrder(order); + } else if (targetControl instanceof Tree) { + ((Tree) targetControl).setColumnOrder(order); + } + } +} diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/layout/AbstractColumnLayout.d --- a/dwtx/jface/layout/AbstractColumnLayout.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/layout/AbstractColumnLayout.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 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 @@ -8,14 +8,14 @@ * Contributors: * IBM Corporation - initial API and implementation (original file dwtx.ui.texteditor.templates.ColumnLayout) * Tom Schindl - refactored to be widget independent (bug 171824) - * - fix for bug 178280, 184342, 184045 + * - fix for bug 178280, 184342, 184045, 208014, 214532 + * Micah Hainline - fix in bug: 208335 * Port to the D programming language: * Frank Benoit *******************************************************************************/ module dwtx.jface.layout.AbstractColumnLayout; - import dwt.DWT; import dwt.graphics.Point; import dwt.graphics.Rectangle; @@ -39,21 +39,24 @@ * in a consistent way even during a resize unlike a {@link TableLayout} which * only sets initial sizes. * - *

You can only add the layout to a container whose - * only child is the table/tree control you want the layouts applied to. + *

+ * You can only add the layout to a container whose only child is the + * table/tree control you want the layouts applied to. *

* - * @since 3.3 + * @since 3.4 */ -abstract class AbstractColumnLayout : Layout { - /** - * The number of extra pixels taken as horizontal trim by the table column. - * To ensure there are N pixels available for the content of the column, - * assign N+COLUMN_TRIM for the column width. - * - * @since 3.1 - */ +public abstract class AbstractColumnLayout : Layout { private static int COLUMN_TRIM; + static { + if ("win32".equals(DWT.getPlatform())) { //$NON-NLS-1$ + COLUMN_TRIM = 4; + } else if ("carbon".equals(DWT.getPlatform())) { //$NON-NLS-1$ + COLUMN_TRIM = 24; + } else { + COLUMN_TRIM = 3; + } + } static const bool IS_GTK; @@ -96,7 +99,7 @@ */ public void setColumnData(Widget column, ColumnLayoutData data) { - if( column.getData(LAYOUT_DATA) is null ) { + if (column.getData(LAYOUT_DATA) is null) { column.addListener(DWT.Resize, resizeListener); } @@ -122,11 +125,11 @@ int width = 0; int size = getColumnCount(scrollable); for (int i = 0; i < size; ++i) { - ColumnLayoutData layoutData = getLayoutData(scrollable,i); + ColumnLayoutData layoutData = getLayoutData(scrollable, i); if ( auto col = cast(ColumnPixelData)layoutData) { width += col.width; if (col.addTrim) { - width += COLUMN_TRIM; + width += getColumnTrim(); } } else if ( auto col = cast(ColumnWeightData)layoutData ) { width += col.minimumWidth; @@ -151,70 +154,62 @@ */ private void layoutTableTree(Scrollable scrollable, int width, Rectangle area, bool increase) { - int size = getColumnCount(scrollable); - int[] widths = new int[size]; + int numberOfColumns = getColumnCount(scrollable); + int[] widths = new int[numberOfColumns]; - int[] weightIteration = new int[size]; + int[] weightColumnIndices = new int[numberOfColumns]; int numberOfWeightColumns = 0; int fixedWidth = 0; - int minWeightWidth = 0; int totalWeight = 0; // First calc space occupied by fixed columns - for (int i = 0; i < size; i++) { - ColumnLayoutData col = getLayoutData(scrollable,i); + for (int i = 0; i < numberOfColumns; i++) { + ColumnLayoutData col = getLayoutData(scrollable, i); if ( auto cpd = cast(ColumnPixelData)col ) { int pixels = cpd.width; if (cpd.addTrim) { - pixels += COLUMN_TRIM; + pixels += getColumnTrim(); } widths[i] = pixels; fixedWidth += pixels; } else if ( auto cw = cast(ColumnWeightData) col ) { - weightIteration[numberOfWeightColumns] = i; + weightColumnIndices[numberOfWeightColumns] = i; numberOfWeightColumns++; totalWeight += cw.weight; - minWeightWidth += cw.minimumWidth; - widths[i] = cw.minimumWidth; } else { Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$ } } - // Do we have columns that have a weight? - int restIncludingMinWidths = width - fixedWidth; - int rest = restIncludingMinWidths - minWeightWidth; - if (numberOfWeightColumns > 0 && rest > 0) { - - // Modify the weights to reflect what each column already - // has due to its minimum. Otherwise, columns with low - // minimums get discriminated. - int totalWantedPixels = 0; - int[] wantedPixels = new int[numberOfWeightColumns]; + bool recalculate; + do { + recalculate = false; for (int i = 0; i < numberOfWeightColumns; i++) { - ColumnWeightData cw = cast(ColumnWeightData) getLayoutData(scrollable,weightIteration[i]); - wantedPixels[i] = totalWeight is 0 ? 0 : cw.weight - * restIncludingMinWidths / totalWeight; - totalWantedPixels += wantedPixels[i]; + int colIndex = weightColumnIndices[i]; + ColumnWeightData cw = (ColumnWeightData) getLayoutData( + scrollable, colIndex); + final int minWidth = cw.minimumWidth; + final int allowedWidth = (width - fixedWidth) * cw.weight + / totalWeight; + if (allowedWidth < minWidth) { + /* + * if the width assigned by weight is less than the minimum, + * then treat this column as fixed, remove it from weight + * calculations, and recalculate other weights. + */ + numberOfWeightColumns--; + totalWeight -= cw.weight; + fixedWidth += minWidth; + widths[colIndex] = minWidth; + System.arraycopy(weightColumnIndices, i + 1, + weightColumnIndices, i, numberOfWeightColumns - i); + recalculate = true; + break; + } + widths[colIndex] = allowedWidth; } - - // Now distribute the rest to the columns with weight. - int totalDistributed = 0; - for (int i = 0; i < numberOfWeightColumns; ++i) { - int pixels = totalWantedPixels is 0 ? 0 : wantedPixels[i] - * rest / totalWantedPixels; - totalDistributed += pixels; - widths[weightIteration[i]] += pixels; - } - - // Distribute any remaining pixels to columns with weight. - int diff = rest - totalDistributed; - for (int i = 0; diff > 0; i = ((i + 1) % numberOfWeightColumns)) { - ++widths[weightIteration[i]]; - --diff; - } - } + } while (recalculate); if (increase) { scrollable.setSize(area.width, area.height); @@ -314,7 +309,20 @@ */ abstract void setColumnWidths(Scrollable tableTree, int[] widths); - abstract ColumnLayoutData getLayoutData(Scrollable tableTree, int columnIndex); + abstract ColumnLayoutData getLayoutData(Scrollable tableTree, + int columnIndex); abstract void updateColumnData(Widget column); + + /** + * The number of extra pixels taken as horizontal trim by the table column. + * To ensure there are N pixels available for the content of the column, + * assign N+COLUMN_TRIM for the column width. + * + * @return the trim used by the columns + * @since 3.4 + */ + protected int getColumnTrim() { + return COLUMN_TRIM; + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/operation/AccumulatingProgressMonitor.d --- a/dwtx/jface/operation/AccumulatingProgressMonitor.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/operation/AccumulatingProgressMonitor.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -126,7 +126,7 @@ synchronized (this) { collector = null; } - display.syncExec(new class(name,totalWork) Runnable { + display.asyncExec(new class(name,totalWork) Runnable { String name_; int totalWork_; this(String a, int b){ @@ -170,7 +170,7 @@ synchronized (this) { collector = null; } - display.syncExec(new class Runnable { + display.asyncExec(new class Runnable { public void run() { getWrappedProgressMonitor().done(); } @@ -195,7 +195,7 @@ synchronized (this) { collector = null; } - display.syncExec(new class(name) Runnable { + display.asyncExec(new class(name) Runnable { String name_; this(String a){ name_=a; diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/operation/ModalContext.d --- a/dwtx/jface/operation/ModalContext.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/operation/ModalContext.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -15,8 +15,11 @@ import dwt.widgets.Display; import dwtx.core.runtime.Assert; import dwtx.core.runtime.IProgressMonitor; +import dwtx.core.runtime.IStatus; import dwtx.core.runtime.OperationCanceledException; import dwtx.core.runtime.ProgressMonitorWrapper; +import dwtx.core.runtime.Status; +import dwtx.jface.util.Policy; import dwtx.jface.operation.IThreadListener; import dwtx.jface.operation.IRunnableWithProgress; @@ -28,12 +31,12 @@ import tango.io.Stdout; /** - * Utility class for supporting modal operations. - * The runnable passed to the run method is executed in a - * separate thread, depending on the value of the passed fork argument. - * If the runnable is executed in a separate thread then the current thread - * either waits until the new thread ends or, if the current thread is the - * UI thread, it polls the DWT event queue and dispatches each event. + * Utility class for supporting modal operations. The runnable passed to the + * run method is executed in a separate thread, depending on the + * value of the passed fork argument. If the runnable is executed in a separate + * thread then the current thread either waits until the new thread ends or, if + * the current thread is the UI thread, it polls the DWT event queue and + * dispatches each event. *

* This class is not intended to be subclassed. *

@@ -41,21 +44,21 @@ public class ModalContext { /** - * Indicated whether ModalContext is in debug mode; - * false by default. + * Indicated whether ModalContext is in debug mode; false by + * default. */ private static bool debug_ = true; /** - * The number of nested modal runs, or 0 if not inside a modal run. - * This is global state. + * The number of nested modal runs, or 0 if not inside a modal run. This is + * global state. */ private static int modalLevel = 0; /** - * Indicates whether operations should be run in a separate thread. - * Defaults to true. - * For internal debugging use, set to false to run operations in the calling thread. + * Indicates whether operations should be run in a separate thread. Defaults + * to true. For internal debugging use, set to false to run operations in + * the calling thread. */ private static bool runInSeparateThread = true; @@ -98,10 +101,13 @@ /** * Creates a new modal context. * - * @param operation the runnable to run - * @param monitor the progress monitor to use to display progress and receive - * requests for cancelation - * @param display the display to be used to read and dispatch events + * @param operation + * the runnable to run + * @param monitor + * the progress monitor to use to display progress and + * receive requests for cancelation + * @param display + * the display to be used to read and dispatch events */ private this(IRunnableWithProgress operation, IProgressMonitor monitor, Display display) { @@ -113,8 +119,8 @@ this.callingThread = Thread.getThis(); } - /* (non-Javadoc) - * Method declared on Thread. + /* + * (non-Javadoc) Method declared on Thread. */ public /+override+/ void run2() { try { @@ -129,15 +135,21 @@ } catch (RuntimeException e) { throwable = e; } catch (ThreadDeath e) { - // Make sure to propagate ThreadDeath, or threads will never fully terminate + // Make sure to propagate ThreadDeath, or threads will never + // fully terminate throw e; +/ } catch (/+Error+/Exception e) { throwable = e; } finally { - //notify the operation of change of thread of control + // notify the operation of change of thread of control if ( auto tl = cast(IThreadListener)runnable ) { - tl.threadChange(callingThread); + auto exception = + invokeThreadListener(tl, callingThread); + + //Forward it if we don't already have one + if(exception !is null && throwable is null) + throwable = exception; } // Make sure that all events in the asynchronous event queue @@ -163,7 +175,7 @@ public void block() { if (display is Display.getCurrent()) { while (continueEventDispatching) { - // Run the event loop. Handle any uncaught exceptions caused + // Run the event loop. Handle any uncaught exceptions caused // by UI events. try { if (!display.readAndDispatch()) { @@ -171,7 +183,8 @@ } } /+ - // ThreadDeath is a normal error when the thread is dying. We must + // ThreadDeath is a normal error when the thread is dying. + // We must // propagate it in order for it to properly terminate. catch (ThreadDeath e) { throw (e); @@ -179,8 +192,14 @@ +/ // For all other exceptions, log the problem. catch (Exception e) { - Stderr.formatln("Unhandled event loop exception during blocked modal context."); //$NON-NLS-1$ - ExceptionPrintStackTrace(e); + Policy + .getLog() + .log( + new Status( + IStatus.ERROR, + Policy.JFACE, + "Unhandled event loop exception during blocked modal context.",//$NON-NLS-1$ + e)); } } } else { @@ -194,13 +213,15 @@ } /** - * Returns whether the first progress monitor is the same as, or - * a wrapper around, the second progress monitor. - * - * @param monitor1 the first progress monitor - * @param monitor2 the second progress monitor - * @return true if the first is the same as, or - * a wrapper around, the second + * Returns whether the first progress monitor is the same as, or a wrapper + * around, the second progress monitor. + * + * @param monitor1 + * the first progress monitor + * @param monitor2 + * the second progress monitor + * @return true if the first is the same as, or a wrapper + * around, the second * @see ProgressMonitorWrapper */ public static bool canProgressMonitorBeUsed(IProgressMonitor monitor1, @@ -223,19 +244,23 @@ * Checks with the given progress monitor and throws * InterruptedException if it has been canceled. *

- * Code in a long-running operation should call this method - * regularly so that a request to cancel will be honored. + * Code in a long-running operation should call this method regularly so + * that a request to cancel will be honored. *

*

* Convenience for: + * *

      * if (monitor.isCanceled())
-     *    throw new InterruptedException();
+     *  throw new InterruptedException();
      * 
+ * *

- * - * @param monitor the progress monitor - * @exception InterruptedException if cancelling the operation has been requested + * + * @param monitor + * the progress monitor + * @exception InterruptedException + * if cancelling the operation has been requested * @see IProgressMonitor#isCanceled() */ public static void checkCanceled(IProgressMonitor monitor) { @@ -245,7 +270,8 @@ } /** - * Returns the currently active modal context thread, or null if no modal context is active. + * Returns the currently active modal context thread, or null if no modal + * context is active. */ private static ModalContextThread getCurrentModalContextThread() { Thread t = Thread.getThis(); @@ -259,13 +285,13 @@ * Returns the modal nesting level. *

* The modal nesting level increases by one each time the - * ModalContext.run method is called within the - * dynamic scope of another call to ModalContext.run. + * ModalContext.run method is called within the dynamic scope + * of another call to ModalContext.run. *

- * - * @return the modal nesting level, or 0 if - * this method is called outside the dynamic scope of any - * invocation of ModalContext.run + * + * @return the modal nesting level, or 0 if this method is + * called outside the dynamic scope of any invocation of + * ModalContext.run */ public static int getModalLevel() { return modalLevel; @@ -274,41 +300,54 @@ /** * Returns whether the given thread is running a modal context. * - * @param thread The thread to be checked - * @return true if the given thread is running a modal context, false if not + * @param thread + * The thread to be checked + * @return true if the given thread is running a modal + * context, false if not */ public static bool isModalContextThread(Thread thread) { return (cast(ModalContextThread)thread) !is null; } /** - * Runs the given runnable in a modal context, passing it a progress monitor. + * Runs the given runnable in a modal context, passing it a progress + * monitor. *

- * The modal nesting level is increased by one from the perspective - * of the given runnable. + * The modal nesting level is increased by one from the perspective of the + * given runnable. *

- *

+ *

* If the supplied operation implements IThreadListener, it * will be notified of any thread changes required to execute the operation. - * Specifically, the operation will be notified of the thread that will call its - * run method before it is called, and will be notified of the - * change of control back to the thread calling this method when the operation - * completes. These thread change notifications give the operation an - * opportunity to transfer any thread-local state to the execution thread before - * control is transferred to the new thread. - *

- * @param operation the runnable to run - * @param fork true if the runnable should run in a separate thread, - * and false if in the same thread - * @param monitor the progress monitor to use to display progress and receive - * requests for cancelation - * @param display the display to be used to read and dispatch events - * @exception InvocationTargetException if the run method must propagate a checked exception, - * it should wrap it inside an InvocationTargetException; runtime exceptions and errors are automatically - * wrapped in an InvocationTargetException by this method - * @exception InterruptedException if the operation detects a request to cancel, - * using IProgressMonitor.isCanceled(), it should exit by throwing - * InterruptedException; this method propagates the exception + * Specifically, the operation will be notified of the thread that will call + * its run method before it is called, and will be notified + * of the change of control back to the thread calling this method when the + * operation completes. These thread change notifications give the operation + * an opportunity to transfer any thread-local state to the execution thread + * before control is transferred to the new thread. + *

+ * + * @param operation + * the runnable to run + * @param fork + * true if the runnable should run in a separate + * thread, and false if in the same thread + * @param monitor + * the progress monitor to use to display progress and receive + * requests for cancelation + * @param display + * the display to be used to read and dispatch events + * @exception InvocationTargetException + * if the run method must propagate a checked exception, it + * should wrap it inside an + * InvocationTargetException; runtime + * exceptions and errors are automatically wrapped in an + * InvocationTargetException by this method + * @exception InterruptedException + * if the operation detects a request to cancel, using + * IProgressMonitor.isCanceled(), it should + * exit by throwing InterruptedException; + * this method propagates the exception */ public static void run(IRunnableWithProgress operation, bool fork, IProgressMonitor monitor, Display display) { @@ -330,11 +369,19 @@ runInCurrentThread(operation, monitor); } else { t = new ModalContextThread(operation, monitor, display); + Exception listenerException = null; if ( auto tl = cast(IThreadListener)operation ) { - tl.threadChange(t); + listenerException = invokeThreadListener(tl, t); } - t.start(); - t.block(); + + if(listenerException is null){ + t.start(); + t.block(); + } + else { + if(t.throwable is null) + t.throwable = listenerException; + } Exception throwable = t.throwable; if (throwable !is null) { if (debug_ @@ -343,8 +390,10 @@ Stderr.formatln("Exception in modal context operation:"); //$NON-NLS-1$ ExceptionPrintStackTrace(throwable); Stderr.formatln("Called from:"); //$NON-NLS-1$ - // Don't create the InvocationTargetException on the throwable, - // otherwise it will print its stack trace (from the other thread). + // Don't create the InvocationTargetException on the + // throwable, + // otherwise it will print its stack trace (from the + // other thread). ExceptionPrintStackTrace( new InvocationTargetException(null)); } if (cast(InvocationTargetException)throwable ) { @@ -352,7 +401,9 @@ } else if (cast(InterruptedException)throwable ) { throw cast(InterruptedException) throwable; } else if (cast(OperationCanceledException)throwable ) { - // See 1GAN3L5: ITPUI:WIN2000 - ModalContext converts OperationCancelException into InvocationTargetException + // See 1GAN3L5: ITPUI:WIN2000 - ModalContext + // converts OperationCancelException into + // InvocationTargetException throw new InterruptedException(throwable .msg); } else { @@ -367,8 +418,32 @@ } /** - * Run a runnable. Convert all thrown exceptions to - * either InterruptedException or InvocationTargetException + * Invoke the ThreadListener if there are any errors or RuntimeExceptions + * return them. + * + * @param listener + * @param switchingThread + * the {@link Thread} being switched to + */ + static Throwable invokeThreadListener(IThreadListener listener, + Thread switchingThread) { + try { + listener.threadChange(switchingThread); + } catch (ThreadDeath e) { + // Make sure to propagate ThreadDeath, or threads will never + // fully terminate + throw e; + } catch (Error e) { + return e; + }catch (RuntimeException e) { + return e; + } + return null; + } + + /** + * Run a runnable. Convert all thrown exceptions to either + * InterruptedException or InvocationTargetException */ private static void runInCurrentThread(IRunnableWithProgress runnable, IProgressMonitor progressMonitor) { @@ -384,7 +459,8 @@ throw new InterruptedException(); /+ } catch (ThreadDeath e) { - // Make sure to propagate ThreadDeath, or threads will never fully terminate + // Make sure to propagate ThreadDeath, or threads will never fully + // terminate throw e; +/ } catch (RuntimeException e) { @@ -396,21 +472,26 @@ /** * Sets whether ModalContext is running in debug mode. - * - * @param debugMode true for debug mode, - * and false for normal mode (the default) + * + * @param debugMode + * true for debug mode, and false + * for normal mode (the default) */ public static void setDebugMode(bool debugMode) { debug_ = debugMode; } /** - * Sets whether ModalContext may process events (by calling Display.readAndDispatch()) - * while running operations. By default, ModalContext will process events while running operations. - * Use this method to disallow event processing temporarily. - * @param allowReadAndDispatch true (the default) if events may be processed while - * running an operation, false if Display.readAndDispatch() should not be called - * from ModalContext. + * Sets whether ModalContext may process events (by calling + * Display.readAndDispatch()) while running operations. By + * default, ModalContext will process events while running operations. Use + * this method to disallow event processing temporarily. + * + * @param allowReadAndDispatch + * true (the default) if events may be processed + * while running an operation, false if + * Display.readAndDispatch() should not be called from + * ModalContext. * @since 3.2 */ public static void setAllowReadAndDispatch(bool allowReadAndDispatch) { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/preference/ComboFieldEditor.d --- a/dwtx/jface/preference/ComboFieldEditor.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/preference/ComboFieldEditor.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Remy Chi Jian Suen - Bug 214392 missing implementation of ComboFieldEditor.setEnabled * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -210,4 +211,15 @@ fCombo.setText(fEntryNamesAndValues[0][0]); } } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.preference.FieldEditor#setEnabled(bool, + * dwt.widgets.Composite) + */ + public void setEnabled(bool enabled, Composite parent) { + super.setEnabled(enabled, parent); + getComboBoxControl(parent).setEnabled(enabled); + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/preference/FieldEditorPreferencePage.d --- a/dwtx/jface/preference/FieldEditorPreferencePage.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/preference/FieldEditorPreferencePage.d Thu May 22 01:36:46 2008 +0200 @@ -358,7 +358,7 @@ public void propertyChange(PropertyChangeEvent event) { if (event.getProperty().equals(FieldEditor.IS_VALID)) { - bool newValue = (cast(ValueWrapperBool) event.getNewValue()).value; + bool newValue = (cast(Boolean) event.getNewValue()).booleanValue(); // If the new value is true then we must check all field editors. // If it is false, then the page is invalid in any case. if (newValue) { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/preference/FileFieldEditor.d --- a/dwtx/jface/preference/FileFieldEditor.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/preference/FileFieldEditor.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -58,7 +58,7 @@ public this(String name, String labelText, Composite parent) { this(name, labelText, false, parent); } - + /** * Creates a file field editor. * @@ -68,14 +68,32 @@ * must be absolute, and false otherwise * @param parent the parent of the field editor's control */ + public this(String name, String labelText, bool enforceAbsolute, Composite parent) { + this(name, labelText, enforceAbsolute, VALIDATE_ON_FOCUS_LOST, parent); + } + /** + * Creates a file field editor. + * + * @param name the name of the preference this field editor works on + * @param labelText the label text of the field editor + * @param enforceAbsolute true if the file path + * must be absolute, and false otherwise + * @param validationStrategy either {@link StringButtonFieldEditor#VALIDATE_ON_KEY_STROKE} + * to perform on the fly checking, or {@link StringButtonFieldEditor#VALIDATE_ON_FOCUS_LOST} + * (the default) to perform validation only after the text has been typed in + * @param parent the parent of the field editor's control. + * @since 3.4 + * @see StringButtonFieldEditor#VALIDATE_ON_KEY_STROKE + * @see StringButtonFieldEditor#VALIDATE_ON_FOCUS_LOST + */ public this(String name, String labelText, - bool enforceAbsolute, Composite parent) { + bool enforceAbsolute, int validationStrategy, Composite parent) { init(name, labelText); this.enforceAbsolute = enforceAbsolute; setErrorMessage(JFaceResources .getString("FileFieldEditor.errorMessage"));//$NON-NLS-1$ setChangeButtonText(JFaceResources.getString("openBrowse"));//$NON-NLS-1$ - setValidateStrategy(VALIDATE_ON_FOCUS_LOST); + setValidateStrategy(validationStrategy); createControl(parent); } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/preference/IntegerFieldEditor.d --- a/dwtx/jface/preference/IntegerFieldEditor.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/preference/IntegerFieldEditor.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,6 +7,8 @@ * * Contributors: * IBM Corporation - initial API and implementation + * - Fix for bug 109389 - IntegerFieldEditor + * does not fire property change all the time * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -117,6 +119,7 @@ if (text !is null) { int value = getPreferenceStore().getInt(getPreferenceName()); text.setText( tango.text.convert.Integer.toString(value));//$NON-NLS-1$ + oldValue = "" + value; //$NON-NLS-1$ } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/preference/JFacePreferences.d --- a/dwtx/jface/preference/JFacePreferences.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/preference/JFacePreferences.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -18,8 +18,8 @@ /** * - * JFacePreferences is a class used to administer the preferences - * used by JFace objects. + * JFacePreferences is a class used to administer the preferences used by JFace + * objects. */ public final class JFacePreferences { @@ -38,6 +38,50 @@ */ public static const String ACTIVE_HYPERLINK_COLOR = "ACTIVE_HYPERLINK_COLOR"; //$NON-NLS-1$ + /** + * Identifier for the color used to show extra informations in labels, as a + * qualified name. For example in 'Foo.txt - myproject/bar', the qualifier + * is '- myproject/bar'. + * + * @since 3.4 + */ + public static final String QUALIFIER_COLOR = "QUALIFIER_COLOR"; //$NON-NLS-1$ + + /** + * Identifier for the color used to show label decorations For example in + * 'Foo.txt [1.16]', the decoration is '[1.16]'. + * + * @since 3.4 + */ + public static final String DECORATIONS_COLOR = "DECORATIONS_COLOR"; //$NON-NLS-1$ + + /** + * Identifier for the color used to counter informations For example in + * 'Foo.txt (2 matches)', the counter information is '(2 matches)'. + * + * @since 3.4 + */ + public static final String COUNTER_COLOR = "COUNTER_COLOR"; //$NON-NLS-1$ + + + /** + * Identifier for the color used for the background of content assist + * popup dialogs. + * + * @since 3.4 + */ + public static final String CONTENT_ASSIST_BACKGROUND_COLOR = "CONTENT_ASSIST_BACKGROUND_COLOR"; //$NON-NLS-1$ + + /** + * Identifier for the color used for the foreground of content assist + * popup dialogs. + * + * @since 3.4 + */ + public static final String CONTENT_ASSIST_FOREGROUND_COLOR = "CONTENT_ASSIST_FOREGROUND_COLOR"; //$NON-NLS-1$ + + + private static IPreferenceStore preferenceStore; /** @@ -48,6 +92,7 @@ /** * Return the preference store for the receiver. + * * @return IPreferenceStore or null */ public static IPreferenceStore getPreferenceStore() { @@ -56,7 +101,9 @@ /** * Set the preference store for the receiver. - * @param store IPreferenceStore + * + * @param store + * IPreferenceStore */ public static void setPreferenceStore(IPreferenceStore store) { preferenceStore = store; diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/preference/PreferenceDialog.d --- a/dwtx/jface/preference/PreferenceDialog.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/preference/PreferenceDialog.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -80,6 +80,7 @@ import dwtx.jface.viewers.SelectionChangedEvent; import dwtx.jface.viewers.StructuredSelection; import dwtx.jface.viewers.TreeViewer; +import dwtx.jface.viewers.ViewerComparator; import dwtx.jface.viewers.ViewerFilter; import dwt.dwthelper.utils; @@ -231,7 +232,6 @@ minimumPageSize = new Point(400, 400); pageChangedListeners = new ListenerList(); super(parentShell); - setShellStyle(getShellStyle() | DWT.RESIZE | DWT.MAX); preferenceManager = manager; } @@ -876,13 +876,12 @@ try { (cast(IPersistentPreferenceStore) store).save(); } catch (IOException e) { - MessageDialog - .openError( - getShell(), - JFaceResources.getString("PreferenceDialog.saveErrorTitle"), //$NON-NLS-1$ - JFaceResources - .format( - "PreferenceDialog.saveErrorMessage", [ page.getTitle(), e.msg ])); //$NON-NLS-1$ + String message =JFaceResources.format( + "PreferenceDialog.saveErrorMessage", new Object[] { page.getTitle(), e.getMessage() }); //$NON-NLS-1$ + Policy.getStatusHandler().show( + new Status(IStatus.ERROR, Policy.JFACE, message, e), + JFaceResources.getString("PreferenceDialog.saveErrorTitle")); //$NON-NLS-1$ + } } } @@ -1007,7 +1006,10 @@ clearSelectedNode(); String message = JFaceResources.getString("SafeRunnable.errorMessage"); //$NON-NLS-1$ - MessageDialog.openError(getShell(), JFaceResources.getString("Error"), message); //$NON-NLS-1$ + + Policy.getStatusHandler().show( + new Status(IStatus.ERROR, Policy.JFACE, message, e), + JFaceResources.getString("Error")); //$NON-NLS-1$ } }); @@ -1033,6 +1035,10 @@ IPreferenceNode node = findNodeMatching(getSelectedNodePreference()); if (node is null) { IPreferenceNode[] nodes = preferenceManager.getRootSubNodes(); + ViewerComparator comparator = getTreeViewer().getComparator(); + if (comparator !is null) { + comparator.sort(null, nodes); + } ViewerFilter[] filters = getTreeViewer().getFilters(); for (int i = 0; i < nodes.length; i++) { IPreferenceNode selectedNode = nodes[i]; @@ -1565,4 +1571,13 @@ }); } } + + /* + * (non-Javadoc) + * @see dwtx.jface.dialogs.Dialog#isResizable() + */ + protected bool isResizable() { + return true; + } + } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/preference/PreferenceManager.d --- a/dwtx/jface/preference/PreferenceManager.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/preference/PreferenceManager.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Jan-Hendrik Diederich, Bredex GmbH - bug 201052 * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -40,6 +41,11 @@ * Post-order means visit the children, and then the root. */ public static const int POST_ORDER = 1; + + /** + * The id of the root node. + */ + private final static String ROOT_NODE_ID = ""; //$NON-NLS-1$ /** * The root node. @@ -58,18 +64,31 @@ * Creates a new preference manager. */ public this() { - this('.'); + this('.', new PreferenceNode(ROOT_NODE_ID)); + } + + /** + * Creates a new preference manager with the given + * path separator. + * + * @param separatorChar + */ + public PreferenceManager(final char separatorChar) { + this(separatorChar, new PreferenceNode(ROOT_NODE_ID)); } /** * Creates a new preference manager with the given - * the path separator. + * path separator and root node. * * @param separatorChar the separator character + * @param rootNode the root node. + * + * @since 3.4 */ - public this(char separatorChar) { - root = new PreferenceNode("");//$NON-NLS-1$ + public this(final char separatorChar, PreferenceNode rootNode) { separator = [ separatorChar ]; + this.root = rootNode; } /** diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/preference/PreferencePage.d --- a/dwtx/jface/preference/PreferencePage.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/preference/PreferencePage.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -35,6 +35,7 @@ import dwtx.jface.dialogs.Dialog; import dwtx.jface.dialogs.DialogPage; import dwtx.jface.dialogs.IDialogConstants; +import dwtx.jface.dialogs.IDialogPage; import dwtx.jface.resource.ImageDescriptor; import dwtx.jface.resource.JFaceResources; import dwtx.jface.util.IPropertyChangeListener; @@ -217,6 +218,7 @@ * If a subclass that overrides this method creates a Composite * that has a layout with default margins (for example, a GridLayout) * it is expected to set the margins of this Layout to 0 pixels. + * @see IDialogPage#createControl(Composite) */ public void createControl(Composite parent){ @@ -398,6 +400,7 @@ * method returns whether this preference page is valid. Preference * pages are considered valid by default; call setValid(false) * to make a page invalid. + * @see IPreferencePage#isValid() */ public bool isValid() { return isValid_; @@ -407,7 +410,7 @@ * Suppresses creation of the standard Default and Apply buttons * for this page. *

- * Subclasses wishing a preference page wihthout these buttons + * Subclasses wishing a preference page without these buttons * should call this framework method before the page's control * has been created. *

@@ -420,6 +423,7 @@ * The PreferencePage implementation of this * IPreferencePage method returns true * if the page is valid. + * @see IPreferencePage#okToLeave() */ public bool okToLeave() { return isValid(); @@ -445,9 +449,10 @@ * method performs special processing when this page's Cancel button has * been pressed. *

- * This is a framework hook method for sublcasses to do special things when + * This is a framework hook method for subclasses to do special things when * the Cancel button has been pressed. The default implementation of this * framework method does nothing and returns true. + * @see IPreferencePage#performCancel() */ public bool performCancel() { return true; @@ -465,16 +470,17 @@ updateApplyButton(); } - /** - * Method declared on IPreferencePage. - * Subclasses should override + + /* (non-Javadoc) + * @see dwtx.jface.preference.IPreferencePage#performOk() */ public bool performOk() { return true; } - /** (non-Javadoc) - * Method declared on IPreferencePage. + + /* (non-Javadoc) + * @see dwtx.jface.preference.IPreferencePage#setContainer(dwtx.jface.preference.IPreferencePageContainer) */ public void setContainer(IPreferencePageContainer container) { this.container = container; @@ -494,8 +500,9 @@ preferenceStore = store; } + /* (non-Javadoc) - * Method declared on IPreferencePage. + * @see dwtx.jface.preference.IPreferencePage#setSize(dwt.graphics.Point) */ public void setSize(Point uiSize) { Control control = getControl(); @@ -509,6 +516,7 @@ * The PreferencePage implementation of this IDialogPage * method extends the DialogPage implementation to update * the preference page container title. Subclasses may extend. + * @see IDialogPage#setTitle(String) */ public override void setTitle(String title) { super.setTitle(title); @@ -539,8 +547,9 @@ } } - /** - * Returns a string suitable for debugging purpose only. + + /* (non-Javadoc) + * @see java.lang.Object#toString() */ public override String toString() { return getTitle(); diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/preference/StringFieldEditor.d --- a/dwtx/jface/preference/StringFieldEditor.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/preference/StringFieldEditor.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -70,8 +70,9 @@ /** * Old text value. + * @since 3.4 this field is protected. */ - private String oldValue; + protected String oldValue; /** * The text field, or null if none. diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/resource/ColorRegistry.d --- a/dwtx/jface/resource/ColorRegistry.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/resource/ColorRegistry.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2003, 2006 IBM Corporation and others. + * Copyright (c) 2003, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -54,6 +54,12 @@ public class ColorRegistry : ResourceRegistry { /** + * Default color value. This is cyan (very unappetizing). + * @since 3.4 + */ + private static final ColorDescriptor DEFAULT_COLOR = new RGBColorDescriptor(new RGB(0, 255, 255)); + + /** * This registries Display. All colors will be allocated using * it. */ @@ -199,7 +205,8 @@ * Returns the color data associated with the given symbolic color name. * * @param symbolicName symbolic color name. - * @return the RGB data. + * @return the RGB data, or null if the symbolic name + * is not valid. */ public RGB getRGB(String symbolicName) { Assert.isNotNull(symbolicName); @@ -207,17 +214,43 @@ } /** - * Returns the color descriptor associated with the given symbolic color name. + * Returns the color descriptor associated with the given symbolic color + * name. As of 3.4 if this color is not defined then an unspecified color + * is returned. Users that wish to ensure a reasonable default value should + * use {@link #getColorDescriptor(String, ColorDescriptor)} instead. + * * @since 3.1 - * + * * @param symbolicName - * @return the color descriptor associated with the given symbolic color name. + * @return the color descriptor associated with the given symbolic color + * name or an unspecified sentinel. */ public ColorDescriptor getColorDescriptor(String symbolicName) { - return ColorDescriptor.createFrom(getRGB(symbolicName)); + return getColorDescriptor(symbolicName, DEFAULT_COLOR); + } + + /** + * Returns the color descriptor associated with the given symbolic color + * name. If this name does not exist within the registry the supplied + * default value will be used. + * + * @param symbolicName + * @param defaultValue + * @return the color descriptor associated with the given symbolic color + * name or the default + * @since 3.4 + */ + public ColorDescriptor getColorDescriptor(String symbolicName, + ColorDescriptor defaultValue) { + RGB rgb = getRGB(symbolicName); + if (rgb is null) + return defaultValue; + return ColorDescriptor.createFrom(rgb); } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see dwtx.jface.resource.ResourceRegistry#clearCaches() */ protected override void clearCaches() { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/resource/FileImageDescriptor.d --- a/dwtx/jface/resource/FileImageDescriptor.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/resource/FileImageDescriptor.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -22,7 +22,10 @@ import dwt.DWT; import dwt.DWTException; +import dwt.graphics.Device; +import dwt.graphics.Image; import dwt.graphics.ImageData; +import dwtx.core.runtime.Path; import dwt.dwthelper.utils; import dwt.dwthelper.InputStream; @@ -31,16 +34,16 @@ import dwt.dwthelper.ByteArrayInputStream; import tango.util.log.Trace; +import tango.text.convert.Format; /** - * An image descriptor that loads its image information - * from a file. + * An image descriptor that loads its image information from a file. */ class FileImageDescriptor : ImageDescriptor { /** - * The class whose resource directory contain the file, - * or null if none. + * The class whose resource directory contain the file, or null + * if none. */ // private ClassInfo location; @@ -51,18 +54,18 @@ private void[] importdata; /** - * Creates a new file image descriptor. - * The file has the given file name and is located - * in the given class's resource directory. If the given - * class is null, the file name must be absolute. + * Creates a new file image descriptor. The file has the given file name and + * is located in the given class's resource directory. If the given class is + * null, the file name must be absolute. *

- * Note that the file is not accessed until its - * getImageDate method is called. + * Note that the file is not accessed until its getImageDate + * method is called. *

- * - * @param clazz class for resource directory, or - * null - * @param filename the name of the file + * + * @param clazz + * class for resource directory, or null + * @param filename + * the name of the file */ this(ImportData importdata) { // this.location = clazz; @@ -70,8 +73,8 @@ this.importdata = importdata.data; } - /* (non-Javadoc) - * Method declared on Object. + /* + * (non-Javadoc) Method declared on Object. */ public override int opEquals(Object o) { if (!( cast(FileImageDescriptor)o )) { @@ -90,9 +93,11 @@ return importdata == other.importdata; } - /* (non-Javadoc) - * Method declared on ImageDesciptor. - * Returns null if the image data cannot be read. + /** + * @see dwtx.jface.resource.ImageDescriptor#getImageData() The + * FileImageDescriptor implementation of this method is not used by + * {@link ImageDescriptor#createImage(bool, Device)} as of version + * 3.4 so that the DWT OS optimised loading can be used. */ public override ImageData getImageData() { InputStream in_ = getStream(); @@ -104,7 +109,7 @@ if (e.code !is DWT.ERROR_INVALID_IMAGE /+&& e.code !is DWT.ERROR_UNSUPPORTED_FORMAT+/) { Trace.formatln( "FileImageDescriptor getImageData DWTException for name={}", name ); throw e; - // fall through otherwise + // fall through otherwise } } finally { in_.close(); @@ -114,11 +119,11 @@ } /** - * Returns a stream on the image contents. Returns - * null if a stream could not be opened. + * Returns a stream on the image contents. Returns null if a stream could + * not be opened. * - * @return the buffered stream on the file or null - * if the file cannot be found + * @return the buffered stream on the file or null if the + * file cannot be found */ private InputStream getStream() { InputStream is_ = null; @@ -137,13 +142,13 @@ // } if (is_ is null) { return null; - } else { - return new BufferedInputStream(is_); } + return new BufferedInputStream(is); + } - /* (non-Javadoc) - * Method declared on Object. + /* + * (non-Javadoc) Method declared on Object. */ public override hash_t toHash() { int code = dwt.dwthelper.utils.toHash(cast(char[])importdata/+name+/); @@ -153,15 +158,77 @@ return code; } - /* (non-Javadoc) - * Method declared on Object. + /* + * (non-Javadoc) Method declared on Object. */ /** - * The FileImageDescriptor implementation of this Object method - * returns a string representation of this object which is suitable only for debugging. + * The FileImageDescriptor implementation of this + * Object method returns a string representation of this + * object which is suitable only for debugging. */ public override String toString() { -// return "FileImageDescriptor(location=" ~ location.toString() ~ ", name=" ~ name ~ ")";//$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ - return "FileImageDescriptor()";//$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ + return Format("FileImageDescriptor(location={}, name={})", location, name );//$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.resource.ImageDescriptor#createImage(bool, + * dwt.graphics.Device) + */ + public Image createImage(bool returnMissingImageOnError, Device device) { + String path = getFilePath(); + if (path is null) + return createDefaultImage(returnMissingImageOnError, device); + try { + return new Image(device, path); + } catch (DWTException exception) { + //if we fail try the default way using a stream + } + return super.createImage(returnMissingImageOnError, device); + } + + /** + * Return default image if returnMissingImageOnError is true. + * + * @param device + * @return Image or null + */ + private Image createDefaultImage(bool returnMissingImageOnError, + Device device) { + try { + if (returnMissingImageOnError) + return new Image(device, DEFAULT_IMAGE_DATA); + } catch (DWTException nextException) { + return null; + } + return null; + } + + /** + * Returns the filename for the ImageData. + * + * @return {@link String} or null if the file cannot be found + */ + private String getFilePath() { + + if (location is null) + return new Path(name).toOSString(); + + URL resource = location.getResource(name); + + if (resource is null) + return null; +// try { +// if (JFaceActivator.getBundleContext() is null) {// Stand-alone case +// +// return new Path(resource.getFile()).toOSString(); +// } +// return new Path(FileLocator.toFileURL(resource).getPath()).toOSString(); + return null; +// } catch (IOException e) { +// Policy.logException(e); +// return null; +// } } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/resource/ImageRegistry.d --- a/dwtx/jface/resource/ImageRegistry.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/resource/ImageRegistry.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -300,9 +300,10 @@ "ImageRegistry key already in use: " ~ key); //$NON-NLS-1$ } - // Should be checking for a null image here. - // Current behavior is that a null image won't be caught until dispose. + // Check for a null image here, otherwise the problem won't appear + // until dispose. // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=130315 + Assert.isNotNull(image, "Cannot register a null image."); //$NON-NLS-1$ entry.image = image; entry.descriptor = new OriginalImageDescriptor(image, manager.getDevice()); diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/resource/JFaceResources.d --- a/dwtx/jface/resource/JFaceResources.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/resource/JFaceResources.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -28,6 +28,7 @@ import dwt.widgets.Display; import dwtx.core.runtime.Assert; import dwtx.jface.dialogs.Dialog; +import dwtx.jface.dialogs.PopupDialog; import dwtx.jface.dialogs.TitleAreaDialog; import dwtx.jface.preference.PreferenceDialog; import dwtx.jface.wizard.Wizard; @@ -200,6 +201,7 @@ public static ColorRegistry getColorRegistry() { if (colorRegistry is null) { colorRegistry = new ColorRegistry(); + initializeDefaultColors(); } return colorRegistry; } @@ -451,12 +453,18 @@ ~ "message_warning.gif", getImportData!( "dwtx.jface.dialogs.images.message_warning.gif")); //$NON-NLS-1$ declareImage(bundle, Dialog.DLG_IMG_MESSAGE_ERROR, ICONS_PATH ~ "message_error.gif", getImportData!( "dwtx.jface.dialogs.images.message_error.gif"));//$NON-NLS-1$ //$NON-NLS-2$ - declareImage(bundle, Dialog.DLG_IMG_HELP, ICONS_PATH - ~ "help.gif", getImportData!( "dwtx.jface.dialogs.images.help.gif"));//$NON-NLS-1$ //$NON-NLS-2$ + declareImage(bundle, Dialog.DLG_IMG_HELP, + ICONS_PATH ~ "help.gif", getImportData!( "dwtx.jface.dialogs.images.help.gif"));//$NON-NLS-1$ //$NON-NLS-2$ declareImage(bundle, TitleAreaDialog.DLG_IMG_TITLE_BANNER, ICONS_PATH ~ "title_banner.png", getImportData!( "dwtx.jface.dialogs.images.title_banner.gif"));//$NON-NLS-1$ //$NON-NLS-2$ declareImage(bundle, PreferenceDialog.PREF_DLG_TITLE_IMG, ICONS_PATH ~ "pref_dialog_title.gif", getImportData!( "dwtx.jface.preference.images.pref_dialog_title.gif"));//$NON-NLS-1$ //$NON-NLS-2$ + declareImage(bundle, PopupDialog.POPUP_IMG_MENU, ICONS_PATH + ~ "popup_menu.gif", getImportData!( "images/popup_menu.gif"));//$NON-NLS-1$ //$NON-NLS-2$ + declareImage( + bundle, + PopupDialog.POPUP_IMG_MENU_DISABLED, + ICONS_PATH ~ "popup_menu_disabled.gif", getImportData!( "images/popup_menu_disabled.gif"));//$NON-NLS-1$ //$NON-NLS-2$ } /** @@ -482,14 +490,14 @@ private static final void declareImage(Object bundle, String key, String path, ImportData importdata/+ClassInfo fallback, String fallbackPath+/) { - ImageDescriptor descriptor = null; if (bundle !is null) { -//FIXME -// URL url = FileLocator.find((Bundle) bundle, new Path(path), null); -// if (url !is null) -// descriptor = ImageDescriptor.createFromURL(url); + /* + URL url = FileLocator.find((Bundle) bundle, new Path(path), null); + if (url !is null) + descriptor = ImageDescriptor.createFromURL(url); + */ } // If we failed then load from the backup file @@ -599,4 +607,12 @@ private this() { // no-op } + + /* + * Initialize any JFace colors that may not be initialized via a client. + */ + private static void initializeDefaultColors() { + // JFace Colors that may not be defined in a workbench theme should be + // defined here. + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/resource/StringConverter.d --- a/dwtx/jface/resource/StringConverter.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/resource/StringConverter.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -556,9 +556,9 @@ if( stok.length < 3 ){ throw new DataFormatException( "not enough values" ); } - String red = stok[0]; - String green = stok[1]; - String blue = stok[2]; + String red = stok[0].trim(); + String green = stok[1].trim(); + String blue = stok[2].trim(); int rval = 0, gval = 0, bval = 0; try { rval = tango.text.convert.Integer.toInt(red); diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/resource/URLImageDescriptor.d --- a/dwtx/jface/resource/URLImageDescriptor.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/resource/URLImageDescriptor.d Thu May 22 01:36:46 2008 +0200 @@ -21,30 +21,41 @@ import dwt.DWT; import dwt.DWTException; +import dwt.graphics.Device; +import dwt.graphics.Image; import dwt.graphics.ImageData; +import dwtx.core.runtime.IStatus; +import dwtx.core.runtime.Status; +import dwtx.jface.util.Policy; import dwt.dwthelper.utils; import dwt.dwthelper.BufferedInputStream; import dwt.dwthelper.InputStream; /** - * An ImageDescriptor that gets its information from a URL. - * This class is not public API. Use ImageDescriptor#createFromURL - * to create a descriptor that uses a URL. + * An ImageDescriptor that gets its information from a URL. This class is not + * public API. Use ImageDescriptor#createFromURL to create a descriptor that + * uses a URL. */ class URLImageDescriptor : ImageDescriptor { + /** + * Constant for the file protocol for optimized loading + */ + private static final String FILE_PROTOCOL = "file"; //$NON-NLS-1$ private Uri url; /** * Creates a new URLImageDescriptor. - * @param url The URL to load the image from. Must be non-null. + * + * @param url + * The URL to load the image from. Must be non-null. */ this(Uri url) { this.url = url; } - /* (non-Javadoc) - * Method declared on Object. + /* + * (non-Javadoc) Method declared on Object. */ public override int opEquals(Object o) { if (!(cast(URLImageDescriptor)o )) { @@ -53,9 +64,9 @@ return (cast(URLImageDescriptor) o).url.opEquals(this.url) !is 0; } - /* (non-Javadoc) - * Method declared on ImageDesciptor. - * Returns null if the image data cannot be read. + /* + * (non-Javadoc) Method declared on ImageDesciptor. Returns null if the + * image data cannot be read. */ public override ImageData getImageData() { ImageData result = null; @@ -68,7 +79,7 @@ } catch (DWTException e) { if (e.code !is DWT.ERROR_INVALID_IMAGE) { throw e; - // fall through otherwise + // fall through otherwise } } } @@ -76,8 +87,9 @@ } /** - * Returns a stream on the image contents. Returns - * null if a stream could not be opened. + * Returns a stream on the image contents. Returns null if a stream could + * not be opened. + * * @return the stream for loading the data */ protected InputStream getStream() { @@ -93,21 +105,70 @@ +/ } - /* (non-Javadoc) - * Method declared on Object. + /* + * (non-Javadoc) Method declared on Object. */ public override hash_t toHash() { return url.toHash(); } - /* (non-Javadoc) - * Method declared on Object. + /* + * (non-Javadoc) Method declared on Object. */ /** - * The URLImageDescriptor implementation of this Object method - * returns a string representation of this object which is suitable only for debugging. + * The URLImageDescriptor implementation of this + * Object method returns a string representation of this + * object which is suitable only for debugging. */ public override String toString() { return "URLImageDescriptor(" ~ url.toString ~ ")"; //$NON-NLS-1$ //$NON-NLS-2$ } + + /** + * Returns the filename for the ImageData. + * + * @return {@link String} or null if the file cannot be found + */ + private String getFilePath() { + + return null; +// try { +// if (JFaceActivator.getBundleContext() is null) { +// if (FILE_PROTOCOL.equalsIgnoreCase(url.getProtocol())) +// return new Path(url.getFile()).toOSString(); +// return null; +// } +// +// URL locatedURL = FileLocator.toFileURL(url); +// if (FILE_PROTOCOL.equalsIgnoreCase(locatedURL.getProtocol())) +// return new Path(locatedURL.getPath()).toOSString(); +// return null; +// +// } catch (IOException e) { +// Policy.logException(e); +// return null; +// } + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.resource.ImageDescriptor#createImage(bool, + * dwt.graphics.Device) + */ + public Image createImage(bool returnMissingImageOnError, Device device) { + + // Try to see if we can optimize using SWTs file based image support. + String path = getFilePath(); + if (path is null) + return super.createImage(returnMissingImageOnError, device); + + try { + return new Image(device, path); + } catch (DWTException exception) { + // If we fail fall back to the slower input stream method. + } + return super.createImage(returnMissingImageOnError, device); + } + } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/util/Geometry.d --- a/dwtx/jface/util/Geometry.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/util/Geometry.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2006 IBM Corporation and others. + * Copyright (c) 2004, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -745,13 +745,13 @@ * be the upper-left corner of the rectangle. * * @param rectangle rectangle to modify - * @param newSize new size of the rectangle + * @param newLocation new location of the rectangle * * @since 3.0 */ - public static void setLocation(Rectangle rectangle, Point newSize) { - rectangle.width = newSize.x; - rectangle.height = newSize.y; + public static void setLocation(Rectangle rectangle, Point newLocation) { + rectangle.x = newLocation.x; + rectangle.y = newLocation.y; } /** diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/util/Policy.d --- a/dwtx/jface/util/Policy.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/util/Policy.d Thu May 22 01:36:46 2008 +0200 @@ -1,10 +1,10 @@ /******************************************************************************* - * Copyright (c) 2004, 2007 IBM Corporation and others. + * Copyright (c) 2004, 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 * Chris Gross (schtoo@schtoo.com) - support for ILogger added @@ -15,7 +15,11 @@ module dwtx.jface.util.Policy; static import dwtx.core.runtime.Assert; +import dwt.events.DisposeEvent; +import dwt.events.DisposeListener; +import dwt.widgets.Display; import dwtx.core.runtime.IStatus; +import dwtx.core.runtime.Status; import dwtx.jface.dialogs.AnimatorFactory; import dwtx.jface.dialogs.ErrorSupportProvider; @@ -40,7 +44,7 @@ /** * The unique identifier of the JFace plug-in. */ - public static const String JFACE = "dwtx.jface";//$NON-NLS-1$ + public static const String JFACE = "dwtx.jface"; //$NON-NLS-1$ private static ILogger log; @@ -66,6 +70,8 @@ private static ErrorSupportProvider errorSupportProvider; + private static StatusHandler statusHandler; + /** * Returns the dummy log to use if none has been set */ @@ -114,6 +120,64 @@ } /** + * Sets the status handler used by JFace to handle statuses. + * + * @param status + * the handler to use, or null to use the default + * one + * @since 3.4 + */ + public static void setStatusHandler(StatusHandler status) { + statusHandler = status; + } + + /** + * Returns the status handler used by JFace to handle statuses. + * + * @return the status handler + * @since 3.4 + */ + public static StatusHandler getStatusHandler() { + if (statusHandler is null) { + statusHandler = getDummyStatusHandler(); + } + return statusHandler; + } + + private static StatusHandler getDummyStatusHandler() { + return new StatusHandler() { + private SafeRunnableDialog dialog; + + public void show(final IStatus status, String title) { + Runnable runnable = new Runnable() { + public void run() { + if (dialog is null || dialog.getShell().isDisposed()) { + dialog = new SafeRunnableDialog(status); + dialog.create(); + dialog.getShell().addDisposeListener( + new DisposeListener() { + public void widgetDisposed( + DisposeEvent e) { + dialog = null; + } + }); + dialog.open(); + } else { + dialog.addStatus(status); + dialog.refresh(); + } + } + }; + if (Display.getCurrent() !is null) { + runnable.run(); + } else { + Display.getDefault().asyncExec(runnable); + } + } + }; + } + + /** * Return the default comparator used by JFace to sort strings. * * @return a default comparator used by JFace to sort strings @@ -207,11 +271,24 @@ /** * Return the ErrorSupportProvider for the receiver. * - * @return ErrorSupportProvider or null if this has not been set + * @return ErrorSupportProvider or null if this has not been + * set * @since 3.3 */ public static ErrorSupportProvider getErrorSupportProvider() { return errorSupportProvider; } + /** + * Log the Exception to the logger. + * + * @param exception + */ + public static void logException(Exception exception) { + getLog().log( + new Status(IStatus.ERROR, JFACE, exception + .getLocalizedMessage(), exception)); + + } + } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/util/SafeRunnable.d --- a/dwtx/jface/util/SafeRunnable.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/util/SafeRunnable.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -17,10 +17,6 @@ import dwtx.jface.util.ISafeRunnableRunner; import dwtx.jface.util.SafeRunnableDialog; import dwtx.jface.util.Policy; - -import dwt.events.DisposeEvent; -import dwt.events.DisposeListener; -import dwt.widgets.Display; import dwtx.core.runtime.ISafeRunnable; import dwtx.core.runtime.IStatus; import dwtx.core.runtime.OperationCanceledException; @@ -32,11 +28,10 @@ /** * Implements a default implementation of ISafeRunnable. The default - * implementation of handleException opens a message dialog. + * implementation of handleException opens a dialog to show any + * errors as they accumulate. *

- * Note: This class can open an error dialog and should not be used - * outside of the UI Thread. - *

+ * This may be executed on any thread. */ public abstract class SafeRunnable : ISafeRunnable { @@ -46,8 +41,6 @@ private String message; - private static SafeRunnableDialog dialog; - /** * Creates a new instance of SafeRunnable with a default error message. */ @@ -65,45 +58,23 @@ this.message = message; } - - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see dwtx.core.runtime.ISafeRunnable#handleException(java.lang.Throwable) */ public void handleException(Exception e) { - // Workaround to avoid interactive error dialogs during automated - // testing - if (!ignoreErrors) { - if (message is null) - message = JFaceResources.getString("SafeRunnable.errorMessage"); //$NON-NLS-1$ + // Workaround to avoid interactive error dialogs during + // automated testing + if (ignoreErrors) + return; - Runnable runnable = new class(new Status(IStatus.ERROR, Policy.JFACE, message,e)) Runnable { - IStatus status; - this(IStatus a){ - status = a; - } - public void run() { - if (dialog is null || dialog.getShell().isDisposed()) { - dialog = new SafeRunnableDialog(status); - dialog.create(); - dialog.getShell().addDisposeListener( - new class DisposeListener { - public void widgetDisposed(DisposeEvent e) { - dialog = null; - } - }); - dialog.open(); - } else { - dialog.addStatus(status); - dialog.refresh(); - } - } - }; - if (Display.getCurrent() !is null) { - runnable.run(); - } else { - Display.getDefault().asyncExec(runnable); - } - } + if (message is null) + message = JFaceResources.getString("SafeRunnable.errorMessage"); //$NON-NLS-1$ + + Policy.getStatusHandler().show( + new Status(IStatus.ERROR, Policy.JFACE, message, e), + JFaceResources.getString("SafeRunnable.errorMessage")); //$NON-NLS-1$ } /** @@ -173,9 +144,11 @@ private void handleException(ISafeRunnable code, Exception e) { if (!(cast(OperationCanceledException)e )) { try { - Policy.getLog().log( - new Status(IStatus.ERROR, Policy.JFACE, - IStatus.ERROR, "Exception occurred", e)); //$NON-NLS-1$ + Policy.getLog() + .log( + new Status(IStatus.ERROR, Policy.JFACE, + IStatus.ERROR, + "Exception occurred", e)); //$NON-NLS-1$ } catch (Exception ex) { ExceptionPrintStackTrace(e); } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/util/SafeRunnableDialog.d --- a/dwtx/jface/util/SafeRunnableDialog.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/util/SafeRunnableDialog.d Thu May 22 01:36:46 2008 +0200 @@ -41,7 +41,7 @@ /** * SafeRunnableDialog is a dialog that can show the results of multiple safe - * runnable errors + * runnable errors. * */ class SafeRunnableDialog : ErrorDialog { @@ -61,7 +61,7 @@ super(null, JFaceResources.getString("error"), status.getMessage(), //$NON-NLS-1$ status, IStatus.ERROR); statuses = new ArraySeq!(IStatus); - setShellStyle(DWT.DIALOG_TRIM | DWT.MODELESS | DWT.RESIZE | DWT.MIN + setShellStyle(DWT.DIALOG_TRIM | DWT.MODELESS | DWT.RESIZE | DWT.MIN | DWT.MAX | getDefaultOrientation()); setStatus(status); diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/util/StatusHandler.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/util/StatusHandler.d Thu May 22 01:36:46 2008 +0200 @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 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 + * Port to the D programming language: + * Frank Benoit + ******************************************************************************/ + +module dwtx.jface.util.StatusHandler; + +import dwtx.core.runtime.IStatus; + +/** + * A mechanism to handle statuses throughout JFace. + *

+ * Clients may provide their own implementation to change how statuses are + * handled from within JFace. + *

+ * + * @see dwtx.jface.util.Policy#getStatusHandler() + * @see dwtx.jface.util.Policy#setStatusHandler(StatusHandler) + * + * @since 3.4 + */ +abstract public class StatusHandler { + + /** + * Show the given status. + * + * @param status + * status to handle + * @param title + * title for the status + */ + abstract public void show(IStatus status, String title); +} diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/util/Util.d --- a/dwtx/jface/util/Util.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/util/Util.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -498,6 +498,43 @@ return defaultString; } + + /** + * Foundation replacement for String.replaceAll(*). + * + * @param src the starting string. + * @param find the string to find. + * @param replacement the string to replace. + * @return The new string. + * @since 3.4 + */ + public static final String replaceAll(String src, String find, String replacement) { + final int len = src.length(); + final int findLen = find.length(); + + int idx = src.indexOf(find); + if (idx < 0) { + return src; + } + + StringBuffer buf = new StringBuffer(); + int beginIndex = 0; + while (idx !is -1 && idx < len) { + buf.append(src.substring(beginIndex, idx)); + buf.append(replacement); + + beginIndex = idx + findLen; + if (beginIndex < len) { + idx = src.indexOf(find, beginIndex); + } else { + idx = -1; + } + } + if (beginIndex - initial API and implementation (bug 174739) + * Port to the D programming language: + * Frank Benoit + ******************************************************************************/ + +module dwtx.jface.viewers.AbstractComboBoxCellEditor; + +import dwt.DWT; +import dwt.custom.CCombo; +import dwt.widgets.Composite; + +/** + * Abstract base class for Cell-Editors presented as combo boxes + * + * @since 3.4 + * + */ +abstract class AbstractComboBoxCellEditor extends CellEditor { + /** + * The list is dropped down when the activation is done through the mouse + */ + public static final int DROP_DOWN_ON_MOUSE_ACTIVATION = 1; + + /** + * The list is dropped down when the activation is done through the keyboard + */ + public static final int DROP_DOWN_ON_KEY_ACTIVATION = 1 << 1; + + /** + * The list is dropped down when the activation is done without + * ui-interaction + */ + public static final int DROP_DOWN_ON_PROGRAMMATIC_ACTIVATION = 1 << 2; + + /** + * The list is dropped down when the activation is done by traversing from + * cell to cell + */ + public static final int DROP_DOWN_ON_TRAVERSE_ACTIVATION = 1 << 3; + + private int activationStyle = DWT.NONE; + + /** + * Create a new cell-editor + * + * @param parent + * the parent of the combo + * @param style + * the style used to create the combo + */ + AbstractComboBoxCellEditor(Composite parent, int style) { + super(parent, style); + } + + /** + * Creates a new cell editor with no control and no st of choices. + * Initially, the cell editor has no cell validator. + * + */ + AbstractComboBoxCellEditor() { + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.CellEditor#activate(dwtx.jface.viewers.ColumnViewerEditorActivationEvent) + */ + public void activate(ColumnViewerEditorActivationEvent activationEvent) { + super.activate(activationEvent); + if (activationStyle !is DWT.NONE) { + bool dropDown = false; + if ((activationEvent.eventType is ColumnViewerEditorActivationEvent.MOUSE_CLICK_SELECTION || activationEvent.eventType is ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION) + && (activationStyle & DROP_DOWN_ON_MOUSE_ACTIVATION) !is 0 ) { + dropDown = true; + } else if (activationEvent.eventType is ColumnViewerEditorActivationEvent.KEY_PRESSED + && (activationStyle & DROP_DOWN_ON_KEY_ACTIVATION) !is 0 ) { + dropDown = true; + } else if (activationEvent.eventType is ColumnViewerEditorActivationEvent.PROGRAMMATIC + && (activationStyle & DROP_DOWN_ON_PROGRAMMATIC_ACTIVATION) !is 0) { + dropDown = true; + } else if (activationEvent.eventType is ColumnViewerEditorActivationEvent.TRAVERSAL + && (activationStyle & DROP_DOWN_ON_TRAVERSE_ACTIVATION) !is 0) { + dropDown = true; + } + + if (dropDown) { + getControl().getDisplay().asyncExec(new Runnable() { + + public void run() { + ((CCombo) getControl()).setListVisible(true); + } + + }); + + } + } + } + + /** + * This method allows to control how the combo reacts when activated + * + * @param activationStyle + * the style used + */ + public void setActivationStyle(int activationStyle) { + this.activationStyle = activationStyle; + } +} diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/AbstractListViewer.d --- a/dwtx/jface/viewers/AbstractListViewer.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/AbstractListViewer.d Thu May 22 01:36:46 2008 +0200 @@ -264,11 +264,6 @@ } } - /* (non-Javadoc) - * Method declared on Viewer. - */ - public override abstract Control getControl(); - /** * Returns the element with the given index from this list viewer. * Returns null if the index is out of range. @@ -385,24 +380,28 @@ topIndex = listGetTopIndex(); } + Object[] children = null; list.setRedraw(false); - listRemoveAll(); - - Object[] children = getSortedChildren(getRoot()); - String[] items = new String[children.length]; - - ILabelProvider labelProvider = cast(ILabelProvider) getLabelProvider(); - - for (int i = 0; i < items.length; i++) { - Object el = children[i]; - items[i] = getLabelProviderText(labelProvider, el); - listMap.append(el); - mapElement(el, list); // must map it, since findItem only looks in map, if enabled + try { + listRemoveAll(); + + children = getSortedChildren(getRoot()); + String[] items = new String[children.length]; + + ILabelProvider labelProvider = cast(ILabelProvider) getLabelProvider(); + + for (int i = 0; i < items.length; i++) { + Object el = children[i]; + items[i] = getLabelProviderText(labelProvider, el); + listMap.append(el); + mapElement(el, list); // must map it, since findItem only looks in map, if enabled + } + + listSetItems(items); + } finally { + list.setRedraw(true); } - listSetItems(items); - list.setRedraw(true); - if (topIndex is -1) { setSelectionToWidget(selection, false); } else { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/AbstractTableViewer.d --- a/dwtx/jface/viewers/AbstractTableViewer.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/AbstractTableViewer.d Thu May 22 01:36:46 2008 +0200 @@ -8,7 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation * Tom Schindl - initial API and implementation bug 154329 - * - fixes in bug 170381, 198665 + * - fixes in bug 170381, 198665, 200731 * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -257,7 +257,7 @@ */ public void add(Object[] elements) { assertElementsNotNull(elements); - if (isBusy()) + if (checkBusy()) return; Object[] filtered = filter(elements); @@ -357,8 +357,8 @@ * java.lang.Object, bool) */ protected override void doUpdateItem(Widget widget, Object element, bool fullMap) { - bool oldBusy = busy; - busy = true; + bool oldBusy = isBusy(); + setBusy(true); try { if ( auto item = cast(Item)widget ) { @@ -415,7 +415,7 @@ } } finally { - busy = oldBusy; + setBusy(oldBusy); } } @@ -622,7 +622,7 @@ if (position is -1) { position = doGetItemCount(); } - if (isBusy()) + if (checkBusy()) return; createItem(element, position); } @@ -768,12 +768,12 @@ Object input = getInput(); for (int i = 0; i < elements.length; ++i) { if (opEquals(elements[i], input)) { - bool oldBusy = busy; - busy = false; + bool oldBusy = isBusy(); + setBusy(false); try { setInput(null); } finally { - busy = oldBusy; + setBusy(oldBusy); } return; } @@ -823,7 +823,7 @@ */ public void remove( Object[] elements) { assertElementsNotNull(elements); - if (isBusy()) + if (checkBusy()) return; if (elements.length is 0) { return; @@ -1000,7 +1000,8 @@ if (count < size) { System.arraycopy(indices, 0, indices = new int[count], 0, count); } - doSetSelection(indices); + doDeselectAll(); + doSelect(indices); if (reveal && firstItem !is null) { doShowItem(firstItem); @@ -1016,7 +1017,7 @@ * @since 3.1 */ public void setItemCount(int count) { - if (isBusy()) + if (checkBusy()) return; int oldCount = doGetItemCount(); if (count < oldCount) { @@ -1048,7 +1049,7 @@ * @since 3.1 */ public void replace(Object element, int index) { - if (isBusy()) + if (checkBusy()) return; Item item = doGetItem(index); refreshItem(item, element); diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/AbstractTreeViewer.d --- a/dwtx/jface/viewers/AbstractTreeViewer.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/AbstractTreeViewer.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -8,6 +8,11 @@ * Contributors: * IBM Corporation - initial API and implementation * Tom Schindl - bug 153993, bug 167323, bug 175192 + * Lasse Knudsen, bug 205700 + * Micah Hainline, bug 210448 + * Michael Schneider, bug 210747 + * Bruce Sutton, bug 221768 + * Matthew Hall, bug 221988 * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -160,7 +165,7 @@ public void add(Object parentElementOrTreePath, Object[] childElements) { Assert.isNotNull(parentElementOrTreePath); assertElementsNotNull(childElements); - if (isBusy()) + if (checkBusy()) return; Widget[] widgets = internalFindItems(parentElementOrTreePath); // If parent hasn't been realized yet, just ignore the add. @@ -346,10 +351,6 @@ TreePath parentPath = internalGetSorterParentPath(widget, comparator); Item[] items = getChildren(widget); - // As the items are sorted already we optimize for a - // start position - int lastInsertion = 0; - // Optimize for the empty case if (items.length is 0) { for (int i = 0; i < elements.length; i++) { @@ -358,49 +359,69 @@ return; } - for (int i = 0; i < elements.length; i++) { - bool newItem = true; - Object element = elements[i]; - int index; - if (comparator is null) { + // Optimize for no comparator + if (comparator is null) { + for (int i = 0; i < elements.length; i++) { + Object element = elements[i]; if (itemExists(items, element)) { internalRefresh(element); - newItem = false; - } - index = -1; - } else { - lastInsertion = insertionPosition(items, comparator, - lastInsertion, element, parentPath); - // As we are only searching the original array we keep track of - // those positions only - if (lastInsertion is items.length) { - index = -1; - } else {// See if we should just refresh - while (lastInsertion < items.length - && internalCompare(comparator, parentPath, element, - items[lastInsertion].getData()) is 0) { - // As we cannot assume the sorter is consistent with - // equals() - therefore we can - // just check against the item prior to this index (if - // any) - if (items[lastInsertion].getData().opEquals(element)) { - // refresh the element in case it has new children - internalRefresh(element); - newItem = false; - } - lastInsertion++;// We had an insertion so increment - } - // Did we get to the end? - if (lastInsertion is items.length) { - index = -1; - } else { - index = lastInsertion + i; // Add the index as the - // array is growing - } + } else { + createTreeItem(widget, element, -1); } } - if (newItem) { - createTreeItem(widget, element, index); + return; + } + // As the items are sorted already we optimize for a + // start position. This is the insertion position relative to the + // original item array. + int indexInItems = 0; + + // Count of elements we have added. See bug 205700 for why this is needed. + int newItems = 0; + + elementloop: for (int i = 0; i < elements.length; i++) { + Object element = elements[i]; + // update the index relative to the original item array + indexInItems = insertionPosition(items, comparator, + indexInItems, element, parentPath); + if (indexInItems is items.length) { + createTreeItem(widget, element, -1); + newItems++; + } else { + // Search for an item for the element. The comparator might + // regard elements as equal when they are not. + + // Use a separate index variable to search within the existing + // elements that compare equally, see + // TreeViewerTestBug205700.testAddEquallySortedElements. + int insertionIndexInItems = indexInItems; + while( insertionIndexInItems < items.length + && internalCompare(comparator, parentPath, element, + items[insertionIndexInItems].getData()) is 0) { + // As we cannot assume the sorter is consistent with + // equals() - therefore we can + // just check against the item prior to this index (if + // any) + if (items[insertionIndexInItems].getData().opEquals(element)) { + // Found the item for the element. + // Refresh the element in case it has new children. + internalRefresh(element); + // Do not create a new item - continue with the next element. + continue elementloop; + } + insertionIndexInItems++; + } + // Did we get to the end? + if (insertionIndexInItems is items.length) { + createTreeItem(widget, element, -1); + newItems++; + } else { + // InsertionIndexInItems is the index in the original array. We + // need to correct by the number of new items we have + // created. See bug 205700. + createTreeItem(widget, element, insertionIndexInItems + newItems); + newItems++; + } } } } @@ -769,8 +790,8 @@ * the widget */ protected void createChildren(Widget widget) { - bool oldBusy = busy; - busy = true; + bool oldBusy = isBusy(); + setBusy(true); try { Item[] tis = getChildren(widget); if (tis !is null && tis.length > 0) { @@ -819,7 +840,7 @@ }); } finally { - busy = oldBusy; + setBusy(oldBusy); } } @@ -1002,8 +1023,8 @@ /* (non-Javadoc) Method declared on StructuredViewer. */ protected override void doUpdateItem(Widget widget, Object element, bool fullMap) { - bool oldBusy = busy; - busy = true; + bool oldBusy = isBusy(); + setBusy(true); try { if ( auto item = cast(Item)widget ) { @@ -1023,7 +1044,7 @@ SafeRunnable.run(new UpdateItemSafeRunnable(item, element)); } } finally { - busy = oldBusy; + setBusy(oldBusy); } } @@ -1058,7 +1079,7 @@ * levels of the tree */ public void expandToLevel(Object elementOrTreePath, int level) { - if (isBusy()) + if (checkBusy()) return; Widget w = internalExpand(elementOrTreePath, true); if (w !is null) { @@ -1076,18 +1097,24 @@ */ protected void fireTreeCollapsed(TreeExpansionEvent event) { Object[] listeners = treeListeners.getListeners(); - for (int i = 0; i < listeners.length; ++i) { - SafeRunnable.run(new class(event,cast(ITreeViewerListener) listeners[i]) SafeRunnable { - TreeExpansionEvent event_; - ITreeViewerListener l; - this(TreeExpansionEvent a,ITreeViewerListener b){ - event_=a; - l = b; - } - public void run() { - l.treeCollapsed(event_); - } - }); + bool oldBusy = isBusy(); + setBusy(true); + try { + for (int i = 0; i < listeners.length; ++i) { + SafeRunnable.run(new class(event,cast(ITreeViewerListener) listeners[i]) SafeRunnable { + TreeExpansionEvent event_; + ITreeViewerListener l; + this(TreeExpansionEvent a,ITreeViewerListener b){ + event_=a; + l = b; + } + public void run() { + l.treeCollapsed(event_); + } + }); + } + } finally { + setBusy(oldBusy); } } @@ -1101,20 +1128,25 @@ */ protected void fireTreeExpanded(TreeExpansionEvent event) { Object[] listeners = treeListeners.getListeners(); - for (int i = 0; i < listeners.length; ++i) { - SafeRunnable.run(new class( event, cast(ITreeViewerListener) listeners[i]) SafeRunnable { - TreeExpansionEvent event_; - ITreeViewerListener l; - this(TreeExpansionEvent a,ITreeViewerListener b){ - event_=a; - l = b; - } - public void run() { - l.treeExpanded(event_); - } - }); + bool oldBusy = isBusy(); + setBusy(true); + try { + for (int i = 0; i < listeners.length; ++i) { + SafeRunnable.run(new class( event, cast(ITreeViewerListener) listeners[i]) SafeRunnable { + TreeExpansionEvent event_; + ITreeViewerListener l; + this(TreeExpansionEvent a,ITreeViewerListener b){ + event_=a; + l = b; + } + public void run() { + l.treeExpanded(event_); + } + }); + } + } finally { + setBusy(oldBusy); } - } /** @@ -1323,8 +1355,8 @@ /* (non-Javadoc) Method declared on StructuredViewer. */ protected override Object[] getRawChildren(Object parentElementOrTreePath) { - bool oldBusy = busy; - busy = true; + bool oldBusy = isBusy(); + setBusy(true); try { Object parent; TreePath path; @@ -1364,7 +1396,7 @@ } return null; } finally { - busy = oldBusy; + setBusy(oldBusy); } } @@ -1475,20 +1507,15 @@ preservingSelection(new class Runnable { public void run() { Control tree = getControl(); - bool useRedraw = true; - // (size > REDRAW_THRESHOLD) || (table.getItemCount() > - // REDRAW_THRESHOLD); - if (useRedraw) { - tree.setRedraw(false); - } - removeAll(tree); - tree.setData(getRoot()); - internalInitializeTree(tree); - if (useRedraw) { + tree.setRedraw(false); + try { + removeAll(tree); + tree.setData(getRoot()); + internalInitializeTree(tree); + } finally { tree.setRedraw(true); } } - }); } @@ -1645,7 +1672,7 @@ TreePath[] paths = tpcp.getParents(elementOrTreePath); if (paths.length > 0) { if (paths[0].getSegmentCount() is 0) { - return getInput(); + return getRoot(); } return paths[0].getLastSegment(); } @@ -1896,11 +1923,28 @@ return; } Widget[] childItems = internalFindItems(element); - for (int j = 0; j < childItems.length; j++) { - Widget childItem = childItems[j]; - if ( auto it = cast(Item)childItem ) { - disassociate(it); - childItem.dispose(); + if (childItems.length > 0) { + for (int j = 0; j < childItems.length; j++) { + Widget childItem = childItems[j]; + if ( auto it = cast(Item)childItem ) { + disassociate(it); + childItem.dispose(); + } + } + } else { + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=210747 + Object parent = getParentElement(element); + if (parent !is null + && !equals(parent, getRoot()) + && !(parent instanceof TreePath && ((TreePath) parent) + .getSegmentCount() is 0)) { + Widget[] parentItems = internalFindItems(parent); + for (int j = 0; j < parentItems.length; j++) { + Widget parentItem = parentItems[j]; + if (parentItem instanceof Item) { + updatePlus((Item) parentItem, parent); + } + } } } } @@ -1927,16 +1971,27 @@ for (int i = 0; i < parentItemArray.length; i++) { Widget parentItem = parentItemArray[i]; + // May happen if parent element is a descendent of of a previously + // removed element + if (parentItem.isDisposed()) + continue; + // Iterate over the child items and remove each one Item[] children = getChildren(parentItem); - for (int j = 0; j < children.length; j++) { - Item child = children[j]; + if (children.length is 1 && children[0].getData() is null && + parentItem instanceof Item) { // dummy node + // Remove plus if parent element has no children + updatePlus((Item) parentItem, parent); + } else { + for (int j = 0; j < children.length; j++) { + Item child = children[j]; - Object data = child.getData(); - if (data !is null && toRemove.containsKey(data)) { - disassociate(child); - child.dispose(); + Object data = child.getData(); + if (data !is null && toRemove.containsKey(data)) { + disassociate(child); + child.dispose(); + } } } } @@ -2119,7 +2174,7 @@ if (elementsOrTreePaths.length is 0) { return; } - if (isBusy()) + if (checkBusy()) return; preservingSelection(new class(elementsOrTreePaths) Runnable { Object[] elementsOrTreePaths_; @@ -2155,7 +2210,7 @@ if (elements.length is 0) { return; } - if (isBusy()) + if (checkBusy()) return; preservingSelection(new class(parent,elements) Runnable { Object parent_; @@ -2258,14 +2313,22 @@ } /** - * Sets the auto-expand level. The value 0 means that there is no - * auto-expand; 1 means that top-level elements are expanded, but not their - * children; 2 means that top-level elements are expanded, and their - * children, but not grandchildren; and so on. + * Sets the auto-expand level to be used when the input of the viewer is set + * using {@link #setInput(Object)}. The value 0 means that there is no + * auto-expand; 1 means that the invisible root element is expanded (since + * most concrete subclasses do not show the root element, there is usually + * no practical difference between using the values 0 and 1); 2 means that + * top-level elements are expanded, but not their children; 3 means that + * top-level elements are expanded, and their children, but not + * grandchildren; and so on. *

* The value ALL_LEVELS means that all subtrees should be * expanded. *

+ *

+ * Note that in previous releases, the Javadoc for this method had an off-by + * one error. See bug 177669 for details. + *

* * @param level * non-negative level, or ALL_LEVELS to expand all @@ -2315,7 +2378,7 @@ */ public void setExpandedElements(Object[] elements) { assertElementsNotNull(elements); - if (isBusy()) { + if (checkBusy()) { return; } CustomHashtable expandedElements = newHashtable(elements.length * 2 + 1); @@ -2352,7 +2415,7 @@ */ public void setExpandedTreePaths(TreePath[] treePaths) { assertElementsNotNull(treePaths); - if (isBusy()) + if (checkBusy()) return; IElementComparer treePathComparer = new class(getComparer()) IElementComparer { IElementComparer comparer; @@ -2398,7 +2461,7 @@ */ public void setExpandedState(Object elementOrTreePath, bool expanded) { Assert.isNotNull(elementOrTreePath); - if (isBusy()) + if (checkBusy()) return; Widget item = internalExpand(elementOrTreePath, false); if ( cast(Item)item ) { @@ -2452,10 +2515,14 @@ // Although setting the selection in the control should reveal it, // setSelection may be a no-op if the selection is unchanged, - // so explicitly reveal the first item in the selection here. + // so explicitly reveal items in the selection here. // See bug 100565 for more details. if (reveal && newSelection.size() > 0) { - showItem(cast(Item) newSelection.get(0)); + // Iterate backwards so the first item in the list + // is the one guaranteed to be visible + for (int i = (newSelection.size()-1); i >= 0; i--) { + showItem(cast(Item) newSelection.get(i)); + } } } @@ -2552,8 +2619,8 @@ oldCnt = getItemCount(tree); } - Item[] items = getChildren(widget); - + Item[] items = getChildren(widget,elementChildren); + // save the expanded elements CustomHashtable expanded = newHashtable(CustomHashtable.DEFAULT_CAPACITY); // assume // num @@ -2700,6 +2767,20 @@ } /** + * Return the items to be refreshed as part of an update. elementChildren are the + * new elements. + * @param widget + * @param elementChildren + * @since 3.4 + * @return Item[] + * NOTE: This API is experimental and may be deleted + * before 3.4 is released. + */ + public Item[] getChildren(Widget widget, Object[] elementChildren) { + return getChildren(widget); + } + + /** * Updates the "+"/"-" icon of the tree node from the given element. It * calls isExpandable to determine whether an element is * expandable. @@ -2891,7 +2972,7 @@ int position) { Assert.isNotNull(parentElementOrTreePath); Assert.isNotNull(element); - if (isBusy()) + if (checkBusy()) return; if (getComparator() !is null || hasFilters()) { add(parentElementOrTreePath, [ element ]); @@ -2918,6 +2999,11 @@ } createTreeItem(item, element, insertionPosition); + } else { + Object parentElement = parentElementOrTreePath; + if (element instanceof TreePath) + parentElement = ((TreePath) parentElement).getLastSegment(); + updatePlus(item, parentElement); } } else { int insertionPosition = position; @@ -3010,7 +3096,7 @@ * @since 3.3 */ final protected bool internalIsInputOrEmptyPath(Object elementOrTreePath) { - if (elementOrTreePath.opEquals(getInput())) + if (elementOrTreePath.opEquals(getRoot())) return true; if (!(cast(TreePath)elementOrTreePath )) return false; diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/CellEditor.d --- a/dwtx/jface/viewers/CellEditor.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/CellEditor.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Tom Schindl - bugfix in: 187963, 218336 * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -21,6 +22,7 @@ import dwt.events.KeyEvent; import dwt.widgets.Composite; import dwt.widgets.Control; +import dwt.widgets.Display; import dwtx.core.runtime.Assert; import dwtx.core.runtime.ListenerList; import dwtx.jface.util.IPropertyChangeListener; @@ -30,8 +32,8 @@ import dwt.dwthelper.utils; /** - * Struct-like layout data for cell editors, with reasonable defaults - * for all fields. + * Struct-like layout data for cell editors, with reasonable defaults for + * all fields. */ public static class LayoutData { /** @@ -40,7 +42,8 @@ public int horizontalAlignment = DWT.LEFT; /** - * Indicates control grabs additional space; true by default. + * Indicates control grabs additional space; true by + * default. */ public bool grabHorizontal = true; @@ -48,32 +51,45 @@ * Minimum width in pixels; 50 pixels by default. */ public int minimumWidth = 50; + + /** + * Minimum height in pixels; by default the height is aligned to the + * row-height + */ + public int minimumHeight = DWT.DEFAULT; + + /** + * The vertical alignment; DWT.CENTER by default. + */ + public int verticalAlignment = DWT.CENTER; } /** - * Abstract base class for cell editors. Implements property change listener handling, - * and DWT window management. + * Abstract base class for cell editors. Implements property change listener + * handling, and DWT window management. *

- * Subclasses implement particular kinds of cell editors. This package contains various - * specialized cell editors: + * Subclasses implement particular kinds of cell editors. This package contains + * various specialized cell editors: *

    - *
  • TextCellEditor - for simple text strings
  • - *
  • ColorCellEditor - for colors
  • - *
  • ComboBoxCellEditor - value selected from drop-down combo box
  • - *
  • CheckboxCellEditor - bool valued checkbox
  • - *
  • DialogCellEditor - value from arbitrary dialog
  • + *
  • TextCellEditor - for simple text strings
  • + *
  • ColorCellEditor - for colors
  • + *
  • ComboBoxCellEditor - value selected from drop-down combo + * box
  • + *
  • CheckboxCellEditor - bool valued checkbox
  • + *
  • DialogCellEditor - value from arbitrary dialog
  • *
*

*/ public abstract class CellEditor { /** - * List of cell editor listeners (element type: ICellEditorListener). + * List of cell editor listeners (element type: + * ICellEditorListener). */ private ListenerList listeners; /** - * List of cell editor property change listeners - * (element type: IPropertyChangeListener). + * List of cell editor property change listeners (element type: + * IPropertyChangeListener). */ private ListenerList propertyChangeListeners; @@ -88,8 +104,8 @@ private ICellEditorValidator validator = null; /** - * The error message string to display for invalid values; - * null if none (that is, the value is valid). + * The error message string to display for invalid values; null + * if none (that is, the value is valid). */ private String errorMessage = null; @@ -99,8 +115,7 @@ private bool dirty = false; /** - * This cell editor's control, or null - * if not created yet. + * This cell editor's control, or null if not created yet. */ private Control control = null; @@ -156,8 +171,9 @@ public static const String UNDO = "undo"; //$NON-NLS-1$ /** - * Creates a new cell editor with no control - * The cell editor has no cell validator. + * Creates a new cell editor with no control The cell editor has no cell + * validator. + * * @since 2.1 */ protected this() { @@ -166,21 +182,24 @@ } /** - * Creates a new cell editor under the given parent control. - * The cell editor has no cell validator. + * Creates a new cell editor under the given parent control. The cell editor + * has no cell validator. * - * @param parent the parent control + * @param parent + * the parent control */ protected this(Composite parent) { this(parent, defaultStyle); } /** - * Creates a new cell editor under the given parent control. - * The cell editor has no cell validator. + * Creates a new cell editor under the given parent control. The cell editor + * has no cell validator. * - * @param parent the parent control - * @param style the style bits + * @param parent + * the parent control + * @param style + * the style bits * @since 2.1 */ protected this(Composite parent, int style) { @@ -193,29 +212,30 @@ /** * Activates this cell editor. *

- * The default implementation of this framework method - * does nothing. Subclasses may reimplement. + * The default implementation of this framework method does nothing. + * Subclasses may reimplement. *

*/ public void activate() { } /** - * Adds a listener to this cell editor. - * Has no effect if an identical listener is already registered. + * Adds a listener to this cell editor. Has no effect if an identical + * listener is already registered. * - * @param listener a cell editor listener + * @param listener + * a cell editor listener */ public void addListener(ICellEditorListener listener) { listeners.add(cast(Object)listener); } /** - * Adds a property change listener to this cell editor. - * Has no effect if an identical property change listener - * is already registered. + * Adds a property change listener to this cell editor. Has no effect if an + * identical property change listener is already registered. * - * @param listener a property change listener + * @param listener + * a property change listener */ public void addPropertyChangeListener(IPropertyChangeListener listener) { propertyChangeListeners.add(cast(Object)listener); @@ -224,19 +244,21 @@ /** * Creates the control for this cell editor under the given parent control. *

- * This framework method must be implemented by concrete - * subclasses. + * This framework method must be implemented by concrete subclasses. *

* - * @param parent the parent control - * @return the new control, or null if this cell editor has no control + * @param parent + * the parent control + * @return the new control, or null if this cell editor has + * no control */ protected abstract Control createControl(Composite parent); /** * Creates the control for this cell editor under the given parent control. * - * @param parent the parent control + * @param parent + * the parent control * @since 2.1 */ public void create(Composite parent) { @@ -245,14 +267,15 @@ // See 1GD5CA6: ITPUI:ALL - TaskView.setSelection does not work // Control is created with getVisible()istrue by default. // This causes composite.setFocus() to work incorrectly. - // The cell editor's control grabs focus instead, even if it is not active. + // The cell editor's control grabs focus instead, even if it is not + // active. // Make the control invisible here by default. deactivate(); } /** - * Hides this cell editor's control. Does nothing if this - * cell editor is not visible. + * Hides this cell editor's control. Does nothing if this cell editor is not + * visible. */ public void deactivate() { if (control !is null && !control.isDisposed()) { @@ -297,14 +320,15 @@ * This framework method must be implemented by concrete subclasses. *

* - * @param value the value of this cell editor + * @param value + * the value of this cell editor * @see #setValue */ protected abstract void doSetValue(Object value); /** - * Notifies all registered cell editor listeners of an apply event. - * Only listeners registered at the time this method is called are notified. + * Notifies all registered cell editor listeners of an apply event. Only + * listeners registered at the time this method is called are notified. * * @see ICellEditorListener#applyEditorValue */ @@ -347,8 +371,10 @@ /** * Notifies all registered cell editor listeners of a value change. * - * @param oldValidState the valid state before the end user changed the value - * @param newValidState the current valid state + * @param oldValidState + * the valid state before the end user changed the value + * @param newValidState + * the current valid state * @see ICellEditorListener#editorValueChanged */ protected void fireEditorValueChanged(bool oldValidState, @@ -372,10 +398,10 @@ } /** - * Notifies all registered property listeners - * of an enablement change. + * Notifies all registered property listeners of an enablement change. * - * @param actionId the id indicating what action's enablement has changed. + * @param actionId + * the id indicating what action's enablement has changed. */ protected void fireEnablementChanged(String actionId) { Object[] array = propertyChangeListeners.getListeners(); @@ -398,7 +424,8 @@ /** * Sets the style bits for this cell editor. * - * @param style the DWT style bits for this cell editor + * @param style + * the DWT style bits for this cell editor * @since 2.1 */ public void setStyle(int style) { @@ -418,7 +445,8 @@ /** * Returns the control used to implement this cell editor. * - * @return the control, or null if this cell editor has no control + * @return the control, or null if this cell editor has no + * control */ public Control getControl() { return control; @@ -427,21 +455,20 @@ /** * Returns the current error message for this cell editor. * - * @return the error message if the cell editor is in an invalid state, - * and null if the cell editor is valid + * @return the error message if the cell editor is in an invalid state, and + * null if the cell editor is valid */ public String getErrorMessage() { return errorMessage; } /** - * Returns a layout data object for this cell editor. - * This is called each time the cell editor is activated - * and controls the layout of the DWT table editor. + * Returns a layout data object for this cell editor. This is called each + * time the cell editor is activated and controls the layout of the DWT + * table editor. *

- * The default implementation of this method sets the - * minimum width to the control's preferred width. - * Subclasses may extend or reimplement. + * The default implementation of this method sets the minimum width to the + * control's preferred width. Subclasses may extend or reimplement. *

* * @return the layout data object @@ -468,8 +495,8 @@ /** * Returns this cell editor's value provided that it has a valid one. * - * @return the value of this cell editor, or null - * if the cell editor does not contain a valid value + * @return the value of this cell editor, or null if the cell + * editor does not contain a valid value */ public final Object getValue() { if (!valid) { @@ -482,8 +509,8 @@ /** * Returns whether this cell editor is activated. * - * @return true if this cell editor's control is - * currently activated, and false if not activated + * @return true if this cell editor's control is currently + * activated, and false if not activated */ public bool isActivated() { // Use the state of the visible style bit (getVisible()) rather than the @@ -493,29 +520,31 @@ } /** - * Returns true if this cell editor is - * able to perform the copy action. + * Returns true if this cell editor is able to perform the + * copy action. *

- * This default implementation always returns - * false. + * This default implementation always returns false. *

*

* Subclasses may override *

- * @return true if copy is possible, - * false otherwise + * + * @return true if copy is possible, false + * otherwise */ public bool isCopyEnabled() { return false; } /** - * Returns whether the given value is valid for this cell editor. - * This cell editor's validator (if any) makes the actual determination. - * @param value the value to check for + * Returns whether the given value is valid for this cell editor. This cell + * editor's validator (if any) makes the actual determination. + * + * @param value + * the value to check for * * @return true if the value is valid, and false - * if invalid + * if invalid */ protected bool isCorrect(Object value) { errorMessage = null; @@ -528,45 +557,45 @@ } /** - * Returns true if this cell editor is - * able to perform the cut action. + * Returns true if this cell editor is able to perform the + * cut action. *

- * This default implementation always returns - * false. + * This default implementation always returns false. *

*

* Subclasses may override *

- * @return true if cut is possible, - * false otherwise + * + * @return true if cut is possible, false + * otherwise */ public bool isCutEnabled() { return false; } /** - * Returns true if this cell editor is - * able to perform the delete action. + * Returns true if this cell editor is able to perform the + * delete action. *

- * This default implementation always returns - * false. + * This default implementation always returns false. *

*

* Subclasses may override *

- * @return true if delete is possible, - * false otherwise + * + * @return true if delete is possible, false + * otherwise */ public bool isDeleteEnabled() { return false; } /** - * Returns whether the value of this cell editor has changed since the - * last call to setValue. + * Returns whether the value of this cell editor has changed since the last + * call to setValue. * - * @return true if the value has changed, and false - * if unchanged + * @return true if the value has changed, and + * false if unchanged */ public bool isDirty() { return dirty; @@ -574,6 +603,7 @@ /** * Marks this cell editor as dirty. + * * @since 2.1 */ protected void markDirty() { @@ -581,96 +611,96 @@ } /** - * Returns true if this cell editor is - * able to perform the find action. + * Returns true if this cell editor is able to perform the + * find action. *

- * This default implementation always returns - * false. + * This default implementation always returns false. *

*

* Subclasses may override *

- * @return true if find is possible, - * false otherwise + * + * @return true if find is possible, false + * otherwise */ public bool isFindEnabled() { return false; } /** - * Returns true if this cell editor is - * able to perform the paste action. + * Returns true if this cell editor is able to perform the + * paste action. *

- * This default implementation always returns - * false. + * This default implementation always returns false. *

*

* Subclasses may override *

- * @return true if paste is possible, - * false otherwise + * + * @return true if paste is possible, false + * otherwise */ public bool isPasteEnabled() { return false; } /** - * Returns true if this cell editor is - * able to perform the redo action. + * Returns true if this cell editor is able to perform the + * redo action. *

- * This default implementation always returns - * false. + * This default implementation always returns false. *

*

* Subclasses may override *

- * @return true if redo is possible, - * false otherwise + * + * @return true if redo is possible, false + * otherwise */ public bool isRedoEnabled() { return false; } /** - * Returns true if this cell editor is - * able to perform the select all action. + * Returns true if this cell editor is able to perform the + * select all action. *

- * This default implementation always returns - * false. + * This default implementation always returns false. *

*

* Subclasses may override *

- * @return true if select all is possible, - * false otherwise + * + * @return true if select all is possible, false + * otherwise */ public bool isSelectAllEnabled() { return false; } /** - * Returns true if this cell editor is - * able to perform the undo action. + * Returns true if this cell editor is able to perform the + * undo action. *

- * This default implementation always returns - * false. + * This default implementation always returns false. *

*

* Subclasses may override *

- * @return true if undo is possible, - * false otherwise + * + * @return true if undo is possible, false + * otherwise */ public bool isUndoEnabled() { return false; } /** - * Returns whether this cell editor has a valid value. - * The default value is false. + * Returns whether this cell editor has a valid value. The default value is + * false. * * @return true if the value is valid, and false - * if invalid + * if invalid * * @see #setValueValid(bool) */ @@ -681,14 +711,14 @@ /** * Processes a key release event that occurred in this cell editor. *

- * The default implementation of this framework method cancels editing - * when the ESC key is pressed. When the RETURN key is pressed the current - * value is applied and the cell editor deactivates. - * Subclasses should call this method at appropriate times. - * Subclasses may also extend or reimplement. + * The default implementation of this framework method cancels editing when + * the ESC key is pressed. When the RETURN key is pressed the current value + * is applied and the cell editor deactivates. Subclasses should call this + * method at appropriate times. Subclasses may also extend or reimplement. *

* - * @param keyEvent the key event + * @param keyEvent + * the key event */ protected void keyReleaseOccured(KeyEvent keyEvent) { if (keyEvent.character is '\u001b') { // Escape character @@ -703,9 +733,8 @@ * Processes a focus lost event that occurred in this cell editor. *

* The default implementation of this framework method applies the current - * value and deactivates the cell editor. - * Subclasses should call this method at appropriate times. - * Subclasses may also extend or reimplement. + * value and deactivates the cell editor. Subclasses should call this method + * at appropriate times. Subclasses may also extend or reimplement. *

*/ protected void focusLost() { @@ -716,8 +745,7 @@ } /** - * Performs the copy action. - * This default implementation does nothing. + * Performs the copy action. This default implementation does nothing. *

* Subclasses may override *

@@ -726,8 +754,7 @@ } /** - * Performs the cut action. - * This default implementation does nothing. + * Performs the cut action. This default implementation does nothing. *

* Subclasses may override *

@@ -736,8 +763,7 @@ } /** - * Performs the delete action. - * This default implementation does nothing. + * Performs the delete action. This default implementation does nothing. *

* Subclasses may override *

@@ -746,8 +772,7 @@ } /** - * Performs the find action. - * This default implementation does nothing. + * Performs the find action. This default implementation does nothing. *

* Subclasses may override *

@@ -756,8 +781,7 @@ } /** - * Performs the paste action. - * This default implementation does nothing. + * Performs the paste action. This default implementation does nothing. *

* Subclasses may override *

@@ -766,8 +790,7 @@ } /** - * Performs the redo action. - * This default implementation does nothing. + * Performs the redo action. This default implementation does nothing. *

* Subclasses may override *

@@ -776,8 +799,7 @@ } /** - * Performs the select all action. - * This default implementation does nothing. + * Performs the select all action. This default implementation does nothing. *

* Subclasses may override *

@@ -786,8 +808,7 @@ } /** - * Performs the undo action. - * This default implementation does nothing. + * Performs the undo action. This default implementation does nothing. *

* Subclasses may override *

@@ -796,21 +817,22 @@ } /** - * Removes the given listener from this cell editor. - * Has no affect if an identical listener is not registered. + * Removes the given listener from this cell editor. Has no affect if an + * identical listener is not registered. * - * @param listener a cell editor listener + * @param listener + * a cell editor listener */ public void removeListener(ICellEditorListener listener) { listeners.remove(cast(Object)listener); } /** - * Removes the given property change listener from this cell editor. - * Has no affect if an identical property change listener is not - * registered. + * Removes the given property change listener from this cell editor. Has no + * affect if an identical property change listener is not registered. * - * @param listener a property change listener + * @param listener + * a property change listener */ public void removePropertyChangeListener(IPropertyChangeListener listener) { propertyChangeListeners.remove(cast(Object)listener); @@ -819,10 +841,12 @@ /** * Sets or clears the current error message for this cell editor. *

- * No formatting is done here, the message to be set is expected to be fully formatted - * before being passed in. + * No formatting is done here, the message to be set is expected to be fully + * formatted before being passed in. *

- * @param message the error message, or null to clear + * + * @param message + * the error message, or null to clear */ protected void setErrorMessage(String message) { errorMessage = message; @@ -838,7 +862,8 @@ /** * Sets the input validator for this cell editor. * - * @param validator the input validator, or null if none + * @param validator + * the input validator, or null if none */ public void setValidator(ICellEditorValidator validator) { this.validator = validator; @@ -847,7 +872,8 @@ /** * Sets this cell editor's value. * - * @param value the value of this cell editor + * @param value + * the value of this cell editor */ public final void setValue(Object value) { valid = isCorrect(value); @@ -856,12 +882,12 @@ } /** - * Sets the valid state of this cell editor. - * The default value is false. + * Sets the valid state of this cell editor. The default value is false. * Subclasses should call this method on construction. * - * @param valid true if the current value is valid, - * and false if invalid + * @param valid + * true if the current value is valid, and + * false if invalid * * @see #isValueValid */ @@ -870,12 +896,14 @@ } /** - * The value has changed. - * Updates the valid state flag, marks this cell editor as dirty, - * and notifies all registered cell editor listeners of a value change. + * The value has changed. Updates the valid state flag, marks this cell + * editor as dirty, and notifies all registered cell editor listeners of a + * value change. * - * @param oldValidState the valid state before the end user changed the value - * @param newValidState the current valid state + * @param oldValidState + * the valid state before the end user changed the value + * @param newValidState + * the current valid state * @see ICellEditorListener#editorValueChanged */ protected void valueChanged(bool oldValidState, bool newValidState) { @@ -885,10 +913,12 @@ } /** - * Activate the editor but also inform the editor which event triggered its activation. - * The default implementation simply calls {@link #activate()} + * Activate the editor but also inform the editor which event triggered its + * activation. The default implementation simply calls + * {@link #activate()} * - * @param activationEvent the editor activation event + * @param activationEvent + * the editor activation event * @since 3.3 */ public void activate(ColumnViewerEditorActivationEvent activationEvent) { @@ -896,12 +926,38 @@ } /** - * This method is for interal use in {@link ColumnViewerEditor} to not break clients - * who don't implement the {@link ICellEditorListener} appropiately + * The default implementation of this method returns true. Subclasses that + * hook their own focus listener should override this method and return + * false. See also bug 58777. * - * @return true to indicate that a focus listener has to be attached + * @return true to indicate that a focus listener has to be + * attached + * @since 3.4 */ - bool dependsOnExternalFocusListener() { + protected bool dependsOnExternalFocusListener() { return true; } + + /** + * @param event + * deactivation event + * + */ + protected void deactivate(ColumnViewerEditorDeactivationEvent event) { + deactivate(); + } + + /** + * Returns the duration, in milliseconds, between the mouse button click + * that activates the cell editor and a subsequent mouse button click that + * will be considered a double click on the underlying control. + * Clients may override, in particular, clients can return 0 to denote that + * two subsequent mouse clicks in a cell should not be interpreted as a + * double click. + * + * @return the timeout or 0 + */ + protected int getDoubleClickTimeout() { + return Display.getCurrent().getDoubleClickTime(); + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/CellLabelProvider.d --- a/dwtx/jface/viewers/CellLabelProvider.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/CellLabelProvider.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 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 @@ -236,5 +236,39 @@ * {@link ViewerCell} */ public abstract void update(ViewerCell cell); + + /** + * Initialize this label provider for use with the given column viewer for + * the given column. Subclasses may extend but should call the super + * implementation (which at this time is empty but may be changed in the + * future). + * + * @param viewer + * the viewer + * @param column + * the column, or null if a column is not + * available. + * + * @since 3.4 + */ + protected void initialize(ColumnViewer viewer, ViewerColumn column) { + } + /** + * Dispose of this label provider which was used with the given column + * viewer and column. Subclasses may extend but should call the super + * implementation (which calls {@link #dispose()}). + * + * @param viewer + * the viewer + * @param column + * the column, or null if a column is not + * available. + * + * @since 3.4 + */ + public void dispose(ColumnViewer viewer, ViewerColumn column) { + dispose(); + } + } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/CheckboxCellEditor.d --- a/dwtx/jface/viewers/CheckboxCellEditor.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/CheckboxCellEditor.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2006 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 @@ -103,12 +103,12 @@ /** * The CheckboxCellEditor implementation of * this CellEditor framework method returns - * the checkbox setting wrapped as a bool. + * the checkbox setting wrapped as a Boolean. * - * @return the bool checkbox value + * @return the Boolean checkbox value */ protected override Object doGetValue() { - return new ValueWrapperBool( value ); + return value ? Boolean.TRUE : Boolean.FALSE; } /* (non-Javadoc) @@ -121,13 +121,13 @@ /** * The CheckboxCellEditor implementation of * this CellEditor framework method accepts - * a value wrapped as a bool. + * a value wrapped as a Boolean. * - * @param value a bool value + * @param value a Boolean value */ protected override void doSetValue(Object value) { - Assert.isTrue( null !is cast(ValueWrapperBool)value ); - this.value = (cast(ValueWrapperBool) value).value; + Assert.isTrue( null !is cast(Boolean)value ); + this.value = (cast(Boolean) value).booleanValue(); } public override void activate(ColumnViewerEditorActivationEvent activationEvent) { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/CheckboxTreeViewer.d --- a/dwtx/jface/viewers/CheckboxTreeViewer.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/CheckboxTreeViewer.d Thu May 22 01:36:46 2008 +0200 @@ -576,9 +576,16 @@ /** * Sets to the given value the checked state for all elements in this viewer. * Does not fire events to check state listeners. + * Assumes that the element has been expanded before. To enforce + * that the item is expanded, call expandToLevel + * for the element. * * @param state true if the element should be checked, * and false if it should be unchecked + * @deprecated as this method only checks or unchecks visible items + * is is recommended that {@link #setSubtreeChecked(Object, bool)} + * is used instead. + * @see #setSubtreeChecked(Object, bool) * * @since 3.2 */ @@ -588,9 +595,11 @@ } /** - * Set the checked state of items and their children to state. + * Set the checked state of the visible items and their children to state. * @param state * @param items + * @deprecated + * @see #setAllChecked(bool) */ private void setAllChecked(bool state, TreeItem[] items) { for (int i = 0; i < items.length; i++) { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/ColumnViewer.d --- a/dwtx/jface/viewers/ColumnViewer.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/ColumnViewer.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 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 @@ -8,7 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation * Tom Schindl - initial API and implementation; bug 153993 - * fix in bug 163317, 151295, 167323, 167858, 184346, 187826, 200558,201002 + * fix in bug 163317, 151295, 167323, 167858, 184346, 187826, 201905 * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -29,7 +29,6 @@ import dwtx.jface.viewers.ITableLabelProvider; import dwtx.jface.viewers.ILabelProvider; import dwtx.jface.viewers.StructuredSelection; - import dwt.events.MouseAdapter; import dwt.events.MouseEvent; import dwt.graphics.Point; @@ -47,14 +46,14 @@ /** * The ColumnViewer is the abstract superclass of viewers that have columns * (e.g., AbstractTreeViewer and AbstractTableViewer). Concrete subclasses of - * {@link ColumnViewer} should implement a matching concrete subclass of - * {@link ViewerColumn}. - * + * {@link ColumnViewer} should implement a matching concrete subclass of {@link + * ViewerColumn}. + * * This class is not intended to be subclassed outside of the JFace * viewers framework. - * + * * @since 3.3 - * + * */ public abstract class ColumnViewer : StructuredViewer { alias StructuredViewer.getLabelProvider getLabelProvider; @@ -74,8 +73,11 @@ private ColumnViewerEditor viewerEditor; - /* package */ bool busy; - /* package */ bool logWhenBusy = true; // initially true, set to false after logging for the first time + private bool busy; + private bool logWhenBusy = true; // initially true, set to false + + // after logging for the first + // time /** * Create a new instance of the receiver. @@ -84,27 +86,6 @@ cell = new ViewerCell(null, 0, null); } - /* package */ bool isBusy() { - if (busy) { - if (logWhenBusy) { - String message = "Ignored reentrant call while viewer is busy."; //$NON-NLS-1$ - if (!InternalPolicy.DEBUG_LOG_REENTRANT_VIEWER_CALLS) { - // stop logging after the first - logWhenBusy = false; - message ~= " This is only logged once per viewer instance," ~ //$NON-NLS-1$ - " but similar calls will still be ignored."; //$NON-NLS-1$ - } - Policy.getLog().log( - new Status( - IStatus.WARNING, - Policy.JFACE, - message, new RuntimeException())); - } - return true; - } - return false; - } - protected override void hookControl(Control control) { super.hookControl(control); viewerEditor = createViewerEditor(); @@ -113,9 +94,9 @@ /** * Hook up the editing support. Subclasses may override. - * + * * @param control - * the control you want to hook on + * the control you want to hook on */ protected void hookEditingSupport(Control control) { // Needed for backwards comp with AbstractTreeViewer and TableTreeViewer @@ -126,7 +107,7 @@ control.addMouseListener(new class MouseAdapter { public void mouseDown(MouseEvent e) { // Workaround for bug 185817 - if( e.count !is 2 ) { + if (e.count !is 2) { handleMouseDown(e); } } @@ -141,22 +122,24 @@ /** * Creates the viewer editor used for editing cell contents. To be * implemented by subclasses. - * - * @return the editor, or null if this viewer does not - * support editing cell contents. + * + * @return the editor, or null if this viewer does not support + * editing cell contents. */ protected abstract ColumnViewerEditor createViewerEditor(); /** * Returns the viewer cell at the given widget-relative coordinates, or * null if there is no cell at that location - * + * * @param point - * the widget-relative coordinates + * the widget-relative coordinates * @return the cell or null if no cell is found at the given - * point + * point + * + * @since 3.4 */ - ViewerCell getCell(Point point) { + public ViewerCell getCell(Point point) { ViewerRow row = getViewerRow(point); if (row !is null) { return row.getCell(point); @@ -167,11 +150,11 @@ /** * Returns the viewer row at the given widget-relative coordinates. - * + * * @param point - * the widget-relative coordinates of the viewer row - * @return ViewerRow the row or null if no row is found at - * the given coordinates + * the widget-relative coordinates of the viewer row + * @return ViewerRow the row or null if no row is found at the + * given coordinates */ protected ViewerRow getViewerRow(Point point) { Item item = getItemAt(point); @@ -186,14 +169,14 @@ return getViewerRow(point); } - - /** - * Returns a {@link ViewerRow} associated with the given row widget. Implementations - * may re-use the same instance for different row widgets; callers can only use the viewer - * row locally and until the next call to this method. - * - * @param item the row widget + * Returns a {@link ViewerRow} associated with the given row widget. + * Implementations may re-use the same instance for different row widgets; + * callers can only use the viewer row locally and until the next call to + * this method. + * + * @param item + * the row widget * @return ViewerRow a viewer row object */ protected abstract ViewerRow getViewerRowFromItem(Widget item); @@ -203,27 +186,27 @@ /** * Returns the column widget at the given column index. - * + * * @param columnIndex - * the column index + * the column index * @return Widget the column widget */ protected abstract Widget getColumnViewerOwner(int columnIndex); /** * Returns the viewer column for the given column index. - * + * * @param columnIndex - * the column index + * the column index * @return the viewer column at the given index, or null if - * there is none for the given index + * there is none for the given index */ /* package */ViewerColumn getViewerColumn(int columnIndex) { ViewerColumn viewer; Widget columnOwner = getColumnViewerOwner(columnIndex); - if (columnOwner is null) { + if (columnOwner is null || columnOwner.isDisposed()) { return null; } @@ -245,7 +228,7 @@ /** * Sets up editing support for the given column based on the "old" cell * editor API. - * + * * @param columnIndex * @param viewer */ @@ -259,13 +242,15 @@ } /* * (non-Javadoc) - * - * @see dwtx.jface.viewers.EditingSupport#canEdit(java.lang.Object) + * + * @see + * dwtx.jface.viewers.EditingSupport#canEdit(java.lang + * .Object) */ public bool canEdit(Object element) { Object[] properties = getColumnProperties(); - if( columnIndex_ < properties.length ) { + if (columnIndex_ < properties.length ) { return getCellModifier().canModify(element, (cast(ArrayWrapperString) getColumnProperties()[columnIndex_]).array); } @@ -275,12 +260,14 @@ /* * (non-Javadoc) - * - * @see dwtx.jface.viewers.EditingSupport#getCellEditor(java.lang.Object) + * + * @see + * dwtx.jface.viewers.EditingSupport#getCellEditor(java + * .lang.Object) */ public CellEditor getCellEditor(Object element) { CellEditor[] editors = getCellEditors(); - if( columnIndex_ < editors.length ) { + if (columnIndex_ < editors.length ) { return getCellEditors()[columnIndex_]; } return null; @@ -288,13 +275,15 @@ /* * (non-Javadoc) - * - * @see dwtx.jface.viewers.EditingSupport#getValue(java.lang.Object) + * + * @see + * dwtx.jface.viewers.EditingSupport#getValue(java.lang + * .Object) */ public Object getValue(Object element) { Object[] properties = getColumnProperties(); - if( columnIndex_ < properties.length ) { + if (columnIndex_ < properties.length) { return getCellModifier().getValue(element, (cast(ArrayWrapperString) getColumnProperties()[columnIndex_]).array); } @@ -304,16 +293,18 @@ /* * (non-Javadoc) - * - * @see dwtx.jface.viewers.EditingSupport#setValue(java.lang.Object, - * java.lang.Object) + * + * @see + * dwtx.jface.viewers.EditingSupport#setValue(java.lang + * .Object, java.lang.Object) */ public void setValue(Object element, Object value) { Object[] properties = getColumnProperties(); - if( columnIndex_ < properties.length ) { + if (columnIndex_ < properties.length) { getCellModifier().modify(findItem(element), - (cast(ArrayWrapperString) getColumnProperties()[columnIndex_]).array, value); + (cast(ArrayWrapperString) getColumnProperties()[columnIndex_]).array, + value); } } @@ -327,11 +318,11 @@ /** * Creates a generic viewer column for the given column widget, based on the * given label provider. - * + * * @param columnOwner - * the column widget + * the column widget * @param labelProvider - * the label provider to use for the column + * the label provider to use for the column * @return ViewerColumn the viewer column */ private ViewerColumn createViewerColumn(Widget columnOwner, @@ -346,16 +337,14 @@ } /** - * Update the cached cell object with the given row and column. Be careful not - * to hold on to element objects longer than required. It is good practice to - * call updateCell(null, 0, null) to clear references immediately after using - * the cached cell object. (See bug 201280 for an example case where this happened.) - * + * Update the cached cell object with the given row and column. + * * @param rowItem * @param column * @return ViewerCell */ - /* package */ViewerCell updateCell(ViewerRow rowItem, int column, Object element) { + /* package */ViewerCell updateCell(ViewerRow rowItem, int column, + Object element) { cell.update(rowItem, column, element); return cell; } @@ -363,17 +352,17 @@ /** * Returns the {@link Item} at the given widget-relative coordinates, or * null if there is no item at the given coordinates. - * + * * @param point - * the widget-relative coordinates - * @return the {@link Item} at the coordinates or null if - * there is no item at the given coordinates + * the widget-relative coordinates + * @return the {@link Item} at the coordinates or null if there + * is no item at the given coordinates */ protected abstract Item getItemAt(Point point); /* * (non-Javadoc) - * + * * @see dwtx.jface.viewers.StructuredViewer#getItem(int, int) */ protected override Item getItem(int x, int y) { @@ -386,20 +375,20 @@ * ITableLabelProvider, ILabelProvider, or * CellLabelProvider. *

- * If the label provider is an {@link ITableLabelProvider}, then it + * If the label provider is an {@link ITableLabelProvider} , then it * provides a separate label text and image for each column. Implementers of - * ITableLabelProvider may also implement - * {@link ITableColorProvider} and/or {@link ITableFontProvider} to provide - * colors and/or fonts. + * ITableLabelProvider may also implement {@link + * ITableColorProvider} and/or {@link ITableFontProvider} to provide colors + * and/or fonts. *

*

- * If the label provider is an ILabelProvider, then it + * If the label provider is an ILabelProvider , then it * provides only the label text and image for the first column, and any * remaining columns are blank. Implementers of ILabelProvider * may also implement {@link IColorProvider} and/or {@link IFontProvider} to * provide colors and/or fonts. *

- * + * */ public override void setLabelProvider(IBaseLabelProvider labelProvider) { Assert.isTrue( null !is cast(ITableLabelProvider)labelProvider @@ -408,6 +397,17 @@ updateColumnParts(labelProvider);// Reset the label providers in the // columns super.setLabelProvider(labelProvider); + if (labelProvider instanceof CellLabelProvider) { + ((CellLabelProvider) labelProvider).initialize(this, null); + } + } + + void internalDisposeLabelProvider(IBaseLabelProvider oldProvider) { + if (oldProvider instanceof CellLabelProvider) { + ((CellLabelProvider) oldProvider).dispose(this, null); + } else { + super.internalDisposeLabelProvider(oldProvider); + } } /** @@ -426,7 +426,7 @@ /** * Cancels a currently active cell editor if one is active. All changes * already done in the cell editor are lost. - * + * * @since 3.1 (in subclasses, added in 3.3 to abstract class) */ public void cancelEditing() { @@ -437,7 +437,7 @@ /** * Apply the value of the active cell editor if one is active. - * + * * @since 3.3 */ protected void applyEditorValue() { @@ -448,11 +448,11 @@ /** * Starts editing the given element at the given column index. - * + * * @param element - * the model element + * the model element * @param column - * the column index + * the column index * @since 3.1 (in subclasses, added in 3.3 to abstract class) */ public void editElement(Object element, int column) { @@ -461,7 +461,7 @@ getControl().setRedraw(false); // Set the selection at first because in Tree's // the element might not be materialized - setSelection(new StructuredSelection(element),true); + setSelection(new StructuredSelection(element), true); Widget item = findItem(element); if (item !is null) { @@ -481,14 +481,15 @@ } /** - * Return the CellEditors for the receiver, or null if no - * cell editors are set. + * Return the CellEditors for the receiver, or null if no cell + * editors are set. *

- * Since 3.3, an alternative API is available, see - * {@link ViewerColumn#setEditingSupport(EditingSupport)} for a more - * flexible way of editing values in a column viewer. + * Since 3.3, an alternative API is available, see {@link + * ViewerColumn#setEditingSupport(EditingSupport)} for a more flexible way + * of editing values in a column viewer. *

- * + * + * * @return CellEditor[] * @since 3.1 (in subclasses, added in 3.3 to abstract class) * @see ViewerColumn#setEditingSupport(EditingSupport) @@ -501,13 +502,13 @@ /** * Returns the cell modifier of this viewer, or null if none * has been set. - * + * *

- * Since 3.3, an alternative API is available, see - * {@link ViewerColumn#setEditingSupport(EditingSupport)} for a more - * flexible way of editing values in a column viewer. + * Since 3.3, an alternative API is available, see {@link + * ViewerColumn#setEditingSupport(EditingSupport)} for a more flexible way + * of editing values in a column viewer. *

- * + * * @return the cell modifier, or null * @since 3.1 (in subclasses, added in 3.3 to abstract class) * @see ViewerColumn#setEditingSupport(EditingSupport) @@ -521,13 +522,13 @@ * Returns the column properties of this table viewer. The properties must * correspond with the columns of the table control. They are used to * identify the column in a cell modifier. - * + * *

- * Since 3.3, an alternative API is available, see - * {@link ViewerColumn#setEditingSupport(EditingSupport)} for a more - * flexible way of editing values in a column viewer. + * Since 3.3, an alternative API is available, see {@link + * ViewerColumn#setEditingSupport(EditingSupport)} for a more flexible way + * of editing values in a column viewer. *

- * + * * @return the list of column properties * @since 3.1 (in subclasses, added in 3.3 to abstract class) * @see ViewerColumn#setEditingSupport(EditingSupport) @@ -543,15 +544,15 @@ /** * Returns whether there is an active cell editor. - * + * *

- * Since 3.3, an alternative API is available, see - * {@link ViewerColumn#setEditingSupport(EditingSupport)} for a more - * flexible way of editing values in a column viewer. + * Since 3.3, an alternative API is available, see {@link + * ViewerColumn#setEditingSupport(EditingSupport)} for a more flexible way + * of editing values in a column viewer. *

- * + * * @return true if there is an active cell editor, and - * false otherwise + * false otherwise * @since 3.1 (in subclasses, added in 3.3 to abstract class) * @see ViewerColumn#setEditingSupport(EditingSupport) * @see EditingSupport @@ -564,10 +565,10 @@ } public override void refresh(Object element) { - if (isBusy()) + if (checkBusy()) return; - if( isCellEditorActive() ) { + if (isCellEditorActive()) { cancelEditing(); } @@ -575,10 +576,10 @@ } public override void refresh(Object element, bool updateLabels) { - if (isBusy()) + if (checkBusy()) return; - if( isCellEditorActive() ) { + if (isCellEditorActive()) { cancelEditing(); } @@ -586,7 +587,7 @@ } public override void update(Object element, String[] properties) { - if (isBusy()) + if (checkBusy()) return; super.update(element, properties); } @@ -594,15 +595,18 @@ /** * Sets the cell editors of this column viewer. If editing is not supported * by this viewer the call simply has no effect. - * + * *

- * Since 3.3, an alternative API is available, see - * {@link ViewerColumn#setEditingSupport(EditingSupport)} for a more - * flexible way of editing values in a column viewer. + * Since 3.3, an alternative API is available, see {@link + * ViewerColumn#setEditingSupport(EditingSupport)} for a more flexible way + * of editing values in a column viewer. *

- * + *

+ * Users setting up an editable {@link TreeViewer} or {@link TableViewer} with more than 1 column have + * to pass the DWT.FULL_SELECTION style bit + *

* @param editors - * the list of cell editors + * the list of cell editors * @since 3.1 (in subclasses, added in 3.3 to abstract class) * @see ViewerColumn#setEditingSupport(EditingSupport) * @see EditingSupport @@ -614,15 +618,18 @@ /** * Sets the cell modifier for this column viewer. This method does nothing * if editing is not supported by this viewer. - * + * *

- * Since 3.3, an alternative API is available, see - * {@link ViewerColumn#setEditingSupport(EditingSupport)} for a more - * flexible way of editing values in a column viewer. + * Since 3.3, an alternative API is available, see {@link + * ViewerColumn#setEditingSupport(EditingSupport)} for a more flexible way + * of editing values in a column viewer. *

- * + *

+ * Users setting up an editable {@link TreeViewer} or {@link TableViewer} with more than 1 column have + * to pass the DWT.FULL_SELECTION style bit + *

* @param modifier - * the cell modifier + * the cell modifier * @since 3.1 (in subclasses, added in 3.3 to abstract class) * @see ViewerColumn#setEditingSupport(EditingSupport) * @see EditingSupport @@ -636,15 +643,18 @@ * correspond with the columns of the control. They are used to identify the * column in a cell modifier. If editing is not supported by this viewer the * call simply has no effect. - * + * *

- * Since 3.3, an alternative API is available, see - * {@link ViewerColumn#setEditingSupport(EditingSupport)} for a more - * flexible way of editing values in a column viewer. + * Since 3.3, an alternative API is available, see {@link + * ViewerColumn#setEditingSupport(EditingSupport)} for a more flexible way + * of editing values in a column viewer. *

- * + *

+ * Users setting up an editable {@link TreeViewer} or {@link TableViewer} with more than 1 column have + * to pass the DWT.FULL_SELECTION style bit + *

* @param columnProperties - * the list of column properties + * the list of column properties * @since 3.1 (in subclasses, added in 3.3 to abstract class) * @see ViewerColumn#setEditingSupport(EditingSupport) * @see EditingSupport @@ -659,9 +669,9 @@ * visually, one column of items may be visible. This occurs when the * programmer uses the column viewer like a list, adding elements but never * creating a column. - * + * * @return the number of columns - * + * * @since 3.3 */ protected abstract int doGetColumnCount(); @@ -672,12 +682,12 @@ /** * Returns the label provider associated with the column at the given index * or null if no column with this index is known. - * + * * @param columnIndex - * the column index + * the column index * @return the label provider associated with the column or - * null if no column with this index is known - * + * null if no column with this index is known + * * @since 3.3 */ public CellLabelProvider getLabelProvider(int columnIndex) { @@ -700,12 +710,12 @@ /** * Invoking this method fires an editor activation event which tries to - * enable the editor but before this event is passed to - * {@link ColumnViewerEditorActivationStrategy} to see if this event should - * really trigger editor activation - * + * enable the editor but before this event is passed to {@link + * ColumnViewerEditorActivationStrategy} to see if this event should really + * trigger editor activation + * * @param event - * the activation event + * the activation event */ protected void triggerEditorActivationEvent( ColumnViewerEditorActivationEvent event) { @@ -718,7 +728,7 @@ /** * @param columnViewerEditor - * the new column viewer editor + * the new column viewer editor */ public void setColumnViewerEditor(ColumnViewerEditor columnViewerEditor) { Assert.isNotNull(viewerEditor); @@ -733,38 +743,123 @@ } protected override Object[] getRawChildren(Object parent) { - bool oldBusy = busy; - busy = true; + bool oldBusy = isBusy(); + setBusy(true); try { return super.getRawChildren(parent); } finally { - busy = oldBusy; + setBusy(oldBusy); } } - /** - * Clear all cell-editors setup for backwards compatibility in - * {@link #setupEditingSupport(int, ViewerColumn)}. This has to be done - * whenever a column is disposed because the index cached when the anonymous - * class is created has to be readjusted - */ void clearLegacyEditingSetup() { - int count = doGetColumnCount(); + if (!getControl().isDisposed() && getCellEditors() !is null) { + int count = doGetColumnCount(); - for( int i = 0; i < count || i is 0; i++ ) { - Widget owner = getColumnViewerOwner(i); - - if( owner !is null && ! owner.isDisposed() ) { - ViewerColumn column = cast(ViewerColumn) owner.getData(ViewerColumn.COLUMN_VIEWER_KEY); - if( column !is null ) { - EditingSupport e = column.getEditingSupport(); - // Ensure that only EditingSupports are wiped that are setup - // for Legacy reasons - if (e !is null && e.isLegacySupport()) { - column.setEditingSupport(null); + for (int i = 0; i < count || i is 0; i++) { + Widget owner = getColumnViewerOwner(i); + if (owner !is null && !owner.isDisposed()) { + ViewerColumn column = cast(ViewerColumn) owner + .getData(ViewerColumn.COLUMN_VIEWER_KEY); + if (column !is null) { + EditingSupport e = column.getEditingSupport(); + // Ensure that only EditingSupports are wiped that are + // setup + // for Legacy reasons + if (e !is null && e.isLegacySupport()) { + column.setEditingSupport(null); + } } } } } } + + /** + * Checks if this viewer is currently busy, logging a warning and returning + * true if it is busy. A column viewer is busy when it is + * processing a refresh, add, remove, insert, replace, setItemCount, + * expandToLevel, update, setExpandedElements, or similar method that may + * make calls to client code. Column viewers are not designed to handle + * reentrant calls while they are busy. The method returns true + * if the viewer is busy. It is recommended that this method be used by + * subclasses to determine whether the viewer is busy to return early from + * state-changing methods. + * + *

+ * This method is not intended to be overridden by subclasses. + *

+ * + * @return true if the viewer is busy. + * + * @since 3.4 + */ + protected bool checkBusy() { + if (isBusy()) { + if (logWhenBusy) { + String message = "Ignored reentrant call while viewer is busy."; //$NON-NLS-1$ + if (!InternalPolicy.DEBUG_LOG_REENTRANT_VIEWER_CALLS) { + // stop logging after the first + logWhenBusy = false; + message += " This is only logged once per viewer instance," + //$NON-NLS-1$ + " but similar calls will still be ignored."; //$NON-NLS-1$ + } + Policy.getLog().log( + new Status(IStatus.WARNING, Policy.JFACE, message, + new RuntimeException())); + } + return true; + } + return false; + } + + /** + * Sets the busy state of this viewer. Subclasses MUST use try + * ...finally as follows to ensure that the busy flag is reset + * to its original value: + * + *
+     * bool oldBusy = isBusy();
+     * setBusy(true);
+     * try {
+     *  // do work
+     * } finally {
+     *  setBusy(oldBusy);
+     * }
+     * 
+ * + *

+ * This method is not intended to be overridden by subclasses. + *

+ * + * @param busy + * the new value of the busy flag + * + * @since 3.4 + */ + protected void setBusy(bool busy) { + this.busy = busy; + } + + /** + * Returns true if this viewer is currently busy processing a + * refresh, add, remove, insert, replace, setItemCount, expandToLevel, + * update, setExpandedElements, or similar method that may make calls to + * client code. Column viewers are not designed to handle reentrant calls + * while they are busy. It is recommended that clients avoid using this + * method if they can ensure by other means that they will not make + * reentrant calls to methods like the ones listed above. See bug 184991 for + * background discussion. + * + *

+ * This method is not intended to be overridden by subclasses. + *

+ * + * @return Returns whether this viewer is busy. + * + * @since 3.4 + */ + public bool isBusy() { + return busy; + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/ColumnViewerEditor.d --- a/dwtx/jface/viewers/ColumnViewerEditor.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/ColumnViewerEditor.d Thu May 22 01:36:46 2008 +0200 @@ -8,7 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation * Tom Schindl - refactoring (bug 153993) - * fix in bug 151295,166500,200337 + * fix in bug: 151295,178946,166500,195908,201906,207676,180504,216706,218336 * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -29,6 +29,8 @@ import dwtx.jface.viewers.OpenEvent; import dwt.DWT; +import dwt.events.DisposeEvent; +import dwt.events.DisposeListener; import dwt.events.FocusAdapter; import dwt.events.FocusEvent; import dwt.events.FocusListener; @@ -38,7 +40,6 @@ import dwt.events.TraverseEvent; import dwt.events.TraverseListener; import dwt.widgets.Control; -import dwt.widgets.Display; import dwt.widgets.Item; import dwtx.core.runtime.ListenerList; @@ -46,7 +47,7 @@ /** * This is the base for all editor implementations of Viewers. ColumnViewer - * implementators have to subclass this class and implement the missing methods + * implementors have to subclass this class and implement the missing methods * * @since 3.3 * @see TableViewerEditor @@ -65,16 +66,16 @@ private TraverseListener tabeditingListener; - private int activationTime; - private ViewerCell cell; - private ColumnViewerEditorActivationEvent activationEvent; - private ListenerList editorActivationListener; private ColumnViewerEditorActivationStrategy editorActivationStrategy; + private bool inEditorDeactivation; + + private DisposeListener disposeListener; + /** * Tabbing from cell to cell is turned off */ @@ -107,6 +108,13 @@ */ public static const int KEYBOARD_ACTIVATION = 1 << 5; + /** + * Style mask used to turn off the feature that an editor activation + * is canceled on double click. It is also possible to turn off this feature + * per cell-editor using {@link CellEditor#getDoubleClickTimeout()} + */ + public static final int KEEP_EDITOR_ON_DOUBLE_CLICK = 1 << 6; + private int feature; /** @@ -134,6 +142,18 @@ .setEnableEditorActivationWithKeyboard(true); } this.feature = feature; + this.disposeListener = new class(viewer) DisposeListener { + ColumnViewer viewer_; + this(ColumnViewer a){ + viewer_=a; + } + public void widgetDisposed(DisposeEvent e) { + if( viewer_.isCellEditorActive() ) { + cancelEditing(); + } + } + + }; initCellEditorListener(); } @@ -154,29 +174,36 @@ }; } - void activateCellEditor() { + private bool activateCellEditor(final ColumnViewerEditorActivationEvent activationEvent) { ViewerColumn part = viewer.getViewerColumn(cell.getColumnIndex()); Object element = cell.getElement(); if (part !is null && part.getEditingSupport() !is null && part.getEditingSupport().canEdit_package(element)) { - cellEditor = part.getEditingSupport().getCellEditor_package(element); if (cellEditor !is null) { + int timeout = cellEditor.getDoubleClickTimeout(); + + final int activationTime; + + if (timeout !is 0) { + activationTime = activationEvent.time + timeout; + } else { + activationTime = 0; + } + if (editorActivationListener !is null && !editorActivationListener.isEmpty()) { Object[] ls = editorActivationListener.getListeners(); for (int i = 0; i < ls.length; i++) { - - if (activationEvent.cancel) { - // Avoid leaking - this.cell = null; - return; - } - (cast(ColumnViewerEditorActivationListener) ls[i]) .beforeEditorActivated(activationEvent); + + // Was the activation canceled ? + if (activationEvent.cancel) { + return false; + } } } @@ -194,13 +221,13 @@ Control control = cellEditor.getControl(); cellEditor.activate(activationEvent); if (control is null) { - return; + return false; } setLayoutData(cellEditor.getLayoutData()); setEditor(control, cast(Item) cell.getItem(), cell.getColumnIndex()); cellEditor.setFocus(); - if( cellEditor.dependsOnExternalFocusListener() ) { + if (cellEditor.dependsOnExternalFocusListener()) { if (focusListener is null) { focusListener = new class FocusAdapter { public void focusLost(FocusEvent e) { @@ -219,7 +246,7 @@ public void mouseDown(MouseEvent e) { // time wrap? // check for expiration of doubleClickTime - if (e.time <= activationTime) { + if (shouldFireDoubleClick(activationTime, e.time, activationEvent) && e.button is 1) { control_.removeMouseListener(mouseListener); cancelEditing(); handleDoubleClickEvent(); @@ -228,7 +255,11 @@ } } }; - control.addMouseListener(mouseListener); + + if (activationTime !is 0 + && (feature & KEEP_EDITOR_ON_DOUBLE_CLICK) is 0) { + control.addMouseListener(mouseListener); + } if (tabeditingListener is null) { tabeditingListener = new class TraverseListener { @@ -253,11 +284,23 @@ .afterEditorActivated(activationEvent); } } + + this.cell.getItem().addDisposeListener(disposeListener); + + return true; } - } else { - // Avoid leaking - this.cell = null; + } + + return false; + } + + private bool shouldFireDoubleClick(int activationTime, int mouseTime, + ColumnViewerEditorActivationEvent activationEvent) { + return mouseTime <= activationTime + && activationEvent.eventType !is ColumnViewerEditorActivationEvent.KEY_PRESSED + && activationEvent.eventType !is ColumnViewerEditorActivationEvent.PROGRAMMATIC + && activationEvent.eventType !is ColumnViewerEditorActivationEvent.TRAVERSAL; } /** @@ -265,62 +308,72 @@ * editor. */ void applyEditorValue() { - CellEditor c = this.cellEditor; - if (c !is null && this.cell !is null) { - // null out cell editor before calling save - // in case save results in applyEditorValue being re-entered - // see 1GAHI8Z: ITPUI:ALL - How to code event notification when - // using cell editor ? - ColumnViewerEditorDeactivationEvent tmp = new ColumnViewerEditorDeactivationEvent( - cell); - if (editorActivationListener !is null - && !editorActivationListener.isEmpty()) { - Object[] ls = editorActivationListener.getListeners(); - for (int i = 0; i < ls.length; i++) { + // avoid re-entering + if (!inEditorDeactivation) { + try { + inEditorDeactivation = true; + CellEditor c = this.cellEditor; + if (c !is null && this.cell !is null) { + ColumnViewerEditorDeactivationEvent tmp = new ColumnViewerEditorDeactivationEvent( + cell); + tmp.eventType = ColumnViewerEditorDeactivationEvent.EDITOR_SAVED; + if (editorActivationListener !is null + && !editorActivationListener.isEmpty()) { + Object[] ls = editorActivationListener.getListeners(); + for (int i = 0; i < ls.length; i++) { - (cast(ColumnViewerEditorActivationListener) ls[i]) - .beforeEditorDeactivated(tmp); - } - } + (cast(ColumnViewerEditorActivationListener) ls[i]) + .beforeEditorDeactivated(tmp); + } + } + + Item t = cast(Item) this.cell.getItem(); + + // don't null out table item -- same item is still selected + if (t !is null && !t.isDisposed()) { + saveEditorValue(c); + } + if (!viewer.getControl().isDisposed()) { + setEditor(null, null, 0); + } - this.cellEditor = null; - this.activationEvent = null; - Item t = cast(Item) this.cell.getItem(); - - // don't null out table item -- same item is still selected - if (t !is null && !t.isDisposed()) { - saveEditorValue(c); - } + c.removeListener(cellEditorListener); + Control control = c.getControl(); + if (control !is null && !control.isDisposed()) { + if (mouseListener !is null) { + control.removeMouseListener(mouseListener); + // Clear the instance not needed any more + mouseListener = null; + } + if (focusListener !is null) { + control.removeFocusListener(focusListener); + } - setEditor(null, null, 0); - c.removeListener(cellEditorListener); - Control control = c.getControl(); - if (control !is null) { - if (mouseListener !is null) { - control.removeMouseListener(mouseListener); - // Clear the instance not needed any more - mouseListener = null; - } - if (focusListener !is null) { - control.removeFocusListener(focusListener); + if (tabeditingListener !is null) { + control.removeTraverseListener(tabeditingListener); + } + } + c.deactivate(tmp); + + if (editorActivationListener !is null + && !editorActivationListener.isEmpty()) { + Object[] ls = editorActivationListener.getListeners(); + for (int i = 0; i < ls.length; i++) { + (cast(ColumnViewerEditorActivationListener) ls[i]) + .afterEditorDeactivated(tmp); + } + } + + if( ! this.cell.getItem().isDisposed() ) { + this.cell.getItem().removeDisposeListener(disposeListener); + } } - if (tabeditingListener !is null) { - control.removeTraverseListener(tabeditingListener); - } + this.cellEditor = null; + this.cell = null; + } finally { + inEditorDeactivation = false; } - c.deactivate(); - - if (editorActivationListener !is null - && !editorActivationListener.isEmpty()) { - Object[] ls = editorActivationListener.getListeners(); - for (int i = 0; i < ls.length; i++) { - (cast(ColumnViewerEditorActivationListener) ls[i]) - .afterEditorDeactivated(tmp); - } - } - - this.cell = null; } } @@ -328,53 +381,69 @@ * Cancel editing */ void cancelEditing() { - if (cellEditor !is null) { - ColumnViewerEditorDeactivationEvent tmp = new ColumnViewerEditorDeactivationEvent( - cell); - if (editorActivationListener !is null - && !editorActivationListener.isEmpty()) { - Object[] ls = editorActivationListener.getListeners(); - for (int i = 0; i < ls.length; i++) { + // avoid re-entering + if (!inEditorDeactivation) { + try { + inEditorDeactivation = true; + if (cellEditor !is null) { + ColumnViewerEditorDeactivationEvent tmp = new ColumnViewerEditorDeactivationEvent( + cell); + tmp.eventType = ColumnViewerEditorDeactivationEvent.EDITOR_CANCELED; + if (editorActivationListener !is null + && !editorActivationListener.isEmpty()) { + Object[] ls = editorActivationListener.getListeners(); + for (int i = 0; i < ls.length; i++) { + + (cast(ColumnViewerEditorActivationListener) ls[i]) + .beforeEditorDeactivated(tmp); + } + } + + if (!viewer.getControl().isDisposed()) { + setEditor(null, null, 0); + } + + cellEditor.removeListener(cellEditorListener); - (cast(ColumnViewerEditorActivationListener) ls[i]) - .beforeEditorDeactivated(tmp); - } - } + Control control = cellEditor.getControl(); + if (control !is null && !viewer.getControl().isDisposed()) { + if (mouseListener !is null) { + control.removeMouseListener(mouseListener); + // Clear the instance not needed any more + mouseListener = null; + } + if (focusListener !is null) { + control.removeFocusListener(focusListener); + } + + if (tabeditingListener !is null) { + control.removeTraverseListener(tabeditingListener); + } + } - setEditor(null, null, 0); - cellEditor.removeListener(cellEditorListener); + CellEditor oldEditor = cellEditor; + oldEditor.deactivate(tmp); - Control control = cellEditor.getControl(); - if (control !is null) { - if (mouseListener !is null) { - control.removeMouseListener(mouseListener); - // Clear the instance not needed any more - mouseListener = null; + if (editorActivationListener !is null + && !editorActivationListener.isEmpty()) { + Object[] ls = editorActivationListener.getListeners(); + for (int i = 0; i < ls.length; i++) { + (cast(ColumnViewerEditorActivationListener) ls[i]) + .afterEditorDeactivated(tmp); + } + } + + if( ! this.cell.getItem().isDisposed() ) { + this.cell.getItem().addDisposeListener(disposeListener); + } + + this.cellEditor = null; + this.cell = null; + } - if (focusListener !is null) { - control.removeFocusListener(focusListener); - } - - if (tabeditingListener !is null) { - control.removeTraverseListener(tabeditingListener); - } + } finally { + inEditorDeactivation = false; } - - CellEditor oldEditor = cellEditor; - oldEditor.deactivate(); - - if (editorActivationListener !is null - && !editorActivationListener.isEmpty()) { - Object[] ls = editorActivationListener.getListeners(); - for (int i = 0; i < ls.length; i++) { - (cast(ColumnViewerEditorActivationListener) ls[i]) - .afterEditorDeactivated(tmp); - } - } - - this.cellEditor = null; - this.activationEvent = null; - this.cell = null; } } @@ -384,18 +453,20 @@ * @param event */ void handleEditorActivationEvent(ColumnViewerEditorActivationEvent event) { - if (editorActivationStrategy.isEditorActivationEvent_package(event)) { + + // Only activate if the event isn't tagged as canceled + if (!event.cancel + && editorActivationStrategy.isEditorActivationEvent_package(event)) { if (cellEditor !is null) { applyEditorValue(); } this.cell = cast(ViewerCell) event.getSource(); - activationEvent = event; - activationTime = event.time - + Display.getCurrent().getDoubleClickTime(); - - activateCellEditor(); + if( ! activateCellEditor(event) ) { + this.cell = null; + this.cellEditor = null; + } } } @@ -487,8 +558,8 @@ && (feature & TABBING_VERTICAL) is TABBING_VERTICAL) { cell2edit = searchCellAboveBelow(row, viewer, columnIndex, true); } else if ((feature & TABBING_HORIZONTAL) is TABBING_HORIZONTAL) { - cell2edit = searchPreviousCell(row, viewer, columnIndex, - columnIndex); + cell2edit = searchPreviousCell(row, row.getCell(columnIndex), + row.getCell(columnIndex), viewer); } } else if (event.detail is DWT.TRAVERSE_TAB_NEXT) { event.doit = false; @@ -498,8 +569,8 @@ cell2edit = searchCellAboveBelow(row, viewer, columnIndex, false); } else if ((feature & TABBING_HORIZONTAL) is TABBING_HORIZONTAL) { - cell2edit = searchNextCell(row, viewer, columnIndex, - columnIndex); + cell2edit = searchNextCell(row, row.getCell(columnIndex), row + .getCell(columnIndex), viewer); } } @@ -540,36 +611,48 @@ return rv; } - private ViewerCell searchPreviousCell(ViewerRow row, ColumnViewer viewer, - int columnIndex, int startIndex) { + private bool isCellEditable(ColumnViewer viewer, ViewerCell cell) { + ViewerColumn column = viewer.getViewerColumn(cell.getColumnIndex()); + return column !is null && column.getEditingSupport() !is null + && column.getEditingSupport().canEdit(cell.getElement()); + } + + private ViewerCell searchPreviousCell(ViewerRow row, + ViewerCell currentCell, ViewerCell originalCell, ColumnViewer viewer) { ViewerCell rv = null; + ViewerCell previousCell; - if (columnIndex - 1 >= 0) { - ViewerColumn column = viewer.getViewerColumn(columnIndex - 1); - if (column !is null - && column.getEditingSupport() !is null - && column.getEditingSupport().canEdit_package( - row.getItem().getData())) { - rv = row.getCell(columnIndex - 1); + if (currentCell !is null) { + previousCell = currentCell.getNeighbor(ViewerCell.LEFT, true); + } else { + if (row.getColumnCount() !is 0) { + previousCell = row.getCell(row.getCreationIndex(row + .getColumnCount() - 1)); } else { - rv = searchPreviousCell(row, viewer, columnIndex - 1, - startIndex); + previousCell = row.getCell(0); + } + + } + + // No endless loop + if (originalCell.equals(previousCell)) { + return null; + } + + if (previousCell !is null) { + if (isCellEditable(viewer, previousCell)) { + rv = previousCell; + } else { + rv = searchPreviousCell(row, previousCell, originalCell, viewer); } } else { if ((feature & TABBING_CYCLE_IN_ROW) is TABBING_CYCLE_IN_ROW) { - // Check that we don't get into endless loop - if (columnIndex - 1 !is startIndex) { - // Don't subtract -1 from getColumnCount() we need to - // start in the virtual column - // next to it - rv = searchPreviousCell(row, viewer, row.getColumnCount(), - startIndex); - } + rv = searchPreviousCell(row, null, originalCell, viewer); } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) is TABBING_MOVE_TO_ROW_NEIGHBOR) { ViewerRow rowAbove = row.getNeighbor(ViewerRow.ABOVE, false); if (rowAbove !is null) { - rv = searchPreviousCell(rowAbove, viewer, rowAbove - .getColumnCount(), startIndex); + rv = searchPreviousCell(rowAbove, null, originalCell, + viewer); } } } @@ -577,32 +660,36 @@ return rv; } - private ViewerCell searchNextCell(ViewerRow row, ColumnViewer viewer, - int columnIndex, int startIndex) { + private ViewerCell searchNextCell(ViewerRow row, ViewerCell currentCell, + ViewerCell originalCell, ColumnViewer viewer) { ViewerCell rv = null; - if (columnIndex + 1 < row.getColumnCount()) { - ViewerColumn column = viewer.getViewerColumn(columnIndex + 1); - if (column !is null - && column.getEditingSupport() !is null - && column.getEditingSupport().canEdit_package( - row.getItem().getData())) { - rv = row.getCell(columnIndex + 1); + ViewerCell nextCell; + + if (currentCell !is null) { + nextCell = currentCell.getNeighbor(ViewerCell.RIGHT, true); + } else { + nextCell = row.getCell(row.getCreationIndex(0)); + } + + // No endless loop + if (originalCell.equals(nextCell)) { + return null; + } + + if (nextCell !is null) { + if (isCellEditable(viewer, nextCell)) { + rv = nextCell; } else { - rv = searchNextCell(row, viewer, columnIndex + 1, startIndex); + rv = searchNextCell(row, nextCell, originalCell, viewer); } } else { if ((feature & TABBING_CYCLE_IN_ROW) is TABBING_CYCLE_IN_ROW) { - // Check that we don't get into endless loop - if (columnIndex + 1 !is startIndex) { - // Start from -1 from the virtual column before the - // first one - rv = searchNextCell(row, viewer, -1, startIndex); - } + rv = searchNextCell(row, null, originalCell, viewer); } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) is TABBING_MOVE_TO_ROW_NEIGHBOR) { ViewerRow rowBelow = row.getNeighbor(ViewerRow.BELOW, false); if (rowBelow !is null) { - rv = searchNextCell(rowBelow, viewer, -1, startIndex); + rv = searchNextCell(rowBelow, null, originalCell, viewer); } } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/ColumnViewerEditorActivationEvent.d --- a/dwtx/jface/viewers/ColumnViewerEditorActivationEvent.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/ColumnViewerEditorActivationEvent.d Thu May 22 01:36:46 2008 +0200 @@ -147,7 +147,7 @@ super(cell); this.eventType = KEY_PRESSED; this.sourceEvent = event; - this.time = 0; + this.time = event.time; this.keyCode = event.keyCode; this.character = event.character; this.stateMask = event.stateMask; diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/ColumnViewerEditorDeactivationEvent.d --- a/dwtx/jface/viewers/ColumnViewerEditorDeactivationEvent.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/ColumnViewerEditorDeactivationEvent.d Thu May 22 01:36:46 2008 +0200 @@ -7,6 +7,8 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Tom Schindl - initial API and implementation + * fixes in bug: 178946 * Port to the D programming language: * Frank Benoit ******************************************************************************/ @@ -29,10 +31,24 @@ private static const long serialVersionUID = 1L; /** + * The event type + */ + public int eventType; + + /** + * Event when editor is canceled + */ + public static final int EDITOR_CANCELED = 1; + + /** + * Event when editor is saved + */ + public static final int EDITOR_SAVED = 2; + + /** * @param source */ public this(Object source) { super(source); } - } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/ColumnViewerToolTipSupport.d --- a/dwtx/jface/viewers/ColumnViewerToolTipSupport.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/ColumnViewerToolTipSupport.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 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 @@ -8,6 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation * Tom Schindl - initial API and implementation + * bugfix in: 195137, 198089 * Fredy Dobler - bug 159600 * Brock Janiczak - bug 182443 * Port to the D programming language: @@ -22,9 +23,9 @@ import dwtx.jface.viewers.CellLabelProvider; import dwtx.jface.viewers.StructuredSelection; -import dwt.DWT; import dwt.graphics.Image; import dwt.graphics.Point; +import dwt.widgets.Composite; import dwt.widgets.Event; import dwtx.jface.util.Policy; import dwtx.jface.window.DefaultToolTip; @@ -33,7 +34,8 @@ import dwt.dwthelper.utils; /** - * The ColumnViewerTooltipSupport is the class that provides tool tips for ColumnViewers. + * The ColumnViewerTooltipSupport is the class that provides tool tips for + * ColumnViewers. * * @since 3.3 * @@ -41,10 +43,8 @@ public class ColumnViewerToolTipSupport : DefaultToolTip { private ColumnViewer viewer; - private static const String LABEL_PROVIDER_KEY = Policy.JFACE - ~ "_LABEL_PROVIDER"; //$NON-NLS-1$ - - private static const String ELEMENT_KEY = Policy.JFACE ~ "_ELEMENT_KEY"; //$NON-NLS-1$ + private static const String VIEWER_CELL_KEY = Policy.JFACE + ~ "_VIEWER_CELL_KEY"; //$NON-NLS-1$ private static const int DEFAULT_SHIFT_X = 10; @@ -57,14 +57,16 @@ * * @param viewer * the viewer the support is attached to - * @param style style passed to control tool tip behavior + * @param style + * style passed to control tool tip behavior * * @param manualActivation * true if the activation is done manually using * {@link #show(Point)} */ - protected this(ColumnViewer viewer, int style, bool manualActivation ) { - super(viewer.getControl(),style,manualActivation); + protected this(ColumnViewer viewer, int style, + bool manualActivation) { + super(viewer.getControl(), style, manualActivation); this.viewer = viewer; } @@ -77,7 +79,7 @@ * the viewer the support is attached to */ public static void enableFor(ColumnViewer viewer) { - new ColumnViewerToolTipSupport(viewer,ToolTip.NO_RECREATE,false); + new ColumnViewerToolTipSupport(viewer, ToolTip.NO_RECREATE, false); } /** @@ -87,21 +89,57 @@ * * @param viewer * the viewer the support is attached to - * @param style style passed to control tool tip behavior + * @param style + * style passed to control tool tip behavior * * @see ToolTip#RECREATE * @see ToolTip#NO_RECREATE */ public static void enableFor(ColumnViewer viewer, int style) { - new ColumnViewerToolTipSupport(viewer,style,false); + new ColumnViewerToolTipSupport(viewer, style, false); } protected override Object getToolTipArea(Event event) { - return viewer.getCell(new Point(event.x,event.y)); + return viewer.getCell(new Point(event.x, event.y)); + } + + /** + * Instead of overwriting this method subclasses should overwrite + * {@link #createViewerToolTipContentArea(Event, ViewerCell, Composite)} + */ + protected Composite createToolTipContentArea(Event event, Composite parent) { + ViewerCell cell = (ViewerCell) getData(VIEWER_CELL_KEY); + setData(VIEWER_CELL_KEY, null); + + return createViewerToolTipContentArea(event, cell, parent); } - protected override final bool shouldCreateToolTip(Event event) { - if( ! super.shouldCreateToolTip(event) ) { + /** + * Creates the content area of the tool tip giving access to the cell the + * tip is shown for. Subclasses can overload this method to implement their + * own tool tip design. + * + *

+ * This method is called from + * {@link #createToolTipContentArea(Event, Composite)} and by default calls + * the {@link DefaultToolTip#createToolTipContentArea(Event, Composite)}. + *

+ * + * @param event + * the event that which + * @param cell + * the cell the tool tip is shown for + * @param parent + * the parent of the control to create + * @return the control to be displayed in the tool tip area + */ + protected Composite createViewerToolTipContentArea(Event event, + ViewerCell cell, Composite parent) { + return super.createToolTipContentArea(event, parent); + } + + protected override bool shouldCreateToolTip(Event event) { + if (!super.shouldCreateToolTip(event)) { return false; } @@ -115,8 +153,9 @@ if (row !is null) { Object element = row.getItem().getData(); - ViewerColumn viewPart = viewer.getViewerColumn(row - .getColumnIndex(point)); + ViewerCell cell = row.getCell(point); + ViewerColumn viewPart = viewer.getViewerColumn(cell + .getColumnIndex()); if (viewPart is null) { return false; @@ -128,11 +167,11 @@ String text = labelProvider.getToolTipText(element); Image img = null; - if( ! useNative ) { + if (!useNative) { img = labelProvider.getToolTipImage(element); } - if( useNative || (text is null && img is null ) ) { + if (useNative || (text is null && img is null)) { viewer.getControl().setToolTipText(text); rv = false; } else { @@ -147,14 +186,15 @@ setShift(new Point(shift.x, shift.y)); } - setData(LABEL_PROVIDER_KEY, labelProvider); - setData(ELEMENT_KEY, element); + setData(VIEWER_CELL_KEY, cell); setText(text); setImage(img); setStyle(labelProvider.getToolTipStyle(element)); - setForegroundColor(labelProvider.getToolTipForegroundColor(element)); - setBackgroundColor(labelProvider.getToolTipBackgroundColor(element)); + setForegroundColor(labelProvider + .getToolTipForegroundColor(element)); + setBackgroundColor(labelProvider + .getToolTipBackgroundColor(element)); setFont(labelProvider.getToolTipFont(element)); // Check if at least one of the values is set @@ -166,12 +206,11 @@ } protected override void afterHideToolTip(Event event) { + super.afterHideToolTip(event); + // Clear the restored value else this could be a source of a leak + setData(VIEWER_CELL_KEY, null); if (event !is null && event.widget !is viewer.getControl()) { - if (event.type is DWT.MouseDown) { - viewer.setSelection(new StructuredSelection()); - } else { - viewer.getControl().setFocus(); - } + viewer.getControl().setFocus(); } } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/ComboBoxCellEditor.d --- a/dwtx/jface/viewers/ComboBoxCellEditor.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/ComboBoxCellEditor.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,7 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Tom Schindl - bugfix in 199775 + * Tom Schindl - bugfix in 174739 * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -35,14 +35,13 @@ import tango.text.convert.Format; /** - * A cell editor that presents a list of items in a combo box. - * The cell editor's value is the zero-based index of the selected - * item. + * A cell editor that presents a list of items in a combo box. The cell editor's + * value is the zero-based index of the selected item. *

* This class may be instantiated; it is not intended to be subclassed. *

*/ -public class ComboBoxCellEditor : CellEditor { +public class ComboBoxCellEditor : AbstractComboBoxCellEditor { /** * The list of items to present in the combo box. @@ -65,8 +64,8 @@ private static const int defaultStyle = DWT.NONE; /** - * Creates a new cell editor with no control and no st of choices. Initially, - * the cell editor has no cell validator. + * Creates a new cell editor with no control and no st of choices. + * Initially, the cell editor has no cell validator. * * @since 2.1 * @see CellEditor#setStyle @@ -79,29 +78,32 @@ } /** - * Creates a new cell editor with a combo containing the given - * list of choices and parented under the given control. The cell - * editor value is the zero-based index of the selected item. - * Initially, the cell editor has no cell validator and - * the first item in the list is selected. + * Creates a new cell editor with a combo containing the given list of + * choices and parented under the given control. The cell editor value is + * the zero-based index of the selected item. Initially, the cell editor has + * no cell validator and the first item in the list is selected. * - * @param parent the parent control - * @param items the list of strings for the combo box + * @param parent + * the parent control + * @param items + * the list of strings for the combo box */ public this(Composite parent, String[] items) { this(parent, items, defaultStyle); } /** - * Creates a new cell editor with a combo containing the given - * list of choices and parented under the given control. The cell - * editor value is the zero-based index of the selected item. - * Initially, the cell editor has no cell validator and - * the first item in the list is selected. + * Creates a new cell editor with a combo containing the given list of + * choices and parented under the given control. The cell editor value is + * the zero-based index of the selected item. Initially, the cell editor has + * no cell validator and the first item in the list is selected. * - * @param parent the parent control - * @param items the list of strings for the combo box - * @param style the style bits + * @param parent + * the parent control + * @param items + * the list of strings for the combo box + * @param style + * the style bits * @since 2.1 */ public this(Composite parent, String[] items, int style) { @@ -121,7 +123,8 @@ /** * Sets the list of choices for the combo box * - * @param items the list of choices for the combo box + * @param items + * the list of choices for the combo box */ public void setItems(String[] items) { // Assert.isNotNull(items); @@ -129,8 +132,8 @@ populateComboBoxItems(); } - /* (non-Javadoc) - * Method declared on CellEditor. + /* + * (non-Javadoc) Method declared on CellEditor. */ protected override Control createControl(Composite parent) { @@ -174,31 +177,31 @@ } /** - * The ComboBoxCellEditor implementation of - * this CellEditor framework method returns - * the zero-based index of the current selection. + * The ComboBoxCellEditor implementation of this + * CellEditor framework method returns the zero-based index + * of the current selection. * - * @return the zero-based index of the current selection wrapped - * as an Integer + * @return the zero-based index of the current selection wrapped as an + * Integer */ protected override Object doGetValue() { return new ValueWrapperInt(selection); } - /* (non-Javadoc) - * Method declared on CellEditor. + /* + * (non-Javadoc) Method declared on CellEditor. */ protected override void doSetFocus() { comboBox.setFocus(); } /** - * The ComboBoxCellEditor implementation of - * this CellEditor framework method sets the - * minimum width of the cell. The minimum width is 10 characters - * if comboBox is not null or disposed - * else it is 60 pixels to make sure the arrow button and some text is visible. - * The list of CCombo will be wide enough to show its longest item. + * The ComboBoxCellEditor implementation of this + * CellEditor framework method sets the minimum width of the + * cell. The minimum width is 10 characters if comboBox is + * not null or disposed else it is 60 pixels + * to make sure the arrow button and some text is visible. The list of + * CCombo will be wide enough to show its longest item. */ public override LayoutData getLayoutData() { LayoutData layoutData = super.getLayoutData(); @@ -215,12 +218,13 @@ } /** - * The ComboBoxCellEditor implementation of - * this CellEditor framework method - * accepts a zero-based index of a selection. + * The ComboBoxCellEditor implementation of this + * CellEditor framework method accepts a zero-based index of + * a selection. * - * @param value the zero-based index of the selection wrapped - * as an Integer + * @param value + * the zero-based index of the selection wrapped as an + * Integer */ protected override void doSetValue(Object value) { Assert.isTrue(comboBox !is null && (cast(ValueWrapperInt)value )); @@ -247,7 +251,7 @@ * Applies the currently selected value and deactivates the cell editor */ void applyEditorValueAndDeactivate() { - // must set the selection before getting value + // must set the selection before getting value selection = comboBox.getSelectionIndex(); Object newValue = doGetValue(); markDirty(); @@ -260,9 +264,9 @@ // try to insert the current value into the error message. setErrorMessage(Format(getErrorMessage(), [ items[selection] ])); - } - else { - // Since we don't have a valid index, assume we're using an 'edit' + } else { + // Since we don't have a valid index, assume we're using an + // 'edit' // combo so format using its text value setErrorMessage(Format(getErrorMessage(), [ comboBox.getText() ])); @@ -274,7 +278,8 @@ } /* - * (non-Javadoc) + * (non-Javadoc) + * * @see dwtx.jface.viewers.CellEditor#focusLost() */ protected override void focusLost() { @@ -284,7 +289,8 @@ } /* - * (non-Javadoc) + * (non-Javadoc) + * * @see dwtx.jface.viewers.CellEditor#keyReleaseOccured(dwt.events.KeyEvent) */ protected override void keyReleaseOccured(KeyEvent keyEvent) { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/ComboBoxViewerCellEditor.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/viewers/ComboBoxViewerCellEditor.d Thu May 22 01:36:46 2008 +0200 @@ -0,0 +1,267 @@ +/******************************************************************************* + * Copyright (c) 2006 Tom Schindl 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: + * Tom Schindl - initial API and implementation + * bugfix in 174739 + * Eric Rizzo - bug 213315 + * Port to the D programming language: + * Frank Benoit + *******************************************************************************/ + +module dwtx.jface.viewers.ComboBoxViewerCellEditor; + +import java.text.MessageFormat; + +import dwt.DWT; +import dwt.custom.CCombo; +import dwt.events.FocusAdapter; +import dwt.events.FocusEvent; +import dwt.events.KeyAdapter; +import dwt.events.KeyEvent; +import dwt.events.SelectionAdapter; +import dwt.events.SelectionEvent; +import dwt.events.TraverseEvent; +import dwt.events.TraverseListener; +import dwt.graphics.GC; +import dwt.widgets.Composite; +import dwt.widgets.Control; +import dwtx.core.runtime.Assert; + +/** + * A cell editor that presents a list of items in a combo box. In contrast to + * {@link ComboBoxCellEditor} it wraps the underlying {@link CCombo} using a + * {@link ComboViewer} + */ +public class ComboBoxViewerCellEditor extends AbstractComboBoxCellEditor { + + /** + * The custom combo box control. + */ + ComboViewer viewer; + + Object selectedValue; + + /** + * Default ComboBoxCellEditor style + */ + private static final int defaultStyle = DWT.NONE; + + /** + * Creates a new cell editor with a combo viewer and a default style + * + * @param parent + * the parent control + */ + public ComboBoxViewerCellEditor(Composite parent) { + this(parent, defaultStyle); + } + + /** + * Creates a new cell editor with a combo viewer and the given style + * + * @param parent + * the parent control + * @param style + * the style bits + */ + public ComboBoxViewerCellEditor(Composite parent, int style) { + super(parent, style); + setValueValid(true); + } + + /* + * (non-Javadoc) Method declared on CellEditor. + */ + protected Control createControl(Composite parent) { + + CCombo comboBox = new CCombo(parent, getStyle()); + comboBox.setFont(parent.getFont()); + viewer = new ComboViewer(comboBox); + + comboBox.addKeyListener(new KeyAdapter() { + // hook key pressed - see PR 14201 + public void keyPressed(KeyEvent e) { + keyReleaseOccured(e); + } + }); + + comboBox.addSelectionListener(new SelectionAdapter() { + public void widgetDefaultSelected(SelectionEvent event) { + applyEditorValueAndDeactivate(); + } + + public void widgetSelected(SelectionEvent event) { + ISelection selection = viewer.getSelection(); + if (selection.isEmpty()) { + selectedValue = null; + } else { + selectedValue = ((IStructuredSelection) selection) + .getFirstElement(); + } + } + }); + + comboBox.addTraverseListener(new TraverseListener() { + public void keyTraversed(TraverseEvent e) { + if (e.detail is DWT.TRAVERSE_ESCAPE + || e.detail is DWT.TRAVERSE_RETURN) { + e.doit = false; + } + } + }); + + comboBox.addFocusListener(new FocusAdapter() { + public void focusLost(FocusEvent e) { + ComboBoxViewerCellEditor.this.focusLost(); + } + }); + return comboBox; + } + + /** + * The ComboBoxCellEditor implementation of this + * CellEditor framework method returns the zero-based index + * of the current selection. + * + * @return the zero-based index of the current selection wrapped as an + * Integer + */ + protected Object doGetValue() { + return selectedValue; + } + + /* + * (non-Javadoc) Method declared on CellEditor. + */ + protected void doSetFocus() { + viewer.getControl().setFocus(); + } + + /** + * The ComboBoxCellEditor implementation of this + * CellEditor framework method sets the minimum width of the + * cell. The minimum width is 10 characters if comboBox is + * not null or disposed eles it is 60 pixels + * to make sure the arrow button and some text is visible. The list of + * CCombo will be wide enough to show its longest item. + */ + public LayoutData getLayoutData() { + LayoutData layoutData = super.getLayoutData(); + if ((viewer.getControl() is null) || viewer.getControl().isDisposed()) { + layoutData.minimumWidth = 60; + } else { + // make the comboBox 10 characters wide + GC gc = new GC(viewer.getControl()); + layoutData.minimumWidth = (gc.getFontMetrics() + .getAverageCharWidth() * 10) + 10; + gc.dispose(); + } + return layoutData; + } + + /** + * Set a new value + * + * @param value + * the new value + */ + protected void doSetValue(Object value) { + Assert.isTrue(viewer !is null); + selectedValue = value; + if (value is null) { + viewer.setSelection(StructuredSelection.EMPTY); + } else { + viewer.setSelection(new StructuredSelection(value)); + } + } + + /** + * @param labelProvider + * the label provider used + * @see StructuredViewer#setLabelProvider(IBaseLabelProvider) + */ + public void setLabelProvider(IBaseLabelProvider labelProvider) { + viewer.setLabelProvider(labelProvider); + } + + /** + * @param provider + * the content provider used + * @see StructuredViewer#setContentProvider(IContentProvider) + */ + public void setContenProvider(IStructuredContentProvider provider) { + viewer.setContentProvider(provider); + } + + /** + * @param input + * the input used + * @see StructuredViewer#setInput(Object) + */ + public void setInput(Object input) { + viewer.setInput(input); + } + + /** + * @return get the viewer + */ + public ComboViewer getViewer() { + return viewer; + } + + /** + * Applies the currently selected value and deactiavates the cell editor + */ + void applyEditorValueAndDeactivate() { + // must set the selection before getting value + ISelection selection = viewer.getSelection(); + if (selection.isEmpty()) { + selectedValue = null; + } else { + selectedValue = ((IStructuredSelection) selection) + .getFirstElement(); + } + + Object newValue = doGetValue(); + markDirty(); + bool isValid = isCorrect(newValue); + setValueValid(isValid); + + if (!isValid) { + MessageFormat.format(getErrorMessage(), + new Object[] { selectedValue }); + } + + fireApplyEditorValue(); + deactivate(); + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.CellEditor#focusLost() + */ + protected void focusLost() { + if (isActivated()) { + applyEditorValueAndDeactivate(); + } + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.CellEditor#keyReleaseOccured(dwt.events.KeyEvent) + */ + protected void keyReleaseOccured(KeyEvent keyEvent) { + if (keyEvent.character is '\u001b') { // Escape character + fireCancelEditor(); + } else if (keyEvent.character is '\t') { // tab key + applyEditorValueAndDeactivate(); + } + } +} diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/ComboViewer.d --- a/dwtx/jface/viewers/ComboViewer.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/ComboViewer.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004-2006 IBM Corporation and others. + * Copyright (c) 2004, 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 @@ -37,9 +37,9 @@ *

* * @see dwtx.jface.viewers.ListViewer - * @since 3.0 + * @since 3.0 (made non-final in 3.4) */ -public final class ComboViewer : AbstractListViewer { +public class ComboViewer : AbstractListViewer { /** * This viewer's list control if this viewer is instantiated with a combo control; otherwise diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/ContentViewer.d --- a/dwtx/jface/viewers/ContentViewer.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/ContentViewer.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -127,7 +127,7 @@ *

* The ContentViewer implementation of this method returns the label * provider recorded in an internal state variable; if none has been - * set (with setLabelProvider) a SimpleLabelProvider + * set (with setLabelProvider) a default label provider * will be created, remembered, and returned. * Overriding this method is generally not required; * however, if overriding in a subclass, @@ -295,7 +295,16 @@ // Dispose old provider after refresh, so that items never refer to stale images. if (oldProvider !is null) { - oldProvider.dispose(); + internalDisposeLabelProvider(oldProvider); } } + + /** + * @param oldProvider + * + * @since 3.4 + */ + void internalDisposeLabelProvider(IBaseLabelProvider oldProvider) { + oldProvider.dispose(); + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/DecoratingLabelProvider.d --- a/dwtx/jface/viewers/DecoratingLabelProvider.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/DecoratingLabelProvider.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/DecoratingStyledCellLabelProvider.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/viewers/DecoratingStyledCellLabelProvider.d Thu May 22 01:36:46 2008 +0200 @@ -0,0 +1,318 @@ +/******************************************************************************* + * Copyright (c) 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 + * Port to the D programming language: + * Frank Benoit + *******************************************************************************/ +module dwtx.jface.viewers.DecoratingStyledCellLabelProvider; + + +import dwt.graphics.Color; +import dwt.graphics.Font; +import dwt.graphics.Image; +import dwtx.core.runtime.Assert; +import dwtx.jface.viewers.StyledString.Styler; + +/** + * A {@link DecoratingStyledCellLabelProvider} is a + * {@link DelegatingStyledCellLabelProvider} that uses a nested + * {@link DelegatingStyledCellLabelProvider.IStyledLabelProvider} to compute + * styled text label and image and takes a {@link ILabelDecorator} to decorate + * the label. + * + *

+ * Use this label provider as a replacement for the + * {@link DecoratingLabelProvider} when decorating styled text labels. + *

+ * + *

+ * The {@link DecoratingStyledCellLabelProvider} will try to evaluate the text + * decoration added by the {@link ILabelDecorator} and will apply the style + * returned by {@link #getDecorationStyle(Object)} + *

+ *

+ * The {@link ILabelDecorator} can optionally implement {@link IColorDecorator} + * and {@link IFontDecorator} to provide foreground and background color and + * font decoration. + *

+ * + * @since 3.4 + */ +public class DecoratingStyledCellLabelProvider extends + DelegatingStyledCellLabelProvider { + + private ILabelDecorator decorator; + private IDecorationContext decorationContext= DecorationContext.DEFAULT_CONTEXT; + private ILabelProviderListener labelProviderListener; + + /** + * Creates a {@link DecoratingStyledCellLabelProvider} that delegates the + * requests for styled labels and for images to a + * {@link DelegatingStyledCellLabelProvider.IStyledLabelProvider}. + * + * @param labelProvider + * the styled label provider + * @param decorator + * a label decorator or null to not decorate the + * label + * @param decorationContext + * a decoration context or null if the no + * decorator is configured or the default decorator should be + * used + */ + public DecoratingStyledCellLabelProvider( + IStyledLabelProvider labelProvider, ILabelDecorator decorator, + IDecorationContext decorationContext) { + super(labelProvider); + + this.decorator = decorator; + this.decorationContext = decorationContext !is null ? decorationContext + : DecorationContext.DEFAULT_CONTEXT; + + this.labelProviderListener = new ILabelProviderListener() { + public void labelProviderChanged(LabelProviderChangedEvent event) { + fireLabelProviderChanged(event); + } + }; + labelProvider.addListener(this.labelProviderListener); + if (decorator !is null) + decorator.addListener(this.labelProviderListener); + } + + /** + * Returns the decoration context associated with this label provider. It + * will be passed to the decorator if the decorator is an instance of + * {@link LabelDecorator}. + * + * @return the decoration context associated with this label provider + */ + public IDecorationContext getDecorationContext() { + return this.decorationContext; + } + + /** + * Set the decoration context that will be based to the decorator for this + * label provider if that decorator implements {@link LabelDecorator}. + * + * @param decorationContext + * the decoration context. + */ + public void setDecorationContext(IDecorationContext decorationContext) { + Assert.isNotNull(decorationContext); + this.decorationContext = decorationContext; + } + + private bool waitForPendingDecoration(ViewerCell cell) { + if (this.decorator is null) + return false; + + Object element = cell.getElement(); + String oldText = cell.getText(); + + bool isDecorationPending = false; + if (this.decorator instanceof LabelDecorator) { + isDecorationPending = !((LabelDecorator) this.decorator) + .prepareDecoration(element, oldText, getDecorationContext()); + } else if (this.decorator instanceof IDelayedLabelDecorator) { + isDecorationPending = !((IDelayedLabelDecorator) this.decorator) + .prepareDecoration(element, oldText); + } + if (isDecorationPending && oldText.length() is 0) { + // item is empty: is shown for the first time: don't wait + return false; + } + return isDecorationPending; + } + + public void update(ViewerCell cell) { + if (waitForPendingDecoration(cell)) { + return; // wait until the decoration is ready + } + super.update(cell); + } + + public Color getForeground(Object element) { + if (this.decorator instanceof IColorDecorator) { + Color foreground = ((IColorDecorator) this.decorator) + .decorateForeground(element); + if (foreground !is null) + return foreground; + } + return super.getForeground(element); + } + + public Color getBackground(Object element) { + if (this.decorator instanceof IColorDecorator) { + Color color = ((IColorDecorator) this.decorator) + .decorateBackground(element); + if (color !is null) + return color; + } + return super.getBackground(element); + } + + public Font getFont(Object element) { + if (this.decorator instanceof IFontDecorator) { + Font font = ((IFontDecorator) this.decorator).decorateFont(element); + if (font !is null) + return font; + } + return super.getFont(element); + } + + public Image getImage(Object element) { + Image image = super.getImage(element); + if (this.decorator is null) { + return image; + } + Image decorated = null; + if (this.decorator instanceof LabelDecorator) { + decorated = ((LabelDecorator) this.decorator).decorateImage(image, + element, getDecorationContext()); + } else { + decorated = this.decorator.decorateImage(image, element); + } + if (decorated !is null) + return decorated; + + return image; + } + + /** + * Returns the styled text for the label of the given element. + * + * @param element + * the element for which to provide the styled label text + * @return the styled text string used to label the element + */ + protected StyledString getStyledText(Object element) { + StyledString styledString = super.getStyledText(element); + if (this.decorator is null) { + return styledString; + } + + String label = styledString.getString(); + String decorated; + if (this.decorator instanceof LabelDecorator) { + decorated = ((LabelDecorator) this.decorator).decorateText(label, + element, getDecorationContext()); + } else { + decorated = this.decorator.decorateText(label, element); + } + if (decorated is null) + return styledString; + + int originalStart = decorated.indexOf(label); + if (originalStart is -1) { + return new StyledString(decorated); // the decorator did + // something wild + } + + if (decorated.length() is label.length()) + return styledString; + + Styler style = getDecorationStyle(element); + if (originalStart > 0) { + StyledString newString = new StyledString(decorated + .substring(0, originalStart), style); + newString.append(styledString); + styledString = newString; + } + if (decorated.length() > originalStart + label.length()) { // decorator + // appended + // something + return styledString.append(decorated.substring(originalStart + + label.length()), style); + } + return styledString; + } + + /** + * Sets the {@link StyledString.Styler} to be used for string + * decorations. By default the + * {@link StyledString#DECORATIONS_STYLER decoration style}. Clients + * can override. + * + * Note that it is the client's responsibility to react on color changes of + * the decoration color by refreshing the view + * + * @param element + * the element that has been decorated + * + * @return return the decoration style + */ + protected Styler getDecorationStyle(Object element) { + return StyledString.DECORATIONS_STYLER; + } + + /** + * Returns the decorator or null if no decorator is installed + * + * @return the decorator or null if no decorator is installed + */ + public ILabelDecorator getLabelDecorator() { + return this.decorator; + } + + /** + * Sets the label decorator. Removes all known listeners from the old + * decorator, and adds all known listeners to the new decorator. The old + * decorator is not disposed. Fires a label provider changed event + * indicating that all labels should be updated. Has no effect if the given + * decorator is identical to the current one. + * + * @param newDecorator + * the label decorator, or null if no decorations + * are to be applied + */ + public void setLabelDecorator(ILabelDecorator newDecorator) { + ILabelDecorator oldDecorator = this.decorator; + if (oldDecorator !is newDecorator) { + if (oldDecorator !is null) + oldDecorator.removeListener(this.labelProviderListener); + this.decorator = newDecorator; + if (newDecorator !is null) { + newDecorator.addListener(this.labelProviderListener); + } + } + fireLabelProviderChanged(new LabelProviderChangedEvent(this)); + } + + public void addListener(ILabelProviderListener listener) { + super.addListener(listener); + if (this.decorator !is null) { + this.decorator.addListener(this.labelProviderListener); + } + } + + public void removeListener(ILabelProviderListener listener) { + super.removeListener(listener); + if (this.decorator !is null) { + this.decorator.removeListener(this.labelProviderListener); + } + } + + public bool isLabelProperty(Object element, String property) { + if (super.isLabelProperty(element, property)) { + return true; + } + return this.decorator !is null + && this.decorator.isLabelProperty(element, property); + } + + public void dispose() { + super.dispose(); + if (this.decorator !is null) { + this.decorator.removeListener(this.labelProviderListener); + this.decorator.dispose(); + this.decorator = null; + } + } + +} diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/DecorationContext.d --- a/dwtx/jface/viewers/DecorationContext.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/DecorationContext.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 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 diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/DecorationOverlayIcon.d --- a/dwtx/jface/viewers/DecorationOverlayIcon.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/DecorationOverlayIcon.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006 IBM Corporation and others. + * Copyright (c) 2006, 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 @@ -158,7 +158,7 @@ * @see java.lang.Object#hashCode() */ public override hash_t toHash() { - int code = base.toHash(); + int code = System.identityHashCode(base); for (int i = 0; i < overlays.length; i++) { if (overlays[i] !is null) { code ^= overlays[i].toHash(); @@ -177,7 +177,11 @@ drawImage(underlay.getImageData(), 0, 0); } } - drawImage(base.getImageData(), 0, 0); + if (overlays.length > IDecoration.REPLACE && overlays[IDecoration.REPLACE] !is null) { + drawImage(overlays[IDecoration.REPLACE].getImageData(), 0, 0); + } else { + drawImage(base.getImageData(), 0, 0); + } drawOverlays(overlays); } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/DelegatingStyledCellLabelProvider.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/viewers/DelegatingStyledCellLabelProvider.d Thu May 22 01:36:46 2008 +0200 @@ -0,0 +1,218 @@ +/******************************************************************************* + * Copyright (c) 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 + * Port to the D programming language: + * Frank Benoit + *******************************************************************************/ +module dwtx.jface.viewers.DelegatingStyledCellLabelProvider; + +import dwt.graphics.Color; +import dwt.graphics.Font; +import dwt.graphics.Image; + +/** + * A {@link DelegatingStyledCellLabelProvider} is a + * {@link StyledCellLabelProvider} that delegates requests for the styled string + * and the image to a + * {@link DelegatingStyledCellLabelProvider.IStyledLabelProvider}. + * + *

+ * Existing label providers can be enhanced by implementing + * {@link DelegatingStyledCellLabelProvider.IStyledLabelProvider} so they can be + * used in viewers with styled labels. + *

+ * + *

+ * The {@link DelegatingStyledCellLabelProvider.IStyledLabelProvider} can + * optionally implement {@link IColorProvider} and {@link IFontProvider} to + * provide foreground and background color and a default font. + *

+ * + * @since 3.4 + */ +public class DelegatingStyledCellLabelProvider extends StyledCellLabelProvider { + + /** + * Interface marking a label provider that provides styled text labels and + * images. + *

+ * The {@link DelegatingStyledCellLabelProvider.IStyledLabelProvider} can + * optionally implement {@link IColorProvider} and {@link IFontProvider} to + * provide foreground and background color and a default font. + *

+ */ + public static interface IStyledLabelProvider extends IBaseLabelProvider { + + /** + * Returns the styled text label for the given element + * + * @param element + * the element to evaluate the styled string for + * + * @return the styled string. + */ + public StyledString getStyledText(Object element); + + /** + * Returns the image for the label of the given element. The image is + * owned by the label provider and must not be disposed directly. + * Instead, dispose the label provider when no longer needed. + * + * @param element + * the element for which to provide the label image + * @return the image used to label the element, or null + * if there is no image for the given object + */ + public Image getImage(Object element); + } + + private IStyledLabelProvider styledLabelProvider; + + /** + * Creates a {@link DelegatingStyledCellLabelProvider} that delegates the + * requests for the styled labels and the images to a + * {@link IStyledLabelProvider}. + * + * @param labelProvider + * the label provider that provides the styled labels and the + * images + */ + public DelegatingStyledCellLabelProvider(IStyledLabelProvider labelProvider) { + if (labelProvider is null) + throw new IllegalArgumentException( + "Label provider must not be null"); //$NON-NLS-1$ + + this.styledLabelProvider = labelProvider; + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.StyledCellLabelProvider#update(dwtx.jface.viewers.ViewerCell) + */ + public void update(ViewerCell cell) { + Object element = cell.getElement(); + + StyledString styledString = getStyledText(element); + cell.setText(styledString.toString()); + if (isOwnerDrawEnabled()) { + cell.setStyleRanges(styledString.getStyleRanges()); + } else { + cell.setStyleRanges(null); + } + + cell.setImage(getImage(element)); + cell.setFont(getFont(element)); + cell.setForeground(getForeground(element)); + cell.setBackground(getBackground(element)); + + super.update(cell); + } + + /** + * Provides a foreground color for the given element. + * + * @param element + * the element + * @return the foreground color for the element, or null to + * use the default foreground color + */ + public Color getForeground(Object element) { + if (this.styledLabelProvider instanceof IColorProvider) { + return ((IColorProvider) this.styledLabelProvider) + .getForeground(element); + } + return null; + } + + /** + * Provides a background color for the given element. + * + * @param element + * the element + * @return the background color for the element, or null to + * use the default background color + */ + public Color getBackground(Object element) { + if (this.styledLabelProvider instanceof IColorProvider) { + return ((IColorProvider) this.styledLabelProvider) + .getBackground(element); + } + return null; + } + + /** + * Provides a font for the given element. + * + * @param element + * the element + * @return the font for the element, or null to use the + * default font + */ + public Font getFont(Object element) { + if (this.styledLabelProvider instanceof IFontProvider) { + return ((IFontProvider) this.styledLabelProvider).getFont(element); + } + return null; + } + + /** + * Returns the image for the label of the given element. The image is owned + * by the label provider and must not be disposed directly. Instead, dispose + * the label provider when no longer needed. + * + * @param element + * the element for which to provide the label image + * @return the image used to label the element, or null if + * there is no image for the given object + */ + public Image getImage(Object element) { + return this.styledLabelProvider.getImage(element); + } + + /** + * Returns the styled text for the label of the given element. + * + * @param element + * the element for which to provide the styled label text + * @return the styled text string used to label the element + */ + protected StyledString getStyledText(Object element) { + return this.styledLabelProvider.getStyledText(element); + } + + /** + * Returns the styled string provider. + * + * @return the wrapped label provider + */ + public IStyledLabelProvider getStyledStringProvider() { + return this.styledLabelProvider; + } + + public void addListener(ILabelProviderListener listener) { + super.addListener(listener); + this.styledLabelProvider.addListener(listener); + } + + public void removeListener(ILabelProviderListener listener) { + super.removeListener(listener); + this.styledLabelProvider.removeListener(listener); + } + + public bool isLabelProperty(Object element, String property) { + return this.styledLabelProvider.isLabelProperty(element, property); + } + + public void dispose() { + super.dispose(); + this.styledLabelProvider.dispose(); + } + +} diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/EditingSupport.d --- a/dwtx/jface/viewers/EditingSupport.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/EditingSupport.d Thu May 22 01:36:46 2008 +0200 @@ -8,7 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation * Tom Schindl - initial API and implementation - * fix in bug 151295,167325,200558 + * fix in bug 151295,167325,201905 * Port to the D programming language: * Frank Benoit *******************************************************************************/ diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/FocusCellHighlighter.d --- a/dwtx/jface/viewers/FocusCellHighlighter.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/FocusCellHighlighter.d Thu May 22 01:36:46 2008 +0200 @@ -7,6 +7,8 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Tom Schindl - initial API and implementation + * bugfix in: 182800 * Port to the D programming language: * Frank Benoit ******************************************************************************/ @@ -40,9 +42,12 @@ } /** - * Called by the framework when the focus cell has changed. Subclasses may extend. + * Called by the framework when the focus cell has changed. Subclasses may + * extend. * - * @param cell the new focus cell + * @param cell + * the new focus cell + * @deprecated use {@link #focusCellChanged(ViewerCell, ViewerCell)} instead */ protected void focusCellChanged(ViewerCell cell) { } @@ -51,6 +56,26 @@ } /** + * Called by the framework when the focus cell has changed. Subclasses may + * extend. + *

+ * The default implementation for this method calls + * focusCellChanged(ViewerCell). Subclasses should override this method + * rather than {@link #focusCellChanged(ViewerCell)} . + * + * @param newCell + * the new focus cell or null if no new cell + * receives the focus + * @param oldCell + * the old focus cell or null if no cell has been + * focused before + * @since 3.4 + */ + protected void focusCellChanged(ViewerCell newCell, ViewerCell oldCell) { + focusCellChanged(newCell); + } + + /** * This method is called by the framework to initialize this cell * highlighter object. Subclasses may extend. */ diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/FocusCellOwnerDrawHighlighter.d --- a/dwtx/jface/viewers/FocusCellOwnerDrawHighlighter.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/FocusCellOwnerDrawHighlighter.d Thu May 22 01:36:46 2008 +0200 @@ -1,17 +1,17 @@ /******************************************************************************* - * Copyright (c) 2007 IBM Corporation and others. + * 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 * Tom Schindl - initial API and implementation - * - fix for bug 183850, 182652 - * IBM Corporation - initial API and implementation + * - fix for bug 183850, 182652, 182800, 215069 * Port to the D programming language: * Frank Benoit - ******************************************************************************/ + *******************************************************************************/ module dwtx.jface.viewers.FocusCellOwnerDrawHighlighter; @@ -31,21 +31,22 @@ import dwt.dwthelper.utils; /** + * A concrete implementation of {@link FocusCellHighlighter} using by setting + * the control into owner draw mode and highlighting the currently selected + * cell. To make the use this class you should create the control with the + * {@link DWT#FULL_SELECTION} bit set + * + * This class can be subclassed to configure how the coloring of the selected + * cell. + * * @since 3.3 * */ public class FocusCellOwnerDrawHighlighter : FocusCellHighlighter { - - private ViewerCell oldCell; - - // Needed to work-around problem in bug 183850 - private static const bool WIN_32; - - static this(){ - WIN_32 = "win32".equals(DWT.getPlatform()); //$NON-NLS-1$ - } - /** + * Create a new instance which can be passed to a + * {@link TreeViewerFocusCellManager} + * * @param viewer * the viewer */ @@ -55,10 +56,12 @@ } private void markFocusedCell(Event event, ViewerCell cell) { - Color background = getSelectedCellBackgroundColor(cell); - Color foreground = getSelectedCellForegroundColor(cell); + Color background = (cell.getControl().isFocusControl()) ? getSelectedCellBackgroundColor(cell) + : getSelectedCellBackgroundColorNoFocus(cell); + Color foreground = (cell.getControl().isFocusControl()) ? getSelectedCellForegroundColor(cell) + : getSelectedCellForegroundColorNoFocus(cell); - if ( WIN_32 || foreground !is null || background !is null) { + if (foreground !is null || background !is null || onlyTextHighlighting(cell)) { GC gc = event.gc; if (background is null) { @@ -73,10 +76,18 @@ gc.setBackground(background); gc.setForeground(foreground); - gc.fillRectangle(event.getBounds()); - - // This is a workaround for an DWT-Bug on WinXP bug 169517 - gc.drawText(" ", cell.getBounds().x, cell.getBounds().y, false); //$NON-NLS-1$ + + if (onlyTextHighlighting(cell)) { + Rectangle area = event.getBounds(); + Rectangle rect = cell.getTextBounds(); + if( rect !is null ) { + area.x = rect.x; + } + gc.fillRectangle(area); + } else { + gc.fillRectangle(event.getBounds()); + } + event.detail &= ~DWT.SELECTED; } } @@ -88,8 +99,6 @@ gc.setForeground(cell.getViewerRow().getForeground( cell.getColumnIndex())); gc.fillRectangle(cell.getBounds()); - // This is a workaround for an DWT-Bug on WinXP bug 169517 - gc.drawText(" ", cell.getBounds().x, cell.getBounds().y, false); //$NON-NLS-1$ event.detail &= ~DWT.SELECTED; } @@ -123,39 +132,81 @@ } /** + * The color to use when rendering the background of the selected cell when + * the control has the input focus + * * @param cell * the cell which is colored - * @return the color + * @return the color or null to use the default */ protected Color getSelectedCellBackgroundColor(ViewerCell cell) { return null; } /** + * The color to use when rendering the foreground (=text) of the selected + * cell when the control has the input focus + * * @param cell * the cell which is colored - * @return the color + * @return the color or null to use the default */ protected Color getSelectedCellForegroundColor(ViewerCell cell) { return null; } - /* - * (non-Javadoc) - * - * @see dwtx.jface.viewers.FocusCellHighlighter#focusCellChanged(dwtx.jface.viewers.ViewerCell) + /** + * The color to use when rendering the foreground (=text) of the selected + * cell when the control has no input focus + * + * @param cell + * the cell which is colored + * @return the color or null to use the same used when + * control has focus + * @since 3.4 */ - protected override void focusCellChanged(ViewerCell cell) { - super.focusCellChanged(cell); + protected Color getSelectedCellForegroundColorNoFocus(ViewerCell cell) { + return null; + } + + /** + * The color to use when rendering the background of the selected cell when + * the control has no input focus + * + * @param cell + * the cell which is colored + * @return the color or null to use the same used when + * control has focus + * @since 3.4 + */ + protected Color getSelectedCellBackgroundColorNoFocus(ViewerCell cell) { + return null; + } + + /** + * Controls whether the whole cell or only the text-area is highlighted + * + * @param cell + * the cell which is highlighted + * @return true if only the text area should be highlighted + * @since 3.4 + */ + protected bool onlyTextHighlighting(ViewerCell cell) { + return false; + } + + protected void focusCellChanged(ViewerCell newCell, ViewerCell oldCell) { + super.focusCellChanged(newCell, oldCell); // Redraw new area - if (cell !is null) { - Rectangle rect = cell.getBounds(); - int x = cell.getColumnIndex() is 0 ? 0 : rect.x; - int width = cell.getColumnIndex() is 0 ? rect.x + rect.width + if (newCell !is null) { + Rectangle rect = newCell.getBounds(); + int x = newCell.getColumnIndex() is 0 ? 0 : rect.x; + int width = newCell.getColumnIndex() is 0 ? rect.x + rect.width : rect.width; // 1 is a fix for Linux-GTK - cell.getControl().redraw(x, rect.y-1, width, rect.height+1, true); + newCell.getControl().redraw(x, rect.y - 1, width, rect.height + 1, + true); } if (oldCell !is null) { @@ -164,9 +215,8 @@ int width = oldCell.getColumnIndex() is 0 ? rect.x + rect.width : rect.width; // 1 is a fix for Linux-GTK - oldCell.getControl().redraw(x, rect.y-1, width, rect.height+1, true); + oldCell.getControl().redraw(x, rect.y - 1, width, rect.height + 1, + true); } - - this.oldCell = cell; } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/IDecoration.d --- a/dwtx/jface/viewers/IDecoration.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/IDecoration.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -54,6 +54,28 @@ public static const int UNDERLAY = 4; /** + * Constant for replacing the original image. Note that for this to have an + * effect on the resulting decorated image, {@link #ENABLE_REPLACE} has to + * be set to {@link Boolean#TRUE} in the {@link IDecorationContext} (opt-in + * model). If replacement behavior is enabled, the resulting decorated image + * will be constructed by first painting the underlay, then the replacement + * image, and then the regular quadrant images. + * + * @since 3.4 + */ + public static final int REPLACE = 5; + + /** + * Constant that is used as the property key on an + * {@link IDecorationContext}. To enable image replacement, set to + * {@link Boolean#TRUE}. + * + * @since 3.4 + * @see IDecorationContext + */ + public static final String ENABLE_REPLACE = "dwtx.jface.viewers.IDecoration.disableReplace"; //$NON-NLS-1$ + + /** * Adds a prefix to the element's label. * * @param prefix diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/IStructuredContentProvider.d --- a/dwtx/jface/viewers/IStructuredContentProvider.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/IStructuredContentProvider.d Thu May 22 01:36:46 2008 +0200 @@ -25,7 +25,12 @@ * when its input is set to the given element. * These elements can be presented as rows in a table, items in a list, etc. * The result is not modified by the viewer. - * + *

+ * NOTE: For instances where the viewer is displaying a tree + * containing a single 'root' element it is still necessary that the + * 'input' does not return itself from this method. This leads + * to recursion issues (see bug 9262). + *

* @param inputElement the input element * @return the array of elements to display in the viewer */ diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/IStructuredSelection.d --- a/dwtx/jface/viewers/IStructuredSelection.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/IStructuredSelection.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -52,6 +52,9 @@ /** * Returns the elements in this selection as a List. + * Note In the default implementation of {@link #toList()} in + * {@link StructuredSelection} the returned list is not a copy of the elements of the + * receiver and modifying it will modify the contents of the selection. * * @return the selected elements as a list */ diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/ITreeSelection.d --- a/dwtx/jface/viewers/ITreeSelection.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/ITreeSelection.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2006 IBM Corporation and others. + * Copyright (c) 2005, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -19,6 +19,25 @@ /** * A selection containing tree paths. + *

+ * It is recommended that clients do not implement this interface but instead + * use the standard implementation of this interface, {@link TreeSelection}. + * TreeSelection adds API for getting the {@link IElementComparer} + * of a selection (if available). This is important for clients who want to + * create a slightly modified tree selection based on an existing tree selection. + * The recommended coding pattern in this case is as follows: + *

+ * ITreeSelection selection = (ITreeSelection)treeViewer.getSelection();
+ * TreePath[] paths = selection.getPaths();
+ * IElementComparer comparer = null;
+ * if (selection instanceof TreeSelection) {
+ *   comparer = ((TreeSelection)selection).getElementComparer();
+ * }
+ * TreePath[] modifiedPaths = ... // modify as required
+ * TreeSelection modifiedSelection = new TreeSelection(modifiedPaths, comparer);
+ * 
+ * See bugs 135818 and 133375 for details. + *

* * @since 3.2 * diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/NamedHandleObjectLabelProvider.d --- a/dwtx/jface/viewers/NamedHandleObjectLabelProvider.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/NamedHandleObjectLabelProvider.d Thu May 22 01:36:46 2008 +0200 @@ -1,55 +1,56 @@ -/******************************************************************************* - * Copyright (c) 2005 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 - * Port to the D programming language: - * Frank Benoit - *******************************************************************************/ - -module dwtx.jface.viewers.NamedHandleObjectLabelProvider; - -import dwtx.jface.viewers.DialogCellEditor; -import dwtx.jface.viewers.LabelProvider; - - -import dwtx.core.commands.common.NamedHandleObject; -import dwtx.core.commands.common.NotDefinedException; - -import dwt.dwthelper.utils; - -/** - * A label provider for instances of NamedHandlerObject, which - * exposes the name as the label. - * - * @since 3.2 - */ -public final class NamedHandleObjectLabelProvider : LabelProvider { - - /** - * The text of the element is simply the name of the element if its a - * defined instance of NamedHandleObject. Otherwise, this - * method just returns null. - * - * @param element - * The element for which the text should be retrieved; may be - * null. - * @return the name of the handle object; null if there is no - * name or if the element is not a named handle object. - */ - public override final String getText(Object element) { - if ( cast(NamedHandleObject)element ) { - try { - return (cast(NamedHandleObject) element).getName(); - } catch (NotDefinedException e) { - return null; - } - } - - return null; - } -} +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Port to the D programming language: + * Frank Benoit + *******************************************************************************/ + +module dwtx.jface.viewers.NamedHandleObjectLabelProvider; + +import dwtx.jface.viewers.DialogCellEditor; +import dwtx.jface.viewers.LabelProvider; + + +import dwtx.core.commands.common.NamedHandleObject; +import dwtx.core.commands.common.NotDefinedException; + +import dwt.dwthelper.utils; + +/** + * A label provider for instances of NamedHandlerObject, which + * exposes the name as the label. + * + * @since 3.2 + */ +public final class NamedHandleObjectLabelProvider : LabelProvider { + + /** + * The text of the element is simply the name of the element if its a + * defined instance of NamedHandleObject. Otherwise, this + * method just returns null. + * + * @param element + * The element for which the text should be retrieved; may be + * null. + * @return the name of the handle object; null if there is no + * name or if the element is not a named handle object. + */ + public override final String getText(Object element) { + if ( cast(NamedHandleObject)element ) { + try { + return (cast(NamedHandleObject) element).getName(); + } catch (NotDefinedException e) { + return null; + } + } + + return null; + } +} + diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/SWTFocusCellManager.d --- a/dwtx/jface/viewers/SWTFocusCellManager.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/SWTFocusCellManager.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 IBM Corporation and others. + * 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 @@ -8,10 +8,10 @@ * Contributors: * IBM Corporation - initial API and implementation * Tom Schindl - initial API and implementation - * - bug fix for bug 187189 + * - bug fix for bug 187189, 182800, 215069 * Port to the D programming language: * Frank Benoit - ******************************************************************************/ + *******************************************************************************/ module dwtx.jface.viewers.SWTFocusCellManager; @@ -52,6 +52,7 @@ private DisposeListener itemDeletionListener; + /** * @param viewer * @param focusDrawingDelegate @@ -114,8 +115,8 @@ } private void handleSelection(Event event) { - if (focusCell !is null && focusCell.getItem() !is event.item - && event.item !is null) { + if ((event.detail & DWT.CHECK) is 0 && focusCell !is null && focusCell.getItem() !is event.item + && event.item !is null ) { ViewerRow row = viewer.getViewerRowFromItem_package(event.item); Assert .isNotNull(row, @@ -180,6 +181,8 @@ } void setFocusCell(ViewerCell focusCell) { + ViewerCell oldCell = this.focusCell; + if( this.focusCell !is null && ! this.focusCell.getItem().isDisposed() ) { this.focusCell.getItem().removeDisposeListener(itemDeletionListener); } @@ -190,7 +193,7 @@ this.focusCell.getItem().addDisposeListener(itemDeletionListener); } - this.cellHighlighter.focusCellChanged_package(focusCell); + this.cellHighlighter.focusCellChanged/*_package*/(focusCell,oldCell); } ColumnViewer getViewer() { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/StructuredSelection.d --- a/dwtx/jface/viewers/StructuredSelection.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/StructuredSelection.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -41,6 +41,11 @@ private Object[] elements; /** + * The element comparer, or null + */ + private IElementComparer comparer; + + /** * The canonical empty selection. This selection should be used instead of * null. */ @@ -83,8 +88,24 @@ * @param elements list of selected elements */ public this(SeqView!(Object) elements) { - Assert.isNotNull(cast(Object)elements); + this(elements, null); + } + + /** + * Creates a structured selection from the given List and + * element comparer. If an element comparer is provided, it will be used to + * determine equality between structured selection objects provided that + * they both are based on the same (identical) comparer. See bug + * + * @param elements + * list of selected elements + * @param comparer + * the comparer, or null + * @since 3.4 + */ + public StructuredSelection(List elements, IElementComparer comparer) { this.elements = elements.toArray(); + this.comparer = comparer; } /** @@ -113,6 +134,8 @@ return false; } + bool useComparer = comparer !is null && comparer is s2.comparer; + //size int myLen = elements.length; if (myLen !is s2.elements.length) { @@ -120,8 +143,14 @@ } //element comparison for (int i = 0; i < myLen; i++) { - if (!elements[i].opEquals(s2.elements[i])) { - return false; + if (useComparer) { + if (!comparer.equals(elements[i], s2.elements[i])) { + return false; + } + } else { + if (!elements[i].equals(s2.elements[i])) { + return false; + } } } return true; diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/StructuredViewer.d --- a/dwtx/jface/viewers/StructuredViewer.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/StructuredViewer.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -334,7 +334,7 @@ } /** - * The ColorAndFontManager collects fonts and colors without a + * The ColorAndFontCollector collects fonts and colors without a * a color or font provider. * */ @@ -1025,7 +1025,7 @@ return StructuredSelection.EMPTY; } auto list = getSelectionFromWidget(); - return new StructuredSelection(list); + return new StructuredSelection(list, comparer); } /** @@ -1382,9 +1382,7 @@ * setSelectionToWidget *
  • rediscovers the resulting selection (via getSelection) *
  • - *
  • calls handleInvalidSelection if the selection did not - * take
  • - *
  • calls postUpdateHook
  • + *
  • calls handleInvalidSelection if the resulting selection is different from the old selection
  • * *

    * @@ -1410,7 +1408,6 @@ * *
  • calls handleInvalidSelection if the selection did not * take
  • - *
  • calls postUpdateHook
  • * *

    * @@ -1539,7 +1536,7 @@ /** * - * Refreshes the given TableItem with the given element. Calls + * Refreshes the given item with the given element. Calls * doUpdateItem(..., false). *

    * This method is internal to the framework; subclassers should not call @@ -1947,6 +1944,9 @@ } } + // flag to indicate that a full refresh took place. See bug 102440. + private bool refreshOccurred; + /** * Updates the given elements' presentation when one or more of their * properties change. Only the given elements are updated. @@ -1987,8 +1987,17 @@ * indicate unknown */ public void update(Object[] elements, String[] properties) { - for (int i = 0; i < elements.length; ++i) { - update(elements[i], properties); + bool previousValue = refreshOccurred; + refreshOccurred = false; + try { + for (int i = 0; i < elements.length; ++i) { + update(elements[i], properties); + if (refreshOccurred) { + return; + } + } + } finally { + refreshOccurred = previousValue; } } @@ -2035,8 +2044,13 @@ Assert.isNotNull(element); Widget[] items = findItems(element); + bool mayExitEarly = !refreshOccurred; for (int i = 0; i < items.length; i++) { internalUpdate(items[i], element, properties); + if (mayExitEarly && refreshOccurred) { + // detected a change from refreshOccurredisfalse to refreshOccurredistrue + return; + } } } @@ -2073,6 +2087,7 @@ preservingSelection(new class Runnable { public void run() { internalRefresh(getRoot()); + refreshOccurred = true; } }); return; diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/StyledCellLabelProvider.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/viewers/StyledCellLabelProvider.d Thu May 22 01:36:46 2008 +0200 @@ -0,0 +1,384 @@ +/******************************************************************************* + * 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 + * Michael Krkoska - initial API and implementation (bug 188333) + * Port to the D programming language: + * Frank Benoit + *******************************************************************************/ +module dwtx.jface.viewers.StyledCellLabelProvider; + + +import dwt.DWT; +import dwt.custom.StyleRange; +import dwt.graphics.Color; +import dwt.graphics.GC; +import dwt.graphics.Image; +import dwt.graphics.Rectangle; +import dwt.graphics.TextLayout; +import dwt.widgets.Display; +import dwt.widgets.Event; +import dwtx.core.runtime.Assert; + +/** + * A {@link StyledCellLabelProvider} supports styled labels by using owner + * draw. + * Besides the styles in labels, the label provider preserves native viewer behavior: + *

      + *
    • similar image and label positioning
    • + *
    • native drawing of focus and selection
    • + *
    + *

    + * For providing the label's styles, create a subclass and overwrite + * {@link StyledCellLabelProvider#update(ViewerCell)} to + * return set all information needed to render a element. Use + * {@link ViewerCell#setStyleRanges(StyleRange[])} to set style ranges + * on the label. + *

    + *

    + * The current version of the {@link StyledCellLabelProvider} will ignore all font settings on + * {@link StyleRange}. Different fonts would make labels wider, and the native + * selection drawing could not be reused. + *

    + * + *

    NOTE: This API is experimental and may be deleted or + * changed before 3.4 is released.

    + * + * @since 3.4 + */ +public abstract class StyledCellLabelProvider extends OwnerDrawLabelProvider { + + /** + * Style constant for indicating that the styled colors are to be applied + * even it the viewer's item is selected. Default is not to apply colors. + */ + public static final int COLORS_ON_SELECTION = 1 << 0; + + /** + * Style constant for indicating to draw the focus if requested by the owner + * draw event. Default is to draw the focus. + */ + public static final int NO_FOCUS = 1 << 1; + + /** + * Private constant to indicate if owner draw is enabled for the + * label provider's column. + */ + private static final int OWNER_DRAW_ENABLED = 1 << 4; + + private int style; + + // reused text layout + private TextLayout cachedTextLayout; + + private ColumnViewer viewer; + private ViewerColumn column; + + /** + * Creates a new StyledCellLabelProvider. By default, owner draw is enabled, focus is drawn and no + * colors are painted on selected elements. + */ + public StyledCellLabelProvider() { + this(0); + } + + /** + * Creates a new StyledCellLabelProvider. By default, owner draw is enabled. + * + * @param style + * the style bits + * @see StyledCellLabelProvider#COLORS_ON_SELECTION + * @see StyledCellLabelProvider#NO_FOCUS + */ + public StyledCellLabelProvider(int style) { + this.style = style & (COLORS_ON_SELECTION | NO_FOCUS) + | OWNER_DRAW_ENABLED; + } + + /** + * Returns true is the owner draw rendering is enabled for this label provider. + * By default owner draw rendering is enabled. If owner draw rendering is disabled, rending is + * done by the viewer and no styled ranges (see {@link ViewerCell#getStyleRanges()}) + * are drawn. + * + * @return true is the rendering of styles is enabled. + */ + public bool isOwnerDrawEnabled() { + return (this.style & OWNER_DRAW_ENABLED) !is 0; + } + + /** + * Specifies whether owner draw rendering is enabled for this label + * provider. By default owner draw rendering is enabled. If owner draw + * rendering is disabled, rendering is done by the viewer and no styled + * ranges (see {@link ViewerCell#getStyleRanges()}) are drawn. + * It is the caller's responsibility to also call + * {@link StructuredViewer#refresh()} or similar methods to update the + * underlying widget. + * + * @param enabled + * specifies if owner draw rendering is enabled + */ + public void setOwnerDrawEnabled(bool enabled) { + bool isEnabled= isOwnerDrawEnabled(); + if (isEnabled !is enabled) { + if (enabled) { + this.style |= OWNER_DRAW_ENABLED; + } else { + this.style &= ~OWNER_DRAW_ENABLED; + } + if (this.viewer !is null) { + setOwnerDrawEnabled(this.viewer, this.column, enabled); + } + } + } + + /** + * Returns the viewer on which this label provider is installed on or null if the + * label provider is not installed. + * + * @return the viewer on which this label provider is installed on or null if the + * label provider is not installed. + */ + protected final ColumnViewer getViewer() { + return this.viewer; + } + + /** + * Returns the column on which this label provider is installed on or null if the + * label provider is not installed. + * + * @return the column on which this label provider is installed on or null if the + * label provider is not installed. + */ + protected final ViewerColumn getColumn() { + return this.column; + } + + /* (non-Javadoc) + * @see dwtx.jface.viewers.OwnerDrawLabelProvider#initialize(dwtx.jface.viewers.ColumnViewer, dwtx.jface.viewers.ViewerColumn) + */ + public void initialize(ColumnViewer viewer, ViewerColumn column) { + Assert.isTrue(this.viewer is null && this.column is null, "Label provider instance already in use"); //$NON-NLS-1$ + + this.viewer= viewer; + this.column= column; + super.initialize(viewer, column, isOwnerDrawEnabled()); + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.BaseLabelProvider#dispose() + */ + public void dispose() { + if (this.cachedTextLayout !is null) { + cachedTextLayout.dispose(); + cachedTextLayout = null; + } + + this.viewer= null; + this.column= null; + + super.dispose(); + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.OwnerDrawLabelProvider#update(dwtx.jface.viewers.ViewerCell) + */ + public void update(ViewerCell cell) { + // clients must override and configure the cell and call super + super.update(cell); // calls 'repaint' to trigger the paint listener + } + + private TextLayout getSharedTextLayout(Display display) { + if (cachedTextLayout is null) { + int orientation = viewer.getControl().getStyle() & (DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT); + cachedTextLayout = new TextLayout(display); + cachedTextLayout.setOrientation(orientation); + } else { + cachedTextLayout.setText(""); // make sure no previous ranges are cleared //$NON-NLS-1$ + } + return cachedTextLayout; + } + + private bool useColors(Event event) { + return (event.detail & DWT.SELECTED) is 0 + || (this.style & COLORS_ON_SELECTION) !is 0; + } + + private bool drawFocus(Event event) { + return (event.detail & DWT.FOCUSED) !is 0 + && (this.style & NO_FOCUS) is 0; + } + + /** + * Returns a {@link TextLayout} instance for the given cell + * configured with the style ranges. The text layout instance is managed by + * the label provider. Caller of the method must not dispose the text + * layout. + * + * @param diplay + * the current display + * @param applyColors + * if set, create colors in the result + * @param cell + * the viewer cell + * @return a TextLayout instance + */ + private TextLayout getTextLayoutForInfo(Display display, ViewerCell cell, bool applyColors) { + TextLayout layout = getSharedTextLayout(display); + + layout.setText(cell.getText()); + layout.setFont(cell.getFont()); // set also if null to clear previous usages + + StyleRange[] styleRanges = cell.getStyleRanges(); + if (styleRanges !is null) { // user didn't fill styled ranges + for (int i = 0; i < styleRanges.length; i++) { + StyleRange curr = prepareStyleRange(styleRanges[i], applyColors); + layout.setStyle(curr, curr.start, curr.start + curr.length - 1); + } + } + + return layout; + } + + /** + * Prepares the given style range before it is applied to the label. This method makes sure that + * no colors are drawn when the element is selected. + * The current version of the {@link StyledCellLabelProvider} will also ignore all font settings on the + * style range. Clients can override. + * + * @param styleRange + * the style range to prepare. the style range element must not be modified + * @param applyColors + * specifies if colors should be applied. + * @return + * returns the style range to use on the label + */ + protected StyleRange prepareStyleRange(StyleRange styleRange, bool applyColors) { + // if no colors apply or font is set, create a clone and clear the + // colors and font + if (styleRange.font !is null || !applyColors + && (styleRange.foreground !is null || styleRange.background !is null)) { + styleRange = (StyleRange) styleRange.clone(); + styleRange.font = null; // ignore font settings until bug 168807 is resolved + if (!applyColors) { + styleRange.foreground = null; + styleRange.background = null; + } + } + return styleRange; + } + + private ViewerCell getViewerCell(Event event, Object element) { + ViewerRow row= viewer.getViewerRowFromItem(event.item); + return new ViewerCell(row, event.index, element); + } + + /** + * Handle the erase event. The default implementation does nothing to ensure + * keep native selection highlighting working. + * + * @param event + * the erase event + * @param element + * the model object + * @see DWT#EraseItem + */ + protected void erase(Event event, Object element) { + // use native erase + if (isOwnerDrawEnabled()) { + // info has been set by 'update': announce that we paint ourselves + event.detail &= ~DWT.FOREGROUND; + } + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.OwnerDrawLabelProvider#measure(dwt.widgets.Event, + * java.lang.Object) + */ + protected void measure(Event event, Object element) { + // use native measuring + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.OwnerDrawLabelProvider#paint(dwt.widgets.Event, + * java.lang.Object) + */ + protected void paint(Event event, Object element) { + if (!isOwnerDrawEnabled()) + return; + + ViewerCell cell= getViewerCell(event, element); + + bool applyColors = useColors(event); + GC gc = event.gc; + // remember colors to restore the GC later + Color oldForeground = gc.getForeground(); + Color oldBackground = gc.getBackground(); + + if (applyColors) { + Color foreground= cell.getForeground(); + if (foreground !is null) { + gc.setForeground(foreground); + } + + Color background= cell.getBackground(); + if (background !is null) { + gc.setBackground(background); + } + } + + Image image = cell.getImage(); + if (image !is null) { + Rectangle imageBounds = cell.getImageBounds(); + if (imageBounds !is null) { + Rectangle bounds = image.getBounds(); + + // center the image in the given space + int x = imageBounds.x + + Math.max(0, (imageBounds.width - bounds.width) / 2); + int y = imageBounds.y + + Math.max(0, (imageBounds.height - bounds.height) / 2); + gc.drawImage(image, x, y); + } + } + + TextLayout textLayout = getTextLayoutForInfo(event.display, cell, applyColors); + + Rectangle textBounds = cell.getTextBounds(); + if (textBounds !is null) { + Rectangle layoutBounds = textLayout.getBounds(); + + int x = textBounds.x; + int y = textBounds.y + + Math.max(0, (textBounds.height - layoutBounds.height) / 2); + + textLayout.draw(gc, x, y); + } + + if (drawFocus(event)) { + Rectangle focusBounds = cell.getViewerRow().getBounds(); + gc.drawFocus(focusBounds.x, focusBounds.y, focusBounds.width, + focusBounds.height); + } + + if (applyColors) { + gc.setForeground(oldForeground); + gc.setBackground(oldBackground); + } + } + +} diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/StyledString.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/viewers/StyledString.d Thu May 22 01:36:46 2008 +0200 @@ -0,0 +1,511 @@ +/******************************************************************************* + * Copyright (c) 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 + * Port to the D programming language: + * Frank Benoit + *******************************************************************************/ +module dwtx.jface.viewers.StyledString; + +import java.util.ArrayList; +import java.util.List; + +import dwt.custom.StyleRange; +import dwt.graphics.TextStyle; +import dwtx.jface.preference.JFacePreferences; +import dwtx.jface.resource.ColorRegistry; +import dwtx.jface.resource.JFaceResources; + +/** + * A mutable string with styled ranges. All ranges mark substrings of the string + * and do not overlap. Styles are applied using instances of {@link Styler} to + * compute the result of {@link #getStyleRanges()}. + * + * The styled string can be built in the following two ways: + *
      + *
    • new strings with stylers can be appended
    • + *
    • stylers can by applied to ranges of the existing string
    • + *
    + * + *

    + * This class may be instantiated; it is not intended to be subclassed. + *

    + * + * @since 3.4 + */ +public class StyledString { + + /** + * A styler will be asked to apply its styles to one ore more ranges in the + * {@link StyledString}. + * + */ + public static abstract class Styler { + + /** + * Applies the styles represented by this object to the given textStyle. + * + * @param textStyle + * the {@link TextStyle} to modify + */ + public abstract void applyStyles(TextStyle textStyle); + } + + /** + * A built-in styler using the {@link JFacePreferences#QUALIFIER_COLOR} + * managed in the JFace color registry (See + * {@link JFaceResources#getColorRegistry()}). + */ + public static final Styler QUALIFIER_STYLER = createColorRegistryStyler( + JFacePreferences.QUALIFIER_COLOR, null); + + /** + * A built-in styler using the {@link JFacePreferences#COUNTER_COLOR} + * managed in the JFace color registry (See + * {@link JFaceResources#getColorRegistry()}). + */ + public static final Styler COUNTER_STYLER = createColorRegistryStyler( + JFacePreferences.COUNTER_COLOR, null); + + /** + * A built-in styler using the {@link JFacePreferences#DECORATIONS_COLOR} + * managed in the JFace color registry (See + * {@link JFaceResources#getColorRegistry()}). + */ + public static final Styler DECORATIONS_STYLER = createColorRegistryStyler( + JFacePreferences.DECORATIONS_COLOR, null); + + /** + * Creates a styler that takes the given foreground and background colors + * from the JFace color registry. + * + * @param foregroundColorName + * the color name for the foreground color + * @param backgroundColorName + * the color name for the background color + * + * @return the created style + */ + public static Styler createColorRegistryStyler(String foregroundColorName, + String backgroundColorName) { + return new DefaultStyler(foregroundColorName, backgroundColorName); + } + + private static final StyleRange[] EMPTY = new StyleRange[0]; + private StringBuffer fBuffer; + private StyleRunList fStyleRuns; + + /** + * Creates an empty {@link StyledString}. + */ + public StyledString() { + fBuffer = new StringBuffer(); + fStyleRuns = null; + } + + /** + * Creates an {@link StyledString} initialized with a string without + * a style associated. + * + * @param string + * the string + */ + public StyledString(String string) { + this(string, null); + } + + /** + * Creates an {@link StyledString} initialized with a string and a + * style. + * + * @param string + * the string + * @param styler + * the styler for the string or null to not + * associated a styler. + */ + public StyledString(String string, Styler styler) { + this(); + append(string, styler); + } + + /** + * Returns the string of this {@link StyledString}. + * + * @return the current string of this {@link StyledString}. + */ + public String getString() { + return fBuffer.toString(); + } + + /** + * Returns the string of this {@link StyledString}. + * + * @return the current string of this {@link StyledString}. + */ + public String toString() { + return getString(); + } + + /** + * Returns the length of the string of this {@link StyledString}. + * + * @return the length of the current string + */ + public int length() { + return fBuffer.length(); + } + + /** + * Appends a string to the {@link StyledString}. The appended string + * will have no associated styler. + * + * @param string + * the string to append + * @return returns a reference to this object + */ + public StyledString append(String string) { + return append(string, null); + } + + /** + * Appends the string representation of the given character array + * to the {@link StyledString}. The appended + * character array will have no associated styler. + * + * @param chars + * the character array to append + * @return returns a reference to this object + */ + public StyledString append(char[] chars) { + return append(chars, null); + } + + /** + * Appends the string representation of the given character + * to the {@link StyledString}. The appended + * character will have no associated styler. + * + * @param ch + * the character to append + * @return returns a reference to this object + */ + public StyledString append(char ch) { + return append(String.valueOf(ch), null); + } + + /** + * Appends a string with styles to the {@link StyledString}. + * + * @param string + * the string to append + * @return returns a reference to this object + */ + public StyledString append(StyledString string) { + if (string.length() is 0) { + return this; + } + + int offset = fBuffer.length(); + fBuffer.append(string.toString()); + + List otherRuns = string.fStyleRuns; + if (otherRuns !is null && !otherRuns.isEmpty()) { + for (int i = 0; i < otherRuns.size(); i++) { + StyleRun curr = (StyleRun) otherRuns.get(i); + if (i is 0 && curr.offset !is 0) { + appendStyleRun(null, offset); // appended string will + // start with the default + // color + } + appendStyleRun(curr.style, offset + curr.offset); + } + } else { + appendStyleRun(null, offset); // appended string will start with + // the default color + } + return this; + } + + /** + * Appends the string representation of the given character + * with a style to the {@link StyledString}. The + * appended character will have the given style associated. + * + * @param ch + * the character to append + * @param styler + * the styler to use for styling the character to append or + * null if no styler should be associated with the + * appended character + * @return returns a reference to this object + */ + public StyledString append(char ch, Styler styler) { + return append(String.valueOf(ch), styler); + } + + /** + * Appends a string with a style to the {@link StyledString}. The + * appended string will be styled using the given styler. + * + * @param string + * the string to append + * @param styler + * the styler to use for styling the string to append or + * null if no styler should be associated with the + * appended string. + * @return returns a reference to this object + */ + public StyledString append(String string, Styler styler) { + if (string.length() is 0) + return this; + + int offset = fBuffer.length(); // the length before appending + fBuffer.append(string); + appendStyleRun(styler, offset); + return this; + } + + /** + * Appends the string representation of the given character array + * with a style to the {@link StyledString}. The + * appended character array will be styled using the given styler. + * + * @param chars + * the character array to append + * @param styler + * the styler to use for styling the character array to append or + * null if no styler should be associated with the + * appended character array + * @return returns a reference to this object + */ + public StyledString append(char[] chars, Styler styler) { + if (chars.length is 0) + return this; + + int offset = fBuffer.length(); // the length before appending + fBuffer.append(chars); + appendStyleRun(styler, offset); + return this; + } + + /** + * Sets a styler to use for the given source range. The range must be + * subrange of actual string of this {@link StyledString}. Stylers + * previously set for that range will be overwritten. + * + * @param offset + * the start offset of the range + * @param length + * the length of the range + * @param styler + * the styler to set + * + * @throws StringIndexOutOfBoundsException + * if start is less than zero, or if offset plus + * length is greater than the length of this object. + */ + public void setStyle(int offset, int length, Styler styler) { + if (offset < 0 || offset + length > fBuffer.length()) { + throw new StringIndexOutOfBoundsException( + "Invalid offset (" + offset + ") or length (" + length + ")"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + } + if (length is 0) { + return; + } + if (!hasRuns() || getLastRun().offset <= offset) { + appendStyleRun(styler, offset); + if (offset + length !is fBuffer.length()) { + appendStyleRun(null, offset + length); + } + return; + } + + int endRun = findRun(offset + length); + if (endRun >= 0) { + // run with the same end index, nothing to change + } else { + endRun = -(endRun + 1); + if (offset + length < fBuffer.length()) { + Styler prevStyle = endRun > 0 ? fStyleRuns.getRun(endRun - 1).style + : null; + fStyleRuns + .add(endRun, new StyleRun(offset + length, prevStyle)); + } + } + + int startRun = findRun(offset); + if (startRun >= 0) { + // run with the same start index + StyleRun styleRun = fStyleRuns.getRun(startRun); + styleRun.style = styler; + } else { + startRun = -(startRun + 1); + + Styler prevStyle = startRun > 0 ? fStyleRuns.getRun(startRun - 1).style + : null; + if (isDifferentStyle(prevStyle, styler) + || (startRun is 0 && styler !is null)) { + fStyleRuns.add(startRun, new StyleRun(offset, styler)); + endRun++; // endrun is moved one back + } else { + startRun--; // we use the previous + } + } + if (startRun + 1 < endRun) { + fStyleRuns.removeRange(startRun + 1, endRun); + } + } + + /** + * Returns an array of {@link StyleRange} resulting from applying all + * associated stylers for this string builder. + * + * @return an array of all {@link StyleRange} resulting from applying the + * stored stylers to this string. + */ + public StyleRange[] getStyleRanges() { + if (hasRuns()) { + ArrayList res = new ArrayList(); + + List styleRuns = getStyleRuns(); + int offset = 0; + Styler style = null; + for (int i = 0; i < styleRuns.size(); i++) { + StyleRun curr = (StyleRun) styleRuns.get(i); + if (isDifferentStyle(curr.style, style)) { + if (curr.offset > offset && style !is null) { + res.add(createStyleRange(offset, curr.offset, style)); + } + offset = curr.offset; + style = curr.style; + } + } + if (fBuffer.length() > offset && style !is null) { + res.add(createStyleRange(offset, fBuffer.length(), style)); + } + return (StyleRange[]) res.toArray(new StyleRange[res.size()]); + } + return EMPTY; + } + + private int findRun(int offset) { + // method assumes that fStyleRuns is not null + int low = 0; + int high = fStyleRuns.size() - 1; + while (low <= high) { + int mid = (low + high) / 2; + StyleRun styleRun = fStyleRuns.getRun(mid); + if (styleRun.offset < offset) { + low = mid + 1; + } else if (styleRun.offset > offset) { + high = mid - 1; + } else { + return mid; // key found + } + } + return -(low + 1); // key not found. + } + + private StyleRange createStyleRange(int start, int end, Styler style) { + StyleRange styleRange = new StyleRange(); + styleRange.start = start; + styleRange.length = end - start; + style.applyStyles(styleRange); + return styleRange; + } + + private bool hasRuns() { + return fStyleRuns !is null && !fStyleRuns.isEmpty(); + } + + private void appendStyleRun(Styler style, int offset) { + StyleRun lastRun = getLastRun(); + if (lastRun !is null && lastRun.offset is offset) { + lastRun.style = style; + return; + } + + if (lastRun is null && style !is null || lastRun !is null + && isDifferentStyle(style, lastRun.style)) { + getStyleRuns().add(new StyleRun(offset, style)); + } + } + + private bool isDifferentStyle(Styler style1, Styler style2) { + if (style1 is null) { + return style2 !is null; + } + return !style1.equals(style2); + } + + private StyleRun getLastRun() { + if (fStyleRuns is null || fStyleRuns.isEmpty()) { + return null; + } + return fStyleRuns.getRun(fStyleRuns.size() - 1); + } + + private List getStyleRuns() { + if (fStyleRuns is null) + fStyleRuns = new StyleRunList(); + return fStyleRuns; + } + + private static class StyleRun { + public int offset; + public Styler style; + + public StyleRun(int offset, Styler style) { + this.offset = offset; + this.style = style; + } + + public String toString() { + return "Offset " + offset + ", style: " + style; //$NON-NLS-1$//$NON-NLS-2$ + } + } + + private static class StyleRunList extends ArrayList { + private static final long serialVersionUID = 123L; + + public StyleRunList() { + super(3); + } + + public StyleRun getRun(int index) { + return (StyleRun) get(index); + } + + public void removeRange(int fromIndex, int toIndex) { + super.removeRange(fromIndex, toIndex); + } + } + + private static class DefaultStyler extends Styler { + private final String fForegroundColorName; + private final String fBackgroundColorName; + + public DefaultStyler(String foregroundColorName, + String backgroundColorName) { + fForegroundColorName = foregroundColorName; + fBackgroundColorName = backgroundColorName; + } + + public void applyStyles(TextStyle textStyle) { + ColorRegistry colorRegistry = JFaceResources.getColorRegistry(); + if (fForegroundColorName !is null) { + textStyle.foreground = colorRegistry.get(fForegroundColorName); + } + if (fBackgroundColorName !is null) { + textStyle.background = colorRegistry.get(fBackgroundColorName); + } + } + } + +} diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/TableLayout.d --- a/dwtx/jface/viewers/TableLayout.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/TableLayout.d Thu May 22 01:36:46 2008 +0200 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Florian Priester - bug 106059 * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -48,12 +49,16 @@ * * @since 3.1 */ - private static int COLUMN_TRIM_ = -1; - private static int COLUMN_TRIM(){ - if( COLUMN_TRIM_ is -1 ){ - COLUMN_TRIM_ = "carbon".equals(DWT.getPlatform()) ? 24 : 3; //$NON-NLS-1$ + private static int COLUMN_TRIM; + + static { + if ("win32".equals(DWT.getPlatform())) { //$NON-NLS-1$ + COLUMN_TRIM = 4; + } else if ("carbon".equals(DWT.getPlatform())) { //$NON-NLS-1$ + COLUMN_TRIM = 24; + } else { + COLUMN_TRIM = 3; } - return COLUMN_TRIM_; } /** diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/TableViewer.d --- a/dwtx/jface/viewers/TableViewer.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/TableViewer.d Thu May 22 01:36:46 2008 +0200 @@ -23,7 +23,6 @@ import dwtx.jface.viewers.ViewerRow; import dwtx.jface.viewers.TableViewerEditor; import dwtx.jface.viewers.ColumnViewerEditorActivationStrategy; - import dwt.DWT; import dwt.graphics.Point; import dwt.widgets.Composite; @@ -47,16 +46,16 @@ *

    *

    * Label providers for table viewers must implement either the - * ITableLabelProvider or the ILabelProvider - * interface (see TableViewer.setLabelProvider for more details). + * ITableLabelProvider or the ILabelProvider interface + * (see TableViewer.setLabelProvider for more details). *

    *

    * As of 3.1 the TableViewer now supports the DWT.VIRTUAL flag. If the - * underlying table is DWT.VIRTUAL, the content provider may implement - * {@link ILazyContentProvider} instead of {@link IStructuredContentProvider}. - * Note that in this case, the viewer does not support sorting or filtering. - * Also note that in this case, the Widget based APIs may return null if the - * element is not specified or not created yet. + * underlying table is DWT.VIRTUAL, the content provider may implement {@link + * ILazyContentProvider} instead of {@link IStructuredContentProvider} . Note + * that in this case, the viewer does not support sorting or filtering. Also + * note that in this case, the Widget based APIs may return null if the element + * is not specified or not created yet. *

    *

    * Users of DWT.VIRTUAL should also avoid using getItems() from the Table within @@ -64,7 +63,11 @@ * TreeViewer to populate the items. It also has the side effect of creating all * of the items thereby eliminating the performance improvements of DWT.VIRTUAL. *

    - * + *

    + * Users setting up an editable table with more than 1 column have to pass the + * DWT.FULL_SELECTION style bit + *

    + * * @see DWT#VIRTUAL * @see #doFindItem(Object) * @see #internalRefresh(Object, bool) @@ -89,9 +92,9 @@ * MULTI, H_SCROLL, V_SCROLL, and BORDER. The * viewer has no input, no content provider, a default label provider, no * sorter, and no filters. The table has no columns. - * + * * @param parent - * the parent control + * the parent control */ public this(Composite parent) { this(parent, DWT.MULTI | DWT.H_SCROLL | DWT.V_SCROLL | DWT.BORDER); @@ -102,11 +105,11 @@ * parent. The table control is created using the given style bits. The * viewer has no input, no content provider, a default label provider, no * sorter, and no filters. The table has no columns. - * + * * @param parent - * the parent control + * the parent control * @param style - * DWT style bits + * DWT style bits */ public this(Composite parent, int style) { this(new Table(parent, style)); @@ -116,9 +119,9 @@ * Creates a table viewer on the given table control. The viewer has no * input, no content provider, a default label provider, no sorter, and no * filters. - * + * * @param table - * the table control + * the table control */ public this(Table table) { this.table = table; @@ -131,7 +134,7 @@ /** * Returns this table viewer's table control. - * + * * @return the table control */ public Table getTable() { @@ -139,7 +142,9 @@ } protected override ColumnViewerEditor createViewerEditor() { - return new TableViewerEditor(this,null,new ColumnViewerEditorActivationStrategy(this),ColumnViewerEditor.DEFAULT); + return new TableViewerEditor(this, null, + new ColumnViewerEditorActivationStrategy(this), + ColumnViewerEditor.DEFAULT); } /** @@ -153,12 +158,12 @@ * Use Table#setSelection(int[] indices) and Table#showSelection() if you * wish to set selection more efficiently when using a ILazyContentProvider. *

    - * + * * @param selection - * the new selection + * the new selection * @param reveal - * true if the selection is to be made visible, - * and false otherwise + * true if the selection is to be made visible, and + * false otherwise * @see Table#setSelection(int[]) * @see Table#showSelection() */ @@ -167,7 +172,7 @@ } protected override ViewerRow getViewerRowFromItem(Widget item) { - if( cachedRow is null ) { + if (cachedRow is null) { cachedRow = new TableViewerRow(cast(TableItem) item); } else { cachedRow.setItem(cast(TableItem) item); @@ -178,7 +183,7 @@ /** * Create a new row with style at index - * + * * @param style * @param rowIndex * @return ViewerRow @@ -199,11 +204,11 @@ protected override Item getItemAt(Point p) { TableItem[] selection = table.getSelection(); - if( selection.length is 1 ) { + if (selection.length is 1) { int columnCount = table.getColumnCount(); - for( int i = 0; i < columnCount; i++ ) { - if( selection[0].getBounds(i).contains(p) ) { + for (int i = 0; i < columnCount; i++) { + if (selection[0].getBounds(i).contains(p)) { return selection[0]; } } @@ -219,7 +224,7 @@ } protected override int doIndexOf(Item item) { - return table.indexOf(cast(TableItem)item); + return table.indexOf(cast(TableItem) item); } protected override void doSetItemCount(int count) { @@ -278,7 +283,7 @@ } protected override void doShowItem(Item item) { - table.showItem(cast(TableItem)item); + table.showItem(cast(TableItem) item); } protected override void doDeselectAll() { @@ -312,38 +317,37 @@ /** * Refreshes this viewer starting with the given element. Labels are updated - * as described in refresh(bool updateLabels). The - * methods attempts to preserve the selection. + * as described in refresh(bool updateLabels). The methods + * attempts to preserve the selection. *

    * Unlike the update methods, this handles structural changes * to the given element (e.g. addition or removal of children). If only the * given element needs updating, it is more efficient to use the * update methods. *

    - * + * *

    * Subclasses who can provide this feature can open this method for the * public *

    - * + * * @param element - * the element + * the element * @param updateLabels - * true to update labels for existing elements, - * false to only update labels as needed, assuming - * that labels for existing elements are unchanged. + * true to update labels for existing elements, + * false to only update labels as needed, assuming that labels + * for existing elements are unchanged. * @param reveal - * true to make the preserved selection visible - * afterwards - * + * true to make the preserved selection visible afterwards + * * @since 3.3 */ public void refresh(Object element, bool updateLabels, bool reveal) { - if (isBusy()) + if (checkBusy()) return; - if( isCellEditorActive() ) { + if (isCellEditorActive()) { cancelEditing(); } @@ -362,26 +366,25 @@ /** * Refreshes this viewer with information freshly obtained from this - * viewer's model. If updateLabels is true - * then labels for otherwise unaffected elements are updated as well. - * Otherwise, it assumes labels for existing elements are unchanged, and - * labels are only obtained as needed (for example, for new elements). + * viewer's model. If updateLabels is true then + * labels for otherwise unaffected elements are updated as well. Otherwise, + * it assumes labels for existing elements are unchanged, and labels are + * only obtained as needed (for example, for new elements). *

    * Calling refresh(true) has the same effect as * refresh(). *

    * Note that the implementation may still obtain labels for existing - * elements even if updateLabels is false. The intent is - * simply to allow optimization where possible. - * + * elements even if updateLabels is false. The intent is simply + * to allow optimization where possible. + * * @param updateLabels - * true to update labels for existing elements, - * false to only update labels as needed, assuming - * that labels for existing elements are unchanged. + * true to update labels for existing elements, + * false to only update labels as needed, assuming that labels + * for existing elements are unchanged. * @param reveal - * true to make the preserved selection visible - * afterwards - * + * true to make the preserved selection visible afterwards + * * @since 3.3 */ public void refresh(bool updateLabels, bool reveal) { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/TableViewerEditor.d --- a/dwtx/jface/viewers/TableViewerEditor.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/TableViewerEditor.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 IBM Corporation and others. + * 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 @@ -8,10 +8,10 @@ * Contributors: * IBM Corporation - initial API and implementation * Tom Schindl - initial API and implementation - * fixes in bug 198665 + * fixes in bug 198665, 200731 * Port to the D programming language: * Frank Benoit - ******************************************************************************/ + *******************************************************************************/ module dwtx.jface.viewers.TableViewerEditor; @@ -26,6 +26,7 @@ // import tango.util.collection.model.Seq; +import dwt.DWT; import dwt.custom.TableEditor; import dwt.widgets.Control; import dwt.widgets.Item; @@ -129,6 +130,11 @@ tableEditor.grabHorizontal = layoutData.grabHorizontal; tableEditor.horizontalAlignment = layoutData.horizontalAlignment; tableEditor.minimumWidth = layoutData.minimumWidth; + tableEditor.verticalAlignment = layoutData.verticalAlignment; + + if( layoutData.minimumHeight !is DWT.DEFAULT ) { + tableEditor.minimumHeight = layoutData.minimumHeight; + } } public override ViewerCell getFocusCell() { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/TableViewerFocusCellManager.d --- a/dwtx/jface/viewers/TableViewerFocusCellManager.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/TableViewerFocusCellManager.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 IBM Corporation and others. + * 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 @@ -7,9 +7,11 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Tom Schindl - initial API and implementation + * fix in bug: 210752 * Port to the D programming language: * Frank Benoit - ******************************************************************************/ + *******************************************************************************/ module dwtx.jface.viewers.TableViewerFocusCellManager; @@ -34,8 +36,27 @@ public class TableViewerFocusCellManager : SWTFocusCellManager { private static const CellNavigationStrategy TABLE_NAVIGATE; static this(){ - TABLE_NAVIGATE = new CellNavigationStrategy(); + /** + * Create a new manager with a default navigation strategy: + *

      + *
    • DWT.ARROW_UP: navigate to cell above
    • + *
    • DWT.ARROW_DOWN: navigate to cell below
    • + *
    • DWT.ARROW_RIGHT: navigate to next visible cell on + * the right
    • + *
    • DWT.ARROW_LEFT: navigate to next visible cell on the + * left
    • + *
    + * + * @param viewer + * the viewer the manager is bound to + * @param focusDrawingDelegate + * the delegate responsible to highlight selected cell + */ + public TableViewerFocusCellManager(TableViewer viewer, + FocusCellHighlighter focusDrawingDelegate) { + this(viewer, focusDrawingDelegate, TABLE_NAVIGATE); } + /** * Create a new manager * @@ -43,10 +64,13 @@ * the viewer the manager is bound to * @param focusDrawingDelegate * the delegate responsible to highlight selected cell + * @param navigationStrategy + * the strategy used to navigate the cells */ - public this(TableViewer viewer, - FocusCellHighlighter focusDrawingDelegate) { - super(viewer, focusDrawingDelegate, TABLE_NAVIGATE); + public TableViewerFocusCellManager(TableViewer viewer, + FocusCellHighlighter focusDrawingDelegate, + CellNavigationStrategy navigationStrategy) { + super(viewer, focusDrawingDelegate, navigationStrategy); } override ViewerCell getInitialFocusCell() { @@ -60,4 +84,20 @@ return null; } + public ViewerCell getFocusCell() { + ViewerCell cell = super.getFocusCell(); + Table t = (Table) getViewer().getControl(); + + // It is possible that the selection has changed under the hood + if (cell !is null) { + if (t.getSelection().length is 1 + && t.getSelection()[0] !is cell.getItem()) { + setFocusCell(getViewer().getViewerRowFromItem( + t.getSelection()[0]).getCell(cell.getColumnIndex())); + } + } + + return super.getFocusCell(); + } + } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/TableViewerRow.d --- a/dwtx/jface/viewers/TableViewerRow.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/TableViewerRow.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 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 @@ -7,8 +7,8 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Tom Shindl - initial API and implementation - * - Fix for bug 174355 + * Tom Schindl - initial API and implementation + * - fix in bug: 174355,195908,198035,215069 * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -202,4 +202,45 @@ public override Object getElement() { return item.getData(); } + + public int getVisualIndex(int creationIndex) { + int[] order = item.getParent().getColumnOrder(); + + for (int i = 0; i < order.length; i++) { + if (order[i] is creationIndex) { + return i; + } + } + + return super.getVisualIndex(creationIndex); + } + + public int getCreationIndex(int visualIndex) { + if( item !is null && ! item.isDisposed() && hasColumns() && isValidOrderIndex(visualIndex) ) { + return item.getParent().getColumnOrder()[visualIndex]; + } + return super.getCreationIndex(visualIndex); + } + + /* (non-Javadoc) + * @see dwtx.jface.viewers.ViewerRow#getTextBounds(int) + */ + public Rectangle getTextBounds(int index) { + return item.getTextBounds(index); + } + + /* (non-Javadoc) + * @see dwtx.jface.viewers.ViewerRow#getImageBounds(int) + */ + public Rectangle getImageBounds(int index) { + return item.getImageBounds(index); + } + + private bool hasColumns() { + return this.item.getParent().getColumnCount() !is 0; + } + + private bool isValidOrderIndex(int currentIndex) { + return currentIndex < this.item.getParent().getColumnOrder().length; + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/TextCellEditor.d --- a/dwtx/jface/viewers/TextCellEditor.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/TextCellEditor.d Thu May 22 01:36:46 2008 +0200 @@ -479,7 +479,16 @@ checkDeleteable(); } - override bool dependsOnExternalFocusListener() { + /** + * This implementation of + * {@link CellEditor#dependsOnExternalFocusListener()} returns false if the + * current instance's class is TextCellEditor, and true otherwise. + * Subclasses that hook their own focus listener should override this method + * and return false. See also bug 58777. + * + * @since 3.4 + */ + protected override bool dependsOnExternalFocusListener() { return this.classinfo !is TextCellEditor.classinfo; } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/TreeNode.d --- a/dwtx/jface/viewers/TreeNode.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/TreeNode.d Thu May 22 01:36:46 2008 +0200 @@ -1,139 +1,140 @@ -/******************************************************************************* - * Copyright (c) 2005 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 - * Port to the D programming language: - * Frank Benoit - ******************************************************************************/ - -module dwtx.jface.viewers.TreeNode; - -import dwtx.jface.util.Util; - -import dwt.dwthelper.utils; - -/** - * A simple data structure that is useful for implemented tree models. This can - * be returned by - * {@link dwtx.jface.viewers.IStructuredContentProvider#getElements(Object)}. - * It allows simple delegation of methods from - * {@link dwtx.jface.viewers.ITreeContentProvider} such as - * {@link dwtx.jface.viewers.ITreeContentProvider#getChildren(Object)}, - * {@link dwtx.jface.viewers.ITreeContentProvider#getParent(Object)} and - * {@link dwtx.jface.viewers.ITreeContentProvider#hasChildren(Object)} - * - * @since 3.2 - */ -public class TreeNode { - - /** - * The array of child tree nodes for this tree node. If there are no - * children, then this value may either by an empty array or - * null. There should be no null children in - * the array. - */ - private TreeNode[] children; - - /** - * The parent tree node for this tree node. This value may be - * null if there is no parent. - */ - private TreeNode parent; - - /** - * The value contained in this node. This value may be anything. - */ - protected Object value; - - /** - * Constructs a new instance of TreeNode. - * - * @param value - * The value held by this node; may be anything. - */ - public this(Object value) { - this.value = value; - } - - public override int opEquals(Object object) { - if ( auto tn = cast(TreeNode)object ) { - return Util.opEquals(this.value, tn.value); - } - - return false; - } - - /** - * Returns the child nodes. Empty arrays are converted to null - * before being returned. - * - * @return The child nodes; may be null, but never empty. - * There should be no null children in the array. - */ - public TreeNode[] getChildren() { - if (children !is null && children.length is 0) { - return null; - } - return children; - } - - /** - * Returns the parent node. - * - * @return The parent node; may be null if there are no - * parent nodes. - */ - public TreeNode getParent() { - return parent; - } - - /** - * Returns the value held by this node. - * - * @return The value; may be anything. - */ - public Object getValue() { - return value; - } - - /** - * Returns whether the tree has any children. - * - * @return true if its array of children is not - * null and is non-empty; false - * otherwise. - */ - public bool hasChildren() { - return children !is null && children.length > 0; - } - - public override hash_t toHash() { - return Util.toHash(value); - } - - /** - * Sets the children for this node. - * - * @param children - * The child nodes; may be null or empty. There - * should be no null children in the array. - */ - public void setChildren(TreeNode[] children) { - this.children = children; - } - - /** - * Sets the parent for this node. - * - * @param parent - * The parent node; may be null. - */ - public void setParent(TreeNode parent) { - this.parent = parent; - } -} +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Port to the D programming language: + * Frank Benoit + *******************************************************************************/ + +module dwtx.jface.viewers.TreeNode; + +import dwtx.jface.util.Util; + +import dwt.dwthelper.utils; + +/** + * A simple data structure that is useful for implemented tree models. This can + * be returned by + * {@link dwtx.jface.viewers.IStructuredContentProvider#getElements(Object)}. + * It allows simple delegation of methods from + * {@link dwtx.jface.viewers.ITreeContentProvider} such as + * {@link dwtx.jface.viewers.ITreeContentProvider#getChildren(Object)}, + * {@link dwtx.jface.viewers.ITreeContentProvider#getParent(Object)} and + * {@link dwtx.jface.viewers.ITreeContentProvider#hasChildren(Object)} + * + * @since 3.2 + */ +public class TreeNode { + + /** + * The array of child tree nodes for this tree node. If there are no + * children, then this value may either by an empty array or + * null. There should be no null children in + * the array. + */ + private TreeNode[] children; + + /** + * The parent tree node for this tree node. This value may be + * null if there is no parent. + */ + private TreeNode parent; + + /** + * The value contained in this node. This value may be anything. + */ + protected Object value; + + /** + * Constructs a new instance of TreeNode. + * + * @param value + * The value held by this node; may be anything. + */ + public this(Object value) { + this.value = value; + } + + public override int opEquals(Object object) { + if ( auto tn = cast(TreeNode)object ) { + return Util.opEquals(this.value, tn.value); + } + + return false; + } + + /** + * Returns the child nodes. Empty arrays are converted to null + * before being returned. + * + * @return The child nodes; may be null, but never empty. + * There should be no null children in the array. + */ + public TreeNode[] getChildren() { + if (children !is null && children.length is 0) { + return null; + } + return children; + } + + /** + * Returns the parent node. + * + * @return The parent node; may be null if there are no + * parent nodes. + */ + public TreeNode getParent() { + return parent; + } + + /** + * Returns the value held by this node. + * + * @return The value; may be anything. + */ + public Object getValue() { + return value; + } + + /** + * Returns whether the tree has any children. + * + * @return true if its array of children is not + * null and is non-empty; false + * otherwise. + */ + public bool hasChildren() { + return children !is null && children.length > 0; + } + + public override hash_t toHash() { + return Util.toHash(value); + } + + /** + * Sets the children for this node. + * + * @param children + * The child nodes; may be null or empty. There + * should be no null children in the array. + */ + public void setChildren(TreeNode[] children) { + this.children = children; + } + + /** + * Sets the parent for this node. + * + * @param parent + * The parent node; may be null. + */ + public void setParent(TreeNode parent) { + this.parent = parent; + } +} + diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/TreeNodeContentProvider.d --- a/dwtx/jface/viewers/TreeNodeContentProvider.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/TreeNodeContentProvider.d Thu May 22 01:36:46 2008 +0200 @@ -1,98 +1,99 @@ -/******************************************************************************* - * Copyright (c) 2005 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 - * Port to the D programming language: - * Frank Benoit - ******************************************************************************/ - -module dwtx.jface.viewers.TreeNodeContentProvider; - -import dwtx.jface.viewers.ITreeContentProvider; -import dwtx.jface.viewers.Viewer; -import dwtx.jface.viewers.TreeNode; - -import dwt.dwthelper.utils; - -/** - *

    - * A content provider that expects every element to be a TreeNode. - * Most methods delegate to TreeNode. dispose() - * and inputChanged(Viewer, Object, Object) do nothing by - * default. - *

    - *

    - * This class and all of its methods may be overridden or extended. - *

    - * - * @since 3.2 - * @see dwtx.jface.viewers.TreeNode - */ -public class TreeNodeContentProvider : ITreeContentProvider { - /* - * (non-Javadoc) - * - * @see dwtx.jface.viewers.IContentProvider#dispose() - */ - public void dispose() { - // Do nothing - } - - /* - * (non-Javadoc) - * - * @see dwtx.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object) - */ - public Object[] getChildren(Object parentElement) { - TreeNode node = cast(TreeNode) parentElement; - return node.getChildren(); - } - - /* - * (non-Javadoc) - * - * @see dwtx.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object) - */ - public Object[] getElements(Object inputElement) { - if ( auto tn = cast(ArrayWrapperT!(TreeNode)) inputElement ) { - return tn.array; - } - return null; - } - - /* - * (non-Javadoc) - * - * @see dwtx.jface.viewers.ITreeContentProvider#getParent(java.lang.Object) - */ - public Object getParent(Object element) { - TreeNode node = cast(TreeNode) element; - return node.getParent(); - } - - /* - * (non-Javadoc) - * - * @see dwtx.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object) - */ - public bool hasChildren(Object element) { - TreeNode node = cast(TreeNode) element; - return node.hasChildren(); - } - - /* - * (non-Javadoc) - * - * @see dwtx.jface.viewers.IContentProvider#inputChanged(dwtx.jface.viewers.Viewer, - * java.lang.Object, java.lang.Object) - */ - public void inputChanged(Viewer viewer, Object oldInput, - Object newInput) { - // Do nothing - } -} +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Port to the D programming language: + * Frank Benoit + *******************************************************************************/ + +module dwtx.jface.viewers.TreeNodeContentProvider; + +import dwtx.jface.viewers.ITreeContentProvider; +import dwtx.jface.viewers.Viewer; +import dwtx.jface.viewers.TreeNode; + +import dwt.dwthelper.utils; + +/** + *

    + * A content provider that expects every element to be a TreeNode. + * Most methods delegate to TreeNode. dispose() + * and inputChanged(Viewer, Object, Object) do nothing by + * default. + *

    + *

    + * This class and all of its methods may be overridden or extended. + *

    + * + * @since 3.2 + * @see dwtx.jface.viewers.TreeNode + */ +public class TreeNodeContentProvider : ITreeContentProvider { + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.IContentProvider#dispose() + */ + public void dispose() { + // Do nothing + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object) + */ + public Object[] getChildren(Object parentElement) { + TreeNode node = cast(TreeNode) parentElement; + return node.getChildren(); + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object) + */ + public Object[] getElements(Object inputElement) { + if ( auto tn = cast(ArrayWrapperT!(TreeNode)) inputElement ) { + return tn.array; + } + return null; + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.ITreeContentProvider#getParent(java.lang.Object) + */ + public Object getParent(Object element) { + TreeNode node = cast(TreeNode) element; + return node.getParent(); + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object) + */ + public bool hasChildren(Object element) { + TreeNode node = cast(TreeNode) element; + return node.hasChildren(); + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.IContentProvider#inputChanged(dwtx.jface.viewers.Viewer, + * java.lang.Object, java.lang.Object) + */ + public void inputChanged(Viewer viewer, Object oldInput, + Object newInput) { + // Do nothing + } +} + diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/TreeViewer.d --- a/dwtx/jface/viewers/TreeViewer.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/TreeViewer.d Thu May 22 01:36:46 2008 +0200 @@ -8,7 +8,8 @@ * Contributors: * IBM Corporation - initial API and implementation * Tom Schindl - concept of ViewerRow, - * refactoring (bug 153993), bug 167323, 191468 + * refactoring (bug 153993), bug 167323, 191468, 205419 + * Matthew Hall - bug 221988 * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -70,8 +71,13 @@ * {@link ILazyTreePathContentProvider}. If the content provider is an * ILazyTreeContentProvider or an * ILazyTreePathContentProvider, the underlying Tree must be - * created using the {@link DWT#VIRTUAL} style bit, and the tree viewer will not - * support sorting or filtering. + * created using the {@link DWT#VIRTUAL} style bit, the tree viewer will not + * support sorting or filtering, and hash lookup must be enabled by calling + * {@link #setUseHashlookup(bool)}. + *

    + *

    + * Users setting up an editable tree with more than 1 column have to pass the + * DWT.FULL_SELECTION style bit *

    */ public class TreeViewer : AbstractTreeViewer { @@ -431,7 +437,7 @@ * @since 3.2 */ public void setChildCount(Object elementOrTreePath, int count) { - if (isBusy()) + if (checkBusy()) return; preservingSelection(new class(elementOrTreePath,count) Runnable { Object elementOrTreePath_; @@ -480,7 +486,7 @@ */ public void replace(Object parentElementOrTreePath, int index, Object element) { - if (isBusy()) + if (checkBusy()) return; Item[] selectedItems = getSelection(getControl()); TreeSelection selection = cast(TreeSelection) getSelection(); @@ -605,8 +611,8 @@ } protected override Object getParentElement(Object element) { - bool oldBusy = busy; - busy = true; + bool oldBusy = isBusy(); + setBusy(true); try { if (contentProviderIsLazy && !contentProviderIsTreeBased && !(cast(TreePath)element )) { ILazyTreeContentProvider lazyTreeContentProvider = cast(ILazyTreeContentProvider) getContentProvider(); @@ -622,7 +628,7 @@ } return super.getParentElement(element); } finally { - busy = oldBusy; + setBusy(oldBusy); } } @@ -773,7 +779,7 @@ // only add a dispose listener if item hasn't already on assigned // because it is reused if (item.getData(VIRTUAL_DISPOSE_KEY) is null) { - item.setData(VIRTUAL_DISPOSE_KEY, new ValueWrapperBool(true)); + item.setData(VIRTUAL_DISPOSE_KEY, Boolean.TRUE); item.addDisposeListener(new class(item) DisposeListener { Widget item_; this(Widget a){ @@ -875,7 +881,7 @@ * @since 3.3 */ public void remove(Object parentOrTreePath_, int index_) { - if (isBusy()) + if (checkBusy()) return; preservingSelection(new class((cast(TreeSelection) getSelection()).getPaths(),parentOrTreePath_,index_) Runnable { Seq!(TreePath) oldSelection; @@ -905,6 +911,8 @@ Widget[] parentItems = internalFindItems(parentOrTreePath); for (int i = 0; i < parentItems.length; i++) { TreeItem parentItem = cast(TreeItem) parentItems[i]; + if (parentItem.isDisposed()) + continue; if (index < parentItem.getItemCount()) { TreeItem item = parentItem.getItem(index); if (item.getData() !is null) { @@ -978,7 +986,7 @@ * @since 3.3 */ public void setHasChildren(Object elementOrTreePath_, bool hasChildren_) { - if (isBusy()) + if (checkBusy()) return; preservingSelection(new class(elementOrTreePath_,hasChildren_) Runnable { Object elementOrTreePath; @@ -1025,8 +1033,8 @@ * @param index */ private void virtualLazyUpdateWidget(Widget widget, int index) { - bool oldBusy = busy; - busy = false; + bool oldBusy = isBusy(); + setBusy(false); try { if (contentProviderIsTreeBased) { TreePath treePath; @@ -1051,7 +1059,7 @@ widget.getData(), index); } } finally { - busy = oldBusy; + setBusy(oldBusy); } } @@ -1061,8 +1069,8 @@ * @param currentChildCount */ private void virtualLazyUpdateChildCount(Widget widget, int currentChildCount) { - bool oldBusy = busy; - busy = false; + bool oldBusy = isBusy(); + setBusy(false); try { if (contentProviderIsTreeBased) { TreePath treePath; @@ -1077,7 +1085,7 @@ (cast(ILazyTreeContentProvider) getContentProvider()).updateChildCount(widget.getData(), currentChildCount); } } finally { - busy = oldBusy; + setBusy(oldBusy); } } @@ -1087,8 +1095,8 @@ * @param currentChildCount */ private void virtualLazyUpdateHasChildren(Item item, int currentChildCount) { - bool oldBusy = busy; - busy = false; + bool oldBusy = isBusy(); + setBusy(false); try { if (contentProviderIsTreeBased) { TreePath treePath; @@ -1105,7 +1113,7 @@ (cast(ILazyTreeContentProvider) getContentProvider()).updateChildCount(item.getData(), currentChildCount); } } finally { - busy = oldBusy; + setBusy(oldBusy); } } @@ -1141,26 +1149,27 @@ public override void editElement(Object element, int column) { if( cast(TreePath)element ) { - setSelection(new TreeSelection(cast(TreePath) element)); - TreeItem[] items = tree.getSelection(); - - if( items.length is 1 ) { - ViewerRow row = getViewerRowFromItem(items[0]); + try { + getControl().setRedraw(false); + setSelection(new TreeSelection(cast(TreePath) element)); + TreeItem[] items = tree.getSelection(); - if (row !is null) { - ViewerCell cell = row.getCell(column); - if (cell !is null) { - getControl().setRedraw(false); - try { + if( items.length is 1 ) { + ViewerRow row = getViewerRowFromItem(items[0]); + + if (row !is null) { + ViewerCell cell = row.getCell(column); + if (cell !is null) { triggerEditorActivationEvent(new ColumnViewerEditorActivationEvent(cell)); - } finally { - getControl().setRedraw(true); } } } + } finally { + getControl().setRedraw(true); } } else { super.editElement(element, column); } } + } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/TreeViewerEditor.d --- a/dwtx/jface/viewers/TreeViewerEditor.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/TreeViewerEditor.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 IBM Corporation and others. + * 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 @@ -8,10 +8,10 @@ * Contributors: * IBM Corporation - initial API and implementation * Tom Schindl - initial API and implementation - * fixes in bug 198665 + * fixes in bug 198665, 200731, 187963 * Port to the D programming language: * Frank Benoit - ******************************************************************************/ + *******************************************************************************/ module dwtx.jface.viewers.TreeViewerEditor; @@ -26,6 +26,7 @@ import tango.util.collection.model.Seq; +import dwt.DWT; import dwt.custom.TreeEditor; import dwt.widgets.Control; import dwt.widgets.Item; @@ -126,6 +127,10 @@ treeEditor.grabHorizontal = layoutData.grabHorizontal; treeEditor.horizontalAlignment = layoutData.horizontalAlignment; treeEditor.minimumWidth = layoutData.minimumWidth; + treeEditor.verticalAlignment = layoutData.verticalAlignment; + if( layoutData.minimumHeight !is DWT.DEFAULT ) { + treeEditor.minimumHeight = layoutData.minimumHeight; + } } public override ViewerCell getFocusCell() { diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/TreeViewerFocusCellManager.d --- a/dwtx/jface/viewers/TreeViewerFocusCellManager.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/TreeViewerFocusCellManager.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 IBM Corporation and others. + * 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 @@ -7,9 +7,11 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Tom Schindl - initial API and implementation + * - fix in bug: 195908, 210752 * Port to the D programming language: * Frank Benoit - ******************************************************************************/ + *******************************************************************************/ module dwtx.jface.viewers.TreeViewerFocusCellManager; @@ -51,31 +53,53 @@ Event event) { if (cellToExpand !is null) { TreeViewer v = cast(TreeViewer) viewer; - v.setExpandedState(v - .getTreePathFromItem_package(cast(Item)cellToExpand.getItem()), true); + v.setExpandedState(v.getTreePathFromItem_package(cast(Item)cellToExpand + .getItem()), true); } } public bool isCollapseEvent(ColumnViewer viewer, ViewerCell cellToCollapse, Event event) { + + if (cellToCollapse is null) { + return false; + } + return cellToCollapse !is null && (cast(TreeItem) cellToCollapse.getItem()).getExpanded() - && cellToCollapse.getColumnIndex() is 0 - && event.keyCode is DWT.ARROW_LEFT; + && event.keyCode is DWT.ARROW_LEFT + && isFirstColumnCell(cellToCollapse); } public bool isExpandEvent(ColumnViewer viewer, ViewerCell cellToExpand, Event event) { + + if (cellToExpand is null) { + return false; + } + return cellToExpand !is null && (cast(TreeItem) cellToExpand.getItem()).getItemCount() > 0 && !(cast(TreeItem) cellToExpand.getItem()).getExpanded() - && cellToExpand.getColumnIndex() is 0 - && event.keyCode is DWT.ARROW_RIGHT; + && event.keyCode is DWT.ARROW_RIGHT + && isFirstColumnCell(cellToExpand); + } + + private bool isFirstColumnCell(ViewerCell cell) { + return cell.getViewerRow().getVisualIndex(cell.getColumnIndex()) is 0; } }; - } + /** - * Create a new manager + * Create a new manager using a default navigation strategy: + *
      + *
    • DWT.ARROW_UP: navigate to cell above
    • + *
    • DWT.ARROW_DOWN: navigate to cell below
    • + *
    • DWT.ARROW_RIGHT: on first column (collapses if item + * is expanded) else navigate to next visible cell on the right
    • + *
    • DWT.ARROW_LEFT: on first column (expands if item is + * collapsed) else navigate to next visible cell on the left
    • + *
    * * @param viewer * the viewer the manager is bound to @@ -84,16 +108,48 @@ */ public this(TreeViewer viewer, FocusCellHighlighter focusDrawingDelegate) { - super(viewer, focusDrawingDelegate,TREE_NAVIGATE); + this(viewer, focusDrawingDelegate, TREE_NAVIGATE); + } + + /** + * Create a new manager with a custom navigation strategy + * + * @param viewer + * the viewer the manager is bound to + * @param focusDrawingDelegate + * the delegate responsible to highlight selected cell + * @param navigationStrategy + * the strategy used to navigate the cells + */ + public this(TreeViewer viewer, + FocusCellHighlighter focusDrawingDelegate, + CellNavigationStrategy navigationStrategy) { + super(viewer, focusDrawingDelegate, navigationStrategy); } override ViewerCell getInitialFocusCell() { Tree tree = cast(Tree) getViewer().getControl(); - if( tree.getItemCount() > 0 ) { + if (tree.getItemCount() > 0) { return getViewer().getViewerRowFromItem_package(tree.getItem(0)).getCell(0); } return null; } + + public ViewerCell getFocusCell() { + ViewerCell cell = super.getFocusCell(); + Tree t = (Tree) getViewer().getControl(); + + // It is possible that the selection has changed under the hood + if (cell !is null) { + if (t.getSelection().length is 1 + && t.getSelection()[0] !is cell.getItem()) { + setFocusCell(getViewer().getViewerRowFromItem( + t.getSelection()[0]).getCell(cell.getColumnIndex())); + } + } + + return super.getFocusCell(); + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/TreeViewerRow.d --- a/dwtx/jface/viewers/TreeViewerRow.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/TreeViewerRow.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 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 @@ -8,7 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation * Tom Schindl - initial API and implementation - * - Fix for bug 174355, 171126 + * - fix in bug: 174355,171126,,195908,198035,215069 * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -34,6 +34,7 @@ /** * TreeViewerRow is the Tree implementation of ViewerRow. + * * @since 3.3 * */ @@ -42,98 +43,129 @@ /** * Create a new instance of the receiver. + * * @param item */ this(TreeItem item) { this.item = item; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see dwtx.jface.viewers.ViewerRow#getBounds(int) */ public override Rectangle getBounds(int columnIndex) { return item.getBounds(columnIndex); } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see dwtx.jface.viewers.ViewerRow#getBounds() */ public override Rectangle getBounds() { return item.getBounds(); } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see dwtx.jface.viewers.ViewerRow#getColumnCount() */ public override int getColumnCount() { return item.getParent().getColumnCount(); } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see dwtx.jface.viewers.ViewerRow#getItem() */ public override Widget getItem() { return item; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see dwtx.jface.viewers.ViewerRow#getBackground(int) */ public override Color getBackground(int columnIndex) { return item.getBackground(columnIndex); } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see dwtx.jface.viewers.ViewerRow#getFont(int) */ public override Font getFont(int columnIndex) { return item.getFont(columnIndex); } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see dwtx.jface.viewers.ViewerRow#getForeground(int) */ public override Color getForeground(int columnIndex) { return item.getForeground(columnIndex); } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see dwtx.jface.viewers.ViewerRow#getImage(int) */ public override Image getImage(int columnIndex) { return item.getImage(columnIndex); } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see dwtx.jface.viewers.ViewerRow#getText(int) */ public override String getText(int columnIndex) { return item.getText(columnIndex); } - /* (non-Javadoc) - * @see dwtx.jface.viewers.ViewerRow#setBackground(int, dwt.graphics.Color) + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.ViewerRow#setBackground(int, + * dwt.graphics.Color) */ public override void setBackground(int columnIndex, Color color) { item.setBackground(columnIndex, color); } - /* (non-Javadoc) - * @see dwtx.jface.viewers.ViewerRow#setFont(int, dwt.graphics.Font) + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.ViewerRow#setFont(int, + * dwt.graphics.Font) */ public override void setFont(int columnIndex, Font font) { item.setFont(columnIndex, font); } - /* (non-Javadoc) - * @see dwtx.jface.viewers.ViewerRow#setForeground(int, dwt.graphics.Color) + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.ViewerRow#setForeground(int, + * dwt.graphics.Color) */ public override void setForeground(int columnIndex, Color color) { item.setForeground(columnIndex, color); } - /* (non-Javadoc) - * @see dwtx.jface.viewers.ViewerRow#setImage(int, dwt.graphics.Image) + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.ViewerRow#setImage(int, + * dwt.graphics.Image) */ public override void setImage(int columnIndex, Image image) { Image oldImage = item.getImage(columnIndex); @@ -142,14 +174,18 @@ } } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see dwtx.jface.viewers.ViewerRow#setText(int, java.lang.String) */ public override void setText(int columnIndex, String text) { item.setText(columnIndex, text is null ? "" : text); //$NON-NLS-1$ } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see dwtx.jface.viewers.ViewerRow#getControl() */ public override Control getControl() { @@ -158,12 +194,13 @@ public override ViewerRow getNeighbor(int direction, bool sameLevel) { - if( direction is ViewerRow.ABOVE ) { + if (direction is ViewerRow.ABOVE) { return getRowAbove(sameLevel); - } else if( direction is ViewerRow.BELOW ) { + } else if (direction is ViewerRow.BELOW) { return getRowBelow(sameLevel); } else { - throw new IllegalArgumentException("Illegal value of direction argument."); //$NON-NLS-1$ + throw new IllegalArgumentException( + "Illegal value of direction argument."); //$NON-NLS-1$ } } @@ -171,18 +208,18 @@ Tree tree = item.getParent(); // This means we have top-level item - if( item.getParentItem() is null ) { - if( sameLevel || ! item.getExpanded() ) { + if (item.getParentItem() is null) { + if (sameLevel || !item.getExpanded()) { int index = tree.indexOf(item) + 1; - if( index < tree.getItemCount() ) { + if (index < tree.getItemCount()) { return new TreeViewerRow(tree.getItem(index)); } - } else if( item.getExpanded() && item.getItemCount() > 0 ) { + } else if (item.getExpanded() && item.getItemCount() > 0) { return new TreeViewerRow(item.getItem(0)); } } else { - if( sameLevel || ! item.getExpanded() ) { + if (sameLevel || !item.getExpanded()) { TreeItem parentItem = item.getParentItem(); int nextIndex = parentItem.indexOf(item) + 1; @@ -191,17 +228,17 @@ TreeItem itemAfter; // This would mean that it was the last item - if( nextIndex is totalIndex ) { - itemAfter = findNextItem( parentItem ); + if (nextIndex is totalIndex) { + itemAfter = findNextItem(parentItem); } else { itemAfter = parentItem.getItem(nextIndex); } - if( itemAfter !is null ) { + if (itemAfter !is null) { return new TreeViewerRow(itemAfter); } - } else if( item.getExpanded() && item.getItemCount() > 0 ) { + } else if (item.getExpanded() && item.getItemCount() > 0) { return new TreeViewerRow(item.getItem(0)); } } @@ -213,16 +250,16 @@ Tree tree = item.getParent(); // This means we have top-level item - if( item.getParentItem() is null ) { + if (item.getParentItem() is null) { int index = tree.indexOf(item) - 1; TreeItem nextTopItem = null; - if( index >= 0 ) { + if (index >= 0) { nextTopItem = tree.getItem(index); } - if( nextTopItem !is null ) { - if( sameLevel ) { + if (nextTopItem !is null) { + if (sameLevel) { return new TreeViewerRow(nextTopItem); } @@ -233,17 +270,18 @@ int previousIndex = parentItem.indexOf(item) - 1; TreeItem itemBefore; - if( previousIndex >= 0 ) { - if( sameLevel ) { + if (previousIndex >= 0) { + if (sameLevel) { itemBefore = parentItem.getItem(previousIndex); } else { - itemBefore = findLastVisibleItem(parentItem.getItem(previousIndex)); + itemBefore = findLastVisibleItem(parentItem + .getItem(previousIndex)); } } else { itemBefore = parentItem; } - if( itemBefore !is null ) { + if (itemBefore !is null) { return new TreeViewerRow(itemBefore); } } @@ -254,8 +292,8 @@ private TreeItem findLastVisibleItem(TreeItem parentItem) { TreeItem rv = parentItem; - while( rv.getExpanded() && rv.getItemCount() > 0 ) { - rv = rv.getItem(rv.getItemCount()-1); + while (rv.getExpanded() && rv.getItemCount() > 0) { + rv = rv.getItem(rv.getItemCount() - 1); } return rv; @@ -269,7 +307,7 @@ int nextIndex; int totalItems; - if( parentItem is null ) { + if (parentItem is null) { nextIndex = tree.indexOf(item) + 1; totalItems = tree.getItemCount(); } else { @@ -279,12 +317,12 @@ // This is once more the last item in the tree // Search on - if( nextIndex is totalItems ) { - if( item.getParentItem() !is null ) { + if (nextIndex is totalItems) { + if (item.getParentItem() !is null) { rv = findNextItem(item.getParentItem()); } } else { - if( parentItem is null ) { + if (parentItem is null) { rv = tree.getItem(nextIndex); } else { rv = parentItem.getItem(nextIndex); @@ -318,4 +356,45 @@ public override Object getElement() { return item.getData(); } + + public int getVisualIndex(int creationIndex) { + int[] order = item.getParent().getColumnOrder(); + + for (int i = 0; i < order.length; i++) { + if (order[i] is creationIndex) { + return i; + } + } + + return super.getVisualIndex(creationIndex); + } + + public int getCreationIndex(int visualIndex) { + if( item !is null && ! item.isDisposed() && hasColumns() && isValidOrderIndex(visualIndex) ) { + return item.getParent().getColumnOrder()[visualIndex]; + } + return super.getCreationIndex(visualIndex); + } + + /* (non-Javadoc) + * @see dwtx.jface.viewers.ViewerRow#getTextBounds(int) + */ + public Rectangle getTextBounds(int index) { + return item.getTextBounds(index); + } + + /* (non-Javadoc) + * @see dwtx.jface.viewers.ViewerRow#getImageBounds(int) + */ + public Rectangle getImageBounds(int index) { + return item.getImageBounds(index); + } + + private bool hasColumns() { + return this.item.getParent().getColumnCount() !is 0; + } + + private bool isValidOrderIndex(int currentIndex) { + return currentIndex < this.item.getParent().getColumnOrder().length; + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/ViewerCell.d --- a/dwtx/jface/viewers/ViewerCell.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/ViewerCell.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 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 @@ -7,13 +7,15 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Tom Shindl - initial API and implementation + * Tom Schindl - initial API and implementation + * - fix in bug: 195908,198035,215069,215735 * Port to the D programming language: * Frank Benoit *******************************************************************************/ module dwtx.jface.viewers.ViewerCell; +import dwt.custom.StyleRange; import dwtx.jface.viewers.ViewerRow; import dwt.graphics.Color; @@ -59,6 +61,7 @@ */ public static int RIGHT = 1 << 3; + /** * Create a new instance of the receiver on the row. * @@ -98,7 +101,12 @@ if (element !is null) { return element; } - return row.getElement(); + + if (row !is null) { + return row.getElement(); + } + + return null; } /** @@ -168,6 +176,31 @@ row.setImage(columnIndex, image); } + + /** + * Set the style ranges to be applied on the text label + * Note: Requires {@link StyledCellLabelProvider} with owner draw enabled. + * + * @param styleRanges the styled ranges + * + * @since 3.4 + */ + public void setStyleRanges(StyleRange[] styleRanges) { + row.setStyleRanges(columnIndex, styleRanges); + } + + + /** + * Returns the style ranges to be applied on the text label or null if no + * style ranges have been set. + * + * @return styleRanges the styled ranges + * + * @since 3.4 + */ + public StyleRange[] getStyleRanges() { + return row.getStyleRanges(columnIndex); + } /** * Set the columnIndex. @@ -210,6 +243,17 @@ } /** + * Get the current index. This can be different from the original index when + * columns are reordered + * + * @return the current index (as shown in the UI) + * @since 3.4 + */ + public int getVisualIndex() { + return row.getVisualIndex(getColumnIndex()); + } + + /** * Returns the specified neighbor of this cell, or null if no * neighbor exists in the given direction. Direction constants can be * combined by bitwise OR; for example, this method will return the cell to @@ -226,7 +270,6 @@ */ public ViewerCell getNeighbor(int directionMask, bool sameLevel) { ViewerRow row; - int columnIndex; if ((directionMask & ABOVE) is ABOVE) { row = this.row.getNeighbor(ViewerRow.ABOVE, sameLevel); @@ -237,16 +280,36 @@ } if (row !is null) { + int columnIndex; + columnIndex = getVisualIndex(); + + int modifier = 0; + if ((directionMask & LEFT) is LEFT) { - columnIndex = getColumnIndex() - 1; + modifier = -1; } else if ((directionMask & RIGHT) is RIGHT) { - columnIndex = getColumnIndex() + 1; - } else { - columnIndex = getColumnIndex(); + modifier = 1; } + columnIndex += modifier; + if (columnIndex >= 0 && columnIndex < row.getColumnCount()) { - return row.getCell(columnIndex); + ViewerCell cell = row.getCellAtVisualIndex(columnIndex); + if( cell !is null ) { + while( cell !is null ) { + if( cell.isVisible() ) { + break; + } + + columnIndex += modifier; + cell = row.getCellAtVisualIndex(columnIndex); + if( cell is null ) { + break; + } + } + } + + return cell; } } @@ -260,7 +323,67 @@ return row; } - /* (non-Javadoc) + /** + * The location and bounds of the area where the text is drawn depends on + * various things (image displayed, control with DWT.CHECK) + * + * @return The bounds of the of the text area. May return null + * if the underlying widget implementation doesn't provide this + * information + * @since 3.4 + */ + public Rectangle getTextBounds() { + return row.getTextBounds(columnIndex); + } + + /** + * Returns the location and bounds of the area where the image is drawn + * + * @return The bounds of the of the image area. May return null + * if the underlying widget implementation doesn't provide this + * information + * @since 3.4 + */ + public Rectangle getImageBounds() { + return row.getImageBounds(columnIndex); + } + + /** + * Gets the foreground color of the cell. + * + * @return the foreground of the cell or null for the default foreground + * + * @since 3.4 + */ + public Color getForeground() { + return row.getForeground(columnIndex); + } + + /** + * Gets the background color of the cell. + * + * @return the background of the cell or null for the default background + * + * @since 3.4 + */ + public Color getBackground() { + return row.getBackground(columnIndex); + } + + /** + * Gets the font of the cell. + * + * @return the font of the cell or null for the default font + * + * @since 3.4 + */ + public Font getFont() { + return row.getFont(columnIndex); + } + + /* + * (non-Javadoc) + * * @see java.lang.Object#hashCode() */ public override hash_t toHash() { @@ -271,7 +394,9 @@ return result; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see java.lang.Object#equals(java.lang.Object) */ public override int opEquals(Object obj) { @@ -291,4 +416,8 @@ return false; return true; } + + private bool isVisible() { + return getBounds().width > 0; + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/ViewerColumn.d --- a/dwtx/jface/viewers/ViewerColumn.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/ViewerColumn.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 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 @@ -8,7 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation * Tom Shindl - initial API and implementation - * fix for bug 163317,200558 + * fix for bug 163317, 201905 * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -34,9 +34,9 @@ * providers and editing support can be configured for each column separately. * Concrete subclasses of {@link ColumnViewer} should implement a matching * concrete subclass of {@link ViewerColumn}. - * + * * @since 3.3 - * + * */ public abstract class ViewerColumn { @@ -50,9 +50,11 @@ private bool listenerRegistered = false; + private ColumnViewer viewer; + /** * Create a new instance of the receiver at columnIndex. - * + * * @param viewer * the viewer the column is part of * @param columnOwner @@ -60,6 +62,7 @@ * this could be the widget itself */ protected this(ColumnViewer viewer, Widget columnOwner) { + this.viewer = viewer; columnOwner.setData(ViewerColumn.COLUMN_VIEWER_KEY, this); this.listener = new class(viewer) ILabelProviderListener { ColumnViewer viewer_; @@ -84,7 +87,7 @@ /** * Return the label provider for the receiver. - * + * * @return ViewerLabelProvider */ /* package */CellLabelProvider getLabelProvider() { @@ -94,7 +97,7 @@ /** * Set the label provider for the column. Subclasses may extend but must * call the super implementation. - * + * * @param labelProvider * the new {@link CellLabelProvider} */ @@ -111,11 +114,15 @@ if (listenerRegistered && this.labelProvider !is null) { this.labelProvider.removeListener(listener); listenerRegistered = false; + if (registerListener) { + this.labelProvider.dispose(viewer, this); + } } this.labelProvider = labelProvider; if (registerListener) { + this.labelProvider.initialize(viewer, this); this.labelProvider.addListener(listener); listenerRegistered = true; } @@ -123,7 +130,7 @@ /** * Return the editing support for the receiver. - * + * * @return {@link EditingSupport} */ /* package */EditingSupport getEditingSupport() { @@ -133,7 +140,10 @@ /** * Set the editing support. Subclasses may extend but must call the super * implementation. - * + *

    + * Users setting up an editable {@link TreeViewer} or {@link TableViewer} with more than 1 column have + * to pass the DWT.FULL_SELECTION style bit when creating the viewer + *

    * @param editingSupport * The {@link EditingSupport} to set. */ @@ -145,7 +155,7 @@ * Refresh the cell for the given columnIndex. NOTE:the * {@link ViewerCell} provided to this method is no longer valid after this * method returns. Do not cache the cell for future use. - * + * * @param cell * {@link ViewerCell} */ @@ -164,14 +174,26 @@ CellLabelProvider cellLabelProvider = labelProvider; setLabelProvider(null, false); if (disposeLabelProvider) { - cellLabelProvider.dispose(); + cellLabelProvider.dispose(viewer, this); } editingSupport = null; listener = null; + viewer = null; } private void handleDispose(ColumnViewer viewer) { handleDispose(); viewer.clearLegacyEditingSetup(); } + + /** + * Returns the viewer of this viewer column. + * + * @return Returns the viewer. + * + * @since 3.4 + */ + public ColumnViewer getViewer() { + return viewer; + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/ViewerDropAdapter.d --- a/dwtx/jface/viewers/ViewerDropAdapter.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/ViewerDropAdapter.d Thu May 22 01:36:46 2008 +0200 @@ -109,11 +109,17 @@ /** * A flag that allows adapter users to turn auto scrolling - * and expanding on or off. Default is true. + * on or off. Default is true. */ - private bool scrollExpandEnabled = true; + private bool scrollEnabled = true; /** + * A flag that allows adapter users to turn auto + * expanding on or off. Default is true. + */ + private bool expandEnabled = true; + + /** * A flag that allows adapter users to turn selection feedback * on or off. Default is true. */ @@ -401,8 +407,11 @@ event.feedback &= ~DND.FEEDBACK_SELECT; } - if (scrollExpandEnabled) { - event.feedback |= DND.FEEDBACK_EXPAND | DND.FEEDBACK_SCROLL; + if (expandEnabled) { + event.feedback |= DND.FEEDBACK_EXPAND; + } + if (scrollEnabled) { + event.feedback |= DND.FEEDBACK_SCROLL; } } @@ -441,7 +450,30 @@ * @since 2.0 */ public void setScrollExpandEnabled(bool value) { - scrollExpandEnabled = value; + expandEnabled = value; + scrollEnabled = value; + } + + /** + * Sets whether auto expanding should be provided during dragging. + * + * @param value true if expanding is desired, and + * false if not + * @since 3.4 + */ + public void setExpandEnabled(bool value) { + expandEnabled = value; + } + + /** + * Sets whether auto scrolling should be provided during dragging. + * + * @param value true if scrolling is desired, and + * false if not + * @since 3.4 + */ + public void setScrollEnabled(bool value) { + scrollEnabled = value; } /** diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/ViewerRow.d --- a/dwtx/jface/viewers/ViewerRow.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/ViewerRow.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 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 @@ -7,9 +7,8 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Tom Shindl - initial API and implementation - * fix for bug 166346, bug 167325s - * - Fix for bug 174355 + * Tom Schindl - initial API and implementation + * - fix in bug: 166346,167325,174355,195908,198035,215069 * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -20,6 +19,7 @@ import dwtx.jface.viewers.ViewerRow; import dwtx.jface.viewers.TreePath; +import dwt.custom.StyleRange; import dwt.graphics.Color; import dwt.graphics.Font; import dwt.graphics.Image; @@ -27,6 +27,7 @@ import dwt.graphics.Rectangle; import dwt.widgets.Control; import dwt.widgets.Widget; +import dwtx.jface.util.Policy; import dwt.dwthelper.utils; @@ -53,6 +54,8 @@ * @see #getNeighbor(int, bool) */ public static const int BELOW = 2; + + private static final String KEY_TEXT_LAYOUT = Policy.JFACE + "styled_label_key_"; //$NON-NLS-1$ /** * Get the bounds of the entry at the columnIndex, @@ -270,4 +273,107 @@ return true; } + /** + * The cell at the current index (as shown in the UI). This can be different + * to the original index when columns are reordered. + * + * @param visualIndex + * the current index (as shown in the UI) + * @return the cell at the currently visible index + */ + ViewerCell getCellAtVisualIndex(int visualIndex) { + return getCell(getCreationIndex(visualIndex)); + } + + /** + * Translate the original column index to the actual one. + *

    + * Because of backwards API compatibility the default implementation + * returns the original index. Implementators of {@link ColumnViewer} should + * overwrite this method if their widget supports reordered columns + *

    + * + * @param creationIndex + * the original index + * @return the current index (as shown in the UI) + * @since 3.4 + */ + protected int getVisualIndex(int creationIndex) { + return creationIndex; + } + + /** + * Translate the current column index (as shown in the UI) to the original + * one. + *

    + * Because of backwards API compatibility the default implementation + * returns the original index. Implementators of {@link ColumnViewer} should + * overwrite this method if their widget supports reordered columns + *

    + * + * @param visualIndex + * the current index (as shown in the UI) + * @return the original index + * @since 3.4 + */ + protected int getCreationIndex(int visualIndex) { + return visualIndex; + } + + /** + * The location and bounds of the area where the text is drawn depends on + * various things (image displayed, control with DWT.CHECK) + * + * @param index + * the column index + * @return the bounds of the of the text area. May return null + * if the underlying widget implementation doesn't provide this + * information + * @since 3.4 + */ + public Rectangle getTextBounds(int index) { + return null; + } + + + /** + * Returns the location and bounds of the area where the image is drawn. + * + * @param index + * the column index + * @return the bounds of the of the image area. May return null + * if the underlying widget implementation doesn't provide this + * information + * @since 3.4 + */ + public Rectangle getImageBounds(int index) { + return null; + } + + /** + * Set the style ranges to be applied on the text label at the column index + * Note: Requires {@link StyledCellLabelProvider} with owner draw enabled. + * + * @param columnIndex the index of the column + * @param styleRanges the styled ranges + * + * @since 3.4 + */ + public void setStyleRanges(int columnIndex, StyleRange[] styleRanges) { + getItem().setData(KEY_TEXT_LAYOUT + columnIndex, styleRanges); + } + + + /** + * Returns the style ranges to be applied on the text label at the column index or null if no + * style ranges have been set. + * + * @param columnIndex the index of the column + * @return styleRanges the styled ranges + * + * @since 3.4 + */ + public StyleRange[] getStyleRanges(int columnIndex) { + return (StyleRange[]) getItem().getData(KEY_TEXT_LAYOUT + columnIndex); + } } diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/viewers/deferred/DeferredContentProvider.d --- a/dwtx/jface/viewers/deferred/DeferredContentProvider.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/viewers/deferred/DeferredContentProvider.d Thu May 22 01:36:46 2008 +0200 @@ -17,6 +17,7 @@ import dwtx.jface.viewers.deferred.BackgroundContentProvider; import dwtx.jface.viewers.deferred.IConcurrentModel; +import dwt.graphics.Rectangle; import dwt.widgets.Control; import dwt.widgets.Table; import dwtx.core.runtime.Assert; @@ -104,11 +105,11 @@ * @see dwtx.jface.viewers.deferred.AbstractVirtualTable#getVisibleItemCount() */ public override int getVisibleItemCount() { - int start = getTopIndex(); - int itemCount = getItemCount(); Table table = viewer.getTable(); - return Math.min(table.getBounds().height / table.getItemHeight() + 2, - itemCount - start); + Rectangle rect = table.getClientArea (); + int itemHeight = table.getItemHeight (); + int headerHeight = table.getHeaderHeight (); + return (rect.height - headerHeight + itemHeight - 1) / (itemHeight + table.getGridLineWidth()); } /* (non-Javadoc) diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/window/ToolTip.d --- a/dwtx/jface/window/ToolTip.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/window/ToolTip.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 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 @@ -7,6 +7,7 @@ * * Contributors: * Tom Schindl - initial API and implementation + * bugfix in: 195137, 198089, 225190 * Port to the D programming language: * Frank Benoit *******************************************************************************/ @@ -23,6 +24,7 @@ import dwt.layout.FillLayout; import dwt.widgets.Composite; import dwt.widgets.Control; +import dwt.widgets.Display; import dwt.widgets.Event; import dwt.widgets.Listener; import dwt.widgets.Monitor; @@ -69,6 +71,8 @@ private TooltipHideListener hideListener; + private Listener shellListener; + private bool hideOnMouseDown = true; private bool respectDisplayBounds = true; @@ -79,6 +83,8 @@ private Object currentArea; + private static final bool IS_OSX = DWT.getPlatform().equals("carbon"); //$NON-NLS-1$ + /** * Create new instance which add TooltipSupport to the widget * @@ -93,7 +99,7 @@ * @param control * the control to which the tooltip is bound * @param style - * style passed to control tooltip behaviour + * style passed to control tooltip behavior * * @param manualActivation * true if the activation is done manually using @@ -108,12 +114,29 @@ this.control.addDisposeListener(new class DisposeListener { public void widgetDisposed(DisposeEvent e) { + data = null; deactivate(); } }); this.listener = new ToolTipOwnerControlListener(); + this.shellListener = new Listener() { + public void handleEvent(final Event event) { + if( ToolTip.this.control !is null && ! ToolTip.this.control.isDisposed() ) { + ToolTip.this.control.getDisplay().asyncExec(new Runnable() { + + public void run() { + // Check if the new active shell is the tooltip itself + if( ToolTip.this.control.getDisplay().getActiveShell() !is CURRENT_TOOLTIP) { + toolTipHide(CURRENT_TOOLTIP, event); + } + } + + }); + } + } + }; if (!manualActivation) { activate(); @@ -296,8 +319,8 @@ * the event * @return the area responsible for the tooltip creation or * null this could be any object describing the area - * (e.g. the {@link Control} onto which the tooltip is bound to, a part of - * this area e.g. for {@link ColumnViewer} this could be a + * (e.g. the {@link Control} onto which the tooltip is bound to, a + * part of this area e.g. for {@link ColumnViewer} this could be a * {@link ViewerCell}) */ protected Object getToolTipArea(Event event) { @@ -343,8 +366,18 @@ } tip.pack(); - tip.setLocation(fixupDisplayBounds(tip.getSize(), getLocation(tip - .getSize(), event))); + Point size = tip.getSize(); + Point location = fixupDisplayBounds(size, getLocation(size, event)); + + // Need to adjust a bit more if the mouse cursor.y is tip.y and + // the cursor.x is inside the tip + Point cursorLocation = tip.getDisplay().getCursorLocation(); + + if( cursorLocation.y is location.y && location.x < cursorLocation.x && location.x + size.x > cursorLocation.x ) { + location.y -= 2; + } + + tip.setLocation(location); tip.setVisible(true); } } @@ -377,12 +410,12 @@ } if (!(bounds.contains(location) && bounds.contains(rightBounds))) { - if (rightBounds.x > bounds.width) { - location.x -= rightBounds.x - bounds.width; + if (rightBounds.x > bounds.x + bounds.width) { + location.x -= rightBounds.x - (bounds.x + bounds.width); } - if (rightBounds.y > bounds.height) { - location.y -= rightBounds.y - bounds.height; + if (rightBounds.y > bounds.y + bounds.height) { + location.y -= rightBounds.y - (bounds.y + bounds.height); } if (location.x < bounds.x) { @@ -414,13 +447,65 @@ private void toolTipHide(Shell tip, Event event) { if (tip !is null && !tip.isDisposed() && shouldHideToolTip(event)) { + control.getShell().removeListener(DWT.Deactivate, shellListener); currentArea = null; + passOnEvent(tip,event); tip.dispose(); CURRENT_TOOLTIP = null; afterHideToolTip(event); } } + private void passOnEvent(Shell tip,Event event) { + if ( control !is null && ! control.isDisposed() && event !is null && event.widget !is control && event.type is DWT.MouseDown) { + final Display display = control.getDisplay(); + Point newPt = display.map(tip, null, new Point(event.x, event.y)); + + final Event newEvent = new Event(); + newEvent.button=event.button; + newEvent.character=event.character; + newEvent.count = event.count; + newEvent.data=event.data; + newEvent.detail=event.detail; + newEvent.display=event.display; + newEvent.doit=event.doit; + newEvent.end=event.end; + newEvent.gc=event.gc; + newEvent.height=event.height; + newEvent.index=event.index; + newEvent.item=event.item; + newEvent.keyCode=event.keyCode; + newEvent.start=event.start; + newEvent.stateMask=event.stateMask; + newEvent.text=event.text; + newEvent.time=event.time; + newEvent.type=event.type; + newEvent.widget=event.widget; + newEvent.width=event.width; + newEvent.x = newPt.x; + newEvent.y = newPt.y; + + tip.close(); + display.asyncExec(new Runnable() { + public void run() { + if( IS_OSX ) { + try { + Thread.sleep(300); + } catch (InterruptedException e) { + + } + + display.post(newEvent); + newEvent.type = DWT.MouseUp; + display.post(newEvent); + } else { + display.post(newEvent); + } + } + }); + } + } + private void toolTipOpen(Shell shell, Event event) { // Ensure that only one Tooltip is shown in time if (CURRENT_TOOLTIP !is null) { @@ -429,6 +514,8 @@ CURRENT_TOOLTIP = shell; + control.getShell().addListener(DWT.Deactivate, shellListener); + if (popupDelay > 0) { control.getDisplay().timerExec(popupDelay, new class(shell,event) Runnable { Shell shell_; diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/window/Window.d --- a/dwtx/jface/window/Window.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/window/Window.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -328,6 +328,11 @@ * This framework method may be extended (super.close must * be called). *

    + *

    + * Note that in order to prevent recursive calls to this method + * it does not call Shell#close(). As a result ShellListeners + * will not receive a shellClosed event. + *

    * * @return true if the window is (or was already) closed, and * false if it is still open diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/wizard/ProgressMonitorPart.d --- a/dwtx/jface/wizard/ProgressMonitorPart.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/wizard/ProgressMonitorPart.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -59,13 +59,13 @@ /** the cancel component */ protected Control fCancelComponent; - /** true if cancled */ + /** true if canceled */ protected bool fIsCanceled; /** current blocked status */ protected IStatus blockedStatus; - /** the cancle lister attached to the cancle component */ + /** the cancel lister attached to the cancel component */ protected Listener fCancelListener; private void init_fCancelListener(){ fCancelListener = new class Listener { @@ -165,9 +165,9 @@ /** * Creates the progress monitor's UI parts and layouts them - * according to the given layout. If the layou is null + * according to the given layout. If the layout is null * the part's default layout is used. - * @param layout The layoutfor the receiver. + * @param layout The layout for the receiver. * @param progressIndicatorHeight The suggested height of the indicator */ protected void initialize(Layout layout, int progressIndicatorHeight) { @@ -281,12 +281,21 @@ * @return String */ private String taskLabel() { - String text = fSubTaskName is null ? "" : fSubTaskName; //$NON-NLS-1$ - if (fTaskName !is null && fTaskName.length > 0) { - text = JFaceResources.format( - "Set_SubTask", [ fTaskName, text ]);//$NON-NLS-1$ + bool hasTask= fTaskName !is null && fTaskName.length() > 0; + bool hasSubtask= fSubTaskName !is null && fSubTaskName.length > 0; + + if (hasTask) { + if (hasSubtask) + return escapeMetaCharacters(JFaceResources.format( + "Set_SubTask", new Object[] { fTaskName, fSubTaskName }));//$NON-NLS-1$ + return escapeMetaCharacters(fTaskName); + + } else if (hasSubtask) { + return escapeMetaCharacters(fSubTaskName); + + } else { + return ""; //$NON-NLS-1$ } - return escapeMetaCharacters(text); } /** diff -r 07b9d96fd764 -r 46a6e0e6ccd4 dwtx/jface/wizard/WizardDialog.d --- a/dwtx/jface/wizard/WizardDialog.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/wizard/WizardDialog.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -888,14 +888,14 @@ * the control * @param h * the map (key type: String, element type: - * bool) + * Boolean) * @param key * the key * @see #saveEnableStateAndSet */ private void restoreEnableState(Control w, Map!(Object,Object) h, String key) { if (w !is null) { - auto b = cast(Boolean) h.get(stringcast(key)); + Boolean b = (Boolean) h.get(stringcast(key)); if (b !is null) { w.setEnabled(b.booleanValue()); } @@ -972,7 +972,7 @@ * the control, or null if none * @param h * the map (key type: String, element type: - * bool) + * Boolean) * @param key * the key * @param enabled @@ -1220,7 +1220,7 @@ * @see #aboutToStart */ private void stopped(Object savedState) { - if (getShell() !is null) { + if (getShell() !is null && !getShell().isDisposed()) { if (wizard.needsProgressMonitor()) { progressMonitorPart.setVisible(false); progressMonitorPart.removeFromCancelComponent(cancelButton); @@ -1235,7 +1235,7 @@ arrowCursor.dispose(); arrowCursor = null; Control focusControl = cast(Control) state.get(stringcast(FOCUS_CONTROL)); - if (focusControl !is null) { + if (focusControl !is null && !focusControl.isDisposed()) { focusControl.setFocus(); } }